/* reel.css: the reel of Ocean of A Cnscsnss, Talk 1 (RUNTIME lane, 17 October 2026; SPINE-REEL R3).
   A film you scroll: every shot pins a 16:9 stage that owns the screen, one large short caption line
   under it, nothing else competing. Chapter cards fill the viewport and assemble with motion. Sim's full
   words wait in a quiet "Read my full notes" drawer. The sound button is a small pill.

   The default (no JavaScript, or reduced motion) is a still list: every stage shows its final frame (each
   shot's own CSS default), captions and beat words visible, nothing pinned. html.o-reel-js (set by
   reel.js only when motion is allowed) turns on the pin, the scrub band and the assembly.
   reel.js sets --o-shot-band on each shot through the CSSOM; present.js sets --o-stage-* the same way.
   Tokens come from read.css (--o-ink, --o-gold, --o-line …) with dark-era fallbacks. Classes only. */

:root{
  /* the pinned stage starts BELOW the site's fixed bar and fits the space left (Sim, 6 Nov: the chart's title was hidden under the bar
     unless he used presenter mode); chrome.js measures the bar live into --x-nav-h */
  --o-pin-h:calc(100svh - var(--x-nav-h,0px));
  --o-pin-top:var(--x-nav-h,0px);
  --o-reel-w:100vw;
  /* the room under the stage for the caption line (normal mode) */
  /* sized for the tallest glass card (a three-line MY READ is ~156px + its 16px pad at 1440x900): the stage is then one fixed size
     and a long card never hangs off the screen nor squeezes the frame (Sim, 6 Nov: no zooming while subtitles play) */
  --o-cap-room:clamp(196px,22svh,240px);
  --o-reel-ink:var(--o-ink,#e9edf2);
  --o-reel-ink-2:var(--o-ink-2,rgba(233,237,242,.72));
  --o-reel-quiet:var(--o-ink-3,rgba(233,237,242,.5));
  --o-reel-gold:var(--o-gold,#e6cf9a);
  --o-reel-line:var(--o-line,rgba(255,255,255,.1));
  --o-reel-glass:var(--o-glass,rgba(255,255,255,.04));
  --o-reel-glass-b:var(--o-glass-border,rgba(255,255,255,.14));
  --o-reel-ease:cubic-bezier(.2,.7,.2,1);
  --o-reel-mono:var(--o-mono,ui-monospace,SFMono-Regular,'SF Mono',Menlo,Consolas,monospace);
  --o-reel-body:var(--o-body,'Inter',system-ui,-apple-system,'Segoe UI',sans-serif);
  --o-reel-display:var(--o-display,'Satoshi','Inter',system-ui,sans-serif);
}
html.is-present{
  --o-pin-h:var(--o-stage-h,100vh);
  --o-pin-top:var(--o-stage-y,0px);
  --o-reel-w:var(--o-stage-w,100vw);
  --o-cap-room:0px;
}

/* ------------------------------------------------------------ a shot: the still default */
section.o-shot{
  position:relative;
  margin:clamp(28px,6vh,72px) 0;
  color:var(--o-reel-ink);
}
.o-shot__pin{
  position:relative;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:clamp(10px,1.6svh,18px);
  padding:0 16px;
}
.o-shot__stage{
  position:relative;
  width:min(100%,1200px);
  aspect-ratio:16/9;
  /* a size container (a superset of the spine's inline-size): cqw AND cqh inside a shot both resolve to
     the stage, never to the page */
  container-type:size;
  overflow:hidden;
  isolation:isolate;
  background:transparent;
}
section.o-shot[data-ground="own"] .o-shot__stage{background:#050308}
.o-shot__stage > [data-composition-id]{position:absolute;inset:0;width:100%;height:100%}
.o-shot__caption{
  margin:0;
  max-width:min(100%,34em);
  font:500 clamp(1.05rem,.72rem + 1.25vw,1.95rem)/1.3 var(--o-reel-body);
  letter-spacing:-.006em;
  text-align:center;
  text-wrap:balance;
  color:var(--o-reel-ink);
  text-shadow:0 1px 14px rgba(0,0,0,.35);
}
html.o-era-light .o-shot__caption{text-shadow:0 0 18px rgba(255,253,248,.85)}
/* Scarlet's line while her narration carries a scene (empty otherwise) */
.o-shot__voice{
  margin:0;max-width:min(100%,40em);
  display:flex;align-items:baseline;justify-content:center;gap:.8em;
  font:500 clamp(.98rem,.7rem + 1vw,1.6rem)/1.35 var(--o-reel-body);
  text-align:center;text-wrap:balance;color:var(--o-reel-ink);
}
.o-shot__voice::before{
  content:"SCARLET";flex:none;
  font:600 .5em/1 var(--o-reel-mono);letter-spacing:.24em;color:var(--o-reel-gold);transform:translateY(-.15em);
}
.o-shot__voice:empty{display:none}
.o-shot__pin:has(.o-shot__voice:not(:empty)) .o-shot__caption{display:none}
/* the beat words: visible as a quiet line when nothing moves (JS off, reduced motion) */
.o-shot__beats{
  list-style:none;margin:8px auto 0;padding:0 16px;max-width:min(100%,1200px);
  display:flex;flex-wrap:wrap;justify-content:center;gap:4px 14px;
  font:500 .78rem/1.4 var(--o-reel-mono);letter-spacing:.06em;color:var(--o-reel-quiet);
}
.o-shot__beats > li{margin:0}
/* the plain description (screen readers, JS off, reduced motion) and a scene's transcript: quiet, under the beats */
.o-shot__what{
  margin:6px auto 0;padding:0 16px;max-width:min(100%,46em);text-align:center;
  font:400 .9rem/1.5 var(--o-reel-body);color:var(--o-reel-quiet);text-wrap:pretty;
}
details.o-shot__transcript{margin:8px auto 0;padding:0 16px;max-width:min(100%,46em);font-size:.86rem;line-height:1.6;color:var(--o-reel-ink-2)}
details.o-shot__transcript > summary{cursor:pointer;width:max-content;margin:0 auto;font:600 .66rem/1 var(--o-reel-mono);letter-spacing:.16em;text-transform:uppercase;color:var(--o-reel-quiet)}
.o-shot__audio{display:none}
.o-shot__beats > li + li::before{content:"·";margin-right:14px;color:var(--o-reel-gold);opacity:.6}

/* the older scene markup, adopted by reel.js as a shot: its head and transcript step back */
section.o-shot--scene{margin:clamp(28px,6vh,72px) 0;padding:0;border:0}
section.o-shot--scene > .o-motion__head,
section.o-shot--scene > .o-motion__transcript{
  position:absolute !important;width:1px;height:1px;margin:-1px;padding:0;border:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap
}
section.o-shot--scene .o-shot__stage{border:0;border-radius:0}
section.o-shot--scene .o-shot__voice.o-motion__captions{min-height:0}
section.o-shot--scene .o-shot__voice.o-motion__captions::before{content:"SCARLET"}

/* ------------------------------------------------------------ the reel: pinned, scrubbed, full bleed */
html.o-reel-js section.o-shot{
  width:var(--o-reel-w);
  max-width:none;
  margin:0 0 0 calc(50% - var(--o-reel-w) / 2);
  height:calc(var(--o-pin-h) + var(--o-shot-band,120svh));
}
html.o-reel-js .o-shot__pin{
  position:sticky;
  top:var(--o-pin-top);
  height:var(--o-pin-h);
  padding:0;
  gap:0;
  z-index:1;
}
html.o-reel-js .o-shot__stage{
  /* letterboxed to the viewport, leaving the caption its room underneath */
  width:min(100%,calc((var(--o-pin-h) - var(--o-cap-room)) * 16 / 9));
  max-width:none;
  cursor:pointer;
}
html.o-reel-js .o-shot__caption,
html.o-reel-js .o-shot__voice{
  min-height:calc(var(--o-cap-room) - 18px);
  padding:clamp(10px,1.8svh,20px) 20px 0;
  box-sizing:border-box;
  max-width:min(100%,38em);
}
html.o-reel-js .o-shot__caption{display:flex;align-items:flex-start;justify-content:center}
html.o-reel-js .o-shot__beats,
html.o-reel-js .o-shot__what,
html.o-reel-js .o-shot__transcript,
html.o-reel-js .o-shot__audio{
  position:absolute;width:1px;height:1px;margin:-1px;padding:0;border:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap
}
/* the final frame is never frozen: a slow push while it holds (motion craft rule 5) */
/* the root's own `scale` (not transform, which GSAP owns), clipped by the stage, only on shots near the view */
@keyframes o-reel-drift{from{scale:1}to{scale:1.014}}
html.o-reel-js section.o-shot.is-near.is-ended .o-shot__stage > [data-composition-id]{animation:o-reel-drift 14s ease-in-out infinite alternate}
html.o-reel-js section.o-shot[data-state="playing"] .o-shot__stage > [data-composition-id]{animation:none}

/* present mode: the stage IS the 16:9 frame; the caption line only when the presenter asks for it */
html.is-present.o-reel-js .o-shot__stage{width:100%;height:100%;aspect-ratio:auto}
html.is-present .o-shot__caption,
html.is-present .o-shot__voice{display:none}
html.is-present.is-pcap.o-reel-js .o-shot__caption,
html.is-present.is-pcap.o-reel-js .o-shot__voice:not(:empty){
  display:flex;position:absolute;left:50%;bottom:5.5%;transform:translateX(-50%);
  width:auto;max-width:72%;min-height:0;padding:.45em .9em;border-radius:10px;
  font-size:calc(var(--o-pin-h) * .036);
  background:rgba(5,3,8,.55);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);z-index:2
}
html.is-present.is-pcap.o-reel-js .o-shot__pin:has(.o-shot__voice:not(:empty)) .o-shot__caption{display:none}

/* the chrome steps back while a stage owns the screen (reel.js: is-reel-pin); scroll up or reach the top to bring it back */
html.o-reel-js header.o-chrome{transition:transform .45s var(--o-reel-ease),opacity .35s ease}
html.o-reel-js.is-reel-pin:not(.is-reel-chrome):not(.is-present) header.o-chrome:not(:focus-within){
  transform:translateY(-100%);opacity:0;pointer-events:none
}

/* nothing competes with a pinned stage: the harbour rail and the key chip fade with the chrome */
html.o-reel-js nav.o-index,html.o-reel-js .o-keychip{transition:opacity .45s var(--o-reel-ease)}
html.o-reel-js.is-reel-pin:not(.is-reel-chrome) nav.o-index:not([data-open]):not(:focus-within),
html.o-reel-js.is-reel-pin .o-keychip{opacity:0;pointer-events:none}

/* ------------------------------------------------------------ chapter cards
   read.css owns the card's look and its assembly (GRAMMAR: one driver per element); reel.js only replays
   it on a step by toggling .is-on. Here: the card fills the stage box in present mode, nothing more. */
html.is-present .o-chapter__card{min-height:var(--o-stage-h,100vh)}

/* ------------------------------------------------------------ the notes drawer
   read.css owns its look (one driver per element). In the reel the closed drawer is a quiet pill centred
   between the last shot and the next flight; open, it reads as a narrow column. */
html.o-reel-js details.o-notes{max-width:min(var(--o-maxw,1100px),820px)}
html.o-reel-js details.o-notes:not([open]){text-align:center}
html.o-reel-js details.o-notes[open] > summary{margin-left:0}
html.o-reel-js details.o-notes[open] > :not(summary){animation:o-notes-in .5s var(--o-reel-ease) both}
@keyframes o-notes-in{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}

/* ------------------------------------------------------------ the sound button: a small pill, off until pressed */
button.o-sound{
  appearance:none;-webkit-appearance:none;
  display:inline-flex;align-items:center;gap:.55em;flex:none;
  min-height:32px;padding:0 .95em 0 .75em;margin:0;border-radius:999px;
  border:1px solid var(--o-reel-glass-b);background:var(--o-reel-glass);color:var(--o-reel-ink-2);
  font:600 .68rem/1 var(--o-reel-mono);letter-spacing:.14em;text-transform:uppercase;white-space:nowrap;
  cursor:pointer;
  transition:border-color .3s var(--o-reel-ease),color .3s var(--o-reel-ease),background-color .3s var(--o-reel-ease);
}
button.o-sound:hover{border-color:var(--o-reel-gold);color:var(--o-reel-ink)}
button.o-sound:focus-visible{outline:2px solid var(--o-reel-gold);outline-offset:2px}
button.o-sound[aria-pressed="true"]{border-color:var(--o-reel-gold);color:var(--o-reel-gold);background:color-mix(in srgb,var(--o-reel-gold) 12%,transparent)}
/* the speaker, drawn in CSS: a body, a cone, then waves when on or a slash when off */
.o-sound__icon{position:relative;display:inline-block;width:15px;height:14px;flex:none}
.o-sound__icon::before{
  content:"";position:absolute;left:0;top:2px;width:9px;height:10px;background:currentColor;
  clip-path:polygon(0 30%,35% 30%,100% 0,100% 100%,35% 70%,0 70%);
}
.o-sound__icon::after{
  content:"";position:absolute;left:8px;top:6px;width:9px;height:1.5px;background:currentColor;border-radius:1px;
  transform:rotate(-45deg);transform-origin:50% 50%;
}
button.o-sound[aria-pressed="true"] .o-sound__icon::after{
  left:9px;top:2px;width:5px;height:9px;background:none;border-radius:0 9px 9px 0;
  border:1.5px solid currentColor;border-left:0;transform:none;box-sizing:border-box;
}
/* "on", but the audio waits for a press (a remembered choice never starts by itself) */
button.o-sound[aria-pressed="true"][data-running="false"]{border-style:dashed}
html.is-present button.o-sound{display:none}

/* ------------------------------------------------------------ reduced motion: the still list, always */
@media (prefers-reduced-motion:reduce){
  html.o-reel-js section.o-shot{height:auto;width:auto;margin:clamp(28px,6vh,72px) 0}
  html.o-reel-js .o-shot__pin{position:relative;height:auto}
  html.o-reel-js .o-shot__beats,html.o-reel-js .o-shot__what,html.o-reel-js .o-shot__transcript{position:static;width:auto;height:auto;margin:8px auto 0;overflow:visible;clip-path:none;white-space:normal}
  section.o-shot .o-shot__stage,section.o-shot .o-shot__stage > [data-composition-id]{animation:none !important}
  html.o-reel-js details.o-notes[open] > :not(summary){animation:none}
}

@media (max-width:600px){
  :root{--o-cap-room:clamp(84px,18svh,150px)}
  .o-shot__caption{font-size:clamp(1.02rem,.8rem + 1.6vw,1.3rem)}
  button.o-sound{min-height:34px}
}

@media print{
  html.o-reel-js section.o-shot{height:auto}
  html.o-reel-js .o-shot__pin{position:relative;height:auto}
}

/* Levels of the Levels: every shot is a LUMEN shot (data-aspect="fluid"), recomposing for any aspect: on an upright
   phone its stage is 4:5, not a letterboxed 16:9 (from assets/ocean/reel.css, 5 Nov 2026). The canvas needs a sized,
   positioned stage. */
.o-shot__stage{position:relative}
@media (max-width:600px){
  :root{--o-cap-room:clamp(84px,18svh,150px)}
  html:not(.is-present) section.o-shot[data-aspect="fluid"] .o-shot__stage{aspect-ratio:4/5}
  html.o-reel-js:not(.is-present) section.o-shot[data-aspect="fluid"] .o-shot__stage{width:min(100%,calc((var(--o-pin-h) - var(--o-cap-room)) * 4 / 5))}
}

/* ============================================================ Scarlet's subtitles (sound lane, 5 Nov 2026)
   assets/levels/voice.js wraps the caption in .x-capstack with her subtitle line (p.x-voice) in the same grid cell, so
   neither moves the layout. While she speaks, section[data-voicing] is set: the caption fades out first (0.8 s), her
   lines crossfade one at a time (the outgoing line leaves quickly, the incoming one arrives after it, nothing pops in a
   gap), and when she ends her last line fades and the caption glows back (1.2 s). Slow, soft easing throughout.
   Present mode: her subtitle shows in the lower third of the 16:9 frame whenever she speaks; the caption keeps P's rule. */
.x-capstack{display:grid;justify-items:center;align-items:start;width:100%}
.x-capstack > .o-shot__caption,.x-capstack > .x-voice{grid-area:1/1}
.x-capstack > .o-shot__caption{transition:opacity 1.2s cubic-bezier(.2,.6,.2,1),filter 1.2s cubic-bezier(.2,.6,.2,1)}
section.o-shot[data-voicing] .x-capstack > .o-shot__caption{opacity:0;filter:blur(3px);transition-duration:.8s;pointer-events:none}
.x-voice{
  margin:0;display:flex;align-items:baseline;justify-content:center;gap:.8em;max-width:min(100%,40em);
  font:500 clamp(.98rem,.7rem + 1vw,1.6rem)/1.35 var(--o-reel-body);text-align:center;color:var(--o-reel-ink);
  text-shadow:0 1px 14px rgba(0,0,0,.35);
  opacity:0;transition:opacity .9s cubic-bezier(.2,.6,.2,1);pointer-events:none;
}
html.o-reel-js .x-voice{box-sizing:border-box}   /* its padding is the glass card's (glass.css) */
section.o-shot[data-voicing="on"] .x-voice{opacity:1;transition-delay:.35s}
.x-voice__who{flex:none;font:600 .5em/1 var(--o-reel-mono);letter-spacing:.24em;text-transform:uppercase;color:var(--o-reel-gold);transform:translateY(-.15em)}
.x-voice__lines{display:grid;text-wrap:balance}
.x-voice__l{grid-area:1/1;opacity:0;transform:translateY(5px);transition:opacity .5s cubic-bezier(.2,.6,.2,1),transform .9s cubic-bezier(.2,.6,.2,1)}
.x-voice__l.is-on{opacity:1;transform:none;transition:opacity .9s cubic-bezier(.2,.6,.2,1) .28s,transform 1.1s cubic-bezier(.2,.6,.2,1) .28s}
[data-era="light"] .x-voice{color:#16101e}
html.is-present.o-reel-js .x-voice{
  position:absolute;left:50%;bottom:5.5%;transform:translateX(-50%);
  width:auto;max-width:72%;padding:.45em .9em;border-radius:10px;
  font-size:calc(var(--o-pin-h) * .036);color:var(--o-reel-ink);text-shadow:none;
  background:rgba(5,3,8,.55);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);z-index:3;
}
@media (prefers-reduced-motion:reduce){.x-voice__l,.x-voice__l.is-on{transform:none}}
/* the subtitle's glass rim and sheen (assets/levels/glass.css) own ::before and ::after */

/* ============================================================ a still frame under a moving caption (Sim, 6 Nov 2026)
   "as the size of the captions box changes it also slightly changes the size of the motion graphic ... zooming in and out".
   The pin is a centred flex column, so a subtitle taller than its room squeezed the stage (flex-shrink) and the composition,
   sized by the stage's container query, zoomed; a shorter line let it grow back and the frame drifted up and down too.
   Now the stage never shrinks and the caption owns a fixed slot of --o-cap-room: a long line spills downward, the frame stays. */
html.o-reel-js:not(.is-present) .o-shot__stage{flex:none}
html.o-reel-js:not(.is-present) .o-shot__pin > .x-capstack{flex:none;height:var(--o-cap-room);overflow:visible;align-content:start}
html.o-reel-js:not(.is-present) .o-shot__pin > .o-shot__caption,
html.o-reel-js:not(.is-present) .o-shot__pin > .o-shot__voice{flex:none;height:calc(var(--o-cap-room) - 18px);overflow:visible}
