/* War of Soccer: Shootout — the game's UI skin.
   Same product as the marketing site: "Cosmic Stadium" — deep cosmic navy,
   electric cyan + gold off the logo rings, pitch green, Space Grotesk / DM Sans.
   The site's tokens are re-declared here (the game is a standalone document and
   does not load the Next.js bundle) under a wos- prefix so nothing collides.

   MOBILE-FIRST. Every touch target obeys --wos-touch-min. */

:root {
  --wos-bg: #04081a;
  --wos-bg-2: #070d24;
  --wos-ink: #eef4ff;
  --wos-body: #c6d2ef;
  --wos-muted: #9fb0dc;
  --wos-muted-2: #7f8cc0;

  --wos-cyan: #2ee0f2;
  --wos-gold: #ffcf3e;
  --wos-green: #35e08a;
  --wos-azure: #4f8dff;
  --wos-red: #ff5a6e;

  --wos-panel: linear-gradient(158deg, rgba(255, 255, 255, 0.075), rgba(255, 255, 255, 0.02));
  --wos-line: rgba(140, 200, 240, 0.13);
  --wos-glass: blur(13px) saturate(1.15);
  --wos-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08), 0 24px 50px -30px rgba(0, 0, 0, 0.7);

  --wos-display: "Space Grotesk", system-ui, sans-serif;
  --wos-body-font: "DM Sans", system-ui, -apple-system, sans-serif;

  /* Apple HIG / Material both land at 44px. A mistap in a shootout is a lost
     trophy, so this is a floor, never a target. */
  --wos-touch-min: 44px;
  --wos-safe-b: env(safe-area-inset-bottom, 0px);
  --wos-safe-l: env(safe-area-inset-left, 0px);
  --wos-safe-r: env(safe-area-inset-right, 0px);
  --wos-safe-t: env(safe-area-inset-top, 0px);
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  overflow: hidden;                 /* the game is a viewport, not a document */
  background: var(--wos-bg);
  color: var(--wos-body);
  font-family: var(--wos-body-font);
  -webkit-font-smoothing: antialiased;
  overscroll-behavior: none;        /* no pull-to-refresh mid-penalty */
  touch-action: none;
}

#wos-canvas {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  background:
    radial-gradient(1200px 820px at 50% -12%, rgba(46, 224, 242, 0.10), transparent 60%),
    radial-gradient(1000px 900px at 50% 122%, rgba(53, 224, 138, 0.07), transparent 60%),
    linear-gradient(180deg, var(--wos-bg) 0%, var(--wos-bg-2) 52%, #03050f 100%);
}

/* ── layers ──────────────────────────────────────────────────────────────── */
#wos-ui { position: fixed; inset: 0; z-index: 2; pointer-events: none; }
.wos-layer { position: absolute; inset: 0; }
/* Only interactive layers take pointer events; the HUD must never eat a tap
   meant for the pitch. */
.wos-layer--hud, .wos-layer--ring, .wos-layer--board { pointer-events: none; }
.wos-layer--touch, .wos-layer--screens, .wos-layer--overlay, .wos-layer--loading { pointer-events: none; }
.wos-layer--touch > *, .wos-layer--screens > *, .wos-layer--overlay > *, .wos-layer--loading > * { pointer-events: auto; }
.wos-layer--screens { z-index: 4; }
.wos-layer--overlay { z-index: 5; }
.wos-layer--loading { z-index: 6; }
.wos-layer--touch { z-index: 3; }

.is-hidden { display: none !important; }

/* ── shared furniture ────────────────────────────────────────────────────── */
.wos-kicker {
  display: inline-flex; align-items: center; gap: 0.5rem;
  font-family: var(--wos-display); font-size: 0.72rem; font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--wos-cyan);
  margin: 0 0 0.4rem;
}
.wos-kicker::before {
  content: ""; width: 7px; height: 7px; border-radius: 50%; flex: none;
  background: var(--wos-cyan); box-shadow: 0 0 12px 2px var(--wos-cyan);
}
.wos-h1 {
  font-family: var(--wos-display); font-weight: 700; color: var(--wos-ink);
  font-size: clamp(2rem, 7vw, 3.6rem); line-height: 0.98; letter-spacing: -0.03em;
  margin: 0 0 0.6rem;
}
.wos-h1 em {
  display: block; font-style: normal; font-size: clamp(0.9rem, 3vw, 1.4rem);
  font-weight: 700; letter-spacing: 0.34em; text-transform: uppercase; margin-top: 0.5rem;
  background: linear-gradient(100deg, var(--wos-cyan), var(--wos-green) 45%, var(--wos-gold));
  background-size: 220% auto; -webkit-background-clip: text; background-clip: text; color: transparent;
  animation: wos-sheen 7s linear infinite;
}
@keyframes wos-sheen { to { background-position: 220% center; } }
.wos-h2 {
  font-family: var(--wos-display); font-weight: 700; color: var(--wos-ink);
  font-size: clamp(1.4rem, 4vw, 2rem); letter-spacing: -0.01em; margin: 0 0 0.35rem;
}
.wos-lede { color: var(--wos-muted); font-size: 1.05rem; margin: 0 0 1.4rem; }
.wos-sub { color: var(--wos-muted-2); font-size: 0.92rem; margin: 0 0 1rem; }
.wos-head { margin-bottom: 1.2rem; }

/* buttons */
.wos-btn {
  min-height: var(--wos-touch-min);
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--wos-display); font-weight: 700; font-size: 0.98rem;
  padding: 0.7rem 1.4rem; border-radius: 999px; border: 1px solid var(--wos-line);
  cursor: pointer; background: rgba(255, 255, 255, 0.05); color: var(--wos-ink);
  transition: transform 0.15s ease, border-color 0.2s ease, filter 0.2s ease;
  -webkit-tap-highlight-color: transparent;
}
.wos-btn--primary {
  color: #0a1030; border-color: transparent;
  background: linear-gradient(100deg, var(--wos-cyan), var(--wos-green) 55%, var(--wos-gold));
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12), 0 14px 34px -12px rgba(46, 224, 242, 0.75);
}
.wos-btn--primary:hover { filter: brightness(1.07); transform: translateY(-1px); }
.wos-btn--ghost:hover { border-color: rgba(255, 255, 255, 0.3); transform: translateY(-1px); }
.wos-btn--text { background: none; border-color: transparent; color: var(--wos-muted); font-weight: 500; }
.wos-btn--text:hover { color: var(--wos-ink); }
.wos-btn:focus-visible { outline: 2px solid var(--wos-cyan); outline-offset: 3px; }
.wos-actions { display: flex; flex-wrap: wrap; gap: 0.7rem; justify-content: center; margin-top: 1.2rem; }
.wos-actions--stack { flex-direction: column; align-items: stretch; }

/* keycaps */
.wos-kbd {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 1.9rem; height: 1.9rem; padding: 0 0.45rem;
  font-family: var(--wos-display); font-size: 0.78rem; font-weight: 700; color: var(--wos-ink);
  background: rgba(255, 255, 255, 0.08); border: 1px solid var(--wos-line);
  border-bottom-width: 2px; border-radius: 6px;
}
.wos-kbd--pad { border-radius: 999px; color: var(--wos-gold); }
.wos-kbd-or { color: var(--wos-muted-2); font-size: 0.7rem; }
.wos-keys { display: inline-flex; align-items: center; gap: 0.3rem; flex: none; }

/* ── loading ─────────────────────────────────────────────────────────────── */
.wos-loading {
  position: absolute; inset: 0; display: grid; place-items: center;
  background: radial-gradient(700px 500px at 50% 40%, rgba(46, 224, 242, 0.10), transparent 62%), var(--wos-bg);
  transition: opacity 0.4s ease;
}
.wos-loading.is-done { opacity: 0; pointer-events: none; }
.wos-load-inner { text-align: center; width: min(24rem, 84vw); }
.wos-load-crest { position: relative; width: 120px; height: 120px; margin: 0 auto 1.2rem; }
.wos-load-crest i {
  position: absolute; inset: 0; border-radius: 50%;
  background: conic-gradient(from 0deg, transparent 0deg, var(--wos-cyan) 55deg, transparent 120deg,
              var(--wos-gold) 195deg, transparent 250deg, var(--wos-green) 315deg, transparent 360deg);
  -webkit-mask: radial-gradient(farthest-side, transparent 58%, #000 62%, #000 88%, transparent 92%);
  mask: radial-gradient(farthest-side, transparent 58%, #000 62%, #000 88%, transparent 92%);
  filter: blur(1px); animation: wos-spin 3.2s linear infinite;
}
.wos-load-crest b {
  position: absolute; inset: 26%; border-radius: 50%;
  background: radial-gradient(circle at 34% 30%, #fff, #9fb0dc 60%, #4a5580);
  box-shadow: 0 8px 26px -8px rgba(46, 224, 242, 0.8);
}
@keyframes wos-spin { to { transform: rotate(360deg); } }
.wos-load-title { font-family: var(--wos-display); font-weight: 700; color: var(--wos-ink); font-size: 1.6rem; margin: 0 0 1.4rem; letter-spacing: -0.02em; }
.wos-load-title em {
  display: block; font-style: normal; font-size: 0.72rem; letter-spacing: 0.34em;
  text-transform: uppercase; margin-top: 0.35rem;
  background: linear-gradient(100deg, var(--wos-cyan), var(--wos-gold));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.wos-load-bar { height: 5px; border-radius: 999px; background: rgba(255, 255, 255, 0.08); overflow: hidden; }
.wos-load-fill {
  display: block; height: 100%; width: 100%; transform-origin: left; transform: scaleX(0);
  background: linear-gradient(90deg, var(--wos-cyan), var(--wos-green) 55%, var(--wos-gold));
  transition: transform 0.25s ease-out;
}
.wos-load-meta { display: flex; justify-content: space-between; gap: 1rem; margin-top: 0.7rem; }
.wos-load-label { color: var(--wos-muted-2); font-size: 0.82rem; margin: 0; text-align: left; }
.wos-load-pct { font-family: var(--wos-display); font-size: 0.82rem; color: var(--wos-cyan); font-variant-numeric: tabular-nums; }
.wos-loading.is-failed .wos-load-fill { background: var(--wos-red); }
.wos-loading.is-failed .wos-load-label { color: var(--wos-red); }

/* ── screens ─────────────────────────────────────────────────────────────── */
.wos-screens {
  position: absolute; inset: 0; display: none; place-items: center;
  padding: calc(1rem + var(--wos-safe-t)) 1rem calc(1rem + var(--wos-safe-b));
  /* NO backdrop-filter here. A large backdrop blur over the WebGL canvas is a
     known Chrome compositing bug: the blur re-samples whenever the content
     underneath changes colour, and it FLICKERS — which is exactly what the menu
     background did while stepping through the game/team pickers. (Chromium
     issues 41471914 / 339841685.) The sibling War of Cricket build never hit
     this because it uses backdrop-filter in exactly one small place. So the
     menu scrim is a plain opaque gradient: same look, zero recompositing. */
  background:
    radial-gradient(120% 90% at 50% 0%, rgba(10, 16, 42, 0.62), rgba(4, 8, 26, 0.86) 70%),
    rgba(4, 8, 26, 0.55);
  overflow-y: auto;
}
.wos-screens.is-open { display: grid; }

/* THE BLUR GOES ON THE CANVAS, NOT ON A BACKDROP-FILTER.
   main.js freezes rendering while a menu is up, so the canvas is a STILL image —
   and a CSS filter over a still image is composited once and never flickers,
   unlike a backdrop-filter that re-samples whatever moves beneath it. This keeps
   the stadium visible and soft behind the menu with none of the flashing. */
#wos-canvas { transition: filter .25s ease; }
#wos-canvas.is-menu-blurred { filter: blur(9px) saturate(.85) brightness(.85); }
.wos-panel {
  width: min(52rem, 100%); text-align: center;
  padding: clamp(1.4rem, 4vw, 2.4rem);
  border-radius: 22px; border: 1px solid var(--wos-line);
  /* Sits on the opaque scrim above, so a backdrop blur here buys nothing and
     only re-composites. Solid panel instead — see the note on .wos-screens. */
  background: linear-gradient(180deg, rgba(18, 26, 58, 0.98), rgba(8, 13, 34, 0.99));
  box-shadow: var(--wos-shadow);
}
.wos-title .wos-lede { max-width: 30rem; margin-inline: auto; }

/* Results ("full time"): the win/lose/draw call should read before the words
   do — colour + a crest glow behind the score line, the way a broadcast
   graphic sells a result. line/detail come from main.js as plain prose;
   screens.js derives the outcome class from the SAME title strings it already
   renders, so this never drifts from what's on screen. */
.wos-title--win .wos-h1 {
  background: linear-gradient(100deg, var(--wos-gold), #fff 45%, var(--wos-green));
  -webkit-background-clip: text; background-clip: text; color: transparent;
  /* text-shadow, not filter — see the note on .wos-toast b: filter on a
     background-clip:text element renders as a solid box in this browser. */
  text-shadow: 0 8px 30px rgba(255, 207, 62, 0.45);
}
.wos-title--lose .wos-h1 { color: var(--wos-muted); }
.wos-title--draw .wos-h1 {
  background: linear-gradient(100deg, var(--wos-cyan), var(--wos-ink) 60%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.wos-results-line {
  font-family: var(--wos-display); font-weight: 700; font-size: clamp(1.3rem, 4.5vw, 1.9rem);
  color: var(--wos-ink); letter-spacing: -0.01em; margin: 0 0 0.5rem;
  font-variant-numeric: tabular-nums;
}
.wos-title--win .wos-results-line { color: var(--wos-gold); }

/* wizard step dots — the "Step X of Y" kicker text already says this; dots
   make it scannable without reading, and double as a sense of "how much is
   left" before Play. Purely decorative (the kicker text is the a11y source). */
.wos-step-dots { display: flex; align-items: center; justify-content: center; gap: 0.4rem; margin: 0 0 0.6rem; }
.wos-step-dot {
  width: 6px; height: 6px; border-radius: 50%; background: var(--wos-line);
  transition: background 0.2s ease, transform 0.2s ease;
}
.wos-step-dot.is-done { background: var(--wos-cyan); }
.wos-step-dot.is-current { background: var(--wos-gold); transform: scale(1.4); }
@media (prefers-reduced-motion: reduce) { .wos-step-dot { transition: none; } }

/* pickers */
.wos-grid {
  display: grid; gap: 0.7rem;
  grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
  margin: 1rem 0;
}
.wos-grid--stadium, .wos-grid--mode { grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); }
.wos-card {
  position: relative; min-height: var(--wos-touch-min);
  display: flex; flex-direction: column; align-items: center; gap: 0.4rem;
  padding: 1rem 0.8rem; border-radius: 16px; cursor: pointer; overflow: hidden;
  border: 1px solid var(--wos-line); background: var(--wos-panel); color: var(--wos-ink);
  transition: transform 0.16s ease, border-color 0.2s ease;
  -webkit-tap-highlight-color: transparent;
}
.wos-card::after {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 2px;
  background: linear-gradient(90deg, transparent, var(--wos-cyan), var(--wos-gold), transparent);
  opacity: 0; transition: opacity 0.2s ease;
}
.wos-card:hover { transform: translateY(-4px); border-color: rgba(255, 255, 255, 0.24); }
.wos-card:hover::after, .wos-card.is-selected::after { opacity: 0.9; }
.wos-card.is-selected { border-color: color-mix(in srgb, var(--wos-cyan) 55%, var(--wos-line)); box-shadow: 0 0 30px -10px rgba(46, 224, 242, 0.6); }
.wos-card:focus-visible { outline: 2px solid var(--wos-cyan); outline-offset: 2px; }
.wos-card-name { font-family: var(--wos-display); font-weight: 700; font-size: 0.98rem; }
.wos-card-sub { color: var(--wos-muted-2); font-size: 0.78rem; line-height: 1.4; }
.wos-card-badge {
  position: absolute; top: 0.5rem; right: 0.5rem;
  font-family: var(--wos-display); font-size: 0.6rem; font-weight: 700;
  letter-spacing: 0.1em; text-transform: uppercase; color: #0a1030;
  background: var(--wos-gold); padding: 0.15rem 0.45rem; border-radius: 999px;
}
/* Team art = colours only. Never a real crest — that is a legal line, not taste. */
.wos-card-art { width: 46px; height: 46px; border-radius: 50%; flex: none; }
.wos-card-art--team {
  background: conic-gradient(from 200deg, var(--c1) 0 40%, var(--c2) 40% 72%, var(--c3) 72% 100%);
  box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.18), 0 6px 18px -6px var(--c1);
}
.wos-card-art--mode, .wos-card-art--stadium, .wos-card-art--camera {
  display: grid; place-items: center;
  background: rgba(255, 255, 255, 0.06); border: 1px solid var(--wos-line);
  font-family: var(--wos-display); color: var(--wos-cyan);
}
.wos-card-art--mode b, .wos-card-art--stadium b, .wos-card-art--camera b { font-size: 1.2rem; }

/* ── HUD ─────────────────────────────────────────────────────────────────── */
.wos-hud { position: absolute; inset: 0; font-family: var(--wos-display); }
.wos-hud.is-hidden { display: none; }
.wos-hud-bar {
  position: absolute; top: calc(0.7rem + var(--wos-safe-t)); left: 50%; transform: translateX(-50%);
  display: flex; align-items: center; gap: 0.6rem;
  padding: 0.4rem 0.5rem; border-radius: 999px;
  border: 1px solid var(--wos-line); background: rgba(4, 8, 26, 0.72);
  backdrop-filter: var(--wos-glass); -webkit-backdrop-filter: var(--wos-glass);
  box-shadow: var(--wos-shadow); white-space: nowrap;
}
.wos-hud-team { display: flex; align-items: center; gap: 0.4rem; padding: 0 0.3rem; }
.wos-hud-flag {
  width: 18px; height: 18px; border-radius: 4px; flex: none;
  background: linear-gradient(160deg, var(--team) 0 60%, var(--team-2) 60% 100%);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.25);
}
.wos-hud-abbr { font-weight: 700; font-size: 0.92rem; color: var(--wos-ink); letter-spacing: 0.06em; }
.wos-hud-scores { display: flex; align-items: center; gap: 0.4rem; }
.wos-hud-score { font-weight: 700; font-size: 1.3rem; color: var(--wos-ink); font-variant-numeric: tabular-nums; min-width: 1ch; text-align: center; }
.wos-hud-dash { color: var(--wos-muted-2); }
.wos-hud-clockwrap { position: relative; padding-left: 0.6rem; margin-left: 0.2rem; border-left: 1px solid var(--wos-line); }
.wos-hud-clock { font-size: 0.92rem; color: var(--wos-cyan); font-variant-numeric: tabular-nums; letter-spacing: 0.04em; }
.wos-hud-clockfill {
  position: absolute; left: 0.6rem; right: 0; bottom: -0.2rem; height: 2px; border-radius: 2px;
  transform-origin: left; transform: scaleX(0); background: var(--wos-cyan); opacity: 0.5;
}
.wos-hud.is-lateon .wos-hud-clock { color: var(--wos-gold); }
/* A shootout has no running clock — showing one would be a lie. */
.wos-hud.is-shootout .wos-hud-clockwrap { display: none; }

.wos-hud-mode {
  /* Clears the "back to site" link, which owns the very top-left corner —
     same derivation as .wos-hud-cam clearing the sound button on the right. */
  position: absolute; top: calc(0.9rem + var(--wos-safe-t));
  left: calc(0.9rem + var(--wos-safe-l) + var(--wos-touch-min) + 0.6rem);
  font-size: 0.66rem; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--wos-muted); border: 1px solid var(--wos-line); border-radius: 999px;
  padding: 0.3rem 0.7rem; background: rgba(4, 8, 26, 0.6);
}
.wos-hud-cam {
  /* Clears the sound button, which owns the very top-right corner. That offset
     is the button (--wos-touch-min) plus the gap either side of it — derived
     from the same tokens the button uses, so the two can never drift apart and
     start overlapping again if the touch minimum changes. */
  position: absolute; top: calc(0.9rem + var(--wos-safe-t));
  right: calc(0.9rem + var(--wos-safe-r) + var(--wos-touch-min) + 0.6rem);
  display: flex; align-items: center; gap: 0.4rem;
  font-size: 0.72rem; color: var(--wos-muted); border: 1px solid var(--wos-line);
  border-radius: 999px; padding: 0.25rem 0.6rem 0.25rem 0.3rem; background: rgba(4, 8, 26, 0.6);
}
.wos-hud-cam b { color: var(--wos-ink); font-weight: 500; }
.wos-hud-cam.is-flash { animation: wos-flash 0.5s ease; }
@keyframes wos-flash {
  0% { border-color: var(--wos-cyan); box-shadow: 0 0 24px -4px var(--wos-cyan); }
  100% { border-color: var(--wos-line); box-shadow: none; }
}

.wos-stamina {
  position: absolute; left: calc(1rem + var(--wos-safe-l)); bottom: calc(1rem + var(--wos-safe-b));
  width: min(11rem, 34vw);
}
.wos-stamina-label { display: block; font-size: 0.58rem; letter-spacing: 0.16em; color: var(--wos-muted-2); margin-bottom: 0.25rem; }
.wos-stamina::after {
  content: ""; display: block; height: 6px; border-radius: 999px;
  background: rgba(255, 255, 255, 0.1); border: 1px solid var(--wos-line);
}
.wos-stamina-fill {
  position: absolute; left: 1px; right: 1px; bottom: 1px; height: 4px; border-radius: 999px;
  transform-origin: left; background: linear-gradient(90deg, var(--wos-green), var(--wos-cyan));
  transition: transform 0.2s linear;
}
.wos-stamina.is-low .wos-stamina-fill { background: linear-gradient(90deg, var(--wos-red), var(--wos-gold)); }
.wos-stamina.is-low .wos-stamina-label { color: var(--wos-red); }

.wos-poss {
  position: absolute; left: 50%; bottom: calc(1rem + var(--wos-safe-b)); transform: translateX(-50%);
  display: none; align-items: center; gap: 0.4rem;
  font-size: 0.72rem; letter-spacing: 0.1em; color: var(--wos-muted);
}
.wos-poss.is-on { display: flex; }
.wos-poss-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--team); box-shadow: 0 0 10px var(--team); }

/* toasts */
.wos-toasts { position: absolute; left: 50%; top: 26%; transform: translateX(-50%); text-align: center; width: max-content; max-width: 90vw; }
.wos-toast { position: relative; animation: wos-pop 0.35s cubic-bezier(0.2, 1.3, 0.4, 1); }
/* A daylight stadium (the "Grand — Afternoon" look) can bleed a bright sky
   straight through gradient-clipped text. A soft radial scrim behind the
   word — not a card, just enough dark to hold contrast — keeps GOAL/SAVE/etc
   readable on every stadium look without boxing in the broadcast feel. */
.wos-toast::before {
  content: ""; position: absolute; inset: -20% -30%; z-index: -1;
  background: radial-gradient(60% 70% at 50% 45%, rgba(3, 5, 15, 0.55), transparent 75%);
}
.wos-toast b {
  display: block; font-size: clamp(2rem, 9vw, 4.2rem); font-weight: 700; letter-spacing: -0.02em; line-height: 1;
  background: linear-gradient(100deg, var(--wos-cyan), var(--wos-green) 45%, var(--wos-gold));
  -webkit-background-clip: text; background-clip: text; color: transparent;
  /* text-shadow, not filter:drop-shadow — a glow that survives the same
     compositing path as the clipped text itself, cheaper to boot. */
  text-shadow: 0 6px 26px rgba(46, 224, 242, 0.5);
}
.wos-toast span { display: block; margin-top: 0.3rem; color: var(--wos-muted); font-size: 0.9rem; }
/* PRE-EXISTING BUG, FOUND + FIXED IN THE LAUNCH POLISH PASS: every one of
   these per-outcome overrides sets `background` as a SHORTHAND. The
   `background` shorthand resets EVERY background-* sub-property it does not
   explicitly re-list — including background-clip — back to its initial
   border-box. So each override silently undid the base rule's
   `background-clip: text`, and GOAL/SAVE/MISS/POST/OFFSIDE all rendered as a
   solid filled rounded-rect instead of the word, on every stadium look —
   verified live (computed style read `background-clip: border-box` despite
   the base rule declaring `text`). Each override below now re-asserts
   background-clip itself so it cannot be silently reset again by a future
   edit to any one of them. */
.wos-toast--goal b { background: linear-gradient(100deg, var(--wos-gold), #fff 50%, var(--wos-green)); -webkit-background-clip: text; background-clip: text; text-shadow: 0 6px 30px rgba(255, 207, 62, 0.7); }
.wos-toast--save b, .wos-toast--miss b, .wos-toast--offside b { background: linear-gradient(100deg, var(--wos-red), var(--wos-gold)); -webkit-background-clip: text; background-clip: text; }
.wos-toast--post b { background: linear-gradient(100deg, var(--wos-azure), var(--wos-cyan)); -webkit-background-clip: text; background-clip: text; }
@keyframes wos-pop { from { opacity: 0; transform: scale(0.82) translateY(8px); } to { opacity: 1; transform: none; } }

/* ── timing ring ─────────────────────────────────────────────────────────── */
/* Bottom-centre, UNDER the goal mouth: the keeper is in the upper half of the
   frame and the ring must never cover him — reading both at once is the game. */
.wos-ring {
  position: absolute; left: 50%; transform: translateX(-50%);
  bottom: calc(4.5rem + var(--wos-safe-b));
  width: clamp(170px, 30vmin, 240px); height: clamp(170px, 30vmin, 240px);
}
/* On a phone the bottom band belongs to the thumbs: the sprint button sat
   straight on top of the ring's lower-right at 390px. The thumbs cannot move
   (they are anchored to the hand), so the ring rises above them. It still sits
   below the goal mouth, which is what keeps the keeper readable. */
@media (max-width: 34rem) {
  .wos-ring {
    bottom: calc(10.75rem + var(--wos-safe-b));
    width: clamp(150px, 40vw, 190px); height: clamp(150px, 40vw, 190px);
  }
}

/* The timing-rating callout — PERFECT/GOOD/OK/MISS — flashes centred over the
   ring the instant a kick is struck, straight off ring.state().result, so the
   player gets a SKILL read (did I time it well?) that is independent of the
   OUTCOME toast (did it go in?) hud.js shows a beat later. Never covers the
   goal/keeper: it lives entirely inside the ring's own footprint, which
   styles.css already keeps clear of both (see the comment above .wos-ring). */
.wos-ring-call {
  position: absolute; left: 50%; bottom: calc(4.5rem + var(--wos-safe-b));
  transform: translate(-50%, 0); width: clamp(170px, 30vmin, 240px);
  text-align: center; pointer-events: none;
  display: flex; align-items: center; justify-content: center;
  height: clamp(170px, 30vmin, 240px);
  font-family: var(--wos-display); font-weight: 700;
  font-size: clamp(1.1rem, 4.5vmin, 1.7rem); letter-spacing: 0.04em;
  text-transform: uppercase; color: var(--wos-ink);
  opacity: 0; transform: translate(-50%, 6px) scale(0.9);
  transition: opacity 0.4s ease, transform 0.4s cubic-bezier(0.2, 1.3, 0.4, 1);
  text-shadow: 0 0 22px currentColor, 0 2px 10px rgba(0, 0, 0, 0.5);
}
.wos-ring-call.is-shown { opacity: 1; transform: translate(-50%, 0) scale(1); }
.wos-ring-call[data-rating="PERFECT"] { color: var(--wos-green); }
.wos-ring-call[data-rating="GOOD"] { color: var(--wos-gold); }
.wos-ring-call[data-rating="OK"] { color: var(--wos-cyan); }
.wos-ring-call[data-rating="MISS"] { color: var(--wos-red); }
@media (max-width: 34rem) {
  .wos-ring-call {
    bottom: calc(10.75rem + var(--wos-safe-b));
    width: clamp(150px, 40vw, 190px); height: clamp(150px, 40vw, 190px);
    font-size: clamp(0.95rem, 5.5vw, 1.3rem);
  }
}

/* ── shootout board ──────────────────────────────────────────────────────── */
.wos-board {
  position: absolute; top: calc(4.2rem + var(--wos-safe-t)); left: 50%; transform: translateX(-50%);
  font-family: var(--wos-display); text-align: center;
  padding: 0.6rem 0.9rem; border-radius: 14px;
  border: 1px solid var(--wos-line); background: rgba(4, 8, 26, 0.66);
  backdrop-filter: var(--wos-glass); -webkit-backdrop-filter: var(--wos-glass);
}
.wos-board.is-sudden { border-color: color-mix(in srgb, var(--wos-gold) 50%, var(--wos-line)); }
.wos-board-title { font-size: 0.6rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--wos-muted-2); margin-bottom: 0.45rem; }
.wos-board.is-sudden .wos-board-title { color: var(--wos-gold); }
.wos-board-body { display: grid; gap: 0.25rem; }
.wos-board-side {
  display: grid; grid-template-columns: 2.6rem 1fr 1.2rem; align-items: center; gap: 0.6rem;
  padding: 0.2rem 0.35rem; border-radius: 8px; border: 1px solid transparent;
}
.wos-board-side.is-next { border-color: color-mix(in srgb, var(--team) 60%, transparent); background: color-mix(in srgb, var(--team) 12%, transparent); }
.wos-board-team { font-size: 0.78rem; font-weight: 700; color: var(--team); letter-spacing: 0.06em; text-align: left; display: flex; align-items: center; gap: 0.3rem; }
/* "Whose turn is it?" must be answerable at a glance — a border tint alone was
   too subtle at broadcast distance. A live dot beats a static label: it reads
   as "happening now", not just "happened to be picked". */
.wos-board-next-dot {
  display: none; width: 6px; height: 6px; border-radius: 50%; flex: none;
  background: var(--team); box-shadow: 0 0 8px 1px var(--team);
}
.wos-board-side.is-next .wos-board-next-dot { display: inline-block; animation: wos-next-pulse 1.3s ease-in-out infinite; }
@keyframes wos-next-pulse { 0%, 100% { opacity: 0.5; transform: scale(0.85); } 50% { opacity: 1; transform: scale(1.15); } }
.wos-board-marks { display: flex; gap: 0.2rem; justify-content: center; }
.wos-board-score { font-size: 0.9rem; font-weight: 700; color: var(--wos-ink); font-variant-numeric: tabular-nums; }
.wos-mark { font-size: 0.85rem; line-height: 1; }
.wos-mark--scored { color: var(--wos-green); text-shadow: 0 0 8px rgba(53, 224, 138, 0.7); }
.wos-mark--missed { color: var(--wos-red); }
.wos-mark--pending { color: rgba(159, 176, 220, 0.35); }
.wos-mark--sudden { filter: drop-shadow(0 0 5px var(--wos-gold)); }

/* ── controls overlay ────────────────────────────────────────────────────── */
.wos-overlay {
  position: absolute; inset: 0; display: none; place-items: center;
  padding: calc(1rem + var(--wos-safe-t)) 1rem calc(1rem + var(--wos-safe-b));
  /* Opaque, not a backdrop blur — same Chrome flicker as .wos-screens. */
  background:
    radial-gradient(120% 90% at 50% 0%, rgba(14, 22, 54, 0.95), rgba(4, 8, 26, 0.99) 70%),
    rgba(4, 8, 26, 0.99);
  overflow-y: auto;
}
.wos-overlay.is-open { display: grid; }
.wos-overlay-panel {
  width: min(46rem, 100%); text-align: left;
  padding: clamp(1.3rem, 4vw, 2.2rem); border-radius: 22px;
  border: 1px solid var(--wos-line); background: var(--wos-panel);
  backdrop-filter: var(--wos-glass); -webkit-backdrop-filter: var(--wos-glass);
  box-shadow: var(--wos-shadow);
}
/* The first-timer summary: the whole shootout in four steps, before the
   detailed reference grid. Numbered chips over the group's default gap so it
   reads as a sequence, not another set of cards. */
.wos-ctrl-flow {
  display: grid; gap: 0.55rem;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  list-style: none; margin: 0 0 1.4rem; padding: 0;
}
.wos-ctrl-flow li {
  display: flex; align-items: center; gap: 0.55rem;
  padding: 0.6rem 0.7rem; border-radius: 12px;
  border: 1px solid var(--wos-line); background: rgba(255, 255, 255, 0.04);
}
.wos-ctrl-flow li span { color: var(--wos-body); font-size: 0.82rem; line-height: 1.35; }
.wos-ctrl-flow b {
  flex: none; width: 1.6rem; height: 1.6rem; display: grid; place-items: center;
  border-radius: 50%; font-family: var(--wos-display); font-size: 0.8rem; font-weight: 700;
  color: #0a1030; background: linear-gradient(100deg, var(--wos-cyan), var(--wos-green));
}
.wos-ctrl-grid { display: grid; gap: 1.2rem; grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr)); }
.wos-ctrl-head {
  font-family: var(--wos-display); font-size: 0.66rem; font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--wos-gold);
  margin: 0 0 0.5rem; padding-bottom: 0.35rem; border-bottom: 1px solid var(--wos-line);
}
.wos-ctrl-row { display: flex; align-items: flex-start; gap: 0.7rem; padding: 0.35rem 0; }
.wos-ctrl-copy { display: flex; flex-direction: column; gap: 0.1rem; }
.wos-ctrl-copy b { font-family: var(--wos-display); color: var(--wos-ink); font-size: 0.88rem; font-weight: 500; }
.wos-ctrl-copy span { color: var(--wos-muted-2); font-size: 0.8rem; line-height: 1.45; }
.wos-ctrl-copy i { color: var(--wos-cyan); font-size: 0.76rem; font-style: normal; opacity: 0.85; }
/* Config still binds these (full-match modes, locked/comingSoon — see
   controls-model.js's 'openplay' note) so the anti-drift law keeps them
   rendered, but a shootout player should read the group as "not today". */
.wos-ctrl-group--soon { order: 99; opacity: 0.5; }
.wos-ctrl-group--soon .wos-ctrl-head { color: var(--wos-muted-2); }

/* Onboarding coach.
   NOT bottom-centre: that is the ring's seat, and the first Chrome pass caught
   the card sitting straight on top of it. The ring is the one thing that must
   never be occluded — the coach yields to it, never the other way round. */
.wos-coach {
  position: absolute; display: none;
  left: calc(1rem + var(--wos-safe-l));
  bottom: calc(5.5rem + var(--wos-safe-b));   /* clears the stamina meter below */
  width: min(21rem, 40vw);
}
.wos-coach.is-open { display: block; }
/* Narrow screens have no room beside the ring, so the coach goes above it —
   under the board, still clear of the ring's whole circle. */
/* Narrow: scorebar + board + coach + ring + thumb pad do not all fit in a
   701px-tall phone viewport. The ring and the thumbs are load-bearing, so the
   COACH is the one that yields — it sits between the board and the ring, and
   goes compact to fit the gap. (Measured: the card was overlapping the ring's
   top arc by 6px before this.) */
@media (max-width: 46rem) {
  .wos-coach {
    left: 50%; right: auto; transform: translateX(-50%);
    bottom: auto; top: calc(10.5rem + var(--wos-safe-t));  /* clears the board */
    width: min(24rem, 88vw);
  }
  .wos-coach-card { padding: 0.7rem 0.85rem; }
  .wos-coach-card b { font-size: 0.92rem; }
  .wos-coach-card p { font-size: 0.8rem; line-height: 1.45; }
  .wos-coach-actions { margin-top: 0.45rem; }
}
.wos-coach-card {
  position: relative; padding: 0.9rem 1rem; border-radius: 14px; text-align: left;
  border: 1px solid color-mix(in srgb, var(--wos-cyan) 35%, var(--wos-line));
  background: rgba(4, 8, 26, 0.86); backdrop-filter: var(--wos-glass); -webkit-backdrop-filter: var(--wos-glass);
  box-shadow: 0 0 40px -14px rgba(46, 224, 242, 0.6);
}
.wos-coach-step { font-family: var(--wos-display); font-size: 0.6rem; letter-spacing: 0.14em; color: var(--wos-cyan); }
.wos-coach-card b { display: block; font-family: var(--wos-display); color: var(--wos-ink); font-size: 1rem; margin: 0.15rem 0 0.2rem; }
.wos-coach-card p { margin: 0; color: var(--wos-muted); font-size: 0.85rem; line-height: 1.5; }
.wos-coach-actions { display: flex; align-items: center; justify-content: space-between; gap: 0.6rem; margin-top: 0.6rem; }

/* ── touch controls ──────────────────────────────────────────────────────── */
.wos-touch { position: absolute; inset: 0; }
.wos-touch.is-hidden { display: none; }
/* The stick ZONE is the whole lower-left quadrant, but only the nub is drawn:
   a floating stick that appears under the thumb beats a fixed one you must
   look down to find. */
.wos-stick-zone {
  position: absolute; left: 0; bottom: 0; width: 46%; height: 52%;
  touch-action: none;
}
.wos-stick {
  position: absolute; width: 112px; height: 112px; margin: -56px 0 0 -56px;
  border-radius: 50%; border: 1px solid var(--wos-line);
  background: rgba(255, 255, 255, 0.04); opacity: 0;
  transition: opacity 0.15s ease; pointer-events: none;
}
.wos-stick.is-active { opacity: 1; }
.wos-stick-nub {
  position: absolute; left: 50%; top: 50%; width: 52px; height: 52px; margin: -26px 0 0 -26px;
  border-radius: 50%; background: rgba(46, 224, 242, 0.28);
  border: 1px solid color-mix(in srgb, var(--wos-cyan) 60%, transparent);
  box-shadow: 0 0 22px -4px var(--wos-cyan);
}
.wos-pad-wrap {
  position: absolute; right: calc(0.9rem + var(--wos-safe-r)); bottom: calc(1.2rem + var(--wos-safe-b));
  display: flex; align-items: flex-end; gap: 0.6rem;
}
.wos-pad { display: grid; grid-template-columns: repeat(2, auto); gap: 0.5rem; justify-items: center; }
.wos-tbtn {
  min-width: var(--wos-touch-min); min-height: var(--wos-touch-min);
  width: 58px; height: 58px; border-radius: 50%; cursor: pointer;
  display: grid; place-items: center; padding: 0;
  font-family: var(--wos-display); font-size: 0.6rem; font-weight: 700; letter-spacing: 0.06em;
  color: var(--wos-ink); border: 1px solid var(--wos-line);
  background: rgba(4, 8, 26, 0.6); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  -webkit-tap-highlight-color: transparent; user-select: none;
}
.wos-tbtn--primary {
  width: 76px; height: 76px; font-size: 0.7rem; color: #0a1030;
  background: linear-gradient(100deg, var(--wos-cyan), var(--wos-green) 55%, var(--wos-gold));
  border-color: transparent; box-shadow: 0 10px 30px -10px rgba(46, 224, 242, 0.8);
}
.wos-tbtn--sprint { width: 64px; height: 64px; border-color: color-mix(in srgb, var(--wos-gold) 45%, var(--wos-line)); color: var(--wos-gold); }
.wos-tbtn.is-down { transform: scale(0.93); filter: brightness(1.15); }

/* ── noscript ────────────────────────────────────────────────────────────── */
.wos-noscript { position: fixed; inset: 0; display: grid; place-items: center; text-align: center; padding: 2rem; z-index: 10; background: var(--wos-bg); }
.wos-noscript h1 { font-family: var(--wos-display); color: var(--wos-ink); }
.wos-noscript a { color: var(--wos-cyan); }

/* ── responsive ──────────────────────────────────────────────────────────── */
@media (max-width: 30rem) {
  .wos-grid { grid-template-columns: repeat(auto-fill, minmax(7.4rem, 1fr)); gap: 0.5rem; }
  .wos-card { padding: 0.7rem 0.5rem; }
  .wos-card-art { width: 38px; height: 38px; }
  .wos-hud-score { font-size: 1.1rem; }
  .wos-actions { flex-direction: column; }
  .wos-actions .wos-btn { width: 100%; }
}

/* A phone's top row cannot hold mode pill + scorebar + camera pill — they
   collided at 390px. The scorebar is the one that must survive intact, so:
   drop the mode pill (the board already says "Best of 5", and the mode was a
   deliberate choice two taps ago), and COLLAPSE the camera pill to its keycap.
   The pill still answers "which camera?" — the name slides out for the length
   of the flash on every change, then folds away. hud.js drops .is-flash when
   the animation ends, which is what makes this transient rather than a
   permanently-expanded pill that collides again. */
@media (max-width: 34rem) {
  .wos-hud-mode { display: none; }
  .wos-hud-cam b {
    max-width: 0; opacity: 0; overflow: hidden; white-space: nowrap;
    transition: max-width 0.28s ease, opacity 0.28s ease;
  }
  .wos-hud-cam.is-flash b { max-width: 9rem; opacity: 1; }
}
/* Landscape phone: vertical space is the scarce resource, not horizontal. */
@media (max-height: 26rem) and (orientation: landscape) {
  .wos-ring { width: clamp(120px, 22vmin, 160px); height: clamp(120px, 22vmin, 160px); bottom: calc(0.8rem + var(--wos-safe-b)); }
  .wos-panel { padding: 1rem; }
  .wos-h1 { font-size: 1.8rem; }
  .wos-grid { grid-template-columns: repeat(auto-fill, minmax(6.5rem, 1fr)); }
  .wos-toasts { top: 16%; }
  .wos-board { top: calc(3.4rem + var(--wos-safe-t)); }
}

@media (prefers-reduced-motion: reduce) {
  .wos-h1 em, .wos-load-crest i, .wos-toast { animation: none; }
  .wos-btn, .wos-card { transition: none; }
  .wos-ring-call { transition: opacity 0.15s linear; }
  .wos-board-next-dot { animation: none; opacity: 1; transform: none; }
}

/* ── aim view ────────────────────────────────────────────────────────────── */
/* Decorative reticle canvas, full-bleed. Pointer events stay off — the side
   rail carries every accessible control, this only draws where it's told. */
.wos-layer--aim { z-index: 1; pointer-events: none; }
.wos-aim { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }

/* ── side controls (the always-on rail) ─────────────────────────────────── */
/* Docked to the right edge at EVERY breakpoint — "all controls on the side,
   all the time" is the product requirement, not just a desktop nicety.
   Desktop: vertically centred with headroom top+bottom. Below that headroom
   the .is-touch rule takes over (see below) rather than relying on centring
   alone, because a touch device's thumb pad (wos-pad-wrap, bottom-right) and
   stick zone (bottom-left) already claim the bottom of the screen — this
   rail must never drift down into that hit-test region. */
.wos-layer--side { z-index: 3; pointer-events: none; }
.wos-layer--side > * { pointer-events: auto; }
.wos-side {
  position: absolute;
  top: 50%; right: calc(0.9rem + var(--wos-safe-r));
  transform: translateY(-50%);
  width: clamp(11.5rem, 20vw, 15.5rem);
  max-height: calc(100% - 7rem - var(--wos-safe-t) - var(--wos-safe-b));
  overflow-y: auto;
  padding: 0.85rem 0.8rem;
  border-radius: 18px;
  border: 1px solid var(--wos-line);
  /* --wos-panel elsewhere always sits on a dark full-bleed scrim the modal
     provides first (wos-screens/wos-overlay). This rail floats directly over
     live gameplay instead — same as wos-hud-bar/wos-board — so it needs that
     darkening baked in, or a bright pitch bleeds straight through the glass. */
  background: linear-gradient(158deg, rgba(10, 16, 38, 0.86), rgba(6, 10, 26, 0.8));
  backdrop-filter: var(--wos-glass); -webkit-backdrop-filter: var(--wos-glass);
  box-shadow: var(--wos-shadow);
  font-family: var(--wos-body-font);
  scrollbar-width: thin;
  transition: border-color 0.25s ease;
}
.wos-side[data-context="kick"] { border-color: color-mix(in srgb, var(--wos-cyan) 32%, var(--wos-line)); }
.wos-side[data-context="keep"] { border-color: color-mix(in srgb, var(--wos-gold) 38%, var(--wos-line)); }
/* THE READY STATE: while you're free to aim (kick context, not yet holding
   SHOOT) the rail breathes gently — an invitation, not a demand. It is the
   answer to "am I ready?" for anyone who hasn't found the reticle yet. */
@keyframes wos-side-ready {
  0%, 100% { box-shadow: var(--wos-shadow), 0 0 0 0 rgba(46, 224, 242, 0); }
  50% { box-shadow: var(--wos-shadow), 0 0 26px 1px rgba(46, 224, 242, 0.35); }
}
.wos-side[data-context="kick"]:not(.is-charging) { animation: wos-side-ready 2.6s ease-in-out infinite; }
/* THE STRIKE STATE: the instant SHOOT is held, the whole rail says so — a
   faster, warmer pulse (gold, the power-meter's own colour) that reads as
   "live now", distinct from the cooler cyan "you may act whenever" glow
   above. This is the single biggest lever for "is it my moment to release?" */
@keyframes wos-side-charging {
  0%, 100% { box-shadow: var(--wos-shadow), 0 0 0 0 rgba(255, 207, 62, 0); border-color: color-mix(in srgb, var(--wos-gold) 45%, var(--wos-line)); }
  50% { box-shadow: var(--wos-shadow), 0 0 30px 2px rgba(255, 207, 62, 0.45); border-color: color-mix(in srgb, var(--wos-gold) 70%, var(--wos-line)); }
}
.wos-side.is-charging { animation: wos-side-charging 0.85s ease-in-out infinite; }

/* The live power readout — mirrors ui/aim-view.js's power arc so the number
   you can READ agrees with the arc you can SEE, in a place that never moves
   (the arc collars the reticle, which does). Text-based, so it survives at a
   glance and for anyone who finds colour-only feedback hard to read. */
.wos-side-power { margin: 0.65rem 0 0; display: none; }
.wos-side-power.is-on { display: block; }
.wos-side-power-track {
  height: 8px; border-radius: 999px; background: rgba(255, 255, 255, 0.08);
  border: 1px solid var(--wos-line); overflow: hidden;
}
.wos-side-power-fill {
  display: block; height: 100%; width: 100%; transform-origin: left; transform: scaleX(0);
  background: linear-gradient(90deg, var(--wos-cyan), var(--wos-gold) 78%, var(--wos-red));
  transition: transform 0.08s linear;
}
.wos-side-power-label {
  display: block; margin-top: 0.3rem; font-family: var(--wos-display);
  font-size: 0.72rem; font-weight: 700; letter-spacing: 0.04em; color: var(--wos-gold);
  font-variant-numeric: tabular-nums;
}
/* The reference row for SHOOT itself, picked out by data-action so the
   invitation to press is not just the rail's ambient glow but the exact key
   the player needs. */
.wos-side-row[data-action="shoot"] .wos-kbd { transition: box-shadow 0.2s ease, border-color 0.2s ease; }
.wos-side[data-context="kick"]:not(.is-charging) .wos-side-row[data-action="shoot"] .wos-kbd {
  border-color: color-mix(in srgb, var(--wos-cyan) 55%, var(--wos-line));
  box-shadow: 0 0 10px -2px var(--wos-cyan);
}
/* Touch: anchor both edges explicitly instead of centring, so the rail can
   never grow down over the thumb pad's footprint (roughly the bottom ~9rem
   on the right, per wos-pad-wrap below). */
.wos-side.is-touch {
  top: calc(3.6rem + var(--wos-safe-t));
  bottom: calc(9.6rem + var(--wos-safe-b));
  transform: none;
  max-height: none;
}

.wos-side-head { margin-bottom: 0.15rem; }
.wos-side-head .wos-kicker { margin: 0; }

.wos-side-methods { display: flex; gap: 0.4rem; margin: 0.7rem 0 0.75rem; }
.wos-side-method-btn {
  flex: 1 1 0; min-height: var(--wos-touch-min); border-radius: 999px; cursor: pointer;
  border: 1px solid var(--wos-line); background: rgba(255, 255, 255, 0.04); color: var(--wos-muted);
  font-family: var(--wos-display); font-size: 0.68rem; font-weight: 700; letter-spacing: 0.02em;
  padding: 0.3rem 0.3rem; -webkit-tap-highlight-color: transparent;
  transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}
.wos-side-method-btn.is-active {
  color: #0a1030; border-color: transparent;
  background: linear-gradient(100deg, var(--wos-cyan), var(--wos-green));
}
.wos-side-method-btn:focus-visible { outline: 2px solid var(--wos-cyan); outline-offset: 2px; }

.wos-side-primary:empty { display: none; }

.wos-side-shoot {
  display: block; width: 100%; min-height: 3.4rem; border-radius: 14px; border: none; cursor: pointer;
  font-family: var(--wos-display); font-weight: 700; font-size: 1.02rem; letter-spacing: 0.03em;
  color: #0a1030;
  background: linear-gradient(100deg, var(--wos-cyan), var(--wos-green) 55%, var(--wos-gold));
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12), 0 12px 28px -12px rgba(46, 224, 242, 0.75);
  -webkit-tap-highlight-color: transparent; user-select: none;
  transition: transform 0.12s ease, filter 0.15s ease;
}
.wos-side-shoot.is-down { transform: scale(0.96); filter: brightness(1.12); }
.wos-side-shoot:focus-visible { outline: 2px solid var(--wos-cyan); outline-offset: 3px; }
/* On touch there is no keycap to glow (see .wos-side-row[data-action="shoot"]
   above, desktop-only) — so the button itself breathes while it's waiting to
   be pressed, and goes still the instant it's held (is-down already covers
   the held look via the scale/brightness rule above). */
@keyframes wos-shoot-invite { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.035); } }
.wos-side[data-context="kick"]:not(.is-charging) .wos-side-shoot:not(.is-down) { animation: wos-shoot-invite 1.7s ease-in-out infinite; }
/* A phone thumb taps this dozens of times a shootout — sized toward the
   60-80px range research recommends for high-frequency mobile taps, not just
   the 44px accessibility floor. */
.wos-side.is-touch .wos-side-shoot { min-height: 4.3rem; font-size: 1.15rem; }

.wos-side-dives { display: flex; flex-direction: column; gap: 0.5rem; border-radius: 12px; }
.wos-side-dive {
  min-height: var(--wos-touch-min); border-radius: 12px; cursor: pointer;
  border: 1px solid var(--wos-line); background: rgba(255, 255, 255, 0.05); color: var(--wos-ink);
  font-family: var(--wos-display); font-weight: 700; font-size: 0.86rem;
  -webkit-tap-highlight-color: transparent; user-select: none;
  transition: transform 0.12s ease, filter 0.15s ease, border-color 0.2s ease;
}
.wos-side-dive[data-action="diveCentre"] { color: var(--wos-gold); }
.wos-side-dive.is-down { transform: scale(0.96); filter: brightness(1.18); border-color: color-mix(in srgb, var(--wos-gold) 55%, var(--wos-line)); }
.wos-side-dive:focus-visible { outline: 2px solid var(--wos-gold); outline-offset: 2px; }
.wos-side.is-touch .wos-side-dive { min-height: 3.3rem; font-size: 0.95rem; }
/* The keeper's choose-window is timed and easy to miss — pulse the dive
   buttons while it's open. setKeeperPrompt(false) (or a context change)
   removes the class and the pulse stops immediately. */
@keyframes wos-side-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255, 207, 62, 0); }
  50% { box-shadow: 0 0 0 6px rgba(255, 207, 62, 0.2); }
}
.wos-side.is-prompting .wos-side-dives { animation: wos-side-pulse 1.1s ease-in-out infinite; }

.wos-side-hint {
  margin: 0.75rem 0; padding: 0.55rem 0.65rem; min-height: 1.3em;
  border-radius: 10px; background: rgba(46, 224, 242, 0.08);
  border: 1px solid color-mix(in srgb, var(--wos-cyan) 22%, var(--wos-line));
  color: var(--wos-muted); font-size: 0.75rem; line-height: 1.4;
}
.wos-side-hint:empty { display: none; }

.wos-side-list { display: flex; flex-direction: column; gap: 0.05rem; border-top: 1px solid var(--wos-line); padding-top: 0.55rem; }
.wos-side-row { display: flex; align-items: flex-start; gap: 0.55rem; padding: 0.32rem 0; }
.wos-side-row-label { display: flex; flex-direction: column; gap: 0.05rem; min-width: 0; }
.wos-side-row-label b { font-family: var(--wos-display); color: var(--wos-ink); font-size: 0.76rem; font-weight: 500; }
.wos-side-row-label i { color: var(--wos-muted-2); font-size: 0.66rem; font-style: normal; line-height: 1.35; }
.wos-side-aimpad { display: inline-flex; gap: 0.25rem; flex: none; }
.wos-side-aimbtn {
  width: 1.7rem; height: 1.7rem; padding: 0; border-radius: 6px; cursor: pointer;
  border: 1px solid var(--wos-line); background: rgba(255, 255, 255, 0.06); color: var(--wos-cyan);
  font-size: 0.76rem; display: grid; place-items: center; -webkit-tap-highlight-color: transparent;
  transition: transform 0.1s ease, filter 0.15s ease;
}
.wos-side-aimbtn:active { transform: scale(0.9); filter: brightness(1.2); }
.wos-side-aimbtn:focus-visible { outline: 2px solid var(--wos-cyan); outline-offset: 2px; }
/* Only a mouse/precision pointer gets the compact 27px pad above — on touch
   this is a real, frequently-tapped target, so it meets the 44px floor. */
.wos-side.is-touch .wos-side-aimbtn { width: var(--wos-touch-min); height: var(--wos-touch-min); font-size: 0.95rem; }

@media (max-width: 30rem) {
  .wos-side { width: clamp(9.5rem, 38vw, 12rem); padding: 0.7rem 0.6rem; }
  .wos-side-row-label b { font-size: 0.7rem; }
  .wos-side-row-label i { display: none; } /* the coach line above already carries the prose */
}
@media (max-height: 26rem) and (orientation: landscape) {
  .wos-side { max-height: calc(100% - 1.6rem - var(--wos-safe-t) - var(--wos-safe-b)); padding: 0.6rem 0.6rem; }
  .wos-side.is-touch { top: calc(0.8rem + var(--wos-safe-t)); bottom: calc(0.8rem + var(--wos-safe-b)); }
}

@media (prefers-reduced-motion: reduce) {
  .wos-side.is-prompting .wos-side-dives { animation: none; }
  .wos-side-shoot, .wos-side-dive, .wos-side-aimbtn, .wos-side-method-btn { transition: none; }
  .wos-side[data-context="kick"]:not(.is-charging) { animation: none; box-shadow: var(--wos-shadow); }
  .wos-side.is-charging { animation: none; box-shadow: var(--wos-shadow); border-color: color-mix(in srgb, var(--wos-gold) 55%, var(--wos-line)); }
  .wos-side-shoot:not(.is-down) { animation: none; }
  .wos-side-power-fill { transition: none; }
}

/* ── SOUND PANEL ──────────────────────────────────────────────────────────
   Three channels (Master / Game sounds / Music), each a slider + its own
   mute, behind one speaker button. Top-right on purpose: bottom-right is the
   thumb pad and bottom-left is the stick, and a mistap there costs a penalty.

   NO backdrop-filter in this block. The panel sits over the live WebGL canvas,
   and blurring a backdrop over it is exactly what made the menu flicker in
   Chrome (Chromium 41471914 / 339841685) — so this uses an opaque panel
   instead of the --wos-glass treatment the rest of the skin uses. */
.wos-audio {
  position: fixed;
  top: calc(0.75rem + var(--wos-safe-t));
  right: calc(0.75rem + var(--wos-safe-r));
  z-index: 60;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.5rem;
  font-family: var(--wos-display);
}

.wos-audio-toggle {
  width: var(--wos-touch-min);
  height: var(--wos-touch-min);
  border-radius: 999px;
  border: 1px solid var(--wos-line);
  background: rgba(7, 13, 36, 0.92);
  color: var(--wos-ink);
  font-size: 1.05rem;
  line-height: 1;
  cursor: pointer;
  display: grid;
  place-items: center;
  box-shadow: var(--wos-shadow);
  transition: background 0.18s ease, border-color 0.18s ease, transform 0.12s ease;
}
.wos-audio-toggle:hover { background: rgba(16, 26, 60, 0.96); border-color: color-mix(in srgb, var(--wos-cyan) 40%, var(--wos-line)); }
.wos-audio-toggle:active { transform: scale(0.94); }
.wos-audio-toggle.is-muted { color: var(--wos-muted-2); border-color: color-mix(in srgb, var(--wos-red) 34%, var(--wos-line)); }
.wos-audio-toggle:focus-visible,
.wos-audio-mute:focus-visible,
.wos-audio-slider:focus-visible { outline: 2px solid var(--wos-green); outline-offset: 2px; }

.wos-audio-panel {
  width: min(19rem, calc(100vw - 1.5rem));
  padding: 0.85rem 0.9rem 0.9rem;
  border-radius: 14px;
  border: 1px solid var(--wos-line);
  background: rgba(5, 10, 28, 0.97);   /* opaque, NOT a backdrop blur — see above */
  box-shadow: var(--wos-shadow);
  animation: wos-audio-in 0.16s ease both;
}
@keyframes wos-audio-in { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .wos-audio-panel { animation: none; } }

.wos-audio-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.7rem; }
.wos-audio-title { font-size: 0.72rem; letter-spacing: 0.18em; color: var(--wos-muted); font-weight: 700; }
.wos-audio-kbd {
  font-size: 0.64rem; letter-spacing: 0.08em; color: var(--wos-muted-2);
  border: 1px solid var(--wos-line); border-radius: 5px; padding: 0.1rem 0.35rem;
}

.wos-audio-body { display: flex; flex-direction: column; gap: 0.7rem; }

.wos-audio-row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  grid-template-areas: "mute meta val" "mute slider slider";
  align-items: center;
  column-gap: 0.6rem;
  row-gap: 0.3rem;
}
.wos-audio-row.is-muted .wos-audio-meta,
.wos-audio-row.is-muted .wos-audio-val { opacity: 0.45; }

.wos-audio-mute {
  grid-area: mute;
  width: 34px; height: 34px;
  border-radius: 9px;
  border: 1px solid var(--wos-line);
  background: rgba(255, 255, 255, 0.045);
  color: var(--wos-ink);
  font-size: 0.9rem; line-height: 1;
  cursor: pointer;
  display: grid; place-items: center;
  transition: background 0.16s ease, border-color 0.16s ease;
}
.wos-audio-mute:hover { background: rgba(255, 255, 255, 0.1); }
.wos-audio-row.is-muted .wos-audio-mute { border-color: color-mix(in srgb, var(--wos-red) 40%, var(--wos-line)); color: var(--wos-red); }

.wos-audio-meta { grid-area: meta; display: flex; flex-direction: column; min-width: 0; }
.wos-audio-label { font-size: 0.84rem; color: var(--wos-ink); font-weight: 600; letter-spacing: 0.01em; }
.wos-audio-note {
  font-family: var(--wos-body-font);
  font-size: 0.66rem; color: var(--wos-muted-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.wos-audio-val {
  grid-area: val;
  font-size: 0.7rem; color: var(--wos-cyan);
  font-variant-numeric: tabular-nums; min-width: 3.2em; text-align: right;
}
.wos-audio-row.is-muted .wos-audio-val { color: var(--wos-red); }

/* The slider. Styled on both the WebKit and Firefox pseudo-elements — a bare
   range input inherits the OS skin and reads as a different product. */
.wos-audio-slider {
  grid-area: slider;
  -webkit-appearance: none; appearance: none;
  width: 100%; height: 22px;
  background: transparent; cursor: pointer; margin: 0;
}
.wos-audio-slider::-webkit-slider-runnable-track {
  height: 5px; border-radius: 999px;
  background: linear-gradient(90deg, var(--wos-cyan), var(--wos-azure)) no-repeat,
              rgba(255, 255, 255, 0.12);
  background-size: calc(var(--wos-fill, 1) * 100%) 100%, 100%;
}
.wos-audio-slider::-moz-range-track { height: 5px; border-radius: 999px; background: rgba(255, 255, 255, 0.12); }
.wos-audio-slider::-moz-range-progress { height: 5px; border-radius: 999px; background: linear-gradient(90deg, var(--wos-cyan), var(--wos-azure)); }
.wos-audio-slider::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 15px; height: 15px; margin-top: -5px;
  border-radius: 999px; border: 2px solid var(--wos-bg);
  background: var(--wos-ink);
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.55);
}
.wos-audio-slider::-moz-range-thumb {
  width: 13px; height: 13px;
  border-radius: 999px; border: 2px solid var(--wos-bg);
  background: var(--wos-ink);
}
.wos-audio-row.is-muted .wos-audio-slider::-webkit-slider-runnable-track { background-size: 0 100%, 100%; }
.wos-audio-row.is-muted .wos-audio-slider::-moz-range-progress { background: transparent; }

@media (max-width: 560px) {
  .wos-audio-panel { width: min(17rem, calc(100vw - 1.25rem)); }
  .wos-audio-note { display: none; }
}

/* ── RADIO (inside the sound panel) ───────────────────────────────────────
   The station's now-playing readout + transport. Deliberately part of the
   sound panel rather than its own floating widget: "what is playing" and "how
   loud is it" are one question, and a second overlay on the 3D canvas is one
   more thing to mistap during a shootout. */
.wos-radio {
  margin-top: 0.85rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--wos-line);
}
.wos-radio .wos-audio-head { margin-bottom: 0.5rem; }
.wos-radio-count { font-family: var(--wos-body-font); font-size: 0.64rem; color: var(--wos-muted-2); }

.wos-radio-now {
  display: flex; flex-direction: column; gap: 0.1rem;
  padding: 0.45rem 0.55rem;
  border-radius: 9px;
  border: 1px solid var(--wos-line);
  background: rgba(255, 255, 255, 0.04);
  margin-bottom: 0.55rem;
  min-width: 0;
}
.wos-radio-track {
  font-size: 0.8rem; font-weight: 600; color: var(--wos-gold);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.wos-radio-meta {
  font-family: var(--wos-body-font);
  font-size: 0.63rem; color: var(--wos-muted-2); letter-spacing: 0.02em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.wos-radio-transport { display: flex; align-items: center; gap: 0.4rem; }
.wos-radio-btn {
  flex: 1 1 auto;
  height: 34px;
  border-radius: 9px;
  border: 1px solid var(--wos-line);
  background: rgba(255, 255, 255, 0.045);
  color: var(--wos-ink);
  font-size: 0.8rem; line-height: 1;
  cursor: pointer;
  display: grid; place-items: center;
  transition: background 0.16s ease, border-color 0.16s ease, color 0.16s ease;
}
.wos-radio-btn:hover { background: rgba(255, 255, 255, 0.1); }
.wos-radio-btn:active { transform: scale(0.96); }
.wos-radio-btn:focus-visible { outline: 2px solid var(--wos-green); outline-offset: 2px; }
.wos-radio-btn--play {
  flex: 1.4 1 auto;
  border-color: color-mix(in srgb, var(--wos-cyan) 40%, var(--wos-line));
  color: var(--wos-cyan);
}
.wos-radio-btn.is-on { color: var(--wos-green); border-color: color-mix(in srgb, var(--wos-green) 45%, var(--wos-line)); background: color-mix(in srgb, var(--wos-green) 12%, transparent); }

/* ── BACK TO THE SITE ─────────────────────────────────────────────────────
   The mirror of the sound button, in the opposite corner. A real link, so it
   opens in a new tab on middle-click / long-press rather than costing the
   player their match. */
.wos-home {
  position: fixed;
  top: calc(0.75rem + var(--wos-safe-t));
  left: calc(0.75rem + var(--wos-safe-l));
  z-index: 60;
  width: var(--wos-touch-min);
  height: var(--wos-touch-min);
  border-radius: 999px;
  border: 1px solid var(--wos-line);
  background: rgba(7, 13, 36, 0.92);
  color: var(--wos-ink);
  font-family: var(--wos-display);
  font-size: 1.15rem;
  line-height: 1;
  text-decoration: none;
  display: grid;
  place-items: center;
  box-shadow: var(--wos-shadow);
  transition: background 0.18s ease, border-color 0.18s ease, transform 0.12s ease;
}
.wos-home:hover { background: rgba(16, 26, 60, 0.96); border-color: color-mix(in srgb, var(--wos-cyan) 40%, var(--wos-line)); }
.wos-home:active { transform: scale(0.94); }
.wos-home:focus-visible { outline: 2px solid var(--wos-green); outline-offset: 2px; }
