/* ============================================================
   base.css — reset, fixed-frame stage, typography primitives
   ============================================================ */

*, *::before, *::after { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  overflow: hidden;                 /* a film does not scroll */
  background: var(--void);
  color: var(--mist-90);
  font-family: var(--font-body);
  font-size: var(--t-body);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

body { cursor: default; }
body.is-recording { cursor: none; }

img { display: block; max-width: 100%; }
button { font: inherit; color: inherit; }

::selection { background: var(--lime); color: var(--ink-deep); }

:focus-visible {
  outline: 2px solid var(--lime);
  outline-offset: 3px;
  border-radius: 4px;
}

/* ------------------------------------------------------------
   FIXED-FRAME STAGE
   Everything composes inside a 1920x1080 frame that is scaled
   to the viewport. Guarantees the recording matches the design
   at every resolution and aspect ratio.
   ------------------------------------------------------------ */

#viewport {
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  height: 100dvh;              /* mobile browser chrome */
  background: var(--void);
  overflow: hidden;
}

/* The frame is 1920x1080 and is scaled to the viewport by fitFrame().
   fitFrame() writes one explicit translate3d(x,y) + scale transform
   from a top-left origin. This avoids the stale 50% centring fault that
   can leave only half the film visible after a preview/window change. */
#frame {
  position: absolute;
  left: 0;
  top: 0;
  width: 1920px;
  height: 1080px;
  transform-origin: 0 0;
  transform: translate3d(0, 0, 0) scale(1);
  will-change: transform;
  perspective: 2200px;
  perspective-origin: 50% 46%;
}

/* Layers, back to front.
   NOTE: #camera MUST carry a z-index. It is position:absolute and it
   has a transform, so it creates its own stacking context — the
   z-index values on #scene-layer and #phone-layer are resolved INSIDE
   that context and can never lift them above a sibling of #camera.
   With z-index:auto here, the opaque .env-base gradient in
   #environment-layer (z-index:1) paints over the entire film and the
   result is a green screen with nothing on it. */
#environment-layer { position: absolute; inset: 0; z-index: 1; }
#camera            { position: absolute; inset: 0; z-index: 2; }
#foreground-layer  { position: absolute; inset: 0; z-index: 3; pointer-events: none; }
#chrome-layer      { position: absolute; inset: 0; z-index: 4; }

/* Inside the camera's stacking context */
#scene-layer       { position: absolute; inset: 0; z-index: 1; transform-style: preserve-3d; }
#phone-layer       { position: absolute; inset: 0; z-index: 2; pointer-events: none; transform-style: preserve-3d; }

/* The camera wraps the scene + phone layers so a single transform
   moves the whole world: this is what produces pans and pushes-in
   rather than each element animating on its own. */
#camera {
  transform-style: preserve-3d;
  will-change: transform, filter;
}

/* ------------------------------------------------------------
   TYPOGRAPHY PRIMITIVES
   ------------------------------------------------------------ */

.t-eyebrow {
  font-family: var(--font-utility);
  font-size: var(--t-eyebrow);
  font-weight: var(--w-med);
  letter-spacing: var(--track-eyebrow);
  text-transform: uppercase;
  color: var(--lime);
  margin: 0;
}
.t-eyebrow.is-gold { color: var(--gold); }

.t-mega {
  font-family: var(--font-display);
  font-size: var(--t-mega);
  font-weight: var(--w-semi);
  letter-spacing: var(--track-mega);
  line-height: 0.94;
  color: var(--white);
  margin: 0;
}

.t-hero {
  font-family: var(--font-display);
  font-size: var(--t-hero);
  font-weight: var(--w-semi);
  letter-spacing: var(--track-hero);
  line-height: 1.0;
  color: var(--white);
  margin: 0;
}

.t-title {
  font-family: var(--font-display);
  font-size: var(--t-title);
  font-weight: var(--w-semi);
  letter-spacing: var(--track-title);
  line-height: 1.06;
  color: var(--white);
  margin: 0;
}

.t-sub {
  font-family: var(--font-display);
  font-size: var(--t-sub);
  font-weight: var(--w-reg);
  letter-spacing: var(--track-sub);
  line-height: 1.28;
  color: var(--mist-70);
  margin: 0;
}

.t-lead {
  font-size: var(--t-lead);
  font-weight: var(--w-reg);
  line-height: 1.6;
  color: var(--mist-70);
  margin: 0;
  max-width: 46ch;
}

.t-caption {
  font-family: var(--font-utility);
  font-size: var(--t-caption);
  letter-spacing: 0.06em;
  color: var(--mist-34);
  margin: 0;
}

.t-thin { font-weight: var(--w-thin); }
.hl-lime { color: var(--lime); }
.hl-gold { color: var(--gold); }
.hl-cream { color: var(--cream); }

/* A word or line that reveals. The engine sets --rv from 0 → 1;
   CSS does the rest.

   NOTE: no `will-change` here, and no `filter` by default. This class
   lands on EVERY WORD of every heading — hundreds of elements. Giving
   each one a will-change promoted every word to its own composited
   layer, and a filter (even a 0px blur) forced a filter pass per word.
   Together they were the single largest cost in the film. Opacity and
   transform alone still run on the compositor and read the same. */
.reveal {
  display: inline-block;
  opacity: calc(var(--rv, 0));
  transform: translate3d(0, calc((1 - var(--rv, 0)) * 0.42em), 0)
             scale(calc(0.985 + var(--rv, 0) * 0.015));
}

/* The blur-in is kept where it actually reads — the big display
   lines, which are only a handful of words and only ever one
   chapter at a time. */
.t-mega .reveal,
.t-hero .reveal,
.lockup .reveal {
  filter: blur(calc((1 - var(--rv, 0)) * 9px));
}

.reveal-line { display: block; overflow: visible; }

/* Utility */
.stack   { display: flex; flex-direction: column; }
.gap-2   { gap: var(--s-2); }
.gap-3   { gap: var(--s-3); }
.gap-4   { gap: var(--s-4); }
.gap-5   { gap: var(--s-5); }
.gap-6   { gap: var(--s-6); }
.gap-7   { gap: var(--s-7); }
.hairline {
  height: 1px;
  background: linear-gradient(90deg,
    var(--lime) 0%, var(--ink-line) 38%, transparent 100%);
  transform-origin: left center;
  transform: scaleX(var(--rv, 0));
}


/* Reliability overrides: keep the film above the environment and fill the viewport. */
#camera { z-index: 20 !important; }
#scene-layer { z-index: 21 !important; }
#phone-layer { z-index: 22 !important; }
#foreground-layer { z-index: 23 !important; }
#chrome-layer { z-index: 30 !important; }
