/* scroll-scenes: declarative scroll choreography on top of scroll-kit.
   Everything is driven by one number, --p (0..1), which scroll-kit writes on [data-scroll] and pin elements
   (custom properties inherit, so children of a pin read the pin's --p).
   Only transform / opacity / clip-path are animated, so scrubbing stays on the compositor.
   All effects live under html.sc (added by scenes.js): without JS the page is fully visible and readable. */

:root {
  --sc-text-dim: .16;          /* opacity of an unfilled word/char in data-scrub-text */
  --sc-rail-color: #fff;       /* white + mix-blend difference = visible on any chapter colour */
  --sc-rail-size: 9px;
  --sc-stack-top: 12vh;        /* where stacked cards stick */
  --sc-stack-step: 22px;       /* peek of each earlier card */
  --sc-zoom-to: .66;           /* scale the zoom scene shrinks to */
  --sc-zoom-lift: -9vh;        /* how far it rises while shrinking, uncovering .sc-under */
  --sc-zoom-r: 40;             /* corner radius (px) the zoom scene reaches */
}

/* ---- shared progress maths: --a/--b = window inside --p, --e = linear 0..1, --k = smoothstep ---- */
html.sc :is([data-scrub], [data-scrub-text], [data-draw], [data-wipe]) {
  --a: 0; --b: 1;
  --e: clamp(0, calc((var(--p, 0) - var(--a)) / (var(--b) - var(--a))), 1);
  --k: calc(var(--e) * var(--e) * (3 - 2 * var(--e)));
}

/* ---- data-scrub="y:60>0 scale:.8>1 opacity:0>1 rotate:-6>0 x:-40>0 blur:12>0" ---- */
html.sc [data-scrub] {
  --x0: 0; --x1: 0; --y0: 0; --y1: 0; --s0: 1; --s1: 1; --r0: 0; --r1: 0; --o0: 1; --o1: 1; --bl0: 0; --bl1: 0;
  transform:
    translate3d(calc((var(--x0) + (var(--x1) - var(--x0)) * var(--k)) * 1px), calc((var(--y0) + (var(--y1) - var(--y0)) * var(--k)) * 1px), 0)
    rotate(calc((var(--r0) + (var(--r1) - var(--r0)) * var(--k)) * 1deg))
    scale(calc(var(--s0) + (var(--s1) - var(--s0)) * var(--k)));
  opacity: calc(var(--o0) + (var(--o1) - var(--o0)) * var(--k));
  will-change: transform, opacity;
}
html.sc [data-scrub].sc-blur { filter: blur(calc((var(--bl0) + (var(--bl1) - var(--bl0)) * var(--k)) * 1px)); }

/* ---- data-scrub-text="words|chars": text fills in as you scroll ---- */
html.sc [data-scrub-text] .sc-u {
  opacity: calc(var(--sc-text-dim) + (1 - var(--sc-text-dim)) * clamp(0, calc(var(--e) * (var(--n) + 1) - var(--i)), 1));
}
.sc-u { display: inline-block; white-space: pre; }

/* ---- data-draw: SVG strokes draw themselves (scenes.js sets pathLength=1) ---- */
html.sc [data-draw] :is(path, line, polyline, polygon, circle, rect, ellipse) {
  stroke-dasharray: 1px; stroke-dashoffset: calc((1 - var(--k)) * 1px);
}
html.sc [data-draw][data-draw-fill] :is(path, polygon, circle, rect, ellipse) { fill-opacity: clamp(0, calc((var(--e) - .85) * 6.6), 1); }

/* ---- data-wipe="left|right|up|down|circle|iris": clip-path reveal ---- */
html.sc [data-wipe], html.sc [data-wipe="left"]  { clip-path: inset(0 calc((1 - var(--k)) * 100%) 0 0); }
html.sc [data-wipe="right"]  { clip-path: inset(0 0 0 calc((1 - var(--k)) * 100%)); }
html.sc [data-wipe="up"]     { clip-path: inset(calc((1 - var(--k)) * 100%) 0 0 0); }
html.sc [data-wipe="down"]   { clip-path: inset(0 0 calc((1 - var(--k)) * 100%) 0); }
html.sc [data-wipe="circle"] { clip-path: circle(calc(var(--k) * 75%) at var(--wx, 50%) var(--wy, 50%)); }
html.sc [data-wipe="iris"]   { clip-path: inset(calc((1 - var(--k)) * 50%) calc((1 - var(--k)) * 50%) round calc((1 - var(--k)) * 40vmin)); }

/* ---- data-scene="zoom": a pinned hero that shrinks into a rounded card, revealing what is under it ----
   markup: <section data-scene="zoom" data-pin="160vh"><div class="sc-under">...</div><div class="sc-inner">...hero...</div></section> */
html.sc [data-scene="zoom"] .sc-under { position: absolute; inset: 0; display: grid; place-items: end center; padding-bottom: 6vh; }
html.sc [data-scene="zoom"] .sc-inner {
  position: absolute; inset: 0; overflow: hidden; transform-origin: 50% 50%; will-change: transform;
  transform: translate3d(0, calc(var(--p, 0) * var(--sc-zoom-lift)), 0) scale(calc(1 - var(--p, 0) * (1 - var(--sc-zoom-to))));
  border-radius: calc(var(--p, 0) * var(--sc-zoom-r) * 1px);
}

/* ---- data-scene="stack": sticky cards that sink and dim as the next one covers them ----
   markup: <div data-scene="stack"><article class="sc-card">...</article>...</div> */
[data-scene="stack"] .sc-card {
  position: sticky; top: calc(var(--sc-stack-top) + var(--i, 0) * var(--sc-stack-step));
  transform-origin: 50% 0; margin-bottom: 14vh;
}
html.sc [data-scene="stack"] .sc-card {
  --cover: 0;
  transform: scale(calc(1 - var(--cover) * .06)); filter: brightness(calc(1 - var(--cover) * .28));
  will-change: transform;
}


/* ---- data-scene="assemble" (on a data-pin section): .sc-part children fly in from scattered offsets and lock together ----
   scenes.js gives each part a seeded --dx/--dy (vw/vh), --dr (deg), --ds and a staggered window --pa..--pb. Author the FINAL layout in CSS;
   the fly-in is only an offset from it. markup: <section data-scene="assemble" data-pin="260vh"><div class="stage"><span class="sc-part">B</span>...</div></section> */
html.sc [data-scene="assemble"] .sc-part {
  --pe: clamp(0, calc((var(--p, 0) - var(--pa, 0)) / (var(--pb, 1) - var(--pa, 0))), 1);
  --pk: calc(var(--pe) * var(--pe) * (3 - 2 * var(--pe)));
  display: inline-block; will-change: transform, opacity;
  transform: translate3d(calc((1 - var(--pk)) * var(--dx, 0) * 1vw), calc((1 - var(--pk)) * var(--dy, 0) * 1vh), 0) rotate(calc((1 - var(--pk)) * var(--dr, 0) * 1deg)) scale(calc(1 + (1 - var(--pk)) * var(--ds, 0)));
  opacity: calc(.0 + var(--pk));
}

/* ---- data-scene="curtain" (on a data-pin section): .sc-l / .sc-r halves slide apart, uncovering .sc-under ---- */
html.sc [data-scene="curtain"] { --ck: calc(var(--p, 0) * var(--p, 0) * (3 - 2 * var(--p, 0))); }
html.sc [data-scene="curtain"] .sc-under { position: absolute; inset: 0; display: grid; place-items: center; }
html.sc [data-scene="curtain"] :is(.sc-l, .sc-r) { position: absolute; top: 0; bottom: 0; width: 50.2%; overflow: hidden; will-change: transform; }
html.sc [data-scene="curtain"] .sc-l { left: 0; transform: translate3d(calc(var(--ck) * -101%), 0, 0); }
html.sc [data-scene="curtain"] .sc-r { right: 0; transform: translate3d(calc(var(--ck) * 101%), 0, 0); }

/* ---- data-scene="tunnel" (on a data-pin section): .sc-layer children rush toward you one after another ----
   markup: <section data-scene="tunnel" data-pin="300vh"><div class="sc-layer">ONE</div><div class="sc-layer">TWO</div>...</section> */
html.sc [data-scene="tunnel"] .sc-layer {
  --t: calc(var(--p, 0) * (var(--n) - 1) - var(--i));       /* -1..1 around this layer's moment */
  position: absolute; inset: 0; display: grid; place-items: center; will-change: transform, opacity;
  transform: scale(calc(1 + var(--t) * var(--sc-tunnel-zoom, 1.1)));
  opacity: clamp(0, calc(1.25 - var(--t) * var(--t) * 1.25), 1);
  pointer-events: none;
}

/* ---- data-chapters: a progress rail whose dots are the chapters ---- */
.sc-rail { position: fixed; right: 14px; top: 50%; translate: 0 -50%; z-index: 40; display: grid; gap: 14px; color: var(--sc-rail-color); mix-blend-mode: difference; }
.sc-rail button {
  all: unset; box-sizing: border-box; position: relative; width: 24px; height: 24px; display: grid; place-items: center; cursor: pointer;
}
.sc-rail button::before { content: ""; width: var(--sc-rail-size); height: var(--sc-rail-size); border-radius: 50%; background: currentColor; opacity: .35; transition: opacity .3s, scale .3s; }
.sc-rail button[aria-current="true"]::before { opacity: 1; scale: 1.6; }
.sc-rail button.sc-hit::before { opacity: 1; scale: 2.4; }
.sc-rail button span {
  position: absolute; right: 30px; white-space: nowrap; font: 11px/1 ui-monospace, monospace; letter-spacing: .08em; text-transform: uppercase;
  opacity: 0; translate: 6px 0; transition: opacity .25s, translate .25s; pointer-events: none;
}
.sc-rail button:hover span, .sc-rail button:focus-visible span, .sc-rail button[aria-current="true"] span { opacity: 1; translate: 0 0; }
.sc-rail button:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; border-radius: 50%; }
@media (max-width: 640px) { .sc-rail { right: 6px; gap: 6px; } .sc-rail button span { display: none; } :root { --sc-stack-top: 9vh; --sc-stack-step: 14px; } }

/* page progress bar: <div class="sc-bar"></div> */
.sc-bar { position: fixed; left: 0; top: 0; height: 3px; width: 100%; z-index: 41; background: var(--accent, currentColor); transform-origin: 0 50%; transform: scaleX(var(--page-p, 0)); pointer-events: none; }

@media (prefers-reduced-motion: reduce) {
  html.sc [data-scrub].sc-blur { filter: none; }
}
