/* Opening shot: retreat through the glass, then resolve into the room.
 * Uses the existing --run timeline and measured --pull. All layers finish
 * before the caption and channel cues; no extra scroll distance or video.
 * Loaded only by the current page, after the shared presentation styles.
 */
.run-stage { --intro-tv-width: min(1180px, 92vw, 106svh); }
.run-layer.is-tv .tv { width: var(--intro-tv-width); }

.intro-optics {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  opacity: 0;
}
/* The optical pass samples the live video. Keep its underlying image stable
 * during the handoff; the original CSS treatment remains the GPU fallback. */
.run-layer.is-tv .tv-screen.intro-optics-active video {
  animation: none;
  transform: none;
  filter: none;
  opacity: var(--intro-source-opacity, 0);
}
.intro-optics-active .intro-glass { display: none; }
.intro-fit-fallback { background: #000; }
.run-layer.is-tv .intro-fit-fallback video {
  position: absolute;
  left: var(--fit-x);
  top: var(--fit-y);
  width: var(--fit-w);
  height: var(--fit-h);
  max-width: none;
  animation: none;
  transform: none;
  filter: none;
}

.intro-room,
.intro-floor,
.intro-veil,
.intro-glass {
  position: absolute;
  pointer-events: none;
  opacity: 0;
}

.intro-room {
  inset: -12%;
  z-index: 0;
  background:
    radial-gradient(ellipse at 49% 48%, rgb(146 185 167 / 24%), transparent 38%),
    radial-gradient(ellipse at 34% 43%, rgb(72 114 103 / 28%), transparent 56%),
    radial-gradient(ellipse at 66% 58%, rgb(84 108 119 / 18%), transparent 47%);
}

.intro-floor {
  left: 8%;
  right: 8%;
  top: calc(50% + var(--intro-tv-width) * 0.28);
  height: calc(var(--intro-tv-width) * 0.2);
  z-index: 1;
  background:
    radial-gradient(ellipse at 53% 30%, rgb(0 0 0 / 94%), transparent 36%),
    radial-gradient(ellipse at 50% 42%, rgb(140 184 163 / 25%), transparent 65%);
  transform-origin: 50% 40%;
}

/* A foreground wash crosses the lens during the breach, then clears. The
 * centre stays transparent so the film remains the subject throughout. */
.intro-veil {
  inset: -8%;
  z-index: 3;
  background:
    radial-gradient(ellipse at 50% 48%, transparent 22%, rgb(115 160 144 / 20%) 52%, transparent 72%),
    radial-gradient(ellipse at 50% 48%, transparent 34%, rgb(0 0 0 / 82%) 77%);
}

.intro-glass {
  inset: -10%;
  background:
    radial-gradient(ellipse at 35% 27%, rgb(205 242 227 / 48%), transparent 46%),
    radial-gradient(ellipse at 52% 52%, transparent 27%, rgb(8 25 21 / 72%) 73%);
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .run-layer.is-tv .tv {
      animation: intro-retreat linear both;
      animation-timeline: --run;
      animation-range: contain 0% contain 46%;
    }
    .run-layer.is-tv .tv-screen video {
      animation: intro-refraction linear both;
      animation-timeline: --run;
      animation-range: contain 0% contain 46%;
    }
    .run-layer.is-tv .tv-frame:not(.tv-frame-mask),
    .run-layer.is-tv .tv-led,
    .run-layer.is-tv .tv-hit {
      animation: intro-cabinet linear both;
      animation-timeline: --run;
      animation-range: contain 0% contain 46%;
    }
    .run-layer.is-tv .tv-bug {
      animation: intro-logo linear both;
      animation-timeline: --run;
      animation-range: contain 0% contain 46%;
    }
    .intro-room {
      animation: intro-room-light linear both;
      animation-timeline: --run;
      animation-range: contain 0% contain 46%;
    }
    .intro-floor {
      animation: intro-floor-light linear both;
      animation-timeline: --run;
      animation-range: contain 0% contain 46%;
    }
    .intro-veil {
      animation: intro-lens-veil linear both;
      animation-timeline: --run;
      animation-range: contain 0% contain 46%;
    }
    .intro-glass {
      animation: intro-glass-light linear both;
      animation-timeline: --run;
      animation-range: contain 0% contain 46%;
    }

  }
}

/* A short hold, acceleration through the screen boundary, a long deceleration.
 * Interpolating the remaining distance from --pull keeps the same arc on a
 * portrait phone and an ultrawide display. No overshoot at the landing. */
@keyframes intro-retreat {
  0%, 9% {
    transform: scale(var(--pull, 2.2));
    animation-timing-function: cubic-bezier(0.55, 0, 0.8, 0.55);
  }
  46% {
    transform: scale(calc(1 + (var(--pull, 2.2) - 1) * 0.38));
    animation-timing-function: cubic-bezier(0.15, 0.65, 0.25, 1);
  }
  100% { transform: scale(1); }
}

/* A visible focus excursion and barrel-like stretch mark the instant the
 * picture becomes a phosphor image. It clears before the controls arrive. */
@keyframes intro-refraction {
  0%, 14% { filter: none; transform: none; }
  30% { filter: saturate(1.12) contrast(1.06) brightness(1.04) blur(0.3px); transform: scale(1.025, 1.04); }
  46% { filter: saturate(1.4) contrast(1.16) brightness(1.16) blur(2.4px); transform: scale(1.065, 1.12); }
  60% { filter: saturate(1.24) contrast(1.13) brightness(1.06) blur(1px); transform: scale(1.025, 1.045); }
  82%, 100% { filter: saturate(1.16) contrast(1.09) brightness(0.98) blur(0.3px); transform: none; }
}

@keyframes intro-cabinet {
  0%, 29% { opacity: 0; }
  47% { opacity: 0.12; }
  66% { opacity: 0.7; }
  88%, 100% { opacity: 1; }
}

@keyframes intro-logo {
  0%, 65% { opacity: 0; }
  90%, 100% { opacity: 1; }
}

@keyframes intro-room-light {
  0%, 18% { opacity: 0; transform: scale(1.5); }
  52% { opacity: 1; transform: scale(1.12); }
  100% { opacity: 0.55; transform: scale(1); }
}

@keyframes intro-floor-light {
  0%, 34% { opacity: 0; transform: translateY(16%) scale(1.3, 0.55); }
  76%, 100% { opacity: 0.65; transform: none; }
}

@keyframes intro-lens-veil {
  0%, 15% { opacity: 0; transform: scale(1.25); }
  43% { opacity: 0.35; transform: scale(1.07); }
  78%, 100% { opacity: 0; transform: scale(1); }
}

@keyframes intro-glass-light {
  0%, 19% { opacity: 0; transform: translateX(-8%) scale(1.08); }
  44% { opacity: 0.8; transform: translateX(0) scale(1); }
  76%, 100% { opacity: 0; transform: translateX(8%) scale(1.04); }
}

/* Leave room for the cabinet's existing 9.25% horizontal offset: the picture
 * stays centred while the speaker and buttons fit inside a portrait screen. */
@media (max-width: 600px) {
  .run-stage { --intro-tv-width: min(1180px, 82vw, 106svh); }
  /* Fixed six-pixel expansion overlaps adjacent rows on the scaled cabinet,
   * causing CH- to intercept the centre of CH+. Match the photographed keys. */
  .run-layer.is-tv .tv-hit::before { inset: 0; }
  .intro-veil { inset: 0; }
  .intro-floor { left: 0; right: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .intro-room, .intro-floor, .intro-veil, .intro-glass { display: none; }
  .intro-optics { display: none; }
  /* Also neutralise the shared file's existing tv-pull and tv-warp. */
  .run-layer.is-tv .tv,
  .run-layer.is-tv .tv-screen video { animation: none !important; transform: none !important; filter: none; }
}
