/* ============================================================================
   event-story.css — "The story of one event" (PROTOTYPE, 2026-10-04)
   ----------------------------------------------------------------------------
   The cinematic, chaptered telling of S1. Four reference reels shaped it (owner-supplied,
   2026-10-04): one substance carried DOWN through verb-named chapters (POUR/PLAY), numbered
   editorial chapters + a ribbon wipe + one object that changes state (ROAST|RITUAL), a giant word
   the object stands in front of (NOCTIS), and scatter→reassemble (pistachio). Here the substance is
   one event, and the dark is MEANING, not mood — and an ACCENT, never a PANEL (owner-delegated
   decision 2026-10-04y, built 2026-10-04ad): the page stays ivory throughout; the two chapters where
   something is judged, Detect and Gate, each draw ONE flat night ribbon behind their verb and the
   judged object. Flat throughout — no gradient, no glow (owner calls, 2026-10-04y).

   ONE NUMBER DRIVES EVERYTHING. `--p` (0→1) is the reader's progress through the pinned section.
   ① where `animation-timeline` exists, a scroll timeline animates the registered `--p` — no JS,
     no scroll listener, composited;
   ② elsewhere event-story.js writes `--p` from scroll position;
   ③ every visual is a pure function of `--p`: `--k` (chapter clock), per-chapter `--t`, and the
     derived `--in` / `--out` / `--h` (enter, leave, the chapter's own action). Scrolling back
     plays the story backwards for free, and there is no state to get out of sync.

   NEVER-BLANK IS STRUCTURAL. The BASE style below is the static story: chapters stacked in
   flow, each frozen at `--t: .74` — its action complete, entered, not yet leaving. The pinned
   cinema exists only under `.es[data-mode="pin"]`, which event-story.js sets when the reader has
   NOT asked for reduced motion. So no-JS, reduced motion and print all receive the finished,
   fully-drawn story; nothing can freeze at an opacity:0 first frame.
   Timing is scroll distance, not time: there is no duration literal in this file (motion-audit).
   ========================================================================== */
/* ── THE SIGNAL RAMP (2026-10-05a, owner: "change the clay outside the logo also").
   Under the one palette (P2A/P2C) clay means FAILURE and nothing else, so every emphasis this file used
   to draw in clay steps onto this ramp instead, step for step (--clay-N -> --sig-N). It is built on P2A
   --signal-emphasis #27506B (= 600). The rules that DO mean failure — a tampered record, a refused
   verdict, a live threat — keep --clay-*, and say so where they sit. ── */
:root {
  --sig-50:#EEF3F7; --sig-100:#DDE7EF; --sig-200:#BCD0DF; --sig-300:#8FB0C8; --sig-400:#5E8AAA;
  --sig-500:#3A6A8C; --sig-600:#27506B; --sig-700:#1F4058; --sig-800:#172F41;
}

@property --p { syntax: '<number>'; inherits: true; initial-value: 0; }

.es-body { background: var(--hearth-canvas); }

/* ── shared palette for this page ─────────────────────────────────────────── */
.es {
  /* the night ACCENT — only ever the ribbon in a judged chapter, never a chapter's ground */
  --es-night: #101114;
  --es-night-2: #191A1E;
  --es-night-line: #292A30;
  --es-night-text: #F5F5F3;
  --es-night-muted: #A9AAAF;
  --es-calm: #5E8B6B;            /* contained — the one cool note, used once */
  --es-ink: var(--hearth-text);
  --es-muted: var(--hearth-text-secondary);
  --es-line: var(--hearth-border);
  --es-verb: color-mix(in oklab, var(--sig-500) 16%, transparent);
  --es-shadow: 0 1px 0 rgba(255,255,255,.6) inset, 0 18px 40px -18px rgba(60,35,15,.35);
  position: relative;
}

/* ── chapter clock (static default: everything rests at its finished pose) ── */
.ch {
  --t: .74;
  --in: clamp(0, var(--t) / .2, 1);
  --out: clamp(0, (var(--t) - .8) / .2, 1);
  --h: clamp(0, (var(--t) - .12) / .62, 1);
  --vis: calc(var(--in) - var(--out));
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
  align-items: center;
  gap: clamp(16px, 4vw, 64px);
  min-height: 86vh;
  padding: clamp(72px, 9vh, 120px) clamp(16px, 5vw, 80px);
  overflow: hidden;
}

/* ── the giant verb, behind the object (NOCTIS / POUR-PLAY) ────────────────── */
.ch-verb {
  position: absolute; inset: auto 0 50% 0; transform: translate(calc((.5 - var(--t)) * 22vw), 50%);
  margin: 0; text-align: center; pointer-events: none; user-select: none;
  font-family: var(--font-display); font-weight: 300; letter-spacing: -.045em; line-height: .8;
  font-size: clamp(4.5rem, 19vw, 17rem); color: var(--es-verb); white-space: nowrap; z-index: 0;
  opacity: var(--vis);
}

/* ── copy column ───────────────────────────────────────────────────────────── */
.ch-copy {
  position: relative; z-index: 2; max-width: 34rem;
  opacity: var(--vis);
  transform: translateY(calc((1 - var(--in)) * 28px - var(--out) * 28px));
}
.ch-n { display: flex; align-items: baseline; gap: .6rem; margin: 0 0 1rem; font: 600 var(--text-xs)/1 var(--font-sans); letter-spacing: .14em; text-transform: uppercase; color: var(--accent-text); }
.ch-n span:first-child { font: 300 var(--text-3xl)/1 var(--font-display); letter-spacing: -.02em; color: var(--sig-500); }
.ch-loop { font-weight: 500; letter-spacing: .06em; color: var(--es-muted); }
.ch-h { margin: 0 0 1rem; font: 400 clamp(2rem, 4.2vw, 3.6rem)/1.04 var(--font-display); letter-spacing: -.02em; color: inherit; text-wrap: balance; }
.ch-h em { font-style: normal; color: var(--sig-600); }
.ch-ack { display: inline-block; margin: 0 0 1rem; padding: .45rem .7rem; border: 1px solid var(--es-line); border-radius: var(--radius-full); font: 500 var(--text-xs)/1.3 var(--font-mono); color: var(--es-muted); background: var(--hearth-surface); }
.ch-ack b { color: var(--sig-600); font-weight: 600; }
/* The page's <body> is not .hearth, so the shared sheet's `balance`/`pretty` never reach it — said here. */
.ch-p { margin: 0; font: 400 var(--text-md)/1.6 var(--font-sans); color: var(--es-muted); max-width: 30rem; text-wrap: pretty; }

/* ── the object column: falls IN from above and OUT below — the substance carried down ── */
.art {
  position: relative; z-index: 1; height: clamp(320px, 58vh, 560px);
  display: grid; place-items: center;
  opacity: var(--vis);
  transform: translateY(calc((1 - var(--in)) * -30vh + var(--out) * 30vh));
}

/* ── the night RIBBON — the only dark on this page ───────────────────────────
   One per judged chapter (Detect, Gate), inside its object column, so the copy never sits on night.
   It bleeds off the page edge like a ribbon pulled through, and carries the chapter's verb and the
   judged object. It is DRAWN IN from the right as the chapter enters (`--in`); its base style is the
   drawn ribbon (`--t: .74` ⇒ `--in: 1`), so static, print and reduced motion see it whole. */
.rib {
  position: relative; justify-self: stretch; align-self: center;
  display: grid; place-items: center; gap: .9rem; min-height: clamp(150px, 22vh, 190px);
  margin-right: calc(-1 * clamp(16px, 5vw, 80px));
  padding: clamp(28px, 4vh, 40px) clamp(16px, 3vw, 40px);
  border-radius: 22px 0 0 22px; background: var(--es-night); color: var(--es-night-text); overflow: hidden;
  clip-path: inset(0 0 0 calc((1 - var(--in)) * 100%) round 22px 0 0 22px);
}
.rib .ch-verb { font-size: clamp(3.5rem, 12vw, 11rem); color: color-mix(in oklab, var(--sig-300) 16%, transparent); opacity: 1; }
.rib > :not(.ch-verb) { position: relative; z-index: 1; }

/* ═════ 01 OBSERVE — raw lines fall into the Sensor; one of them is ours ═════ */
.dev { position: absolute; left: 50%; bottom: 8%; transform: translateX(-50%); width: min(300px, 70%); display: grid; justify-items: center; }
.dev-funnel { width: 70%; height: 46px; background: var(--hearth-sunken); clip-path: polygon(0 0, 100% 0, 78% 100%, 22% 100%); border-top: 2px solid var(--hearth-border-strong); }
.dev-body {
  position: relative; width: 100%; height: 128px; border-radius: 22px; overflow: hidden;
  display: grid; align-content: center; justify-items: center; gap: .25rem;
  background: var(--hearth-raised); color: var(--hearth-text); border: 1px solid var(--hearth-border-strong); box-shadow: var(--es-shadow);
}
.dev-led { width: 10px; height: 10px; border-radius: 50%; background: var(--sig-500); }
.dev-name { font: 500 var(--text-lg)/1 var(--font-mono); letter-spacing: .02em; }
.dev-kind { font: 600 var(--text-xs)/1 var(--font-sans); letter-spacing: .18em; text-transform: uppercase; color: var(--hearth-text-muted); }
.chip {
  --f: clamp(0, (var(--h) - var(--j) * .07) / .34, 1);
  position: absolute; left: 50%; top: 30%; white-space: nowrap;
  padding: .4rem .65rem; border-radius: var(--radius-md); border: 1px solid var(--es-line);
  background: var(--hearth-raised); color: var(--es-muted); box-shadow: var(--shadow-sm);
  font: 500 var(--text-xs)/1 var(--font-mono);
  transform: translate(calc(-50% + var(--x) * (1 - var(--f))), calc((var(--f) - 1) * 46vh + var(--f) * 60px)) scale(calc(1 - var(--f) * .55));
  opacity: calc(1 - clamp(0, (var(--f) - .82) / .18, 1));
}
.chip-hot {
  border-color: var(--sig-400); color: var(--sig-700); background: var(--accent-subtle-bg);
  box-shadow: 0 0 0 4px color-mix(in oklab, var(--sig-400) 22%, transparent), var(--shadow-md);
  transform: translate(-50%, calc((var(--f) - 1) * 46vh)) scale(calc(1 + var(--f) * .06));
  opacity: 1; z-index: 2;
}
.es-hint { position: absolute; left: 50%; bottom: 22px; transform: translateX(-50%); margin: 0; font: 600 var(--text-xs)/1 var(--font-sans); letter-spacing: .16em; text-transform: uppercase; color: var(--hearth-text-muted); display: none; }

/* ═════ 02 SHAPE — fragments scattered across the frame fly together (pistachio) ═════ */
.card {
  --c: clamp(0, (var(--h) - .55) / .3, 1);
  position: relative; width: min(380px, 92%); padding: 1.1rem 1.2rem 1rem; border-radius: var(--radius-xl); display: grid; gap: .5rem;
  background: color-mix(in oklab, var(--hearth-raised) calc(var(--c) * 100%), transparent);
  border: 1px solid color-mix(in oklab, var(--hearth-border) calc(var(--c) * 100%), transparent);
  box-shadow: 0 18px 40px -18px rgba(60,35,15, calc(var(--c) * .35));
}
.card-h { font: 600 var(--text-xs)/1 var(--font-sans); letter-spacing: .16em; text-transform: uppercase; color: var(--hearth-text-muted); opacity: clamp(0, (var(--h) - .7) / .2, 1); }
.row {
  --a: clamp(0, (var(--h) - var(--r) * .1) / .45, 1);
  display: flex; justify-content: space-between; gap: 1rem; padding: .55rem .7rem; border-radius: var(--radius-md);
  background: var(--hearth-surface); border: 1px solid var(--hearth-border-subtle);
  font: 500 var(--text-sm)/1.2 var(--font-mono);
  transform: translate(calc(var(--sx) * (1 - var(--a))), calc(var(--sy) * (1 - var(--a)))) rotate(calc((1 - var(--a)) * (var(--r) - 2) * 9deg));
}
.row i { font-style: normal; color: var(--hearth-text-muted); }
.row b { font-weight: 500; color: var(--es-ink); text-align: right; }
.row-id { background: var(--accent-subtle-bg); border-color: color-mix(in oklab, var(--sig-400) 40%, transparent); }
.row-id b { color: var(--sig-700); }

/* ═════ 03 SEAL — the exploded view ═════ */
.art-seal { perspective: 1200px; }
.iso { position: relative; width: 240px; height: 240px; transform-style: preserve-3d; transform: rotateX(58deg) rotateZ(-38deg); }
.plate {
  position: absolute; inset: 0; border-radius: 26px; transform-style: preserve-3d;
  background: var(--hearth-raised); border: 1px solid var(--hearth-border-strong);
  box-shadow: 0 30px 50px -30px rgba(60,35,15,.45);
  transform: translateZ(calc(var(--r) * (8px + var(--h) * 46px)));
}
.plate-seal { background: var(--sig-500); border-color: var(--sig-700); }
.plate-seal::before, .plate-seal::after { content: ""; position: absolute; border-radius: 50%; border: 2px solid rgba(255,255,255,.75); }
.plate-seal::before { inset: 28%; }
.plate-seal::after { inset: 38%; border-width: 1px; background: radial-gradient(circle, rgba(255,255,255,.55) 0 18%, transparent 19%); }
.plate-prev { --r: 0; inset: 0; transform: translate3d(-150px, 150px, 0) scale(.62); opacity: calc(.25 + var(--h) * .5); border-style: dashed; background: var(--hearth-surface); box-shadow: none; }
.plate-labels { position: absolute; right: 0; top: 50%; margin: 0; padding: 0; list-style: none; display: grid; gap: .55rem; transform: translateY(-50%); }
.plate-labels li {
  --a: clamp(0, (var(--h) - (3 - var(--r)) * .12) / .4, 1);
  font: 500 var(--text-xs)/1.2 var(--font-mono); color: var(--es-muted); opacity: var(--a);
  transform: translateX(calc((1 - var(--a)) * 24px)); padding-left: .8rem; border-left: 2px solid var(--es-line);
}
.plate-labels li b { display: block; font: 600 var(--text-xs)/1.3 var(--font-sans); letter-spacing: .12em; text-transform: uppercase; color: var(--es-ink); }
.plate-labels li:first-child { border-color: var(--sig-500); }
.plate-labels li:first-child b { color: var(--sig-600); }
.chain { position: absolute; left: 4%; bottom: 6%; font: 500 var(--text-xs)/1 var(--font-mono); color: var(--hearth-text-muted); opacity: clamp(0, (var(--h) - .5) / .3, 1); }
.chain::before { content: ""; display: inline-block; width: 46px; border-top: 1px dashed var(--hearth-border-strong); margin-right: .5rem; vertical-align: middle; }

/* ═════ 04 STORE — dropped once onto the lake; copies go to every reader ═════ */
.lake { position: relative; width: 220px; height: 220px; perspective: 900px; }
.lk {
  position: absolute; left: 0; right: 0; height: 120px; top: calc(70px + (2 - var(--r)) * 14px);
  border-radius: 50%; background: var(--hearth-sunken); border: 1px solid var(--hearth-border-strong);
  transform: rotateX(68deg); opacity: calc(.5 + var(--r) * .1);
}
.lk-ours {
  --r: 5; top: 28px; background: var(--sig-500); border-color: var(--sig-700); opacity: 1;
  transform: translateY(calc((1 - clamp(0, var(--h) / .4, 1)) * -160px)) rotateX(68deg) scale(.86);
}
.reader {
  --a: clamp(0, (var(--h) - .45 - var(--r) * .08) / .25, 1);
  position: absolute; left: 50%; top: 50%; padding: .45rem .8rem; border-radius: var(--radius-full);
  background: var(--hearth-raised); border: 1px solid var(--es-line); box-shadow: var(--shadow-sm);
  font: 600 var(--text-sm)/1 var(--font-sans); color: var(--es-ink); opacity: var(--a);
  transform: translate(calc(-50% + var(--rx) * var(--a) * var(--rs, 1)), calc(-50% + var(--ry) * var(--a) * var(--rs, 1)));
}
.reader::before { content: ""; display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: var(--sig-500); margin-right: .45rem; vertical-align: 1px; }

/* ═════ 05 DETECT — the stream passes the beam; ours does not (all on the ribbon) ═════ */
.art-detect .rib { padding-block: 76px 44px; }   /* headroom for the alert that rises off our event */
.beam { position: absolute; left: 50%; top: 0; bottom: 0; width: 2px; transform: translateX(-50%);
  background: var(--sig-400); opacity: calc(.4 + var(--h) * .6); }
.stream {
  --go: clamp(0, var(--h) / .6, 1);
  display: flex; gap: 18px; align-items: center;
  transform: translateX(calc((1 - var(--go)) * 520px));
}
.ev { flex: none; width: 92px; height: 58px; border-radius: var(--radius-lg); border: 1px solid var(--es-night-line); background: var(--es-night-2); opacity: .7; }
.ev-ours {
  --hit: clamp(0, (var(--h) - .55) / .12, 1);
  position: relative; opacity: 1;
  border-color: color-mix(in oklab, #27506B calc(var(--hit) * 100%), var(--es-night-line));
  background: color-mix(in oklab, var(--accent-solid-bg) calc(var(--hit) * 100%), var(--es-night-2));
}
.alert {
  --a: clamp(0, (var(--h) - .68) / .2, 1);
  position: absolute; left: 50%; bottom: calc(100% + 18px); white-space: nowrap;
  padding: .45rem .75rem; border-radius: var(--radius-full); background: var(--clay-300); color: var(--es-night);   /* ≈8:1 — a light pill on night, apart from the clay event below */
  font: 600 var(--text-xs)/1 var(--font-mono); opacity: var(--a);
  transform: translate(-50%, calc((1 - var(--a)) * 22px));
}
.alert::after { content: ""; position: absolute; left: 50%; top: 100%; height: 18px; border-left: 1px dashed var(--clay-300); }

/* ═════ 06 DECIDE — ten guardrails light in turn; one verdict ═════ */
.art-gate { align-content: center; gap: 1.2rem; }
.ring { width: min(300px, 70vw); height: auto; overflow: visible; }
.seg { fill: none; stroke-width: 10; stroke-linecap: round;
  stroke: color-mix(in oklab, var(--sig-500) calc(clamp(0, var(--h) * 11 - var(--s) - .5, 1) * 100%), var(--hearth-border-strong)); }
.ring-n { font: 400 30px/1 var(--font-display); fill: var(--hearth-text); }
.ring-s { font: 600 9px/1 var(--font-sans); letter-spacing: .16em; text-transform: uppercase; fill: var(--hearth-text-muted); }
.verdicts { display: flex; gap: .5rem; }
.vd { padding: .5rem .9rem; border-radius: var(--radius-full); border: 1px solid var(--es-night-line); font: 600 var(--text-sm)/1 var(--font-sans); color: var(--es-night-muted); }
.vd-allow {
  --a: clamp(0, (var(--h) - .9) / .1, 1);
  color: color-mix(in oklab, #fff calc(var(--a) * 100%), var(--es-night-muted));
  background: color-mix(in oklab, var(--sig-600) calc(var(--a) * 100%), transparent);
  border-color: color-mix(in oklab, var(--sig-400) calc(var(--a) * 100%), var(--es-night-line));
}
.receipt { margin: 0; font: 500 var(--text-xs)/1 var(--font-mono); color: var(--es-night-muted); opacity: clamp(0, (var(--h) - .92) / .08, 1); }
.receipt::before { content: "▤ "; }

/* ═════ 07 CONTAIN — one drop falls back onto the host that saw it (the SIP moment) ═════ */
.art-contain .dev { bottom: 18%; }
.drop {
  --d: clamp(0, var(--h) / .45, 1);
  position: absolute; left: 50%; top: 0; width: 18px; height: 26px; margin-left: -9px;
  border-radius: 50% 50% 50% 50% / 62% 62% 38% 38%; background: var(--sig-600);
  transform: translateY(calc(var(--d) * clamp(160px, 26vh, 260px))) scale(calc(1 - clamp(0, (var(--h) - .43) / .04, 1)));
}
.ripple {
  --w: clamp(0, (var(--h) - .45 - var(--r) * .07) / .4, 1);
  position: absolute; left: 50%; top: calc(clamp(160px, 26vh, 260px) + 30px); width: 340px; height: 70px; margin-left: -170px;
  border-radius: 50%; border: 2px solid var(--sig-400);
  transform: scale(calc(.1 + var(--w) * .9)); opacity: calc((1 - var(--w)) * clamp(0, var(--w) * 8, 1));
}
.art-contain .dev-led {
  --c: clamp(0, (var(--h) - .8) / .15, 1);
  background: color-mix(in oklab, var(--es-calm) calc(var(--c) * 100%), var(--accent-solid-bg));
}
.steps { position: absolute; left: 50%; bottom: 0; transform: translateX(-50%); margin: 0; padding: 0; list-style: none; display: flex; gap: .4rem; white-space: nowrap; }
.steps li {
  --a: clamp(0, (var(--h) - .55 - var(--r) * .1) / .1, 1);
  padding: .4rem .7rem; border-radius: var(--radius-full); font: 600 var(--text-xs)/1 var(--font-mono);
  border: 1px solid color-mix(in oklab, var(--es-calm) calc(var(--a) * 100%), var(--es-line));
  color: color-mix(in oklab, var(--es-calm) calc(var(--a) * 100%), var(--hearth-text-muted));
}
.steps li + li::before { content: "→ "; color: var(--hearth-text-muted); }

/* ── progress rail ─────────────────────────────────────────────────────────── */
.es-rail { display: none; }

/* ── the ending: choose your plane (POUR/PLAY's "find your cup") ─────────── */
.es-end { padding: clamp(72px, 12vh, 140px) 0; background: var(--hearth-canvas); }
.es-end-k { margin: 0 0 .6rem; font: 600 var(--text-xs)/1 var(--font-sans); letter-spacing: .16em; text-transform: uppercase; color: var(--accent-text); text-align: center; }
.es-end-h { margin: 0 auto 2.6rem; text-align: center; font: 400 clamp(2rem, 4.6vw, 3.8rem)/1.05 var(--font-display); letter-spacing: -.02em; text-wrap: balance; }
.es-end-h em { font-style: normal; color: var(--sig-600); }
.es-cards { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1rem; }
.es-card {
  display: grid; gap: .5rem; align-content: start; padding: 1.4rem 1.3rem 1.2rem; min-height: 200px;
  border-radius: var(--radius-xl); background: var(--hearth-raised); border: 1px solid var(--es-line, var(--hearth-border));
  box-shadow: var(--shadow-sm); color: var(--hearth-text); text-decoration: none;
  transition: transform var(--duration-base) var(--ease-standard), box-shadow var(--duration-base) var(--ease-standard), border-color var(--duration-base) var(--ease-standard);
}
.es-card:hover, .es-card:focus-visible { transform: translateY(-6px); box-shadow: var(--shadow-lg); border-color: var(--sig-300); }
.es-card-n { font: 300 var(--text-3xl)/1 var(--font-display); color: var(--sig-500); }
.es-card b { font: 600 var(--text-lg)/1.2 var(--font-sans); }
.es-card span:not(.es-card-n):not(.es-card-go) { color: var(--hearth-text-secondary); font-size: var(--text-sm); line-height: 1.5; }
.es-card-go { margin-top: auto; font: 600 var(--text-sm)/1 var(--font-sans); color: var(--accent-text); }
.es-end-more { margin: 2rem 0 0; text-align: center; }
.es-end-more a { color: var(--accent-text); font-weight: 600; }

@media (max-width: 860px) {
  .ch { grid-template-columns: 1fr; align-content: center; }
  .art { height: clamp(300px, 46vh, 420px); }
  .es-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .plate-labels { right: -4px; }
  .iso { width: 170px; height: 170px; }
  .reader { --rs: .62; }
  /* the gate's ring + its ribbon must share a phone-height object box (46vh / 44vh pinned) */
  .art-gate .ring { width: min(220px, 56vw); }
  .rib { min-height: 0; padding-block: 22px; }
}
@media (max-width: 520px) {
  .es-cards { grid-template-columns: 1fr; }
  .plate-labels { position: static; transform: none; margin-top: 1rem; }
  .art-seal { display: flex; flex-direction: column; justify-content: center; }
  .iso { width: 130px; height: 130px; }
  .chain { display: none; }
  .reader { --rs: .5; }
}

/* ============================================================================
   PINNED MODE — the cinema. Set by event-story.js only when motion is welcome.
   ========================================================================== */
.es[data-mode="pin"] { height: 820vh; }
.es[data-mode="pin"] .es-stage {
  --k: calc(.2 + var(--p) * 6.6);
  position: sticky; top: 0; height: 100vh; height: 100svh; overflow: hidden; color: var(--hearth-text);
}
.es[data-mode="pin"] .ch {
  --t: clamp(0, var(--k) - var(--i), 1);
  position: absolute; inset: 0; min-height: 0; background: none;
  padding-top: calc(64px + clamp(24px, 6vh, 72px));
  visibility: visible;
}
/* a chapter that is fully out takes no hits and is skipped by find-in-page highlighting */
.es[data-mode="pin"] .ch { pointer-events: none; }

.es[data-mode="pin"] .es-hint { display: block; opacity: calc(1 - clamp(0, var(--k) * 4 - 1, 1)); }

.es[data-mode="pin"] .es-rail {
  display: flex; position: absolute; left: 50%; bottom: 18px; transform: translateX(-50%); z-index: 3;
  margin: 0; padding: 0; list-style: none; gap: clamp(6px, 1.6vw, 22px);
}
.es-rail li {
  --on: clamp(0, var(--k) - var(--s), 1);
  position: relative; padding-top: 10px; font: 600 10px/1 var(--font-sans); letter-spacing: .12em; text-transform: uppercase;
  color: color-mix(in oklab, var(--sig-500) calc(var(--on) * 100%), color-mix(in oklab, currentColor 45%, transparent));
}
.es-rail li::before { content: ""; position: absolute; left: 0; right: 0; top: 0; height: 2px; border-radius: 2px; background: color-mix(in oklab, currentColor 25%, transparent); }
.es-rail li::after { content: ""; position: absolute; left: 0; top: 0; height: 2px; border-radius: 2px; width: calc(var(--on) * 100%); background: var(--sig-500); }

/* ① the scroll timeline: CSS animates --p itself — no listener, no main-thread work */
@supports (animation-timeline: view()) {
  .es[data-mode="pin"] { view-timeline: --es block; }
  .es[data-mode="pin"] .es-stage { animation: es-p linear both; animation-timeline: --es; animation-range: contain 0% contain 100%; }
}
@keyframes es-p { from { --p: 0; } to { --p: 1; } }

@media (max-width: 860px) {
  .es[data-mode="pin"] .ch { align-content: start; gap: 8px; padding-top: calc(64px + 12px); }
  .es[data-mode="pin"] .ch-p { display: none; }
  .es[data-mode="pin"] .ch-h { font-size: clamp(1.6rem, 7vw, 2.2rem); }
  .es[data-mode="pin"] .art { height: 44vh; }
  .es[data-mode="pin"] .es-rail li { font-size: 0; padding-top: 0; width: 22px; }
}

@media print {
  .es[data-mode="pin"] { height: auto; }
  .es[data-mode="pin"] .es-stage { position: static; height: auto; animation: none; }
  .es[data-mode="pin"] .ch { --t: .74; position: relative; inset: auto; }
  .es-rail, .es-hint { display: none !important; }
}

/* ── the sound control (site-sound.js): one speaker, bottom-left, never covering content ── */
.snd { position: fixed; left: 16px; bottom: 16px; z-index: 50; width: 40px; height: 40px; border-radius: 50%;
  display: grid; place-items: center; cursor: pointer; padding: 0;
  background: color-mix(in oklab, var(--hearth-raised) 88%, transparent); border: 1px solid var(--hearth-border);
  box-shadow: var(--shadow-sm); color: var(--hearth-text-secondary); backdrop-filter: blur(6px); }
.snd svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.snd svg path:first-child { fill: currentColor; stroke: none; }
.snd[aria-pressed="false"] .snd-w { opacity: .18; }
.snd[aria-pressed="false"]::after { content: ""; position: absolute; width: 22px; height: 1.7px; background: currentColor; transform: rotate(-45deg); border-radius: 2px; }
.snd:hover, .snd:focus-visible { color: var(--sig-600); border-color: var(--sig-300); }
@media print { .snd { display: none; } }
