/* Saturn Engine — public site.
 *
 * Governed by DESIGN.md; the site is surface ⑯, specced in
 * docs/design/25-public-site.md. Palette is the warm umber ramp with gold for
 * the engine's own activity and pale ice for the human — DESIGN.md §4a/§4b.
 *
 * The short names here are the site's own — DESIGN.md calls --gold `--live` and
 * --ice `--accent` — but every VALUE is a DESIGN.md value. Two exceptions,
 * --gold2 and --goldsoft, are logged in §4b/§17 as marketing-only tints of
 * --live: the tool has no eyebrows and no CTA hover to need them.
 */

/* ── the faces (E7a) ──────────────────────────────────────────────────────
 * Self-hosted, all three. The site used to pull them from Google, requesting
 * five Archivo weights for the one it uses, over a connection index.html
 * preconnected to the WRONG origin — gstatic was warmed while the
 * render-blocking stylesheet came from googleapis.
 *
 * That mattered more here than it usually does. After E1a chapter I is pure
 * typography: no image, no video, so the fonts ARE the first paint of the one
 * screen every visitor sees, and `display=swap` put Arial on it for the length
 * of D4's 1.2s reveal.
 *
 * Archivo is `optional`, not `swap`: on the headline a late swap is a visible
 * jolt through the opening beat, and the file is 35 KB, local and preloaded, so
 * "not ready in time" means something is very wrong anyway. Geist and Geist
 * Mono keep `swap`, matching src/tokens.css — losing body copy to Arial for a
 * whole visit is worse than a swap nobody is looking at.
 *
 * unicode-range is the latin subset Google serves, kept so anything outside it
 * falls back to the stack rather than rendering tofu.
 *
 * Vendored under SIL OFL 1.1 — public/fonts/LICENSE-Archivo.txt and
 * LICENSE-Geist.txt.
 */
@font-face {
  font-family: "Archivo";
  src: url("fonts/Archivo-Variable.woff2") format("woff2-variations");
  font-weight: 600 800;
  font-style: normal;
  font-display: optional;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Geist";
  src: url("fonts/Geist-Variable.woff2") format("woff2-variations");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Geist Mono";
  src: url("fonts/GeistMono-Variable.woff2") format("woff2-variations");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

:root {
  --void: #0c0805;
  --base: #120d08;
  --panel: #1a140c;
  --raised: #241b10;
  --float: #2e2416;

  /* T13. These were #2A2014 and #3D2E1C, which matched no value in §4a — close
     enough to look deliberate and wrong enough to drift further. DESIGN.md's
     three tiers, verbatim, with the site's shorter names kept as aliases so
     each usage below still says which tier it means. */
  --border-subtle: #241b11;
  --border: #33271a;
  --border-strong: #45351f;
  --line: var(--border-subtle); /* hairlines between rows */
  --line2: var(--border); /* panel edges, control borders */

  /* DESIGN.md §9. The cap is 8px on anything structural, which the prompt, the
     gate and the two framed images were all over at 10-12px (T20). */
  --radius-control: 6px;
  --radius-panel: 8px;
  --radius-pill: 999px;

  --cream: #f4ece0;
  --cream2: #c4b3a0;
  --cream3: #8d7f6e;

  --gold: #f5b544;
  --gold2: #c98f3c;
  --goldsoft: #ffd894;
  --ice: #6fd8e0;
  --ok: #46c98a;
  --danger: #ff6b5e;

  --display: "Archivo", "Helvetica Neue", Arial, sans-serif;
  --sans: "Geist", "Segoe UI", Arial, sans-serif;
  --mono: "Geist Mono", "Cascadia Mono", Consolas, monospace;

  /* DESIGN.md §11 defines the tool's motion scale at 60–360ms. The film's beats
     are deliberately much longer: a tool must not draw attention to itself and a
     film has to breathe. T15 records these as the marketing-lean set. */
  --beat-rise: 700ms;
  --beat-ring: 1400ms;
  --ease-enter: cubic-bezier(0.2, 0, 0, 1);

  color-scheme: dark;
}

* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; }

body {
  background: var(--void);
  color: var(--cream);
  font-family: var(--sans);
  -webkit-font-smoothing: antialiased;
}

::selection { background: rgba(245, 181, 68, 0.28); color: #fff; }

:focus-visible {
  outline: 2px solid var(--ice);
  outline-offset: 3px;
  border-radius: 4px;
}

.skip {
  position: fixed;
  left: 12px;
  top: -100px;
  z-index: 60;
  padding: 10px 16px;
  border-radius: var(--radius-control);
  background: var(--float);
  color: var(--cream);
  font-size: 14px;
  text-decoration: none;
  transition: top 150ms var(--ease-enter);
}
.skip:focus { top: 12px; }

/* ── the reel ─────────────────────────────────────────────────────────────
 * Snap is what makes the CUT between chapters: you never sit between scenes.
 * T9 relaxes this to proximity below 900px and adds the min-height release.
 */
.reel {
  height: 100vh;
  height: 100dvh;
  overflow-y: scroll;
  scroll-snap-type: y mandatory;
  scroll-behavior: smooth;
}

.ch {
  position: relative;
  min-height: 100vh;
  min-height: 100dvh;
  scroll-snap-align: start;
  scroll-snap-stop: always;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}

.inner {
  position: relative;
  z-index: 2;
  width: 100%;
  max-width: 1180px;
  margin: 0 auto;
  padding: 0 28px 9vh;
}
.inner--center { flex: 1; display: flex; flex-direction: column; justify-content: center; padding-bottom: 0; }
.inner--wide { padding-bottom: 6vh; }
@media (min-width: 768px) { .inner { padding: 0 48px 10vh; } }

.media { position: absolute; inset: 0; z-index: 0; }
.media img, .media video { width: 100%; height: 100%; object-fit: cover; display: block; }
.wash { opacity: 0.16; filter: saturate(0.5); }
.wash-strong { opacity: 0.34; }

/* Each chapter supplies its own --scrim (E5a). One rule, six compositions. */
.scrim { position: absolute; inset: 0; z-index: 1; background: var(--scrim, none); }

/* ── type ─────────────────────────────────────────────────────────────── */
.display {
  font-family: var(--display);
  font-weight: 800;
  letter-spacing: -0.035em;
  line-height: 0.94;
  text-wrap: balance;
  margin: 22px 0 0;
  font-size: clamp(44px, 8.4vw, 108px);
  max-width: 15ch;
}
.display--lg { font-size: clamp(34px, 5.6vw, 74px); max-width: 15ch; }
.display--md { font-size: clamp(30px, 4.6vw, 58px); max-width: 19ch; }
.display--sm { font-size: clamp(28px, 3.5vw, 44px); max-width: 18ch; }

.eyebrow {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  margin: 0;
  color: var(--gold2);
}
.eyebrow--bright { color: var(--goldsoft); }
.eyebrow--ok { color: var(--ok); }
.eyebrow--no { color: var(--danger); }

.lede {
  max-width: 56ch;
  font-size: clamp(16px, 1.55vw, 20px);
  line-height: 1.6;
  color: var(--cream2);
  margin: 20px 0 0;
}
.lede--bright { color: #e6dacb; }
.lede--tight { font-size: 16px; margin: 16px 0 22px; max-width: 46ch; }

.mono { font-family: var(--mono); }

/* ── reveal ───────────────────────────────────────────────────────────────
 * E1: visible by DEFAULT. The `js` class on <html> is what opts a browser into
 * hide-then-reveal, so a script that never runs leaves a readable page rather
 * than six blank screens.
 */
.js .ch:not(.on) .rise,
.js .ch:not(.on) .notes li,
.js .ch:not(.on) .claims li {
  opacity: 0;
  transform: translateY(22px);
}
.rise, .notes li, .claims li {
  transition: opacity var(--beat-rise) var(--ease-enter), transform var(--beat-rise) var(--ease-enter);
}
.ch.on .rise:nth-child(2) { transition-delay: 0.08s; }
.ch.on .rise:nth-child(3) { transition-delay: 0.16s; }
.ch.on .rise:nth-child(4) { transition-delay: 0.24s; }
.ch.on .rise:nth-child(5) { transition-delay: 0.32s; }
.js .ch:not(.on) .notes li, .js .ch:not(.on) .claims li { transform: translateX(14px); }
.ch.on .notes li:nth-child(1), .ch.on .claims li:nth-child(1) { transition-delay: 0.3s; }
.ch.on .notes li:nth-child(2), .ch.on .claims li:nth-child(2) { transition-delay: 0.45s; }
.ch.on .notes li:nth-child(3), .ch.on .claims li:nth-child(3) { transition-delay: 0.6s; }
.ch.on .notes li:nth-child(4), .ch.on .claims li:nth-child(4) { transition-delay: 0.75s; }
.ch.on .notes li:nth-child(5) { transition-delay: 0.9s; }

/* ── the rings ────────────────────────────────────────────────────────── */
.rings {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  display: grid;
  place-items: center;
  will-change: transform, opacity; /* E7b — 150vmax repaint per chapter change */
  transition: transform var(--beat-ring) var(--ease-enter), opacity var(--beat-ring) ease;
}
.rings svg { width: 150vmax; max-width: none; opacity: 0.42; }

/* ── chrome ───────────────────────────────────────────────────────────── */
.brand {
  position: fixed;
  left: 28px;
  top: 24px;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: var(--display);
  font-weight: 800;
  font-size: 17px;
  letter-spacing: -0.02em;
  color: var(--cream);
  text-decoration: none;
}

.dl {
  position: fixed;
  right: 20px;
  top: 20px;
  z-index: 41;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 38px;
  padding: 0 20px;
  border-radius: var(--radius-pill);
  background: var(--gold);
  color: var(--void);
  font-size: 13.5px;
  font-weight: 500;
  text-decoration: none;
  transition: opacity 300ms ease, transform 300ms var(--ease-enter);
}
/* D5: absent on chapter I, present from chapter II onward. Without JS it is
   simply always there, which is the safe direction to fail.
   T5: `visibility` and not just opacity, or the button stays in the tab order
   while invisible and a keyboard user on chapter I focuses something that is
   not on screen. Kept out of the transition list so showing is immediate. */
.js .dl { opacity: 0; transform: translateY(-8px); pointer-events: none; visibility: hidden; }
.js .dl.show { opacity: 1; transform: none; pointer-events: auto; visibility: visible; }

/* ── the rail ─────────────────────────────────────────────────────────── */
.rail {
  position: fixed;
  right: 20px;
  top: 50%;
  transform: translateY(-50%);
  z-index: 40;
  display: flex;
  flex-direction: column;
  gap: 6px;
  align-items: flex-end;
}
.rail a {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 24px; /* DESIGN.md §15 floor; T10 finishes the a11y pass */
  padding: 2px 0;
  text-decoration: none;
  color: var(--cream3);
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.rail .tick { width: 22px; height: 1px; background: var(--line2); transition: all 0.3s; }
.rail .lbl { opacity: 0; text-align: right; line-height: 1.25; transition: opacity 0.3s; }
.rail a:hover .lbl, .rail a.cur .lbl { opacity: 1; }
.rail a.cur { color: var(--gold); }
.rail a.cur .tick { width: 38px; background: var(--gold); }
/* D8: the functional subtitle, only on the chapter you are in, and on its own
   line — inline it reads as one run-on label rather than a gloss. */
.rail .sub { display: none; font-size: 9px; letter-spacing: 0.06em; text-transform: none; color: var(--cream3); }
.rail a.cur .sub { display: block; }
/* ── the phone (T9) ───────────────────────────────────────────────────────
 * D7 kept the same six chapters on every device and sanded the edges rather
 * than serving a different, lesser page to whoever opened the link on a phone.
 * Three edges:
 *
 * PROXIMITY, NOT MANDATORY. Mandatory snap on a touch screen fights thumb
 * momentum: a fast flick is caught and parked one chapter along, which reads as
 * the page grabbing your scroll. Proximity still lands the cuts when you stop
 * near one and lets a long swipe travel. `scroll-snap-stop: normal` for the
 * same reason — `always` forbids passing more than one chapter per gesture.
 *
 * THE HEIGHT RELEASE is already in the base rules and worth not undoing: `.ch`
 * is min-height, never height, so a chapter whose content outgrows a short
 * viewport (a landscape phone, chapter V's sheet and five notes) simply gets
 * taller and scrolls like an ordinary page. Combined with proximity, nothing
 * traps.
 *
 * THE RAIL BECOMES A BAR. It is hidden here because seven labels down the right
 * edge of a 375px screen is not navigation, it is clutter — but hiding it with
 * nothing in its place leaves a phone reader with no idea how much film is
 * left. The bar is that, and only that.
 */
.progress {
  display: none;
  position: fixed;
  inset: 0 0 auto 0;
  height: 2px;
  z-index: 42;
  background: var(--line);
  pointer-events: none;
}
.progress span {
  display: block;
  height: 100%;
  width: 0;
  background: var(--gold);
  transition: width 120ms linear;
}

/* Base rules first, then the breakpoint. The other way round the `display:none`
   above wins at equal specificity and the bar never appears. */
@media (max-width: 900px) {
  .reel { scroll-snap-type: y proximity; }
  .ch { scroll-snap-stop: normal; }
  .rail { display: none; }
  .progress { display: block; }
}

/* ── buttons ──────────────────────────────────────────────────────────── */
.cta {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  height: 52px;
  padding: 0 30px;
  border-radius: var(--radius-pill);
  background: var(--gold);
  color: var(--void);
  font-size: 15px;
  font-weight: 500;
  text-decoration: none;
  transition: 0.2s;
}
.cta:hover { background: var(--goldsoft); box-shadow: 0 0 36px -6px rgba(245, 181, 68, 0.6); }
.cta--ghost { background: none; border: 1px solid var(--line2); color: var(--cream); }
.cta--ghost:hover { border-color: var(--gold2); color: var(--goldsoft); box-shadow: none; }
.actions { display: flex; flex-wrap: wrap; gap: 16px; margin: 34px 0 0; }
.fineprint { font-size: 12px; color: var(--cream3); margin: 18px 0 0; }

/* ── I. nothing ───────────────────────────────────────────────────────────
 * T3, the two beats. Beat one is a subtraction, not an addition: the finished
 * chapter is what the markup says, and `beat1` takes things away for 1.2s.
 * Framed the other way round (hide in CSS, reveal in JS) a browser that never
 * runs the script would sit on the void forever with no product statement,
 * which is the exact failure E1 exists to prevent.
 *
 * Nothing leaves the flow, so there is no layout jump at the hand-off: the
 * headline simply arrives in the space that was already reserved for it, and
 * the opening line stops being the largest thing on screen.
 */
#c1 .opening {
  display: inline-block;
  transform-origin: left center;
  transition: transform 900ms var(--ease-enter), color 900ms ease;
}
#c1 .beat { transition: opacity 700ms var(--ease-enter); }

.js #c1.beat1 .beat { opacity: 0; }
.js #c1.beat1 .opening {
  transform: scale(1.7);
  color: var(--cream);
}

.hint {
  position: absolute;
  left: 50%;
  bottom: 5vh;
  z-index: 3;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--cream3);
  animation: bob 2.6s ease-in-out infinite;
}
@keyframes bob {
  0%, 100% { transform: translateX(-50%) translateY(0); opacity: 0.5; }
  50% { transform: translateX(-50%) translateY(6px); opacity: 1; }
}

/* ── II. the ask ──────────────────────────────────────────────────────── */
.prompt {
  max-width: 780px;
  margin-top: 30px;
  border: 1px solid var(--line2);
  background: rgba(26, 20, 12, 0.72);
  border-radius: var(--radius-panel);
  padding: 18px 20px;
  display: flex;
  align-items: center;
  gap: 12px;
  backdrop-filter: blur(8px);
}
.prompt .chev { color: var(--gold); font-family: var(--mono); font-size: 15px; }
.prompt__txt { font-size: clamp(16px, 2vw, 24px); font-family: var(--display); font-weight: 600; letter-spacing: -0.02em; }
.caret {
  display: inline-block;
  width: 2px;
  height: 1.05em;
  background: var(--gold);
  vertical-align: -0.16em;
  margin-left: 3px;
  animation: blink 1.1s steps(1) infinite;
}
@keyframes blink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }

.gate {
  margin-top: 22px;
  max-width: 780px;
  border: 1px solid var(--line);
  border-radius: var(--radius-panel);
  overflow: hidden;
  background: rgba(18, 13, 8, 0.78);
  backdrop-filter: blur(8px);
}
.gate__bar {
  display: flex;
  align-items: center;
  gap: 10px;
  height: 38px;
  padding: 0 16px;
  border-bottom: 1px solid var(--line);
  background: rgba(36, 27, 16, 0.7);
  font-family: var(--mono);
  font-size: 11px;
  color: var(--cream2);
}
.gate__file { margin-left: auto; }
@media (max-width: 560px) { .gate__file { display: none; } }
.gate__rows { margin: 0; padding: 0; list-style: none; }
.gate__rows li {
  display: grid;
  grid-template-columns: 10px 104px 1fr auto;
  gap: 0 14px;
  align-items: center;
  padding: 11px 16px;
  border-top: 1px solid var(--line);
  font-size: 13.5px;
}
.gate__rows li:first-child { border-top: 0; }
/* JS dims the un-run rows; with no JS every row reads at full strength, which
   is the correct resting state for a sequence that has already finished. */
.js .gate__rows li { opacity: 0.25; transition: opacity 0.45s; }
.js .gate__rows li.lit { opacity: 1; }

.dot { width: 8px; height: 8px; border-radius: var(--radius-pill); background: var(--gold); flex: none; }
[data-by="you"] .dot { background: var(--ice); }
.dot.done { background: var(--ok); }
.k { font-family: var(--mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.09em; color: var(--gold); }
[data-by="you"] .k { color: var(--ice); }
.k.done { color: var(--ok); }
.gate .t { color: var(--cream2); }
.gate .m { font-family: var(--mono); font-size: 11px; color: var(--cream3); }
@media (max-width: 640px) {
  .gate__rows li { grid-template-columns: 10px 1fr; row-gap: 2px; }
  .gate .m { grid-column: 2; }
}
.breathe { animation: br 1.6s ease-in-out infinite; }
@keyframes br { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } }

/* ── III. the city ────────────────────────────────────────────────────────
 * T6 — a guaranteed contrast floor under text that sits on moving footage.
 *
 * The chapter scrim is tuned for mood against ONE frame someone looked at. It
 * cannot promise a ratio against a frame nobody has seen yet, and chapter III
 * is six seconds of a city at night with headlights in it. This plate is sized
 * to the text block rather than the viewport, so the footage stays open where
 * there is nothing to read and the copy always has its floor.
 *
 * --cream2 (#C4B3A0) on --void (#0C0805) is ~6.5:1. At 0.88 alpha the plate
 * holds the composite well above the 4.5:1 body-text floor in DESIGN.md §4c
 * whatever is playing underneath.
 */
.ch--media .inner { isolation: isolate; }
.ch--media .inner::before {
  content: "";
  position: absolute;
  inset: -8vh -40px -4vh;
  z-index: -1;
  pointer-events: none;
  background: linear-gradient(
    to top,
    rgba(12, 8, 5, 0.94) 0%,
    rgba(12, 8, 5, 0.88) 40%,
    rgba(12, 8, 5, 0.62) 72%,
    rgba(12, 8, 5, 0) 100%
  );
}

/* The refusal control. Amber because the engine is the thing that is not
   running; it is the one control on the page that reports engine state. */
.playctl {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: 18px;
  min-height: 24px;
  padding: 8px 16px;
  border: 1px solid var(--gold2);
  border-radius: var(--radius-pill);
  background: rgba(12, 8, 5, 0.6);
  color: var(--goldsoft);
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 150ms ease, border-color 150ms ease;
}
.playctl:hover { background: rgba(245, 181, 68, 0.14); border-color: var(--gold); }
/* `display` on a class outranks the UA stylesheet's [hidden] rule, so without
   this the hidden attribute is inert and the control shows on every load. */
.playctl[hidden] { display: none; }

.readout { display: flex; flex-wrap: wrap; gap: 8px; margin: 18px 0 0; padding: 0; list-style: none; }
.readout li {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--cream);
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(12, 8, 5, 0.5);
  padding: 5px 10px;
  border-radius: var(--radius-control);
}

/* ── IV. the instrument ───────────────────────────────────────────────── */
.instrument { display: grid; gap: 28px; margin-top: 30px; align-items: center; }
@media (min-width: 1000px) { .instrument { grid-template-columns: 1.4fr 1fr; gap: 44px; } }
.instrument__shot { margin: 0; }
.instrument__shot img { width: 100%; border-radius: var(--radius-panel); border: 1px solid var(--line2); display: block; }
.instrument__shot figcaption { margin-top: 10px; font-size: 11px; color: var(--cream3); }
.claims { margin: 0; padding: 0; list-style: none; }
.claims li { padding: 14px 0; border-top: 1px solid var(--line); }
.claims li:first-child { border-top: 0; padding-top: 0; }
.claims b { display: block; font-weight: 500; color: var(--cream); font-size: 15px; }
.claims span { color: var(--cream2); font-size: 14px; line-height: 1.5; }

/* ── V. the look ──────────────────────────────────────────────────────── */
.look { display: grid; gap: 26px; align-items: center; }
@media (min-width: 1000px) { .look { grid-template-columns: 1.35fr 1fr; gap: 40px; } }
.look__sheet { margin: 0; }
.look__sheet img { width: 100%; border-radius: var(--radius-panel); border: 1px solid var(--line2); display: block; }
.look__sheet figcaption { margin-top: 10px; font-size: 11px; color: var(--cream3); }
.notes { margin: 0; padding: 0; list-style: none; }
.notes li { display: grid; grid-template-columns: auto 1fr; gap: 12px; padding: 13px 0; border-top: 1px solid var(--line); }
.notes li:first-child { border-top: 0; padding-top: 0; }
.vd {
  height: fit-content;
  font-family: var(--mono);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  padding: 4px 8px;
  border-radius: var(--radius-control);
}
.vd--keep { background: rgba(70, 201, 138, 0.15); color: var(--ok); }
.vd--fix { background: rgba(245, 181, 68, 0.15); color: var(--gold); }
.notes b { display: block; font-weight: 500; color: var(--cream); font-size: 14.5px; }
.notes .d { color: var(--cream2); font-size: 14px; line-height: 1.5; }

/* ── VI. the ship ─────────────────────────────────────────────────────── */
@keyframes drift {
  from { transform: scale(1.06); }
  to { transform: scale(1.18) translate3d(-2%, -2%, 0); }
}
.drift { animation: drift 24s ease-out infinite alternate; }

/* ── coda ─────────────────────────────────────────────────────────────── */
/* A snap target like the chapters, or `scroll-snap-type: mandatory` has nothing
   to land on here and bounces back to chapter VI — which broke deep links to
   #fine and, worse, fought anyone simply scrolling down to read the scope. No
   `scroll-snap-stop` though: this is taller than the viewport, and the spec
   lets you scroll freely once inside a snap area bigger than the snapport. */
.coda { scroll-snap-align: start; background: var(--base); border-top: 1px solid var(--line); padding: 76px 28px 0; }
@media (min-width: 768px) { .coda { padding: 88px 48px 0; } }
.coda .wrap { max-width: 1180px; margin: 0 auto; }
.coda .display { margin-top: 14px; }
.cols { display: grid; gap: 36px; margin-top: 30px; }
@media (min-width: 640px) { .cols { grid-template-columns: 1fr 1fr; gap: 48px; } }
.scope { margin: 14px 0 0; padding: 0; list-style: none; }
.scope li { display: grid; grid-template-columns: 14px 1fr; gap: 12px; padding: 7px 0; font-size: 15px; color: var(--cream2); line-height: 1.5; }
.scope b { font-weight: 500; color: var(--cream); }
.mark { font-family: var(--mono); }
.mark--yes { color: var(--ok); }
.mark--no { color: var(--danger); }

.facts { display: grid; gap: 26px; border-top: 1px solid var(--line); margin: 52px 0 0; padding: 34px 0 0; list-style: none; }
@media (min-width: 640px) { .facts { grid-template-columns: repeat(4, 1fr); } }
.facts .n { display: block; font-family: var(--display); font-weight: 800; font-size: 34px; color: var(--gold); font-variant-numeric: tabular-nums; }
.facts .l { display: block; margin-top: 6px; font-size: 14px; color: var(--cream2); line-height: 1.35; }

.coda footer {
  border-top: 1px solid var(--line);
  margin-top: 56px;
  padding: 34px 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px 28px;
  font-size: 13px;
  color: var(--cream3);
}
.footer__mid { margin-left: auto; }

/* ── reduced motion ───────────────────────────────────────────────────────
 * T18 replaces this blanket rule with per-device states. Blanket is the right
 * placeholder because it fails toward "everything visible and still".
 */
@media (prefers-reduced-motion: reduce) {
  .reel { scroll-snap-type: none; scroll-behavior: auto; }
  *, *::before, *::after { animation: none !important; transition: none !important; }
  .js .ch:not(.on) .rise,
  .js .ch:not(.on) .notes li,
  .js .ch:not(.on) .claims li { opacity: 1 !important; transform: none !important; }
  .js .gate__rows li { opacity: 1 !important; }
  .js .dl { opacity: 1 !important; transform: none !important; pointer-events: auto !important; visibility: visible !important; }
}
