/* ================================================================
   TURBO RACER — premium H5 race mini-game (betting + race phases)
   ================================================================ */

@font-face { font-family:"Orbitron"; src:local("Orbitron"); font-weight:700 900; }

/* ── Design Tokens ──────────────────────────────────────────── */
:root {
  --game-w: 390px;
  --game-h: 844px;
  --stream-h: calc(var(--game-h) * 0.4);   /* top 40% — livestream, always blank */
  --play-h:   calc(var(--game-h) - var(--stream-h));   /* bottom 60% — the game */
  --scale: 1;   /* set by resizeGame() in script.js */

  --blue-900: #050f2e;
  --blue-800: #0a1f52;
  --blue-700: #123a82;
  --blue-600: #1a56b8;

  /* Bright play-area backdrop — the reference app's betting screen is
     a vivid royal blue, not a near-black dark-mode panel. --blue-900
     above stays dark (used only behind the livestream placeholder). */
  --play-bg-top:    #3f7bec;
  --play-bg-mid:    #2c5fd6;
  --play-bg-bottom: #1a3fa0;

  --cyan:      #18e4ff;
  --cyan-soft: rgba(24,228,255,.28);
  --cyan-dim:  rgba(24,228,255,.14);

  --purple:      #7c5cff;
  --purple-dark: #241a5e;

  --gold:      #ffc933;
  --gold-dark: #ca8b00;

  --win:  #38e29a;
  --lose: #ff5c7a;

  --text:  #ffffff;
  --muted: rgba(255,255,255,.66);
  --faint: rgba(255,255,255,.4);

  --panel:        linear-gradient(155deg, rgba(48,92,205,.62), rgba(14,34,108,.8));
  --panel-border: rgba(180,215,255,.4);
  --panel-glass:  rgba(255,255,255,.1);

  --shadow-panel: 0 6px 18px rgba(0,8,30,.45), inset 0 1px 0 rgba(255,255,255,.1);
  --shadow-cyan:  0 0 0 1px rgba(24,228,255,.4), 0 0 18px rgba(24,228,255,.35);
  --shadow-gold:  0 0 0 1px rgba(255,201,51,.5), 0 0 16px rgba(255,201,51,.4);

  --radius-lg: 18px;
  --radius-md: 12px;
  --radius-sm: 8px;

  --sp-1: 4px; --sp-2: 6px; --sp-3: 10px; --sp-4: 14px; --sp-5: 20px;

  --font-display: "Orbitron", "Segoe UI", sans-serif;
  --font-ui:      "Segoe UI", system-ui, sans-serif;
  --font-number:  "Segoe UI", system-ui, sans-serif;
  --font-chip:    "Segoe UI", system-ui, sans-serif;

  --t-fast: .15s;
  --t-med:  .3s;
  --t-slow: .5s;

  --dur-betting:   20000ms;
  --dur-locking:     500ms;
  --dur-countdown:  3000ms;
  --dur-finishing:  1000ms;
  --dur-result:     3000ms;

  /* z-index system: never hand-pick a random value outside this list */
  --z-bg: 0;
  --z-race-bg: 1;
  --z-road: 2;
  --z-lane: 3;
  --z-vehicle: 4;
  --z-hud: 5;
  --z-controls: 6;
  --z-particles: 7;
  --z-overlay: 8;
  --z-modal: 9;
  --z-toast: 10;
}

/* ── Game Shell ─────────────────────────────────────────────── */
* , *::before, *::after { box-sizing: border-box; margin:0; padding:0; }
/* Transparent, not black — this game runs embedded over a host app's live
   video. A black page background would paint over that video anywhere the
   scaled game box doesn't fully cover (e.g. the side letterboxing on a
   tablet/laptop, or any edge rounding on a phone). */
html, body { width:100%; height:100%; overflow:hidden; background:transparent; }
/* Tablet / laptop: the game is one centred phone-shaped column (see resizeGame in script.js);
   the page around it gets a deep blue backdrop instead of being empty. */
html.is-desktop { background: radial-gradient(ellipse 90% 60% at 50% 35%, #123a82 0%, #0a1f52 55%, #050f2e 100%); }
body { font-family:var(--font-ui); color:var(--text); -webkit-user-select:none; user-select:none; touch-action:manipulation; }
button { border:0; cursor:pointer; font:inherit; color:inherit; background:none; -webkit-tap-highlight-color:transparent; }
.hidden { display:none !important; }

.race-game {
  /* Bottom-anchored, not vertically centered. When the scaled box is taller
     than the real viewport (phone browser chrome eating into the visible
     height, or scale being width-driven — see resizeGame()), something has
     to give: anchoring to the bottom means it's always the STREAM AREA (top
     40%, meant to be blank anyway) that shrinks/gets clipped at the top,
     while the PLAY AREA (bottom 60% — the actual betting UI, cards, race
     track) stays pinned to the bottom edge and is never the part that's cut.
     transform-origin is bottom-center to match: scaling grows/shrinks the
     box from its bottom edge, not its middle. */
  position: fixed;
  bottom: 0; left: 50%;
  width: var(--game-w);
  height: var(--game-h);
  transform: translateX(-50%) scale(var(--scale));
  transform-origin: center bottom;
  overflow: hidden;
  /* Transparent, not var(--blue-900) — that solid navy would otherwise show
     through .stream-area (also transparent now) wherever the live video is
     supposed to be visible. .play-area still paints its own opaque blue
     background below, so the actual game UI is unaffected. */
  background: transparent;
  font-variant-numeric: tabular-nums;
}

/* ── HUD (shared look for top pills/icons) ─────────────────── */
.hud-top {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4) 0;
  z-index: var(--z-hud);
}
.balance-pill {
  display: flex; align-items: center; gap: var(--sp-2);
  background: rgba(255,255,255,.92);
  border-radius: 999px;
  padding: 5px 6px 5px 10px;
  box-shadow: 0 3px 8px rgba(0,0,0,.3);
}
.coin-icon img { display:block; width:20px; height:20px; object-fit:contain; }
/* Small coin used for the pool total and each vehicle card's wager
   amount — was a plain SVG circle sized via width/height attributes;
   those don't apply to a raster <img>, so it's sized here instead. */
.coin-sm { display:block; width:12px; height:12px; object-fit:contain; flex-shrink:0; }
.balance-value { font-family:var(--font-number); font-weight:800; font-size:14px; color:#0a2050; }
.recharge-btn {
  width:20px; height:20px; border-radius:50%;
  display:grid; place-items:center;
  background: linear-gradient(180deg,#4ff0e0,#12c9c9);
  color:#023; font-weight:900; font-size:13px; line-height:1;
  box-shadow: inset 0 1px rgba(255,255,255,.5);
}
.recharge-btn:active { transform: scale(.9); }

.hud-icons { display:flex; align-items:center; gap:12px; }
.hud-icon {
  width:24px; height:24px;
  display:grid; place-items:center;
  color: rgba(255,255,255,.92);
  transition: transform var(--t-fast), opacity var(--t-fast);
}
.hud-icon img { width:100%; height:100%; object-fit:contain; filter: drop-shadow(0 1px 3px rgba(0,10,40,.5)); pointer-events:none; }
.hud-icon:active { transform: scale(.88); opacity:.7; }

/* ── History row ────────────────────────────────────────────── */
.history-row {
  display:flex; align-items:center; gap:5px;
  padding: var(--sp-4) var(--sp-4) 0;
  min-height: 22px;
  overflow:hidden;
  z-index: var(--z-hud);
  -webkit-mask-image: linear-gradient(90deg,#000 0 92%, transparent);
  mask-image: linear-gradient(90deg,#000 0 92%, transparent);
}
/* Betting-only — the top panel otherwise stays identical across
   both screens, but recent-winners history is 1st-screen-specific. */
.race-game:not([data-phase="betting"]) .history-row { display:none; }
.hist-chip {
  flex-shrink:0; height:18px; padding:0 8px; border-radius:999px;
  display:inline-flex; align-items:center;
  font-size:9.5px; font-weight:800; letter-spacing:.2px;
  border:1px solid transparent;
  animation: histIn .3s cubic-bezier(.34,1.56,.64,1) both;
}
@keyframes histIn { from{opacity:0; transform:translateX(-10px) scale(.85);} to{opacity:1; transform:translateX(0) scale(1);} }
.hist-chip[data-vehicle="truck"]    { background:rgba(226,98,31,.22); border-color:rgba(226,98,31,.55); color:#ffb27a; }
.hist-chip[data-vehicle="supercar"] { background:rgba(255,47,143,.2);  border-color:rgba(255,47,143,.5);  color:#ff9ac6; }
.hist-chip[data-vehicle="atv"]      { background:rgba(255,154,31,.2);  border-color:rgba(255,154,31,.5);  color:#ffcb8a; }

/* ── Track Selector ─────────────────────────────────────────── */
.track-strip {
  margin: 17px var(--sp-4) 3px;
  display:flex; align-items:stretch;
  height: 49px;
  border-radius: 8px;
  overflow:hidden;
  /* The whole strip is now artwork (assets/ui/firstpagehighway.png, 708x100):
     purple "Highway >" tab, two "???" tabs and the checkered end flags are all
     baked into the picture, so the DOM labels/flags below are made invisible
     (they stay in the DOM for clicks and screen readers). The side padding
     keeps the tab hit-areas between the two flags, as in the art. If more
     tracks unlock, the labels in the PNG will need to be redrawn. */
  background: url("assets/ui/firstpagehighway.png") 0 0 / 100% 100% no-repeat;
  box-shadow: 0 6px 14px rgba(0,8,30,.35);
  z-index: var(--z-hud);
}
/* Page 2 (Desert / Bump / Pothole): assets/ui/secondpagetrack.webp is
   secondpagetrack.png cropped to its visible art (1240x146, flatter than the
   strip), drawn at its own aspect ratio and centred so the text is not
   stretched. script.js setTrackPage() sets data-page (page 2 = racing screen). */
.track-strip[data-page="2"] {
  background: url("assets/ui/secondpagetrack.webp") center / 100% auto no-repeat;
}
/* The checkered end flags are baked into the art; these are just spacers that
   keep the tab hit-areas between them. */
.flag { flex: 0 0 4.7%; background:none; }
.track-slot {
  flex:1; display:flex; align-items:center; justify-content:center; gap:4px;
  font-family:var(--font-ui); font-size:12px; font-weight:700; color:transparent;
  border-right: 0;
  transition: background var(--t-fast), color var(--t-fast);
}
.track-slot:last-of-type { border-right:0; }
.track-slot .track-chevron { opacity:.8; font-weight:900; }
.track-slot[aria-selected="true"] {
  color:transparent;        /* the selected look is baked into the artwork */
  background: transparent;
  box-shadow: none;
  font-weight:800;
}
.track-slot:not([aria-selected="true"]) { pointer-events:none; }
.track-strip[data-page="2"] .track-slot { pointer-events:auto; }   /* page 2 tabs are all locked: let a tap show the locked toast */

/* ── Round Info ─────────────────────────────────────────────── */
.round-info {
  margin: var(--sp-4) var(--sp-4) 0;
  display:flex; align-items:center; justify-content:space-between; gap:6px;
  z-index: var(--z-hud);
  /* Dark glass strip behind players / pool / timer so they stay readable over
     the bright neon light trails of the background image. Same 22px height as
     the chips inside, so the layout below does not move. */
  padding: 0 10px;
  border-radius: 11px;
  background: linear-gradient(180deg, rgba(22,52,140,.6), rgba(16,40,120,.5));
  box-shadow: inset 0 0 0 1px rgba(150,190,255,.22);   /* inset, so it adds no height */
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
}
/* Plain icon + number, no pill — the reference screen has these
   floating directly on the blue backdrop rather than in chips. */
.info-chip {
  display:flex; align-items:center; gap:5px;
  height: 22px;
  font-size:12px; font-weight:700;
  color: var(--text);
  text-shadow: 0 1px 2px rgba(0,10,40,.4);
}
.info-chip--pool { flex:1; justify-content:center; }
.info-chip--timer {
  font-family:var(--font-number); font-weight:800; color:#fff;
  transition: color var(--t-med);
}
.info-chip--timer .timer-unit { font-size:9px; opacity:.8; margin-left:1px; }
.info-chip--timer[data-urgency="last-call"] {
  color:#ffc2cf;
  animation: timerPulse .5s ease-in-out infinite alternate;
}
@keyframes timerPulse { from{ transform:scale(1);} to{ transform:scale(1.08);} }

/* ── Vehicle Cards ──────────────────────────────────────────── */
.vehicle-cards {
  /* Base 201px, plus whatever extra resizeGame() computes is left over in
     the play area once the chip bar's own natural size is accounted for
     (--vehicle-cards-extra-h, 0 on a phone where there's normally no slack
     to speak of). Using flex:1 to fill that space directly — an earlier
     version of this — let the cards balloon to dominate the whole screen,
     AND, worse, made resizeGame()'s own live measurement of .top-panel feed
     back into itself every phase change, growing a little more each time
     (see the naturalTopPanelH comment in resizeGame()). A plain computed
     px value from JS avoids both: no runaway growth, and no more dominating
     than the actual leftover room calls for. Overridden below by the
     racing/finishing/result/resetting rule (higher specificity), so this
     extra only ever applies during betting/locking/countdown. */
  flex: 0 0 calc(201px + var(--vehicle-cards-extra-h, 0px));
  margin: 13px var(--sp-4) 0;
  display:grid; grid-template-columns: repeat(3, 1fr); gap: 5px;
  grid-auto-rows: 100%;
  min-height: 0;
  overflow: hidden;
  z-index: var(--z-controls);
}
/* Shrinks for the racing screen only (betting stays at the 201px
   above, untouched) — freeing that height for the race track below,
   which .bottom-panel's flex:1 picks up automatically.

   No transition here (there was one) — animating flex-basis while
   .bottom-panel's absolutely-positioned children (race-stage) resize
   in lockstep every frame produced a real, persistent paint bug: the
   grid's implicit row was sized to its CONTENT's natural height, not
   the shrunk 96px box, and without overflow:hidden that overflow
   just rendered past the bottom edge — under/into the race track
   starting right below it, exactly like the "track under the cards"
   report. grid-auto-rows:100% forces the row (and the cards in it)
   to actually respect the container's height instead of sizing to
   content, and overflow:hidden clips anything that still doesn't
   fit rather than letting it bleed into the race track below. */
/* Shrinks starting at "racing" (right after GO) — during locking and
   the 3-2-1-GO countdown the cards stay full-size, matching the
   chip-bar/race-stage swap timing above. */
.race-game[data-phase="racing"]    .vehicle-cards,
.race-game[data-phase="finishing"] .vehicle-cards,
.race-game[data-phase="result"]    .vehicle-cards,
.race-game[data-phase="resetting"] .vehicle-cards { flex-basis: 148px; }


/* Two stacked panels, not one flat card: a slim header strip
   (odds + indicator) sitting directly on top of a taller body panel
   (name/image/wager) — matching the reference exactly, rather than
   one uniform box with the odds just floating at its top edge. */
.vehicle-card {
  position:relative;
  display:flex; flex-direction:column;
  background:transparent; border:0; padding:0;
  border-radius: var(--radius-md);
  transition: transform var(--t-fast);
}
.v-header {
  display:flex; align-items:center; justify-content:space-between;
  padding: 5px 8px;
  border-radius: var(--radius-md) var(--radius-md) 6px 6px;
  background: linear-gradient(180deg, rgba(58,105,215,.66), rgba(28,62,160,.6));
  border: 1.5px solid var(--panel-border);
  border-bottom: 1px solid rgba(90,140,220,.5);
  transition: border-color var(--t-fast), background var(--t-fast);
}
.v-body {
  position:relative;
  flex:1; display:flex; flex-direction:column; align-items:center;
  min-height:0;
  padding: 8px 4px 16px;   /* generous bottom padding — the gap below the coin amount */
  margin-top:3px;
  border-radius: 6px 6px var(--radius-md) var(--radius-md);
  background: var(--panel);
  border: 1.5px solid var(--panel-border);
  box-shadow: var(--shadow-panel);
  overflow:hidden;
  -webkit-mask-image: -webkit-radial-gradient(circle, #fff 100%, #000 100%);
  transform: translateZ(0);
  transition: border-color var(--t-fast), box-shadow var(--t-fast), filter var(--t-fast);
}
.v-body::before {
  content:""; position:absolute; inset:0;
  background: radial-gradient(circle at 50% -10%, rgba(24,228,255,.22), transparent 60%);
  pointer-events:none;
}
.vehicle-card .v-odds {
  font-family:var(--font-number); font-weight:800; font-size:12.5px; color:#fff;
  text-shadow: 0 1px 2px rgba(0,0,0,.4);
}
.vehicle-card .v-indicator {
  width:17px; height:17px; flex-shrink:0;
  opacity:.9;
  transition: opacity var(--t-fast), transform var(--t-fast), filter var(--t-fast);
}
.vehicle-card .v-indicator img { width:100%; height:100%; object-fit:contain; }
.vehicle-card .v-name { font-size:10.5px; font-weight:700; color:var(--muted); margin-top:2px; }
/* Grows to fill whatever space the body panel has, instead of
   sitting at a fixed small size and leaving a dead gap below — the
   car should be the dominant element, not a small icon near the top. */
.vehicle-card .v-image {
  flex: 1; width:100%; min-height:0;
  display:flex; align-items:center; justify-content:center;
  margin: 2px 0 8px;
}
.vehicle-card .v-image img { max-width:92%; max-height:100%; width:auto; height:auto; object-fit:contain; filter: drop-shadow(0 4px 6px rgba(0,0,0,.4)); }
.vehicle-card .v-wager {
  display:flex; align-items:center; gap:3px;
  font-family:var(--font-number); font-size:10.5px; font-weight:700; color:#ffe9ab;
}
.vehicle-card .v-mybet {
  margin-top:3px; font-size:9px; font-weight:700; color:var(--cyan);
  background: rgba(24,228,255,.14); border-radius:999px; padding:1px 7px;
}
.vehicle-card .v-mybet b { font-family:var(--font-number); }

.vehicle-card:active { transform: translateY(1px) scale(.98); }

.vehicle-card[data-bet="active"] .v-header,
.vehicle-card[data-bet="active"] .v-body {
  border-color: var(--cyan);
}
.vehicle-card[data-bet="active"] .v-body { box-shadow: var(--shadow-cyan), var(--shadow-panel); }
.vehicle-card[data-bet="active"] { transform: translateY(-2px) scale(1.02); }
.vehicle-card[data-bet="active"] .v-indicator { opacity:1; filter:none; transform: scale(1.15) rotate(8deg); }

.vehicle-card[data-state="locked"] {
  pointer-events:none;
  filter: saturate(.5) brightness(.75);
  opacity:.85;
}

.vehicle-card.winner .v-header,
.vehicle-card.winner .v-body { border-color: var(--gold); }
.vehicle-card.winner .v-body { box-shadow: var(--shadow-gold), 0 0 30px rgba(255,201,51,.5); }
.vehicle-card.winner {
  animation: winnerPop .5s cubic-bezier(.34,1.56,.64,1) both;
}
@keyframes winnerPop { 0%{transform:scale(1);} 45%{transform:scale(1.08);} 100%{transform:scale(1.03);} }

/* ── Chips ──────────────────────────────────────────────────── */
.chip-bar {
  display:flex; align-items:center; justify-content:space-between; gap:5px;
  padding: 15px var(--sp-4) var(--sp-3);
  z-index: var(--z-controls);
}
.chip {
  flex:1;
  display:flex; align-items:center; justify-content:center; gap:3px;
  height: 30px; border-radius: 999px;
  font-family:var(--font-chip); font-size:10.5px; font-weight:800;
  font-variant-numeric: tabular-nums;
  color: rgba(255,255,255,.95);
  /* Resting look: teal-cyan capsule. Selected chip below swaps to a
     blue gradient instead, matching the reference bet-bar. */
  background: linear-gradient(180deg, #2fd8c4, #14a898);
  border: 1.5px solid rgba(255,255,255,.28);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.3), 0 2px 4px rgba(0,0,0,.25);
  transition: transform var(--t-fast), box-shadow var(--t-fast), border-color var(--t-fast), filter var(--t-fast), background var(--t-fast);
}
.chip-coin {
  width:13px; height:13px; flex-shrink:0;
  background: url("assets/ui/coin 2.png") center/contain no-repeat;
}
.chip:active { transform: translateY(1px) scale(.95); }
.chip.active {
  color:#fff;
  border-color: rgba(255,255,255,.5);
  background: linear-gradient(180deg, #4f8dff, #1a56d8);
  box-shadow: 0 0 0 1px rgba(120,170,255,.6), 0 0 14px rgba(79,141,255,.6), inset 0 1px 0 rgba(255,255,255,.35);
  transform: translateY(-1px);
}
.chip.locked { opacity:.45; filter:saturate(.4); pointer-events:none; }

/* ── Play Area (one persistent screen) ───────────────────────── */
.play-area {
  position:absolute; left:0; right:0; bottom:0;
  height: var(--play-h);
  overflow:hidden;
  z-index: var(--z-race-bg);
  /* Night race-circuit artwork, softened (blurred + lightened, pre-rendered as
     assets/ui/background-soft.webp from background.png) so it reads as a light,
     dreamy backdrop; the cards and strips on top are darker glass to stay
     readable. The old blue gradient is underneath as a fallback while it loads. */
  background:
    url("assets/ui/background-soft.webp") center top / cover no-repeat,
    linear-gradient(165deg, var(--play-bg-top) 0%, var(--play-bg-mid) 45%, var(--play-bg-bottom) 100%);
  display:flex; flex-direction:column;
}
/* Soft diagonal light streak — the glossy "shine" across the
   reference screenshots' betting screen. Decorative only. */
.play-area::before {
  /* No explicit z-index: it's generated content, so it paints before
     .top-panel/.bottom-panel in DOM order and — since neither of
     those set a z-index either (both "auto") — DOM order is exactly
     what decides paint order here, keeping this safely behind them
     without needing to out-rank the z-index system above. */
  content:""; position:absolute; pointer-events:none;
  top:-20%; left:-30%; width:70%; height:160%;
  background: linear-gradient(100deg, transparent 35%, rgba(255,255,255,.16) 48%, rgba(255,200,255,.1) 52%, transparent 65%);
  transform: rotate(8deg);
}
/* One persistent screen (see index.html's PLAY AREA comment): the
   top panel (HUD/history/track-strip/round-info/vehicle-cards)
   never moves or fades — it's simply always there. Only the strip
   below it changes, and even that isn't a phase-swap animation
   anymore, just a visibility toggle between two absolutely-
   positioned siblings occupying the same box (see "Bottom Panel
   Swap" below). Phase 1's look (top-panel) is completely untouched
   by any of this. */
.top-panel {
  display:flex; flex-direction:column;
  flex-shrink:0;
}

/* ── Bottom Panel Swap ──────────────────────────────────────── */
.bottom-panel {
  position:relative;
  flex:1;
  min-height:0;
}
.chip-bar {
  /* Vertically centered in .bottom-panel, not top-anchored. Top-anchoring
     put the chips right after the vehicle cards on a phone (where
     .bottom-panel is barely taller than the chip bar itself, so this is
     indistinguishable from top:0 there) — but on a wider/shorter-content
     viewport (e.g. a tablet, where .play-area gets more height than the
     betting UI strictly needs so the race track — race-stage, flex:1 — has
     comfortable room during racing), that same top-anchoring left a large
     empty gap below the chips with nothing else in .bottom-panel to fill it
     during betting. Centering distributes that leftover space evenly above
     and below instead of dumping all of it at the bottom, without touching
     .race-stage at all — chip-bar and race-stage are never visible at the
     same time (see the phase-based display:none rules below), so this
     changes betting/locking/countdown only. */
  position:absolute; left:0; right:0; top:50%;
  transform: translateY(-50%);
}
.race-stage {
  position:absolute; inset: var(--sp-3) var(--sp-4) var(--sp-4);
}
/* The swap happens at "racing" (right after GO), not at "locking" or
   "countdown" — those still show the chip-bar/full-size cards so the
   3-2-1-GO overlay has the betting screen behind it, not the race
   track (which shouldn't be visible until the race actually starts). */
.race-game[data-phase="racing"]    .chip-bar,
.race-game[data-phase="finishing"] .chip-bar,
.race-game[data-phase="result"]    .chip-bar,
.race-game[data-phase="resetting"] .chip-bar { display:none; }

.race-game[data-phase="connecting"] .race-stage,
.race-game[data-phase="betting"]   .race-stage,
.race-game[data-phase="locking"]   .race-stage,
.race-game[data-phase="countdown"] .race-stage { display:none; }

/* ── Race Stage ─────────────────────────────────────────────── */
.race-stage {
  border-radius: var(--radius-lg);
  overflow:hidden;
  border: 1px solid var(--panel-border);
  box-shadow: var(--shadow-panel);
  background: linear-gradient(180deg, #12305e 0%, #0a1c40 60%, #071230 100%);
}
/* Checkered side borders framing the whole track — same pattern as
   the track-strip's flag ends, reused here so the two look like one
   family. Spans the full height of the lanes on both edges, matching
   the reference (not a single finish-line inside one lane). */
.race-edge {
  position:absolute; top:0; bottom:0; width:9px; z-index: var(--z-lane);
  background-image:
    linear-gradient(45deg,#0a1330 25%,transparent 25%),
    linear-gradient(-45deg,#0a1330 25%,transparent 25%),
    linear-gradient(45deg,transparent 75%,#0a1330 75%),
    linear-gradient(-45deg,transparent 75%,#0a1330 75%);
  background-size: 6px 6px;
  background-color: #eef3ff;
}
.race-edge-left  { left:0; box-shadow: 2px 0 6px rgba(0,0,0,.35); }
.race-edge-right { right:0; box-shadow: -2px 0 6px rgba(0,0,0,.35); }
.race-bg-layer { position:absolute; inset:0; z-index: var(--z-race-bg); pointer-events:none; }
.layer-sky { background: linear-gradient(180deg, rgba(124,92,255,.28), transparent 55%); }
.layer-distant {
  background-image: radial-gradient(2px 2px at 15% 30%, rgba(255,255,255,.5), transparent),
                     radial-gradient(2px 2px at 45% 20%, rgba(255,255,255,.35), transparent),
                     radial-gradient(2px 2px at 75% 35%, rgba(255,255,255,.45), transparent),
                     radial-gradient(2px 2px at 90% 15%, rgba(255,255,255,.3), transparent);
  background-size: 220px 100%;
  animation: driftBg 6s linear infinite;
}
.layer-mid {
  background-image: repeating-linear-gradient(90deg, rgba(124,92,255,.22) 0 3px, transparent 3px 46px);
  background-position-y: 0;
  animation: driftBg 2.2s linear infinite;
}
@keyframes driftBg { from{background-position-x:0;} to{background-position-x:-220px;} }
.race-game[data-phase="betting"] .layer-distant,
.race-game[data-phase="betting"] .layer-mid { animation-play-state: paused; }

.dust-layer {
  position:absolute; inset:0; z-index: var(--z-particles); pointer-events:none; opacity:0;
  background-image: radial-gradient(3px 3px at 20% 70%, rgba(230,190,130,.5), transparent),
                     radial-gradient(2px 2px at 55% 40%, rgba(230,190,130,.4), transparent),
                     radial-gradient(3px 3px at 80% 60%, rgba(230,190,130,.5), transparent);
  transition: opacity var(--t-med);
}
.race-game[data-track="desert"][data-phase="racing"] .dust-layer,
.race-game[data-track="desert"][data-phase="finishing"] .dust-layer { opacity:.8; animation: driftBg 1.4s linear infinite; }

/* Page 2 of the track selector (Desert / Bump / Pothole): the race track is
   drawn from assets/ui/runningtrack.webp (runningtrack.png cropped to its art;
   desert sand, then bumpy stripes, then a rocky pothole stretch, with the lane
   lines and checkered end flags baked in). The cars still run left to right
   over it exactly as before, so the DOM lanes turn transparent and the
   built-in road, stripes, flags and drifting layers are hidden. */
.race-game[data-track-page="2"] .race-stage {
  background: url("assets/ui/runningtrack.webp") 0 0 / 100% 100% no-repeat;
}
.race-game[data-track-page="2"] .layer-sky,
.race-game[data-track-page="2"] .layer-mid,
.race-game[data-track-page="2"] .race-edge { display:none; }
.race-game[data-track-page="2"] .lane-road { background:none; border:0; }
/* The picture itself is still, so the sense of speed comes from what scrolls
   right-to-left over it (under the cars): just the dashed line down the middle
   of each lane, plus a few faint drifting specks. Only while racing (paused
   otherwise, like the old road). No extra streak lines: the art already has
   its own lane lines. */
.race-game[data-track-page="2"] .lane-stripes { opacity:.85; }
.race-game[data-track-page="2"] .layer-distant { opacity:.6; animation-duration:2.4s; }

/* ── Race Lanes ─────────────────────────────────────────────── */
.lanes { position:relative; z-index: var(--z-lane); height:100%; display:flex; flex-direction:column; padding: 6px 9px; gap: 4px; }
.lane { position:relative; flex:1; min-height:0; }
.lane-road {
  position:absolute; inset: 3px 0; border-radius:6px;
  background: linear-gradient(180deg, rgba(6,14,34,.9), rgba(3,8,22,.95));
  border-top:1px solid rgba(255,255,255,.06); border-bottom:1px solid rgba(0,0,0,.4);
  overflow:hidden;
}
.lane-stripes {
  position:absolute; inset:0; top:50%; height:2px; transform:translateY(-50%);
  background-image: repeating-linear-gradient(90deg, rgba(255,255,255,.35) 0 16px, transparent 16px 34px);
  animation: driftBg 1s linear infinite;
}
.race-game[data-phase="betting"] .lane-stripes,
.race-game[data-phase="locking"] .lane-stripes,
.race-game[data-phase="countdown"] .lane-stripes { animation-play-state: paused; }


/* ── Vehicles ───────────────────────────────────────────────── */
.vehicle {
  /* left/translateX is written directly by updateRace() every frame
     (script.js measures the lane's actual pixel width via
     clientWidth, which — like offsetWidth elsewhere in this project
     — ignores the responsive CSS `scale()` transform, so the math
     stays correct at any --scale). CSS only owns the vertical
     centering here; horizontal position is JS-driven, not a CSS var
     + calc(), because that would need the lane's live pixel width
     inside CSS, which CSS has no way to read. */
  position:absolute; left:8px; top:50%;
  width: 15%; min-width:46px; aspect-ratio: 64/34;
  transform: translate(0, -50%);
  z-index: var(--z-vehicle);
  will-change: transform;
}
/* The race is seen from directly above, so a car has no ground-shadow ellipse
   sitting under/beside it (that looked like a side view). It gets one soft
   shadow hugging its own outline (see .vehicle-body's drop-shadow), and it does
   not bounce or tilt on the road. */
.vehicle-shadow { display:none; }
.vehicle-body {
  position:relative; width:100%; height:100%;
  filter: drop-shadow(0 0 3px rgba(0,0,0,.5));
  transform: none;    /* script.js still writes --bounce/--tilt; ignored on purpose */
}
.vehicle-body svg { display:block; width:100%; height:100%; }
/* The *straightrunning* photos are already shot nose-right (bed/rear
   on the left, cab/hood on the right) — i.e. already facing the
   lane's left-to-right direction of travel. No rotation needed; a
   first pass here assumed a top-down nose-up photo and rotated 90°,
   which was based on a wrong reading of the source image. */
.vehicle-body img { display:block; width:100%; height:100%; object-fit:contain; }

.vehicle-glow {
  position:absolute; inset:-30%; border-radius:50%;
  background: radial-gradient(circle, rgba(24,228,255,.0) 40%, transparent 70%);
  opacity:0; pointer-events:none; transition: opacity var(--t-med);
}
.speed-trail {
  position:absolute; right:100%; top:38%; height:22%; width:0;
  background: linear-gradient(90deg, transparent, rgba(24,228,255,.55));
  border-radius:4px; opacity:0;
  transition: width .12s linear, opacity .12s linear;
}
.race-game[data-phase="racing"] .speed-trail { opacity:.85; width:26px; }

.vehicle.winner .vehicle-glow { opacity:1; background: radial-gradient(circle, rgba(255,201,51,.55) 0%, transparent 68%); }
.vehicle.winner .vehicle-body { filter: drop-shadow(0 0 10px rgba(255,201,51,.8)) drop-shadow(0 0 3px rgba(0,0,0,.5)); }

/* Track-driven micro-motion */
.race-game[data-track="bump"] .vehicle-body    { animation: bounceLoop .38s ease-in-out infinite; }
.race-game[data-track="pothole"] .race-stage   { animation: stageShake .6s ease-in-out infinite; }
@keyframes bounceLoop { 0%,100%{ transform: translateY(0) rotate(0deg);} 50%{ transform: translateY(-3px) rotate(-1.5deg);} }
@keyframes stageShake { 0%,100%{ transform: translate(0,0);} 25%{ transform: translate(-1px,1px);} 75%{ transform: translate(1px,-1px);} }
.race-game:not([data-phase="racing"]):not([data-phase="finishing"]) .vehicle-body { animation:none !important; }
.race-game:not([data-phase="racing"]):not([data-phase="finishing"]) .race-stage { animation:none !important; }

/* ── Overlays: Locking / Countdown ────────────────────────────── */
/* top: var(--stream-h), not inset:0 — these are direct children of
   .race-game (siblings of .play-area, not inside it), so inset:0
   covered the stream area too: its dark translucent + blur wash was
   tinting the top 40% (meant to stay untouched, plain black) during
   locking/countdown/result. Constraining them to start where
   .play-area starts keeps the stream area completely unaffected by
   any game-phase overlay. */
.locking-overlay, .countdown-overlay {
  position:absolute; top: var(--stream-h); left:0; right:0; bottom:0;
  z-index: var(--z-overlay);
  display:grid; place-items:center;
  background: rgba(2,6,20,.62); backdrop-filter: blur(3px);
}
.locking-overlay span {
  font-family:var(--font-display); font-weight:900; font-size:18px; letter-spacing:3px;
  color:#fff; text-shadow: 0 0 20px rgba(24,228,255,.7);
  animation: lockPulse .5s ease-in-out infinite alternate;
  padding: 12px 26px; border-radius:12px;
  background: rgba(24,228,255,.12); border:1px solid rgba(24,228,255,.5);
}
@keyframes lockPulse { from{opacity:.75;} to{opacity:1;} }

.countdown-number {
  font-family:var(--font-display); font-weight:900; font-size:88px; color:#fff;
  text-shadow: 0 0 40px rgba(24,228,255,.9), 0 0 80px rgba(24,228,255,.5);
  animation: countPop .5s cubic-bezier(.2,1.4,.4,1) both;
}
.countdown-number[data-go="true"] {
  color: var(--gold);
  text-shadow: 0 0 46px rgba(255,201,51,1), 0 0 90px rgba(255,201,51,.6);
}
@keyframes countPop { 0%{opacity:0; transform:scale(.3);} 55%{opacity:1; transform:scale(1.15);} 100%{opacity:1; transform:scale(1);} }

/* ── Result ─────────────────────────────────────────────────── */
.result-overlay {
  /* Same reasoning as locking/countdown above — stays within
     .play-area's bounds so the stream area is never tinted by it. */
  position:absolute; top: var(--stream-h); left:0; right:0; bottom:0;
  z-index: var(--z-overlay);
  display:grid; place-items:center;
  background: rgba(2,6,20,.72); backdrop-filter: blur(3px);
}
.result-card {
  position:relative; z-index:1;
  display:flex; flex-direction:column; align-items:center; gap:5px;
  padding: 22px 30px 24px;
  border-radius: var(--radius-lg);
  background: var(--panel);
  border:1.5px solid rgba(255,201,51,.55);
  box-shadow: var(--shadow-gold), 0 16px 36px rgba(0,0,0,.5);
  animation: resultIn .38s cubic-bezier(.3,1.5,.5,1) both;
}
@keyframes resultIn { from{opacity:0; transform:scale(.82) translateY(-10px);} to{opacity:1; transform:scale(1) translateY(0);} }
.result-label { font-size:11px; font-weight:800; letter-spacing:4px; color:var(--muted); }
.result-vehicle-img { width:88px; aspect-ratio:64/34; margin:4px 0; filter: drop-shadow(0 6px 10px rgba(0,0,0,.5)); overflow:hidden; }
.result-vehicle-img svg, .result-vehicle-img img { display:block; width:100%; height:100%; object-fit:contain; }
.result-vehicle-name { font-family:var(--font-display); font-weight:800; font-size:18px; }
.result-outcome { font-size:12px; font-weight:800; letter-spacing:1px; padding:4px 14px; border-radius:999px; margin-top:2px; }
.result-outcome[data-win="true"]  { color:#062; background: rgba(56,226,154,.9); }
.result-outcome[data-win="false"] { color:#fff; background: rgba(255,92,122,.28); border:1px solid rgba(255,92,122,.6); }
.result-payout {
  font-family:var(--font-number); font-weight:900; font-size:26px; color: var(--gold);
  text-shadow: 0 0 16px rgba(255,201,51,.6);
}

.confetti-layer { position:absolute; inset:0; z-index: var(--z-particles); pointer-events:none; overflow:hidden; }
.confetto {
  position:absolute; top:-8%; width:6px; height:10px; opacity:0;
  animation: confettiFall 1.4s ease-in forwards;
}
@keyframes confettiFall {
  0%   { opacity:1; transform: translateY(0) rotate(0deg); }
  100% { opacity:0; transform: translateY(340px) rotate(360deg); }
}

/* ── States (shared) ──────────────────────────────────────────── */
.race-game[data-phase="betting"]  .vehicle-cards .vehicle-card { pointer-events:auto; }
.race-game:not([data-phase="betting"]) .vehicle-cards .vehicle-card,
.race-game:not([data-phase="betting"]) .chip-bar .chip,
.race-game:not([data-phase="betting"]) .track-strip .track-slot { pointer-events:none; }

/* ── Info Modal (Garage / Race rules / Help) ──────────────────── */
.info-modal {
  /* Same reasoning as locking/countdown/result overlays — stays within
     .play-area's bounds so the stream area is never tinted by it. */
  position:fixed; top: var(--stream-h); left:0; right:0; bottom:0;
  z-index: var(--z-modal);
  display:grid; place-items:center;
  padding: 24px;
  background: rgba(2,6,20,.72); backdrop-filter: blur(3px);
}
.info-modal-card {
  position:relative;
  width:100%; max-width:300px; max-height:80vh;
  overflow-y:auto;
  display:flex; flex-direction:column; gap:10px;
  padding: 20px 18px 18px;
  border-radius: var(--radius-lg);
  background: var(--panel);
  border:1.5px solid var(--panel-border);
  box-shadow: var(--shadow-panel), 0 16px 36px rgba(0,0,0,.5);
  animation: resultIn .28s cubic-bezier(.3,1.5,.5,1) both;
}
.info-modal-close {
  position:absolute; top:8px; right:8px;
  width:26px; height:26px; border-radius:50%;
  display:grid; place-items:center;
  background: rgba(0,0,0,.25); color:#fff; font-size:18px; line-height:1;
}
.info-modal-title {
  font-family:var(--font-display); font-weight:800; font-size:15px; color:#fff;
  padding-right:20px;
}
.info-modal-body {
  font-size:12px; line-height:1.6; color: rgba(255,255,255,.85);
}
.info-modal-body p { margin:0 0 8px; }
.info-modal-body ol, .info-modal-body ul { margin:0; padding-left:18px; }
.info-modal-body li { margin-bottom:6px; }

.garage-grid { display:flex; flex-direction:column; gap:10px; }
.garage-row {
  display:flex; align-items:center; gap:10px;
  padding:8px; border-radius:var(--radius-md);
  background: rgba(255,255,255,.06); border:1px solid var(--panel-border);
}
.garage-row img { width:56px; height:32px; object-fit:contain; filter: drop-shadow(0 3px 5px rgba(0,0,0,.4)); }
.garage-row-name { font-weight:700; font-size:12.5px; color:#fff; }
.garage-row-odds { font-size:10.5px; color: var(--gold); font-weight:700; }

.rules-table { width:100%; border-collapse:collapse; font-size:11.5px; }
.rules-table th, .rules-table td { text-align:left; padding:5px 6px; border-bottom:1px solid rgba(255,255,255,.12); }
.rules-table th { color: var(--muted); font-weight:700; }

/* ── Toast ──────────────────────────────────────────────────── */
.toast-root {
  position:absolute; left:50%; bottom: calc(var(--play-h) + 10px);
  transform:translateX(-50%);
  display:flex; flex-direction:column; align-items:center; gap:6px;
  z-index: var(--z-toast);
  pointer-events:none;
  width: 90%;
}
.toast {
  padding: 8px 16px; border-radius:999px;
  font-size:11.5px; font-weight:700; color:#fff; text-align:center;
  max-width:100%;
  box-shadow: 0 6px 16px rgba(0,0,0,.4);
  animation: toastIn .25s ease, toastOut .25s ease 2.1s forwards;
}
.toast-success { background: linear-gradient(180deg, rgba(56,226,154,.96), rgba(20,140,90,.96)); }
.toast-error   { background: linear-gradient(180deg, rgba(255,92,122,.96), rgba(170,20,45,.96)); }
.toast-info    { background: linear-gradient(180deg, rgba(24,228,255,.92), rgba(10,110,150,.96)); }
.toast-warning { background: linear-gradient(180deg, rgba(255,201,51,.96), rgba(180,120,0,.96)); color:#2a1a00; }
@keyframes toastIn  { from{opacity:0; transform:translateY(8px);} to{opacity:1; transform:translateY(0);} }
@keyframes toastOut { to{opacity:0; transform:translateY(-6px);} }

/* ── Stream Area ────────────────────────────────────────────── */
/* Transparent, not a black placeholder — the actual livestream video feed is
   rendered by the host app BEHIND this page, so this area has to let it
   show through, not paint over it. */
.stream-area {
  position:absolute; top:0; left:0; right:0; height: var(--stream-h);
  background: transparent;
  z-index: var(--z-bg);
}

/* ── Banner ─────────────────────────────────────────────────── */
/* Game logo (assets/ui/banner.png, 1137x219) over the bottom of the stream
   area, sitting right on top of the play area. The PNG has ~11px of
   transparent padding under the art (of 219), so the box is placed from where
   the ART ends, and tucked 1px under the play area (which is above it in
   z-order) so there is no gap. If banner.png is replaced, update the 11 and
   1137 below (transparent rows under the art, image width). */
.banner {
  --bw: 230px;
  position:absolute; left:50%;
  bottom: calc(var(--play-h) - 1px - var(--bw) * 11 / 1137);
  width: var(--bw);
  transform: translateX(-50%);
  z-index: var(--z-bg);
  pointer-events:none;
  filter: drop-shadow(0 3px 6px rgba(0,8,24,.5));
}

/* ── Performance Mode ───────────────────────────────────────── */
.perf-mode .vehicle-glow,
.perf-mode .dust-layer,
.perf-mode .layer-sky { display:none !important; }
.perf-mode .lane-road { box-shadow:none !important; }
.perf-mode .vehicle-card::before { display:none; }
.perf-mode .chip.active,
.perf-mode .info-chip--timer[data-urgency="last-call"] { animation:none !important; }

/* ── Reduced Motion ─────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .layer-distant, .layer-mid, .lane-stripes, .chip.active,
  .info-chip--timer[data-urgency="last-call"], .vehicle-card[data-bet="active"],
  .history-row .hist-chip { animation-duration:.001ms !important; }
}

/* ── Responsive ─────────────────────────────────────────────── */
/* No breakpoints — the whole .race-game is scaled as a unit by
   resizeGame() in script.js to fit any viewport (320–1024px+ wide,
   any height) while every internal layout number here stays fixed
   to the 390×844 design. See "Game Shell" above. */
