/* css/lights-out.css */
/* The start/finish straight. --t is the launch: 0 while this owns the viewport,
   1 once the lap does. Animated by a scroll timeline, so no scroll listener and
   no main-thread work; @property is what lets a custom property interpolate. */
@property --t { syntax: "<number>"; inherits: true; initial-value: 0; }
/* The radius of the light the launch throws across the grid. */
@property --kick { syntax: "<length>"; inherits: false; initial-value: 0px; }

/* The persistent world layers: the WebGL telemetry canvas and the atmosphere
   wash over it. Both are created once in js/main.js and sit fixed behind the
   whole lap, not just this start line, so they outlive the scroll past here. */
.horizon {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  z-index: 0;
  pointer-events: none;
}
.atmos {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    repeating-linear-gradient(0deg, transparent 0 2px, rgba(0, 0, 0, .10) 2px 4px),
    radial-gradient(130% 88% at 50% 40%, transparent 52%, rgba(0, 0, 0, .55) 100%),
    linear-gradient(to bottom,
      rgba(12, 20, 28, .42) 0%, transparent 26%,
      transparent 72%, rgba(4, 6, 8, .62) 100%);
}

#os-root { --t: 0; position: relative; }

@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    #os-root {
      animation: launch linear both;
      animation-timeline: scroll(root block);
      animation-range: 0 100vh;
    }
    @keyframes launch { from { --t: 0; } to { --t: 1; } }
  }
}

.lap-start {
  position: relative; z-index: 1;
  min-height: 100svh;
  display: grid; grid-template-rows: 1fr auto;
  padding-bottom: var(--strip);
  overflow: hidden;
  background:
    radial-gradient(ellipse 95% 75% at 50% 60%, rgba(20, 24, 34, .45) 0%, rgba(6, 8, 12, .92) 65%, #040508 100%),
    linear-gradient(to bottom, #06080d 0%, #090c12 40%, #050608 100%);
}
/* Atmospheric night track depth & floodlight wash */
.lap-start::before {
  content: '';
  position: absolute; inset: 0; z-index: 0;
  background:
    radial-gradient(circle at 50% 50%, rgba(225, 6, 0, .03) 0%, transparent 60%),
    linear-gradient(to bottom, rgba(5, 7, 10, .2) 0%, transparent 30%, rgba(5, 7, 10, .85) 85%, var(--asphalt) 100%);
  opacity: calc(1 - var(--t) * .96);
  pointer-events: none;
}
.telemetry-canvas {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  pointer-events: none;
  z-index: 1;
}

/* Atmospheric particle lighting context */

/* ---- the gantry, centred ---- */
.gantry {
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  display: flex; gap: clamp(var(--sp-3), 1.6vw, 26px);
  z-index: 3;
}
.light {
  width: clamp(22px, 3vw, 44px); aspect-ratio: 1; border-radius: 50%;
  background: #200B09; border: 1px solid var(--line);
}
/* Five reds come on one at a time and then go out TOGETHER. That simultaneous
   blackout is the whole drama of an F1 start, and staggering it throws the
   moment away. Each light holds from its own onset to a shared end: the
   duration shrinks as the delay grows, so light 0 runs 3800ms and light 4 runs
   1400ms, and all five finish at 3800ms exactly.

   The countdown is the content of this surface, not decoration on it, so it
   plays under reduced motion too -- it changes colour, it does not move. */
@keyframes light-hold {
  0%, 99.99% { background: var(--red); box-shadow: 0 0 22px var(--red); }
  100%       { background: #200B09; box-shadow: none; }
}
.light {
  animation: light-hold calc(3800ms - var(--i) * 600ms) steps(1) forwards;
  animation-delay: calc(var(--i) * 600ms);
}

@media (prefers-reduced-motion: no-preference) {
  /* The gantry retires once it has done its job, rather than hanging over the
     car as five dead circles. */
  .gantry { animation: gantry-clear 520ms cubic-bezier(.4, 0, .8, .4) 3800ms forwards; }
  @keyframes gantry-clear { to { opacity: 0; transform: translate(-50%, -50%) translateY(-78px); } }
}

/* ---- the car, the name, the number ---- */
.start-inner {
  position: relative; z-index: 2;
  align-self: center; justify-self: center;
  width: min(1180px, 94vw); text-align: center;
  padding-top: 3vh;
  opacity: calc(1 - var(--t) * 0.95);
  transform: translate3d(0, calc(var(--t) * -4vh), 0);
  will-change: opacity, transform;
}
.telemetry-hud, .start-controls {
  opacity: calc(1 - var(--t) * 2.5);
  transition: opacity 120ms ease;
}

/* Ambient telemetry and carbon ember canvas */
.telemetry-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 1;
}

/* Telemetry HUD framing the central car */
.telemetry-hud {
  display: grid;
  grid-template-columns: 190px minmax(0, 1fr) 190px;
  align-items: center;
  gap: clamp(12px, 2.4vw, 32px);
  width: 100%;
  max-width: 1160px;
  margin-inline: auto;
  margin-bottom: var(--sp-2);
}

@media (max-width: 900px) {
  .telemetry-hud {
    grid-template-columns: 1fr 1fr;
    grid-template-areas:
      "stage stage"
      "left right";
    gap: 10px;
    width: 100%;
    max-width: min(480px, 94vw);
    margin-inline: auto;
  }
  .start-stage {
    grid-area: stage;
    width: 100%;
    max-width: 100%;
  }
  .hud-wing--left {
    grid-area: left;
    padding: 8px 10px;
    font-size: .52rem;
    gap: 4px;
  }
  .hud-wing--right {
    grid-area: right;
    padding: 8px 10px;
    font-size: .52rem;
    gap: 4px;
  }
  .hud-bar {
    width: 26px;
    height: 4px;
  }
}

.hud-wing {
  display: flex;
  flex-direction: column;
  gap: 7px;
  padding: 12px 15px;
  background: rgba(7, 12, 22, .78);
  border: 1px solid rgba(135, 180, 240, .14);
  border-radius: var(--radius);
  backdrop-filter: blur(14px);
  box-shadow: 0 10px 32px rgba(0, 0, 0, .6), inset 0 1px 0 rgba(255, 255, 255, .05);
  font-family: var(--font-mono);
  font-size: .62rem;
  letter-spacing: .08em;
  text-align: left;
}
.hud-header {
  font-size: .52rem;
  letter-spacing: .16em;
  color: rgba(145, 190, 250, .7);
  border-bottom: 1px solid rgba(255, 255, 255, .08);
  padding-bottom: 4px;
  margin-bottom: 2px;
}
.hud-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
}
.hud-k {
  color: var(--slate);
  font-size: .56rem;
  text-transform: uppercase;
}
.hud-v {
  color: var(--bone);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}
.hud-accent {
  color: #ff3838;
  font-weight: 700;
  text-shadow: 0 0 10px rgba(255, 56, 56, .45);
}
.hud-bar {
  display: inline-block;
  width: 42px;
  height: 5px;
  background: rgba(255, 255, 255, .1);
  border-radius: 2px;
  overflow: hidden;
  vertical-align: middle;
  margin-right: 6px;
}
.hud-fill {
  display: block;
  height: 100%;
  background: #00e676;
  border-radius: 2px;
  transition: width 120ms ease;
}
.hud-fill--speed {
  background: #00d2ff;
  transition: width 90ms ease-out;
}

/* The challenger stage: the car and background watermark number */
.start-stage {
  position: relative;
  isolation: isolate;
  width: 100%;
  max-width: 720px;
  margin-inline: auto;
}

.stage-no {
  position: absolute; left: 0; right: 0; top: 50%;
  transform: translateY(-56%);
  z-index: 0;
  text-align: center;
  font-family: var(--font-display);
  font-size: clamp(6.5rem, 20vw, 15rem);
  line-height: .75;
  letter-spacing: -.07em;
  color: rgba(220, 235, 255, .04);
  -webkit-text-stroke: 1.5px rgba(220, 235, 255, .15);
  pointer-events: none;
  user-select: none;
}

.grid-car {
  position: relative;
  z-index: 2;
  isolation: isolate;
  width: min(100%, calc(44svh * 1.768));
  margin-inline: auto;
  cursor: pointer;
  filter: drop-shadow(0 14px 32px rgba(0, 0, 0, .92)) drop-shadow(0 0 24px rgba(225, 6, 0, .12));
  transition: transform 260ms cubic-bezier(.16, 1, .3, 1), filter 260ms ease;
}
.grid-car:hover {
  transform: translateY(-3px) scale(1.012);
  filter: drop-shadow(0 20px 42px rgba(0, 0, 0, .98)) drop-shadow(0 0 38px rgba(225, 6, 0, .26));
}
.car-img {
  display: block;
  width: 100%;
  height: auto;
  object-fit: contain;
}
/* ---- the launch ----------------------------------------------------------
   Everything below hangs off one instant: 3800ms, when the five reds go dark.

   The previous version gave the car, the badge, the name and the line one
   identical fade-and-rise on a stagger. That is the default entrance, and on
   the one moment this whole surface is built around it delivered a crossfade.
   A start is not a crossfade.

   So the focal idea is BLUR, and it is the material rather than an effect laid
   on top: the car resolves out of motion instead of appearing, and the lit
   panel behind it comes into focus as it powers on. Everything else is quieter
   and deliberately made of different stuff -- the wordmark is a wipe, the badge
   is a snap, the body copy simply fades -- so nothing reads as the same
   animation applied five times.
   -------------------------------------------------------------------------- */

/* THE CAR. It does not fade in; it arrives. Scaled slightly large and blurred,
   settling to sharp and still -- what a camera catches when a car launches at
   it. 150ms after the lights, which is about a real driver's reaction time.
   760ms puts it in authored-entrance territory rather than routine transition. */
@keyframes launch-car {
  from { opacity: 0; transform: scale(1.055); filter: blur(15px); }
  55%  { opacity: 1; }
  to   { opacity: 1; transform: none;         filter: blur(0);   }
}

/* The floodlights catch it. Fast in, slow out: a flash decays, it does not ease
   symmetrically. Fires ON the blackout, because that is what it reacts to. */
@keyframes floodlight {
  0%   { opacity: 0; }
  9%   { opacity: 1; }
  100% { opacity: 0; }
}

/* The launch throws light across the grid, once. This is the only time the
   painted markings are shown rather than found, and it earns its place by
   doing a job: the reader learns they are there, which is what makes the
   cursor-as-light discoverable instead of a secret nobody trips over. */
@keyframes grid-kick {
  0%   { --kick: 0px; }
  34%  { --kick: 92vmax; }
  100% { --kick: 0px; }
}
@keyframes grid-kick-flat {
  0%, 100% { opacity: .12; }
  34%      { opacity: .34; }
}

/* THE NAME. A light bar passes across the lettering, left to right, after lights out
   is complete and the car arrives. Both opacity and clip-path ensure zero premature visibility. */
@keyframes wipe {
  from { opacity: 0; clip-path: inset(0 100% 0 0); }
  1%   { opacity: 1; }
  to   { opacity: 1; clip-path: inset(0 0 0 0); }
}

/* THE PANEL behind the car powers on: up through its own bloom, slowly,
   because a light that size is slow. Same material as the car, one beat ahead. */
@keyframes power-on {
  from { opacity: 0; filter: blur(9px); }
  to   { opacity: 1; filter: blur(0); }
}

/* THE BADGE snaps. 180ms is feedback timing, and feedback is what it is: the
   constructor and the number confirming what just arrived. */
@keyframes snap {
  from { opacity: 0; transform: scale(.94); }
  to   { opacity: 1; transform: none; }
}

@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }

/* The readout's opacity is already spoken for by the scroll timeline, so its
   entrance goes through filter instead and the two compose. */
@keyframes instruments { from { filter: opacity(0); } to { filter: opacity(1); } }

@media (prefers-reduced-motion: no-preference) {
  .stage-no    { animation: power-on   1500ms ease-out                    3700ms both; }
  .grid-car    { animation: launch-car  760ms cubic-bezier(.16, 1, .3, 1) 3950ms both; }
  .start-inner > .badge { animation: snap  180ms cubic-bezier(.16, 1, .3, 1) 4180ms both; }
  /* The name appears cleanly AFTER the five red lights go out (3800ms) and the gantry clears (4320ms). */
  .start-name > .name-part { animation: wipe      620ms cubic-bezier(.22, 1, .36, 1) both; }
  .start-name > .name-part--first { animation-delay: 4300ms; }
  .start-name > .name-part--last  { animation-delay: 4440ms; }
  .telemetry-hud { animation: fade-in   650ms cubic-bezier(.16, 1, .3, 1) 4280ms both; }
  .start-controls { animation: fade-in   700ms cubic-bezier(.16, 1, .3, 1) 4400ms both; }
  .start-readout { animation: instruments 900ms ease-out                    4600ms both; }

  .lap-start::after {
    content: '';
    position: absolute; inset: 0; z-index: 1;
    pointer-events: none;
    opacity: 0;
    background: radial-gradient(58% 44% at 50% 48%,
      rgba(190, 218, 244, .26) 0%, rgba(140, 180, 220, .09) 44%, transparent 74%);
    animation: floodlight 1200ms ease-out 3800ms forwards;
  }
  .grid-marks { animation: grid-kick 1600ms cubic-bezier(.22, 1, .36, 1) 3800ms forwards; }
  @media (hover: none) {
    .grid-marks { animation: grid-kick-flat 1600ms cubic-bezier(.22, 1, .36, 1) 3800ms forwards; }
  }
}

/* Reduced motion is fewer and gentler, not silent. The countdown above still
   plays -- it is the content. Here the arrivals keep their timing and their
   order, so the sequence still reads as a sequence, but nothing scales, blurs,
   wipes or moves: things simply come up. */
@media (prefers-reduced-motion: reduce) {
  .stage-no, .grid-car, .start-inner > .badge, .start-name > .name-part, .telemetry-hud, .start-controls {
    animation: fade-in 520ms ease-out both;
  }
  .stage-no    { animation-delay: 3700ms; }
  .grid-car    { animation-delay: 3950ms; }
  .telemetry-hud { animation-delay: 4100ms; }
  .start-inner > .badge { animation-delay: 4180ms; }
  .start-name > .name-part--first { animation-delay: 4300ms; }
  .start-name > .name-part--last  { animation-delay: 4440ms; }
  .start-controls { animation-delay: 4400ms; }
  .gantry      { animation: fade-in 400ms ease-out 4000ms reverse forwards; }
}

.badge {
  display: inline-flex; align-items: stretch; margin: 0;
  border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden;
  font-family: var(--font-display); line-height: 1;
}
.badge-mark { padding: var(--sp-2) var(--sp-3); color: var(--bone); font-size: .8rem; letter-spacing: .06em; }
.badge-no   { padding: var(--sp-2) var(--sp-3); background: var(--bone); color: var(--asphalt); font-size: .8rem; }

.start-name {
  position: relative;
  z-index: 3;
  margin: 0 auto clamp(8px, 1.8vh, 18px);
  text-align: center;
  font-family: var(--font-hero, 'Syncopate', sans-serif);
  font-weight: 700;
  font-size: clamp(1.85rem, 4.4vw, 4.0rem);
  line-height: .98;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--bone);
  text-shadow: 0 2px 24px rgba(0, 0, 0, .9);
  pointer-events: none;
}
.start-name > .name-part {
  display: inline-block;
  opacity: 0;
  clip-path: inset(0 100% 0 0);
  will-change: transform, opacity, clip-path;
  transition: opacity 120ms ease;
}
.start-name > .name-part + .name-part { margin-left: .28em; }

/* Act 1 Name-to-Monaco Track Morph Stage */
.name-morph-stage {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: min(520px, 88vw);
  height: min(260px, 40vh);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  opacity: 1;
  z-index: 4;
}
.name-morph-svg {
  width: 100%;
  height: 86%;
  overflow: visible;
  filter: drop-shadow(0 0 16px rgba(204, 255, 0, 0.28));
}
.name-morph-sig {
  fill: none;
  stroke: #CCFF00;
  stroke-width: 2.4;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 1200;
  stroke-dashoffset: 0;
  opacity: 1;
  will-change: stroke-dashoffset, opacity, transform;
  animation: sig-write 1.5s cubic-bezier(0.22, 1, 0.36, 1) 400ms both;
}
@keyframes sig-write {
  from { stroke-dashoffset: 1200; opacity: 0; }
  to { stroke-dashoffset: 0; opacity: 1; }
}
.name-morph-circuit {
  fill: none;
  stroke: var(--bone);
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0;
  will-change: stroke-dashoffset, opacity;
}
.name-morph-beacon {
  will-change: transform, opacity;
  opacity: 0;
}
.name-morph-label {
  font-family: var(--font-mono);
  font-size: 0.56rem;
  letter-spacing: 0.18em;
  color: #CCFF00;
  margin-top: 6px;
  white-space: nowrap;
  opacity: 0;
  transition: opacity 300ms ease;
}

.start-controls {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-2);
  margin-top: var(--sp-2);
}
.start-action {
  margin: 4px 0;
}
.start-race-btn {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  padding: 10px 32px;
  background: rgba(14, 18, 25, .85);
  border: 1px solid rgba(225, 6, 0, .45);
  border-radius: var(--radius);
  color: var(--bone);
  text-decoration: none;
  font-family: var(--font-mono);
  position: relative;
  transition: all 180ms ease-out;
  cursor: pointer;
  box-shadow: 0 4px 18px rgba(0, 0, 0, .5);
}
.start-race-btn:hover {
  border-color: #ff3333;
  background: rgba(28, 12, 12, .9);
  color: #fff;
  transform: translateY(-2px);
  box-shadow: 0 6px 24px rgba(225, 6, 0, .25);
}
.start-race-btn:active {
  transform: translateY(0);
}
.btn-bracket {
  color: #ff3333;
  font-weight: bold;
  padding: 0 4px;
}
.btn-text {
  font-size: .84rem;
  font-weight: 700;
  letter-spacing: .16em;
  color: var(--bone);
}
.btn-sub {
  font-size: .56rem;
  letter-spacing: .12em;
  color: var(--slate);
  margin-top: 3px;
  text-transform: uppercase;
}
.start-race-btn:hover .btn-sub {
  color: #ff8888;
}

/* Easter Egg #3: Pit-wall team radio transmission badge */
.pit-radio {
  display: inline-flex; align-items: center; gap: var(--sp-3);
  margin: var(--sp-3) auto 0;
  padding: 4px var(--sp-3);
  background: rgba(20, 24, 29, .78);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  max-width: 90vw;
}
.radio-btn {
  display: inline-flex; align-items: center; gap: 6px;
  background: none; border: none; padding: 0;
  color: var(--bone); cursor: pointer;
  font-family: var(--font-mono); font-size: .66rem; letter-spacing: .1em;
}
.radio-btn:hover { color: var(--bone); }
.radio-beacon {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--green);
  display: inline-block;
}
.pit-radio.is-tx .radio-beacon { background: var(--amber); }
.radio-feed {
  font-family: var(--font-mono); font-size: .62rem;
  color: var(--slate); letter-spacing: .08em;
  text-transform: uppercase;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pit-radio.is-tx .radio-feed { color: var(--green); }

.start-readout {
  display: none !important;
}

@media (prefers-reduced-motion: reduce) {
  .start-inner { transform: none; }
}
@media (max-width: 768px) {
  .start-readout { gap: 0 var(--sp-3); font-size: .56rem; }
  .start-inner {
    padding-top: calc(var(--ses-h) + clamp(12px, 2.6vh, 24px));
    width: min(94vw, 560px);
  }
  .start-name {
    font-size: clamp(1.4rem, 6.2vw, 2.2rem);
    margin-bottom: clamp(6px, 1.4vh, 12px);
  }
  .name-morph-stage {
    width: min(340px, 90vw);
    height: clamp(80px, 18vh, 120px);
  }
  .gantry {
    top: 48%;
    gap: clamp(8px, 2.2vw, 16px);
  }
  .stage-no {
    -webkit-text-stroke-width: 1.8px;
    font-size: clamp(6rem, 24vw, 12rem);
    top: -5%;
  }
  .grid-car {
    max-width: min(340px, 86vw);
    margin: 0 auto;
  }
  .start-controls {
    gap: 8px;
    margin-top: 4px;
  }
  .start-race-btn {
    padding: 8px 24px;
    min-height: 44px;
  }
  .btn-text {
    font-size: .78rem;
    letter-spacing: .12em;
  }
  .pit-radio {
    display: none !important;
  }
}
