/* The scroll story under the exchange: four chapters, §3 trade, §4 launch, §5 ask (assets/story/ask.js) and §6 the app.
   Every word is in the page first, and every chapter is a textured stage (glow, a floor grid, dust, its big number) even when nothing moves.
   With motion allowed and scroll timelines supported, each stage pins for a full screen while its scene plays, then the next chapter
   slides up over it while it sinks back, so there is never an empty screen between them. Everyone else gets the plain page. */
@property --gain { syntax: "<integer>"; inherits: false; initial-value: 184; }
@property --edge { syntax: "<percentage>"; inherits: true; initial-value: 0%; } /* how far a covered chapter's air fades at its edges (sc-sink) */

/* film grain over the whole home page: one still tile (assets/story/grain.webp), nudged a few times a second (only with motion allowed) */
body.home::after { content: ""; position: fixed; inset: -10%; z-index: 80; pointer-events: none; opacity: .07;
  background: url(/assets/story/grain.webp) 0 0 / 200px 200px; }

/* ── the stage ─────────────────────────────────────────── */
.story { position: relative; overflow-x: clip; }
.sc { --c1: 153 69 255; --c2: 20 241 149; position: relative; }
.sc-launch { --c1: 20 241 149; --c2: 204 255 0; }
.sc-ask { --c1: 40 200 255; --c2: 153 69 255; }
.sc-app { --c1: 153 69 255; --c2: 204 255 0; }
.sc-stage { position: relative; isolation: isolate; padding: clamp(84px, 10vw, 128px) 0 clamp(72px, 9vw, 112px); }
.sc-air { position: absolute; inset: 0; z-index: -1; overflow: hidden; pointer-events: none;
  background: url(/assets/story/clouds.webp) 0 0 / 720px 720px, /* a tile that wraps: the old smoke.webp's edges didn't match, so every 720 px drew a line through the glow */
    radial-gradient(62% 54% at 86% 14%, rgba(var(--c1) / .24), transparent 70%), radial-gradient(54% 48% at 6% 100%, rgba(var(--c2) / .15), transparent 72%), #050505;
  background-blend-mode: soft-light, normal, normal, normal; }
.sc-trade .sc-air { -webkit-mask-image: linear-gradient(transparent, #000 160px); mask-image: linear-gradient(transparent, #000 160px); } /* out of the exchange's black, no seam */
/* a floor grid running to a horizon behind the scene */
.sc-air::before { content: ""; position: absolute; left: -60%; right: -60%; top: 70%; height: 620px; transform-origin: 50% 0; transform: perspective(620px) rotateX(70deg);
  background: linear-gradient(rgba(var(--c1) / .26) 1px, transparent 1px) 0 0 / 80px 80px, linear-gradient(90deg, rgba(var(--c1) / .26) 1px, transparent 1px) 0 0 / 80px 80px;
  -webkit-mask-image: linear-gradient(transparent, #000 30%, #000 55%, transparent 90%), linear-gradient(90deg, rgba(0 0 0 / .3) 30%, #000 56%); -webkit-mask-composite: source-in;
  mask-image: linear-gradient(transparent, #000 30%, #000 55%, transparent 90%), linear-gradient(90deg, rgba(0 0 0 / .3) 30%, #000 56%); mask-composite: intersect; }
/* dust: four dot tiles of odd sizes, so no pattern repeats where the eye can see it */
.sc-air::after { content: ""; position: absolute; inset: -20% 0; opacity: .7;
  background-image: radial-gradient(1.5px 1.5px at 17px 23px, #fff, transparent), radial-gradient(1px 1px at 131px 77px, rgba(255 255 255 / .75), transparent),
    radial-gradient(1.6px 1.6px at 63px 151px, rgb(var(--c1)), transparent), radial-gradient(1px 1px at 199px 197px, rgba(255 255 255 / .55), transparent);
  background-size: 223px 211px, 263px 241px, 397px 383px, 307px 251px; }
.sc-num { position: absolute; left: -2.5vw; top: -2svh; font: 800 min(58svh, 36vw)/.76 var(--sans); font-style: normal; letter-spacing: -.07em; color: transparent;
  -webkit-text-stroke: 1px rgba(255 255 255 / .08); background: linear-gradient(168deg, rgba(var(--c1) / .16), rgba(var(--c1) / 0) 62%); -webkit-background-clip: text; background-clip: text; }
.sc + .sc > .sc-stage::before { content: ""; position: absolute; inset: 0 0 auto; z-index: 4; height: 1px; pointer-events: none; /* the edge of the next chapter, lit */
  background: linear-gradient(90deg, transparent, rgba(var(--c1) / .9) 30%, rgba(var(--c2) / .9) 70%, transparent); box-shadow: 0 0 34px 3px rgba(var(--c1) / .35); }
.sc-stage::after { content: ""; position: absolute; inset: 0; z-index: 5; pointer-events: none; background: #020202; opacity: 0; } /* dims a chapter as the next one covers it */

.sc-in { position: relative; display: grid; grid-template-columns: minmax(0, .92fr) minmax(0, 1.08fr); gap: clamp(28px, 4.5vw, 72px); align-items: center; }
.sc-copy { display: grid; gap: clamp(16px, 2.6svh, 26px); align-content: center; justify-items: start; }
.sc-copy header { display: flex; align-items: center; gap: 12px; }
.sc-copy h2 { font: 700 clamp(40px, min(5.6vw, 9.6svh), 88px)/.96 var(--sans); letter-spacing: -.055em; perspective: 700px; }
.sc-copy h2 > span { display: block; width: fit-content; padding-bottom: .06em; transform-origin: 50% 100%; text-wrap: balance; }
.sc-sub { max-width: 40ch; font: 400 clamp(15px, 1.3vw, 18px)/1.5 var(--sans); color: #a8a7a2; text-wrap: pretty; }

/* the beats: what the scene shows, one line each, lit in turn on a rail */
.sc-beats { position: relative; display: grid; gap: clamp(12px, 2.2svh, 20px); padding-left: 24px; }
.sc-beats::before, .sc-beats::after { content: ""; position: absolute; left: 0; top: 7px; bottom: 7px; width: 2px; border-radius: 2px; background: var(--line-2); }
.sc-beats::after { background: linear-gradient(rgb(var(--c1)), rgb(var(--c2))); box-shadow: 0 0 14px rgba(var(--c1) / .7); transform-origin: 50% 0; }
.sc-beats li { position: relative; display: grid; gap: 4px; align-content: start; }
.sc-beats li::before { content: ""; position: absolute; left: -28px; top: 7px; width: 10px; height: 10px; border-radius: 50%; background: #050505; border: 2px solid rgb(var(--c2)); box-shadow: 0 0 12px rgba(var(--c2) / .6); }
.sc-beats li > b { font: 600 clamp(17px, 1.45vw, 21px)/1.2 var(--sans); letter-spacing: -.02em; color: var(--text); }
.sc-beats li > span { font: 400 13px/1.5 var(--mono); color: var(--dim); }
.sc-beats a { color: var(--accent); }
.sc-vis { position: relative; perspective: 1400px; }

/* ── §3: the thread, in front of the trade it describes ─────────── */
.tr-vis { display: grid; justify-items: end; align-items: end; min-height: clamp(600px, 56vw, 780px); }
.tr-chart { position: absolute; top: 0; left: 0; width: 100%; aspect-ratio: 640 / 400; }
.tr-chart { -webkit-mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent); mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent); }
.tr-chart svg { position: absolute; inset: 0; display: block; width: 100%; height: 100%; }
.tr-ghost path { fill: none; stroke: rgba(255 255 255 / .16); stroke-width: 1.5; stroke-dasharray: 2 7; stroke-linecap: round; }
.tr-grid line { stroke: rgba(255 255 255 / .1); stroke-width: 1; stroke-dasharray: 3 7; }
.tr-area { fill: url(#tr-f); }
.tr-line, .tr-glow { fill: none; stroke: url(#tr-g); stroke-linecap: round; stroke-linejoin: round; }
.tr-line { stroke-width: 3; }
.tr-glow { stroke-width: 16; opacity: .2; }
.tr-pin { position: absolute; display: inline-flex; align-items: center; gap: 9px; translate: -7px -50%; padding: 6px 11px 6px 0; font: 600 11px/1 var(--mono); letter-spacing: .14em; color: var(--text); white-space: nowrap; }
.tr-pin i { flex: none; width: 14px; height: 14px; border-radius: 50%; background: #050505; border: 3px solid rgb(var(--c2)); box-shadow: 0 0 0 5px rgba(var(--c2) / .14), 0 0 22px rgba(var(--c2) / .8); }
.tr-buy { left: 15%; top: 79.5%; } .tr-buy i { border-color: #b98dff; box-shadow: 0 0 0 5px rgba(153 69 255 / .16), 0 0 22px rgba(153 69 255 / .9); }
.tr-sell { left: 85.6%; top: 16%; flex-direction: row-reverse; translate: calc(-100% + 7px) -50%; padding: 6px 0 6px 11px; } .tr-sell i { border-color: var(--neon); box-shadow: 0 0 0 5px rgba(204 255 0 / .14), 0 0 22px rgba(204 255 0 / .8); }
.sc-thread { position: relative; z-index: 2; display: grid; gap: 12px; width: min(100%, 450px); transform-style: preserve-3d; }
.sc-thread .x-post { position: relative; overflow: hidden; padding: 15px 18px; border: 1px solid rgba(255 255 255 / .08); border-radius: 20px;
  background: linear-gradient(180deg, #151514, #0b0b0a); box-shadow: 0 30px 70px -32px #000, inset 0 1px 0 rgba(255 255 255 / .05); }
.sc-thread .x-post p { font-size: 15.5px; }
.sc-thread .x-re { margin-left: clamp(18px, 3vw, 34px); }
.sc-thread .bot { border-color: rgba(var(--accent-rgb) / .34); box-shadow: 0 30px 70px -32px #000, 0 0 0 1px rgba(var(--accent-rgb) / .06), 0 20px 70px -40px rgba(var(--accent-rgb) / .8); }
.sc-thread .bot::after { content: ""; position: absolute; inset: 0; pointer-events: none; translate: -110% 0; background: linear-gradient(105deg, transparent 30%, rgba(255 255 255 / .1) 48%, rgba(var(--accent-rgb) / .14) 52%, transparent 70%); } /* the light that runs across a receipt as it lands */
.gain { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 10px; margin-top: 10px; }
.gain .g-n { margin: 0; counter-reset: g var(--gain); font: 700 clamp(32px, 3vw, 44px)/1 var(--sans); letter-spacing: -.035em; color: var(--ok); text-shadow: 0 0 30px rgba(var(--accent-rgb) / .5); }
.g-n::before { content: "+" counter(g) "%"; }
.g-l { font: 500 12px/1 var(--mono); letter-spacing: .08em; color: var(--soft); }
.gain .sample { margin-left: auto; }

/* ── §4: the post and its image, the coin, the live line ─────────── */
.lv { display: grid; gap: 26px; justify-items: center; align-content: center; }
.lv-post { width: min(100%, 460px); padding: 15px 18px; border: 1px solid rgba(255 255 255 / .08); border-radius: 20px; background: linear-gradient(180deg, #151514, #0b0b0a); box-shadow: 0 30px 70px -32px #000; }
.lv-post p { font-size: 15.5px; }
.lv-img { position: relative; display: block; width: min(100%, 320px); aspect-ratio: 1; margin-top: 12px; overflow: hidden; border: 1px solid var(--line-2); border-radius: 16px; background: #10100f; }
.lv-img img { position: absolute; inset: 0; width: 100%; height: 100%; border-radius: 0; background: none; }
.lv-blur { filter: blur(7px) saturate(.5) brightness(.8); transform: scale(1.1); } /* a pre-blurred layer: the wipe animates clip-path, never blur */
.lv-scan { position: absolute; top: 0; bottom: 0; left: 0; width: 24%; opacity: 0; background: linear-gradient(90deg, transparent, rgba(var(--accent-rgb) / .65), rgba(204 255 0 / .4), transparent); mix-blend-mode: screen; }
.lv-grok { position: absolute; right: 8px; bottom: 8px; padding: 4px 7px; border-radius: 6px; background: rgba(0 0 0 / .7); font: 600 10px/1 var(--mono); font-style: normal; letter-spacing: .14em; color: var(--text); }
.lv-coin { position: relative; display: grid; place-items: center; perspective: 900px; transform-style: preserve-3d; }
.lv-c3 { position: relative; width: clamp(180px, 21vw, 300px); aspect-ratio: 1; transform-style: preserve-3d; }
.lv-coin::before { content: ""; position: absolute; left: 50%; top: calc(50% - 22px); z-index: -1; width: 200%; aspect-ratio: 1; translate: -50% -50%; border-radius: 50%; background: radial-gradient(closest-side, rgba(var(--accent-rgb) / .2), rgba(204 255 0 / .05) 55%, transparent); }
.lv-orbit { position: absolute; left: 50%; top: calc(50% - 22px); width: 175%; aspect-ratio: 1; margin: -87.5% 0 0 -87.5%; border-radius: 50%; border: 1px solid rgba(var(--accent-rgb) / .28); transform: rotateX(76deg) rotateY(-8deg); transform-style: preserve-3d; }
.lv-orbit b { position: absolute; inset: 0; border-radius: 50%; }
.lv-orbit b::before { content: ""; position: absolute; left: 50%; top: -5px; width: 10px; height: 10px; margin-left: -5px; border-radius: 50%; background: var(--neon); box-shadow: 0 0 14px var(--neon), 0 0 30px rgba(204 255 0 / .6); }
.lv-rim { position: absolute; inset: 1.5%; border-radius: 50%; transform: translateZ(calc(var(--z) * 1px)); background: conic-gradient(from 40deg, #6f6f69, #f4f4ee 18%, #8a8a84 34%, #e2e2dc 52%, #75756f 70%, #f0f0ea 86%, #6f6f69); } /* stacked discs: the edge has thickness when it turns */
.lv-face { position: absolute; inset: 0; display: grid; place-items: center; overflow: hidden; border-radius: 50%; backface-visibility: hidden; transform: translateZ(8px); background: #121211;
  box-shadow: inset 0 0 0 5px rgba(255 255 255 / .18), inset 0 -20px 36px rgba(0 0 0 / .4), inset 0 14px 26px rgba(255 255 255 / .08); }
.lv-face img { width: 100%; height: 100%; }
.lv-back { transform: rotateY(180deg) translateZ(8px); background: var(--brand); }
.lv-back img { width: 60%; height: 60%; }
.lv-coin::after { content: ""; display: block; width: 76%; height: 22px; margin-top: 22px; border-radius: 50%; background: radial-gradient(closest-side, rgba(var(--accent-rgb) / .45), transparent); }
.lv-ring { position: absolute; left: 50%; top: calc(50% - 22px); width: clamp(180px, 21vw, 300px); aspect-ratio: 1; translate: -50% -50%; border: 2px solid rgba(204 255 0 / .8); border-radius: 50%; opacity: 0; box-shadow: 0 0 30px rgba(var(--accent-rgb) / .5), inset 0 0 30px rgba(var(--accent-rgb) / .3); }
.lv-r2 { border-color: rgba(var(--accent-rgb) / .7); }
.lv-sparks { position: absolute; left: 50%; top: calc(50% - 22px); width: 0; height: 0; }
.lv-sparks i { position: absolute; width: 7px; height: 7px; margin: -3.5px; border-radius: 50%; background: var(--neon); box-shadow: 0 0 12px var(--neon); opacity: 0; }
.lv-sparks i:nth-child(even) { background: var(--accent); box-shadow: 0 0 12px var(--accent); }
.lv-live { display: grid; gap: 12px; justify-items: center; text-align: center; }
.lv-title { font: 700 clamp(30px, 3.6vw, 52px)/1.05 var(--sans); letter-spacing: -.045em; color: var(--text); }
.lv-t { color: var(--accent); text-shadow: 0 0 34px rgba(var(--accent-rgb) / .45); }
.lv-t i { display: inline-block; font-style: normal; }
.lv-ca { display: inline-flex; align-items: center; gap: 10px; padding: 8px 12px; border: 1px solid var(--line-2); border-radius: 99px; background: #0c0c0b; font: 500 13px/1 var(--mono); color: var(--text); }

/* ── §6: the app, with its coins in orbit ───────────────────────── */
.ap-vis { display: grid; place-items: center; }
.ap { position: relative; z-index: 1; display: grid; gap: 16px; width: min(100%, 390px); padding: 18px; border: 1px solid rgba(255 255 255 / .1); border-radius: 34px; background: linear-gradient(180deg, #121211, #080807);
  box-shadow: 0 0 0 7px #0d0d0c, 0 0 0 8px rgba(255 255 255 / .08), 0 60px 140px -50px rgba(var(--accent-rgb) / .5), 0 40px 90px -40px #000; } /* a phone's bezel, two rings deep */
.ap > .sample { position: absolute; top: -9px; right: 26px; background: #0c0c0b; }
.ap-bal { display: grid; justify-items: center; gap: 6px; padding: 18px 12px; border: 1px solid transparent; border-radius: 22px; text-align: center;
  background: linear-gradient(#0b0b0a, #0b0b0a) padding-box, linear-gradient(135deg, rgba(153 69 255 / .55), rgba(20 241 149 / .3) 50%, rgba(204 255 0 / .25)) border-box; }
.ap-bal b { font: 700 clamp(36px, 4vw, 46px)/1 var(--sans); letter-spacing: -.045em; font-variant-numeric: tabular-nums; }
.ap-bal small { font: 400 12px/1 var(--mono); color: var(--soft); }
/* the balance as an odometer: each digit is a strip of 0–9 four times over, rolled to its digit */
.odo { display: inline-flex; align-items: flex-start; }
.odo i { --spins: 20; display: inline-block; height: 1em; overflow: hidden; font-style: normal; }
.odo i::before { content: "0\A 1\A 2\A 3\A 4\A 5\A 6\A 7\A 8\A 9\A 0\A 1\A 2\A 3\A 4\A 5\A 6\A 7\A 8\A 9\A 0\A 1\A 2\A 3\A 4\A 5\A 6\A 7\A 8\A 9\A 0\A 1\A 2\A 3\A 4\A 5\A 6\A 7\A 8\A 9";
  display: block; white-space: pre; line-height: 1; translate: 0 calc((var(--d) + var(--spins)) * -1em); }
.ap-acts { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; }
.ap-acts li { display: grid; justify-items: center; gap: 6px; font: 500 11px/1.2 var(--sans); color: var(--dim); }
.ap-acts i { width: 40px; height: 40px; border: 1px solid var(--line-2); border-radius: 50%; background: var(--raise); }
.ap-acts i.pri { border-color: transparent; background: var(--brand); }
.ap-rows { display: grid; gap: 2px; }
.ap-rows li { display: grid; grid-template-columns: 32px minmax(0, 1fr) auto; gap: 10px; align-items: center; padding: 8px 6px; border-radius: 14px; }
.ap-rows img { width: 32px; height: 32px; border-radius: 50%; }
.ap-rows b { font: 600 14px/1.2 var(--sans); }
.ap-rows span { font: 500 13px/1 var(--mono); color: var(--text); font-variant-numeric: tabular-nums; }
.ap-rows .up { color: var(--ok); }
.ap-trade { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 14px; border: 1px solid var(--line-2); border-radius: 18px; background: rgba(255 255 255 / .02); }
.ap-trade span { display: grid; gap: 4px; } .ap-trade b { font: 600 14px/1.2 var(--sans); } .ap-trade small { font: 400 12px/1 var(--mono); color: var(--soft); }
.ap-sw { position: relative; flex: none; width: 46px; height: 26px; border-radius: 99px; background: var(--accent); box-shadow: 0 0 14px rgba(var(--accent-rgb) / .5); }
.ap-sw::after { content: ""; position: absolute; top: 3px; left: 3px; width: 20px; height: 20px; border-radius: 50%; background: #050505; translate: 20px 0; }
.ap-float img { position: absolute; z-index: 0; width: clamp(48px, 5vw, 72px); height: auto; aspect-ratio: 1; border-radius: 50%; padding: 9px; background: radial-gradient(circle at 34% 28%, #2a2a27, #0c0c0b 70%);
  box-shadow: inset 0 0 0 1px rgba(255 255 255 / .14), inset 0 -8px 16px rgba(0 0 0 / .5), 0 24px 50px -20px #000, 0 0 40px -8px rgba(var(--c1) / .55); }
.ap-float .f1 { left: 4%; top: 12%; } .ap-float .f2 { right: 3%; top: 26%; width: clamp(40px, 4vw, 58px); }
.ap-float .f3 { left: 9%; bottom: 14%; width: clamp(40px, 4vw, 56px); } .ap-float .f4 { right: 8%; bottom: 8%; padding: 0; }
.app-go { margin-top: 4px; }

/* ── the chapter rail (wide screens, with motion) ─────────────── */
.st-rail { display: none; }

@media (max-width: 860px) {
  .sc-in { grid-template-columns: minmax(0, 1fr); }
  .sc-copy h2 { font-size: clamp(34px, 9.4vw, 52px); }
  .sc-num { left: auto; right: -6vw; top: 34%; font-size: 70vw; }
  .tr-vis { display: flex; flex-direction: column; justify-content: flex-end; gap: 12px; min-height: 0; }
  .tr-chart { position: relative; aspect-ratio: 640 / 300; } /* under the thread; the svg stretches to its box, the strokes stay crisp */
  .sc-thread { width: 100%; gap: 9px; }
  .sc-thread .x-post { padding: 12px 14px; border-radius: 18px; }
  .sc-thread .x-post p { font-size: 14px; }
  .ap-float img { width: 46px; }
}

/* ── motion: only with motion allowed and scroll timelines supported ─────────── */
@media (prefers-reduced-motion: no-preference) { @supports (animation-timeline: view()) {
  body.home::after { animation: grain 1.4s steps(7) infinite; }
  .story { timeline-scope: --trade, --launch, --ask, --app; view-timeline: --story block; margin-top: clamp(40px, 6vw, 80px); }
  .sc-trade { --tl: --trade; view-timeline: --trade block; }
  .sc-launch { --tl: --launch; view-timeline: --launch block; }
  .sc-ask { --tl: --ask; view-timeline: --ask block; }
  .sc-app { --tl: --app; view-timeline: --app block; }
  /* each chapter: a screen to slide in, a screen pinned, and a screen while the next one covers it (the last one has no next) */
  .sc { height: 300svh; }
  .sc-app { height: 200svh; }
  .sc + .sc { margin-top: -100svh; }
  .sc-ask:not(.is-story) { height: auto; } /* without ask.js the read can't play: a plain block, and the app doesn't cover it */
  .sc-ask:not(.is-story) + .sc { margin-top: 0; }
  .sc > .sc-stage { position: sticky; top: 0; height: 100svh; padding: 0; }
  .sc-ask:not(.is-story) > .sc-stage { position: relative; height: auto; padding: clamp(84px, 10vw, 128px) 0 clamp(72px, 9vw, 112px); }
  /* the air runs on under a collapsing phone toolbar; and while the next chapter covers this one, its edges fade (--edge), so the shrunken stage shows no box
     (the incoming chapter keeps its lit hard edge: feathering it let the covered chapter's text show through) */
  .sc-air { bottom: -30svh; --top: var(--edge);
    -webkit-mask-image: linear-gradient(transparent, #000 var(--top), #000 calc(100% - 30svh), transparent), linear-gradient(90deg, transparent, #000 var(--edge), #000 calc(100% - var(--edge)), transparent); -webkit-mask-composite: source-in;
    mask-image: linear-gradient(transparent, #000 var(--top), #000 calc(100% - 30svh), transparent), linear-gradient(90deg, transparent, #000 var(--edge), #000 calc(100% - var(--edge)), transparent); mask-composite: intersect; }
  .sc-trade .sc-air { --top: max(160px, var(--edge)); }
  .sc-stage::after { -webkit-mask-image: linear-gradient(transparent, #000 var(--edge), #000 calc(100% - var(--edge)), transparent), linear-gradient(90deg, transparent, #000 var(--edge), #000 calc(100% - var(--edge)), transparent); -webkit-mask-composite: source-in;
    mask-image: linear-gradient(transparent, #000 var(--edge), #000 calc(100% - var(--edge)), transparent), linear-gradient(90deg, transparent, #000 var(--edge), #000 calc(100% - var(--edge)), transparent); mask-composite: intersect; } /* the dimming fades with the air */
  .sc-in { height: 100%; grid-template-rows: minmax(0, 1fr); padding: clamp(56px, 9svh, 96px) 0 clamp(24px, 5svh, 56px); }
  .sc > .sc-stage .sc-vis { align-self: center; height: min(100%, 780px); min-height: 0; }

  /* the air drifts: the number rises, the dust lifts, the floor runs toward you */
  .sc-num, .sc-air::after, .sc-air::before { animation-timing-function: linear; animation-fill-mode: both; animation-timeline: var(--tl); animation-range: cover 0% cover 100%; }
  .sc-num { animation-name: sc-num; }
  .sc-air::after { animation-name: sc-dust; }
  .sc-air::before { animation-name: sc-floor; }
  /* the next chapter covers this one: it sinks and dims */
  .sc-trade > .sc-stage, .sc-trade > .sc-stage::after { animation: sc-sink linear both; animation-timeline: --launch; animation-range: entry 0% entry 100%; }
  .sc-launch > .sc-stage, .sc-launch > .sc-stage::after { animation: sc-sink linear both; animation-timeline: --ask; animation-range: entry 0% entry 100%; }
  .sc-ask > .sc-stage, .sc-ask > .sc-stage::after { animation: sc-sink linear both; animation-timeline: --app; animation-range: entry 0% entry 100%; }
  .sc-stage::after { animation-name: sc-dim !important; }
  .sc > .sc-stage { transform-origin: 50% 40%; }

  /* the copy arrives with the stage: the label, then the headline line by line, tipping up out of the page */
  .sc-copy header { animation: sc-fade cubic-bezier(.2, .7, .2, 1) both; animation-timeline: var(--tl); animation-range: entry 25% entry 60%; }
  .sc-copy h2 > span { animation: sc-line cubic-bezier(.2, .75, .25, 1) both; animation-timeline: var(--tl); animation-range: entry 30% entry 78%; }
  .sc-copy h2 > span + span { animation-range: entry 40% entry 88%; }
  .sc-sub { animation: sc-fade ease-out both; animation-timeline: var(--tl); animation-range: entry 50% entry 90%; }
  .app-go { animation: sc-fade ease-out both; animation-timeline: var(--tl); animation-range: entry 60% entry 100%; }

  /* the beats light in turn (each chapter sets its windows); the rail fills under them */
  .sc-beats li { animation: beat linear both; animation-timeline: var(--tl); }
  .sc-beats li:nth-child(1) { animation-range: var(--r1); } .sc-beats li:nth-child(2) { animation-range: var(--r2); }
  .sc-beats li:nth-child(3) { animation-range: var(--r3); } .sc-beats li:nth-child(4) { animation-name: beat-last; animation-range: var(--r4); }
  .sc-beats::after { animation: beat-fill linear both; animation-timeline: var(--tl); animation-range: var(--rf); }
  .sc-trade { --r1: entry 60% contain 4%; --r2: contain 4% contain 14%; --r3: contain 14% contain 36%; --r4: contain 36% contain 44%; --rf: entry 60% contain 40%; }
  .sc-launch { --r1: entry 60% contain 0%; --r2: contain 0% contain 18%; --r3: contain 18% contain 40%; --r4: contain 40% contain 46%; --rf: entry 60% contain 44%; }
  .sc-app { --r1: entry 60% contain 8%; --r2: contain 8% contain 20%; --r3: contain 20% contain 32%; --r4: contain 32% contain 42%; --rf: entry 60% contain 40%; }
  .sc-ask .sc-beats li, .sc-ask .sc-beats::after { animation: none !important; } /* §5's beats follow ask.js (ask.css) */
  .sc-ask:not(.is-story) > .sc-stage, .sc-ask:not(.is-story) > .sc-stage::after { animation: none !important; }

  /* §3: the thread stands up as the trade draws itself behind it: buy, the climb, sell half, the gain */
  .tr-vis { min-height: 0; }
  .sc-thread { animation: tr-tilt cubic-bezier(.25, .7, .25, 1) both; animation-timeline: --trade; animation-range: entry 30% contain 36%; }
  .sc-trade .x-post { animation: sc-rise cubic-bezier(.2, .8, .2, 1) both; animation-timeline: --trade; }
  .sc-trade .x-post.bot { animation-name: sc-flip; transform-origin: 0 50%; }
  .sc-trade .x-post:nth-child(1) { animation-range: entry 55% entry 95%; }
  .sc-trade .x-post:nth-child(2) { animation-range: contain 2% contain 11%; }
  .sc-trade .x-post:nth-child(3) { animation-range: contain 14% contain 22%; }
  .sc-trade .x-post:nth-child(4) { animation-range: contain 24% contain 33%; }
  .sc-trade .bot::after { animation: bot-shine linear both; animation-timeline: --trade; }
  .sc-trade .x-post:nth-child(2)::after { animation-range: contain 8% contain 15%; }
  .sc-trade .x-post:nth-child(4)::after { animation-range: contain 30% contain 37%; }
  .sc-trade .g-n { animation: sc-gain ease-out both; animation-timeline: --trade; animation-range: contain 31% contain 42%; }
  .tr-chart { animation: sc-fade ease-out both; animation-timeline: --trade; animation-range: entry 35% entry 80%; }
  .tr-draw { animation: tr-draw linear both; animation-timeline: --trade; animation-range: entry 70% contain 32%; }
  .tr-pin { animation: tr-pin cubic-bezier(.3, 1.6, .5, 1) both; animation-timeline: --trade; }
  .tr-buy { animation-range: contain 3% contain 9%; }
  .tr-sell { animation-range: contain 30% contain 36%; }

  /* §4: the scan wipes the blurry image sharp, the post falls back, a coin turns in and lands with a shockwave, $FROG goes live */
  .lv { grid-template-areas: "s"; }
  .lv-post, .lv-coin, .lv-live { grid-area: s; }
  .lv-coin { align-self: center; margin-bottom: clamp(90px, 11vw, 150px); }
  .lv-live { align-self: end; }
  .lv-post { animation: lv-post linear both; animation-timeline: --launch; animation-range: entry 50% contain 26%; } /* 50svh in, a hold, then away from contain 18% */
  .lv-sharp { animation: lv-wipe linear both; animation-timeline: --launch; animation-range: contain 0% contain 14%; }
  .lv-scan { animation: lv-scan linear both; animation-timeline: --launch; animation-range: contain 0% contain 14%; }
  .lv-grok { animation: lv-pop ease-out both; animation-timeline: --launch; animation-range: contain 13% contain 17%; }
  .lv-c3 { animation: lv-spin linear both, lv-bob 4.5s ease-in-out infinite; animation-timeline: --launch, auto; animation-range: contain 20% contain 35%, normal; } /* the bob runs on time: the landed coin breathes */
  .lv-coin::after { animation: lv-shadow linear both; animation-timeline: --launch; animation-range: contain 20% contain 35%; }
  .lv-coin::before { animation: sc-fade ease-out both; animation-timeline: --launch; animation-range: contain 24% contain 36%; }
  .lv-orbit { animation: lv-orbit cubic-bezier(.2, .8, .2, 1) both; animation-timeline: --launch; animation-range: contain 30% contain 42%; }
  .lv-orbit b { animation: spin 7s linear infinite; }
  .lv-ring { animation: lv-ring cubic-bezier(.1, .7, .3, 1) both; animation-timeline: --launch; animation-range: contain 32% contain 42%; }
  .lv-r2 { animation-range: contain 34% contain 46%; }
  .lv-sparks i { animation: lv-spark cubic-bezier(.1, .8, .3, 1) both; animation-timeline: --launch; animation-range: contain 32% contain 42%; }
  .lv-sparks i:nth-child(even) { animation-range: contain 33% contain 44%; --r: .7; }
  .lv-t i { animation: lv-ltr cubic-bezier(.2, .9, .3, 1.3) both; animation-timeline: --launch; }
  .lv-t i:nth-child(1) { animation-range: contain 33% contain 37%; }
  .lv-t i:nth-child(2) { animation-range: contain 34% contain 38%; }
  .lv-t i:nth-child(3) { animation-range: contain 35% contain 39%; }
  .lv-t i:nth-child(4) { animation-range: contain 36% contain 40%; }
  .lv-t i:nth-child(5) { animation-range: contain 37% contain 41%; }
  .lv-rest { display: inline-block; animation: lv-fade ease-out both; animation-timeline: --launch; animation-range: contain 39% contain 43%; }
  .lv-ca { animation: lv-fade ease-out both; animation-timeline: --launch; animation-range: contain 42% contain 46%; }

  /* §6: the phone swings up flat, the balance rolls in, the coins arrive, the switch flips on; its coins drift past at their own depths */
  .ap { animation: ap-up cubic-bezier(.2, .8, .2, 1) both; animation-timeline: --app; animation-range: entry 35% contain 8%; transform-origin: 50% 100%; }
  .odo i::before { animation: odo cubic-bezier(.15, .7, .2, 1) both; animation-timeline: --app; animation-range: contain 0% contain 26%; }
  .odo i:nth-child(n+5)::before { animation-range: contain 2% contain 28%; --spins: 30; } /* the cents spin longest */
  .ap-rows li { animation: ap-row cubic-bezier(.2, .8, .2, 1) both; animation-timeline: --app; }
  .ap-rows li:nth-child(1) { animation-range: contain 8% contain 16%; }
  .ap-rows li:nth-child(2) { animation-range: contain 12% contain 20%; }
  .ap-rows li:nth-child(3) { animation-range: contain 16% contain 24%; }
  .ap-rows li:nth-child(4) { animation-range: contain 20% contain 28%; }
  .ap-sw { animation: ap-on linear both; animation-timeline: --app; animation-range: contain 34% contain 40%; }
  .ap-sw::after { animation: ap-flip linear both; animation-timeline: --app; animation-range: contain 34% contain 40%; }
  .ap-float img { animation: ap-drift linear both; animation-timeline: --app; animation-range: cover 0% cover 100%; }
  .ap-float .f2 { --dy: 34svh; } .ap-float .f3 { --dy: 50svh; } .ap-float .f4 { --dy: 26svh; }

  /* with a mouse, the scene leans toward it (home.js sets --mx and --my on the stage under the pointer); §5 orbits instead */
  @media (hover: hover) and (pointer: fine) {
    .sc-vis:not(.as-vis) { transform: perspective(1800px) rotateY(calc(var(--mx, 0) * 7deg)) rotateX(calc(var(--my, 0) * -5deg)); transition: transform .9s cubic-bezier(.2, .8, .2, 1); }
  }

  /* the chapter rail: wide screens only, in the gutter left of the page */
  @media (min-width: 1360px) {
    .st-rail { position: sticky; top: 0; z-index: 20; display: flex; flex-direction: column; justify-content: center; gap: 22px; height: 100svh; margin-bottom: -100svh;
      padding-left: 28px; pointer-events: none; animation: rail-in linear both; animation-timeline: --story; animation-range: entry 70% exit 40%; }
    .st-rail a { pointer-events: auto; position: relative; display: grid; gap: 4px; width: fit-content; padding-left: 16px; font: 500 11px/1 var(--mono); letter-spacing: .16em; text-transform: uppercase; color: var(--mute);
      animation: rail-on linear both; animation-range: entry 50% contain 75%; }
    .st-rail a::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 2px; border-radius: 2px; background: currentColor; }
    .st-rail b { font-weight: 600; letter-spacing: .08em; }
    .st-rail a:nth-child(1) { --c: 153 69 255; animation-timeline: --trade; } .st-rail a:nth-child(2) { --c: 20 241 149; animation-timeline: --launch; }
    .st-rail a:nth-child(3) { --c: 40 200 255; animation-timeline: --ask; } .st-rail a:nth-child(4) { --c: 204 255 0; animation-name: rail-last; animation-timeline: --app; animation-range: entry 50% contain 100%; }
    .st-rail a:hover { color: var(--text); }
  }

  /* phones: the stage is the whole screen: label and headline up top, one beat at a time, the scene fills the rest */
  @media (max-width: 860px) {
    .sc-in { grid-template-rows: auto minmax(0, 1fr); align-items: stretch; gap: 14px; padding: max(18px, 3svh) 0 14px; }
    .sc-copy { align-content: start; gap: 12px; }
    .sc-copy h2 { font-size: clamp(30px, min(8.6vw, 5svh), 46px); }
    .sc-sub { display: none; }
    .sc > .sc-stage .sc-vis { height: 100%; }
    .sc-beats { grid-template-areas: "b"; padding-left: 20px; }
    .sc-beats li { grid-area: b; }
    .sc-beats li::before { left: -24px; }
    .sc-beats li:not(:nth-child(4)) { animation-name: beat-solo; } .sc-beats li:nth-child(4) { animation-name: beat-solo-last; }
    .tr-chart { flex: 1 1 0; min-height: 90px; aspect-ratio: auto; } /* whatever height the thread leaves */
    .lv-img { width: min(100%, 230px); }
    .lv-coin { margin-bottom: 86px; }
    .lv-c3, .lv-ring { width: 180px; }
    .ap { width: min(100%, 340px); padding: 14px; gap: 12px; }
    .ap-bal { padding: 12px; }
    .ap-rows li { padding: 6px; }
  }
  @media (max-width: 860px) and (max-height: 760px) { .sc-thread, .ap { zoom: .88; } .lv-img { width: 190px; } .ap-acts { display: none; } }
  @media (max-width: 860px) and (max-height: 640px) { .sc-thread, .ap { zoom: .78; } .tr-chart { display: none; } .lv-img { width: 160px; } .lv-c3, .lv-ring { width: 140px; } }
  @media (min-width: 861px) and (max-height: 760px) {
    .sc-copy h2 { font-size: clamp(36px, min(5vw, 8.4svh), 72px); }
    .sc-beats { gap: 10px; }
    .tr-chart { width: 92%; }
  }
}}

@keyframes grain { 0%, 100% { transform: translate(0, 0); } 14% { transform: translate(-4%, 3%); } 28% { transform: translate(3%, -5%); } 42% { transform: translate(-6%, -2%); } 57% { transform: translate(5%, 4%); } 71% { transform: translate(-2%, 6%); } 85% { transform: translate(6%, -3%); } }
@keyframes sc-num { from { translate: 0 22svh; } to { translate: 0 -22svh; } }
@keyframes sc-dust { from { translate: 0 9%; } to { translate: 0 -9%; } }
@keyframes sc-floor { from { transform: perspective(620px) rotateX(70deg) translateY(-160px); } to { transform: perspective(620px) rotateX(70deg) translateY(0); } }
@keyframes sc-sink { to { transform: scale(.9) translateY(-2%); --edge: 9%; } }
@keyframes sc-dim { to { opacity: .72; } }
@keyframes sc-fade { from { opacity: 0; transform: translateY(18px); } }
@keyframes sc-line { from { opacity: 0; transform: translateY(.42em) rotateX(-80deg); } }
@keyframes beat { 0% { opacity: .26; } 18%, 82% { opacity: 1; } to { opacity: .5; } }
@keyframes beat-last { 0% { opacity: .26; } 35%, to { opacity: 1; } }
@keyframes beat-solo { 0% { opacity: 0; translate: 0 14px; } 16%, 80% { opacity: 1; translate: 0 0; } 94%, to { opacity: 0; translate: 0 -14px; } }
@keyframes beat-solo-last { 0% { opacity: 0; translate: 0 14px; } 30%, to { opacity: 1; translate: 0 0; } }
@keyframes beat-fill { from { transform: scaleY(0); } }
@keyframes tr-tilt { from { transform: translateZ(-120px) rotateX(34deg) rotateY(-16deg); } to { transform: rotateY(-7deg) rotateX(4deg); } }
@keyframes sc-rise { from { opacity: 0; transform: translate3d(0, 80px, -220px) rotateX(30deg); } }
@keyframes sc-flip { from { opacity: 0; transform: rotateY(-90deg) translateZ(50px); } 55% { opacity: 1; } }
@keyframes bot-shine { from { translate: -110% 0; } to { translate: 110% 0; } } /* not "sweep": that is grokto.css's composer ring, and a second "sweep" here slid the ring sideways off the input */
@keyframes sc-gain { from { --gain: 0; opacity: 0; transform: scale(.6); } 20% { opacity: 1; } 70% { transform: scale(1.12); } to { --gain: 184; } } /* no "+0%" before the count starts */
@keyframes tr-draw { 0% { clip-path: inset(-10% 100% -10% 0); } 42%, 52% { clip-path: inset(-10% 85% -10% 0); } 100% { clip-path: inset(-10% 0 -10% 0); } } /* to the buy (x 15%), a held breath, then the climb */
@keyframes tr-pin { from { opacity: 0; scale: .3; } }
@keyframes lv-post { 0% { opacity: 0; transform: translateY(80px) rotateX(26deg); animation-timing-function: cubic-bezier(.2, .8, .2, 1); } 44%, 84% { opacity: 1; transform: none; animation-timing-function: ease-in; } 100% { opacity: 0; transform: translate3d(0, -60px, -360px) rotateX(24deg); } }
@keyframes lv-wipe { from { clip-path: inset(0 100% 0 0); } }
@keyframes lv-scan { from { translate: -100% 0; opacity: 1; } 90% { opacity: 1; } to { translate: 420% 0; opacity: 0; } }
@keyframes lv-pop { from { opacity: 0; scale: .6; } }
@keyframes lv-spin { from { opacity: 0; transform: translateY(100px) scale(.2) rotateX(50deg) rotateY(-1080deg); } 12% { opacity: 1; } 74% { transform: translateY(-14px) scale(1.08) rotateX(-6deg) rotateY(-24deg); } to { transform: none; } }
@keyframes lv-shadow { from { opacity: 0; transform: scaleX(.2); } 74% { opacity: .5; } }
@keyframes lv-ring { 0% { opacity: 0; scale: .5; } 3% { opacity: .9; } to { opacity: 0; scale: 2.4; } }
@keyframes lv-spark { 0% { opacity: 0; transform: rotate(var(--a)) translateX(30px) scale(1.2); } 3% { opacity: 1; } to { opacity: 0; transform: rotate(var(--a)) translateX(calc(var(--r, 1) * 210px)) scale(.3); } }
@keyframes lv-ltr { from { opacity: 0; transform: translateY(80%) rotateX(-80deg) scale(1.4); } }
@keyframes lv-fade { from { opacity: 0; transform: translateY(14px); } }
@keyframes lv-bob { 50% { translate: 0 -8px; } }
@keyframes lv-orbit { from { opacity: 0; scale: .4; } }
@keyframes ap-up { from { opacity: 0; transform: perspective(1400px) rotateX(50deg) translateY(26%) scale(.84); } 30% { opacity: 1; } }
@keyframes odo { from { translate: 0 0; } }
@keyframes ap-row { from { opacity: 0; transform: translateX(-26px); } }
@keyframes ap-on { from { background: var(--raise); box-shadow: none; } }
@keyframes ap-flip { from { translate: 0 0; } }
@keyframes ap-drift { from { opacity: 0; translate: 0 var(--dy, 40svh) ; } 25% { opacity: 1; } to { translate: 0 calc(var(--dy, 40svh) * -1); } }
@keyframes rail-in { from { opacity: 0; } 8%, 92% { opacity: 1; } to { opacity: 0; } }
@keyframes rail-on { 0% { color: var(--mute); } 12%, 88% { color: rgb(var(--c)); } to { color: var(--mute); } }
@keyframes rail-last { 0% { color: var(--mute); } 20%, to { color: rgb(var(--c)); } }
