/**
 * Sport theme — the portal wearing BrettZone's broadcast design language.
 *
 * One of the themes registered in PortalThemeService::THEMES. Like matrix it
 * rides Bootstrap's own dark component CSS (data-bs-theme stays "dark") and
 * gets its whole look from this sheet, keyed off `html[data-portal-theme=
 * "sport"]`, which base.twig stamps unconditionally. Adding a theme = one
 * THEMES entry + one stylesheet like this + one entry in portal-theme.js's
 * PORTAL_THEMES — nothing in the toggle/cascade machinery changes.
 *
 * WHAT IT IS FOR. NHRL runs two products on the same wall: this portal and
 * Austin's BrettZone. /tv already has ?skin=sport so a kiosk board can match
 * the panel beside it. This is the same answer for the APP pages — a person
 * at an event can put the whole portal in BrettZone's language and stop
 * context-switching between two companies' software. Ungated: it is a brand
 * look, not a toy, so everyone gets the row in Appearance.
 *
 * ── SOURCE OF TRUTH, AND AN HONEST CAVEAT ────────────────────────────────
 *
 * The BrettZone "sport" refresh (Austin, September 2026) is a FINISH, not a
 * new design language: upstream, bz-tokens.css and bz-components.css are
 * byte-identical before and after it, and the whole refresh is one 6KB sheet
 * loaded after the components. Same palette, same three faces, same corner
 * cut — what changes is that the ornament comes off.
 *
 * THE UPSTREAM SPORT SHEETS ARE NOT ON THIS MACHINE. The local
 * havocManager checkout is at bd5ff32 (Aug 18 2026), which predates the
 * refresh: `app/brettzone/v2/assets/css/bz-sport.css`, `app/mi/css/sport.css`
 * and design.md's "September 2026 UI refresh" section do not exist here, and
 * `git fetch` brings nothing newer. So the authority chain used to write this
 * file is, in order:
 *
 *   1. havocManager/design.md §§1-9 — the brand law, named as such by that
 *      repo's AGENTS.md §8. (NOT app/mi/docs/DESIGN_GUIDE.md, which describes
 *      the pre-July-2026 HAVOC theme and was never updated.)
 *   2. havocManager/app/brettzone/v2/assets/css/bz-tokens.css — the palette.
 *   3. havocManager/app/mi/css/havoc.css — THE CLOSEST ANALOGUE THERE IS:
 *      the BrettZone language applied to a Bootstrap-5 admin surface with an
 *      unchanged class vocabulary. That is exactly this file's problem, and
 *      where the Bootstrap-shaped rules below (.card, .table, .form-control,
 *      .dropdown-menu, .badge, focus ring, scrollbars) trace to.
 *   4. For the SPORT finish specifically: public/css/brettzone/brettzone-sport
 *      .css and public/css/tv-pages/tv-brettzone-sport.css IN THIS REPO. They
 *      were written against a newer upstream and cite the rule they trace to
 *      block by block. Second-hand, but the best record that exists here.
 *
 * If you are re-syncing against a fresh havocManager, diff §2 below against
 * bz-tokens.css first — that is where drift would land.
 *
 * ── THE SPORT FINISH, IN ONE SENTENCE ────────────────────────────────────
 *
 * Flat surfaces and dividers where a bordered card adds nothing; no shadows,
 * no hover lift, no outline echoes; 2px radii on controls; DIN Heavy Italic
 * carries the page title; the corner cut stays on the things that are OBJECTS
 * and comes off the things that are merely ACTIVE.
 *
 * ── FIVE THINGS THAT WILL BITE THE NEXT READER ───────────────────────────
 *
 * 1. THE SWATCH SELECTOR. §2's token block carries BOTH
 *    `html[data-portal-theme="sport"] body` AND
 *    `.portal-theme-scope[data-portal-theme="sport"]`. It is not belt and
 *    braces. portal-components.css declares --portal-c-* on
 *    `.portal-theme-scope[data-bs-theme="dark"|"light"]` and has no third
 *    branch, so a theme whose tokens live only on `html[…] body` is handed
 *    DARK's tokens inside a scope element — which is how the matrix swatch
 *    shipped pixel-identical to the dark swatch for months (kit 3.8.1).
 *    tests/visual/appearance.spec.js now asserts every theme's swatch ground
 *    AND accent are unique across all themes.
 *
 * 2. THERE ARE TWO TOKEN BLOCKS, §2 AND §2b, AND THEY ARE NOT A TIDINESS
 *    SPLIT. Everything --portal-* and --bz-* can live on `body` and inherit.
 *    Everything --bs-* cannot: `.portal-page-themed` carries data-bs-theme on
 *    <main>, and both Bootstrap and portal-theme.css declare --bs-* on a bare
 *    [data-bs-theme="dark"], so that inner element re-declares them on itself
 *    and shadows the theme for the whole page beneath it. Measured before the
 *    split: `body` reported the 2px/4px sport radius ladder while cards
 *    rendered at 10px, inputs at 4px and tiles at 6px. §2b's own header has
 *    the selector and the guard it needs.
 *
 * 3. !important EVERYWHERE IN §2, same as matrix, and for a specificity
 *    reason rather than a stylistic one: the glass degrade gates at the end
 *    of portal-components.css declare on
 *    `html[data-portal-glass="off"] .portal-theme-scope[data-bs-theme]`,
 *    which is (0,3,0) and beats this file's (0,1,2)/(0,2,0). Without
 *    !important a device with glass off would pull dark's translucent
 *    surfaces back over the top. It also means any token this file OMITS
 *    falls through to dark — which is why §2 covers the kit's dark-block
 *    tokens IN FULL rather than the partial mirror matrix pays for. (Deliberately
 *    not a count: the two obvious ways to census that block disagree by six,
 *    so a number here would be a fact the next reader cannot reproduce.
 *    tests/Contract/TokenRegistryTest is the check that actually holds.)
 *    Matrix is a
 *    DEVELOPER toy and can afford to inherit; this one is offered to
 *    everybody, and every inherited token is a piece of another theme's
 *    palette on a page somebody is working from.
 *
 * 4. NO color-mix() IN THIS FILE, on purpose. tests/Contract/
 *    ParseFloorTwinsTest scans public/css/site for `--x: color-mix(…)` and
 *    demands a literal twin in BOTH halves of gate 4 at the end of
 *    portal-components.css, with the value recomputed. BrettZone's palette is
 *    literal anyway, so writing rgba() by hand costs nothing and buys this
 *    theme out of that maintenance entirely.
 *
 * 5. NO clip-path ON CARDS. design.md keeps the arena-corner cut on objects,
 *    and it is the most recognisable thing BrettZone owns — but clip-path
 *    clips absolutely-positioned descendants and EATS OUTER box-shadow focus
 *    rings, and a portal card routinely hosts a Bootstrap dropdown, a Tom
 *    Select menu and focusable controls at its edge. A cut card would trade a
 *    keyboard focus ring for a motif. So the cut lands on .btn-primary only
 *    (a leaf, whose ring is converted to inset in §5) — see §5's note; taking
 *    it further is a decision, not an oversight.
 *
 * And one more that is not a trap but is worth knowing: --portal-c-surface-
 * header is a FALSE FRIEND. Four of its seven consumers are not headers, so
 * emptying it to get R10's transparent headers turns a login field into a
 * hole in the card. §2 gives it a flat rung; §4 makes the two real headers
 * transparent by name.
 */


/* ═══ 1. Faces ═══════════════════════════════════════════════════════════
 * DIN Next LT Pro and Berkeley Mono, the two commercial faces NHRL licences
 * for BrettZone. The files already live in public/fonts/brettzone/ for the
 * /tv skin; they are re-declared here rather than pulled in via
 * brettzone-kit.css because that sheet also PAINTS (.bz-page) and carries a
 * whole component library this theme does not want.
 *
 * A face declared and never used costs one parsed rule and zero bytes — the
 * browser fetches nothing until a `sport` document actually renders in it, so
 * dark and light users pay nothing for these nine.
 *
 * THE WEIGHT RANGES ARE NOT A TYPO. There is no 600 cut of DIN Next, and the
 * kit's --portal-weight-label is 600; upstream hits the same wall and answers
 * it the same way (havoc.css:31 declares Medium as `500 600`, :41 declares
 * Heavy as `800 900`). Without the ranges the browser synthesises a fake
 * 600 — a smeared, slightly-too-heavy DIN that reads as a rendering fault.
 * §2 also moves --portal-weight-label onto the real 700 cut, so the ranges
 * are a backstop for page CSS that asks for 600 by hand.
 * ═══════════════════════════════════════════════════════════════════════ */

@font-face {
    font-family: 'DIN Next LT Pro';
    src: url('/fonts/brettzone/DINNextLTPro-Regular.woff2') format('woff2');
    font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
    font-family: 'DIN Next LT Pro';
    src: url('/fonts/brettzone/DINNextLTPro-Italic.woff2') format('woff2');
    font-weight: 400; font-style: italic; font-display: swap;
}
@font-face {
    font-family: 'DIN Next LT Pro';
    src: url('/fonts/brettzone/DINNextLTPro-Medium.woff2') format('woff2');
    font-weight: 500 600; font-style: normal; font-display: swap;
}
@font-face {
    font-family: 'DIN Next LT Pro';
    src: url('/fonts/brettzone/DINNextLTPro-Bold.woff2') format('woff2');
    font-weight: 700; font-style: normal; font-display: swap;
}
@font-face {
    font-family: 'DIN Next LT Pro';
    src: url('/fonts/brettzone/DINNextLTPro-Heavy.woff2') format('woff2');
    font-weight: 800 900; font-style: normal; font-display: swap;
}
@font-face {
    font-family: 'DIN Next LT Pro';
    src: url('/fonts/brettzone/DINNextLTPro-HeavyItalic.woff2') format('woff2');
    font-weight: 800 900; font-style: italic; font-display: swap;
}
@font-face {
    font-family: 'Berkeley Mono';
    src: url('/fonts/brettzone/BerkeleyMono-Regular.woff2') format('woff2');
    font-weight: 400 500; font-style: normal; font-display: swap;
}
@font-face {
    font-family: 'Berkeley Mono';
    src: url('/fonts/brettzone/BerkeleyMono-Italic.woff2') format('woff2');
    font-weight: 400 500; font-style: italic; font-display: swap;
}
@font-face {
    font-family: 'Berkeley Mono';
    src: url('/fonts/brettzone/BerkeleyMono-Bold.woff2') format('woff2');
    font-weight: 600 900; font-style: normal; font-display: swap;
}


/* ═══ 2. Tokens ══════════════════════════════════════════════════════════
 * The whole palette, mapped onto the kit's own token names so every
 * .portal-page-themed surface — cards, buttons, badges, forms, tables, the
 * lot — repaints with no per-component CSS.
 *
 * The --bz-* half is copied verbatim from bz-tokens.css and is declared HERE
 * rather than read from brettzone-kit.css, which app pages do not link. It
 * exists so the mapping below reads as "the portal's X is BrettZone's Y"
 * instead of as 130 unexplained hex values, and so a future diff against
 * upstream has something to diff against. Custom properties resolve at the
 * consumer, so declaration order inside this block does not matter.
 * ═══════════════════════════════════════════════════════════════════════ */

html[data-portal-theme="sport"] body,
.portal-theme-scope[data-portal-theme="sport"] {

    /* ── BrettZone's own tokens, verbatim from bz-tokens.css ──────────── */

    /* NHRL brand palette (2022 guide) */
    --bz-brand-purple:   #291c5e;
    --bz-brand-offwhite: #f4f4f4;
    --bz-brand-lilac:    #c9ccf0;

    /* Surfaces. Cast toward the brand purple — never neutral grey, and never
       derived from black (§1). */
    --bz-bg:            #0b0a16;
    --bz-surface-1:     #141126;   /* cards, panels         */
    --bz-surface-2:     #1b1734;   /* hover, inset wells    */
    --bz-surface-3:     #241e42;   /* deep wells            */
    --bz-border:        #2d2750;
    --bz-border-strong: #3f3770;
    --bz-overlay:       rgba(10, 8, 20, 0.72);

    /* Text. Cool, slightly violet-cast. PURE WHITE IS BANNED (§9). */
    --bz-text:       #f0eff6;
    --bz-text-dim:   #bcb9cd;
    --bz-text-muted: #7e7a94;
    --bz-text-faint: #57536e;

    /* Accent — brand pink, interactive */
    --bz-accent:        #cf23ca;
    --bz-accent-strong: #ea5ce6;   /* brightened for hover/text on dark */
    --bz-accent-dim:    #6d1a6b;
    --bz-accent-bg:     rgba(207, 35, 202, 0.14);

    /* Secondary accent — brand light blue: focus, links */
    --bz-focus:    #666fe5;
    --bz-focus-bg: rgba(102, 111, 229, 0.14);

    /* Weight class — data-w="3|12|30|fs" is the universal indicator */
    --bz-w3:   #00dad8;
    --bz-w12:  #f2a01c;
    --bz-w30:  #e8433f;
    --bz-w-fs: #9edd2c;

    /* Status. --bz-live is STRICTLY on-air (§1): not "error", not "delayed",
       not a loss. --bz-w30 is the red for everything that is not happening
       right now — which is why the danger badge below takes w30 and not this. */
    --bz-live: #ff2e3d;
    --bz-win:  #10b981;
    --bz-warn: #f2a01c;

    /* Radii. Hard-edged. §9 caps these at 10px and bans pills. */
    --bz-r-xs: 2px;
    --bz-r-sm: 4px;
    --bz-r-md: 6px;

    /* The arena-corner notch (§3) */
    --bz-cut: 12px;

    /* Motion. --portal-ease-out is ALREADY cubic-bezier(.2,.7,.3,1), byte
       identical to --bz-ease, so it is deliberately not redeclared. */
    --bz-d-fast: 120ms;
    --bz-d-base: 220ms;


    /* ── Surfaces ─────────────────────────────────────────────────────────
       Flat and OPAQUE. The portal's dark surfaces are translucent glass over
       an aurora; design.md §9 bans glass outright and §1 bans neutral-grey
       darks. Every value here is the brand purple darkened — never black,
       never grey. */
    --portal-c-surface:               var(--bz-surface-1) !important;
    --portal-c-surface-opaque:        var(--bz-surface-1) !important;
    /* The see-through twin — the launcher cards, the home floor group and the
       docs tiles paint with it. Under a theme with no glass it is simply the
       card surface; leaving it translucent would show the canvas through a
       surface nothing else on the page lets you see through. */
    --portal-c-surface-seethrough:    var(--bz-surface-1) !important;
    --portal-c-surface-sunken:        var(--bz-bg) !important;
    --portal-c-surface-sunken-opaque: var(--bz-bg) !important;
    --portal-c-surface-raised:        var(--bz-surface-2) !important;
    --portal-c-surface-raised-opaque: var(--bz-surface-2) !important;
    /* Hover wash. BrettZone's hover IS surface-2, but this token is an
       overlay tint painted ON a surface, so it has to be the difference
       between the two rungs rather than the rung itself. */
    --portal-c-surface-lift:          rgba(240, 239, 246, 0.045) !important;
    /* NOT transparent, despite R10 wanting transparent headers — this token
       is a false friend. Four of its seven consumers are not headers at all:
       .login-input's field surface, .input-group-text (the addon beside a
       field), .portal-ios-sheet .portal-ios-list (whose own comment says
       "lists inside a sheet go opaque-on-header" precisely so they do not
       read as a smudge) and the table-card footer. Emptying it turns a login
       field into a hole in the card. So the token takes an honest flat rung,
       and the two rules that ARE headers go transparent by name in §4. */
    --portal-c-surface-header:        var(--bz-surface-2) !important;

    /* ═══ WHY THESE ARE `0 0 #0000` AND NOT `none` ═══════════════════════
       Because `none` is only legal as the WHOLE box-shadow value, never as a
       LAYER in a comma-separated list — and the kit composes these constantly:
       `box-shadow: var(--portal-c-edge-card), var(--portal-c-shadow)`, and
       critically `box-shadow: var(--portal-c-input-inset), var(--portal-c-focus-ring)`.
       Substituting the keyword makes the whole declaration invalid at
       computed-value time, so the browser drops it — INCLUDING the layer that
       was carrying meaning.

       This shipped, and it was invisible for exactly the reason it is
       dangerous: where both layers were decoration, "invalid" and "no shadow"
       look identical. Where one layer was not, it took that with it. Measured
       across the kit: 61 composed declarations read edge-card, 39 read
       -shadow, 22 edge-dialog, 18 -shadow-raised, 10 input-inset. The
       casualties were EVERY text input, select and textarea's keyboard focus
       ring, both validation rings, the Chrome autofill mask (the one lever
       that stops Chrome's blue wash on /login), Mission Control's stalled-cage
       rings, live-bracket's game-state rings and vision-system's.

       `0 0 #0000` is a fully transparent zero-offset zero-blur shadow: valid
       alone, valid as a layer, and it paints nothing. Use it for any
       box-shadow token this theme wants to empty. `none` stays correct for
       --portal-c-surface-sheen and the *-grad tokens (background-image) and
       for --portal-blur-* (backdrop-filter), where it is the real keyword and
       nothing composes them. ═══════════════════════════════════════════════ */

    /* ── Edges: the bevel comes off ───────────────────────────────────────
       "No shadows, no hover lift, no outline echoes." The kit builds its
       bevels by composing --portal-c-specular against --portal-c-edge-shade,
       so zeroing the ingredients is not enough on its own — the three
       composed edge tokens are set to `none` as well, which is what actually
       removes the inset highlight from every card, dialog and hero. */
    --portal-c-specular:            transparent !important;
    --portal-c-specular-strong:     transparent !important;
    --portal-c-specular-raised:     transparent !important;
    --portal-c-specular-pressed:    transparent !important;
    --portal-c-specular-pointer:    transparent !important;
    --portal-c-edge-shade:          transparent !important;
    --portal-c-edge-shade-raised:   transparent !important;
    --portal-c-edge-bloom:          transparent !important;
    --portal-c-btn-specular:        transparent !important;
    --portal-c-edge-card:           0 0 #0000 !important;
    --portal-c-edge-card-raised:    0 0 #0000 !important;
    --portal-c-edge-card-pressed:   0 0 #0000 !important;
    --portal-c-edge-chip:           0 0 #0000 !important;
    --portal-c-edge-dialog:         0 0 #0000 !important;
    --portal-c-edge-hero:           0 0 #0000 !important;
    --portal-c-surface-sheen:       none !important;

    /* ── Keylines. The border does the separating, so it is the one piece of
       structure this theme spends on. --border-subtle has no BrettZone rung:
       surface-3 stands in, because it reads as a hairline on surface-1 and
       vanishes on the canvas, which is what "subtle" has to mean here. ── */
    --portal-c-border:                var(--bz-border) !important;
    --portal-c-border-subtle:         var(--bz-surface-3) !important;
    --portal-c-edge-control:          var(--bz-border-strong) !important;
    --portal-c-edge-control-subtle:   var(--bz-border) !important;

    /* ── Text ─────────────────────────────────────────────────────────────
       --text-muted takes bz-text-DIM, not bz-text-muted, and the reason is
       measured rather than aesthetic: #7e7a94 is 4.48:1 on surface-1 and
       4.18:1 on surface-2, so it FAILS AA on the raised rung — and this token
       carries secondary labels, table meta and every "n of m" in the portal.
       BrettZone tunes it for one surface at 60cm; the portal reads it on two.

       bz-text-DIM (#bcb9cd) is the safe end of that and was tried first — it
       measures 9.63:1, and screenshotting /system-management against dark
       showed why that is not a win: every flag's description came forward
       until it competed with the flag's own name. Dark's muted is 6.64:1 on
       its own card and the hierarchy is built on that. So this is
       bz-text-dim and bz-text-muted INTERPOLATED, which lands on 6.76:1 over
       surface-1, 6.31:1 over surface-2 and 7.19:1 over the canvas — the
       portal's own contrast, in BrettZone's hue. Same kind of measured departure the /tv skin makes for
       --bz-focus-bright.

       bz-text-muted still does the genuinely tertiary work below
       (placeholders, kbd, idle status, inactive tabs), all of which sit on
       the darkest ground. */
    --portal-c-text:       var(--bz-text) !important;
    --portal-c-text-muted: #9d9ab1 !important;

    /* ── Shadows. Flat. `none` is a valid box-shadow, so nothing downstream
       needs a rule of its own. Genuine OVERLAYS keep one — a menu floating
       over the page still has to say it is floating, and bz-shadow-2 is the
       value upstream reserves for exactly that. ── */
    --portal-c-shadow:         0 0 #0000 !important;
    --portal-c-shadow-raised:  0 0 #0000 !important;
    --portal-c-shadow-pressed: 0 0 #0000 !important;
    --portal-c-elev-overlay:   0 8px 24px rgba(0, 0, 0, 0.45) !important;
    --portal-c-elev-menu:      0 8px 24px rgba(0, 0, 0, 0.45) !important;
    --portal-c-elev-hero:      0 8px 24px rgba(0, 0, 0, 0.45) !important;

    /* ── Brand + accent ───────────────────────────────────────────────────
       The portal's accent is teal; BrettZone's is brand pink, and in this
       language teal MEANS 3lb. Handing the interactive accent to teal here
       would put the portal quietly at odds with the panel next to it about
       what a colour means, so pink it is — which is also, not coincidentally,
       the NHRL 2022 brand accent the portal already carries as
       --portal-accent.

       --portal-c-accent is read as `color:` far more often than as a fill,
       and raw #cf23ca is 3.9:1 on surface-1 — a hover value, not a body-text
       value. bz-tokens names the answer itself: accent-STRONG, "brightened
       for hover/text on dark". The raw brand pink stays on the fills. */
    --portal-c-brand:          var(--bz-brand-purple) !important;
    --portal-c-brand-offwhite: var(--bz-brand-offwhite) !important;

    /* THE RAW BRAND PAIR, and --portal-accent-teal is the one that matters.
       It is declared on :root in portal-theme.css, so it is NOT part of the
       --portal-c-* set above — and SEVEN page stylesheets derive their own
       accent from it directly: live-bracket (--lb-blue), tournament-buddy
       (--tb-blue), live-stats, sparky-predict, graphics-helper,
       fight-scheduler and tournament-viewer's presentation sheet. Left alone
       they paint teal inside a pink theme.

       That is not just inconsistent, it is WRONG IN THIS LANGUAGE. Teal is
       --bz-w3: on a BrettZone surface it means 3lb, and everything
       weight-coded keys off it. Measured on /live-bracket before this line:
       the 12lb final's blue corner rendered rgb(139,230,233) — a 12lb fight
       with a 3lb-coloured fighter in it, on the one page most likely to be
       open next to Austin's panel.

       Brand light blue instead, which is the same scoped exception the /tv
       skin takes and for the same reason: the two fight corners have to be
       told apart across a hall, and red is spent on live. --portal-accent is
       left alone — the portal's brand pink #cf23ca IS --bz-accent already. */
    --portal-accent-teal: var(--bz-focus) !important;
    --portal-c-accent:         var(--bz-accent-strong) !important;
    --portal-c-accent-muted:   var(--bz-accent-bg) !important;
    --portal-c-accent-border:  rgba(207, 35, 202, 0.45) !important;
    --portal-c-on-accent:      var(--bz-bg) !important;

    /* THE ONE SANCTIONED RING (design.md §4) is light blue, and it is
       deliberately NOT the accent: on a surface where pink is already the
       colour of "this is interactive", a pink focus ring says nothing. Blue
       says "the keyboard is here". Kept as the kit's two-layer ring shape so
       every consumer of --portal-c-focus-ring keeps working. */
    --portal-c-focus-ring: 0 0 0 1px var(--bz-focus),
                           0 0 0 0.25rem rgba(102, 111, 229, 0.22) !important;

    /* ── The two fight corners ────────────────────────────────────────────
       The portal names them pink and blue and resolves blue to teal — which
       in BrettZone's language means 3lb and would collide with the weight
       coding. Brand light blue instead. §1 nominally reserves that blue for
       focus rings; this is the same scoped exception the /tv skin takes, for
       the same reason: the two corners must be told apart, and red is spent
       on live. */
    --portal-c-corner-pink:        var(--bz-accent) !important;
    --portal-c-corner-blue:        var(--bz-focus) !important;
    --portal-c-corner-pink-ink:    var(--bz-accent-strong) !important;
    --portal-c-corner-blue-ink:    #9aa0ef !important;
    --portal-c-corner-pink-soft:   rgba(207, 35, 202, 0.14) !important;
    --portal-c-corner-blue-soft:   rgba(102, 111, 229, 0.14) !important;
    --portal-c-corner-pink-border: rgba(207, 35, 202, 0.45) !important;
    --portal-c-corner-blue-border: rgba(102, 111, 229, 0.45) !important;

    /* ── Tabs. Active is tint + inset wedge, never a raised plate (§9 bans
       glow rings on active elements; the September finish replaces the plate
       with a line). The portal's tabs are HORIZONTAL, so the wedge is an
       underline rather than MI's left bar — same recipe, right axis. ── */
    --portal-c-tab-track:          var(--bz-bg) !important;
    --portal-c-tab-track-inset:    0 0 #0000 !important;
    --portal-c-tab-hover:          rgba(240, 239, 246, 0.05) !important;
    --portal-c-tab-active-bg:      var(--bz-surface-2) !important;
    --portal-c-tab-active-border:  var(--bz-border-strong) !important;
    --portal-c-tab-active-shadow:  inset 0 -2px 0 var(--bz-accent) !important;
    --portal-c-tab-active-color:   var(--bz-text) !important;
    --portal-c-tab-inactive-color: var(--bz-text-muted) !important;

    /* ── Primary button. BrettZone's CTA is the brand pink, flat, with dark
       ink on it — brettzone-kit.css:578-585 — the local port of upstream's
       bz-components.css rule — verbatim, minus the clip, which
       §5 puts back where it is safe. The gradients go to `none`: they are
       consumed as background-image, so the flat colour underneath shows
       through, and a vertical sheen is precisely the ornament this finish
       takes off. ── */
    /* accent-STRONG, not accent, and the label ink below is why. BrettZone's
       own `.bz-btn--primary` is `background: --bz-accent; color: #0b0a16` —
       dark ink on pink — and at #cf23ca that pairing measures 4.44:1, six
       hundredths short of AA for a 13px/700 label. One step up the brand's
       own ramp clears it at 6.72:1 without leaving the palette.

       Hover and active hold the SAME fill on purpose: with dark ink a darker
       press state loses contrast rather than gaining it, and this theme
       already says hover is a keyline brightening rather than a plate change
       (§4). The border tokens carry both states; the kit's press-scale
       carries the press. */
    --portal-c-btn-primary-bg:            var(--bz-accent-strong) !important;
    --portal-c-btn-primary-bg-hover:      var(--bz-accent-strong) !important;
    --portal-c-btn-primary-bg-active:     var(--bz-accent-strong) !important;
    --portal-c-btn-primary-border:        var(--bz-accent) !important;
    --portal-c-btn-primary-border-hover:  var(--bz-text) !important;
    --portal-c-btn-primary-shadow:        0 0 #0000 !important;
    --portal-c-btn-primary-shadow-hover:  0 0 #0000 !important;
    --portal-c-btn-primary-grad:          none !important;
    --portal-c-btn-primary-grad-hover:    none !important;

    /* ── Danger / success / warning. The hues are BrettZone's status set. Note
       danger takes --bz-w30 and NOT --bz-live: §1 makes on-air red mean
       exactly one thing, and a delete button is not on-air. ── */
    --portal-c-btn-danger-bg:            var(--bz-w30) !important;
    --portal-c-btn-danger-bg-hover:      #f05a56 !important;
    --portal-c-btn-danger-border:        var(--bz-w30) !important;
    --portal-c-btn-danger-border-hover:  #f05a56 !important;
    --portal-c-btn-danger-shadow:        0 0 #0000 !important;
    --portal-c-btn-danger-shadow-hover:  0 0 #0000 !important;
    --portal-c-btn-danger-disabled-bg:   rgba(232, 67, 63, 0.35) !important;
    --portal-c-btn-danger-grad:          none !important;
    --portal-c-btn-danger-grad-hover:    none !important;

    --portal-c-btn-success-bg:           var(--bz-win) !important;
    --portal-c-btn-success-bg-hover:     #2fd39b !important;
    --portal-c-btn-success-border:       var(--bz-win) !important;
    --portal-c-btn-success-border-hover: #2fd39b !important;
    --portal-c-btn-success-grad:         none !important;
    --portal-c-btn-success-grad-hover:   none !important;

    --portal-c-btn-warning-bg:           var(--bz-warn) !important;
    --portal-c-btn-warning-bg-hover:     #ffb43c !important;
    --portal-c-btn-warning-border:       var(--bz-warn) !important;
    --portal-c-btn-warning-border-hover: #ffb43c !important;
    --portal-c-btn-warning-grad:         none !important;
    --portal-c-btn-warning-grad-hover:   none !important;

    /* ── Outline / ghost button = bz-btn--ghost: transparent, keylined. ── */
    --portal-c-btn-outline-border:       var(--bz-border-strong) !important;
    --portal-c-btn-outline-bg:           transparent !important;
    --portal-c-btn-outline-color:        var(--bz-text-dim) !important;
    --portal-c-btn-outline-hover-bg:     var(--bz-surface-2) !important;
    --portal-c-btn-outline-hover-color:  var(--bz-text) !important;
    --portal-c-btn-outline-hover-border: var(--bz-text-muted) !important;

    /* ── Badges. The hairline comes off (a bordered pill is "another bordered
       card" at chip scale) and the tint carries the meaning — MI's
       `.status-badge { border: 0 }`. Colours are BrettZone's status set;
       weight-class hues are NOT used here, they belong to data-w. ── */
    --portal-c-badge-inset:         0 0 #0000 !important;
    --portal-c-badge-brand-bg:      var(--bz-brand-purple) !important;
    --portal-c-badge-brand-border:  transparent !important;
    /* LIVE is the one badge that gets the reserved on-air red (§1). */
    /* The live pair is self-tinting — on-air red on a 16% wash of itself — and
       that lands at 4.30:1 on a card, 3.73:1 on a raised surface. The ink is
       §1's reserved on-air red and cannot move, so the GROUND does: a fixed
       dark plum in the same hue family. Being opaque rather than a wash, it
       measures the same 4.78:1 wherever the chip lands, instead of sliding
       with the surface under it. */
    --portal-c-badge-live-bg:       #2d0f1b !important;
    --portal-c-badge-live-color:    var(--bz-live) !important;
    --portal-c-badge-muted-bg:      var(--bz-surface-2) !important;
    --portal-c-badge-muted-color:   var(--bz-text-dim) !important;
    --portal-c-badge-running-bg:    rgba(207, 35, 202, 0.16) !important;
    --portal-c-badge-running-color: var(--bz-accent-strong) !important;
    --portal-c-badge-success-bg:    rgba(16, 185, 129, 0.16) !important;
    --portal-c-badge-success-color: #2fd39b !important;
    --portal-c-badge-warning-bg:    rgba(242, 160, 28, 0.16) !important;
    --portal-c-badge-warning-color: var(--bz-warn) !important;
    --portal-c-badge-danger-bg:     rgba(232, 67, 63, 0.16) !important;
    --portal-c-badge-danger-color:  #ff7a76 !important;
    --portal-c-badge-info-bg:       var(--bz-focus-bg) !important;
    --portal-c-badge-info-color:    #9aa0ef !important;

    /* ── Form controls. bz-input: surface-1 ground, border, 4px — but the
       September finish puts controls at 2px, which §3's geometry does
       globally. The inset well goes with every other bevel. ── */
    --portal-c-input-bg:          var(--bz-bg) !important;
    --portal-c-input-bg-focus:    var(--bz-bg) !important;
    --portal-c-input-inset:       0 0 #0000 !important;
    --portal-c-input-placeholder: var(--bz-text-muted) !important;

    /* Validation. Literal rgba() rather than color-mix, per note 3 above; the
       glyphs are the kit's own SVGs re-inked to the BrettZone status hues. */
    --portal-c-input-border-invalid: rgba(232, 67, 63, 0.55) !important;
    --portal-c-input-ring-invalid:   0 0 0 1px rgba(232, 67, 63, 0.45),
                                     0 0 0 0.25rem rgba(232, 67, 63, 0.14) !important;
    --portal-c-input-glyph-invalid:  url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23ff7a76'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23ff7a76' stroke='none'/%3e%3c/svg%3e") !important;
    --portal-c-input-border-valid:   rgba(16, 185, 129, 0.55) !important;
    --portal-c-input-ring-valid:     0 0 0 1px rgba(16, 185, 129, 0.45),
                                     0 0 0 0.25rem rgba(16, 185, 129, 0.14) !important;
    --portal-c-input-glyph-valid:    url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8' width='8' height='8'%3e%3cpath fill='%232fd39b' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e") !important;

    /* ── Rows, progress, skeletons ──────────────────────────────────────── */
    --portal-c-row-hover:          rgba(240, 239, 246, 0.045) !important;
    --portal-c-row-selected:       rgba(207, 35, 202, 0.14) !important;
    --portal-c-status-idle:        var(--bz-text-muted) !important;
    --portal-c-progress-bg:        var(--bz-surface-2) !important;
    --portal-c-progress-bar-bg:    var(--bz-accent) !important;
    --portal-c-progress-bar-stripe: rgba(10, 8, 20, 0.25) !important;
    --portal-c-skeleton-bg:        var(--bz-surface-2) !important;
    --portal-c-skeleton-sheen:     rgba(240, 239, 246, 0.05) !important;

    /* ── Overlays + chrome. Scrims are purple-cast per §1 — rgba(10,8,20,x),
       never rgba(0,0,0,x). ── */
    --portal-c-overlay:        var(--bz-surface-1) !important;
    --portal-c-overlay-opaque: var(--bz-surface-1) !important;
    --portal-c-scrim:          var(--bz-overlay) !important;
    --portal-c-kbd:            var(--bz-text-muted) !important;
    --portal-c-chrome-hover:   rgba(240, 239, 246, 0.06) !important;
    --portal-c-chrome-surface: var(--bz-bg) !important;

    /* The impersonation strip has to shout across a room and is not part of
       the brand conversation — kept legible, moved onto BrettZone's amber. */
    --portal-c-impersonation-bg:  #b45309 !important;
    /* Brand offwhite, not #fff — design.md §9 lists "Pure white text" as a
       hard don't, and this is the one place the kit reached for it. 8.0:1 on
       the amber, so the strip still shouts. */
    --portal-c-impersonation-ink: var(--bz-brand-offwhite) !important;

    /* ── Glass off, at the token level ────────────────────────────────────
       Not because design.md forbids it — it says nothing about glass, blur or
       translucency anywhere, and claiming otherwise put a checkable falsehood
       in four files. The real reason is narrower and sufficient: BrettZone
       defines no translucent surface, every rung of its ladder is an opaque
       hex, and §9 does ban the two things glass is usually paired with here
       (glow rings on active elements, rgba(0,0,0,…) scrims). So there is no
       glass to degrade — which is what this theme's THEME_FACTS row means by
       degrades:false, rather than that it opts out of the gates. ── */
    --portal-blur-chrome:  none !important;
    --portal-blur-dim:     none !important;
    --portal-blur-overlay: none !important;
    --portal-chrome-opacity: 1 !important;
    /* AND THAT IS THE WHOLE GLASS KILL — no rule below writes
       `backdrop-filter: none` on a chrome strip or a menu, because every
       backdrop-filter in the kit already reads one of these three tokens and
       BlurBudgetTest / KitCssLiteralsTest both refuse an untokenised blur
       ("a blur the degrade gates cannot turn off"). Emptying the token turns
       it off everywhere at once, including surfaces this file has never
       heard of. */

    /* ── Type. Real DIN Next, so the whole ladder is available: 400 body, 500
       the middle rung, 700 labels, 800 Heavy for display. Berkeley Mono
       carries every number (§2) — it is genuinely tabular, which is what the
       kit's clocks and score columns are asking for. Joyride stays the hero
       face and is reserved, per design.md, for one true hero moment. ── */
    --portal-font-body:    'DIN Next LT Pro', 'Inter', 'Inter Fallback', system-ui, -apple-system, sans-serif !important;
    --portal-font-mono:    'Berkeley Mono', ui-monospace, 'SF Mono', Menlo, monospace !important;
    --portal-font-display: 'Joyride STD', 'DIN Next LT Pro', 'Arial Black', sans-serif !important;

    --portal-weight-body:   400 !important;
    --portal-weight-medium: 500 !important;
    --portal-weight-label:  700 !important;   /* DIN Bold — a real cut, not a synthesised 600 */
    --portal-weight-strong: 800 !important;   /* DIN Heavy — the display voice */

    /* DIN's caps want more air than Inter's. design.md §2 puts the range at
       0.06-0.18em; the wall skin sits at the top of it. These are the
       desk-distance end of the same range — enough to read as BrettZone,
       not so much that a dense table stops scanning. */
    --portal-tracking-caps:  0.06em !important;
    --portal-label-tracking: 0.12em !important;

    /* ── Motion. bz-d-fast/base/slow. The longer kit durations are left
       alone: they belong to page transitions, not to this finish. ── */
    --portal-dur-1: var(--bz-d-fast) !important;
    --portal-dur-2: 200ms !important;
    --portal-dur-3: var(--bz-d-base) !important;
}



/* ═══ 2b. Bootstrap's own tokens — and why they need a second selector ═══
 * Everything in §2 is a --portal-* or --bz-* property, and nothing declares
 * those on a bare [data-bs-theme], so `body` is enough: the page inherits
 * them.
 *
 * THE --bs-* HALF CANNOT LIVE THERE. `.portal-page-themed` carries
 * data-bs-theme on <main>, and both Bootstrap's own dark block and
 * portal-theme.css:352 declare --bs-* on a BARE [data-bs-theme="dark"] — so
 * that inner <main> re-declares them on itself and shadows anything set on
 * body for the entire page. portal-theme.css's own comment names this trap
 * ("would otherwise re-declare Bootstrap's value on an INNER element and
 * shadow ours for the whole page"); it is why the border-colour line lives
 * where it does rather than with the other tokens.
 *
 * It is not theoretical here either. With this block on `body` the theme
 * measured a 10px card, a 6px tile and a 4px input while `body` itself
 * reported the 4px/2px sport ladder — every radius in the page came from
 * dark, and nothing looked broken enough to notice.
 *
 * `html[data-portal-theme="sport"] [data-bs-theme]` is (0,2,1) and clears
 * both (0,1,0) declarations. The body selector stays for the chrome, which
 * sits OUTSIDE main and so has no data-bs-theme of its own.
 *
 * THE TWO :not()s KEEP IT OFF ANYTHING THAT IS DELIBERATELY PAINTING IN
 * ANOTHER THEME, and both are load-bearing:
 *
 *   :not([data-portal-theme]) — the Appearance SWATCHES. Each is a
 *   .portal-theme-scope carrying its own data-portal-theme AND its own
 *   data-bs-theme, so without this the descendant selector reaches the dark,
 *   light and matrix squares inside a sport page and hands them sport's
 *   Bootstrap values. Every swatch advertising the theme you are already in
 *   is the exact bug kit 3.8.1 fixed; this is that mistake from the other
 *   direction. (Sport's own swatch is still covered, by the third selector.)
 *
 *   :not(.portal-theme-scope) — the style guide's SIDE-BY-SIDE PANES, which
 *   the first guard does not catch: `.sg-split-pane.portal-theme-scope` has
 *   data-bs-theme but NO data-portal-theme, so it matched. The Light pane
 *   then rendered on sport's near-black ground with light inks still on it —
 *   its form control measured 1.14:1, i.e. invisible — on the one page whose
 *   whole job is showing whether the light theme is still correct.
 *
 * The general rule, worth keeping: a .portal-theme-scope is an element that
 * has been told what to paint. This block must never reach one it does not
 * own.
 * ═══════════════════════════════════════════════════════════════════════ */

html[data-portal-theme="sport"] body,
html[data-portal-theme="sport"] [data-bs-theme]:not([data-portal-theme]):not(.portal-theme-scope),
.portal-theme-scope[data-portal-theme="sport"] {
    /* ── Bootstrap's own semantic colours ─────────────────────────────────
       Not part of the --portal-c-* set, and the kit reads them directly in a
       handful of places — the icon badge's success/warning/danger tints, the
       alert emphases, .text-secondary. Left alone they would hand BrettZone's
       surfaces Bootstrap's stock green, amber and red, which is three colours
       this palette does not contain. The -rgb twins matter too: the kit builds
       tints with rgba(var(--bs-x-rgb), a). */
    --bs-success:      var(--bz-win) !important;
    --bs-success-rgb:  16, 185, 129 !important;
    --bs-warning:      var(--bz-warn) !important;
    --bs-warning-rgb:  242, 160, 28 !important;
    --bs-danger:       var(--bz-w30) !important;
    --bs-danger-rgb:   232, 67, 63 !important;
    --bs-info:         var(--bz-focus) !important;
    --bs-info-rgb:     102, 111, 229 !important;
    --bs-primary:      var(--bz-accent) !important;
    --bs-primary-rgb:  207, 35, 202 !important;
    --bs-success-text-emphasis: #2fd39b !important;
    --bs-warning-text-emphasis: var(--bz-warn) !important;
    --bs-danger-text-emphasis:  #ff7a76 !important;
    --bs-info-text-emphasis:    #9aa0ef !important;
    --bs-secondary-color: var(--bz-text-dim) !important;
    --bs-secondary-bg:    var(--bz-surface-2) !important;
    --bs-border-color:    var(--bz-border) !important;
    --bs-body-color:      var(--bz-text) !important;
    --bs-body-bg:         var(--bz-bg) !important;
    --bs-emphasis-color:  var(--bz-text) !important;
    --bs-link-color:            var(--bz-accent-strong) !important;
    --bs-link-hover-color:      var(--bz-text) !important;
    --bs-link-color-rgb:        234, 92, 230 !important;
    --bs-link-hover-color-rgb:  240, 239, 246 !important;

    /* ── Geometry. §9 caps radii at 10px and bans pills; the September finish
       puts CONTROLS at 2px specifically. Bootstrap's own ladder is what
       almost everything derives from, so it is retuned here once rather than
       overridden per component. ── */
    --bs-border-radius:     var(--bz-r-xs) !important;
    --bs-border-radius-sm:  var(--bz-r-xs) !important;
    --bs-border-radius-lg:  var(--bz-r-sm) !important;
    --bs-border-radius-xl:  var(--bz-r-md) !important;
    --bs-border-radius-xxl: var(--bz-r-md) !important;
}

/* ═══ 3. Canvas ══════════════════════════════════════════════════════════
 * The aurora is the portal's atmosphere and BrettZone has none — havoc.css
 * kills its own with `body::before { content: none }` and the note "the v2
 * brief bans animated gradient washes". Same answer here.
 *
 * The background-color must stay a LITERAL and stay on this selector:
 * tests/Rendering/ThemeColorSingleSourceTest reads it out of this file as the
 * source of truth and asserts _kit-head.twig's pre-paint style, head-meta's
 * theme-color and portal-theme.js's PORTAL_THEME_COLORS all agree with it.
 * Four copies, one source — change it here and change it in all four.
 * ═══════════════════════════════════════════════════════════════════════ */

html[data-portal-theme="sport"] body {
    background-color: #0b0a16 !important;
    background-image: none !important;
    /* The ink is a LITERAL in portal-page-theme.css:45, not a token read, so
       overriding --portal-c-text does not reach it. Measured: with the token
       correctly resolving to #f0eff6 everywhere, `color` on <body> still
       computed rgb(232,231,238) — dark's ink — and inherited to every element
       that does not set its own. A two-point difference nobody would spot by
       eye, and the whole point of BrettZone's ink is that it is violet-cast
       rather than neutral. Anything literal in that file has to be answered
       literally here. */
    color: var(--bz-text) !important;
}

html[data-portal-theme="sport"] body::before,
html[data-portal-theme="sport"] body::after {
    background-image: none !important;
}

html[data-portal-theme="sport"] ::selection {
    background: var(--bz-accent-bg);
    color: var(--bz-text);
}


/* ═══ 4. The sport finish: the ornament comes off ════════════════════════
 * Everything above is palette. This is the FINISH — the half of the
 * September refresh that is not a colour, applied to the kit's own
 * components. Each block names the upstream rule it traces to.
 * ═══════════════════════════════════════════════════════════════════════ */

/* ── Surfaces: flat, and they stop moving ─────────────────────────────────
   bz-sport.css: `.bz-fightcard, .bz-tcard { box-shadow: none }`;
   bz-watch.css: `.bz-hero:hover { transform: none }`; MI:
   `.quick-card:hover { transform: none }`. The card keeps its border and
   stops lifting.

   THE TRANSITION IS NARROWED TOO, not just the hover. The kit's hoverable
   utility names `transform` in its transition list; leaving it there animates
   a value that never changes, which costs a compositor layer per card for
   nothing. ── */
html[data-portal-theme="sport"] .portal-hoverable:hover,
html[data-portal-theme="sport"] .portal-hoverable:focus-within,
html[data-portal-theme="sport"] .portal-page-themed .card:hover,
html[data-portal-theme="sport"] .portal-tile:hover,
html[data-portal-theme="sport"] .portal-tile:has(.stretched-link:hover),
html[data-portal-theme="sport"] .portal-tile:has(.stretched-link:focus-visible) {
    transform: none !important;
}

html[data-portal-theme="sport"] .portal-hoverable,
html[data-portal-theme="sport"] .portal-page-themed .card,
html[data-portal-theme="sport"] .portal-tile {
    transition: border-color var(--bz-d-base) var(--portal-ease-out),
                background-color var(--bz-d-base) var(--portal-ease-out),
                color var(--bz-d-base) var(--portal-ease-out);
}

/* Hover is a keyline brightening, not a plate. MI: the card's only hover is
   `border-color`. */
html[data-portal-theme="sport"] .portal-page-themed .card:hover,
html[data-portal-theme="sport"] .portal-tile:hover {
    border-color: var(--bz-border-strong);
}

/* ── Headers go transparent with a keyline under them ─────────────────────
   "Use flat surfaces and dividers where another bordered card adds no
   meaning." MI takes every header to transparent with a 1px --bz-border
   beneath; bz-sport.css: `.bz-topbar { background: transparent }`. Done per
   rule rather than by emptying --portal-c-surface-header, because that token
   also dresses four things that are not headers — see its note in §2. ── */
html[data-portal-theme="sport"] .portal-page-themed .card-header {
    background-color: transparent;
    border-bottom: 1px solid var(--bz-border);
}

/* The modal header, same treatment. !important rather than a longer selector:
   the kit's rule is `body:has(.portal-page-themed) .modal .modal-content:not(
   .portal-search-content) .modal-header` at (0,5,1), and out-specifying that
   by hand produces a selector nobody can read or safely edit later. */
html[data-portal-theme="sport"] .modal .modal-header {
    background-color: transparent !important;
    border-bottom: 1px solid var(--bz-border) !important;
}

/* THE ONE HEADER THAT CANNOT GO TRANSPARENT is a sticky table head — rows
   would scroll through it. It takes the page canvas instead of the surface it
   sits on: flat, and still opaque. Same answer for a sticky group row. */
html[data-portal-theme="sport"] .portal-page-themed .table > thead th,
html[data-portal-theme="sport"] .portal-page-themed .table-responsive thead th,
html[data-portal-theme="sport"] .portal-page-themed .portal-table-sticky thead th {
    background-color: var(--bz-bg);
    border-bottom-color: var(--bz-border);
    color: var(--bz-text-dim);
}

/* ── Dividers are plain lines ─────────────────────────────────────────────
   The kit's divider fades out at both ends; every divider in both sport
   sheets is a flat rule. ── */
html[data-portal-theme="sport"] .portal-page-themed hr,
html[data-portal-theme="sport"] .dropdown-divider {
    background-image: none !important;
    background-color: var(--bz-border) !important;
    border: 0;
    opacity: 1;
}

/* ── Active is a wedge, not a plate ───────────────────────────────────────
   MI's board filters: `.is-active { background: surface-2; border-color:
   border-strong; box-shadow: inset 3px 0 accent }`. §2 wired the horizontal
   tabs (whose wedge lands on the sliding thumb, .portal-tabs[data-thumb]
   .has-thumb::before, since that is what actually paints once the thumb is
   real); this is the same recipe for the vertical lists — a nav pill, a
   sidebar link, a settings row — where the wedge goes on the LEFT edge,
   which is the axis those have.

   .nav-pills is deliberately NOT in this list even though .portal-tabs
   carries it: those tabs are HORIZONTAL, a left wedge on them points at
   nothing, and they are already handled — by --portal-c-tab-active-shadow
   above, which the thumb reads (measured: inset 0 -2px, at the bottom edge
   where it belongs). Adding .nav-pills here would put a left bar on every
   horizontal tab set that happens to render without the thumb. ── */
html[data-portal-theme="sport"] .portal-page-themed .list-group-item.active {
    background-color: var(--bz-surface-2);
    border-color: var(--bz-border-strong);
    box-shadow: inset 3px 0 0 var(--bz-accent);
    color: var(--bz-text);
}

/* ── Chips and badges lose the pill ───────────────────────────────────────
   design.md §9 bans pills outright, and the September finish puts labels at
   2px like every other control.

   DONE PER COMPONENT, NOT BY REMAPPING --bs-border-radius-pill, which is the
   obvious move and the wrong one: the same token rounds the .portal-switch
   track, the .form-range track and the notification count dot, and
   portal-theme.css:168 says so in as many words — "genuinely round things
   stay round". A square toggle is not a BrettZone toggle, it is a broken one.
   §9 is about LABELS shaped like lozenges, which is these two. ── */
html[data-portal-theme="sport"] .portal-chip,
html[data-portal-theme="sport"] .portal-ios-status,
html[data-portal-theme="sport"] .portal-page-themed .badge {
    border-radius: var(--bz-r-xs);
    border-color: transparent;
}

/* ── Empty states stay rounder than loaded ones ───────────────────────────
   design.md §3, and it survives the refresh untouched: "empty states keep
   dashed borders and rounded corners on purpose (empty ≠ loaded)". The
   portal's dashed surface is .portal-dropzone (the kit's .portal-empty-state
   is a bare centred text block with no box at all, so there is nothing there
   to keep). It already has the dashes; what it needs is to stay visibly
   rounder than the 2px everything else just moved to, or the distinction
   design.md is protecting quietly disappears. ── */
html[data-portal-theme="sport"] .portal-page-themed .portal-dropzone {
    border-radius: var(--bz-r-md);
    border-color: var(--bz-border-strong);
}


/* ═══ 5. Type and the one corner cut ═════════════════════════════════════ */

/* ── The title voice ──────────────────────────────────────────────────────
   "DIN Heavy Italic carries titles and matchups." MI's refreshed page header
   is `italic 800 … letter-spacing: -.025em`, and bz-sport.css sets its one
   full-bleed title the same way.

   ONLY THE PAGE TITLE LEANS. brettzone-sport.css:73-75 states the reason and
   it is the whole difference between a voice and a texture: "l/m/s stay
   upright, because a lean on every heading is a texture, not a voice." So the
   lean is spent once per page and nowhere else.

   AND NOTHING BELOW h1 GETS A WEIGHT HERE. An earlier draft put
   `font-weight: 800` on :is(h2…h6) + .card-title, reasoning that DIN Heavy is
   the display voice. It was actively wrong. The kit's own headings already
   read --portal-weight-label and --portal-weight-strong, which §2 moved to
   700 and 800 — real DIN cuts, each a step heavier than dark's 600/700 — and
   the empty state's MESSAGE is an <h5> the kit deliberately sets a step
   LIGHTER than its own title. Measured on /judging with the blanket rule in
   place: title 18px/800 and message 20px/800, the message shouting louder
   than the heading above it, with every rung of the ladder collapsed onto one
   weight. Without it the ladder is 800 / 700 / 500 — dark's own structure in
   BrettZone's cuts. The tokens already do this job; a second opinion layered
   on top of them can only flatten it. ── */
html[data-portal-theme="sport"] .portal-page-title,
html[data-portal-theme="sport"] .portal-page-themed h1 {
    font-weight: 800;
    font-style: italic;
    letter-spacing: -0.025em;
    text-transform: uppercase;
}

/* ── Solid fills take a dark label ────────────────────────────────────────
   `.bz-btn--primary { background: var(--bz-accent); color: #0b0a16 }` — dark
   ink on the bright fill is BrettZone's own recipe, and here it is also the
   only thing that makes these buttons legible. The kit hardcodes
   `color: #fff` (portal-components.css:1104 and the three siblings), which is
   right for dark's muted fills and wrong for this palette's bright ones.

   Measured, white 13px/700 on sport's fills: primary 4.42:1, danger 3.96:1,
   success 2.54:1, warning 2.14:1. Primary and danger are REGRESSIONS this
   theme caused (dark: 10.04 and 5.46); success and warning were already
   failing in dark (3.45 and 2.93) and this simply stops making them worse.
   With the near-black ink: primary 6.72:1, danger 4.96:1, success 7.74:1,
   warning 9.18:1 — all four clear AA, and every hover state is brighter
   still, so it can only improve from there. ── */
html[data-portal-theme="sport"] .portal-page-themed :is(.btn-primary, .btn-danger, .btn-success, .btn-warning),
html[data-portal-theme="sport"] .portal-page-themed :is(.btn-primary, .btn-danger, .btn-success, .btn-warning):hover,
html[data-portal-theme="sport"] .portal-page-themed :is(.btn-primary, .btn-danger, .btn-success, .btn-warning):focus,
html[data-portal-theme="sport"] .portal-page-themed :is(.btn-primary, .btn-danger, .btn-success, .btn-warning):active {
    color: var(--bz-bg);
}

/* The same pairing wherever the danger fill carries a numeral rather than a
   label: the system bar's unread count and the bell's badge both hardcode
   #fff (notifications-bell.css:71), which on --bz-w30 is a 10px/800 digit at
   3.96:1 — and that badge is on every page in the portal. */
html[data-portal-theme="sport"] :is(.portal-bar-dock-count, .portal-notif-badge, .portal-notif-count-badge),
html[data-portal-theme="sport"] .portal-page-themed .badge.text-bg-danger {
    color: var(--bz-bg) !important;
}

/* Buttons wear DIN's caps. brettzone-kit.css:557-560, the local port of
   upstream's bz-components.css rule:
   `font: 600 12px/1 var(--bz-font-ui); letter-spacing: .06em;
   text-transform: uppercase`. 700 rather than 600 because that is the cut
   that exists — see §1. */
html[data-portal-theme="sport"] .portal-page-themed .btn {
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-weight: 700;
}

/* ── The corner cut, on the one element it is safe on ─────────────────────
   design.md keeps "cut-corner primary actions" by name, and bz-sport.css
   keeps the notch on .bz-btn--primary while stripping its shadow. A button is
   a leaf: nothing positions out of it, so the clip has nothing to amputate.

   THE FOCUS RING HAS TO BECOME INSET. clip-path clips a box's own outer
   box-shadow, so a cut button with the kit's two-layer outer ring would show
   a keyboard user nothing at all. This is the same trap the /tv skin hit and
   recorded; the fix is the same.

   Cards, tiles and dialogs deliberately do NOT get this — see note 4 in the
   file header. ── */
html[data-portal-theme="sport"] .portal-page-themed .btn-primary {
    border-radius: 0;
    clip-path: polygon(0 0, calc(100% - 8px) 0, 100% 8px, 100% 100%, 0 100%);
}

/* THE RING IS DARK-THEN-BLUE, not blue alone. --bz-focus on this button's own
   fill measures 1.45:1 — it renders, and you cannot see it, which is the worst
   of both. The canvas colour is the only ink in this palette that clears 3:1
   against a bright pink (6.7:1), so it goes outermost as a separator and the
   blue sits inside it at 4.7:1 against that. Both layers are perceivable, and
   the ring still reads as the portal's blue focus ring rather than as a
   second border. */
html[data-portal-theme="sport"] .portal-page-themed .btn-primary:focus-visible {
    box-shadow: inset 0 0 0 2px var(--bz-bg),
                inset 0 0 0 4px var(--bz-focus);
    outline: none;
}

/* Every number, per §2. Berkeley Mono is genuinely tabular — the portal's
   clocks, counts and score columns already ask for tabular-nums, and this is
   what finally gives them a face that has them. */
html[data-portal-theme="sport"] .portal-page-themed :is(.portal-stat-value, .portal-mono, .portal-label, code, kbd, samp) {
    font-family: var(--portal-font-mono);
}


/* ═══ 6. Chrome ══════════════════════════════════════════════════════════
 * TOKENS ALONE DO NOT REPAINT THE CHROME. The system bar, the sidebar and the
 * tab bar paint from --portal-chrome-* primitives declared on :root in
 * portal-theme.css, not from the --portal-c-* set — a :root declaration is
 * outside `body`, so §2 never reaches them. matrix spends about half its
 * sheet here for the same reason.
 * ═══════════════════════════════════════════════════════════════════════ */

html[data-portal-theme="sport"] #site-sidebar,
html[data-portal-theme="sport"] #site-footer,
html[data-portal-theme="sport"] #portal-tab-bar {
    background-color: var(--bz-bg) !important;
    background-image: none !important;
    box-shadow: none !important;
    color: var(--bz-text) !important;
    /* ALL FOUR SIDES. portal-theme.css:576/:615 puts a 1px
       rgba(0,0,0,0.66) border on every side of these slabs, and since v3
       floated the chrome they are inset 8px from the viewport — so all four
       edges are visible against the canvas, not just the one facing the page.
       Overriding only border-top left three sides painting dark's black
       hairline around a BrettZone bar. Measured on /home: top rgb(45,39,80),
       the other three rgba(0,0,0,0.66). matrix sets all four; so does this. */
    border-color: var(--bz-border) !important;
}

html[data-portal-theme="sport"] #site-footer {
    border-top: 1px solid var(--bz-border) !important;
}

html[data-portal-theme="sport"] #site-sidebar {
    border-right: 1px solid var(--bz-border) !important;
}

html[data-portal-theme="sport"] #portal-tab-bar {
    border-top: 1px solid var(--bz-border) !important;
}

/* The chrome's own controls. .portal-tab-link matches both buttons and
   anchors on purpose — an anchor-only selector was a real bug in the matrix
   sheet and the tab bar renders both. */
html[data-portal-theme="sport"] #site-footer .portal-bar-breadcrumb,
html[data-portal-theme="sport"] #site-footer .portal-launcher-btn,
html[data-portal-theme="sport"] #site-footer .portal-bar-user-btn,
html[data-portal-theme="sport"] #site-sidebar .portal-sidebar-link {
    color: var(--bz-text-dim) !important;
}

/* THE PHONE TAB BAR STATES ARE WRITTEN OUT, and the reason is a bug this
   file shipped for about an hour: the blanket colour rule above originally
   included .portal-tab-link, and being !important it flattened the ACTIVE
   link into the same ink as its four neighbours. Measured on /home at 390px:
   every link rgb(188,185,205), where dark has teal against dimmed white.
   Not that where-am-I vanished entirely — portal-theme.css:747-750 also gives
   the current tab --portal-weight-strong, and its own comment at :732 says
   "Colour AND weight carry it, never colour alone." One of the two survived.
   But a weight step on a 10px label is much the weaker half, and it is the
   half that goes first on a phone in daylight, so the theme has no business
   spending the other one.

   Inactive is pushed back to muted rather than dim so the accent has room to
   read as the answer to "which page am I on" across a pit at arm's length. */
html[data-portal-theme="sport"] #portal-tab-bar .portal-tab-link {
    color: var(--bz-text-muted) !important;
}

html[data-portal-theme="sport"] #portal-tab-bar .portal-tab-link.is-active,
html[data-portal-theme="sport"] #portal-tab-bar .portal-tab-link[aria-current] {
    color: var(--bz-accent-strong) !important;
}

html[data-portal-theme="sport"] #site-sidebar .portal-sidebar-link i {
    color: var(--bz-text-muted) !important;
}

/* …but NOT the current page's icon. Dark paints that one in the accent and
   it is half of where-am-I; an !important on the blanket rule above swallows
   it and leaves the wedge doing the job alone. Found by diffing every chrome
   state against dark rather than by looking — the two greys are three points
   apart and read as identical. Same bug the phone tab bar had. */
html[data-portal-theme="sport"] #site-sidebar .portal-sidebar-link.active i,
html[data-portal-theme="sport"] #site-sidebar .portal-sidebar-link[aria-current] i {
    color: var(--bz-accent-strong) !important;
}

html[data-portal-theme="sport"] #site-sidebar .portal-sidebar-link:hover,
html[data-portal-theme="sport"] #portal-tab-bar .portal-tab-link:hover {
    background-color: var(--bz-surface-2) !important;
    color: var(--bz-text) !important;
}

/* The sidebar's current page: the September wedge again, on the axis a
   vertical list actually has. */
html[data-portal-theme="sport"] #site-sidebar .portal-sidebar-link.active,
html[data-portal-theme="sport"] #site-sidebar .portal-sidebar-link[aria-current] {
    background-color: var(--bz-surface-2) !important;
    box-shadow: inset 3px 0 0 var(--bz-accent) !important;
    color: var(--bz-text) !important;
}

html[data-portal-theme="sport"] .portal-notif-btn,
html[data-portal-theme="sport"] .portal-launcher-btn,
html[data-portal-theme="sport"] .portal-bar-user-btn {
    background-color: transparent !important;
    border-color: var(--bz-border) !important;
    box-shadow: none !important;
}

html[data-portal-theme="sport"] .portal-notif-btn:hover,
html[data-portal-theme="sport"] .portal-launcher-btn:hover,
html[data-portal-theme="sport"] .portal-bar-user-btn:hover {
    background-color: var(--bz-surface-2) !important;
}

/* The badge keeps its data-tint variants — they are how the launcher tells one
   tool from the next, and the accent/brand/success/warning/danger inks are
   already BrettZone's by §2 and the --bs-* remap there. Only the glow behind
   it goes, which is the one thing this finish objects to. */
html[data-portal-theme="sport"] .portal-icon-badge {
    box-shadow: none !important;
}

/* Menus. A dropdown is a genuine overlay, so it is the one place this theme
   still spends a shadow (§2's --portal-c-elev-menu) — but it is opaque, flat
   and keylined like everything else. */
html[data-portal-theme="sport"] .dropdown-menu {
    background-color: var(--bz-surface-1) !important;
    background-image: none !important;
    border: 1px solid var(--bz-border) !important;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45) !important;
}

html[data-portal-theme="sport"] .dropdown-menu .dropdown-header {
    color: var(--bz-text-muted) !important;
    letter-spacing: 0.12em;
    text-transform: uppercase;
}

html[data-portal-theme="sport"] .dropdown-menu .dropdown-item {
    color: var(--bz-text-dim) !important;
}

html[data-portal-theme="sport"] .dropdown-menu .dropdown-item:hover,
html[data-portal-theme="sport"] .dropdown-menu .dropdown-item:focus {
    background-color: var(--bz-surface-2) !important;
    color: var(--bz-text) !important;
}

html[data-portal-theme="sport"] .dropdown-menu .dropdown-item.active {
    background-color: var(--bz-surface-2) !important;
    box-shadow: inset 3px 0 0 var(--bz-accent) !important;
    color: var(--bz-text) !important;
}

/* Scrollbars — havoc.css:982-985, verbatim intent: square thumb, canvas
   track, no radius. WebKit only; Firefox reads scrollbar-color. */
html[data-portal-theme="sport"] ::-webkit-scrollbar-track {
    background: var(--bz-bg);
}

html[data-portal-theme="sport"] ::-webkit-scrollbar-thumb {
    background: var(--bz-surface-3);
    border-radius: 0;
}

html[data-portal-theme="sport"] ::-webkit-scrollbar-thumb:hover {
    background: var(--bz-border-strong);
}


/* ═══ 7. Sliders ═════════════════════════════════════════════════════════
 * Bootstrap's stock range thumb and track are near-invisible on this canvas.
 *
 * EACH ENGINE GETS ITS OWN RULE, never a shared selector list: a browser
 * drops the WHOLE list when it does not recognise the other engine's
 * pseudo-element, so one combined rule styles neither. (This is the shape
 * matrix uses, and the reason is worth keeping written down.)
 * ═══════════════════════════════════════════════════════════════════════ */

html[data-portal-theme="sport"] .form-range::-webkit-slider-thumb {
    background: var(--bz-accent);
    box-shadow: none;
}

html[data-portal-theme="sport"] .form-range::-webkit-slider-runnable-track {
    background: var(--bz-surface-2);
}

html[data-portal-theme="sport"] .form-range::-moz-range-thumb {
    background: var(--bz-accent);
    box-shadow: none;
}

html[data-portal-theme="sport"] .form-range::-moz-range-track {
    background: var(--bz-surface-2);
}

html[data-portal-theme="sport"] .form-range:focus::-webkit-slider-thumb {
    box-shadow: var(--portal-c-focus-ring);
}

html[data-portal-theme="sport"] .form-range:focus::-moz-range-thumb {
    box-shadow: var(--portal-c-focus-ring);
}
