/* MAXIMUM - arcade cricket broadcast skin.
   Two dark navy panels over a white name-plate row, huge outlined lime pop-ups and
   two-tone skewed banners. Everything animates with transform/opacity only: no layout
   shift, no horizontal scroll, nothing that forces a reflow mid-delivery. */

/* ------------------------------------------------------------------- fonts */
/* Self-hosted so a delivery never waits on a font server. Titan One is the chunky rounded
   display face every pop-up and banner word is cut from; Montserrat carries the scoreboard,
   the plates and every label. Latin subsets only; both are OFL 1.1.
   Neither family ships an italic here: the arcade lean is a skewX transform on the banners,
   which keeps the letterforms true instead of shearing them twice. */

@font-face {
  font-family: 'Montserrat';
  font-style: normal;
  font-weight: 600;
  font-display: block;
  src: url('assets/fonts/montserrat-600.woff2') format('woff2');
}
@font-face {
  font-family: 'Montserrat';
  font-style: normal;
  font-weight: 700;
  font-display: block;
  src: url('assets/fonts/montserrat-700.woff2') format('woff2');
}
@font-face {
  font-family: 'Montserrat';
  font-style: normal;
  font-weight: 800;
  font-display: block;
  src: url('assets/fonts/montserrat-800.woff2') format('woff2');
}
@font-face {
  font-family: 'Titan One';
  font-style: normal;
  font-weight: 400;
  font-display: block;
  src: url('assets/fonts/titanone-400.woff2') format('woff2');
}

:root {
  --navy: #0d1b4c;
  --navy-2: #14225f;
  --navy-3: #091238;
  --ink: #050a24;
  --cyan: #29e0ff;
  --lime: #b8ff2a;
  --magenta: #ff2fb3;
  --pink: #ff4fa0;
  --yellow: #ffd23f;
  --purple: #6a2fd0;
  --white: #ffffff;
  --plate: #ffffff;
  --plate-ink: #111111;

  /* Challenge tiers. Gold IS the yellow the power play already wears, so the palette does not
     grow a third warm hue; bronze and silver are the only two new colours in the game. */
  --bronze: #e2853a;
  --silver: #c9d8ee;
  --gold: #ffd23f;

  --line: rgba(196, 224, 255, 0.42);
  --line-soft: rgba(196, 224, 255, 0.22);
  --dim: rgba(226, 240, 255, 0.66);
  --dim-2: rgba(226, 240, 255, 0.34);

  /* One radius scale for the whole skin. Nothing in MAXIMUM has a square corner: micro chips
     take --r-s, panels and tiles --r-m, buttons and rows --r-l, cards and sheets --r-xl, and
     anything that reads as a bar or a pill takes --r-pill. Skewed bars keep their skew and
     wear --r-pill, so the ends round off into the slant instead of ending in a spike. */
  --r-s: 6px;
  --r-m: 10px;
  --r-l: 14px;
  --r-xl: 20px;
  --r-pill: 999px;
  --sa-t: env(safe-area-inset-top, 0px);
  --sa-b: env(safe-area-inset-bottom, 0px);
  --sa-l: env(safe-area-inset-left, 0px);
  --sa-r: env(safe-area-inset-right, 0px);

  --ui: 'Montserrat', 'Helvetica Neue', Arial, system-ui, sans-serif;
  --display: 'Titan One', 'Lilita One', 'Montserrat', 'Helvetica Neue', Arial, system-ui, sans-serif;
  /* One lean, one value. Banners and the hero pop-up wear it; nothing else does. */
  --skew: -7deg;

  --shadow: 0 14px 40px rgba(0, 0, 0, 0.6);
  --panel-bg: linear-gradient(180deg, #17275f 0%, #0d1b4c 62%, #0a1540 100%);
  color-scheme: dark;
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; -webkit-touch-callout: none; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  overflow: hidden;
  background: var(--ink);
  color: var(--white);
  font-family: var(--ui);
  overscroll-behavior: none;
  /* No double-tap zoom or long-press selection anywhere; the two scroll panes below
     opt back in with pan-y, and the canvas locks everything out with touch-action: none. */
  touch-action: manipulation;
  -webkit-user-select: none;
  user-select: none;
}

body { position: fixed; inset: 0; }

#game {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  touch-action: none;
  background: linear-gradient(#0a1540, #14225f 45%, #1f6b46);
}

/* --------------------------------------------------------------------- root */

.ui-root {
  position: fixed;
  inset: 0;
  z-index: 10;
  pointer-events: none;
  user-select: none;
  -webkit-user-select: none;
  font-family: var(--ui);
  font-synthesis: none;
  overflow: hidden;
  contain: strict;
}

.ui-root .hidden { display: none !important; }

/* Heavy outline: every slab that carries a data-t twin paints that twin underneath itself,
   stroked wide in the outline colour. The fill on top then leaves a clean thick edge, and the
   counters of 4, 6 and O read dark, exactly like a broadcast graphic. --otl-w is the stroke
   width (half of it shows, the inner half is covered) and --otl-c the outline colour. */

/* Legibility scrims over a bright 3D scene. */
.scrim { position: absolute; left: 0; right: 0; pointer-events: none; }
.scrim-top {
  top: 0; height: 27%;
  background: linear-gradient(to bottom, rgba(5, 10, 36, 0.78), rgba(5, 10, 36, 0.26) 52%, transparent);
}
.scrim-bot {
  bottom: 0; height: 20%;
  background: linear-gradient(to top, rgba(5, 10, 36, 0.6), transparent);
}

/* ==========================================================================
   HUD
   Row 1: two navy panels. Row 2: two white name plates. Row 3: chips + pause.
   ========================================================================== */

.hud {
  position: absolute;
  top: calc(var(--sa-t) + 8px);
  left: calc(var(--sa-l) + 9px);
  right: calc(var(--sa-r) + 9px);
  display: flex;
  flex-direction: column;
  gap: 7px;
  opacity: 0;
  transform: translateY(-10px);
  transition: opacity .22s ease, transform .22s ease;
  pointer-events: none;
}
.hud.is-on { opacity: 1; transform: none; }

.hud-panels { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; align-items: stretch; }

.npanel {
  position: relative;
  min-width: 0;
  padding: 5px 8px 6px;
  border-radius: var(--r-m);
  border: 1.5px solid var(--line);
  background: var(--panel-bg);
  box-shadow: 0 5px 16px rgba(0, 0, 0, .5), inset 0 1px 0 rgba(255, 255, 255, .14);
  display: flex;
  flex-direction: column;
  gap: 3px;
}

/* ---- left panel: scoreline + run rate ---- */

.np-score {
  display: flex;
  align-items: baseline;
  gap: 3px;
  min-width: 0;
  font-family: var(--ui);
  font-weight: 800;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.score-team {
  font-size: 11px;
  letter-spacing: 0.02em;
  color: var(--cyan);
  margin-right: 1px;
}
.score-runs {
  font-size: 19px;
  letter-spacing: -.01em;
  color: var(--white);
  display: inline-block;
  transform-origin: 50% 78%;
  text-shadow: 0 2px 8px rgba(0, 0, 0, .6);
}
.score-runs.bump { animation: bump .34s cubic-bezier(.2, 1.6, .4, 1); }
@keyframes bump { 0% { transform: scale(1.34); } 60% { transform: scale(.96); } 100% { transform: scale(1); } }
.score-slash { font-size: 13px; color: var(--dim-2); }
.score-wkts { font-size: 13px; color: var(--white); }
.score-tgt {
  margin-left: auto;
  display: inline-flex;
  align-items: baseline;
  gap: 3px;
  font-size: 9.5px;
  letter-spacing: 0.02em;
  color: var(--cyan);
}
.score-cap { font-weight: 800; letter-spacing: 0.034em; opacity: .8; }
.score-target { font-size: 11px; color: var(--cyan); }

/* One line, one job: the chase, and only while there is one. It holds its own height so
   switching it on never nudges the scoreline above it. */
.np-rate {
  display: flex;
  align-items: center;
  min-height: 17px;
  min-width: 0;
  white-space: nowrap;
}
.need-chip {
  margin-left: auto;
  padding: 2px 8px 3px;
  border-radius: var(--r-s);
  border: 1.2px solid var(--line-soft);
  background: rgba(5, 10, 36, .5);
  font-size: 8px;
  font-weight: 800;
  letter-spacing: 0.024em;
  color: var(--white);
  opacity: 0;
  transition: opacity .16s ease;
  white-space: nowrap;
}
.need-chip.is-on { opacity: 1; }
.need-chip.has-band { border-color: var(--band); color: var(--band); }
.need-chip.is-hot {
  background: var(--band, var(--magenta));
  border-color: rgba(255, 255, 255, .8);
  color: var(--ink);
}
.need-chip.is-done {
  background: var(--lime);
  border-color: rgba(255, 255, 255, .8);
  color: #10240a;
  animation: none;
}
.need-chip.jolt { animation: needJolt .32s cubic-bezier(.2, 1.7, .4, 1); }
@keyframes needJolt {
  0% { transform: scale(.7); }
  60% { transform: scale(1.18); }
  100% { transform: scale(1); }
}

/* ---- right panel: overs + this-over ball strip ---- */

.npanel-r { align-items: flex-end; }
.np-overs {
  display: flex;
  align-items: baseline;
  gap: 4px;
  white-space: nowrap;
  line-height: 1;
}
.overs-cap {
  font-size: 8px;
  font-weight: 700;
  letter-spacing: 0.054em;
  color: var(--dim);
}
.overs-val {
  font-weight: 800;
  font-size: 13px;
  letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--white);
}
.overs-tot { font-size: 9.5px; font-weight: 700; color: var(--cyan); }

.ball-dots { display: flex; gap: 3px; justify-content: flex-end; }
.dot {
  width: 19px;
  height: 19px;
  border-radius: var(--r-s);
  background: rgba(5, 10, 36, .5);
  border: 1.2px solid rgba(196, 224, 255, .24);
  display: flex;
  align-items: center;
  justify-content: center;
  font-style: normal;
  transform-origin: 50% 50%;
  flex: 0 0 auto;
}
.dot > b {
  font-family: var(--ui);
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: -.01em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.dot.is-next { border-color: var(--cyan); box-shadow: 0 0 0 2px rgba(41, 224, 255, .24); }
.dot.filled { border-color: transparent; }
.dot.k6 { background: var(--lime); color: #142200; box-shadow: 0 0 12px rgba(184, 255, 42, .5); }
.dot.k4 { background: var(--cyan); color: #002230; }
.dot.kw { background: var(--magenta); color: #ffffff; box-shadow: 0 0 12px rgba(255, 47, 179, .5); }
.dot.kd { background: rgba(5, 10, 36, .58); border-color: rgba(196, 224, 255, .3); color: var(--dim); }
.dot.kwd { background: var(--yellow); color: #2a1c00; }
.dot.kwd > b { font-size: 8px; letter-spacing: 0; }
.dot.filled:not(.kd):not(.kw) { color: #071228; }
.dot.filled:not(.kd):not(.kw):not(.k6):not(.k4):not(.kwd) { background: var(--white); }
.dot.pop { animation: dotpop .34s cubic-bezier(.2, 1.7, .4, 1); }
@keyframes dotpop { 0% { transform: scale(.4) rotate(-12deg); } 65% { transform: scale(1.2); } 100% { transform: scale(1); } }

/* ---- tier bar: how close this over is to the next tier ----
   A single slim row under the panels: what is being counted on the left, the track with its
   bronze / silver / gold ticks in the middle, the live number against the next target on the
   right. Hidden entirely outside a challenge, so the classic HUD is unchanged. */

.hud-tier {
  --fill: 0;
  display: none;
  align-items: center;
  gap: 8px;
  height: 22px;
  padding: 0 9px;
  border-radius: var(--r-pill);
  border: 1.2px solid var(--line-soft);
  background: rgba(5, 10, 36, .62);
  box-shadow: 0 4px 14px rgba(0, 0, 0, .45);
}
.hud-tier.is-on { display: flex; }
.tier-cap {
  flex: 0 0 auto;
  max-width: 40%;
  font-size: 7.5px;
  font-weight: 800;
  letter-spacing: 0.086em;
  color: var(--dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tier-track {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
  height: 7px;
  border-radius: var(--r-pill);
  background: rgba(196, 224, 255, .2);
  box-shadow: inset 0 0 0 1px rgba(5, 10, 36, .5);
  overflow: hidden;
}
/* The fill and the ticks are inset by the same 2 px, so a gold tick sits inside the rounded
   end instead of being clipped by it, and a full bar lands exactly on it. */
.tier-fill {
  position: absolute;
  left: 2px;
  right: 2px;
  top: 0;
  bottom: 0;
  border-radius: var(--r-pill);
  background: linear-gradient(90deg, rgba(41, 224, 255, .55), var(--tier-now, var(--cyan)));
  transform: scaleX(var(--fill));
  transform-origin: 0 50%;
  transition: transform .32s cubic-bezier(.2, .9, .3, 1), background .3s ease;
}
.tier-tick {
  position: absolute;
  top: -1px;
  bottom: -1px;
  left: calc(2px + (100% - 4px) * var(--at, 0));
  width: 3px;
  margin-left: -1.5px;
  border-radius: 1px;
  background: var(--tick, var(--line));
  /* A dark hairline so a silver tick still reads on top of a pale silver fill. */
  box-shadow: 0 0 0 1px rgba(5, 10, 36, .8);
}
.tier-tick.t-bronze { --tick: var(--bronze); }
.tier-tick.t-silver { --tick: var(--silver); }
.tier-tick.t-gold { --tick: var(--gold); }
.tier-read {
  flex: 0 0 auto;
  display: flex;
  align-items: baseline;
  gap: 2px;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}
.tier-val {
  font-family: var(--display);
  font-size: 13px;
  color: var(--tier-now, var(--white));
  transition: color .3s ease;
}
.tier-goal { font-size: 8.5px; font-weight: 800; letter-spacing: 0.02em; color: var(--dim-2); }
.tier-goal:empty { display: none; }

.hud-tier.t-bronze { --tier-now: var(--bronze); }
.hud-tier.t-silver { --tier-now: var(--silver); }
.hud-tier.t-gold { --tier-now: var(--gold); }
.hud-tier.t-gold { border-color: rgba(255, 210, 63, .55); }

/* Crossing a tier is the only moment this bar is allowed to shout. */
.hud-tier.cross { animation: tierCross .62s cubic-bezier(.2, 1.3, .4, 1); }
@keyframes tierCross {
  0% { transform: scale(1); box-shadow: 0 4px 14px rgba(0, 0, 0, .45); }
  24% { transform: scale(1.045); box-shadow: 0 0 0 3px var(--tier-now, var(--cyan)), 0 6px 20px rgba(0, 0, 0, .5); }
  100% { transform: scale(1); box-shadow: 0 4px 14px rgba(0, 0, 0, .45); }
}
@media (prefers-reduced-motion: reduce) {
  .hud-tier.cross { animation: none; }
  .tier-fill { transition: none; }
}

/* The tier bar adds a row to the HUD, so the pop-up band drops with it and the six over
   midwicket still lands clear of the scoreline. */
.ui-root.has-tier .center-stack { top: calc(var(--sa-t) + 187px); }

/* ---- white name plates ---- */

.hud-plates { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.plate {
  position: relative;
  min-width: 0;
  padding: 4px 9px 5px;
  border-radius: var(--r-m);
  background: var(--plate);
  color: var(--plate-ink);
  box-shadow: 0 4px 12px rgba(0, 0, 0, .45);
  overflow: hidden;
}
.plate-bowl { text-align: right; }

/* 24x16 flag slot, one in each plate. Empty it reads as the team's colour flash; a World Tour
   flag drops in as an <img> or an <svg> child and fills it edge to edge. */
.plate-flag {
  flex: 0 0 auto;
  display: block;
  width: 24px;
  height: 16px;
  border-radius: 4px;
  overflow: hidden;
  background: linear-gradient(160deg, var(--lime), #7cc400);
  box-shadow: inset 0 0 0 1px rgba(5, 10, 36, .22);
}
.plate-bowl .plate-flag { background: linear-gradient(160deg, var(--magenta), #b8007a); }
.plate-flag > * { display: block; width: 100%; height: 100%; object-fit: cover; }
/* With a flag in it the slot stops being a colour block, so it drops the tint and keeps only
   the hairline that separates a pale flag from the white plate. */
.plate-flag.has-flag { background: var(--navy-3); box-shadow: inset 0 0 0 1px rgba(5, 10, 36, .38); }

.plate-main {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  font-weight: 800;
  font-size: 11px;
  line-height: 1.16;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  white-space: nowrap;
}
.plate-bowl .plate-main { justify-content: flex-end; }
.bat-who, .bowler-pill { overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.bat-runs { margin-left: auto; font-variant-numeric: tabular-nums; color: #0c2f66; }
/* The player's jersey number, right where a broadcast graphic puts it: hard against the name,
   quieter than it, and gone entirely until a profile exists. */
.bat-num {
  flex: 0 0 auto;
  margin-left: -2px;
  font-style: normal;
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 0;
  color: #6b7a90;
  font-variant-numeric: tabular-nums;
}
.bat-num:empty { display: none; }

.plate-sub {
  display: flex;
  align-items: center;
  gap: 3px;
  min-width: 0;
  font-weight: 800;
  font-size: 8px;
  letter-spacing: 0.041em;
  line-height: 1.2;
  color: #4a5a72;
  white-space: nowrap;
}
.plate-bowl .plate-sub { justify-content: flex-end; }
.bowl-type { overflow: hidden; text-overflow: ellipsis; }
.bowl-type.is-empty::after { content: "READY"; }
/* While a delivery is on its way the line is the ball itself, so it takes the bowler's own
   magenta and a little more weight than the standing "LEG SPIN" it replaces. */
.plate-bowl.is-live .bowl-type { color: #c9007a; font-weight: 800; letter-spacing: 0.02em; }

.streak-flame { display: block; width: 8px; height: 8px; flex: 0 0 auto; color: #b4c0d2; }
.streak-flame svg { width: 100%; height: 100%; display: block; fill: currentColor; }
.streak-num { overflow: hidden; text-overflow: ellipsis; }
.streak-badge.is-fire { color: #c9007a; }
.streak-badge.is-fire .streak-flame { color: var(--magenta); }
.streak-badge.is-blazing { color: #7d00c9; }
.streak-badge.is-blazing .streak-flame { color: var(--purple); }
.streak-badge.ignite { animation: ignite .55s cubic-bezier(.2, 1.5, .4, 1); }
@keyframes ignite {
  0% { transform: scale(.7) translateX(-6px); }
  50% { transform: scale(1.12); }
  100% { transform: scale(1); }
}

/* ---- rail: level tag, live chips, square pause ---- */

.hud-rail {
  display: flex;
  align-items: center;
  gap: 6px;
  min-height: 26px;
}
.level-pill {
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  padding: 2px 2px 3px;
  font-size: 8px;
  font-weight: 800;
  letter-spacing: 0.061em;
  text-transform: uppercase;
  color: rgba(226, 240, 255, .68);
  text-shadow: 0 1px 6px rgba(0, 0, 0, .95);
}

.rail-chips {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 5px;
  min-width: 0;
}
.pp-badge, .wind-chip, .ghost-chip {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 2px 6px 3px;
  border-radius: var(--r-s);
  font-size: 8px;
  font-weight: 800;
  letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  opacity: 0;
  transform: scale(.82);
  transition: opacity .2s ease, transform .2s ease;
}
.pp-badge.is-on, .wind-chip.is-on, .ghost-chip.is-on { opacity: 1; transform: none; }
.pp-badge { background: var(--yellow); color: #2a1c00; box-shadow: 0 0 14px rgba(255, 210, 63, .5); }
.pp-badge svg { width: 10px; height: 10px; fill: currentColor; display: block; }
.pp-badge.pp-in { animation: ppIn .5s cubic-bezier(.2, 1.6, .4, 1); }
@keyframes ppIn { 0% { transform: scale(.4) rotate(-14deg); } 55% { transform: scale(1.3); } 100% { transform: scale(1); } }

.wind-chip, .ghost-chip {
  background: rgba(9, 18, 56, .72);
  border: 1.2px solid var(--line-soft);
  color: var(--dim);
}
.wind-chip.is-strong { border-color: rgba(41, 224, 255, .6); color: var(--cyan); }
.wind-chip svg, .ghost-chip svg { width: 10px; height: 10px; fill: currentColor; display: block; }
.wind-arrow { display: block; width: 10px; height: 10px; color: var(--cyan); }
.ghost-chip.is-ahead { border-color: rgba(184, 255, 42, .55); color: var(--lime); }
.ghost-chip.is-behind { border-color: rgba(255, 79, 160, .55); color: var(--pink); }

/* Rounded outlined pause control, right of the rail. */
.btn-pause {
  position: relative;
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  border-radius: var(--r-m);
  border: 1.5px solid var(--line);
  background: rgba(9, 18, 56, .78);
  color: var(--white);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  cursor: pointer;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity .22s ease, visibility .22s, background .12s ease, transform .1s ease;
  touch-action: manipulation;
}
/* The glyph is 30px so the rail stays slim; the thumb gets the full 44px. */
.btn-pause::after { content: ""; position: absolute; inset: -7px; border-radius: var(--r-l); }
.btn-pause.is-on { opacity: 1; visibility: visible; pointer-events: auto; }
.btn-pause svg { width: 15px; height: 15px; fill: currentColor; display: block; }
.btn-pause:hover { background: rgba(41, 224, 255, .28); }
.btn-pause:active { transform: scale(.9); }

/* Streak heat bleeding into the scoreline. */
.hud.is-fire .score-runs { text-shadow: 0 0 16px rgba(255, 47, 179, .8), 0 2px 8px rgba(0, 0, 0, .7); }
.hud.is-blazing .score-runs { text-shadow: 0 0 22px rgba(184, 255, 42, .95), 0 2px 8px rgba(0, 0, 0, .7); }
.hud.has-pp .score-target { color: var(--yellow); }

/* ==========================================================================
   Centre pop-ups. Anchored to a fixed band in the TOP THIRD so the ball flight
   and the batter's head are never covered at contact.
   ========================================================================== */

.center-stack {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(var(--sa-t) + 158px);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  pointer-events: none;
}

/* Entrance and exit are separate forwards-filled animations, so the caller's
   `ms` really controls how long the banner stays up. */
.shot-name, .flash, .outcome {
  opacity: 0;
  visibility: hidden;
  will-change: transform, opacity;
  text-align: center;
  line-height: 1;
}
.shot-name.is-on, .flash.is-on, .outcome.is-on { visibility: visible; }

/* clearBall(): whatever exit a transient owns, it runs at 120 ms and then the element is gone.
   One rule covers all of them because they all fade out through their own anim-out. */
.is-clearing { animation-duration: .12s !important; animation-delay: 0s !important; }

/* ---- small timing word ---- */

.flash {
  position: relative;
  z-index: 2;
  min-height: 21px;
  font-family: var(--ui);
  font-size: clamp(13px, 3.6vmin, 19px);
  font-weight: 800;
  letter-spacing: 0.061em;
  text-transform: uppercase;
  color: var(--white);
  /* Its own dark keyline plus a soft navy pad, so the little word never dissolves into a
     bright crowd the way a plain drop shadow does. */
  --fl-key: rgba(5, 10, 36, .95);
  text-shadow:
    0 0 3px var(--fl-key), 0 0 3px var(--fl-key),
    1.5px 1.5px 0 var(--fl-key), -1.5px 1.5px 0 var(--fl-key),
    1.5px -1.5px 0 var(--fl-key), -1.5px -1.5px 0 var(--fl-key),
    0 0 16px rgba(5, 10, 36, .95), 0 3px 12px rgba(0, 0, 0, .9);
  transform-origin: 50% 50%;
  margin-bottom: 11px;
}
.flash.s-perfect { color: var(--lime); }
.flash.s-good { color: var(--cyan); }
.flash.s-bad { color: var(--yellow); }
.flash.s-info { color: rgba(255, 255, 255, .92); }
.flash.s-six { color: var(--lime); }
.flash.s-four { color: var(--cyan); }
.flash.s-wicket { color: var(--magenta); }
.flash.anim-pop { animation: flashIn .16s cubic-bezier(.2, 1.7, .4, 1) forwards; }
.flash.anim-out { animation: flashOut .18s ease-in forwards; }
@keyframes flashIn {
  0% { transform: scale(.6) translateY(6px); opacity: 0; }
  60% { transform: scale(1.12); opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}
@keyframes flashOut {
  from { transform: scale(1); opacity: 1; }
  to { transform: scale(.94) translateY(10px); opacity: 0; }
}

/* ---- the hero ---- */

.outcome {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1px;
  min-height: clamp(104px, 25.8vmin, 156px);
  width: 100%;
}
.outcome-burst {
  position: absolute;
  left: 50%;
  top: 50%;
  width: clamp(184px, 43vmin, 258px);
  height: clamp(184px, 43vmin, 258px);
  margin: -3% 0 0 0;
  transform: translate(-50%, -50%) scale(.2);
  opacity: 0;
  pointer-events: none;
}
.burst-svg { width: 100%; height: 100%; display: block; filter: drop-shadow(0 6px 14px rgba(4, 7, 26, .6)); }
/* Dark rim ring first, then magenta, then a hot-pink core: the star reads as one object
   against a bright crowd instead of dissolving into it. */
.burst-r { fill: #05081e; opacity: .92; }
.burst-o { fill: var(--magenta); }
.burst-i { fill: var(--pink); }
.outcome.k-six .outcome-burst { transform: translate(-50%, -50%) scale(1); opacity: .96; }

/* Four layers, bottom to top, so a numeral reads the same over the green outfield, the sand
   pitch and the pink stands:
     ::after   a dark navy backplate, blurred and held at 55% so it never becomes a box
     ::before  the fat black edge, carrying the hard offset shadow
     text-shadow  a thin white rim between the black edge and the fill
     colour    the fill itself
   --otl-w is the stroke width; half of it shows outside the glyph, so 18px reads as a 9px edge. */
.outcome-main {
  position: relative;
  display: block;
  font-family: var(--display);
  font-size: clamp(50px, 14.6vmin, 79px);
  font-weight: 400;
  letter-spacing: -.005em;
  line-height: .96;
  text-transform: uppercase;
  color: var(--lime);
  transform: skewX(var(--skew));
  --otl-w: 14px;
  --otl-c: #05081e;
  --pop-back: #050f38;
  --pop-blur: 11px;
  --pop-drop: 5px 7px 0 rgba(4, 7, 26, .92);
  --pop-rim: 1.6px;
  text-shadow:
    0 calc(var(--pop-rim) * -1) 0 rgba(255, 255, 255, .95),
    var(--pop-rim) 0 0 rgba(255, 255, 255, .6),
    calc(var(--pop-rim) * -1) 0 0 rgba(255, 255, 255, .6),
    0 var(--pop-rim) 0 rgba(255, 255, 255, .34);
}
.outcome-main::before {
  content: attr(data-t);
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  z-index: -1;
  color: var(--otl-c);
  -webkit-text-stroke: var(--otl-w) var(--otl-c);
  text-shadow: var(--pop-drop);
  pointer-events: none;
}
.outcome-main::after {
  content: attr(data-t);
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  z-index: -2;
  color: var(--pop-back);
  -webkit-text-stroke: calc(var(--otl-w) * 2.1) var(--pop-back);
  filter: blur(var(--pop-blur));
  opacity: .58;
  pointer-events: none;
}
/* The boundary calls are the big ones: a full-height slab with a fat black edge. Lime for the
   six and cyan for the four, matching the ball strip in the HUD. */
.outcome.k-six .outcome-main,
.outcome.k-four .outcome-main {
  font-size: clamp(82.5px, 25.8vmin, 144.5px);
  --otl-w: 20px;
  --pop-blur: 16px;
  --pop-drop: 7px 10px 0 rgba(4, 7, 26, .94);
  --pop-rim: 2.4px;
}
.outcome.k-six { min-height: clamp(150px, 35.3vmin, 208px); }
.outcome.k-six .outcome-main { color: var(--lime); }
.outcome.k-four .outcome-main { color: var(--cyan); }
.outcome.k-runs .outcome-main { font-size: clamp(43px, 12.9vmin, 70.5px); --otl-w: 13px; }
.outcome.k-out .outcome-main { color: var(--white); font-size: clamp(51.5px, 16.3vmin, 94.5px); --otl-w: 17px; --pop-blur: 14px; --pop-rim: 2px; }
.outcome.k-dot .outcome-main { color: rgba(255, 255, 255, .94); font-size: clamp(29px, 8.6vmin, 46.5px); --otl-w: 11px; }
.outcome.k-extra .outcome-main { color: var(--yellow); font-size: clamp(34.5px, 10.3vmin, 55px); --otl-w: 12px; }
.outcome.k-free .outcome-main { color: var(--cyan); font-size: clamp(34.5px, 10.3vmin, 55px); --otl-w: 12px; }
.outcome.k-drop .outcome-main { color: var(--yellow); font-size: clamp(36px, 11.2vmin, 60px); --otl-w: 13px; }
.outcome.k-safe .outcome-main { color: var(--cyan); font-size: clamp(36px, 11.2vmin, 60px); --otl-w: 13px; }

/* Second tone: the shout. Same four layers as the hero, at half the weight, so a long call
   like INTO THE STANDS! still cuts through a crowd shot. */
.outcome-sub {
  position: relative;
  display: block;
  max-width: 94vw;
  margin-top: 10px;
  font-family: var(--display);
  font-size: clamp(16.5px, 4.6vmin, 27.5px);
  letter-spacing: 0.02em;
  line-height: 1;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--magenta);
  transform: skewX(var(--skew));
  --otl-w: 8px;
  --otl-c: #05081e;
  --pop-back: #050f38;
  --pop-drop: 3px 4px 0 rgba(4, 7, 26, .9);
  text-shadow:
    0 -1px 0 rgba(255, 255, 255, .8),
    1px 0 0 rgba(255, 255, 255, .45),
    -1px 0 0 rgba(255, 255, 255, .45);
  transition: opacity .12s linear;
}
.outcome-sub::before {
  content: attr(data-t);
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  z-index: -1;
  color: var(--otl-c);
  -webkit-text-stroke: var(--otl-w) var(--otl-c);
  text-shadow: var(--pop-drop);
  pointer-events: none;
}
.outcome-sub::after {
  content: attr(data-t);
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  z-index: -2;
  color: var(--pop-back);
  -webkit-text-stroke: calc(var(--otl-w) * 2.2) var(--pop-back);
  filter: blur(8px);
  opacity: .55;
  pointer-events: none;
}
.outcome-sub.is-empty { display: none; }
/* The six's shout sits over its own magenta starburst, so it takes the yellow. */
.outcome.k-six .outcome-sub { color: var(--yellow); }
.outcome.k-four .outcome-sub { color: var(--white); }
.outcome.k-extra .outcome-sub, .outcome.k-free .outcome-sub { color: var(--white); }
.outcome.k-safe .outcome-sub { color: var(--lime); }

/* One spring in, one fade out. That is the whole vocabulary for a result: the burst, the
   numeral and the shout all ride this single animation instead of each running their own. */
.outcome.anim-slam { animation: slamIn .26s cubic-bezier(.1, 1.7, .3, 1) forwards; }
.outcome.anim-out { animation: slamOut .18s ease-in forwards; }
@keyframes slamIn {
  0% { transform: scale(1.7) translateY(-12px); opacity: 0; }
  60% { transform: scale(.96); opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}
@keyframes slamOut {
  from { transform: scale(1); opacity: 1; }
  to { transform: scale(.94) translateY(16px); opacity: 0; }
}

/* ---- caption below the hero: shot name or coaching line ---- */

.shot-name {
  position: relative;
  z-index: 2;
  min-height: 22px;
  max-width: 92vw;
  padding: 2px 12px 3px;
  font-size: clamp(10.5px, 2.9vmin, 14.5px);
  font-weight: 800;
  letter-spacing: 0.048em;
  text-transform: uppercase;
  transform: skewX(var(--skew));
  border-radius: var(--r-pill);
}
.shot-name.is-shot {
  background: var(--white);
  color: var(--plate-ink);
  box-shadow: 0 5px 16px rgba(0, 0, 0, .55);
}
.shot-name.is-coach {
  background: var(--magenta);
  color: var(--white);
  box-shadow: 0 5px 16px rgba(0, 0, 0, .55), 0 0 22px rgba(255, 47, 179, .38);
}
.shot-name.anim-slam { animation: capIn .18s ease-out forwards; }
.shot-name.anim-out { animation: capOut .16s ease-in forwards; }
@keyframes capIn {
  from { transform: skewX(var(--skew)) translateY(5px); opacity: 0; }
  to { transform: skewX(var(--skew)) translateY(0); opacity: 1; }
}
@keyframes capOut {
  from { transform: skewX(var(--skew)) translateY(0); opacity: 1; }
  to { transform: skewX(var(--skew)) translateY(8px); opacity: 0; }
}

/* ------------------------------------------------------------- timing bar   */
/* Where the tap landed inside the swing window. --g and --a (the PERFECT and GOOD half
   widths) are stamped from CONFIG by ui.js so the zones cannot drift from the rules.
   Parked under the stack so switching it on never moves the hero. */

.timing-bar {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(100% + 6px);
  display: flex;
  flex-direction: column;
  align-items: center;
  opacity: 0;
  transition: opacity .16s ease;
}
.timing-bar.is-on { opacity: 1; }
.timing-bar.anim-in { animation: tmIn .22s cubic-bezier(.2, 1.5, .4, 1); }
@keyframes tmIn { from { transform: scaleX(.7); opacity: 0; } to { transform: scaleX(1); opacity: 1; } }

.timing-track {
  --g: 12.5%;
  --a: 27.8%;
  position: relative;
  width: min(52vw, 210px);
  height: 6px;
  border-radius: var(--r-pill);
  box-shadow: inset 0 0 0 1.5px rgba(255, 255, 255, .24), 0 2px 10px rgba(0, 0, 0, .6);
  background: linear-gradient(90deg,
    #7a1060 0, #7a1060 calc(50% - var(--a)),
    var(--magenta) calc(50% - var(--a)), var(--magenta) calc(50% - var(--g)),
    var(--lime) calc(50% - var(--g)), var(--lime) calc(50% + var(--g)),
    var(--magenta) calc(50% + var(--g)), var(--magenta) calc(50% + var(--a)),
    #7a1060 calc(50% + var(--a)), #7a1060 100%);
}
.timing-fill {
  position: absolute;
  inset: 0;
  transform: translateX(calc(var(--tp, 0) * 50%));
  transition: transform .2s cubic-bezier(.2, 1.3, .4, 1);
}
.timing-needle {
  position: absolute;
  top: -4px;
  bottom: -4px;
  left: 50%;
  width: 3px;
  margin-left: -1.5px;
  border-radius: var(--r-pill);
  background: var(--white);
  box-shadow: 0 0 8px rgba(0, 0, 0, .95);
}
.timing-ms {
  margin-top: 5px;
  padding: 1px 9px 2px;
  border-radius: var(--r-pill);
  background: rgba(5, 10, 36, .78);
  font-size: 8px;
  font-weight: 800;
  letter-spacing: 0.061em;
  font-variant-numeric: tabular-nums;
  color: var(--dim);
  text-shadow: 0 2px 8px rgba(0, 0, 0, .9);
}
.timing-bar.t-perfect .timing-ms { color: var(--lime); }
.timing-bar.t-good .timing-ms { color: var(--cyan); }
.timing-bar.t-off .timing-ms { color: var(--yellow); }
.timing-bar.t-miss .timing-ms { color: var(--pink); }
.timing-bar.t-perfect .timing-needle { box-shadow: 0 0 12px rgba(184, 255, 42, .95); }

/* ---------------------------------------------------------------- review    */

.review-wrap {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(100% + 36px);
  display: flex;
  justify-content: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity .18s ease;
}
.review-wrap.is-on { opacity: 1; pointer-events: auto; }
.review-wrap.anim-in { animation: revIn .26s cubic-bezier(.2, 1.5, .4, 1); }
@keyframes revIn { from { transform: translateY(10px) scale(.9); opacity: 0; } to { transform: none; opacity: 1; } }

.btn-review {
  position: relative;
  min-height: 44px;
  padding: 0 18px 0 44px;
  border-radius: var(--r-l);
  border: 2px solid var(--cyan);
  background: rgba(9, 18, 56, .94);
  color: var(--cyan);
  font-family: var(--ui);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.061em;
  display: inline-flex;
  align-items: center;
  cursor: pointer;
  touch-action: manipulation;
  box-shadow: 0 6px 22px rgba(0, 0, 0, .6), 0 0 22px rgba(41, 224, 255, .26);
}
.btn-review:active { transform: scale(.95); }
.review-ring { position: absolute; left: 5px; top: 50%; width: 32px; height: 32px; margin-top: -16px; }
.review-ring-bg { stroke: rgba(255, 255, 255, .18); }
/* stroke-dashoffset is a paint-only property: the ring drains without touching layout. */
.review-ring-fg { stroke: var(--cyan); stroke-dasharray: 106.8; stroke-dashoffset: 0; }
.review-ring-fg.ring-drain { animation: ringDrain 2500ms linear forwards; }
@keyframes ringDrain { from { stroke-dashoffset: 0; } to { stroke-dashoffset: 106.8; } }
.review-ico { position: absolute; left: 13px; top: 50%; width: 16px; height: 16px; margin-top: -8px; }
.review-ico svg { width: 100%; height: 100%; display: block; fill: var(--cyan); }

/* ==========================================================================
   Diagonal two-tone banner: streaks, power play, badges.
   ========================================================================== */

.dbanner {
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(var(--sa-b) + 124px);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  opacity: 0;
  pointer-events: none;
  will-change: transform, opacity;
}
.db-bar {
  display: block;
  border-radius: var(--r-pill);
  max-width: 96vw;
  padding: 4px 26px 5px;
  transform: skewX(var(--skew));
  box-shadow: 0 8px 26px rgba(0, 0, 0, .55);
}
.db-a { background: var(--lime); align-self: center; margin-right: 12%; }
.db-b { background: var(--magenta); align-self: center; margin-left: 12%; }
.db-t {
  display: block;
  position: relative;
  transform: skewX(calc(var(--skew) * -1));
  font-family: var(--ui);
  font-weight: 800;
  font-size: clamp(15.5px, 4.5vmin, 26px);
  letter-spacing: 0.02em;
  line-height: 1.08;
  color: var(--white);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  --otl-w: 5px;
  --otl-c: #0a1030;
}
.db-t::before {
  content: attr(data-t);
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  z-index: -1;
  color: var(--otl-c);
  -webkit-text-stroke: var(--otl-w) var(--otl-c);
  pointer-events: none;
}
.db-b .db-t { font-size: clamp(10.5px, 3.1vmin, 17px); letter-spacing: 0.041em; }
.dbanner.t-power .db-a { background: var(--yellow); }
.dbanner.t-badge .db-a { background: var(--cyan); }
.dbanner.t-badge .db-b { background: var(--purple); }

.dbanner.anim-slam .db-a { animation: dbLeft .34s cubic-bezier(.12, 1.5, .3, 1) both; }
.dbanner.anim-slam .db-b { animation: dbRight .34s .07s cubic-bezier(.12, 1.5, .3, 1) both; }
.dbanner.anim-slam { animation: dbShow .01s linear forwards; }
.dbanner.anim-out { animation: dbHide .22s ease-in forwards; }
@keyframes dbShow { to { opacity: 1; } }
@keyframes dbHide { from { opacity: 1; transform: none; } to { opacity: 0; transform: translateY(16px); } }
@keyframes dbLeft {
  0% { transform: skewX(var(--skew)) translateX(-130vw); }
  70% { transform: skewX(var(--skew)) translateX(2%); }
  100% { transform: skewX(var(--skew)) translateX(0); }
}
@keyframes dbRight {
  0% { transform: skewX(var(--skew)) translateX(130vw); }
  70% { transform: skewX(var(--skew)) translateX(-2%); }
  100% { transform: skewX(var(--skew)) translateX(0); }
}

/* ------------------------------------------------------- v6 swipe feedback */

.aim-trail {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
.aim-chip {
  position: absolute;
  left: 0;
  top: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
  padding: 6px 14px 7px;
  border-radius: var(--r-pill, 999px);
  background: rgba(9, 18, 56, .82);
  border: 2px solid var(--lime);
  box-shadow: 0 6px 18px rgba(0, 0, 0, .35);
  color: #fff;
  pointer-events: none;
  opacity: 0;
  transform: translate(-999px, -999px);
  transition: opacity .08s linear, transform .05s linear;
  white-space: nowrap;
  will-change: transform;
}
.aim-chip.is-on { opacity: 1; }
.aim-chip .aim-shot {
  font-family: var(--font-display, inherit);
  font-weight: 800;
  font-size: 15px;
  letter-spacing: .02em;
  line-height: 1;
  color: var(--lime);
}
.aim-chip .aim-where {
  font-style: normal;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .12em;
  color: rgba(255, 255, 255, .78);
}
.aim-chip[data-risk='blocked'] { border-color: #ffa01e; }
.aim-chip[data-risk='blocked'] .aim-shot { color: #ffa01e; }
.aim-chip[data-risk='loft'] { border-color: var(--magenta); }
.aim-chip[data-risk='loft'] .aim-shot { color: var(--magenta); }
.aim-chip[data-risk='loft'] .aim-where { color: var(--magenta); }

/* --------------------------------------------------------- edge flash      */

.edge-flash {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  --edge: rgba(184, 255, 42, .85);
  background: radial-gradient(120% 90% at 50% 50%, transparent 40%, var(--edge) 100%);
}
.edge-flash.e-lime { --edge: rgba(184, 255, 42, .8); }
.edge-flash.e-cyan { --edge: rgba(41, 224, 255, .78); }
.edge-flash.e-magenta { --edge: rgba(255, 47, 179, .8); }
.edge-flash.anim-edge { animation: edgePulse .42s ease-out forwards; }
@keyframes edgePulse {
  0% { opacity: 0; transform: scale(1.06); }
  18% { opacity: 1; transform: scale(1); }
  100% { opacity: 0; transform: scale(1); }
}

/* ------------------------------------------------------------------ toast  */

.toast {
  position: absolute;
  left: 50%;
  bottom: calc(var(--sa-b) + 22px);
  transform: translate(-50%, 10px);
  padding: 8px 16px 9px;
  border-radius: var(--r-l);
  border: 1.5px solid var(--line-soft);
  background: rgba(9, 18, 56, .94);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  width: max-content;
  max-width: min(84vw, 460px);
  text-align: center;
  opacity: 0;
  transition: opacity .2s ease, transform .2s ease;
}
.toast.is-on { opacity: 1; transform: translate(-50%, 0); }

/* --------------------------------------------------------- field-move strip */

.field-toast {
  position: absolute;
  left: 50%;
  bottom: calc(var(--sa-b) + 132px);
  transform: translate(-50%, 8px);
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 5px 12px 6px;
  border-radius: var(--r-l);
  background: rgba(9, 18, 56, .9);
  border: 1.5px solid rgba(41, 224, 255, .45);
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: 0.041em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .94);
  white-space: nowrap;
  max-width: 86vw;
  overflow: hidden;
  text-overflow: ellipsis;
  opacity: 0;
  pointer-events: none;
  transition: opacity .2s ease, transform .2s ease;
}
.field-toast.is-on { opacity: 1; transform: translate(-50%, 0); }
.field-toast svg { width: 11px; height: 11px; fill: var(--cyan); display: block; flex: 0 0 auto; transform: rotate(90deg); }
.field-toast.anim-in { animation: ftIn .3s cubic-bezier(.2, 1.4, .4, 1); }
@keyframes ftIn {
  from { transform: translate(-50%, 12px) scale(.94); opacity: 0; }
  to { transform: translate(-50%, 0) scale(1); opacity: 1; }
}

/* ------------------------------------------------------------ bowler card   */

.bowler-card {
  position: absolute;
  left: 50%;
  top: 62%;
  transform: translate(-50%, -50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 10px 22px 12px;
  border-radius: var(--r-l);
  background: var(--panel-bg);
  border: 1.5px solid var(--line);
  box-shadow: var(--shadow), 0 0 40px rgba(41, 224, 255, .18);
  width: max-content;
  max-width: min(88vw, 420px);
  opacity: 0;
  pointer-events: none;
  will-change: transform, opacity;
}
.bc-nick { font-size: 8.5px; font-weight: 800; letter-spacing: 0.095em; color: var(--cyan); }
.bc-name {
  font-family: var(--display);
  font-size: clamp(20.5px, 6vmin, 34.5px);
  letter-spacing: 0.02em;
  line-height: 1;
  color: var(--white);
  text-shadow: 0 4px 16px rgba(0, 0, 0, .8);
}
.bc-meta {
  padding: 3px 11px 4px;
  border-radius: var(--r-s);
  background: var(--white);
  color: var(--plate-ink);
  font-size: 8.5px;
  font-weight: 800;
  letter-spacing: 0.048em;
  white-space: nowrap;
}
.bc-tell {
  font-size: 8.5px;
  font-weight: 800;
  letter-spacing: 0.068em;
  color: var(--lime);
  text-transform: uppercase;
}
.bc-tell.is-none { color: var(--dim); }
.bowler-card.anim-slam { animation: bcIn .24s cubic-bezier(.12, 1.5, .3, 1) forwards; }
.bowler-card.anim-out { animation: bcOut .2s ease-in forwards; }
@keyframes bcIn {
  0% { transform: translate(-50%, -50%) skewX(-18deg) scale(1.35); opacity: 0; }
  60% { transform: translate(-50%, -50%) skewX(0deg) scale(1.04); opacity: 1; }
  100% { transform: translate(-50%, -50%) scale(1); opacity: 1; }
}
@keyframes bcOut {
  from { transform: translate(-50%, -50%) scale(1); opacity: 1; }
  to { transform: translate(-50%, -50%) scale(1.06) translateY(-12px); opacity: 0; }
}

/* ------------------------------------------------- level intro slam banner */
/* Non-blocking: only the banner itself takes pointer events (tap = start now). */

.intro-banner {
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(var(--sa-b) + 118px);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 9px;
  opacity: 0;
  pointer-events: none;
  will-change: transform, opacity;
  cursor: pointer;
  touch-action: manipulation;
}
.intro-banner.is-on { pointer-events: auto; }
.ib-bar {
  position: relative;
  display: block;
  border-radius: var(--r-pill);
  max-width: 94vw;
  padding: 4px 26px 5px;
  transform: skewX(var(--skew));
  font-weight: 800;
  text-transform: uppercase;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--white);
  box-shadow: 0 8px 24px rgba(0, 0, 0, .55);
  --otl-w: 4px;
  --otl-c: #0a1030;
}
.ib-bar::before {
  content: attr(data-t);
  position: absolute;
  left: 26px;
  top: 4px;
  z-index: -1;
  color: var(--otl-c);
  -webkit-text-stroke: var(--otl-w) var(--otl-c);
  pointer-events: none;
}
.ib-level {
  background: var(--lime);
  font-size: clamp(13px, 3.8vmin, 20.5px);
  letter-spacing: 0.054em;
  margin-right: 10%;
}
.ib-meta {
  background: var(--magenta);
  font-size: clamp(9.5px, 2.8vmin, 14px);
  letter-spacing: 0.048em;
  margin-left: 10%;
}
.intro-banner.is-boss .ib-level { background: var(--yellow); }
.ib-target {
  display: flex;
  align-items: center;
  gap: 14px;
  font-family: var(--display);
  line-height: .9;
  letter-spacing: 0;
  transform: skewX(var(--skew));
}
.ib-target b {
  position: relative;
  font-weight: 400;
  font-size: clamp(34.5px, 10.3vmin, 63.5px);
  color: var(--white);
  --otl-w: 9px;
  --otl-c: #05081e;
  filter: drop-shadow(4px 6px 0 rgba(5, 8, 30, .82));
}
.ib-target b::before {
  content: attr(data-t);
  position: absolute;
  left: 0;
  top: 0;
  z-index: -1;
  color: var(--otl-c);
  -webkit-text-stroke: var(--otl-w) var(--otl-c);
}
.ib-target em {
  align-self: center;
  padding: 2px 8px 3px;
  border-radius: var(--r-s);
  background: rgba(5, 10, 36, .85);
  font-family: var(--ui);
  font-size: clamp(10.5px, 2.8vmin, 14.5px);
  font-weight: 800;
  letter-spacing: 0.068em;
  color: var(--cyan);
}
.ib-mod {
  padding: 3px 12px 4px;
  border-radius: var(--r-pill);
  background: var(--yellow);
  color: #2a1c00;
  font-size: 8.5px;
  font-weight: 800;
  letter-spacing: 0.061em;
  text-transform: uppercase;
  box-shadow: 0 0 18px rgba(255, 210, 63, .45);
}
.intro-banner.anim-in .ib-level { animation: dbLeft .34s cubic-bezier(.12, 1.5, .3, 1) both; }
.intro-banner.anim-in .ib-meta { animation: dbRight .34s .08s cubic-bezier(.12, 1.5, .3, 1) both; }
.intro-banner.anim-in .ib-target { animation: ibPop .34s .04s cubic-bezier(.12, 1.6, .3, 1) both; }
.intro-banner.anim-in { animation: ibIn .01s linear forwards; }
.intro-banner.anim-out { animation: ibOut .2s ease-in forwards; }
@keyframes ibIn { to { opacity: 1; } }
@keyframes ibOut {
  from { opacity: 1; transform: scale(1); }
  to { opacity: 0; transform: scale(1.06); }
}
@keyframes ibPop {
  0% { transform: skewX(var(--skew)) scale(1.7); opacity: 0; }
  60% { transform: skewX(var(--skew)) scale(.97); opacity: 1; }
  100% { transform: skewX(var(--skew)) scale(1); opacity: 1; }
}

/* ------------------------------------------------------- tutorial strip    */

.tut-strip {
  position: absolute;
  left: 50%;
  bottom: calc(var(--sa-b) + 88px);
  transform: translate(-50%, 8px);
  width: max-content;
  max-width: min(94vw, 560px);
  padding: 6px 12px 7px;
  border-radius: var(--r-l);
  background: rgba(9, 18, 56, .9);
  border: 1.5px solid var(--line-soft);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  font-size: clamp(7.5px, 2.1vmin, 10.5px);
  font-weight: 800;
  letter-spacing: 0.02em;
  text-align: center;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .94);
  opacity: 0;
  pointer-events: none;
  transition: opacity .2s ease, transform .2s ease;
}
.tut-strip.is-on { opacity: 1; transform: translate(-50%, 0); }
.tut-strip.anim-in { animation: tutIn .3s cubic-bezier(.2, 1.4, .4, 1); }
@keyframes tutIn {
  from { transform: translate(-50%, 14px) scale(.94); opacity: 0; }
  to { transform: translate(-50%, 0) scale(1); opacity: 1; }
}

.tut-zones { position: absolute; inset: 0; pointer-events: none; opacity: 0; transition: opacity .25s ease; }
.tut-zones.is-on { opacity: 1; }
.tut-zone {
  position: absolute;
  bottom: calc(var(--sa-b) + 18px);
  width: clamp(30px, 6.9vmin, 44px);
  height: clamp(30px, 6.9vmin, 44px);
  color: rgba(41, 224, 255, .5);
}
.tut-zone svg { width: 100%; height: 100%; display: block; filter: drop-shadow(0 2px 6px rgba(0, 0, 0, .8)); }
.tz-l { left: calc(var(--sa-l) + 14px); transform: scaleX(-1); animation: zoneL 1.8s ease-in-out infinite; }
.tz-r { right: calc(var(--sa-r) + 14px); animation: zoneR 1.8s ease-in-out infinite; }
@keyframes zoneL {
  0%, 100% { transform: scaleX(-1) translateX(0); opacity: .55; }
  50% { transform: scaleX(-1) translateX(7px); opacity: 1; }
}
@keyframes zoneR {
  0%, 100% { transform: translateX(0); opacity: .55; }
  50% { transform: translateX(7px); opacity: 1; }
}

/* ------------------------------------------------------------- pause veil  */

.pause-veil {
  position: absolute;
  inset: 0;
  background: rgba(5, 10, 36, .7);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  visibility: hidden;
  transition: opacity .2s ease, visibility .2s;
}
.pause-veil.is-on { opacity: 1; visibility: visible; }
.pause-word {
  font-family: var(--display);
  font-size: clamp(26px, 7.7vmin, 53.5px);
  letter-spacing: 0.095em;
  text-indent: .28em;
  color: var(--white);
}
/* With the pause card up, the veil's big word would only duplicate the card title. */
.pause-veil.has-menu .pause-word { display: none; }
/* The hint strip and its chevrons are painted after the veil, so they would otherwise
   float on top of a paused screen at full brightness. */
.pause-veil.is-on ~ .tut-strip,
.pause-veil.is-on ~ .tut-zones { opacity: 0; }

/* ==========================================================================
   Screens
   ========================================================================== */

.screen {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: calc(var(--sa-t) + 12px) calc(var(--sa-r) + 14px) calc(var(--sa-b) + 12px) calc(var(--sa-l) + 14px);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity .22s ease, visibility .22s;
  overflow: hidden;
  touch-action: manipulation;
}
.screen.is-open { opacity: 1; visibility: visible; pointer-events: auto; }
.screen.anim-in > * { animation: screenin .3s cubic-bezier(.2, 1.2, .3, 1) both; }
/* The end card is on the retry path: it has to be there instantly. */
.screen-end { transition-duration: .1s; }
.screen-end.anim-in > * { animation-duration: .14s; }
@keyframes screenin {
  from { transform: translateY(16px) scale(.97); opacity: 0; }
  to { transform: none; opacity: 1; }
}

/* Deep navy ground with a lime/magenta rake across it, so a menu reads as the same
   world as the pop-ups rather than a settings dialog. */
.screen-menu, .screen-sheet, .screen-ch, .screen-end::before {
  background:
    repeating-linear-gradient(115deg, rgba(255, 255, 255, .028) 0 3px, transparent 3px 26px),
    radial-gradient(90% 55% at 12% 4%, rgba(184, 255, 42, .16), transparent 62%),
    radial-gradient(90% 60% at 92% 12%, rgba(255, 47, 179, .18), transparent 60%),
    linear-gradient(180deg, rgba(13, 27, 76, .95), rgba(5, 10, 36, .97));
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
/* The end screen's dim is a separate layer so the replay can fade it down without
   dragging the card (or its entrance animation) around with it. */
.screen-end::before {
  content: "";
  position: absolute;
  inset: 0;
  transition: opacity .38s ease;
}
.screen-end.is-replay::before { opacity: .24; }

/* -------------------------------------------------------------------- menu  */

.menu-inner {
  width: min(560px, 100%);
  max-height: 100%;
  display: flex;
  flex-direction: column;
  gap: clamp(14px, 2.8vmin, 24px);
  align-items: stretch;
}

.brand { text-align: center; margin: 0; }
.logo-wrap {
  position: relative;
  display: inline-block;
  padding: 0 .18em;
  /* Seven letters have to clear the sound and vibration buttons in the top corner on a
     phone, so the size is capped by the viewport WIDTH as well as by vmin. */
  --logo-size: clamp(36px, min(13.4vmin, 11.2vw), 98px);
  margin-top: clamp(30px, 7vmin, 52px);
}
/* The bolt: a magenta strike with a lime edge behind the word, flashing in and then
   breathing. It sits under the letters, which carry their own outline and shadow. */
.logo-bolt {
  position: absolute;
  left: 50%;
  top: 50%;
  height: calc(var(--logo-size) * 2.5);
  width: auto;
  transform: translate(-50%, -52%) rotate(18deg);
  fill: var(--magenta);
  stroke: var(--lime);
  stroke-width: 7;
  stroke-linejoin: round;
  filter: drop-shadow(0 0 10px rgba(255, 47, 179, .75)) drop-shadow(0 0 26px rgba(184, 255, 42, .35));
  animation: boltflash .9s cubic-bezier(.2, .9, .3, 1) both, boltbreathe 2.8s 1s ease-in-out infinite;
  pointer-events: none;
}
.logo {
  position: relative;
  margin: 0;
  font-family: var(--display);
  font-size: var(--logo-size);
  font-weight: 400;
  letter-spacing: 0.01em;
  line-height: .88;
  display: flex;
  justify-content: center;
  transform: skewX(var(--skew));
}
.logo span {
  position: relative;
  color: var(--white);
  --otl-w: 10px;
  --otl-c: #05081e;
  filter: drop-shadow(4px 6px 0 rgba(5, 8, 30, .9));
  animation: logopop .6s cubic-bezier(.2, 1.5, .35, 1) both;
}
.logo span::before {
  content: attr(data-t);
  position: absolute;
  left: 0;
  top: 0;
  z-index: -1;
  color: var(--otl-c);
  -webkit-text-stroke: var(--otl-w) var(--otl-c);
}
.logo span:nth-child(1) { animation-delay: .02s; }
.logo span:nth-child(2) { animation-delay: .06s; }
.logo span:nth-child(3) { animation-delay: .10s; color: var(--lime); }
.logo span:nth-child(4) { animation-delay: .14s; }
.logo span:nth-child(5) { animation-delay: .18s; }
.logo span:nth-child(6) { animation-delay: .22s; }
.logo span:nth-child(7) { animation-delay: .26s; }
@keyframes boltflash {
  0% { opacity: 0; transform: translate(-50%, -70%) rotate(18deg) scale(.6); }
  30% { opacity: 1; transform: translate(-50%, -52%) rotate(18deg) scale(1.06); }
  42% { opacity: .35; }
  52% { opacity: 1; }
  100% { opacity: 1; transform: translate(-50%, -52%) rotate(18deg) scale(1); }
}
@keyframes boltbreathe {
  0%, 100% { filter: drop-shadow(0 0 10px rgba(255, 47, 179, .75)) drop-shadow(0 0 26px rgba(184, 255, 42, .35)); }
  50% { filter: drop-shadow(0 0 16px rgba(255, 47, 179, .95)) drop-shadow(0 0 40px rgba(184, 255, 42, .55)); }
}
@keyframes logopop {
  0% { transform: translateY(26px) rotate(-6deg); opacity: 0; }
  70% { transform: translateY(-4px) rotate(1deg); opacity: 1; }
  100% { transform: none; opacity: 1; }
}
.tagline {
  margin: 7px 0 0;
  font-size: clamp(9.5px, 2.4vmin, 12px);
  font-weight: 800;
  letter-spacing: 0.082em;
  text-transform: uppercase;
  color: var(--cyan);
}

/* Three headline acts in a column: WORLD TOUR (the one primary), ACADEMY, DAILY BOWLER.
   Everything else lives in the quiet grid under them. */
.menu-actions { display: flex; flex-direction: column; gap: 9px; }
.menu-actions .btn { width: 100%; }
.menu-actions .btn-play, .menu-actions .btn-dailybowler { min-height: 48px; }
.menu-actions .btn-play .btn-main, .menu-actions .btn-dailybowler .btn-main {
  font-size: clamp(11px, 2.8vmin, 14px);
  letter-spacing: 0.041em;
}
.btn-dailybowler.is-done .btn-sub { color: var(--lime); }

/* --------------------------------------------------------------- buttons   */

.btn {
  -webkit-appearance: none;
  appearance: none;
  position: relative;
  border: 1.5px solid var(--line);
  background: var(--panel-bg);
  color: var(--white);
  border-radius: var(--r-l);
  min-height: 52px;
  padding: 8px 14px;
  font-family: var(--ui);
  cursor: pointer;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1px;
  pointer-events: auto;
  box-shadow: 0 4px 0 rgba(5, 8, 30, .55), inset 0 1px 0 rgba(255, 255, 255, .14);
  transition: transform .12s ease, box-shadow .12s ease, background .12s ease, filter .12s ease;
  touch-action: manipulation;
}
.btn:hover { filter: brightness(1.14); }
.btn:active { transform: translateY(3px); box-shadow: 0 1px 0 rgba(5, 8, 30, .55); }
.btn-main {
  font-size: clamp(13px, 3.2vmin, 17px);
  font-weight: 800;
  letter-spacing: 0.034em;
  text-transform: uppercase;
}
.btn-sub {
  font-size: 8.5px;
  font-weight: 800;
  letter-spacing: 0.048em;
  color: var(--dim);
  text-transform: uppercase;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.btn-sub:empty { display: none; }

.btn.is-primary {
  background: var(--lime);
  border-color: #ffffff;
  color: #10240a;
  box-shadow: 0 4px 0 #5f8a00, 0 8px 22px rgba(184, 255, 42, .3);
}
.btn.is-primary .btn-sub { color: rgba(16, 36, 10, .78); }
.btn.is-primary:active { box-shadow: 0 1px 0 #5f8a00; }

.btn.is-strong {
  background: var(--magenta);
  border-color: #ffffff;
  color: var(--white);
  box-shadow: 0 4px 0 #9c0069, 0 8px 22px rgba(255, 47, 179, .3);
}
.btn.is-strong:active { box-shadow: 0 1px 0 #9c0069; }

.btn-flat {
  min-height: 44px;
  background: rgba(20, 34, 95, .8);
  box-shadow: 0 3px 0 rgba(5, 8, 30, .5);
}
.btn-flat .btn-main { font-size: clamp(9.5px, 2.4vmin, 11px); letter-spacing: 0.044em; color: var(--cyan); }
.btn-flat:active { box-shadow: 0 1px 0 rgba(5, 8, 30, .5); }

.extra-row .btn-flat {
  border-color: transparent;
  background: none;
  box-shadow: none;
}
.extra-row .btn-flat:active { transform: scale(.96); box-shadow: none; }
.extra-row .btn-sub { color: rgba(226, 240, 255, .45); }

.mode-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 2px 4px; }
.mode-btn {
  min-height: 46px;
  border-color: transparent;
  background: none;
  box-shadow: none;
}
.mode-btn:hover { filter: none; }
.mode-btn:active { transform: scale(.96); box-shadow: none; }
.mode-btn .btn-main { font-size: clamp(9.5px, 2.4vmin, 11px); letter-spacing: 0.041em; }
.mode-btn .btn-sub { color: rgba(226, 240, 255, .45); }
.btn-endless .btn-main { color: var(--yellow); }
.btn-super .btn-main { color: var(--cyan); }
.btn-survival .btn-main { color: var(--pink); }
.btn-daily .btn-main { color: var(--lime); }
.btn-daily.is-done { border-color: rgba(184, 255, 42, .6); }
.btn-daily.is-done .btn-sub { color: var(--lime); }

.extra-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 2px 4px; margin-top: -8px; }

/* v13: the mode menu, the level ladder and the collection sheets are off the map. The nodes
   stay in the document so every game.js and ui-tour.js querySelector still resolves - they
   just have nowhere on screen to be. src/ui-challenges.js owns what a player sees instead. */
.menu-legacy { display: none; }

/* ---------------------------------------------------------------- levels   */

.levels-wrap {
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.levels-cap, .end-level {
  font-size: 8.5px;
  font-weight: 800;
  letter-spacing: 0.109em;
  color: var(--cyan);
  text-transform: uppercase;
}
.level-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(56px, 1fr));
  gap: 9px;
  overflow-y: auto;
  overscroll-behavior: contain;
  touch-action: pan-y;
  min-height: 0;
  padding-right: 2px;
}
.level-tile {
  -webkit-appearance: none;
  appearance: none;
  position: relative;
  aspect-ratio: 1 / 1;
  min-height: 50px;
  border-radius: var(--r-l);
  border: 1.5px solid transparent;
  background: rgba(20, 34, 95, .5);
  color: var(--white);
  font-family: var(--ui);
  cursor: pointer;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  pointer-events: auto;
  transition: transform .12s ease, box-shadow .12s ease;
  touch-action: manipulation;
  padding: 0;
}
.level-tile:active { transform: scale(.94); }
.tile-num {
  font-family: var(--display);
  font-size: clamp(14px, 3.1vmin, 18px);
  letter-spacing: 0;
}
.tile-stars { display: flex; gap: 2px; }
.tile-star { width: 8px; height: 8px; display: block; }
.tile-star svg { width: 100%; height: 100%; display: block; fill: rgba(255, 255, 255, .2); }
.tile-star.on svg { fill: var(--lime); filter: drop-shadow(0 0 4px rgba(184, 255, 42, .8)); }
.tile-lock { display: flex; }
.tile-lock svg { width: 16px; height: 16px; fill: rgba(255, 255, 255, .28); display: block; }
.level-tile.is-locked { background: rgba(20, 34, 95, .26); cursor: default; }
.level-tile.is-boss { border-color: var(--magenta); background: linear-gradient(180deg, #2a1055, #14225f); }
.level-tile.is-boss .tile-num { color: var(--pink); }
.level-tile.is-next {
  border-color: var(--lime);
  box-shadow: 0 0 0 2px rgba(184, 255, 42, .3), 0 6px 16px rgba(184, 255, 42, .24);
}

/* Sound + vibration share one square so the pair reads as a single settings cluster. */
.btn-mute, .btn-haptic {
  width: 44px;
  height: 44px;
  border-radius: var(--r-m);
  border: 1.5px solid var(--line);
  background: rgba(9, 18, 56, .82);
  color: var(--white);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  pointer-events: auto;
  padding: 0;
  touch-action: manipulation;
  transition: transform .12s ease, background .12s ease;
}
.btn-mute svg, .btn-haptic svg { width: 20px; height: 20px; fill: currentColor; display: block; }
.btn-mute.is-off, .btn-haptic.is-off { color: var(--magenta); border-color: rgba(255, 47, 179, .6); }
.btn-mute:active, .btn-haptic:active { transform: scale(.92); }
/* Only the menu's copies are parked in the corner; the pause card's sit in the flow. */
.screen-menu > .menu-toggles {
  position: absolute;
  top: calc(var(--sa-t) + 12px);
  right: calc(var(--sa-r) + 12px);
  display: flex;
  gap: 8px;
  pointer-events: none;   /* the buttons themselves take the taps */
}

/* ------------------------------------------------------------------ cards  */

.card {
  width: min(440px, 100%);
  max-height: 100%;
  overflow-y: auto;
  overscroll-behavior: contain;
  touch-action: pan-y;
  background: var(--panel-bg);
  border: 1.5px solid var(--line);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow), inset 0 1px 0 rgba(255, 255, 255, .12);
  padding: clamp(15px, 3.1vmin, 24px);
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(7px, 1.5vmin, 13px);
}

/* --------------------------------------------------------------- end card  */

.end-wrap { width: min(440px, 100%); max-height: 100%; display: flex; }
.end-card { width: 100%; }

.end-head {
  position: relative;
  margin: 0;
  border-radius: var(--r-pill);
  max-width: 100%;
  padding: 4px 26px 5px;
  background: var(--lime);
  color: var(--white);
  font-size: clamp(17px, 4.8vmin, 26px);
  font-weight: 800;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  transform: skewX(var(--skew));
  box-shadow: 0 6px 18px rgba(0, 0, 0, .5);
  --otl-w: 5px;
  --otl-c: #0a1030;
}
.end-head::before {
  content: attr(data-t);
  position: absolute;
  left: 26px;
  top: 4px;
  z-index: -1;
  color: var(--otl-c);
  -webkit-text-stroke: var(--otl-w) var(--otl-c);
}
.screen-end.is-lose .end-head { background: var(--magenta); }
.screen-end.is-win .end-card { border-color: rgba(184, 255, 42, .55); }
.screen-end.is-lose .end-card { border-color: rgba(255, 47, 179, .45); }

.end-scoreline { display: flex; align-items: baseline; gap: 8px; font-variant-numeric: tabular-nums; }
.end-score {
  font-family: var(--display);
  font-size: clamp(39.5px, 11.2vmin, 65.5px);
  line-height: 1;
  color: var(--white);
}
.end-target { font-size: clamp(14px, 3.6vmin, 19px); font-weight: 800; color: var(--cyan); }

.end-starrow { display: flex; gap: 10px; }
.end-star { width: clamp(30px, 6.9vmin, 42px); height: clamp(30px, 6.9vmin, 42px); display: block; }
.end-star svg { width: 100%; height: 100%; display: block; fill: rgba(255, 255, 255, .14); }
.end-star.on svg { fill: var(--lime); filter: drop-shadow(0 0 12px rgba(184, 255, 42, .85)); }
.end-star.anim-star { animation: starpop .34s cubic-bezier(.2, 1.7, .35, 1) both; }
@keyframes starpop {
  0% { transform: scale(0) rotate(-120deg); }
  65% { transform: scale(1.3) rotate(8deg); }
  100% { transform: scale(1) rotate(0); }
}

.end-stats { display: flex; flex-wrap: wrap; gap: 7px; width: 100%; }
/* Shot names are long: BEST SHOT gets its own full-width row instead of an ellipsis. */
.stat.stat-wide { flex-basis: 100%; }
.stat-wide .stat-val { white-space: normal; }
.stat {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 8px 5px 9px;
  border-radius: var(--r-m);
  background: rgba(5, 10, 36, .5);
  border: 1.2px solid var(--line-soft);
  min-width: 0;
}
.stat-cap { font-size: 8px; font-weight: 700; letter-spacing: 0.068em; color: var(--dim); text-align: center; }
.stat-val {
  font-size: clamp(10.5px, 2.8vmin, 13px);
  font-weight: 800;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.end-share-row { width: 100%; }
.btn-share { width: 100%; min-height: 44px; flex-direction: row; gap: 8px; }
.btn-share svg { width: 14px; height: 14px; fill: var(--cyan); display: block; }
.btn-share .btn-main { font-size: clamp(9.5px, 2.4vmin, 11px); letter-spacing: 0.054em; color: var(--cyan); }
.btn-share.is-busy { opacity: .55; pointer-events: none; }

.end-actions { display: flex; gap: 8px; width: 100%; margin-top: 2px; align-items: stretch; }
.end-actions .btn { flex: 1; min-height: 50px; }
.end-actions .btn-menu { flex: .55; min-height: 44px; align-self: center; }
.end-actions .btn-menu .btn-main { font-size: clamp(9.5px, 2.4vmin, 11px); letter-spacing: 0.044em; color: var(--dim); }
.end-actions .btn-retry { flex: 1.5; min-height: 56px; }
.end-actions .btn-retry .btn-main { font-size: clamp(14.5px, 3.6vmin, 19px); }

/* The card slides aside so the 3D replay plays in the clear, then comes back to centre. */
.end-card { transition: transform .45s cubic-bezier(.22, .9, .3, 1); }
.screen-end.is-replay .end-card { transform: translateY(26%) scale(.84); }

/* ------------------------------------------------------------- pause card  */
/* The pause veil underneath already dims and blurs the pitch, so this screen
   only carries the card. */

.screen-pause { background: none; }
.pause-card { width: min(340px, 100%); }
.pause-cap {
  font-size: 8.5px;
  font-weight: 800;
  letter-spacing: 0.109em;
  color: var(--cyan);
  text-transform: uppercase;
}
.pause-head {
  position: relative;
  margin: 0 0 2px;
  border-radius: var(--r-pill);
  padding: 3px 24px 4px;
  background: var(--cyan);
  color: var(--white);
  font-size: clamp(15.5px, 4.5vmin, 22.5px);
  font-weight: 800;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  transform: skewX(var(--skew));
  --otl-w: 4px;
  --otl-c: #0a1030;
}
.pause-head::before {
  content: attr(data-t);
  position: absolute;
  left: 24px;
  top: 3px;
  z-index: -1;
  color: var(--otl-c);
  -webkit-text-stroke: var(--otl-w) var(--otl-c);
}
.pause-actions { display: flex; flex-direction: column; gap: 8px; width: 100%; }
.pause-actions .btn { width: 100%; }
.pause-actions .btn-resume { min-height: 56px; }
.pause-actions .btn-resume .btn-main { font-size: clamp(14.5px, 3.6vmin, 19px); }
.pause-actions .btn-pause-menu .btn-main { color: var(--dim); }
.pause-foot { display: flex; justify-content: center; gap: 10px; margin-top: 2px; }

/* v5 SHOT WHEEL rows. One tap cycles each, and the row says what it is now rather than what
   tapping it would do, so there is nothing to read twice. */
.pause-opts { display: flex; flex-direction: column; gap: 6px; width: 100%; margin-top: 2px; }
.btn-opt {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  min-height: 40px;
  padding: 0 14px;
  border: 2px solid var(--line-soft);
  border-radius: var(--r-l);
  background: rgba(9, 18, 56, 0.55);
  color: var(--white);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .12s cubic-bezier(.2, 1.1, .4, 1), border-color .12s linear;
}
.btn-opt:active { transform: scale(.97); }
.btn-opt .opt-cap {
  font-family: var(--ui);
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: 0.14em;
  color: var(--dim);
}
.btn-opt .opt-val {
  font-family: var(--ui);
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.08em;
  color: var(--lime);
}
.btn-opt.is-off { border-color: var(--line-soft); }
.btn-opt.is-off .opt-val { color: var(--dim-2); }

/* --------------------------------------------------------------- sheets    */
/* One screen serves ACADEMY, BATS and BADGES: a pinned header, a scrolling list
   and a footnote. Only the list scrolls, so the back button never leaves the thumb. */

.sheet-card {
  width: min(520px, 100%);
  height: 100%;
  overflow: hidden;
  text-align: left;
  align-items: stretch;
  gap: 11px;
  padding: clamp(13px, 2.8vmin, 19px);
}
.sheet-head { display: flex; align-items: center; gap: 10px; width: 100%; flex: 0 0 auto; }
.btn-sheet-back {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  border-radius: var(--r-m);
  border: 1.5px solid var(--line);
  background: rgba(9, 18, 56, .8);
  color: var(--white);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  cursor: pointer;
  pointer-events: auto;
  touch-action: manipulation;
  transition: background .12s ease, transform .12s ease;
}
.btn-sheet-back:hover { background: rgba(41, 224, 255, .24); }
.btn-sheet-back:active { transform: scale(.92); }
.btn-sheet-back svg { width: 18px; height: 18px; display: block; }
.sheet-titles { flex: 1; min-width: 0; }
.sheet-cap { font-size: 8px; font-weight: 800; letter-spacing: 0.102em; color: var(--cyan); text-transform: uppercase; }
.sheet-title {
  margin: 1px 0 0;
  font-family: var(--display);
  font-size: clamp(18px, 4.8vmin, 27.5px);
  font-weight: 400;
  letter-spacing: 0.02em;
  line-height: 1;
  transform-origin: 0 50%;
  color: var(--white);
}
.sheet-count {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 4px 10px 5px;
  border-radius: var(--r-m);
  background: rgba(5, 10, 36, .6);
  border: 1.5px solid var(--line-soft);
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--lime);
}
.sheet-count svg { width: 12px; height: 12px; fill: var(--lime); display: block; }

.sheet-list {
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 7px;
  overflow-y: auto;
  overscroll-behavior: contain;
  touch-action: pan-y;
  padding-right: 2px;
}
.sheet-card.is-badges .sheet-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(146px, 1fr));
  align-content: start;
}
.sheet-note {
  flex: 0 0 auto;
  width: 100%;
  font-size: 9px;
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--dim);
  text-align: center;
}

.sheet-row {
  -webkit-appearance: none;
  appearance: none;
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  min-height: 60px;
  padding: 9px 11px;
  border-radius: var(--r-l);
  border: 1.5px solid var(--line-soft);
  background: rgba(20, 34, 95, .62);
  color: var(--white);
  font-family: var(--ui);
  text-align: left;
  pointer-events: auto;
  cursor: pointer;
  touch-action: manipulation;
  transition: transform .12s ease, border-color .14s ease, background .14s ease;
}
.sheet-row:active { transform: scale(.985); }
.sheet-row.is-locked { cursor: default; opacity: .5; }
.sheet-row.is-locked:active { transform: none; }

/* academy */
.ac-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.ac-name { font-size: 13px; font-weight: 800; letter-spacing: 0.02em; }
.ac-goal { font-size: 8px; font-weight: 800; letter-spacing: 0.054em; color: var(--cyan); }
.ac-hint { font-size: 10px; font-weight: 500; letter-spacing: 0.02em; color: var(--dim); line-height: 1.3; }
.ac-stars { display: flex; gap: 3px; flex: 0 0 auto; }
.ac-star { width: 13px; height: 13px; display: block; }
.ac-star svg { width: 100%; height: 100%; display: block; fill: rgba(255, 255, 255, .18); }
.ac-star.on svg { fill: var(--lime); filter: drop-shadow(0 0 5px rgba(184, 255, 42, .8)); }
.ac-row.is-done { border-color: rgba(184, 255, 42, .45); background: rgba(184, 255, 42, .08); }

/* bats */
.bat-icon { flex: 0 0 auto; width: 30px; height: 40px; }
.bat-icon svg { width: 100%; height: 100%; display: block; filter: drop-shadow(0 3px 6px rgba(0, 0, 0, .6)); }
.bat-body { flex: 1; min-width: 0; }
.bat-name { display: block; font-size: 13px; font-weight: 800; letter-spacing: 0.02em; }
.bat-blurb { display: block; margin-top: 2px; font-size: 9.5px; font-weight: 500; color: var(--dim); line-height: 1.3; }
.bat-stats { display: flex; gap: 8px; margin-top: 7px; }
.bstat { display: flex; flex-direction: column; gap: 3px; flex: 1; min-width: 0; }
.bstat-cap { font-size: 8px; font-weight: 700; letter-spacing: 0.048em; color: var(--dim); }
.bstat-track { height: 4px; border-radius: var(--r-pill); background: rgba(255, 255, 255, .16); overflow: hidden; }
.bstat-fill {
  display: block;
  height: 100%;
  width: 100%;
  transform-origin: 0 50%;
  border-radius: var(--r-pill);
  background: linear-gradient(90deg, var(--cyan), var(--lime));
}
.bat-act { flex: 0 0 auto; }
.bat-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  min-height: 44px;
  min-width: 60px;
  padding: 0 12px;
  border-radius: var(--r-m);
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: 0.041em;
  font-variant-numeric: tabular-nums;
  background: rgba(41, 224, 255, .16);
  border: 1.5px solid rgba(41, 224, 255, .6);
  color: var(--cyan);
}
.bat-btn svg { width: 12px; height: 12px; fill: currentColor; display: block; }
.bat-btn.is-buy { background: var(--lime); border-color: #fff; color: #10240a; }
.bat-btn.is-poor { background: rgba(255, 255, 255, .05); border-color: var(--line-soft); color: var(--dim); }
.bat-tag {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 12px;
  border-radius: var(--r-m);
  font-size: 8.5px;
  font-weight: 800;
  letter-spacing: 0.048em;
  color: var(--lime);
}
.bat-row.is-selected { border-color: rgba(184, 255, 42, .6); background: rgba(184, 255, 42, .1); }
.bat-row:not(.is-owned) .bat-name { color: rgba(255, 255, 255, .78); }

/* badges */
.badge-row {
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-start;
  gap: 6px;
  min-height: 102px;
  cursor: default;
}
.badge-row:active { transform: none; }
.badge-icon { width: 28px; height: 28px; display: block; }
.badge-icon svg { width: 100%; height: 100%; display: block; fill: rgba(255, 255, 255, .24); }
.badge-icon.is-emoji { font-size: 20.5px; line-height: 28px; }
.badge-row.is-on { border-color: rgba(184, 255, 42, .45); background: rgba(184, 255, 42, .09); }
.badge-row.is-on .badge-icon svg { fill: var(--lime); filter: drop-shadow(0 0 8px rgba(184, 255, 42, .6)); }
.badge-row:not(.is-on) { opacity: .58; }
.badge-body { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.badge-name { font-size: 11px; font-weight: 800; letter-spacing: 0.024em; line-height: 1.15; }
.badge-desc { font-size: 9.5px; font-weight: 500; color: var(--dim); line-height: 1.32; }

/* ==========================================================================
   Responsive
   ========================================================================== */

/* Narrow phones: the two panels have to give up some tracking before they wrap. */
@media (max-width: 380px) {
  .hud { left: calc(var(--sa-l) + 7px); right: calc(var(--sa-r) + 7px); }
  .npanel { padding: 4px 6px 5px; }
  .score-runs { font-size: 17px; }
  .score-team { font-size: 10.5px; }
  .dot { width: 17px; height: 17px; }
  .dot > b { font-size: 9.5px; }
  .plate-main { font-size: 10.5px; }
  .plate-sub { font-size: 8px; letter-spacing: 0.031em; }
  .overs-cap { letter-spacing: 0.034em; }
  .need-chip { letter-spacing: 0.02em; }
  /* 44 is the floor for a tap target, so these two never shrink past it. */
  .screen-menu > .menu-toggles { gap: 7px; }
  .menu-inner { padding-top: 44px; }
  .logo-wrap { --logo-size: clamp(34px, 11.8vmin, 72px); }
}

/* Very short portrait (small phones in split view): trim the menu stack rather than
   letting the level grid collapse to nothing. */
@media (orientation: portrait) and (max-height: 700px) {
  .logo-wrap { --logo-size: clamp(30px, 9.6vmin, 56px); }
  .mode-btn { min-height: 44px; }
  .extra-row .btn { min-height: 42px; }
  .center-stack { top: calc(var(--sa-t) + 146px); }
}

/* The replay shuffle goes sideways when there is width to give, so the card clears the
   middle of the frame instead of sliding off the bottom of a short one. */
@media (orientation: landscape) {
  .screen-end.is-replay .end-card { transform: translateX(-58%) scale(.86); }
}

@media (orientation: landscape) and (max-height: 560px) {
  .menu-inner {
    width: min(940px, 100%);
    display: grid;
    grid-template-columns: 1fr 1.05fr;
    grid-template-areas: "brand levels" "actions levels" "modes levels" "extras levels";
    align-items: center;
    gap: 8px 18px;
  }
  .brand { grid-area: brand; }
  .menu-actions { grid-area: actions; }
  .mode-grid { grid-area: modes; }
  .extra-row { grid-area: extras; }
  .levels-wrap { grid-area: levels; max-height: 88dvh; }
  .logo { font-size: clamp(31px, 9.5vmin, 62px); }
  /* Titan One overshoots its line box the way Anton did, so the tagline needs real air or it
     runs through the bottom of the logo on a short landscape frame. */
  .tagline { margin-top: 11px; }
  /* A 900px-wide HUD strung across a phone in landscape is mostly empty. Cap and centre it. */
  .hud { max-width: 660px; left: 50%; right: auto; transform: translateX(-50%) translateY(-10px); }
  .hud.is-on { transform: translateX(-50%); }
  .menu-actions .btn { min-height: 46px; }
  .mode-btn { min-height: 42px; }
  .extra-row .btn { min-height: 42px; }
  .bowler-card { top: 58%; padding: 8px 18px 10px; gap: 2px; }
  .field-toast { bottom: calc(var(--sa-b) + 92px); }
  .sheet-card { width: min(760px, 100%); gap: 8px; padding: 12px 16px; }
  .sheet-card.is-badges .sheet-list { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); }
  .badge-row { min-height: 86px; }
  .end-share-row .btn-share { min-height: 42px; }
  .center-stack { top: calc(var(--sa-t) + 104px); }
  .outcome { min-height: clamp(80px, 20.6vmin, 120px); }
  .dbanner { bottom: calc(var(--sa-b) + 86px); }
  .card { width: min(560px, 100%); }
  .end-card { padding: 15px 20px; gap: 8px; }
  .intro-banner { bottom: calc(var(--sa-b) + 80px); gap: 3px; }
  .tut-strip { bottom: calc(var(--sa-b) + 50px); }
  .scrim-top { height: 38%; }
}

@media (min-width: 900px) {
  .menu-inner { width: min(640px, 100%); }
  .sheet-card { width: min(640px, 100%); }
  .hud { max-width: 720px; left: 50%; right: auto; transform: translateX(-50%) translateY(-10px); }
  .hud.is-on { transform: translateX(-50%); }
}

@media (prefers-reduced-motion: reduce) {
  .ui-root *, .ui-root *::before, .ui-root *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}
