/* ==========================================================================
   Pavilion — a cricket management game.
   The front end of a GAME, not a web app. The ground at night stands behind
   every screen; a masthead wears the club and carries the one thing to do
   next; the screens are a ribbon of tabs rather than a rail of labels; the
   panels are glass over the stage; and a slanted cut — the game's own
   signature — marks the screen you are on, the panel you are reading and the
   button you are about to press. One green system accent, gold reserved for
   live/scoreboard moments, a display face for headings + numerals, a heavy
   condensed face for the wordmark and the menu, a single line-icon set.
   Fully accessible: every animation is decorative and disabled under
   prefers-reduced-motion; information is never conveyed by motion/colour alone.
   ========================================================================== */

/* Self-hosted display face — Archivo (SIL OFL 1.1, variable). Used for headings,
   stats and scoreboards. See static/fonts/ATTRIBUTION.md. */
@font-face {
  font-family: "Archivo"; font-style: normal; font-weight: 100 900; font-display: swap;
  src: url("../fonts/archivo-var.woff2") format("woff2");
}
/* Heavy condensed grotesque for the wordmark, the main menu and the stadium
   big-moment captions (FOUR / SIX / OUT on the pitch). Anton, SIL OFL 1.1. */
@font-face {
  font-family: "Anton"; font-style: normal; font-weight: 400; font-display: swap;
  src: url("../fonts/anton.woff2") format("woff2");
}

:root {
  /* ---- Stadium night (dark, default) ---- */
  --bg: #070a09; --bg-2: #0a0e0c; --surface: #121815;
  --surface-2: #192019; --surface-3: #222b25;
  --text: #e9f1ec; --muted: #94a89d; --faint: #62756a;
  --turf: #34c47a; --turf-d: #1f9d5c; --gold: #f2b53a; --leather: #e0584f;
  --accent: var(--turf); --accent-d: var(--turf-d); --accent-2: var(--gold);
  --danger: var(--leather);
  --border: #202a24; --border-2: #2c3a32; --focus: #5cc8ff; --ring: rgba(92,200,255,.5);

  /* tiers (ratings + attribute bars) */
  --t-elite: #34c47a; --t-strong: #7fd06a; --t-good: #d9c24a; --t-ok: #e6a23c; --t-weak: #e0584f;

  /* type — one shipped family (Archivo, variable 100–900) for body AND display, so
     the identity is consistent on every OS. Inter was in the stack but never
     bundled, so body text silently fell back to a different face per platform. */
  --font: "Archivo", "Segoe UI", system-ui, -apple-system, sans-serif;
  --font-display: "Archivo", "DIN Alternate", "Bahnschrift", system-ui, sans-serif;
  --font-impact: "Anton", "DIN Condensed", "Haettenschweiler", "Impact", "Arial Narrow", sans-serif;
  /* --fs-xs IS THE FLOOR. 11.52px at the 16px root, which is the smallest text
     this game ships: the mobile audit (tests/test_mobile_layout.py) fails any
     element carrying words that computes under 11.5px, on five real viewports.
     Anything tempted to go smaller wants `max(var(--fs-xs), …)` rather than a
     number of its own — an `em` that looks harmless compounds against whatever
     it is nested in, which is how a .8em landed at 9.2px. */
  --fs-xs: .72rem; --fs-sm: .82rem; --fs-base: .94rem; --fs-md: 1.05rem;
  --fs-lg: 1.3rem; --fs-xl: 1.85rem; --fs-2xl: 2.5rem;

  /* spacing */
  --s-1: .35rem; --s-2: .6rem; --s-3: .9rem; --s-4: 1.25rem; --s-5: 1.75rem; --s-6: 2.4rem;

  /* Tight corners: a game's panels, not a web app's pillows. */
  --radius: 8px; --radius-sm: 5px; --radius-xs: 3px;
  --shadow: 0 8px 26px rgba(0,0,0,.38); --shadow-lg: 0 20px 56px rgba(0,0,0,.5);

  /* The stage shows through every panel. */
  --glass: rgba(12, 18, 15, .74); --glass-2: rgba(16, 23, 19, .84);
  --glass-line: rgba(255,255,255,.075); --glass-hi: rgba(255,255,255,.05);
  --chrome: rgba(5, 8, 7, .64); --chrome-line: rgba(255,255,255,.08);
  /* The signature cut. */
  --slant: -14deg;
  /* The mark's ground: the turf and the sky through the pavilion's doorway, and the straw of the strip.
     The ink is currentColor. See templates/_brand.html (generated by scripts/render_brand.py). */
  --pv-turf: #2ec272; --pv-sky: #0d1b2e; --pv-straw: #f2b53a;

  /* The managed club's colours. base.html sets these on the shell from the
     club's kit (see data/team_colors); on the lobby and the auth pages they fall
     back to the system green, so nothing below has to special-case "no club". */
  --club: var(--turf); --club-2: var(--gold); --club-ink: #04130b;
  /* Aliases the drama layer reaches for. */
  --line: var(--border); --panel: var(--surface); --panel-2: var(--surface-2); --fg: var(--text);
}
[data-theme="light"] {
  /* ---- Day at the ground (light) ---- */
  --bg: #eef2ee; --bg-2: #e7ede7; --surface: #ffffff; --surface-2: #f4f8f4; --surface-3: #e8f1ea;
  --text: #14201a; --muted: #51665a; --faint: #7d9085;
  --turf: #149a57; --turf-d: #0f7c45; --gold: #b07914; --leather: #cc3a32;
  --accent: var(--turf); --accent-d: var(--turf-d); --accent-2: var(--gold);
  --danger: var(--leather);
  --border: #dde6df; --border-2: #c9d8cc; --focus: #0b63ff; --ring: rgba(11,99,255,.3);
  --t-elite: #149a57; --t-strong: #4fae4b; --t-good: #b89512; --t-ok: #cc8a1c; --t-weak: #cc3a32;
  --shadow: 0 6px 20px rgba(20,50,30,.09); --shadow-lg: 0 16px 40px rgba(20,50,30,.14);
  --glass: rgba(255,255,255,.76); --glass-2: rgba(255,255,255,.9);
  --glass-line: rgba(20,50,30,.13); --glass-hi: rgba(255,255,255,.9);
  --chrome: rgba(255,255,255,.72); --chrome-line: rgba(20,50,30,.14);
  --pv-turf: #1fb267; --pv-sky: #dfe8e2;
}

* { box-sizing: border-box; }
/* The UA's `[hidden] { display: none }` is the weakest rule in the cascade: any
   author rule that sets `display` on the same element (a class laying it out as
   grid/flex) silently beats it, and the element stays on screen with its
   `hidden` attribute set — the panel looks dismissed-proof and JS that toggles
   `.hidden` appears to do nothing. Every component that reveals itself does so
   by clearing the attribute FIRST and animating after, so forcing it here is
   safe and stops the bug returning with the next `display:` rule. */
[hidden] { display: none !important; }
/* `100%`, never a px value: a fixed root size silently overrides the font size
   the reader chose in their browser. Every other size in this sheet is rem. */
html { font-size: 100%; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
body {
  margin: 0; color: var(--text); -webkit-font-smoothing: antialiased;
  font-family: var(--font); line-height: 1.55; background: var(--bg);
  /* A floodlit night behind the whole app: the club's colour washing in from
     the top-left, the turf's from the top-right, and the ground darkening
     towards the foot. Procedural — no imagery to license. */
  background-attachment: fixed;
  /* App-feel touch handling: no blue tap flash (we draw our own ripple), and
     scroll momentum is contained to panels rather than bouncing the whole page. */
  -webkit-tap-highlight-color: transparent;
}

/* ---- Keyframes (all decorative) ---- */
@keyframes fadeUp { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@keyframes rise { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@keyframes pop { 0% { transform: scale(.92); opacity: 0; } 60% { transform: scale(1.02); } 100% { transform: scale(1); opacity: 1; } }
@keyframes spin { to { transform: rotate(360deg); } }
@keyframes toastIn { from { opacity: 0; transform: translateY(-10px) scale(.97); } to { opacity: 1; transform: none; } }
@keyframes ripple { to { transform: scale(2.4); opacity: 0; } }
@keyframes livePulse { 0%,100% { opacity: 1; } 50% { opacity: .35; } }

a { color: var(--focus); text-decoration: none; }
a:hover { text-decoration: underline; }
:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; border-radius: 5px; }

.visually-hidden, .sr-label { position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* ---- Icons ---- */
.ico { width: 1.15em; height: 1.15em; flex: none; display: inline-block; vertical-align: -.18em;
  fill: currentColor; }
.btn .ico, .btn-link .ico, .nav-link .ico, .tab .ico { margin-right: .1rem; }
.h-ico { width: 1em; height: 1em; opacity: .85; color: var(--turf); margin-right: .15rem; }

/* ---- App shell ----
   A frame, not a document: the chrome (masthead + ribbon) runs across the top
   and <main> scrolls INSIDE the frame, the way a game's screens change inside
   one window. The stage — the ground at night — is fixed at the back of the
   frame; the club's colour washes over it from the top-left, the turf's from
   the top-right. On small screens (≤820px) the document scrolls again and the
   ribbon becomes the bottom bar — see the responsive block. */
/* `dvh` tracks the *dynamic* viewport so the mobile URL-bar collapse doesn't crop
   the app; `vh` is the fallback for older engines. */
.app { display: grid; grid-template-rows: auto minmax(0, 1fr); height: 100vh; height: 100dvh; overflow: hidden;
  position: relative; isolation: isolate; }
/* The stage sits at the very back of the frame's own stacking context; the
   wash rides just in front of it and behind everything else. */
.app > .backdrop { z-index: -2; }
.app::before { content: ""; position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background:
    radial-gradient(900px 460px at 12% -10%, color-mix(in srgb, var(--club) 24%, transparent), transparent 66%),
    radial-gradient(1100px 520px at 90% -14%, color-mix(in srgb, var(--turf) 10%, transparent), transparent 70%),
    linear-gradient(180deg, rgba(5,8,7,.18) 0, rgba(5,8,7,.34) 55%, rgba(4,7,6,.58) 100%); }
[data-theme="light"] .app::before { background:
    radial-gradient(900px 460px at 12% -10%, color-mix(in srgb, var(--club) 16%, transparent), transparent 66%),
    radial-gradient(1100px 520px at 90% -14%, color-mix(in srgb, var(--turf) 10%, transparent), transparent 70%),
    linear-gradient(180deg, rgba(255,255,255,.3) 0, rgba(238,244,238,.55) 60%, rgba(232,240,233,.72) 100%); }
/* The title screen and the main menu: the ground is the picture. */
.app--bare::before, .app--lobby::before { background:
    linear-gradient(180deg, rgba(4,7,6,.06) 0, rgba(4,7,6,.28) 70%, rgba(4,7,6,.5) 100%); }
/* The main menu's wordmark sits where the floodlights are: keep that zone quiet. */
.app--lobby::before { background:
    linear-gradient(180deg, rgba(4,7,6,.72) 0, rgba(4,7,6,.5) 30%, rgba(4,7,6,.18) 62%, rgba(4,7,6,.5) 100%); }
[data-theme="light"] .app--bare::before, [data-theme="light"] .app--lobby::before { background:
    linear-gradient(180deg, rgba(255,255,255,.08) 0, rgba(255,255,255,.28) 100%); }
/* The lobby — the main menu, settings, the par board, a new or a loaded
   campaign, a campaign's end — has no chrome at all: the screen stands over
   the ground with a Back button at the top of the view (base.html renders it
   from `back_link`), the way a game's options screen does. The chrome stays
   in the DOM (spa.js keys on its presence) but is empty and hidden. */
.app--lobby .chrome { display: none; }
/* With the chrome gone the view is the frame's only row: give it the whole
   height, or it lands in the `auto` row and the 1fr row sits empty beneath. */
.app--lobby, .app--match { grid-template-rows: minmax(0, 1fr); }
.app--menu main { max-width: none; padding: 0; display: grid; align-content: center; }
/* Live match: no chrome, an opaque frame, no stage — the ground there is the
   real one. The chrome stays in the DOM (so the match can be entered by SPA
   without a chrome-swap full load, which is what lets the menu music
   cross-fade into the crowd) but is hidden. */
.app--match { background: var(--bg); }
.app--match::before, .app--match > .backdrop, .app--match .chrome { display: none; }
.app--match .card { background: var(--surface); -webkit-backdrop-filter: none; backdrop-filter: none; }
.content { min-width: 0; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }
main { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; width: 100%; max-width: 1240px;
  margin: 0 auto; padding: clamp(1rem, 2.4vw, 1.5rem) clamp(1rem, 3vw, 2rem) 2.2rem; }
.panel-scroll { overflow-y: auto; overscroll-behavior: contain; min-height: 0; }

/* ---- SPA navigation (pjax): slick view transition + top progress bar ---- */
main { transition: opacity .14s cubic-bezier(.4,0,1,1), transform .14s cubic-bezier(.4,0,1,1); }
main.pjax-out { opacity: 0; transform: translateY(-8px); }
main.pjax-in { animation: pjaxIn .3s cubic-bezier(.2,.8,.2,1) both; }
@keyframes pjaxIn { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
html[data-nav="back"] main.pjax-out { transform: translateY(8px); }
html[data-nav="back"] main.pjax-in { animation-name: pjaxInBack; }
@keyframes pjaxInBack { from { opacity: 0; transform: translateY(-12px); } to { opacity: 1; transform: none; } }
html[data-nav="match"] main.pjax-out { transform: none; transition-duration: .22s; }
html[data-nav="match"] main.pjax-in { animation: pjaxInMatch .42s ease both; }
@keyframes pjaxInMatch { from { opacity: 0; transform: scale(1.012); } to { opacity: 1; transform: none; } }
#pjax-bar { position: fixed; top: 0; left: 0; height: 2px; width: 0; z-index: 100;
  background: linear-gradient(90deg, var(--turf), var(--gold)); box-shadow: 0 0 8px var(--turf);
  opacity: 0; pointer-events: none; transition: width .18s ease, opacity .25s ease; }
#pjax-bar.show { width: 82%; opacity: 1; transition: width 8s cubic-bezier(.1,.7,.2,1), opacity .15s; }
#pjax-bar.done { width: 100%; opacity: 0; transition: width .18s ease, opacity .35s ease .1s; }

/* Native View Transitions (Package 14) — where supported, spa.js swaps inside
   document.startViewTransition and the engine crossfades the page; the shared
   header morphs rather than flashing. Falls back to the .pjax fade above. */
/* THE CHOREOGRAPHY. The whole screen used to crossfade in .22s as one
   picture, masthead and all, which read as a flicker rather than a move. Now
   the parts move as parts:
     chrome     the masthead + ribbon HOLD STILL between two campaign screens
                (only the lit tab changes), slide up and away into a system
                screen or the match, and drop back in on the way out;
     view       the screen itself (<main>) lifts out and the next one rises
                in behind it — the other way round going Back;
     page-head  the screen's own title morphs from one place to the next;
     root       the stage behind them (the ground, the club's wash) dissolves.
   Into the live match the view does not turn like a page: it dissolves into
   the broadcast (html[data-nav="match"], set by spa.js). Between whole
   documents (a full load: leaving the match, signing in) the browser plays the
   same choreography where it can (@view-transition below). */
@media (prefers-reduced-motion: no-preference) {
  /* Only the page's own header: a card that borrows the class (a section head)
     would make the name a duplicate and abort the transition. */
  main > .page-head { view-transition-name: page-head; }
  .chrome { view-transition-name: chrome; }
  #main { view-transition-name: view; }
  @view-transition { navigation: auto; }
}
::view-transition-group(root) { animation-duration: .34s; }
::view-transition-old(root), ::view-transition-new(root) { animation-duration: .34s; animation-timing-function: ease; }
::view-transition-group(view), ::view-transition-group(page-head), ::view-transition-group(chrome) {
  animation-duration: .38s; animation-timing-function: cubic-bezier(.2,.8,.2,1); }
::view-transition-old(view) { animation: vt-view-out .17s cubic-bezier(.4,0,1,1) both; }
::view-transition-new(view) { animation: vt-view-in .36s cubic-bezier(.2,.8,.2,1) .07s both; }
html[data-nav="back"]::view-transition-old(view) { animation-name: vt-view-out-back; }
html[data-nav="back"]::view-transition-new(view) { animation-name: vt-view-in-back; }
/* into the match: the screen gives way to the broadcast, no page-turn */
html[data-nav="match"]::view-transition-old(view) { animation: vt-fade-out .3s ease both; }
html[data-nav="match"]::view-transition-new(view) { animation: vt-match-in .55s cubic-bezier(.2,.7,.2,1) .08s both; }
html[data-nav="match"]::view-transition-old(root), html[data-nav="match"]::view-transition-new(root) { animation-duration: .5s; }
/* the masthead arriving on, or leaving, a screen that has none */
::view-transition-old(chrome):only-child { animation: vt-chrome-out .26s cubic-bezier(.4,0,1,1) both; }
::view-transition-new(chrome):only-child { animation: vt-chrome-in .38s cubic-bezier(.2,.8,.2,1) .06s both; }
@keyframes vt-view-out { to { opacity: 0; transform: translateY(-10px); } }
@keyframes vt-view-in { from { opacity: 0; transform: translateY(16px); } }
@keyframes vt-view-out-back { to { opacity: 0; transform: translateY(10px); } }
@keyframes vt-view-in-back { from { opacity: 0; transform: translateY(-16px); } }
@keyframes vt-fade-out { to { opacity: 0; } }
@keyframes vt-match-in { from { opacity: 0; transform: scale(1.015); } }
@keyframes vt-chrome-out { to { opacity: 0; transform: translateY(-100%); } }
@keyframes vt-chrome-in { from { opacity: 0; transform: translateY(-100%); } }
/* The in-game "reduce motion" setting is on the document, not the OS: a
   transition the browser starts by itself between two documents plays with
   no motion at all. */
html[data-reduce-motion="true"]::view-transition-group(*),
html[data-reduce-motion="true"]::view-transition-old(*),
html[data-reduce-motion="true"]::view-transition-new(*) { animation: none !important; }

/* Off air: the live match is left by a full load, so it fades to the frame's
   black first (spa.js leaveLiveMatch) while its sound fades down, and the next
   screen rises out of the black instead of cutting in. */
html.is-leaving .app { opacity: 0; transition: opacity .5s ease; }
html.is-leaving body { background: var(--bg); }
@media (prefers-reduced-motion: reduce) { html.is-leaving .app { transition: none; } }

/* Slow-load skeleton — shown in <main> after 300ms. It used to blank the old
   view for grey bars and then fade the new one in over THEM: two changes of
   picture for one click. Now the old view stays where it is and settles back
   (dimmed, a light sweeping across it) until the new one arrives, so the only
   change of picture is the one the click asked for. Decorative; disabled under
   reduced motion (spa.js won't add it). */
main.pjax-skeleton { position: relative; }
main.pjax-skeleton > * { opacity: .42; filter: saturate(.7); transition: opacity .35s ease, filter .35s ease; pointer-events: none; }
main.pjax-skeleton::after {
  content: ""; position: absolute; inset: 0; border-radius: var(--radius); pointer-events: none;
  background: linear-gradient(100deg, transparent 30%, rgba(255,255,255,.05) 50%, transparent 70%);
  background-size: 250% 100%; background-repeat: no-repeat;
  animation: skShimmer 1.3s ease-in-out infinite, skIn .35s ease both; }
@keyframes skShimmer { from { background-position: 120% 0; } to { background-position: -20% 0; } }
@keyframes skIn { from { opacity: 0; } }

/* ---- The chrome: masthead + ribbon ----
   What a manager game puts across the top of every screen: the club you are
   (crest, name, competition), what is next, and the one green button that
   moves the game on, with MENU beside it. Under it the screens run as a
   ribbon of tabs. */
.chrome { position: relative; z-index: 5; background: var(--chrome);
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--chrome-line); box-shadow: 0 12px 34px -20px rgba(0,0,0,.9); }
/* A hairline of the club along the very top of the frame. */
.chrome::before { content: ""; display: block; height: 3px;
  background: linear-gradient(90deg, var(--club) 0 64%, var(--club-2) 64% 100%); }
.masthead { display: flex; align-items: center; gap: 1.1rem; min-height: 4.1rem;
  padding: .45rem clamp(1rem, 2.2vw, 1.6rem); }
.go { display: contents; }
/* A table cell holding more than one way out of the row. `.go` is display:
   contents, so the buttons themselves are what this lays out. Right-aligned and
   held on one line: the ledger reads left to right and the actions are its end,
   not another column of data. */
.report-ways { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; }
.row-actions { display: flex; gap: .4rem; justify-content: flex-end;
               align-items: center; white-space: nowrap; }
.brand-btn { display: flex; align-items: center; gap: .65rem; color: var(--text);
  padding: .3rem .5rem; margin-left: -.5rem; background: none; border: 0; border-radius: var(--radius-sm);
  font: inherit; text-align: left; cursor: pointer; min-width: 0; }
.brand-btn:hover { background: var(--glass-hi); }
.brand-mark { display: grid; place-items: center; color: var(--text); }
.pv-mark, .pv-wordmark { display: block; width: auto; flex: none; }
.brand-text { display: flex; flex-direction: column; line-height: 1; }
.brand-text strong { display: block; }
.brand-text small { color: var(--faint); font-size: .64rem; letter-spacing: .04em; margin-top: .22rem; }

/* Procedural club crests + player avatars (Package 8). Sized via --crest-size. */
.crest, .avatar { flex: none; display: inline-block; vertical-align: middle;
  width: var(--crest-size, 22px); height: var(--crest-size, 22px); line-height: 0; }
.avatar { border-radius: 999px; box-shadow: inset 0 0 0 1px rgba(255,255,255,.12); overflow: hidden; }
/* The crest is a SHAPE — a shield, a roundel, an octagon, with a scroll that
   reaches the box's edges (G-52) — so it is never clipped to a disc, and where
   it casts a shadow the shadow is a drop-shadow that follows its outline. */
.crest svg, .avatar svg { display: block; }
.crest-cell { display: inline-flex; align-items: center; gap: .5rem; }

/* The club: crest, the name in display caps, the competition beneath. */
.club-chip { gap: .75rem; }
.club-chip .crest { flex: none; filter: drop-shadow(0 4px 7px rgba(0,0,0,.45)); }
.club-chip-text { display: flex; flex-direction: column; min-width: 0; line-height: 1.1; }
.club-name { font-family: var(--font-display); font-weight: 900; font-size: 1.12rem; letter-spacing: .02em;
  text-transform: uppercase; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.club-sub { color: var(--muted); font-size: .72rem; margin-top: .22rem; font-variant-numeric: tabular-nums;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* A slanted hairline between the club and the readout. */
.mast-div { flex: none; width: 1px; height: 2.2rem; background: var(--chrome-line); transform: skewX(var(--slant)); }
/* NEXT · MD 3 · v PBKS (H) */
.mast-next { display: flex; align-items: center; gap: .55rem; min-width: 0; margin: 0;
  color: var(--muted); font-size: .84rem; font-variant-numeric: tabular-nums; white-space: nowrap; }
.mast-kicker { font-family: var(--font-display); font-weight: 800; font-size: .64rem; letter-spacing: .18em;
  text-transform: uppercase; color: var(--gold); }
.mast-next .crest-cell { color: var(--text); font-weight: 700; font-family: var(--font-display); }
.mast-next .mast-ha { font-size: .7rem; letter-spacing: .06em; color: var(--faint); font-weight: 700; }
.mast-spacer { flex: 1 1 auto; }
.continue-btn { flex: none; text-transform: uppercase; letter-spacing: .05em; font-size: .86rem;
  padding: .7rem 1.3rem; }
.continue-btn .ico { width: 1rem; height: 1rem; }
/* MENU: everything that is not a screen of the club — settings, the par
   board, the main menu, signing out — as one labelled button at the
   masthead's end, opening the pause menu. A word, not an icon cluster. */
.menu-btn { flex: none; font-family: var(--font-display); font-weight: 800; font-size: .76rem;
  letter-spacing: .1em; text-transform: uppercase; color: var(--muted); padding: .62rem .9rem; }
.menu-btn:hover { color: var(--text); background: var(--glass-hi); filter: none; }
.menu-btn .ico { width: 1.15rem; height: 1.15rem; margin: 0; }

/* ---- Ribbon: the screens ---- */
.ribbon { display: flex; align-items: stretch; min-height: 2.75rem; padding: 0 clamp(.6rem, 1.8vw, 1.2rem);
  border-top: 1px solid var(--chrome-line); background: rgba(0,0,0,.2); }
[data-theme="light"] .ribbon { background: rgba(255,255,255,.35); }
.nav { display: flex; align-items: stretch; min-width: 0; }
/* The group names are for screen readers here; the sheet shows them. */
.nav-group { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip: rect(0 0 0 0);
  white-space: nowrap; }
.nav ul { list-style: none; margin: 0; padding: 0; display: flex; align-items: stretch; }
/* a slanted hairline between the groups */
.nav ul:not(:first-of-type)::before { content: ""; align-self: center; width: 1px; height: 1.2rem; margin: 0 .3rem;
  background: var(--chrome-line); transform: skewX(var(--slant)); }
.nav li { display: flex; }
.nav-link { position: relative; display: inline-flex; align-items: center; gap: .45rem; padding: .55rem .85rem; margin: 0;
  color: var(--muted); background: none; border: 0; font: inherit; font-family: var(--font-display);
  font-weight: 800; font-size: .76rem; letter-spacing: .07em; text-transform: uppercase; white-space: nowrap;
  cursor: pointer; transition: color .14s, background .14s; }
.nav-link .ico { width: 1.05rem; height: 1.05rem; opacity: .8; }
.nav-link:hover { color: var(--text); background: var(--glass-hi); }
.nav-link.active { color: var(--text); }
.nav-link.active .ico { color: var(--club); opacity: 1; }
/* The signature: a slanted bar under the screen you are on, in the club's colour. */
.nav-link.active::after { content: ""; position: absolute; left: .7rem; right: .7rem; bottom: 0; height: 3px;
  background: var(--club); transform: skewX(var(--slant));
  box-shadow: 0 0 12px color-mix(in srgb, var(--club) 60%, transparent); }
.nav .dot { width: .45rem; height: .45rem; border-radius: 50%; background: var(--gold); }
/* A screen's short name is for the phone bar only. */
.nav-short { display: none; }
/* Mobile-only overflow toggle (shown only on the JS-curated bottom bar). */
.nav-more { display: none; }

/* ---- Buttons ----
   Weight and bevel: a light edge on top, a dark one beneath, the display face
   for the label. The primary is the game's green. */
.btn { position: relative; overflow: hidden; display: inline-flex; align-items: center; justify-content: center;
  gap: .45rem; font: inherit; font-family: var(--font-display); font-weight: 700; cursor: pointer;
  border: 1px solid var(--border-2); background: linear-gradient(180deg, var(--surface-3), var(--surface-2));
  color: var(--text); padding: .55rem 1rem; border-radius: var(--radius-sm);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.07), 0 2px 6px rgba(0,0,0,.22);
  transition: transform .06s ease, background .15s, border-color .15s, box-shadow .15s, filter .15s; }
.btn:hover { filter: brightness(1.12); border-color: color-mix(in srgb, var(--text) 22%, var(--border-2)); }
.btn:active { transform: translateY(1px) scale(.99); }
.btn-primary { background: linear-gradient(180deg, #48d68e, var(--turf-d)); border-color: transparent;
  color: #04130b; box-shadow: 0 8px 20px rgba(52,196,122,.26), inset 0 1px 0 rgba(255,255,255,.36),
  inset 0 -2px 0 rgba(0,0,0,.16); }
.btn-primary:hover { filter: brightness(1.06); transform: translateY(-1px);
  box-shadow: 0 12px 26px rgba(52,196,122,.32), inset 0 1px 0 rgba(255,255,255,.36), inset 0 -2px 0 rgba(0,0,0,.16); }
.btn-primary:active { transform: translateY(1px) scale(.99); }
.btn-danger { background: transparent; box-shadow: none; border-color: color-mix(in srgb, var(--danger) 55%, transparent);
  color: var(--danger); }
.btn-danger:hover { background: var(--danger); color: #fff; border-color: var(--danger); filter: none; }
.btn-ghost { background: transparent; box-shadow: none; border-color: var(--glass-line); }
.btn-sm { padding: .34rem .7rem; font-size: .82rem; }
.btn-lg { padding: .78rem 1.45rem; font-size: 1rem; }
.btn-block { width: 100%; }
.btn[disabled] { opacity: .5; cursor: not-allowed; }
.btn.is-setting { cursor: progress; }   /* fielders are running to their positions */
.btn-link { display: inline-flex; align-items: center; gap: .25rem; font: inherit; font-weight: 700;
  cursor: pointer; border: 0; background: none; padding: 0; color: var(--turf);
  text-decoration: none; transition: color .12s, transform .06s ease; }
.btn-link:hover { color: var(--turf-d); text-decoration: underline; }
.btn-link:active { transform: translateY(1px); }
.btn .ripple { position: absolute; width: 14px; height: 14px; margin: -7px; border-radius: 50%;
  background: rgba(255,255,255,.45); transform: scale(0); animation: ripple .5s ease-out forwards; pointer-events: none; }

/* ---- Screen header ----
   Not a web page's heading: a title band in display caps on a rule that spans
   the view, with the club's slanted mark under it — the way a game titles a
   screen. `.page-head` on its own is only the flex row (cards use it for their
   own header lines); the band belongs to the screen's own header in <main>. */
.page-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 1rem;
  flex-wrap: wrap; margin-bottom: 1.4rem; }
main > .page-head { position: relative; margin: 0 0 1.3rem; padding: 0 0 .85rem;
  border-bottom: 1px solid var(--glass-line); }
main > .page-head::after { content: ""; position: absolute; left: 0; bottom: -2px; width: 5.5rem; height: 3px;
  background: var(--club); transform: skewX(var(--slant)); transform-origin: left bottom; }
.page-head-text { min-width: 0; }
.page-actions { display: flex; gap: .55rem; flex-wrap: wrap; align-items: center; }
.eyebrow { margin: 0 0 .2rem; font-family: var(--font-display); font-size: .66rem; font-weight: 800;
  letter-spacing: .18em; text-transform: uppercase; color: var(--turf); }
h1 { font-family: var(--font-display); font-size: var(--fs-xl); margin: 0; letter-spacing: -.01em; font-weight: 900;
  text-transform: uppercase; display: flex; align-items: center; gap: .5rem; line-height: 1.05; }
h2 { font-family: var(--font-display); font-size: var(--fs-md); margin: 0 0 .8rem; letter-spacing: 0; font-weight: 800; }
h3 { font-size: 1rem; margin: 0 0 .5rem; }
.sub { color: var(--muted); font-size: .9rem; margin: .35rem 0 0; }
.card h2 { display: flex; align-items: center; gap: .5rem; }
/* A panel's own title: small display caps on a rule, the broadcast way. */
.card > h2, .card > .page-head > h2 { font-size: .74rem; font-weight: 800; letter-spacing: .14em;
  text-transform: uppercase; color: var(--muted); }
.card > h2 { margin: 0 0 .85rem; padding-bottom: .55rem; border-bottom: 1px solid var(--glass-line); }
.card > .page-head { border-bottom: 1px solid var(--glass-line); padding-bottom: .5rem; }
.card > h2 .h-ico, .card > .page-head > h2 .h-ico { width: 1.1em; height: 1.1em; }
/* The live match keeps its own register (the console's questions are sentences). */
.app--match .card > h2 { font-size: var(--fs-md); letter-spacing: 0; text-transform: none; color: var(--text);
  border-bottom: 0; padding-bottom: 0; }

/* ---- The way back ----
   A screen with no ribbon (settings, the par board, the lobby) or a
   sub-screen of the club (a player) carries one word at the top-left of the
   view, the arrow, and the key that does the same thing (ui.back). */
.back-row { margin: 0 0 .9rem; }
.back-btn { font-family: var(--font-display); font-weight: 800; font-size: .76rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--muted); padding: .5rem .8rem .5rem .6rem; }
.back-btn:hover { color: var(--text); background: var(--glass-hi); filter: none; }
.back-btn .ico { width: 1.1rem; height: 1.1rem; margin: 0; }
/* A key cap: the shortcut a control answers to. Keyboard caps by default, the
   pad's button under [data-tv]; none at all on a touch screen, where there is
   no key to press (the [data-tv] cap comes back for a pad on a TV). */
.key { display: inline-grid; place-items: center; min-width: 1.6em; height: 1.45em; padding: 0 .35em;
  margin-left: .2rem; border-radius: 4px; font-family: var(--font-display); font-size: .72rem; font-weight: 800;
  letter-spacing: .04em; text-transform: uppercase; line-height: 1; color: var(--faint);
  background: var(--surface-2); border: 1px solid var(--border-2); box-shadow: inset 0 -1.5px 0 rgba(0,0,0,.35); }
.key--pad { display: none; }
[data-tv] .key--kb { display: none; }
[data-tv] .key--pad { display: inline-grid; }
@media (hover: none) { .key { display: none; } [data-tv] .key--pad { display: inline-grid; } }

/* ---- Hero / broadcast feature header ---- */
.hero, .broadcast { position: relative; overflow: hidden; border-radius: var(--radius); padding: 1.5rem 1.6rem;
  margin-bottom: 1.4rem; border: 1px solid var(--glass-line); box-shadow: var(--shadow);
  -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
  background:
    radial-gradient(120% 140% at 100% 0%, color-mix(in srgb, var(--club) 20%, transparent), transparent 55%),
    linear-gradient(180deg, var(--glass-2), var(--glass)); }
.hero::before, .broadcast::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 4px;
  background: linear-gradient(180deg, var(--club), var(--club-2)); }
.hero h1 { font-size: var(--fs-2xl); }
.broadcast .bc-teams { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; }
.broadcast .bc-team { font-family: var(--font-display); font-size: 1.5rem; font-weight: 800; letter-spacing: .3px; }
.broadcast .bc-vs { color: var(--muted); font-weight: 700; font-size: .9rem; }
.bc-meta { display: flex; gap: .4rem; flex-wrap: wrap; margin: .6rem 0 1rem; }

/* Gold broadcast card — used for the campaign-complete finale / season end. */
.broadcast.gold { border-color: var(--gold);
  background:
    radial-gradient(120% 140% at 100% 0%, color-mix(in srgb, var(--gold) 22%, transparent), transparent 55%),
    linear-gradient(180deg, var(--surface-2), var(--surface)); }

/* ---- Campaign completion screen ---- */
.campaign-end { max-width: 880px; }
.end-hero { text-align: center; }
.end-hero .eyebrow { justify-content: center; }
.end-badge { display: inline-flex; align-items: center; gap: .4rem; margin: .2rem 0 .4rem;
  font-family: var(--font-display); font-weight: 800; letter-spacing: .12em; text-transform: uppercase;
  font-size: .8rem; color: var(--gold); }
.end-headline { font-family: var(--font-display); font-size: clamp(1.6rem, 5vw, 2.4rem);
  line-height: 1.1; margin: .1rem 0; }
.end-actions { display: flex; flex-direction: column; align-items: flex-start; gap: .7rem; }
.end-actions p { margin: 0; color: var(--muted); }

/* ---- The main menu (the campaigns lobby) ----
   A title screen you can act on: the wordmark, then the choices stacked the
   way a game stacks them — CONTINUE first and biggest, then the rest — with
   the campaign slots and the trophy cabinet beside them. */
.menu-screen { display: grid; grid-template-columns: minmax(min(18rem, 100%), 24rem) minmax(0, 1fr);
  gap: clamp(1.4rem, 4vw, 3.5rem); align-items: start; margin-top: clamp(.4rem, 3vh, 2rem); }
.menu-wordmark { margin: 0; display: flex; justify-content: center; color: var(--text);
  filter: drop-shadow(0 10px 34px rgba(0,0,0,.55)); }
.menu-tag { margin: .4rem 0 1.4rem; color: var(--muted); font-style: italic; }
.mainmenu { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .5rem; }
.mainmenu li { display: flex; }
.menu-item { position: relative; display: flex; align-items: center; gap: .9rem; width: 100%;
  padding: .8rem 1.1rem .8rem 1.25rem; text-align: left; overflow: hidden;
  border: 1px solid var(--glass-line); border-radius: var(--radius-sm); background: var(--glass);
  color: var(--text); font: inherit; cursor: pointer;
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  box-shadow: inset 0 1px 0 var(--glass-hi), 0 8px 24px rgba(0,0,0,.28);
  transition: transform .08s, background .14s, border-color .14s; }
.menu-item::before { content: ""; position: absolute; left: -2px; top: -4px; bottom: -4px; width: 5px;
  background: var(--faint); transform: skewX(var(--slant)); opacity: .45; }
.menu-item:hover { background: var(--glass-2); transform: translateX(4px);
  border-color: color-mix(in srgb, var(--text) 22%, var(--glass-line)); }
.menu-item:hover::before { background: var(--turf); opacity: 1; }
.menu-item:active { transform: translateX(4px) scale(.995); }
.menu-item > .ico { width: 1.35rem; height: 1.35rem; color: var(--turf); flex: none; }
.menu-item-text { display: flex; flex-direction: column; min-width: 0; }
.menu-item-label { font-family: var(--font-impact); font-weight: 400; font-size: 1.35rem; letter-spacing: .08em;
  text-transform: uppercase; line-height: 1; }
.menu-item-sub { color: var(--muted); font-size: .8rem; margin-top: .3rem; white-space: nowrap; overflow: hidden;
  text-overflow: ellipsis; }
/* CONTINUE: the campaign you were in, first and biggest, in its club's colour. */
.menu-item--continue { padding: 1rem 1.2rem 1rem 1.3rem;
  border-color: color-mix(in srgb, var(--turf) 45%, var(--glass-line));
  background: linear-gradient(100deg, color-mix(in srgb, var(--club) 28%, var(--glass)), var(--glass) 72%); }
.menu-item--continue::before { background: var(--turf); opacity: 1; }
.menu-item--continue .crest { flex: none; filter: drop-shadow(0 6px 9px rgba(0,0,0,.4)); }
.menu-item--continue .menu-item-label { font-size: 1.75rem; color: var(--turf); }
.menu-item--continue .menu-item-sub { color: var(--text); font-weight: 600; white-space: normal; }
.menu-item--quit > .ico { color: var(--muted); }
.menu-item--quit:hover::before { background: var(--leather); }

/* The main menu proper: wordmark, the stack, the corners. */
.title-menu { min-height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 1.6rem; padding: clamp(1.5rem, 6vh, 4rem) 1rem calc(4.5rem + env(safe-area-inset-bottom)); text-align: center; }
.title-menu-head .menu-tag { margin: .4rem 0 0; }
.mainmenu--centered { width: min(26rem, 100%); text-align: left; }
.menu-count { margin-left: auto; font-family: var(--font-display); font-weight: 800; font-size: .8rem;
  min-width: 1.6rem; height: 1.6rem; padding: 0 .45rem; border-radius: 999px; display: inline-grid; place-items: center;
  background: var(--surface-3); color: var(--muted); border: 1px solid var(--border-2); }
.title-corner { position: fixed; bottom: calc(1rem + env(safe-area-inset-bottom)); z-index: 3; display: flex;
  align-items: center; gap: .6rem; }
.title-corner--bl { left: clamp(1rem, 2.5vw, 2rem); }
.title-corner--br { right: clamp(1rem, 2.5vw, 2rem); }
.corner-btn { color: var(--muted); }
.corner-btn:hover { color: var(--text); }
/* The username is the door to the profile: a corner button like its neighbour,
   the name in tabular figures so a numbered handle sits still. */
.corner-who { font-variant-numeric: tabular-nums; max-width: 14rem; }
.corner-who span, .corner-who { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Three labelled buttons do not fit across a phone's foot: the username goes,
   and the left corner stacks (How to play over Settings), so nothing in one
   corner ever runs into the other. The menu keeps clear of the taller corner. */
@media (max-width: 560px) {
  .corner-who { display: none; }
  .title-corner--bl { flex-direction: column; align-items: flex-start; gap: .4rem; }
  .title-menu { padding-bottom: calc(7.4rem + env(safe-area-inset-bottom)); }
}
/* The Fold's cover screen: the corners slim down so both still fit. */
@media (max-width: 360px) { .corner-btn { padding: .4rem .6rem; font-size: .84rem; } }

/* The load screen's slots. */
.menu-side { min-width: 0; }
.menu-side-head { margin-bottom: .8rem; }
.menu-side-head h2 { margin: 0; font-size: .8rem; letter-spacing: .16em; text-transform: uppercase; color: var(--muted); }
/* `min(Npx, 100%)` so a track never demands more than the container has — a
   bare minmax(280px,1fr) overflowed the page on a 280px-wide phone. */
.save-grid { display: grid; gap: .8rem; grid-template-columns: repeat(auto-fill, minmax(min(280px, 100%), 1fr)); }
.save-card { display: flex; flex-direction: column; gap: .55rem; margin: 0; overflow: hidden; padding: 1rem 1.1rem 1rem 1.25rem;
  background: linear-gradient(100deg, color-mix(in srgb, var(--club) 18%, var(--glass)), var(--glass) 62%); }
.save-card::before { content: ""; position: absolute; left: -1px; top: -2px; width: 5px; height: 3rem;
  background: linear-gradient(180deg, var(--club), var(--club-2)); transform: skewX(var(--slant));
  transform-origin: top left; }
.save-card-done { border-color: color-mix(in srgb, var(--gold) 45%, var(--glass-line)); }
.save-card-head { display: flex; align-items: center; justify-content: space-between; gap: .7rem; }
.save-card-head .crest { flex: none; filter: drop-shadow(0 6px 9px rgba(0,0,0,.35)); }
.save-card-text { flex: 1 1 auto; min-width: 0; }
.save-name { font-size: 1.1rem; margin: 0; font-family: var(--font-display); font-weight: 900; letter-spacing: -.01em; }
.save-meta-line { margin: .1rem 0 0; }
.save-progress { display: flex; flex-direction: column; gap: .3rem; }
.save-progress-bar { display: block; height: 5px; border-radius: 3px; background: var(--surface-3); overflow: hidden; }
.save-progress-bar i { display: block; height: 100%; border-radius: 3px;
  background: linear-gradient(90deg, var(--club), var(--turf)); }
.save-updated { margin: 0; }
.save-actions { display: flex; align-items: center; gap: .5rem; margin-top: auto; flex-wrap: wrap; }
.empty-state { text-align: center; }
/* `minmax(0, 1fr)`, not `1fr`: a bare 1fr track's minimum is the content's
   min-content width, and a menu item's one-line sub ran the lobby to 446px
   on a 390px phone. */
.menu-screen > * { min-width: 0; }
@media (max-width: 880px) { .menu-screen { grid-template-columns: minmax(0, 1fr); } }

/* ---- Cards & tiles ----
   Glass over the stage: the ground shows through, softened, with a light
   edge along the top. */
.card { position: relative; background: var(--glass); border: 1px solid var(--glass-line); border-radius: var(--radius);
  padding: 1.1rem 1.25rem; margin-bottom: 1.1rem; animation: fadeUp .4s both;
  -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
  box-shadow: var(--shadow), inset 0 1px 0 var(--glass-hi); }
.grid { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(min(230px, 100%), 1fr)); }
.tiles { display: grid; gap: .9rem; grid-template-columns: repeat(auto-fit, minmax(min(170px, 100%), 1fr)); margin-bottom: 1.4rem; }
.tile { position: relative; overflow: hidden; background: var(--glass); border: 1px solid var(--glass-line);
  border-radius: var(--radius); padding: 1.05rem 1.15rem; box-shadow: var(--shadow); animation: fadeUp .45s both;
  -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
  transition: transform .15s ease, border-color .15s; }
.tile:hover { transform: translateY(-2px); border-color: var(--border-2); }
.tile-ico { position: absolute; top: .9rem; right: .95rem; color: var(--faint); }
.tile-ico .ico { width: 1.25rem; height: 1.25rem; }
.tiles .tile:nth-child(2) { animation-delay: .05s; }
.tiles .tile:nth-child(3) { animation-delay: .1s; }
.tiles .tile:nth-child(4) { animation-delay: .15s; }
.tile .label, .label { color: var(--muted); font-family: var(--font-display); font-size: .68rem; text-transform: uppercase;
  letter-spacing: .12em; font-weight: 800; }
.tile .value { font-family: var(--font-display); font-size: 1.95rem; font-weight: 800; color: var(--text);
  letter-spacing: .2px; margin-top: .15rem; font-variant-numeric: tabular-nums; line-height: 1.1; }
.tile .value.accent { color: var(--turf); }
.tile .foot { color: var(--faint); font-size: .8rem; margin-top: .3rem; }
.stat-big { font-family: var(--font-display); font-size: 2rem; font-weight: 800; color: var(--turf);
  margin: .2rem 0; font-variant-numeric: tabular-nums; letter-spacing: .2px; }

/* ---- Ratings: one colour-graded overall pill ---- */
.ovr { display: inline-block; min-width: 2.2rem; text-align: center; padding: .12rem .42rem; border-radius: 7px;
  font-family: var(--font-display); font-weight: 800; font-size: .86rem; font-variant-numeric: tabular-nums;
  background: var(--surface-3); color: var(--text); border: 1px solid var(--border-2); }
.ovr.r-elite { background: color-mix(in srgb, var(--t-elite) 22%, var(--surface)); border-color: color-mix(in srgb, var(--t-elite) 60%, transparent); color: color-mix(in srgb, var(--t-elite) 75%, var(--text)); }
.ovr.r-strong { background: color-mix(in srgb, var(--t-strong) 18%, var(--surface)); border-color: color-mix(in srgb, var(--t-strong) 50%, transparent); }
.ovr.r-good { background: color-mix(in srgb, var(--t-good) 16%, var(--surface)); border-color: color-mix(in srgb, var(--t-good) 45%, transparent); }
.ovr.r-ok { background: color-mix(in srgb, var(--t-ok) 16%, var(--surface)); border-color: color-mix(in srgb, var(--t-ok) 45%, transparent); }
.ovr.r-weak { background: color-mix(in srgb, var(--t-weak) 16%, var(--surface)); border-color: color-mix(in srgb, var(--t-weak) 45%, transparent); }

/* ---- Attribute bars (player profile) ---- */
.attr { display: grid; grid-template-columns: 8.5rem 1fr 2rem; align-items: center; gap: .6rem; padding: .3rem 0; }
.attr-label { font-size: .86rem; color: var(--muted); }
.attr-track { height: 8px; border-radius: 5px; background: var(--surface-3); overflow: hidden; }
.attr-fill { display: block; height: 100%; border-radius: 5px; background: var(--turf); }
.attr-fill.r-elite { background: var(--t-elite); } .attr-fill.r-strong { background: var(--t-strong); }
.attr-fill.r-good { background: var(--t-good); } .attr-fill.r-ok { background: var(--t-ok); } .attr-fill.r-weak { background: var(--t-weak); }
.attr-val { font-family: var(--font-display); font-weight: 800; font-size: .9rem; text-align: right;
  font-variant-numeric: tabular-nums; color: var(--text); }

/* ---- Player rows (squad / transfers / lineup) ---- */
.role-badge { display: inline-grid; place-items: center; width: 1.7rem; height: 1.7rem; border-radius: 8px;
  background: var(--surface-3); border: 1px solid var(--border-2); color: var(--muted); flex: none; }
.role-badge .ico { width: 1rem; height: 1rem; }
.role-bat { color: var(--turf); } .role-bowl { color: var(--leather); }
.role-ar { color: var(--gold); } .role-wk { color: var(--focus); }
.p-cell { display: flex; align-items: center; gap: .6rem; min-width: 0; }
.p-name { font-weight: 700; }
.form-up { color: var(--turf); } .form-down { color: var(--leather); } .form-flat { color: var(--faint); }
/* recent-form sparkline: one bar per recent innings (height ∝ runs) */
.spark { display: inline-flex; align-items: flex-end; gap: 2px; height: 1.5rem; }
.spark-bar { width: 4px; min-height: 2px; border-radius: 1px; background: var(--faint); }
.spark-bar.s-hi { background: var(--turf); } .spark-bar.s-mid { background: var(--gold); } .spark-bar.s-lo { background: var(--leather); }
.spark-empty { color: var(--faint); font-size: .8rem; }

/* sortable table headers */
table.sortable thead th[data-sort] { cursor: pointer; user-select: none; white-space: nowrap; }
table.sortable thead th[data-sort]:hover { color: var(--text); }
table.sortable thead th[data-sort]::after { content: "⇅"; opacity: .35; margin-left: .25rem; font-size: .8em; }
table.sortable thead th[aria-sort="ascending"]::after { content: "↑"; opacity: .9; }
table.sortable thead th[aria-sort="descending"]::after { content: "↓"; opacity: .9; }

/* ---- Scoreboard component ---- */
.scoreboard { display: inline-flex; align-items: baseline; gap: .5rem; padding: .5rem .9rem; border-radius: 10px;
  background: #05100a; border: 1px solid #18372550; box-shadow: inset 0 0 18px rgba(0,0,0,.55);
  font-variant-numeric: tabular-nums; }
.scoreboard .runs { font-family: var(--font-display); font-size: 2.2rem; font-weight: 800; color: #ffd86b;
  letter-spacing: 1px; text-shadow: 0 0 14px rgba(255,216,107,.35); }
.scoreboard .ov { color: #7fe0a6; font-weight: 700; }

/* ---- Tables ---- */
table { border-collapse: collapse; width: 100%; font-size: .92rem; }
caption { text-align: left; font-weight: 600; margin-bottom: .5rem; color: var(--muted); font-size: .85rem; }
th, td { text-align: left; padding: .6rem .65rem; border-bottom: 1px solid var(--glass-line); }
thead th { position: sticky; top: 0; background: var(--surface-2); color: var(--muted); z-index: 1;
  font-family: var(--font-display); font-size: .66rem; font-weight: 800; text-transform: uppercase;
  letter-spacing: .1em; border-bottom: 1px solid var(--border-2); }
tbody tr { transition: background .12s; }
tbody tr:hover { background: var(--glass-hi); }
tfoot th, tfoot td { border-top: 2px solid var(--border-2); font-weight: 700; }
.num { text-align: right; font-variant-numeric: tabular-nums; }
.data-table td .num, td.num { font-family: var(--font-display); }
tr.is-mine { background: color-mix(in srgb, var(--club) 16%, transparent); box-shadow: inset 3px 0 0 var(--club); }
tr.is-mine th { font-weight: 800; }

/* ---- Forms ---- */
form label { display: block; font-weight: 600; margin: .9rem 0 .3rem; }
input, select, textarea { font: inherit; padding: .6rem .75rem; width: 100%; max-width: 460px; color: var(--text);
  background: var(--surface-2); border: 1px solid var(--border-2); border-radius: var(--radius-sm);
  transition: border-color .15s, box-shadow .15s; }
input:focus, select:focus { border-color: var(--turf); box-shadow: 0 0 0 3px rgba(52,196,122,.18); outline: none; }
input[type="checkbox"], input[type="radio"] { width: auto; accent-color: var(--turf); }
input[type="range"] { padding: 0; accent-color: var(--turf); }
fieldset { border: 1px solid var(--border); border-radius: var(--radius-sm); padding: .85rem 1.05rem; margin: 1rem 0; }
legend { font-weight: 800; padding: 0 .4rem; }
.help { color: var(--muted); font-size: .85rem; }
.error-text { color: var(--danger); }
.form-card { max-width: 460px; }
.form-card input, .form-card select { max-width: none; }

/* ---- Switch (settings toggle) ---- */
.field-toggle { padding: .55rem 0; border-bottom: 1px solid var(--border); }
.field-toggle:last-child { border-bottom: 0; }
.switch { display: flex; align-items: center; gap: .7rem; cursor: pointer; font-weight: 600; margin: 0; }
.switch input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.switch-track { position: relative; flex: none; width: 2.6rem; height: 1.5rem; border-radius: 999px;
  background: var(--surface-3); border: 1px solid var(--border-2); transition: background .16s, border-color .16s; }
.switch-thumb { position: absolute; top: 2px; left: 2px; width: 1.15rem; height: 1.15rem; border-radius: 50%;
  background: var(--muted); transition: transform .16s, background .16s; }
.switch input:checked + .switch-track { background: color-mix(in srgb, var(--turf) 40%, var(--surface)); border-color: var(--turf); }
.switch input:checked + .switch-track .switch-thumb { transform: translateX(1.1rem); background: var(--turf); }
.switch input:focus-visible + .switch-track { outline: 3px solid var(--focus); outline-offset: 2px; }
.switch-label { font-weight: 600; }
.switch-help { margin: .2rem 0 0 3.3rem; }

/* ---- Settings page layout ---- */
.settings-card { max-width: 620px; }
.settings-group { border: 0; margin: 0 0 1.1rem; padding: 0; }
.settings-group:last-child { margin-bottom: 0; }
.settings-group > legend { font-family: var(--font-display); font-weight: 800; font-size: .78rem;
  text-transform: uppercase; letter-spacing: .1em; color: var(--muted);
  padding: 0 0 .35rem; margin-bottom: .3rem; width: 100%; border-bottom: 1px solid var(--border); }
/* Wraps onto two lines rather than crushing the control: on a 280px screen the
   label won the row and left the <select> 26px wide. */
.setting-row { display: flex; align-items: center; gap: .3rem .6rem; flex-wrap: wrap;
  margin: .55rem 0 .2rem; }
.setting-row > label { flex: 0 1 auto; font-weight: 600; margin: 0; }
.setting-row select, .setting-row input[type="range"],
.setting-row input[type="password"] { flex: 1 1 10rem; min-width: 9rem; max-width: 16rem; }
.settings-actions { display: flex; align-items: center; gap: .8rem; margin-top: 1.1rem; }
.settings-saved { display: inline-flex; align-items: center; gap: .3rem; color: var(--turf); font-weight: 700; }
.settings-saved .ico { width: 1em; height: 1em; }
/* The speech-rate readout beside its slider: tabular, so the number does not
   shuffle the row as it counts. */
.rate-val { flex: 0 0 auto; min-width: 3.2em; text-align: right;
  font-variant-numeric: tabular-nums; }
/* A fader row: the name, then the fader taking the rest. */
.vol-row > label { flex: 0 0 8rem; }

/* The same settings, drawn inside the match's modal (settings/_controls.html).
   The card IS the modal, so the panels drop their own card chrome and the whole
   thing sizes to the dialog rather than to the 620px settings column. */
.match-settings-card .settings-tabs { margin: 0; }
.match-settings-card .settings-card { max-width: none; padding: 0;
  border: 0; background: none; box-shadow: none; -webkit-backdrop-filter: none; backdrop-filter: none; }
.match-settings-card .tab-panel { padding-top: .5rem; }
.match-settings-card .tablist { position: sticky; top: 0; z-index: 2;
  background: var(--surface); margin-bottom: .6rem; }
/* Three tabs in a dialog the width of a phone. Left as the page's tabs they
   overflowed and the first one ("Display") was scrolled half out of sight the
   moment another was chosen — so the panel opened on a tab whose name was cut
   in half. They share the row instead. */
.match-settings-card .tablist .tab { flex: 1 1 auto; justify-content: center;
  padding: .55rem .4rem; }
@media (max-width: 460px) {
  /* .72rem = 11.52px: the phone floor, never under it. What gives on a narrow
     screen is the tracking and the gaps — and past that the row scrolls, which
     the tablist already does. */
  .match-settings-card .tablist .tab { font-size: .72rem; letter-spacing: .03em;
    gap: .25rem; padding: .5rem .3rem; }
  .match-settings-card .tablist .tab .ico { width: .85rem; height: .85rem; }
}
.match-settings-card .vol-row > label { flex: 0 0 6.5rem; }
.match-settings-foot { margin: .9rem 0 0; padding-top: .7rem; border-top: 1px solid var(--border); }

/* ---- Toast notifications ---- */
.toasts { position: fixed; top: 1rem; right: 1rem; z-index: 150; display: flex; flex-direction: column;
  gap: .6rem; max-width: min(380px, 92vw); }
.toast { display: flex; align-items: flex-start; gap: .6rem; padding: .8rem 1rem; border-radius: var(--radius-sm);
  background: var(--surface); border: 1px solid var(--border-2); box-shadow: var(--shadow);
  border-left: 4px solid var(--muted); animation: toastIn .35s both; }
.toast--out { opacity: 0; transform: translateY(-10px); transition: opacity .35s, transform .35s; }
.toast-success { border-left-color: var(--turf); }
.toast-error { border-left-color: var(--leather); }
.toast-info { border-left-color: var(--focus); }
.toast-ico { font-size: 1.1rem; }
.toast-close { margin-left: auto; background: none; border: 0; color: var(--muted); cursor: pointer; font-size: 1.1rem; line-height: 1; }

/* ---- Banner ---- */
.banner { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap;
  padding: .9rem 1.15rem; border-radius: var(--radius); margin-bottom: 1.2rem; animation: fadeUp .4s both;
  background: var(--surface); border: 1px solid var(--border-2); border-left: 4px solid var(--muted); }
.banner.gold { border-left-color: var(--gold);
  background: linear-gradient(90deg, color-mix(in srgb, var(--gold) 14%, var(--surface)), var(--surface)); }
.banner-row { display: flex; align-items: center; gap: .55rem; }

/* ---- Badges, chips, pills ---- */
.badge { display: inline-flex; align-items: center; gap: .25rem; padding: .14rem .55rem; border-radius: 999px;
  background: var(--surface-3); border: 1px solid var(--border-2); font-size: .72rem; color: var(--muted); font-weight: 700; }
.badge.true { border-color: color-mix(in srgb, var(--turf) 55%, transparent); color: var(--turf);
  background: color-mix(in srgb, var(--turf) 12%, transparent); }
/* An unavailable player / stale intel — the one "watch out" state a badge has.
   (Used by the squad + scouting tables; it had no styling at all, so both read
   as ordinary neutral badges.) */
.badge.badge-warn { border-color: color-mix(in srgb, var(--danger) 50%, transparent);
  color: var(--danger); background: color-mix(in srgb, var(--danger) 12%, transparent); }
.badge .ico { width: .85rem; height: .85rem; }
.metachip { display: inline-flex; align-items: center; gap: .3rem; padding: .2rem .6rem; border-radius: 8px;
  background: var(--surface-2); border: 1px solid var(--border); font-size: .78rem; color: var(--muted); font-weight: 600; }
.metachip .ico { width: .9rem; height: .9rem; color: var(--faint); }
.metachip-warn { border-color: color-mix(in srgb, var(--danger) 45%, transparent);
  color: var(--danger); background: color-mix(in srgb, var(--danger) 10%, transparent); }
.metachip-warn .ico { color: var(--danger); }
/* A control that must sit on ONE line inside a table cell (assign a scout, buy a
   facility upgrade). Without this the global `select { width:100% }` pushed the
   button onto its own row and the label claimed a whole line. */
.inline-form { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; margin: 0; }
.inline-form label { margin: 0; }
.inline-form select, .inline-form input { width: auto; min-width: 9rem; max-width: 14rem; flex: 1 1 auto; }
.inline-form .btn { flex: 0 0 auto; }
.controls { display: flex; gap: .55rem; flex-wrap: wrap; margin: .4rem 0 1rem; align-items: center; }

/* ---- DRS review countdown ---- */
.review-card { border-color: color-mix(in srgb, var(--gold) 45%, var(--border-2)); }
.review-timer { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
  margin: 0 0 .7rem; }
.review-clock { font-family: Archivo, sans-serif; font-weight: 800; font-size: 1.5rem;
  font-variant-numeric: tabular-nums; color: var(--gold); min-width: 1.7em; }
.review-track { flex: 1 1 8rem; height: .42rem; border-radius: 999px; overflow: hidden;
  background: var(--surface-3); border: 1px solid var(--border-2); }
.review-fill { display: block; height: 100%; width: 100%; background: var(--gold);
  transform-origin: left center; }
/* Under five seconds the clock turns and pulses — you can feel it running out. */
.review-timer.is-urgent .review-clock { color: var(--danger); animation: reviewPulse .85s ease-in-out infinite; }
.review-timer.is-urgent .review-fill { background: var(--danger); }
@keyframes reviewPulse { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }
[data-reduce-motion="true"] .review-timer.is-urgent .review-clock { animation: none; }
/* The dressing room's read — set apart from the situation so it is obviously
   advice rather than fact, and readable in the couple of seconds available. */
.review-advice { margin: 0 0 .8rem; padding: .6rem .75rem; border-radius: var(--radius-sm, 8px);
  background: var(--surface-2); border-left: 3px solid var(--gold); font-size: var(--fs-sm); }
.review-advice strong { color: var(--gold); }
.review-advice .pick-tag { font-size: .68rem; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--muted); margin-right: .3rem; }

/* ---- Ability shown as a scouted range ---- */
.ovr-band { font-size: .78em; letter-spacing: -.02em; padding-inline: .4rem; }

/* ---- Match-up history (evidence, not a rating) ---- */
.hist-line { display: block; color: var(--gold); opacity: .9; }
.hist-line .ico { width: .75rem; height: .75rem; }
.matchup-table td { vertical-align: middle; }

/* ---- The ball's condition (live bowling panel) ---- */
.ball-state { border-left: 3px solid var(--border-2); padding-left: .6rem; }
.ball-state.ball-new { border-left-color: var(--accent); }
.ball-state.ball-reverse { border-left-color: var(--gold); }
.chip-matchup { border-color: color-mix(in srgb, var(--gold) 55%, transparent); }
.mu-tag { color: var(--gold); font-weight: 800; }

/* ---- Team news (pre-match planning) ---- */
.teamnews { display: grid; gap: 1rem; grid-template-columns: 1.15fr .85fr; align-items: start; }
.teamnews .card { margin-bottom: 0; }
@media (max-width: 980px) { .teamnews { display: block; } .teamnews .card { margin-bottom: 1.2rem; } }
.badge-lh { border-color: color-mix(in srgb, var(--accent) 55%, transparent); color: var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, transparent); }
/* A scout's claim. Muted until you ACT on it — acting is the decision. */
.intel-chip { display: inline-flex; align-items: center; gap: .25rem; margin: .1rem .2rem .1rem 0;
  padding: .12rem .45rem; border-radius: 7px; font-size: .72rem; font-weight: 600;
  background: var(--surface-3); border: 1px dashed var(--border-2); color: var(--muted); }
.intel-chip.is-acted { border-style: solid; border-color: color-mix(in srgb, var(--gold) 60%, transparent);
  color: var(--gold); background: color-mix(in srgb, var(--gold) 12%, transparent); }
.intel-chip .ico { width: .8rem; height: .8rem; }
.form-strip { display: flex; align-items: center; gap: .3rem; flex-wrap: wrap; }
.form-pip { display: inline-flex; align-items: center; justify-content: center; width: 1.35rem; height: 1.35rem;
  border-radius: 6px; font-size: .72rem; font-weight: 800; background: var(--surface-3);
  border: 1px solid var(--border-2); color: var(--muted); }
.form-pip.form-w { border-color: color-mix(in srgb, var(--turf) 55%, transparent); color: var(--turf);
  background: color-mix(in srgb, var(--turf) 14%, transparent); }
.form-pip.form-l { border-color: color-mix(in srgb, var(--danger) 50%, transparent); color: var(--danger);
  background: color-mix(in srgb, var(--danger) 12%, transparent); }

/* ---- Dashboard ---- */
.dash { display: flex; flex-direction: column; gap: 1rem; }
.dash-body { display: grid; gap: 1rem; grid-template-columns: 1.25fr .75fr; align-items: start; }
.dash-col { display: flex; flex-direction: column; gap: 1rem; }
.dash-body .card { margin-bottom: 0; }
.dash-body .card .newsfeed { max-height: 20rem; overflow-y: auto; }
@media (max-width: 820px) {
  .dash, .dash-body, .dash-col { display: block; }
  .dash-body .card { margin-bottom: 1.2rem; }
  .dash-body .card .newsfeed { max-height: none; }
}

/* ---- Tournament points table + leaderboards ---- */
.tourn-block table { font-size: .86rem; }
.tourn-sub { font-size: .8rem; font-weight: 800; text-transform: uppercase; letter-spacing: .06em;
  color: var(--faint); margin: .1rem 0 .5rem; display: flex; align-items: center; gap: .35rem; }
.standings-grid { display: grid; gap: .6rem 1.5rem; grid-template-columns: repeat(auto-fit, minmax(min(250px, 100%), 1fr)); }
.standings-group { min-width: 0; }
.leaders-grid { display: grid; gap: 1rem 1.6rem; grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr)); }
.leader-col { min-width: 0; }

.newsfeed { list-style: none; margin: 0; padding: 0; }
.newsfeed li { padding: .6rem 0; border-bottom: 1px solid var(--border); font-size: .92rem; display: flex; gap: .55rem;
  align-items: baseline; animation: rise .4s both; }
.newsfeed li:last-child { border-bottom: 0; }
.confidence-bar { display: inline-block; vertical-align: middle; background: var(--surface-3); border-radius: 999px;
  height: .5rem; width: 90px; overflow: hidden; }
.confidence-bar > span { display: block; height: 100%; background: var(--gold); }

/* ---- Live match: commentary + ball rows ---- */
.commentary-feed, .commentary-live { max-height: 56vh; overflow-y: auto; border: 1px solid var(--border);
  border-radius: var(--radius-sm); background: var(--bg-2); }
.ball { padding: .55rem .8rem; border-bottom: 1px solid var(--border); font-size: .92rem; animation: rise .3s both;
  border-left: 4px solid transparent; }
.ball:last-child { border-bottom: 0; }
.ball.wicket { background: color-mix(in srgb, var(--leather) 14%, transparent); border-left-color: var(--leather); font-weight: 600; }
.ball.boundary { background: color-mix(in srgb, var(--turf) 13%, transparent); border-left-color: var(--turf); }
.ball.divider-row { font-weight: 700; background: var(--surface-2); }
/* A fifty / hundred in the replayed feed (app.js tags these) — a gold edge so a
   milestone doesn't read as an ordinary single. */
.ball.milestone { border-left-color: var(--gold); background: color-mix(in srgb, var(--gold) 11%, transparent); }
.commentary-live .ball:first-child { border-top-left-radius: var(--radius-sm); border-top-right-radius: var(--radius-sm); }

/* dramatic burst overlay (decorative; the event is also announced via ARIA) */
.burst { position: fixed; left: 50%; top: 42%; z-index: 120; pointer-events: none; font-family: var(--font-display);
  font-weight: 900; font-size: clamp(3.5rem, 15vw, 9rem); letter-spacing: 2px; opacity: 0; text-transform: uppercase;
  text-shadow: 0 6px 30px rgba(0,0,0,.5); }
@keyframes burstIn { 0% { transform: translate(-50%,-50%) scale(.4) rotate(-8deg); opacity: 0; }
  35% { transform: translate(-50%,-50%) scale(1.15) rotate(2deg); opacity: 1; }
  100% { transform: translate(-50%,-50%) scale(1) rotate(0); opacity: 0; } }
.burst.show { animation: burstIn .9s cubic-bezier(.2,1.3,.4,1) forwards; }
.burst.four { color: var(--turf); text-shadow: 0 0 40px color-mix(in srgb, var(--turf) 70%, transparent), 0 6px 30px rgba(0,0,0,.5); }
.burst.six { color: var(--gold); text-shadow: 0 0 48px color-mix(in srgb, var(--gold) 80%, transparent), 0 6px 30px rgba(0,0,0,.5); }
.burst.out { color: var(--leather); text-shadow: 0 0 40px color-mix(in srgb, var(--leather) 70%, transparent), 0 6px 30px rgba(0,0,0,.5); }
#fx-flash { position: fixed; inset: 0; z-index: 110; pointer-events: none; opacity: 0; }
.fx-flash.show { animation: fxflash .5s ease-out; }
.fx-flash.four { background: radial-gradient(circle at 50% 45%, color-mix(in srgb, var(--turf) 36%, transparent), transparent 60%); }
.fx-flash.six { background: radial-gradient(circle at 50% 45%, color-mix(in srgb, var(--gold) 42%, transparent), transparent 62%); }
.fx-flash.out { background: radial-gradient(circle at 50% 45%, color-mix(in srgb, var(--leather) 40%, transparent), transparent 60%); }
@keyframes fxflash { 0% { opacity: 0; } 18% { opacity: 1; } 100% { opacity: 0; } }
.shake { animation: shake .5s; }
@keyframes shake { 10%,90% { transform: translateX(-2px); } 30%,70% { transform: translateX(4px); } 50% { transform: translateX(-5px); } }

.scoreboard { transition: transform .16s ease; }

/* ---- Live match HUD ---- */
.match-head { margin-bottom: .7rem; display: flex; align-items: flex-start;
  justify-content: space-between; gap: .6rem 1rem; flex-wrap: wrap; }
.match-head h1 { font-size: 1.5rem; }
.match-head .sub { margin: .25rem 0 0; }
.match-head .match-exit { flex: none; }
/* Wraps rather than forcing the match wider than the phone: at 280px the title
   and the two chrome buttons needed 357px side by side. */
.match-head-text { min-width: 0; flex: 1 1 12rem; }
.match-head-actions { flex: 0 0 auto; display: flex; align-items: flex-start;
  gap: .5rem; margin-left: auto; }

/* Settings panel (opened by the top-right gear button during a live match). */
.match-settings-modal { position: fixed; inset: 0; z-index: 160; display: grid; place-items: center;
  padding: 1rem; }
.match-settings-modal[hidden] { display: none; }
.match-settings-backdrop { position: absolute; inset: 0; background: rgba(4, 10, 7, .62);
  backdrop-filter: blur(2px); }
.match-settings-card { position: relative; width: min(440px, 100%); max-height: 86vh; overflow-y: auto;
  overscroll-behavior: contain; box-shadow: 0 18px 50px rgba(0,0,0,.5); animation: fadeUp .22s both; }
.match-settings-head { display: flex; align-items: center; justify-content: space-between; gap: .5rem;
  margin: 0 0 .9rem; }
.match-settings-head h2 { margin: 0; font-size: 1.15rem; display: flex; align-items: center; gap: .4rem; }
@media (prefers-reduced-motion: reduce) { .match-settings-card { animation: none; } }

.hud { position: sticky; top: .5rem; z-index: 40; display: flex; flex-wrap: wrap; align-items: center;
  gap: 1rem 1.4rem; padding: .75rem 1.1rem; margin-bottom: 1rem; border-radius: var(--radius);
  background: linear-gradient(100deg, #05100b, var(--surface)); border: 1px solid #1c332680;
  box-shadow: var(--shadow); }
.hud-main { display: flex; align-items: center; gap: .9rem; min-width: 0; }
.hud-team { font-family: var(--font-display); font-weight: 800; letter-spacing: .2px;
  color: var(--text); min-width: 0; }
/* A long club name truncates rather than pushing the score off a narrow HUD. */
.hud-team > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hud .scoreboard { padding: .35rem .8rem; }
.hud .scoreboard .runs { font-size: 1.9rem; }
.hud-batters { display: flex; flex-direction: column; gap: .1rem; font-size: .86rem; }
.hud-bat { color: var(--muted); font-variant-numeric: tabular-nums; display: flex; align-items: baseline; gap: .35rem; }
.hud-bat strong { color: var(--text); }
.hud-bat.on-strike { color: var(--text); }
.hud-bat .bn { font-weight: 600; }
.hud-bat .bm { color: var(--muted); font-size: .76rem; opacity: .85; }
/* The bat marks the man ON STRIKE, and the strike changes ends — so the glyph
   sits in BOTH rows and is only shown in the striker's. Hidden rather than
   removed: the two lines keep the same indent, which they never did when only
   the top row carried an icon. */
.hud-bat .bat-ico { flex: none; }
.hud-bat:not(.on-strike) .bat-ico { visibility: hidden; }
.hud-target { margin-left: auto; text-align: right; display: flex; flex-direction: column; }
.hud-chase { color: var(--gold); font-weight: 700; }
.hud-need { color: var(--muted); font-size: .82rem; font-variant-numeric: tabular-nums; }
/* "This over", ball by ball — a circle per delivery filled live by livematch.js.
   Wides / no-balls add their own circle (an over with an extra runs to more than
   six balls). Sits on its own row in the HUD; hidden until the over begins. */
.hud-over { flex-basis: 100%; display: flex; align-items: center; gap: .55rem; margin-top: .4rem; }
.hud-over:not(.has-balls) { display: none; }
.hud-over-label { font-size: .62rem; letter-spacing: .08em; text-transform: uppercase; color: var(--faint);
  white-space: nowrap; }
.hud-over-balls { display: flex; flex-wrap: wrap; gap: .32rem; }
.ob { --c: var(--muted); display: inline-flex; align-items: center; justify-content: center;
  min-width: 1.5rem; height: 1.5rem; padding: 0 .22rem; border-radius: 999px; line-height: 1;
  font-size: .82rem; font-weight: 800; font-variant-numeric: tabular-nums; color: var(--text);
  background: color-mix(in srgb, var(--c) 15%, transparent);
  border: 1.5px solid color-mix(in srgb, var(--c) 55%, transparent);
  animation: ob-pop .26s cubic-bezier(.2,1.4,.5,1); }
.ob-dot { --c: var(--muted); color: var(--muted); }
.ob-run { --c: var(--turf); }
.ob-four { --c: var(--turf); color: #eafff3; background: color-mix(in srgb, var(--turf) 36%, transparent); }
.ob-six { --c: var(--gold); color: #fff4d6; background: color-mix(in srgb, var(--gold) 42%, transparent); }
.ob-wkt { --c: var(--leather); color: #fff; background: color-mix(in srgb, var(--leather) 70%, transparent); }
.ob-wide, .ob-noball { --c: var(--gold); font-size: .62rem; text-transform: uppercase; letter-spacing: .01em; }
@keyframes ob-pop { from { transform: scale(.4); opacity: 0; } to { transform: scale(1); opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .ob { animation: none; } }

/* Live win-probability meter — a hard-divided bar: green = home share on the
   left, red = away share on the right, split at the home probability (NOT a
   gradient). The numbers + the split tick over every ball via livematch.js. */
.hud-winprob { flex-basis: 100%; margin-top: .55rem; }
.wp-head { display: flex; align-items: baseline; justify-content: space-between; gap: .5rem;
  font-size: .8rem; margin-bottom: .3rem; }
.wp-side { display: flex; align-items: baseline; gap: .35rem; min-width: 0; flex: 0 1 auto; }
.wp-side-away { flex-direction: row; text-align: right; justify-content: flex-end; }
.wp-name { font-family: var(--font-display); font-weight: 800; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 11ch;
  min-width: 0; }
.wp-pct { flex: none; }
.wp-pct { font-variant-numeric: tabular-nums; font-weight: 800; color: var(--text); }
.wp-cap { font-size: .62rem; letter-spacing: .08em; text-transform: uppercase; color: var(--faint);
  white-space: nowrap; }
.wp-swatch { width: .6rem; height: .6rem; border-radius: 2px; align-self: center; flex: none; }
.wp-swatch-home { background: var(--turf); }
.wp-swatch-away { background: var(--leather); }
.wp-bar { position: relative; height: 12px; border-radius: 6px; overflow: hidden;
  background: var(--leather); box-shadow: inset 0 0 0 1px rgba(255,255,255,.08); }
.wp-fill { position: absolute; inset: 0 auto 0 0; height: 100%; background: var(--turf);
  border-right: 2px solid var(--bg, #0d1611); transition: width .6s ease; }
@media (prefers-reduced-motion: reduce) { .wp-fill { transition: none; } }
@media (max-width: 560px) {
  .wp-cap { display: none; }
  /* Two club names plus two percentages don't fit a 280px HUD at full length —
     clip the names, never the numbers. */
  .wp-name { max-width: 6ch; }
}
.hud.tense { animation: hud-pulse 1.1s ease-in-out infinite; }
@keyframes hud-pulse { 0%,100% { box-shadow: 0 0 0 0 transparent; }
  50% { box-shadow: 0 0 0 3px color-mix(in srgb, var(--gold) 32%, transparent); } }
@media (prefers-reduced-motion: reduce) { .hud.tense { animation: none; } }

/* Match-centre tabs (Commentary / Scorecard / Settings) share the global .tab
   styling; the head puts the Skip button on the same row as the tablist. */
.comm-tabhead { display: flex; align-items: flex-end; justify-content: space-between; gap: .5rem; }
.comm-tabhead .tablist { margin-bottom: 0; flex: 1 1 auto; }
.comm-tabhead #lm-skip-anim { flex: 0 0 auto; margin-bottom: .3rem; }
.comm-tabhead .centre-toggle { flex: 0 0 auto; margin-bottom: .3rem; margin-left: .4rem; }
.centre-toggle .ico { transition: transform .18s; transform: rotate(90deg); }   /* points down: fold it away */
.commentary-panel.is-shut .centre-toggle .ico { transform: rotate(-90deg); }
.commentary-panel.is-shut > .tab-panel { display: none; }
/* A tab's panel eases in when it is chosen, rather than the old one blinking
   into the new (it is un-hidden, which restarts the animation). */
.tab-panel:not([hidden]) { animation: tabIn .22s ease backwards; }
@keyframes tabIn { from { opacity: 0; transform: translateY(4px); } }
@media (prefers-reduced-motion: reduce) { .tab-panel:not([hidden]) { animation: none; } }
[data-reduce-motion="true"] .tab-panel:not([hidden]) { animation: none; }

/* Live scorecard */
.match-scorecard { max-height: 56vh; overflow-y: auto; overscroll-behavior: contain; }
/* Innings switcher — each side's score is a button that brings up their card,
   the way a broadcast scorecard flips between innings. Sticks to the top of the
   scrolling card so it stays reachable down a long batting list. */
.sc-switch { position: sticky; top: 0; z-index: 2; display: flex; gap: .4rem;
  margin: 0 0 .8rem; padding: .1rem 0 .5rem; overflow-x: auto; scrollbar-width: thin;
  background: var(--surface); border-bottom: 1px solid var(--border); }
.sc-tab { display: inline-flex; align-items: center; gap: .4rem; flex: 1 1 0; min-width: max-content;
  padding: .4rem .7rem; border-radius: var(--radius-sm); cursor: pointer; font: inherit;
  color: var(--muted); background: var(--surface-2); border: 1px solid var(--border-2);
  white-space: nowrap; transition: background .12s, border-color .12s, color .12s; }
.sc-tab:hover { background: var(--surface-3); color: var(--text); }
.sc-tab.is-on { color: var(--text); border-color: var(--turf);
  background: color-mix(in srgb, var(--turf) 14%, var(--surface));
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--turf) 45%, transparent); }
.sc-tab-team { font-weight: 700; font-size: .84rem; gap: .35rem; }
.sc-tab-inns { font-size: .6rem; letter-spacing: .06em; text-transform: uppercase;
  color: var(--faint); font-weight: 800; }
.sc-tab-score { font-family: var(--font-display); font-weight: 800; font-size: .95rem;
  font-variant-numeric: tabular-nums; color: var(--text); }
.sc-tab-ov { font-size: .74rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.sc-tab .sc-tag { margin-left: 0; }
.sc-tab[hidden] { display: none; }
@media (max-width: 560px) { .sc-tab { flex: 0 0 auto; } .sc-tab-ov { display: none; } }
.sc-innings { margin: 0 0 1rem; }
.sc-innings[hidden] { display: none; }
.sc-head { display: flex; align-items: baseline; gap: .5rem; margin: .1rem 0 .55rem; }
.sc-head .sc-team { font-weight: 700; }
.sc-head .sc-score { font-family: var(--font-display); font-weight: 800; }
.sc-head .sc-ov { color: var(--muted); font-weight: 500; font-size: .85em; }
.sc-tag { margin-left: auto; align-self: center; font-size: .6rem; letter-spacing: .08em;
  text-transform: uppercase; color: #fff; background: var(--turf); padding: .1rem .45rem; border-radius: 999px; }
.sc-bat, .sc-bowl { width: 100%; font-size: .86rem; margin: .1rem 0 .5rem; }
.sc-bat th, .sc-bowl th { font-size: .64rem; }
.sc-name { font-weight: 600; }
.sc-strike { color: var(--turf); font-weight: 800; }
.sc-onstrike > td { background: var(--surface-2); }
.sc-out { display: block; font-size: .72rem; color: var(--muted); }
.sc-ytb { margin: .1rem 0 .55rem; }
.sc-vols label { display: block; font-size: .8rem; color: var(--muted); margin-bottom: .1rem; }
.bbb-toggle { display: flex; align-items: center; gap: .5rem; font-size: .82rem; color: var(--muted);
  margin: .5rem 0 .6rem; cursor: pointer; }
.locked-bowler { font-weight: 700; color: var(--text); margin: .15rem 0; }
.replay-row { opacity: .85; font-style: italic; }
.replay-badge { display: inline-block; background: var(--gold); color: #1a1206; font-weight: 800; font-size: .62rem;
  letter-spacing: .5px; padding: .05rem .35rem; border-radius: 3px; margin-right: .35rem; vertical-align: middle; }
.analyst-line { margin: .6rem 0 0; padding: .5rem .7rem; border-left: 3px solid var(--gold);
  background: color-mix(in srgb, var(--gold) 9%, transparent); border-radius: 0 6px 6px 0; font-style: italic; color: var(--text); }
.analysis-row { border-left: 3px solid var(--gold); padding-left: .5rem; font-style: italic; }
/* Which commentator is speaking — a broadcast credit rather than a microphone
   emoji (screen readers read that aloud before every line). */
.say-who { font-family: var(--font-display); font-style: normal; font-weight: 800;
  font-size: var(--fs-xs); letter-spacing: .1em; text-transform: uppercase;
  color: var(--faint); margin-right: .35rem; }
.break-line.is-caller .say-who { color: var(--turf); }
.break-line.is-expert .say-who { color: var(--gold); }

/* Break show — the commentators' drinks / innings-break / post-match chat. */
.break-show { margin: .7rem 0 0; padding: .6rem .75rem; border: 1px solid var(--border);
  border-radius: 10px; background: color-mix(in srgb, var(--gold) 7%, var(--panel, transparent));
  box-shadow: inset 0 1px 0 rgba(255,255,255,.04); }
.break-show-head { display: flex; align-items: center; justify-content: space-between; gap: .5rem;
  margin-bottom: .4rem; }
.break-show-title { font-weight: 800; letter-spacing: .3px; text-transform: uppercase;
  font-size: .72rem; color: var(--gold); }
.break-show-feed { display: flex; flex-direction: column; gap: .35rem; max-height: 34vh; overflow-y: auto; }
.break-line { padding: .3rem .5rem; border-radius: 7px; font-size: .92rem; line-height: 1.35;
  background: color-mix(in srgb, var(--text) 5%, transparent); }
.break-line.is-caller { border-left: 3px solid color-mix(in srgb, var(--accent, #4ea1ff) 80%, transparent); }
.break-line.is-expert { border-left: 3px solid var(--gold); font-style: italic; }

.pitch-wrap { position: relative; margin: 0 0 1.1rem; border-radius: 14px; overflow: hidden;
  box-shadow: 0 3px 14px rgba(0,0,0,.28); border: 1px solid rgba(255,255,255,.08); }
/* The broadcast view is the star: a wide 16:7 letterbox that scales with the
   viewport instead of a fixed 330px thumbnail. Old fixed heights stay as the
   fallback where aspect-ratio isn't supported. */
.pitch-canvas { display: block; width: 100%; aspect-ratio: 16 / 7.4; height: auto;
  max-height: min(57vh, 610px); background: #0c1712; }
@supports not (aspect-ratio: 1) {
  .pitch-canvas { height: 330px; }
  @media (max-width: 720px) { .pitch-canvas { height: 240px; } }
}
/* ---- The opening slate (livematch.js THE OPENING SLATE) ----
   What the match opens on while the ground is built behind it: the venue's
   photograph drifting in slowly (or, with no photograph, the two sides'
   colours meeting on a diagonal), the crests and the fixture set in the
   display face, where it is being played, and a thin bar in both sides'
   colours. Everything that moves on it is transform/opacity — the compositor
   keeps it moving while the ground's build holds the main thread. It
   dissolves (is-lifting) into the drawn picture. */
.match-slate { position: absolute; inset: 0; z-index: 7; display: grid; place-items: center; overflow: hidden;
  pointer-events: none; background: #060a08; color: #f1f6f2; opacity: 1;
  transition: opacity 1s cubic-bezier(.4,0,.2,1); }
.match-slate::before { content: ""; position: absolute; inset: -3%;
  background:
    radial-gradient(120% 95% at 50% 42%, rgba(6,10,8,.1), rgba(4,7,5,.9) 72%),
    linear-gradient(112deg, color-mix(in srgb, var(--home, #1f9d5c) 42%, #050806) 0 49.6%,
                            color-mix(in srgb, var(--away, #f2b53a) 42%, #050806) 50.4% 100%);
  animation: msDrift 16s cubic-bezier(.2,.6,.3,1) both; }
.match-slate.has-ground::before {
  background:
    linear-gradient(180deg, rgba(5,9,7,.62), rgba(5,9,7,.3) 38%, rgba(5,9,7,.4) 62%, rgba(5,9,7,.9)),
    var(--ground-photo) center 40% / cover no-repeat; }
.match-slate::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 3px;
  background: linear-gradient(90deg, var(--home, #1f9d5c) 0 50%, var(--away, #f2b53a) 50% 100%); opacity: .85; }
@keyframes msDrift { from { transform: scale(1.09) translateY(1.2%); } to { transform: scale(1.02); } }
.ms-card { position: relative; text-align: center; padding: 1rem 1.2rem; max-width: 100%;
  animation: msIn .7s cubic-bezier(.2,.8,.2,1) .05s backwards;
  transition: transform 1s cubic-bezier(.4,0,.2,1); }
@keyframes msIn { from { opacity: 0; transform: translateY(10px); } }
.ms-eyebrow { margin: 0 0 .8rem; font: 800 .74rem/1.1 var(--font-display); letter-spacing: .22em;
  text-transform: uppercase; color: var(--gold); text-shadow: 0 2px 12px rgba(0,0,0,.6); }
.ms-eyebrow span { color: #cfdcd3; letter-spacing: .1em; }
.ms-bill { display: flex; align-items: center; justify-content: center; gap: clamp(.7rem, 3vw, 2rem); margin: 0; }
.ms-side { display: flex; flex-direction: column; align-items: center; gap: .55rem; min-width: 0; flex: 1 1 0; }
.ms-side .crest { --crest-size: clamp(36px, 6.2vw, 72px) !important; filter: drop-shadow(0 8px 16px rgba(0,0,0,.55)); }
.ms-name { font-family: var(--font-impact); font-size: clamp(1.05rem, 2.7vw, 2.2rem); line-height: 1.02;
  letter-spacing: .04em; text-transform: uppercase; text-shadow: 0 4px 24px rgba(0,0,0,.65); overflow-wrap: anywhere; }
.ms-v { flex: none; font: italic 800 clamp(.85rem, 1.5vw, 1.15rem)/1 var(--font-display); color: rgba(241,246,242,.6); }
.ms-ground { margin: 1rem 0 0; font-size: .8rem; font-weight: 700; letter-spacing: .16em; text-transform: uppercase;
  color: #d6e2da; text-shadow: 0 2px 12px rgba(0,0,0,.7); }
.ms-bar { display: block; width: min(11rem, 46%); height: 2px; margin: 1rem auto 0; border-radius: 2px;
  background: rgba(255,255,255,.14); overflow: hidden; }
.ms-bar i { display: block; width: 38%; height: 100%; border-radius: 2px;
  background: linear-gradient(90deg, var(--home, #1f9d5c), var(--gold), var(--away, #f2b53a));
  animation: veilBar 1.5s ease-in-out infinite; }
.match-slate.is-lifting { opacity: 0; }
.match-slate.is-lifting .ms-card { transform: translateY(-8px) scale(.985); }
@media (max-width: 560px) {
  .ms-eyebrow { margin-bottom: .5rem; } .ms-ground { margin-top: .6rem; font-size: .74rem; letter-spacing: .1em; }
  .ms-bar { margin-top: .7rem; }
}
@media (prefers-reduced-motion: reduce) {
  .match-slate, .ms-card { transition: none; } .match-slate::before, .ms-card, .ms-bar i { animation: none; }
}
[data-reduce-motion="true"] .match-slate, [data-reduce-motion="true"] .ms-card { transition: none; }
[data-reduce-motion="true"] .match-slate::before, [data-reduce-motion="true"] .ms-card,
[data-reduce-motion="true"] .ms-bar i { animation: none; }

/* A dip through black between two segments on the ground (livematch.js
   dipThrough): down quickly, the camera cuts under it, up more slowly. Under
   the toss card and the break package, which have fades of their own. */
.pitch-dip { position: absolute; inset: 0; z-index: 3; background: #040705; opacity: 0; pointer-events: none;
  transition: opacity .45s cubic-bezier(.4,0,.2,1); }
.pitch-dip.on { opacity: 1; transition-duration: .22s; }

/* The console's next panel, after an over, eases in over the last one rather
   than blinking (livematch.js panelIn). */
#decision.panel-in > * { animation: panelIn .32s cubic-bezier(.2,.8,.2,1) backwards; }
@keyframes panelIn { from { opacity: 0; transform: translateY(6px); } }
@media (prefers-reduced-motion: reduce) { #decision.panel-in > * { animation: none; } }

/* Portrait phones: a taller 16:9 so the ground isn't a thin sliver. */
@media (max-width: 720px) and (orientation: portrait) {
  /* (G-42) Squarer, so the picture is two fifths of a phone's height or more
     (8:7 on a 390px screen is 341px of an 844px one), not a sliver. */
  .pitch-canvas { aspect-ratio: 1 / 1; max-height: 50vh; }
}
.pitch-badge { position: absolute; top: .55rem; left: .6rem; background: var(--gold); color: #1a1206;
  font-weight: 800; font-size: .68rem; letter-spacing: 1.5px; padding: .18rem .55rem; border-radius: 5px;
  animation: livePulse 1s steps(2) infinite; }
@media (prefers-reduced-motion: reduce) { .pitch-badge { animation: none; } }

/* 10-foot / gamepad mode (Package 13) — when a controller is connected the root
   gets [data-tv]: a bigger focus ring and slightly larger type so the UI reads
   from the couch. Purely additive; keyboard/mouse are unaffected. */
[data-tv] { font-size: 17.5px; }
[data-tv] :focus-visible { outline: 4px solid var(--focus) !important;
  outline-offset: 3px !important; border-radius: 8px; }
[data-tv] .btn, [data-tv] .nav-link { scroll-margin: 2rem; }

/* Broadcast lower-third (Package 10) — a super over the bottom of the pitch. */
.lower-third { position: absolute; left: 0; right: 0; bottom: 0; z-index: 3;
  padding: .5rem .7rem; pointer-events: none;
  transform: translateY(110%); opacity: 0; transition: transform .32s cubic-bezier(.2,.9,.2,1), opacity .32s; }
.lower-third.show { transform: translateY(0); opacity: 1; }
.lower-third .lt-bar { display: inline-flex; align-items: baseline; gap: .6rem;
  max-width: 100%; padding: .38rem .8rem; border-radius: 8px;
  background: linear-gradient(90deg, rgba(9,14,11,.92), rgba(9,14,11,.72));
  border-left: 4px solid var(--turf); box-shadow: 0 6px 18px rgba(0,0,0,.4); }
.lower-third .lt-title { font-family: var(--font-display); font-weight: 800;
  letter-spacing: .3px; color: #fff; font-size: 1rem; text-transform: uppercase; }
.lower-third .lt-sub { color: #cdd8d0; font-size: .82rem; font-variant-numeric: tabular-nums; }
.lower-third.lt-gold .lt-bar { border-left-color: var(--gold); }
.lower-third.lt-out .lt-bar { border-left-color: var(--leather); }
@media (prefers-reduced-motion: reduce) {
  .lower-third { transition: none; }
  .lower-third:not(.show) { transform: translateY(110%); }
}
[data-reduce-motion="true"] .lower-third { transition: none; }

/* ---- DRS review graphics (drs.js) — the broadcast third-umpire sequence ---- */
.drs-overlay { position: absolute; inset: 0; z-index: 4; display: flex; flex-direction: column;
  align-items: center; justify-content: flex-start; gap: .5rem; padding: .55rem .7rem;
  background: rgba(4, 9, 7, .78); backdrop-filter: blur(2px); -webkit-backdrop-filter: blur(2px);
  opacity: 0; transition: opacity .3s ease; pointer-events: none; }
.drs-overlay.show { opacity: 1; }
.drs-top { display: flex; align-items: center; gap: .7rem; width: min(680px, 96%);
  padding: .3rem .65rem; border-radius: 8px; background: rgba(8, 14, 11, .92);
  border: 1px solid rgba(255,255,255,.14); font-family: var(--font-display); }
.drs-live { display: inline-flex; align-items: center; gap: .35rem; color: #ff5c51;
  font-weight: 800; font-size: .68rem; letter-spacing: .1em; white-space: nowrap; }
.drs-dot { width: .5rem; height: .5rem; border-radius: 50%; background: #ff5c51;
  animation: livePulse 1s steps(2) infinite; }
.drs-title { flex: 1; text-align: center; color: #eef6f0; font-weight: 800; font-size: .8rem;
  letter-spacing: .06em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.drs-by { color: var(--gold); font-weight: 800; font-size: .66rem; letter-spacing: .09em;
  white-space: nowrap; }
.drs-stage { width: min(680px, 96%); flex: 1; min-height: 0; display: grid; place-items: center; }
.drs-svg { width: 100%; height: 100%; max-height: 100%; }
.drs-panel { fill: rgba(7, 13, 10, .94); stroke: rgba(255,255,255,.13); }
.drs-cap { fill: #9fb4a7; font: 800 15px var(--font-display); letter-spacing: .12em; }
.drs-cap-sm { font-size: 11px; }
.drs-ground { stroke: rgba(255,255,255,.22); stroke-width: 2; }
.drs-stumps rect, .drs-stump-side { fill: #e8c257; }
.drs-pad { fill: #cfd8dc; }
.drs-bat { fill: #d8b98a; stroke: #8a6b42; stroke-width: 1; }
.drs-ball { fill: #e0382b; stroke: #7a130c; stroke-width: 1.5; }
.drs-ball-hot { filter: drop-shadow(0 0 6px #ff8c7a); }
.drs-ball-ghost { fill: rgba(224, 56, 43, .38); stroke: #e0382b; stroke-width: 1.5;
  stroke-dasharray: 3 3; }
.drs-ball-hit { animation: drsHit .7s ease-in-out infinite alternate; }
@keyframes drsHit { from { opacity: .75; } to { opacity: 1; } }
.drs-crease { stroke: #fff; stroke-width: 3; opacity: .9; }
.drs-gapline { stroke: #ff6a5e; stroke-width: 5; stroke-linecap: round; }
.drs-snick { fill: #04140b; stroke: rgba(255,255,255,.14); }
.drs-wave { fill: none; stroke: #7df0a0; stroke-width: 1.6; }
.drs-track { fill: none; stroke: #ff6a5e; stroke-width: 2.4; }
.drs-flag { fill: #ffd86b; font: 800 19px var(--font-display); letter-spacing: .08em; }
.drs-flag-out { fill: #ff8c7a; }
.drs-flag-ok { fill: #7df0a0; }
.drs-row-label { fill: #cfe0d5; font: 800 15px var(--font-display); letter-spacing: .08em; }
.drs-pill { stroke: rgba(255,255,255,.2); }
.drs-pill-ok { fill: #0f5aa8; }
.drs-pill-out { fill: #c0271b; }
.drs-pill-no { fill: #1d7a43; }
.drs-pill-off { fill: #26312b; }
.drs-pill-text { fill: #fff; font: 800 13.5px var(--font-display); letter-spacing: .05em; }
.drs-decision { position: absolute; left: 50%; top: 50%; transform: translate(-50%,-50%) scale(.7);
  opacity: 0; text-align: center; padding: 1rem 2.2rem; border-radius: 14px;
  border: 2px solid rgba(255,255,255,.28); box-shadow: 0 18px 60px rgba(0,0,0,.6);
  transition: transform .28s cubic-bezier(.2,1.3,.4,1), opacity .28s; }
.drs-decision.show { opacity: 1; transform: translate(-50%,-50%) scale(1); }
.drs-decision small { display: block; font-family: var(--font-display); font-weight: 800;
  letter-spacing: .22em; font-size: .66rem; color: rgba(255,255,255,.85); }
.drs-decision strong { display: block; font-family: var(--font-impact); font-size: clamp(2.4rem, 8vw, 4.2rem);
  line-height: 1; color: #fff; letter-spacing: .04em; transform: skewX(-6deg);
  text-shadow: 0 3px 0 rgba(0,0,0,.35), 0 8px 26px rgba(0,0,0,.5); }
.drs-decision span { display: block; margin-top: .3rem; font-family: var(--font-display);
  font-weight: 800; font-size: .7rem; letter-spacing: .14em; color: rgba(255,255,255,.92); }
.drs-decision.drs-out { background: linear-gradient(160deg, #a01309, #5f0b04); border-color: #ff8c7a; }
.drs-decision.drs-notout { background: linear-gradient(160deg, #0d7a3f, #06511f); border-color: #7df0a0; }
@media (max-width: 720px) {
  .drs-title { font-size: .68rem; }
  .drs-by { display: none; }
}

/* Theatre / fullscreen toggle — top-right of the pitch, next to the REPLAY badge. */
.pitch-theatre { position: absolute; top: .5rem; right: .5rem; z-index: 3;
  display: inline-flex; align-items: center; gap: .3rem; padding: .28rem .5rem;
  border-radius: 8px; border: 1px solid rgba(255,255,255,.16); cursor: pointer;
  background: rgba(8,14,11,.62); color: #eaf3ee; font: inherit; font-size: .72rem;
  font-weight: 700; -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px); }
.pitch-theatre:hover { background: rgba(8,14,11,.82); }
.pitch-theatre .ico { width: 1em; height: 1em; }

/* Fullscreen (desktop) OR the iOS immersive fallback: the pitch fills the screen
   and the existing #scoreboard HUD is lifted to a fixed overlay at the top — the
   SAME element (all live-update ids intact), just repositioned, restored on exit. */
.pitch-wrap:fullscreen { border-radius: 0; border: 0; margin: 0; height: 100vh; }
.pitch-wrap:fullscreen .pitch-canvas { aspect-ratio: auto; height: 100vh; max-height: none; }
/* HUD lift is driven by a JS-toggled body class so it works for BOTH the native
   :fullscreen path and the iOS immersive fallback with one rule. */
body.theatre-on #scoreboard {
  position: fixed; top: 0; left: 0; right: 0; z-index: 2147483000;
  margin: 0; border-radius: 0; box-shadow: 0 6px 22px rgba(0,0,0,.5);
  pointer-events: none; }
/* iOS Safari lacks element fullscreen → an immersive fixed overlay instead. */
.pitch-wrap.immersive { position: fixed; inset: 0; z-index: 2147482000; height: 100dvh;
  margin: 0; border-radius: 0; border: 0; background: #0c1712; }
.pitch-wrap.immersive .pitch-canvas { aspect-ratio: auto; height: 100dvh; max-height: none; }
.pitch-theatre.is-on .ico-expand { display: none; }
.pitch-theatre:not(.is-on) .ico-collapse { display: none; }
/* Big-moment caption over the 3D pitch (SIX / FOUR / OUT) — a heavy condensed
   stadium font (Anton), crisp DOM text over the WebGL canvas so it stays sharp at
   any pixel ratio. Italic skew + tight tracking + a bold dark edge = broadcast. */
/* The ground's big-moment caption (G-05): a STRAP in the lower third, in the
   colours of the side the moment belongs to — never stamped over the stumps or
   the ball. pitch3d.js puts it up on the beat after the event and takes it down;
   the slide is garnish, so reduced motion shows it without one. */
.pitch3d-flash { position: absolute; left: clamp(.6rem, 2.2%, 1.4rem); bottom: clamp(3rem, 16%, 5.6rem);
  z-index: 2; pointer-events: none; display: inline-flex; align-items: baseline; gap: .55em;
  max-width: calc(100% - 2rem); padding: .2em .8em .16em .62em;
  font-family: var(--font-impact); font-weight: 400; letter-spacing: .04em; text-transform: uppercase;
  font-size: clamp(1.35rem, 3.1vw, 2.5rem); line-height: 1; color: #fff;
  background: linear-gradient(90deg, rgba(8,12,10,.94), rgba(8,12,10,.80));
  border-left: .3em solid var(--pf-club, var(--turf));
  box-shadow: 0 8px 22px rgba(0,0,0,.42); transform: skewX(var(--slant, -14deg)) translateX(-1.2rem);
  opacity: 0; transition: opacity .22s ease, transform .34s cubic-bezier(.2,.9,.2,1); }
.pitch3d-flash > span { display: inline-block; transform: skewX(calc(-1 * var(--slant, -14deg))); }
.pitch3d-flash .pf-sub { font-family: var(--font-display); font-weight: 800; letter-spacing: .06em;
  font-size: .42em; color: #d8e2dc; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pitch3d-flash[data-tone="six"] .pf-word, .pitch3d-flash[data-tone="free"] .pf-word { color: var(--gold); }
.pitch3d-flash[data-tone="out"] .pf-word { color: #ff6a58; }
.pitch3d-flash.show { opacity: 1; transform: skewX(var(--slant, -14deg)) translateX(0); }
@media (prefers-reduced-motion: reduce) { .pitch3d-flash { transition: none; } }
[data-reduce-motion="true"] .pitch3d-flash { transition: none; }

/* The ground takes the larger share here too — roughly 65/35 — for the same
   reason it does on the stage: it is the picture, not a sidebar. */
.match-grid { display: grid; gap: 1.1rem; grid-template-columns: 1.86fr 1fr; align-items: start; }
/* Same grid trap as .lineup-cols: without this the console couldn't shrink below
   the widest thing inside it (the 560px-min stance table), so a phone had to
   scroll the whole match sideways instead of just that table. */
.match-grid > * { min-width: 0; }
@media (max-width: 880px) { .match-grid { grid-template-columns: 1fr; } }
.commentary-panel { position: sticky; top: 6.2rem; }

/* ==========================================================================
   The split stage — a desktop live match that never scrolls the page
   --------------------------------------------------------------------------
   Setting an over is a decision you make WHILE looking at the ground: picking a
   preset runs the nine men to their posts out there, and the console is only
   meaningful next to the thing it changes. Stacked, it wasn't. The ground ran to
   449px, the console began below the fold and went on for another 1100, so
   reaching "Bowl this over" scrolled the ground off the screen entirely — and
   the renderer, which pauses the moment the canvas leaves the viewport, then
   TELEPORTED the field instead of running it (setField's `!visible` branch).
   You were placing men you could not see.

   So above the stacked breakpoint the match stops being a document and becomes
   a frame: <main> is a fixed-height column and the stage fills exactly what is
   left of the viewport. The broadcast holds the left — score, ground, match
   centre — and the console takes the right as its OWN scrollport, with the over
   you are setting pinned at its head and the orders (plus the button that bowls
   them) pinned at its foot. Nothing here scrolls the page; the two panes scroll
   themselves, and the ground never leaves the screen.

   Guarded on height as well as width: on a short window there is no stage worth
   splitting, and the stacked layout is the honest one.
   ========================================================================== */
@media (min-width: 881px) and (min-height: 560px) {
  /* The frame. `overflow: hidden` is what makes the promise — there is no page
     scroll left to lose the ground to. */
  .app--match main { display: flex; flex-direction: column; overflow: hidden;
    max-width: min(2000px, 100%); padding-bottom: clamp(.5rem, 1.2vh, .9rem); }
  .app--match main > .match-head { flex: 0 0 auto; margin-bottom: .5rem; }
  .app--match .match-head h1 { font-size: 1.25rem; }
  .app--match .match-head .sub { margin-top: .1rem; font-size: .82rem; }
  .app--match .match-head .stakes-line { margin-top: .18rem; font-size: .82rem; }

  .app--match #live-match { flex: 1 1 auto; min-height: 0; display: grid;
    gap: .6rem .9rem;
    /* Roughly 65/35 in the ground's favour. It used to be an even split, which
       gave a broadcast the same room as a form. The console is the taller of the
       two and every inch of width buys back a row of chips — at 1.25fr the attack
       once wrapped to three rows and the plan sat below the fold — so the chips
       are sized for THIS column further down rather than the column being sized
       for the chips. It keeps a hard floor: below about 25rem the console stops
       giving ground and the split slides back toward even. */
    grid-template-columns: minmax(0, 1.86fr) minmax(min(27rem, 40%), 1fr);
    /* The ground keeps a floor of its own: as the HUD dresses itself (the over
       strip, the win bar) the stage has less to share, and the grass is the last
       thing that should pay for it. Nudged up once the ground became worth
       looking at — enough to read the field and the stands, not enough to push
       the commentary off the stage. */
    grid-template-rows: auto minmax(min(268px, 38vh), 2.25fr) minmax(0, 1fr);
    /* (G-42) The ground takes the left column from the top down to the match
       centre: the score is ON the picture now, and the scoreboard heads the
       console column beside it instead of taking a band off the grass. */
    grid-template-areas: "ground  hud"
                         "ground  console"
                         "centre  console"; }
  /* The two panels place themselves on the stage, so their wrapper steps out of
     the way rather than becoming a nested grid inside one column. (A plain div
     with no role — `display: contents` costs nothing in the a11y tree.) */
  .app--match .match-grid { display: contents; }

  /* ---- left: the broadcast ---- */
  .app--match #scoreboard { grid-area: hud; min-width: 0; }
  /* Sticky bought nothing once the page stopped scrolling, and the HUD's full
     dress cost the ground 40px it can now spend on grass. */
  .app--match .hud { position: static; margin-bottom: 0; padding: .55rem .95rem;
    gap: .45rem 1.15rem; }
  .app--match .hud .scoreboard .runs { font-size: 1.6rem; }
  /* At the stage's width the chase block wrapped to a line entirely its own —
     48px of dead band over the ground for two short lines of text. It rides on
     the row the over strip already takes instead, where a broadcast puts it. */
  .app--match .hud-target { order: 1; }
  .app--match .hud-over { order: 1; flex: 1 1 auto; margin-top: 0; }
  .app--match .hud-winprob { order: 2; margin-top: .35rem; }

  .app--match .pitch-wrap { grid-area: ground; margin: 0; min-height: 0; }
  /* The ground now takes its share of the STAGE instead of setting the page
     height from an aspect ratio. */
  .app--match .pitch-wrap > .pitch-canvas { aspect-ratio: auto; height: 100%;
    max-height: none; }

  .app--match .commentary-panel { grid-area: centre; position: static; margin: 0;
    min-height: 0; display: flex; flex-direction: column; overflow: hidden;
    padding: .75rem .95rem .85rem; }
  .app--match .commentary-panel .tablist { margin-bottom: .5rem; }
  .app--match .commentary-panel .comm-tabhead { flex: 0 0 auto; margin-bottom: .4rem; }
  .app--match .commentary-panel .tab-panel { flex: 1 1 auto; min-height: 0;
    display: flex; flex-direction: column; }
  /* The live feed is the part that grows; everything else in the tab keeps its
     natural height and the feed gives way to it. It may shrink to NOTHING —
     given a floor, a short stage pushed the card's own foot out of the panel and
     the last line of commentary was cut through the middle. */
  .app--match .commentary-panel .commentary-live { flex: 1 1 auto; min-height: 0;
    max-height: none; }
  .app--match .commentary-panel .match-scorecard { flex: 1 1 auto; min-height: 0;
    max-height: none; }
  .app--match .commentary-panel .commentary-feed { max-height: 26vh; }
  .app--match .commentary-panel .break-show-feed { max-height: 20vh; }

  /* ---- the match centre is small, dense, and can go away ----
     The ground never gives up its row to the card. The panel keeps the room the
     stage leaves it, so what it holds is set TIGHT — the dismissal on the
     batter's line, rows at half the table's usual padding, the tab strip a
     strip — and the whole panel folds to its tab strip (the Hide button, or
     `c`), at which point the ground takes the row. */
  .app--match .commentary-panel { padding: .5rem .85rem .55rem; }
  .app--match .commentary-panel .comm-tabhead { margin-bottom: .3rem; }
  .app--match .commentary-panel .tab { padding: .35rem .7rem; font-size: .72rem; }
  .app--match .commentary-panel .comm-tabhead .btn-sm { margin-bottom: .15rem; }
  .app--match .commentary-panel .ball { padding: .3rem .6rem; font-size: .85rem; }
  .app--match .commentary-panel .sc-switch { margin-bottom: .45rem; padding-bottom: .3rem; }
  .app--match .commentary-panel .sc-head { margin: 0 0 .3rem; font-size: .95rem; }
  .app--match .commentary-panel .sc-innings { margin-bottom: .5rem; }
  .app--match .commentary-panel .sc-bat, .app--match .commentary-panel .sc-bowl { font-size: .8rem; margin: 0 0 .35rem; }
  .app--match .commentary-panel .sc-bat th, .app--match .commentary-panel .sc-bat td,
  .app--match .commentary-panel .sc-bowl th, .app--match .commentary-panel .sc-bowl td { padding: .28rem .5rem; }
  .app--match .commentary-panel .sc-out { display: inline; margin-left: .4rem; }
  .app--match .commentary-panel .sc-ytb { margin: .1rem 0 .3rem; font-size: .78rem; }
  .app--match .commentary-panel.is-shut > .tab-panel { display: none; }
  .app--match .commentary-panel.is-shut .comm-tabhead { margin-bottom: 0; }
  .app--match .commentary-panel.is-shut .tablist { border-bottom-color: transparent; }
  .app--match #live-match:has(.commentary-panel.is-shut) {
    grid-template-rows: auto minmax(min(268px, 38vh), 1fr) auto; }
  /* Open, the log IS the tab: it takes the room the live replay had (every line
     the replay shows is in the log) instead of a 26vh box that, on a short
     stage, was taller than the tab itself and clipped through a row. */
  .app--match .commentary-panel .tab-panel:has(#commentary-log[open]) .commentary-live { display: none; }
  .app--match .commentary-panel #commentary-log[open] { display: flex; flex-direction: column;
    flex: 1 1 auto; min-height: 0; }
  @supports selector(::details-content) {
    .app--match .commentary-panel #commentary-log[open]::details-content { display: flex;
      flex-direction: column; flex: 1 1 auto; min-height: 0; }
    .app--match .commentary-panel #commentary-log[open] .commentary-feed { flex: 1 1 auto;
      min-height: 0; max-height: none; }
  }

  /* ---- right: the console, a scrollport of its own ---- */
  /* The card's chrome moves out to the pane so the head and the action bar can
     span its full width and pin to its own edges. */
  .app--match #decision { grid-area: console; min-height: 0; overflow-y: auto;
    overscroll-behavior: contain; scrollbar-width: thin; padding: 0 1.25rem;
    background: var(--surface); border: 1px solid var(--border);
    border-radius: var(--radius); box-shadow: var(--shadow); }
  .app--match #decision > * { margin: 0; padding: 1rem 0; }
  .app--match #decision > .card { border: 0; border-radius: 0; background: none;
    box-shadow: none; }
  /* Which over you are setting, and what phase it falls in — the two facts that
     must survive a scroll down a long console. */
  .app--match #decision .decision-head { position: sticky; top: 0; z-index: 3;
    margin: -1rem -1.25rem .7rem; padding: .7rem 1.25rem .55rem;
    background: var(--surface); border-bottom: 1px solid var(--border);
    border-radius: var(--radius) var(--radius) 0 0; }
  .app--match #decision .decision-head h2 { font-size: 1.1rem; }

  /* A console you scroll needs its rhythm tightened, or half the pane is gaps. */
  .app--match #decision .tactic-group { margin-bottom: .75rem; }
  .app--match #decision .tactic-label { margin-bottom: .35rem; }
  .app--match #decision .chips { gap: .38rem; }
  .app--match #decision .situation { margin: 0 0 .7rem; padding: .45rem .7rem; }
  .app--match #decision .field-layout { gap: .8rem; }
  .app--match #decision .delegate-bar { margin-top: .7rem; }

  /* The foot of the console rides with it: what you have ordered, and the button
     that bowls it. Sticky inside the FORM, so it releases only once the form's
     own end (and the hand-over bar under it) has scrolled into view. */
  .app--match .console-actions { position: sticky; bottom: 0; z-index: 3;
    margin: .6rem -1.25rem 0; padding: .55rem 1.25rem .65rem;
    background: var(--surface); border-top: 1px solid var(--border);
    box-shadow: 0 -12px 20px -14px rgba(0,0,0,.85); }
  .app--match .console-actions .orders-line { margin: 0 0 .3rem; }
  .app--match .console-actions .bbb-toggle { margin: 0 0 .45rem; }
  .app--match .console-actions .kbd-hint { margin: .35rem 0 0; font-size: .68rem; }
  /* A pane you scroll should say so at its seams, not just stop. */
  .app--match .console-actions::before { content: ""; position: absolute;
    left: 0; right: 0; bottom: 100%; height: 1.1rem; pointer-events: none;
    background: linear-gradient(to top, var(--surface), transparent); }

  /* ---- console density ----
     Beside the ground the console is a column roughly 670px tall, and at the
     shipped rhythm the bowling panel wanted 1066 of them: a scroll to reach the
     plan even with the ground in view. The small print is what pays — chips lose
     their generous padding, the diagram its inch, the help lines a point — and
     the whole attack, the ball, the field and the plan come within a flick. */
  .app--match #decision .chip:not(.chip-lg) { padding: .32rem .58rem; }
  .app--match #decision .chip:not(.chip-lg) .chip-main { font-size: .84rem; }
  .app--match #decision .chip .chip-sub { font-size: .68rem; line-height: 1.25; }
  /* The attack, sized for the column it is actually in. The console gave up a
     third of its width to the ground (65/35 above), and at 7.6rem the nine
     bowlers fell from three rows to five — so the chips get narrower and share
     the row evenly instead, and a long name ellipsises rather than wrapping the
     chip to two lines and taking the row's height with it. */
  /* Tiled, not wrapped: with `auto-fill` the nine share equal columns and the
     odd one out keeps its column width instead of stretching across the row on
     its own, which is what plain flex-wrap does to a last row of one. */
  .app--match #decision .chips:has(.chip-bowler) {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(min(7.4rem, 100%), 1fr)); }
  .app--match #decision .chip-bowler { min-width: 0; }
  .app--match #decision .chip-bowler .chip-main,
  .app--match #decision .chip-bowler .chip-sub {
    display: block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  /* The full name, not the surname: it may take two lines; the figures under
     it still ellipsise so the chip never grows past those two. */
  .app--match #decision .chip-bowler .chip-main { white-space: normal; line-height: 1.15; }
  .app--match #decision .help { font-size: .78rem; }
  .app--match #decision .bbb-toggle { font-size: .78rem; }
  .app--match #decision .field-custom summary,
  .app--match #decision .stance-more > summary { font-size: .78rem; padding: .22rem 0; }
  /* The ground behind IS the field diagram now — nine men standing where you
     just put them, at broadcast size. The inset map stays as the quick read of
     the shape, but it no longer sets the height of the whole group. */
  .app--match #decision .fd-svg { width: 124px; height: 124px; }
  .app--match #decision .batter-row, .app--match #decision .stance-row { padding: .35rem .45rem; }
  .app--match #decision .tactic-sublabel { margin: .45rem 0 .2rem; }
  /* Handing the over over is a real choice, but a secondary one — five buttons
     at full size were three rows of the pane. */
  .app--match #decision .delegate-bar .btn { padding: .24rem .55rem; font-size: .75rem; }
}

/* ---- Tactic chips / decision console ---- */
.decision-card { animation: fadeUp .4s both; }
.decision-head { display: flex; align-items: center; gap: .6rem; justify-content: space-between; }
.decision-head h2 { margin: 0; }
.phase-tag { font-size: .66rem; font-weight: 800; text-transform: uppercase; letter-spacing: .1em;
  padding: .2rem .55rem; border-radius: 999px; border: 1px solid var(--border-2); color: var(--muted); }
.phase-powerplay { color: var(--gold); border-color: color-mix(in srgb, var(--gold) 50%, transparent); }
.phase-death { color: var(--leather); border-color: color-mix(in srgb, var(--leather) 50%, transparent); }
.tactics-form { margin: 0; }
.tactic-group { margin: 0 0 1rem; }
.tactic-label { font-size: .72rem; text-transform: uppercase; letter-spacing: .08em; font-weight: 800;
  color: var(--faint); margin: 0 0 .45rem; }
.tactic-label .facing { color: var(--muted); text-transform: none; letter-spacing: 0; font-weight: 600; }
.chips { display: flex; flex-wrap: wrap; gap: .5rem; counter-reset: chip; }
.decision-card .chips > .chip { counter-increment: chip; }
/* The number is the key that picks the chip — a hint for the eye. Generated
   content is part of a label's accessible name, so without the empty
   alternative after the slash a screen reader heard "Full 2". (A browser that
   does not know the slash syntax drops that declaration and keeps the first.) */
.decision-card .chips > .chip::after { content: counter(chip); content: counter(chip) / ""; position: absolute; top: 1px; right: 3px;
  font-size: .56rem; line-height: 1; color: var(--faint); font-weight: 700; opacity: .7; }
.decision-card .chips > .chip:has(input:checked)::after { color: #04130b; opacity: .85; }
.kbd-hint { display: inline-block; font-size: .72rem; color: var(--faint); margin-left: .5rem; font-weight: 600; }
.kbd { display: inline-block; min-width: 1.1rem; text-align: center; padding: 0 .3rem; border-radius: 5px;
  border: 1px solid var(--border-2); background: var(--surface-2); font-size: .72rem; font-weight: 800; }
.chips-lg { gap: .8rem; }
.chip { position: relative; display: inline-flex; flex-direction: column; gap: .1rem; cursor: pointer;
  margin: 0; padding: .5rem .8rem; border-radius: var(--radius-sm); font-weight: 600; line-height: 1.2;
  background: var(--surface-2); border: 1px solid var(--border-2); color: var(--text);
  transition: transform .08s, border-color .12s, background .12s, box-shadow .12s; user-select: none; }
.chip:hover { background: var(--surface-3); transform: translateY(-1px); }
.chip input { position: absolute; opacity: 0; width: 1px; height: 1px; pointer-events: none; }
.chip .chip-main { font-size: .9rem; }
.chip .chip-sub { font-size: .72rem; color: var(--muted); font-weight: 500; }
.chip .chip-ico { font-size: 1.3rem; }
.chip:has(input:checked) { background: linear-gradient(135deg, color-mix(in srgb, var(--turf) 28%, var(--surface)), var(--surface));
  border-color: var(--turf); box-shadow: 0 0 0 1px var(--turf), 0 6px 16px rgba(52,196,122,.16); color: var(--text); }
.chip:has(input:checked) .chip-sub { color: color-mix(in srgb, var(--text) 80%, var(--muted)); }
.chip:has(input:focus-visible) { outline: 3px solid var(--focus); outline-offset: 2px; }
/* Browsers without :has() (older Firefox, Safari < 15.4): the focused radio is
   1px and invisible inside the chip, so keyboard focus showed nothing at all.
   :focus-within cannot tell keyboard from mouse, so it only stands in where
   :has() is absent — everywhere else the focus-visible rule above is exact. */
@supports not selector(:has(a)) {
  .chip:focus-within { outline: 3px solid var(--focus); outline-offset: 2px; }
}
.chip-sm { padding: .32rem .6rem; }
.chip-sm .chip-main { font-size: .8rem; }
.chip-lg { flex-direction: row; align-items: center; gap: .5rem; padding: .8rem 1.1rem; }
.chip-bowler { min-width: 9rem; }
/* The figures, the pick and the record each on their own line at every width
   (the desktop block above only starts at 881px). */
.chip-bowler .chip-sub { display: block; }

/* ---- THE READ: information, kept apart from the decision -----------------
   The console used to interleave the two — a conditions box between the bowler
   and the field, a ball-state box between the field and the plan, a paragraph
   under every one of nine plan chips. Nobody reads a spreadsheet with buttons in
   the middle of it. The read is now one card of dense, scannable numbers; the
   card below it is nothing but calls. */
.read-card { padding: .55rem .8rem; }
.read > summary { cursor: pointer; list-style: none; display: flex; align-items: baseline;
  gap: .6rem; flex-wrap: wrap; }
.read > summary::-webkit-details-marker { display: none; }
.read-title { display: inline-flex; align-items: center; gap: .35rem;
  font-size: .7rem; font-weight: 800; letter-spacing: .09em; text-transform: uppercase;
  color: var(--muted); }
.read-title .ico { width: .95em; height: .95em; }
.read-sum { display: flex; flex-wrap: wrap; gap: .25rem; flex: 1 1 8rem; min-width: 0; }
.rchip { padding: .1rem .38rem; border-radius: 999px; border: 1px solid var(--border-2);
  background: var(--surface-2); font-size: .68rem; font-weight: 700;
  color: var(--muted); white-space: nowrap; font-variant-numeric: tabular-nums; }
.rchip-hot { border-color: color-mix(in srgb, var(--gold) 45%, transparent); color: var(--gold); }
.read-toggle { flex: 0 0 auto; margin-left: auto; color: var(--faint);
  display: inline-flex; align-self: center; }
.read-toggle .ico { width: .95em; height: .95em; transition: transform .15s; }
.read[open] .read-toggle .ico { transform: rotate(180deg); }
.read-grid { display: grid; gap: .55rem 1.1rem; margin-top: .5rem;
  grid-template-columns: repeat(auto-fit, minmax(min(12rem, 100%), 1fr)); }
.read-col { min-width: 0; }
.read-col-wide { grid-column: 1 / -1; }
.read-label { margin: 0 0 .3rem; font-size: .68rem; font-weight: 800; letter-spacing: .07em;
  text-transform: uppercase; color: var(--faint); }
.read-note { margin: .35rem 0 0; font-size: .76rem; color: var(--muted); line-height: 1.35; }

/* The figures, in the console's OWN visual language: the same bordered, rounded
   tile a chip is, so the read looks like the controls it sits above instead of
   like a spreadsheet that wandered in. Tiles also pack four to a row where
   full-width label/value rows packed one, which is where the space went. */
.stat-chips { margin: 0; display: grid; gap: .25rem;
  grid-template-columns: repeat(auto-fill, minmax(min(4.6rem, 100%), 1fr)); }
.stat-chip { min-width: 0; padding: .22rem .4rem; border-radius: var(--radius-sm);
  border: 1px solid var(--border-2); background: var(--surface-2); }
.stat-chip dt { font-size: .6rem; font-weight: 700; letter-spacing: .05em;
  text-transform: uppercase; color: var(--faint); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; }
.stat-chip dd { margin: 0; font-size: .84rem; font-weight: 800; line-height: 1.15;
  font-variant-numeric: tabular-nums; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; }
.stat-sub { font-size: .68rem; font-weight: 600; color: var(--faint); }

/* Who is about to bowl, and what is going up behind him. */
.next-over { border: 1px solid color-mix(in srgb, var(--gold) 34%, var(--border-2));
  border-radius: var(--radius-sm); padding: .45rem .55rem;
  background: color-mix(in srgb, var(--gold) 7%, var(--surface)); }
.next-over .tactic-label { margin-top: 0; }
.next-over .help { margin: .3rem 0 0; }
.next-over .stance-row { margin-top: .4rem; }

.cond-list { list-style: none; margin: 0; padding: 0; display: grid; gap: .22rem; }
.cond-row { display: grid; grid-template-columns: 7.5rem 1fr 3.6rem; align-items: center;
  gap: .45rem; font-size: .76rem; }
.cond-label { color: var(--muted); font-weight: 600; }
.cond-bar { display: block; height: .4rem; border-radius: 999px; background: var(--surface-3);
  overflow: hidden; }
.cond-bar > i { display: block; height: 100%; border-radius: 999px;
  background: linear-gradient(90deg, var(--turf), var(--gold)); }
.cond-word { color: var(--text); font-weight: 700; font-size: .72rem; text-align: right;
  font-variant-numeric: tabular-nums; }

/* ---- The decision card: names, not paragraphs ---------------------------- */
.chips-grid { display: grid; gap: .35rem;
  grid-template-columns: repeat(auto-fill, minmax(min(9.5rem, 100%), 1fr)); }
.chips-grid > .chip { margin: 0; min-width: 0; }
.plan-chip .chip-main { white-space: normal; }
/* One line, under the group, for the option that is actually selected. */
.plan-note { margin: .35rem 0 0; min-height: 1.1em; font-style: italic; }
/* What the conditions do NOT allow — shown, never hidden, but folded into a row. */
.locked-list { margin-top: .4rem; }
.locked-list > summary { cursor: pointer; font-size: .74rem; color: var(--faint);
  font-weight: 700; display: flex; align-items: center; gap: .3rem; }
.locked-list > summary .ico { width: .9em; height: .9em; }
.locked-list ul { list-style: none; margin: .3rem 0 0; padding: 0; display: grid; gap: .2rem; }
.locked-list li.is-locked { display: flex; gap: .5rem; align-items: baseline;
  font-size: .74rem; opacity: .75; }
.lock-name { font-weight: 700; white-space: nowrap; }
.lock-why { color: var(--faint); font-style: italic; }

/* The adjustments, rowed up: each is one click and used to take a whole panel. */
.fine-row { display: grid; gap: .5rem .9rem; align-items: start;
  grid-template-columns: repeat(auto-fit, minmax(min(13rem, 100%), 1fr)); }
.fine-item { min-width: 0; }
.fine-item select { max-width: 100%; }
.fine-toggles { display: grid; gap: .3rem; align-content: start; }
/* Four preset names wrap to a second row rather than being squeezed into three
   lines apiece by an equal-width segmented control. */
.chips-presets { display: flex; flex-wrap: wrap; gap: .3rem; }
.chips-presets > .chip { white-space: nowrap; margin: 0; }

@media (max-width: 600px) {
  .cond-row { grid-template-columns: 6.4rem 1fr 3.2rem; }
  .read-grid { grid-template-columns: 1fr; }
  .chips-grid { grid-template-columns: repeat(auto-fill, minmax(min(8rem, 100%), 1fr)); }
}
.situation { margin: 0 0 1rem; padding: .55rem .8rem; border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--gold) 11%, var(--surface)); border: 1px solid var(--border-2);
  font-weight: 600; font-size: .9rem; }
.tactic-label-row { display: flex; align-items: baseline; justify-content: space-between; gap: .6rem; flex-wrap: wrap; margin-bottom: .45rem; }
.apply-all { font-size: .76rem; color: var(--faint); font-weight: 600; }
.link-btn { background: none; border: 0; color: var(--accent); font: inherit; font-size: .76rem; font-weight: 700; cursor: pointer; padding: 0 .1rem; }
.link-btn:hover { text-decoration: underline; }
.batter-row { display: flex; align-items: center; gap: .7rem; flex-wrap: wrap; padding: .5rem .55rem;
  border-radius: var(--radius-sm); border: 1px solid transparent; justify-content: space-between; margin-bottom: .3rem; }
.batter-row.is-striker { background: color-mix(in srgb, var(--turf) 9%, var(--surface)); border-color: var(--border-2); }
.batter-name { font-weight: 700; min-width: 8rem; font-size: .92rem; }
.chips-role { gap: .3rem; }
/* ---- Their attack: one live row, the rest folded away -------------------- */
/* Deliberately the same rhythm as .batter-row — name and meta on the left, a
   segmented control on the right — so "how we play" reads as one idea whether
   it is our batter or their bowler. */
.stance-row { display: flex; align-items: center; justify-content: space-between; gap: .7rem;
  flex-wrap: wrap; padding: .45rem .55rem; border-radius: var(--radius-sm);
  border: 1px solid transparent; margin-bottom: .25rem; }
.stance-row.is-now { background: color-mix(in srgb, var(--leather) 9%, var(--surface)); border-color: var(--border-2); }
.stance-who { display: flex; flex-direction: column; gap: .05rem; min-width: 9rem; }
.stance-name { font-weight: 700; font-size: .92rem; }
.stance-meta { font-size: .72rem; color: var(--muted); font-weight: 500; }
/* Left as a default `list-item` summary on purpose: any other `display` value
   drops the disclosure triangle in Chrome, and that arrow is the only thing
   saying the rest of the attack is still there. */
.stance-more > summary { cursor: pointer; font-size: .82rem; color: var(--muted); font-weight: 700;
  padding: .35rem 0; }
.stance-more > summary::marker { color: var(--faint); }
.stance-more > summary:hover { color: var(--text); }
.stance-more[open] > summary { margin-bottom: .15rem; }
.stance-set { color: var(--turf); font-weight: 600; font-size: .78rem; }
.stance-set::before { content: "· "; color: var(--faint); }
/* A segmented control never wraps mid-way (it would look broken), so on a narrow
   screen it scrolls sideways inside itself instead of widening the console. */
.chips.seg { gap: 0; border: 1px solid var(--border-2); border-radius: var(--radius-sm);
  overflow-x: auto; overflow-y: hidden; flex-wrap: nowrap; max-width: 100%;
  scrollbar-width: none; }
.chips.seg::-webkit-scrollbar { display: none; }
.chips.seg .chip { border-radius: 0; border: 0; border-left: 1px solid var(--border-2); background: var(--surface-2); box-shadow: none; padding: .34rem .62rem; }
.chips.seg .chip:first-child { border-left: 0; }
.chips.seg .chip:hover { transform: none; background: var(--surface-3); }
.chips.seg .chip:has(input:checked) { box-shadow: none; background: linear-gradient(135deg, var(--turf), var(--turf-d)); color: #04130b; }
.chips.seg .chip:has(input:checked) .chip-main { color: #04130b; }
.set-both-btn { cursor: pointer; }
.field-preset.on { background: linear-gradient(135deg, var(--turf), var(--turf-d)); color: #04130b; border-color: var(--turf); box-shadow: 0 0 0 1px var(--turf); }
.field-preset.on .chip-main, .field-preset.on { color: #04130b; }
.field-custom { margin-top: .4rem; }
.field-custom summary { cursor: pointer; font-size: .82rem; color: var(--muted); font-weight: 700; padding: .3rem 0; }
.field-custom summary:hover { color: var(--text); }
.tactic-sublabel { font-size: .72rem; font-weight: 700; color: var(--faint); margin: .6rem 0 .25rem; text-transform: uppercase; letter-spacing: .05em; }
.chips-pos { gap: .3rem; }
.pos-chip { padding: .28rem .55rem; }
.field-layout { display: flex; gap: 1rem; align-items: flex-start; flex-wrap: wrap; }
/* Presets, the count, what the shape does and the over's allowance — the column
   that reads beside the map. (Was an inline style; it needed a name once the
   help lines moved in with it.) */
.field-picker { flex: 1; min-width: 230px; }
.field-diagram { flex: 0 0 auto; }
.fd-svg { width: 168px; height: 168px; display: block; }
.fd-oval { fill: url(#fdg); stroke: color-mix(in srgb, var(--turf) 55%, transparent); stroke-width: 1; }
.fd-ring { fill: none; stroke: color-mix(in srgb, #fff 18%, transparent); stroke-width: .5; stroke-dasharray: 2 2; }
.fd-pitch { fill: color-mix(in srgb, var(--gold) 30%, var(--surface)); stroke: color-mix(in srgb,#fff 20%,transparent); stroke-width: .4; }
.fd-bat { fill: var(--gold); }
.fd-bowler { fill: var(--muted); }
.fd-svg .fl circle { fill: var(--leather); stroke: #fff; stroke-width: .5; }
.orders-line { min-height: 1.1rem; margin: .2rem 0 .8rem; font-size: .82rem; color: var(--turf); font-weight: 600; }
.intel-line { color: var(--gold); }

/* ---- Tabs ----
   Display caps on a rule, the selected one marked with the slanted cut. */
.tablist { display: flex; gap: .15rem; border-bottom: 1px solid var(--glass-line); margin-bottom: 1.2rem;
  overflow-x: auto; scrollbar-width: none; }
.tablist::-webkit-scrollbar { display: none; }
.tab { position: relative; background: none; border: 0; color: var(--muted); display: inline-flex; align-items: center;
  gap: .4rem; font: inherit; font-family: var(--font-display); font-weight: 800; font-size: .78rem;
  letter-spacing: .08em; text-transform: uppercase; padding: .6rem .9rem; cursor: pointer; white-space: nowrap;
  border-radius: var(--radius-sm) var(--radius-sm) 0 0; transition: color .12s, background .12s; }
.tab .ico { width: 1rem; height: 1rem; opacity: .85; }
.tab:hover { color: var(--text); background: var(--glass-hi); }
.tab[aria-selected="true"] { color: var(--text); }
.tab[aria-selected="true"]::after { content: ""; position: absolute; left: .6rem; right: .6rem; bottom: -1px; height: 3px;
  background: var(--turf); transform: skewX(var(--slant)); }
.tab[aria-selected="true"] .ico { color: var(--turf); opacity: 1; }
.tab:focus-visible { outline: 3px solid var(--focus); outline-offset: -3px; }
.tab-panel { animation: fadeUp .3s both; }
/* A table that stands on its own (a tab panel's, or a screen's) gets a glass
   backing, so its rows never sit straight on the floodlights. game.js wraps
   every table in .table-scroll; inside a card the card is the backing. */
.tab-panel > .table-scroll, main > .table-scroll { background: var(--glass); border: 1px solid var(--glass-line);
  border-radius: var(--radius); padding: 0 .35rem; -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
  box-shadow: var(--shadow), inset 0 1px 0 var(--glass-hi); }
.tab-panel > .table-scroll > table caption { padding: .7rem .4rem 0; margin-bottom: .2rem; }

/* ---- Playing XI selector ---- */
/* `min-width: 0` on the columns is load-bearing, not tidiness: a grid item
   defaults to `min-width: auto`, so it refuses to shrink below its content —
   and the widest .pl-row (name + four 42px touch targets) then forced the whole
   PAGE to 428px on every phone. */
.lineup-cols { display: grid; gap: 1.1rem; grid-template-columns: 1fr 1fr; align-items: start; }
.lineup-cols > * { min-width: 0; }
@media (max-width: 880px) { .lineup-cols { grid-template-columns: 1fr; } }
.pl-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .4rem; }
.pl-ordered { counter-reset: pos; }
.pl-row { display: flex; align-items: center; justify-content: space-between; gap: .6rem; padding: .5rem .65rem;
  border-radius: var(--radius-sm); border: 1px solid var(--border-2); background: var(--surface-2); }
.pl-ordered .pl-row { counter-increment: pos; }
.pl-ordered .pl-row .pl-info { position: relative; padding-left: 1.9rem; }
.pl-ordered .pl-row .pl-info::before { content: counter(pos); position: absolute; left: 0; top: 50%; transform: translateY(-50%);
  width: 1.4rem; height: 1.4rem; border-radius: 50%; display: grid; place-items: center; background: var(--turf);
  color: #04130b; font-family: var(--font-display); font-weight: 800; font-size: .78rem; }
.pl-info { display: flex; flex-direction: column; gap: .05rem; min-width: 0; }
.pl-name { font-weight: 700; }
.pl-meta { font-size: .74rem; color: var(--muted); }
.pl-stat { font-size: .78rem; color: var(--text); font-variant-numeric: tabular-nums; }
.pl-actions { display: flex; gap: .25rem; flex-shrink: 0; }
.pl-actions .btn { padding: .25rem .5rem; }
#xi-list .act-add { display: none; }
.bench-list .act-up, .bench-list .act-down, .bench-list .act-remove { display: none; }
.bench-head { font-size: .72rem; text-transform: uppercase; letter-spacing: .08em; color: var(--faint); font-weight: 800; margin: .9rem 0 .4rem; }
.bench-cat:first-of-type .bench-head { margin-top: .2rem; }

/* ---- New-career wizard (cascading picker) ---- */
.career-form { max-width: 720px; }
.career-form input, .career-form select { max-width: none; }
/* When JS drives the wizard, steps reveal one at a time; without JS every step
   (and the plain selects) stays visible so the form still works. */
.career-form.js-on .wiz-step:not(.show) { display: none; }
.wiz-step { margin: 0 0 1.3rem; animation: rise .3s both; }
.wiz-step > .tactic-label { display: flex; align-items: center; gap: .5rem; }
.wiz-step .step-num { display: inline-grid; place-items: center; width: 1.3rem; height: 1.3rem;
  border-radius: 50%; background: var(--surface-3); border: 1px solid var(--border-2);
  color: var(--muted); font-family: var(--font-display); font-weight: 800; font-size: .72rem; }
.wiz-step.show > .tactic-label .step-num { background: var(--turf); color: #04130b; border-color: var(--turf); }
.wiz-chips .chip { min-width: 8.5rem; }
.wiz-chip-ico { color: var(--turf); }
.wiz-chip-ico .ico { width: 1.4rem; height: 1.4rem; }
.career-summary { margin: 0 0 1rem; padding: .7rem .9rem; border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--turf) 8%, var(--surface)); border: 1px solid var(--border-2);
  font-size: .9rem; }
.career-summary:empty { display: none; }

/* ---- The stage ----
   The ground at night (templates/_backdrop.html — masts, beams, stands, the
   mown outfield; SVG, both themes) sits fixed at the back of the frame on
   every screen. On the title screen and the main menu it IS the picture;
   behind a campaign's screens it is pushed back — darker, softer — so the
   panels read over it. Decorative only. */
.backdrop { position: fixed; inset: 0; overflow: hidden; pointer-events: none;
  background: linear-gradient(180deg, #05080a 0%, #0a1412 48%, #0c1a14 70%, #071009 100%); }
.backdrop-svg { position: absolute; left: 50%; bottom: 0; width: max(100%, 1200px); height: 100%;
  transform: translateX(-50%); }
.app--stage .backdrop-svg { filter: blur(3px) brightness(.68) saturate(.85);
  transform: translateX(-50%) scale(1.03); }
/* A blurred layer must not repaint every frame. */
.app--stage .bd-lamp-glow { animation: none; }
/* Behind a screen of TEXT the floodlight heads go up out of the frame (G-07).
   At 900px they sat at 154-170px — exactly the band every screen's title and
   subtitle occupy — so a near-white lamp head stood behind "…to the rankings"
   and "…how each one plays" and took their contrast with it (a scrim cannot
   fix that: muted text over a lamp needs the lamp dimmed ~95%). The masts and
   their beams still rise into the picture; the title screen and the main menu,
   where the ground IS the picture, keep the lamps where they are. */
.app--stage .bd-masts, .app--lobby:not(.app--menu) .bd-masts { transform: translateY(-260px); }
.bd-glow-a { stop-color: #7fe0a6; stop-opacity: .16; } .bd-glow-b { stop-color: #7fe0a6; stop-opacity: 0; }
.bd-beam-a { stop-color: #fff6d6; stop-opacity: .16; } .bd-beam-b { stop-color: #fff6d6; stop-opacity: 0; }
.bd-mast { stroke: #1d2a24; stroke-width: 4; fill: none; }
.bd-lamp { fill: #fff9e4; }
.bd-lamp-glow { fill: #fff2c2; opacity: .18; filter: blur(14px); }
.bd-stand-roof { fill: #182420; }
.bd-stand { fill: #101915; }
.bd-tier { fill: none; stroke: #1c2923; stroke-width: 2; }
.bd-turf-a { stop-color: #1f6b3d; } .bd-turf-b { stop-color: #0d3a20; }
.bd-stripe { fill: #ffffff; opacity: .05; }
.bd-square { fill: #b39a63; opacity: .55; }
[data-theme="light"] .backdrop { background: linear-gradient(180deg, #d8e6ee 0%, #e6eee9 45%, #dfe9e0 100%); }
[data-theme="light"] .app--stage .backdrop-svg { filter: blur(3px) brightness(1.02) saturate(.7); }
[data-theme="light"] .bd-glow-a { stop-color: #ffffff; stop-opacity: .5; }
[data-theme="light"] .bd-beam-a { stop-opacity: .05; }
[data-theme="light"] .bd-mast { stroke: #9fb0a8; }
[data-theme="light"] .bd-lamp-glow { opacity: .08; }
[data-theme="light"] .bd-stand-roof { fill: #b9c8c0; }
[data-theme="light"] .bd-stand { fill: #a9b9b0; }
[data-theme="light"] .bd-tier { stroke: #93a59b; }
[data-theme="light"] .bd-turf-a { stop-color: #3fae66; } [data-theme="light"] .bd-turf-b { stop-color: #1f8a49; }
[data-theme="light"] .bd-square { fill: #d8c48c; }
@media (prefers-reduced-motion: no-preference) {
  .bd-lamp-glow { animation: lampFlicker 6s ease-in-out infinite; }
  @keyframes lampFlicker { 0%, 100% { opacity: .18; } 50% { opacity: .24; } }
}

/* ---- Title screen (auth) ---- */
.app--bare main { max-width: 480px; margin-top: 4vh; }
.title-screen { position: relative; z-index: 1; animation: fadeUp .5s both; }
.title-hero { text-align: center; margin-bottom: 1.3rem; }
.title-hero .logo { display: inline-grid; place-items: center; color: var(--text);
  filter: drop-shadow(0 18px 40px rgba(0,0,0,.55)); }
.title-hero h1 { display: flex; justify-content: center; margin: .9rem 0 .35rem; color: var(--text);
  filter: drop-shadow(0 8px 30px rgba(0,0,0,.5)); }
.title-tag { color: var(--muted); font-style: italic; margin: 0; font-size: 1rem; }
.title-card { background: var(--glass-2); border-color: var(--glass-line); }
.title-card > h2 { font-size: 1.15rem; letter-spacing: 0; text-transform: none; color: var(--text);
  border-bottom: 0; padding-bottom: 0; margin-bottom: .6rem; }
.title-card form label { margin-top: .8rem; }
.title-card .remember { margin: .8rem 0 .2rem; }
.title-alt { margin: .3rem 0 0; color: var(--muted); }
.title-alt .btn-link { margin-left: .35rem; }

/* ---- Sign in with Google ----
   The G stays Google's four colours (ui.google_g) because it is their mark and
   people read it at a glance; the button around it is ours, so the title screen
   still looks like one screen rather than a game with somebody else's widget
   bolted to it. Nothing here renders unless the install is configured. */
.google-form { margin: 0; }
.btn-google { background: linear-gradient(180deg, var(--surface-3), var(--surface-2));
  letter-spacing: .01em; }
.btn-google .g-mark { flex: 0 0 auto; }
/* The word sits in a GAP in the rule, not on top of it — no background patch to
   keep in step with the card behind (the title card is glass over the ground). */
.or-rule { display: flex; align-items: center; gap: .7rem; margin: 1rem 0 .1rem;
  color: var(--muted); font-family: var(--font-display); font-size: .72rem;
  font-weight: 700; text-transform: uppercase; letter-spacing: .14em; }
.or-rule::before, .or-rule::after { content: ""; flex: 1 1 auto; height: 1px;
  background: var(--glass-line); }
/* "Signed in with Google as name@example.com" — the mark, then the address.
   The mark never wraps away from the words it belongs to; the address does, and
   breaks inside itself on a narrow phone rather than pushing the row wide. */
.google-who { display: inline-flex; align-items: center; gap: .45rem;
  flex-wrap: nowrap; }
.google-who > span { min-width: 0; overflow-wrap: anywhere; }
.g-mark { flex: 0 0 auto; }
.title-card .google-who { margin: .9rem 0 .2rem; }
/* A settings row whose control is a button rather than a field: the label takes
   the slack so the button stays at the right edge. */
.account-row > span:first-child { flex: 1 1 12rem; }
.account-value { font-weight: 700; overflow-wrap: anywhere; }
/* On a phone the row stacks: the account it is connected to, then the button
   under it at a full thumb's width, rather than a button squeezed against a
   two-line address. */
@media (max-width: 520px) {
  .account-row { flex-direction: column; align-items: stretch; }
  /* The 12rem basis above is a WIDTH in a row and a HEIGHT in a column: left in
     place it stood the "connected as" line in 12rem of empty space. */
  .account-row > span:first-child { flex: 0 0 auto; }
  .account-row > .btn { width: 100%; }
}
/* The password fields sit in a column. Without a fixed label track each box
   starts and ends wherever its own label happened to leave off — "Repeat it" is
   half the width of "Current password" — and three boxes ended up three
   different sizes. */
.pw-row > label { flex: 0 0 10.5rem; }
.pw-row input[type="password"] { flex: 0 1 15rem; min-width: 0; }
@media (max-width: 520px) {
  .pw-row > label { flex: 1 1 100%; }
  .pw-row input[type="password"] { flex: 1 1 100%; max-width: none; }
}
/* A plain checkbox, drawn as one of ours. */
label.check { display: inline-flex; align-items: center; gap: .55rem; font-weight: 500; cursor: pointer; margin: 0; }
label.check input { width: 1.1rem; height: 1.1rem; margin: 0; accent-color: var(--turf); }

/* ---- Reduced motion: kill ALL animation/transition ---- */
[data-reduce-motion="true"] *, [data-reduce-motion="true"] *::before, [data-reduce-motion="true"] *::after {
  animation: none !important; transition: none !important; scroll-behavior: auto !important; }
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; scroll-behavior: auto !important; }
}

/* ==========================================================================
   Cross-platform / adaptive layer — behaviour that responds to input type,
   pointer, viewport and form factor (not just visual scaling).
   ========================================================================== */

/* ---- Pointer & hover adaptivity ----
   Hover affordances only where a real hover exists; on touch they "stick" after
   a tap. Coarse pointers (fingers) get ≥44px hit targets and 16px form text
   (which stops iOS from auto-zooming the page on focus). */
@media (hover: none) {
  .tile:hover { transform: none; }
  .chip:hover { transform: none; }
  .nav-link:hover { transform: none; background: none; }
  tbody tr:hover { background: transparent; }
}
@media (pointer: coarse) {
  .btn { min-height: 44px; }
  .btn-sm { min-height: 38px; }
  .btn-lg { min-height: 52px; }
  .tab { min-height: 46px; }
  .sc-tab { min-height: 40px; }
  .chip { min-height: 42px; }
  .chip-sm { min-height: 34px; }
  .chips.seg .chip { min-height: 38px; }
  .pl-actions .btn { min-width: 42px; min-height: 42px; padding: .35rem .45rem; }
  /* 16px stops iOS zooming the page when a field takes focus. Checkboxes and
     radios are EXCLUDED: they're replaced elements, so `min-height` stretched
     them into 13×44 slivers. Their wrapping <label> is the real target. */
  input:not([type="checkbox"]):not([type="radio"]), select, textarea {
    min-height: 44px; font-size: 16px; }
  /* The link-styled buttons (a tile's "Manage squad", a player's name in the
     squad table, "scorecard") sat at 20–23px — under WCAG 2.5.8's 24px floor. */
  .btn-link { min-height: 28px; }
  .link-btn { min-height: 30px; padding: 0 .35rem; }
  /* A bare checkbox/radio is a ~13px box — too small to hit. Grow the control
     itself and give its wrapping label a real touch area too. (The visually
     hidden ones inside .chip / .switch keep their own 1px rules, which are more
     specific than this.) */
  input[type="checkbox"], input[type="radio"] { width: 1.35rem; height: 1.35rem; }
  .bbb-toggle, .drs-toggle, label.switch { min-height: 34px; }
  table.sortable thead th[data-sort] { padding-block: .8rem; }
  .toast-close { min-width: 40px; min-height: 40px; }
  .switch-track { width: 3rem; height: 1.7rem; }
  .switch input:checked + .switch-track .switch-thumb { transform: translateX(1.3rem); }
  .field-custom summary { padding: .55rem 0; }
}

/* ---- Responsive tables ----
   game.js wraps every data table in `.table-scroll`. On desktop the wrapper is
   inert (sticky headers keep working); on narrow screens dense tables scroll
   sideways instead of crushing into unreadable columns. */
.table-scroll { width: 100%; }
/* On the profile's Matches tab the ACTIONS are the point of the table — it is
   the way back into a match — so they must not be the thing that scrolls off a
   phone. The campaign a match was played in is the column that can go: most
   managers have one, and it is still on the row for anyone who scrolls. */
@media (max-width: 760px) {
  .table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; overscroll-behavior-x: contain; scrollbar-width: thin; }
  .table-scroll > .data-table { min-width: 560px; }
  table { font-size: .9rem; }
  th, td { padding: .5rem .55rem; }
}
/* The profile's Matches tab carries the way back into each match, so the less it
   has to be scrolled sideways on a phone the better. The campaign a match was
   played in is the column that can go: most managers have one.
   The 560px floor above STAYS. Releasing it was tried and is worse — three
   columns squeezed into 360px wraps "Mumbai Indians v Gujarat Titans" over six
   lines and the buttons overflow anyway. Scrolling a dense table sideways is
   what every other table in the app does, and consistency beats a special case
   that does not even work. */
@media (max-width: 560px) { .col-campaign { display: none; } }

/* ---- Large desktop: let the working area breathe ---- */
@media (min-width: 1500px) { main { max-width: 1340px; } }

/* ---- Stacked match layout (same breakpoint as .match-grid) ----
   Beside the ground the panels are columns you scroll independently; stacked
   under it they are simply the end of the page, and a 56vh panel with its own
   scrollbar swallows the flick that was meant to scroll the page. Let them run
   their natural height instead. */
@media (max-width: 880px) {
  /* ...and that applies to EVERY panel down here, not only these two. The
     commentary log and the break-show chat kept scrollports of their own (56vh
     and 50vh), so on a stacked layout a flick that was meant to move the page
     died inside them instead — the exact fault this block was written to fix,
     left in two of the panels it was written for. A panel taller than a quarter
     of the viewport with its own scrollbar is a scroll trap; stacked, these are
     simply the end of the page, so they run their natural height and the page
     scrolls. */
  .commentary-live, .commentary-feed, .break-show-feed, .match-scorecard {
    max-height: none; overflow: visible; }
  /* The innings switcher stuck to the top of the scorecard's own scrollport; with
     that scrollport gone it would stick to the VIEWPORT and slide under the HUD. */
  .sc-switch { position: static; }
}

/* ---- Touch devices: readable broadcast micro-type ----
   These labels are sized for a scoreboard you sit two feet from. On anything
   held in the hand they were landing at 9.6–10.9px. Keyed on the INPUT, not the
   viewport: a 1024px tablet is still a device at arm's length. */
@media (pointer: coarse) {
  .hud-over-label, .wp-cap, .sc-tag, .phase-tag, .sc-tab-inns,
  .sc-bat th, .sc-bowl th, thead th, .eyebrow, .tile .label, .label, .bench-head,
  .nav-group, .pitch-badge, .brand-text small, .mast-kicker, .mast-ha, .menu-side-head h2,
  .matchup-tag, .guide-kicker, .ft-pom-text .label, .status-item .value small,
  .news-md, .club-sub, .stat-chip dt, .tab-count, .join-kicker,
  .rchip, .stat-sub, .read-label,
  .ob-wide, .ob-noball { font-size: .72rem; }
  .guide-more > summary { min-height: 28px; }
  /* The console's folds are tapped: "Why bowl?", "What it does", "3 locked". */
  .why > summary, .locked-list > summary { min-height: 28px; }
  .sc-bat, .sc-bowl { font-size: .9rem; }
  .sc-out, .pl-meta { font-size: .8rem; }
}

/* ==========================================================================
   Phones / small tablets ≤820px — the masthead slims to a strip and the ribbon
   becomes the bottom navigation bar.
   ========================================================================== */
@media (max-width: 820px) {
  /* A phone scrolls the PAGE, not a pane inside it.
     The desktop shell is a fixed-height frame with <main> scrolling internally.
     Letting the document scroll hands the browser back its URL-bar collapse
     and native momentum, and the bottom bar's clearance belongs to the last
     thing on the page — <main>'s own padding. */
  .app { display: block; height: auto; min-height: 100dvh; overflow: visible; }
  .app--bare { height: auto; overflow: visible; }
  .content { height: auto; min-height: 0; overflow: visible; display: block; }
  main { overflow: visible; overscroll-behavior: auto; max-width: none;
         padding: .9rem .9rem calc(5.4rem + env(safe-area-inset-bottom)); }
  .app--bare main { margin-top: 3vh; }

  /* fluid headings so big display type never overflows a phone */
  h1 { font-size: clamp(1.3rem, 6vw, 1.6rem); }
  .hero h1 { font-size: clamp(1.6rem, 8vw, 2.2rem); }
  .broadcast .bc-team { font-size: clamp(1.15rem, 6vw, 1.5rem); }
  .tile .value { font-size: 1.7rem; }
  .page-head { gap: .6rem; }
  .page-actions { width: 100%; }

  /* new-career wizard: chips stack full-width for easy thumbing */
  .wiz-chips { flex-direction: column; }
  .wiz-chips .chip { width: 100%; min-width: 0; }

  /* ---- The masthead: a strip — crest, club, CONTINUE ---- */
  .chrome { position: static; background: none; -webkit-backdrop-filter: none; backdrop-filter: none;
    border: 0; box-shadow: none; }
  .masthead { min-height: 3.2rem; padding: .35rem .8rem; gap: .55rem; background: var(--chrome);
    -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px); border-bottom: 1px solid var(--chrome-line); }
  .brand-text small, .mast-div, .mast-next, .club-sub { display: none; }
  .brand-mark .pv-mark { height: 1.7rem !important; }
  .brand-text strong .pv-wordmark { height: .95rem !important; }
  .club-chip .crest { width: 30px; height: 30px; }
  .club-name { font-size: .92rem; }
  .continue-btn { padding: .48rem .75rem; font-size: .72rem; letter-spacing: .04em; }
  /* MENU is the glyph alone on a phone (the label stays for readers and as
     the tooltip); the club's name keeps the room. */
  .menu-btn { padding: .45rem .55rem; }
  .menu-btn > span { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden;
    clip: rect(0 0 0 0); white-space: nowrap; }
  .menu-btn .ico { width: 1.3rem; height: 1.3rem; }
  /* A lobby screen has no bottom bar, so nothing to clear beneath the view. */
  .app--lobby main { padding-bottom: calc(1.2rem + env(safe-area-inset-bottom)); }

  /* ---- Bottom navigation bar (no-JS: every item, horizontally scrollable) ---- */
  .ribbon { position: fixed; left: 0; right: 0; bottom: 0; z-index: 90; min-height: 0;
    flex-direction: row; align-items: stretch; gap: 0;
    padding: .2rem .15rem calc(.2rem + env(safe-area-inset-bottom));
    border-top: 1px solid var(--chrome-line); overflow-x: auto; overflow-y: hidden;
    background: var(--bg-2); box-shadow: 0 -8px 24px rgba(0,0,0,.28); -webkit-overflow-scrolling: touch; }
  .nav { display: contents; }
  .nav-group { display: none; }
  .nav ul { display: flex; flex-direction: row; gap: 0; }
  .nav ul:not(:first-of-type)::before { display: none; }
  /* Five labels in 390px: the bar reads in sentence case (the sheet keeps
     the caps), and a long label ellipsises rather than running into the next. */
  .nav-link { position: relative; flex-direction: column; align-items: center; justify-content: center; gap: .12rem;
    min-width: 4.2rem; margin: 0; padding: .4rem .35rem; border-radius: 0; white-space: nowrap;
    font-size: .62rem; letter-spacing: 0; text-transform: none; }
  .nav-link > span { max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
  .nav-link .ico { width: 1.35rem; height: 1.35rem; }
  .nav-link.active { background: none; color: var(--turf); }
  .nav-link.active .ico { color: var(--turf); }
  .nav-link.active::after { top: 0; bottom: auto; left: 30%; right: 30%; height: 2px; background: var(--turf);
    box-shadow: none; }
  .nav .dot { position: absolute; margin: 0; top: .3rem; right: 50%; transform: translateX(1rem); }
  .nav-more { display: none; }
  .toasts { left: .6rem; right: .6rem; top: .6rem; max-width: none; }

  /* The "More" toggle, styled like a bar item. */
  .ribbon.nav-js .nav-more { display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: .12rem; padding: .4rem .35rem; border: 0; background: none; color: var(--muted);
    font: inherit; font-family: var(--font-display); font-weight: 800; font-size: .62rem; letter-spacing: 0;
    cursor: pointer; border-radius: 0; }
  .ribbon.nav-js .nav-more .ico { width: 1.35rem; height: 1.35rem; }
  .ribbon.nav-js .nav-more.active { color: var(--turf); }

  /* ---- Collapsed (curated) bar: flatten the lists so the core items + More
     share the bar evenly; everything else waits in the sheet. ---- */
  .ribbon.nav-js:not(.nav-open) { overflow-x: hidden; }
  .ribbon.nav-js:not(.nav-open) .nav ul { display: contents; }
  .ribbon.nav-js:not(.nav-open) .nav li:has(.nav-link:not(.nav-core)) { display: none; }
  .ribbon.nav-js:not(.nav-open) .nav li { display: flex; flex: 1 1 0; min-width: 0; }
  .ribbon.nav-js:not(.nav-open) .nav li .nav-link { flex: 1; min-width: 0; }
  .ribbon.nav-js:not(.nav-open) .nav-link > .nav-long:not(:last-child) { display: none; }
  .ribbon.nav-js:not(.nav-open) .nav-link > .nav-short { display: block; }
  .ribbon.nav-js:not(.nav-open) .nav-more { flex: 1 1 0; min-width: 0; }

  /* ---- More sheet (expanded) — the rest of the ribbon as a bottom sheet ---- */
  .ribbon.nav-js.nav-open { flex-direction: column; align-items: stretch; justify-content: flex-start;
    overflow-y: auto; max-height: 82dvh; border-radius: 14px 14px 0 0;
    padding: .9rem .8rem calc(1rem + env(safe-area-inset-bottom)); box-shadow: 0 -18px 44px rgba(0,0,0,.5);
    animation: sheetUp .22s ease both; }
  .ribbon.nav-js.nav-open::before { content: ""; align-self: center; width: 2.4rem; height: 4px; border-radius: 3px;
    background: var(--border-2); margin-bottom: .7rem; flex: none; }
  .ribbon.nav-js.nav-open .nav, .ribbon.nav-js.nav-open .nav ul,
  .ribbon.nav-js.nav-open .nav li { display: block; }
  .ribbon.nav-js.nav-open .nav-group { display: block; position: static; width: auto; height: auto; margin: .8rem .8rem .3rem;
    overflow: visible; clip: auto; font-family: var(--font-display); font-size: .62rem; letter-spacing: .16em;
    text-transform: uppercase; color: var(--faint); font-weight: 800; }
  .ribbon.nav-js.nav-open .nav-link { display: flex; flex-direction: row; justify-content: flex-start;
    min-width: 0; width: 100%; padding: .68rem .8rem; font-size: .8rem; gap: .75rem; border-radius: var(--radius-sm);
    text-transform: uppercase; letter-spacing: .07em; }
  .ribbon.nav-js.nav-open .nav-link .ico { width: 1.3rem; height: 1.3rem; }
  .ribbon.nav-js.nav-open .nav-link.active { background: var(--surface-2); color: var(--text); }
  .ribbon.nav-js.nav-open .nav-link.active::after { display: none; }
  .ribbon.nav-js.nav-open .nav-link.active .ico { color: var(--turf); }
  .ribbon.nav-js.nav-open .nav-more { flex-direction: row; align-self: flex-end; width: auto;
    padding: .4rem .7rem; font-size: .8rem; text-transform: uppercase; letter-spacing: .07em; }
  @keyframes sheetUp { from { transform: translateY(18px); opacity: .5; } to { transform: none; opacity: 1; } }

  .nav-backdrop { position: fixed; inset: 0; z-index: 80; background: rgba(0,0,0,.5); }

  /* ---- Live match on a phone ---- */
  .commentary-panel { position: static; }
  .hud { top: 0; gap: .6rem 1rem; padding: .6rem .8rem; }
  .hud .scoreboard .runs { font-size: 1.6rem; }
  /* keep the over's primary action thumb-reachable while scrolling the console.
     A DESCENDANT selector since the button moved inside `.console-actions` (the
     pinned foot of the desktop console) — the same set of buttons either way,
     and on a phone it is still the BUTTON that pins, not the whole bar, which
     would take a third of the screen. */
  .tactics-form button[type="submit"] { position: sticky; bottom: calc(4.9rem + env(safe-area-inset-bottom));
    z-index: 6; box-shadow: 0 8px 22px rgba(0,0,0,.45); }
  /* …but a match has NO bottom bar (`.app--match` hides the rail), so don't
     reserve room for one: the console was leaving a dead 4.9rem strip under the
     page and floating "Bowl this over" well clear of the thumb. */
  .app--match main { padding-bottom: 1rem; }
  .app--match .tactics-form button[type="submit"] { bottom: calc(.5rem + env(safe-area-inset-bottom)); }
}

/* ---- Phone bottom-nav labels: the touch floor, AFTER the bar's own sizes ----
   The (pointer: coarse) floor above sets .72rem, but the bar's .nav-link /
   .nav-more / sheet .nav-group rules come later in the source at .62rem and
   out-specify it — so the labels landed at 9.9px on every phone. Same floor,
   stated after the bar and at higher specificity. */
@media (max-width: 820px) and (pointer: coarse) {
  .app .ribbon .nav-link, .app .ribbon.nav-js .nav-more,
  .app .ribbon.nav-js.nav-open .nav-group { font-size: .72rem; }
}

/* ---- Very narrow phones (and the Fold's cover screen) --------------------- */
@media (max-width: 480px) {
  /* The XI editor keeps four 42px touch targets per row; below this width there
     is no room left for the player's name beside them, so the controls take
     their own line rather than squeezing the name to nothing. */
  .pl-row { flex-wrap: wrap; }
  .pl-actions { width: 100%; justify-content: flex-end; }
  .pl-info { flex: 1 1 100%; }
  .save-actions .btn { flex: 1 1 auto; }
}

/* ---- Landscape phones / very short viewports: slim the bar, drop labels ---- */
@media (max-width: 920px) and (max-height: 440px) {
  .ribbon.nav-js .nav-link > span, .ribbon.nav-js .nav-more > span:last-child { display: none; }
  .ribbon { padding-bottom: env(safe-area-inset-bottom); }
  main { padding-bottom: calc(3.6rem + env(safe-area-inset-bottom)); }
  .app--match main { padding-bottom: calc(1rem + env(safe-area-inset-bottom)); }
}

/* =========================================================================
   Drama layer (docs/archive/gameplay.md) — what a result WEIGHS.
   Stakes lines, the trophy cabinet, the toss coin, the title ceremony, the
   delegation bar and the first-session coach marks. Everything here is
   decorative: the same facts always exist as text in the live regions or the
   page body, and every animation is dropped under reduced motion.
   ========================================================================= */

/* ---- Stakes: what this match is worth, said out loud --------------------- */
.stakes-line { display: flex; align-items: flex-start; gap: .4rem; margin: .5rem 0 0;
  font-size: .92rem; line-height: 1.45; color: var(--fg); }
.stakes-line .ico { flex: 0 0 auto; margin-top: .18rem; color: var(--gold); }
.stakes-line.stake-big { color: var(--fg); font-weight: 600; }
.stakes-line.stake-bad { color: var(--muted); }
/* On the match page the stakes are a two-word badge in the sub line — the
   sentence is its tooltip — so the flex block above becomes an inline tag. */
.stakes-tag { display: inline-flex; align-items: center; gap: .25rem; margin: 0;
  font-size: inherit; font-weight: 600; vertical-align: baseline; }
.stakes-tag .ico { margin-top: 0; width: .8rem; height: .8rem; }
.stake-big { color: var(--gold); }
.stake-good { color: var(--turf); }
.stake-bad { color: var(--muted); }
.badge.stake-big { border-color: color-mix(in srgb, var(--gold) 55%, transparent); }
.badge.stake-bad { opacity: .75; }

/* ---- The trophy cabinet on the campaigns lobby --------------------------- */
.cabinet { margin-top: 1.4rem; }
.cabinet-shelf { list-style: none; margin: 0; padding: 0; display: grid; gap: .5rem; }
.cabinet-row { display: flex; align-items: flex-start; gap: .7rem; padding: .6rem .7rem;
  border: 1px solid var(--line); border-radius: 10px; background: var(--panel-2, transparent); }
.cabinet-row.is-title { border-color: color-mix(in srgb, var(--gold) 45%, var(--line)); }
.cabinet-badge { flex: 0 0 auto; color: var(--muted); }
.cabinet-row.is-title .cabinet-badge { color: var(--gold); }
.cabinet-body { display: flex; flex-direction: column; gap: .15rem; flex: 1 1 auto; min-width: 0; }
.cabinet-head { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.cabinet-mods { display: flex; gap: .3rem; flex-wrap: wrap; margin-top: .15rem; }
.cabinet-date { flex: 0 0 auto; white-space: nowrap; }
.cabinet-note { border-left: 3px solid var(--gold); padding-left: .6rem; }
@media (max-width: 620px) { .cabinet-date { display: none; } }

/* ---- The season's story, above its statistics --------------------------- */
.story-cards { display: grid; gap: .8rem; margin: 1.1rem 0;
  grid-template-columns: repeat(auto-fit, minmax(min(230px, 100%), 1fr)); }
.story-card { margin: 0; }
.story-title { margin: .1rem 0 .3rem; font-family: var(--font-display); font-size: 1.05rem; }
.end-prediction { margin-top: .5rem; }

/* ---- The result's register ---------------------------------------------- */
.match-reaction { display: flex; flex-direction: column; gap: .2rem; margin: .6rem 0 0;
  padding: .55rem .7rem; border-radius: 8px; border-left: 3px solid var(--turf);
  background: color-mix(in srgb, var(--turf) 8%, transparent); text-align: left; }
.match-reaction.tone-upset { border-left-color: var(--gold);
  background: color-mix(in srgb, var(--gold) 10%, transparent); }
.match-reaction.tone-statement { border-left-color: var(--turf-d); }
.match-reaction.tone-tight { border-left-color: var(--leather); }
.match-reaction .sub { margin: 0; font-size: .86rem; }
.mood-chip { align-self: center; }
.news-reaction span:last-child { font-style: italic; }

/* ---- The toss: a coin over the ground ----------------------------------- */
.toss-overlay { position: absolute; inset: 0; z-index: 5; display: grid; place-items: center;
  background: rgba(6,10,8,.62); opacity: 0; transition: opacity .28s; pointer-events: none; }
.toss-overlay.show { opacity: 1; }
/* (G-44) When the captains toss on the ground, the card sits low over the
   picture and leaves the coin in the middle to be seen. */
.toss-overlay.on-ground { background: transparent; place-items: end center; padding-bottom: 7%; }
.toss-overlay.on-ground .toss-card { padding: .55rem 1rem; max-width: min(92%, 26rem); }
.toss-overlay.on-ground .toss-card .coin { display: none; }
.toss-card { text-align: center; padding: 1rem 1.4rem; border-radius: 12px;
  background: linear-gradient(180deg, rgba(12,18,14,.94), rgba(12,18,14,.8));
  border: 1px solid color-mix(in srgb, var(--gold) 40%, transparent);
  box-shadow: 0 14px 40px rgba(0,0,0,.5); max-width: min(92%, 30rem); }
.toss-card .coin { display: block; width: 3rem; height: 3rem; margin: 0 auto .5rem;
  border-radius: 50%; background: radial-gradient(circle at 35% 30%, #ffe9a8, var(--gold) 60%, #8a6413);
  box-shadow: 0 4px 14px rgba(0,0,0,.45); animation: coin-flip 1.1s ease-in-out 2; }
@keyframes coin-flip { 0% { transform: rotateY(0) translateY(0); }
  50% { transform: rotateY(540deg) translateY(-28px); }
  100% { transform: rotateY(1080deg) translateY(0); } }
.toss-teams { margin: 0 0 .25rem; color: #e8f0ea; font-weight: 600; }
.toss-teams em { color: var(--muted); font-style: normal; padding: 0 .35rem; }
.toss-result { margin: 0; font-family: var(--font-display); font-size: 1.15rem;
  text-transform: uppercase; letter-spacing: .4px; color: #fff; }
.toss-note { margin: .3rem 0 0; font-size: .82rem; color: #b9c6bd; }

/* ---- The title ceremony: the lift --------------------------------------- */
.ceremony { position: absolute; inset: 0; z-index: 6; display: grid; place-items: center;
  background: radial-gradient(120% 120% at 50% 30%, rgba(24,18,4,.72), rgba(4,8,6,.9));
  opacity: 0; transition: opacity .4s; cursor: pointer; overflow: hidden; }
.ceremony.show { opacity: 1; }
.ceremony-card { text-align: center; position: relative; z-index: 2; padding: 1.2rem; }
.ceremony-cup { display: block; margin: 0 auto .4rem; color: var(--gold); }
.ceremony-cup .ico { width: 3.4rem; height: 3.4rem;
  filter: drop-shadow(0 0 18px color-mix(in srgb, var(--gold) 60%, transparent));
  animation: cup-lift 2.6s ease-in-out infinite; }
@keyframes cup-lift { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-10px); } }
.ceremony-eyebrow { margin: 0; text-transform: uppercase; letter-spacing: 1.4px;
  font-size: .72rem; color: var(--gold); }
.ceremony-title { margin: .2rem 0; font-family: var(--font-display); font-weight: 800;
  font-size: clamp(1.4rem, 5vw, 2.6rem); color: #fff; text-transform: uppercase;
  text-shadow: 0 4px 24px rgba(0,0,0,.6); }
.ceremony-sub { margin: 0; color: #d8e2da; font-size: .9rem; }
.confetti { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
.confetti .cf { position: absolute; top: -8%; width: 7px; height: 12px; border-radius: 2px;
  background: var(--gold); opacity: .9; animation-name: cf-fall;
  animation-timing-function: linear; animation-iteration-count: infinite; }
.confetti .cf:nth-child(3n) { background: var(--turf); }
.confetti .cf:nth-child(3n+1) { background: #fff; }
@keyframes cf-fall { 0% { transform: translateY(0) rotate(var(--cf-rot)); opacity: 1; }
  100% { transform: translateY(112vh) rotate(calc(var(--cf-rot) + 540deg)); opacity: .2; } }

/* The last over of a limited-overs innings — the HUD tightens. */
.hud.last-over, .scoreboard-card.last-over {
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--leather) 55%, transparent); }

/* ---- Delegation: hand it to your captain -------------------------------- */
.delegate-bar { display: flex; flex-wrap: wrap; gap: .35rem; margin-top: .7rem;
  padding-top: .7rem; border-top: 1px dashed var(--line); }
.delegate-form { display: inline; }
.delegate-btn { white-space: nowrap; }
/* The verb for the whole row, once, so the buttons can be a word each. */
.delegate-kicker { display: inline-flex; align-items: center; gap: .25rem; align-self: center;
  font-size: .72rem; font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
  color: var(--faint); padding-right: .2rem; }
.delegate-kicker .ico { width: .85rem; height: .85rem; color: var(--gold); }

/* ---- The text diet: words on the face, sentences one fold down ----------- */
.head-tags { display: inline-flex; gap: .3rem; flex-wrap: wrap; justify-content: flex-end; }
.phase-role { color: var(--faint); }
/* The folds under a chip group sit on one row: "What it does · 3 locked". */
.fold-row { display: flex; flex-wrap: wrap; gap: .2rem 1rem; margin-top: .4rem; align-items: baseline; }
.fold-row > details { margin-top: 0; }
.why > summary { cursor: pointer; font-size: .74rem; color: var(--faint); font-weight: 700;
  list-style: none; display: inline-flex; align-items: center; gap: .3rem; }
.why > summary::-webkit-details-marker { display: none; }
.why > summary::before { content: "?"; display: inline-grid; place-items: center; width: 1.05rem; height: 1.05rem;
  border-radius: 50%; border: 1px solid var(--border-2); font-size: .66rem; line-height: 1; }
.why > summary:hover, .why[open] > summary { color: var(--muted); }
.why > p { margin: .3rem 0 0; font-size: .78rem; color: var(--muted); line-height: 1.4; max-width: 48ch; }
.why > p.plan-note { font-style: normal; min-height: 0; }
.pick-tag { color: var(--gold); }
/* "your call": the panel is no longer what the analysts offered. The gold of
   the pick-tag, filled, because it is a state and not a label. */
.own-call-tag { color: #1a1400; border-color: transparent;
  background: linear-gradient(180deg, var(--gold), #b8860b); }
.next-over-meta { margin: .35rem 0 0; gap: .25rem; }
.followon-stats { margin: 0 0 .8rem; }
.review-label { font-size: .72rem; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--faint); }
.review-call { display: flex; align-items: center; gap: .45rem; flex-wrap: wrap; }
.review-verdict { font-family: var(--font-display); font-size: 1.05rem; letter-spacing: .04em; }
.read-word { text-transform: none; letter-spacing: 0; color: var(--muted); font-weight: 600; margin-left: .3rem; }
.read-word.ball-reverse { color: var(--gold); }
.read-label-sub { margin-top: .4rem; }
/* Your side, in the match head: an underline in the club colour, not a line of copy. */
.mh-title .is-mine { text-decoration: underline; text-decoration-color: var(--club, var(--turf));
  text-decoration-thickness: 3px; text-underline-offset: .16em; }

/* ---- First-session coach marks ------------------------------------------ */
/* The coach marks are a full-width fixed strip across the bottom of the screen,
   but only the CARD in the middle of it is anything to click. Left solid, the
   empty half of the strip swallowed every pointer event in the bottom ~170px of
   the viewport — which is exactly where "Bowl this over" sits on a laptop-height
   window, so a first-time captain could not start their first over until they
   had dismissed the guide. The strip is transparent to the pointer; the card
   takes its clicks back. */
/* (G-54) IN THE PAGE, not over it: a strip under the match's title. As a
   fixed card bottom-left it sat over the commentary — live text — and before
   that over the console; every place over the stage covers something the
   captain is reading. In the flow it covers nothing: the stage gives up the
   strip's height while it is up, and it is up once, in a first session. */
.coach-marks { position: relative; display: block; margin: 0 0 .5rem; padding: 0;
  pointer-events: none; }
.coach-card { display: flex; flex-wrap: wrap; align-items: center; gap: .25rem 1rem;
  max-width: none; margin: 0; padding: .55rem .9rem; border-color: var(--gold);
  box-shadow: none; pointer-events: auto; animation: rise .3s both; }
.coach-card .coach-text { flex: 1 1 18rem; margin: 0; }
.coach-card .eyebrow { margin-bottom: .1rem; color: var(--gold); }
.coach-text { margin: .1rem 0 .55rem; font-size: .88rem; line-height: 1.45; }
.coach-card .controls { margin: 0; }
.coach-card .controls .btn { padding: .3rem .65rem; font-size: .8rem; }

@media (prefers-reduced-motion: reduce) {
  .toss-overlay, .ceremony { transition: none; }
  .toss-card .coin, .ceremony-cup .ico, .confetti .cf { animation: none; }
  .confetti { display: none; }
}
[data-reduce-motion="true"] .toss-card .coin,
[data-reduce-motion="true"] .ceremony-cup .ico { animation: none; }
[data-reduce-motion="true"] .confetti { display: none; }

/* Joining a match part-way — the middle ground between the full 240 balls and
   throwing the broadcast away. Sits under the primary match actions. */
.join-controls { align-items: center; gap: .4rem; margin-top: -.4rem; }
.join-kicker { font-family: var(--font-display); font-weight: 800; font-size: .64rem; letter-spacing: .16em;
  text-transform: uppercase; color: var(--gold); margin-right: .2rem; }

/* =========================================================================
   The par board — the one page where accounts meet.
   Golf's scorecard vocabulary, because golf's word for this is cricket's too.
   ========================================================================= */
/* The rankings' explainer (and any fold that opens with a kicker line). */
.explainer { padding-block: .7rem; }
.explainer p { margin: .6rem 0 0; max-width: 72ch; }
.explainer-sum { cursor: pointer; list-style: none; display: inline-flex; align-items: center; gap: .4rem;
  font-family: var(--font-display); font-weight: 800; font-size: .74rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--muted); }
.explainer-sum::-webkit-details-marker { display: none; }
.explainer-sum:hover { color: var(--text); }
.tab-count { display: inline-grid; place-items: center; min-width: 1.3rem; height: 1.3rem; padding: 0 .3rem;
  border-radius: 999px; background: var(--surface-3); color: var(--text); font-size: .66rem; letter-spacing: 0; }
.save-progress-num { font-variant-numeric: tabular-nums; }

/* The tier scale, in the rankings' explainer: the rung, then what it costs. */
.tier-scale { list-style: none; margin: .5rem 0 0; padding: 0; display: flex;
  flex-wrap: wrap; gap: .35rem .9rem; }
.tier-scale li { display: inline-flex; align-items: baseline; gap: .35rem; }
.explainer-lede { margin: 0; }
.explainer-lede + details { margin-top: .7rem; }

/* ---- the rankings: wins added, tiers, the captain's report ------------------
   A figure in win chance is coloured only when it is yours to answer for:
   green for a call that added, red for one that cost. Everything else stays
   in the ink. */
.wins { font-family: var(--font-display); font-weight: 800; font-variant-numeric: tabular-nums;
  letter-spacing: .3px; white-space: nowrap; }
.wins.is-up { color: var(--turf); }
.wins.is-down { color: var(--bad, #d9534f); }
.tier { display: inline-block; font-family: var(--font-display); font-weight: 800; font-size: .72rem;
  letter-spacing: .12em; text-transform: uppercase; padding: .12rem .5rem; border-radius: 6px;
  border: 1px solid var(--line); color: var(--muted); white-space: nowrap; }
.tier-district { color: var(--text); }
.tier-state { color: #04130b; border-color: transparent;
  background: linear-gradient(135deg, var(--turf), var(--turf-d)); }
.tier-test { color: #1a1400; border-color: transparent;
  background: linear-gradient(135deg, var(--gold), #b8860b); }
.tier-legend { color: #fff; border-color: transparent;
  background: linear-gradient(135deg, #6a3df5, #2b1a7a); }
.tier-none { border-style: dashed; }
.standing-main { display: flex; align-items: center; gap: .8rem; flex-wrap: wrap; margin-bottom: .3rem; }
.standing-figure .wins { font-size: 1.35rem; }
.standing-line { border-left: 3px solid var(--gold); padding-left: .55rem; }
.odds-line { display: flex; align-items: center; gap: .4rem; margin: .35rem 0 0; color: var(--muted);
  font-size: .9rem; }
.ledger-card { border-color: color-mix(in srgb, var(--turf) 40%, var(--line));
  border-left: 3px solid var(--turf); }
.ledger-card h2 { margin: .1rem 0 .5rem; font-family: var(--font-display); font-size: 1.15rem; }
.report-head { display: grid; gap: .8rem; margin: .2rem 0 .6rem;
  grid-template-columns: repeat(auto-fit, minmax(min(160px, 100%), 1fr)); }
.report-figure { display: flex; flex-direction: column; gap: .1rem; }
.report-figure strong { font-family: var(--font-display); font-size: 1.25rem; }
.report-table th[scope="row"] { font-weight: 600; }
.report-table th[scope="row"] .help { display: block; font-weight: 400; }
.report-table td.help { font-size: .84rem; }
.ladder th[scope="row"] { font-weight: 600; }
.edition { margin-top: .6rem; }
.edition > summary { margin-bottom: .4rem; }

/* =========================================================================
   First-visit guides + the first-campaign checklist.
   A landmark at the top of <main>, never a modal: nothing to escape from, no
   focus trap, and it reads perfectly with the panel simply ignored.
   ========================================================================= */
/* A strip: mark | kicker · title · first sentence · [More] | Got it. The rest
   of the copy folds behind "More" so the screen it explains is never pushed
   below the fold by its own explanation. */
.guide { position: relative; display: flex; align-items: center; gap: .7rem; flex-wrap: wrap; overflow: hidden;
  margin: 0 0 1rem; padding: .5rem .8rem .5rem .8rem; border-radius: var(--radius-sm);
  border: 1px solid var(--glass-line); background: var(--glass);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px); }
.guide::before { content: ""; position: absolute; left: -1px; top: -2px; width: 5px; height: 2.6rem;
  background: var(--gold); transform: skewX(var(--slant)); transform-origin: top left; }
.guide-mark { flex: none; display: grid; place-items: center; width: 1.75rem; height: 1.75rem;
  border-radius: 8px; color: var(--gold); background: color-mix(in srgb, var(--gold) 14%, transparent); }
.guide-mark .ico { width: 1rem; height: 1rem; }
.guide-body { flex: 1 1 16rem; min-width: 0; display: flex; align-items: baseline; gap: .2rem .8rem; flex-wrap: wrap; }
.guide-lead { display: flex; align-items: baseline; gap: .2rem .55rem; flex-wrap: wrap; line-height: 1.4; }
.guide-kicker { font-size: .72rem; font-weight: 800; letter-spacing: .12em; text-transform: uppercase;
  color: var(--gold); white-space: nowrap; }
.guide-title { margin: 0; font-family: var(--font-display); font-size: .95rem; font-weight: 800;
  line-height: 1.3; }
.guide-more { margin: 0; }
.guide-more > summary { cursor: pointer; list-style: none; display: inline-flex; align-items: center;
  gap: .15rem; font-size: .76rem; font-weight: 700; color: var(--turf); }
.guide-more > summary::-webkit-details-marker { display: none; }
.guide-more > summary .ico { width: .95em; height: .95em; transition: transform .15s; }
.guide-more[open] > summary .ico { transform: rotate(180deg); }
.guide-more p { margin: .45rem 0 0; max-width: 64ch; font-size: .88rem; line-height: 1.5; }
.guide-more[open] { flex-basis: 100%; }
.guide-dismiss { flex: 0 0 auto; margin-left: auto; }
.guide.is-going { opacity: 0; transform: translateY(-4px); }
@media (prefers-reduced-motion: no-preference) {
  .guide { transition: opacity .2s ease, transform .2s ease; }
}
@media (max-width: 620px) {
  .guide { padding-top: .65rem; }
  .guide-kicker, .guide-mark { display: none; }
  .guide-dismiss { margin-left: 0; width: 100%; }
  .guide-dismiss .btn { width: 100%; }
  /* On a phone the five steps are a strip you thumb sideways, not five rows. */
  .checklist-steps { grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: minmax(min(13rem, 80%), 1fr);
    overflow-x: auto; scroll-snap-type: x mandatory; padding-bottom: .3rem; scrollbar-width: thin; }
  .checklist-steps li { scroll-snap-align: start; }
}

/* Five steps in a row, not five rows. */
.checklist { margin-bottom: 1rem; padding: .85rem 1.1rem .8rem; }
.checklist-head { display: flex; align-items: baseline; gap: .6rem; flex-wrap: wrap; margin-bottom: .6rem; }
.checklist-head .eyebrow { margin: 0; }
.checklist-title { margin: 0; font-size: .98rem; }
.checklist-count { margin-left: auto; font-size: .78rem; color: var(--muted); font-variant-numeric: tabular-nums;
  font-weight: 700; }
.checklist-steps { list-style: none; margin: 0; padding: 0; display: grid; gap: .45rem;
  grid-template-columns: repeat(auto-fit, minmax(min(11rem, 100%), 1fr)); counter-reset: none; }
/* `position: relative` is load-bearing: each step carries a visually-hidden
   "Done" / "Not done yet" span, which is absolutely positioned. Without a
   positioned step it was positioned against the CARD, so on a phone — where
   the steps are a strip you scroll sideways — the last steps' spans escaped
   the strip's clip and made every dashboard 860px wide. */
.checklist-steps li { position: relative; display: flex; align-items: flex-start; gap: .5rem; min-width: 0;
  padding: .5rem .6rem; border-radius: 9px; border: 1px solid var(--line); background: var(--surface-2); }
.checklist-steps li.is-done { opacity: .6; border-color: transparent; background: transparent; }
.checklist-steps li.is-done .check-label { text-decoration: line-through; }
.checklist-steps li { align-items: center; cursor: default; }
.check-mark { flex: 0 0 auto; display: grid; place-items: center; width: 1.35rem; height: 1.35rem;
  border-radius: 50%; color: var(--muted); border: 1px solid var(--border-2); margin-top: .05rem; }
.check-mark .ico { width: .8rem; height: .8rem; }
.checklist-steps li.is-done .check-mark { color: #04130b; background: var(--turf); border-color: var(--turf); }
.check-body { display: flex; flex-direction: column; gap: .05rem; min-width: 0; }
.check-label { font-weight: 700; font-size: .86rem; }




/* ---- the between-overs package -------------------------------------------
   The seconds the box spends writing the next over, dressed as television
   dresses them: the ground noise up, a bed under it, and a card that CYCLES
   rather than a spinner that spins. Nothing here says "loading", because
   nothing here is waiting for the viewer — it is the interval between overs,
   which every broadcast has whether or not anybody is fetching anything. */
.over-break { position: absolute; inset: 0; z-index: 4; display: flex;
  align-items: center; justify-content: center; pointer-events: none;
  background: radial-gradient(ellipse at 50% 55%, rgba(3,14,8,.34), rgba(3,14,8,.62));
  opacity: 0; transition: opacity .45s ease; }
.over-break.show { opacity: 1; }
.ob-card { min-width: min(70%, 24rem); max-width: 90%; padding: .95rem 1.25rem 1.05rem;
  text-align: center; border-radius: .7rem; border: 1px solid rgba(255,255,255,.16);
  border-left: 4px solid var(--gold, #d8b25a);
  background: linear-gradient(180deg, rgba(9,26,16,.93), rgba(6,18,11,.95));
  box-shadow: 0 14px 40px rgba(0,0,0,.45);
  transform: translateY(10px) scale(.985); transition: transform .45s cubic-bezier(.2,.8,.2,1); }
.over-break.show .ob-card { transform: none; }
.ob-eyebrow { margin: 0 0 .25rem; font-size: .68rem; letter-spacing: .18em;
  text-transform: uppercase; color: var(--gold, #d8b25a); font-weight: 800; }
.ob-headline { margin: 0; font-family: var(--font-display, inherit); font-weight: 800;
  font-size: clamp(1.05rem, 3.4vw, 1.5rem); color: #f2f7f3; line-height: 1.15; }
.ob-sub { margin: .3rem 0 0; font-size: .82rem; color: #c6d4cb;
  font-variant-numeric: tabular-nums; }
/* The panel that is showing fades between states rather than cutting. */
.ob-card.ob-turn .ob-headline, .ob-card.ob-turn .ob-sub, .ob-card.ob-turn .ob-eyebrow {
  opacity: 0; transition: opacity .18s ease; }
.ob-card .ob-headline, .ob-card .ob-sub, .ob-card .ob-eyebrow { opacity: 1; transition: opacity .3s ease .06s; }
/* Which panel of the package we are on — the only moving part, and it moves
   because the package is a sequence, not because anything is pending. */
.ob-dots { display: flex; gap: .3rem; justify-content: center; margin: .6rem 0 0; }
.ob-dots i { width: 5px; height: 5px; border-radius: 50%; background: rgba(255,255,255,.26); }
.ob-dots i.on { background: var(--gold, #d8b25a); }
@media (prefers-reduced-motion: reduce) {
  .over-break, .ob-card, .ob-card .ob-headline, .ob-card .ob-sub, .ob-card .ob-eyebrow {
    transition: none; }
  .ob-card { transform: none; }
}


/* =========================================================================
   Identity — portraits, the player card, the next-match bill, the status strip,
   the crest grid. The parts of a manager game that make its people and its
   fixtures look like people and fixtures.
   ========================================================================= */

/* ---- Portraits ---- */
.portrait { position: relative; flex: none; display: inline-block; vertical-align: middle; line-height: 0;
  width: var(--crest-size, 40px); height: var(--crest-size, 40px); border-radius: 50%;
  overflow: hidden; background: var(--surface-3);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.12), 0 2px 6px rgba(0,0,0,.25); }
.portrait svg, .portrait img { display: block; width: 100%; height: 100%; }
/* The PLATE (G-51). Every portrait, photographed or drawn, stands on the same
   card: his club's colour lit from behind his head, a hairline ring in its
   second colour. The colours are inline custom properties from
   portrait_svg.plate_for, the same ones the standalone /portrait/<name> SVG
   paints, and they are drawn here rather than baked into the picture because
   the same man plays for different sides in different campaigns. The
   photograph is his normalised portrait: a 4:5 cut-out framed to his face,
   whose top square is the disc and whose whole is the card. */
.portrait--plate {
  background: radial-gradient(115% 95% at 50% 36%, var(--plate-lift) 0%, var(--plate) 46%, var(--plate-deep) 100%); }
.portrait--plate::after { content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--plate-accent) 45%, transparent); }
.portrait--plate.portrait--card {
  background: linear-gradient(118deg, transparent 0 58%, color-mix(in srgb, var(--plate-accent) 22%, transparent) 58% 62%, transparent 62%),
    radial-gradient(115% 95% at 50% 34%, var(--plate-lift) 0%, var(--plate) 46%, var(--plate-deep) 100%); }
.portrait--plate img { object-fit: cover; object-position: 50% 0; }
.credits-table td { vertical-align: middle; }
.credits-table .portrait { margin-right: .5rem; }
.p-cell .portrait { margin-right: .1rem; }
/* The hero card: a taller crop with more of the kit and his number on the chest. */
.portrait--card { height: calc(var(--crest-size, 40px) * 1.22); border-radius: 12px;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.14), 0 14px 30px rgba(0,0,0,.4); }
/* Faces on the live HUD (batters at the crease) and the broadcast super. */
.hud-face { flex: none; align-self: center; }
.hud-face .portrait { width: 1.55rem; height: 1.55rem; box-shadow: inset 0 0 0 1px rgba(255,255,255,.14); }
.hud-bat.on-strike .hud-face .portrait { box-shadow: 0 0 0 2px var(--turf), inset 0 0 0 1px rgba(255,255,255,.14); }
.lower-third .lt-faces { display: inline-flex; align-items: center; gap: .25rem; margin-right: .4rem; }
.lower-third .lt-faces .portrait { width: 1.9rem; height: 1.9rem; box-shadow: inset 0 0 0 1px rgba(255,255,255,.16), 0 2px 6px rgba(0,0,0,.35); }
.lower-third .lt-faces .portrait + .portrait { margin-left: -.45rem; }
.lower-third .lt-faces:empty { display: none; }

/* ---- The ground ---- */
.ground-bill { position: relative; display: grid; grid-template-columns: minmax(0, 1fr); overflow: hidden;
  border-radius: 12px; background: var(--surface-2); min-height: 11rem;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.08); }
.ground-bill-art { position: absolute; inset: 0; background: var(--ground-photo, linear-gradient(160deg, #1d3a2a, #0e1a14)) center / cover no-repeat; }
.ground-bill-art::after { content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, rgba(8,12,10,.92) 0%, rgba(8,12,10,.78) 45%, rgba(8,12,10,.25) 100%),
              linear-gradient(0deg, rgba(8,12,10,.7), transparent 55%); }
.ground-bill.has-photo .ground-bill-art { filter: saturate(.92); }
.ground-bill-text { position: relative; padding: 1rem 1.2rem; max-width: 40rem; }
.ground-bill-name { font-family: var(--font-display); font-size: 1.35rem; margin: .1rem 0 0; letter-spacing: .01em; }
.ground-bill-place { color: var(--muted); margin: .1rem 0 .7rem; }
.ground-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(11rem, 100%), 1fr)); gap: .35rem 1rem; margin: 0 0 .6rem; }
.ground-facts dt { font-size: .68rem; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.ground-facts dd { margin: 0; font-weight: 600; font-variant-numeric: tabular-nums; }
.ground-bill-note { margin: 0; color: var(--muted); font-size: .92rem; max-width: 34rem; }
.ground-bill--compact { min-height: 6rem; }
.ground-bill--compact .ground-bill-text { padding: .7rem 1rem; }
.ground-bill--compact .ground-bill-name { font-size: 1.1rem; }
.ground-chip-city { color: var(--muted); font-weight: 400; }
.section-h { margin: 1.4rem 0 .6rem; font-size: 1.1rem; }
.ground-card { padding: .6rem; }
.ground-card-meta { margin: .6rem .3rem 0; }
.grounds-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(22rem, 100%), 1fr)); gap: 1rem; }
.grounds-grid .ground-bill { min-height: 14rem; }
.toss-ground { font-family: var(--font-display); font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  font-size: .78rem; color: var(--muted); margin: 0 0 .4rem; }
.toss-card.has-ground { background-image: linear-gradient(rgba(8,12,10,.72), rgba(8,12,10,.86)), var(--ground-photo);
  background-size: cover; background-position: center; }
@media (pointer: coarse) { .ground-facts dt { font-size: .72rem; } }

/* ---- The player card ---- */
.player-hero { display: grid; grid-template-columns: auto 1fr auto; gap: 1.2rem; align-items: center;
  padding: 1.2rem 1.4rem; margin-bottom: 1.2rem; overflow: hidden;
  background:
    radial-gradient(90% 140% at 0% 50%, color-mix(in srgb, var(--club) 26%, transparent), transparent 60%),
    linear-gradient(180deg, var(--glass-2), var(--glass)); }
.player-hero::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 5px;
  background: linear-gradient(180deg, var(--club), var(--club-2)); }
.player-hero-portrait .portrait { box-shadow: 0 0 0 3px color-mix(in srgb, var(--club) 55%, transparent),
  0 14px 30px rgba(0,0,0,.4); }
.player-hero-text { min-width: 0; }
.player-hero-text .eyebrow { margin-bottom: .25rem; }
.player-hero-text h1 { font-size: clamp(1.6rem, 3.2vw, 2.3rem); margin-bottom: .45rem; }
.player-hero-text .bc-meta { margin: 0 0 .5rem; }
.player-hero-lines { display: flex; flex-wrap: wrap; gap: .3rem 1.2rem; margin: 0; font-size: .92rem;
  color: var(--muted); }
.player-hero-lines .ico { color: var(--turf); }
.player-hero-side { display: flex; flex-direction: column; align-items: flex-end; gap: .6rem; min-width: 10.5rem; }
.player-hero-ovr { display: inline-flex; flex-direction: column; align-items: center; gap: .15rem; }
.player-hero-ovr .ovr { font-size: 1.7rem; min-width: 3.2rem; padding: .25rem .6rem; border-radius: 12px; }
.player-hero-ovr .label { font-size: .72rem; }
.player-hero-stats { grid-template-columns: 1fr 1fr; width: 100%; }
@media (max-width: 680px) {
  .player-hero { grid-template-columns: auto 1fr; }
  .player-hero-side { grid-column: 1 / -1; flex-direction: row; align-items: center; justify-content: space-between; }
}

/* ---- The next match, billed ---- */
.matchup { padding: 1.1rem 1.4rem 1.2rem; margin-bottom: 0; overflow: hidden;
  background:
    linear-gradient(100deg, color-mix(in srgb, var(--home, var(--club)) 26%, var(--glass-2)) 0%, var(--glass-2) 42%,
                    var(--glass-2) 58%, color-mix(in srgb, var(--away, var(--club-2)) 26%, var(--glass-2)) 100%); }
.matchup::before { content: ""; position: absolute; left: 0; right: 0; top: 0; height: 4px;
  background: linear-gradient(90deg, var(--home, var(--club)) 0 50%, var(--away, var(--club-2)) 50% 100%); }
.matchup-head { display: flex; align-items: center; justify-content: space-between; gap: .6rem; flex-wrap: wrap;
  margin-bottom: .6rem; }
.matchup-head .eyebrow { margin: 0; }
.matchup-teams { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 1rem;
  margin: .2rem 0 .7rem; }
.matchup-side { display: flex; align-items: center; gap: .85rem; min-width: 0; }
.matchup-side:last-child { flex-direction: row-reverse; text-align: right; }
.matchup-side .crest { flex: none; filter: drop-shadow(0 8px 11px rgba(0,0,0,.4)); }
.matchup-name { font-family: var(--font-display); font-weight: 900; font-size: clamp(1.15rem, 2.3vw, 1.7rem);
  letter-spacing: -.02em; line-height: 1.05; }
.matchup-tag { display: block; font-size: .72rem; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
  color: var(--faint); margin-top: .15rem; }
.matchup-side.is-mine .matchup-tag { color: var(--turf); }
.matchup-side > span { display: flex; flex-direction: column; min-width: 0; }
.matchup-side:last-child > span { align-items: flex-end; }
.matchup-vs { font-family: var(--font-display); font-weight: 900; font-size: 1.1rem; color: var(--faint);
  padding: .3rem .6rem; border-radius: 999px; border: 1px solid var(--border-2); background: var(--surface-2); }
.matchup-meta { margin: 0 0 .5rem; }
.matchup .stakes-line { margin: .1rem 0 .8rem; }
.matchup-actions { display: flex; gap: .55rem; flex-wrap: wrap; align-items: center; }
@media (max-width: 560px) {
  .matchup-teams { grid-template-columns: 1fr; gap: .5rem; }
  .matchup-side:last-child { flex-direction: row; text-align: left; }
  .matchup-side:last-child > span { align-items: flex-start; }
  .matchup-vs { justify-self: start; }
}

/* ---- The status strip ---- */
.status-strip { display: grid; gap: .6rem; grid-template-columns: repeat(auto-fit, minmax(min(150px, 100%), 1fr)); }
.status-item { display: flex; flex-direction: column; gap: .1rem; min-width: 0; padding: .7rem .9rem;
  border-radius: var(--radius-sm); background: var(--glass); border: 1px solid var(--glass-line);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  box-shadow: inset 0 1px 0 var(--glass-hi); }
.status-item .label { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.status-item .value { font-family: var(--font-display); font-size: 1.45rem; font-weight: 800; line-height: 1.15;
  font-variant-numeric: tabular-nums; letter-spacing: -.01em; display: flex; align-items: baseline; gap: .1rem; }
.status-item .value small { font-size: .72rem; font-weight: 700; color: var(--muted); }
.status-item .value.accent { color: var(--turf); }
.status-item .foot { color: var(--faint); font-size: .74rem; display: flex; gap: .3rem; align-items: baseline;
  flex-wrap: wrap; }
.status-item .form-strip { gap: .25rem; min-height: 1.6rem; }
.status-item .form-strip .form-pip { width: 1.5rem; height: 1.5rem; font-size: .76rem; }
.status-item .form-strip .help { font-size: .78rem; font-family: var(--font); font-weight: 500; }
.fixture-list li { align-items: center; }
.fixture-md { margin-left: auto; font-variant-numeric: tabular-nums; }
.news-ico { flex: none; display: grid; place-items: center; width: 1.6rem; height: 1.6rem; border-radius: 7px;
  color: var(--muted); background: var(--surface-2); border: 1px solid var(--border); margin-top: .05rem; }
.news-ico .ico { width: .9rem; height: .9rem; }
.news-milestone .news-ico { color: var(--gold); }
.news-result .news-ico { color: var(--turf); }
.news-injury .news-ico { color: var(--leather); }
.news-text { display: flex; flex-direction: column; gap: .05rem; min-width: 0; }
.news-md { font-size: .72rem; }
.newsfeed li { align-items: flex-start; }

/* ---- The sides (new campaign): your team and the opponent, the same control
   side by side; the series' length and venue beneath. ---- */
.field-row { display: grid; gap: .6rem 1rem; margin-top: .4rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr)); }
.field-row > div > label { margin-top: 0; }
.career-preview { display: flex; align-items: center; gap: .9rem; margin: 0 0 1rem; padding: .75rem .95rem;
  border-radius: var(--radius-sm); border: 1px solid color-mix(in srgb, var(--team, var(--turf)) 45%, var(--border-2));
  background: linear-gradient(100deg, color-mix(in srgb, var(--team, var(--turf)) 22%, var(--surface)), var(--surface) 70%); }
.career-preview-text { display: flex; flex-direction: column; gap: .05rem; min-width: 0; }
.career-preview-text .eyebrow { margin: 0; }
.career-preview-text strong { font-family: var(--font-display); font-size: 1.15rem; font-weight: 800; }
/* The competition picker is the other big choice — give the select some size. */
.career-form #era { font-weight: 700; padding: .7rem .8rem; }
/* XI editor rows carry a portrait now. */
.pl-row > .portrait { margin-right: .65rem; }


/* ---- The game's dialog ---- */
.dlg { border: 0; padding: 0; background: transparent; max-width: min(92vw, 30rem); width: 100%;
  color: var(--text); }
.dlg::backdrop { background: rgba(3, 8, 5, .66); -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px); }
/* A dialog leaves the way it arrived. Where the engine can animate a closing
   dialog (display/overlay allow-discrete, @starting-style) the card and its
   backdrop fade out; elsewhere it closes at once, as it always did. */
/* (Only where `overlay` itself can be held: an engine that drops the closing
   dialog out of the top layer at once would draw it in the page, unpositioned,
   for the length of the fade.) */
@supports (overlay: auto) {
  @media (prefers-reduced-motion: no-preference) {
    .dlg, .dlg::backdrop { transition: opacity .2s ease, display .2s allow-discrete, overlay .2s allow-discrete; }
    .dlg:not([open]), .dlg:not([open])::backdrop { opacity: 0; }
    @starting-style { .dlg[open], .dlg[open]::backdrop { opacity: 0; } }
  }
}
html[data-reduce-motion="true"] .dlg, html[data-reduce-motion="true"] .dlg::backdrop { transition: none; }
.dlg[open] .dlg-card { animation: pop .22s cubic-bezier(.2,1.2,.4,1) both; }
.dlg-card { background: var(--surface); border: 1px solid var(--border-2); border-radius: var(--radius);
  border-top: 3px solid var(--gold);
  padding: 1.2rem 1.35rem 1.15rem; box-shadow: var(--shadow-lg), inset 0 1px 0 rgba(255,255,255,.05); }
.dlg-kicker { margin: 0 0 .2rem; color: var(--gold); }
.dlg-title { margin: 0 0 .4rem; font-family: var(--font-display); font-size: 1.25rem; font-weight: 900;
  letter-spacing: -.01em; line-height: 1.2; }
.dlg-body { margin: 0 0 1rem; color: var(--muted); font-size: .92rem; line-height: 1.5; }
.dlg-body[hidden] { display: none; }
.dlg-actions { display: flex; gap: .55rem; justify-content: flex-end; flex-wrap: wrap; }
@media (prefers-reduced-motion: reduce) { .dlg[open] .dlg-card, .dlg[open] .pause-card { animation: none; } }

/* ---- The pause menu ----
   MENU on the masthead (Esc, a pad's Start) dims the screen and stacks the
   game's own choices down the middle in the main menu's dress: Resume,
   Settings, Par board, Main menu, Sign out. No card around them — the items
   stand over the dimmed screen the way the main menu's stand over the ground. */
.dlg.pause { max-width: min(92vw, 23rem); }
.dlg.pause::backdrop { background: rgba(3, 8, 5, .74); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); }
.dlg.pause[open] .pause-card { animation: pop .22s cubic-bezier(.2,1.2,.4,1) both; }
.pause-card { display: flex; flex-direction: column; gap: 1.1rem; text-align: center; }
.pause-wordmark { margin: 0; display: flex; justify-content: center; color: var(--faint); }
.pause-title { margin: .1rem 0 0; font-family: var(--font-impact); font-weight: 400; font-size: 2.6rem;
  letter-spacing: .14em; line-height: 1; text-transform: uppercase; text-shadow: 0 10px 34px rgba(0,0,0,.55); }
.pause-menu { text-align: left; }
.pause-menu .key { margin-left: auto; }

/* ---- The advancing veil ---- */
.veil { position: fixed; inset: 0; z-index: 190; display: grid; place-items: center; padding: 1rem;
  background: radial-gradient(70% 70% at 50% 40%, rgba(6, 14, 9, .86), rgba(3, 8, 5, .94));
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); animation: fadeUp .25s both; }
.veil-card { display: flex; flex-direction: column; align-items: center; gap: .55rem; text-align: center;
  max-width: 26rem; }
.veil-mark { display: grid; place-items: center; width: 5rem; height: 5rem; border-radius: 50%;
  background: color-mix(in srgb, var(--club) 18%, var(--surface));
  box-shadow: 0 0 0 6px color-mix(in srgb, var(--club) 25%, transparent), 0 18px 50px rgba(0,0,0,.55);
  animation: veilPulse 1.6s ease-in-out infinite; }
.veil-mark .brand-mark { color: #eef5f0; }
.veil-title { margin: .5rem 0 0; font-family: var(--font-display); font-size: 1.3rem; font-weight: 900;
  letter-spacing: -.01em; color: #eef5f0; }
.veil-sub { margin: 0; color: #a9bcb1; font-size: .9rem; line-height: 1.45; }
.veil-sub[hidden] { display: none; }
.veil-bar { display: block; width: 12rem; height: 3px; border-radius: 3px; overflow: hidden; margin-top: .5rem;
  background: rgba(255,255,255,.1); }
.veil-bar i { display: block; width: 40%; height: 100%; border-radius: 3px;
  background: linear-gradient(90deg, var(--club), var(--turf)); animation: veilBar 1.3s ease-in-out infinite; }
@keyframes veilPulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.05); } }
@keyframes veilBar { 0% { transform: translateX(-100%); } 100% { transform: translateX(260%); } }
.veil.veil--out { animation: veilOut .28s ease both; }
@keyframes veilOut { from { opacity: 1; } to { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .veil, .veil-mark, .veil-bar i { animation: none; } }

/* ---- Toasts, as notifications rather than alerts ---- */
.toasts { top: auto; bottom: 1.1rem; left: 1.1rem; right: auto; max-width: min(400px, 92vw); }
.toast { padding: .7rem .9rem .8rem; border-left: 0; overflow: hidden; align-items: center;
  border: 1px solid var(--border-2); animation: toastIn .3s cubic-bezier(.2,1,.4,1) both;
  box-shadow: var(--shadow-lg), inset 0 1px 0 rgba(255,255,255,.05); }
.toast::after { content: ""; position: absolute; left: 0; bottom: 0; height: 2px; width: 100%;
  background: var(--muted); transform-origin: left; animation: toastLife 5s linear forwards; }
.toast-success::after { background: var(--turf); } .toast-error::after { background: var(--leather); }
.toast-info::after { background: var(--focus); }
.toast-ico { display: grid; place-items: center; width: 1.7rem; height: 1.7rem; border-radius: 8px; flex: none;
  color: var(--muted); background: var(--surface-2); font-size: 1rem; }
.toast-success .toast-ico { color: var(--turf); } .toast-error .toast-ico { color: var(--leather); }
.toast-info .toast-ico { color: var(--focus); }
@keyframes toastLife { from { transform: scaleX(1); } to { transform: scaleX(0); } }
@media (prefers-reduced-motion: reduce) { .toast::after { animation: none; } }
/* A toast that stays until it is dismissed (the browser's autoplay switch,
   game.js): no life bar counting it down. */
.toast--sticky::after { animation: none; }


/* ---- Full time ---- */
.fulltime { margin-bottom: 1.2rem; }
.ft-teams .matchup-side > span { gap: .15rem; }
.ft-score { display: inline-flex; align-items: baseline; gap: .35rem; font-variant-numeric: tabular-nums; }
.ft-score strong { font-family: var(--font-display); font-size: 1.35rem; font-weight: 900; letter-spacing: -.01em; }
.ft-score small { color: var(--muted); font-size: .74rem; }
.matchup-side.is-winner .matchup-name { color: var(--text); }
.matchup-side:not(.is-winner) .ft-score strong { color: var(--muted); }
.ft-result { font-family: var(--font-display); font-size: clamp(1.3rem, 2.6vw, 1.9rem); font-weight: 900;
  letter-spacing: -.02em; margin: .2rem 0 .5rem; display: block; color: var(--gold); }
.ft-result.is-win { color: var(--turf); }
.ft-result.is-loss { color: var(--text); }
.fulltime .match-reaction { margin: 0 0 .9rem; }
.ft-foot { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap;
  padding-top: .8rem; border-top: 1px solid var(--border); }
.ft-pom { display: flex; align-items: center; gap: .7rem; }
.ft-pom .portrait { box-shadow: 0 0 0 3px color-mix(in srgb, var(--gold) 55%, transparent), 0 8px 20px rgba(0,0,0,.35); }
.ft-pom-text { display: flex; flex-direction: column; gap: .05rem; }
.ft-pom-text .label { color: var(--gold); }
.ft-pom-text strong { font-family: var(--font-display); font-size: 1.05rem; font-weight: 800; }
.moments { list-style: none; margin: 0; padding: 0; display: grid; gap: .35rem; }
.moment { display: grid; grid-template-columns: 3.4rem 1fr auto; align-items: center; gap: .7rem;
  padding: .5rem .7rem; border-radius: var(--radius-sm); border: 1px solid var(--border);
  background: var(--surface-2); border-left-width: 4px; }
.moment-wicket { border-left-color: var(--leather); }
.moment-six { border-left-color: var(--gold); }
.moment-milestone { border-left-color: var(--turf); }
.moment-swing { border-left-color: var(--focus); }
.moment-over { font-family: var(--font-display); font-weight: 800; font-variant-numeric: tabular-nums;
  color: var(--muted); }
.moment-text { min-width: 0; font-size: .92rem; }
.moment-text .help { margin-left: .3rem; }
.moment-swing { font-family: var(--font-display); font-weight: 800; font-size: .8rem; padding: .1rem .45rem;
  border-radius: 999px; border: 1px solid var(--border-2); color: var(--muted); }

/* ---- The live match strip ---- */
.mh-title { gap: .45rem; }
.mh-title .crest { filter: drop-shadow(0 3px 4px rgba(0,0,0,.35)); }
.mh-v { font-size: .72em; color: var(--faint); font-weight: 800; padding: 0 .1rem; }
.mh-stage { margin-left: .35rem; align-self: center; }
.mh-btn { gap: .35rem; }
.mh-btn .ico { width: 1rem; height: 1rem; }
.matchup--news { margin-bottom: 1.2rem; }
.matchup-note { margin: -.2rem 0 .8rem; font-size: .88rem; }
.matchup--news .join-controls { margin: .6rem 0 0; }
/* The landing point after a navigation is <main>; it is not a control, and a
   3px ring around the whole view after every screen change reads as a fault. */
main:focus { outline: none; }


/* ---- The live console's full-time card ---- */
.ft-card { text-align: center; }
.ft-card .eyebrow { justify-content: center; display: flex; align-items: center; gap: .3rem; }
.ft-card-teams { display: flex; align-items: center; justify-content: center; gap: .8rem; margin: .4rem 0 .5rem; }
.ft-card-teams .crest { filter: drop-shadow(0 6px 9px rgba(0,0,0,.35)); }
.ft-card-v { font-family: var(--font-display); font-weight: 900; color: var(--faint); }
.ft-card-line { font-family: var(--font-display); font-size: 1.35rem; font-weight: 900; letter-spacing: -.01em;
  margin: 0 0 .3rem; color: var(--gold); }
.ft-card.is-win .ft-card-line { color: var(--turf); }
.ft-card-sub { margin: 0 0 .9rem; }
.ft-card p:last-child { margin-bottom: 0; }
.fixtures .next-match, .next-match { margin-bottom: 1rem; }


/* ---- Leaderboards ---- */
.lb-rank { width: 3rem; }
.lb-name { display: flex; flex-direction: column; gap: .05rem; font-weight: 700; }
.lb-team { display: inline-flex; align-items: center; gap: .3rem; font-weight: 500; font-size: .76rem; }

/* =========================================================================
   How to play — the manual (templates/tutorial/how_to_play.html).
   A system screen over the ground: nine numbered plates, full width — the
   numeral in the wordmark face, nearly not there; a mark; a title in
   display caps; the chapter's prose, in two columns where it is long enough
   to need them — each with the screen it describes a click away, and the
   controls with their key caps at the foot.
   ========================================================================= */
.howto-chapters { display: flex; flex-direction: column; gap: .9rem; margin-bottom: 1.1rem; }
.chapter { margin: 0; overflow: hidden; padding: 1.1rem 1.35rem 1.1rem 1.45rem; }
.chapter::before { content: ""; position: absolute; left: -1px; top: -2px; width: 5px; height: 3rem;
  background: linear-gradient(180deg, var(--turf), var(--turf-d)); transform: skewX(var(--slant));
  transform-origin: top left; }
.howto-chapters .chapter:nth-child(2) { animation-delay: .05s; } .howto-chapters .chapter:nth-child(3) { animation-delay: .1s; }
.howto-chapters .chapter:nth-child(4) { animation-delay: .15s; } .howto-chapters .chapter:nth-child(n+5) { animation-delay: .2s; }
/* The plate's number: big, in the wordmark face, and nearly not there. */
.chapter-num { position: absolute; top: .3rem; right: .85rem; font-family: var(--font-impact); font-size: 3.4rem;
  line-height: 1; letter-spacing: .04em; color: var(--text); opacity: .08; pointer-events: none; user-select: none; }
.chapter-head { display: flex; align-items: center; gap: .8rem; margin-bottom: .75rem; padding-right: 4rem; }
.chapter-mark { flex: none; display: grid; place-items: center; width: 2.1rem; height: 2.1rem; border-radius: 8px;
  color: var(--turf); background: color-mix(in srgb, var(--turf) 14%, transparent); }
.chapter-mark .ico { width: 1.15rem; height: 1.15rem; }
.chapter-title { display: block; margin: 0; padding: 0; border: 0; font-family: var(--font-display); font-size: 1.1rem;
  font-weight: 900; letter-spacing: .02em; text-transform: uppercase; line-height: 1.15; color: var(--text); }
/* The prose: a reading measure, and two columns on a wide screen once a
   chapter is long enough that one column would leave half the plate empty. */
.chapter-prose { max-width: 72ch; }
.chapter-prose p { margin: 0 0 .85rem; font-size: .94rem; line-height: 1.65; color: var(--text); }
.chapter-prose p:last-child { margin-bottom: 0; }
/* Paragraphs may break across the columns, as a printed column does, so the
   two come out level rather than one long and one short. */
@media (min-width: 960px) {
  .chapter-prose.is-long { max-width: none; columns: 2; column-gap: 2.6rem; }
}
.chapter-go { margin: .9rem 0 0; padding-top: .7rem; border-top: 1px solid var(--glass-line); font-size: .86rem; }
.chapter-go .btn-link { font-family: var(--font-display); font-weight: 800; font-size: .78rem; letter-spacing: .08em;
  text-transform: uppercase; }

/* ---- The controls: rows of key caps ---- */
.controls-card { margin-bottom: 1.1rem; }
.howto-keys { display: grid; gap: .55rem; margin: 0; }
.howto-keys-row { display: flex; flex-wrap: wrap; align-items: center; gap: .35rem 1rem; }
.howto-keys dt { flex: 0 0 5.5rem; font-family: var(--font-display); font-weight: 800; font-size: .74rem;
  letter-spacing: .12em; text-transform: uppercase; color: var(--muted); }
.howto-keys dd { margin: 0; display: flex; flex-wrap: wrap; align-items: center; gap: .4rem 1.1rem; min-width: 0; }
.howto-key { display: inline-flex; align-items: center; gap: .45rem; font-size: .88rem; white-space: nowrap; }
/* The caps are the point here: they stay on a touch screen, where .key
   otherwise hides (there is no key to press — but there is one to read about). */
.howto-keys .key { display: inline-grid; margin: 0; font-size: .74rem; }
.howto-key-note { font-size: .88rem; color: var(--text); }
.howto-note { margin: .75rem 0 0; }
.howto-foot { margin: .4rem 0 0; display: flex; justify-content: center; }
@media (max-width: 620px) {
  .howto-keys dt { flex-basis: 100%; }
  .howto-foot .btn { width: 100%; }
}

/* Credits: a kit swatch — the shirt, edged in the trouser colour. */
.kit-swatch { display: inline-block; width: 1.1rem; height: 1.1rem; border-radius: 3px;
  border: 3px solid transparent; margin-right: .3rem; vertical-align: middle;
  box-shadow: 0 0 0 1px rgba(0,0,0,.25) inset; }

/* ---- The break package (breakshow.js): the broadcast graphics over the ground
   during drinks, the innings break and the close. A dark glass panel over the
   picture — the players walking off / the huddle stay visible round it — in the
   DRS overlay's language: display face, gold accent, kit-coloured bars. ---- */
.brk-overlay { position: absolute; inset: 0; z-index: 4; display: flex; flex-direction: column;
  align-items: center; padding: .55rem .7rem .8rem; gap: .4rem; pointer-events: none;
  background: linear-gradient(180deg, rgba(4,9,6,.5), rgba(4,9,6,0) 22%, rgba(4,9,6,0) 60%, rgba(4,9,6,.45));
  opacity: 0; transition: opacity .32s ease; font-family: var(--font-display); color: #eef6f0; }
.brk-overlay.show { opacity: 1; }
.brk-top { display: flex; align-items: center; gap: .7rem; width: min(760px, 96%); font-size: .72rem;
  font-weight: 800; letter-spacing: .12em; text-transform: uppercase; padding-right: 6.4rem; box-sizing: border-box; }
.brk-live { display: inline-flex; align-items: center; gap: .35rem; color: #ffd86b; }
.brk-dot { width: .5rem; height: .5rem; border-radius: 50%; background: #ff5c51;
  box-shadow: 0 0 0 3px rgba(255,92,81,.25); animation: brkPulse 1.2s ease-in-out infinite; }
@keyframes brkPulse { 50% { opacity: .45; } }
.brk-topscore { flex: 1; text-align: center; color: #cfe0d5; letter-spacing: .05em; font-variant-numeric: tabular-nums;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* .75rem, not .68: this is the one control a viewer actually presses during a
   package, and at .68 it was 10.88px — under the 11.5px phone floor the mobile
   audit enforces. It only ever showed mid-break before, so nothing caught it
   until the build-up put a package on screen the moment a match opens. */
.brk-skip { pointer-events: auto; cursor: pointer; font: inherit; font-size: .75rem; letter-spacing: .1em; font-weight: 800;
  color: #eef6f0; background: rgba(255,255,255,.1); border: 1px solid rgba(255,255,255,.22); border-radius: 999px;
  padding: .26rem .8rem; }
.brk-skip:hover { background: rgba(255,255,255,.2); }
.brk-stage { position: relative; width: min(760px, 96%); flex: 1; min-height: 0; display: grid; place-items: center; }
/* A card sizes to its content and sits at the foot of the frame, the way a
   broadcast package does — the ground (the huddle, the walk-off) stays in shot
   above it. The sting alone is centred. */
.brk-card { position: absolute; left: 0; right: 0; bottom: 0; width: 100%; max-height: 100%; overflow: hidden;
  box-sizing: border-box; display: flex; flex-direction: column; padding: .7rem .95rem .8rem; border-radius: 12px;
  background: rgba(7, 13, 10, .93); border: 1px solid rgba(255,255,255,.13); box-shadow: 0 8px 30px rgba(0,0,0,.45);
  opacity: 0; transform: translateY(14px) scale(.985); transition: opacity .26s ease, transform .3s cubic-bezier(.2,.7,.2,1); }
.brk-card.in { opacity: 1; transform: none; }
.brk-card.out { opacity: 0; transform: translateY(-10px) scale(.99); pointer-events: none; transition-duration: .14s, .14s; }
.brk-overlay.brk-reduce, .brk-overlay.brk-reduce .brk-card, .brk-overlay.brk-reduce .brk-dot { transition: none; animation: none; }
.brk-eyebrow { margin: 0; font-size: var(--fs-xs); font-weight: 800; letter-spacing: .16em; text-transform: uppercase; color: #9fb4a7;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.brk-head { margin: .05rem 0 .45rem; font-size: clamp(1rem, 2.2vw, 1.35rem); font-weight: 900; letter-spacing: .01em; color: #fff;
  border-left: 4px solid #ffd86b; padding-left: .55rem; line-height: 1.1; }
.brk-body { flex: 1; min-height: 0; overflow: hidden; }
.brk-title-card { top: 0; bottom: 0; left: 0; right: 0; margin: auto; width: fit-content; min-width: 42%; height: fit-content;
  padding: 1rem 2.6rem 1.1rem; text-align: center; justify-content: center; background: rgba(7,13,10,.82); }
.brk-title-card .brk-head { border: 0; padding: 0; font-family: var(--font-impact); font-weight: 400;
  font-size: clamp(2rem, 7vw, 3.6rem); letter-spacing: .1em; color: #ffd86b; margin: 0; }
.brk-big-score { margin: .3rem 0 0; font-size: clamp(.85rem, 2vw, 1.15rem); font-weight: 800; color: #cfe0d5; letter-spacing: .04em;
  font-variant-numeric: tabular-nums; }
.brk-teams { display: flex; flex-direction: column; gap: .35rem; }
.brk-team-row { display: grid; grid-template-columns: 6px 1fr auto auto; align-items: center; gap: .6rem;
  padding: .3rem .5rem; background: rgba(255,255,255,.05); border-radius: 8px; }
.brk-bar { width: 6px; height: 100%; min-height: 1.6rem; border-radius: 3px; border-right: 2px solid; }
.brk-team { font-weight: 800; font-size: clamp(.8rem, 1.8vw, 1.05rem); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.brk-team em { font-style: normal; font-size: var(--fs-xs); color: #9fb4a7; letter-spacing: .1em; text-transform: uppercase; margin-left: .35rem; }
.brk-runs { font-family: var(--font-impact); font-weight: 400; font-size: clamp(1.3rem, 3.4vw, 2rem); letter-spacing: .03em;
  font-variant-numeric: tabular-nums; line-height: 1; }
.brk-runs small { font-size: max(var(--fs-xs), .55em); color: #cfe0d5; }
.brk-ov { font-size: .72rem; color: #9fb4a7; font-variant-numeric: tabular-nums; min-width: 4.4rem; text-align: right; }
.brk-ov em { font-style: normal; color: #7df0a0; font-size: var(--fs-xs); letter-spacing: .1em; text-transform: uppercase; }
.brk-foot { margin: .5rem 0 0; font-size: .78rem; color: #cfe0d5; }
.brk-foot b { color: #fff; }
.brk-result-line { color: #ffd86b; font-weight: 800; }
.brk-result .brk-head { font-family: var(--font-impact); font-weight: 400; font-size: clamp(1.6rem, 5vw, 2.8rem); letter-spacing: .06em; border-color: #7df0a0; }
.brk-margin { margin: 0; font-size: clamp(.95rem, 2.4vw, 1.4rem); font-weight: 800; color: #fff; padding-left: .6rem; border-left: 4px solid; }
.brk-hero { display: flex; align-items: center; gap: .9rem; }
.brk-face { flex: none; width: 3rem; height: 3rem; border-radius: 50%; overflow: hidden; background: #1c2a22;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.14), 0 3px 8px rgba(0,0,0,.4); }
.brk-face img { display: block; width: 100%; height: 100%; object-fit: cover; }
.brk-face-lg { width: clamp(3.4rem, 9vw, 5.2rem); height: clamp(3.4rem, 9vw, 5.2rem); }
.brk-hero-team { margin: 0; font-size: var(--fs-xs); letter-spacing: .12em; text-transform: uppercase; color: #9fb4a7; }
.brk-hero-figs { margin: 0; font-size: clamp(.9rem, 2.4vw, 1.3rem); font-weight: 800; font-variant-numeric: tabular-nums; }
.brk-hero-figs b { font-family: var(--font-impact); font-weight: 400; font-size: 1.7em; letter-spacing: .03em; color: #ffd86b; vertical-align: -.05em; }
.brk-hero-figs span { color: #cfe0d5; font-size: max(var(--fs-xs), .8em); font-weight: 600; }
.brk-hero-sub { margin: .2rem 0 0; font-size: .74rem; color: #9fb4a7; }
.brk-hero-ww { margin-left: auto; width: clamp(5.5rem, 22%, 8.5rem); }
.brk-men { display: grid; grid-template-columns: 1fr 1fr; gap: .6rem; }
.brk-man { display: flex; align-items: center; gap: .6rem; padding: .45rem .55rem; border-radius: 10px; background: rgba(255,255,255,.05);
  border: 1px solid transparent; min-width: 0; }
.brk-man.is-striker { border-color: rgba(255,216,107,.5); }
.brk-man-txt { min-width: 0; }
.brk-man-name { margin: 0; font-weight: 800; font-size: clamp(.78rem, 1.8vw, .98rem); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.brk-man-name i { font-style: normal; color: #ffd86b; }
.brk-man-figs { margin: .1rem 0 0; font-size: .74rem; color: #cfe0d5; font-variant-numeric: tabular-nums; }
.brk-man-figs b { font-size: 1.25em; color: #fff; }
.brk-man-figs span { color: #9fb4a7; }
.brk-table { width: 100%; border-collapse: collapse; font-size: clamp(var(--fs-xs), 1.5vw, .8rem); font-variant-numeric: tabular-nums; }
.brk-table th { text-align: right; font-size: var(--fs-xs); letter-spacing: .1em; text-transform: uppercase; color: #9fb4a7; font-weight: 800;
  padding: 0 .3rem .25rem; border-bottom: 1px solid rgba(255,255,255,.14); }
.brk-table th:first-child { text-align: left; }
.brk-table td { padding: .17rem .3rem; text-align: right; white-space: nowrap; border-bottom: 1px solid rgba(255,255,255,.05); }
.brk-table td:first-child { text-align: left; overflow: hidden; text-overflow: ellipsis; max-width: 0; width: 46%; }
.brk-table td small { display: block; font-size: max(var(--fs-xs), .78em); color: #9fb4a7; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.brk-table td i { font-style: normal; color: #ffd86b; }
.brk-table tr.is-in td { color: #fff; }
.brk-table tr.is-in td:first-child { color: #ffd86b; }
.brk-table .brk-total td { border-top: 1px solid rgba(255,255,255,.18); border-bottom: 0; padding-top: .3rem; color: #fff; }
.brk-table .brk-total td[colspan] { text-align: right; }
.brk-ytb { font-size: var(--fs-xs); color: #9fb4a7; margin-top: .35rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.brk-svg { display: block; width: 100%; height: auto; max-height: 100%; }
.brk-grid { stroke: rgba(255,255,255,.12); stroke-width: 1; }
.brk-grid-inn { stroke-dasharray: 4 4; stroke: rgba(255,216,107,.5); }
.brk-axis { fill: #9fb4a7; font: 700 11px var(--font-display); }
.brk-bar-o { fill: #4ea1ff; }
.brk-bar-o.is-big { fill: #ffd86b; }
.brk-bar-o.is-tight { fill: #6f8f7c; }
.brk-wkt { fill: #ff5c51; stroke: #fff; stroke-width: 1; }
.brk-fow-line { fill: none; stroke: #ffd86b; stroke-width: 2.4; stroke-linejoin: round; }
.brk-fow-dot { fill: #ff5c51; stroke: #fff; stroke-width: 1.5; }
.brk-fow-score { fill: #fff; font: 800 13px var(--font-display); }
.brk-fow-name { fill: #cfe0d5; font: 700 11px var(--font-display); }
.brk-fow-ov { fill: #9fb4a7; font: 600 10px var(--font-display); }
.brk-pships { display: flex; flex-direction: column; gap: .28rem; }
.brk-pship { display: grid; grid-template-columns: 1.2rem minmax(0, 11rem) 1fr auto; align-items: center; gap: .5rem; font-size: .76rem; }
.brk-pship-n { color: #9fb4a7; font-weight: 800; }
.brk-pship-names { font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.brk-pship-bar { height: .7rem; background: rgba(255,255,255,.08); border-radius: 4px; overflow: hidden; }
.brk-pship-bar i { display: block; height: 100%; background: #4ea1ff; border-radius: 4px; }
.brk-pship-bar i.is-live { background: #7df0a0; }
.brk-pship-runs { font-variant-numeric: tabular-nums; color: #cfe0d5; white-space: nowrap; }
.brk-pship-runs b { color: #fff; }
.brk-phases { display: grid; grid-template-columns: repeat(3, 1fr); gap: .5rem; }
.brk-phase { padding: .5rem .6rem; border-radius: 10px; background: rgba(255,255,255,.05); text-align: center; }
.brk-phase-label { margin: 0; font-size: var(--fs-xs); letter-spacing: .12em; text-transform: uppercase; color: #9fb4a7; font-weight: 800; }
.brk-phase-label small { display: block; letter-spacing: .04em; text-transform: none; font-weight: 600; }
.brk-phase-runs { margin: .15rem 0 0; font-family: var(--font-impact); font-weight: 400; font-size: clamp(1.3rem, 4vw, 2.1rem); letter-spacing: .03em; line-height: 1; }
.brk-phase-runs b { color: #ffd86b; }
.brk-phase-rr { margin: .15rem 0 0; font-size: .72rem; color: #cfe0d5; }
.brk-ww-wrap { display: flex; align-items: center; gap: 1rem; }
.brk-ww { width: clamp(9rem, 38%, 14rem); flex: none; }
.brk-ww-ground { fill: #1f6b3d; stroke: rgba(255,255,255,.6); stroke-width: 1.5; }
.brk-ww-ring { fill: none; stroke: rgba(255,255,255,.28); stroke-width: 1; stroke-dasharray: 3 3; }
.brk-ww-pitch { fill: #cda86b; }
.brk-ww-shot { stroke: rgba(255,255,255,.62); stroke-width: 1.3; }
.brk-ww-shot.is-four { stroke: #7df0a0; stroke-width: 2; }
.brk-ww-shot.is-six { stroke: #ffd86b; stroke-width: 2.3; }
.brk-ww-side { fill: rgba(255,255,255,.55); font: 800 10px var(--font-display); letter-spacing: .12em; }
.brk-ww-legend p { margin: .2rem 0; font-size: .8rem; display: flex; align-items: center; gap: .45rem; }
.brk-ww-legend i { width: 1.1rem; height: 3px; border-radius: 2px; background: rgba(255,255,255,.6); }
.brk-ww-legend i.is-four { background: #7df0a0; }
.brk-ww-legend i.is-six { background: #ffd86b; }
.brk-ww-split { color: #9fb4a7; }
.brk-ww-split b { color: #fff; }
.brk-eq { display: grid; grid-template-columns: repeat(3, 1fr); gap: .5rem; text-align: center; }
.brk-eq div { padding: .45rem .3rem; border-radius: 10px; background: rgba(255,255,255,.05); }
.brk-eq small { display: block; font-size: var(--fs-xs); letter-spacing: .14em; text-transform: uppercase; color: #9fb4a7; font-weight: 800; }
.brk-eq b { display: block; font-family: var(--font-impact); font-weight: 400; font-size: clamp(1.6rem, 5vw, 2.6rem); letter-spacing: .03em; line-height: 1.05; color: #ffd86b; }
.brk-big { margin: 0; font-size: clamp(1rem, 2.6vw, 1.4rem); font-weight: 800; }
.brk-big b { font-family: var(--font-impact); font-weight: 400; font-size: 1.6em; letter-spacing: .03em; color: #ffd86b; }
.brk-big small { color: #9fb4a7; font-size: max(var(--fs-xs), .7em); margin-left: .4rem; }
.brk-bls { display: flex; flex-direction: column; gap: .3rem; }
.brk-bl { display: grid; grid-template-columns: minmax(0, 1fr) auto auto auto; align-items: center; gap: .6rem; font-size: .78rem;
  padding: .25rem .4rem; border-radius: 8px; background: rgba(255,255,255,.05); }
.brk-bl-name { font-weight: 800; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.brk-bl-figs { color: #cfe0d5; font-variant-numeric: tabular-nums; }
.brk-bl-dots { display: inline-flex; gap: .2rem; }
.brk-bl-dots i { width: .55rem; height: .55rem; border-radius: 50%; background: rgba(255,255,255,.18); }
.brk-bl-dots i.is-left { background: #7df0a0; }
.brk-bl-left { color: #9fb4a7; font-size: var(--fs-xs); letter-spacing: .06em; text-transform: uppercase; min-width: 3.4rem; text-align: right; }
.brk-list { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: .3rem; font-size: .8rem; }
.brk-list li small { display: inline-block; min-width: 4.4rem; font-size: var(--fs-xs); letter-spacing: .12em; text-transform: uppercase; color: #9fb4a7; font-weight: 800; }
.brk-list li span { color: #9fb4a7; }
.brk-notes li { padding: .3rem .5rem; background: rgba(255,255,255,.05); border-radius: 8px; line-height: 1.35; }
.brk-wp-line { fill: none; stroke: #ffd86b; stroke-width: 2.4; stroke-linejoin: round; }

/* --- THE BUILD-UP's graphics -------------------------------------------------
   A pre-match show has no scoreline, so its cards are the ones a broadcast
   opens with: the bill, the two team sheets, the table, the form guide, the
   players to watch, the key battles, the head-to-head and the ground. Same
   glass, same eyebrow, same foot as every other card in the package. */
.brk-bill-grid { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: .6rem; }
.brk-bill-side { min-width: 0; display: flex; flex-direction: column; gap: .15rem; }
.brk-bill-side.is-away { text-align: right; align-items: flex-end; }
.brk-bill-team { margin: 0; font-family: var(--font-impact); font-weight: 400; letter-spacing: .02em; line-height: 1.02;
  font-size: clamp(1.1rem, 3.6vw, 2rem); text-transform: uppercase; overflow-wrap: anywhere; }
.brk-bill-cap { margin: 0; font-size: var(--fs-xs); color: #9fb4a7; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
.brk-bill-v { font-family: var(--font-impact); font-weight: 400; color: #ffd86b; font-size: clamp(.9rem, 2.6vw, 1.5rem); }
.brk-bill .brk-bar { width: 2.2rem; height: .28rem; min-height: 0; border-radius: 2px; border-bottom: 2px solid; }
.brk-bill-side.is-away .brk-bar { align-self: flex-end; }
.brk-bill-stake { margin: .35rem 0 0; font-size: .8rem; font-weight: 700; color: #ffd86b; }

.brk-xi { margin: 0; padding: 0; list-style: none; display: grid; grid-template-columns: 1fr 1fr; gap: .1rem .8rem;
  font-size: clamp(var(--fs-xs), 1.5vw, .78rem); }
.brk-xi li { display: grid; grid-template-columns: 1.1rem minmax(0, 1fr) auto; align-items: baseline; gap: .35rem;
  padding: .1rem 0; border-bottom: 1px solid rgba(255,255,255,.05); }
.brk-xi-no { color: #9fb4a7; font-weight: 800; font-variant-numeric: tabular-nums; }
.brk-xi-name { font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.brk-xi-tag { font-style: normal; color: #ffd86b; font-size: max(var(--fs-xs), .82em); font-weight: 800; text-transform: uppercase; }
.brk-xi-hand { font-style: normal; color: #9fb4a7; font-size: max(var(--fs-xs), .8em); }
.brk-xi-role { color: #9fb4a7; font-size: max(var(--fs-xs), .84em); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 7.5rem; }

.brk-form-row { display: grid; grid-template-columns: 2.2rem minmax(0, 1fr) auto; align-items: center; gap: .5rem;
  padding: .28rem 0; border-bottom: 1px solid rgba(255,255,255,.05); }
.brk-form-row .brk-bar { width: 2.2rem; height: .28rem; min-height: 0; border-radius: 2px; border-bottom: 2px solid; }
.brk-form-team { font-weight: 800; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.brk-form-pips { display: inline-flex; gap: .22rem; }
.brk-form-row small { grid-column: 2 / -1; color: #9fb4a7; font-size: var(--fs-xs); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.brk-pip { font-style: normal; display: grid; place-items: center; width: 1.15rem; height: 1.15rem; border-radius: 4px;
  font-size: .62rem; font-weight: 800; background: rgba(255,255,255,.1); color: #cfe0d5; }
.brk-pip.is-win { background: #2f7d4f; color: #fff; }
.brk-pip.is-loss { background: #7d2f2f; color: #fff; }
.brk-pip.is-tie { background: rgba(255,216,107,.25); color: #ffd86b; }

.brk-key-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .4rem .8rem; }
.brk-key { display: flex; align-items: center; gap: .55rem; min-width: 0; }
.brk-key-txt { min-width: 0; }
.brk-key-name { margin: 0; font-weight: 800; font-size: .84rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.brk-key-rank { font-style: normal; color: #ffd86b; font-size: max(var(--fs-xs), .66em); font-weight: 800; text-transform: uppercase; letter-spacing: .08em; }
.brk-key-team { margin: 0; font-size: var(--fs-xs); letter-spacing: .1em; text-transform: uppercase; color: #9fb4a7; }
.brk-key-line { margin: .05rem 0 0; font-size: .72rem; color: #cfe0d5; }

.brk-mu { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: .5rem;
  padding: .3rem 0; border-bottom: 1px solid rgba(255,255,255,.05); }
.brk-mu-side { display: flex; align-items: center; gap: .45rem; min-width: 0; }
.brk-mu-side.is-bat { flex-direction: row-reverse; text-align: right; }
.brk-mu-side p { margin: 0; font-weight: 800; font-size: .8rem; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.brk-mu-side small { display: block; font-weight: 500; font-size: var(--fs-xs); letter-spacing: .08em; text-transform: uppercase; color: #9fb4a7; }
.brk-mu-v { font-family: var(--font-impact); font-weight: 400; color: #ffd86b; }
.brk-mu-line { grid-column: 1 / -1; margin: .1rem 0 0; font-size: .74rem; color: #cfe0d5; font-variant-numeric: tabular-nums; }

.brk-h2h { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: .6rem; text-align: center; }
.brk-h2h-side { min-width: 0; }
.brk-h2h-side .brk-bar { display: block; width: 2.2rem; height: .28rem; min-height: 0; margin: 0 auto .25rem; border-radius: 2px; border-bottom: 2px solid; }
.brk-h2h-side p { margin: 0; font-size: var(--fs-xs); letter-spacing: .08em; text-transform: uppercase; color: #9fb4a7;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.brk-h2h-side b { display: block; font-family: var(--font-impact); font-weight: 400; font-size: clamp(1.6rem, 5vw, 2.6rem);
  line-height: 1.05; color: #ffd86b; }
.brk-h2h-n { font-size: var(--fs-xs); letter-spacing: .1em; text-transform: uppercase; color: #9fb4a7; font-weight: 800; }
.brk-cols { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .2rem .8rem; }

.brk-absent .brk-body { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .3rem .9rem; }
.brk-absent .brk-foot { grid-column: 1 / -1; }
.brk-out-side { min-width: 0; }
.brk-out-side .brk-bar { display: inline-block; width: 1.6rem; height: .24rem; min-height: 0;
  border-radius: 2px; border-bottom: 2px solid; margin-right: .4rem; vertical-align: middle; }
.brk-out-team { font-size: var(--fs-xs); letter-spacing: .1em; text-transform: uppercase; color: #9fb4a7; font-weight: 800; }
.brk-out-list { margin: .25rem 0 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: .25rem; }
.brk-out-list li { display: flex; align-items: center; gap: .45rem; min-width: 0; }
.brk-out-list li .brk-face { width: 1.8rem; height: 1.8rem; filter: grayscale(1) brightness(.8); }
.brk-out-list span { min-width: 0; font-weight: 700; font-size: .78rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.brk-out-list small { display: block; font-weight: 500; font-size: var(--fs-xs); color: #9fb4a7; text-transform: none; letter-spacing: 0; }

/* The table. `.brk-table` left-aligns its FIRST cell only, which here is the
   position — so the team names were pushed to the right of an empty column,
   and the club stripe (a full-height `.brk-bar`, sized for the scoreline card)
   collapsed into a stray vertical tick beside each one. */
.brk-standings th.brk-pos, .brk-standings td.brk-pos { text-align: left; width: 2.2rem; }
.brk-standings th.brk-st-team, .brk-standings td.brk-st-team {
  text-align: left; width: auto; max-width: none; }
.brk-standings td.brk-st-team { display: flex; align-items: center; gap: .45rem; }
.brk-standings td.brk-st-team span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.brk-standings .brk-bar { flex: none; width: .32rem; height: .95rem; min-height: 0;
  border-radius: 2px; border-right: 2px solid; }
.brk-standings tr.is-in td { background: rgba(255,216,107,.08); }
/* A man's SEASON, which is a sentence — not a scoreline. */
.brk-hero-season { margin: 0 0 .15rem; font-size: clamp(.86rem, 2.1vw, 1.1rem);
  font-weight: 800; color: #ffd86b; font-variant-numeric: tabular-nums; }
.brk-hero-note { margin: .2rem 0 0; font-size: .76rem; color: #cfe0d5; line-height: 1.35; }

/* The console is not the captain's until the broadcast hands it over. */
/* (G-54) Waiting, not broken: at .35 the console's own text fell to 2.8:1 on
   its panel and the muted labels to 1.8:1, and the whole toss panel read as
   dead. At .64 the text is 6.9:1 and the muted labels 3.6:1 (the faint key
   hints are decoration) — plainly not yet yours, plainly still there. */
#decision.is-preshow { opacity: .64; filter: saturate(.65); transition: opacity .3s ease, filter .3s ease; }
@media (prefers-reduced-motion: reduce) { #decision.is-preshow { transition: none; } }
@media (max-width: 640px) {
  .brk-overlay { padding: .35rem .4rem .45rem; }
  .brk-card { padding: .5rem .6rem .55rem; }
  .brk-table .brk-sr, .brk-table td small { display: none; }
  .brk-men { grid-template-columns: 1fr; gap: .3rem; }
  .brk-ww-wrap { gap: .5rem; }
  .brk-topscore { display: none; }
  .brk-hero-ww { display: none; }
  .brk-key-grid, .brk-cols, .brk-absent .brk-body { grid-template-columns: 1fr; }
  .brk-xi { gap: .05rem .5rem; font-size: var(--fs-xs); }
  .brk-xi-role { display: none; }
}
/* A phone's ground is a short letterbox (~200px): the package is a compact
   strip there — no eyebrow, a small head, six rows of a card, tight charts.
   Compact means LESS CONTENT, never smaller words: these rules used to shrink
   the type to .6rem (9.6px) to make things fit, which is below the floor
   --fs-xs sets and below what anyone can read on the device the rules exist
   for. When it will not fit, something is dropped — the eyebrow, the role
   column, the rows past six — and what remains stays legible. */
.pitch-wrap.brk-short .brk-eyebrow { display: none; }
.pitch-wrap.brk-short .brk-head { font-size: .92rem; margin: 0 0 .3rem; }
.pitch-wrap.brk-short .brk-card { padding: .4rem .55rem .45rem; }
.pitch-wrap.brk-short .brk-table { font-size: var(--fs-xs); }
.pitch-wrap.brk-short .brk-table td { padding: .1rem .25rem; }
.pitch-wrap.brk-short .brk-table tbody tr:nth-child(n+7):not(.brk-total) { display: none; }
.pitch-wrap.brk-short .brk-ytb, .pitch-wrap.brk-short .brk-foot { display: none; }
.pitch-wrap.brk-short .brk-xi { gap: 0 .5rem; font-size: var(--fs-xs); }
.pitch-wrap.brk-short .brk-xi li { padding: .02rem 0; }
.pitch-wrap.brk-short .brk-xi-role { display: none; }
.pitch-wrap.brk-short .brk-key-grid { grid-template-columns: 1fr; gap: .18rem; }
.pitch-wrap.brk-short .brk-key .brk-face { width: 2.1rem; height: 2.1rem; }
.pitch-wrap.brk-short .brk-key-name { font-size: .76rem; }
.pitch-wrap.brk-short .brk-key-team { font-size: var(--fs-xs); letter-spacing: .08em; }
.pitch-wrap.brk-short .brk-key-line { font-size: var(--fs-xs); line-height: 1.25; }
.pitch-wrap.brk-short .brk-bill-cap { display: none; }
.pitch-wrap.brk-short .brk-team-row { padding: .15rem .4rem; }
.pitch-wrap.brk-short .brk-runs { font-size: 1.25rem; }
.pitch-wrap.brk-short .brk-svg { max-height: 120px; }
.pitch-wrap.brk-short .brk-ww { width: 6.4rem; }
.pitch-wrap.brk-short .brk-phase-runs { font-size: 1.25rem; }
.pitch-wrap.brk-short .brk-eq b { font-size: 1.5rem; }
.pitch-wrap.brk-short .brk-title-card .brk-head { font-size: 1.7rem; }
.pitch-wrap.brk-short .brk-pships { gap: .15rem; }
.pitch-wrap.brk-short .brk-pship { font-size: var(--fs-xs); }
@media (prefers-reduced-motion: reduce) {
  .brk-overlay, .brk-card, .brk-dot { transition: none; animation: none; }
}

/* =========================================================================
   A manager's profile (templates/rankings/manager.html) — the ledger and the
   cabinet, cut the ways a cricket person would cut them. The hero wears the
   tier the way the player hero wears the club; everything below reuses the
   tiles, the data tables, the cabinet shelf and the wins figures.
   ========================================================================= */
.profile-hero { display: grid; grid-template-columns: auto 1fr auto; gap: 1.2rem; align-items: center;
  padding: 1.2rem 1.4rem; margin-bottom: 1.2rem; overflow: hidden; --tier-a: var(--muted); --tier-b: var(--faint);
  background:
    radial-gradient(90% 140% at 0% 50%, color-mix(in srgb, var(--tier-a) 22%, transparent), transparent 60%),
    linear-gradient(180deg, var(--glass-2), var(--glass)); }
.profile-hero::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 5px;
  background: linear-gradient(180deg, var(--tier-a), var(--tier-b)); }
.profile-hero.is-district { --tier-a: var(--text); --tier-b: var(--muted); }
.profile-hero.is-state { --tier-a: var(--turf); --tier-b: var(--turf-d); }
.profile-hero.is-test { --tier-a: var(--gold); --tier-b: #b8860b; }
.profile-hero.is-legend { --tier-a: #6a3df5; --tier-b: #2b1a7a; }
.profile-badge { width: 5.4rem; height: 5.4rem; border-radius: 50%; display: grid; place-items: center;
  font-family: var(--font-display); font-weight: 900; font-size: 2rem; letter-spacing: .02em; color: #fff;
  background: linear-gradient(135deg, var(--tier-a), var(--tier-b));
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--tier-a) 45%, transparent), 0 14px 30px rgba(0,0,0,.4);
  text-shadow: 0 1px 2px rgba(0,0,0,.35); }
.profile-hero.is-none .profile-badge, .profile-hero.is-club .profile-badge { color: var(--text);
  background: linear-gradient(135deg, var(--surface-3), var(--surface-2)); border: 1px solid var(--border-2); }
.profile-hero-text { min-width: 0; }
.profile-hero-text .eyebrow { margin-bottom: .25rem; }
.profile-hero-text h1 { font-size: clamp(1.6rem, 3.2vw, 2.3rem); margin-bottom: .45rem; overflow-wrap: anywhere; }
.profile-hero-text .bc-meta { margin: 0 0 .5rem; align-items: center; }
.metachip.is-gold { border-color: color-mix(in srgb, var(--gold) 55%, transparent); color: var(--gold); }
.metachip.is-gold .ico { color: var(--gold); }
.profile-clubs { display: flex; align-items: center; gap: .35rem; flex-wrap: wrap; margin: 0; }
.profile-clubs .crest { filter: drop-shadow(0 4px 6px rgba(0,0,0,.35)); }
.profile-hero-side { display: flex; flex-direction: column; align-items: flex-end; gap: .6rem; min-width: 10.5rem; }
.profile-figure { display: inline-flex; flex-direction: column; align-items: center; gap: .1rem; }
.profile-figure .wins { font-size: 2.1rem; line-height: 1; }
.profile-figure .label { font-size: .72rem; }
.profile-hero-stats { margin: 0; display: grid; grid-template-columns: 1fr 1fr; gap: .35rem; width: 100%; }
.profile-hero-stats > div { padding: .3rem .55rem; border-radius: var(--radius-sm); border: 1px solid var(--border-2);
  background: var(--surface-2); min-width: 0; text-align: center; }
.profile-hero-stats dt { font-size: .72rem; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  color: var(--faint); white-space: nowrap; }
.profile-hero-stats dd { margin: 0; font-family: var(--font-display); font-size: .98rem; font-weight: 800;
  font-variant-numeric: tabular-nums; white-space: nowrap; }
@media (max-width: 680px) {
  .profile-hero { grid-template-columns: auto 1fr; }
  .profile-hero-side { grid-column: 1 / -1; flex-direction: row; align-items: center; justify-content: space-between; }
  .profile-hero-stats { width: auto; }
}

.profile-grid { display: grid; gap: 1rem; grid-template-columns: minmax(0, 1.45fr) minmax(0, .8fr); align-items: start;
  margin-bottom: 1.1rem; }
.profile-grid > .card, .profile-side > .card:last-child { margin-bottom: 0; }
.profile-side { display: flex; flex-direction: column; gap: 1rem; }
@media (max-width: 900px) { .profile-grid { grid-template-columns: minmax(0, 1fr); } }
.profile-pair { margin-bottom: 1.1rem; grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr)); }
.profile-pair > .card { margin-bottom: 0; }
.profile-meta { margin: .8rem 0 0; }
.profile-foot { margin: .4rem 0 0; }

/* The record: the "all matches" row leads; the first row of each group is set off. */
.splits tr.split-all th, .splits tr.split-all td { font-weight: 800; }
.splits tr.split-t20 th, .splits tr.split-t20 td, .splits tr.split-home th, .splits tr.split-home td,
.splits tr.split-league th, .splits tr.split-league td, .splits tr.split-captained th, .splits tr.split-captained td,
.data-table tr.is-group th, .data-table tr.is-group td { border-top: 1px solid var(--border-2); }

/* Form and streaks. */
.profile-form { margin: 0 0 .7rem; }
.profile-form .form-pip { width: 1.6rem; height: 1.6rem; font-size: .76rem; }
.profile-streaks { margin: 0; display: grid; gap: .45rem; }
.profile-streaks > div { display: flex; align-items: baseline; justify-content: space-between; gap: .8rem; flex-wrap: wrap; }
.profile-streaks dt { color: var(--muted); font-size: .86rem; }
.profile-streaks dd { margin: 0; font-family: var(--font-display); font-weight: 800; font-size: .95rem;
  font-variant-numeric: tabular-nums; text-align: right; }
.profile-streaks dd.crest-cell { font-family: var(--font); font-weight: 700; }

/* Where the value comes from: a bar beside the figure, scaled to the biggest kind. */
.bar-cell { min-width: 9rem; white-space: nowrap; }
.bar { display: inline-block; vertical-align: middle; width: 4.6rem; height: 8px; border-radius: 5px; margin-right: .5rem;
  background: var(--surface-3); overflow: hidden; }
.bar-fill { display: block; height: 100%; border-radius: 5px; background: var(--faint); }
.bar-fill.is-up { background: var(--turf); }
.bar-fill.is-down { background: var(--bad, #d9534f); }

/* What the numbers mean: the glossary behind "What the numbers mean". */
.profile-glossary { margin-bottom: 1.2rem; }
/* Five tabs do not fit a phone in one row, and a tab you cannot see is a tab
   you do not know is there. Wrap rather than scroll them out of sight. */
@media (max-width: 620px) { .profile-tabs > .tablist { flex-wrap: wrap; } }
.gloss { margin: .7rem 0 0; display: grid; gap: .4rem; }
.gloss > div { display: flex; gap: .5rem; flex-wrap: wrap; align-items: baseline; }
.gloss dt { flex: 0 0 9.5rem; font-family: var(--font-display); font-weight: 800; font-size: .8rem;
  letter-spacing: .02em; }
.gloss dd { margin: 0; flex: 1 1 14rem; color: var(--muted); font-size: .86rem; }
@media (max-width: 560px) { .gloss dt { flex-basis: 100%; } }

/* The reading: a word on the face, the sentence on the row's tooltip. */
.reading-list dd { font-family: var(--font-display); }
.reading-list .help { font-family: var(--font); font-weight: 500; }

/* The calls and the nights that made the number. Four cards, always paired —
   auto-fit left a lone orphan on the second row. */
.night-grid { display: grid; gap: 1rem; grid-template-columns: repeat(2, minmax(0, 1fr));
  margin-bottom: 1.1rem; align-items: start; }
.night-grid > .card { margin-bottom: 0; }
@media (max-width: 720px) { .night-grid { grid-template-columns: minmax(0, 1fr); } }
.night-card { border-left: 3px solid var(--border-2); }
.night-card.is-up { border-left-color: var(--turf); }
.night-card.is-down { border-left-color: var(--bad, #d9534f); }
.night-figure { margin: 0 0 .3rem; display: flex; align-items: baseline; gap: .4rem; flex-wrap: wrap; }
.night-figure .wins { font-size: 1.7rem; line-height: 1; }
.night-when { margin: 0; font-family: var(--font-display); font-weight: 800; font-size: 1rem; }
.night-teams { margin: .45rem 0 0; }
.night-meta { margin: .5rem 0 0; }
.night-match { margin: .5rem 0 0; display: flex; align-items: center; gap: .5rem; }
.night-comp { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* .go is display:contents, so the BUTTON is the flex item — and a .btn hides
   its overflow, which lets it shrink under its own label. Pin it. */
.night-match > .go > .btn { flex: none; margin-left: auto; }

/* What you picked against what the analysts had, side by side. */
.call-swap { margin: .5rem 0 0; display: grid; gap: .25rem; }
.call-swap > div { display: flex; gap: .5rem; align-items: baseline; }
.call-swap dt { flex: 0 0 4.6rem; font-size: .68rem; font-weight: 800; letter-spacing: .06em;
  text-transform: uppercase; color: var(--faint); }
.call-swap dd { margin: 0; min-width: 0; font-weight: 700; font-size: .88rem; }
.call-swap > div:last-child dd { font-weight: 500; color: var(--muted); }

/* A card whose head carries a chip beside the title. */
.card > .page-head > .bc-meta, .card > .page-head > .metachip { margin: 0; }

/* Giant-killings and banana skins. */
.upset-list { list-style: none; margin: .6rem 0 0; padding: 0; display: grid; gap: .5rem; }
.upset-list li { display: flex; align-items: center; gap: .75rem; padding: .55rem .7rem;
  border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface-2); }
.upset-odds { flex: none; display: inline-flex; flex-direction: column; align-items: center; min-width: 3.2rem;
  font-family: var(--font-display); font-weight: 900; font-size: 1.25rem; line-height: 1; font-variant-numeric: tabular-nums; }
.upset-odds small { font-family: var(--font); font-weight: 600; font-size: .72rem; color: var(--faint); letter-spacing: .02em; }
.upset-odds.is-up { color: var(--turf); }
.upset-odds.is-down { color: var(--bad, #d9534f); }
.upset-body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: .1rem; }
.upset-body .help { overflow: hidden; text-overflow: ellipsis; }
/* .go is display:contents, so the BUTTON is the flex item — and a .btn hides its
   overflow, which lets it shrink under its own label. Pin it. */
.upset-list li > .go > .btn { flex: none; }

/* Clubs. */
.club-list { list-style: none; margin: 0; padding: 0; display: grid; gap: .5rem; }
.club-row { display: flex; align-items: center; gap: .75rem; padding: .5rem .6rem; border: 1px solid var(--border);
  border-radius: var(--radius-sm); background: var(--surface-2); }
.club-row .crest { filter: drop-shadow(0 4px 6px rgba(0,0,0,.35)); }
.club-body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: .1rem; }
.club-body .help { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.club-rec { flex: none; display: flex; flex-direction: column; align-items: flex-end; gap: .1rem; }
.club-line { font-family: var(--font-display); font-weight: 800; font-size: .92rem; font-variant-numeric: tabular-nums;
  white-space: nowrap; }
.cabinet-head.page-head { margin: 0 0 .6rem; }
.cabinet-head.page-head h2 { margin: 0; }

/* ---- Highlights ---------------------------------------------------------
   The library is a shelf of packages; the player is a video player in the
   game's dress. The picture is deliberately the biggest thing on the screen —
   everything else is chrome around it, the way a broadcast page is built. */

.reel-shelf { list-style: none; margin: 0; padding: 0; display: grid; gap: 1rem;
  grid-template-columns: repeat(auto-fill, minmax(min(310px, 100%), 1fr)); }
.reel-card { display: flex; flex-direction: column; gap: .62rem; margin: 0; height: 100%;
  text-decoration: none; color: inherit; overflow: hidden; padding-top: 1.25rem;
  transition: transform .16s ease, box-shadow .16s ease; }
/* The two clubs as a stripe along the TOP edge only. `border-image` colours the
   whole border box, which put half the away kit down the card's right-hand
   side. */
.reel-card::before { content: ""; position: absolute; inset: 0 0 auto 0; height: 3px;
  background: linear-gradient(90deg, var(--home) 0 50%, var(--away) 50% 100%); }
.reel-card:hover, .reel-card:focus-visible { transform: translateY(-2px);
  box-shadow: var(--shadow-lg), inset 0 1px 0 var(--glass-hi); }
.reel-card.is-mine { outline: 1px solid color-mix(in srgb, var(--club) 42%, transparent); }
.reel-card-top { display: flex; align-items: center; justify-content: space-between; gap: .6rem; }
.reel-card-top .eyebrow { margin: 0; }
.reel-runtime { font-family: var(--font-display); font-weight: 800; font-size: .82rem;
  font-variant-numeric: tabular-nums; color: var(--gold); }
.reel-card-teams { display: flex; align-items: center; gap: .5rem; }
.reel-card-vs { color: var(--faint); font-size: .8rem; }
.reel-card-names { font-family: var(--font-display); font-weight: 800; font-size: 1.02rem;
  margin-left: .25rem; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.reel-card-result { font-size: var(--fs-sm); color: var(--text); }
.reel-card-cta { margin-top: auto; padding-top: .55rem; display: inline-flex; align-items: center;
  gap: .35rem; font-family: var(--font-display); font-weight: 800; font-size: .8rem;
  letter-spacing: .04em; text-transform: uppercase; color: var(--club); }
.reel-card-cta .ico { width: .9rem; height: .9rem; }
.empty-mark .ico { width: 44px; height: 44px; color: var(--faint); }

/* ---- the player ---- */
.reel-stage { position: relative; margin: 0 0 .75rem; border-radius: 14px; overflow: hidden;
  background: #070c09; border: 1px solid rgba(255,255,255,.08);
  box-shadow: 0 6px 26px rgba(0,0,0,.42); }
.reel-ground { display: block; width: 100%; aspect-ratio: 16 / 9; height: auto;
  max-height: min(64vh, 720px); background: #0c1712; }
@supports not (aspect-ratio: 1) { .reel-ground { height: 420px; } }
/* The furniture sits over the ground at exactly its size — the two are
   composited into one frame on export, so they must line up on screen too. */
.reel-overlay { position: absolute; inset: 0; width: 100%; height: 100%;
  pointer-events: none; }
.reel-loading { position: absolute; inset: 0; display: grid; place-items: center; margin: 0;
  color: var(--muted); font-family: var(--font-display); font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase; font-size: .8rem; }
.reel.is-ready .reel-loading, .reel.is-failed .reel-loading { display: none; }

.reel-transport { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
  padding: .6rem .7rem; border-radius: 10px; margin-bottom: .6rem;
  background: var(--chrome); border: 1px solid var(--chrome-line);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px); }
.reel-play { min-width: 7.2rem; }
.btn-icon { padding-inline: .6rem; }
.reel-scrub { flex: 1 1 200px; min-width: 130px; accent-color: var(--club); margin: 0; }
.reel-clock { font-family: var(--font-display); font-weight: 800; font-size: .82rem;
  font-variant-numeric: tabular-nums; color: var(--muted); white-space: nowrap; }
.reel-cuts { display: inline-flex; gap: .25rem; }
.reel-cuts .btn[aria-pressed="true"] { background: var(--club); color: var(--club-ink);
  border-color: transparent; }
.reel-voice { margin: 0 0 .5rem; font-size: var(--fs-sm); color: var(--muted);
  display: flex; align-items: center; gap: .4rem; min-height: 1.2em; }
.reel-voice::before { content: ""; width: .5rem; height: .5rem; border-radius: 50%;
  background: var(--faint); flex: none; }
.reel-voice[data-state="working"]::before { background: var(--gold); }
.reel-voice[data-state="ready"]::before { background: var(--turf); }
.reel-voice[data-state="captioned"]::before { background: var(--leather); }
.reel-voice[data-state="idle"] { display: none; }   /* nothing to say yet */
.reel-status { margin: 0 0 .7rem; font-size: var(--fs-sm); color: var(--text); }
.reel-status.is-bad { color: var(--danger); }

/* ---- the running order ---- */
.reel-order-head { display: flex; align-items: baseline; justify-content: space-between;
  gap: .8rem; margin-bottom: .4rem; }
.reel-order-head h2 { margin: 0; }
.reel-chapters { list-style: none; margin: 0; padding: 0; max-height: 26rem; overflow-y: auto;
  counter-reset: none; }
.reel-chapter { display: grid; grid-template-columns: 3.1rem 6.4rem 1fr; gap: .6rem;
  align-items: baseline; width: 100%; text-align: left; padding: .45rem .5rem;
  background: none; border: 0; border-left: 3px solid transparent; border-radius: var(--radius-sm);
  color: inherit; font: inherit; cursor: pointer; }
.reel-chapter:hover { background: var(--surface-2); }
.reel-chapter.is-now { background: color-mix(in srgb, var(--club) 16%, transparent);
  border-left-color: var(--club); }
.reel-ch-over { font-family: var(--font-display); font-weight: 800; font-size: .78rem;
  font-variant-numeric: tabular-nums; color: var(--gold); }
.reel-ch-tag { font-family: var(--font-display); font-weight: 800; font-size: .74rem;
  letter-spacing: .09em; text-transform: uppercase; color: var(--muted); }
.reel-chapter.reel-show .reel-ch-tag, .reel-chapter.reel-chapter .reel-ch-tag,
.reel-chapter.reel-title .reel-ch-tag { color: var(--club); }
.reel-ch-text { font-size: var(--fs-sm); color: var(--text); min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---- making the file ---- */
.reel-quality { flex: none; width: auto; padding: .3rem .4rem;
  border-radius: var(--radius-sm); font: inherit;
  font-size: .82rem; background: var(--surface-2); color: var(--text);
  border: 1px solid var(--chrome-line); }
/* The render panel stands in for the transport while a package is being written
   to a file: there is nothing to scrub through, and the one control that means
   anything is "stop". */
.reel-render { padding: .7rem .8rem; border-radius: 10px; margin-bottom: .6rem;
  background: var(--chrome); border: 1px solid var(--chrome-line); }
.reel-render-top { display: flex; align-items: center; justify-content: space-between;
  gap: .8rem; margin-bottom: .5rem; }
.reel-render-top strong { font-family: var(--font-display); font-weight: 800;
  letter-spacing: .04em; text-transform: uppercase; font-size: .84rem; }
.reel-render-bar { height: .5rem; border-radius: 99px; overflow: hidden;
  background: var(--surface-2); border: 1px solid var(--chrome-line); }
.reel-render-bar span { display: block; height: 100%; width: 0;
  background: linear-gradient(90deg, var(--club), var(--gold));
  transition: width .3s linear; }
.reel-render .help { margin: .45rem 0 0; }
.reel-rendering .reel-stage { outline: 2px solid var(--club); outline-offset: 2px; }
/* The panel REPLACES the transport rather than sitting under a greyed-out copy
   of it: there is nothing to play, scrub or re-cut while the file is being
   made, and two Cancel buttons is one too many. */
.reel.is-rendering .reel-transport { display: none; }
/* The picture keeps drawing while the file is made — it IS the file being made
   — but it is no longer something to interact with. */
.reel.is-rendering .reel-chapters { opacity: .55; pointer-events: none; }

/* While the file is being recorded the picture must stay on screen and
   undisturbed — a background tab throttles rAF and the capture stalls. */
.reel-exporting .reel-stage { outline: 2px solid var(--leather); outline-offset: 2px; }
#reel-export.is-recording { background: var(--leather); border-color: transparent; color: #fff; }
#reel-export.is-recording .ico { animation: livePulse 1s steps(2) infinite; }
@media (prefers-reduced-motion: reduce) { #reel-export.is-recording .ico { animation: none; } }

@media (max-width: 720px) {
  .reel-ground { aspect-ratio: 16 / 10; max-height: 44vh; }
  .reel-chapter { grid-template-columns: 2.6rem 1fr; }
  .reel-chapter .reel-ch-text { grid-column: 1 / -1; }
  .reel-clock { order: 9; }
  .reel-scrub { flex-basis: 100%; order: 8; }
}

/* ==========================================================================
   G-50 · Use the screen width (the 2026 graphics pass)
   At 1440px a campaign screen was a 1176px column with 132px of floodlights
   either side, and inside it most screens drew ONE thing: a leaderboard with
   the name at the far left and the number at the far right, the next match
   with nothing beside it, a player's attributes with his career hidden behind
   a tab. From 1200px the column takes 94% of the window (capped for very
   wide screens) and those screens split into two columns — player, matches,
   analytics, intel, history, and the rankings (a lobby screen, which opts in
   with `.wide-view`). Below 1200px nothing here changes the layout: `.split`
   is one column, which is the phone's.
   ========================================================================== */
.split { display: grid; gap: 1.1rem 1.25rem; grid-template-columns: minmax(0, 1fr); align-items: start;
  margin-bottom: 1.1rem; }
.split > * { min-width: 0; }
.split > .card, .split > * > .card:last-child, .split > * > .matchup:last-child { margin-bottom: 0; }

/* The player: his career as a board of figures (small caps over a number). */
.career-grid { display: grid; gap: .45rem; margin: 0;
  grid-template-columns: repeat(auto-fill, minmax(min(9.2rem, 100%), 1fr)); }
.career-grid > div { min-width: 0; padding: .5rem .65rem; border-radius: var(--radius-sm);
  display: flex; flex-direction: column; justify-content: space-between;
  background: color-mix(in srgb, var(--surface-2) 55%, transparent); border: 1px solid var(--glass-line); }
.career-grid dt { font-family: var(--font-display); font-size: .72rem; font-weight: 800; letter-spacing: .05em;
  text-transform: uppercase; color: var(--muted); line-height: 1.25; }
.career-grid dd { margin: .1rem 0 0; font-family: var(--font-display); font-size: 1.12rem; font-weight: 800;
  font-variant-numeric: tabular-nums; }
.career-cap { margin: .6rem 0 0; }
/* Three attribute cards in two tracks leave an orphan; it takes the row. */
.player-attrs .grid > .card { margin-bottom: 0; }

/* Matches › Next: your run under the bill, the table beside it. */
.next-main > .next-match { margin-bottom: 1.1rem; }
.run-cols { display: grid; gap: .2rem 1.6rem; grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr)); }
.run-list li { align-items: center; padding: .45rem 0; }
.run-list .crest-cell { flex: none; font-weight: 700; }
.run-list .run-opp { flex: 1 1 auto; min-width: 0; }
.run-opp > span, .run-line { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.run-line { flex: 1; }
.run-list .fixture-md { margin-left: auto; white-space: nowrap; }
.table-compact th, .table-compact td { padding: .48rem .5rem; }
.table-compact thead th { position: static; }
/* Six narrow columns fit a phone: no sideways-scroll floor (see .table-scroll). */
.table-scroll > .data-table.table-compact { min-width: 0; }

/* Analytics: where your own best man stands on each board. */
.your-boards { list-style: none; margin: 0; padding: 0; }
.your-boards li { display: grid; grid-template-columns: minmax(6.5rem, 8.5rem) minmax(0, 1fr) auto; align-items: center;
  gap: .75rem; padding: .6rem 0; border-bottom: 1px solid var(--glass-line); }
.your-boards li:last-child { border-bottom: 0; }
.your-boards .lb-name .help { font-family: var(--font-display); font-weight: 800; color: var(--text);
  font-variant-numeric: tabular-nums; }
.your-rank { font-family: var(--font-display); font-weight: 800; font-size: 1.15rem; white-space: nowrap; }
.your-rank small { font-size: .72rem; font-weight: 600; color: var(--muted); }

/* Intel: the report you pick, read in full. Not drawn below 1200px. */
.intel-detail, .intel-pick { display: none; }
.intel-pick { font-weight: 700; color: var(--text); text-align: left; }
.intel-report-head { display: flex; gap: 1rem; align-items: center; margin-bottom: .9rem; }
.intel-report-who { min-width: 0; }
.intel-report-who h3 { margin: 0; font-family: var(--font-display); font-size: 1.35rem; font-weight: 800; line-height: 1.15; }
.intel-report-lines { display: flex; flex-wrap: wrap; gap: .2rem 1rem; margin: .35rem 0 0; }
.intel-report-lines .ico { color: var(--turf); }
.intel-claim { margin: 0 0 1rem; padding: .7rem .95rem; border-left: 3px solid var(--gold); border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  background: color-mix(in srgb, var(--gold) 8%, transparent); font-size: 1.05rem; line-height: 1.45; }
.intel-meter { display: flex; align-items: center; gap: .7rem; margin-bottom: .8rem; }
.intel-meter .confidence-bar { flex: 1; width: auto; max-width: 16rem; height: .6rem; }
.intel-meter strong { font-family: var(--font-display); font-variant-numeric: tabular-nums; }
.intel-report .bc-meta { margin: 0 0 1rem; }

@media (min-width: 1200px) {
  .app--stage main, .app--lobby main:has(> .wide-view) { max-width: min(94vw, 1760px); }
  .split { grid-template-columns: minmax(0, 1.45fr) minmax(0, 1fr); }
  .player-split { grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr); }
  .player-attrs .grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .player-attrs .grid > .card:nth-child(3):last-child { grid-column: 1 / -1; }
  .player-attrs .attr { grid-template-columns: 6.9rem minmax(0, 1fr) 2rem; }
  .next-split, .intel-split { grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); }
  .rk-split { grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); }
  .rk-split > .explainer { margin-bottom: 0; }
  .intel-detail { display: block; position: sticky; top: .25rem; }
  .intel-split.is-live .intel-pick { display: inline-flex; }
  .intel-split.is-live .intel-name, .intel-split.is-live .col-claim { display: none; }
  .intel-split.is-live tr[data-row] { cursor: pointer; }
  .intel-split.is-live tr.is-picked { background: color-mix(in srgb, var(--turf) 11%, transparent);
    box-shadow: inset 3px 0 0 var(--turf); }
}

/* ==========================================================================
   G-53 · Empty screens and missing charts (the 2026 graphics pass)
   The management side had no charts at all and a new campaign opened on
   screens of dashes. Everything below draws templates/_charts.html, which
   draws services/charts.py.

   COLOUR. Two categorical slots, validated (the dataviz six checks) against
   both themes' chart surfaces — the glass over the ground, #0b100d at night
   and #fbfcfb by day: lightness band, chroma floor, contrast >= 3:1, and a
   colour-blind separation of ΔE 25+ (protan/deutan), so the pair reads for
   everyone. A single series always wears slot 1. Green is NOT a series colour
   here: the turf green means "good" all over this game (money in, a win, a
   rating), and a chart must not borrow a status. Text never wears a series
   colour — labels, values and legends are the text tokens.
   ========================================================================== */
:root {
  --viz-1: #3987e5; --viz-2: #d95926;
  --viz-grid: rgba(255,255,255,.07); --viz-axis: rgba(255,255,255,.22);
  --viz-ring: #0e1411; --viz-soft: rgba(233,241,236,.3);
  --viz-ghost: color-mix(in srgb, #3987e5 38%, transparent);
}
[data-theme="light"] {
  --viz-1: #2a78d6; --viz-2: #eb6834;
  --viz-grid: rgba(20,50,30,.1); --viz-axis: rgba(20,50,30,.28);
  --viz-ring: #fbfcfb; --viz-soft: rgba(20,32,26,.26);
  --viz-ghost: color-mix(in srgb, #2a78d6 32%, transparent);
}
.viz-s1 { --viz-s: var(--viz-1); } .viz-s2 { --viz-s: var(--viz-2); }

.viz { margin: 0; min-width: 0; }
.viz + .viz { margin-top: 1.2rem; }
.viz-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between;
  gap: .3rem 1rem; margin-bottom: .5rem; }
.viz-title { font-family: var(--font-display); font-size: .74rem; font-weight: 800; letter-spacing: .1em;
  text-transform: uppercase; color: var(--muted); }
.viz-legend { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: .2rem 1rem;
  font-size: .82rem; color: var(--muted); }
.viz-legend li { display: inline-flex; align-items: center; gap: .4rem; }
.viz-legend strong { color: var(--text); font-family: var(--font-display); font-variant-numeric: tabular-nums; }
/* The key mirrors the mark: a stroke for a line, a block for bars. */
.viz-key { display: inline-block; width: 16px; height: 3px; border-radius: 2px; background: var(--viz-s); }
.viz--cols .viz-key { width: 10px; height: 10px; border-radius: 2px; }

/* The plot box. Tick labels hang outside it (left and below), as HTML. */
.viz-plot { position: relative; height: var(--viz-h, 12rem); margin: .55rem .4rem 1.8rem 3.2rem; }
.viz-svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.viz-grid, .viz-zero { stroke-width: 1px; vector-effect: non-scaling-stroke; }
.viz-grid { stroke: var(--viz-grid); }
.viz-zero { stroke: var(--viz-axis); }
.viz-stroke { fill: none; stroke: var(--viz-s); stroke-width: 2px; stroke-linejoin: round; stroke-linecap: round;
  vector-effect: non-scaling-stroke; }
.viz-area { fill: var(--viz-s); fill-opacity: .1; stroke: none; }
/* Dots are zero-length strokes with round caps: with a non-scaling stroke they
   stay round however the plot is stretched. The ring is the surface, 2px out. */
.viz-dot, .viz-ring { fill: none; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.viz-dot { stroke: var(--viz-s); stroke-width: 8px; }
.viz-ring { stroke: var(--viz-ring); stroke-width: 12px; }
.viz-yl, .viz-xl, .viz-end { position: absolute; font-size: .72rem; line-height: 1; color: var(--muted);
  font-variant-numeric: tabular-nums; white-space: nowrap; pointer-events: none; }
.viz-yl { right: 100%; margin-right: .5rem; transform: translateY(-50%); }
.viz-xl { top: 100%; margin-top: .5rem; transform: translateX(-50%); }
.viz-end { transform: translate(-100%, -170%); padding-right: .1rem; color: var(--text);
  font-family: var(--font-display); font-weight: 800; font-size: .84rem; }
.viz-end.is-below { transform: translate(-100%, 75%); }
.viz-hcol { position: absolute; top: 0; bottom: 0; }
.viz-cross { position: absolute; top: 0; bottom: 0; left: var(--viz-cx, 0); width: 1px; background: var(--viz-axis);
  opacity: 0; pointer-events: none; }
.viz-plot.is-hover .viz-cross { opacity: 1; }

/* Columns: HTML boxes, so the rounded data-end and the 2px gaps are exact. */
.viz-gl { position: absolute; left: 0; right: 0; height: 1px; background: var(--viz-grid); pointer-events: none; }
.viz-bars { position: absolute; inset: 0; display: flex; align-items: stretch; gap: 2px;
  border-bottom: 1px solid var(--viz-axis); }
.viz-g { flex: 1 1 0; min-width: 0; display: flex; align-items: flex-end; justify-content: center; gap: 2px; }
.viz-b { position: relative; flex: 1 1 0; max-width: 24px; min-width: 1px; background: var(--viz-s);
  border-radius: 4px 4px 0 0; }
.viz-g.is-on .viz-b { filter: brightness(1.2) saturate(1.1); }
.viz-g.is-on { background: var(--viz-grid); }
.viz-ws { position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%); padding-bottom: 3px;
  display: flex; flex-direction: column-reverse; align-items: center; gap: 2px; }
.viz-w { display: block; width: 8px; height: 8px; border-radius: 50%; background: var(--viz-s);
  box-shadow: 0 0 0 2px var(--viz-ring); }

/* Horizontal bars (nominal categories): one hue, the value at the tip. */
.viz-hbars { list-style: none; margin: 0; padding: 0; display: grid; gap: .5rem; }
.viz-hbars li { display: grid; grid-template-columns: minmax(5rem, 44%) minmax(0, 1fr) auto; align-items: center;
  gap: .75rem; font-size: .88rem; }
.viz-hl { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.viz-ht { display: block; height: 10px; }
.viz-hb { display: block; height: 100%; min-width: 2px; background: var(--viz-1); border-radius: 0 4px 4px 0; }
.viz-hv { font-family: var(--font-display); font-weight: 800; font-variant-numeric: tabular-nums; text-align: right;
  white-space: nowrap; }
.viz-hbars .is-other .viz-hb { background: var(--viz-soft); }
.viz-hbars .is-other .viz-hl { color: var(--muted); }
.viz-sub { margin: .9rem 0 .45rem; }
.viz-sub:first-child { margin-top: 0; }

/* A player's form strip: his last six scores, the latest in the accent. */
.viz-form { display: flex; gap: .5rem; align-items: flex-end; flex-wrap: wrap; }
.viz-fi { display: flex; flex-direction: column; align-items: center; gap: .3rem; min-width: 2.1rem; }
.viz-fcol { display: flex; align-items: flex-end; justify-content: center; width: 100%; height: 2.8rem;
  border-bottom: 1px solid var(--viz-axis); }
.viz-fb { display: block; width: 14px; background: var(--viz-soft); border-radius: 4px 4px 0 0; }
.viz-fi.is-last .viz-fb { background: var(--viz-1); }
.viz-fv { font-family: var(--font-display); font-weight: 800; font-size: .84rem; font-variant-numeric: tabular-nums; }
.season-figures { display: flex; flex-wrap: wrap; gap: .4rem 1.4rem; margin: 0 0 1rem; }
.season-figures div { display: flex; flex-direction: column; }
.season-figures dt { font-family: var(--font-display); font-size: .72rem; font-weight: 800; letter-spacing: .06em;
  text-transform: uppercase; color: var(--muted); }
.season-figures dd { margin: 0; font-family: var(--font-display); font-size: 1.2rem; font-weight: 800;
  font-variant-numeric: tabular-nums; }
.season-form { margin-bottom: 1.1rem; }

/* The numbers behind a chart, one tap away. */
.viz-table { margin-top: .35rem; }
.viz-table > summary { display: inline-flex; align-items: center; gap: .35rem; min-height: 24px; cursor: pointer;
  list-style: none; font-size: .8rem; font-weight: 700; color: var(--muted); }
.viz-table > summary::-webkit-details-marker { display: none; }
.viz-table > summary:hover { color: var(--text); }
.viz-table > summary .ico { width: .85rem; height: .85rem; transition: transform .15s; }
.viz-table[open] > summary .ico { transform: rotate(180deg); }
.viz-table table { margin-top: .35rem; font-size: .84rem; }

/* The readout (charts.js). */
.viz-tip { position: fixed; z-index: 95; pointer-events: none; max-width: 19rem; padding: .45rem .65rem;
  border-radius: var(--radius-sm); background: var(--surface-2); border: 1px solid var(--border-2);
  box-shadow: var(--shadow); font-size: .82rem; line-height: 1.35; color: var(--text); }
.viz-tip-head { font-family: var(--font-display); font-weight: 800; margin-bottom: .15rem; }
.viz-tip-row { font-variant-numeric: tabular-nums; }

/* The designed empty state: a faint drawing of what will be here. */
.viz-empty { display: grid; justify-items: center; gap: .2rem; padding: .9rem .5rem 1.1rem; text-align: center; }
.viz-ghost { width: min(13rem, 78%); height: auto; margin-bottom: .55rem; color: var(--viz-ghost); }
.viz-ghost .g-grid { fill: none; stroke: currentColor; stroke-width: 1; opacity: .55; }
.viz-ghost .g-line { fill: none; stroke: currentColor; stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; }
.viz-ghost .g-dot, .viz-ghost .g-bar { fill: currentColor; }
.viz-ghost .g-grid-bar { fill: currentColor; opacity: .55; }
.viz-empty-title { margin: 0; font-family: var(--font-display); font-size: 1rem; font-weight: 800; }
.viz-empty-when { margin: 0; max-width: 36ch; color: var(--muted); font-size: .86rem; }

/* Analytics: a bar against the board's leader, in the row's empty middle. */
/* Every bar starts at the cell's left edge: the number sits in a fixed box to
   its right, so a narrower number cannot shift the bar along. */
.lb-table .lb-val { width: 52%; text-align: left; white-space: nowrap; }
.lb-bar { display: inline-block; vertical-align: middle; width: calc(100% - 4.4rem); height: 8px; margin-right: .6rem; }
.lb-bar .viz-hb { height: 100%; }
.lb-val strong { display: inline-block; width: 3.8rem; text-align: right; vertical-align: middle; }
/* Three columns fit a phone: no sideways-scroll floor, and the number is the
   thing to read there, so the bar gives way to it. */
.table-scroll > .data-table.lb-table { min-width: 0; }
@media (max-width: 560px) {
  .lb-table .lb-val { width: auto; text-align: right; }
  .lb-bar { display: none; }
  .your-boards li { grid-template-columns: minmax(0, 1fr) auto; gap: .35rem .75rem; }
  .your-boards li > .label { grid-column: 1 / -1; }
}

/* Where the charts sit. */
.split > .viz { margin-top: 0; }
.season-split { margin-bottom: 0; }
.season-split .season-form { margin-bottom: 0; }
.overs-split { margin-bottom: 0; }
.fin-split .card { margin-bottom: 0; }
.fin-split > div { display: grid; gap: 1.1rem; }
.titles-card { margin-bottom: 1.1rem; }
@media (pointer: coarse) {
  .viz-table > summary { min-height: 30px; }
}
@media (min-width: 1200px) {
  .overs-split { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .season-split { grid-template-columns: minmax(0, 1fr) minmax(0, 1.7fr); }
}


/* THE REPLAY STINGER (G-41): a panel in the club's colour, its leading edge cut
   at the slant of the PAVILION mark's own stem, with a gold edge, sweeps across
   the picture in 400ms carrying the mark, and covers the cut into (and out of)
   a replay. It covers the whole frame at its midpoint. Decoration only. */
.pitch3d-stinger { position: absolute; inset: 0; z-index: 7; pointer-events: none; overflow: hidden; }
.pitch3d-stinger::before {
  content: ""; position: absolute; top: 0; bottom: 0; left: 0; width: 140%;
  background: linear-gradient(90deg, var(--pf-club, #0d1b2e) 0 91%, #f2b53a 91% 100%);
  clip-path: polygon(0 0, 100% 0, 92% 100%, 0 100%);
  transform: translateX(-100%);
  animation: pv-sting 400ms cubic-bezier(.55, .05, .45, .95) forwards;
}
.pitch3d-stinger svg {
  position: absolute; left: 50%; top: 50%; height: 36%; width: auto;
  transform: translate(-50%, -50%); color: #f3ead6; opacity: 0;
  animation: pv-sting-mark 400ms linear forwards;
}
@keyframes pv-sting { from { transform: translateX(-100%); } to { transform: translateX(72%); } }
@keyframes pv-sting-mark { 0%, 32% { opacity: 0; } 50% { opacity: 1; } 68%, 100% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .pitch3d-stinger { display: none; } }


/* ==========================================================================
   THE SCORE ON THE PICTURE (G-42)
   The bug a broadcast puts over the cricket, bottom left: the batting side
   (its crest and name), the score and the overs, the two batters with the man
   on strike lit, the bowler's figures, the chase (or the rate), this over; the
   speed of the last ball bottom right. Decoration — the scoreboard and the live
   regions carry every fact.
   ========================================================================== */
.pic-bug { position: absolute; left: clamp(.5rem, 1.6%, 1.1rem); bottom: clamp(.5rem, 2.4%, 1rem);
  z-index: 3; display: flex; align-items: stretch; max-width: calc(100% - 1rem);
  pointer-events: none; border-radius: 7px; overflow: hidden;
  background: rgba(6, 10, 8, .84); color: #eef4f0; box-shadow: 0 6px 18px rgba(0, 0, 0, .45);
  font-size: .82rem; line-height: 1; font-variant-numeric: tabular-nums;
  -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px); }
.pic-bug[hidden] { display: none; }
.pic-bug > span { display: flex; align-items: center; gap: .4rem; padding: .42rem .62rem; white-space: nowrap; }
.pic-bug > span + span { border-left: 1px solid rgba(255, 255, 255, .1); }
.pic-bug > span:empty, .pic-bug .pb-bowl:empty, .pic-bug .pb-need:empty { display: none; }
.pb-crest { display: none; }
.pic-bug[data-bat="home"] .pb-crest-home, .pic-bug[data-bat="away"] .pb-crest-away { display: inline-flex; }
.pb-abbr { font-family: var(--font-impact); font-weight: 400; font-size: 1.08rem; letter-spacing: .05em; }
.pb-score { gap: .45rem !important; }
.pb-score b { font-family: var(--font-impact); font-weight: 400; font-size: 1.3rem; letter-spacing: .02em; color: #fff; }
.pb-ov { color: #a9bdb2; font-size: .8rem; }
.pb-bat { display: inline-flex; align-items: baseline; gap: .22rem; color: #b8c7be; }
.pb-bat + .pb-bat { margin-left: .55rem; }
.pb-bat b { color: #fff; font-weight: 800; }
.pb-bat small { color: #8fa498; font-size: .72rem; }
.pb-bat.on { color: #fff; }
.pb-bowl { color: #cdd8d0; }
.pb-need { color: var(--gold, #f2b53a); font-weight: 800; }
.pb-over { gap: .18rem !important; }
.pb-over .ob { min-width: 1.15rem; height: 1.15rem; font-size: .66rem; animation: none; }
.pic-speed { position: absolute; right: clamp(.5rem, 1.6%, 1.1rem); bottom: clamp(.5rem, 2.4%, 1rem);
  z-index: 3; pointer-events: none; padding: .4rem .62rem; border-radius: 7px;
  background: rgba(6, 10, 8, .84); color: #fff; font-family: var(--font-impact);
  font-size: 1.02rem; letter-spacing: .05em; }
.pic-speed[hidden] { display: none; }
/* the supers and the big-moment strap stand above the bug, never on it */
.pitch-wrap .lower-third { bottom: clamp(2.7rem, 9.5%, 3.8rem); }
/* the console drawer's handle: only where there is a stage to give it */
.pitch-console-toggle { display: none; }
@media (min-width: 881px) and (min-height: 560px) {
  .app--match .pitch-console-toggle { display: inline-flex; position: absolute; top: .5rem; right: 6.6rem;
    z-index: 3; align-items: center; gap: .3rem; padding: .28rem .5rem; border-radius: 8px;
    border: 1px solid rgba(255, 255, 255, .16); cursor: pointer; background: rgba(8, 14, 11, .62);
    color: #eaf3ee; font: inherit; font-size: .72rem; font-weight: 700;
    -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px); }
  .app--match .pitch-console-toggle:hover { background: rgba(8, 14, 11, .82); }
  .pitch-console-toggle .ico { width: 1em; height: 1em; }
  .pitch-console-toggle[aria-pressed="true"] .ico-fold,
  .pitch-console-toggle[aria-pressed="false"] .ico-unfold { display: none; }
  /* FOLDED: the ground takes the whole stage */
  body.console-closed .app--match #live-match { grid-template-columns: minmax(0, 1fr) 0; column-gap: 0; }
  body.console-closed .app--match #scoreboard,
  body.console-closed .app--match #decision { display: none; }
}
/* THE PHONE: the picture holds the top of the screen and the scoreboard, the
   console and the commentary scroll under it. */
@media (max-width: 720px) {
  #live-match { display: flex; flex-direction: column; }
  #live-match > .pitch-wrap { order: -1; position: sticky; top: 0; z-index: 20; }
  /* ...and the scoreboard scrolls with the page under it: the score is on the
     picture now, and two sticky headers fought for the top of a small screen */
  #live-match .hud { position: static; }
  .pic-bug { font-size: .74rem; left: .4rem; bottom: .4rem; max-width: calc(100% - .8rem); }
  .pic-bug > span { padding: .34rem .44rem; gap: .28rem; }
  .pb-score b { font-size: 1.08rem; }
  .pic-bug .pb-bowl, .pic-bug .pb-over { display: none; }
  .pic-speed { right: .4rem; bottom: 2.6rem; font-size: .86rem; }
}
@media (prefers-reduced-motion: reduce) { .pb-over .ob { animation: none; } }

/* ==========================================================================
   THE PHONE'S CONSOLE: sections that fold, and a button for the thumb
   --------------------------------------------------------------------------
   Under the ground the console was every chip at once — nine bowlers, eight
   plans, the field and its map, the angle, the ball, the keeper, five captain's
   buttons — about five screens of it, with "Bowl this over" at the far end
   (and its `position: sticky` did nothing: it stuck inside .console-actions,
   a box exactly its own size). So, stacked:
   - each group folds behind ONE row that names it and says what it is set to
     ("PLAN  Full"); a tap opens it (_decision.html cx_head, livematch.js
     paintSections / toggleSection). Folded, the whole over fits under the
     picture; what a captain keeps open is remembered.
   - the button that plays the over is a bar pinned to the foot of the screen,
     where the thumb is, wherever the page is scrolled. The one-button panels
     (toss, review, impact, follow-on, super over) get the same bar.
   Keyed on `#live-match.cx-on` — livematch.js sets it — because without the
   script nothing could open a fold; with no script the groups stay open.
   Beside the ground (the split stage, ≥881px) none of this applies.
   ========================================================================== */
.cx-head { display: none; margin: 0; font: inherit; }
.cx-toggle { display: flex; align-items: center; gap: .65rem; width: 100%; min-height: 48px; margin: 0;
  padding: .55rem .8rem; border: 0; border-radius: inherit; background: none; color: var(--text);
  font: inherit; text-align: left; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.cx-toggle:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }
/* Small caps by the font, not capitals by text-transform: Chrome and WebKit put
   the transformed text in the accessible name, and "BOWLER" is a word some
   voices spell out. */
.cx-name { flex: none; font-size: .9rem; font-weight: 800; letter-spacing: .06em;
  font-variant-caps: all-small-caps; color: var(--muted); }
.cx-val { flex: 1 1 auto; min-width: 0; text-align: right; font-size: .95rem; font-weight: 700;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cx-caret { flex: none; width: 1rem; height: 1rem; color: var(--muted); transition: transform .18s ease; }
.cx.is-open .cx-caret { transform: rotate(180deg); }
@keyframes cxFade { from { opacity: 0; } }
@media (max-width: 880px) {
  #live-match.cx-on .cx-head { display: block; }
  #live-match.cx-on .cx { margin: 0 0 .4rem; border: 1px solid var(--border-2); border-radius: var(--radius-sm);
    background: var(--surface-2); }
  #live-match.cx-on .cx.is-open { border-color: color-mix(in srgb, var(--turf) 45%, var(--border-2)); }
  #live-match.cx-on .cx.is-open .cx-name { color: var(--turf); }
  #live-match.cx-on .cx:not(.is-open) > .cx-body { display: none; }
  #live-match.cx-on .cx > .cx-body { margin: 0; padding: .1rem .8rem .85rem; }
  /* the head names the group, so the group's own label keeps only what it
     adds ("to Prabhsimran Singh · RHB", "max 2 out") */
  #live-match.cx-on .cx-body .tl-name { display: none; }
  #live-match.cx-on .cx-body .tactic-label:not(:has(.facing)),
  #live-match.cx-on .cx-nextover .cx-body > .tactic-label,
  #live-match.cx-on .cx-body .delegate-kicker { display: none; }
  #live-match.cx-on .cx-body .tactic-label-row { justify-content: flex-end; }
  /* the next bowler is information about the over: the gold card it always was */
  #live-match.cx-on .cx-nextover { border-color: color-mix(in srgb, var(--gold) 34%, var(--border-2));
    background: color-mix(in srgb, var(--gold) 7%, var(--surface)); }
  #live-match.cx-on .cx > .next-over { border: 0; background: none; }
  #live-match.cx-on .cx > .delegate-bar { border-top: 0; }
  /* the inset field map sits beside the presets instead of under them */
  #live-match.cx-on .cx .field-picker { min-width: 0; flex: 1 1 8rem; }
  #live-match.cx-on .cx .fd-svg { width: 124px; height: 124px; }
  /* the rows that were always one line take the same dress */
  #live-match.cx-on .stance-group,
  #live-match.cx-on #bat-form > .tactic-label-row { margin: 0 0 .4rem; padding: 0 .8rem;
    border: 1px solid var(--border-2); border-radius: var(--radius-sm); background: var(--surface-2); }
  #live-match.cx-on #bat-form > .tactic-label-row { min-height: 48px; align-items: center; padding-block: .4rem;
    flex-wrap: nowrap; }
  #live-match.cx-on #bat-form > .tactic-label-row select { flex: 0 1 16rem; min-width: 0; }
  /* "Running" over the running chips, inside the section called Running (it
     stays when the session clock sits beside it and the two need telling apart) */
  #live-match.cx-on .cx[data-cx="running"] .fine-item:only-child > .tactic-sublabel { display: none; }
  #live-match.cx-on .stance-more > summary { padding: .85rem 0; }
  #live-match.cx-on .read > summary { min-height: 44px; align-items: center; }

  /* ---- the bar ---- */
  #live-match.cx-on .console-actions,
  #live-match.cx-on .decision-actions {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 45; margin: 0;
    display: flex; align-items: center; gap: .6rem;
    padding: .6rem max(1rem, env(safe-area-inset-right)) max(.6rem, env(safe-area-inset-bottom))
             max(1rem, env(safe-area-inset-left));
    background: color-mix(in srgb, var(--surface) 92%, transparent);
    -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
    border-top: 1px solid var(--border); box-shadow: 0 -12px 28px rgba(0, 0, 0, .45); }
  #live-match.cx-on .console-actions button[type="submit"],
  #live-match.cx-on .decision-actions button[type="submit"] {
    position: static; flex: 1 1 auto; width: auto; min-height: 54px; margin: 0;
    font-size: 1.08rem; box-shadow: 0 6px 18px rgba(0, 0, 0, .35); }
  #live-match.cx-on .console-actions .bbb-toggle { flex: none; margin: 0; min-height: 54px; padding: 0 .75rem;
    display: inline-flex; align-items: center; gap: .45rem; border: 1px solid var(--border-2);
    border-radius: var(--radius-sm); background: var(--surface-2); color: var(--muted);
    font-size: .82rem; font-weight: 700; line-height: 1.15; cursor: pointer; }
  #live-match.cx-on .console-actions .bbb-toggle:has(input:checked) { border-color: var(--turf); color: var(--text); }
  /* the page — the commentary at its foot — scrolls clear of it, and so do the toasts */
  .app--match main:has(#live-match.cx-on .console-actions, #live-match.cx-on .decision-actions) {
    padding-bottom: calc(6.2rem + env(safe-area-inset-bottom)); }
  body:has(#live-match.cx-on .console-actions, #live-match.cx-on .decision-actions) .toasts {
    bottom: calc(6.2rem + env(safe-area-inset-bottom)); }
  /* focus moved by the keyboard (or a screen reader) stops clear of the bar */
  html:has(#live-match.cx-on .console-actions, #live-match.cx-on .decision-actions) {
    scroll-padding-bottom: calc(6.4rem + env(safe-area-inset-bottom)); }
  /* not the captain's yet: the build-up holds the console, and its bar */
  #live-match.cx-on #decision.is-preshow .console-actions,
  #live-match.cx-on #decision.is-preshow .decision-actions { display: none; }
  /* A transform on any ancestor makes it the containing block of a fixed
     element, so a panel that SLID in carried the bar up the page with it for
     the length of the slide. Here the panels fade in, and fill backwards only:
     an effect still filling afterwards would hold the card's layer for good. */
  #live-match.cx-on #decision > .card { animation: cxFade .35s backwards; }
  #live-match.cx-on #decision.panel-in > * { animation-name: cxFade; }
}
/* ...and clear of the picture pinned over the top of a phone (THE PHONE: the
   canvas is the width of <main>'s content, square in portrait, at most half the
   screen; 16:7.4 at most 57% in landscape). */
@media (max-width: 720px) and (orientation: portrait) {
  html:has(#live-match.cx-on) { scroll-padding-top: calc(min(100vw - 1.8rem, 50vh) + .5rem); }
}
@media (max-width: 720px) and (orientation: landscape) {
  html:has(#live-match.cx-on) { scroll-padding-top: calc(min((100vw - 1.8rem) * .4625, 57vh) + .5rem); }
}
@media (max-width: 880px) and (prefers-reduced-motion: reduce) {
  #live-match.cx-on #decision > .card, #live-match.cx-on #decision.panel-in > * { animation: none; }
  .cx-caret { transition: none; }
}

/* The keyboard's hints — a number on every chip, the ⏎ on the button — mean
   nothing to a finger, and on a phone they were most of the clutter on a
   segmented control ("Over¹ Round²"). */
@media (hover: none) {
  .decision-card .chips > .chip::after { content: none; }
  .console-actions .kbd { display: none; }
}

/* The match head on a phone: the two chrome buttons keep their icons and give
   their words to the screen reader alone, so the fixture keeps its line. */
@media (max-width: 560px) {
  .match-head .mh-btn { position: relative; min-width: 44px; justify-content: center; padding-inline: .6rem; }
  .match-head .mh-label { position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
}


/* ==========================================================================
   THE PITCH MAP AND THE BEEHIVE (G-43), on the picture: top left, on glass,
   the strip from behind the bowler with the lengths banded and the batter's
   end face-on. Decoration — every delivery is in the commentary.
   ========================================================================== */
.pitch3d-map { position: absolute; left: clamp(.5rem, 1.6%, 1.1rem); top: clamp(.5rem, 2.4%, 1rem); z-index: 3;
  pointer-events: none; padding: .45rem .55rem .35rem; border-radius: 8px;
  background: rgba(6, 10, 8, .84); box-shadow: 0 6px 18px rgba(0, 0, 0, .45);
  -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px); }
.pitch3d-map[hidden] { display: none; }
.dmap-svg { display: block; width: clamp(16rem, 28vw, 22rem); height: auto; font-family: var(--font-display); }
.dmap-cap { fill: #f3ead6; font-size: 12px; font-weight: 800; letter-spacing: .1em; }
.dmap-sub { fill: #94a89d; font-size: 10px; font-weight: 800; letter-spacing: .12em; }
.dmap-len { fill: #94a89d; font-size: 9px; font-weight: 800; letter-spacing: .06em; }
/* (a phone's picture is too small to carry it: the commentary has every ball) */
@media (max-width: 720px) { .pitch3d-map { display: none !important; } }
.dmap-strip { fill: #b89660; opacity: .35; }
.dmap-band-0 { fill: rgba(255, 255, 255, .05); }
.dmap-band-1 { fill: rgba(0, 0, 0, .12); }
.dmap-stumps, .dmap-stump { fill: #f3ead6; }
.dmap-ground { stroke: rgba(255, 255, 255, .35); stroke-width: 1; }
.dmap-dot { stroke: rgba(0, 0, 0, .55); stroke-width: .8; }
.pitch-map-toggle { display: none; }
@media (min-width: 881px) and (min-height: 560px) {
  .app--match .pitch-map-toggle { display: inline-flex; position: absolute; top: .5rem; right: 12.5rem;
    z-index: 3; align-items: center; gap: .3rem; padding: .28rem .5rem; border-radius: 8px;
    border: 1px solid rgba(255, 255, 255, .16); cursor: pointer; background: rgba(8, 14, 11, .62);
    color: #eaf3ee; font: inherit; font-size: .72rem; font-weight: 700;
    -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px); }
  .app--match .pitch-map-toggle[aria-pressed="true"] { border-color: var(--gold); color: #fff; }
  .pitch-map-toggle .ico { width: 1em; height: 1em; }
}
/* the review over the 3D ground: only the verdict rows, no panel over the picture */
.drs-overlay.drs-3d { background: transparent; -webkit-backdrop-filter: none; backdrop-filter: none; }
.drs-stage-3d .drs-panel, .drs-stage-3d .drs-cap { opacity: 0; }
