/* ============================================================
   TotalOdds — "Broadcast" design system
   Single stylesheet, no build step, no external assets.
   ------------------------------------------------------------
   Palette rules (unchanged in spirit, sharpened in form):
     - Black / dark grey / red / white. Nothing else, apart from
       the amber warning colour and the yellow of a yellow card.
     - Red is the one chromatic accent: brand, interaction, "home",
       "this team's own number". White is the "away" / positive
       highlight; greys are baselines and draws. There is no green
       and no blue anywhere any more.
     - Type: Barlow Condensed (headings, numbers, labels — uppercase,
       italic on display) over Barlow (body). Self-hosted from
       /static/fonts when present, with Arial Narrow / system
       fallbacks so nothing depends on the files being there.
     - Shape: cut-corner cards, skewed tabs/chips/bars, a red slash
       before every heading. Defined once, in the "Broadcast layer"
       at the END of this file, so the older component rules above
       still read as the structural baseline.
   ============================================================ */

/* Barlow -- self-hosted from /static/fonts (WOFF2, TTF fallback). Regular/SemiBold/Bold for
   body copy, Condensed SemiBold/Bold/ExtraBold-Italic for headings and
   labels. There is no Medium file, so weight 500 resolves to Regular. */
@font-face { font-family: "Barlow"; font-weight: 400; font-style: normal; font-display: swap;
    src: url("/static/fonts/Barlow-Regular.woff2") format("woff2"), url("/static/fonts/Barlow-Regular.ttf") format("truetype"), local("Barlow-Regular"), local("Barlow"); }
@font-face { font-family: "Barlow"; font-weight: 600; font-style: normal; font-display: swap;
    src: url("/static/fonts/Barlow-SemiBold.woff2") format("woff2"), url("/static/fonts/Barlow-SemiBold.ttf") format("truetype"), local("Barlow-SemiBold"), local("Barlow SemiBold"); }
@font-face { font-family: "Barlow"; font-weight: 700; font-style: normal; font-display: swap;
    src: url("/static/fonts/Barlow-Bold.woff2") format("woff2"), url("/static/fonts/Barlow-Bold.ttf") format("truetype"), local("Barlow-Bold"), local("Barlow Bold"); }
@font-face { font-family: "Barlow Condensed"; font-weight: 600; font-style: normal; font-display: swap;
    src: url("/static/fonts/BarlowCondensed-SemiBold.woff2") format("woff2"), url("/static/fonts/BarlowCondensed-SemiBold.ttf") format("truetype"), local("BarlowCondensed-SemiBold"), local("Barlow Condensed SemiBold"); }
@font-face { font-family: "Barlow Condensed"; font-weight: 700; font-style: normal; font-display: swap;
    src: url("/static/fonts/BarlowCondensed-Bold.woff2") format("woff2"), url("/static/fonts/BarlowCondensed-Bold.ttf") format("truetype"), local("BarlowCondensed-Bold"), local("Barlow Condensed Bold"); }
@font-face { font-family: "Barlow Condensed"; font-weight: 800; font-style: italic; font-display: swap;
    src: url("/static/fonts/BarlowCondensed-ExtraBoldItalic.woff2") format("woff2"), url("/static/fonts/BarlowCondensed-ExtraBoldItalic.ttf") format("truetype"), local("BarlowCondensed-ExtraBoldItalic"), local("Barlow Condensed ExtraBold Italic"); }

:root {
    /* surfaces */
    --bg:            #08080a;
    --bg-sunken:     #0c0c0f;
    --bg-card:       #111114;
    --bg-card-hover: #18181c;
    --bg-input:      #0c0c0f;
    --bg-tile:       #18181c;

    /* lines */
    --border:        #26262c;
    --border-strong: #34343c;

    /* type */
    --text:          #f5f5f6;
    --text-mid:      #b9b9c1;
    --text-dim:      #8d8d96;

    /* red ramp */
    --red:           #e4162f;
    --red-bright:    #ff4d5e;
    --red-deep:      #9e0f20;
    --red-wash:      rgba(228, 22, 47, 0.13);
    --red-wash-soft: rgba(228, 22, 47, 0.06);
    --red-line:      rgba(228, 22, 47, 0.42);
    --red-glow:      rgba(228, 22, 47, 0.30);

    /* "positive" ramp. Was green. The palette is black / grey / red / white,
       so a good outcome is now WHITE (text, wash, hairline) and a bad one is
       red — which is also why nothing below is named for a colour any more
       than it has to be. The names survive so every existing rule keeps
       working; the Broadcast layer re-points the few that should be red. */
    --green:         #f5f5f6;
    --green-bright:  #ffffff;
    --green-wash:    rgba(255, 255, 255, 0.08);
    --green-line:    rgba(255, 255, 255, 0.30);
    --green-glow:    rgba(255, 255, 255, 0.14);

    /* was blue — the "away side" fill in a comparison bar. Away is white. */
    --blue:          #f4f4f5;

    /* semantic chart colours: home / away / draw, yes / no, over / under */
    --c-home:        var(--red);
    --c-away:        #f4f4f5;
    --c-draw:        #55555d;
    --c-yes:         var(--red);
    --c-no:          #3a3a42;
    --c-over:        var(--red);
    --track:         #1f1f25;

    /* semantics */
    --accent:        var(--red);
    --pos:           #ffffff;
    --neg:           var(--red);
    --warn:          #e8a33d;
    --warn-wash:     rgba(232, 163, 61, 0.10);
    --card-yellow:   #f5c518;

    /* win / draw / lose encoding, used for prob bars, form pills, outcomes */
    --draw:          #55555d;

    /* type stacks */
    --font-display:  "Barlow Condensed", "Arial Narrow", "Helvetica Neue Condensed", "Roboto Condensed", sans-serif;
    --font-body:     "Barlow", ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

    /* shape */
    --radius:        2px;
    --radius-sm:     2px;
    --radius-pill:   2px;
    --cut:           18px;
    --cut-sm:        10px;
    --slant:         -18deg;

    --shadow:        0 1px 0 rgba(255,255,255,0.02) inset;
    --ease:          180ms cubic-bezier(0.4, 0, 0.2, 1);

    /* ------------------------------------------------------------------
       THEME TOKENS (2026-10). Dark is the default and these are exactly the
       literals the stylesheet used to hard-code, so dark mode is unchanged.
       `:root[data-theme="light"]` below redefines them. Never write #fff or a
       dark literal in new CSS: pick the token that says what the colour is FOR.
       ------------------------------------------------------------------ */
    color-scheme: dark;

    /* emphasis text / hover text: white on dark, near-black on light */
    --text-strong:   #ffffff;
    /* text that sits on a red fill (or any other theme-invariant dark fill) */
    --on-red:        #ffffff;
    --on-red-soft:   rgba(255, 255, 255, 0.86);
    /* text that sits on the "away" fill and on the "draw" fill of a bar/pill */
    --on-away:       #0b0b0d;
    --on-draw:       #ffffff;

    /* translucent hover / zebra tints (white-on-dark, ink-on-light) */
    --hover-tint-soft:   rgba(255, 255, 255, 0.035);
    --hover-tint-mid:    rgba(255, 255, 255, 0.05);
    --hover-tint:        rgba(255, 255, 255, 0.07);
    --hover-tint-strong: rgba(255, 255, 255, 0.12);
    --tab-wash:          rgba(228, 22, 47, 0.14);
    --red-deep-wash:     rgba(179, 18, 31, 0.16);
    --border-hover:      #3a3a42;

    /* chrome */
    --topbar-bg:     rgba(8, 8, 10, 0.92);
    --scrim:         rgba(0, 0, 0, 0.6);
    --picker-bg:     #18181c;     /* league picker + theme toggle fill */
    --card-shadow:   none;

    /* floating-surface shadows */
    --shadow-drawer: -8px 0 24px rgba(0, 0, 0, 0.5);
    --shadow-pop:    0 12px 28px rgba(0, 0, 0, 0.45);
    --shadow-popup:  0 12px 32px rgba(0, 0, 0, 0.5);
    --shadow-search: 0 12px 32px rgba(0, 0, 0, 0.65);
    --shadow-tip:    0 8px 24px rgba(0, 0, 0, 0.5);
    --shadow-sticky: 0 -8px 12px -4px rgba(0, 0, 0, 0.5);

    /* club / league badge plate and photo wells */
    --plate-bg:      radial-gradient(circle at 32% 26%, #ffffff 0%, #ececf0 62%, #d5d5dc 100%);
    --plate-ring:    0 0 0 1px rgba(255, 255, 255, 0.10), 0 2px 6px rgba(0, 0, 0, 0.55);
    --photo-well:    var(--bg-sunken);
    --photo-ring:    var(--border);
    --photo-badge-bg: rgba(0, 0, 0, 0.55);
    --photo-text-shadow: 0 1px 3px rgba(0, 0, 0, 0.8);

    /* lineup pitch */
    --pitch-a:       #131317;
    --pitch-b:       #1a1a1f;
    --pitch-line:    rgba(255, 255, 255, 0.40);
    --pitch-mark:    rgba(255, 255, 255, 0.34);
    --pitch-text:    #ffffff;
    --pitch-text-shadow:    0 1px 3px rgba(0, 0, 0, 0.95), 0 0 6px rgba(0, 0, 0, 0.5);
    --pitch-text-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.95);
    --jersey-filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.6));
    --badge-filter:  drop-shadow(0 1px 2px rgba(0, 0, 0, 0.85));
    --sub-red:       #ff6b6b;

    /* availability flags (out / doubtful) */
    --flag-out:        #ff6b6b;
    --flag-out-line:   rgba(255, 107, 107, 0.35);
    --flag-maybe:      #d4c04a;
    --flag-maybe-line: rgba(212, 192, 74, 0.35);

    /* charts */
    --em-tick:       #ffffff;     /* league-average tick on a meter */
    --ring-soft:     rgba(255, 255, 255, 0.11);
    --ring-strong:   rgba(255, 255, 255, 0.30);
    --ring-fill:     rgba(255, 255, 255, 0.025);

    /* glyphs in icons.svg (evg-*): ink and the dark patches on a ball */
    --evg-ink:       #f4f4f5;
    --evg-patch:     #0b0b0d;

    /* form pills: W / D / L */
    --form-w-bg:     var(--red);
    --form-w-fg:     #ffffff;
    --form-d-bg:     #55555d;
    --form-d-fg:     #ffffff;
    --form-l-bg:     #2b2b32;
    --form-l-fg:     #c9c9d0;
}

/* ==========================================================================
   LIGHT THEME TOKENS ("A: Paper": white header and cards on a soft grey page)
   Chosen client-side only: an inline script in <head> sets data-theme="light"
   from localStorage "to_theme" before first paint, app.js flips it. Never
   render it server-side (pages are edge-cached). Dark = no attribute.
   ========================================================================== */
:root[data-theme="light"] {
    color-scheme: light;

    --bg:            #f3f3f5;
    --bg-sunken:     #ececf0;
    --bg-card:       #ffffff;
    --bg-card-hover: #f7f7f9;
    --bg-input:      #ffffff;
    --bg-tile:       #f4f4f6;

    --border:        #dedee4;
    --border-strong: #c9c9d1;

    --text:          #131317;
    --text-mid:      #464650;
    --text-dim:      #686872;

    --red:           #e4162f;
    --red-bright:    #c20e27;     /* red TEXT / links: >= 4.5:1 on white */
    --red-deep:      #9e0f20;
    --red-wash:      rgba(228, 22, 47, 0.08);
    --red-wash-soft: rgba(228, 22, 47, 0.04);
    --red-line:      rgba(228, 22, 47, 0.35);
    --red-glow:      rgba(228, 22, 47, 0.18);

    /* "positive" is near-black on light (white on dark) */
    --green:         #1d1d23;
    --green-bright:  #131317;
    --green-wash:    rgba(19, 19, 23, 0.06);
    --green-line:    rgba(19, 19, 23, 0.25);
    --green-glow:    rgba(19, 19, 23, 0.10);
    --pos:           #131317;

    /* away side + draw + neutral chart colours */
    --blue:          #1d1d23;
    --c-away:        #1d1d23;
    --c-draw:        #a6a6b0;
    --draw:          #a6a6b0;
    --c-no:          #c9c9d1;
    --track:         #e6e6eb;

    --warn:          #a35f00;
    --warn-wash:     rgba(163, 95, 0, 0.10);

    --shadow:        none;
    --card-shadow:   0 1px 2px rgba(20, 20, 30, 0.05);

    --text-strong:   #131317;
    --on-away:       #ffffff;
    --on-draw:       #131317;
    --hover-tint-soft:   rgba(19, 19, 23, 0.035);
    --hover-tint-mid:    rgba(19, 19, 23, 0.05);
    --hover-tint:        rgba(19, 19, 23, 0.06);
    --hover-tint-strong: rgba(19, 19, 23, 0.10);
    --tab-wash:          rgba(228, 22, 47, 0.08);
    --red-deep-wash:     rgba(158, 15, 32, 0.08);
    --border-hover:      #b4b4be;

    --topbar-bg:     rgba(255, 255, 255, 0.94);
    --scrim:         rgba(20, 20, 30, 0.45);
    --picker-bg:     #ffffff;

    --shadow-drawer: -8px 0 24px rgba(20, 20, 30, 0.14);
    --shadow-pop:    0 10px 24px rgba(20, 20, 30, 0.16);
    --shadow-popup:  0 12px 32px rgba(20, 20, 30, 0.20);
    --shadow-search: 0 12px 28px rgba(20, 20, 30, 0.18);
    --shadow-tip:    0 8px 20px rgba(20, 20, 30, 0.16);
    --shadow-sticky: 0 -8px 12px -4px rgba(20, 20, 30, 0.10);

    /* white badges on a white card need the ring to stay defined */
    --plate-bg:      radial-gradient(circle at 32% 26%, #ffffff 0%, #f7f7f9 62%, #e4e4ea 100%);
    --plate-ring:    0 0 0 1px #d3d3da, 0 2px 6px rgba(20, 20, 30, 0.12);
    --photo-well:    #ececf0;
    --photo-ring:    #d3d3da;
    --photo-badge-bg: rgba(255, 255, 255, 0.82);
    --photo-text-shadow: 0 1px 2px rgba(255, 255, 255, 0.9);

    --pitch-a:       #e9e9ed;
    --pitch-b:       #e1e1e6;
    --pitch-line:    rgba(19, 19, 23, 0.25);
    --pitch-mark:    rgba(19, 19, 23, 0.25);
    --pitch-text:    #131317;
    --pitch-text-shadow:    0 1px 2px rgba(255, 255, 255, 0.95), 0 0 5px rgba(255, 255, 255, 0.8);
    --pitch-text-shadow-sm: 0 1px 2px rgba(255, 255, 255, 0.95);
    --jersey-filter: drop-shadow(0 2px 3px rgba(20, 20, 30, 0.28));
    --badge-filter:  drop-shadow(0 1px 1px rgba(255, 255, 255, 0.9));
    --sub-red:       #c20e27;

    --flag-out:        #c20e27;
    --flag-out-line:   rgba(194, 14, 39, 0.35);
    --flag-maybe:      #7a5f00;
    --flag-maybe-line: rgba(122, 95, 0, 0.35);

    --em-tick:       #1d1d23;
    --ring-soft:     rgba(19, 19, 23, 0.12);
    --ring-strong:   rgba(19, 19, 23, 0.30);
    --ring-fill:     rgba(19, 19, 23, 0.03);

    --evg-ink:       #1d1d23;
    --evg-patch:     #f4f4f6;

    /* W stays red (as in dark) so a result never changes meaning with the
       theme; L is the dark pill, D the light grey with dark text. */
    --form-d-bg:     #a6a6b0;
    --form-d-fg:     #131317;
    --form-l-bg:     #1d1d23;
    --form-l-fg:     #ffffff;
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

html { overflow-x: hidden; }

body {
    margin: 0;
    /* `clip`, not `hidden`, on body: `hidden` makes body a scroll container (it
       turns overflow-y into `auto`, and html's own `hidden` stops it
       propagating to the viewport), and a sticky element inside a scroll
       container that never scrolls can never stick. That silently disabled every
       `position: sticky` on the site until the Historic Bets phone bar needed
       one. Same visual clipping; browsers without `clip` keep the old `hidden`. */
    overflow-x: hidden;
    overflow-x: clip;
    font-family: ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    background: var(--bg);
    color: var(--text);
    line-height: 1.55;
    font-size: 15px;
    letter-spacing: -0.006em;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
    min-height: 100vh;
}

::selection { background: var(--red); color: var(--on-red); }

:focus-visible {
    outline: 2px solid var(--red);
    outline-offset: 2px;
    border-radius: 4px;
}

/* thin dark scrollbars so overflow areas don't break the black */
* { scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent; }
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 999px; border: 3px solid var(--bg); }
*::-webkit-scrollbar-thumb:hover { background: var(--border-hover); }

.container {
    max-width: 1120px;
    margin: 0 auto;
    padding: 36px 22px 80px;
}

/* ---------------------------------------------------------- top bar */

/* The whole site header -- topbar and, on pages that have one, the submenu
   under it -- pins as a single block. Stickiness lives here rather than on
   .topbar so the submenu never needs `top` set to the topbar's height, which
   grows by a whole row when the nav wraps below 1100px. */
.site-head {
    /* This was `position: sticky; top: 0`, but it never pinned: body was a
       scroll container (see body's overflow-x), so sticky had nothing to stick
       to. Fixing body would suddenly pin the whole header, three rows of it on a
       phone, so it is held at `relative` here, which is how the site has always
       behaved. Pinning the header is a separate decision: put sticky back (and
       un-stick it on phones, as base.html's comment says) to turn it on. */
    position: relative;
    top: 0;
    z-index: 20;
}

.topbar {
    /* .topbar and .subnav are sibling backdrop-filter elements, and
       backdrop-filter alone (like filter/opacity/transform) creates a new
       stacking context regardless of position -- so without an explicit
       order here, .subnav (later in the DOM, otherwise the same auto
       stacking level) paints over .topbar's *entire* box on plain paint
       order, trapping the league dropdown's own z-index:30 (which only
       competes with siblings inside .topbar's own stacking context) behind
       the subnav bar. Confirmed live: opening the league picker on a
       fixture page hid "Premier League" behind the Odds & Bets tab strip.
       position+z-index here makes the order explicit instead of relying on
       DOM order between two same-level stacking contexts. */
    position: relative;
    z-index: 2;
    background: var(--topbar-bg);
    backdrop-filter: saturate(160%) blur(14px);
    -webkit-backdrop-filter: saturate(160%) blur(14px);
    border-bottom: 1px solid var(--border);
}
/* hairline of brand red across the very top */
.topbar::before {
    content: "";
    display: block;
    height: 2px;
    background: linear-gradient(90deg, var(--red-deep), var(--red) 45%, var(--red-deep));
    opacity: 0.9;
}

.topbar-inner {
    max-width: 1120px;
    margin: 0 auto;
    padding: 12px 22px;
    display: flex;
    align-items: center;
    gap: 18px;
}

.brand {
    display: inline-flex;
    align-items: center;
    text-decoration: none;
    white-space: nowrap;
    opacity: 1;
    transition: opacity var(--ease);
}
.brand:hover { opacity: 0.85; }
.brand-logo {
    display: block;
    height: 26px;
    width: auto;
}

nav {
    display: flex; gap: 4px; flex: 1; align-items: center; min-width: 0;
    /* Safety net for any width where nav's own links don't fit next to the
       search box/league picker/refresh button -- scrolls internally instead
       of overflowing onto (and being painted over by) a sibling. */
    overflow-x: auto; scrollbar-width: none;
}
nav::-webkit-scrollbar { height: 0; }
nav a {
    position: relative;
    color: var(--text-dim);
    text-decoration: none;
    font-size: 0.875rem;
    font-weight: 500;
    padding: 7px 9px;
    border-radius: var(--radius-sm);
    transition: color var(--ease), background var(--ease);
    white-space: nowrap;
}
nav a:hover { color: var(--text); background: var(--bg-card-hover); }
nav a.active { color: var(--text-strong); background: var(--red-wash); }
nav a.active::after {
    content: "";
    position: absolute;
    left: 9px;
    right: 9px;
    bottom: 1px;
    height: 2px;
    border-radius: 2px;
    background: var(--red);
}

/* ------------------------------------------------- page submenu (tabs)

   Second-tier nav rendered into base.html's `subnav` block, directly under
   the topbar and inside the same sticky wrapper. Currently only the fixture
   page uses it, to split one very long page into five sections; the markup
   and the JS behind it (app.js, `.js-tabbar`) are deliberately generic so
   another page can adopt it without a second implementation.

   Every panel is rendered server-side and merely hidden, so all of a
   fixture's content stays in one document on one canonical URL -- switching
   tabs costs no request, and a crawler still sees the lot. */

.subnav {
    /* Explicit, lower than .topbar's (see .topbar's own comment) so the
       league dropdown's stacking context always paints above this bar. */
    position: relative;
    z-index: 1;
    background: var(--bg-card);
    backdrop-filter: saturate(160%) blur(14px);
    -webkit-backdrop-filter: saturate(160%) blur(14px);
    border-bottom: 1px solid var(--border);
}
/* With scripting off nothing can switch panels, so the bar would be five
   dead buttons over a page that already shows everything (see the
   [hidden] override below). Hide it rather than lie about it. */
html:not(.js) .subnav { display: none; }

.subnav-inner {
    max-width: 1120px;
    margin: 0 auto;
    padding: 0 22px;
    display: flex;
    align-items: stretch;
    gap: 2px;
    /* Narrow screens scroll the tabs sideways rather than wrapping them onto
       a second row -- a wrapped tab bar changes height as you switch tabs,
       which shifts the whole page under a sticky header. */
    overflow-x: auto;
    scrollbar-width: none;
    scroll-snap-type: x proximity;
}
.subnav-inner::-webkit-scrollbar { height: 0; }

.subnav-tab {
    position: relative;
    flex: 0 0 auto;
    /* It is a <button>, so opt out of the site's button chrome entirely. */
    background: none;
    border: 0;
    border-radius: 0;
    padding: 12px 14px;
    font-size: 0.85rem;
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--text-mid);
    white-space: nowrap;
    cursor: pointer;
    scroll-snap-align: center;
    transition: color var(--ease), background var(--ease);
}
.subnav-tab:hover { color: var(--text); background: var(--bg-card-hover); }
/* base button:active nudges down 1px -- wrong for a nav row that has to
   sit flush against the topbar above it. */
.subnav-tab:active { transform: none; }
.subnav-tab:focus-visible { outline: 2px solid var(--red); outline-offset: -2px; }
.subnav-tab[aria-selected="true"] { color: var(--text-strong); }
.subnav-tab[aria-selected="true"]::after {
    content: "";
    position: absolute;
    left: 10px;
    right: 10px;
    bottom: 0;
    height: 2px;
    border-radius: 2px 2px 0 0;
    background: var(--red);
}
/* Two labels per tab, one shown at a time via the phone breakpoint below --
   not two rows (see the no-wrap comment on .subnav-inner) but shorter text,
   so more of the strip is legible before a reader needs to scroll it. */
.tab-label-short { display: none; }
/* Panels. The `hidden` attribute is what the JS toggles; this rule only
   exists so that *without* JS every panel stays visible and the page reads
   as one long document, exactly as it did before the tabs existed. */
.tabpanel[hidden] { display: block; }
html.js .tabpanel[hidden] { display: none; }

@media (max-width: 640px) {
    .subnav-inner { padding: 0 10px; gap: 0; }
    .subnav-tab { padding: 11px 11px; font-size: 0.8rem; }
    .subnav-tab[aria-selected="true"]::after { left: 8px; right: 8px; }
    .tab-label-full { display: none; }
    .tab-label-short { display: inline; }
}

/* ------------------------------------------------- mobile nav drawer

   Hamburger + off-canvas panel, phone widths only. The topbar's own <nav>
   and search box stay exactly as they render above 640px; below it they're
   hidden and duplicated inside #mobile-drawer instead (search's own JS
   already wires up every [data-search-kind] element independently, so the
   duplicate needs no JS changes of its own -- see base.html). .nav-toggle
   in the topbar opens it; without JS it's never shown (html:not(.js)
   below), so a no-JS visitor keeps today's scrolling nav/search
   unchanged. */

/* An explicit box (border-box, so this is padding included) rather than
   relying on its content to size it: .ui-icon is width/height:100%, and a
   percentage height only resolves against a parent with a DEFINITE height
   -- against an auto-sized flex button it falls back to the SVG's own
   unstyled intrinsic size (a `viewBox` alone doesn't set one), which
   rendered as a huge icon filling most of the drawer, not the small icon
   this was meant to be. Same fix on the drawer's own .icon-btn below. */
.nav-toggle {
    display: none;
    /* 39px box, 8px padding -> 23px icon, ~15% up from the 20px this
       started at. */
    width: 39px;
    height: 39px;
    background: none;
    border: 0;
    padding: 8px;
    cursor: pointer;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}
html:not(.js) .nav-toggle { display: none !important; }

.nav-backdrop { position: fixed; inset: 0; background: var(--scrim); z-index: 99; }
.nav-backdrop:not([hidden]) { display: block; }

.mobile-drawer {
    position: fixed;
    top: 0; right: 0; bottom: 0;
    width: min(304px, 82vw);
    background: var(--bg-card);
    border-left: 1px solid var(--border);
    box-shadow: var(--shadow-drawer);
    z-index: 100;
    flex-direction: column;
}
.mobile-drawer:not([hidden]) { display: flex; }

.mobile-drawer-head { display: flex; justify-content: flex-end; padding: 6px 8px 0; flex-shrink: 0; }
.mobile-drawer .icon-btn {
    width: 36px;
    height: 36px;
    background: none;
    border: 0;
    padding: 8px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
}
/* app.js moves focus here when the drawer opens (so a keyboard/screen
   reader user lands somewhere sensible) -- but a script-triggered focus()
   reads as "visible" on several mobile browsers the same as a keyboard
   tab, so the sitewide :focus-visible ring (see its own rule near the top
   of this file) showed up as an unwanted red box around the icon the
   instant the drawer opened, tight enough against the search box below to
   look like it was overlapping it. */
.mobile-drawer .icon-btn:focus-visible { outline: none; }

/* Full-width overrides for the duplicated search widget: its dropdown
   panel is a fixed 320px/78vw sized for the full-width topbar (see its own
   comment above) and would spill past this narrower drawer's edge -- and
   off the phone's own screen edge, since the drawer is flush against it --
   without these. Mirrors the same width:100%/max-width:none override this
   file already uses for the topbar's own narrow-layout breakpoint. */
.mobile-drawer .topbar-search-wrap { padding: 2px 16px 14px; border-bottom: 1px solid var(--border); flex-shrink: 0; }
.mobile-drawer .topbar-search,
.mobile-drawer .topbar-search-wrap:focus-within .topbar-search,
.mobile-drawer .topbar-search-wrap:has(.topbar-search-input:not(:placeholder-shown)) .topbar-search { width: 100%; }
.mobile-drawer .topbar-search-panel { width: 100%; max-width: none; }
.mobile-drawer .topbar-search { --search-h: 40px; }

/* flex, not the bare `nav{...}` rule above (a tag selector that predates
   this second <nav> existing) -- overridden here rather than there so the
   topbar's own nav is untouched. */
.mobile-drawer-nav { display: block; flex: 1; min-height: 0; overflow-y: auto; }
.drawer-link {
    display: block;
    padding: 14px 20px;
    border-bottom: 1px solid var(--border);
    color: var(--text-mid);
    text-decoration: none;
    font-size: 0.95rem;
    border-left: 3px solid transparent;
}
.drawer-link.is-current {
    color: var(--text-strong);
    font-weight: 600;
    background: var(--red-wash);
    border-left-color: var(--red);
}

@media (max-width: 640px) {
    html.js .topbar nav[data-nav-league],
    html.js .topbar-inner > .topbar-search-wrap { display: none; }
    /* nav's own flex:1 (desktop) is what pushes search/league-select/toggle
       to the right edge; hidden on a phone, so the same job falls to
       .league-select instead -- everything after it in the row (just
       .nav-toggle) rides along. */
    html.js .league-select { margin-left: auto; }
    html.js .nav-toggle { display: flex; }
}

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

button {
    font: inherit;
    font-size: 0.83rem;
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--text);
    background: var(--bg-card);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    padding: 7px 14px;
    cursor: pointer;
    transition: background var(--ease), border-color var(--ease), color var(--ease), transform var(--ease);
}
button:hover {
    color: var(--text-strong);
    border-color: var(--red-line);
    background: var(--red-wash);
}
button:active { transform: translateY(1px); }

/* ---- league picker + theme toggle (a pair of slanted buttons) -------------
   Both use the house "slanted shape, upright text" recipe: the button itself
   is an upright, transparent box, and ::before carries the fill and border,
   skewed by --slant. The dropdown list hangs from the BOTTOM edge of that
   parallelogram. With skewX(-18deg) about the centre the bottom edge is
   shifted LEFT by (height / 2) * tan(18deg): 5.85px at 36px tall, 6.5px at
   40px. The list is positioned against .league-select (which is exactly the
   trigger's size, because it is a flex container around the one button), so
   `top: 100%; left: -6px; right: 6px` makes it as wide as that bottom edge
   and flush against it. Phone (40px tall) uses -7px / 7px. */
.league-select {
    position: relative;
    flex: 0 0 auto;
    display: flex;
}
.league-select-trigger {
    position: relative;
    isolation: isolate;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    box-sizing: border-box;
    height: 36px;
    min-width: 0;
    max-width: 100%;
    font: inherit;
    font-size: 0.83rem;
    font-weight: 600;
    color: var(--text);
    background: none;
    border: 0;
    border-radius: 0;
    padding: 0 16px 0 12px;
    cursor: pointer;
}
.league-select-trigger::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    transform: skewX(var(--slant));
    background: var(--picker-bg);
    border: 1px solid var(--border-strong);
    transition: border-color var(--ease), background var(--ease);
}
/* beat the generic `button:hover` wash, which would paint a rectangle */
.league-select-trigger:hover,
.league-select-trigger[aria-expanded="true"] { background: none; border: 0; }
.league-select-trigger:hover::before,
.league-select-trigger:focus-visible::before,
.league-select-trigger[aria-expanded="true"]::before { border-color: var(--red); }
.league-select-caret {
    flex: none;
    font-size: 0.7em;
    color: var(--text-dim);
    margin-left: 1px;
}
/* The label cell holds the CURRENT league's name and, invisibly, the longest
   league name, so the trigger (and therefore the dropdown, which is exactly as
   wide as the trigger) is always wide enough for "Premier League" whichever
   league is showing, in any font. Both spans share one grid cell. */
.league-select-label { display: inline-grid; min-width: 0; }
.league-select-label > span {
    grid-area: 1 / 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.league-select-label > .ls-size { visibility: hidden; height: 0; padding-right: 8px; }  /* slack for the active option's tick */
.league-select-list {
    position: absolute;
    top: 100%;
    left: -6px;
    right: 6px;
    width: auto;
    min-width: 0;
    z-index: 30;
    list-style: none;
    margin: 0;
    padding: 0;
    overflow: hidden;           /* keeps the options' washes inside the border */
    background: var(--bg-card);
    border: 2px solid var(--red);
    border-top: 0;              /* the trigger's own bottom edge is the top */
    border-radius: 0;
    box-shadow: var(--shadow-pop);
}
.league-select-option {
    position: relative;
    isolation: isolate;
    display: flex;
    align-items: center;
    gap: 8px;
    white-space: nowrap;
    min-width: 0;
    font-size: 0.83rem;
    font-weight: 600;
    color: var(--text);
    padding: 8px 10px 8px 14px;
    border-radius: 0;
    cursor: pointer;
    /* Now an <a> rather than an <li> -- see base.html: the switcher has to be
       real links so crawlers (and middle-clicks) can follow them. */
    text-decoration: none;
}
.league-select-option > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
/* square wash filling the whole option, edge to edge of the list's inner
   border (the list has no padding), so it sits exactly on the menu line */
.league-select-option::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background: transparent;
    transition: background var(--ease);
}
.league-select-option:hover,
.league-select-option:focus { background: none; outline: none; }
.league-select-option:hover::before,
.league-select-option:focus-visible::before { background: var(--red-wash); }
.league-select-option.active { color: var(--text-strong); }
/* the current league: a stronger red wash than hover, no bar */
.league-select-option.active::before {
    background: color-mix(in srgb, var(--red) 22%, transparent);
}
.league-select-option.active::after {
    content: "\2713";
    margin-left: auto;
    color: var(--red-bright);
}

/* theme toggle: the picker's twin, 44 x 36, sun in dark (switch to light) and
   moon in light. Both icons are in the markup; CSS shows one by theme, so the
   icon is right before app.js has run. Hidden without JS (nothing could flip
   it), exactly like .nav-toggle. */
.theme-toggle {
    position: relative;
    isolation: isolate;
    display: none;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    width: 44px;
    height: 36px;
    padding: 0;
    color: var(--text);
    background: none;
    border: 0;
    border-radius: 0;
    cursor: pointer;
}
html.js .theme-toggle { display: inline-flex; }
.theme-toggle::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    transform: skewX(var(--slant));
    background: var(--picker-bg);
    border: 1px solid var(--border-strong);
    transition: border-color var(--ease), background var(--ease);
}
.theme-toggle:hover { background: none; border: 0; color: var(--text-strong); }
.theme-toggle:hover::before,
.theme-toggle:focus-visible::before { border-color: var(--red); }
.theme-toggle:focus-visible { outline: 2px solid var(--red); outline-offset: 3px; border-radius: 0; }
.theme-toggle .ui-icon { width: 20px; height: 20px; }
.theme-toggle .theme-icon-moon { display: none; }
:root[data-theme="light"] .theme-toggle .theme-icon-sun { display: none; }
:root[data-theme="light"] .theme-toggle .theme-icon-moon { display: block; }

/* ---------------------------------------------------------- headings */

h1 {
    font-size: 1.85rem;
    line-height: 1.2;
    font-weight: 700;
    letter-spacing: -0.03em;
    margin: 0 0 6px;
}
h2 {
    font-size: 1.05rem;
    font-weight: 650;
    letter-spacing: -0.015em;
    margin: 38px 0 14px;
}
.card h2 { margin: 0 0 14px; }
h3 {
    font-size: 0.72rem;
    font-weight: 650;
    margin: 22px 0 10px;
    color: var(--text-dim);
    text-transform: uppercase;
    letter-spacing: 0.09em;
}
.subtitle {
    color: var(--text-dim);
    margin: 0 0 28px;
    font-size: 0.92rem;
    max-width: 68ch;
}

a { color: var(--red); }
a:hover { color: var(--red-bright); }

code {
    font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
    font-size: 0.85em;
    background: var(--bg-card-hover);
    border: 1px solid var(--border);
    border-radius: 5px;
    padding: 1px 5px;
    color: var(--text-mid);
}

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

.card {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 18px 20px;
    margin-bottom: 12px;
    box-shadow: var(--shadow);
    transition: border-color var(--ease), background var(--ease);
}
.card:has(.fixture-row):hover { border-color: var(--border-strong); }

/* ---------------------------------------------------------- fixture rows */

.fixture-row {
    display: grid;
    grid-template-columns: minmax(0, 1.35fr) minmax(0, 320px) minmax(0, 1.15fr);
    align-items: center;
    gap: 20px;
}

.fixture-row > * { min-width: 0; }
.fixture-teams .date {
    color: var(--text-dim);
    font-size: 0.72rem;
    display: block;
    margin-bottom: 3px;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    font-variant-numeric: tabular-nums;
}
.fixture-teams .teams {
    font-weight: 650;
    font-size: 1rem;
    letter-spacing: -0.015em;
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}
.fixture-teams .xg {
    display: block;
    color: var(--text-dim);
    font-size: 0.74rem;
    margin-top: 3px;
    font-variant-numeric: tabular-nums;
}

.probs {
    display: flex;
    flex-wrap: wrap;
    gap: 5px;
    max-width: 360px;
}
.prob-bar { min-width: 64px; }
.prob-bar {
    flex: 1;
    text-align: center;
    border-radius: var(--radius-sm);
    padding: 8px 4px;
    font-size: 0.86rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    border: 1px solid transparent;
    letter-spacing: -0.01em;
}
.prob-bar .label {
    display: block;
    font-size: 0.62rem;
    font-weight: 600;
    opacity: 0.72;
    margin-bottom: 2px;
    text-transform: uppercase;
    letter-spacing: 0.09em;
}
.prob-bar.win { background: var(--green-wash); color: var(--green-bright); border-color: var(--green-line); }
.prob-bar.lose { background: var(--red-wash); color: var(--red-bright); border-color: var(--red-line); }
.prob-bar.neutral { background: var(--hover-tint-soft); color: var(--draw); border-color: var(--border-strong); }
.predicted-score {
    width: 100%;
    text-align: center;
    font-size: 0.72rem;
    color: var(--text-dim);
    letter-spacing: 0.01em;
}
.predicted-score strong {
    color: var(--text);
    font-variant-numeric: tabular-nums;
}

.final-score {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    width: 100%;
}
.final-score .score-line {
    font-size: 1.55rem;
    font-weight: 750;
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
}
.final-score .score-line .win { color: var(--green-bright); }
.final-score .score-line .lose { color: var(--red-bright); }
.final-score .score-line .neutral { color: var(--draw); }

.odds-block {
    font-size: 0.82rem;
    color: var(--text-dim);
    min-width: 0;
    font-variant-numeric: tabular-nums;
}
.odds-block > * { display: block; }
.odds-block .badge-conf { margin-top: 3px; }
.odds-block > a.btn-link { margin-top: 7px; }
.odds-block a.btn-link { font-size: 0.8rem; }
.odds-block .none { color: var(--text-dim); font-style: italic; }
.odds-line strong { color: var(--text); font-weight: 650; }

/* The trailing line of an odds-block card (live badge / freshness badge on
   the left, "Full analysis" on the right) -- a flex row rather than the
   plain inline flow the rest of .odds-block uses, so the link always lands
   at the column's right edge with consistent breathing room instead of
   sitting wherever the preceding inline-block badge happens to end. */
.odds-bottom-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 8px 18px;
    margin-top: 7px;
}
.odds-bottom-row .badge-conf { margin-top: 0; }

/* ---------------------------------------------------------- live panel */

.live-panel { margin-bottom: 22px; }
.live-panel-heading {
    display: flex;
    align-items: center;
    gap: 9px;
    margin: 0 0 12px;
}
.live-dot {
    display: inline-block;
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--red);
    box-shadow: 0 0 8px var(--red-glow);
    animation: live-pulse 1.6s ease-in-out infinite;
    flex: none;
}
@keyframes live-pulse {
    0%, 100% { opacity: 1; transform: scale(1); }
    50% { opacity: 0.45; transform: scale(0.75); }
}
.live-panel-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 12px;
}
.live-card { margin-bottom: 0; }
/* Only a real <a> (the grid panel's cards, linked=true) gets the pointer
   cursor and hover highlight -- a fixture's own page renders this as a plain
   <div> (linked=false), since linking a card to the page it's already on
   would be pointless. */
a.live-card {
    display: block;
    text-decoration: none;
    color: inherit;
    cursor: pointer;
}
a.live-card:hover, a.live-card:focus-visible {
    border-color: var(--red-line);
    background: var(--bg-card-hover);
    box-shadow: 0 0 0 1px var(--red-line), 0 0 18px var(--red-glow);
}
.live-card-top { margin-bottom: 10px; }
.live-badge {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 3px 10px;
    border-radius: var(--radius-pill);
    background: var(--red-wash);
    border: 1px solid var(--red-line);
    color: var(--red-bright);
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    font-variant-numeric: tabular-nums;
}
.live-card-teams {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: 10px;
    color: var(--text);
}
.live-card-team {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    font-weight: 650;
}
/* A name too wide for its half of the card wraps onto a second line at its
   natural word break ("Bolton" / "Wanderers") instead of truncating with an
   ellipsis -- the crest's own align-items: center on the row above keeps it
   centred against the full two-line block, so both sides stay symmetrical
   whether a name wraps or not. */
.live-card-team .team-name {
    overflow-wrap: break-word;
    line-height: 1.15;
}
.live-card-team:last-child { flex-direction: row-reverse; text-align: right; }
.live-card-score {
    font-size: 1.35rem;
    font-weight: 750;
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.live-card-stats {
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    gap: 7px;
}
.live-stat { display: flex; flex-direction: column; gap: 5px; }
.live-stat-row {
    display: grid;
    grid-template-columns: 44px 1fr 44px;
    align-items: center;
    gap: 8px;
    font-size: 0.8rem;
}
.live-stat-val {
    font-weight: 650;
    font-variant-numeric: tabular-nums;
    color: var(--text);
}
.live-stat-val.home { text-align: left; }
.live-stat-val.away { text-align: right; }
.live-stat-label {
    text-align: center;
    color: var(--text-dim);
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
/* Split bar under each stat row: two segments sized to that stat's home/away
   share of the total, so which side has more is visible at a glance without
   reading the numbers. Home is always red (left), away always blue (right)
   -- not a win/lose judgement, just which side of the card each is on. */
.live-stat-bar {
    display: flex;
    height: 4px;
    border-radius: var(--radius-pill);
    overflow: hidden;
    background: var(--border);
}
.bar-seg { display: block; height: 100%; }
.bar-seg.bar-home { background: var(--red); }
.bar-seg.bar-away { background: var(--blue); }
.live-card-events {
    margin-top: 10px;
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.live-event {
    font-size: 0.78rem;
    color: var(--text-mid);
    font-variant-numeric: tabular-nums;
}
/* Scorer sits on the side of the team that scored -- same left=home,
   right=away convention as the score line and stat bars above it. */
.live-event.home { align-self: flex-start; text-align: left; }
.live-event.away { align-self: flex-end; text-align: right; }

/* ---------------------------------------------------------- match report */

/* The fixture page's post-match report is two cards -- Match stats and Key
   events -- in the shared .two-col grid (below), Match stats kept to a
   single column (stat_rows_block's own default layout, no override needed)
   so both panels sit side by side on a wide viewport and stack on a narrow
   one. */

/* Auto-generated two-paragraph write-up (ingest/match_summaries.py) appended
   under the stat rows in the Match stats card -- absent (no heading, no
   placeholder) until that module's own settle-gate produces one for this
   fixture, same convention as every other optional panel on this page. */
.match-summary {
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid var(--border);
}
.match-summary h3 { margin-bottom: 6px; }
.match-summary p {
    font-size: 0.85rem;
    line-height: 1.55;
    color: var(--text-mid);
}
.match-summary p + p { margin-top: 10px; }

/* Key events, sized to match Match stats' own height (app.js::syncKeyEvents
   Height) rather than either card stretching to the other's -- the JS reads
   #match-stats-card's rendered height and caps #key-events-scroll's
   max-height to match it, revealing #key-events-more only when the event
   list is actually taller than that. overflow-y is a static rule here (not
   set from JS) so the list scrolls the instant a max-height is applied;
   padding-right mirrors .live-events-feed's own convention of clearing the
   scrollbar rather than letting it sit flush against the text. Expanding
   removes the cap entirely (see the click handler), which is what makes the
   expand "push out just that panel" -- Match stats was never part of this
   card's own height to begin with. */
.key-events-card { display: flex; flex-direction: column; }
.key-events-scroll {
    overflow-y: auto;
    padding-right: 4px;
}
.key-events-more { align-self: center; margin-top: 10px; }
/* .btn-link sets its own `display: inline-block` -- an author-origin rule,
   which beats the browser's default `[hidden] { display: none }` (user-agent
   origin) regardless of either selector's specificity, since origin is
   compared before specificity in the cascade. Confirmed live: toggling the
   `hidden` property from app.js set the attribute correctly but the button
   stayed rendered (computed display: block) until this override was added.
   Higher specificity than .btn-link alone (two classes vs one) is what lets
   this win within the same author origin. */
.key-events-more[hidden] { display: none; }

/* The standalone /matches/{id} box score (match_detail.html) is a single
   full-width card with no paired events panel next to it, so its stat list
   still gets its own two-column layout at wider viewports -- otherwise
   thirteen rows of stats in one column looks sparse on a 1030px-wide card.

   grid-auto-flow: column (not the grid default, row) plus an explicit row
   count is what makes the list fill top-to-bottom in column 1 before
   starting column 2, rather than the default left-right-left-right zigzag
   every other 2-col grid on this page uses. The row count (7) is
   ceil(13 / 2) for main.py's _LIVE_STAT_DISPLAY_EXTENDED, which is exactly
   what stat_rows always renders (every configured stat gets a row,
   defaulting to 0-0 -- see that list's own comment) -- column 1 gets the
   first 7 stats, column 2 the remaining 6. **Bump this row count if
   _LIVE_STAT_DISPLAY_EXTENDED's length changes**, or the split will land in
   the wrong place (too few rows would wrap a later stat back into column
   1's bottom instead of starting column 2). */
@media (min-width: 700px) {
    .match-report-stats {
        display: grid;
        grid-template-columns: 1fr 1fr;
        grid-auto-flow: column;
        grid-template-rows: repeat(7, auto);
        column-gap: 32px;
        row-gap: 7px;
    }
}

/* ------------------------------------------------- team report stat panels */

/* Ball Stats / Disciplinary-Tackles cards on the fixture page: last-10-games
   aggregates from analysis.team_match_report_stats (Sportmonks match_reports,
   not the live-match feature). Reuses stat_rows_block's existing home/label/
   away row-plus-comparison-bar layout (.live-stat/.live-stat-row/
   .live-stat-bar), but the values here are longer than the live panel's bare
   "58%" -- "512 (51.2 avg)" -- so the side columns need real width instead of
   the live panel's 44px scoreboard slots, and long values wrap instead of
   overflowing their column at a narrow .two-col width. */
.team-report-stats .live-stat-row {
    grid-template-columns: minmax(84px, 112px) 1fr minmax(84px, 112px);
    gap: 6px;
}
.team-report-stats .live-stat-val {
    font-size: 0.78rem;
    min-width: 0;
    overflow-wrap: break-word;
    white-space: normal;
}
.team-report-stats .live-stat-label {
    font-size: 0.68rem;
}
.report-stats-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 8px;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--border);
}
.report-stats-team {
    display: flex;
    align-items: center;
    gap: 6px;
    font-weight: 700;
    font-size: 0.82rem;
    min-width: 0;
}
.report-stats-team.away { flex-direction: row-reverse; }
.report-stats-team .team-code { letter-spacing: 0.03em; }

.match-events {
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.match-event {
    display: grid;
    grid-template-columns: 34px 22px 1fr auto;
    align-items: center;
    gap: 10px;
    padding: 16px 0;
    border-bottom: 1px solid var(--border);
    font-size: 0.86rem;
}
.match-event:last-child { border-bottom: none; }
.match-event-minute {
    color: var(--text-dim);
    font-size: 0.76rem;
    font-variant-numeric: tabular-nums;
}
.match-event-icon { font-size: 1rem; text-align: center; }
.match-event-text { font-weight: 600; min-width: 0; }
.match-event-text .event-player-link,
.live-event .event-player-link {
    color: inherit;
    text-decoration: none;
}
.match-event-text .event-player-link:hover,
.live-event .event-player-link:hover {
    color: var(--accent);
    text-decoration: underline;
}
/* Inline photo-or-initials avatar next to each player name inside an event's
   text (e.g. "[pic] Kevin Schade (Header)", "[pic] Lewis Cook → [pic] Tyler
   Adams") -- same .player-avatar/.player-avatar-initials/.player-photo
   treatment as the squad list and injury panels, just shrunk to a circle
   that fits inline with the event row's own compact text. vertical-align
   keeps it level with the surrounding plain text and arrow rather than
   sitting on the text baseline (an inline-flex child's default). */
.event-player { display: inline-flex; align-items: center; gap: 5px; vertical-align: middle; }
.event-player-avatar { width: 20px; height: 20px; border-radius: 50%; flex: 0 0 auto; }
.event-player-avatar .player-photo,
.event-player-avatar .player-avatar-initials { border-radius: 50%; }
.event-player-avatar .player-avatar-initials { font-size: 0.56rem; }
.match-event-team {
    color: var(--text-dim);
    font-size: 0.76rem;
    white-space: nowrap;
    text-align: right;
}
.match-event-team .crest { width: 28px; height: 28px; margin-right: 4px; }

/* ---------------------------------------------------------- tables */

table {
    width: 100%;
    border-collapse: collapse;
    font-variant-numeric: tabular-nums;
}
th, td {
    text-align: left;
    padding: 11px 10px;
    border-bottom: 1px solid var(--border);
    font-size: 0.86rem;
}
th {
    color: var(--text-dim);
    font-weight: 650;
    font-size: 0.68rem;
    text-transform: uppercase;
    letter-spacing: 0.09em;
    border-bottom-color: var(--border-strong);
    white-space: nowrap;
}
tbody tr { transition: background var(--ease); }
tbody tr:hover { background: var(--hover-tint-soft); }
tbody tr:last-child td { border-bottom: none; }

/* League table zone dividers (Champions League / Europa / Conference /
   Relegation) -- deliberately no colour, just rules and a label; see
   config.TABLE_ZONES. A labelled caption row opens each zone; a plain rule
   with no row of its own marks the return to mid-table after one ends. */
tr.table-zone-caption td {
    padding: 7px 10px;
    background: var(--bg-sunken);
    border-top: 1px solid var(--border-strong);
    border-bottom: 1px solid var(--border-strong);
    font-family: var(--font-display);
    font-size: 0.68rem;
    font-weight: 650;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-dim);
}
tr.table-zone-plain td { border-top: 2px solid var(--border-strong); }

tr.row-home { background: var(--red-wash-soft); box-shadow: inset 2px 0 0 var(--red); }
tr.row-home:hover { background: var(--red-wash); }
tr.row-away { background: var(--green-wash); box-shadow: inset 2px 0 0 var(--green); }
tr.row-away:hover { background: var(--green-wash); }

.stat-table th, .stat-table td { padding: 8px 10px; font-size: 0.82rem; }
/* Side by side, 11 columns of stat data don't fit a 320-550px card at every
   viewport width. The previous fix here (`.stat-table { display:block;
   overflow-x:auto }`) didn't actually work: the base `table { width:100% }`
   rule still applied, and a block box can never overflow ITSELF -- so the
   table just got squeezed to fit its card, silently clipping/overlapping
   the rightmost columns instead of scrolling to reveal them, exactly the
   "data still not visible" report that followed. A wrapper is required: the
   *wrapper* scrolls, the *table* is freed from width:100% so it can render
   at its natural (wider) content width when that's more than the wrapper
   has -- only then does the wrapper have real overflow to scroll through.
   Harmless when the table already fits: min-width:100% just fills the
   available space and nothing overflows, so no scrollbar appears at all. */
.table-scroll {
    max-width: 100%;
    overflow-x: auto;
    scrollbar-width: auto;
    scrollbar-color: var(--text-dim) var(--bg-sunken);
}
.table-scroll::-webkit-scrollbar { height: 10px; }
.table-scroll::-webkit-scrollbar-track { background: var(--bg-sunken); border-radius: 5px; }
.table-scroll::-webkit-scrollbar-thumb { background: var(--text-dim); border-radius: 5px; }
.table-scroll::-webkit-scrollbar-thumb:hover { background: var(--text-mid); }
.stat-table {
    width: auto;
    min-width: 100%;
    white-space: nowrap;
}
.scroll-hint {
    margin: 6px 0 0;
    font-size: 0.74rem;
    color: var(--text-dim);
}

/* Forebet-inspired form/stats comparison card: Overall/Home/Away as columns,
   compact enough to need no horizontal scroll (unlike the old 11-column
   version it replaced). */
.form-stats-card { margin: 4px 0 6px; }
.league-pos { color: var(--text-dim); font-size: 0.82rem; margin: 0 0 12px; }
.recent-match-heading {
    color: var(--text-dim);
    font-size: 0.72rem;
    font-weight: 650;
    text-transform: uppercase;
    letter-spacing: 0.09em;
    margin: 14px 0 8px;
}
.form-mini-table, .venue-stats-table { margin-bottom: 14px; }
.form-mini-table td, .venue-stats-table td { padding: 8px 10px; font-size: 0.82rem; }
.form-mini-table th, .venue-stats-table th { padding: 8px 10px; }
.venue-stats-table th:not(:first-child),
.venue-stats-table td:not(:first-child) {
    text-align: center;
}
.venue-stats-table th.hl,
.venue-stats-table td.hl {
    background: var(--red-wash-soft);
}
.form-fallback-note { margin: -6px 0 14px; }

/* --------------------------------------------------------- sortable tables */

table.js-sortable th[data-sort] {
    cursor: pointer;
    user-select: none;
    padding-right: 18px;
    position: relative;
    transition: color var(--ease);
}
table.js-sortable th[data-sort]:hover { color: var(--text); }
/* The indicator's shape is drawn in the ARROWS block at the end of this file. */
table.js-sortable th[data-sort]::after {
    content: "";
    position: absolute;
    right: 4px;
    top: 50%;
    transform: translateY(-50%);
    opacity: 0.35;
}
table.js-sortable th[data-sort].sort-asc::after,
table.js-sortable th[data-sort].sort-desc::after {
    opacity: 1;
    color: var(--red);
}

/* ---------------------------------------------------------- empty states */

.empty-state {
    text-align: center;
    padding: 52px 24px;
    color: var(--text-dim);
}
.empty-state p { max-width: 56ch; margin-left: auto; margin-right: auto; }
.empty-state .big {
    font-size: 1.9rem;
    margin-bottom: 12px;
    filter: grayscale(1);
    opacity: 0.45;
}

/* ---------------------------------------------------------- footer */

.footer {
    text-align: center;
    color: var(--text-dim);
    font-size: 0.75rem;
    padding: 28px 22px 34px;
    border-top: 1px solid var(--border);
    background: var(--bg-sunken);
}
.footer p { max-width: 74ch; margin: 0 auto; }
.footer p + p { margin-top: 8px; }
.footer-legal { margin-top: 14px; font-size: 0.76rem; }
.footer-legal a { color: var(--text-dim); }
.footer-legal a:hover { color: var(--text); }

/* ---------------------------------------------------------- small type */

.badge-conf {
    font-size: 0.74rem;
    color: var(--text-dim);
    display: inline-block;
    font-variant-numeric: tabular-nums;
}
.badge-conf.warn { color: var(--warn); }

.muted { color: var(--text-dim); font-size: 0.82rem; }
.pos { color: var(--pos); font-weight: 650; }
.neg { color: var(--neg); font-weight: 650; }
.rowlabel { color: var(--text-mid); white-space: nowrap; }

.btn-link {
    display: inline-block;
    color: var(--red);
    text-decoration: none;
    font-size: 0.83rem;
    font-weight: 650;
    transition: color var(--ease);
}
.btn-link:hover { color: var(--red-bright); text-decoration: underline; text-underline-offset: 3px; }
button.btn-link { background: none; border: none; padding: 0; font: inherit; font-weight: 650; cursor: pointer; }

td a, .fixture-teams a.teams { color: var(--text); text-decoration: none; transition: color var(--ease); }
td a:hover, .fixture-teams a.teams:hover { color: var(--red-bright); }

/* ---------------------------------------------------------- toolbar / chips */

.toolbar {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    margin-bottom: 24px;
    padding-bottom: 18px;
    border-bottom: 1px solid var(--border);
}
.chip {
    display: inline-block;
    padding: 5px 13px;
    border-radius: var(--radius-pill);
    border: 1px solid var(--border-strong);
    background: var(--bg-card);
    color: var(--text-dim);
    font-size: 0.78rem;
    font-weight: 550;
    text-decoration: none;
    transition: color var(--ease), border-color var(--ease), background var(--ease);
}
.chip:hover { color: var(--text); border-color: var(--border-hover); }
.chip.on {
    border-color: var(--red-line);
    background: var(--red-wash);
    color: var(--red-bright);
}

/* ---------------------------------------------------------- callouts */

.callout {
    border-left: 2px solid var(--red);
    padding: 2px 0 2px 16px;
    font-size: 0.88rem;
    color: var(--text-mid);
}
.callout strong { color: var(--text); font-weight: 650; }
.card.callout { padding: 18px 20px 18px 22px; border-left-width: 2px; background: var(--red-wash-soft); }

/* ---------------------------------------------------------- fixture detail */

.outcome-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 10px;
    margin-bottom: 16px;
}
.outcome {
    background: var(--bg-sunken);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 16px 14px;
    text-align: center;
}
.outcome-label {
    display: block;
    color: var(--text-dim);
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.09em;
    font-weight: 600;
}
.outcome-value {
    display: block;
    font-size: 1.9rem;
    font-weight: 700;
    letter-spacing: -0.035em;
    margin-top: 6px;
    font-variant-numeric: tabular-nums;
}
.outcome.win .outcome-value { color: var(--green-bright); }
.outcome.lose .outcome-value { color: var(--red-bright); }
.outcome.neutral .outcome-value { color: var(--draw); }
.outcome.win {
    border-color: var(--green-line);
    background: var(--green-wash);
    box-shadow: 0 0 24px -8px var(--green-glow);
}

.prob-stack {
    display: flex;
    height: 8px;
    border-radius: var(--radius-pill);
    overflow: hidden;
    margin-bottom: 14px;
    background: var(--bg-sunken);
    gap: 2px;
}
.prob-stack .seg { transition: width var(--ease); }
.prob-stack .seg.win { background: var(--green); }
.prob-stack .seg.lose { background: var(--red); }
.prob-stack .seg.neutral { background: var(--draw); }

.scorelines { display: flex; flex-wrap: wrap; gap: 8px; }
.scoreline {
    background: var(--bg-sunken);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: 9px 14px;
    text-align: center;
    min-width: 76px;
    transition: border-color var(--ease);
}
.scoreline:hover { border-color: var(--red-line); }
/* Alternatives sit behind the headline score: same shape, dimmer, so the
   top pick still reads as the prediction and these as the range around it. */
.scoreline.alt { opacity: 0.62; }
.scoreline.alt .line { font-weight: 600; }
.scoreline .line { display: block; font-weight: 700; font-size: 0.95rem; font-variant-numeric: tabular-nums; }
.scoreline .lineprob { display: block; color: var(--text-dim); font-size: 0.73rem; font-variant-numeric: tabular-nums; }

/* Event markets: BTTS, over/under goals, clean sheets, cards, corners --
   a compact grid of probability tiles under the predicted outcome. */
.event-markets {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 8px;
    margin-bottom: 10px;
}
.event-market {
    background: var(--bg-sunken);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: 8px 10px;
    text-align: center;
}
.event-market .em-label {
    display: block;
    color: var(--text-dim);
    font-size: 0.62rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.event-market .em-value {
    display: block;
    font-size: 1.15rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    margin-top: 2px;
    font-variant-numeric: tabular-nums;
    color: var(--text);
}
.event-market .em-avg {
    display: block;
    color: var(--text-dim);
    font-size: 0.66rem;
    margin-top: 3px;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.em-note { margin: 0 0 14px; }

/* Event markets (left) + radar team comparison (right), inside the same
   Predicted outcome card -- stacked on narrow viewports, side by side once
   there's room for both. */
.predicted-compare {
    margin-top: 18px;
    padding-top: 16px;
    border-top: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    gap: 22px;
}
@media (min-width: 760px) {
    .predicted-compare {
        display: grid;
        grid-template-columns: 1.3fr 1fr;
        gap: 32px;
    }
}
.predicted-compare-col { min-width: 0; }
.predicted-compare-col h3 { margin-top: 0; }

.h2h-layout {
    display: grid;
    grid-template-columns: minmax(230px, 340px) 1fr;
    gap: 20px;
    align-items: start;
}
@media (max-width: 720px) {
    .h2h-layout { grid-template-columns: 1fr; }
}

/* Fixed layout + per-cell ellipsis, not a horizontal scroll: this table
   lives in a column-constrained half of the card, and team names (up to
   "Queens Park Rangers" in the lower leagues) will always outrun a plain
   auto-sized table at that width. Fixed column percentages let the browser
   commit to a width per cell up front, which is what makes overflow:hidden
   + text-overflow:ellipsis on .h2h-name actually take effect -- an
   auto-layout table just grows the column to fit the content instead. */
.h2h-table {
    table-layout: fixed;
    width: 100%;
    min-width: 0;
    white-space: normal;
}
.h2h-table th, .h2h-table td { font-size: 0.76rem; padding: 6px 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.h2h-table th { letter-spacing: 0; font-size: 0.58rem; }
.h2h-table th:nth-child(1), .h2h-table td:nth-child(1) { width: 23%; }
.h2h-table th:nth-child(2), .h2h-table td:nth-child(2) { width: 31%; }
.h2h-table th:nth-child(3), .h2h-table td:nth-child(3) { width: 13%; }
.h2h-table th:nth-child(4), .h2h-table td:nth-child(4) { width: 33%; }
.h2h-table .h2h-score { text-align: center; }
.h2h-table .h2h-team .crest { width: 15px; height: 15px; margin-right: 4px; }
.h2h-table .h2h-team-link { color: inherit; text-decoration: none; }
.h2h-table .h2h-team-link:hover { color: var(--red); }
.h2h-table .h2h-name {
    display: inline-block;
    max-width: calc(100% - 20px);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: middle;
}

.h2h-stats { display: flex; flex-direction: column; gap: 12px; }

.h2h-pie-block {
    display: flex;
    align-items: center;
    gap: 16px;
    flex-wrap: wrap;
}
.pie-chart {
    position: relative;
    width: 92px;
    height: 92px;
    border-radius: 50%;
    flex: 0 0 auto;
}
.pie-chart-hole {
    position: absolute;
    inset: 12px;
    border-radius: 50%;
    background: var(--bg-card);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
}
.pie-chart-hole span { font-size: 1.05rem; font-weight: 700; letter-spacing: -0.03em; line-height: 1.1; }
.pie-chart-hole small { font-size: 0.56rem; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.07em; }

.pie-legend { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 5px; font-size: 0.78rem; color: var(--text-mid); }
.pie-legend .swatch {
    display: inline-block;
    width: 9px;
    height: 9px;
    border-radius: 3px;
    margin-right: 6px;
    vertical-align: middle;
}
.pie-legend .swatch.win { background: var(--green); }
.pie-legend .swatch.draw { background: var(--draw); }
.pie-legend .swatch.lose { background: var(--red); }
.pie-legend .swatch.over { background: var(--blue); }
.pie-legend .swatch.under { background: var(--draw); }
.pie-legend .swatch.yes { background: var(--green); }
.pie-legend .swatch.no { background: var(--red); }

/* Small-multiple donuts for a team's recent-matches goal lines + BTTS,
   below its Form & stats card -- a smaller variant of the H2H donut above. */
.game-stats-cols { margin-top: 6px; }
.game-stats-col { min-width: 0; }
/* Extra breathing room and a divider between the two teams' columns once
   they sit side by side -- at the narrower stacked layout (.two-col's own
   collapse point) there's no "left" column to divide against, so both are
   scoped to the same width the grid actually goes two-up at. The divider is
   an absolutely-positioned line centred in the gap rather than a real
   border+padding on the column -- each column already needs its full width
   to fit two donuts per row, and a border/padding would eat into that and
   wrap the second donut onto its own line.

   The gap is deliberately 52px, not an arbitrary "looks wider" number: the
   two team cards in the row above this one are two separate .card boxes
   inside a .two-col (12px grid gap), each with the standard .card padding
   (20px each side) between its own border and its content -- so the visible
   gap between *their* content is 12 + 20 + 20 = 52px. This card is a single
   box with one shared 20px padding at each outer edge, so matching that same
   52px here as the *inner* column gap lines the divider up with the gap
   above pixel-for-pixel instead of just looking roughly similar. The -6px
   `left` offset is calibrated against the actual rendered midpoint (checked
   with a pixel-level screenshot diff), not derived from the theoretical
   half-gap -- the two 1fr grid tracks don't split perfectly evenly in
   practice, so a hand-derived offset landed a visible ~20px off. Re-verify
   with a screenshot if this section's column widths or padding ever change. */
@media (min-width: 700px) {
    .game-stats-cols { gap: 52px; }
    .game-stats-col + .game-stats-col {
        position: relative;
        /* Breathing room off the divider -- the crest/data otherwise start
           only ~5px after the line. Doesn't move the divider itself, which
           is positioned off this column's border box, not its padding. */
        padding-left: 16px;
    }
    .game-stats-col + .game-stats-col::before {
        content: "";
        position: absolute;
        top: 0;
        bottom: 0;
        left: -6px;
        width: 1px;
        background: var(--border);
    }
}
.game-stats-team {
    display: flex;
    align-items: center;
    font-size: 0.95rem;
    font-weight: 650;
    margin: 0 0 14px;
}
.recent-pies { display: flex; flex-direction: column; gap: 10px; }
.pie-row { display: flex; align-items: flex-start; gap: 16px; flex-wrap: wrap; }
.pie-item { display: flex; align-items: center; gap: 14px; }
/* Season Statistics' donuts each carry their own label + info-dot above the
   chart (PPG/Clean Sheets/BTTS/O-U goals/O-U corners) -- unlike the plainer
   .pie-item usages elsewhere (league snapshot, recent-form small multiples)
   which rely on the hole text alone, since these five specifically need a
   hover explainer. */
.pie-item-wrap { display: flex; flex-direction: column; gap: 6px; }
.pie-item-title {
    margin: 0;
    display: flex;
    align-items: center;
    gap: 5px;
    color: var(--text-dim);
    font-size: 0.62rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-weight: 600;
}
/* .info-tip's default right:-6px assumes room to its LEFT (true of the
   h2h-metric-label usage it was built for), but this title sits at the far
   left edge of the Season Statistics card -- a right-anchored tip would hang
   off the edge of the page. Left-anchor it here instead; the card is wide
   enough that a 240px tip growing rightward from the dot stays on-screen. */
.pie-item-title .info-tip { left: -6px; right: auto; }
/* Fixed-width legend column so a second donut on the same row (e.g. Corners
   next to Goals) sits at the same x position regardless of how wide "Under
   3 (30%)" vs "Under 10 (100%)" happens to render -- otherwise every row
   shifts left/right independently as the underlying counts change. */
.pie-item .pie-legend { flex: 0 0 150px; white-space: nowrap; }
.pie-item .pie-legend strong { font-variant-numeric: tabular-nums; }
/* Legend narrowed 160->150 and the chart-to-legend gap tightened 14->12 to
   offset the donut growing 64->76 -- keeps each row's total footprint (and
   therefore the two-per-row fit + divider alignment already calibrated
   above) unchanged even though the donut itself is visibly bigger. */
.pie-item { gap: 12px; }
.pie-chart-sm { width: 76px; height: 76px; flex-shrink: 0; }
.pie-chart-sm .pie-chart-hole { inset: 9px; }
.pie-chart-sm .pie-chart-hole span { font-size: 0.95rem; }
.pie-chart-sm .pie-chart-hole small { font-size: 0.56rem; }

/* "Recent Player Statistics" card -- four small leaderboards (goals, shots
   on target, total shots, cards) per team, sat directly below the
   Previous Game Statistics donuts and reusing that section's two-col/
   crest/divider layout (.game-stats-cols / .game-stats-col) so the two
   cards read as one family. Each row reuses the squad table's own
   .player-avatar initials-plus-photo treatment so a name here and that same
   player's row on /teams/{team} look like the same person at a glance. */
.player-leaders-col { display: flex; flex-direction: column; gap: 18px; }
.player-leader-group h4 {
    margin: 0 0 8px;
    font-size: 0.68rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-weight: 700;
    color: var(--text-dim);
}
/* 7 tracks: avatar, name, 3 individual last-match slots, season total pill,
   season appearances. The 3 match slots and appearances are fixed narrow
   tracks (single digits / a dash); the total stays `max-content` rather
   than a fixed width, like before, so the "2Y 1R" cards format never clips. */
.player-leader-list {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) 18px 18px 18px max-content 22px;
    column-gap: 8px;
    row-gap: 8px;
    margin: 0; padding: 0; list-style: none;
}
.player-leader-row {
    display: grid;
    grid-column: 1 / -1;
    grid-template-columns: subgrid;
    align-items: center;
}
.player-leader-name {
    min-width: 0;
    color: var(--text);
    font-weight: 600;
    font-size: 0.86rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.player-leader-value {
    font-variant-numeric: tabular-nums;
    font-weight: 700;
    font-size: 0.9rem;
    color: var(--text);
    background: var(--bg-sunken);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: 1px 7px;
    min-width: 40px;
    text-align: center;
}
/* Legend row: the first <li> in each list, sharing the same subgrid tracks
   as every data row below it so "Last 3" (spanning the 3 match-slot tracks)
   and "Total"/"Apps" land exactly above their own columns without a second,
   separately-sized grid to keep in sync. Hidden from screen readers -- each
   data cell below carries its own aria-label instead. */
.player-leader-legend-row {
    font-size: 0.6rem; text-transform: uppercase; letter-spacing: 0.05em;
    color: var(--text-dim); padding-bottom: 2px;
}
.player-leader-legend-l3 { grid-column: 3 / 6; text-align: center; }
.player-leader-legend-total { grid-column: 6; text-align: center; }
.player-leader-legend-apps { grid-column: 7; text-align: center; }
.player-leader-recent {
    font-variant-numeric: tabular-nums; font-weight: 700; font-size: 0.86rem;
    color: var(--text-mid); text-align: center;
}
.player-leader-recent.is-na { color: var(--text-dim); font-weight: 400; }
/* Padding rows added when a category has fewer than 3 qualifying players --
   same grid tracks (including the empty .player-avatar box, so the row
   height matches a real row exactly) but faded out, keeping every category
   box the same height whether it has 1, 2 or 3 entries. */
.player-leader-row-empty { opacity: 0.45; }
.player-leader-value.is-na {
    color: var(--text-dim);
    background: transparent;
    border-color: transparent;
    font-weight: 400;
}
.player-leader-apps {
    font-variant-numeric: tabular-nums; font-size: 0.78rem;
    color: var(--text-dim); text-align: center;
}
@media (max-width: 480px) {
    .player-leader-list { column-gap: 5px; grid-template-columns: auto minmax(0,1fr) 15px 15px 15px max-content 18px; }
    .player-leader-recent, .player-leader-value, .player-leader-apps { font-size: 0.74rem; }
    .player-leader-value { min-width: 34px; padding: 1px 5px; }
    .player-leader-legend-row { font-size: 0.55rem; }
}

.h2h-metrics {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
    gap: 8px;
}
@media (max-width: 480px) {
    .h2h-metrics { grid-template-columns: repeat(2, 1fr); }
}
.h2h-metric {
    background: var(--bg-sunken);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: 8px 10px;
}
.h2h-metric-label {
    display: block;
    color: var(--text-dim);
    font-size: 0.62rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-weight: 600;
}
.h2h-metric-value {
    display: block;
    font-size: 1.1rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    margin-top: 2px;
    font-variant-numeric: tabular-nums;
}
.h2h-metric-sub { display: block; color: var(--text-dim); font-size: 0.66rem; margin-top: 1px; }
.h2h-biggest { margin: 0; }
.h2h-summary { margin: 14px 0 0; line-height: 1.6; color: var(--text); }

/* ---------------------------------------------------------- league table snapshot */

/* /table's "league snapshot" -- the same win/draw/loss + BTTS + over/under
   donut treatment as the H2H card above, reused here for the league-wide
   split instead of two teams' head-to-head record. Sits above the standings
   table, replacing what used to be a flat row of status pills. */
.league-snapshot-caption {
    margin: 0 0 16px;
    color: var(--text-dim);
    font-size: 0.82rem;
}
.league-snapshot-pies {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    /* Narrower than .pie-row's 16px/.h2h-pie-block's 16px would suggest --
       tightened specifically so all four donuts (win/draw/loss + BTTS +
       over/under 2.5 + over/under 9.5 corners) fit on one row at the
       card's own max width (1120px container - padding) instead of the
       fourth wrapping onto a sparse second line. */
    gap: 10px;
    padding-bottom: 20px;
    margin-bottom: 20px;
    border-bottom: 1px solid var(--border);
}
.league-snapshot-pies .pie-item { gap: 8px; }
.league-snapshot-metrics { gap: 12px; }
.league-snapshot-season .h2h-metric-value small {
    font-size: 0.6rem;
    font-weight: 600;
    color: var(--text-dim);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin-left: 2px;
}
.season-progress-bar {
    height: 5px;
    border-radius: var(--radius-pill);
    background: var(--bg-sunken);
    border: 1px solid var(--border);
    overflow: hidden;
    margin-top: 7px;
}
.season-progress-fill {
    height: 100%;
    border-radius: var(--radius-pill);
    background: var(--red);
}

/* ---------------------------------------------------------- team pages */

/* League hub: table and upcoming fixtures side by side, each a true half of
   the page rather than .two-col's 320px floor -- with the table's own 8
   fixed columns, a floor that low would let it win nearly the whole row on
   a mid-width viewport before the fixtures column ever got to stack. */
.hub-split {
    display: grid;
    /* min(400px, 100%) rather than a bare 400px: auto-fit still forces a
       single track down to its floor even when the container itself is
       narrower than that (any phone under ~430px content width), which used
       to push both .hub-col children 400px wide and clip the excess behind
       body's overflow-x: hidden -- silently unreachable, not just ugly. */
    grid-template-columns: repeat(auto-fit, minmax(min(400px, 100%), 1fr));
    gap: 12px;
    align-items: start;
}
.hub-col > table { margin: 0; }

.two-col {
    display: grid;
    /* min(320px, 100%): see .hub-split's comment -- same overflow trap below
       ~350px viewport width, and .two-col is the far more widely used class
       (Squad pairing, .game-stats-cols, etc.), so it hit more pages. */
    grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr));
    gap: 12px;
}
/* The generic .two-col floor (minmax(320px, 1fr)) is too narrow for 5
   numeric tracks (3 match slots, season total, appearances) plus a pill on
   top of the avatar/name -- at ~700px it would give two ~340px columns and
   crowd the name. Scoped to .player-leaders-cols (markup-only class on
   recent_player_statistics, no rule of its own until now) and placed after
   .two-col so it wins the same-specificity cascade, so .game-stats-cols and
   every other .two-col user, including the team page's Squad pairing, is
   untouched. */
.player-leaders-cols { grid-template-columns: repeat(auto-fit, minmax(min(380px, 100%), 1fr)); }
/* The fixture page's Match stats / Key events pairing (m.match_report_panel)
   -- .two-col's grid items stretch to equal height by default, which left
   the shorter Match stats card padded out with empty space below its own
   content to match the much longer Key events list. align-items: start lets
   each card size to its own content instead; the Match summary paragraphs
   appended under the stat rows (see .match-summary below) are what actually
   fill most of that space now, this just stops the layout padding out
   whatever's left. Same after-.two-col placement as .player-leaders-cols
   above, for the same cascade reason -- .two-col itself (the team page's
   Squad pairing, .game-stats-cols, etc.) is untouched. */
.match-report-cols { align-items: start; }

.form-run { display: inline-flex; gap: 3px; vertical-align: middle; }
.form-pill {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 21px;
    height: 21px;
    border-radius: 6px;
    font-size: 0.68rem;
    font-weight: 700;
    border: 1px solid transparent;
    cursor: default;
}
.form-pill.w { background: var(--green-wash); color: var(--green-bright); border-color: var(--green-line); }
.form-pill.d { background: var(--hover-tint); color: var(--text-mid); border-color: var(--border-strong); }
.form-pill.l { background: var(--red-wash); color: var(--red-bright); border-color: var(--red-line); }

/* --- All/Home/Away and All/League toggles (client-side, see app.js) --- */
button.chip { font: inherit; cursor: pointer; appearance: none; -webkit-appearance: none; }
.variant-tabs { display: inline-flex; gap: 6px; margin-bottom: 12px; }
.variant-panel[hidden] { display: none; }
.history-toggle, .leaderboard-toggle { display: inline-block; margin-top: 8px; }

.recent-match-list { display: flex; flex-direction: column; gap: 6px; margin: 10px 0 18px; padding: 0; list-style: none; }
.rm-details {
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--bg-sunken);
    overflow: hidden;
}
.rm-summary {
    display: grid;
    grid-template-columns: 78px 20px minmax(120px, 1fr) auto auto;
    align-items: center;
    gap: 10px;
    padding: 7px 38px 7px 12px;
    font-size: 0.85rem;
    cursor: pointer;
    list-style: none;
    position: relative;
}
.rm-summary::-webkit-details-marker { display: none; }
.rm-summary::marker { content: ''; }
.rm-chevron {
    position: absolute;
    right: 12px;
    top: 50%;
    color: var(--text-dim);
    transform: translateY(-50%);
    transition: transform 0.15s ease;
}
.rm-details[open] .rm-chevron { transform: translateY(-50%) rotate(180deg); }
.rm-date { color: var(--text-dim); font-variant-numeric: tabular-nums; }
.rm-venue { font-weight: 700; color: var(--text-dim); text-align: center; }
.rm-matchup { display: flex; align-items: center; gap: 5px; min-width: 0; }
.rm-own-team { font-weight: 700; white-space: nowrap; flex-shrink: 0; }
.rm-vs { color: var(--text-dim); font-size: 0.78rem; flex-shrink: 0; }
.rm-matchup .team-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rm-score { font-variant-numeric: tabular-nums; }
.rm-expand { padding: 10px 12px 14px; border-top: 1px solid var(--border); }
.rm-expand .live-card-stats { margin-top: 0; padding-top: 0; border-top: none; }
.rm-view-all { display: inline-block; margin-top: 10px; font-size: 0.82rem; }
@media (max-width: 640px) {
    .rm-summary { grid-template-columns: auto auto 1fr auto; }
}

/* ---------------------------------------------------------- responsive */

@media (max-width: 1000px) {
    .fixture-row { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
    .fixture-teams { grid-column: 1 / -1; }
}

@media (max-width: 1100px) {
    .topbar-inner { flex-wrap: wrap; gap: 12px; }
    .brand, .league-select { flex: 0 0 auto; }
    nav { order: 3; flex: 1 1 100%; width: 100%; gap: 2px; padding-bottom: 2px; }
}

@media (max-width: 640px) {
    body { font-size: 14.5px; }
    .container { padding: 26px 16px 60px; }
    h1 { font-size: 1.5rem; }
    .fixture-row { grid-template-columns: 1fr; gap: 14px; }
    .probs { max-width: none; }
    table { display: block; overflow-x: auto; white-space: nowrap; }
}

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        transition-duration: 0.01ms !important;
        animation-duration: 0.01ms !important;
    }
}

/* ---------------------------------------------------------- team badges */

.team-name {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
}

.crest {
    flex: none;
    display: inline-block;
    border-radius: 4px;
    object-fit: contain;
    vertical-align: middle;
    background: var(--bg-sunken);
}
.crest-sm { width: 18px; height: 18px; }
.crest-md { width: 26px; height: 26px; }
.crest-lg { width: 40px; height: 40px; }

.crest-fallback {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: var(--bg-card-hover);
    border: 1px solid var(--border-strong);
    color: var(--text-dim);
    font-weight: 700;
    line-height: 1;
}
.crest-fallback.crest-sm { font-size: 0.62rem; }
.crest-fallback.crest-md { font-size: 0.78rem; }
.crest-fallback.crest-lg { font-size: 1.15rem; }

.team-title, .matchup-title {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
}
/* ---------------------------------------------------------- matchweek nav */

.matchday-heading {
    display: flex;
    align-items: center;
    gap: 10px;
}
.md-label-group {
    display: flex;
    align-items: baseline;
    gap: 10px;
    flex-wrap: wrap;
}
.md-daterange {
    color: var(--text-dim);
    font-weight: 500;
    font-size: 0.78rem;
}
.day-heading {
    margin-top: 14px;
}
/* League hub's compact fixture list (m.simple_fixture_row): time and teams
   only, one row per fixture, grouped under the .day-heading above. */
.hub-fixtures .day-heading:first-child { margin-top: 0; }
.hub-totw-head { margin-top: 22px; }
/* Capped so a wide hub column doesn't stretch the portrait pitch past a
   readable height -- the fixture/team pages' own two-up lineups grid never
   hits this since it's always sharing the row with a second side. */
.hub-totw { max-width: 360px; margin: 0 auto; }
/* Team of the week's own banner: league position (with a mover arrow when
   it changed across this matchday), crest+name, formation, last-5 form --
   above the pitch, replacing the plain lineup-head a single-team card
   would otherwise get. */
.totw-banner {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 10px;
}
.totw-pos {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-pill);
    padding: 1px 9px;
    font-size: 0.82rem;
}
.totw-mover { width: 8px; height: 8px; flex: none; }
.totw-mover.up { color: var(--green-bright); }
.totw-mover.down { color: var(--red-bright); }

.hub-fixture-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 0;
    text-decoration: none;
    color: inherit;
}
.hub-fixture-row:not(:last-child) { border-bottom: 1px solid var(--border); }
.hub-fixture-row:hover, .hub-fixture-row:focus-visible { color: var(--red); }
/* Mirrored: both .hfr-team halves share the leftover width equally and the
   time has a fixed minimum, so the time column and the two crest columns
   either side of it line up on every row (a "-" for a missing kickoff
   included). */
.hfr-time {
    flex: none;
    min-width: 5.6em;
    text-align: center;
    font-variant-numeric: tabular-nums;
    font-size: 0.82rem;
    color: var(--text-dim);
    white-space: nowrap;
}
.hfr-team { display: flex; align-items: center; gap: 7px; min-width: 0; flex: 1 1 0; }
.hfr-home { justify-content: flex-end; text-align: right; }
.hfr-away { justify-content: flex-start; }
/* A long name wraps to a second line, hyphenated at a syllable if a single
   word is too long for the half ("Bourne-mouth" on a 320px phone; needs the
   page's lang and a browser with a dictionary, which phones have), and is
   only cut with an ellipsis past two lines or where no hyphenation exists --
   so the name stays readable and the crest beside it never moves. */
.hfr-name {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    line-height: 1.15;
    -webkit-hyphens: auto;
    hyphens: auto;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
}
/* Phone: the same mirrored layout, but each name only gets about a quarter
   of the row, so "UTC" drops under the clock and the card's side padding
   and the gaps tighten to hand that width back to the names. Crests keep
   their full size: they are what the reader scans down. */
@media (max-width: 480px) {
    .card.hub-fixtures { padding-left: 12px; padding-right: 12px; }
    .hub-fixture-row { gap: 6px; }
    .hfr-team { gap: 5px; }
    .hfr-name { font-size: 0.92em; }
    .hfr-time { min-width: 3.4em; line-height: 1.15; }
    .hfr-tz { display: block; font-size: 0.68rem; letter-spacing: 0.04em; }
}

.md-arrow {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    flex: none;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border-strong);
    background: var(--bg-card);
    color: var(--text-mid);
    text-decoration: none;
    font-size: 0.85rem;
    transition: color var(--ease), border-color var(--ease), background var(--ease);
}
.md-arrow:hover { color: var(--text-strong); border-color: var(--red-line); background: var(--red-wash); }
.md-arrow.disabled { opacity: 0.28; pointer-events: none; }
.matchweek-jump { display: flex; flex-wrap: wrap; gap: 6px; margin: 2px 0 18px; }
.matchweek-jump .chip { padding: 4px 10px; font-size: 0.78rem; letter-spacing: 0.04em; min-width: 34px; text-align: center; }


/* --- Predicted lineups & injuries ------------------------------------ */
.lineups-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 18px;
}
@media (max-width: 720px) {
    .lineups-grid { grid-template-columns: 1fr; }
}
.lineup-side {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-sunken);
    padding: 12px;
}
.lineup-head {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    margin-bottom: 10px;
}
.lineup-head .lineup-team {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-weight: 650;
}
.lineup-head .formation {
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.06em;
    color: var(--text-mid);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-pill);
    padding: 1px 9px;
    font-size: 0.78rem;
}

/* The pitch: a portrait green field with markings, GK at the bottom. */
.pitch {
    position: relative;
    width: 100%;
    aspect-ratio: 68 / 90;
    border-radius: var(--radius-sm);
    overflow: hidden;
    background: repeating-linear-gradient(
        0deg,
        var(--pitch-a) 0,
        var(--pitch-a) calc(100% / 12),
        var(--pitch-b) calc(100% / 12),
        var(--pitch-b) calc(100% / 6)
    );
    border: 1px solid var(--border-strong);
}
/* pitch markings drawn with a couple of overlays, kept cheap (no images) */
.pitch::before {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    background:
        /* centre line */
        linear-gradient(var(--pitch-line), var(--pitch-line)) 0 50% / 100% 2px no-repeat;
}
/* `::after` is the last child, so it paints ABOVE every .player. Without
   pointer-events:none the centre circle swallows clicks on whoever stands in
   it (a #6/#8 in a midfield-diamond or a lone holding midfielder) -- the
   player neither highlights nor opens. */
.pitch::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 50%;
    width: 26%;
    aspect-ratio: 1;
    transform: translate(-50%, -50%);
    border: 2px solid var(--pitch-mark);
    border-radius: 50%;
    pointer-events: none;
}

/* Penalty box + six-yard box at each end. The edge flush with the goal line
   is left un-bordered since the pitch's own border already draws it. */
.pitch .box {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    border: 2px solid var(--pitch-mark);
}
.pitch .box-penalty { width: 62%; height: 16%; }
.pitch .box-six { width: 30%; height: 6.5%; }
.pitch .box.at-top { top: 0; border-top: none; }
.pitch .box.at-bottom { bottom: 0; border-bottom: none; }

.player {
    position: absolute;
    transform: translate(-50%, -50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 92px;
    text-align: center;
    pointer-events: none;
}
/* `.player` keeps pointer-events:none so its 92px-wide box can't swallow
   clicks meant for the jersey next to it -- only the link inside it takes
   them back. A player whose name didn't resolve to a squad row renders the
   same markup as a plain span, so the pitch looks identical either way. */
.player-link {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-decoration: none;
    color: inherit;
    border-radius: var(--radius-sm);
    /* no horizontal padding: `.player` is a fixed 92px and `.pname` ellipsises
       against that width, so padding the sides would clip a character. */
    width: 100%;
    padding: 2px 0;
    transition: transform var(--ease), background var(--ease);
}
/* `.player-link-popup` (the finished-match popup trigger, see pitch() macro)
   is a <span role="button">, not an <a> -- needs the same pointer-events
   opt-back-in as the real link, or it inherits `.player`'s pointer-events:
   none and silently swallows nothing while the pitch-marking div underneath
   it eats the click instead. Confirmed the hard way: a scripted
   element.click() "worked" (it bypasses hit-testing entirely) while a real
   mouse click on the goalkeeper -- standing inside the six-yard box marking
   -- did not, until this rule existed. */
a.player-link, .player-link-popup { pointer-events: auto; cursor: pointer; }
a.player-link:hover, .player-link-popup:hover { transform: translateY(-2px); background: var(--hover-tint); }
a.player-link:hover .pname, .player-link-popup:hover .pname { color: var(--text-strong); text-decoration: underline; }
a.player-link:focus-visible, .player-link-popup:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.player .jersey {
    display: block;
    line-height: 0;
    filter: var(--jersey-filter);
}
.player .jersey svg { display: block; width: 56px; height: 54px; }
.player .pname {
    margin-top: 4px;
    max-width: 92px;
    font-size: 0.78rem;
    font-weight: 650;
    line-height: 1.1;
    color: var(--pitch-text);
    text-shadow: var(--pitch-text-shadow);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
@media (max-width: 480px) {
    .player { width: 68px; }
    .player .jersey svg { width: 42px; height: 40px; }
    .player .pname { max-width: 68px; font-size: 0.66rem; }
}

/* Goal/assist/card/subbed-off icons under a pitch player's name -- see
   player_badges() in _macros.html. Kept tiny and drop-shadowed like `.pname`
   so they stay legible over the grass at any kit colour. */
.player-badges {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: 2px;
    margin-top: 2px;
    line-height: 1;
}
.pbadge {
    display: inline-flex;
    align-items: center;
    font-size: 0.72rem;
    filter: var(--badge-filter);
}
.pbadge-n {
    font-size: 0.62rem;
    font-weight: 700;
    color: var(--pitch-text);
    margin-left: 1px;
    text-shadow: var(--pitch-text-shadow-sm);
}
.pbadge-sub {
    font-size: 0.62rem;
    font-weight: 650;
    color: var(--sub-red);
    text-shadow: var(--pitch-text-shadow-sm);
}
.pbadge-card {
    display: inline-block;
    width: 8px;
    height: 11px;
    border-radius: 1.5px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.7);
}
.pbadge-yellow { background: #f2c230; }
.pbadge-red { background: #e0342d; }
@media (max-width: 480px) {
    .pbadge { font-size: 0.62rem; }
    .pbadge-n, .pbadge-sub { font-size: 0.56rem; }
    .pbadge-card { width: 6px; height: 9px; }
}

/* Player match-stats popup (see player_stat_popup() in _macros.html and
   app.js's own .player-link-popup click handler, which clones the player's
   own <template> into this overlay). A plain centred card + backdrop rather
   than a native <dialog> -- this codebase has no other modal anywhere to
   match against, and a fixed-position overlay works identically across every
   browser this app targets without a polyfill. */
.player-link-popup { cursor: pointer; }
.player-popup-overlay {
    position: fixed;
    inset: 0;
    z-index: 200;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
    background: var(--scrim);
}
.player-popup {
    position: relative;
    width: 100%;
    max-width: 360px;
    max-height: 85vh;
    overflow-y: auto;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 18px;
    box-shadow: var(--shadow-popup);
}
.player-popup-close {
    position: absolute;
    top: 10px;
    right: 10px;
    width: 26px;
    height: 26px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: none;
    background: transparent;
    color: var(--text-dim);
    font-size: 1.1rem;
    line-height: 1;
    cursor: pointer;
    border-radius: 50%;
}
.player-popup-close:hover { background: var(--bg-sunken); color: var(--text); }
.player-popup-head {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 12px;
}
.player-popup-photo.player-avatar {
    width: 52px;
    height: 52px;
    border-radius: 50%;
}
.player-popup-photo .player-photo,
.player-popup-photo .player-avatar-initials { border-radius: 50%; }
.player-popup-photo .player-avatar-initials { font-size: 1rem; }
.player-popup-id { display: flex; flex-direction: column; gap: 2px; }
.player-popup-name { font-size: 1.02rem; }
.player-popup-match {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    flex-wrap: wrap;
    padding: 8px 0 12px;
    border-bottom: 1px solid var(--border);
    margin-bottom: 12px;
}
.player-popup-teams {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 0.86rem;
    color: var(--text-mid);
}
.player-popup h4 {
    margin: 0 0 6px;
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-dim);
}
.player-popup-stats { display: flex; flex-direction: column; }
.pp-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 8px 0;
    border-bottom: 1px solid var(--border);
    font-size: 0.88rem;
}
.pp-row:last-child { border-bottom: none; }
.pp-row span { color: var(--text-mid); }
.player-popup-link { display: block; text-align: center; margin-top: 14px; }

.injuries { margin-top: 12px; }
.injuries h3 {
    margin: 0 0 6px;
    font-family: inherit; /* was an h4, which took the body face; the global h3 rule uses the display face */
    font-weight: 700;
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-dim);
}
.injury-list { list-style: none; margin: 0; padding: 0; }
.injury-list li {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 8px;
    padding: 6px 0;
    border-bottom: 1px solid var(--border);
    font-size: 0.85rem;
}
.injury-list li:last-child { border-bottom: none; }
.injury-list .inj-avatar { width: 26px; height: 26px; border-radius: 50%; flex: 0 0 auto; }
.injury-list .inj-avatar .player-photo,
.injury-list .inj-avatar .player-avatar-initials { border-radius: 50%; }
.injury-list .inj-avatar .player-avatar-initials { font-size: 0.6rem; }
.injury-list .inj-player { color: var(--text); font-weight: 550; }
a.inj-player { text-decoration: none; }
a.inj-player:hover { color: var(--red-bright); text-decoration: underline; }
/* Two states only: definitely out (red) or a real chance either way
   (yellow) -- a 0% "chance of playing" next to "injured" said nothing the
   word didn't already say, so that case just doesn't carry a percentage.
   `.inj-label` used to be its own smaller, bolder, uppercase run inside this
   same line -- so "INJURED" rendered in a visibly different size/weight than
   the "Ankle injury - Expected back 14 Sep" text right next to it, on the
   same line, in the same color. One font-size/weight for the whole line
   fixes that; `.inj-label` keeps only the letter-spacing that marks it as
   the status word, not a different size. */
.injury-list .inj-detail {
    margin-left: auto;
    text-align: right;
    font-size: 0.78rem;
    font-weight: 600;
}
.injury-list .inj-out { color: var(--flag-out); }
.injury-list .inj-maybe { color: var(--flag-maybe); }
.injury-list .inj-label {
    letter-spacing: 0.02em;
}


/* --- Teams index ------------------------------------------------------
   One card per club, ordered by league position. The whole card is the
   link, so nothing inside it may be an anchor of its own. */
.club-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: 14px;
}
.club-card {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 16px 18px;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    color: inherit;
    text-decoration: none;
    transition: border-color var(--ease), background var(--ease), transform var(--ease);
}
.club-card:hover {
    border-color: var(--red-line);
    background: var(--bg-card-hover);
    transform: translateY(-1px);
}
.club-head { display: flex; align-items: center; gap: 12px; }
.club-id { display: flex; flex-direction: column; min-width: 0; }
.club-name {
    font-weight: 700;
    font-size: 1.02rem;
    color: var(--text);
    letter-spacing: -0.01em;
}
.club-rank {
    font-size: 0.78rem;
    color: var(--text-dim);
    font-variant-numeric: tabular-nums;
}
.club-form { line-height: 1; }
.club-stats {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 14px;
    font-size: 0.78rem;
    color: var(--text-dim);
    font-variant-numeric: tabular-nums;
}
.club-stats strong { color: var(--text-mid); font-weight: 650; }
.club-next {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 7px;
    padding-top: 10px;
    border-top: 1px solid var(--border);
    font-size: 0.8rem;
    color: var(--text-mid);
}
.club-next .label {
    font-size: 0.66rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-dim);
}
.club-next .venue {
    font-size: 0.64rem;
    font-weight: 700;
    padding: 1px 6px;
    border-radius: var(--radius-pill);
    border: 1px solid var(--border-strong);
    color: var(--text-dim);
}
.club-next .opp { font-weight: 650; color: var(--text); }
.club-next .when { margin-left: auto; color: var(--text-dim); font-variant-numeric: tabular-nums; }

/* --- A club's own next-fixtures list ---------------------------------- */
.team-fixtures { display: flex; flex-direction: column; gap: 8px; }
.team-fixture {
    display: grid;
    grid-template-columns: minmax(150px, auto) minmax(160px, 1fr) auto auto;
    align-items: center;
    gap: 14px;
    padding: 10px 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--bg-sunken);
    color: inherit;
    text-decoration: none;
    transition: border-color var(--ease), background var(--ease);
}
.team-fixture:hover { border-color: var(--red-line); background: var(--bg-card-hover); }
.tf-when { font-size: 0.8rem; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.tf-opp {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-weight: 650;
    min-width: 0;
}
.tf-venue {
    font-size: 0.62rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    padding: 1px 6px;
    border-radius: var(--radius-pill);
    border: 1px solid var(--border-strong);
    color: var(--text-dim);
}
.tf-venue.home { color: var(--text-mid); border-color: var(--text-dim); }
.tf-probs { display: flex; gap: 6px; }
.tf-probs .prob-bar { min-width: 58px; }
.tf-go { font-size: 0.78rem; color: var(--red-bright); white-space: nowrap; }
@media (max-width: 860px) {
    .team-fixture { grid-template-columns: 1fr; gap: 8px; }
    .tf-go { display: none; }
}

/* One-sided lineup panel: a club's own page has no opponent to sit beside,
   so the pitch is capped rather than stretched across the full card. */
.lineups-grid.one-up { grid-template-columns: minmax(0, 520px); }

/* --- Squad list ------------------------------------------------------- */
.squad-group {
    margin: 20px 0 8px;
    font-size: 0.82rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-dim);
    font-weight: 700;
}
.squad-group .muted { text-transform: none; letter-spacing: 0; }
.squad-table td:first-child { text-align: right; font-variant-numeric: tabular-nums; }
/* The flex layout lives on an inner wrapper, never on the <td>: a table cell
   with display:flex drops out of the column layout (see the Shot Profile
   note in pl-betting-ui-ux). */
.squad-name { min-width: 0; }
.squad-cell { display: flex; align-items: center; gap: 9px; }
.squad-names { display: flex; flex-direction: column; align-items: flex-start; gap: 0; }
.squad-status { font-size: 0.72rem; line-height: 1.2; }
.squad-full { max-width: 100px; overflow: hidden; text-overflow: ellipsis; }
.squad-table th, .squad-table td { padding-left: 6px; padding-right: 6px; }
table.squad-table.js-sortable th[data-sort] { padding-right: 16px; }
.squad-table th.squad-num, .squad-table td.squad-num { padding-right: 4px; width: 1%; }
/* The squad is the wide card of the pair: up to ten stat columns want more
   than half the page, and below 960px the two stack so the table gets the
   full width. */
.two-col.squad-and-stats { grid-template-columns: minmax(0, 1fr); }
@media (min-width: 960px) {
    .two-col.squad-and-stats { grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr); }
}
.squad-legend { margin: 6px 0 0; font-size: 0.74rem; line-height: 1.5; }
.squad-legend b { color: var(--text-mid); font-weight: 700; }
.squad-table td:not(.squad-name):not(.squad-num),
.squad-table th:not(:nth-child(2)):not(.squad-num) { text-align: center; font-variant-numeric: tabular-nums; }
/* Phone: the shirt number goes and the player column pins to the left edge,
   so the name stays in view while the stat columns scroll under it. */
@media (max-width: 600px) {
    .squad-table .squad-num { display: none; }
    .squad-name {
        min-width: 0;
        position: sticky;
        left: 0;
        z-index: 1;
        background: var(--bg-card);
        box-shadow: 1px 0 0 var(--border);
    }
    .squad-table thead th:nth-child(2) { position: sticky; left: 0; z-index: 2; background: var(--bg-card); }
    .squad-table .squad-cell { gap: 7px; }
    .squad-table .squad-short { font-size: 0.8rem; max-width: 110px; white-space: normal; line-height: 1.2; }
    .squad-table .squad-full { display: none; }
    .squad-table th, .squad-table td { padding: 8px 6px; }
    /* Landing on a row (#player-123) tints it, but the pinned cell has to stay
       opaque or the columns scrolling under it show through: tint over solid. */
    .squad-table tr:target td.squad-name {
        background: var(--bg-card) linear-gradient(var(--red-wash), var(--red-wash));
        animation: none;
    }
    /* Sorting still works on a tap; the idle arrows go so the short tables
       (a goalkeeper has four stat columns) fit a phone without scrolling. */
    table.squad-table.js-sortable th[data-sort] { padding-right: 6px; }
    table.squad-table.js-sortable th[data-sort]:not(.sort-asc):not(.sort-desc)::after { display: none; }
}
a.squad-short { color: var(--text); font-weight: 650; text-decoration: none; }
a.squad-short:hover { color: var(--red-bright); text-decoration: underline; }
.squad-full { font-size: 0.72rem; color: var(--text-dim); line-height: 1.2; }
/* The avatar is a fixed 28x36 well holding the player's initials, with the
   headshot laid over it. A photo that 403s on every path (42 of 622 players
   have none on premierleague.com at all -- mostly academy and just-signed)
   just uncovers the initials, so the row still reads as a person rather than
   as a broken image, and the column width never moves either way. */
.player-avatar {
    position: relative;
    width: 28px;
    height: 36px;
    flex: 0 0 auto;
    border-radius: 4px;
    background: var(--photo-well);
    border: 1px solid var(--photo-ring);
    overflow: hidden;
}
.player-avatar-initials {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.66rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    color: var(--text-dim);
}
.player-photo {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: top center;
    border-radius: 4px;
    background: var(--photo-well);
}
/* Set by app.js once every candidate URL has failed. */
.player-photo.is-missing { display: none; }
/* A row for a player who can't play is dimmed rather than hidden -- knowing
   who is missing is the point of showing availability at all. */
/* Landing from a jersey or injury link elsewhere on the site: :target does
   the whole job, no JS, and the browser's own anchor scroll puts the row on
   screen -- scroll-margin-top just keeps it clear of the sticky top bar. The
   flash fades but the left rule and tint stay, so the row is still findable
   after the animation has finished. */
.squad-table tr[id] { scroll-margin-top: 96px; }
.squad-table tr:target td {
    background: var(--red-wash);
    box-shadow: inset 0 1px 0 var(--red-line), inset 0 -1px 0 var(--red-line);
    animation: squad-target-flash 1.6s var(--ease);
}
.squad-table tr:target td:first-child {
    box-shadow: inset 3px 0 0 var(--accent), inset 0 1px 0 var(--red-line), inset 0 -1px 0 var(--red-line);
}
.squad-table tr:target .squad-short { color: var(--red-bright); }
/* An unavailable player's row is dimmed; undo that while it's the target, or
   the row you were sent to is the hardest one on the page to read. */
.squad-table tr.squad-out:target td,
.squad-table tr.squad-out:target .squad-cell { opacity: 1; }
@keyframes squad-target-flash {
    0%, 45% { background: var(--red-glow); }
    100% { background: var(--red-wash); }
}
@media (prefers-reduced-motion: reduce) {
    .squad-table tr:target td { animation: none; }
}

/* Dim the cell contents, not the pinned player cell itself, or the columns
   scrolling beneath it show through. */
.squad-table tr.squad-out td:not(.squad-name) { opacity: 0.55; }
.squad-table tr.squad-out .squad-cell { opacity: 0.55; }
.squad-table .inj-out { color: var(--flag-out); font-weight: 600; }
.squad-table .inj-maybe { color: var(--flag-maybe); font-weight: 600; }

/* ============================================================
   Landing page (/) — the cross-league front door.
   Only page that ignores the league cookie; see main.py's
   _live_matches_all() note.
   ============================================================ */

.hero {
    padding: 8px 0 30px;
    border-bottom: 1px solid var(--border);
    margin-bottom: 30px;
}
.hero h1 {
    font-size: clamp(1.7rem, 4.4vw, 2.6rem);
    line-height: 1.12;
    letter-spacing: -0.03em;
    margin: 0 0 12px;
    max-width: 26ch;
}
.hero-sub {
    margin: 0;
    max-width: 68ch;
    color: var(--text-mid);
    font-size: 1.02rem;
}

.landing-section { margin: 0 0 40px; }
.landing-section > h2 { margin: 0 0 4px; }
.section-sub { margin: 0 0 16px; color: var(--text-dim); font-size: 0.88rem; }
.section-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 14px;
    margin-bottom: 14px;
    flex-wrap: wrap;
}
.section-head h2 { margin: 0; }

/* -- league picker boxes -- */
.league-boxes {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 12px;
}
.league-box {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 16px 18px;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    text-decoration: none;
    color: inherit;
    transition: border-color var(--ease), background var(--ease), transform var(--ease);
}
.league-box:hover, .league-box:focus-visible {
    border-color: var(--red-line);
    background: var(--bg-card-hover);
    transform: translateY(-1px);
}
.league-box-head { display: flex; align-items: center; gap: 10px; }
.league-box-logo { width: 30px; height: 30px; object-fit: contain; flex-shrink: 0; }
.league-box-name {
    font-weight: 650;
    font-size: 1.02rem;
    letter-spacing: -0.01em;
    color: var(--text);
    flex: 1;
    min-width: 0;
}
.league-box-head .live-badge { flex-shrink: 0; }

.league-box-next {
    border-top: 1px solid var(--border);
    border-bottom: 1px solid var(--border);
    padding: 11px 0;
    display: flex;
    flex-direction: column;
    gap: 5px;
}
.league-box-label {
    font-size: 0.62rem;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--text-dim);
    font-weight: 650;
}
.league-box-teams {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
    font-size: 0.9rem;
}
.lb-team { font-weight: 550; }
.league-box-kick { font-size: 0.78rem; color: var(--text-dim); }

.league-box-foot { display: flex; flex-direction: column; gap: 4px; font-size: 0.8rem; }
.lb-fact { display: flex; align-items: center; gap: 6px; color: var(--text-mid); }
.lb-fact strong { font-weight: 600; color: var(--text); }

/* -- "Upcoming Fixtures": the compact cross-league fixture list -- */
.mini-fixtures { padding: 6px 18px 16px; }
/* Each day is a .mf-group (a <section>) opened by a full-width date banner, so
   where one day ends and the next begins is obvious while scrolling. The
   weekday is white, the date red, the match count small and right-aligned;
   a red bar down the left edge and a wide gap above each group do the rest.
   Real dates, never "Today"/"Tomorrow" (see _landing_fixtures). */
.mf-group { margin-top: 32px; }
.mf-group:first-of-type { margin-top: 10px; }
.mf-day {
    position: relative;
    display: flex;
    align-items: baseline;
    gap: 0.45em;
    margin: 0 -18px 8px;
    padding: 12px 18px 12px 26px;
    background: var(--bg-sunken);
    border-top: 1px solid var(--border);
    border-bottom: 1px solid var(--border);
    font-family: var(--font-display);
    font-style: italic;
    font-weight: 800;
    font-size: 1.9rem;
    line-height: 1.1;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}
.mf-day::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 7px;
    background: var(--red);
}
.mf-day-wd { color: var(--text-strong); }
.mf-day-date { color: var(--red); }
.mf-day-count {
    margin-left: auto;
    padding-left: 12px;
    font-style: normal;
    font-weight: 600;
    font-size: 0.8rem;
    letter-spacing: 0.12em;
    color: var(--text-dim);
    white-space: nowrap;
}
/* 8 fixed-width tracks (only the teams column is fluid) rather than `auto`
   for the trailing ones: the head bar and every fixture row below are each
   their own independent grid (a row is a whole `<a>`, not a table row), so
   an `auto` track is sized off *that one grid's own content* -- the head
   bar's wide labels ("Predicted Score") and a row's short values ("1-0")
   would each compute a different width and drift out of register column by
   column, worst at the left of this group and barely visible by the last
   one. Fixed pixel widths, shared verbatim between both grids below, are
   the only way two separate grids agree on where a column starts. */
.mini-fixtures-head,
.mini-fixture {
    grid-template-columns: 64px minmax(0, 1fr) repeat(4, 84px) 146px 150px;
    gap: 12px;
}
.mini-fixtures-head {
    display: grid;
    align-items: center;
    /* No horizontal padding here: `.mini-fixture` below nets to a zero
       horizontal inset (padding 8px cancelled by margin -8px, which lets its
       hover background bleed to the card's edges), so this header -- which
       has no such background and would otherwise keep its 8px padding as a
       flat inset -- has to drop that padding too, or every column of the
       header sits 8px to the right of the identical column in every row
       beneath it. */
    padding: 0 0 6px;
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-dim);
}
/* Only 6 of the 8 grid columns have content here -- pin them explicitly
   rather than relying on auto-placement, which would drop them into
   columns 1-2 instead of lining up with the stats/score/probs cells below. */
.mfh-stat:nth-of-type(1) { grid-column: 3; }
.mfh-stat:nth-of-type(2) { grid-column: 4; }
.mfh-stat:nth-of-type(3) { grid-column: 5; }
.mfh-stat:nth-of-type(4) { grid-column: 6; }
.mfh-score { grid-column: 7; }
.mfh-probs { grid-column: 8; display: flex; gap: 4px; }
.mfh-probs span { min-width: 42px; text-align: center; }
/* Every one of "who's playing" (fixed-width teams column), each of the 4
   secondary-market stats, and the model's predicted score gets its own rule
   and the same 14px gutter after it -- one visual grammar (a bordered table
   column) repeated identically rather than a one-off gap value per pair, so
   "how far apart are two columns" has a single answer everywhere in this
   row. The W/D/L trio is the one exception: each value is already its own
   bordered pill (see .mf-prob below), so a further rule immediately to its
   left would double up against a border that's already there. */
.mfh-stat, .mf-stat, .mfh-score, .mf-score {
    border-left: 1px solid var(--border);
    padding-left: 14px;
    text-align: left;
    white-space: nowrap;
}
.mini-fixture {
    display: grid;
    align-items: center;
    padding: 9px 8px;
    margin: 0 -8px;
    border-radius: var(--radius-sm);
    text-decoration: none;
    color: inherit;
    transition: background var(--ease);
}
.mini-fixture:not(:last-child) { border-bottom: 1px solid var(--border); }
.mini-fixture:hover, .mini-fixture:focus-visible { background: var(--bg-card-hover); }
.mf-time {
    font-variant-numeric: tabular-nums;
    font-size: 1rem;
    color: var(--text-dim);
    white-space: nowrap;
}
.mf-teams { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.mf-team { display: flex; align-items: center; gap: 7px; min-width: 0; }
.mf-name {
    font-size: 0.9rem;
    font-weight: 550;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.mf-stat {
    font-variant-numeric: tabular-nums;
    font-size: 0.86rem;
    font-weight: 600;
    color: var(--text-mid);
    white-space: nowrap;
}
.mf-score {
    font-variant-numeric: tabular-nums;
    font-size: 0.86rem;
    font-weight: 600;
    color: var(--text-mid);
    white-space: nowrap;
}
.mf-probs { display: flex; gap: 4px; font-size: 0.76rem; }
.mf-prob {
    min-width: 42px;
    text-align: center;
    padding: 3px 6px;
    border-radius: var(--radius-sm);
    background: var(--bg-sunken);
    border: 1px solid var(--border);
    color: var(--text-dim);
    font-variant-numeric: tabular-nums;
}
/* The model's own favourite, so a scan down the column reads as a column of
   calls rather than three equal numbers. Red = brand emphasis, not "good". */
.mf-prob.top {
    color: var(--text);
    border-color: var(--red-line);
    background: var(--red-wash);
    font-weight: 600;
}
.mf-note { font-size: 0.78rem; margin: 8px 2px 0; }
/* Desktop: the stats wrapper steps aside so its 4 cells stay direct grid
   items under the header; the per-number labels are for screen readers only
   (the header says it visually); the split bar is phone-only. */
.mf-stats { display: contents; }
.mf-label {
    position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.mf-split { display: none; }

/* -- "Upcoming Fixtures": per-league subheading nested under a day heading,
   replacing the league crest that used to repeat on every row (mini_fixture
   in _macros.html). Same red skewed bar as every h2 (style.css, top of this
   file), one size down, so it reads as a real heading in the page's own
   grammar rather than a label -- holds up whether a day has one league or
   several. */
.mf-league-head {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 14px 0 8px;
}
.mf-day + .mf-league-head { margin-top: 0; }
.mf-league-head::before {
    content: "";
    flex: none;
    width: 6px;
    height: 16px;
    background: var(--red);
    transform: skewX(-20deg);
}
.mf-league-head span {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 1.1rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text);
}

/* -- search results (topbar type-ahead) -- */
.ts-item a {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 7px 10px;
    border-radius: var(--radius-sm);
    text-decoration: none;
    color: var(--text);
    transition: background var(--ease);
}
.ts-item a:hover, .ts-item a:focus-visible { background: var(--bg-card-hover); }
.ts-name {
    font-size: 0.88rem;
    font-weight: 550;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.ts-league {
    margin-left: auto;
    font-size: 0.68rem;
    color: var(--text-dim);
    white-space: nowrap;
    flex-shrink: 0;
}

/* -- feature cards -- */
.feature-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(270px, 1fr));
    gap: 12px;
}
.feature-card {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 0;
    text-decoration: none;
    color: inherit;
}
.feature-card:hover, .feature-card:focus-visible {
    border-color: var(--red-line);
    background: var(--bg-card-hover);
}
.feature-icon { font-size: 1.5rem; line-height: 1; }
.feature-card h3 {
    margin: 0;
    font-size: 0.95rem;
    text-transform: none;
    letter-spacing: -0.01em;
    color: var(--text);
}
.feature-card p { margin: 0; font-size: 0.86rem; color: var(--text-mid); flex: 1; }
.feature-card .btn-link { margin-top: 2px; }

/* -- headline stats -- */
.stats-bar {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 8px;
    text-align: center;
    padding: 22px 20px;
    margin-bottom: 10px;
}
.stat-cell { display: flex; flex-direction: column; gap: 2px; }
.stat-num {
    font-size: 1.55rem;
    font-weight: 680;
    letter-spacing: -0.03em;
    font-variant-numeric: tabular-nums;
}
.stat-label {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.09em;
    color: var(--text-dim);
}

/* League tag on a live card — only ever set on the landing page's
   cross-league strip; /live's cards are all one league already. */
.live-card-league {
    font-size: 0.64rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-dim);
    font-weight: 650;
}


.live-card-top:has(.live-card-league) {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
}

/* -- topbar search (sits before the league dropdown) --
   Two elements, not one: `.topbar-search-wrap` is the positioned flex item
   (and the dropdown's offset parent); `.topbar-search` is the visible box.
   The shape is a HALF parallelogram: a straight left edge carrying the 3px
   red brand tick, and a right edge that leans at the same --slant as the
   league picker's (top further right than bottom). A border can't follow a
   clip-path, so the box is two stacked, identically clipped layers: ::before
   is the outline colour (plus the tick), ::after is the fill inset by --bw.
   --lean is height * tan(18deg), the horizontal run of the slanted edge; the
   0.376/0.274 terms keep the outline an even --bw wide along it. The input
   and icon are ordinary upright children. The dropdown panel stays a sibling
   of the box, not a child, so it never inherits the box's stacking context. */
.topbar-search-wrap { position: relative; flex-shrink: 0; }
.topbar-search {
    --search-h: 36px;
    --lean: calc(var(--search-h) * 0.3249);
    --bw: 1px;
    position: relative;
    isolation: isolate;
    display: flex;
    align-items: center;
    box-sizing: border-box;
    height: var(--search-h);
    width: 130px;
    max-width: 100%;
    background: none;
    transition: width var(--ease);
}
.topbar-search::before,
.topbar-search::after {
    content: "";
    position: absolute;
    z-index: -1;
}
.topbar-search::before {
    inset: 0;
    background: linear-gradient(var(--red), var(--red)) 0 0 / 3px 100% no-repeat, var(--border-strong);
    clip-path: polygon(0 0, 100% 0, calc(100% - var(--lean)) 100%, 0 100%);
    transition: background-color var(--ease);
}
.topbar-search::after {
    inset: var(--bw) var(--bw) var(--bw) 3px;
    background: var(--bg-input);
    clip-path: polygon(0 0, calc(100% - 0.376 * var(--bw)) 0, calc(100% - var(--lean) + 0.274 * var(--bw)) 100%, 0 100%);
}
.topbar-search-wrap:focus-within .topbar-search,
.topbar-search-wrap:has(.topbar-search-input:not(:placeholder-shown)) .topbar-search {
    --bw: 2px;
    width: 230px;
}
.topbar-search-wrap:focus-within .topbar-search::before,
.topbar-search-wrap:has(.topbar-search-input:not(:placeholder-shown)) .topbar-search::before {
    background-color: var(--red-line);
}
/* Compound selector, not just `.topbar-search-icon`: beats the generic
   `.ui-icon { width: 100%; height: 100% }` rule regardless of which comes
   later in the cascade (the broadcast layer at the end of this file redefines
   plenty of single-class selectors, and specificity is safer here than
   depending on source order). */
.topbar-search .topbar-search-icon { width: 13px; height: 13px; flex: none; align-self: center; margin-left: 12px; color: var(--text-dim); }
.topbar-search-input {
    flex: 1;
    min-width: 0;
    align-self: stretch;
    padding: 0 14px 0 7px;
    font-size: 0.82rem;
    font-family: inherit;
    color: var(--text);
    background: none;
    border: none;
    outline: none;
}
.topbar-search-input::placeholder {
    color: var(--text-dim);
    font-family: var(--font-display);
    font-size: 0.78rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}
.topbar-search-panel {
    position: absolute;
    top: calc(100% + 8px);
    left: 0;
    z-index: 60;
    width: 320px;
    max-width: 78vw;
    padding: 10px;
    background: var(--bg-card);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    box-shadow: var(--shadow-search);
}
.topbar-search-tabs { display: flex; gap: 6px; margin-bottom: 10px; }
.ts-tab {
    flex: 1;
    font-family: var(--font-display);
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    padding: 6px 8px;
    background: transparent;
    border: 1px solid var(--border-strong);
    border-radius: 2px;
    color: var(--text-dim);
}
.ts-tab.is-active { background: var(--bg-card-hover); border-color: var(--red-line); color: var(--text); }
.topbar-search-results,
.topbar-search-empty {
    margin: 0;
    padding: 0;
    list-style: none;
    max-height: 300px;
    overflow-y: auto;
}
.topbar-search-empty { padding: 8px 2px; font-size: 0.82rem; color: var(--text-dim); }
.topbar-search-results .ts-item a { padding: 8px 10px; }
.topbar-search-results .ts-league { font-size: 0.66rem; }
/* Player rows show a headshot (.player-avatar), scaled down to match the
   18px crest teams/referees use in the same list. */
.topbar-search-results .ts-avatar { width: 18px; height: 23px; border-radius: 3px; }
.topbar-search-results .ts-avatar .player-avatar-initials { font-size: 0.5rem; }

/* -- game of the week -- */
.gotw {
    display: block;
    padding: 22px 24px;
    background:
        radial-gradient(120% 140% at 0% 0%, var(--red-wash) 0%, transparent 60%),
        var(--bg-card);
    border: 1px solid var(--red-line);
    border-radius: var(--radius);
    text-decoration: none;
    color: inherit;
    transition: border-color var(--ease), background var(--ease);
}
.gotw:hover, .gotw:focus-visible { border-color: var(--red); }
.gotw-head {
    display: flex;
    align-items: baseline;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 16px;
}
.gotw-tag {
    font-size: 0.64rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: var(--red);
}
.gotw-reason { font-size: 0.86rem; color: var(--text-mid); }
.gotw-teams {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: clamp(14px, 5vw, 46px);
    flex-wrap: wrap;
}
.gotw-side { display: flex; align-items: center; gap: 11px; min-width: 0; }
.gotw-name {
    font-size: clamp(1.05rem, 2.6vw, 1.4rem);
    font-weight: 660;
    letter-spacing: -0.02em;
}
.gotw-pos {
    font-size: 0.68rem;
    color: var(--text-dim);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-pill);
    padding: 1px 7px;
    flex-shrink: 0;
}
.gotw-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    margin-top: 18px;
    padding-top: 14px;
    border-top: 1px solid var(--border);
}
.gotw-when {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 0.8rem;
    color: var(--text-dim);
}
.gotw-probs { display: flex; gap: 4px; }


/* -- league box top-3 table -- */
.league-box-table { display: flex; flex-direction: column; gap: 5px; }
.lb-row {
    display: grid;
    grid-template-columns: 14px auto minmax(0, 1fr) auto auto;
    align-items: center;
    gap: 7px;
    font-size: 0.82rem;
}
.lb-pos { color: var(--text-dim); font-variant-numeric: tabular-nums; text-align: right; }
.lb-club { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 550; }
.lb-pts {
    font-variant-numeric: tabular-nums;
    color: var(--text-mid);
    font-weight: 600;
    min-width: 20px;
    text-align: right;
}
.lb-row .form-run { gap: 2px; }
.lb-row .form-pill { width: 15px; height: 15px; font-size: 0.55rem; line-height: 15px; }

/* -- biggest movers -- */
.movers-section { margin-top: 40px; }
.movers-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 12px;
}
.movers-col { margin: 0; padding: 16px 18px; }
.movers-head { margin: 0 0 10px; font-size: 0.68rem; }
.movers-head.up { color: var(--green-bright); }
.movers-head.down { color: var(--red); }
.mover {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center;
    gap: 9px;
    padding: 8px 10px;
    margin: 0 -10px;
    border-radius: var(--radius-sm);
    text-decoration: none;
    color: inherit;
    transition: background var(--ease);
}
.mover:hover, .mover:focus-visible { background: var(--bg-card-hover); }
.mover-name {
    font-size: 0.9rem;
    font-weight: 550;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.mover-delta {
    font-variant-numeric: tabular-nums;
    font-weight: 650;
    font-size: 0.84rem;
    min-width: 48px;
    text-align: right;
}
.mover-delta.up { color: var(--green-bright); }
.mover-delta.down { color: var(--red); }

/* -- live "view more" -- */
.live-more {
    display: inline-block;
    margin-top: 4px;
    background: none;
    border: 0;
    padding: 6px 0;
    cursor: pointer;
    font: inherit;
}

@media (max-width: 900px) {
    .topbar-search { width: 110px; }
    .topbar-search-wrap:focus-within .topbar-search,
    .topbar-search-wrap:has(.topbar-search-input:not(:placeholder-shown)) .topbar-search { width: 170px; }
}
@media (max-width: 640px) {
    .topbar-search-wrap { order: 3; width: 100%; }
    .topbar-search { width: 100%; }
    .topbar-search-panel { width: 100%; max-width: none; }
    .gotw-teams { gap: 10px; }
}

/* ------------------------------------------------- live card, split layout */

/* The live match on a fixture's own page (#live-fixture-panel) renders as
   two separate cards side by side once there's room (past 700px, the same
   threshold the post-match report's own two-column stat grid uses): the
   score/stats card, and a dedicated "Key events" card next to it. Below
   700px, and on the grid/landing pages' own `layout='stacked'` cards
   (untouched by any of this), they stack instead. */
.live-events-layout {
    display: flex;
    flex-direction: column;
    gap: 12px;
}
@media (min-width: 700px) {
    .live-events-layout {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 12px;
        align-items: start;
    }
}
.live-events-card { display: flex; flex-direction: column; }
.live-events-card h2 { margin-top: 0; margin-bottom: 12px; }
/* The "Match stats" heading right below the score already reads as a
   divider on its own (uppercase, dimmed, spaced) -- .live-card-stats' usual
   top border/padding (added for the contexts where it follows something
   with no heading of its own) would just double it up here. */
.live-card-split h3 + .live-card-stats { margin-top: 0; padding-top: 0; border-top: none; }
/* The feed tails live -- newest event at the bottom, app.js keeps it
   scrolled there as events arrive unless the reader has scrolled up (see
   refreshFixture's isStuckToBottom). max-height here is a static fallback
   cap (and what governs it below the 700px breakpoint, where the two cards
   stack and "match stats' height" has no meaning) -- side by side, app.js::
   syncLiveEvents overrides it inline to match #live-stats-card's own height
   instead, same mechanism as the post-match report's #key-events-scroll
   (see that rule's own comment), revealing #live-events-more only when the
   feed is actually taller than that. */
.live-events-feed {
    max-height: 55vh;
    overflow-y: auto;
    scroll-behavior: smooth;
    padding-right: 4px;
}
.live-events-more { align-self: center; margin-top: 10px; }
/* Same author-origin-beats-user-agent cascade gotcha as .key-events-more
   (see that rule's own comment in this file) -- .btn-link's own
   `display: inline-block` otherwise wins over the browser's default
   `[hidden] { display: none }` regardless of specificity. */
.live-events-more[hidden] { display: none; }
/* "Who's on top" derived callout (ingest/sportmonks_live.py::
   _momentum_callout) -- sits above the feed, not inside it: it's a running
   "as of now" read on the last 10 minutes, not a point-in-time event, so it
   doesn't belong in the permanent append-only timeline below it. */
.live-momentum-note {
    border-left: 2px solid var(--blue);
    padding: 6px 0 6px 12px;
    margin: 0 0 12px;
    font-size: 0.82rem;
    color: var(--text-mid);
}
/* Match-level period markers (kick-off/half-time/second-half/full-time)
   read as a section divider rather than a team's event -- centered icon+text,
   no side-indented team column to line up (there's no team). */
.match-event.side-neutral {
    color: var(--text-dim);
}
.match-event.side-neutral .match-event-text { color: var(--text-dim); font-weight: 650; }

/* "Did you know" trend callouts -- reuses .card.callout's existing left-rule
   treatment (already used elsewhere for a single warning line) for a list. */
.trend-callouts h2 { margin-top: 0; }
.trend-list { margin: 0; padding-left: 20px; display: flex; flex-direction: column; gap: 8px; }
.trend-list li { color: var(--text-mid); font-size: 0.9rem; }
.trend-list li strong { color: var(--text); }

/* Once there are more than two facts, split into a left/right pair of
   columns (grid-auto-flow: column fills the left column first, then the
   right) rather than one long stack. A grid instead of floats so each
   column has real width and long sentences wrap inside their own column
   instead of overlapping the other -- collapses back to the single-column
   flex layout above once the card gets too narrow for two to read cleanly. */
.trend-list.trend-list-2col {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    grid-template-rows: repeat(2, auto);
    grid-auto-flow: column;
    column-gap: 28px;
    row-gap: 8px;
}
@media (max-width: 560px) {
    .trend-list.trend-list-2col {
        display: flex;
        flex-direction: column;
    }
}

.referee-lean { margin: 8px 0 0; }

/* Radar/spider team comparison: two overlaid SVG polygons over 5 fixed axes
   (analysis.radar_values) -- home in red, away in blue, matching the same
   colour convention as the live-match stat bars (.bar-home/.bar-away). */
.radar-chart { display: flex; flex-direction: column; align-items: center; gap: 10px; }
.radar-svg { width: 100%; max-width: 380px; height: auto; overflow: visible; }
.radar-spoke { stroke: var(--border-strong); stroke-width: 1; }
.radar-poly { stroke-width: 2; fill-opacity: 0.22; }
.radar-poly.radar-home { stroke: var(--red); fill: var(--red); }
.radar-poly.radar-away { stroke: var(--blue); fill: var(--blue); }
.radar-legend { flex-direction: row; gap: 18px; }
.pie-legend.radar-legend .swatch.radar-swatch-home { background: var(--red); }
.pie-legend.radar-legend .swatch.radar-swatch-away { background: var(--blue); }
.radar-label { fill: var(--text-dim); font-size: 13px; text-transform: uppercase; letter-spacing: 0.03em; }

/* FPL-style fixture-difficulty badge (1 easiest - 5 hardest opponent),
   green -> amber -> red across the 5 tiers. */
.fdr {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 18px;
    height: 18px;
    padding: 0 4px;
    border-radius: 4px;
    font-size: 0.7rem;
    font-weight: 700;
    color: var(--on-away);
    margin-left: 4px;
}
.fdr-1 { background: var(--green); }
.fdr-2 { background: var(--green-bright); }
.fdr-3 { background: var(--draw); color: var(--text); }
.fdr-4 { background: var(--warn); }
.fdr-5 { background: var(--red); color: var(--on-red); }

/* --- Players index -----------------------------------------------------
   Team/position filter bar (vanilla JS, see app.js) sits above one section
   per club (alphabetical), each a grid of player cards. Cards deliberately
   echo a FUT-style ultimate-team card (portrait plate, corner number/
   position, a small stat block) without borrowing its gold/blue palette or
   its fabricated 1-99 rating -- see analysis.card_stats' docstring for why
   there's no single "OVR" number here. */
.players-filter-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 16px;
    margin-bottom: 20px;
    padding: 14px 16px;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
}
.players-filter-field {
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-dim);
}
.players-filter-select {
    font: inherit;
    font-size: 0.86rem;
    font-weight: 500;
    text-transform: none;
    letter-spacing: normal;
    color: var(--text);
    background: var(--bg-input);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    padding: 7px 10px;
    min-width: 180px;
}
.players-filter-select:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.players-filter-count { font-size: 0.8rem; margin-left: auto; }

.players-team-group { margin-bottom: 34px; }
.players-team-heading { margin: 0 0 14px; }
.players-team-heading .team-name {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    color: var(--text);
    text-decoration: none;
    font-size: 1.1rem;
    font-weight: 700;
    letter-spacing: -0.01em;
}
.players-team-heading .team-name:hover { color: var(--red-bright); }
.players-team-group[hidden] { display: none; }

.player-card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 14px;
}
.player-card {
    display: flex;
    flex-direction: column;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
    color: inherit;
    text-decoration: none;
    transition: border-color var(--ease), background var(--ease), transform var(--ease);
}
.player-card:hover {
    border-color: var(--red-line);
    background: var(--bg-card-hover);
    transform: translateY(-2px);
}
.player-card[hidden] { display: none; }
.player-card.is-out { opacity: 0.55; }
.player-card.is-out:hover { opacity: 0.85; }
.player-card-photo {
    position: relative;
    aspect-ratio: 1 / 1;
    background: linear-gradient(180deg, var(--photo-well), var(--bg-card) 85%);
    border-bottom: 1px solid var(--photo-ring);
    overflow: hidden;
}
.player-card-photo .player-avatar-initials {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.6rem;
    font-weight: 700;
    color: var(--text-dim);
}
.player-card-photo .player-photo,
.player-hero-photo .player-photo {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: top center;
}
.player-card-number {
    position: absolute;
    top: 6px;
    left: 8px;
    font-size: 0.82rem;
    font-weight: 800;
    color: var(--text-mid);
    z-index: 1;
    text-shadow: var(--photo-text-shadow);
}
.player-card-pos {
    position: absolute;
    top: 6px;
    right: 8px;
    font-size: 0.64rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    color: var(--text);
    background: var(--photo-badge-bg);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    padding: 1px 6px;
    z-index: 1;
}
.player-card-body {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 10px 12px 12px;
}
.player-card-name {
    font-weight: 700;
    font-size: 0.9rem;
    color: var(--text);
    letter-spacing: -0.01em;
    line-height: 1.2;
}
.player-card-team {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 0.72rem;
    color: var(--text-dim);
}
.player-card-stats {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 6px 10px;
    margin-top: 4px;
    padding-top: 8px;
    border-top: 1px solid var(--border);
}
.player-card-stat { display: flex; flex-direction: column; }
.player-card-stat-val {
    font-size: 0.92rem;
    font-weight: 700;
    color: var(--text);
    font-variant-numeric: tabular-nums;
}
.player-card-stat-label {
    font-size: 0.62rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-dim);
}
.player-card-flag, .player-hero-flag {
    display: inline-flex;
    width: fit-content;
    font-size: 0.66rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    padding: 2px 7px;
    border-radius: var(--radius-pill);
    border: 1px solid var(--border-strong);
}
.flag-out { color: var(--flag-out); border-color: var(--flag-out-line); }
.flag-maybe { color: var(--flag-maybe); border-color: var(--flag-maybe-line); }
.flag-ok { color: var(--green-bright); border-color: var(--green-line); }
.player-hero-flag { font-size: 0.72rem; padding: 3px 10px; }
.players-empty { margin-top: 24px; }

/* --- Player detail hero ------------------------------------------------- */
.player-hero {
    display: flex;
    gap: 24px;
    align-items: flex-start;
    margin-bottom: 20px;
}
.player-hero-photo {
    position: relative;
    flex: 0 0 auto;
    width: 148px;
    height: 148px;
    border-radius: var(--radius);
    background: linear-gradient(180deg, var(--photo-well), var(--bg-card) 85%);
    border: 1px solid var(--photo-ring);
    overflow: hidden;
}
.player-hero-photo .player-avatar-initials {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 2.6rem;
    font-weight: 700;
    color: var(--text-dim);
}
.player-hero-id { flex: 1 1 auto; min-width: 0; }
.player-hero-id h1 { margin: 0 0 2px; }
.player-hero-known-as { margin: 0 0 2px; }
.player-hero-stats {
    margin-top: 14px;
    padding-top: 14px;
    border-top: 1px solid var(--border);
    grid-template-columns: repeat(4, minmax(70px, 120px));
}
.player-hero-stats .player-card-stat-val { font-size: 1.15rem; }
@media (max-width: 640px) {
    .player-hero { flex-direction: column; align-items: center; text-align: center; }
    .player-hero-stats { grid-template-columns: repeat(2, minmax(70px, 120px)); justify-content: center; }
}

/* --- Players/Referees tab toggle (players.html, referees.html) --------- */
.prf-toggle {
    display: inline-flex;
    gap: 4px;
    padding: 4px;
    margin-bottom: 18px;
    background: var(--bg-input);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-pill);
}
.prf-toggle-tab {
    padding: 6px 18px;
    border-radius: var(--radius-pill);
    font-size: 0.86rem;
    font-weight: 700;
    color: var(--text-dim);
    text-decoration: none;
    transition: background var(--ease), color var(--ease);
}
.prf-toggle-tab:hover { color: var(--text); }
.prf-toggle-tab.active { background: var(--red-wash); color: var(--text-strong); }

/* --- Referee panel heading (fixture page) ------------------------------- */
.referee-panel-heading {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-bottom: 4px;
    color: inherit;
    text-decoration: none;
}
.referee-panel-avatar {
    flex: 0 0 auto;
    width: 56px;
    height: 56px;
    border-radius: 50%;
    border: 1px solid var(--photo-ring);
}
.referee-panel-avatar .player-avatar-initials { font-size: 1.1rem; }
.referee-panel-heading-text { display: flex; flex-direction: column; gap: 2px; }
.referee-panel-heading-text h2 { margin: 0; }
.referee-panel-name { margin: 0; color: var(--text-strong); }
.referee-panel-heading:hover .referee-panel-name { color: var(--red-bright); }

.player-rank-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.player-rank-list li { font-size: 0.88rem; color: var(--text-mid); }
.player-rank-list strong { color: var(--text); font-variant-numeric: tabular-nums; }

.historic-bets-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.historic-bets-list li {
    display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px;
    padding: 10px 0; border-bottom: 1px solid var(--border);
}
.historic-bets-list li:last-child { border-bottom: none; }
.hb-rank {
    flex: 0 0 auto; width: 20px; height: 20px; border-radius: 50%;
    background: var(--bg-sunken); color: var(--text-dim); font-size: 0.72rem; font-weight: 700;
    display: flex; align-items: center; justify-content: center;
}
.hb-label { flex: 1 1 auto; font-weight: 600; color: var(--text); }
.hb-prob { flex: 0 0 auto; font-weight: 800; font-style: italic; font-variant-numeric: tabular-nums; color: var(--green-bright); }
.hb-sample { flex-basis: 100%; font-size: 0.78rem; }
/* Entity tag (team or player name) -- only needed where a single list pools
   several subjects (the fixture page's Team/Player columns), unlike the
   player page's own Historic Bets list where the subject is fixed and named
   once in the card's own intro line. */
.hb-entity {
    flex: 0 0 auto; display: inline-flex; align-items: center; gap: 6px;
    font-weight: 600; color: var(--text-mid); text-decoration: none;
}
.hb-entity:hover { color: var(--red-bright); text-decoration: underline; }
.hb-avatar {
    position: relative; flex: 0 0 auto; width: 48px; height: 48px;
    border-radius: var(--radius-pill); background: var(--photo-well);
    border: 1px solid var(--photo-ring); overflow: hidden;
    display: flex; align-items: center; justify-content: center;
}
.hb-avatar-initials { font-size: 1.2rem; font-weight: 700; color: var(--text-dim); }
.hb-avatar img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

/* Fixture page's Historic Bets card: a market menu rail. The left menu lists
   every category (Team group, Player group) and the panel beside it shows the
   chosen one; it is the generic .variant-switcher, so every panel is in the
   page and a click only swaps `hidden`. Phones turn the rail into a sideways
   row of slanted chips (see the 760px block below). Without JS the rail is
   hidden and every panel shows in turn, each with its own title. */
.hb-rail-layout {
    display: grid; grid-template-columns: 224px minmax(0, 1fr);
    border: 1px solid var(--border); background: var(--bg-card);
}
html:not(.js) .hb-rail { display: none; }
html:not(.js) .hb-rail-switcher .variant-panel[hidden] { display: block; }
html:not(.js) .hb-rail-layout { grid-template-columns: minmax(0, 1fr); }
.hb-rail { background: var(--bg-tile); border-right: 1px solid var(--border); min-width: 0; }
/* "Team" / "Player" section headings: a sunken band with the site's skewed red
   bar and white text one step larger than the entries, so it is plain where
   each group of categories starts. */
.hb-rail-group {
    display: flex; align-items: center; gap: 10px;
    padding: 13px 16px 11px 16px;
    background: var(--bg-sunken);
    border-bottom: 1px solid var(--border);
    font-family: var(--font-display); font-weight: 800; font-size: 1.2rem;
    letter-spacing: 0.14em; text-transform: uppercase; color: var(--text-strong);
}
.hb-rail-group::before {
    content: ""; flex: none; width: 6px; height: 20px;
    background: var(--red); transform: skewX(var(--slant));
}
.hb-rail .hb-rail-tab {
    position: relative; isolation: isolate;
    display: flex; align-items: center; justify-content: space-between; gap: 8px;
    width: 100%; padding: 8px 12px 8px 22px;
    background: none; border: 0; border-bottom: 1px solid var(--border); border-radius: 0;
    text-align: left; cursor: pointer;
    font-family: var(--font-display); font-weight: 700; font-size: 0.95rem;
    letter-spacing: 0.07em; text-transform: uppercase; color: var(--text-mid);
}
.hb-rail .hb-rail-tab::before {
    content: ""; position: absolute; left: 8px; top: 7px; bottom: 7px; width: 4px;
    background: transparent; transform: skewX(var(--slant));
}
.hb-rail .hb-rail-tab:hover { background: var(--hover-tint-mid); border-color: var(--border); color: var(--text-strong); }
.hb-rail .hb-rail-tab.on { background: var(--tab-wash); color: var(--text-strong); }
.hb-rail .hb-rail-tab.on::before { background: var(--red); }
.hb-rail-count { font-weight: 600; font-size: 0.82rem; letter-spacing: 0.04em; color: var(--text-dim); }
.hb-rail-panels { min-width: 0; padding: 18px 22px 10px; }
.hb-panel-kicker {
    font-family: var(--font-display); font-weight: 700; font-size: 0.8rem;
    letter-spacing: 0.16em; text-transform: uppercase; color: var(--red-bright); margin: 0 0 4px;
}
.hb-panel .hb-panel-kicker + .historic-bets-list { margin-top: 4px; }
.hb-panel .historic-bets-list + .hb-panel-kicker { margin-top: 22px; }
/* Team / Player sections inside "Top 5 Bangers": the rail's group heading
   (.hb-rail-group) one size down, so the two lists read as two parts. */
.hb-top-group {
    display: flex; align-items: center; gap: 9px;
    margin: 0 0 4px; padding: 8px 12px 7px;
    background: var(--bg-sunken); border-bottom: 1px solid var(--border);
    font-family: var(--font-display); font-weight: 800; font-size: 1rem;
    letter-spacing: 0.14em; text-transform: uppercase; color: var(--text-strong);
}
.hb-top-group::before {
    content: ""; flex: none; width: 5px; height: 15px;
    background: var(--red); transform: skewX(var(--slant));
}
.hb-panel .historic-bets-list + .hb-top-group { margin-top: 22px; }
/* Longer labels ("... in the Match") wrap inside their own space instead of
   pushing the percentage onto a line of its own in a narrow panel. */
.historic-bets-top .hb-label { flex: 1 1 0; min-width: 12ch; }
.hb-panel-title {
    display: flex; align-items: center; gap: 12px; margin: 0 0 4px;
    font-family: var(--font-display); font-style: italic; font-weight: 800;
    font-size: 1.4rem; line-height: 1.1; letter-spacing: 0.045em; text-transform: uppercase;
    color: var(--text);
}
.hb-panel-title::before {
    content: ""; flex: none; width: 9px; height: 22px; background: var(--red);
    transform: skewX(-20deg);
}
.hb-panel-sub { margin: 0 0 12px; }
/* Phone: the rail becomes a slide-out drawer (same list, same selected style)
   opened from a bar pinned above the panel, and the bar's arrows step to the
   previous / next category. The head, bar and scrim are phone and JS only.
   Z-indexes sit with the site's own menu drawer (99 scrim, 100 panel); only
   one of them is open at a time. */
.hb-bar, .hb-rail-head, .hb-scrim { display: none; }
@media (max-width: 760px) {
    .hb-rail-layout { grid-template-columns: minmax(0, 1fr); border: 0; background: none; }
    html.js .hb-bar {
        display: block; position: sticky; top: 0; z-index: 6;
        margin: 0 -2px; padding: 8px 2px 10px; background: var(--bg-card);
    }
    .hb-bar-box {
        display: flex; align-items: stretch;
        background: var(--bg-tile); border: 1px solid var(--border); border-left: 3px solid var(--red);
    }
    .hb-bar .hb-bar-arr, .hb-bar .hb-bar-mid {
        background: none; border: 0; border-radius: 0; color: var(--text); cursor: pointer;
    }
    .hb-bar .hb-bar-arr:hover, .hb-bar .hb-bar-mid:hover { background: var(--hover-tint-mid); border-color: transparent; }
    .hb-bar .hb-bar-arr { flex: none; width: 46px; display: flex; align-items: center; justify-content: center; padding: 0; }
    .hb-bar .hb-bar-arr:first-child { border-right: 1px solid var(--border); }
    .hb-bar .hb-bar-arr:last-child { border-left: 1px solid var(--border); }
    .hb-bar .hb-bar-mid { flex: 1; min-width: 0; padding: 8px 6px; text-align: center; letter-spacing: 0; }
    .hb-bar-meta {
        display: block; font-family: var(--font-display); font-weight: 700; font-size: 0.72rem;
        letter-spacing: 0.16em; text-transform: uppercase; color: var(--text-dim); line-height: 1.1;
    }
    .hb-bar-name {
        display: block; font-family: var(--font-display); font-weight: 800; font-size: 1.2rem;
        letter-spacing: 0.05em; text-transform: uppercase; line-height: 1.15;
        white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    }
    .hb-bar-name svg { color: var(--text-dim); vertical-align: 1px; }

    /* `html.js .hb-open`, not `.hb-open` alone: the base rule above is
       `html.js .hb-scrim`, which outranks a bare `.hb-open .hb-scrim`, and
       the open state then never applied (an invisible, untappable scrim). */
    html.js .hb-scrim {
        display: block; position: fixed; inset: 0; z-index: 99; background: var(--scrim);
        opacity: 0; pointer-events: none; transition: opacity 0.28s ease;
        cursor: pointer; touch-action: none; -webkit-tap-highlight-color: transparent;
    }
    html.js .hb-open .hb-scrim { opacity: 1; pointer-events: auto; }

    /* the rail, off-canvas until .hb-open; visibility keeps it out of the tab
       order and away from screen readers while closed */
    .hb-rail {
        position: fixed; top: 0; bottom: 0; left: 0; z-index: 100;
        width: min(316px, 86vw); display: flex; flex-direction: column; overflow-y: auto;
        overscroll-behavior: contain;
        touch-action: pan-y;   /* vertical scroll stays the browser's; a sideways swipe is app.js's (swipe to close) */
        border-right: 1px solid var(--border-strong); box-shadow: none;
        transform: translateX(-102%); visibility: hidden;
        transition: transform 0.28s ease, visibility 0s linear 0.28s, box-shadow 0.28s ease;
    }
    .hb-open .hb-rail {
        transform: none; visibility: visible; box-shadow: var(--shadow-drawer);
        transition-delay: 0s;
    }
    /* while a finger is dragging the drawer it follows the finger with no easing */
    .hb-rail.hb-dragging { transition: none; }
    html.js .hb-scrim.hb-dragging { transition: none; }
    html.js .hb-rail-head {
        display: flex; align-items: center; justify-content: space-between; flex: none;
        height: 55px; padding: 0 8px 0 18px; border-top: 3px solid var(--red);
        border-bottom: 1px solid var(--border); background: var(--bg-card);
        position: sticky; top: 0; z-index: 1;
    }
    .hb-rail-head-title {
        font-family: var(--font-display); font-style: italic; font-weight: 800; font-size: 1.2rem;
        letter-spacing: 0.05em; text-transform: uppercase;
    }
    .hb-rail .hb-rail-close {
        width: 44px; height: 44px; padding: 0; display: flex; align-items: center; justify-content: center;
        background: none; border: 0; border-radius: 0; color: var(--text); cursor: pointer;
    }
    .hb-rail .hb-rail-tab { min-height: 44px; font-size: 1.05rem; padding-left: 28px; }
    .hb-rail .hb-rail-tab::before { left: 10px; top: 9px; bottom: 9px; }
    .hb-rail-count { font-size: 0.9rem; }
    .hb-rail-panels { padding: 6px 2px 6px; }
    .hb-panel-title { font-size: 1.25rem; }
}
/* Team crests in this panel are double the sitewide crest-sm (18px) rather
   than a shared size class, since the double-size ask was specific to this
   panel's icons, not every crest-sm use elsewhere (tables, leaderboard, ...).
   Baseline alignment on .historic-bets-list li (shared with the player
   page's single-subject list, which has no icon) reads oddly once the icon
   is this much taller than the text next to it, so this panel alone
   recentres the row. */
.hb-rail-switcher .crest { width: 36px; height: 36px; }
.hb-rail-switcher .crest-fallback { font-size: 1.1rem; }
.hb-rail-switcher .historic-bets-list li { align-items: center; }

.hb-category {
    border: 1px solid var(--border); border-radius: var(--radius); margin-top: 10px;
    overflow: hidden; background: var(--bg-sunken);
}
.hb-category summary {
    /* flex-start, not space-between: a box with no .hb-category-count (a
       summary with just one label span and no count) would otherwise
       get pushed to the row's far end -- svg.hb-arrow plus a single real
       label span is already "2 items" to space-between.
       margin-left: auto on .hb-category-count is what actually pins the
       count to the right, independent of how many items came before it. */
    display: flex; align-items: center; justify-content: flex-start; gap: 10px;
    padding: 10px 14px; cursor: pointer; font-weight: 700; color: var(--text);
    list-style: none;
}
.hb-category summary::-webkit-details-marker { display: none; }
/* Down-pointing chevron, rotating 180° to point up on open -- same resting
   direction and rotation as the Form tab's .rm-chevron (they used to disagree:
   this one rested sideways and rotated 90°), and red-on-open like every other
   "active" affordance on the site (sortable table headers, the active subnav
   tab, .chip.on) rather than staying flat grey whether open or closed. A real
   flex item (svg.hb-arrow in the template) rather than a ::before pseudo-
   element -- see the flex-start note on .hb-category summary below, which
   still applies unchanged. */
.hb-arrow {
    flex: 0 0 auto; color: var(--text-dim);
    transition: transform 0.18s ease, color 0.18s ease;
}
.hb-category[open] .hb-arrow { color: var(--red-bright); transform: rotate(180deg); }
.hb-category-count { font-weight: 400; font-size: 0.8rem; margin-left: auto; }
.hb-category-body { padding: 4px 14px 6px; background: var(--bg); }
/* Home/away badge strip above a Player category's rows -- see
   hb_category_teams' own comment for why Team categories don't need one. */
.hb-category-teams {
    display: flex; align-items: center; justify-content: space-between;
    padding: 8px 0; margin-bottom: 4px; border-bottom: 1px solid var(--border);
}
.hb-category-teams .hb-entity { font-size: 0.85rem; }

.hb-row { padding: 10px 0; border-bottom: 1px solid var(--border); }
.hb-row:last-child { border-bottom: none; }
.hb-row-label { font-size: 0.82rem; color: var(--text-mid); margin-bottom: 6px; }
.hb-row-sides { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 14px; }
.hb-side {
    display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; min-width: 0;
}
.hb-side-home { justify-content: flex-start; }
.hb-side-away { justify-content: flex-end; text-align: right; }
.hb-side .hb-entity { font-size: 0.9rem; }
.hb-side .hb-avatar { width: 32px; height: 32px; }
.hb-side .hb-avatar-initials { font-size: 0.85rem; }
/* The % reading -- always its own line under the name/crest, never sharing
   it, so a short team name ("Leeds") and a long player name ("Dominic
   Calvert-Lewin") lay out identically instead of the % only wrapping down
   once the name is too long to share a line (the bug this replaced: team
   and player rows used to disagree on where the % landed). Same display-face
   number + meter treatment as .em-value/.em-meter (Event markets), so this
   panel's most important figure reads with the same weight as everywhere
   else on the site that shows a big number over a bar. */
.hb-prob-row { flex-basis: 100%; display: flex; flex-direction: column; gap: 3px; }
.hb-prob-row .hb-prob { font-size: 1.2rem; line-height: 1.05; }
.hb-prob-meter { position: relative; display: block; height: 5px; background: var(--track); transform: skewX(-25deg); }
.hb-prob-meter-fill { position: absolute; left: 0; top: 0; bottom: 0; background: var(--red); }
.hb-side-away .hb-prob-row .hb-prob { text-align: right; }
/* Away side reads right-aligned (name, %), so its fill grows from the right
   too -- fixed to the left edge like the home side left the number stranded
   over empty track whenever the reading was well under 100%. */
.hb-side-away .hb-prob-meter-fill { left: auto; right: 0; }
.hb-side .hb-sample { flex-basis: 100%; font-size: 0.72rem; }
.hb-side-away .hb-sample { text-align: right; }
.hb-none { font-size: 0.85rem; }

.hb-category-teams-phone { display: none; }

@media (max-width: 480px) {
    /* Phone width: the two sides stay side by side (home left, away right,
       as on desktop) rather than stacking, which used to make every market
       half a screen tall -- too long once the panel grew past 100 markets.
       To fit, team rows drop the club name and keep the crest (the
       .hb-category-teams-phone strip at the top of each box names both
       clubs once), and player names wrap rather than truncate. */
    .hb-row-sides { gap: 6px 16px; }
    .hb-category-teams-phone { display: flex; }
    .hb-side .hb-entity-team > span {
        position: absolute; width: 1px; height: 1px; overflow: hidden;
        clip: rect(0 0 0 0); white-space: nowrap;
    }
    .hb-side .hb-entity { font-size: 0.82rem; min-width: 0; overflow-wrap: anywhere; }
    .hb-side .hb-avatar { width: 26px; height: 26px; }
    .hb-side .hb-prob-row .hb-prob { font-size: 1.05rem; }
    /* Two long club names ("Borussia Dortmund", "Werder Bremen") no longer
       fit on one line: give each half the row and let the name wrap. */
    .hb-category-teams { gap: 12px; align-items: flex-start; }
    .hb-category-teams .hb-entity { flex: 1 1 0; min-width: 0; overflow-wrap: anywhere; }
    .hb-category-teams .hb-entity:last-child { justify-content: flex-end; text-align: right; }
}

/* Historic Bets (career) and Recent Form (last 10) sit side by side above
   Season by season, equal columns across the same 20px gap perf-traits-row
   uses so their edges land exactly where that row's two columns do. With no
   Recent Form partner (too few appearances on file) Historic Bets keeps the
   half-width calc(50% - 10px) it always had -- a half-width card, not a
   full-width one stretched over a single short list. The row's own flex-wrap
   stacks the two once 2 x 380px plus the gap no longer fit; the 860px rule
   below only has to cover the lone card. */
.historic-bets-row { display: flex; align-items: stretch; gap: 20px; flex-wrap: wrap; margin-bottom: 12px; }
.historic-bets-row > .card { flex: 1 1 380px; min-width: 0; margin-bottom: 0; }
.historic-bets-row > .card:only-child { flex: 0 0 calc(50% - 10px); max-width: calc(50% - 10px); }
@media (max-width: 860px) {
    .historic-bets-row > .card:only-child { flex-basis: 100%; max-width: 100%; }
}

/* Recent Form: one hit/miss dot per match, oldest to newest. Filled red = the
   market landed (this player's own number, per the chart colour convention),
   hollow grey = it didn't. The strip and the "7 of 10 vs career" text share
   the row's second line (the strip first, the text pushed right) so each row
   is exactly as tall as its Historic Bets twin and the two lists line up; on
   a narrow card the text simply wraps beneath. */
.recent-form-list li { row-gap: 0; }
.rf-break { flex-basis: 100%; height: 0; }
.rf-strip { flex: 0 0 auto; display: flex; align-items: center; gap: 6px; min-height: 19px; margin-top: 4px; }
.recent-form-list .hb-sample { flex: 1 1 auto; text-align: right; margin-top: 4px; }
.rf-dot {
    flex: 0 0 auto; width: 12px; height: 12px; box-sizing: border-box;
    transform: skewX(-25deg);
}
.rf-dot.hit { background: var(--red); }
.rf-dot.miss { background: transparent; border: 1px solid var(--border-strong); }
.rf-trend { font-weight: 600; margin-left: 4px; }
.rf-trend.up { color: var(--text); }
.rf-trend.down { color: var(--red-bright); }
/* The trend arrow is drawn in the ARROWS block at the end of this file. */

/* --- Season Performance + [Player Traits, Squad standing], side by side
   (player page) -- Season Performance is the denser panel (a multi-
   section grid) so it gets its own column; Player Traits' radar already
   scales fluidly (.radar-svg is width:100% up to a max) so it compresses
   cleanly into a narrower column, with Squad standing stacked directly
   beneath it in that same column. Equal flex-basis with flex-wrap: below
   the width both columns need side by side, they fall back to the page's
   normal full-width stacked cards instead of squeezing unreadably. */
.perf-traits-row {
    display: flex;
    align-items: flex-start;
    gap: 20px;
    flex-wrap: wrap;
}
.perf-traits-row > .card, .perf-traits-row > .traits-col {
    flex: 1 1 380px;
    min-width: 0;
}
.perf-traits-row > .card { margin-bottom: 0; }
.traits-col { display: flex; flex-direction: column; gap: 12px; }
.traits-col > .card { margin-bottom: 0; }
.perf-traits-row:has(.stat-perf-card):has(.traits-col) { margin-bottom: 12px; }

/* --- Season Performance, merged (player page) ---------------------------
   A spreadsheet-style table: stats grouped into Shooting/Passing/
   Defending/Discipline/Goalkeeping sections via a full-width subheading
   row, Value and Season Avg across the top. Value/Avg both toggle Total
   <-> Per-90 (the two .variant-tab buttons, handled by app.js's existing
   generic .variant-switcher click delegate -- no new JS needed); only the
   Value cell is highlighted, against the positional-average comparison
   computed in analysis.player_stat_table -- green above average, red
   below, orange on par, neutral when there isn't enough peer data. */
.stat-perf-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 10px 16px;
    margin-bottom: 14px;
}
.stat-perf-minutes { margin: 0; }
.stat-value-tabs { margin-bottom: 0; }
.info-dot {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 15px;
    height: 15px;
    border-radius: 50%;
    border: 1px solid var(--border);
    color: var(--text-dim);
    font-size: 0.68rem;
    font-weight: 700;
    cursor: help;
    vertical-align: middle;
}
/* Native `title` tooltips are slow (OS hover delay) and easy to miss --
   this is a real hover/focus card instead, positioned below the icon so
   it never gets clipped by .table-scroll's overflow-x:auto (which the
   CSS spec computes overflow-y to `auto` too once overflow-x isn't
   `visible`, so anything popping ABOVE the header row's top edge would
   be cut off; below has the whole table body to render into). */
.info-tip {
    position: absolute;
    top: 130%;
    right: -6px;
    width: 240px;
    max-width: 60vw;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: 8px 10px;
    font-size: 0.72rem;
    font-weight: 400;
    text-transform: none;
    letter-spacing: normal;
    line-height: 1.4;
    color: var(--text-mid);
    box-shadow: var(--shadow-tip);
    opacity: 0;
    visibility: hidden;
    transition: opacity var(--ease);
    pointer-events: none;
    z-index: 20;
    white-space: normal;
}
.info-dot:hover .info-tip, .info-dot:focus .info-tip, .info-dot:focus-within .info-tip {
    opacity: 1;
    visibility: visible;
}
.stat-group-row td {
    padding-top: 18px;
    font-size: 0.72rem;
    font-weight: 650;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-dim);
    border-bottom: 1px solid var(--border);
}
.stat-group-row:first-child td { padding-top: 8px; }
.stat-value-cell, .stat-avg-cell { font-variant-numeric: tabular-nums; font-weight: 650; }
.stat-avg-cell { color: var(--text-dim); font-weight: 500; }
.stat-value-cell.cell-green { background: var(--green-wash); color: var(--green-bright); box-shadow: inset 2px 0 0 var(--green); }
.stat-value-cell.cell-red { background: var(--red-wash); color: var(--red-bright); box-shadow: inset 2px 0 0 var(--red); }
.stat-value-cell.cell-orange { background: var(--warn-wash); color: var(--warn); box-shadow: inset 2px 0 0 var(--warn); }

/* --- Player Traits list (percentile numbers beside the radar chart) ---- */
.traits-legend { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 6px 16px; }
.traits-legend li { display: flex; justify-content: space-between; gap: 8px; font-size: 0.82rem; color: var(--text-mid); padding: 4px 0; border-bottom: 1px solid var(--border); }
.traits-legend .traits-pct { font-weight: 650; font-variant-numeric: tabular-nums; }
.traits-legend .traits-pct.rank-1, .traits-legend .traits-pct.rank-2 { color: var(--green-bright); }
.traits-legend .traits-pct.rank-3 { color: var(--text-mid); }
.traits-legend .traits-pct.rank-4 { color: var(--warn); }
.traits-legend .traits-pct.rank-5 { color: var(--red-bright); }

/* --- Leaderboard page: one card per stat category, top 5 ranked rows,
   expandable to the full ranked list via .leaderboard-toggle (app.js) --- */
.leaderboard-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 16px;
    margin-top: 16px;
    /* Without this, CSS Grid's default stretch sizes every row track to its
       tallest card -- so expanding one card's list (up to ~880px, see
       .leaderboard-list) also stretched its unexpanded row-mates to match,
       leaving them with a large blank gap below their own 5 rows. Each
       card should only ever be as tall as its own content. */
    align-items: start;
}
.leaderboard-card {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 16px;
}
.leaderboard-card-header {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    margin-bottom: 12px;
}
.leaderboard-icon {
    font-size: 1.25rem;
    line-height: 1;
    flex-shrink: 0;
}
.leaderboard-title {
    margin: 0;
    font-size: 0.95rem;
    font-weight: 650;
    color: var(--text);
}
.leaderboard-subtitle {
    margin: 2px 0 0;
}
.leaderboard-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
    /* Collapsed, this is just 5 rows (~220px), well under the cap below, so
       there's nothing to scroll. Expanded via .leaderboard-toggle (app.js),
       the list grows to fit up to ~20 rows before this kicks in -- past
       that it scrolls internally instead of pushing the rest of the page
       down, while the "Show fewer" toggle stays reachable below it. */
    max-height: 880px;
    overflow-y: auto;
}
.leaderboard-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 6px;
    border-radius: var(--radius-sm);
    color: inherit;
    text-decoration: none;
    transition: background var(--ease);
}
.leaderboard-row:hover { background: var(--bg-card-hover); }
.leaderboard-rank {
    flex-shrink: 0;
    width: 20px;
    text-align: center;
    font-size: 0.82rem;
    font-weight: 700;
    color: var(--text-dim);
    font-variant-numeric: tabular-nums;
}
.leaderboard-rank.rank-1 { color: var(--accent); }
.leaderboard-row-photo {
    position: relative;
    flex-shrink: 0;
    width: 30px;
    height: 30px;
    border-radius: var(--radius-pill);
    background: var(--photo-well);
    border: 1px solid var(--photo-ring);
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
}
.leaderboard-row-photo img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}
.leaderboard-avatar-initials {
    font-size: 0.68rem;
    font-weight: 700;
    color: var(--text-dim);
}
.leaderboard-row-name {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 1px;
}
.leaderboard-row-name strong {
    font-size: 0.86rem;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.leaderboard-row-name strong .crest { margin-right: 6px; vertical-align: -3px; }
.leaderboard-row-team {
    display: flex;
    align-items: center;
    gap: 4px;
    font-size: 0.72rem;
    color: var(--text-dim);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.leaderboard-value {
    flex-shrink: 0;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--text);
}

/* On a phone, an expanded category (up to ~20 rows/880px, see
   .leaderboard-list above) can be taller than the whole viewport, so
   reaching "Show fewer" meant scrolling past every player row first --
   fighting the reader who actually wanted to scroll the page, not the
   list. Pinning it to the bottom of the screen while expanded means it's
   reachable from anywhere in that list and the card can still be
   collapsed upwards at any time. `position: sticky` (not `fixed`) keeps
   it scoped to its own card -- it never floats over a card that isn't
   expanded, and it scrolls away normally once the card's own bottom edge
   passes. `[data-expanded="true"]` is the same attribute app.js already
   toggles; no JS change needed for this. */
@media (max-width: 640px) {
    .leaderboard-toggle[data-expanded="true"] {
        display: block;
        position: sticky;
        bottom: 0;
        z-index: 5;
        width: 100%;
        margin-top: 0;
        padding: 10px 0;
        text-align: center;
        background: var(--bg-card);
        box-shadow: var(--shadow-sticky);
    }
}


/* ------------------------------------------------ league hub + footer nav */
/* The sitewide footer's league/page grid -- the only plain <a href> path
   between the five leagues (the topbar dropdown is a listbox, the homepage
   boxes only reach one page each), so it has to be a real link in the
   markup, not JS navigation. The hub page's own subpages (fixtures, table,
   live, ...) don't need a second nav here: the topbar already links every
   one of them, scoped to whichever league is current. */
.footer-nav {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 20px 24px;
    margin: 0 0 28px;
    padding-bottom: 24px;
    border-bottom: 1px solid var(--border);
    text-align: left;
}
.footer-nav h2 {
    margin: 0 0 8px;
    font-size: 0.74rem;
    font-weight: 650;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-dim);
}
.footer-nav ul {
    list-style: none;
    margin: 0;
    padding: 0;
}
.footer-nav li { margin: 0 0 5px; }
.footer-nav a {
    color: var(--text-mid);
    font-size: 0.82rem;
    text-decoration: none;
}
.footer-nav a:hover { color: var(--text); text-decoration: underline; }


/* ==========================================================================
   BROADCAST LAYER
   --------------------------------------------------------------------------
   The 2026-09 redesign ("A · Broadcast"). Everything above is the structural
   baseline (layout, grids, behaviour); this block is the look — condensed
   uppercase type, cut corners, slanted tabs/chips/bars, crests on light
   plates, designed event icons. It sits LAST so it wins on source order at
   equal specificity, and so a future re-skin is "replace this block".

   Recipes used throughout (so a new component can copy one):
     slanted shape, upright text : position:relative; isolation:isolate;
                                   ::before { inset:0; z-index:-1;
                                   transform:skewX(var(--slant)) }
     cut corner                  : ::after triangle in the page colour with
                                   a diagonal hairline (no clip-path, so
                                   popups/tooltips inside a card still show)
     display numbers             : var(--font-display), 700-800, tabular
   ========================================================================== */

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

body {
    font-family: var(--font-body);
    letter-spacing: 0;
    background: var(--bg);
}
a { color: var(--red-bright); }
a:hover { color: var(--text-strong); }
::selection { background: var(--red); color: var(--on-red); }
:focus-visible { border-radius: 0; outline-color: var(--red-bright); }

/* ---- type -------------------------------------------------------------- */

h1 {
    font-family: var(--font-display);
    font-style: italic;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    line-height: 1.02;
    font-size: clamp(2rem, 4.4vw, 2.9rem);
    margin: 0 0 8px;
}
h2 {
    display: flex;
    align-items: center;
    gap: 12px;
    font-family: var(--font-display);
    font-style: italic;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.045em;
    font-size: 1.4rem;
    line-height: 1.1;
    margin: 40px 0 16px;
}
h2::before {
    content: "";
    flex: none;
    width: 9px;
    height: 22px;
    background: var(--red);
    transform: skewX(-20deg);
}
.card h2 { margin: 0 0 16px; }
h3 {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 0.86rem;
    letter-spacing: 0.14em;
    color: var(--text-mid);
    margin: 24px 0 10px;
}
.subtitle { color: var(--text-mid); font-size: 0.98rem; }
.muted { font-size: 0.84rem; }
.section-sub { font-size: 0.92rem; }

/* every big number on the site reads in the display face */
.outcome-value, .em-value, .h2h-metric-value, .stat-num, .live-card-score,
.final-score .score-line, .scoreline .line, .pie-chart-hole span, .lb-pts,
.mf-score, .mover-delta, .predicted-score strong,
.hb-prob {
    font-family: var(--font-display);
    letter-spacing: 0;
}

/* ---- crests: every club and league badge sits on a light plate so a dark
        crest (Juventus, Nottingham Forest, Newcastle...) is as clear as a
        light one on the black page --------------------------------------- */

.crest, .league-box-logo, .gotw-league-logo {
    object-fit: contain;
    border-radius: 50%;
    background: var(--plate-bg);
    box-shadow: var(--plate-ring);
    /* fixed px, never %: a percentage padding resolves against the
       CONTAINING BLOCK's width, which inside a flex row is the whole row. */
    padding: 3px;
}
.crest-sm { width: 24px; height: 24px; padding: 3px; }
.crest-md { width: 36px; height: 36px; padding: 5px; }
.crest-lg { width: 54px; height: 54px; padding: 7px; }
.crest-xl { width: 76px; height: 76px; padding: 10px; }
.league-box-logo { width: 42px; height: 42px; padding: 6px; }
.gotw-league-logo { width: 22px; height: 22px; padding: 3px; }
.crest-fallback {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    background: var(--bg-tile);
    border: 1px solid var(--border-strong);
    box-shadow: none;
    color: var(--text-mid);
    font-family: var(--font-display);
    font-weight: 800;
}
.crest-fallback.crest-sm { font-size: 0.8rem; }
.crest-fallback.crest-md { font-size: 1.05rem; }
.crest-fallback.crest-lg { font-size: 1.5rem; }
.crest-fallback.crest-xl { font-size: 2rem; }
.match-event-team .crest { width: 30px; height: 30px; margin-right: 6px; }
.h2h-table .h2h-team .crest { width: 20px; height: 20px; margin-right: 5px; padding: 2px; }
.team-name { gap: 9px; }
.report-stats-team { gap: 10px; }

/* ---- header ------------------------------------------------------------ */

.topbar { background: var(--topbar-bg); border-bottom: 1px solid var(--border); }
.topbar::before { height: 3px; background: var(--red); opacity: 1; }
.topbar-inner { padding: 10px 22px; gap: 12px; }
.brand-logo { height: 30px; }
/* nav's own overflow-x:auto (structural baseline, above) clips anything
   that renders outside its scrollport -- including the skewed ::before
   backgrounds below, which lean past their own anchor's box at one corner
   by design (the "slanted shape" recipe this whole layer is built on). With
   no padding, the first tab's low corner and the last tab's high corner get
   clipped flat instead of finishing their slant, which on the first tab
   (Home) also let its active background graze the logo. Same fix
   .subnav-inner already uses for its own slanted tabs: pad the scrollport
   so the lean has room. */
nav { padding: 0 8px; }

nav a {
    isolation: isolate;
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 0.95rem;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    padding: 7px 10px;
    border-radius: 0;
    color: var(--text-mid);
    background: none;
}
nav a::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    transform: skewX(var(--slant));
    background: transparent;
    transition: background var(--ease);
}
nav a:hover { background: none; color: var(--text-strong); }
nav a:hover::before { background: var(--hover-tint); }
nav a.active { background: none; color: var(--on-red); }
nav a.active::before { background: var(--red); }
nav a.active::after { content: none; }

.topbar-search { font-family: var(--font-body); }
.topbar-search::after { background-color: var(--bg-sunken); }
.topbar-search-wrap:focus-within .topbar-search::before,
.topbar-search-wrap:has(.topbar-search-input:not(:placeholder-shown)) .topbar-search::before { background-color: var(--red); }
.topbar-search-panel, .ts-tab { border-radius: 0; }

.league-select-trigger {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 0.95rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    padding: 0 16px 0 12px;
    white-space: nowrap;
}
.league-select-trigger .crest { width: 24px; height: 24px; flex: none; }
.league-select-list { border-radius: 0; background: var(--bg-card); }
.league-select-option { font-family: var(--font-display); font-weight: 700; font-size: 0.95rem; letter-spacing: 0.07em; text-transform: uppercase; }
.league-select-option .crest { width: 24px; height: 24px; flex: none; }
.league-select-option.active::after { color: var(--red-bright); }

/* ---- page submenu / tabs ----------------------------------------------- */

.subnav { background: var(--bg-card); border-bottom: 1px solid var(--border); }
.subnav-inner { gap: 4px; }
.subnav-tab {
    isolation: isolate;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 1rem;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    padding: 13px 18px 14px;
    color: var(--text-mid);
    background: none;
    border: 0;
}
.subnav-tab::before {
    content: "";
    position: absolute;
    inset: 6px 0 0;
    z-index: -1;
    transform: skewX(var(--slant));
    background: transparent;
    transition: background var(--ease);
}
.subnav-tab:hover { background: none; color: var(--text-strong); border: 0; }
.subnav-tab:hover::before { background: var(--hover-tint-mid); }
.subnav-tab[aria-selected="true"] { color: var(--text-strong); }
.subnav-tab[aria-selected="true"]::before { background: var(--tab-wash); }
.subnav-tab[aria-selected="true"]::after {
    left: 6px; right: 6px; bottom: 0; height: 3px;
    border-radius: 0;
    transform: skewX(-30deg);
    background: var(--red);
}
@media (max-width: 640px) {
    .subnav-tab { padding: 11px 13px 12px; font-size: 0.92rem; }
    .subnav-tab[aria-selected="true"]::after { left: 4px; right: 4px; }
}

/* ---- buttons, chips ---------------------------------------------------- */

button {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 0.92rem;
    text-transform: uppercase;
    letter-spacing: 0.09em;
    border-radius: 0;
    background: var(--bg-tile);
    border: 1px solid var(--border-strong);
}
button:hover { border-color: var(--red); background: var(--red-wash); color: var(--text-strong); }
.btn-link {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 0.92rem;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--red-bright);
    text-decoration: none;
}
.btn-link:hover { color: var(--text-strong); text-decoration: none; }

.chip {
    position: relative;
    isolation: isolate;
    background: none;
    border: 0;
    border-radius: 0;
    padding: 6px 16px;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 0.9rem;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--text-mid);
}
.chip::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    transform: skewX(var(--slant));
    background: var(--bg-tile);
    border: 1px solid var(--border-strong);
    transition: background var(--ease), border-color var(--ease);
}
.chip:hover { color: var(--text-strong); border: 0; }
.chip:hover::before { border-color: var(--draw); }
.chip.on { background: none; color: var(--on-red); border: 0; }
.chip.on::before { background: var(--red); border-color: var(--red); }

/* ---- cards: cut bottom-right corner ------------------------------------ */

.card, .league-box, .gotw, .feature-card {
    position: relative;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 0;
    box-shadow: var(--card-shadow);
}
.card::after, .league-box::after, .gotw::after, .feature-card::after {
    content: "";
    position: absolute;
    right: -1px;
    bottom: -1px;
    width: var(--cut);
    height: var(--cut);
    pointer-events: none;
    background: linear-gradient(135deg, transparent 0 calc(50% - 0.5px), var(--cut-line, var(--border-strong)) calc(50% - 0.5px) calc(50% + 0.5px), var(--bg) calc(50% + 0.5px));
}
/* The hairline is its own element, so it has to be told when the box border
   changes colour; otherwise a highlighted card is outlined all the way round
   except the cut corner. Set --cut-line wherever a card's border-color is. */
a.live-card:hover, a.live-card:focus-visible,
.league-box:hover, .league-box:focus-visible, .gotw:hover, .gotw:focus-visible,
.feature-card:hover { --cut-line: var(--red); }
.feature-card:focus-visible { --cut-line: var(--red-line); }
.card.fixture-live:has(.fixture-row):hover { --cut-line: var(--red-line); }
.card { padding: 20px 22px; }
.card.callout { border-left: 3px solid var(--red); }
a.live-card:hover, a.live-card:focus-visible,
.league-box:hover, .league-box:focus-visible, .gotw:hover, .gotw:focus-visible, .feature-card:hover {
    border-color: var(--red);
    box-shadow: var(--card-shadow);
    transform: none;
}

/* ---- tables ------------------------------------------------------------ */

th {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 0.8rem;
    letter-spacing: 0.13em;
    color: var(--text-dim);
    border-bottom: 2px solid var(--border-strong);
}
td { font-size: 0.9rem; }
tbody tr:hover { background: var(--hover-tint-soft); }
tr.row-home { background: var(--red-wash-soft); box-shadow: inset 3px 0 0 var(--red); }
tr.row-away { background: var(--hover-tint-mid); box-shadow: inset 3px 0 0 var(--text-strong); }
tr.row-away:hover { background: var(--hover-tint); }

/* ---- fixture rows / probability tiles ---------------------------------- */

.fixture-teams .teams {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 1.22rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    gap: 10px;
}
.fixture-teams .date { font-family: var(--font-display); font-weight: 600; font-size: 0.82rem; letter-spacing: 0.12em; }

.prob-bar {
    position: relative;
    isolation: isolate;
    background: none;
    border: 0;
    border-radius: 0;
    color: var(--text-mid);
    font-family: var(--font-display);
    font-size: 1.1rem;
    font-weight: 700;
    padding: 8px 4px 7px;
}
.prob-bar::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    transform: skewX(var(--slant));
    background: var(--bg-tile);
    border: 1px solid var(--border-strong);
}
.prob-bar.win, .prob-bar.lose, .prob-bar.neutral { background: none; border: 0; }
.prob-bar .label { font-size: 0.68rem; font-weight: 600; letter-spacing: 0.14em; opacity: 0.85; }
/* identity by position, exactly as the stack bar below: home red, draw grey,
   away white. The model's favourite (.win) is the one that fills. */
.prob-bar.win, .prob-bar.win:first-child { color: var(--on-red); }
.prob-bar.win::before { background: var(--red); border-color: var(--red); }
.prob-bar.win:last-child { color: var(--on-away); }
.prob-bar.win:last-child::before { background: var(--c-away); border-color: var(--c-away); }
.prob-bar.win:nth-child(2) { color: var(--on-draw); }
.prob-bar.win:nth-child(2)::before { background: var(--c-draw); border-color: var(--c-draw); }
.prob-bar.lose { color: var(--text-mid); }
.prob-bar.lose::before { background: var(--bg-tile); border-color: var(--border-strong); }
.prob-bar.neutral { color: var(--text-mid); }
.prob-bar.neutral::before { background: var(--bg-tile); border-color: var(--border-strong); }
.predicted-score { font-family: var(--font-display); font-size: 0.86rem; letter-spacing: 0.08em; text-transform: uppercase; }

.final-score .score-line { font-size: 2.1rem; font-weight: 800; font-style: italic; }
.final-score .score-line .win { color: var(--text-strong); }
.final-score .score-line .lose { color: var(--text-dim); }
.final-score .score-line .neutral { color: var(--text-mid); }

.mf-prob {
    position: relative;
    isolation: isolate;
    background: none;
    border: 0;
    border-radius: 0;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 0.95rem;
    color: var(--text-mid);
}
.mf-prob::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    transform: skewX(var(--slant));
    background: var(--bg-tile);
    border: 1px solid var(--border-strong);
}
.mf-prob.top { color: var(--on-red); background: none; border: 0; }
.mf-prob.top::before { background: var(--red); border-color: var(--red); }
.mf-name { font-family: var(--font-display); font-weight: 700; font-size: 1.05rem; text-transform: uppercase; letter-spacing: 0.03em; }
/* Head bar and rows are separate grids: they must share the gap too, not just
   the tracks, or each column drifts 2px further right of its heading. */
.mini-fixtures-head, .mini-fixture { gap: 10px; }
.mf-team .crest { width: 28px; height: 28px; padding: 4px; }
.lb-row .crest { width: 26px; height: 26px; padding: 4px; }
.ts-item .crest { width: 28px; height: 28px; padding: 4px; }
.mini-fixtures-head { font-family: var(--font-display); letter-spacing: 0.13em; }

/* ---- live -------------------------------------------------------------- */

.live-badge {
    position: relative;
    isolation: isolate;
    background: none;
    border: 0;
    border-radius: 0;
    color: var(--on-red);
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 0.86rem;
    letter-spacing: 0.12em;
    padding: 3px 12px;
}
.live-badge::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    transform: skewX(var(--slant));
    background: var(--red);
}
.live-badge .live-dot, .live-dot { background: var(--on-red); box-shadow: 0 0 8px rgba(255, 255, 255, 0.7); }
.live-panel-heading .live-dot { background: var(--red); box-shadow: 0 0 10px var(--red-glow); }
.live-card-teams { grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); gap: 8px; }
.live-card-team { min-width: 0; font-family: var(--font-display); font-weight: 700; font-size: 1.05rem; text-transform: uppercase; letter-spacing: 0.03em; }
.live-card-team .team-name { overflow-wrap: anywhere; }
.live-card-team .crest { width: 28px; height: 28px; padding: 3px; flex: none; }
.live-card-score { font-size: 1.9rem; font-weight: 800; font-style: italic; }
.live-card-league { font-family: var(--font-display); letter-spacing: 0.12em; }

/* A fixture row that is being played right now (fixture_card): red edge, the
   score where the win/draw/loss tiles sit. Same edge as .card.callout. */
.card.fixture-live,
.card.fixture-live:has(.fixture-row):hover { border-color: var(--red-line); border-left: 3px solid var(--red); }
.live-now { width: 100%; display: flex; flex-direction: column; align-items: center; gap: 6px; }
.live-now-score {
    font-family: var(--font-display);
    font-size: 2.4rem;
    font-weight: 800;
    font-style: italic;
    line-height: 1;
    letter-spacing: 0.02em;
    color: var(--text-strong);
    font-variant-numeric: tabular-nums;
}

.live-stat-label {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 0.8rem;
    letter-spacing: 0.12em;
    color: var(--text-dim);
}
.live-stat-val { font-family: var(--font-display); font-weight: 700; font-size: 1rem; }
/* comparison bars: two slanted segments, home red | away white, with a gap */
.live-stat-bar {
    height: 6px;
    gap: 3px;
    overflow: visible;
    background: none;
    border-radius: 0;
}
.bar-seg { transform: skewX(-25deg); min-width: 0; }
.bar-seg.bar-home { background: var(--red); }
.bar-seg.bar-away { background: var(--c-away); }

/* compact live events: icon + minute + text on one line */
.live-event { display: flex; align-items: center; gap: 7px; font-size: 0.84rem; }
.live-event.away { flex-direction: row-reverse; text-align: right; }
.live-event .evi { width: 26px; height: 26px; flex: none; }
.live-event-min { font-family: var(--font-display); font-weight: 700; font-size: 0.95rem; color: var(--text); letter-spacing: 0.04em; }
.live-event-text { color: var(--text-mid); }

.evi, .evg { display: block; flex: none; overflow: visible; }

/* ---- lineup badges: the same glyphs, bare, small ------------------------ */

.pbadge { font-size: 0.72rem; filter: var(--badge-filter); }
.pbadge .evg { width: 19px; height: 19px; }
.pbadge-card-wrap .evg { width: 20px; height: 20px; }
.pbadge-sub { color: var(--red-bright); font-family: var(--font-display); font-weight: 700; font-size: 0.72rem; gap: 2px; }
.pbadge-sub .evg-suboff { width: 8px; height: 8px; }
@media (max-width: 480px) {
    .pbadge .evg { width: 15px; height: 15px; }
    .pbadge-card-wrap .evg { width: 16px; height: 16px; }
}
td .pbadge-card-wrap { margin-right: 2px; }
td .pbadge .evg { width: 18px; height: 18px; }

/* ---- fixture page: matchup scoreboard ---------------------------------- */

.matchup-title {
    gap: 6px 22px;
    margin-bottom: 10px;
}
.matchup-title .team-name { gap: 16px; color: var(--text-strong); text-decoration: none; }
.matchup-title .team-name:hover { color: var(--red-bright); }
/* the "vs" between two teams, everywhere: a small red parallelogram with white
   text. One rule so every matchup (fixture rows, league boxes, game of the
   week, the fixture page title) reads the same; each context only sets its
   size below. */
.vs {
    position: relative;
    isolation: isolate;
    display: inline-block;
    flex: none;
    font-family: var(--font-display);
    font-style: normal;
    font-weight: 700;
    font-size: 0.7rem;
    line-height: 1;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    text-indent: 0.14em;          /* balances the trailing letter-space so VS sits centred */
    color: var(--on-red);
    padding: 5px 11px;
}
.vs::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background: var(--red);
    transform: skewX(var(--slant));
}
.league-box-teams .vs { font-size: 0.6rem; padding: 4px 9px; }
.gotw-teams .vs { font-size: 0.9rem; padding: 6px 15px; }
@media (max-width: 760px) {
    /* phones and small tablets: home, chip, away in one centred column
       instead of the chip wrapping up beside the home side */
    .gotw-teams { flex-direction: column; flex-wrap: nowrap; gap: 10px; }
    .gotw-teams .gotw-side { max-width: 100%; }
}
.matchup-title .vs { font-size: 0.95rem; padding: 5px 14px; }

/* outcome tiles — home | draw | away; identity by position, favourite lifted */
.outcome-grid { gap: 8px; }
.outcome {
    background: var(--bg-tile);
    border: 1px solid var(--border);
    border-top: 4px solid var(--c-draw);
    border-radius: 0;
    text-align: left;
    padding: 14px 16px 12px;
    box-shadow: none;
}
.outcome:first-child { border-top-color: var(--c-home); }
.outcome:last-child { border-top-color: var(--c-away); }
.outcome-label { font-family: var(--font-display); font-weight: 600; font-size: 0.86rem; letter-spacing: 0.13em; color: var(--text-mid); }
.outcome-value { font-size: 3rem; font-weight: 800; font-style: italic; line-height: 1; margin-top: 8px; color: var(--text-mid); }

.prob-stack { height: 10px; gap: 3px; border-radius: 0; background: none; overflow: visible; margin: 14px 0 16px; }
.prob-stack .seg { transform: skewX(-25deg); background: var(--c-draw); }
.prob-stack .seg:first-child { background: var(--c-home); }
.prob-stack .seg:last-child { background: var(--c-away); }
.prob-stack .seg.win, .prob-stack .seg.lose, .prob-stack .seg.neutral { background: inherit; }
.prob-stack .seg.win:first-child, .prob-stack .seg.lose:first-child, .prob-stack .seg.neutral:first-child { background: var(--c-home); }
.prob-stack .seg.win:last-child, .prob-stack .seg.lose:last-child, .prob-stack .seg.neutral:last-child { background: var(--c-away); }
.prob-stack .seg.win:nth-child(2), .prob-stack .seg.lose:nth-child(2), .prob-stack .seg.neutral:nth-child(2) { background: var(--c-draw); }

.scoreline {
    background: var(--bg-tile);
    border: 1px solid var(--border);
    border-radius: 0;
    text-align: left;
}
.scoreline .line { font-size: 1.5rem; font-weight: 800; font-style: italic; }
.scoreline .lineprob { font-family: var(--font-display); letter-spacing: 0.06em; }
.scoreline:hover { border-color: var(--red); }

/* event markets: value + bar filled to the model's number, tick at the league average */
.event-markets { grid-template-columns: repeat(auto-fill, minmax(168px, 1fr)); gap: 8px; }
.event-market {
    background: var(--bg-tile);
    border: 1px solid var(--border);
    border-radius: 0;
    text-align: left;
    padding: 10px 12px 10px;
}
.event-market .em-label { font-family: var(--font-display); font-weight: 600; font-size: 0.78rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-mid); }
.event-market .em-value { font-size: 1.9rem; font-weight: 800; font-style: italic; line-height: 1.05; margin-top: 4px; }
.em-meter {
    position: relative;
    display: block;
    height: 6px;
    margin: 8px 4px 8px 0;
    background: var(--track);
    transform: skewX(-25deg);
}
.em-fill { position: absolute; left: 0; top: 0; bottom: 0; background: var(--red); }
.em-tick { position: absolute; top: -3px; bottom: -3px; width: 2px; margin-left: -1px; background: var(--em-tick); }
.event-market .em-avg { font-size: 0.72rem; color: var(--text-dim); }

/* head-to-head / season metric tiles */
.h2h-metric { background: var(--bg-tile); border: 1px solid var(--border); border-radius: 0; padding: 9px 12px; }
.h2h-metric-label { font-family: var(--font-display); font-weight: 600; font-size: 0.74rem; letter-spacing: 0.11em; color: var(--text-mid); }
.h2h-metric-value { font-size: 1.55rem; font-weight: 800; font-style: italic; line-height: 1.1; }
.h2h-metric-sub { font-size: 0.72rem; }

/* donuts: thin ring, big number in the hole */
.pie-chart { width: 104px; height: 104px; }
.pie-chart-hole { inset: 13px; background: var(--bg-card); }
.pie-chart-hole span { font-size: 1.5rem; font-weight: 800; font-style: italic; }
.pie-chart-hole small { font-family: var(--font-display); font-weight: 600; font-size: 0.66rem; letter-spacing: 0.12em; }
/* Restated here: equal specificity to .pie-chart above, so without this the
   104px there wins on width/height and "sm" donuts silently render full-size. */
.pie-chart-sm { width: 76px; height: 76px; }
.pie-chart-sm .pie-chart-hole span { font-size: 1.05rem; }
.pie-legend { font-size: 0.86rem; gap: 6px; }
.pie-legend .swatch { width: 12px; height: 8px; border-radius: 0; transform: skewX(-25deg); }
.pie-legend .swatch.win { background: var(--c-home); }
.pie-legend .swatch.draw { background: var(--c-draw); }
.pie-legend .swatch.lose { background: var(--c-away); }
.pie-legend .swatch.over { background: var(--c-over); }
.pie-legend .swatch.under { background: var(--c-draw); }
.pie-legend .swatch.yes { background: var(--c-yes); }
.pie-legend .swatch.no { background: var(--c-no); }
.radar-poly.radar-away { stroke: var(--c-away); fill: var(--c-away); }
.radar-poly.radar-home { stroke: var(--red); fill: var(--red); }
.radar-label { font-family: var(--font-display); font-weight: 600; letter-spacing: 0.1em; }

/* ---- form pills: slanted, W red / D grey / L dark ----------------------- */

.form-pill {
    border: 0;
    border-radius: 0;
    width: 24px;
    height: 22px;
    clip-path: polygon(18% 0, 100% 0, 82% 100%, 0 100%);
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 0.86rem;
}
.form-pill.w { background: var(--form-w-bg); color: var(--form-w-fg); border: 0; }
.form-pill.d { background: var(--form-d-bg); color: var(--form-d-fg); border: 0; }
.form-pill.l { background: var(--form-l-bg); color: var(--form-l-fg); border: 0; }
.lb-row .form-pill { width: 17px; height: 17px; font-size: 0.66rem; line-height: 17px; }

/* ---- semantic leftovers (were green / red pairs) ------------------------- */

.movers-head.up, .mover-delta.up { color: var(--text-strong); }
.movers-head.down, .mover-delta.down { color: var(--red-bright); }
.fdr { border-radius: 0; }
.fdr-1 { background: #f4f4f5; color: #0b0b0d; }
.fdr-2 { background: #b9b9c1; color: #0b0b0d; }
.fdr-3 { background: #55555d; color: #fff; }
.fdr-4 { background: var(--red-deep); color: var(--on-red); }
.fdr-5 { background: var(--red); color: var(--on-red); }
.stat-value-cell.cell-green { box-shadow: inset 3px 0 0 var(--text-strong); }
.stat-value-cell.cell-red { box-shadow: inset 3px 0 0 var(--red); }
.hb-prob { color: var(--text-strong); }
.flag-ok { color: var(--text-strong); }

/* ---- landing ------------------------------------------------------------ */

.hero { border-bottom: 1px solid var(--border); padding: 26px 0 34px; margin-bottom: 34px; }
.hero h1 { font-size: clamp(2.3rem, 5.6vw, 4rem); max-width: 18ch; line-height: 0.98; margin-bottom: 16px; }
.hero-sub { font-size: 1.08rem; color: var(--text-mid); }
.league-box-name { font-family: var(--font-display); font-weight: 800; font-style: italic; font-size: 1.3rem; text-transform: uppercase; letter-spacing: 0.04em; }
.league-box-label, .lb-fact { font-family: var(--font-display); letter-spacing: 0.1em; }
.feature-icon { font-size: 1.4rem; }
.feature-card h3 { color: var(--text); font-size: 1.05rem; }
.stat-num { font-weight: 800; font-style: italic; }
.stat-label { font-family: var(--font-display); letter-spacing: 0.12em; }
.gotw-name { font-family: var(--font-display); font-weight: 800; font-style: italic; text-transform: uppercase; }
.gotw-tag { font-family: var(--font-display); letter-spacing: 0.14em; }
.leaderboard-icon { filter: grayscale(1) contrast(1.15); }
.leaderboard-icon .evg { width: 24px; height: 24px; filter: none; }

/* ---- matchweek arrows, misc chrome --------------------------------------- */

.md-arrow { border-radius: 0; }
.callout { border-left-width: 3px; }
.badge-conf { font-family: var(--font-display); letter-spacing: 0.06em; font-size: 0.82rem; }

/* ---- footer ------------------------------------------------------------- */

.footer { background: var(--bg-sunken); border-top: 3px solid var(--red); }
.footer-nav h2 {
    display: block;
    font-family: var(--font-display);
    font-style: italic;
    font-weight: 800;
    font-size: 0.95rem;
    letter-spacing: 0.1em;
    margin: 0 0 8px;
    color: var(--text);
}
.footer-nav h2::before { content: none; }
.footer-nav h2 a { color: inherit; text-decoration: none; }
.footer-nav a { color: var(--text-mid); }
.footer-nav a:hover { color: var(--text-strong); }

@media (max-width: 640px) {
    h2 { font-size: 1.25rem; }
    .outcome-value { font-size: 2.4rem; }
    .crest-xl { width: 60px; height: 60px; padding: 8px; }
    .card { padding: 16px 16px; }
}

@media (max-width: 560px) {
}

/* ---- line icons (empty states, feature cards) --------------------------- */

.ui-icon { display: block; width: 100%; height: 100%; overflow: visible; }
.empty-state .big { width: 56px; height: 56px; margin: 0 auto 14px; filter: none; opacity: 1; color: var(--text-mid); font-size: 0; }
.feature-icon {
    position: relative;
    isolation: isolate;
    display: inline-grid;
    place-items: center;
    width: 52px;
    height: 46px;
    color: var(--text-strong);
    font-size: 0;
}
.feature-icon::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    transform: skewX(var(--slant));
    background: var(--bg-tile);
    border: 1px solid var(--border-strong);
    border-bottom: 3px solid var(--red);
}
.feature-icon .ui-icon { width: 30px; height: 30px; }

/* ---- lineups: the pitch is a dark-grey mown stripe with white markings,
        not grass green (the palette has no green) -------------------------- */

.pitch {
    border-radius: 0;
    background: repeating-linear-gradient(
        0deg,
        var(--pitch-a) 0,
        var(--pitch-a) calc(100% / 12),
        var(--pitch-b) calc(100% / 12),
        var(--pitch-b) calc(100% / 6)
    );
    border: 1px solid var(--border-strong);
}
.pitch::before { background: linear-gradient(var(--pitch-line), var(--pitch-line)) 0 50% / 100% 2px no-repeat; }
.pitch::after, .pitch .box { border-color: var(--pitch-mark); }

/* ---- header fit: the display face is wide until the Barlow files are
        installed, so give the nav room and tighten it ------------------- */
.topbar-inner { max-width: 1200px; gap: 10px; }
nav { gap: 0; }
nav a { padding: 7px 8px; font-size: 0.9rem; letter-spacing: 0.05em; }
@media (min-width: 641px) {
    .topbar-search { width: 104px; }
    .topbar-search-wrap:focus-within .topbar-search,
    .topbar-search-wrap:has(.topbar-search-input:not(:placeholder-shown)) .topbar-search { width: 170px; }
}
@media (max-width: 640px) {
    .topbar-search { width: 100%; }
}

/* ---- phone header: logo, league picker (full name), theme toggle, hamburger.
        Picker and toggle are 40px tall here (toggle 44px wide), the dropdown
        hangs from the 40px parallelogram (bottom edge shifted 6.5px, so
        -7px / 7px), and its options are 44px tall touch targets. ------------ */
@media (max-width: 640px) {
    .topbar-inner { padding: 9.5px 12px; gap: 6px; flex-wrap: nowrap; }
    html.js .league-select { flex: 0 1 auto; min-width: 0; }
    .league-select-trigger { height: 40px; font-size: 0.85rem; letter-spacing: 0.04em; padding: 0 13px 0 9px; gap: 6px; }
    .theme-toggle { height: 40px; }
    .league-select-list { left: -7px; right: 7px; }
    .league-select-option { min-height: 44px; gap: 6px; padding: 6px 8px 6px 12px; font-size: 0.85rem; letter-spacing: 0.04em; }
    .league-select-label > .ls-size { padding-right: 0; }
    .league-select-option.active::after { display: none; }   /* wash + bar mark it; the tick would truncate "Premier League" */
}
/* ---- desktop header budget: the slanted picker + toggle must not take more
        nav room than they have to. Fine pointers only; phones and
        pointer:coarse keep the roomier 40px / 44px targets. ----------------- */
@media (min-width: 641px) and (pointer: fine) {
    .league-select { margin-left: -8px; }
    .league-select-trigger { padding: 0 9px 0 7px; gap: 5px; font-size: 0.85rem; letter-spacing: 0.03em; }
    .league-select-trigger .crest { width: 20px; height: 20px; }
    .league-select-caret { margin-left: 0; }
    .league-select-label > .ls-size { padding-right: 0; }
    .league-select-option.active::after { display: none; }   /* the red wash + bar already mark it; saves the tick's width */
    .theme-toggle { width: 40px; margin-left: -6px; }
    .league-select-option { gap: 6px; padding: 7px 8px 7px 12px; font-size: 0.85rem; letter-spacing: 0.03em; }
    .league-select-option .crest { width: 20px; height: 20px; }
}
/* the full-size 30px logo fits down to 390px; below that it steps down first */
@media (max-width: 380px) {
    .brand-logo { height: 24px; }
}
/* very narrow phones (<= 360px): shrink the logo and paddings first; as a last
   resort the trigger label (and the options) truncate with an ellipsis, so
   nothing can push the page wider than the screen. */
@media (max-width: 360px) {
    .brand-logo { height: 20px; }
    .topbar-inner { padding: 8px 10px; gap: 6px; }
    .league-select-trigger { padding: 0 12px 0 8px; gap: 6px; }
    .league-select-trigger .crest { width: 22px; height: 22px; }
    .nav-toggle { width: 36px; }
    .brand { flex: 0 1 auto; min-width: 0; }
    .league-select-option { gap: 5px; padding: 6px 6px 6px 10px; font-size: 0.78rem; letter-spacing: 0.02em; }
}

/* ---- avatars: a headshot always fully covers its initials ------------------
   Sportmonks cut-outs are partly transparent, so any photo layer without an
   opaque backing lets the initials underneath show through. Every avatar
   image gets the same solid well colour; a photo that fails is hidden by
   app.js (.is-missing) which uncovers the initials on purpose. */
.hb-avatar img, .leaderboard-row-photo img, .player-photo { background: var(--photo-well); }
.hb-avatar img.is-missing, .leaderboard-row-photo img.is-missing { display: none; }

/* Historic-bets rows: keep the percentage pinned right even when the label
   wraps onto a second line in a narrow column. */
.historic-bets-list li { align-items: center; }
.historic-bets-list .hb-prob { margin-left: auto; }


/* ==========================================================================
   FIXTURE PAGE, PASS 2 -- predicted outcome / score chips / radar rings /
   centre-spine Key events. Matches the approved slide.
   ========================================================================== */

/* ---- outcome tiles: the model's lean is a solid red tile ------------------ */

.outcome {
    position: relative;
    background: var(--bg-tile);
    border: 1px solid var(--border);
    border-top: 1px solid var(--border);
    padding: 14px 16px 14px;
    --tile-line: var(--border-strong);
}
.outcome:first-child, .outcome:last-child { border-top-color: var(--border); }
.outcome::after {
    content: "";
    position: absolute;
    right: -1px;
    bottom: -1px;
    width: 14px;
    height: 14px;
    pointer-events: none;
    background: linear-gradient(135deg, transparent 0 calc(50% - 0.5px), var(--tile-line) calc(50% - 0.5px) calc(50% + 0.5px), var(--bg-card) calc(50% + 0.5px));
}
.outcome-label { font-size: 0.8rem; color: var(--text-dim); }
.outcome-value { color: var(--text); }
.outcome.neutral .outcome-value { color: var(--text-mid); }
.outcome.win .outcome-value, .outcome.lose .outcome-value { color: var(--text); }
.outcome.neutral .outcome-value { color: var(--text-mid); }
.outcome.lean { background: var(--red); border-color: var(--red); --tile-line: var(--red-deep); }
.outcome.lean .outcome-label { color: var(--on-red); }
.outcome.lean .outcome-value, .outcome.lean.win .outcome-value, .outcome.lean.neutral .outcome-value { color: var(--on-red); }

/* ---- event-market tiles: value and league average share a row ------------- */

.event-market .em-label { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.em-row { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; margin-top: 4px; }
.em-row .em-value { margin-top: 0; }
.event-market .em-avg { font-size: 0.78rem; white-space: nowrap; }
.em-legend { display: flex; align-items: center; gap: 8px; margin: 4px 0 20px; font-size: 0.8rem; color: var(--text-dim); }
.em-key { display: inline-block; flex: none; }
.em-key-fill { width: 16px; height: 4px; background: var(--red); transform: skewX(-25deg); }
.em-key-tick { width: 2px; height: 12px; background: var(--em-tick); transform: skewX(-25deg); margin-left: 10px; }

/* ---- predicted score chips ------------------------------------------------- */

.scorelines { gap: 8px; }
.scoreline {
    position: relative;
    isolation: isolate;
    background: none;
    border: 0;
    padding: 8px 22px;
    min-width: 0;
    text-align: center;
    opacity: 1;
}
.scoreline::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    transform: skewX(var(--slant));
    background: var(--bg-tile);
    border: 1px solid var(--border);
    transition: border-color var(--ease);
}
.scoreline:hover::before { border-color: var(--red); }
.scoreline.lead::before { background: var(--red); border-color: var(--red); }
.scoreline.alt .line { font-weight: 800; color: var(--text); }
.scoreline .line { font-family: var(--font-display); font-size: 1.6rem; line-height: 1.1; }
.scoreline .lineprob { font-size: 0.78rem; }
.scoreline.lead .line { color: var(--on-red); }
.scoreline.lead .lineprob { color: var(--on-red-soft); }
.scoreline:hover { border: 0; }

/* ---- radar: pentagon outline + rings --------------------------------------- */

.radar-ring { fill: none; stroke: var(--ring-soft); stroke-width: 1; }
.radar-ring-outer { stroke: var(--ring-strong); stroke-width: 1.5; fill: var(--ring-fill); }
.radar-spoke { stroke: var(--ring-soft); }

/* ---- Key events: centre spine ---------------------------------------------- */

.me-head { display: flex; flex-direction: column; gap: 10px; margin: 0 0 16px; }
.me-head h2 { margin: 0; }
/* Home pinned to the true left edge, away to the true right edge -- crest
   outermost on each side (see the macro's own comment) so each badge sits
   directly above its own column in the centre-spine timeline below. */
.me-scoreboard { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.me-side { display: inline-flex; align-items: center; gap: 10px; min-width: 0; font-weight: 700; font-size: 0.95rem; color: var(--text); }
.me-side .crest { flex: none; }
.me-side-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.match-events { gap: 0; }
.match-event.me-row {
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1fr) 84px minmax(0, 1fr);
    align-items: center;
    gap: 6px;
    padding: 0 0 12px;
    border: 0;
    background: none;
    box-shadow: none;
    font-size: 0.92rem;
}
.match-event.me-row::before {
    content: "";
    position: absolute;
    left: 50%;
    top: 0;
    bottom: 0;
    width: 2px;
    transform: translateX(-50%);
    background: var(--border-strong);
}
.me-mid {
    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 3px;
    padding: 4px 0;
    background: var(--bg-card);
}
.me-icon { display: flex; align-items: center; justify-content: center; font-size: 0; }
.me-mid .evi { width: 38px; height: 38px; }
.me-min {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 0.85rem;
    letter-spacing: 0.06em;
    color: var(--text-mid);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.me-cell { min-width: 0; display: flex; flex-direction: column; gap: 6px; padding: 0 4px; }
.me-home { align-items: flex-end; text-align: right; }
.me-away { align-items: flex-start; text-align: left; }
.me-text { display: flex; flex-direction: column; gap: 3px; font-weight: 600; color: var(--text); min-width: 0; }
.me-home .me-text { align-items: flex-end; }
.me-away .me-text { align-items: flex-start; }
.me-text .event-player-link { color: inherit; text-decoration: none; }
.me-text .event-player-link:hover { color: var(--red-bright); text-decoration: underline; }
.me-text .event-player { gap: 8px; }
.me-text .event-player-avatar { width: 30px; height: 30px; border-radius: 50%; flex: 0 0 auto; }
.me-text .event-player-avatar .player-photo,
.me-text .event-player-avatar .player-avatar-initials { border-radius: 50%; }
.ev-main { display: inline-flex; }
.ev-detail { font-weight: 500; font-size: 0.8rem; color: var(--text-dim); }
.ev-sub { display: flex; flex-direction: column; gap: 6px; }
.me-home .ev-sub { align-items: flex-end; }
.ev-sub-line { display: inline-flex; align-items: center; gap: 7px; }
.ev-sub-line.ev-off { font-weight: 500; color: var(--text-mid); }
.ev-tri { width: 10px; height: 10px; flex: none; }
.ev-tri-up { color: var(--text-strong); }
.ev-tri-down { color: var(--red-bright); }
.ev-note { font-size: 0.8rem; font-weight: 500; color: var(--red-bright); }

.me-score {
    position: relative;
    isolation: isolate;
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 3px 16px 3px 8px;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 0.95rem;
    letter-spacing: 0.06em;
    color: var(--on-red);
}
.me-score::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    transform: skewX(var(--slant));
    background: var(--red);
}
.me-score .crest { width: 22px; height: 22px; padding: 2px; margin: 0; }
.me-score b { font-weight: 700; }

.match-event.me-phase {
    display: flex;
    align-items: center;
    gap: 14px;
    margin: 6px 0 14px;
    padding: 0;
    border: 0;
    background: none;
    box-shadow: none;
}
.me-rule { flex: 1; height: 1px; background: var(--border-strong); }
.me-pill {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    padding: 4px 22px 4px 14px;
    background: var(--bg-tile);
    clip-path: polygon(10px 0, 100% 0, calc(100% - 10px) 100%, 0 100%);
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 0.92rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--text-mid);
    white-space: nowrap;
}
.me-pill .evi { width: 26px; height: 26px; }
.me-pill-score { color: var(--text-strong); }
.me-pill-score::before { content: "\00b7"; margin-right: 10px; color: var(--text-dim); }

@media (max-width: 560px) {
    .match-event.me-row { grid-template-columns: minmax(0, 1fr) 60px minmax(0, 1fr); gap: 4px; font-size: 0.85rem; }
    .me-mid .evi { width: 32px; height: 32px; }
    .me-cell { padding: 0 2px; }
    .me-text .event-player-avatar { width: 26px; height: 26px; }
    .me-pill { letter-spacing: 0.08em; padding-right: 16px; font-size: 0.82rem; }
    .me-side { gap: 7px; font-size: 0.82rem; max-width: 45%; }
    .me-side .crest { width: 36px; height: 36px; padding: 5px; }
}

/* Leaderboard category icons: designed glyphs keep their own colours (yellow
   and red cards, the goal ball); only the leftover emoji are toned down. */
.leaderboard-icon.is-glyph { filter: none; }
.leaderboard-icon.is-glyph .evg { width: 26px; height: 26px; }

/* ---- BADGES: light plate, never a CSS filter ----------------------------
   Club and league badges sit on the light plate defined with the base crest
   rules above (that is what keeps dark crests -- Nottingham Forest, Juventus,
   the Premier League lion -- legible on the black theme and lets a badge's
   transparent cut-outs read as white instead of as holes).

   Do NOT put `filter` (drop-shadow / hue-rotate / brightness) on a badge <img>.
   An earlier "bare badge" layer did, with up to six chained drop-shadows on the
   Premier League logo, and on real GPUs Chrome intermittently rasterised the
   filtered image in mismatched tiles: a pixelated, offset ghost copy of the
   crest at its top-left that bled over the neighbouring text, on team and
   league badges alike. The plate gets its edge from box-shadow instead, which
   is painted from the box and has no such failure mode.

   League logos (any /leagues/ CDN path) are not all round -- Ligue 1 is a
   150x110 JPEG and the Bundesliga mark is a square -- so they take a
   rounded-square plate; a circle would clip their corners. */
.crest:not(.crest-fallback),
.league-box-logo,
.gotw-league-logo {
    filter: none;
    background: var(--plate-bg);
    box-shadow: var(--plate-ring);
    border-radius: 50%;
}
img[src*="/images/soccer/leagues/"].crest:not(.crest-fallback),
img[src*="/images/soccer/leagues/"].league-box-logo,
img[src*="/images/soccer/leagues/"].gotw-league-logo {
    border-radius: 22%;
}

/* ---- About page ---------------------------------------------------------
   One reading column of cards. Reuses .card / .callout / h2 / h3 from the
   layer above; only the pieces with no existing equivalent live here: the
   feature tiles, the label-and-text lists and the 18+ mark. Kept at the very
   end of the file, after the Broadcast layer, so it wins on source order. */
.about { max-width: 860px; margin: 0 auto; }
.about .subtitle { margin: 0 0 22px; }
.about .card { margin-bottom: 16px; }
.about .card p { color: var(--text-mid); line-height: 1.65; margin: 0; }
.about .card p + p { margin-top: 12px; }
.about .card p a,
.about-list a { color: var(--text); text-decoration: underline; text-decoration-color: var(--red); text-underline-offset: 3px; }
.about .card p a:hover,
.about-list a:hover { color: var(--text-strong); text-decoration-color: var(--red-bright); }
.about .card p strong { color: var(--text); }
.about-notice p { color: var(--text); }

.about-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 12px;
}
.about-tile {
    display: block;
    padding: 14px 16px;
    background: var(--bg-tile);
    border: 1px solid var(--border);
    border-left: 3px solid var(--red);
    color: inherit;
    text-decoration: none;
    transition: background var(--ease), border-color var(--ease);
}
.about-tile:hover,
.about-tile:focus-visible { background: var(--bg-card-hover); border-color: var(--border-strong); border-left-color: var(--red-bright); }
.about-tile-title {
    display: block;
    font-family: var(--font-display);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-size: 1rem;
    color: var(--text);
}
.about-tile-text { display: block; margin-top: 4px; font-size: 0.88rem; line-height: 1.5; color: var(--text-mid); }

.about-list { margin: 16px 0 0; padding: 0; }
.about-list > div {
    display: grid;
    grid-template-columns: 200px minmax(0, 1fr);
    gap: 4px 20px;
    padding: 11px 0;
    border-top: 1px solid var(--border);
}
.about-list > div:last-child { border-bottom: 1px solid var(--border); }
.about-list dt { font-weight: 650; color: var(--text); }
.about-list dd { margin: 0; color: var(--text-mid); line-height: 1.6; }
/* The gambling notice reads as short paragraphs, so its labels sit above the
   text rather than beside it. */
.about-list-stacked > div { grid-template-columns: 1fr; gap: 3px; }
.about .card h3 { margin: 26px 0 0; }
.about .card .muted { margin-top: 16px; line-height: 1.6; }
.about-warning { margin-top: 18px; padding: 14px 0 14px 18px; border-left: 3px solid var(--red); background: var(--red-wash-soft); }
.about-warning p { padding-right: 16px; }

.age-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 34px;
    height: 34px;
    border: 2px solid var(--text);
    border-radius: 50%;
    font-family: var(--font-display);
    font-style: normal;
    font-weight: 800;
    font-size: 0.86rem;
    letter-spacing: 0;
    line-height: 1;
    color: var(--text);
}

@media (max-width: 600px) {
    .about-list > div { grid-template-columns: 1fr; gap: 2px; }
}

/* ============================================================
   PLAYER STAT BANDS (fixture page, Players & Referee tab)
   One full-width band per category, home leaders left, away
   leaders right (m.recent_player_statistics). Built on the
   Broadcast tokens: display face for headings and numbers, a red
   slash before each title, the designed evg-* glyph on a tile with
   a red underline, cut-corner bands, a skewed VS pill. Red is the
   season leader and the "did it that match" chips; the away side is
   told apart by position, never by a new colour.
   ============================================================ */
.psb { display: flex; flex-direction: column; gap: 12px; }
.psb-teams {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
    align-items: center;
    gap: 16px;
    padding: 16px 22px;
    background: var(--bg-sunken);
    border: 1px solid var(--border);
}
.psb-team {
    display: flex;
    align-items: center;
    gap: 14px;
    min-width: 0;
    font-family: var(--font-display);
    font-style: italic;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.01em;
    font-size: 2rem;
    line-height: 1;
    color: var(--text);
    text-decoration: none;
}
.psb-team span { min-width: 0; overflow-wrap: anywhere; }
.psb-team:hover, .psb-team:focus-visible { color: var(--red-bright); }
.psb-team-away { justify-content: flex-end; text-align: right; }
.psb-vs {
    position: relative;
    isolation: isolate;
    padding: 4px 18px;
    font-family: var(--font-display);
    font-style: italic;
    font-weight: 800;
    font-size: 1.25rem;
    letter-spacing: 0.06em;
    color: var(--on-red);
}
.psb-vs::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background: var(--red);
    transform: skewX(var(--slant));
}
.psb-band {
    position: relative;
    background: var(--bg-card);
    border: 1px solid var(--border);
    padding: 18px 24px 10px;
}
.psb-band::after {
    content: "";
    position: absolute;
    right: -1px;
    bottom: -1px;
    width: var(--cut);
    height: var(--cut);
    pointer-events: none;
    background: linear-gradient(135deg, transparent 0 calc(50% - 0.5px), var(--border-strong) calc(50% - 0.5px) calc(50% + 0.5px), var(--bg-card) calc(50% + 0.5px));
}
.psb-band-head { display: flex; align-items: center; gap: 16px; margin-bottom: 6px; }
.psb-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 60px;
    height: 52px;
    background: var(--bg-tile);
    border-bottom: 2px solid var(--red);
}
.psb-icon .evg { width: 34px; height: 34px; }
.psb-band h3 {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 0;
    font-style: italic;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.01em;
    font-size: 1.9rem;
    line-height: 1;
    color: var(--text);
}
.psb-band h3::before {
    content: "";
    flex: none;
    width: 8px;
    height: 20px;
    background: var(--red);
    transform: skewX(var(--slant));
}
.psb-band-sub { margin: 3px 0 0 18px; font-size: 0.84rem; color: var(--text-dim); }
.psb-sides {
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    column-gap: 44px;
}
.psb-sides::before {
    content: "";
    position: absolute;
    left: 50%;
    top: 0;
    bottom: 0;
    width: 1px;
    background: var(--border);
}
.psb-side { min-width: 0; }
/* the team name over each side: read by screen readers always, shown only
   once the two sides stack (the clubs strip at the top names them otherwise) */
.psb-side-team {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    font-family: var(--font-display);
    font-style: italic;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    font-size: 1.2rem;
    color: var(--text);
}
.psb-side-head, .psb-row {
    display: grid;
    grid-template-columns: 24px 32px minmax(0, 1fr) 80px 58px 28px;
    column-gap: 10px;
    align-items: center;
}
.psb-side-head {
    height: 26px;
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 0.7rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--text-dim);
    text-align: center;
}
.psb-h-l3 { grid-column: 4; }
.psb-h-total { grid-column: 5; }
.psb-h-apps { grid-column: 6; }
.psb-list { list-style: none; margin: 0; padding: 0; }
.psb-row { min-height: 56px; border-top: 1px solid var(--track); }
.psb-rank {
    text-align: center;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 1.15rem;
    color: var(--text-dim);
}
.psb-row.is-lead .psb-rank, .psb-row.is-lead .psb-total { color: var(--red-bright); }
.psb-avatar { width: 32px; height: 40px; }
.psb-name {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 600;
    font-size: 1rem;
    color: var(--text);
    text-decoration: none;
}
.psb-name:hover, .psb-name:focus-visible { color: var(--red-bright); text-decoration: underline; }
.psb-recent { display: flex; gap: 4px; }
.psb-pip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    background: var(--bg-tile);
    color: var(--text-mid);
    border-radius: 2px;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 0.95rem;
    line-height: 1;
    font-variant-numeric: tabular-nums;
}
.psb-pip.is-on { background: var(--red-wash); color: var(--text-strong); box-shadow: inset 0 -2px 0 var(--red); }
.psb-pip.is-na { background: transparent; color: var(--text-dim); font-weight: 600; }
.psb-total {
    text-align: center;
    font-family: var(--font-display);
    font-style: italic;
    font-weight: 800;
    font-size: 2.1rem;
    line-height: 1;
    color: var(--text);
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}
.psb-total.is-cards { font-size: 1.5rem; }
.psb-apps {
    text-align: center;
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 0.95rem;
    color: var(--text-dim);
}
.psb-row-empty { opacity: 0.4; }
.psb-none {
    margin: 0;
    padding: 18px 0;
    min-height: 194px;
    border-top: 1px solid var(--track);
    color: var(--text-dim);
    font-style: italic;
    font-size: 0.9rem;
}
.psb-unavailable { margin: 4px 0 0; font-size: 0.84rem; color: var(--text-dim); }

/* Below ~1100px each side would be too narrow for a full name next to the
   last-3 chips, so the two sides stack (team name shown over each). */
@media (max-width: 1100px) {
    .psb-sides { grid-template-columns: minmax(0, 1fr); row-gap: 8px; }
    .psb-sides::before { display: none; }
    .psb-side-team {
        position: static;
        display: flex;
        align-items: center;
        gap: 8px;
        width: auto;
        height: auto;
        overflow: visible;
        clip: auto;
        margin: 10px 0 2px;
    }
    .psb-none { min-height: 0; }
}
@media (max-width: 820px) {
    .psb-band { padding: 16px 16px 8px; }
    .psb-band h3 { font-size: 1.5rem; }
    .psb-team { font-size: 1.5rem; gap: 10px; }
    .psb-teams { padding: 12px 14px; gap: 10px; }
    .psb-teams .crest-lg { width: 44px; height: 44px; padding: 5px; }
}
@media (max-width: 480px) {
    /* Phone: two lines per player. Line 1 the name, line 2 the last-3 chips
       with appearances at the far end; the season total keeps the right edge. */
    .psb-side-head { display: flex; justify-content: space-between; height: 22px; padding-left: 58px; }
    .psb-h-apps { display: none; }
    .psb-row {
        grid-template-columns: 20px 30px minmax(0, 1fr) 52px;
        grid-template-areas: "rank av name total" "rank av recent total";
        column-gap: 8px;
        row-gap: 4px;
        padding: 8px 0;
    }
    .psb-rank { grid-area: rank; }
    .psb-avatar { grid-area: av; align-self: center; }
    .psb-name { grid-area: name; }
    .psb-recent { grid-area: recent; justify-self: start; }
    .psb-total { grid-area: total; }
    .psb-apps { grid-area: recent; justify-self: end; font-size: 0.8rem; }
    .psb-apps::after { content: " apps"; }
    .psb-pip { width: 20px; height: 20px; font-size: 0.85rem; }
    .psb-recent { gap: 3px; }
    .psb-avatar { width: 30px; height: 38px; }
    .psb-total { font-size: 1.7rem; }
    .psb-total.is-cards { font-size: 1.25rem; }
    .psb-name { font-size: 0.92rem; }
    .psb-icon { width: 48px; height: 44px; }
    .psb-icon .evg { width: 28px; height: 28px; }
    .psb-band h3 { font-size: 1.3rem; }
    .psb-team { font-size: 1.15rem; }
    .psb-vs { padding: 3px 12px; font-size: 1rem; }
    .psb-teams .crest-lg { width: 36px; height: 36px; padding: 4px; }
}

/* ---- Match Outlook (fixture page, top of the Form tab) -----------------
   A preview paragraph plus one chip per key absentee. Red marks a confirmed
   absence and grey a doubt; amber stays reserved for stale data warnings. */
.match-outlook-text { margin: 0; line-height: 1.65; color: var(--text); max-width: 78ch; }
.match-outlook-text strong { color: var(--text-strong); font-weight: 700; }
.outlook-absences {
    display: flex; flex-wrap: wrap; gap: 8px;
    list-style: none; margin: 16px 0 0; padding: 0;
}
.outlook-absence {
    display: inline-flex; align-items: center; gap: 8px;
    padding: 5px 12px 5px 6px;
    background: var(--bg-tile);
    border-left: 3px solid var(--red);
    font-size: 0.88rem;
}
.outlook-absence.is-doubt { border-left-color: var(--text-dim); }
.outlook-absence-status {
    font-family: var(--font-display); font-weight: 700; font-size: 0.74rem;
    letter-spacing: 0.1em; text-transform: uppercase; color: var(--red-bright);
}
.outlook-absence.is-doubt .outlook-absence-status { color: var(--text-mid); }
.outlook-absence-note { color: var(--text-mid); }


/* ==========================================================================
   LIGHT THEME
   --------------------------------------------------------------------------
   Almost all of the light look is the token set redefined under
   `:root[data-theme="light"]` right after `:root` at the top of this file
   (backgrounds, text, red text, positive/away/draw ramps, shadows, crest
   plate, photo wells, pitch, glyph ink, form pills). Dark is the default and
   the same tokens carry today's literal values, so dark never changes.

   Only the handful of rules that need a DIFFERENT SHAPE or a literal that has
   no token live here, all scoped by `:root[data-theme="light"]` (specificity
   (0,2,0)+ so they win over the layers above regardless of order). Add a new
   light-only override here, not scattered through the file; and never write
   #fff or a dark literal in new CSS: use --text-strong / --on-red /
   --hover-tint / --picker-bg etc.
   ========================================================================== */

/* two logo files, one per theme; the hidden one is display:none, so it is
   neither painted nor announced. No JS needed: CSS alone picks by theme. */
.brand .brand-logo-on-light { display: none; }
:root[data-theme="light"] .brand .brand-logo-on-dark { display: none; }
:root[data-theme="light"] .brand .brand-logo-on-light { display: block; }

/* search boxes: a soft grey well on the white header */
:root[data-theme="light"] .topbar-search::after { background-color: #f3f3f5; }

/* footer: white, like the header */
:root[data-theme="light"] .footer { background: var(--bg-card); color: var(--text-mid); }

/* fixture difficulty chips: easy = pale grey, hard = red; the pale end needs
   a ring and darker steps on a white card */
:root[data-theme="light"] .fdr-1 { background: #e4e4ea; color: #131317; }
:root[data-theme="light"] .fdr-2 { background: #c9c9d1; color: #131317; }
:root[data-theme="light"] .fdr-3 { background: #6b6b75; color: #ffffff; }

/* the pitch sits inside a card: keep it defined against white */
:root[data-theme="light"] .pitch { border-color: var(--border-strong); }

/* optional short colour transition while the theme flips (app.js adds the
   class for ~250ms); never under reduced motion */
@media (prefers-reduced-motion: no-preference) {
    html.theme-anim, html.theme-anim *, html.theme-anim *::before, html.theme-anim *::after {
        transition: background-color 200ms ease, border-color 200ms ease, color 200ms ease, fill 200ms ease, stroke 200ms ease !important;
    }
}

/* ---- Upcoming Fixtures on phones and tablets ------------------------------
   The desktop row's 9 columns need about 1100px: narrower, the fluid teams
   column is squeezed first (cut-off names at 1000px, gone entirely at 768px).
   So up to 1100px each fixture becomes its own scoreboard card carrying every
   number the row does, cards flowing 1 / 2 / 3 across by width: league and
   kick-off, crests either side of the predicted score, one bar split into
   home / draw / away chance (home red, draw grey, away white, by position as
   everywhere else), then the four stats as labelled tiles. Same markup as the
   desktop row (mini_fixture in _macros.html); this block only rearranges it,
   and sits last so it wins over the Broadcast layer. */
@media (max-width: 1100px) {
    .mini-fixtures-head { display: none; }
    .card.mini-fixtures {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr));
        gap: 10px;
        background: none;
        border: 0;
        box-shadow: none;
        padding: 0;
    }
    .card.mini-fixtures::after { display: none; }
    /* The cards need a grid of their own per day: the group is the grid item
       of .mini-fixtures, so it spans the row and re-creates the columns. */
    .mini-fixtures .mf-group {
        grid-column: 1 / -1;
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr));
        gap: 10px;
        margin-top: 28px;
    }
    .mini-fixtures .mf-group:first-of-type { margin-top: 0; }
    .mini-fixtures .mf-day { grid-column: 1 / -1; margin: 0; border-left: 0; }
    .mini-fixtures .mf-league-head { grid-column: 1 / -1; margin: 10px 0 2px; }
    .mini-fixtures .mf-day + .mf-league-head { margin-top: 0; }

    .mini-fixture {
        position: relative;
        grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
        grid-template-areas:
            ".      .      time"
            "home   score  away"
            "split  split  split"
            "probs  probs  probs"
            "stats  stats  stats";
        gap: 14px 8px;
        align-items: start;
        margin: 0;
        padding: 14px 14px 16px;
        background: var(--bg-card);
        border: 1px solid var(--border);
        border-radius: 0;
    }
    .mini-fixture:hover, .mini-fixture:focus-visible { background: var(--bg-card); border-color: var(--red); }

    .mf-label {
        position: static; width: auto; height: auto; margin: 0;
        overflow: visible; clip: auto; white-space: normal;
        font-family: var(--font-display);
        font-weight: 600;
        font-size: 0.7rem;
        line-height: 1.15;
        letter-spacing: 0.1em;
        text-transform: uppercase;
        color: var(--text-dim);
    }

    .mf-time {
        grid-area: time;
        justify-self: end;
        align-self: center;
        font-family: var(--font-display);
        font-weight: 700;
        font-size: 0.95rem;
        color: var(--text);
    }

    .mf-teams { display: contents; }
    .mf-team {
        flex-direction: column;
        justify-content: flex-start;
        gap: 7px;
        text-align: center;
    }
    .mf-team:first-child { grid-area: home; }
    .mf-team:last-child { grid-area: away; }
    .mf-team .crest { width: 44px; height: 44px; padding: 6px; }
    .mf-name {
        font-size: 1rem;
        line-height: 1.1;
        white-space: normal;
        overflow-wrap: anywhere;
    }

    .mf-score {
        grid-area: score;
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 2px;
        padding: 4px 0 0;
        border-left: 0;
        color: var(--text-strong);
    }
    .mf-score-val { font-weight: 800; font-size: 2.25rem; line-height: 1; letter-spacing: 0.04em; }

    .mf-split { grid-area: split; display: flex; height: 8px; gap: 2px; margin-bottom: -8px; }
    .mf-split > span { flex-basis: 0; min-width: 2px; }
    .mf-split-home { background: var(--c-home); }
    .mf-split-draw { background: var(--c-draw); }
    .mf-split-away { background: var(--c-away); }

    .mf-probs { grid-area: probs; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0; }
    .mf-prob, .mf-prob.top {
        display: flex;
        align-items: baseline;
        gap: 5px;
        min-width: 0;
        padding: 0;
        font-weight: 800;
        font-size: 1.06rem;
        color: var(--text-strong);
    }
    .mf-prob::before, .mf-prob.top::before { display: none; }
    .mf-probs > .muted { grid-column: 1 / -1; text-align: center; }
    .mf-prob:nth-child(2) { justify-content: center; }
    .mf-prob:nth-child(3) { justify-content: flex-end; }

    .mf-stats { grid-area: stats; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 2px; }
    .mf-stat {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: flex-end;
        gap: 2px;
        padding: 8px 4px;
        border-left: 0;
        background: var(--bg-tile);
        text-align: center;
        white-space: normal;
        font-family: var(--font-display);
        font-weight: 700;
        font-size: 1.2rem;
        color: var(--text);
    }
}

/* ---- stats hub, stat tables, team head to head ----------------------------
   /{league}/stats, /{league}/stats/{stat} and the Head to head card on a
   team page. Reuses the tokens, .h2h-metrics, .variant-switcher and the
   leaderboard avatar. */

.stat-chips { display: flex; flex-wrap: wrap; gap: 4px 14px; margin: 4px 0 8px; }

/* The stats hub's Teams/Players toggle: the page's main switch, so it sits
   directly under the heading and reads larger than an in-card chip row. */
.stats-hub-tabs { margin: 4px 0 18px; gap: 8px; }
.stats-hub-tabs .variant-tab { font-size: 1.05rem; padding: 10px 26px; letter-spacing: .08em; }
.stats-hub-switcher > .variant-panel > .landing-section:first-child { margin-top: 0; }
.stat-league-links { margin: 0; padding-left: 18px; line-height: 1.9; }
.stat-back { margin: 0 0 8px; }
.stat-footnote { margin: 6px 0 24px; }
.stat-explainer p { margin: 0 0 12px; color: var(--text-mid); line-height: 1.6; }
.stat-explainer p:last-child { margin-bottom: 0; }

/* The ranking tables. The sorted column reads brighter, the league average
   is a grey baseline row under a heavier rule (red = the team's own number,
   grey = the baseline). */
.stat-ranking th, .stat-ranking td { text-align: right; }
.stat-ranking th:nth-child(-n+2), .stat-ranking td:nth-child(-n+2) { text-align: left; }
.stat-ranking .col-sorted { color: var(--text-strong); font-weight: 800; }
.stat-ranking th.col-sorted { color: var(--red-bright); }
.stat-ranking td.muted { font-weight: 400; }
.stat-ranking td a { white-space: nowrap; }
.stat-avg-row td { border-top: 2px solid var(--border-strong); }
.stat-player { display: flex; align-items: center; gap: 8px; color: var(--text); text-decoration: none; }
.stat-player:hover { color: var(--red-bright); }
.stat-player strong { font-weight: 650; white-space: nowrap; }
.stat-player .leaderboard-row-photo { flex: none; }
.stat-player-team { flex: none; display: flex; }

/* "Full table" link under a leaderboard card, beside its Show all toggle. */
.leaderboard-full { display: inline-block; margin: 8px 0 0 14px; }
.leaderboard-list + .leaderboard-full { margin-left: 0; }

/* Head to head card at the foot of a team page. A plain table in its own
   scroll box: columns keep their natural width, the page never scrolls. */
.h2h-card-table th, .h2h-card-table td { text-align: left; }
.h2h-card-table th:nth-child(n+2):nth-child(-n+5),
.h2h-card-table td:nth-child(n+2):nth-child(-n+5) { text-align: center; }
.h2h-card-table td { white-space: nowrap; }
.h2h-card-table td.h2h-none:nth-child(n+2):nth-child(-n+5) { text-align: left; }

/* ---- stats hub: the stat tables section (featured tiles + list) -------------
   /{league}/stats, one per Teams / Players view (`stat_hub_section` in
   _macros.html). Featured tiles are an icon on the angled plate, the label,
   the unit, the leader's own value and the leader. The list under them is one
   plain link per row. Palette: black, dark grey, red, white (tokens only).
   `.is-team` / `.is-player` pick the view (never bare .team / .player). */

.stat-ico { display: block; width: 24px; height: 24px; flex: none; }
.stat-val {
    font-family: var(--font-display);
    font-weight: 800;
    font-style: italic;
    line-height: 1.05;
    font-variant-numeric: tabular-nums;
    color: var(--text-strong);
}
.stat-who {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
    color: var(--text-mid);
    font-size: .84rem;
}
.stat-who > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.stat-who .crest { flex: none; }

/* the angled icon plate: same recipe as .feature-icon */
.stat-plate {
    position: relative;
    isolation: isolate;
    display: inline-grid;
    place-items: center;
    width: 56px;
    height: 52px;
    color: var(--text-strong);
    flex: none;
}
.stat-plate::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    transform: skewX(var(--slant));
    background: var(--bg-sunken);
    border: 1px solid var(--border-strong);
    border-bottom: 3px solid var(--red);
    transition: border-color var(--ease);
}
.stat-plate .stat-ico { width: 34px; height: 34px; }
a:hover > .stat-plate::before,
a:focus-visible > .stat-plate::before { border-color: var(--red); }

/* featured tiles */
.stat-feat { display: grid; gap: 8px; grid-template-columns: repeat(4, minmax(0, 1fr)); }
.stat-feat.is-team { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.stat-feat-tile {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-areas: "ico label" "ico unit" "value value" "who who";
    column-gap: 12px;
    align-items: center;
    padding: 14px 14px 12px;
    background: var(--bg-tile);
    border: 1px solid var(--border);
    color: inherit;
    text-decoration: none;
    transition: border-color var(--ease), background var(--ease);
}
.stat-feat-tile:hover,
.stat-feat-tile:focus-visible { border-color: var(--red); background: var(--bg-card-hover); color: inherit; }
.stat-feat-tile .stat-plate { grid-area: ico; }
.stat-feat-label {
    grid-area: label;
    align-self: end;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .9rem;
    letter-spacing: .11em;
    text-transform: uppercase;
    color: var(--text-strong);
    line-height: 1.15;
}
.stat-unit { grid-area: unit; align-self: start; font-size: .74rem; color: var(--text-dim); margin-top: 2px; }
.stat-feat-value { grid-area: value; font-size: 2.5rem; margin-top: 10px; }
.stat-feat-tile .stat-who { grid-area: who; margin-top: 6px; }
.stat-feat-tile:hover .stat-feat-label { color: var(--red-bright); }

@media (max-width: 1000px) {
    .stat-feat { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .stat-feat.is-team { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 640px) {
    .stat-feat, .stat-feat.is-team { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; }
    .stat-feat-tile {
        padding: 10px 10px 9px;
        grid-template-areas: "ico label" "value value" "who who";
        column-gap: 8px;
    }
    .stat-feat-tile .stat-plate { width: 38px; height: 36px; }
    .stat-feat-tile .stat-plate .stat-ico { width: 24px; height: 24px; }
    .stat-feat .stat-unit { display: none; }
    .stat-feat-label { font-size: .78rem; align-self: center; }
    .stat-feat-value { font-size: 1.9rem; margin-top: 6px; }
}

/* ---- past-game page (/matches/{slug}) ----------------------------------------
   Score card with scorers, match story, the two SVG charts (xG timeline and
   shot map), bookings, the per-player table, form and meeting links. Reuses
   .final-score, .two-col, .variant-switcher, .stat-table, .h2h-metrics,
   .form-pill and the key-events timeline; only what those lack is here.
   Colours are tokens only (home --c-home, away --c-away), so both themes work. */

.match-score-ht { text-align: center; margin: 2px 0 0; }
.match-scorers {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 4px 18px;
    margin-top: 10px;
}
.scorers { list-style: none; margin: 0; padding: 0; font-size: 0.92rem; line-height: 1.45; color: var(--text-mid); }
.scorers-home { text-align: right; }
.scorers-away { text-align: left; }
.scorers li { display: flex; align-items: flex-start; gap: 6px; }
.scorers-home li { justify-content: flex-end; }
.scorers .evg { width: 16px; height: 16px; margin-top: calc((1.45em - 16px) / 2); }

.match-story p { margin: 0 0 10px; line-height: 1.55; }
.match-story p:last-child { margin-bottom: 0; }

/* Charts. Each is drawn twice (narrow and wide viewBoxes, see
   _match_charts.html) and the figure's own width chooses, so the SVG type is
   never scaled below ~12px: narrow below 480px of figure width, wide above. */
.chart { margin: 0; container-type: inline-size; }
.chart-svg {
    display: block;
    width: 100%;
    height: auto;
    font-family: var(--font-display);
    overflow: visible;
}
.chart .chart-wide { display: none; }
.chart .chart-narrow { max-width: 420px; margin-inline: auto; }
@container (min-width: 480px) {
    .chart .chart-narrow { display: none; }
    .chart .chart-wide { display: block; }
}
.ch-grid { stroke: var(--border); stroke-width: 1; }
.ch-axis { fill: var(--text-mid); }
.ch-ht { stroke: var(--text-mid); stroke-dasharray: 4 4; stroke-width: 1; }
.ch-ht-label { letter-spacing: 0.06em; }
.ch-line { fill: none; stroke-width: 2.5; stroke-linejoin: round; }
.ch-total { font-weight: 700; }
.ch-goal { cursor: pointer; }
.ch-goal circle { stroke: var(--bg-card); stroke-width: 2; }
.ch-goal text { fill: var(--text); font-weight: 600; }
.ch-pitch { fill: none; stroke: var(--text-mid); stroke-opacity: 0.45; stroke-width: 1.5; }
.ch-spot { fill: var(--text-mid); stroke: none; }
.ch-shot { stroke-width: 1.5; cursor: pointer; }
.ch-shot.is-goal { stroke-width: 2.5; }
.shotmap-ends {
    display: flex;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 6px;
    font-family: var(--font-display);
    font-size: 0.82rem;
    letter-spacing: 0.05em;
    text-transform: uppercase;
}
.shotmap-ends .home { color: var(--c-home); text-align: right; }
.shotmap-ends .away { color: var(--text); }
.chart-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 16px;
    margin-top: 8px;
    font-size: 0.84rem;
    color: var(--text-dim);
}
.chart-legend span { display: inline-flex; align-items: center; gap: 6px; }
.lg-line { display: inline-block; width: 18px; height: 3px; }
.lg-dot {
    display: inline-block;
    width: 11px;
    height: 11px;
    border-radius: 50%;
    border: 1.5px solid var(--text-mid);
    box-sizing: border-box;
}
.lg-dot.goal { background: var(--text-mid); }
.lg-dot.on { background: color-mix(in srgb, var(--text-mid) 35%, transparent); }
.chart-tip { margin: 6px 0 0; min-height: 1.3em; }

/* Bookings under the key events (older games: no minute on file). */
.match-bookings { margin-top: 16px; }
.match-bookings h3 { margin: 0 0 2px; }
.bk-side { margin-top: 8px; }
.bk-team { display: inline-flex; align-items: center; gap: 6px; font-family: var(--font-display); font-weight: 600; letter-spacing: 0.05em; }
.bk-side ul { list-style: none; margin: 4px 0 0; padding: 0; }
.bk-side li { padding: 2px 0; }

/* Per-player table. The table scrolls inside .table-scroll, never the page;
   the name column stays put while the numbers scroll under it on a phone. */
.player-match-table th,
.player-match-table td { padding: 7px 9px; text-align: right; white-space: nowrap; }
.player-match-table th:first-child,
.player-match-table td:first-child { text-align: left; }
.player-match-table th:nth-child(2),
.player-match-table td:nth-child(2) { text-align: left; }
.player-match-table td:first-child,
.player-match-table th:first-child {
    position: sticky;
    left: 0;
    z-index: 1;
    background: var(--bg-card);
}
.player-match-table tr.is-sub td { color: var(--text-dim); }
.pm-cards { display: inline-flex; gap: 2px; align-items: center; vertical-align: middle; }
.pm-cards .evg { width: 12px; height: 16px; }
.bk-side .pm-cards { margin-left: 8px; }

.form-line { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin: 8px 0; flex-wrap: wrap; }
.form-line .form-run a { text-decoration: none; }

.meeting-links { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 10px 20px; }
.meeting-links .btn-link { white-space: normal; text-align: left; }
.match-source { margin-top: 4px; }

/* ---- head-to-head page (/fixtures/{home}-vs-{away}) ---------------------------
   Reuses the latest-result card of the past-game page (.match-score) and the
   fixture page's .h2h-table. The meetings table here is the card's whole
   width, so on a phone it stays a real table (the global phone rule above
   turns every table into a scroll box, which hid the away club) and club
   names wrap instead of being cut. */
@media (max-width: 640px) {
    .h2h-table.h2h-table-full { display: table; white-space: normal; }
    .h2h-table-full th, .h2h-table-full td { white-space: normal; overflow: visible; }
    .h2h-table-full .h2h-name { display: inline; white-space: normal; max-width: none; }
    .h2h-table-full th:nth-child(1), .h2h-table-full td:nth-child(1) { width: 22%; }
    .h2h-table-full th:nth-child(2), .h2h-table-full td:nth-child(2) { width: 32%; }
    .h2h-table-full th:nth-child(3), .h2h-table-full td:nth-child(3) { width: 14%; }
    .h2h-table-full th:nth-child(4), .h2h-table-full td:nth-child(4) { width: 32%; }
}

/* Every meeting: the whole row opens that game. The score link's ::after
   stretches over the row (tr is the positioned ancestor; td is not), so it is
   still one real link: middle-click, open in new tab and keyboard all work. */
.h2h-row-link { position: relative; cursor: pointer; }
.h2h-row-link:hover td { background: var(--hover-tint); }
.h2h-row-anchor { color: inherit; text-decoration: none; }
.h2h-row-anchor::after { content: ""; position: absolute; inset: 0; }
.h2h-row-link:hover .h2h-row-anchor { color: var(--red); }
.h2h-row-anchor:focus-visible { outline: none; }
.h2h-row-anchor:focus-visible::after { outline: 2px solid var(--red); outline-offset: -2px; }

/* ---- season archive (/{league}/seasons, /{league}/seasons/{yyyy-yy}) --------
   Reuses .card, .h2h-metrics, .stat-table inside .table-scroll, .hb-category
   (the results groups are plain <details>) and .h2h-table-full. Only the small
   tag beside a club in the final table and the notes under a table are new. */
.season-tag {
    display: inline-block; margin-left: 6px; padding: 1px 6px; border: 1px solid var(--border);
    border-radius: 3px; font-family: var(--font-display); font-size: 0.68rem; font-weight: 600;
    letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-mid); vertical-align: middle;
}
.season-tag.is-champion { border-color: var(--red-bright); color: var(--red-bright); }
.season-note { margin: 8px 0 0; font-size: 0.82rem; }
.season-results .hb-category > summary { flex-wrap: wrap; }
.season-results .hb-category-count { white-space: normal; text-align: right; }
.season-records .h2h-metric-sub { line-height: 1.5; }
.season-records .h2h-metric-sub a { white-space: normal; overflow-wrap: anywhere; }
.seasons-table .season-current td { background: var(--bg-sunken); }
.season-chips { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin: 8px 0 0; }
/* On a phone the final table keeps position, club, played, goal difference and
   points (and points per game), and the scorer lists drop games played, so the
   figure that matters is on screen without scrolling. */
@media (max-width: 640px) {
    .season-table .col-x, .season-players .col-x { display: none; }
    /* Let a long club name or its Champions/Relegated tag take a second
       line rather than push points off screen. */
    .season-table td:nth-child(2), .season-players td { white-space: normal; }
    .season-table .season-tag { margin-left: 0; }
}


/* ==========================================================================
   ARROWS (2026-10). One family everywhere: a long arrow with an open head and
   round ends (chevrons for "open / close" and sort), drawn as a CSS mask so it
   takes `currentColor`, both themes and every hover/active rule for free.
   Use <span class="arr arr-r" aria-hidden="true"></span> in markup; never a
   text glyph (the display font has none, so the browser falls back to a thin
   system arrow). Directions: r l d u, ur dr (diagonals: trends and movers),
   cd cu (chevrons), ud (stacked chevrons: idle sort).
   Put "&nbsp;" between a word and its arrow (and after a leading one) so the
   arrow never wraps onto a line of its own. Sizes are per context below.
   ========================================================================== */
:root {
    --ic-arrow-r: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 12h16.5M13.5 5.5 20 12l-6.5 6.5'/%3E%3C/svg%3E");
    --ic-arrow-l: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20.5 12H4M10.5 5.5 4 12l6.5 6.5'/%3E%3C/svg%3E");
    --ic-arrow-d: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3.5V20M5.5 13.5 12 20l6.5-6.5'/%3E%3C/svg%3E");
    --ic-arrow-u: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 20.5V4M5.5 10.5 12 4l6.5 6.5'/%3E%3C/svg%3E");
    --ic-arrow-ur: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 18 18 6M8.5 6H18v9.5'/%3E%3C/svg%3E");
    --ic-arrow-dr: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 6l12 12M18 8.5V18H8.5'/%3E%3C/svg%3E");
    --ic-arrow-cd: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5.5 9 12 15.5 18.5 9'/%3E%3C/svg%3E");
    --ic-arrow-cu: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5.5 15 12 8.5 18.5 15'/%3E%3C/svg%3E");
    --ic-arrow-ud: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M7 9.5 12 4.5l5 5M7 14.5l5 5 5-5'/%3E%3C/svg%3E");
}
.arr {
    --arr: var(--ic-arrow-r);   /* a missing direction class still draws an arrow, never a solid block */
    display: inline-block;
    flex: none;
    width: 1.45em;
    height: 1.45em;
    vertical-align: -0.34em;
    background: currentColor;
    -webkit-mask: var(--arr) center / contain no-repeat;
            mask: var(--arr) center / contain no-repeat;
}
.arr-r  { --arr: var(--ic-arrow-r); }
.arr-l  { --arr: var(--ic-arrow-l); }
.arr-d  { --arr: var(--ic-arrow-d); }
.arr-u  { --arr: var(--ic-arrow-u); }
.arr-ur { --arr: var(--ic-arrow-ur); }
.arr-dr { --arr: var(--ic-arrow-dr); }
.arr-cd { --arr: var(--ic-arrow-cd); }
.arr-cu { --arr: var(--ic-arrow-cu); }
.arr-ud { --arr: var(--ic-arrow-ud); }
/* Link arrows nudge in the direction they point. */
.arr-r, .arr-l { transition: transform 0.15s ease; }
a:hover .arr-r, button:hover .arr-r { transform: translateX(3px); }
a:hover .arr-l, button:hover .arr-l { transform: translateX(-3px); }
@media (prefers-reduced-motion: reduce) {
    .arr-r, .arr-l { transition: none; }
    a:hover .arr-r, a:hover .arr-l, button:hover .arr-r, button:hover .arr-l { transform: none; }
}
/* Small print and chart direction labels */
.scroll-hint .arr, .shotmap-ends .arr { width: 1.3em; height: 1.3em; vertical-align: -0.3em; }
/* Matchweek prev / next: 34px square, 20px arrow */
.md-arrow { width: 34px; height: 34px; font-size: 0; }
.md-arrow .arr { width: 20px; height: 20px; vertical-align: 0; }
a.md-arrow:hover .arr-r, a.md-arrow:hover .arr-l { transform: none; }
/* Row expanders (chevron down; rotates to point up and turns red when open) */
.arr.rm-chevron { width: 20px; height: 20px; font-size: inherit; vertical-align: 0; }
.rm-details[open] .arr.rm-chevron { color: var(--red-bright); }
.arr.hb-arrow { width: 20px; height: 20px; vertical-align: 0; }
/* Dropdown carets */
.arr.league-select-caret { width: 16px; height: 16px; font-size: inherit; margin-left: 0; vertical-align: 0; }
.hb-bar-name .arr { width: 16px; height: 16px; vertical-align: -0.2em; }
.hb-bar-arr .arr { width: 22px; height: 22px; vertical-align: 0; }
/* "On the way up / down" headings and the league-position mover */
.movers-head .arr { width: 1.2em; height: 1.2em; vertical-align: -0.22em; }
.arr.totw-mover { width: 13px; height: 13px; vertical-align: -0.15em; }
/* Trend ("Above / Below career") */
.rf-trend.up::before, .rf-trend.down::before {
    content: "";
    display: inline-block;
    width: 1.1em;
    height: 1.1em;
    margin-right: 0.15em;
    vertical-align: -0.22em;
    background: currentColor;
    -webkit-mask: var(--ic-arrow-ur) center / contain no-repeat;
            mask: var(--ic-arrow-ur) center / contain no-repeat;
}
.rf-trend.down::before {
    -webkit-mask-image: var(--ic-arrow-dr);
            mask-image: var(--ic-arrow-dr);
}
/* Sortable table headers: stacked chevrons when idle, one chevron when active */
table.js-sortable th[data-sort]::after,
table.js-sortable th[data-sort].sort-asc::after,
table.js-sortable th[data-sort].sort-desc::after {
    content: "";
    width: 14px;
    height: 14px;
    font-size: 0;
    background: currentColor;
    -webkit-mask: var(--ic-arrow-ud) center / contain no-repeat;
            mask: var(--ic-arrow-ud) center / contain no-repeat;
}
table.js-sortable th[data-sort].sort-asc::after {
    -webkit-mask-image: var(--ic-arrow-cu);
            mask-image: var(--ic-arrow-cu);
}
table.js-sortable th[data-sort].sort-desc::after {
    -webkit-mask-image: var(--ic-arrow-cd);
            mask-image: var(--ic-arrow-cd);
}
/* Windows high-contrast: a background-drawn shape would be repainted to the page
   colour and vanish, so pin these to the system text colour. */
@media (forced-colors: active) {
    .arr, .rf-trend.up::before, .rf-trend.down::before,
    table.js-sortable th[data-sort]::after { forced-color-adjust: none; background: CanvasText; }
}

/* Phones: one line for the date banner, so the match count never wraps under it. */
@media (max-width: 520px) {
    .mf-day { font-size: 1.55rem; padding: 10px 14px 10px 22px; }
    .mf-day-count { font-size: 0.7rem; letter-spacing: 0.08em; }
}

/* ============================================================
   NEWS (/news, article pages) and the journalist's EDITOR (/editor).
   Tokens only, so both themes work; no colour outside the palette.
   ============================================================ */
.news-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: 12px;
    margin-bottom: 24px;
}
.news-card {
    display: flex;
    flex-direction: column;
    margin: 0;
    padding: 0;
    /* No overflow: hidden here. The cut corner (.card::after) hangs 1px over
       the border; clipping it left the square outline showing past the cut. */
    text-decoration: none;
    color: inherit;
}
.news-card:hover, .news-card:focus-visible {
    border-color: var(--red-line);
    background: var(--bg-card-hover);
}
.news-card-img {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 16 / 9;
    object-fit: cover;
    background: var(--bg-sunken);
}
.news-card-body { display: flex; flex-direction: column; gap: 6px; padding: 14px 18px 16px; flex: 1; }
.news-card h2::before { content: none; }
.news-card h2, .news-card h3 {
    display: block;
    font-style: normal;
    font-weight: 700;
    margin: 0;
    font-family: var(--font-display);
    font-size: 1.3rem;
    line-height: 1.15;
    letter-spacing: 0;
    text-transform: none;
    color: var(--text);
}
.news-card-summary { color: var(--text-mid); font-size: 0.9rem; line-height: 1.45; flex: 1; }
.news-kicker {
    font-family: var(--font-display);
    font-size: 0.78rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--red);
    margin: 0;
}
.news-kicker a { color: inherit; text-decoration: none; }
.news-kicker a:hover { text-decoration: underline; text-underline-offset: 3px; }
.news-meta { color: var(--text-dim); font-size: 0.8rem; margin: 0; }
.pager { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 4px 0 24px; }

.news-article { max-width: 780px; margin: 0 auto 32px; }
.news-article-head h1 { font-size: clamp(1.9rem, 5vw, 2.7rem); line-height: 1.1; margin: 4px 0 10px; }
.news-dek { font-size: 1.15rem; line-height: 1.5; color: var(--text-mid); margin: 0 0 10px; }
.news-hero { margin: 18px 0 8px; }
.news-hero img { display: block; width: 100%; height: auto; border: 1px solid var(--border); background: var(--bg-sunken); }
.article-body { font-size: 1.05rem; line-height: 1.75; color: var(--text); overflow-wrap: anywhere; }
.article-body > :first-child { margin-top: 0; }
.article-body p { margin: 0 0 1.1em; }
.article-body h2 { font-size: 1.5rem; margin: 1.6em 0 0.5em; }
.article-body h3 { font-size: 1.15rem; margin: 1.4em 0 0.4em; color: var(--text); text-transform: none; letter-spacing: 0; }
.article-body h4 { margin: 1.2em 0 0.4em; }
.article-body a { color: var(--red); text-decoration: underline; text-underline-offset: 3px; }
.article-body a:hover { color: var(--red-bright); }
.article-body ul, .article-body ol { margin: 0 0 1.1em; padding-left: 1.4em; }
.article-body li { margin-bottom: 0.35em; }
.article-body blockquote {
    margin: 1.2em 0;
    padding: 4px 0 4px 18px;
    border-left: 3px solid var(--red);
    color: var(--text-mid);
}
.article-body blockquote p:last-child { margin-bottom: 0; }
.article-body img { display: block; max-width: 100%; height: auto; margin: 1.2em auto; border: 1px solid var(--border); }
.article-body hr { border: 0; border-top: 1px solid var(--border); margin: 1.8em 0; }
.article-body code { font-size: 0.92em; background: var(--bg-sunken); padding: 1px 5px; border-radius: 3px; }
.article-body pre { overflow-x: auto; background: var(--bg-sunken); padding: 12px 14px; margin: 0 0 1.1em; }
.article-body .table-scroll { margin: 0 0 1.1em; }
.editor-preview-banner { border-left: 3px solid var(--red); margin-bottom: 18px; }

/* --- the editor: its own light page shell, same tokens --- */
.ed-bar {
    display: flex; flex-wrap: wrap; align-items: center; gap: 8px 20px;
    padding: 12px 22px; border-bottom: 1px solid var(--border); background: var(--bg-card);
}
.ed-brand { font-family: var(--font-display); font-weight: 800; font-style: italic; font-size: 1.2rem; color: var(--text); text-decoration: none; margin-right: auto; }
.ed-bar a { color: var(--text-mid); text-decoration: none; font-weight: 600; }
.ed-bar a:hover { color: var(--red); }
.ed-bar form { margin: 0; }
.ed-main { max-width: 1280px; margin: 0 auto; padding: 24px 22px 80px; }
.ed-main h1 { margin-bottom: 14px; }
.ed-login { max-width: 380px; margin: 60px auto; }
.ed-field { display: block; margin: 0 0 14px; }
.ed-field > span, .ed-label { display: block; font-size: 0.8rem; font-weight: 650; color: var(--text-mid); margin-bottom: 5px; }
.ed-field small, .ed-help { display: block; color: var(--text-dim); font-size: 0.78rem; margin-top: 4px; line-height: 1.4; }
.ed-main input[type="text"], .ed-main input[type="password"], .ed-main input[type="search"],
.ed-main input[type="datetime-local"], .ed-main select, .ed-main textarea {
    width: 100%; box-sizing: border-box; padding: 9px 11px; font: inherit; font-size: 0.95rem;
    color: var(--text); background: var(--bg-input); border: 1px solid var(--border-strong); border-radius: 4px;
}
.ed-main input:focus, .ed-main select:focus, .ed-main textarea:focus { outline: 2px solid var(--red); outline-offset: 1px; }
.ed-title-input { font-size: 1.4rem !important; font-weight: 700; }
.ed-body-input { min-height: 520px; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace !important; font-size: 0.92rem !important; line-height: 1.6; resize: vertical; }
.ed-btn {
    display: inline-block; padding: 9px 18px; font: inherit; font-weight: 700; cursor: pointer;
    color: var(--text); background: var(--bg-tile); border: 1px solid var(--border-strong); border-radius: 4px;
}
.ed-btn:hover { border-color: var(--red); }
.ed-btn-primary { background: var(--red); border-color: var(--red); color: #fff; }
.ed-btn-primary:hover { background: var(--red-bright); }
.ed-btn-small { padding: 5px 10px; font-size: 0.82rem; }
.ed-layout { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: 20px; align-items: start; }
.ed-side .card { margin-bottom: 14px; }
.ed-side h2 { font-size: 0.95rem; }
.ed-split { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 16px; }
.ed-toolbar { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 8px; }
.ed-preview { border: 1px solid var(--border); background: var(--bg-card); padding: 16px 20px; min-height: 520px; overflow: auto; }
.ed-alert { border-left: 3px solid var(--red); margin-bottom: 14px; }
.ed-alert ul, .ed-warn ul { margin: 6px 0 0; padding-left: 1.2em; }
.ed-warn { border-left: 3px solid var(--warn, var(--text-dim)); margin-bottom: 14px; }
.ed-ok { border-left: 3px solid var(--text); margin-bottom: 14px; }
.ed-found { list-style: none; margin: 6px 0 0; padding: 0; }
.ed-found li button { width: 100%; text-align: left; background: none; border: 0; border-bottom: 1px solid var(--border); color: var(--text); padding: 7px 4px; cursor: pointer; font: inherit; }
.ed-found li button:hover { color: var(--red); }
.ed-found small { color: var(--text-dim); margin-left: 6px; }
.ed-thumb { display: block; max-width: 100%; height: auto; margin: 8px 0; border: 1px solid var(--border); }
.ed-count { float: right; font-weight: 500; color: var(--text-dim); }
.ed-count.over { color: var(--red); }
.ed-status { display: inline-block; padding: 2px 9px; border: 1px solid var(--border-strong); border-radius: 99px; font-size: 0.75rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; }
.ed-status.live { border-color: var(--text); color: var(--text); }
.ed-status.scheduled { border-color: var(--red); color: var(--red); }
.ed-actions { display: flex; flex-wrap: wrap; gap: 8px; }
@media (max-width: 980px) {
    .ed-layout, .ed-split { grid-template-columns: minmax(0, 1fr); }
    .ed-preview { min-height: 200px; }
    .ed-body-input { min-height: 360px; }
}

/* --- news: share bar, author page, entity "latest news" strips --- */
.share-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 14px 0 18px; }
.share-bar .share-label {
    font-family: var(--font-display); font-size: 0.8rem; font-weight: 700;
    letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-dim); margin-right: 2px;
}
.share-bar .chip { cursor: pointer; text-decoration: none; font: inherit; line-height: 1.2; }
.share-bar .share-chip {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 5px 11px; font-size: 0.68rem; letter-spacing: 0.04em;
}
.share-bar .share-ico { flex: none; width: 15px; height: 15px; display: block; }
.share-bar .share-chip[hidden] { display: none; }
.share-bar .chip[hidden] { display: none; }
/* The chip's visible shape is its skewed ::before, so state styling goes there.
   The sitewide `button:hover` (red wash, red border) paints the button's own
   square box, which showed as a red square behind the Copy link and Share
   buttons; cancel it and highlight the skewed shape instead. */
.share-bar .chip:hover, .share-bar .chip:focus-visible, .share-bar .chip:active {
    color: var(--text);
    background: none;
    border: 0;
    box-shadow: none;
}
.share-bar .chip:focus-visible { outline: none; }
.share-bar .chip:hover::before, .share-bar .chip:focus-visible::before { border-color: var(--red-line); }
.share-bar .chip.is-done { color: var(--text); }
.share-bar .chip.is-done::before { border-color: var(--red); }
.author-head { max-width: 780px; margin: 0 0 28px; }
.author-head h1 { font-size: clamp(2rem, 5vw, 2.8rem); line-height: 1.1; margin: 4px 0 14px; }
.author-bio p { font-size: 1.05rem; line-height: 1.7; color: var(--text-mid); margin: 0 0 1em; }
.author-articles-title { margin-top: 8px; }
.entity-news { margin-top: 8px; }
.entity-news > .muted { margin: 0 0 12px; }
.news-meta a { color: inherit; text-decoration: underline; text-underline-offset: 3px; }
.news-meta a:hover { color: var(--red); }


/* --- Team page: Historic Bets summary --------------------------------- */
.hb-vs {
    display: inline-block;
    margin-left: 4px;
    padding: 0 6px;
    border-radius: 3px;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 0.74rem;
    letter-spacing: 0.02em;
    color: var(--text-strong);
    background: var(--bg-sunken);
}
/* Red = this club's number sitting above the baseline, grey = at or below it. */
.hb-vs-above { background: var(--red-wash); color: var(--red-bright); }
.hb-summary { margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--border); }
.hb-summary h3 {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 10px;
    margin: 0 0 8px;
    font-size: 1rem;
}
.hb-summary p { margin: 0 0 10px; font-size: 0.9rem; line-height: 1.55; color: var(--text-mid); }
.hb-summary .hb-summary-note { font-size: 0.74rem; margin-bottom: 0; }
.hb-verdict {
    padding: 2px 8px;
    border-radius: 3px;
    font-family: var(--font-display);
    font-size: 0.72rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    background: var(--bg-sunken);
    color: var(--text-mid);
}
.hb-verdict-above { background: var(--red-wash); color: var(--red-bright); }


/* ============================================================
   ODDS BOARD (fixture page, Odds tab)
   Bookmaker price comparison. Tokens only, so both themes work.
   Best price = red (brand accent, never green); worst = dimmed.
   ============================================================ */

.ob-fine { margin: 14px 0 0; font-size: 0.78rem; line-height: 1.45; }

/* bookmaker logo: the site's light plate (as behind a club crest) so dark and
   light marks both read in either theme; the monogram is the no-logo fallback */
.ob-logo {
    flex: none; display: inline-flex; align-items: center; justify-content: center;
    width: 36px; height: 36px; padding: 3px; border-radius: 4px;
    background: var(--plate-bg); box-shadow: var(--plate-ring);
    transition: box-shadow var(--ease);
}
.ob-logo img { display: block; width: 100%; height: 100%; object-fit: contain; border-radius: 3px; }
.ob-mono {
    font-family: var(--font-display); font-weight: 800; font-style: italic;
    font-size: 0.95rem; letter-spacing: 0.04em; color: #3a3a42;
}

/* ---- A: price board ---------------------------------------------------- */

.ob-best {
    display: grid; grid-template-columns: repeat(var(--tiles, 4), minmax(0, 1fr));
    gap: 10px; margin: 0 0 20px;
}
/* two columns once four across gets tight; an odd last tile (3 markets when
   there is no BTTS price) then takes the full row instead of sitting alone */
@media (max-width: 760px) {
    .ob-best { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .ob-tile:last-child:nth-child(odd) { grid-column: 1 / -1; }
}
.ob-tile {
    position: relative; display: flex; flex-direction: column; gap: 3px;
    padding: 12px 14px 12px 16px;
    background: var(--bg-tile); border: 1px solid var(--border); border-left: 3px solid var(--red);
    color: var(--text); text-decoration: none;
    transition: background var(--ease), border-color var(--ease);
}
a.ob-tile:hover { background: var(--bg-card-hover); border-color: var(--red-line); border-left-color: var(--red); color: var(--text); text-decoration: none; }
.ob-tile-label {
    font-family: var(--font-display); font-weight: 600; font-size: 0.74rem;
    letter-spacing: 0.11em; text-transform: uppercase; color: var(--text-mid);
}
.ob-tile-price {
    font-family: var(--font-display); font-weight: 800; font-style: italic;
    font-size: 2.2rem; line-height: 1; color: var(--text-strong);
    font-variant-numeric: tabular-nums;
}
.ob-tile-at { display: flex; align-items: center; flex-wrap: wrap; gap: 0 6px; font-weight: 600; font-size: 0.86rem; color: var(--text); }
.ob-tile-at .arr { color: var(--red-bright); }
.ob-tile-sub { font-size: 0.72rem; color: var(--text-dim); }

.ob-books { --cols: repeat(var(--n), minmax(62px, 1fr)); }
.ob-head, .ob-book {
    display: grid; grid-template-columns: minmax(150px, 2.2fr) var(--cols);
    align-items: center; gap: 8px;
}
.ob-head {
    padding: 0 6px 7px; border-bottom: 1px solid var(--border-strong);
    font-family: var(--font-display); font-weight: 700; font-size: 0.74rem;
    letter-spacing: 0.12em; text-transform: uppercase; color: var(--text-dim);
}
.ob-head-c { text-align: center; }
.ob-list { list-style: none; margin: 0; padding: 0; }
.ob-book { padding: 7px 6px; border-bottom: 1px solid var(--border); transition: background var(--ease); }
.ob-book:hover { background: var(--hover-tint-soft); }
.ob-name { display: flex; align-items: center; gap: 11px; min-width: 0; color: var(--text); text-decoration: none; }
a.ob-name:hover { color: var(--text); text-decoration: none; }
a.ob-name:hover .ob-logo { box-shadow: 0 0 0 2px var(--red); }
.ob-name-text { display: flex; flex-direction: column; min-width: 0; line-height: 1.2; }
.ob-name-main { font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ob-name-visit {
    display: inline-flex; align-items: center; gap: 4px; font-size: 0.72rem; font-weight: 600;
    color: var(--text-dim); transition: color var(--ease);
}
a.ob-name:hover .ob-name-visit { color: var(--red-bright); }

/* a price: plain number, the best one sits on a red slanted plate */
.ob-px {
    position: relative; isolation: isolate; justify-self: center; min-width: 54px; text-align: center;
    padding: 4px 8px; font-family: var(--font-display); font-weight: 700; font-style: italic;
    font-size: 1.12rem; line-height: 1.1; color: var(--text); font-variant-numeric: tabular-nums;
}
.ob-px-best { color: var(--on-red); font-weight: 800; }
.ob-px-best::before {
    content: ""; position: absolute; inset: 0; z-index: -1; background: var(--red);
    transform: skewX(var(--slant));
}
.ob-px-worst { color: var(--text-dim); font-weight: 600; }
.ob-px-na { color: var(--text-dim); font-weight: 400; }

/* ---- phones ------------------------------------------------------------- */

@media (max-width: 640px) {
    .ob-tile-price { font-size: 1.9rem; }

    .ob-head { display: none; }
    .ob-book {
        grid-template-columns: repeat(var(--n), minmax(0, 1fr)); gap: 10px 6px; padding: 12px 4px;
    }
    .ob-book .ob-name { grid-column: 1 / -1; }
    /* inset by the plate's skew overhang so a red best-price plate stays inside the card */
    .ob-book .ob-px { display: flex; flex-direction: column; gap: 2px; min-width: 0; width: auto; margin: 0 7px; padding: 6px 4px 5px; }
    .ob-book .ob-px::after {
        content: attr(data-l); order: -1;
        font-family: var(--font-display); font-style: normal; font-weight: 600; font-size: 0.64rem;
        letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-dim);
    }
    .ob-book .ob-px-best::after { color: var(--on-red); opacity: 0.85; }
}
