:root { --mono: ui-monospace, "SFMono-Regular", "JetBrains Mono", Menlo, Consolas, "Liberation Mono", monospace; --sans: Arial, "Helvetica Neue", system-ui, sans-serif; }
* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; overflow: hidden; background: #050505; color: #ececec; overscroll-behavior: none; }
body { touch-action: none; -webkit-tap-highlight-color: transparent; font-family: var(--sans); }
#gl { position: fixed; inset: 0; width: 100vw; height: 100vh; height: 100dvh; display: block; }
#vignette { position: fixed; inset: 0; pointer-events: none; background: radial-gradient(ellipse at 50% 45%, rgba(0,0,0,0) 45%, rgba(0,0,0,.55) 100%); }
#fade { position: fixed; inset: 0; pointer-events: none; opacity: 0; }
#fade img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* P10: the black the film fades up from (under the shell, over the canvas and captions); also the stills fallback's bed */
#black { position: fixed; inset: 0; background: #000; opacity: 1; pointer-events: none; z-index: 8; transition: opacity 2.4s ease; }
#black.off { opacity: 0; }
#black.quick { transition-duration: .6s; }
/* P10: no-WebGL fallback: the rests as stills, crossfaded by chapter under the same shell */
#stills { position: fixed; inset: 0; background: #050505; }
#stills[hidden] { display: none; }
#stills img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; opacity: 0; transition: opacity 1.1s ease; }
#stills img.on { opacity: 1; }
/* P10: decode spans (live only while a headline resolves; the real text nodes come back when it lands) */
.dr { visibility: hidden; }                                                                                       /* the real text, in place and laid out, hidden while the overlay draws */
.dl { position: absolute; inset: 0; pointer-events: none; }                                                       /* the overlay */
.dc { position: absolute; display: block; white-space: pre; text-align: center; clip-path: inset(-0.2em 0); }   /* a character slot at the character's measured rect; a cycling glyph is centred and clipped inside it */
/* P10: the first-load intro holds the shell's controls until the headline has decoded; then they fade in */
html[data-intro] .em-shell > :not(.em-loader) { opacity: 0 !important; }
html.introfade .em-shell > :not(.em-loader) { transition: opacity 1.2s ease; }
/* workbench only: ?clean=1 for the hero stills: film only */
html[data-clean] .seg, html[data-clean] .em-shell { display: none !important; }

.seg { position: fixed; left: clamp(20px, 6vw, 110px); top: 50%; transform: translateY(-50%); pointer-events: none; opacity: 0; max-width: 46vw; }
/* S4: every caption sits on a local darkening (a wide, soft radial scrim behind the text block, never a box) so the sub-line
   and the CTA stay legible over the light shafts and the lit ceiling; the text also carries a shadow. The scrim is sized from
   the caption's own box (closest-side ellipse: alpha 0 at the box edge, so it never shows a hard edge) and measured at every
   rest, desktop and phone: see the go-live proof (contrast.mjs). */
.seg::before { content: ""; position: absolute; left: -60%; right: -70%; top: -120%; bottom: -120%; z-index: -1; pointer-events: none; background: radial-gradient(closest-side at 45% 50%, rgba(5,5,6,.8) 0%, rgba(5,5,6,.68) 50%, rgba(5,5,6,.34) 74%, rgba(5,5,6,0) 100%); }
.seg h1 { font-weight: 400; font-size: clamp(34px, 4.3vw, 66px); line-height: 1.08; margin: 0 0 .5em; letter-spacing: -.01em; text-shadow: 0 2px 30px rgba(0,0,0,.6); }
.seg h2 { font-weight: 400; font-size: clamp(36px, 4.6vw, 72px); margin: 0 0 .25em; letter-spacing: .01em; text-shadow: 0 2px 30px rgba(0,0,0,.6); }
.seg .sub { margin: 0; font-size: clamp(15px, 1.35vw, 21px); color: #c4c4c4; text-shadow: 0 1px 2px rgba(0,0,0,.9), 0 2px 18px rgba(0,0,0,.7); }
.seg .cta { display: inline-block; margin-top: 1.4em; font-family: var(--mono); font-size: 13px; letter-spacing: .12em; text-transform: uppercase; color: #9be11e; text-decoration: none; border-bottom: 1px solid rgba(155,225,30,.5); padding-bottom: 3px; pointer-events: auto; text-shadow: 0 1px 2px rgba(0,0,0,.9), 0 2px 14px rgba(0,0,0,.7); }
.seg .cta:hover { color: #c6ff5c; }
.seg1 { top: 30%; }
.seg2 { top: 50%; }
.seg3 { top: 50%; }
.seg4 { top: 34%; max-width: 34vw; }
.seg5 { top: 50%; }
.seg .links { margin: 0; display: flex; gap: 28px; }
.seg .links .cta { margin-top: 1.4em; }
.seg .soon { margin: 1.2em 0 0; font-family: var(--mono); font-size: 11px; letter-spacing: .16em; text-transform: uppercase; color: rgba(255,255,255,.38); }
/* S4: at rest 6 the shell's bottom corners sit on the white floor pool. Two soft corner vignettes fade in under the shell's
   controls there (bottom-right under "Press / to ask Charles" and the Sound toggle, bottom-left under the dial): wide radial
   darkenings anchored past the viewport corners, so they read as the frame's own vignette, never as a box. The shell's own
   CSS is shared and untouched: this is page styling keyed on the active chapter. */
.em-shell::before, .em-shell::after { content: ""; position: absolute; z-index: -1; pointer-events: none; opacity: 0; transition: opacity .9s ease; background: radial-gradient(closest-side at 50% 50%, rgba(5,5,6,.92) 0%, rgba(5,5,6,.72) 45%, rgba(5,5,6,0) 100%); }
.em-shell::after { right: -20vw; bottom: -14vh; width: 70vw; height: 48vh; }
.em-shell::before { left: -12vw; bottom: -12vh; width: 44vw; height: 36vh; }
.em-shell[data-active="builders"]::before, .em-shell[data-active="builders"]::after { opacity: 1; }

@media (max-width: 760px) {
  .seg { left: 22px; right: 70px; max-width: none; top: auto; bottom: 120px; transform: none; }
  .seg::before { left: -40%; right: -40%; top: -110%; bottom: -110%; background: radial-gradient(closest-side at 50% 50%, rgba(5,5,6,.8) 0%, rgba(5,5,6,.68) 50%, rgba(5,5,6,.34) 74%, rgba(5,5,6,0) 100%); }
  .seg1 { top: 9%; bottom: auto; }
  .seg2 { bottom: 120px; }            /* phones: the reactor hangs across the top of the frame; the caption sits in the dark below it */
  .seg3 { bottom: 110px; }
  .seg4 { top: 9%; bottom: auto; }
  .seg5 { top: 9%; bottom: auto; }    /* phones: the floor pool is white at the bottom; the caption sits on the dark wall */
  .seg .links { gap: 18px; }
  /* phones: the bottom of the frame at rest 6 is the pure white pool, where a vignette reads as a blot. The corner vignettes stay
     off there; the Sound toggle (the only corner control on phones) turns dark on the white, and the reactor dial reads as it is. */
  .em-shell[data-active="builders"]::before, .em-shell[data-active="builders"]::after { opacity: 0; }
  .em-sound, .em-sound b, .em-sound-dot { transition: color .9s ease, border-color .9s ease; }
  .em-shell[data-active="builders"] .em-sound { color: #2a2d31; }
  .em-shell[data-active="builders"] .em-sound b { color: #0b0c0e; }
  .em-shell[data-active="builders"] .em-sound-dot { border-color: #2a2d31; }
}
#whiteout { position: fixed; inset: 0; pointer-events: none; opacity: 0; background: radial-gradient(ellipse at 50% 50%, #fffdf8 0%, #f1eee6 60%, #e2ded4 100%); }

/* The site-wide Frank chat bubble is injected by nginx on every page; the homepage opts out in nginx, and this rule keeps it
   hidden if the injection ever reaches the page. The reactor dial is Charles's presence here (orchestrator, 2026-10-14). */
.frank-chat-toggle, .frank-chat-panel { display: none !important; }
