/* ============================================================
   Keyframe — Landing
   A pen for visual storytellers.
   ============================================================ */

:root {
  --bg:          #0a0a0b;
  --bg-warm:     #0e0c0a;
  --bg-deep:     #050506;
  --ink:         #ece7dc;
  --ink-soft:    rgba(236, 231, 220, 0.72);
  --ink-mute:    rgba(236, 231, 220, 0.42);
  --ink-faint:   rgba(236, 231, 220, 0.16);
  --rule:        rgba(236, 231, 220, 0.10);
  --amber:       #e0b277;
  --amber-soft:  rgba(224, 178, 119, 0.18);
  --crimson:     #c96a5f;
  --sky:         #9ab8d6;
  --violet:      #b79bd4;

  --serif: "Instrument Serif", "Times New Roman", Georgia, serif;
  --mono:  "IBM Plex Mono", ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  --sans:  -apple-system, BlinkMacSystemFont, system-ui, "Helvetica Neue", sans-serif;

  --ease-out:  cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in:   cubic-bezier(0.7, 0, 0.84, 0);
  --ease-std:  cubic-bezier(0.6, 0.05, 0.2, 1);

  --dur-slow:  1200ms;
  --dur-med:   700ms;
  --dur-fast:  400ms;

  --container: min(92vw, 1100px);
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }

html {
  scroll-behavior: smooth;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-weight: 400;
  font-size: 17px;
  line-height: 1.55;
  letter-spacing: -0.005em;
  overflow-x: hidden;
  overscroll-behavior-y: none;
  min-height: 100vh;
}

/* Subtle color arc across the narrative */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(1200px 800px at 50% 110%, rgba(224, 178, 119, 0.08), transparent 60%),
    radial-gradient(900px 700px at 100% 0%, rgba(155, 184, 214, 0.04), transparent 60%);
  z-index: 0;
  transition: opacity 1200ms var(--ease-std);
}

/* ============================================================
   Cinematic overlays
   ============================================================ */

.grain {
  position: fixed;
  inset: -10%;
  z-index: 200;
  pointer-events: none;
  opacity: 0.06;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1  0 0 0 0 1  0 0 0 0 1  0 0 0 1 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
  animation: grain-shift 1.4s steps(6) infinite;
}

@keyframes grain-shift {
  0%   { transform: translate(0, 0); }
  20%  { transform: translate(-3%, 2%); }
  40%  { transform: translate(2%, -3%); }
  60%  { transform: translate(-2%, -2%); }
  80%  { transform: translate(3%, 2%); }
  100% { transform: translate(0, 0); }
}

.vignette {
  position: fixed;
  inset: 0;
  z-index: 150;
  pointer-events: none;
  background: radial-gradient(120% 100% at 50% 50%, transparent 55%, rgba(0,0,0,0.55) 100%);
}

/* ============================================================
   Side timeline — clickable scene dots
   ============================================================ */

.timeline {
  position: fixed;
  left: 28px;
  top: 50%;
  transform: translateY(-50%);
  z-index: 90;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
}

/* Persistent top-right Get Early Access CTA */
.nav-cta {
  position: fixed;
  top: 22px;
  right: 26px;
  z-index: 95;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 10px 18px 10px 12px;
  background: rgba(10, 10, 11, 0.55);
  color: var(--ink);
  border: 1px solid rgba(236, 231, 220, 0.22);
  border-radius: 999px;
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  cursor: pointer;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  transition: background 220ms var(--ease-std),
              border-color 220ms var(--ease-std),
              transform 220ms var(--ease-out);
}

.nav-cta-icon {
  width: 22px;
  height: 22px;
  object-fit: contain;
  display: block;
}

.nav-cta:hover {
  background: rgba(20, 20, 22, 0.75);
  border-color: rgba(236, 231, 220, 0.45);
  transform: translateY(-1px);
}

.nav-cta:active {
  transform: translateY(0);
}

@media (max-width: 600px) {
  .nav-cta {
    top: 12px;
    right: 12px;
    padding: 8px 14px 8px 10px;
    font-size: 10px;
    letter-spacing: 0.1em;
    gap: 8px;
  }
  .nav-cta-icon { width: 18px; height: 18px; }
}

.timeline-dot {
  width: 7px;
  height: 7px;
  padding: 0;
  margin: 0;
  border: 1px solid rgba(236, 231, 220, 0.22);
  background: transparent;
  border-radius: 1.5px;
  cursor: pointer;
  outline: 0;
  transition:
    background 420ms var(--ease-std),
    border-color 420ms var(--ease-std),
    transform 420ms var(--ease-out);
}

.timeline-dot::before {
  /* larger invisible hit area */
  content: "";
  display: block;
  width: 22px;
  height: 22px;
  margin: -8px 0 0 -8px;
}

.timeline-dot:hover {
  border-color: var(--ink-soft);
}

.timeline-dot.is-past {
  background: rgba(236, 231, 220, 0.22);
  border-color: rgba(236, 231, 220, 0.22);
}

.timeline-dot.is-current {
  background: var(--ink);
  border-color: var(--ink);
  transform: scale(1.35);
  box-shadow: 0 0 0 4px rgba(236, 231, 220, 0.08);
}

.timeline-dot.is-current:hover {
  border-color: var(--ink);
}

/* ============================================================
   Scenes
   ============================================================ */

main#film {
  position: relative;
  z-index: 1;
}

.scene {
  position: relative;
  min-height: 100vh;
  padding: 12vh 6vw;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  isolation: isolate;
}

.scene + .scene {
  border-top: 1px solid transparent;
}

.inner {
  width: var(--container);
  margin: 0 auto;
  max-width: 100%;
}

.inner.stack-wide > * + * { margin-top: 0.4em; }

/* Serif italic helper */
.serif-italic {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  letter-spacing: -0.01em;
}

/* ============================================================
   Typography — narrative lines
   ============================================================ */

.line {
  font-family: var(--serif);
  font-weight: 400;
  color: var(--ink);
  line-height: 1.15;
  letter-spacing: -0.015em;
  margin: 0;
}

.line.l-lg  { font-size: clamp(34px, 5.6vw, 72px); }
.line.l-xl  { font-size: clamp(38px, 6vw, 80px); }

.hero-line {
  font-family: var(--serif);
  font-size: clamp(34px, 5.5vw, 80px);
  line-height: 1.02;
  letter-spacing: -0.025em;
  margin: 0;
  color: var(--ink);
}

/* ============================================================
   Inline aside — muted phrase within a larger line
   ============================================================ */

.aside {
  color: var(--ink-mute);
}

/* ============================================================
   Scene — Prologue (with Macintosh)
   ============================================================ */

.scene--prologue .prologue-grid {
  display: grid;
  grid-template-columns: 1fr;
  justify-items: center;
  text-align: center;
  gap: clamp(16px, 2.5vh, 32px);
}

.prologue-top { order: 1; }
.mac-frame    { order: 2; }
.prologue-bottom { order: 3; }

.prologue-bottom .serif-italic {
  color: var(--ink-soft);
}

.mac-frame {
  margin: 0;
  width: 100%;
  max-width: 340px;
  justify-self: center;
  animation: mac-drift 6s ease-in-out infinite alternate;
  will-change: transform;
}

.mac-container {
  position: relative;
  display: block;
}

.mac-svg {
  display: block;
  width: 100%;
  height: auto;
  filter: drop-shadow(0 24px 40px rgba(0,0,0,0.55));
}

#matrix-rain,
.mac-scanlines {
  position: absolute;
  left: 26.30%;
  top: 12.51%;
  width: 42.44%;
  height: 30.75%;
  border-radius: 2.6% / 2.6%;
  overflow: hidden;
}

#matrix-rain {
  image-rendering: pixelated;
}

.mac-scanlines {
  pointer-events: none;
}

@keyframes mac-drift {
  0%   { transform: translateY(-3px) rotate(-0.15deg); }
  100% { transform: translateY(3px)  rotate(0.15deg); }
}

@media (max-width: 820px) {
  .mac-frame { max-width: 240px; }
}

@media (prefers-reduced-motion: reduce) {
  .mac-frame { animation: none !important; }
  #matrix-rain { display: none; }
}

/* ============================================================
   Scene 4 — Highlights
   ============================================================ */

.hl {
  position: relative;
  display: inline-block;
  font-family: var(--serif);
  font-style: italic;
  transition: color 900ms var(--ease-std);
}

.hl::before {
  content: "";
  position: absolute;
  left: -6px;
  right: -6px;
  bottom: -4px;
  height: 10px;
  border-radius: 2px;
  opacity: 0;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 700ms var(--ease-out), opacity 700ms var(--ease-std);
  z-index: -1;
}

.reveal-words.is-in .hl::before,
.rot.is-active .hl::before { opacity: 0.32; transform: scaleX(1); }

.hl-revolution { color: var(--crimson); }
.hl-revolution::before { background: var(--crimson); }

.hl-brand { color: var(--sky); }
.hl-brand::before { background: var(--sky); }

.hl-fly { color: var(--amber); }
.hl-fly::before { background: var(--amber); }

/* ============================================================
   Scene — "A story can" pinned rotator
   ============================================================ */

.scene--story-can {
  display: block;
  min-height: 320vh;
  padding: 0;
  align-items: stretch;
  overflow: clip;
}

.story-can-sticky {
  position: sticky;
  top: 0;
  width: 100%;
  height: 100vh;
  display: flex;
  align-items: center;
  padding: 0 6vw;
  overflow: clip;
  background: var(--bg);
}

/* Left-side scrim keeps the text crisp against the scene backdrop */
.story-can-sticky::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(90deg,
    rgba(10, 10, 11, 0.72) 0%,
    rgba(10, 10, 11, 0.4)  34%,
    rgba(10, 10, 11, 0)    68%);
}

.story-can-inner {
  position: relative;
  z-index: 2;
  width: var(--container);
  margin: 0 auto;
  max-width: 100%;
}

.story-can-inner .story-can-anchor,
.story-can-inner .story-can-rotator .rot {
  text-shadow: 0 2px 30px rgba(0, 0, 0, 0.55), 0 0 10px rgba(0, 0, 0, 0.4);
}

/* ============================================================
   Word-as-world scenes (behind "A story can ..." text)
   --
   Two custom properties drive everything, set by JS each frame:
     --scene-alpha : opacity 0..1 for this scene (crossfades cleanly)
     --local-p     : 0..1 progress as user scrolls through this scene
     --enter-p     : 0..1 progress clamped to first half of the scene
                     (used to scrub "entrance" motions so they settle
                     while the text phrase is still active)
   Idle loops (smoke, fire, embers, clouds) run only after the scene
   has been entered once (.has-entered) and never replay.
   ============================================================ */

.story-scenes {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}

.story-scene {
  position: absolute;
  inset: 0;
  opacity: var(--scene-alpha, 0);
  will-change: opacity;
}

.story-scene .scene-svg {
  width: 100%;
  height: 100%;
  display: block;
}

/* ---- Revolution ---------------------------------------------- */

/* statics — visible as soon as scene is opaque */
.rev-glow  { opacity: 0.9; }
.rev-smoke { opacity: 0.32; }
.rev-fire  { opacity: 0.7; }

/* idle loops (once has-entered, forever) */
.story-scene--revolution.has-entered .rev-fire {
  animation: rev-fire-flicker 4.2s ease-in-out infinite alternate;
}
.story-scene--revolution.has-entered .rev-smoke {
  animation: rev-smoke-drift 14s ease-in-out infinite alternate;
}
.story-scene--revolution.has-entered .rev-embers .rev-ember {
  animation: rev-ember-float 3.8s ease-out infinite;
  animation-delay: calc(var(--i) * 0.42s);
}

@keyframes rev-fire-flicker {
  0%   { opacity: 0.55; }
  40%  { opacity: 0.9;  }
  60%  { opacity: 0.6;  }
  100% { opacity: 0.82; }
}
@keyframes rev-smoke-drift {
  from { transform: translate(-20px, 4px); }
  to   { transform: translate(20px, -6px); }
}
@keyframes rev-ember-float {
  0%   { opacity: 0; transform: translate(0, 0); }
  18%  { opacity: 1; }
  100% { opacity: 0; transform: translate(0, -220px); }
}

/* Torch flames flare — subtle scale + flicker */
.story-scene--revolution.has-entered .rev-flame {
  animation: rev-flame-flare 0.7s ease-in-out infinite alternate;
  transform-box: fill-box;
  transform-origin: center bottom;
}
@keyframes rev-flame-flare {
  0%   { transform: scaleX(0.82) scaleY(0.88); opacity: 0.85; }
  50%  { transform: scaleX(1.18) scaleY(1.08); opacity: 1; }
  100% { transform: scaleX(0.92) scaleY(1.12); opacity: 0.9; }
}

/* scrubbed crowd rise — each figure has its own window */
.rev-fig {
  --start: calc(var(--i, 0) * 0.045);
  --stage: clamp(0, calc((var(--enter-p, 0) - var(--start)) / 0.22), 1);
  opacity: var(--stage);
  transform: translateY(calc((1 - var(--stage)) * 60px));
  will-change: transform, opacity;
}

/* scrubbed banner drop */
.rev-banner {
  --stage: clamp(0, calc((var(--enter-p, 0) - 0.18) / 0.34), 1);
  opacity: var(--stage);
  transform: translateY(calc((1 - var(--stage)) * -140px))
             rotate(calc((1 - var(--stage)) * -1.2deg));
  transform-origin: 310px 0;
}

/* banner slogan marks reveal as banner settles */
.rev-banner-marks rect {
  --mark-stage: clamp(0, calc((var(--enter-p, 0) - 0.55) / 0.3), 1);
  opacity: calc(var(--mark-stage) * 0.95);
  transform: scaleX(var(--mark-stage));
  transform-origin: left;
}

/* embers — hidden until has-entered (loop handles opacity) */
.rev-embers .rev-ember { opacity: 0; }

/* ---- Brand — Newton under the tree (B&W + one red apple) ---- */

/* Scrubbed scene build-up (ground → tree → Newton → apple) */
.nw-ground {
  --stage: clamp(0, calc(var(--enter-p, 0) * 2.8), 1);
  opacity: var(--stage);
}
.nw-tree {
  --stage: clamp(0, calc((var(--enter-p, 0) - 0.05) * 2.4), 1);
  opacity: var(--stage);
  transform: translateY(calc((1 - var(--stage)) * 20px));
  transform-box: fill-box;
  transform-origin: 964px 680px;
}
.nw-newton-wrap {
  --stage: clamp(0, calc((var(--enter-p, 0) - 0.16) * 2.8), 1);
  opacity: var(--stage);
  transform: translateY(calc((1 - var(--stage)) * 24px));
}

/* Foliage rustles gently — idle loop after entry */
.story-scene--brand.has-entered .nw-foliage {
  animation: nw-rustle 5.4s ease-in-out infinite alternate;
  transform-box: fill-box;
  transform-origin: 970px 450px;
}
@keyframes nw-rustle {
  from { transform: rotate(-0.5deg); }
  to   { transform: rotate(0.6deg);  }
}

/* Newton's head jolts on impact, then settles */
.nw-head {
  --jolt:    clamp(0, calc((var(--local-p, 0) - 0.39) * 30), 1);
  --recover: clamp(0, calc((var(--local-p, 0) - 0.43) * 14), 1);
  transform: translateY(calc((var(--jolt) - var(--recover)) * 5px));
  transform-box: fill-box;
  transform-origin: center;
}

/* -- The single red apple: in tree → fall → settle → roll -- */
/* Newton head is at global (918, 572). Apple starts at (960, 250). */
.nw-apple {
  --fall-t:   clamp(0, calc((var(--local-p, 0) - 0.25) / 0.15), 1);
  --settle-t: clamp(0, calc((var(--local-p, 0) - 0.46) / 0.10), 1);
  --roll-t:   clamp(0, calc((var(--local-p, 0) - 0.58) / 0.37), 1);

  opacity: clamp(0, calc((var(--enter-p, 0) - 0.08) * 2.4), 1);

  transform:
    translate(960px, 250px)
    translate(
      calc(var(--fall-t) * -42px + var(--settle-t) * -28px + var(--roll-t) * -690px),
      calc(var(--fall-t) * var(--fall-t) * 322px + var(--settle-t) * 108px)
    );
  will-change: transform;
}

/* Apple spins while rolling */
.nw-apple-spin {
  transform: rotate(calc(var(--roll-t, 0) * -3500deg));
  transform-box: fill-box;
  transform-origin: center;
}

/* ---- Fly ----------------------------------------------------- */

.fly-sky {
  opacity: clamp(0, calc(var(--enter-p, 0) * 1.5), 1);
}
.fly-sun {
  opacity: clamp(0, calc((var(--enter-p, 0) - 0.05) * 1.8), 0.9);
}
.fly-clouds {
  opacity: clamp(0, calc((var(--enter-p, 0) - 0.1) * 5), 0.28);
}
.fly-child {
  opacity: clamp(0, calc((var(--enter-p, 0) - 0.2) * 3), 1);
}

.fly-cloud {
  transform-box: fill-box;
  transform-origin: center;
}
.story-scene--fly.has-entered .fly-cloud {
  animation: fly-cloud-drift 32s linear infinite;
  animation-delay: calc(var(--i) * -8s);
}
@keyframes fly-cloud-drift {
  from { transform: translateX(-60px); }
  to   { transform: translateX(60px); }
}

/* paper airplane — flies along the path as user scrolls the whole scene */
.fly-plane {
  offset-path: path("M 240 700 C 340 540, 460 700, 600 480 C 720 300, 900 440, 1030 210");
  offset-rotate: auto;
  offset-distance: calc(var(--local-p, 0) * 100%);
  opacity: clamp(0, calc(var(--local-p, 0) * 12), 1);
  will-change: offset-distance, opacity;
}

/* trail stroke-draws in sync with plane */
.fly-trail {
  stroke-dasharray: 1400;
  stroke-dashoffset: calc(1400px * (1 - var(--local-p, 0)));
  opacity: clamp(0, calc(var(--local-p, 0) * 10), 0.75);
}

.story-can-anchor {
  color: var(--ink-mute);
  margin: 0 0 0.08em 0;
}

.story-can-rotator {
  position: relative;
  min-height: 2.6em;
  margin: 0;
}

.story-can-rotator .rot {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  margin: 0;
  opacity: 0;
  transform: translateY(18px);
  transition:
    opacity 650ms var(--ease-out),
    transform 650ms var(--ease-out);
  pointer-events: none;
}

.story-can-rotator .rot.is-active {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}

.story-can-rotator .rot.is-past {
  opacity: 0;
  transform: translateY(-18px);
}

.story-can-progress {
  display: flex;
  gap: 10px;
  margin-top: clamp(36px, 6vh, 72px);
}

.sp-tick {
  display: block;
  width: 22px;
  height: 2px;
  border-radius: 1px;
  background: var(--ink-faint);
  transition:
    background 500ms var(--ease-std),
    width 500ms var(--ease-out);
}

.sp-tick.is-past    { background: var(--ink-mute); }
.sp-tick.is-active  { background: var(--ink); width: 44px; }

@media (max-width: 820px) {
  .scene--story-can { min-height: 240vh; }

  /* Text needs to fit narrow screens — scale down and give the rotator room to wrap */
  .story-can-anchor { font-size: clamp(24px, 6.5vw, 34px); }
  .story-can-rotator { min-height: 5em; }
  .story-can-rotator .rot { font-size: clamp(24px, 6.5vw, 34px); }

  /* Vertical scrim — lighter center so cropped scenes show through */
  .story-can-sticky::before {
    background:
      linear-gradient(180deg,
        rgba(10, 10, 11, 0.78) 0%,
        rgba(10, 10, 11, 0.35) 30%,
        rgba(10, 10, 11, 0.18) 55%,
        rgba(10, 10, 11, 0.78) 100%);
  }

  /* Scenes can be brighter on mobile since the tighter viewBox
     already keeps key elements in frame */
  .story-scene { opacity: calc(var(--scene-alpha, 0) * 0.85); }
  .rev-embers { display: none; }
  .fly-clouds { opacity: calc(clamp(0, calc((var(--enter-p, 0) - 0.1) * 5), 0.28) * 0.7); }
}

@media (max-width: 500px) {
  .story-can-anchor { font-size: clamp(20px, 6vw, 28px); }
  .story-can-rotator .rot { font-size: clamp(20px, 6vw, 28px); }
  .story-can-rotator { min-height: 6em; }

  .rev-banner { transform-origin: center; }
  .fly-child  { display: none; }
  .rev-smoke  { opacity: 0.18; }
  .nw-grass   { display: none; }
}

/* ============================================================
   Scene 5 — Cameras morphing through history (pinned, scroll-scrubbed)
   ============================================================ */

.scene--cameras {
  display: block;
  min-height: 260vh;
  padding: 0;
  align-items: stretch;
  overflow: clip;
}

.cameras-sticky {
  position: sticky;
  top: 0;
  height: 100vh;
  display: flex;
  align-items: center;
  padding: 0 6vw;
}

.cameras-grid {
  width: var(--container);
  margin: 0 auto;
  max-width: 100%;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(24px, 6vw, 80px);
  align-items: center;
}

/* Left: morphing camera */
.cam-morph {
  position: relative;
  width: 100%;
  aspect-ratio: 1;
  max-width: 520px;
  margin: 0 auto;
}
.cam-morph svg {
  width: 100%;
  height: 100%;
  display: block;
}

.cam-stage {
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
  will-change: opacity;
}

/* Stage windows — scrubbed crossfades as --local-p progresses 0→1 */
.cam-stage--1 {
  opacity: clamp(0, calc((0.32 - var(--local-p, 0)) * 10), 1);
}
.cam-stage--2 {
  opacity: min(
    clamp(0, calc((var(--local-p, 0) - 0.18) * 10), 1),
    clamp(0, calc((0.56 - var(--local-p, 0)) * 10), 1)
  );
}
.cam-stage--3 {
  opacity: min(
    clamp(0, calc((var(--local-p, 0) - 0.46) * 10), 1),
    clamp(0, calc((0.80 - var(--local-p, 0)) * 10), 1)
  );
}
.cam-stage--4 {
  opacity: clamp(0, calc((var(--local-p, 0) - 0.68) * 10), 1);
}

/* Right: stacked words, one per line */
.cam-text {
  display: flex;
  flex-direction: column;
  gap: 0.05em;
}

.cam-word {
  font-family: var(--serif);
  font-weight: 400;
  color: var(--ink);
  font-size: clamp(44px, 7.2vw, 104px);
  line-height: 1.0;
  letter-spacing: -0.025em;
  margin: 0;

  --stage: clamp(0, calc((var(--local-p, 0) - var(--threshold, 0)) * 10), 1);
  opacity: var(--stage);
  transform: translateY(calc((1 - var(--stage)) * 28px));
  will-change: opacity, transform;
}

/* "smaller" and "cheaper" get a serif-italic treatment for emphasis */
.cam-word:nth-child(4),
.cam-word:nth-child(6) {
  font-style: italic;
}

/* ============================================================
   Scene 6 — The Ledger ("But you still need —")
   Sticky, scroll-scrubbed. Rows fill in, a hand-drawn rule
   draws itself, the sum lands, and then the italic "big"
   grows — amber shifting to crimson — until it fills the viewport.
   ============================================================ */

.scene--ledger {
  display: block;
  min-height: 240vh;
  padding: 0;
  align-items: stretch;
  overflow: clip;
}

.ledger-sticky {
  position: sticky;
  top: 0;
  height: 100vh;
  display: flex;
  align-items: center;
  padding: 0 6vw;
  /* Grow-stage drives the whole "big gets huge" moment.
     0 at local-p 0.55, 1 at local-p 0.92. */
  --grow-stage: clamp(0, calc((var(--local-p, 0) - 0.55) * 2.7), 1);
}

/* Atmospheric backing — a crimson-warm swell that grows with "big" */
.ledger-sticky::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background:
    radial-gradient(75% 65% at 50% 55%, rgba(201, 106, 95, calc(var(--grow-stage, 0) * 0.12)), transparent 70%),
    radial-gradient(100% 80% at 50% 50%, rgba(224, 178, 119, calc(var(--grow-stage, 0) * 0.05)), transparent 80%);
  transition: none;
}

.ledger-inner {
  position: relative;
  z-index: 1;
  width: var(--container);
  margin: 0 auto;
  max-width: 100%;
}

.ledger-prompt {
  margin: 0 0 clamp(28px, 4.5vh, 56px) 0;
}

/* ---- Ledger grid ------------------------------------------- */

.ledger {
  position: relative;
  max-width: 760px;
  display: grid;
  grid-template-columns: clamp(28px, 3vw, 44px) auto minmax(clamp(30px, 6vw, 80px), 1fr) auto;
  column-gap: clamp(14px, 1.8vw, 28px);
  row-gap: clamp(10px, 1.4vh, 18px);
  align-items: baseline;
  /* Subtle paper-warm underlay */
  background:
    radial-gradient(120% 100% at 50% 50%, rgba(224, 178, 119, 0.035), transparent 70%);
  padding: clamp(14px, 2vh, 22px) 0;
}

.ledger-row {
  display: grid;
  grid-template-columns: subgrid;
  grid-column: 1 / -1;
  align-items: baseline;
  position: relative;
  padding: clamp(4px, 0.6vh, 8px) 0;
}

/* Scrubbed per-row entrance — every direct child reveals together. */
.ledger-row > * {
  --stage: clamp(0, calc((var(--local-p, 0) - var(--threshold, 0)) * 14), 1);
  opacity: var(--stage);
  transform: translateY(calc((1 - var(--stage)) * 12px));
  will-change: opacity, transform;
}

/* Numeral — small mono, subtly tracked */
.led-num {
  font-family: var(--mono);
  font-size: clamp(11px, 0.95vw, 13px);
  letter-spacing: 0.08em;
  color: var(--ink-mute);
  font-variant-numeric: tabular-nums;
  text-transform: lowercase;
  align-self: center;
  padding-top: 0.3em;
  justify-self: start;
}

.led-num--sum {
  font-size: clamp(14px, 1.2vw, 16px);
  color: var(--ink-soft);
  letter-spacing: 0;
  text-transform: none;
  padding-top: 0.1em;
}

/* Label — serif body */
.led-label {
  font-family: var(--serif);
  font-size: clamp(30px, 4.6vw, 56px);
  line-height: 1.05;
  color: var(--ink);
  letter-spacing: -0.015em;
  white-space: nowrap;
}

.led-label--sum {
  font-family: var(--mono);
  font-size: clamp(11px, 0.95vw, 13px);
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--ink-mute);
  align-self: center;
  padding-top: 0.3em;
  font-weight: 500;
}

/* Dotted leader — fills the horizontal gap, lines up with the
   type baseline. Wipes in left-to-right with --stage. */
.led-leader {
  height: 3px;
  align-self: center;
  background-image: radial-gradient(circle, rgba(236, 231, 220, 0.45) 0.9px, transparent 1.2px);
  background-size: 10px 3px;
  background-repeat: repeat-x;
  background-position: left center;
  margin: 0 clamp(10px, 1.2vw, 18px);
  transform: translateY(0.15em);
  -webkit-mask-image: linear-gradient(90deg, #000 0%, #000 calc(var(--stage, 0) * 100%), transparent calc(var(--stage, 0) * 100%));
          mask-image: linear-gradient(90deg, #000 0%, #000 calc(var(--stage, 0) * 100%), transparent calc(var(--stage, 0) * 100%));
}

.led-leader--sum {
  background-image: radial-gradient(circle, rgba(236, 231, 220, 0.3) 0.9px, transparent 1.2px);
}

/* Value column — $$$ in mono amber, each $ tumbles in with stagger.
   Override the row-level transform because each glyph animates on its own. */
.led-val {
  font-family: var(--mono);
  font-size: clamp(24px, 3vw, 34px);
  letter-spacing: 0.08em;
  color: var(--amber);
  font-variant-numeric: tabular-nums;
  display: inline-flex;
  align-self: center;
  line-height: 1;
  justify-self: end;
}
.ledger-row--item > .led-val {
  opacity: 1 !important;
  transform: none !important;
}

.led-d {
  display: inline-block;
  --d-stage: clamp(0, calc((var(--local-p, 0) - var(--threshold, 0) - var(--d, 0) * 0.028) * 16), 1);
  opacity: var(--d-stage);
  transform:
    translateY(calc((1 - var(--d-stage)) * -14px))
    rotate(calc((1 - var(--d-stage)) * -10deg));
  transform-origin: 50% 100%;
  text-shadow: 0 0 20px rgba(224, 178, 119, calc(var(--d-stage) * 0.35));
  will-change: opacity, transform;
}

/* Sum row — the payoff */
.led-val--sum {
  font-family: var(--serif);
  font-size: clamp(30px, 4.6vw, 56px);
  color: var(--ink);
  letter-spacing: -0.015em;
  text-transform: none;
  line-height: 1.05;
  justify-self: end;
  white-space: nowrap;
}

/* ---- Hand-drawn rule -------------------------------------- */

.ledger-rule {
  grid-column: 1 / -1;
  height: 10px;
  margin: clamp(8px, 1.4vh, 18px) 0 clamp(10px, 1.6vh, 22px);
  color: var(--ink-mute);
  --rule-stage: clamp(0, calc((var(--local-p, 0) - var(--threshold, 0)) * 14), 1);
  opacity: var(--rule-stage);
}

.ledger-rule svg {
  width: 100%;
  height: 100%;
  display: block;
  overflow: visible;
}

.ledger-rule-path {
  stroke-dasharray: 1200;
  stroke-dashoffset: calc(1200 * (1 - clamp(0, calc((var(--local-p, 0) - var(--threshold, 0)) * 5), 1)));
}

/* ---- The Big Budget grows ---------------------------------- */
/* After the sum lands (local-p ≥ 0.55), the italic "big" scales up
   to fill the viewport, color-shifting amber → crimson. The rest
   of the ledger dims so "big" becomes the only thing on screen.
   --grow-stage is defined on .ledger-sticky above; inherits here. */

/* Line items, numerals, leader dots, and rule recede as big grows */
.ledger-row--item {
  /* Multiplies with the per-child --stage opacity, dimming the row as big grows */
  opacity: calc(1 - var(--grow-stage, 0) * 0.88);
  will-change: opacity;
}
.ledger-rule {
  /* Rule-stage × grow-fade */
  opacity: calc(var(--rule-stage, 0) * (1 - var(--grow-stage, 0) * 0.95));
}
.ledger-row--sum .led-num,
.ledger-row--sum .led-label,
.ledger-row--sum .led-leader {
  opacity: calc(var(--stage, 0) * (1 - var(--grow-stage, 0) * 0.95));
}

/* The "a" and "budget." words fade as "big" takes over */
.led-big {
  display: inline-flex;
  align-items: baseline;
  white-space: nowrap;
  /* Give "big" its own stacking context so the glow layers sit above neighbours */
  position: relative;
}
.led-big-a,
.led-big-after {
  display: inline-block;
  opacity: calc(1 - var(--grow-stage, 0) * 0.92);
  transition: none;
  will-change: opacity;
}
.led-big-sp {
  display: inline-block;
  width: 0.25em;
  /* Space also collapses as big grows, so "budget." slides in toward the action */
  flex: 0 0 auto;
}

/* The main event — "big" grows dramatically */
.led-big-em {
  display: inline-block;
  position: relative;
  transform-origin: 50% 58%;
  color: var(--amber);
  /* Landing stage for the initial sum-row entrance */
  --big-stage: clamp(0, calc((var(--local-p, 0) - var(--threshold, 0) - 0.03) * 14), 1);
  /* Landing bounce + exponential growth (1× → 8×) + drift toward
     viewport center since "big" starts right-justified in the sum row */
  transform:
    translate(
      calc(var(--grow-stage, 0) * -12vw),
      calc((1 - var(--big-stage)) * 8px + var(--grow-stage, 0) * -8vh)
    )
    scale(calc(
      (0.88 + var(--big-stage) * 0.12)
      + var(--grow-stage, 0) * 7
    ));
  /* Display-weight letter-spacing for scale */
  letter-spacing: calc(-0.02em - var(--grow-stage, 0) * 0.05em);
  /* Amber + crimson glow intensifies */
  text-shadow:
    0 0 calc(12px + var(--grow-stage, 0) * 72px)  rgba(224, 178, 119, calc(0.15 + var(--grow-stage, 0) * 0.28)),
    0 0 calc(4px  + var(--grow-stage, 0) * 44px)  rgba(201, 106, 95,  calc(var(--grow-stage, 0) * 0.45));
  will-change: transform, color, letter-spacing;
  z-index: 5;
}

/* Color ramp amber → crimson via color-mix (supported in all modern browsers) */
@supports (color: color-mix(in oklch, red, blue)) {
  .led-big-em {
    color: color-mix(in oklch, var(--amber), var(--crimson) calc(var(--grow-stage, 0) * 60%));
  }
}


/* ============================================================
   Scene 8 — The Notebook ("easy as writing")
   A cream paper page with ruled lines and a red margin sits on
   the dark stage. Lines 1–2 read in serif like print; the final
   word "writing" appears in cursive as an animated fountain pen
   travels left-to-right, inking it in.
   ============================================================ */

.scene--writing {
  /* Default dark scene background; the notebook is the focal object. */
  overflow: clip;
}

/* ---- The notebook figure ---------------------------------- */

.notebook {
  margin: 0 auto;
  width: min(94vw, 940px);
  max-width: 100%;
  position: relative;
  /* Slight counter-clockwise tilt — a page placed, not typeset */
  transform: rotate(-0.6deg);
  transform-origin: 50% 50%;
  isolation: isolate;
}

/* Floor-shadow pad beneath the page */
.notebook-shadow {
  position: absolute;
  inset: auto -2% -3% -2%;
  height: 40px;
  background:
    radial-gradient(60% 100% at 50% 0%, rgba(0, 0, 0, 0.55), transparent 70%);
  filter: blur(14px);
  z-index: 0;
  pointer-events: none;
}

.notebook-page {
  --paper:        #efe3c9;
  --paper-edge:   #d9c99f;
  --ink:          #2c231a;
  --ink-soft:     rgba(44, 35, 26, 0.68);
  --ink-red:      rgba(196, 86, 82, 0.58);
  --rule:         rgba(120, 140, 168, 0.26);
  --rule-spacing: clamp(62px, 8.2vh, 84px);
  --margin-x:     clamp(68px, 9vw, 108px);

  position: relative;
  z-index: 1;
  background-color: var(--paper);
  padding:
    clamp(70px, 9vh, 110px)
    clamp(44px, 5.4vw, 72px)
    clamp(70px, 9vh, 110px)
    calc(var(--margin-x) + clamp(20px, 2.4vw, 36px));
  box-shadow:
    /* Inner lightness so paper feels slightly lifted */
    inset 0 1px 0 rgba(255, 255, 255, 0.5),
    /* Edge bevel */
    inset 0 0 0 1px rgba(0, 0, 0, 0.06),
    /* Cast shadow */
    0 1px 0 rgba(0, 0, 0, 0.1),
    0 36px 60px -20px rgba(0, 0, 0, 0.55),
    0 14px 32px -12px rgba(0, 0, 0, 0.35);
  /* Horizontal rules + red margin baked into the background */
  background-image:
    /* Red margin line (slight pink, like a pencil line) */
    linear-gradient(
      to right,
      transparent calc(var(--margin-x) - 1.2px),
      var(--ink-red) calc(var(--margin-x) - 1.2px) calc(var(--margin-x) + 0.4px),
      transparent calc(var(--margin-x) + 0.4px)
    ),
    /* Horizontal ruled lines */
    repeating-linear-gradient(
      to bottom,
      transparent 0 calc(var(--rule-spacing) - 1px),
      var(--rule) calc(var(--rule-spacing) - 1px) var(--rule-spacing)
    );
  background-repeat: no-repeat, repeat;
  /* Offset rules so text baselines sit on them (tuned empirically) */
  background-position: 0 0, 0 calc(var(--rule-spacing) * 0.72);
  /* Top-edge paper cream → slightly darker at bottom for subtle vignette */
  background-attachment: local, local;
}

/* Subtle paper grain — SVG noise via mask-image */
.notebook-grain {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0.2  0 0 0 0 0.14  0 0 0 0 0.08  0 0 0 0.55 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
  opacity: 0.08;
  mix-blend-mode: multiply;
  z-index: 2;
}

/* ---- Text on the page ------------------------------------- */

.nb-line {
  font-family: var(--serif);
  font-weight: 400;
  color: var(--ink);
  font-size: clamp(30px, 3.6vw, 48px);
  line-height: var(--rule-spacing);
  letter-spacing: -0.005em;
  margin: 0;
  position: relative;
  z-index: 3;
}

/* Line 3 — contains the handwritten word */
.nb-line--writing {
  /* Caveat sits taller than serif — align baselines */
  font-size: clamp(32px, 3.8vw, 52px);
}

.wl-prefix {
  font-family: var(--serif);
  color: var(--ink);
}

.wl-space { white-space: pre; }

/* Wrapper for the handwritten word — needed for absolute pen overlay.
   --wl-w is set by JS after fonts load (actual pixel width of the word).
   white-space: nowrap keeps the cursive word and its period on one line. */
.wl-word {
  position: relative;
  display: inline-block;
  /* Both children (text + period) are in Caveat — shift the wrapper down
     slightly so they sit on the same rule as the surrounding serif. */
  vertical-align: -0.08em;
  white-space: nowrap;
  /* JS fills this in with the real pixel width once fonts have loaded.
     Fallback width is a reasonable guess for "writing" at ~65px Caveat. */
  --wl-w: 240px;
}

/* The actual cursive text — hidden via clip-path, revealed by pen's travel */
.wl-text {
  font-family: "Caveat", cursive;
  font-weight: 700;
  color: var(--ink);
  font-size: 1.32em; /* bump up since Caveat reads smaller x-height */
  letter-spacing: 0.005em;
  display: inline-block;
  /* Subtle ink depth — tiny shadow gives the cursive a fountain-pen feel */
  text-shadow:
    0 0.5px 0 rgba(44, 35, 26, 0.18),
    0.2px 0 0 rgba(44, 35, 26, 0.12);
  /* Start fully hidden; pen will reveal left-to-right */
  clip-path: inset(-20% 100% -20% 0);
  -webkit-clip-path: inset(-20% 100% -20% 0);
}

/* Period that punctuates the handwritten word — pops in after writing */
.wl-period {
  font-family: "Caveat", cursive;
  font-weight: 700;
  color: var(--ink);
  font-size: 1.32em;
  opacity: 0;
  transform: scale(0.4);
  transform-origin: 30% 80%;
  display: inline-block;
  transition:
    opacity 220ms var(--ease-out),
    transform 280ms cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* ---- The persistent pen ---------------------------------- */
/* The pen element lives outside every scene (in .persistent-pen at the
   end of <main>), fixed to the viewport. JS drives its transform every
   frame: writing in the notebook, then flying between scene-anchors as
   the user scrolls. Rotation pivots around the nib tip so the tip stays
   put when the pen tilts. */

.persistent-pen {
  position: fixed;
  top: 0;
  left: 0;
  /* Sized 3× larger than visual so the browser rasterizes at high-res.
     JS divides all scale values by 3 to compensate. */
  width: clamp(168px, 16.8vw, 228px);
  height: clamp(168px, 16.8vw, 228px);
  pointer-events: none;
  z-index: 120; /* above scenes, below grain/vignette overlays */
  will-change: transform, opacity;
  /* Nib tip is at (20%, 89%) of the sprite; rotation pivots there so
     the tip stays planted when the pen tilts — the weighting trick. */
  transform-origin: 20% 89%;
  /* Initial — offscreen until JS moves it */
  transform: translate(-200px, -200px) rotate(0deg);
  opacity: 0;
  /* Opacity fade smooths the initial appear; the rest is JS per-frame. */
  transition: opacity 320ms var(--ease-std);
}

.wl-pen {
  display: block;
  width: 100%;
  height: 100%;
  filter: drop-shadow(0 3px 4px rgba(28, 18, 10, 0.35));
}

/* Text reveal — wipe the clip-path from full-hidden to full-revealed.
   Synced in duration to PenController's writing-travel phase (1100ms)
   and in delay to its 450+380=830ms entry wait. */
.nb-line--writing.is-in .wl-text {
  animation: wl-reveal 1100ms cubic-bezier(0.42, 0.05, 0.58, 0.95) 830ms forwards;
}

/* Period pops right as the pen lands at the end of "writing" */
.nb-line--writing.is-in .wl-period {
  transition-delay: 1930ms;
  opacity: 1;
  transform: scale(1);
}

@keyframes wl-reveal {
  0%   { clip-path: inset(-20% 100% -20% 0);  -webkit-clip-path: inset(-20% 100% -20% 0); }
  100% { clip-path: inset(-20% 0 -20% 0);     -webkit-clip-path: inset(-20% 0 -20% 0); }
}

/* Small-screen tuning */
@media (max-width: 700px) {
  .notebook-page {
    --rule-spacing: clamp(48px, 7.5vh, 62px);
    --margin-x: clamp(52px, 13vw, 72px);
    padding:
      clamp(52px, 8vh, 72px)
      clamp(20px, 4vw, 32px)
      clamp(52px, 8vh, 72px)
      calc(var(--margin-x) + clamp(12px, 3vw, 20px));
  }
  .nb-line { font-size: clamp(22px, 5.6vw, 32px); }
  .nb-line--writing { font-size: clamp(24px, 6vw, 36px); }
  .wl-pen { width: 100%; height: 100%; }
  .persistent-pen { width: clamp(120px, 30vw, 162px); height: clamp(120px, 30vw, 162px); }
}

/* ============================================================
   Scene 10 — The reveal
   ============================================================ */

/* Reveal scene — the pen blooms above the tagline. */
.scene--reveal {
  background:
    radial-gradient(70% 55% at 50% 45%, rgba(224, 178, 119, 0.10), transparent 70%),
    radial-gradient(90% 60% at 50% 100%, rgba(224, 178, 119, 0.05), transparent 70%);
}

.reveal-stage {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

/* The mono subtitle — used in the Brand scene ("And we're calling it"). */
.pre-reveal {
  font-family: var(--mono);
  font-size: clamp(11px, 1vw, 12px);
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 0 0 clamp(24px, 4vh, 44px) 0;
  font-weight: 400;
}

/* Reveal-scene specifically: the preamble is big and cinematic, not small mono. */
.scene--reveal .pre-reveal {
  font-family: var(--serif);
  font-size: clamp(30px, 4.6vw, 60px);
  line-height: 1.1;
  letter-spacing: -0.015em;
  text-transform: none;
  color: var(--ink);
  font-weight: 400;
  margin: 0 0 clamp(20px, 3vh, 36px) 0;
}

/* Pen stage — a vertical space where the pen blooms to 4.2× its normal
   size. The .pen-anchor-reveal is a 0×0 point dead-center; JS anchors the
   nib there, and transform-origin at the nib means the pen grows around
   its own tip while staying planted. */
.pen-stage {
  position: relative;
  width: 100%;
  height: clamp(260px, 38vh, 400px);
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0 0 clamp(28px, 5vh, 56px);
  /* Warm halo behind the pen so it reads as the hero object */
  background:
    radial-gradient(38% 60% at 50% 50%, rgba(224, 178, 119, 0.18), transparent 70%),
    radial-gradient(65% 90% at 50% 50%, rgba(224, 178, 119, 0.05), transparent 80%);
}

.pen-anchor-reveal {
  display: block;
  width: 0;
  height: 0;
}

/* The tagline — "The pen for visual storytellers." — supporting, not hero. */
.tagline-reveal {
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(22px, 3vw, 40px);
  line-height: 1.2;
  letter-spacing: 0.005em;
  margin: 0;
  color: var(--ink-soft);
  max-width: 28ch;
  text-align: center;
}

.tl-emph {
  /* "pen" gets a warm amber so it echoes the gold pen nib — solid color
     avoids background-clip:text fragility under reveal-words nesting. */
  color: #e0b277;
  display: inline-block;
}

@media (max-width: 700px) {
  .scene--reveal .pre-reveal { margin-bottom: clamp(12px, 2vh, 20px); }
  .pen-stage { height: clamp(160px, 26vh, 260px); margin-bottom: clamp(12px, 2vh, 20px); }
}

/* Keyframe in Koulen — display face, distinct from the surrounding serif.
   No glow; the font weight and shape already sets it apart. */
.kf-spot {
  display: inline-block;
  font-family: "Koulen", sans-serif;
  font-style: normal;
  font-weight: 400;
  font-size: 1.15em;
  letter-spacing: 0.02em;
  color: var(--ink);
  /* Koulen sits taller than Instrument Serif — nudge down for baseline alignment */
  vertical-align: -0.04em;
  text-transform: capitalize;
}

/* ============================================================
   Scene 11 — Closing: Steamboat Willie invitation + signup
   Steamboat Willie plays as a vintage "Now Showing" reel atop
   the signup. The heading echoes the notebook's writing metaphor
   ("write with it"). Everything centers in a single column.
   ============================================================ */

.scene--closing {
  /* Warmer tint than the reveal scene — shifts the "room" */
  background:
    radial-gradient(80% 55% at 50% 40%, rgba(224, 178, 119, 0.09), transparent 70%),
    radial-gradient(60% 40% at 50% 100%, rgba(224, 178, 119, 0.04), transparent 70%);
}

.signup-stage {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: clamp(40px, 6vh, 72px);
}

/* ============================================================
   The Ticket — simplified premiere-ticket signup.
   Three things: brand, call-to-action, email. That's it.
   Dashed inner border + perforated tear + star-adorned stub.
   ============================================================ */

.ticket {
  --paper:     #f0e6cc;
  --paper-dk:  #d4c49e;
  --paper-ink: #2c231a;
  --paper-sub: #917a56;

  display: flex;
  position: relative;
  width: min(520px, 92vw);
  background: var(--paper);
  transform: rotate(-0.7deg);
  box-shadow:
    0 2px 0 rgba(0,0,0,0.08),
    0 40px 80px -24px rgba(0,0,0,0.55),
    0 16px 36px -14px rgba(0,0,0,0.35);
}

/* ---- Perforated edges — both sides ---- */

.ticket-perf {
  width: 20px;
  flex-shrink: 0;
  background-color: var(--paper);
}

.ticket-perf--left {
  background-image:
    radial-gradient(circle at 0 50%, var(--bg) 4.5px, transparent 5px);
  background-size: 20px 18px;
  background-repeat: repeat-y;
}

.ticket-perf--right {
  background-image:
    radial-gradient(circle at 100% 50%, var(--bg) 4.5px, transparent 5px);
  background-size: 20px 18px;
  background-repeat: repeat-y;
}

/* ---- Main body (between perforations) ---- */

.ticket-main {
  flex: 1;
  min-width: 0;
  padding: clamp(36px, 5vw, 60px) clamp(24px, 3vw, 40px);
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: clamp(22px, 3.4vh, 38px);
  position: relative;
}

/* Dashed inner border (classic ticket frame) */
.ticket-border {
  position: absolute;
  inset: 8px;
  border: 1.5px dashed var(--paper-dk);
  pointer-events: none;
}

.ticket-head {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
}

.ticket-brand {
  font-family: "Koulen", sans-serif;
  font-size: clamp(28px, 3.8vw, 44px);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--paper-ink);
  margin: 0;
  line-height: 1;
}

.ticket-subtitle {
  font-family: var(--mono);
  font-size: clamp(10px, 1.1vw, 12px);
  font-weight: 500;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--paper-sub);
  margin: 0;
  line-height: 1;
}

/* Form: stacked — email underline, then button below */
.ticket .signup {
  width: 100%;
  max-width: 320px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(14px, 2vh, 22px);
}

.ticket-input {
  width: 100%;
  background: transparent;
  border: none;
  border-bottom: 1.5px solid var(--paper-dk);
  outline: none;
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(14px, 1.5vw, 16px);
  color: var(--paper-ink);
  padding: 6px 0;
  text-align: center;
  transition: border-color 250ms;
}

.ticket-input::placeholder {
  color: rgba(145, 122, 86, 0.5);
}

.ticket-input:focus {
  border-bottom-color: var(--paper-ink);
}

.ticket-btn {
  background: var(--paper-ink);
  color: var(--paper);
  border: none;
  padding: 18px 40px;
  font-family: var(--mono);
  font-size: clamp(13px, 1.35vw, 15px);
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 14px;
  box-shadow: 0 10px 24px -12px rgba(0, 0, 0, 0.55);
  transition: background 200ms, transform 200ms, box-shadow 200ms;
}

.ticket-btn-icon {
  width: 26px;
  height: 26px;
  display: block;
  object-fit: contain;
}

.ticket-btn:hover {
  background: #4a3a24;
  transform: translateY(-1px);
  box-shadow: 0 14px 28px -12px rgba(0, 0, 0, 0.65);
}

.ticket-btn:active {
  transform: translateY(0);
}

.ticket .signup-ok {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  min-height: 1.2em;
  margin: 0;
  text-align: center;
  opacity: 0;
  transition: opacity 400ms;
}
.ticket .signup-ok.is-visible { opacity: 1; }

/* ---- Mobile ---- */
@media (max-width: 420px) {
  .ticket { width: min(340px, 96vw); }
  .ticket-perf { width: 14px; }
}

/* ---- Steamboat Willie (below ticket) ---- */

.signup-film {
  margin: 0;
  width: clamp(240px, 26vw, 340px);
  display: flex;
  flex-direction: column;
  align-items: center;
}

.signup-film-frame {
  position: relative;
  width: 100%;
  aspect-ratio: 378 / 316;
  border-radius: 6px;
  overflow: hidden;
  background: #050505;
  box-shadow:
    0 36px 70px -22px rgba(0, 0, 0, 0.7),
    0 14px 28px -14px rgba(0, 0, 0, 0.5),
    inset 0 0 0 1px rgba(236, 231, 220, 0.08),
    inset 0 0 0 3px rgba(0, 0, 0, 0.6);
  animation: signup-film-drift 9s ease-in-out infinite alternate;
  will-change: transform;
}

.signup-film-video {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
  filter: contrast(1.08) sepia(0.12) brightness(1.02);
}

.signup-film-grain {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='1.1' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1  0 0 0 0 1  0 0 0 0 1  0 0 0 0.7 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
  opacity: 0.12;
  mix-blend-mode: overlay;
  animation: signup-film-grain-shift 1.2s steps(4) infinite;
}

.signup-film-vignette {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(120% 100% at 50% 50%, transparent 55%, rgba(0,0,0,0.6) 100%);
}

/* ---- Animations ---- */

@keyframes signup-film-drift {
  0%   { transform: translateY(-1.5px) rotate(-0.15deg); }
  100% { transform: translateY(1.5px)  rotate(0.15deg); }
}

@keyframes signup-film-grain-shift {
  0%   { transform: translate(0, 0); }
  25%  { transform: translate(-3%, 2%); }
  50%  { transform: translate(2%, -3%); }
  75%  { transform: translate(-2%, -2%); }
  100% { transform: translate(0, 0); }
}

/* ---- Mobile: ticket stacks vertically ---- */
@media (max-width: 520px) {
  .ticket { flex-direction: column; width: min(380px, 94vw); }
  .ticket-perf {
    width: 100%;
    height: 20px;
    background-image:
      radial-gradient(circle at 50% 0,   var(--bg) 5px, transparent 5.5px),
      radial-gradient(circle at 50% 100%, var(--bg) 5px, transparent 5.5px);
    background-size: 20px 20px;
    background-repeat: repeat-x;
  }
  .ticket-stub {
    width: 100%;
    flex-direction: row;
    padding: 14px 20px;
    gap: 14px;
  }
  .ticket-admit,
  .ticket-number {
    writing-mode: horizontal-tb;
    text-orientation: initial;
  }
  .ticket-form-row { flex-direction: column; align-items: stretch; }
  .ticket-seal { width: 100%; height: auto; border-radius: 999px; padding: 14px 0; }
}

@media (prefers-reduced-motion: reduce) {
  .signup-film-frame { animation: none; }
  .signup-film-grain { animation: none; }
}

.signup-ok.is-visible { opacity: 1; }

.end-card {
  margin-top: 14vh;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
  color: var(--ink-mute);
}

.end-card p {
  font-family: var(--serif);
  font-style: italic;
  font-size: 18px;
  letter-spacing: 0.02em;
  margin: 0;
}

.mark-end { color: var(--ink-soft); }

/* ============================================================
   Reveal engine
   ============================================================ */

.reveal {
  opacity: 0;
  transform: translateY(18px);
  transition:
    opacity var(--dur-med) var(--ease-out),
    transform var(--dur-med) var(--ease-out);
}

.reveal.is-in {
  opacity: 1;
  transform: translateY(0);
}

.reveal-words {
  /* Words are wrapped in spans at runtime */
}

.reveal-words .word {
  display: inline-block;
  vertical-align: baseline;
  /* Clip the entrance animation from ABOVE (so text slides in cleanly from
     below) while letting glyph descenders (g, p, y, j) hang BELOW the
     line-height box without being cropped. Negative bottom inset extends
     the visible region past the element's bottom edge. Tiny horizontal
     negative insets also give italic glyphs room for optical overshoot. */
  clip-path: inset(0 -0.08em -0.35em -0.08em);
  -webkit-clip-path: inset(0 -0.08em -0.35em -0.08em);
}

.reveal-words .word > span {
  display: inline-block;
  transform: translateY(110%);
  opacity: 0;
  transition:
    transform var(--dur-slow) var(--ease-out),
    opacity var(--dur-med) var(--ease-std);
}

.reveal-words.is-in .word > span {
  transform: translateY(0);
  opacity: 1;
}

/* Stagger per word via CSS var set in JS (--i) */
.reveal-words.is-in .word > span {
  transition-delay: calc(var(--i, 0) * 40ms);
}

/* ============================================================
   Scene-level adjustments
   ============================================================ */

/* ============================================================
   Scene — "It's a story." (continuous film reel of iconic stories)
   ============================================================ */

.scene--pivot {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  /* no panel background — let the page bg flow continuously above and below the reel */
}

/* The moving reel of frames */
.reel {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  z-index: 0;
  pointer-events: none;
  background: transparent;
  opacity: 0;
  transition: opacity 1400ms var(--ease-out);
}

.scene--pivot.is-in .reel {
  opacity: 1;
}

.reel-track {
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 0 18px;
  animation: reel-scroll 200s linear infinite;
  animation-play-state: paused;
  will-change: transform;
}

.scene--pivot.is-in .reel-track {
  animation-play-state: running;
}

.reel-frame {
  flex: 0 0 auto;
  /* size by height so the reel fills more of the viewport vertically */
  height: clamp(360px, 72vh, 700px);
  aspect-ratio: 5 / 7;
  margin: 0;
  overflow: hidden;
  border-radius: 3px;
  /* No y-offset shadow — 64 stacked drop-shadows would form a visible band
     below the reel. Just a thin inset highlight to define the frame edge. */
  box-shadow: inset 0 0 0 1px rgba(224, 178, 119, 0.10);
}

.reel-frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

@keyframes reel-scroll {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}

/* No overlays on the section — the page bg shows through above and below
   the reel uninterrupted. Text contrast comes from the headline's text-shadow. */

.scene--pivot .inner {
  position: relative;
  z-index: 2;
}

.scene--pivot .hero-line {
  text-shadow:
    0 6px 48px rgba(0, 0, 0, 0.95),
    0 0 18px rgba(0, 0, 0, 0.7),
    0 1px 2px rgba(0, 0, 0, 0.6);
}

@media (max-width: 700px) {
  /* Shorter duration since JS reduces to 20 frames (vs 64) on mobile */
  .reel-track { gap: 12px; padding: 0 12px; animation-duration: 60s; }
  .reel-frame { height: clamp(280px, 60vh, 460px); }
}

@media (prefers-reduced-motion: reduce) {
  .reel-track { animation: none; }
}

.scene--change {
  background: radial-gradient(60% 45% at 50% 50%, rgba(201, 106, 95, 0.04), transparent 70%);
}

.scene--cameras .inner { max-width: 900px; }

/* ============================================================
   Small screens
   ============================================================ */

@media (max-width: 700px) {
  body { font-size: 16px; }
  .timeline { display: none; }
  :root { --container: min(96vw, 1100px); }
  .scene { padding: 14vh 3vw; }
  .scene--story-can { padding: 0; }
  .story-can-sticky { padding: 0 3vw; }
  .cameras-sticky { padding: 0 3vw; }
  .ledger-sticky { padding: 0 3vw; }
  .line.l-xl  { font-size: clamp(32px, 9vw, 56px); }
  .line.l-lg  { font-size: clamp(28px, 8vw, 48px); }
  .hero-line  { font-size: clamp(44px, 14vw, 88px); }
  .scene--ledger { min-height: 220vh; }

  /* --- iOS crash prevention ---
     Disable the grain overlay: feTurbulence + mix-blend-mode: overlay
     composites the entire viewport every frame — too expensive for mobile GPUs */
  .grain { display: none; }

  /* Strip will-change from elements that don't need dedicated compositing
     layers on mobile — each one eats GPU texture memory */
  .story-scene  { will-change: auto; }
  .rev-fig      { will-change: auto; }
  .nw-apple     { will-change: auto; }
  .fly-plane    { will-change: auto; }
  .cam-stage    { will-change: auto; }
  .reel-track   { will-change: auto; }
  /* Keep 4 columns so row subgrid still lines up, but collapse the leader column to 0 */
  .ledger {
    grid-template-columns: auto auto minmax(0, 1fr) auto;
    column-gap: clamp(6px, 2vw, 12px);
  }
  .led-label { font-size: clamp(26px, 7.5vw, 40px); white-space: normal; }
  .led-num { font-size: 10px; padding-top: 0.35em; }
  .led-val { font-size: clamp(20px, 5.2vw, 28px); letter-spacing: 0.04em; }
  .led-val--sum { font-size: clamp(24px, 6.8vw, 38px); }
  /* Hide the dotted leader on tight screens */
  .led-leader { display: none; }

  /* Smaller peak scale for "big" on mobile so it fits the viewport */
  .led-big-em {
    transform:
      translate(
        calc(var(--grow-stage, 0) * -6vw),
        calc((1 - var(--big-stage)) * 8px + var(--grow-stage, 0) * -5vh)
      )
      scale(calc(
        (0.88 + var(--big-stage) * 0.12)
        + var(--grow-stage, 0) * 4.2
      ));
  }
  /* Cameras scene — keep two-column layout on mobile: camera left, words right */
  .scene--cameras { min-height: 220vh; }
  .cameras-sticky { padding: 0 14px; }
  .cameras-grid { grid-template-columns: 1fr 1.1fr; gap: 12px; }
  .cam-morph { max-width: 160px; }
  .cam-word { font-size: clamp(26px, 7vw, 40px); line-height: 1.02; }

  .signup-film { width: min(88vw, 320px); }
}

/* ============================================================
   Reduced motion
   ============================================================ */

@media (prefers-reduced-motion: reduce) {
  .grain { display: none; }
  .reveal, .reveal-words .word > span {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
    transition: none !important;
  }
  html { scroll-behavior: auto; }

  /* Notebook — render in final state without the pen travel */
  .wl-text {
    clip-path: none !important;
    -webkit-clip-path: none !important;
    animation: none !important;
  }
  .wl-period {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
  /* Persistent pen — hide entirely; motion-reduced users don't need the
     cross-scene travel choreography */
  .persistent-pen { display: none !important; }

  /* Word-as-world scenes — kill idle loops only; scroll-scrub is inherently reduced-motion-safe */
  .story-scene * { animation: none !important; }

  /* Ledger — render the final landed state, skip scrubbed motion */
  .ledger-row > *,
  .led-d, .ledger-rule, .ledger-prompt,
  .led-big-a, .led-big-after {
    opacity: 1 !important;
    transform: none !important;
  }
  .led-big-em {
    /* No growing scale — just render at 1x */
    transform: none !important;
    letter-spacing: -0.02em !important;
    text-shadow: none !important;
  }
  .ledger-rule-path { stroke-dashoffset: 0 !important; }
  .ledger-row--item { filter: none !important; }
  .led-leader {
    -webkit-mask-image: none !important;
            mask-image: none !important;
  }
  .ledger-sticky::before { display: none !important; }
}

/* ============================================================
   Selection
   ============================================================ */

::selection {
  background: var(--amber);
  color: var(--bg-deep);
}
