/* ============================================================
   SAACHO STORY APP — Ant-informed skin over the brand base
   ------------------------------------------------------------
   Owner : apps/content/story  (routes /stories, /story,
           /story/{id}, /story/{id}/{slug})
   Loads : /brand/css/saacho.css?v=2026-10-01   (shared, read-only)
   Serves: /public/assets/story/story.css

    WHY THIS FILE EXISTS
    Five files used to carry their own inline <style> block. Four of them
    (stories.php, story.php, includes/components/layout.php and this
    file's own predecessors) are collected here so they are cacheable
    instead of being re-downloaded with every page view. editor.php
    deliberately keeps its block inline: it has to load after
    summernote-lite.css to win on the WYSIWYG widgets, and it is behind
    admin auth so the extra bytes cost nothing. dashboard.php and
    admin.php still carry theirs and are not on this app's routes.

   WHAT IT CHANGES - the Ant mechanics, on Saacho tokens
     - container      1100px shell / 24px gutters, centred
     - cards          --card-bg + --hairline + --radius-lg + --shadow-1,
                       hover lifts to --shadow-2 and translateY(-1px)
     - controls       --radius-md (6px), min-height --control-h (32px),
                       --control-h-lg (40px) for primaries, --fs-base (14px)
     - pills killed   no border-radius:999px/50% on anything clickable,
                       no 2px+ borders on inputs - hairlines throughout
     - form focus     box-shadow: var(--focus-ring)
     - spacing        the 8 / 16 / 24 / 32 scale, real grid + flex with
                       12-24px gaps. No inline-block, no float, no ad-hoc rem
     - canvas         --bg grey behind white --card-bg surfaces

   WHAT IT KEEPS - the Saacho identity
     - Source Serif 4 on every display heading (hero, card titles, article
       h2/h3, "Continue Exploring", 404). This is a reading app; the serif
       display face is the brand, not decoration.
     - the gold rule. .toc-title and .share-label carry the same
       small-caps + 36px gold ::after rule that .kicker uses in
       saacho.css, and the stories masthead keeps its gold full stop.
     - teal as a FILL (--brand) on progress bar, primary buttons, native
       share, bar charts; teal TEXT on --brand-text everywhere, because
       --brand measures 4.24:1 on white and fails AA as text.
     - gold as a FILL (--gold) on the kicker rules, blockquote rail,
       summary rail; gold TEXT on --gold-text.
     - 16px body prose (--fs-md). 14px (--fs-base) is only ever used on
       controls, labels, chips, metadata and card meta.

   DELIBERATE DEPARTURE FROM THE 1100px CONTAINER
   .article-container stays at 720px. It is the prose measure, not the page
   shell: at 16px, 672px of text is ~80 characters, and the contract puts
   prose legibility above density on a reading page. Every page shell
   (.container, the article hero, the cover band) is 1100px.

    NO CLASS WAS RENAMED. Every selector here matches a class the PHP
    already emitted; a few were undefined before and are defined now
    (.card, .btn, .btn-primary, .hero) because the markup already used them.
    Four new hook classes were ADDED, none removed, purely to move
    presentation out of style="" attributes: .empty-icon,
    .story-disclaimer-inline, .reactions-empty and .copy-text.
    No custom property is declared anywhere in this file - every colour,
    radius, shadow and size below is a token from saacho.css.
   ============================================================ */

/* ── Shell ────────────────────────────────────────────────── */
html, body { max-width: 100%; overflow-x: clip; }

body {
  background: var(--bg);
  color: var(--ink);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

/* Body is a flex column, so something has to absorb the leftover height or
   short pages (the 404, a stub article) leave the footer stranded mid-screen
   with grey beneath it. stories.php wraps its content in <main>; story.php
   has no <main> at all, so its two top-level regions grow here instead. */
main,
.article-container,
.article-not-found {
  flex: 1 0 auto;
  width: 100%;
}

.container {
  max-width: 1100px;
  margin-inline: auto;
  padding-inline: 24px;
}

/* ── Card primitive ────────────────────────────────────────────
   The markup already shipped class="card" on the story and related
   cards; nothing in saacho.css defined it, so they were rendering as
   bare <a> elements. This is that missing definition, Ant-shaped. */
.card {
  background: var(--card-bg);
  border: var(--hairline);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-1);
  transition: box-shadow var(--dur) var(--ease),
              transform var(--dur) var(--ease),
              border-color var(--dur) var(--ease);
}
.card:hover {
  border-color: var(--border);
  box-shadow: var(--shadow-2);
  transform: translateY(-1px);
}

/* ── Button primitives ─────────────────────────────────────────
   Same story: markup says class="btn btn-primary" and
   class="btn btn-ghost"; neither .btn nor .btn-primary existed. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: var(--control-h-lg);
  padding: 0 16px;
  border: var(--hairline);
  border-radius: var(--radius-md);
  background: var(--card-bg);
  color: var(--ink);
  font-family: inherit;
  font-size: var(--fs-base);
  line-height: var(--lh-body);
  font-weight: 400;
  cursor: pointer;
  text-decoration: none;
  transition: background-color var(--dur) var(--ease),
              border-color var(--dur) var(--ease),
              color var(--dur) var(--ease),
              box-shadow var(--dur) var(--ease);
}
.btn:hover {
  background: var(--brand-light);
  border-color: var(--brand-text);
  color: var(--brand-text);
  text-decoration: none;
}

.btn-primary {
  background: var(--brand);
  border-color: var(--brand);
  color: #fff;
  box-shadow: 0 2px 0 rgba(14, 138, 125, .1);
}
.btn-primary:hover {
  background: var(--brand-dark);
  border-color: var(--brand-dark);
  color: #fff;
}

/* .btn-ghost is a shared saacho.css class (a borderless text link).
   On the story footer it has to read as a real secondary button, so the
   override is scoped rather than global. */
.article-footer-actions .btn-ghost {
  min-height: var(--control-h-lg);
  padding: 0 16px;
  border: var(--hairline);
  border-radius: var(--radius-md);
  background: var(--card-bg);
  color: var(--ink);
  font-size: var(--fs-base);
  font-weight: 400;
}
.article-footer-actions .btn-ghost:hover {
  background: var(--brand-light);
  border-color: var(--brand-text);
  color: var(--brand-text);
}

/* ── Stories index: masthead ────────────────────────────────
   Stays full-bleed so the hairline runs the width of the viewport like every
   other band on the site (.footer-brand, .section-spacing). Its content is
   already centre-constrained: the h1 by its clamp()ed size, the lede by
   max-width, the stat row by justify-content. */
.stories-hero {
  text-align: center;
  background: var(--bg);
  padding: 64px 24px 48px;
  border-bottom: var(--hairline);
}
.stories-hero h1 {
  font-family: var(--saacho-serif);
  font-size: clamp(2.2rem, 5vw, 3.4rem);
  font-weight: 650;
  line-height: 1.2;
  letter-spacing: -.015em;
  color: var(--ink);
  margin: 0 0 16px;
}
.stories-hero h1 .dot { color: var(--gold-text); }
.stories-hero p {
  max-width: 560px;
  margin-inline: auto;
  color: var(--ink-dim);
  font-size: var(--fs-md);
  line-height: var(--lh-body);
}

.stories-stats {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 16px 32px;
  margin-top: 32px;
}
.stories-stat b {
  display: block;
  font-size: 1.5rem;
  font-weight: 700;
  line-height: 1.25;
  color: var(--brand-text);
}
.stories-stat span {
  font-size: var(--fs-xs);
  line-height: var(--lh-body);
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--ink-mute);
}

/* The brand ornament between masthead and grid: same 320x32 asset,
   recoloured to the neutral hairline so it reads as a rule rather than
   a dark ornament sitting on the grey canvas. */
.section-rule-divider {
  display: block;
  width: 320px;
  max-width: 100%;
  margin-inline: auto;
  color: var(--border);
}

/* ── Stories index: grid ──────────────────────────────────── */
.stories-section { padding: 48px 0 64px; }
.stories-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 24px;
}

/* ── Stories index: card ──────────────────────────────────── */
.story-card {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  color: inherit;
  text-decoration: none;
  background: var(--card-bg);
  border: var(--hairline);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-1);
  transition: box-shadow var(--dur) var(--ease),
              transform var(--dur) var(--ease),
              border-color var(--dur) var(--ease);
}
.story-card:hover {
  border-color: var(--border);
  box-shadow: var(--shadow-2);
  transform: translateY(-1px);
}

.story-card-img {
  aspect-ratio: 16 / 10;
  width: 100%;
  position: relative;
  overflow: hidden;
  border-bottom: var(--hairline);
}
.story-card-img img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  transition: transform 400ms var(--ease);
}
.story-card:hover .story-card-img img { transform: scale(1.04); }

.story-card-body {
  display: flex;
  flex-direction: column;
  flex: 1;
  padding: 16px;
}
.story-card-title {
  font-family: var(--saacho-serif);
  font-size: var(--fs-md);
  font-weight: 650;
  line-height: 1.4;
  color: var(--ink);
  margin: 0 0 8px;
}
.story-card:hover .story-card-title { color: var(--brand-text); }
.story-card-excerpt {
  color: var(--ink-dim);
  font-size: var(--fs-md);
  line-height: var(--lh-body);
  margin: 0 0 16px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.story-card-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 16px;
  margin-top: auto;
  padding-top: 16px;
  border-top: var(--hairline);
  font-size: var(--fs-xs);
  line-height: var(--lh-body);
  color: var(--ink-mute);
}
.story-card-meta span {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.story-card-meta i { opacity: .7; }

.draft-badge {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  min-height: var(--control-h-sm);
  padding: 0 8px;
  background: var(--warning);
  color: #fff;
  border-radius: var(--radius-sm);
  font-size: var(--fs-xs);
  font-weight: 600;
  line-height: var(--lh-body);
  letter-spacing: .08em;
  text-transform: uppercase;
}

.story-card-placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--brand-light);
  color: var(--brand-dark);
  font-size: 2rem;
}

/* ── Stories index: empty state ───────────────────────────── */
.empty {
  max-width: 480px;
  margin: 32px auto;
  padding: 32px 24px;
  text-align: center;
  background: var(--card-bg);
  border: var(--hairline);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-1);
}
.empty-icon {
  display: block;
  margin-bottom: 16px;
  font-size: 3rem;
  line-height: 1;
  opacity: .4;
  color: var(--border);
}
.empty h3 {
  font-family: var(--saacho-serif);
  font-size: 1.5rem;
  font-weight: 650;
  margin: 0 0 8px;
}
.empty p {
  color: var(--ink-dim);
  margin: 0 0 24px;
}

/* ── Story page: reading progress ─────────────────────────── */
.reading-progress {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 3px;
  background: transparent;
  z-index: 200;
  /* the bar sits over the sticky navbar; without this it swallows
     clicks on whatever it happens to overlap */
  pointer-events: none;
}
.reading-progress-bar {
  height: 100%;
  width: 0%;
  background: var(--brand);
  transition: width 100ms linear;
}

/* ── Story page: hero ─────────────────────────────────────── */
.article-hero,
.hero {
  background: transparent;
  padding: 56px 0 32px;
  border-bottom: var(--hairline);
}
.article-hero .hero-inner { text-align: center; }
.article-hero h1 {
  font-family: var(--saacho-serif);
  font-size: clamp(1.9rem, 4.5vw, 2.9rem);
  font-weight: 650;
  line-height: 1.2;
  letter-spacing: -.02em;
  color: var(--ink);
  max-width: 24ch;
  margin: 0 auto 24px;
  overflow-wrap: break-word;
  text-wrap: balance;
}

.article-meta {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 8px 24px;
  color: var(--ink-mute);
  font-size: var(--fs-base);
  line-height: var(--lh-body);
}
.article-meta-item {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  white-space: nowrap;
}
.article-meta-item i { opacity: .65; }

/* Ant chip: tinted fill, hairline, 4px radius, 24px control height */
.reading-time-badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: var(--control-h-sm);
  padding: 0 8px;
  background: var(--brand-light);
  border: 1px solid var(--brand-border);
  border-radius: var(--radius-sm);
  font-size: var(--fs-base);
  font-weight: 400;
  color: var(--brand-text);
  white-space: nowrap;
}

/* ── Story page: cover band ───────────────────────────────── */
.article-cover {
  max-width: 1100px;
  margin: 24px auto 0;
  padding: 0 24px;
}
.article-cover-inner {
  border-radius: var(--radius-lg);
  overflow: hidden;
  border: var(--hairline);
}
.article-cover-image {
  display: block;
  width: 100%;
  max-height: 70vh;
  object-fit: contain;
  background: var(--surface-2);
  transition: opacity 350ms var(--ease);
}
.article-cover-placeholder {
  width: 100%;
  min-height: 260px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--surface-2);
  color: var(--border);
  font-size: 3rem;
}

/* ── Story page: reading column ───────────────────────────── */
.article-container {
  width: 100%;
  max-width: 1100px;
  margin: 0 auto;
  padding: 32px 24px 64px;
}

.article-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 32px;
  align-items: start;
}

.article-layout.has-aside {
  grid-template-columns: minmax(0, 1fr) 260px;
}

.article-aside {
  position: sticky;
  top: 24px;
  min-width: 0;
  display: none;
}

.article-layout.has-aside .article-aside { display: block; }

@media (max-width: 900px) {
  .article-layout,
  .article-layout.has-aside { grid-template-columns: 1fr; }
  .article-aside { position: static; order: -1; }
}

.article-back-link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: var(--control-h);
  padding: 0 8px;
  margin: 0 0 24px -8px;
  border-radius: var(--radius-md);
  color: var(--ink-dim);
  font-size: var(--fs-base);
  line-height: var(--lh-body);
  font-weight: 400;
  text-decoration: none;
  transition: color var(--dur) var(--ease), background-color var(--dur) var(--ease);
}
.article-back-link:hover {
  background: var(--brand-light);
  color: var(--brand-text);
  text-decoration: none;
}

/* ── Story page: table of contents ────────────────────────── */
.toc-section {
  background: var(--card-bg);
  border: var(--hairline);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-1);
  padding: 16px 24px;
  margin-bottom: 24px;
}
/* the .kicker idiom from saacho.css: small caps + a 36px gold rule */
.toc-title {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 8px;
  font-size: var(--fs-xs);
  font-weight: 600;
  line-height: var(--lh-body);
  text-transform: uppercase;
  letter-spacing: .12em;
  color: var(--ink-dim);
}
.toc-title::after {
  content: "";
  width: 36px;
  height: 1px;
  background: var(--gold);
}
.toc-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.toc-list li { margin: 0; }
.toc-list a {
  display: block;
  padding: 8px 12px;
  border-left: 1px solid var(--border);
  color: var(--ink-dim);
  font-size: var(--fs-base);
  line-height: 1.4;
  text-decoration: none;
  transition: color var(--dur) var(--ease),
              border-color var(--dur) var(--ease),
              background-color var(--dur) var(--ease);
}
.toc-list a:hover,
.toc-list a:focus-visible {
  background: var(--brand-light);
  border-left-color: var(--brand-text);
  color: var(--brand-text);
  text-decoration: none;
}
.toc-list .toc-h3 {
  padding-left: 24px;
  font-size: var(--fs-base);
}

/* ── Story page: prose card ───────────────────────────────── */
.article-body {
  min-width: 0;
  overflow-wrap: break-word;
  background: var(--card-bg);
  border: var(--hairline);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-1);
  padding: clamp(16px, 3vw, 32px);
  font-size: var(--fs-md);
  line-height: 1.75;
}

/* Keep editor-authored content inside the column: wrap long words,
   scroll wide tables, and cap every embedded element. */
.article-body > * { max-width: 100%; }
.article-body > :first-child { margin-top: 0; }

.article-body h2 {
  font-family: var(--saacho-serif);
  font-size: 1.5rem;
  font-weight: 650;
  line-height: 1.3;
  margin: 32px 0 16px;
}
.article-body h3 {
  font-family: var(--saacho-serif);
  font-size: 1.25rem;
  font-weight: 650;
  line-height: 1.4;
  margin: 24px 0 12px;
}
.article-body h4 {
  font-size: var(--fs-md);
  font-weight: 600;
  line-height: 1.45;
  margin: 24px 0 8px;
}
.article-body p {
  line-height: 1.75;
  margin: 0 0 24px;
}
/* prose links are underlined: an unadorned teal run inside a paragraph
   is the classic reading-page legibility failure */
.article-body a {
  color: var(--brand-text);
  text-decoration: underline;
  text-underline-offset: .28em;
  text-decoration-thickness: 1px;
}
.article-body ul,
.article-body ol {
  margin: 0 0 24px;
  padding-left: 24px;
}
.article-body li { margin-bottom: 8px; }
.article-body img {
  max-width: 100%;
  height: auto;
  margin: 24px 0;
  border: var(--hairline);
  border-radius: var(--radius-md);
}
.article-body blockquote {
  margin: 24px 0;
  padding: 16px 24px;
  border-left: 3px solid var(--gold);
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
  background: var(--gold-light);
  color: var(--ink-dim);
}
.article-body blockquote p:last-child { margin-bottom: 0; }
.article-body pre {
  white-space: pre-wrap;
  overflow-x: auto;
  padding: 16px;
  border: var(--hairline);
  border-radius: var(--radius-md);
  background: var(--surface-2);
  font-size: var(--fs-base);
  line-height: 1.6;
}
.article-body code {
  font-family: "JetBrains Mono", ui-monospace, Menlo, Consolas, monospace;
  font-size: .875em;
}
.article-body hr {
  border: none;
  border-top: var(--hairline);
  margin: 32px 0;
}
.article-body video,
.article-body iframe {
  max-width: 100%;
  border: var(--hairline);
  border-radius: var(--radius-md);
}
.article-body table { display: block; overflow-x: auto; }
.article-body table.spss-table { display: block; width: 100%; overflow-x: auto; }

/* ── Story page: disclaimer (Ant alert) ───────────────────── */
.story-disclaimer {
  margin-top: 24px;
  padding: 16px 24px;
  background: var(--warning-soft);
  border: 1px solid var(--warning-border);
  border-left: 4px solid var(--warning);
  border-radius: var(--radius-md);
  color: var(--warning);
  font-size: var(--fs-md);
  line-height: 1.7;
}
.story-disclaimer strong { color: var(--warning); font-weight: 600; }
/* the outdated-content banner is the first child of the prose card, so it
   needs its own bottom gap rather than the .story-disclaimer margin-top */
.story-disclaimer-inline { margin-bottom: 24px; }

/* ── Story page: share ────────────────────────────────────── */
.share-section,
.reactions-section {
  margin-top: 24px;
  padding: 24px;
  background: var(--card-bg);
  border: var(--hairline);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-1);
}
.share-label {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 16px;
  font-size: var(--fs-xs);
  font-weight: 600;
  line-height: var(--lh-body);
  text-transform: uppercase;
  letter-spacing: .12em;
  color: var(--ink-dim);
}
.share-label::after {
  content: "";
  width: 36px;
  height: 1px;
  background: var(--gold);
}
.share-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.share-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: var(--control-h);
  padding: 0 16px;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  color: #fff;
  font-family: inherit;
  font-size: var(--fs-base);
  line-height: var(--lh-body);
  font-weight: 400;
  cursor: pointer;
  text-decoration: none;
  transition: transform var(--dur) var(--ease), filter var(--dur) var(--ease);
}
/* third-party networks keep their own brand fills; hover darkens
   rather than lightens, which is the Ant direction for a solid fill */
.share-btn:hover {
  transform: translateY(-1px);
  filter: brightness(.94);
  color: #fff;
  text-decoration: none;
}
/* the site's own share action is the primary control on this row */
.share-btn.native {
  min-height: var(--control-h-lg);
  padding: 0 24px;
  background: var(--brand);
}
.share-btn.native:hover { background: var(--brand-dark); }
.share-btn.facebook { background: #1877f2; }
.share-btn.twitter  { background: #0f1419; }
.share-btn.linkedin { background: #0a66c2; }
.share-btn.whatsapp { background: #25d366; }
.share-btn.copy     { background: var(--ink-dim); }
.share-btn.copy.copied { background: var(--success); }
/* JS swaps "Copy Link" for "Copied!" - keep the label on one line so the
   button does not resize under the reader while it is being pressed */
.copy-text { white-space: nowrap; }

/* ── Story page: reactions ────────────────────────────────── */
.reactions-header {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 16px;
}
.reactions-header h3 {
  font-size: var(--fs-md);
  font-weight: 600;
  margin: 0;
}
.reactions-count {
  display: inline-flex;
  align-items: center;
  min-height: var(--control-h-sm);
  padding: 0 8px;
  background: var(--brand);
  color: #fff;
  border-radius: var(--radius-sm);
  font-size: var(--fs-xs);
  font-weight: 600;
  line-height: var(--control-h-sm);
}
.reactions-display {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  min-height: var(--control-h);
  margin-bottom: 16px;
}
.reaction-tag {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: var(--control-h-sm);
  padding: 0 8px;
  background: var(--surface-2);
  border: var(--hairline);
  border-radius: var(--radius-sm);
  font-size: var(--fs-base);
  color: var(--ink);
}
.reaction-tag .count {
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--ink-mute);
}
.reaction-input-area {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}
.reaction-input-area label {
  margin: 0;
  font-size: var(--fs-base);
  color: var(--ink-dim);
}
/* element+class so it ties with saacho.css's input[type="text"]
   block and, being later, wins */
input.reaction-input {
  flex: 1 1 200px;
  min-width: 120px;
  max-width: 200px;
  min-height: var(--control-h);
  padding: 4px 11px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card-bg);
  color: var(--ink);
  font-family: inherit;
  font-size: var(--fs-base);
  line-height: var(--lh-body);
}
input.reaction-input:focus {
  outline: none;
  border-color: var(--brand-text);
  box-shadow: var(--focus-ring);
}
.reaction-submit {
  min-height: var(--control-h);
  padding: 0 16px;
  background: var(--brand);
  border: 1px solid var(--brand);
  border-radius: var(--radius-md);
  color: #fff;
  font-family: inherit;
  font-size: var(--fs-base);
  line-height: var(--lh-body);
  font-weight: 400;
  cursor: pointer;
  transition: background-color var(--dur) var(--ease),
              border-color var(--dur) var(--ease);
}
.reaction-submit:hover {
  background: var(--brand-dark);
  border-color: var(--brand-dark);
}
.reaction-submit:disabled {
  opacity: .5;
  cursor: not-allowed;
}
.reaction-message {
  margin-top: 8px;
  padding: 8px 12px;
  border-radius: var(--radius-md);
  font-size: var(--fs-base);
  line-height: var(--lh-body);
}
.reaction-message.success {
  background: var(--success-soft);
  color: var(--success);
}
.reaction-message.error {
  background: var(--danger-soft);
  color: var(--danger);
}
/* the empty-reactions placeholder, emitted by loadReactions() */
.reactions-empty {
  font-size: var(--fs-base);
  line-height: var(--lh-body);
  color: var(--ink-mute);
}

/* ── Story page: related ──────────────────────────────────── */
.related-section {
  margin-top: 48px;
  padding-top: 32px;
  border-top: var(--hairline);
}
.related-section h3 {
  text-align: center;
  font-family: var(--saacho-serif);
  font-size: 1.5rem;
  font-weight: 650;
  margin-bottom: 24px;
}
.related-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 24px;
}
.related-card {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  color: inherit;
  text-decoration: none;
  background: var(--card-bg);
  border: var(--hairline);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-1);
  transition: box-shadow var(--dur) var(--ease),
              transform var(--dur) var(--ease),
              border-color var(--dur) var(--ease);
}
.related-card:hover {
  border-color: var(--border);
  box-shadow: var(--shadow-2);
  transform: translateY(-1px);
}
.related-card-image {
  aspect-ratio: 16 / 10;
  width: 100%;
  position: relative;
  overflow: hidden;
  border-bottom: var(--hairline);
}
.related-card-image img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  transition: transform 400ms var(--ease);
}
.related-card:hover .related-card-image img { transform: scale(1.03); }
.related-card-placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--surface-2);
  color: var(--ink-mute);
  font-size: 1.5rem;
}
.related-card-content {
  display: flex;
  flex-direction: column;
  flex: 1;
  padding: 16px;
}
.related-card-title {
  font-family: var(--saacho-serif);
  font-size: var(--fs-md);
  font-weight: 650;
  line-height: 1.4;
  color: var(--ink);
  margin: 0 0 8px;
}
.related-card:hover .related-card-title { color: var(--brand-text); }
.related-card-meta {
  font-size: var(--fs-xs);
  line-height: var(--lh-body);
  color: var(--ink-mute);
}

/* ── Story page: footer actions ───────────────────────────── */
.article-footer-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 40px;
  padding-top: 24px;
  border-top: var(--hairline);
}

/* ── Story page: 404 ──────────────────────────────────────── */
.article-not-found {
  max-width: 520px;
  margin: 64px auto;
  padding: 48px 32px;
  text-align: center;
  background: var(--card-bg);
  border: var(--hairline);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-1);
}
.article-not-found i {
  display: block;
  margin-bottom: 16px;
  font-size: 3.5rem;
  color: var(--border);
}
.article-not-found h2 {
  font-family: var(--saacho-serif);
  font-size: 1.75rem;
  font-weight: 650;
  margin-bottom: 8px;
}
.article-not-found p {
  color: var(--ink-dim);
  margin-bottom: 24px;
}

/* ── Editor-authored blocks that live inside article bodies ────
   These classes are emitted by the HTML editors paste into an article,
   not by this app's markup. They are restyled, never renamed. */
.demo-form,
.spss-chart,
.summary-box { box-sizing: border-box; max-width: 100%; }

.demo-form {
  margin: 24px 0;
  padding: 16px 24px;
  border: var(--hairline);
  border-radius: var(--radius-md);
  background: var(--surface-2);
}
.demo-form-title {
  margin: 0 0 16px;
  font-size: var(--fs-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--ink-dim);
}
.demo-form fieldset { border: none; margin: 0; padding: 0; }
.demo-form legend {
  padding: 0;
  margin-bottom: 8px;
  font-size: var(--fs-base);
  font-weight: 600;
}
.demo-option {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 0;
  font-size: var(--fs-md);
  cursor: pointer;
}
.demo-option input {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  accent-color: var(--brand);
}
.demo-note {
  margin: 8px 0 0;
  font-size: var(--fs-base);
  color: var(--ink-mute);
}

.article-body .summary-box {
  margin: 24px 0;
  padding: 16px 24px;
  border-left: 4px solid var(--brand);
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
  background: var(--brand-light);
}
.article-body .summary-box h3 { margin-top: 0; }

/* Simulated SPSS Variable View table */
.spss-table {
  width: 100%;
  margin: 24px 0;
  border-collapse: collapse;
  font-size: var(--fs-base);
}
.spss-table caption {
  caption-side: top;
  text-align: left;
  padding-bottom: 8px;
  font-size: var(--fs-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--ink-dim);
}
.spss-table th {
  background: var(--surface-2);
  color: var(--ink);
  font-weight: 600;
  text-align: left;
}
.spss-table th,
.spss-table td {
  padding: 8px 12px;
  border: var(--hairline);
  vertical-align: top;
}
.spss-table tbody tr:nth-child(odd) { background: var(--surface-2); }

/* Simulated SPSS output charts */
.spss-chart {
  margin: 24px 0;
  padding: 16px 24px;
  border: var(--hairline);
  border-radius: var(--radius-md);
  background: var(--card-bg);
}
.spss-chart-title {
  margin-bottom: 16px;
  font-size: var(--fs-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--ink-dim);
}
.bar-row {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
  margin: 8px 0;
  font-size: var(--fs-base);
}
.bar-label {
  flex-shrink: 0;
  min-width: 7.5em;
  text-align: right;
}
.bar-track {
  flex: 1;
  display: flex;
  align-items: center;
  height: 16px;
  overflow: hidden;
  border: var(--hairline);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
}
.bar-fill {
  display: block;
  height: 100%;
  border-radius: var(--radius-sm) 0 0 var(--radius-sm);
}
.bar-fill-brand { background: var(--brand); }
.bar-fill-blue  { background: #8fb8e1; }
.bar-fill-coral { background: #e8847c; }
.bar-fill-teal  { background: #698c8c; }
.bar-val {
  flex-shrink: 0;
  min-width: 3.2em;
  font-variant-numeric: tabular-nums;
}
.chart-flex {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 24px;
  margin: 8px 0;
}
/* a pie chart is a data mark, not a control: the circle stays */
.pie {
  width: 130px;
  height: 130px;
  flex-shrink: 0;
  border-radius: 50%;
}
.legend {
  font-size: var(--fs-base);
  line-height: 1.9;
}
.legend-swatch {
  display: inline-block;
  width: .8em;
  height: .8em;
  margin-right: 8px;
  border-radius: var(--radius-sm);
  vertical-align: -1px;
}

/* ── Lazy-image shimmer ───────────────────────────────────────
   Kept (it is what image-loader.js toggles .loaded against) but on
   tokens, and switched off under reduced motion. */
.img-skeleton {
  position: relative;
  background: linear-gradient(90deg,
    var(--surface-2) 25%,
    color-mix(in srgb, var(--border) 55%, var(--card-bg)) 50%,
    var(--surface-2) 75%);
  background-size: 200% 100%;
  animation: img-skeleton-shimmer 1.3s ease-in-out infinite;
}
.img-skeleton img { opacity: 0; }
.img-skeleton.loaded {
  background: var(--surface-2);
  animation: none;
}
.img-skeleton.loaded img { opacity: 1; }

@keyframes img-skeleton-shimmer {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/* ── Responsive ───────────────────────────────────────────── */
@media (width <= 900px) {
  .stories-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (width <= 640px) {
  .stories-hero { padding: 40px 24px 32px; }
  .stories-stats { gap: 16px 24px; }
  .stories-section { padding: 32px 0 48px; }
  .stories-grid { grid-template-columns: 1fr; }

  .article-hero,
  .hero { padding: 32px 0 24px; }
  .article-meta { flex-direction: column; gap: 8px; }
  .article-cover { padding: 0 16px; }
  .article-cover-image,
  .article-cover-placeholder { max-height: 50vh; }
  .article-meta { font-size: var(--fs-base); }

  .share-btn { padding: 0 12px; }
  .share-btn.native { flex-basis: 100%; }

  .reaction-input-area { flex-direction: column; align-items: stretch; }
  .reaction-input-area label { white-space: normal; }
  input.reaction-input { max-width: 100%; }
  .reaction-submit { width: 100%; }
}

@media (width <= 480px) {
  .share-section,
  .reactions-section { padding: 16px; }
}

/* ── Keyboard focus ──────────────────────────────────────────
   saacho.css already puts a 2px --brand-text ring on every
   :focus-visible; these restate it for the interactive pieces this
   app owns so the ring survives their own hover/transform states. */
:is(.story-card,
    .related-card,
    .share-btn,
    .reaction-submit,
    .btn,
    .article-back-link,
    .toc-list a):focus-visible {
  outline: 2px solid var(--brand-text);
  outline-offset: 2px;
}
:is(.share-btn,
    .reaction-submit,
    .btn-primary):focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

/* ── Reduced motion ──────────────────────────────────────────
   The global block in saacho.css collapses durations; this one stops
   the hover lift and the shimmer outright, so nothing moves at all. */
@media (prefers-reduced-motion: reduce) {
  :is(.card, .story-card, .related-card, .share-btn):hover {
    transform: none;
  }
  .story-card-img img,
  .related-card-image img,
  .article-cover-image {
    transition: none;
  }
  .img-skeleton { animation: none; }
  .reading-progress-bar { transition: none; }
}
