/* BallKnowMe NCAAF — sportsbook cockpit theme.
   Ported from mlb-dashboard's production bkm.css (the LIVE mlb.ballknowme.com
   look): Saira grotesque sans, near-black radial ground, amber accent, flat
   gradient panels, transparent dense tables with tabular numerals. Replaces the
   old editorial-terminal serif/glass layer that was cloned by mistake. */

@import url('https://fonts.googleapis.com/css2?family=Saira:wght@400;500;600;700;800&display=swap');

:root {
    /* surfaces (near-black → panel steps; depth from fill, not shadow) */
    --bg:        #090b0f;
    --bg2:       #0c0f14;
    --panel:     #12151c;
    --panel2:    #171b23;
    --panel3:    #1e2430;
    /* hairlines */
    --line:      #242a35;
    --line-soft: #1a1f28;
    /* ink */
    --text:      #f3f5f9;
    --text2:     #c3cdd9;   /* 2026-08-29 two-ink lift: labels/context must READ */
    --text3:     #8d9cb0;   /* was #626c7d — the fog tier; nothing on the page may be dimmer than this */
    /* semantic — color only ever encodes meaning */
    --pos:       #2fd27a;
    --pos-soft:  rgba(47, 210, 122, 0.14);
    --neg:       #ff5b62;
    --neg-soft:  rgba(255, 91, 98, 0.14);
    /* LIVE — a game in progress. Its own hue on purpose: green/red are OUTCOMES
       (ui_audit.sh polices that) and gold is ACTIONABLE, and a game being played
       is neither. Cyan is unused elsewhere in this palette, so it reads as
       "happening now" without colliding with a meaning already in service. */
    --live:      #35c8e8;
    --live-soft: rgba(53, 200, 232, 0.14);
    --acc:       #ffb020;              /* brand + confidence gold */
    --acc-dim:   rgba(255, 176, 32, 0.14);
    --acc-line:  rgba(255, 176, 32, 0.50);
    /* type — one grotesque family, hierarchy from weight/size/mute */
    --font:      "Saira", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

* { box-sizing: border-box; }

html { background-color: var(--bg); }
html::before {
    content: ''; position: fixed; inset: 0; z-index: -2;
    background: radial-gradient(1200px 600px at 70% -10%, #10151d 0%, var(--bg) 55%);
}

body {
    margin: 0; background: transparent; color: var(--text);
    font-family: var(--font); font-size: 0.9rem; line-height: 1.5; letter-spacing: 0.005em;
    min-height: 100vh; display: flex; flex-direction: column;
}
/*  1240px was set when the board was rail + panels. It now carries rail +
    panels + slip, and on a 1700px screen that left ~500px of dead margin on
    each side while the panels squeezed. Wider cap, and the board's own columns
    grow with it. Content still centres and still reflows below 1240. */
main { flex: 1; width: min(1680px, 100% - 2rem); margin: 0 auto; padding: 18px 0 64px; }
.tnum, table, .hero-stat .num { font-variant-numeric: tabular-nums; }

/* ── masthead / nav ─────────────────────────────────────────────────────── */
.site-header {
    display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
    padding: 12px 22px;
    background: linear-gradient(180deg, rgba(18, 21, 28, 0.95), rgba(9, 11, 15, 0.9));
    border-bottom: 1px solid var(--line);
}
.site-header h1 {
    font-family: var(--font); font-weight: 800; font-size: 17px;
    letter-spacing: 0.06em; text-transform: uppercase; color: var(--text); margin: 0;
}
.site-header h1 .bk-b2 { color: var(--acc); }
.site-tagline {
    font-family: var(--font); font-size: 11px; font-weight: 600; color: var(--text3);
    text-transform: none; letter-spacing: 0.02em; margin-left: 8px;
}
.site-header nav { display: flex; gap: 15px; align-items: center; margin-left: 6px; }
.site-header nav a {
    color: var(--text2); text-decoration: none; font-size: 13px; font-weight: 600;
    letter-spacing: 0.02em; padding: 5px 2px; background: none; border-radius: 0;
    transition: color 0.12s;
}
.site-header nav a:hover { color: var(--text); }
.site-header nav a.active { color: var(--acc); background: none; }

/* ── sections / cards ───────────────────────────────────────────────────── */
section, .dashboard-section {
    background: linear-gradient(180deg, var(--panel), var(--bg2));
    border: 1px solid var(--line); border-radius: 14px;
    box-shadow: 0 20px 50px -30px rgba(0, 0, 0, 0.8);
    padding: 16px 18px; margin: 18px 0;
}
.dashboard-section > h2:first-child, section > h2:first-child {
    font-family: var(--font); font-weight: 800; font-size: 18px; letter-spacing: -0.01em;
    color: var(--text); margin: 0 0 10px; text-transform: none;
}
.card, .metric-card {
    background: var(--panel2); border: 1px solid var(--line);
    border-radius: 11px; padding: 13px 14px;
}
.card:hover { border-color: var(--acc-line); }

.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 1.1rem; }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.9rem; }
.grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.9rem; }
@media (max-width: 860px) { .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr 1fr; } }
@media (max-width: 560px) { .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; } }

/* ── hero stats ─────────────────────────────────────────────────────────── */
.hero-stat { text-align: center; }
.hero-stat .num {
    font-family: var(--font); font-size: 2.1rem; font-weight: 800; line-height: 1.1;
    color: var(--text);
}
.hero-stat .num.gold { color: var(--text); }
.hero-stat .label {
    font-size: 0.62rem; text-transform: uppercase; letter-spacing: 0.12em; color: var(--text3);
    font-weight: 700; margin-top: 2px;
}

/* ── tables ─────────────────────────────────────────────────────────────── */
.table-wrap { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; background: transparent; font-family: var(--font); }
thead th {
    background: transparent; color: var(--text3);
    font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em;
    text-align: left; padding: 8px 9px; border-bottom: 1px solid var(--line);
    white-space: nowrap;
}
tbody td {
    font-family: var(--font); font-variant-numeric: tabular-nums; font-size: 12.5px;
    color: var(--text); padding: 7px 9px; border-bottom: 1px solid var(--line-soft);
    white-space: nowrap;
}
tbody td:first-child { color: var(--text); font-weight: 600; }
tbody tr:hover td { background: rgba(255, 255, 255, 0.03); }
td a, .team-link { color: var(--text); text-decoration: none; font-weight: 600; }
td a:hover, .team-link:hover { color: var(--acc); }

/* ── chips / badges / pills ─────────────────────────────────────────────── */
.chip {
    display: inline-block; padding: 0.1rem 0.45rem; border: 1px solid var(--line);
    border-radius: 6px; font-family: var(--font); font-size: 0.68rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.06em; color: var(--text2);
    font-variant-numeric: tabular-nums;
}
.chip.fbs { color: var(--acc); border-color: var(--acc-line); }
.chip.fcs { color: var(--text2); }
.chip.pos, .positive-diff { color: var(--pos); }
.chip.neg, .negative-diff { color: var(--neg); }
.badge-gold {
    display: inline-block; background: var(--acc); color: #14100a;
    font-size: 0.7rem; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase;
    padding: 0.14rem 0.5rem; border-radius: 6px;
}
/* The honesty note above the board. Muted, but not hidden in the fine print —
   it carries the backtest verdict, so it reads at body size. */
.disclosure {
    color: var(--text2); border-left: 2px solid var(--line);
    padding: 0.1rem 0 0.1rem 0.75rem; margin-top: 0.6rem;
}
.disclosure strong { color: var(--text); }

/* The book's de-vigged number sits quieter than ours — it's the reference, not
   the claim — but same size, because hiding the comparison is the whole sin. */
.book-p { color: var(--text2); }

/* A model LEAN is not a result — so it is deliberately NEUTRAL, never green.
   Green (--pos) means a pick WON; nothing on this board has an outcome yet, and
   the model has no proven edge (see ncaaf-ml/reports/MARKET_BACKTEST_2026-07-15.md).
   Painting leans green asserted a win we hadn't earned. Do not re-add a green
   lean chip; when grading exists, .result-win / .result-loss carry the colour. */
.lean-badge {
    display: inline-block; background: var(--panel3); border: 1px solid var(--line);
    color: var(--text); font-family: var(--font); font-weight: 700; font-size: 0.72rem;
    padding: 0.12rem 0.5rem; border-radius: 6px; font-variant-numeric: tabular-nums;
}
.result-win { background: var(--pos-soft); color: var(--pos); }
.result-loss { background: var(--neg-soft); color: var(--neg); }

/* Schedule: small conference tag + marquee (power-conference) marker. The amber
   dot is wayfinding — "this is a top-tier game" — which is the one job amber is
   allowed to do (top tier / where you are), never a data value. */
.conf-tag { font-size: 10px; font-weight: 700; letter-spacing: 0.05em; color: var(--text3); }
.marquee-dot { color: var(--text2); font-size: 10px; vertical-align: 1px; }

/* ── Matchup tab: feed cards + deep-dive ─────────────────────────────────── */
.mu-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 10px; margin-top: 8px; }
.mu-card { display: block; background: var(--panel2); border: 1px solid var(--line); border-radius: 11px; padding: 12px 13px; text-decoration: none; transition: border-color 0.12s; }
.mu-card:hover { border-color: var(--acc-line); }
.mu-card-head { display: flex; align-items: center; gap: 6px; margin-bottom: 5px; }
.mu-date { font-size: 11px; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; color: var(--text3); }
.mu-teams { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px; color: var(--text); font-weight: 700; font-size: 13.5px; line-height: 1.35; }
.mu-at { color: var(--text3); font-weight: 600; }
.mu-proj { margin-top: 8px; font-size: 12.5px; font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.mu-proj-sep { color: var(--text3); }
.mu-score { margin-top: 3px; font-size: 11px; color: var(--text2); font-variant-numeric: tabular-nums; }
.mu-teamsmall { color: var(--text3); }
.mu-venue { margin-top: 7px; font-size: 11.5px; color: var(--text3); }
.mu-noproj { color: var(--text3); font-weight: 600; }

.mu-back { display: inline-block; font-size: 11px; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; color: var(--text2); text-decoration: none; margin-bottom: 6px; }
.mu-back:hover { color: var(--acc); }
.mu-detail-sub { color: var(--text3); font-size: 12px; margin-top: 2px; }
.mu-headline { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin-top: 12px; }
@media (max-width: 640px) { .mu-headline { grid-template-columns: repeat(2, 1fr); } }
.mu-hl-item { background: var(--panel2); border: 1px solid var(--line); border-radius: 11px; padding: 12px; text-align: center; }
.mu-hl-num { font-size: 1.7rem; font-weight: 800; color: var(--text); font-variant-numeric: tabular-nums; line-height: 1.05; }
.mu-hl-label { font-size: 0.6rem; text-transform: uppercase; letter-spacing: 0.1em; color: var(--text3); font-weight: 700; margin-top: 4px; }
.mu-edges { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 12px; }
@media (max-width: 560px) { .mu-edges { grid-template-columns: 1fr; } }
.mu-edge { background: var(--panel2); border: 1px solid var(--line); border-radius: 11px; padding: 10px 12px; }
.mu-edge-label { font-size: 11px; color: var(--text2); font-weight: 600; }
.mu-edge-val { font-size: 1.2rem; font-weight: 800; color: var(--text); font-variant-numeric: tabular-nums; margin-top: 3px; }

/* ── Betting board (/board) — MLB /matchups/preview layout, CFB data ──────── */
/* The comp's split, at the comp's numbers: 352px rail | canvas, 24px gutter,
   capped at 1440px and centred. Two columns — the ticket floats, it does not
   own a track (see the dock rules by the slip section). */
/*  ONE COLUMN since 2026-09-05. The 352px track held the ledger rail, and the
    rail was replaced by board/_sheet.html — a full-width table that carries the
    same slate grouped by game state. No view renders an aside any more, so a
    second track would only ever be empty space. The rail's own rules below are
    left in place rather than swept: .lg-res still styles the result chip in the
    All-games table and on the home slate, and pulling the block apart mid-change
    is how a shared stylesheet loses something quietly.  */
.bk-board { display: grid; grid-template-columns: minmax(0, 1fr); gap: 24px; align-items: start;
            max-width: 1680px; margin: 0 auto; }
@media (max-width: 1200px) { .bk-board { gap: 16px; } }

/* Full-height rail that scrolls INTERNALLY: head and foot pinned, the rows
   scroll between them (.lg-scroll). The whole rail scrolling with the page was
   part of why the board still read as the old skeleton. */
.bk-rail { position: sticky; top: 12px; display: flex; flex-direction: column; gap: 4px; max-height: calc(100vh - 40px); overflow: hidden; }
.lg-scroll { overflow-y: auto; min-height: 0; }
.bk-weeks { max-width: 1440px; margin: 0 auto 10px; }
.rail-h { font-size: 10px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text3); padding: 2px 2px 4px; }
.slate-card { display: block; background: var(--panel2); border: 1px solid var(--line); border-radius: 8px; padding: 6px 9px; text-decoration: none; transition: border-color 0.12s; }
.slate-card:hover { border-color: var(--acc-line); }
.sc-row { display: flex; align-items: baseline; gap: 6px; color: var(--text); font-weight: 700; font-size: 12.5px; }
.sc-at { color: var(--text3); font-weight: 600; font-size: 11px; }
.sc-line { font-size: 11.5px; color: var(--text2); font-variant-numeric: tabular-nums; margin-top: 2px; }

.pickstrip-h { display: flex; justify-content: space-between; align-items: baseline; font-size: 13px; font-weight: 800; color: var(--text); letter-spacing: 0.02em; }
.pickstrip-rec { font-size: 11.5px; font-weight: 700; color: var(--text2); font-variant-numeric: tabular-nums; }
.pickrow { display: flex; flex-wrap: wrap; gap: 8px; }
.pick-card { flex: 1 1 150px; min-width: 150px; background: var(--panel2); border: 1px solid var(--line); border-radius: 10px; padding: 9px 11px; text-decoration: none; transition: border-color 0.12s; }
.pick-card:hover { border-color: var(--acc-line); }
.pc-fav { font-size: 13px; font-weight: 800; color: var(--text); line-height: 1.2; }
.pc-line { font-size: 12px; font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; margin-top: 3px; }
.pc-opp { font-size: 10.5px; color: var(--text3); margin-top: 2px; }
/* the best available quote for the card's own side — market fact, not a pick */
.pc-odds { font-size: 10.5px; color: var(--text2); margin-top: 6px; padding-top: 5px;
           border-top: 1px solid var(--line-soft); font-variant-numeric: tabular-nums; }
.pc-odds b { color: var(--text); font-weight: 700; }
.pc-odds-bk { color: var(--text3); }

.panels-h { font-size: 12px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text2); margin: 16px 0 8px; }
.gpanel { background: linear-gradient(180deg, var(--panel), var(--bg2)); border: 1px solid var(--line); border-radius: 14px; padding: 14px 16px; margin-bottom: 12px; scroll-margin-top: 14px; }
.gpanel-head { display: grid; grid-template-columns: 1fr auto 1fr; gap: 10px; align-items: center; }
.gp-team { min-width: 0; }
.gp-home { text-align: right; }
.gp-name { font-size: 15px; font-weight: 800; color: var(--text); line-height: 1.2; }
.gp-sub { font-size: 11px; color: var(--text3); font-variant-numeric: tabular-nums; margin-top: 2px; }
.gp-mid { text-align: center; white-space: nowrap; }
.gp-line { font-size: 13px; font-weight: 800; color: var(--text); }
.gp-score { font-size: 1.5rem; font-weight: 800; color: var(--text); line-height: 1.1; }
.gp-ou { font-size: 11px; color: var(--text2); font-variant-numeric: tabular-nums; }
.gp-when { font-size: 10px; color: var(--text3); text-transform: uppercase; letter-spacing: 0.05em; margin-top: 2px; }
.gp-strip { margin-top: 10px; padding: 6px 10px; background: var(--panel2); border: 1px solid var(--line); border-radius: 8px; font-size: 12.5px; color: var(--text2); font-variant-numeric: tabular-nums; }
.gp-strip-l { font-weight: 700; color: var(--text3); text-transform: uppercase; font-size: 10px; letter-spacing: 0.06em; margin-right: 4px; }
.gp-note { color: var(--text3); font-size: 10px; font-style: italic; margin-left: 6px; }
.gp-body { margin-top: 10px; }
.gp-edges { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
@media (max-width: 560px) { .gp-edges { grid-template-columns: 1fr; } .gpanel-head { grid-template-columns: 1fr; text-align: left; } .gp-home { text-align: left; } }
.gp-edge { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; background: var(--panel2); border: 1px solid var(--line); border-radius: 8px; padding: 7px 10px; }
.gp-edge span { font-size: 11px; color: var(--text2); }
.gp-edge b { font-size: 13px; color: var(--text); font-variant-numeric: tabular-nums; }
.gp-sit { margin-top: 8px; display: flex; flex-wrap: wrap; gap: 10px; align-items: baseline; font-size: 11px; color: var(--text2); }
.gp-sit-i { color: var(--text); }
.gp-more { display: inline-block; margin-top: 10px; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text2); text-decoration: none; }
.gp-more:hover { color: var(--acc); }

/* ── buttons / filter pills ─────────────────────────────────────────────── */
.window-btn, .filter-btn {
    display: inline-block; font-family: var(--font); font-size: 11.5px; font-weight: 700;
    color: var(--text2); background: var(--panel2); border: 1px solid var(--line);
    border-radius: 7px; padding: 4px 9px; text-decoration: none; cursor: pointer;
    transition: 0.12s;
}
.window-btn:hover, .filter-btn:hover { color: var(--text); }
.window-btn.active, .filter-btn.active { background: var(--acc-dim); color: var(--acc); border-color: var(--acc); }
.filter-row { display: flex; flex-wrap: wrap; gap: 0.35rem; margin-bottom: 0.9rem; }

/* ── link-chip grid (team browser) ──────────────────────────────────────── */
.team-link-grid { display: flex; flex-wrap: wrap; gap: 7px; }
a.team-link-chip {
    position: relative; display: block; padding: 6px 1.6rem 6px 11px;
    background: var(--panel2); border: 1px solid var(--line); border-radius: 8px;
    font-family: var(--font); font-size: 12.5px; font-weight: 600; color: var(--text2);
    text-decoration: none; transition: border-color 0.12s, color 0.12s;
}
a.team-link-chip::after {
    content: '→'; position: absolute; right: 0.6rem; top: 50%; transform: translate(-4px, -50%);
    opacity: 0; color: var(--acc); transition: all 0.15s ease;
}
a.team-link-chip:hover { border-color: var(--acc-line); color: var(--text); }
a.team-link-chip:hover::after { opacity: 1; transform: translate(0, -50%); }
a.team-link-chip .sub {
    display: block; font-family: var(--font); font-size: 0.62rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.1em; color: var(--text3); margin-top: 0.15rem;
}

/* ── footer ─────────────────────────────────────────────────────────────── */
footer {
    display: flex; justify-content: space-between; flex-wrap: wrap; gap: 0.5rem;
    width: min(1240px, 100% - 2rem); margin: 0 auto; padding: 0.9rem 0 1.2rem;
    border-top: 1px solid var(--line); color: var(--text3); font-size: 0.75rem;
}
.data-freshness strong { color: var(--text2); font-weight: 700; }

/* ── mobile: tables → stacked label/value cards ─────────────────────────── */
@media (max-width: 640px) {
    table.stack thead { display: none; }
    table.stack tbody tr {
        display: block; border: 1px solid var(--line-soft); border-radius: 11px;
        margin-bottom: 0.6rem; padding: 0.4rem 0.6rem; background: var(--panel2);
    }
    table.stack tbody td {
        display: flex; justify-content: space-between; gap: 1rem;
        border: none; padding: 0.18rem 0; white-space: normal;
    }
    table.stack tbody td::before {
        content: attr(data-label); font-family: var(--font); font-size: 0.62rem; font-weight: 700;
        text-transform: uppercase; letter-spacing: 0.1em; color: var(--text3);
        align-self: center; flex: none;
    }
    /*  THE STACK HAS TO CONTAIN ITSELF. The rows went display:block but the TABLE
        did not, so it kept a table box sized to its widest content — the
        best-number cell holds one .mk-pick per leg (both spread sides, both total
        sides, both moneylines), six buttons in a non-wrapping row, which came to
        925px inside a 326px column. Every label rendered and every value sat off
        the right edge of the phone. Pre-dates the sheet; it is simply what this
        view has looked like on a phone.  */
    table.stack { display: block; width: 100%; }
    table.stack tbody { display: block; width: 100%; }
    table.stack tbody td { flex-wrap: wrap; align-items: baseline; min-width: 0; }
    table.stack .bn-cell { display: flex; flex-wrap: wrap; gap: 4px; justify-content: flex-end; }
    table.stack .mk-pick-sm { min-height: 40px; }
    table.stack .tbl-matchup { flex-wrap: wrap; justify-content: flex-end; text-align: right; }
    table.stack .tbl-sides { display: flex; flex-wrap: wrap; gap: 3px 8px; justify-content: flex-end; }
    /*  a cell with nothing in it is a label and a blank line on a phone  */
    table.stack tbody td:empty { display: none; }
}

footer a { color: var(--text2); text-decoration: none; border-bottom: 1px solid var(--line); }
footer a:hover { color: var(--acc); border-bottom-color: var(--acc-line); }
.data-sources { color: var(--text3); }

/* ---- Field-diagram matchup card ---- */
.fld-card { }
.fld-h2h {
    text-align: center; font-size: 13px; font-weight: 700; color: var(--text);
    padding-bottom: 12px; margin-bottom: 4px; border-bottom: 1px solid var(--line-soft);
}
.fld-series {
    display: inline-block; font-size: 9.5px; font-weight: 800; letter-spacing: 0.1em;
    text-transform: uppercase; color: var(--text3); margin-right: 6px;
}
.fld-series-since { color: var(--text3); font-weight: 600; font-size: 11.5px; }
.fld-tile {
    display: grid; grid-template-columns: 1fr auto 1fr; gap: 14px; align-items: center;
    padding: 14px 0 4px;
}
.fld-team { min-width: 0; }
.fld-team.away { text-align: right; }
.fld-team-name {
    font-family: var(--font); font-weight: 800; font-size: 15px; color: var(--text);
    letter-spacing: -0.01em; line-height: 1.2;
}
.fld-coach { font-size: 11.5px; color: var(--text2); font-weight: 600; margin-top: 3px; }
.fld-chips { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 8px; }
.fld-team.away .fld-chips { justify-content: flex-end; }
.fld-chip {
    font-size: 10.5px; font-weight: 700; color: var(--text2);
    background: var(--panel2); border: 1px solid var(--line); border-radius: 999px;
    padding: 3px 9px; white-space: nowrap;
}
.fld-chip.dual { color: #e8b64c; border-color: #4a3d1c; background: #1c1810; }
.fld-field { display: flex; flex-direction: column; align-items: center; }
.fld-def-name, .fld-off-name {
    font-size: 11px; font-weight: 700; color: var(--text2); letter-spacing: 0.02em;
    text-align: center; margin: 2px 0;
}
.fld-svg { width: 300px; max-width: 78vw; height: auto; display: block; }
.fld-svg .fld-pos { font-family: var(--font); font-size: 8.5px; font-weight: 800; fill: #f3f5f9; pointer-events: none; }
.fld-svg .fld-zone { font-family: var(--font); font-size: 9px; font-weight: 800; letter-spacing: 0.22em; fill: #ffffff; fill-opacity: 0.13; }
.fld-flip {
    margin-top: 8px; font-family: var(--font); font-size: 11.5px; font-weight: 700;
    color: var(--text2); background: var(--panel2); border: 1px solid var(--line);
    border-radius: 8px; padding: 5px 12px; cursor: pointer;
}
.fld-flip:hover { color: var(--text); border-color: var(--text3); }
.fld-legend { display: flex; align-items: center; justify-content: center; gap: 9px; margin-top: 12px; }
.fld-leg-label { font-size: 10.5px; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text3); }
.fld-leg-bar {
    width: 120px; height: 8px; border-radius: 4px;
    background: linear-gradient(90deg, #c04a4a 0%, #2f3644 50%, #2fa866 100%);
    border: 1px solid var(--line);
}
.fld-leg-ends { font-size: 10.5px; color: var(--text3); font-weight: 600; }

@media (max-width: 640px) {
    .fld-tile { grid-template-columns: 1fr; gap: 10px; }
    .fld-team.away { text-align: left; order: 3; }
    .fld-team.home { order: 4; }
    .fld-team.away .fld-chips { justify-content: flex-start; }
    .fld-field { order: 1; }
}

/* ---- Record page ---- */
.rec-empty {
    background: var(--panel2); border: 1px solid var(--line); border-radius: 12px;
    padding: 14px 16px; margin-bottom: 14px;
}
.rec-empty-head {
    font-family: var(--font); font-weight: 800; font-size: 15px; color: var(--text);
    margin-bottom: 6px;
}
.rec-empty p { margin: 0; color: var(--text2); font-size: 13px; line-height: 1.55; }
.rec-muted { color: var(--text3); }
/* The base a one-line rule was graded on, when it is not the market's own base.
   Its whole job is to be READ — the denominator used to live in a hover title,
   which is invisible on a phone and in every screenshot. Block, not nowrap. */
.rec-base { display:block; margin-top:2px; color:var(--text3); font-size:11px;
            font-weight:400; line-height:1.35; white-space:normal; }
/* outcome colours — the ONE place green is allowed, because these ARE outcomes */
.rec-win  { color: #2fa866; font-weight: 700; }
.rec-loss { color: #c04a4a; font-weight: 700; }
.rec-push, .rec-void { color: var(--text3); font-weight: 700; }

/* non-D1 opponents (no ESPN division): muted, never styled like a real tier */
.chip.unknown { color: var(--text3); border-color: var(--line-soft); }

/* ---- Player ratings ---- */
.pl-filters { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin: 10px 0 12px; }
.pl-chip {
    font-size: 11.5px; font-weight: 700; color: var(--text2); text-decoration: none;
    background: var(--panel2); border: 1px solid var(--line); border-radius: 999px;
    padding: 4px 11px;
}
.pl-chip:hover { color: var(--text); border-color: var(--text3); }
.pl-chip.on { color: var(--bg); background: var(--amber, #e8b64c); border-color: transparent; }
.pl-sep { width: 1px; height: 18px; background: var(--line); margin: 0 4px; }
.rt-sub { font-family: var(--font); font-size: 13px; font-weight: 800; color: var(--text2);
          letter-spacing: 0.02em; margin: 14px 0 6px; }

/* ---- Schedule: kickoff stacked, venue demoted under the matchup ---- */
.sc-when { white-space: nowrap; font-variant-numeric: tabular-nums; }
.sc-when .sc-time { display: block; font-size: 11px; color: var(--text3); font-weight: 600; }
.sc-venue { display: block; font-size: 11px; color: var(--text3); margin-top: 2px; }

/* ---- Matchups: our number beside the market's ---- */
.gp-mkt {
    display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px;
    padding: 9px 12px; margin: 8px 0 0;
    background: var(--panel2); border: 1px solid var(--line); border-radius: 11px;
}
.gp-mkt-col { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.gp-mkt-l {
    font-size: 10.5px; font-weight: 800; letter-spacing: 0.07em;
    text-transform: uppercase; color: var(--text3);
}
.gp-mkt-col .tnum { font-size: 14px; font-weight: 700; color: var(--text); }
@media (max-width: 640px) { .gp-mkt { grid-template-columns: 1fr; gap: 6px; } }
/*  NOT A FLOAT. This was `float: right`, and a float wider than its container is
    quietly catastrophic for anything below it that establishes a block formatting
    context — a BFC does not overlap a float, it SHRINKS to the space beside it.
    .gpanel and .table-wrap are both BFCs, so on a 390px phone the three chips
    (~340px) squeezed the marquee panels to 82px and the All-games table into a
    sliver. It predates the sheet: with two chips the float was shorter and the
    panels came out at 138px, which is equally unusable and simply less obviously
    wrong. Adding a third view made an existing bug louder rather than causing it.

    A flex header instead: the toggle sits right on a wide screen and wraps to its
    own line on a phone, and nothing downstream has to dodge it.  */
.panels-h { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; }
.view-toggle { display: inline-flex; gap: 5px; margin-left: auto; flex-wrap: wrap; }
@media (max-width: 640px) { .view-toggle { margin-left: 0; width: 100%; } }
/* All-games view: the rail would repeat the table, so the table gets the width */
.bk-board-wide { grid-template-columns: minmax(0, 1fr); }
.hm-go { font-size: 11px; font-weight: 700; color: var(--text3); margin-left: 8px; white-space: nowrap; }
.hm-go:hover { color: var(--text); }
.hm-more { float: right; font-size: 12.5px; font-weight: 700; color: var(--text2); }
.hm-more:hover { color: var(--acc); }
.pickstrip-rec a { color: inherit; }

/* ── school identity: logo + colour + link (templates/_marks.html) ────────
   A school colour is IDENTITY, never a data value — it appears as a ring or a
   left rule beside the logo and nowhere else. Amber stays wayfinding, green
   stays outcome-only (BALLKNOWME_DESIGN_SPEC.md). Dark brand colours are
   lifted in teamnames._accent() so navy and black still read on the ground. */
.tm { display: inline-flex; align-items: center; gap: 7px; min-width: 0; }
.tm-logo {
    flex: none; object-fit: contain; border-radius: 3px;
    /* the ground is near-black and a lot of marks are dark navy or black — a
       faint plate behind the logo keeps them from disappearing */
    background: rgba(255, 255, 255, 0.06); padding: 1px;
}
.tm-logo-fallback {
    display: inline-flex; align-items: center; justify-content: center;
    border: 1px solid var(--line); font-size: 9px; font-weight: 800;
    letter-spacing: 0.02em; color: var(--text2); background: var(--panel3);
}
.tm-name {
    font-weight: 700; color: inherit; overflow: hidden; text-overflow: ellipsis;
    white-space: nowrap;
}
.tm-rank {
    flex: none; font-size: 10px; font-weight: 800; color: var(--text3);
    font-variant-numeric: tabular-nums;
}
.tm-rank::before { content: "#"; opacity: 0.6; }
.tm-link { color: var(--text); text-decoration: none; min-width: 0; display: inline-flex; }
.tm-link:hover .tm-name { color: var(--acc); }
.tm-link:focus-visible { outline: 2px solid var(--acc-line); outline-offset: 2px; border-radius: 4px; }

/* ── home: season bar ─────────────────────────────────────────────────────
   Three centred hero tiles used to take a whole band of the fold to say two
   things nobody came for. Only the countdown is news, so it keeps the type and
   the rest ride beside it. */
.season-bar {
    display: flex; align-items: center; gap: 22px; flex-wrap: wrap;
    background: linear-gradient(180deg, var(--panel), var(--bg2));
    border: 1px solid var(--line); border-radius: 14px;
    padding: 10px 18px; margin: 14px 0 12px;
}
.sb-count { display: flex; align-items: baseline; gap: 8px; }
.sb-num {
    font-size: 2rem; font-weight: 800; line-height: 1; color: var(--text);
    font-variant-numeric: tabular-nums;
}
.sb-unit { font-size: 11px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: var(--text2); }
.sb-facts { display: flex; gap: 20px; flex-wrap: wrap; margin-left: auto; }
.sb-facts span { font-size: 12px; color: var(--text2); font-variant-numeric: tabular-nums; }
.sb-facts strong { color: var(--text); font-weight: 800; }

/* ── home: top-ten ribbon ─────────────────────────────────────────────────── */
.top10 { padding: 12px 16px 14px; margin: 0 0 14px; }
.top10 > h2:first-child { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin-bottom: 9px; }
.t10-sub { font-size: 11px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text3); }
.t10-strip {
    list-style: none; margin: 0; padding: 0 0 2px;
    display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr);
    gap: 8px; overflow-x: auto;
}
.t10-item a {
    display: flex; flex-direction: column; align-items: center; gap: 3px;
    padding: 9px 6px 8px; text-decoration: none; min-width: 84px;
    background: var(--panel2); border: 1px solid var(--line); border-radius: 10px;
    /* school colour along the top edge — identity, not a value */
    border-top: 3px solid var(--tm, var(--line));
    transition: border-color 0.12s;
}
.t10-item a:hover { border-color: var(--acc-line); border-top-color: var(--tm, var(--acc-line)); }
.t10-rank { font-size: 10.5px; font-weight: 800; color: var(--text3); font-variant-numeric: tabular-nums; }
.t10-name {
    font-size: 11.5px; font-weight: 700; color: var(--text); text-align: center;
    line-height: 1.25; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.t10-item a:hover .t10-name { color: var(--acc); }
.t10-val { font-size: 11px; font-weight: 700; color: var(--text2); font-variant-numeric: tabular-nums; }
@media (max-width: 900px) {
    .t10-strip { grid-auto-columns: 96px; }   /* swipe instead of squeeze */
}

/* ── home: rail LEFT, slate right ─────────────────────────────────────────── */
/*  280px, not 248: at the narrower width "North Dakota State" and "South Dakota
    State" both ellipsed, and a ranking that cannot print the team's name is not
    a ranking. */
.hm-split { display: grid; grid-template-columns: 280px minmax(0, 1fr); gap: 1.1rem; align-items: start; }
.hm-slate, .hm-rails > .dashboard-section { margin-top: 0; }
.hm-slate { order: 2; }
.hm-rails { order: 1; display: flex; flex-direction: column; gap: 12px; position: sticky; top: 10px; }
@media (max-width: 980px) {
    .hm-split { grid-template-columns: 1fr; }
    .hm-rails { position: static; order: 3; }   /* on a phone the games come first */
    .hm-slate { order: 1; }
}

/* the slate is a list of games, not a spreadsheet — each row leads with the two
   schools, because that is what a reader is scanning for */
.slate-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 5px; }
/*  Each game is its own plate on the panel rather than a hairline-ruled row.
    Rows floating on the section's gradient read as a table someone forgot to
    style; a plate says "this is one game" and gives the date something to sit
    against. */
.slate-row {
    display: grid; grid-template-columns: 104px minmax(0, 1fr) 190px auto;
    gap: 12px; align-items: center;
    padding: 9px 12px; border-radius: 10px;
    background: var(--panel2); border: 1px solid var(--line-soft);
    transition: border-color 0.12s, background 0.12s;
}
.slate-row:hover { background: var(--panel3); border-color: var(--acc-line); }
/*  The date was --text3 on a gradient: legible in the mockup, grey mush on a
    phone in daylight. Day-of-week + date, at body weight, in --text2. */
.sr-when { font-size: 11.5px; font-weight: 700; color: var(--text2); font-variant-numeric: tabular-nums; line-height: 1.35; }
/*  Weekday label stays neutral: amber is wayfinding ("you are here", top tier),
    and every row having a date does not make every row a landmark. */
.sr-dow { display: block; font-size: 10.5px; font-weight: 800; letter-spacing: 0.09em; text-transform: uppercase; color: var(--text3); }
.sr-neutral { display: block; font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text3); }
.sr-teams { display: flex; align-items: center; gap: 10px; min-width: 0; flex-wrap: wrap; }
.sr-team {
    display: flex; align-items: center; gap: 7px; min-width: 0;
    /* the school colour, as a rule and nothing more */
    border-left: 3px solid var(--tm, var(--line)); padding-left: 8px;
}
.sr-team .tm-name { font-size: 13.5px; }
.sr-at { color: var(--text3); font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; }
.sr-model { display: flex; flex-direction: column; gap: 3px; align-items: flex-start; }
.sr-margin { font-size: 12px; color: var(--text2); font-variant-numeric: tabular-nums; font-weight: 700; }
.sr-go {
    font-size: 11px; font-weight: 700; color: var(--text2); text-decoration: none;
    white-space: nowrap; letter-spacing: 0.02em;
}
.sr-go:hover { color: var(--acc); }
@media (max-width: 700px) {
    .slate-row { grid-template-columns: 1fr auto; row-gap: 7px; }
    .sr-teams { grid-column: 1 / -1; }
    .sr-model { grid-column: 1; }
    .sr-go { grid-column: 2; align-self: end; }
}

/* ── one day's slate (/matchup/day/<date>) ────────────────────────────────
   Rides on .slate-list / .slate-row above rather than defining a second row
   style: it IS the home page's row, with a kickoff time in the leading cell
   instead of a date. Only the page furniture is new. */
.day-counts {
    display: flex; align-items: baseline; gap: 18px; flex-wrap: wrap;
    margin: -2px 0 10px; font-size: 12px; color: var(--text2);
    font-variant-numeric: tabular-nums;
}
.day-counts strong { color: var(--text); font-weight: 800; }
.day-nav { display: flex; gap: 14px; margin-left: auto; }
.day-nav a { font-size: 12px; font-weight: 700; color: var(--text2); text-decoration: none; white-space: nowrap; }
.day-nav a:hover { color: var(--acc); }
/*  "Today" is wayfinding — you-are-here — which is what amber is for here.
    It is not an outcome, so it must never borrow the result green. */
.chip-now { color: var(--acc); border-color: var(--acc-line); }
/*  A final's score sits WITH its school, not in a separate results column: the
    row is already "away at home", and splitting the two numbers off into their
    own cell asks the reader to re-pair them. (Dimming finished rows was tried
    and dropped — on any past date every row is final, so it washed the whole
    page out to say nothing.) */
.sr-score {
    font-size: 15px; font-weight: 800; color: var(--text);
    font-variant-numeric: tabular-nums; margin-left: 2px;
}

/*  The season bar's count, when there are games to list, is a link to that
    day. It must not look like body copy that happens to be underlined, and it
    must not look like a button either — the number is already the loudest thing
    in the bar, so the affordance is a quiet caret and a hover. */
.sb-link { display: flex; align-items: baseline; gap: 8px; text-decoration: none; color: inherit; }
.sb-link .sb-caret { font-size: 13px; font-weight: 800; color: var(--text3); transition: transform 0.12s, color 0.12s; }
.sb-link:hover .sb-num, .sb-link:focus-visible .sb-num { color: var(--acc); }
.sb-link:hover .sb-caret { color: var(--acc); transform: translateX(2px); }
.sb-link:focus-visible { outline: 2px solid var(--acc-line); outline-offset: 4px; border-radius: 8px; }

/* the rails: reference, so compact and quiet */
.pw-rail { padding: 12px 13px; }
.pw-rail > h2:first-child { font-size: 13px; letter-spacing: 0.04em; text-transform: uppercase; margin-bottom: 2px; }
.pw-sub { font-size: 11px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text3); margin-bottom: 8px; }
.pw-list { list-style: none; margin: 0; padding: 0; }
.pw-row {
    display: grid; grid-template-columns: 18px minmax(0, 1fr) auto; gap: 8px;
    align-items: center; padding: 4px 0 4px 7px;
    border-left: 3px solid var(--tm, var(--line));
    border-bottom: 1px solid var(--line-soft);
}
.pw-row:last-child { border-bottom: 0; }
.pw-rank { font-size: 11px; font-weight: 800; color: var(--text3); font-variant-numeric: tabular-nums; text-align: right; }
.pw-row .tm-name { font-size: 12.5px; }
.pw-val { font-size: 11.5px; font-weight: 700; color: var(--text2); font-variant-numeric: tabular-nums; }
.pw-note { font-size: 11px; margin: 0; }

/* data-centre counts, in the rail */
.dc-rail .dc-list { margin: 4px 0 0; padding: 0; }
.dc-list > div {
    display: flex; align-items: baseline; gap: 8px;
    padding: 5px 0; border-bottom: 1px solid var(--line-soft);
}
.dc-list > div:last-child { border-bottom: 0; }
.dc-list dt { font-size: 15px; font-weight: 800; color: var(--text); font-variant-numeric: tabular-nums; }
.dc-list dd { margin: 0; font-size: 10.5px; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; color: var(--text3); }

/* ── second pass: bigger crests, real school colour, whole-row click ────────
   Will, looking at the first cut: "it all blends together, it looks like the
   same thing", and "let me just click on the line". Three fixes below. */

/* 1. The crest carries the brand, so give it room and let the school colour
      sit behind it. --tm-rgb is the lifted colour as an r,g,b triplet so it can
      be mixed at low alpha; the plate stays neutral when a team has no colour. */
.tm-logo {
    background: rgba(var(--tm-rgb, 255, 255, 255), 0.10);
    border: 1px solid rgba(var(--tm-rgb, 255, 255, 255), 0.22);
    padding: 2px;
}

/* 2. The top-ten ribbon should not read as another list panel. Bigger crest,
      a wash of the school's own colour, and the rank as a proper numeral. */
.t10-item a {
    gap: 5px; padding: 11px 8px 10px; min-width: 96px;
    background:
        linear-gradient(180deg, rgba(var(--tm-rgb, 255, 255, 255), 0.16), rgba(var(--tm-rgb, 255, 255, 255), 0.03)),
        var(--panel2);
    border-top-width: 3px;
}
.t10-item a:hover {
    background:
        linear-gradient(180deg, rgba(var(--tm-rgb, 255, 255, 255), 0.26), rgba(var(--tm-rgb, 255, 255, 255), 0.06)),
        var(--panel2);
}
.t10-rank { font-size: 12px; color: var(--text2); }
.t10-name { font-size: 12px; }
.t10-item .tm-logo { background: rgba(255, 255, 255, 0.06); border-color: rgba(255, 255, 255, 0.12); }
@media (max-width: 900px) { .t10-strip { grid-auto-columns: 108px; } }

/* 3. The whole slate row is the link. The overlay sits under the school links
      so a crest still goes to that team; everything else goes to the game. */
.slate-row { position: relative; cursor: pointer; }
.sr-hit { position: absolute; inset: 0; z-index: 0; border-radius: inherit; }
.sr-hit:focus-visible { outline: 2px solid var(--acc-line); outline-offset: -2px; }
/*  The row's own content must not swallow the click, so it stops taking pointer
    events entirely and the real links opt back in above the overlay. Raising the
    content with z-index instead would leave the middle of the row dead. */
.slate-row > *:not(.sr-hit) { pointer-events: none; }
.slate-row a:not(.sr-hit) { pointer-events: auto; position: relative; z-index: 1; }
/* the row is clickable, so the trailing link is a cue rather than the only way in */
.slate-row:hover .sr-go { color: var(--acc); }

/* ── rail: more colour, more contrast, and a TD-leaders card ────────────────
   Will: "it's better, but it's not good... we need to really pop it up".
   The rail rows now carry the school's own colour as a wash behind the crest,
   the same device the top-ten ribbon uses, so the rail stops being a grey list. */
.pw-row {
    padding: 5px 8px; border-radius: 8px; border-bottom: 0;
    background: linear-gradient(90deg, rgba(var(--tm-rgb, 255, 255, 255), 0.13), transparent 62%);
}
.pw-row + .pw-row { margin-top: 3px; }
.pw-row:hover { background: linear-gradient(90deg, rgba(var(--tm-rgb, 255, 255, 255), 0.24), transparent 70%); }
.pw-rank { color: var(--text2); }
.pw-val { color: var(--text); }
.pw-rail > h2:first-child { font-size: 14px; }
.pw-foot { margin: 8px 0 0; font-size: 11px; color: var(--text3); line-height: 1.4; }

/* TD leaders: two lines in the name cell, so the school stays visible without
   a second column the 248px rail cannot afford. */
.td-row { grid-template-columns: 18px 22px minmax(0, 1fr) auto; }
.td-who { min-width: 0; line-height: 1.2; }
.td-name {
    display: block; font-size: 12px; font-weight: 700; color: var(--text);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.td-team { display: block; font-size: 10px; font-weight: 700; color: var(--text3); }
.td-val { font-size: 14px; font-weight: 800; color: var(--text); }

/* ── Matchups tab revamp ───────────────────────────────────────────────────
   Will: "completely revamp that, because it's all gray and black and a little
   bit of yellow." The colour that was missing is the schools' own — every game
   here has two of them. Amber stays wayfinding, green stays outcome-only. */

/* Panel: the two schools' colours meet at the top edge. One coloured element
   per panel, carrying identity for both sides at once. */
.gpanel { position: relative; overflow: hidden; padding-top: 17px; }
.gp-ribbon {
    position: absolute; top: 0; left: 0; right: 0; height: 3px;
    background: linear-gradient(90deg,
        rgb(var(--away-rgb, 36, 42, 53)) 0%, rgb(var(--away-rgb, 36, 42, 53)) 46%,
        rgb(var(--home-rgb, 36, 42, 53)) 54%, rgb(var(--home-rgb, 36, 42, 53)) 100%);
}
.gpanel-head { grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); }
.gp-team { display: flex; align-items: center; gap: 11px; }
.gp-home { flex-direction: row; justify-content: flex-end; }
.gp-id { min-width: 0; }
.gp-crest { flex: none; display: block; }
.gp-crest .tm-logo { background: rgba(255, 255, 255, 0.06); border-color: rgba(255, 255, 255, 0.14); }
.gp-name a { color: var(--text); text-decoration: none; }
.gp-name a:hover { color: var(--acc); }

/* Win probability as a meter. Length encodes the number; the fill stays neutral
   because a lean is not an outcome — colouring it green would claim a result. */
.gp-wp { display: flex; align-items: center; gap: 9px; margin-top: 11px; }
.gp-wp-track { flex: 1; display: flex; height: 6px; border-radius: 999px; overflow: hidden; background: var(--panel3); }
/*  Both halves have to be legible as bars: --text3 on --panel3 was so close to
    the empty track that the away side read as "no data" rather than as 40%. */
.gp-wp-away { background: rgba(255, 255, 255, 0.34); }
.gp-wp-home { background: rgba(255, 255, 255, 0.92); box-shadow: inset 1px 0 0 var(--panel3); }
.gp-wp-end {
    font-size: 11px; font-weight: 800; color: var(--text2);
    font-variant-numeric: tabular-nums; min-width: 30px;
}
.gp-wp-end:last-child { text-align: right; }
/*  The meter's stand-in when the calibration refuses the margin (matchup._cdf).
    Occupies the same slot at the same rhythm so a panel does not reflow, and is
    muted rather than warning-coloured: the model declining to quote a number is
    a correct outcome, not an error state. */
.gp-wp-none {
    margin-top: 11px; font-size: 11px; font-weight: 700; color: var(--text3);
    border-top: 1px solid var(--line); padding-top: 9px;
}

/* Rail slate cards: a crest each side and the two colours as end rules, so a
   50-game rail is scannable by shape instead of by reading 4-letter codes. */
.slate-card {
    border-left: 3px solid rgb(var(--away-rgb, 36, 42, 53));
    border-right: 3px solid rgb(var(--home-rgb, 36, 42, 53));
}
.sc-row { gap: 5px; }
.sc-row .tm-logo { flex: none; }
.sc-ab { font-weight: 800; }

/* Pick cards in the winners strip take the favourite's colour. */
.pick-card {
    background: linear-gradient(160deg, rgba(var(--tm-rgb, 255, 255, 255), 0.17), transparent 70%), var(--panel2);
    border-top: 3px solid var(--tm, var(--line));
}
.pc-head { display: flex; align-items: center; gap: 8px; }
.pc-head .tm-logo { flex: none; }

/* All-games table rows carry crests too — the table was the greyest surface
   on the site and it is the one people scan longest. */
.tbl-matchup { display: inline-flex; align-items: center; gap: 6px; }
.tbl-matchup .tm-logo { flex: none; }

/* ── best available number ─────────────────────────────────────────────────
   The one edge that measured real (ncaaf/ncaaf_line_shopping.py: +0.86% win
   rate, +1.61% ROI, 8,652 bets). It is STRUCTURAL, not predictive, so it must
   never be styled like a pick: no green — green is outcome-only in this design
   spec and nothing here has an outcome. A side where the books actually differ
   gets a quiet amber rule, which is amber doing its one legal job: wayfinding,
   "look here", not "this wins". */
.gp-best { margin-top: 10px; padding: 9px 11px; background: var(--panel2);
           border: 1px solid var(--line); border-radius: 10px; }
.gp-best-h { font-size: 11px; font-weight: 800; letter-spacing: 0.08em;
             text-transform: uppercase; color: var(--text2); margin-bottom: 7px;
             display: flex; gap: 8px; align-items: baseline; }
.gp-best-n { font-weight: 700; color: var(--text3); letter-spacing: 0.04em; }
.gp-best-row { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 7px; }
@media (max-width: 640px) { .gp-best-row { grid-template-columns: repeat(2, 1fr); } }
.gp-best-cell { background: var(--panel3); border: 1px solid var(--line-soft);
                border-left: 2px solid var(--line); border-radius: 8px; padding: 6px 8px;
                min-width: 0; }
.gp-best-cell.is-shop { border-left-color: var(--acc-line); }
.bn-side { display: block; font-size: 10px; font-weight: 700; color: var(--text3);
           overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bn-line { display: block; font-size: 14px; font-weight: 800; color: var(--text);
           font-variant-numeric: tabular-nums; line-height: 1.25; }
.bn-price { font-size: 11px; font-weight: 700; color: var(--text2); }
.bn-book { display: block; font-size: 10px; font-weight: 700; color: var(--text2);
           overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gp-best-note { margin-top: 7px; font-size: 10.5px; color: var(--text3); line-height: 1.45; }
.gp-best-note strong { color: var(--text2); }
/* how many books hold this number — "1/6" is the shop, "5/6" is the market */
.bn-share { color: var(--text3); font-weight: 700; font-variant-numeric: tabular-nums; }
.gp-best-cell.is-shop .bn-share { color: var(--acc); }

/* best number in the all-games table — two sides stacked, book named */
.bn-cell { white-space: normal; min-width: 190px; }
.bn-inline { display: block; font-size: 11.5px; font-weight: 700; color: var(--text);
             line-height: 1.35; }
.bn-inline.is-shop .bn-book-sm { color: var(--acc); }
.bn-abbr { display: inline-block; min-width: 40px; color: var(--text2); font-weight: 800; }
.bn-book-sm { font-size: 10px; font-weight: 700; color: var(--text3); }

/* ── matchup card: BOTH directions, ranked ─────────────────────────────────
   Was one field behind a "flip offense" button. A toggle hid half the matchup
   and made the reader hold the first half in their head to compare it with the
   second — which is the research the site exists to do for them. */
.fld2-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-top: 10px; }
@media (max-width: 820px) { .fld2-grid { grid-template-columns: 1fr; } }
.fld2 { background: var(--panel2); border: 1px solid var(--line); border-radius: 12px; padding: 11px; }
.fld2-head { display: flex; align-items: baseline; gap: 7px; flex-wrap: wrap;
             font-size: 13px; font-weight: 800; color: var(--text); margin-bottom: 8px; }
.fld2-role { font-size: 10px; font-weight: 700; letter-spacing: 0.07em;
             text-transform: uppercase; color: var(--text3); }
.fld2-vs { font-size: 10px; font-weight: 700; text-transform: uppercase;
           letter-spacing: 0.08em; color: var(--text3); }
.fld2 .fld-svg { width: 100%; height: auto; display: block; }

/* the ranks: the part that answers "is this the worst pass defense?" */
.fld2-ranks { list-style: none; margin: 9px 0 0; padding: 0;
              display: grid; grid-template-columns: 1fr 1fr; gap: 5px; }
.fld2-rank { display: flex; align-items: baseline; gap: 5px; padding: 5px 7px;
             background: var(--panel3); border: 1px solid var(--line-soft);
             border-left: 2px solid var(--line); border-radius: 7px; min-width: 0; }
/* elite/poor are the two ends of a MEASURED scale, not outcomes — so they use
   the neutral ink ramp and a border weight, never --pos/--neg, which mean a
   pick won or lost. */
.fld2-rank.elite { border-left-color: var(--text); }
.fld2-rank.poor  { border-left-color: var(--text3); }
.fr-label { font-size: 10px; font-weight: 700; color: var(--text3); flex: 1;
            overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fr-rank { font-size: 14px; font-weight: 800; color: var(--text); font-variant-numeric: tabular-nums; }
.fld2-rank.elite .fr-rank { color: var(--text); }
.fld2-rank.poor .fr-rank { color: var(--text2); }
.fr-of { font-size: 10.5px; font-weight: 700; color: var(--text3); }
.fld2 .fld-chips { margin-top: 9px; }
.fld2-coaches { display: flex; gap: 18px; flex-wrap: wrap; margin-top: 10px;
                font-size: 11.5px; color: var(--text2); }
.fld2-coach strong { color: var(--text); }

/* who carried each team last season */
.plr-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
@media (max-width: 700px) { .plr-grid { grid-template-columns: 1fr; } }
.plr-team { font-size: 12px; font-weight: 800; color: var(--text); margin-bottom: 6px;
            padding-bottom: 5px; border-bottom: 1px solid var(--line); }
.plr-row { display: grid; grid-template-columns: 34px minmax(0, 1fr) auto; gap: 8px;
           align-items: baseline; padding: 6px 0; border-bottom: 1px solid var(--line-soft); }
.plr-row:last-child { border-bottom: 0; }
.plr-pos { font-size: 10px; font-weight: 800; color: var(--text3); letter-spacing: 0.04em; }
.plr-name { font-size: 12.5px; font-weight: 700; color: var(--text); min-width: 0; }
.plr-stat { display: block; font-size: 10.5px; font-weight: 600; color: var(--text3);
            overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.plr-rank { font-size: 12px; font-weight: 800; color: var(--text); font-variant-numeric: tabular-nums; }
.plr-rank-lbl { font-size: 10.5px; font-weight: 700; color: var(--text3); }
.plr-none { font-size: 11px; color: var(--text3); padding: 6px 0; }

/* ── head-to-head unit callouts ────────────────────────────────────────────
   "X's #52 pass offense meets Y's #29 pass defense — edge Y." The four ranks
   above state the facts; this states what they MEAN, which is the research the
   reader came here to avoid doing.

   Colour discipline: an "edge" is a DESCRIPTION of last season's units, not an
   outcome and not a pick. So it takes the ink ramp and a border weight, never
   --pos/--neg, which are reserved for graded results. */
.h2h-list { list-style: none; margin: 9px 0 0; padding: 0; display: flex;
            flex-direction: column; gap: 5px; }
.h2h { display: grid; grid-template-columns: 66px minmax(0, 1fr) auto; gap: 9px;
       align-items: baseline; padding: 7px 9px; border-radius: 8px;
       background: var(--panel3); border: 1px solid var(--line-soft);
       border-left: 2px solid var(--line); }
.h2h.edge { border-left-color: var(--text2); }
.h2h-phase { font-size: 10px; font-weight: 800; letter-spacing: 0.06em;
             text-transform: uppercase; color: var(--text3); }
.h2h-line { font-size: 11.5px; color: var(--text2); font-variant-numeric: tabular-nums;
            min-width: 0; }
.h2h-line strong { color: var(--text); font-weight: 800; }
.h2h-vs { color: var(--text3); font-style: italic; margin: 0 2px; }
.h2h-verdict { font-size: 11px; font-weight: 700; color: var(--text2);
               white-space: nowrap; text-align: right; }
.h2h.edge .h2h-verdict strong { color: var(--text); }
.h2h-gap { display: block; font-size: 10.5px; font-weight: 700; color: var(--text3);
           font-variant-numeric: tabular-nums; }

/* ── projection basis ──────────────────────────────────────────────────────
   Will, 2026-08-01: "I don't understand how you can have those predictions yet
   when we don't have all that data... we have no idea whether the starting
   quarterback is going to break his ankle in the first play of the season."

   He is right, and the presentation was the dishonest part. Before Week 0 EVERY
   projection on the site — week 0 and week 15 alike — is built from identical
   inputs: last season regressed toward the mean, with the L2 form adjustment at
   exactly 0. The number was printed in the same type it will carry in November
   with ten games of real form behind it, so the two states looked the same.

   Neutral, not alarming: this is a statement of what the number knows, not a
   warning that it is wrong. No --neg (that means a pick lost). */
.basis { display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px;
         margin-top: 10px; padding: 8px 11px; border-radius: 9px;
         background: var(--panel2); border: 1px solid var(--line);
         border-left: 3px solid var(--line); }
.basis-pre { border-left-color: var(--text3); }
.basis-live { border-left-color: var(--text2); }
.basis-tag { font-size: 10px; font-weight: 800; letter-spacing: 0.08em;
             text-transform: uppercase; color: var(--text); }
.basis-detail { font-size: 11.5px; color: var(--text2); }
.basis-warn { flex-basis: 100%; font-size: 11px; color: var(--text3); line-height: 1.5; }
.basis-warn strong { color: var(--text2); }

/* per-panel: one short tag under the kickoff line */
.gp-basis { font-size: 10.5px; font-weight: 800; letter-spacing: 0.07em;
            text-transform: uppercase; margin-top: 3px; }
.gp-basis.pre { color: var(--text3); }
.gp-basis.live { color: var(--text2); }

/* ── the remaining five tabs: school identity + honest chips ───────────────
   Ratings, Teams, Players, Record and History were five pages of grey text
   where every row is a school with a crest and colours of its own.

   And they were the last of the amber-chip spam: a division tag on all 50
   ratings rows, all 50 player rows, and BOTH sides of all 78 history rows —
   ~156 amber chips on one page to say "FBS", which is true of nearly every row
   and therefore tells the reader nothing. Amber is wayfinding in this spec.
   .divtag is the neutral version; the amber .chip.fbs survives only where a
   division MISMATCH is the actual fact (cross-division games). */
.divtag {
    display: inline-block; padding: 0.05rem 0.4rem; border: 1px solid var(--line-soft);
    border-radius: 5px; font-size: 10px; font-weight: 700; letter-spacing: 0.06em;
    text-transform: uppercase; color: var(--text3); vertical-align: 1px;
}
.divtag.fcs { color: var(--text3); }
/* the Key-3 money card names the book — that IS the actionable fact */
.rec-book { color: var(--text2); font-weight: 700; font-size: 12px; }

/* a school cell in a dense table: crest, name, its colour as a left rule */
.tm-cell { border-left: 2px solid var(--tm, transparent); padding-left: 9px !important; }

/* teams index: crest on every card */
.team-link-chip { display: flex; align-items: center; gap: 9px;
                  border-left: 3px solid var(--tm, var(--line)); }
.team-link-chip .tm-logo { flex: none; }
.tlc-body { min-width: 0; }
.tlc-name { display: block; font-weight: 700; color: var(--text); font-size: 12.5px;
            overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* history: the winner's crest carries the weight, not a <strong> around a link */
.hist-side { display: inline-flex; align-items: center; opacity: 0.72; }
.hist-side.won { opacity: 1; }
.hist-side.won .tm-name { color: var(--text); font-weight: 800; }

/* ── pick slip / bet builder ───────────────────────────────────────────────
   Ported from nfl.css per PICK_SLIP_SPEC.md — verbatim, on shared tokens.
   CFB addition: .mk-book names the sportsbook holding the best price, which
   NFL cannot show because its data has no juice. .mk-book.only marks a price
   only one book is offering — the actual shop. Amber there is wayfinding
   ("look here"), never a recommendation. */
.doss-grid { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: 16px; align-items: start; }
/* Will, 2026-08-29 (second telling): the EMPTY builder is never on screen —
   ANY page. It exists only while a ticket does (.live, stamped by the slip's
   own JS) and lives fixed in the UPPER RIGHT. */
.doss-rail { display: none; position: fixed; top: 64px; right: 18px; width: 330px;
    max-height: min(80vh, 760px); overflow-y: auto; z-index: 60; border-radius: 13px;
    box-shadow: 0 14px 44px rgba(0, 0, 0, 0.6); }
.doss-rail.live { display: block; }
.slip {
    background: linear-gradient(180deg, var(--panel), var(--bg2));
    border: 1px solid var(--line); border-radius: 13px; overflow: hidden;
}
.slip-h {
    display: flex; align-items: center; justify-content: space-between;
    padding: 10px 12px; border-bottom: 1px solid var(--line);
}
.slip-t { font-size: 12px; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase; }
.slip-clear {
    background: none; border: none; color: var(--text3); font-size: 10.5px; font-weight: 700;
    cursor: pointer; font-family: var(--font); text-transform: uppercase; letter-spacing: 0.06em;
}
.slip-clear:hover { color: var(--neg); }
.slip-mkts { padding: 10px 12px; border-bottom: 1px solid var(--line); }
.mk-grp + .mk-grp { margin-top: 10px; }
.mk-h { font-size: 10.5px; font-weight: 800; letter-spacing: 0.09em; text-transform: uppercase;
    color: var(--text3); margin-bottom: 5px; display: flex; justify-content: space-between; }
.mk-note { text-transform: none; letter-spacing: 0; font-weight: 600; }
.mk-picks { display: grid; grid-template-columns: 1fr 1fr; gap: 5px; }
.mk-pick {
    display: flex; align-items: center; justify-content: space-between; gap: 6px;
    padding: 7px 9px; cursor: pointer; font-family: var(--font);
    background: var(--panel2); border: 1px solid var(--line); border-radius: 8px;
    color: var(--text); text-align: left;
}
.mk-pick:hover { border-color: var(--text3); background: var(--panel3); }
.mk-pick.on { border-color: var(--acc); background: var(--acc-dim); }
.mk-sel { font-size: 11.5px; font-weight: 700; }
.mk-price { font-size: 11.5px; font-weight: 800; color: var(--text2); font-variant-numeric: tabular-nums; }
.mk-pick.on .mk-price { color: var(--acc); }
.mk-price i { font-style: normal; color: var(--text3); }
.mk-foot { font-size: 10.5px; color: var(--text3); margin-top: 8px; line-height: 1.5; }
.slip-legs { padding: 8px 12px; }
.slip-empty { font-size: 11.5px; color: var(--text3); padding: 6px 0; }
.slip-leg {
    display: grid; grid-template-columns: 16px 1fr auto; gap: 6px; align-items: baseline;
    padding: 6px 0; border-bottom: 1px solid var(--line-soft);
}
.slip-x { grid-row: span 2; background: none; border: none; cursor: pointer;
    color: var(--text3); font-size: 15px; line-height: 1; padding: 0; font-family: var(--font); }
.slip-x:hover { color: var(--neg); }
.slip-leg-m { grid-column: 2; font-size: 10.5px; font-weight: 700; letter-spacing: 0.06em;
    text-transform: uppercase; color: var(--text3); }
.slip-leg-l { grid-column: 2; font-size: 12.5px; font-weight: 700; color: var(--text); }
.slip-leg-p { grid-column: 3; grid-row: 2; font-size: 12px; font-weight: 800;
    color: var(--text2); font-variant-numeric: tabular-nums; }
.slip-calc { padding: 10px 12px; border-top: 1px solid var(--line); }
.slip-warn {
    font-size: 10.5px; line-height: 1.5; color: var(--text); margin-bottom: 9px;
    background: var(--neg-soft); border: 1px solid rgba(255,91,98,.35);
    border-radius: 8px; padding: 7px 9px;
}
.slip-row { display: flex; align-items: center; justify-content: space-between; padding: 3px 0; }
.slip-k { font-size: 10.5px; font-weight: 700; letter-spacing: 0.06em;
    text-transform: uppercase; color: var(--text3); }
.slip-v { font-size: 13px; font-weight: 800; font-variant-numeric: tabular-nums; }
.slip-row.total { border-top: 1px solid var(--line-soft); margin-top: 5px; padding-top: 7px; }
.slip-row.total .slip-v { color: var(--pos); font-size: 15px; }   /* a return IS an outcome */
.slip-note { font-size: 10.5px; color: var(--text3); margin-top: 9px; line-height: 1.55; }
@media (max-width: 1080px) {
    /* the builder flows under the dossier rather than squeezing it */
    .doss-grid { grid-template-columns: 1fr; }
    .doss-rail { position: static; }
    .mk-picks { grid-template-columns: repeat(4, 1fr); }
}
/*  The three rules above are also emitted OUTSIDE their @media block by the
    extraction that ported this file — that orphan pinned .doss-rail to
    position:static at every width and killed the sticky slip. Removed. */
/*  The book name is a FACT the reader needs (where to place the bet), so it must
    be legible whether or not it is the exclusive holder. 9.5px in --text3 was
    barely readable — Will: "a faint gray that I can barely see". Bigger, and up
    to --text2; amber still marks the one case that means something. */
.mk-book { display: block; font-size: 10.5px; font-weight: 700; color: var(--text2);
           letter-spacing: 0.02em; margin-top: 1px; }
.mk-book.only { color: var(--acc); }
.mk-pick.on .mk-book { color: var(--text2); }
@media (max-width: 900px) { .doss-grid { grid-template-columns: 1fr; } .doss-rail { position: static; } }

/* ── board: the best-number row IS the bet builder ─────────────────────────
   Four markets across a panel (moneyline, spread, total, and team total named
   as absent), each cell a slip leg. Reuses .mk-pick so there is ONE click
   handler on the site rather than a second implementation to drift. */
/* The ticket no longer owns a page column. The comp's skeleton is two columns
   — rail | canvas — and the slip's 330px track sat mostly empty beside it,
   which is what kept the mockup's proportions unreachable. It docks bottom-
   right over the canvas instead: same markup, same .mk-pick handler, same
   storage key. Below 900px it returns to the flow after the board, exactly
   where the old one-column collapse put it. Scoped to .bk-board so the deep
   dive's .doss-grid slip is untouched. */
/* Will, 2026-08-29: the EMPTY builder doesn't belong on screen — you see the
   books until you select a pick; the ticket then appears in the UPPER RIGHT.
   The slip's own JS stamps .live on the rail whenever legs > 0. */
/* (the hidden-until-live dock rules moved to the GLOBAL .doss-rail block —
   the deep dive kept an always-visible empty column for one more round of
   Will telling us to remove it. Nothing is scoped to .bk-board any more.) */
@media (max-width: 900px) {
    .doss-rail { position: static; width: auto; max-height: none;
        overflow-y: visible; box-shadow: none; }
}
.gp-best .gp-best-row { grid-template-columns: repeat(4, minmax(0, 1fr)); align-items: start; }
@media (max-width: 900px) { .gp-best .gp-best-row { grid-template-columns: repeat(2, 1fr); } }
.gp-best .mk-grp { min-width: 0; }
.gp-best .mk-h { font-size: 10.5px; font-weight: 800; letter-spacing: 0.07em;
                 text-transform: uppercase; color: var(--text3); margin-bottom: 4px; }
.gp-best .mk-picks { display: flex; flex-direction: column; gap: 4px; }
/* a market we cannot price is SAID, not skipped: a missing group would read as
   "this game has no team totals" rather than "we have no team-total data" */
.mk-absent .mk-none { font-size: 10.5px; color: var(--text3); font-style: italic;
                      padding: 6px 8px; border: 1px dashed var(--line);
                      border-radius: 8px; }

/* the rail has room at 250px — let a long school abbreviation breathe */
.bk-rail .sc-row { gap: 6px; }
.bk-rail .slate-card { padding: 7px 10px; }
/* compact leg buttons for the 76-game table */
.bn-cell { white-space: normal; min-width: 300px; }
.mk-pick-sm { display: inline-flex; align-items: baseline; gap: 6px; margin: 2px 3px 2px 0;
              padding: 3px 7px; font-size: 11px; }
.mk-pick-sm .mk-sel { font-size: 11px; }
.mk-pick-sm .mk-price { font-size: 11px; }
.mk-pick-sm .mk-book { display: inline; font-size: 9px; }

/* ── send the built ticket to the book ─────────────────────────────────────
   sids captured free off the odds pull. Amber because this is wayfinding —
   "go here next" — which is the one job amber is allowed on this site. */
/* ── the books grid (deep dive): one row per account book, every side a leg ──
   Cells reuse .mk-pick so the ONE delegated handler works; the grid only
   restyles them to sit inline in a table. Gold price = best on that side. */
.bkgrid td { white-space: nowrap; }
.bkgrid .mk-pick { display: inline-flex; align-items: baseline; gap: 7px;
                   padding: 4px 9px; width: auto; }
.bkgrid .mk-price { font-size: 12px; font-weight: 700; }
.bkgrid .bkg-best .mk-price, .bkg-best-key { color: var(--acc); font-weight: 800; }
.bkg-name { font-weight: 700; }
.bkg-dead { color: var(--text3); font-size: 12px; }
/* folded copy of the grid on each board panel */
.gp-books { margin-top: 8px; }
.gp-books > summary { cursor: pointer; font-size: 10px; font-weight: 800;
    letter-spacing: 0.08em; text-transform: uppercase; color: var(--text2);
    padding: 6px 2px; user-select: none; }
.gp-books > summary:hover { color: var(--text); }
.gp-books > summary .gp-note { text-transform: none; letter-spacing: 0; font-weight: 400; }
.gp-books[open] > summary { color: var(--text); }
.gp-books .table-wrap { margin-top: 2px; }

/* ── the book switcher: pick the ticket, then pick the BOOK (MLB pattern) ── */
.slip-books { display: grid; grid-template-columns: 1fr 1fr; gap: 5px; padding: 10px 12px;
              border-bottom: 1px solid var(--line); }
.slip-bk { display: flex; justify-content: space-between; align-items: baseline; gap: 6px;
           padding: 6px 9px; background: var(--panel2); border: 1px solid var(--line);
           border-radius: 7px; cursor: pointer; font: 700 12px var(--font); color: var(--text2); }
.slip-bk:hover { color: var(--text); border-color: var(--text3); }
.slip-bk.on { border-color: var(--acc); color: var(--acc); background: var(--acc-dim); }
.slip-bk.none { opacity: 0.45; }
/*  The chip carries the book's OWN number for the ticket, not a coverage count —
    the comparison is the reason the switcher exists, and it used to cost a click
    per book (Will, 2026-09-05). The price gets the tabular treatment and enough
    weight to be read across five chips at a glance.  */
.slip-cvg { font: 700 11.5px var(--font); font-variant-numeric: tabular-nums;
            color: var(--text); white-space: nowrap; }
.slip-bk.none .slip-cvg { color: var(--text3); }
/*  priced, but not for every leg — the number is real and partial, so it is
    marked rather than hidden  */
.slip-bk.part .slip-cvg { color: var(--text2); }
.slip-bk.part .slip-cvg::after { content: '*'; color: var(--text3); }
/*  and the one that actually pays most, when one of them does  */
.slip-bk.best { border-color: var(--acc-line); }
.slip-bk.best .slip-cvg { color: var(--acc); }
.slip-bk.on.best .slip-cvg { color: var(--acc); }
.slip-cnt { display: inline-block; min-width: 17px; text-align: center; margin-left: 6px;
            background: var(--acc); color: #14100a; border-radius: 9px;
            font: 800 11px/17px var(--font); }
.slip-hint { grid-column: 2; font-size: 10.5px; color: var(--text2); }
.slip-hint.on { color: var(--pos); }
.slip-hint.warn { color: var(--neg); }
.slip-open { display: block; margin-top: 10px; padding: 11px 12px; text-align: center;
             background: var(--acc); color: #14100a; border-radius: 8px; text-decoration: none;
             font: 800 13px var(--font); letter-spacing: 0.03em; }
.slip-open:hover { filter: brightness(1.08); }
.slip-open.off { background: var(--panel3); color: var(--text3); pointer-events: none; }

.slip-send { padding: 9px 12px; border-top: 1px solid var(--line); }
.ss-h { font-size: 9.5px; font-weight: 800; letter-spacing: 0.08em;
        text-transform: uppercase; color: var(--text3); margin-bottom: 6px; }
.ss-btn { display: block; padding: 7px 10px; margin-bottom: 5px; border-radius: 8px;
          background: var(--panel3); border: 1px solid var(--acc-line);
          color: var(--acc); font-size: 11.5px; font-weight: 800;
          text-decoration: none; text-align: center; }
.ss-btn:hover { background: var(--acc); color: #14100a; }
.ss-btn.one { border-color: var(--line); color: var(--text2); font-weight: 700; }
.ss-btn.one:hover { background: var(--panel2); color: var(--text); }
.ss-note { font-size: 10.5px; color: var(--text3); line-height: 1.5; margin-top: 5px; }
.gp-best-key { margin-top: 8px; font-size: 10px; color: var(--text3); }
.gp-best-key .mk-book { display: inline; font-size: 10px; }

/* ── season + conference record, and the conference-game flag ──────────────
   Will: "somewhere - hopefully aside of the team - we should see their season
   record and their conference record. Also if the matchup is a conference
   matchup, that should be highlighted somewhere in the header."

   Before Week 0 these are LAST season's, and the year is printed beside them —
   a 0-0 record in August is technically true and useless, but showing 8-5
   without saying which year would be the roster-placeholder mistake again. */
.gp-rec { font-size: 11px; font-weight: 700; color: var(--text2);
          font-variant-numeric: tabular-nums; margin-top: 2px; }
.gp-rec-yr { font-size: 10px; font-weight: 700; color: var(--text3); }
/* a conference game IS wayfinding — it is why the game matters in the standings */
.gp-conf { font-size: 10.5px; font-weight: 800; letter-spacing: 0.07em;
           text-transform: uppercase; color: var(--text2); margin-top: 3px; }
.conf-flag { display: inline-block; vertical-align: 3px; margin-left: 8px;
             padding: 2px 8px; border: 1px solid var(--line); border-radius: 6px;
             font-size: 10.5px; font-weight: 800; letter-spacing: 0.07em;
             text-transform: uppercase; color: var(--text2); }
.mu-records { display: flex; gap: 18px; flex-wrap: wrap; margin-top: 8px;
              font-size: 12.5px; color: var(--text2); font-variant-numeric: tabular-nums; }
.mu-records strong { color: var(--text); font-weight: 800; }
.mu-rec-note { color: var(--text3); font-size: 11px; }

/* ── team profile: percentile bars ─────────────────────────────────────────
   Eight metrics against the FBS field. The bar length IS the percentile, so
   length carries the value and colour only says which direction is good.
   Pace renders neutral because plays-per-game is a style, not a quality —
   colouring it green would assert that fast is better, which is not a fact. */
.tp-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 7px; }
.tp-row { display: grid; grid-template-columns: minmax(140px, 220px) minmax(0, 1fr) 62px 62px;
          gap: 12px; align-items: center; }
.tp-label { font-size: 12px; font-weight: 700; color: var(--text2);
            overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tp-track { position: relative; height: 12px; background: var(--panel3);
            border: 1px solid var(--line-soft); border-radius: 999px; overflow: hidden; }
.tp-fill { display: block; height: 100%; background: var(--text); border-radius: 999px; }
.tp-row.style .tp-fill { background: var(--text3); }
/*  The median reference line, which the whole chart is read against — so it has
    to be visible on BOTH the dark empty track and the light fill. A white line
    disappeared entirely on any bar past 50%, which is most of a good team's
    profile. `difference` inverts against whatever is beneath it: white on the
    dark track, dark on the light fill. */
.tp-mid { position: absolute; left: 50%; top: 0; bottom: 0; width: 1px;
          background: #fff; mix-blend-mode: difference; z-index: 2; }
.tp-pct { font-size: 13px; font-weight: 800; color: var(--text);
          font-variant-numeric: tabular-nums; text-align: right; }
.tp-row.style .tp-pct { color: var(--text2); }
.tp-ord { font-size: 9px; font-weight: 700; color: var(--text3); margin-left: 1px; }
.tp-raw { font-size: 11px; font-weight: 700; color: var(--text3);
          font-variant-numeric: tabular-nums; text-align: right; }
.tp-key { margin: 12px 0 0; font-size: 10.5px; color: var(--text3); display: flex;
          align-items: center; gap: 6px; flex-wrap: wrap; }
.tp-key-mid { display: inline-block; width: 1px; height: 11px; background: rgba(255,255,255,0.35); }
.tp-key-style { display: inline-block; width: 14px; height: 7px; border-radius: 999px;
                background: var(--text3); }
@media (max-width: 640px) { .tp-row { grid-template-columns: 1fr 54px; }
                            .tp-track { grid-column: 1 / -1; } .tp-raw { display: none; } }

/* ── Mobile pass 2026-08-23 ───────────────────────────────────────────────────
   MEASURED at a 390px viewport (chromium, is_mobile): the nav is a single
   non-wrapping flex row, so header.site-header reports clientWidth 390 against
   scrollWidth 471 and document.scrollWidth becomes 472 — THE WHOLE PAGE SCROLLS
   SIDEWAYS, and the last nav link sat 81px off-screen (NCAAF "History", NFL
   "Depth Charts" at 21px). .site-header itself already had flex-wrap:wrap; the
   nav nested inside it did not, and a flex item will not shrink below its
   content width. Before this block the smallest breakpoint in the file was
   560px, so nothing at all applied on a phone.

   Nav links also measured 30px tall. 44px is the Apple HIG minimum for a touch
   target; min-height on an inline-flex is used rather than padding so the
   height is guaranteed regardless of font metrics. Wrapping (not a scrolling
   nav strip) is deliberate: with 7-8 links everything stays visible, and no
   destination is hidden behind a swipe nobody knows to make. */
@media (max-width: 560px) {
    .site-header { padding: 10px 14px; gap: 8px 12px; }
    .site-header nav {
        flex-wrap: wrap;
        width: 100%;
        margin-left: 0;
        gap: 0 14px;
    }
    .site-header nav a {
        display: inline-flex;
        align-items: center;
        min-height: 44px;
        padding: 0 2px;
        font-size: 14px;
    }
    .site-tagline { margin-left: 0; }
}

/* ── Mobile pass II · 2026-08-23 ─────────────────────────────────────────────
   Run against the polish checklist at 320/360/390/430px with chromium at
   is_mobile. What this block fixes, all MEASURED not assumed:

   TYPE FLOOR. 23 selectors on this site declared font-size under 10px — the
   smallest measured 8px. That is below readable at arm's length on any device.
   Raised to 12px on touch only, so the desktop density is untouched. The
   10-11.5px tier (~150 rules across both sites) is deliberately NOT changed:
   that is a defensible dense-data idiom and changing it would redesign the
   site. Note the usual 16px "body minimum" has two rationales — readability
   and iOS zoom-on-input-focus; the second does not apply here because these
   pages contain ZERO text inputs (verified). Only readability drives this.

   TOUCH TARGETS. Row links measured 17-34px tall against a 44px minimum
   (Apple HIG). Given min-height here rather than restructuring. Small inline
   marks get an expanded hit area via a pseudo-element so the tap zone grows
   without moving any layout.

   TAP FEEDBACK. Touch has no hover, so every :hover affordance on this site was
   invisible on a phone and presses had no acknowledgment. :active now answers.
*/

@media (hover: none) {
.conf-tag,
.fld-series,
.fld-leg-label,
.gp-mkt-l,
.tm-logo-fallback,
.sr-neutral,
.fr-of,
.plr-rank-lbl,
.h2h-gap,
.gp-basis,
.mk-h,
.mk-foot,
.slip-leg-m,
.slip-note,
.gp-best .mk-h,
.mk-pick-sm .mk-book,
.ss-h,
.ss-note,
.gp-rec-yr,
.gp-conf,
.tp-ord { font-size: 12px; }
}

@media (max-width: 560px) {
    p { font-size: 16px; line-height: 1.55; }
}

@media (hover: none) {
    a, button, summary, [role=button] { touch-action: manipulation; }
    a:active, button:active, [role=button]:active { opacity: .72; }
}

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

/* §1 TOUCH TARGETS — measured against the 44px minimum:
   .tm-link 34px · .sr-go 17px · .hm-more 18px. */
@media (hover: none) {
    .tm-link, .st-row, .mk-pick { min-height: 44px; }
    .sr-go, .hm-more {
        display: inline-flex; align-items: center; min-height: 44px;
    }
}

/* §9 The sticky board rail capped itself with 100vh. Mobile browser chrome
   collapses on scroll and vh is computed against the LARGEST viewport, so the
   rail was taller than the visible screen and its last cards were unreachable.
   dvh tracks the live viewport. */
@media (max-width: 900px) {
    .bk-rail { max-height: calc(100dvh - 20px); }
}

/* Second sweep: these declare their size in rem, so the px-based audit missed
   them (0.62rem computes to 9.92px). Same floor, same reason. */
@media (hover: none) {
    .sb-unit { font-size: 12px; }
    /* remaining sub-44px rows measured on /board/ and /record/ */
    .gp-more, .filter-btn, .pl-chip {
        display: inline-flex; align-items: center; min-height: 44px;
    }
    .tbl-matchup { display: inline-flex; align-items: center; min-height: 44px; }
}

/* Same table-cell link target as NFL: bare <a> inside <td> measured 19px tall. */
@media (hover: none) {
    td > a, td a:not([class]) {
        display: inline-flex; align-items: center; min-height: 44px;
    }
}


/* ── Touch type floor · 13px · 2026-08-23 ────────────────────────────────────
   SUPERSEDES the 12px floor in the blocks above (those covered only the sub-10px
   tier; these rules are later in source order with equal specificity, so 13px
   wins). Left in place rather than surgically removed — the earlier rules are now
   redundant, not contradictory.

   144 selectors on this site declared text below 13px; the smallest was
   9.0px. Raised to a flat 13px floor on TOUCH DEVICES ONLY —
   desktop density is completely untouched, which is the whole point of keying on
   (hover: none) rather than a width.

   Why 13px and not 12: moving an 11.5px chip to 12px is a 4% change nobody can
   see, so a floor that shallow is churn, not a fix. 13px makes a 10px label 30%
   larger — a real gain — while keeping numeric tables compact enough to stay
   tables. Body copy is separately at 16px.

   Why not 16px across the board: the 16px rule exists for readability AND to stop
   iOS zooming when a sub-16px input is focused. These pages contain ZERO text
   inputs (verified), so only readability applies, and 16px numerals would break
   dense stat tables for no safety benefit.

   SVG diagram text is excluded throughout — it scales with its viewBox, so its px
   values are not literal screen pixels. */
@media (hover: none) {
.tm-logo-fallback,
.mk-pick-sm .mk-book,
.gp-rec-yr,
.tp-ord,
.conf-tag,
.fld-series,
.fld-leg-label,
.gp-mkt-l,
.sr-neutral,
.fr-of,
.plr-rank-lbl,
.h2h-gap,
.gp-basis,
.mk-h,
.mk-foot,
.slip-leg-m,
.slip-note,
.gp-best .mk-h,
.ss-h,
.ss-note,
.gp-conf,
.mu-hl-label,
.hero-stat .label,
a.team-link-chip .sub,
table.stack tbody td::before,
.sb-unit,
.divtag,
.marquee-dot,
.mu-date,
.rail-h,
.gp-when,
.gp-strip-l,
.gp-note,
.tm-rank,
.t10-sub,
.sr-dow,
.pw-sub,
.pw-foot,
.td-team,
.gp-best-h,
.bn-side,
.bn-book,
.bn-book-sm,
.fld2-role,
.fld2-vs,
.fr-label,
.plr-pos,
.h2h-phase,
.basis-tag,
.gp-best-key,
.gp-best-key .mk-book,
.conf-flag,
thead th,
.mu-venue,
.sc-line,
.pc-opp,
.fld-chip,
.fld-leg-ends,
.hm-go,
.dc-list dd,
.gp-best-note,
.plr-stat,
.slip-clear,
.slip-warn,
.slip-k,
.mk-book,
.mk-absent .mk-none,
.tp-key,
.chip,
.site-tagline,
.mu-score,
.mu-back,
.mu-edge-label,
.sc-at,
.pickstrip-rec,
.gp-sub,
.gp-ou,
.gp-edge span,
.gp-sit,
.gp-more,
.fld-def-name,
.fld-off-name,
.sc-when .sc-time,
.sc-venue,
.t10-val,
.sr-at,
.sr-margin,
.sr-go,
.pw-rank,
.pw-note,
.gp-wp-end,
.gp-wp-none,
.bn-price,
.plr-none,
.h2h-verdict,
.basis-warn,
.mk-pick-sm,
.mk-pick-sm .mk-sel,
.mk-pick-sm .mk-price,
.gp-rec,
.mu-rec-note,
.tp-raw,
.badge-gold,
.lean-badge,
.gp-strip,
.window-btn,
.filter-btn,
.fld-series-since,
.fld-coach,
.fld-flip,
.pl-chip,
.sr-when,
.pw-val,
.bn-inline,
.fld2-coaches,
.h2h-line,
.basis-detail,
.mk-sel,
.mk-price,
.slip-empty,
.ss-btn,
.mu-detail-sub,
.pc-line,
.panels-h,
footer,
.hm-more,
.sb-facts span,
.t10-rank,
.t10-name,
.td-name,
.plr-team,
.plr-rank,
.slip-t,
.slip-leg-p,
.tp-label,
tbody td,
.mu-proj,
.sc-row,
a.team-link-chip,
.gp-mkt-col .tnum,
.pw-row .tm-name,
.plr-name,
.tlc-name,
.slip-leg-l,
.mu-records { font-size: 13px; }
}

/* The last sub-13px text on every page was the footer's <small> elements —
   copyright, the "not affiliated with" disclaimer, and the data-source credits.
   No CSS rule declares their size, so a selector-based floor could not see them:
   it is the browser's own `small` shrink (0.8125em) applied to inherited 13.33px
   = 10.83px. These are legal and attribution lines; they should be readable. */
@media (hover: none) {
    small, small a, small strong { font-size: 13px; }
}

/* The unit-rank block now states which season it describes. It is a caption, not
   a warning: the ranks are correct, they simply describe the last completed
   season because 2026 has played no games. Muted, above the list, always visible
   — not a tooltip, because the whole point is that a reader scrolling to the
   field diagram never saw the preseason banner in the card above it. */
.fld2-ranks-season {
    font-size: 13px; font-weight: 600; color: var(--text3);
    letter-spacing: 0.02em; margin: 8px 2px 4px; line-height: 1.4;
}

/* Team-total slot on the best-number row: the model's projection where a price
   would sit. Deliberately NOT a button — no price exists, so nothing here may
   enter the slip or read as a quote. Dashed border = same "absent market"
   language the slot already spoke; the numbers just stop being missing. */
.mk-proj-rows { display: flex; flex-direction: column; gap: 3px; }
.mk-proj {
    display: inline-flex; align-items: baseline; justify-content: space-between;
    gap: 8px; padding: 3px 8px; border: 1px dashed var(--line);
    border-radius: 7px; font-size: 13px;
}
.mk-proj .mk-sel { font-weight: 700; color: var(--text2); }
.mk-proj .mk-price { color: var(--text); }
.mk-proj-tag {
    font-size: 13px; font-weight: 700; letter-spacing: 0.05em;
    text-transform: uppercase; color: var(--text3); margin-left: 5px;
}

/* Empty opening/next-up slate — see home/index.html. */
.slate-empty { padding: 14px 4px; font-size: 13px; list-style: none; }

/* ══════════════════════════════════════════════════════════════════════════
   BOARD: THE LEDGER AND THE GAP BAR                     added 2026-08-29
   Scoped to /matchup/ on purpose. The shared tokens above are the contract
   NCAAF adopts from BALLKNOWME_DESIGN_SPEC.md and every other page reads them,
   so this pass adds classes and changes none of them. BOARD_REDESIGN_SPEC.md
   carries what each remaining page needs before the rest follows.

   TWO RULES THIS SECTION KEEPS, both from the shared spec:
     · Amber is WAYFINDING, not a data series. It marks the wide band — rare by
       construction, WIDE_GAP_PTS is p90 of the measured distribution — and
       nothing else here. The gap bar itself is drawn in the ink ramp.
     · Green and red are OUTCOME colours. A disagreement with the market is not
       an outcome, so neither appears in this section.
   ────────────────────────────────────────────────────────────────────────── */

/* ── the gap bar: book at the centre, our number beside it, one scale ── */
.gb { position: relative; display: block; height: 12px; }
.gb-rule { position: absolute; left: 0; right: 0; top: 6px; height: 1px; background: var(--line); }
.gb-span { position: absolute; top: 4px; height: 5px; border-radius: 3px; background: var(--panel3); }
.gb-book { position: absolute; top: 2px; width: 1px; height: 9px; background: var(--text3); }
.gb-ours { position: absolute; top: 0; width: 3px; height: 13px; border-radius: 2px;
           background: var(--text2); transform: translateX(-1px); }
.gb-wide .gb-span { background: var(--acc-dim); }
.gb-wide .gb-ours { background: var(--acc); }
.gb-none .gb-rule { background: var(--line-soft); }

/* ── the ledger rail ── */
.lg-head { padding: 2px 2px 7px; }
.lg-title { font-size: 10px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
            color: var(--text3); }
.lg-sort { color: var(--text3); font-weight: 600; letter-spacing: 0.04em; text-transform: none; }
.lg-tally { display: grid; grid-template-columns: repeat(4, 1fr); gap: 3px; margin-top: 6px; }
.lg-t { background: var(--bg2); border-radius: 6px; padding: 5px 2px 4px; text-align: center;
        font-size: 8.5px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
        color: var(--text3); }
.lg-t b { display: block; font-size: 14px; font-weight: 800; letter-spacing: -0.01em;
          color: var(--text); margin-bottom: 1px; }
.lg-t.on b { color: var(--text); }

.lg-grp { padding: 11px 2px 4px; font-size: 10px; font-weight: 700; letter-spacing: 0.13em;
          text-transform: uppercase; color: var(--text3); }
.lg-empty { padding: 8px 10px; background: var(--bg2); border-radius: 8px;
            font-size: 10.5px; line-height: 1.5; color: var(--text3); }

.lg-row {
    display: grid; grid-template-columns: minmax(0, 1fr) 40px;
    grid-template-areas: "m d" "s d" "k d" "b b";
    column-gap: 7px; align-items: center;
    background: var(--panel2); border: 1px solid var(--line); border-radius: 8px;
    padding: 6px 9px 7px; text-decoration: none; transition: border-color 0.12s;
    border-left: 3px solid rgb(var(--away-rgb, 36, 42, 53));
    border-right: 3px solid rgb(var(--home-rgb, 36, 42, 53));
}
.lg-row:hover { border-top-color: var(--acc-line); border-bottom-color: var(--acc-line); }
.lg-m { grid-area: m; display: flex; align-items: center; gap: 5px; min-width: 0;
        color: var(--text); font-weight: 700; font-size: 12.5px; }
.lg-s { grid-area: s; font-size: 12px; font-weight: 600; color: var(--text);
        font-variant-numeric: tabular-nums; margin-top: 1px;
        white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lg-d { grid-area: d; text-align: right; font-size: 15px; font-weight: 800;
        font-variant-numeric: tabular-nums; letter-spacing: -0.02em; color: var(--text2); }
.lg-b { grid-area: b; margin-top: 6px; }
.lg-wide .lg-d { color: var(--text); }
.lg-s-mut { color: var(--text3); font-weight: 400; }
.lg-foot { margin: 10px 2px 0; font-size: 11px; line-height: 1.55; color: var(--text3); }

/* ── the gap, full width, in a panel head ── */
.gp-gap {
    display: grid; grid-template-columns: auto minmax(120px, 1fr) auto;
    gap: 14px; align-items: center;
    margin: 8px 0 0; padding: 9px 12px;
    background: var(--panel2); border: 1px solid var(--line); border-radius: 11px;
}
.gp-gap-end { display: flex; flex-direction: column; gap: 2px; white-space: nowrap; }
.gp-gap-end b { font-size: 13px; font-weight: 800; color: var(--text2); }
.gp-gap-ours { text-align: right; }
.gp-gap-ours b { color: var(--text); }
.gp-gap-axis { position: relative; padding-bottom: 15px; }
.gp-gap-mid { position: absolute; left: 0; right: 0; bottom: 0; text-align: center;
              font-size: 10px; font-weight: 700; letter-spacing: 0.06em;
              text-transform: uppercase; color: var(--text3); }
.gp-gap-wide .gp-gap-ours b, .gp-gap-wide .gp-gap-mid { color: var(--text); }
@media (max-width: 640px) {
    .gp-gap { grid-template-columns: 1fr 1fr; gap: 8px; }
    .gp-gap-axis { grid-column: 1 / -1; order: 3; }
}

/* four columns once the gap has its own — .gp-mkt is shared with the deep dive,
   which has no gap block, so the modifier carries the change and the deep dive
   keeps its three */
.gp-mkt-4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 900px) { .gp-mkt-4 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px) { .gp-mkt-4 { grid-template-columns: 1fr; } }

/* ── panel head: our number is the headline, the score steps down ── */
.gp-verdict { font-size: 1.45rem; font-weight: 800; color: var(--text);
              line-height: 1.1; letter-spacing: -0.02em; }
.gp-under { margin-top: 3px; color: var(--text3); }
.gp-under .tnum { color: var(--text2); }

/* ── deep dive: the same hierarchy fix the board panel got ──  2026-08-29
   .mu-headline was four 1.7rem tiles answering four questions at one volume, so
   "which side, by how much" sat at the weight of "proj score (away–home)". The
   spread leads now; the other three support. mu- classes are matchup/detail.html
   only, so nothing else moves. */
.mu-headline { grid-template-columns: 1.6fr 1fr 1fr 1fr; }
.mu-hl-num { font-size: 1.3rem; }
.mu-hl-lead { text-align: left; }
.mu-hl-lead .mu-hl-num { font-size: 2.1rem; letter-spacing: -0.02em; }
@media (max-width: 640px) {
    .mu-headline { grid-template-columns: repeat(2, 1fr); }
    .mu-hl-lead { grid-column: 1 / -1; }
}

/* ══════════════════════════════════════════════════════════════════════════
   SEPARATION AND SCALE — the half of the redesign that was missing
                                                        added 2026-08-29 (2)
   The first pass changed WHAT the board says and not HOW IT LOOKS, and the
   result was a page carrying new information in the same skin. Measured after
   the fact:

     · a game panel held SIX bordered boxes before, and the new .gp-gap block
       made it SEVEN. The diagnosis was box-in-box and the fix added a box.
     · the biggest number in a panel head went 1.5rem -> 1.45rem. The CONTENT
       changed (projected score -> our number) but the SHAPE of the page did
       not, so nothing read as different.
     · not one label class was touched, though the commit said otherwise.

   The mockup's character came from exactly the part that was skipped: depth
   carried by surface lightness ALONE, and a real display size. Both below.
   Nothing here changes a token — only which elements draw a line.
   ────────────────────────────────────────────────────────────────────────── */

/* ── 1 · depth is lightness, not lines ──
   Every inner block already sits on --panel2 over the panel's --panel ground.
   It was ALSO drawing a --line border, so nesting was signalled twice and read
   as "another box" each time. The border goes; the step stays and does the work.
   The panel's own outer edge is kept — that one separates game from game, which
   is the one place on this page a line is load-bearing. */
.gp-mkt, .gp-gap, .gp-best, .gp-strip, .gp-edge, .mu-edge, .mu-hl-item { border-color: transparent; }
.gp-mkt, .gp-gap { background: var(--panel2); }
/* ...and one step further in, where a block nests inside a block, so the two
   levels stay distinguishable without either drawing an edge */
.gp-best .mk-grp, .gp-gap .gb { background: transparent; }
.mk-pick { border-color: transparent; background: var(--panel3); }

/* Ledger rows lose their box too. The left/right team colours stay — that is
   identity, not separation, and it is the part of this design that was already
   working. Hover lifts by lightness for the same reason. */
.lg-row { border-top-color: transparent; border-bottom-color: transparent; }
.lg-row:hover { background: var(--panel3); border-top-color: transparent;
                border-bottom-color: transparent; }

/* ── 2 · a real display size ──
   1.45rem next to 13px is not a hierarchy, it is two similar numbers. The
   verdict is the one thing on the panel a reader came for, so it gets the
   ratio the mockup had (~3x the supporting line) and the rest holds still. */
.gp-verdict { font-size: 2.35rem; line-height: 1; letter-spacing: -0.03em; }
.gp-under { font-size: 11px; letter-spacing: 0.01em; }
.mu-hl-lead .mu-hl-num { font-size: 2.6rem; line-height: 1; }
@media (max-width: 900px) { .gp-verdict { font-size: 1.9rem; } }

/* ── 3 · the label tier, which the first pass claimed and did not do ──
   These were 800-weight at 9.5px — the same weight as the values they label,
   holding their own against numbers three times their size. Weight is what was
   wrong, not colour: they were already --text3. */
.gp-mkt-l, .mu-hl-label, .mk-h, .gp-strip-l, .gp-best-h, .mu-edge-label {
    font-weight: 600; letter-spacing: 0.13em;
}
.gp-best-h { font-size: 9.5px; text-transform: uppercase; color: var(--text3); }

/* ── top picks: one strip per market, each with its record ──  2026-08-29 (3)
   Ported from the MLB board's tabbed "Top plays" module. The record chip is the
   point of the component, not an afterthought: two of these four markets do not
   beat the price, and .tp-rec.under says so in the same type as the rest. Red is
   an OUTCOME colour here and that is exactly what a losing record is, so this is
   the one place in the board pass where --neg is correct. */
.tp-tabs { display: flex; gap: 4px; flex-wrap: wrap; margin: 4px 0 10px; }
.tp-tab { display: inline-flex; align-items: center; gap: 6px; min-height: 30px;
          padding: 5px 12px; border: 0; border-radius: 999px; cursor: pointer;
          background: var(--panel2); color: var(--text2);
          font: 700 11.5px var(--font); letter-spacing: 0.04em; }
.tp-tab b { font-weight: 800; color: var(--text3); font-variant-numeric: tabular-nums; }
.tp-tab:hover { background: var(--panel3); color: var(--text); }
.tp-tab.on { background: var(--acc); color: #12151c; }
.tp-tab.on b { color: rgba(18, 21, 28, 0.65); }
.tp-cat { display: none; }
.tp-cat.on { display: block; }
.tp-h { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin-bottom: 8px; }
.tp-t { font-size: 13px; font-weight: 800; color: var(--text); letter-spacing: -0.01em; }
.tp-sub { font-size: 12px; color: var(--text3); flex: 1 1 320px; min-width: 0; }
.tp-rec { font: 700 11px var(--font); font-variant-numeric: tabular-nums;
          padding: 3px 9px; border-radius: 999px;
          background: var(--pos-soft); color: var(--pos); white-space: nowrap; }
.tp-rec.under { background: var(--neg-soft); color: var(--neg); }
.tp-rec.none  { background: var(--panel2); color: var(--text3); font-weight: 600; }
@media (max-width: 640px) { .tp-sub { flex-basis: 100%; } }
/* The ledger's widest group is a caution, not a highlight — ncaaf_edge_audit.py
   puts that bucket at 46.8% ATS. Muted, never amber. */
.lg-caution { color: var(--text3); font-weight: 600; text-transform: none; letter-spacing: 0.02em; }

/* ── the ledger needs the width it was designed at ──  2026-08-29 (4)
   The rail was rebuilt as a ledger — matchup, our side, a gap bar and a gap
   number — and then left in the 250px track the old two-line slate cards used.
   At that width the bar is ~70px and the whole component reads as the previous
   rail with a dash added, which is why the board did not look like the mockup it
   was built from. The mockup's rail is 352px — set where the grid is defined
   (.bk-board, top of file). Everything below is the same component at the
   size it was drawn for. */
.bk-rail .lg-row { padding: 7px 11px 8px; }
.lg-row { grid-template-columns: minmax(0, 1fr) 48px; column-gap: 10px; }
.lg-d { font-size: 16px; }
.lg-m { font-size: 13px; }
.lg-b { margin-top: 7px; }
.gb { height: 14px; }
.gb-rule { top: 7px; } .gb-span { top: 5px; height: 6px; }
.gb-book { top: 2px; height: 11px; } .gb-ours { top: 1px; height: 13px; }

/* ── the week at a glance, across the top ──
   Direction 2's status strip. It answers "what is even on this slate" before the
   eye has to search the rail for it, and it is the one place the model's own
   state (preseason vs live ratings) is stated as a fact rather than a footnote. */
.bk-strip { display: flex; flex-wrap: wrap; gap: 1px; margin: 0 auto 12px; max-width: 1440px;
            background: var(--line-soft); border-radius: 10px; overflow: hidden; }
.bk-st { flex: 1 1 110px; background: var(--panel); padding: 9px 14px 8px; }
.bk-st .k { font: 700 10px var(--font); letter-spacing: 0.13em; text-transform: uppercase;
            color: var(--text3); }
.bk-st .v { font: 800 18px var(--font); font-variant-numeric: tabular-nums;
            letter-spacing: -0.02em; color: var(--text); margin-top: 3px; line-height: 1.05; }
.bk-st.q .v { color: var(--text3); }
.bk-st.state .v { font-size: 11.5px; font-weight: 700; color: var(--text2); letter-spacing: 0.04em; }
@media (max-width: 640px) { .bk-st { flex-basis: 45%; } .bk-st .v { font-size: 15px; } }

/* ═══ PANEL DIRECTION 4 — team colors own it ═══  Will picked it 2026-08-29.
   The clash masthead + gold plate + one statline + the flat books table.
   The old meter/axis/compare/best-number blocks no longer render on the
   board; their CSS stays for the deep dive where some classes are shared. */
.gp4 .gp-clash { display: grid; grid-template-columns: 1fr 1fr; position: relative; min-height: 96px; }
.gp-cside { padding: 16px 22px 14px; display: flex; align-items: center; gap: 13px; }
.gp-cid { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.gp-cside .gp-crest { flex: none; filter: drop-shadow(0 1px 3px rgba(0,0,0,.55)); }
.gp-cside-away { background: linear-gradient(100deg, rgba(var(--away-rgb, 46, 54, 68), 0.94) 74%, rgba(var(--away-rgb, 46, 54, 68), 0) 100%); }
.gp-cside-home { background: linear-gradient(280deg, rgba(var(--home-rgb, 46, 54, 68), 0.94) 74%, rgba(var(--home-rgb, 46, 54, 68), 0) 100%); text-align: right; justify-content: flex-end; }
.gp-cside-home .gp-cid { align-items: flex-end; }
/*  THE ★ IS GOLD (Will, 2026-09-04: "the stars need to, well, be gold"). It was
    #fff, which read as punctuation next to the number rather than as a mark.
    Gold is this site's wayfinding accent and "the side our number implies" is
    exactly wayfinding — it tells the reader what our projection MEANS, which is
    the job the legend gives it.

    IT DOES NOT COLLIDE WITH THE GOLD PRICE. The two live on different elements in
    the cell: the best-available price is gold TEXT on .mk-price (.bkg-best), the
    star is a glyph in front of the line. A cell can carry both — best price AND
    our side — and that pairing is the one a reader most wants to spot. Green is
    still forbidden here: it is reserved for a settled OUTCOME, and this mark is
    explicitly a read, not a result (BKM-DESIGN-SYSTEM-SPEC.md). */
.mk-star { color: var(--acc); font-size: 11px; margin-right: 1px; }
.gp-ab { font: 800 21px/1.05 var(--font); letter-spacing: 0.01em; text-transform: uppercase; color: #fff; text-decoration: none; text-shadow: 0 1px 3px rgba(0,0,0,.5); }
.gp-ab:hover { color: var(--acc); }
.gp-cmeta { font: 700 12px var(--font); color: rgba(255,255,255,.88); text-shadow: 0 1px 2px rgba(0,0,0,.5); }
.gp-plate { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); z-index: 2;
    background: #000; border: 2px solid var(--acc); border-radius: 5px; padding: 8px 22px;
    text-align: center; box-shadow: 0 0 30px rgba(255, 176, 32, 0.3); }
.gp-plate-v { font: 800 27px/1 var(--font); letter-spacing: -0.02em; color: var(--acc); white-space: nowrap; }
.gp-plate small { display: block; font: 700 10.5px var(--font); letter-spacing: 0.06em; text-transform: uppercase; color: #fff; margin-top: 4px; }
.gp-statline { display: flex; flex-wrap: wrap; background: #000; border-top: 1px solid var(--line); }
.gps { flex: 1 1 170px; padding: 9px 18px 10px; border-right: 1px solid var(--line); }
.gps:last-child { border-right: 0; }
.gps b { display: block; font: 800 15px var(--font); margin-top: 3px; }
.gps b em { font-style: normal; color: var(--acc); }
.gp-nomkt { padding: 14px 22px; font: 500 13px var(--font); color: var(--text2); background: var(--bg2); }
.gp-footline { display: flex; flex-wrap: wrap; gap: 18px; align-items: baseline; padding: 10px 20px 13px; font: 600 12px var(--font); color: var(--text3); }
.gp-footline b { color: var(--text); }
.gp-footline .gold { color: var(--acc); }
.gp-footline .gp-more { margin-top: 0; margin-left: auto; }
/* the books table inside a panel goes FLAT — text cells, gold best, team-color
   column bars; the cells stay real .mk-pick buttons for the slip */
.gp4 .bkgrid th { background: #12161d; border-bottom: 2px solid var(--acc); }
.gp4 .bkgrid .mk-pick { background: none; border: none; border-radius: 4px; padding: 3px 6px; }
.gp4 .bkgrid .mk-pick:hover { background: var(--panel3); }
.gp4 .bkgrid th:nth-child(2), .gp4 .bkgrid td:nth-child(2),
.gp4 .bkgrid th:nth-child(6), .gp4 .bkgrid td:nth-child(6) { box-shadow: inset 3px 0 0 rgb(var(--away-rgb, 70, 82, 100)); }
.gp4 .bkgrid th:nth-child(3), .gp4 .bkgrid td:nth-child(3),
.gp4 .bkgrid th:nth-child(7), .gp4 .bkgrid td:nth-child(7) { box-shadow: inset 3px 0 0 rgb(var(--home-rgb, 70, 82, 100)); }
.gp4 .table-wrap { margin: 0; }
@media (max-width: 700px) {
    .gp4 .gp-clash { display: block; }
    .gp-cside-home { text-align: left; align-items: flex-start; }
    .gp-plate { position: static; transform: none; margin: 10px 16px; display: inline-block; }
}

/* ── public vs books: tickets split bar + money divergence flag ── */
.gp-public { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 26px;
    padding: 8px 20px 9px; background: var(--bg2); border-top: 1px solid var(--line); }
.gp-public-h { font: 700 10.5px var(--font); letter-spacing: 0.08em; text-transform: uppercase; color: var(--text3); }
.gp-public-h em { display: block; font: 500 10px var(--font); letter-spacing: 0.02em; text-transform: none; font-style: normal; }
.gpub { display: inline-flex; align-items: center; gap: 8px; }
.gpub-k { font: 700 10.5px var(--font); letter-spacing: 0.07em; text-transform: uppercase; color: var(--text3); }
.gpub-bar { width: 62px; height: 8px; border-radius: 4px; overflow: hidden; display: flex; flex: none; }
.gpub-bar .a { background: rgb(var(--away-rgb, 122, 136, 158)); }
.gpub-bar .h { flex: 1; background: rgb(var(--home-rgb, 62, 72, 90)); }
.gpub-bar.neut .a { background: #96a6bb; }
.gpub-bar.neut .h { background: #46536a; }
.gpub-v { font: 600 12px var(--font); color: var(--text2); }
.gpub-v b { color: var(--text); font-weight: 800; }
.gpub-flip { color: var(--text); }

/* ── result chips: a graded game wears its score and W/L per market ── */
.gp-resband { display: flex; flex-wrap: wrap; align-items: center; gap: 12px;
    padding: 8px 20px; background: #000; border-top: 1px solid var(--line); }
.gp-res-tag { font: 800 10.5px var(--font); letter-spacing: 0.1em; text-transform: uppercase;
    background: #fff; color: #000; padding: 2px 8px; border-radius: 3px; }
.gp-resband > b { font: 800 16px var(--font); }
.gp-res-chip { font: 800 11px var(--font); letter-spacing: 0.05em; text-transform: uppercase;
    padding: 3px 9px; border-radius: 4px; }
.gp-res-chip.win  { background: var(--pos-soft); color: var(--pos); }
.gp-res-chip.loss { background: var(--neg-soft); color: var(--neg); }
.gp-res-chip.push { background: var(--panel3); color: var(--text2); }
.gp-res-note { font: 500 11.5px var(--font); color: var(--text3); margin-left: auto; }

/* rail result chip: W/L + final score ahead of the pick line */
.lg-res { font-weight: 800; font-variant-numeric: tabular-nums; }
.lg-res.win { color: var(--pos); }
.lg-res.loss { color: var(--neg); }
.lg-res.push { color: var(--text2); }

/* the unpriced mass: one line, off the rail, into the schedule view */
.lg-unpriced { display: block; margin-top: 10px; padding: 9px 11px; background: var(--bg2);
    border-radius: 8px; font: 600 12px var(--font); color: var(--text2); text-decoration: none; }
.lg-unpriced:hover { color: var(--text); }
.bk-st-sub { font: 600 12px var(--font); color: var(--text3); letter-spacing: 0; }
.lg-tally { grid-template-columns: repeat(3, 1fr); }

/* a finished game's strip card grades in place — result where the price was */
.pc-res { font-size: 12px; font-weight: 700; margin-top: 6px; padding-top: 5px;
          border-top: 1px solid var(--line-soft); color: var(--text); font-variant-numeric: tabular-nums; }

.sc-final { display: block; font: 700 12px var(--font); margin-top: 2px; }

/* ── LIVE: a game while it is being played (services/live.py) ─────────────────
   Deliberately NOT gold. Gold on this site means ACTIONABLE (the two-ink pass,
   2026-08-29: "less gold; gold = actionable only"), and a live score is a fact
   about the world, not something to act on. It gets its own accent and a pulse
   so the eye finds the game in play without the palette claiming it is a bet. */
.lg-res.live { color: var(--live); }
.lg-live-q { font: 600 11px var(--font); color: var(--text3); }

.gp-liveband { border-left: 3px solid var(--live); }
.gp-live-tag { background: var(--live-soft) !important; color: var(--live) !important; }
.gp-live-tag::before { content: ""; display: inline-block; width: 6px; height: 6px;
    margin-right: 5px; border-radius: 50%; background: var(--live);
    animation: bkm-live-pulse 2s ease-in-out infinite; vertical-align: middle; }
.gp-res-chip.live { background: var(--live-soft); color: var(--live);
    text-transform: none; letter-spacing: 0; }

/* per-quarter line, away over home, in the band */
.gp-qline { display: inline-flex; align-items: center; gap: 3px;
    font: 600 11px var(--font); color: var(--text2); }
.gp-qline i { font-style: normal; min-width: 16px; text-align: center;
    padding: 1px 3px; background: var(--panel3); border-radius: 3px; }
.gp-qline em { font-style: normal; color: var(--text3); margin: 0 3px; }

/* all-games table: the kickoff cell becomes a scoreboard */
.sc-time.sc-live { color: var(--live); font-weight: 700; }

/* pick card: the scoreboard replaces the price once a game has kicked */
.pc-live .lg-res.live { color: var(--live); }
.pc-live .tnum { color: var(--text3); font-size: 11px; }

@keyframes bkm-live-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } }
@media (prefers-reduced-motion: reduce) {
    .gp-live-tag::before { animation: none; }
}
.lg-live-status { margin-left: 8px; font: 700 10.5px var(--font); letter-spacing: 0.04em;
    text-transform: uppercase; color: var(--live); }

/* ── OUR SIDE — which side our number implies, per market ────────────────────
   Sits directly under the clash so it is the first thing read after the two
   numbers that need reconciling. NOT gold: gold means actionable on this site
   and this is orientation, not a bet. The value is the loud part; the market
   label and the caveat are quiet. */
.gp-sides { display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px 18px;
    padding: 10px 16px; background: var(--panel2); border-bottom: 1px solid var(--line); }
.gp-sides-h { font: 800 10.5px var(--font); letter-spacing: 0.1em; text-transform: uppercase;
    color: var(--text3); }
.gp-side { display: inline-flex; align-items: baseline; gap: 6px; }
.gp-side i { font-style: normal; font: 600 11px var(--font); color: var(--text3);
    text-transform: uppercase; letter-spacing: 0.04em; }
.gp-side b { font: 800 15px var(--font); color: var(--text); }
/* logged/moved markers: quiet — orientation, not a verdict. `moved` is the live
   read disagreeing with the frozen pick, shown so the panel never prints a
   frozen sentence beside a moving number without saying so. */
.gp-side-tag { font-style: normal; font: 600 9.5px var(--font); color: var(--text3);
    text-transform: uppercase; letter-spacing: 0.08em; border: 1px solid var(--line);
    border-radius: 3px; padding: 1px 4px; }
i.gp-side-moved { font: 500 11px var(--font); color: var(--text3); font-style: italic;
    text-transform: none; letter-spacing: 0; }
.gp-sides-note { margin-left: auto; font: 500 11.5px var(--font); color: var(--text3); }
@media (max-width: 720px) {
    .gp-sides-note { margin-left: 0; flex-basis: 100%; }
    .gp-side b { font-size: 14px; }
}

/* rail: the side our number implies, under our number itself */
.lg-k { grid-area: k; display: flex; align-items: baseline; gap: 6px; margin-top: 2px;
    font: 700 11.5px var(--font); font-variant-numeric: tabular-nums; color: var(--text2);
    white-space: nowrap; overflow: hidden; }
.lg-k i { font-style: normal; font-weight: 600; font-size: 9.5px; letter-spacing: 0.09em;
    text-transform: uppercase; color: var(--text3); flex: none; }
.lg-k b { font-weight: 700; }
.lg-k b + b::before { content: "·"; color: var(--text3); margin: 0 5px; font-weight: 400; }

/* all-games table: three sides stacked, win% muted beneath */
.tbl-sides { display: flex; flex-direction: column; gap: 1px; }
.tbl-sides b { font: 700 12.5px var(--font); color: var(--text); }
.tbl-sides i { font-style: normal; font: 600 11px var(--font); color: var(--text3); }

/* ══ THE MATCHUP PAGE, rebuilt 2026-08-29 ═══════════════════════════════════
   Will: "look at how much space we are wasting. It is just all black with small
   font... this entire screen needs to be reimagined." He chose a blend of two
   directions — a Broadcast masthead over a Data-newspaper body — kept dark.

   THE SEPARATION STRATEGY IS HAIRLINES AND SURFACE STEPS, NOT BOXES. Fifteen
   bordered rounded panels on a near-black page is why nothing read as more
   important than anything else, and why each section spent ~34px of chrome
   saying nothing. Everything below is scoped to .mu2 so no other page moves. */

.mu2 { --mu2-hair: #1e242e; --mu2-rule: #2a3240; }
.mu2 .doss-main { max-width: none; }
/*  the page's own sections lose their card chrome here */
.mu2 .dashboard-section { background: none; border: 0; border-radius: 0;
    padding: 0; margin: 0 0 var(--sp-6, 36px); box-shadow: none; }

/* ── masthead: team colour full bleed, the call at display scale ───────────── */
.mu2-mast { position: relative; display: grid;
    grid-template-columns: minmax(0,1fr) auto minmax(0,1fr); align-items: stretch;
    background: linear-gradient(90deg,
        rgb(var(--away-rgb, 36,42,53)) 0%, rgba(var(--away-rgb, 36,42,53), .5) 30%,
        var(--bg) 47%, var(--bg) 53%,
        rgba(var(--home-rgb, 36,42,53), .5) 70%, rgb(var(--home-rgb, 36,42,53)) 100%);
    border-bottom: 1px solid var(--mu2-rule); margin-bottom: 0; }
.mu2-back { position: absolute; top: 10px; left: 14px; z-index: 2;
    font: 700 10px var(--font); letter-spacing: .14em; text-transform: uppercase;
    color: rgba(255,255,255,.72); text-decoration: none; }
.mu2-back:hover { color: #fff; }
.mu2-sd { padding: 30px 34px 24px; display: flex; flex-direction: column; justify-content: center; min-width: 0; }
.mu2-sd.r { align-items: flex-end; text-align: right; }
.mu2-sd h1 { margin: 0; font: 800 27px/1.06 var(--font); letter-spacing: -.025em; color: #fff; }
.mu2-rec { font: 600 12px var(--font); color: rgba(255,255,255,.76); margin-top: 3px; }
.mu2-call { background: rgba(0,0,0,.62); padding: 24px 46px; text-align: center;
    min-width: 380px; display: flex; flex-direction: column; justify-content: center; }
.mu2-call i { font-style: normal; font: 800 10px var(--font); letter-spacing: .2em;
    text-transform: uppercase; color: var(--acc); }
.mu2-call b { display: block; font: 800 clamp(34px, 4.2vw, 58px)/1 var(--font);
    letter-spacing: -.04em; margin: 8px 0 5px; font-variant-numeric: tabular-nums; }
.mu2-call s { text-decoration: none; font: 600 12px var(--font); color: var(--text3); }

/* ── ledger: hung label, hairlines, no boxes. Replaces the four headline tiles
      AND the four-column row that used to repeat them. ─────────────────────── */
.mu2-ledger { display: grid; grid-template-columns: 96px minmax(0,1fr); gap: 0 24px;
    padding: 16px 0; border-bottom: 1px solid var(--mu2-rule); }
.mu2-lab { font: 800 10px var(--font); letter-spacing: .16em; text-transform: uppercase;
    color: var(--text3); padding-top: 7px; }
.mu2-lgs { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 0 24px; }
.mu2-lg { border-left: 2px solid var(--mu2-rule); padding-left: 12px; }
.mu2-lg.on { border-left-color: var(--acc); }
.mu2-lg.wide { border-left-color: var(--neg); }
.mu2-lg i { font-style: normal; font: 700 10px var(--font); letter-spacing: .13em;
    text-transform: uppercase; color: var(--text3); }
.mu2-lg b { display: block; font: 800 23px/1.15 var(--font); letter-spacing: -.025em;
    margin: 3px 0 1px; font-variant-numeric: tabular-nums; }
.mu2-lg b s { text-decoration: none; font: 600 13px var(--font); color: var(--text3); }
.mu2-lg em { font-style: normal; font: 400 12px var(--font); color: var(--text2); }
.mu2-lg .mu2-why { margin: 4px 0 0; font: 400 12px/1.45 var(--font); color: var(--text2); max-width: 62ch; }  /* D36: why this side */

.mu2-meta { display: flex; flex-wrap: wrap; gap: 6px 22px; align-items: baseline;
    padding: 11px 0; border-bottom: 1px solid var(--mu2-hair);
    font: 500 12.5px var(--font); color: var(--text3); }
.mu2-meta b { color: var(--text2); font-weight: 700; }
.mu2-basis { font: 700 10px var(--font); letter-spacing: .1em; text-transform: uppercase;
    border: 1px solid var(--mu2-rule); padding: 2px 8px; cursor: help; }
.mu2-basis.pre { color: var(--acc); border-color: var(--acc-line); }
.mu2-note { font: 500 12.5px/1.6 var(--font); color: var(--text2);
    border-left: 2px solid var(--mu2-rule); padding: 8px 0 8px 12px; margin: 14px 0 0; max-width: 92ch; }

/* ── canvas: books spine + evidence rail, instead of stacked full-width slabs ─ */
/*  WAS a two-column grid, books beside a tall evidence rail. A grid row is as tall
    as its tallest item, so the moment the rail outran the books table — which it did
    by ~270px, five book rows against three stacked blocks — the short column left a
    void underneath it that nothing could fill. Balancing the two by hand would have
    held only until a game had six books or no splits.
    So: the books take the full width they want (seven columns), and the evidence
    runs as its own row beneath. Unequal heights can no longer produce a hole. */
.mu2-canvas { padding: 30px 0 0; }
.mu2-ev { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 20px 44px; align-items: start; margin-top: 34px;
    padding-top: 26px; border-top: 1px solid var(--mu2-rule); }
.mu2-ev .mu2-blk { margin-bottom: 0; }
.mu2 h3 { margin: 0 0 14px; font: 800 11px var(--font); letter-spacing: .18em;
    text-transform: uppercase; color: var(--text3); }
.mu2 h3 span { font: 500 12px var(--font); letter-spacing: .01em; text-transform: none;
    color: var(--text3); margin-left: 9px; }
.mu2-fine { font: 400 12px/1.6 var(--font); color: var(--text3); margin: 12px 0 0; max-width: 76ch; }
.mu2-fine strong { color: var(--text2); }
.mu2-blk { margin-bottom: 34px; }
.mu2-kv { display: flex; justify-content: space-between; align-items: baseline;
    padding: 7px 0; border-bottom: 1px solid var(--mu2-hair); }
.mu2-kv i { font-style: normal; font: 600 12px var(--font); color: var(--text3); }
.mu2-kv b { font: 700 15px var(--font); font-variant-numeric: tabular-nums; }
.mu2-kv b.mut { color: var(--text2); font-weight: 500; }
.mu2-kv b s { text-decoration: none; color: var(--text3); font-size: 13px; font-weight: 500; }
.mu2-bar { display: grid; grid-template-columns: 62px 1fr 46px; align-items: center; gap: 10px;
    padding: 6px 0; border-bottom: 1px solid var(--mu2-hair); }
.mu2-bar i { font-style: normal; font: 600 11.5px var(--font); color: var(--text3); }
.mu2-bar span { height: 9px; background: var(--panel3); }
.mu2-bar u { display: block; height: 100%; background: var(--text3); text-decoration: none; }
.mu2-bar u.bad { background: var(--neg); opacity: .82; }
.mu2-bar b { text-align: right; font: 700 12.5px var(--font); font-variant-numeric: tabular-nums; }
.mu2-bar b.bad { color: var(--neg); }

/* ── lower zone: three columns, not three slabs ───────────────────────────── */
.mu2-sec { border-top: 1px solid var(--mu2-rule); padding-top: 34px; margin-top: 34px; }
.mu2-low { display: grid; grid-template-columns: 1.25fr 1fr 1fr; gap: 44px; }
.mu2-pw { width: 100%; border-collapse: collapse; }
.mu2-pw thead th { font: 700 9.5px var(--font); letter-spacing: .11em; text-transform: uppercase;
    color: var(--text3); text-align: right; padding: 0 8px 6px; border-bottom: 1.5px solid var(--mu2-rule); }
.mu2-pw thead th:first-child { text-align: left; padding-left: 0; }
.mu2-pw tbody th { text-align: left; padding: 9px 8px 9px 0; border-bottom: 1px solid var(--mu2-hair);
    font: 700 13px var(--font); }
.mu2-pw tbody th a { color: var(--text); text-decoration: none; }
.mu2-pw tbody th a:hover { color: var(--acc); }
.mu2-pw tbody th s { display: block; text-decoration: none; font: 600 10px var(--font);
    letter-spacing: .1em; text-transform: uppercase; color: var(--text3); }
.mu2-pw td { text-align: right; padding: 9px 8px; border-bottom: 1px solid var(--mu2-hair);
    font: 600 14px var(--font); color: var(--text2); font-variant-numeric: tabular-nums; }
.mu2-pw td.rk { color: var(--text); font-weight: 800; }
.mu2-dl { display: flex; justify-content: space-between; align-items: baseline; gap: 14px;
    padding: 9px 0; border-bottom: 1px solid var(--mu2-hair); }
.mu2-dl i { font-style: normal; font: 600 11.5px var(--font); color: var(--text3); }
.mu2-dl b { font: 800 17px var(--font); font-variant-numeric: tabular-nums; white-space: nowrap; }
.mu2-dl b.sm { font: 600 12.5px var(--font); color: var(--text2); white-space: normal; text-align: right; }

/* ── the trenches, tightened. _field.html is untouched; only its scale moves.
      The two formations were ~640px tall each for what a 300px one conveys. ── */
.mu2 .fld-svg { max-height: 300px; }
.mu2 .fld2 { background: none; border: 0; border-radius: 0; padding: 0; }
/*  gap:0 collapsed the COLUMN gap too, so '#25 of 265' ran straight into
    'Pass offense'. Rows tighten; the columns keep their gutter. */
.mu2 .fld2-ranks { gap: 0 26px; }
.mu2 .fld2-rank { background: none; border: 0; border-bottom: 1px solid var(--mu2-hair);
    border-radius: 0; padding: 6px 0; }
.mu2 .fld-chip { border-radius: 0; }

/* ── THE BET SLIP HAS TO FIT (Will, 2026-08-29). It is position:fixed and only
      appears once a leg is on it, so it costs nothing empty — but on a layout
      that finally uses the full width it would sit on top of the evidence rail.
      When it goes live the page gives back exactly its width plus a gutter,
      rather than the slip covering a column. ─────────────────────────────── */
body.slip-live .mu2 .doss-main { padding-right: 360px; }
@media (max-width: 1180px) { body.slip-live .mu2 .doss-main { padding-right: 0; } }

/*  THE SHEET AND A FLOATING SLIP DO NOT BOTH FIT, MEASURED. The slip is
    position:fixed in the upper right by decision (2026-08-29), which was harmless
    while the board's main column stopped short of it. The sheet uses the full
    width and its ten columns need ~1419px; on a 1560px screen the give-back the
    deep dive uses leaves 1136px, so the table simply overflowed its own padding
    and the ticket still covered Total and Where it stands — the two columns a
    reader checks immediately after tapping a price.

    So: reserve the width only where the table actually still fits, and below that
    DOCK the ticket along the bottom instead of floating it over the sheet. The
    slip keeps its markup, its handler and its book switcher; only where it sits
    changes, and only on this view. A bottom dock is also the right answer on a
    phone, where a 330px panel pinned to the upper right never was.  */
@media (min-width: 1800px) {
  body.slip-live .bk-board-sheet .table-wrap.sheet,
  body.slip-live .bk-board-sheet .sh-live { padding-right: 360px; }
}
@media (max-width: 1799px) {
  .bk-board-sheet .doss-rail.live {
      position: fixed; top: auto; bottom: 0; right: 0; left: 0; width: auto;
      border-radius: 13px 13px 0 0; max-height: min(38dvh, 380px); overflow-y: auto;
      box-shadow: 0 -14px 44px rgba(0, 0, 0, 0.6); z-index: 60;
  }
  /*  the sheet ends above the dock rather than under it */
  body.slip-live .bk-board-sheet { padding-bottom: min(38dvh, 380px); }
  .bk-board-sheet .doss-rail.live .slip { border-radius: 13px 13px 0 0; }
}
/*  PHONES GET THE DOCK TOO, and need it most. The global rule below 900px puts
    .doss-rail back in the flow, which on a 90-row sheet means tapping a price
    scrolls nothing and shows nothing — the ticket is thousands of pixels down
    the page. `position: fixed` above is inside a max-width query that the 900px
    rule overrides by source order, so the sheet restates it here.  */
@media (max-width: 900px) {
  .bk-board-sheet .doss-rail.live { position: fixed; max-height: min(46dvh, 420px); }
  body.slip-live .bk-board-sheet { padding-bottom: calc(min(46dvh, 420px) + env(safe-area-inset-bottom, 0px)); }
  /*  the collapsed ticker was cutting a cell in half at 390px — narrower columns
      so two land whole and the third reads as "there is more this way"  */
  .sh-live.is-stuck .sh-live-g { grid-auto-columns: 176px; }
  .sh-live.is-stuck .sh-lc { padding: 5px 8px 6px 10px; }
  .sh-live.is-stuck .sh-lc-q { min-width: 44px; font-size: 9px; }
}

@media (max-width: 1180px) {
    .mu2-low { grid-template-columns: 1fr; gap: 30px; }
    .mu2-mast { grid-template-columns: 1fr; }
    .mu2-call { min-width: 0; padding: 20px 24px; }
    .mu2-sd.r { align-items: flex-start; text-align: left; }
    .mu2-ledger { grid-template-columns: 1fr; gap: 10px; }
}

/* ── THE TRENCHES, EDGE-FIRST (direction C, chosen 2026-08-29) ───────────────
   Will: "this section is so discombobulated... a lot of wasted space." It was
   two 640px formation diagrams floating centred in wide columns, each wrapped in
   its own ranks list, collision rows and chip row — eight mirrored blocks around
   four numbers. The verdict now leads and the ranks are the footnote.
   Broadcast recipe: the call at display scale, colour only on the team that wins. */
.tr-season { font: 500 12px var(--font); color: var(--text3); margin: 0 0 14px; }
.tr-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px 40px; }
.tr-st { border-left: 3px solid var(--line); padding: 12px 0 12px 16px; }
.tr-st.edge { border-left-color: var(--acc); }
.tr-h { display: flex; align-items: baseline; gap: 12px; }
.tr-h i { font-style: normal; font: 800 9.5px var(--font); letter-spacing: .15em;
    text-transform: uppercase; color: var(--text3); width: 74px; flex: none; }
.tr-h b { font: 800 23px/1.1 var(--font); letter-spacing: -.025em;
    font-variant-numeric: tabular-nums; }
.tr-st.edge .tr-h b { color: var(--text); }
.tr-st.even .tr-h b { color: var(--text3); }
.tr-h s { text-decoration: none; font: 500 11.5px var(--font); color: var(--text3); margin-left: auto; }
/*  ONE bar, split where the two ranks meet — the reader sees the mismatch, not two
    numbers to subtract. Neutral greys on purpose: green/red are OUTCOMES on this
    site (ui_audit.sh polices that) and a unit rank is not an outcome. */
.tr-b { height: 10px; background: var(--panel3); margin: 10px 0 6px; }
.tr-b span { display: block; height: 100%;
    background: linear-gradient(90deg, var(--text2), var(--panel3)); }
.tr-f { display: flex; justify-content: space-between; gap: 14px;
    font: 500 11.5px var(--font); color: var(--text3); }
.tr-f em { font-style: normal; }
.tr-f em.r { text-align: right; }
.tr-f strong { color: var(--text2); font-weight: 700; font-variant-numeric: tabular-nums; }
.tr-chips { display: flex; flex-wrap: wrap; align-items: baseline; gap: 7px 10px; margin-top: 18px; }
.tr-team { font: 700 11.5px var(--font); color: var(--text2); }
.tr-team:not(:first-child) { margin-left: 16px; }
@media (max-width: 900px) { .tr-grid { grid-template-columns: 1fr; } }

/* ── the evidence row: players, power and provenance share one row ──────────
   "Who carried each team" was a full-width section rendering a two-column list
   across 1500px, so every row had a canyon between the name and the rank; the
   power table was another full-width section with five short columns in the same
   space. Same kind of thing — evidence for the number at the top — so one row. */
.mu2-h5 { margin: 0 0 10px; font: 700 12px var(--font); color: var(--text2); }
.mu2-low { grid-template-columns: 1.5fr 1.1fr 1fr; }
.mu2-low .plr-grid { grid-template-columns: 1fr; gap: 0; }
.mu2-low .plr-col + .plr-col { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--mu2-rule); }
.mu2-low .plr-row { padding: 6px 0; border-bottom: 1px solid var(--mu2-hair); }
.mu2-low .plr-team { font: 700 11px var(--font); letter-spacing: .1em; text-transform: uppercase;
    color: var(--text3); margin-bottom: 4px; }
.mu2-notes { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 0 44px; margin-top: 26px; padding-top: 18px; border-top: 1px solid var(--mu2-hair); }
.mu2-notes .mu2-fine { margin-top: 0; }
@media (max-width: 1180px) { .mu2-low { grid-template-columns: 1fr; } }

/*  A final we never picked is not a result. It reads FINAL in the muted tier with
    the reason attached, so it can never be mistaken for a grade we forgot to run
    — or for a push, which until 2026-08-29 rendered identically. */
.lg-res.nopick { color: var(--text3); }
.pc-nopick { display: block; font: 500 10.5px var(--font); color: var(--text3);
    line-height: 1.3; margin-top: 2px; }

/* ══ THE RECORD, THREE BANDS (direction 2, chosen 2026-08-30) ════════════════
   Will: "this whole thing needs to be looked at. idk which is which." Measured:
   nine sections, eight tables, six sharing the shape `Game date | Matchup | our
   pick | a number | Logged at` — and "Top spreads" / "Top totals" were 99%
   identical copy. The page answers three questions; it now looks like it.
   Swiss recipe: the grid and hairlines do the separating, no boxes, extreme size
   contrast, and one oversized numeral per band as pure graphic form. */
.rec2 { --r2-hair: #1e242e; --r2-rule: #2a3240; }
.rec2 .dashboard-section { background: none; border: 0; padding: 0; }
.rb { padding: 34px 0; border-top: 1px solid var(--r2-rule); }
.rb:first-child { border-top: 0; padding-top: 0; }
.rb-h { display: flex; gap: 20px; align-items: flex-start; margin-bottom: 22px; }
/*  the band number as graphic form, tinted per band so the three are never
    confusable at a glance — the entire point of the redesign */
.rb-q { font: 800 52px/.82 var(--font); letter-spacing: -.05em; flex: none; width: 62px;
    color: var(--panel3); }
.rb1 .rb-q { color: #2b3a4a; }
.rb2 .rb-q { color: #5a4415; }
.rb3 .rb-q { color: #243a2c; }
.rb4 .rb-q, .rb-claim .rb-q { color: var(--panel3); font-size: 34px; }
.rb-h h2 { margin: 0; font: 800 21px var(--font); letter-spacing: -.02em; }
.rb-h p { margin: 3px 0 0; font: 500 12.5px var(--font); color: var(--text3); }
.rb-h .chip { margin-left: 8px; }
.rb-u { margin-left: auto; text-align: right; font: 800 30px var(--font);
    letter-spacing: -.03em; font-variant-numeric: tabular-nums; }
.rb-u.neg { color: var(--neg); } .rb-u.pos { color: var(--pos); }
.rb-u s { display: block; text-decoration: none; font: 600 11.5px var(--font); color: var(--text3); }
.rb-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 0 26px; margin-bottom: 22px; }
.rb-gc { padding: 11px 0; border-top: 2px solid #2b3a4a; }
.rb-gc i { font-style: normal; display: block; font: 600 10px var(--font);
    letter-spacing: .12em; text-transform: uppercase; color: var(--text3); }
.rb-gc b { display: block; font: 800 25px/1.1 var(--font); letter-spacing: -.03em;
    margin: 2px 0; font-variant-numeric: tabular-nums; }
.rb-gc em { font-style: normal; font: 700 12px var(--font); color: var(--text2); }
.rb-gc u { display: block; text-decoration: none; font: 500 11px var(--font); color: var(--text3); }
.rb-sub { margin: 30px 0 12px; font: 800 11px var(--font); letter-spacing: .18em;
    text-transform: uppercase; color: var(--text3); }
.rb-sub span { font: 500 12px var(--font); letter-spacing: .01em; text-transform: none; margin-left: 8px; }
.rb .table-wrap { background: none; border: 0; }
.rb-tbl { margin-bottom: 4px; }

/*  the live ledger's filter chips — the four Top-* sections, as a control */
.rl-filt { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 16px; }
.rl-filt button { font: 600 11.5px var(--font); color: var(--text3); background: none;
    border: 1px solid var(--r2-rule); padding: 5px 12px; cursor: pointer; border-radius: 0; }
.rl-filt button b { color: var(--text2); margin-left: 4px; }
.rl-filt button:hover { color: var(--text); border-color: var(--text3); }
.rl-filt button.on { color: var(--bg); background: var(--acc); border-color: var(--acc); font-weight: 800; }
.rl-filt button.on b { color: var(--bg); }
.rl-filt button.alt { margin-left: auto; }
.rl-mk { font: 700 10px var(--font); letter-spacing: .06em; text-transform: uppercase;
    padding: 2px 7px; border: 1px solid var(--r2-rule); white-space: nowrap; }
.rl-moneyline { color: #8fb4e0; border-color: #2c4258; }
.rl-spread    { color: #e0b78f; border-color: #584428; }
.rl-total     { color: #9fd9b0; border-color: #2a4a35; }
.rl-team_total{ color: #c9a8e0; border-color: #463055; }
.rb-exp { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 0 26px; }
.rb-ex { padding: 11px 0; border-top: 1px solid var(--r2-rule); }
.rb-ex i { font-style: normal; display: block; font: 700 12px var(--font); color: var(--text2); }
.rb-ex b { font: 800 20px var(--font); font-variant-numeric: tabular-nums; }
.rb-ex u { text-decoration: none; font: 500 11px var(--font); color: var(--text3); margin-left: 7px; }
.rb-ex s { display: block; text-decoration: none; font: 400 11.5px/1.5 var(--font);
    color: var(--text3); margin-top: 3px; }
.rb-claim { border-top: 1px solid var(--r2-rule); }
@media (max-width: 720px) { .rb-q { width: 40px; font-size: 34px; } .rb-u { margin-left: 0; text-align: left; } }

/*  when the public-vs-books snapshot was taken. Muted by default; amber when the
    market has had hours to move; the live hue when the capture happened after
    kickoff, because that is in-game money and not a preview at all. */
.gp-public-at { font: 600 10.5px var(--font); color: var(--text3); margin-left: auto;
    letter-spacing: .02em; }
.gp-public-at.stale { color: var(--acc); }
.gp-public-at.ingame { color: var(--live); }
.rb-priced { color: var(--text2) !important; }
.rb-priced b { color: var(--acc); font-weight: 700; }

/* ── home rail: the live scorecard ─────────────────────────────────────────
   Will, 2026-09-04: "a little mini schedule and then game updates, like a live
   little scorecard." It sits at the head of the rail because it is the only
   thing on the page that moves while you are reading it.

   Three states, one row: is-pre (a kickoff time, no numbers), is-live (cyan —
   the same --live hue the board and the matchup band use, never green, because
   a game in progress is not an outcome) and is-final. The poller swaps the
   class in place, so a game that kicks off during the visit lights up without
   a reload. */
/*  The counts line has three segments where the other rails have one word, so
    it runs tighter than the shared .pw-sub to stay on a single line at 280px. */
.lsc-rail .pw-sub { font-size: 10.5px; letter-spacing: 0.035em; margin-bottom: 7px; }
.lsc-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.lsc-game { border-radius: 8px; background: var(--panel2); border: 1px solid var(--line-soft);
    transition: border-color 0.12s, background 0.12s; }
.lsc-game:hover { background: var(--panel3); border-color: var(--acc-line); }
.lsc-hit { display: block; padding: 7px 9px 6px; text-decoration: none; color: inherit; }
.lsc-hit:focus-visible { outline: 2px solid var(--acc-line); outline-offset: -2px; border-radius: 8px; }
/*  The crest carries the school colour (--tm-rgb feeds the shared .tm-logo wash),
    so the row needs no second identity device in 280px. */
.lsc-side { display: grid; grid-template-columns: 20px minmax(0, 1fr) auto; gap: 7px;
    align-items: center; padding: 1px 0; }
.lsc-team { font-size: 12px; font-weight: 700; color: var(--text); line-height: 1.3;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lsc-game:hover .lsc-team { color: var(--acc); }
.lsc-pts { font-size: 14px; font-weight: 800; color: var(--text); min-width: 17px; text-align: right; }
/*  A game that has not kicked has no score to reserve room for — but the cells
    are still in the DOM, because that is where the poller puts the first score
    of a game that starts while the page is open. */
.lsc-game.is-pre .lsc-pts { display: none; }
.lsc-status { display: flex; align-items: center; gap: 6px; margin-top: 4px; padding-top: 4px;
    border-top: 1px solid var(--line-soft); }
.lsc-when { font-size: 10.5px; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase;
    color: var(--text3); }
.lsc-tag { font-size: 9.5px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
    color: var(--text3); margin-left: auto; }
.lsc-game.is-final .lsc-when { color: var(--text2); }
.lsc-game.is-live { border-color: rgba(53, 200, 232, 0.34); background: var(--panel2); }
.lsc-game.is-live .lsc-when { color: var(--live); }
.lsc-game.is-live .lsc-when::before {
    content: ""; display: inline-block; width: 6px; height: 6px; border-radius: 50%;
    background: var(--live); margin-right: 5px; vertical-align: middle;
    animation: bkm-live-pulse 2s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
    .lsc-game.is-live .lsc-when::before { animation: none; }
}
.lsc-empty { font-size: 11.5px; padding: 6px 2px; }

/*  ON A PHONE THE SCORECARD LEADS. The rail as a whole drops below the slate
    below 980px — reference belongs under the games — but a live scoreboard is
    not reference, and burying tonight's scores under twelve slate rows is the
    one place that rule gets the wrong answer. `display: contents` lets the
    rail's cards be ordered individually against the slate for that one card. */
@media (max-width: 980px) {
    .hm-rails { display: contents; }
    .hm-rails > * { order: 3; }
    .hm-slate { order: 2; }
    .lsc-rail { order: 1; }
}

/* ══════════════════════════════════════════════════════════════════════════
   THE SHEET — the week as one ruled table, grouped by game state
                                                          added 2026-09-05
   Replaces the ledger rail. See board/_sheet.html for why, and board.py's
   RELIABILITY_BANDS for the measurement the ink ramp is drawn from.

   FOUR COLOR JOBS, AND THEY MAY NOT BLEED. Each answers "it is that color
   because ___", and each is paired with a glyph or a word so nothing depends
   on hue alone:
     --live   a game in progress. Its own hue because a game being played is
              neither an outcome nor an action. Paired with a dot and the clock.
     team     the picked side, as a 3px edge. IDENTITY, not quality — the one
              use of team color BKM-DESIGN-SYSTEM-SPEC.md allows. Paired with
              the abbreviation in the same cell.
     --acc    the best available number on that side. Gold already means "best
              price" on this site (books grid, panel footline, top-picks quotes)
              and line shopping is the one edge measured real. Paired with ◆ and
              the book's name.
     --pos/--neg  GRADED results only. Paired with W / L.

   AND AMBER IS ABSENT FROM THE WIDE BAND HERE, only here. The board section
   above marks wide in amber, which is right on a surface where amber means
   nothing else. This one also marks the best price, and one accent carrying two
   meanings in adjacent columns is exactly the dilution the accent-economy rule
   warns about. The wide band keeps its caution as the dimmest step of the ramp
   plus its own text tag — the treatment .lg-caution already gives the widest
   group's label ("Muted, never amber"). The deep dive's bar is untouched.
   ────────────────────────────────────────────────────────────────────────── */

/* ── the color key ──
   Wrapped in a native <details> for phones (see board/_sheet.html). Desktop
   hides the summary and reveals the contents, so the wide screen is unchanged. */
.sh-keyd { border-top: 1px solid var(--line); }
/*  wraps rather than colliding with the view toggle that floats beside it  */
.sh-keyd-s { list-style: none; cursor: pointer; padding: 10px 0;
             font: 700 11px var(--font); letter-spacing: 0.1em; text-transform: uppercase;
             color: var(--text2); display: flex; align-items: baseline; gap: 8px;
             flex-wrap: wrap; }
.sh-keyd-s::-webkit-details-marker { display: none; }
.sh-keyd-s::after { content: '+'; margin-left: auto; font-size: 15px; color: var(--text3); }
.sh-keyd[open] .sh-keyd-s::after { content: '\2212'; }
.sh-keyd-h { font-weight: 400; letter-spacing: 0.02em; text-transform: none; color: var(--text3); }
/*  A <details> hides its non-summary children through a UA rule that an explicit
    `display` on a direct child overrides — and .sh-key carries `display: grid`,
    so the collapse has to be stated. SCOPED TO THE PHONE: written unscoped it also
    beat the desktop reveal below (:not([open]) adds specificity, 0-0-3-0 against
    0-0-2-0) and hid the key on every screen.  */
@media (max-width: 900px) {
  .sh-keyd:not([open]) > .sh-key, .sh-keyd:not([open]) > .sh-ramp { display: none; }
}
@media (min-width: 901px) {
  .sh-keyd-s { display: none; }
  .sh-keyd > .sh-key, .sh-keyd > .sh-ramp { display: revert; }
  .sh-keyd > .sh-key { display: grid; }
}

/*  A grid, not a flex row: the four jobs are peers and must read as four
    columns. Flex-wrap put "Outcome" on a line of its own under "State", which
    made two of the four look like sub-points of the other two — the opposite of
    the thing the key exists to say.  */
.sh-key { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0;
          padding: 11px 0 12px; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line-soft); }
.shk { padding-right: 20px; margin-right: 20px; border-right: 1px solid var(--line-soft); min-width: 0; }
.shk:last-child { border-right: 0; padding-right: 0; margin-right: 0; }
.shk-r { flex-wrap: wrap; }
.shk-h { display: block; font-size: 9px; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase;
         color: var(--text3); padding-bottom: 7px; }
.shk-r { display: flex; align-items: center; gap: 6px; font-size: 11px; line-height: 1.55; color: var(--text2); }
.shk-r em { font-style: normal; color: var(--text3); }
.shk-r b { color: var(--text); font-weight: 600; }
.shk-dot { width: 7px; height: 7px; border-radius: 50%; flex: none; }
.shk-dot.live, .sh-dot.live { background: var(--live); box-shadow: 0 0 0 3px var(--live-soft); }
.shk-dot.pre,  .sh-dot.pre  { border: 1px solid var(--text3); }
.shk-dot.done, .sh-dot.done { background: var(--text3); }
.shk-edge { width: 13px; height: 14px; flex: none; background: var(--panel2); box-shadow: inset 3px 0 0 #f47423; }
.shk-shop { font-style: normal; color: var(--acc); font-size: 10px; }
.shk-gold { color: var(--acc) !important; }
.shk-n { padding-left: 4px; }

/* ── the measured reliability ramp, printed with its own evidence ── */
.sh-ramp { padding: 10px 0 12px; border-bottom: 2px solid var(--line); }
.sh-ramp .shk-h em { font-style: normal; font-weight: 400; letter-spacing: 0.02em; text-transform: none; }
.sh-ramp-r { display: flex; flex-wrap: wrap; align-items: center; }
.shr { display: inline-flex; align-items: center; gap: 5px; padding-right: 14px; font-size: 10.5px; color: var(--text2); }
.shr b { color: var(--text); }
.shr em { font-style: normal; color: var(--text3); font-size: 10px; }
.shr-sw { width: 17px; height: 5px; flex: none; }
.shr-sw.b1 { background: #8b9bb0; } .shr-sw.b2 { background: #6b7a8d; }
.shr-sw.b3 { background: #4e5a6a; } .shr-sw.b4, .shr-sw.bw { background: #39424e; }
.sh-ramp-note { margin: 7px 0 0; max-width: 104ch; font-size: 11px; line-height: 1.6; color: var(--text3); }
.sh-ramp-note b { color: var(--text2); }

/* ── the ink ramp, on the sheet's bars only ── */
/*  NO OVERFLOW ON THE SHEET'S WRAPPER. .table-wrap sets overflow-x:auto for the
    wide books grid, and an overflow ancestor becomes the scroll container for
    position:sticky — so the sticky column header stuck to a box that never
    scrolls and slid off the top of the page instead of pinning under the live
    band. The sheet is built to fit its column set and reflows to a grid on
    phones, so it needs no horizontal scroll of its own.  */
.table-wrap.sheet { overflow: visible; }

.sheet .gb-b1 .gb-span, .sh-live .gb-b1 .gb-span { background: #8b9bb0; }
.sheet .gb-b2 .gb-span, .sh-live .gb-b2 .gb-span { background: #6b7a8d; }
.sheet .gb-b3 .gb-span, .sh-live .gb-b3 .gb-span { background: #4e5a6a; }
.sheet .gb-b4 .gb-span, .sh-live .gb-b4 .gb-span { background: #39424e; }
/* the wide band is the dimmest step here, not the loudest — see the note above */
.sheet .gb-wide .gb-span, .sh-live .gb-wide .gb-span { background: #39424e; }
.sheet .gb-wide .gb-ours, .sh-live .gb-wide .gb-ours { background: var(--text2); }

/* ── the live band: the sheet's own first band, stuck to the top ── */
/*  STUCK, IT CONDENSES. Eighteen live games is four grid rows — 315px measured,
    a third of a 1000px viewport — and pinning that much on top of a sticky
    column header meant the header hid underneath it and the sheet scrolled with
    no column names at all. So the band collapses to a single horizontally
    scrollable row the moment the table reaches it, which is what the mockup this
    was built from always said it would do. Collapsed height is fixed at 96px,
    which is what thead offsets by; before the collapse the header is below the
    fold anyway, so the constant is exact rather than approximate.  */
.sh-live { position: sticky; top: 0; z-index: 6; background: var(--bg);
           border-bottom: 2px solid var(--line); box-shadow: 0 14px 18px -16px #000; margin-bottom: 2px; }
.sh-live.is-stuck .sh-live-g { grid-template-columns: none; grid-auto-flow: column;
           grid-auto-columns: 236px; overflow-x: auto; overflow-y: hidden; }
.sh-live.is-stuck .sh-live-f { display: none; }
.sh-live.is-stuck .sh-live-note { display: none; }
.sh-live.is-stuck .sh-live-h { padding: 6px 0 5px; }
.sh-live.is-stuck .sh-live-h::after { content: 'scroll for the rest'; font-size: 9.5px;
           color: var(--text3); letter-spacing: 0.02em; text-transform: none; font-weight: 400; }
.sh-stick-sentinel { height: 1px; margin: 0; }
.sh-live-h { display: flex; align-items: center; gap: 7px; padding: 9px 0 7px; }
.sh-live-h b { font-size: 12px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; }
.sh-live-n { color: var(--live); font-weight: 700; }
.sh-live-note { font-size: 10.5px; color: var(--text3); }
.sh-live-g { display: grid; grid-template-columns: repeat(5, 1fr); gap: 1px; background: var(--line-soft);
             border-top: 1px solid var(--line-soft); border-left: 1px solid var(--line-soft); }
.sh-lc { display: block; background: var(--bg); padding: 6px 9px 7px 11px; color: inherit; text-decoration: none;
         box-shadow: inset 3px 0 0 rgba(var(--pick-rgb, 141, 156, 176), 0.85); }
.sh-lc:hover { background: var(--panel); }
.sh-lc1 { display: flex; align-items: center; gap: 3px; }
.sh-lc-sc { margin-left: auto; font-size: 12.5px; font-weight: 700; }
.sh-lc2 { display: flex; align-items: center; gap: 6px; padding-top: 4px; }
.sh-lc-q { font-size: 9.5px; color: var(--text3); min-width: 58px; }
.sh-lc-b { flex: 1; min-width: 42px; }
.sh-lc-b .gb { height: 9px; }
.sh-lc-b .gb-rule { top: 4px; } .sh-lc-b .gb-span { top: 3px; height: 3px; }
.sh-lc-b .gb-book { top: 1px; height: 7px; } .sh-lc-b .gb-ours { top: 0; height: 9px; }
.sh-lc-g { font-size: 10px; color: var(--text3); min-width: 24px; text-align: right; }
.sh-live-f { margin: 8px 0 10px; font-size: 10.5px; line-height: 1.55; color: var(--text3); max-width: 110ch; }
.sh-live-f b { color: var(--text2); }
/* the live margin: never green or red — nothing is graded until it is final */
.sh-edge { font-size: 11px; font-weight: 700; }
.sh-edge.on { color: var(--live); } .sh-edge.off { color: var(--text3); }
.sh-el { font-size: 9.5px; color: var(--text3); padding-left: 5px; }
.sh-shop { font-style: normal; color: var(--acc); font-size: 9px; }

/* ── the table ── */
table.sh { width: 100%; border-collapse: collapse; }
/*  MEASURED, NOT GUESSED. This was a hardcoded 96px, which is the collapsed band
    height on one viewport and wrong on every other — the header then sat ON TOP of
    the first rows and sliced them (Will, 2026-09-05: "half of the data looks cut
    off"). The observer that collapses the band now writes its real height into
    --sh-stick on every resize, so the header always lands directly under it.  */
table.sh thead th { position: sticky; top: var(--sh-stick, 0px); background: var(--bg);
    text-align: left; z-index: 2;
    font-size: 9px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: var(--text3);
    padding: 10px 9px 7px; border-bottom: 2px solid var(--line); white-space: nowrap; }
table.sh thead th.grp, table.sh tbody td.grp { border-left: 1px solid var(--line-soft); }
table.sh tbody td { padding: 0 9px; height: 30px; border-bottom: 1px solid var(--line-soft); vertical-align: middle; }
table.sh tbody tr:hover td { background: var(--panel); }
.sh-row { box-shadow: inset 3px 0 0 rgba(var(--pick-rgb, 36, 42, 53), 0.9); }
.sh-rule td { height: 40px; padding-top: 12px; vertical-align: bottom;
              border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.sh-rl { font-size: 15px; font-weight: 700; letter-spacing: 0.02em; }
.sh-rn { color: var(--live); font-weight: 700; padding-left: 9px; }
/*  The band rule's note is a SENTENCE and has to wrap. Its <td> inherits
    white-space: nowrap from the sheet's cell rules, which on a 320px screen made
    a 238px line push the whole document 63px sideways — and nothing read as too
    wide, because every individual cell was under the viewport. Found by walking
    the tree hiding one element at a time.  */
.sh-rule td, .sh-rnote { white-space: normal; }
.sh-rnote { font-size: 10.5px; color: var(--text3); padding-left: 14px; font-weight: 400; }
.sh-k { width: 108px; font-size: 10.5px; color: var(--text2); white-space: nowrap; }
.sh-kt { color: var(--text3); }
.sh-dot { display: inline-block; width: 6px; height: 6px; border-radius: 50%; margin-right: 6px; vertical-align: middle; }
.sh-m { min-width: 210px; }
.sh-m a { display: flex; align-items: center; gap: 5px; color: inherit; text-decoration: none; white-space: nowrap; }
.sh-m a:hover .sh-nm { color: var(--acc); }
.sh-nm { font-size: 12px; font-weight: 600; }
.st-final .sh-nm { color: var(--text2); font-weight: 400; }
th.sh-sc, td.sh-sc { width: 56px; text-align: right; font-weight: 700; }
.sh-o, .sh-bk { width: 92px; white-space: nowrap; }
.sh-t { font-size: 10px; font-weight: 700; color: var(--text3); }
.sh-o b { font-size: 12px; } .sh-bk b { font-size: 12px; color: var(--text2); font-weight: 400; }
.sh-g { width: 172px; white-space: nowrap; }
.sh-g .gb { display: inline-block; width: 110px; vertical-align: middle; }
.sh-gv { font-size: 10.5px; color: var(--text2); padding-left: 9px; }
.sh-wtag { font-size: 8.5px; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase;
           color: var(--text3); padding-left: 7px; }
.sh-p { width: 142px; }
.sh-pick { font-size: 11.5px; color: var(--text); }
.sh-moved { display: block; font-size: 9.5px; color: var(--text3); }
.sh-v { width: 244px; white-space: nowrap; }
.sh-book { font-size: 10.5px; font-weight: 600; color: var(--text2); }
.sh-book.on { color: var(--acc); }
.sh-book i { font-style: normal; padding-right: 4px; font-size: 9px; }
.sh-bn { font-size: 10.5px; padding-left: 6px; color: var(--text2); }
/*  The gain is the answer to "which is the best line", so it is the loud part
    of the cell — gold, and stated in points. A game with nothing to shop prints
    a dash instead of "all 5 books level" on fifty rows.  */
/*  The gain is the answer to "which is the best line", so it is legible rather
    than a footnote: 11.5px against the 10.5px book name above it, and the unit
    spelled out because a bare number cannot say whether it is points or money.  */
.sh-gain { display: block; font-size: 10px; color: var(--text3); margin-top: 1px; }
.sh-gain b { color: var(--acc); font-size: 11.5px; font-weight: 700; }
.sh-gain .u { color: var(--text2); }
.sh-level { font-size: 10px; color: var(--text3); }
.sh-bc { display: block; font-size: 9.5px; color: var(--text3); }
.sh-tt { width: 96px; }
.sh-ou { font-size: 9px; color: var(--text3); padding-right: 5px; }
.sh-e { width: 168px; white-space: nowrap; }
.sh-mk { display: inline-block; font-size: 9px; font-weight: 700; letter-spacing: 0.04em;
         padding: 3px 4px; margin-right: 2px; }
.sh-mk.win  { color: var(--pos); box-shadow: inset 0 0 0 1px var(--pos-soft); }
.sh-mk.loss { color: var(--neg); box-shadow: inset 0 0 0 1px var(--neg-soft); }
.sh-mk.na   { color: var(--text3); box-shadow: inset 0 0 0 1px var(--line); }
.sh-pb { display: inline-block; width: 38px; height: 5px; background: var(--panel3); vertical-align: middle; }
.sh-pb i { display: block; height: 5px; background: var(--text3); }
.sh-pbn { font-size: 10.5px; color: var(--text2); padding-left: 6px; }
.sh-mut { color: var(--text3); font-size: 10.5px; }
.sh-empty { color: var(--text3); padding: 18px 9px !important; }
/* the printed scale, in the column head */
.sh-ruler { display: block; position: relative; width: 132px; height: 11px; margin-top: 5px;
            font-size: 8px; letter-spacing: 0.02em; text-transform: none; font-weight: 400; }
.sh-ruler i { position: absolute; top: 0; width: 1px; height: 4px; background: var(--line); }
.sh-ruler i:nth-child(1) { left: 0; } .sh-ruler i.mid { left: 50%; height: 7px; background: var(--text3); }
.sh-ruler i:nth-child(3) { left: 100%; }
.sh-ruler b { position: absolute; top: 5px; font-weight: 400; color: var(--text3); white-space: nowrap; }
.sh-ruler b.l { left: 0; } .sh-ruler b.m { left: 50%; transform: translateX(-50%); }
.sh-ruler b.r { left: 100%; transform: translateX(-100%); }
.sh-unpriced { display: inline-block; margin: 10px 0 0; font-size: 11.5px; color: var(--text2); text-decoration: none; }
.sh-unpriced:hover { color: var(--acc); }
.sh-foot { margin: 12px 0 0; max-width: 108ch; font-size: 11px; line-height: 1.65; color: var(--text3); }
.sh-foot strong { color: var(--text2); }
.bk-board-sheet .bk-main { min-width: 0; }


/* ── phones: the table becomes two lines per game, and every color survives
      because none of them is carried by area (BKM-DESIGN-SYSTEM-SPEC.md's
      phone-first rule: maximize information per viewport, waste nothing) ── */
/* ── THE PHONE ROW ──                                        rebuilt 2026-09-05
   The first cut reflowed the ten columns into a 5-row grid, which is the
   label/value stack BKM-DESIGN-SYSTEM-SPEC.md bans outright. Measured at 390px:
   214-250px rows, 3 per viewport, 477px of horizontal overflow — against the
   spec's floor of ~56px rows and ~8 per viewport. Will: "fix the mobile layout."

   Rebuilt as the atomic unit the spec asks for: ONE GAME, TWO LINES.
     line 1   who is playing (abbreviations, team dots) + when, or the score
     line 2   the side we logged · how far we sit from the market · the best
              price, as a 44px tap target
   Everything else is desktop luxury and is DROPPED here rather than stacked:
   our number and the book's (the gap number carries the distance), the total,
   the win-probability bar, and the five-book field strip — the slip's own book
   switcher prints every book's number, which is the phone answer to "what are
   the other odds".

   EVERY CELL RULE IS WRITTEN `.sh-row td.x`, NOT `.x`. The layout reset two rules
   up sets `table.sh td { display: block }`, which at 0-0-1-2 out-specifies a bare
   class at 0-0-1-0 — so the first version's `display: none` and `display: flex`
   silently lost and the stack stayed 187px tall while the CSS read as if it had
   been fixed. Specificity, not source order, was the bug. */
@media (max-width: 900px) {
  /*  ON A PHONE THE LIVE BAND IS ALWAYS THE TICKER. One-across, 26 games in
      progress and three lines each is ~2000px of strip before the table starts —
      the band is a glanceable status rail, not the substance of the page. It gets
      the collapsed treatment at every scroll position here: horizontal, two cells
      visible, the rest a swipe away. The third line (our number against the
      book's) goes with it, for the same reason the table row drops those columns:
      the gap number carries the distance.  */
  /*  BOTH STATES, or the stuck rule wins: `.sh-live.is-stuck .sh-live-g` is
      0-0-3-0 against a bare `.sh-live-g` at 0-0-1-0, so the phone kept the
      desktop's 236px columns and the ticker ran past a 320px screen.  */
  .sh-live .sh-live-g, .sh-live.is-stuck .sh-live-g {
               display: grid; grid-template-columns: none; grid-auto-flow: column;
               grid-auto-columns: 168px; overflow-x: auto; overflow-y: hidden;
               -webkit-overflow-scrolling: touch; }
  .sh-live .sh-lc3 { display: none; }
  .sh-live .sh-lc { padding: 5px 8px 6px 10px; }
  .sh-live .sh-lc-q { min-width: 42px; font-size: 9px; }
  .sh-live .sh-lc-b { min-width: 26px; }
  .sh-live-f { font-size: 10px; }
  .sh-key { display: block; }
  .shk { border-right: 0; padding-right: 0; margin: 0 0 10px; }
  .sheet { overflow: visible; }
  table.sh, table.sh tbody, table.sh tr, table.sh td { display: block; width: auto; }
  table.sh thead { display: none; }

  /*  THREE COLUMNS, TWO ROWS. The first cut used two columns and parked the gap
      on a third row while the price cell spanned rows 2-3 — the two then
      occupied the same space and the text overlapped. Side, distance and price
      each get their own column on line 2 instead, and nothing spans.  */
  table.sh tr.sh-row { display: grid;
            grid-template-columns: minmax(0, 1fr) auto auto;
            column-gap: 9px; row-gap: 1px; padding: 6px 10px 7px 12px;
            border-bottom: 1px solid var(--line-soft); align-items: center; }
  /*  WIDTH: AUTO ON EVERY CELL. The desktop column widths (.sh-g 172px, .sh-p
      142px, .sh-k 88px) survive the reflow — they are set on the class, and the
      grid then cannot fit three of them in 320px, so table.sh pushed the document
      63px wide on an iPhone SE. Bisected by hiding elements one at a time; no
      element READ as too wide because each cell was individually under the
      viewport.  */
  .sh-row td { height: auto !important; padding: 0 !important; border: 0 !important;
               min-width: 0; width: auto; }
  .sh-row td.grp { border-left: 0 !important; }

  /* line 1 — identity, and the clock or the score */
  .sh-row td.sh-m { display: block; grid-column: 1 / 3; grid-row: 1; }
  .sh-m a { gap: 4px; }
  .sh-nm { display: none; }                        /* the school name is desktop-only */
  .sh-ab { display: inline; font-size: 12.5px; font-weight: 700; }
  .sh-row td.sh-k { display: block; grid-column: 3; grid-row: 1; text-align: right;
                    font-size: 10.5px; white-space: nowrap; }
  .sh-row td.sh-sc { display: none; }
  .sh-row.st-final td.sh-sc { display: block; grid-column: 3; grid-row: 1;
                              text-align: right; font-size: 13px; }
  .sh-row.st-final td.sh-k { display: none; }

  /* line 2 — the side, the distance, the price */
  .sh-row td.sh-p { display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap;
                    grid-column: 1; grid-row: 2; }
  .sh-pick { font-size: 11.5px; padding: 0; }
  .sh-moved { display: inline; font-size: 9.5px; padding-left: 0; }
  .sh-row td.sh-g { display: block; grid-column: 2; grid-row: 2; text-align: right; }
  .sh-g .gb { display: none; }                     /* the bar needs width it does not have */
  .sh-gv { padding-left: 0; font-size: 10px; }
  .sh-row .sh-gv::after { content: ' gap'; color: var(--text3); font-size: 9px; }
  /*  the grid track sized itself to the row's other content (34px) while the
      button inside carries min-height 44, so the tap target hung 10px outside its
      own cell and over the row boundary. The cell claims the height instead.  */
  .sh-row td.sh-v { display: flex; align-items: center; justify-content: flex-end;
                    grid-column: 3; grid-row: 2; width: auto; min-height: 44px; }

  /* dropped on a phone — see the note above */
  .sh-row td.sh-o, .sh-row td.sh-bk, .sh-row td.sh-tt,
  .sh-row td.sh-e { display: none; }
  /*  scoped to .sh-row so it outweighs the later `.sh-field { display: flex }`
      — media queries add no specificity, so the bare class lost on source order
      and the five-book strip kept rendering on top of the row  */
  .sh-row .sh-field, .sh-row .sh-pb, .sh-row .sh-pbn { display: none; }
  /*  A PLAYED ROW trades the price cell for its grades. The grades were placed at
      `grid-column: 2 / -1` while the gap still occupied column 2 of the same row,
      so the chips painted straight over "19.9 gap" — plainly visible on a phone,
      and invisible to a row-height or overflow check, which is why I shipped it.
      They get column 3 alone: the cell the price button vacates.  */
  .sh-row.st-final td.sh-v { display: none; }
  .sh-row.st-final td.sh-e { display: flex; align-items: center; gap: 4px;
                             grid-column: 3; grid-row: 2; justify-content: flex-end;
                             flex-wrap: wrap; }
  .sh-row.st-final .sh-mk { font-size: 8.5px; padding: 2px 3px; margin: 0; }

  /* the tap target is the whole price block, at the spec's 44px floor */
  .sh-bet { min-height: 44px; padding: 4px 20px 4px 8px; margin: 0;
            display: flex; flex-direction: column; justify-content: center; }
  .sh-bet .sh-add { opacity: 1; color: var(--text3); right: 5px; }
  .sh-book { font-size: 11px; }
  .sh-bn { font-size: 11px; padding-left: 4px; }
  .sh-gain { font-size: 9.5px; margin-top: 0; }
  .sh-gain b { font-size: 10px; }
  .sh-row .sh-gain .u { display: none; }           /* the unit is implied by the sign */
  .sh-stale { text-align: right; }
  .sh-stale b { font-size: 11px; }
  .sh-stale-n { font-size: 9px; }

  /*  the desktop band rule is a fixed 38px row; on a phone its note wraps to two
      or three lines and overflowed that box straight over the first game.  */
  .sh-rule td { display: block; height: auto !important; padding: 10px 10px 8px !important; }
  .sh-rl { font-size: 15px; }
  .sh-rnote { display: block; padding-left: 0; padding-top: 2px; }
}


/* ── the sheet's rows are tappable ──                       2026-09-05
   The sheet shipped as the board's default with the slip rendering beside it and
   nothing on the surface able to fill it: the tappable prices had always lived on
   the panels and in the All-games table, and neither is the default any more.
   Will: "there is no way to actually make a pick and add it to the bet slip."

   Same .mk-pick class, same data-leg payload, same delegated handler in
   matchup/_slip.html — this only makes the button look like the cell it replaced
   instead of like a chip, and gives it a real touch target. */
.sh-bet { display: block; width: 100%; text-align: left; background: none; border: 0;
          padding: 5px 6px; margin: -5px -6px; border-radius: 5px; color: inherit;
          font: inherit; cursor: pointer; position: relative; min-height: 34px; }
.sh-bet:hover { background: var(--panel2); }
.sh-bet:focus-visible { outline: 2px solid var(--acc-line); outline-offset: -2px; }
.sh-bet .sh-add { position: absolute; right: 4px; top: 50%; transform: translateY(-50%);
                  font-size: 15px; font-weight: 700; line-height: 1; color: var(--text3); opacity: 0; }
.sh-bet:hover .sh-add, .sh-bet:focus-visible .sh-add { opacity: 1; color: var(--acc); }
/*  .mk-pick's own "already on the slip" state is set by the slip's handler; it
    has to read on a table row, where a filled chip would fight the row rules. */
.sh-bet.on, .sh-bet[aria-pressed="true"] { background: var(--acc-dim); box-shadow: inset 0 0 0 1px var(--acc-line); }
.sh-bet.on .sh-add, .sh-bet[aria-pressed="true"] .sh-add { opacity: 1; color: var(--acc); content: none; }
.sh-bet-t { display: inline-flex; align-items: baseline; gap: 5px; width: auto; padding-right: 20px; }
.sh-tp { font-size: 10px; color: var(--text3); }

/*  The phone rules that used to live here are superseded by THE PHONE ROW block
    above. They forced .sh-v and .sh-tt onto their own full-width grid rows with
    !important, which is what rebuilt the label/value stack the rewrite removed —
    and being later in the file, they won. The 44px floor moved up there with the
    rest of the phone layout so there is one place that owns it.  */

/* ── in play: the number prints, the offer does not ──        2026-09-05
   Every price in ncaaf.Game_Odds is a pre-kickoff snapshot; this site does not
   ingest live odds (measured: 0 of 12 in-progress games had a post-kickoff row,
   median 278 minutes stale). Will: "if it's in play, how is that helpful since we
   don't do live odds?" The line still shows — it is what the logged pick was
   taken at and the record is read against it — but it is stated, not offered. */
.sh-stale { display: block; line-height: 1.3; }
.sh-stale b { font-size: 11px; font-weight: 400; color: var(--text2); font-family: var(--font); }
.sh-stale-n { display: block; font-size: 9.5px; color: var(--text3); }

/* ── the rest of the field ──
   The best book and the size of its edge is the summary; this is the field it
   beat. Book ORDER, not price order, so the same book sits in the same place all
   the way down the column and the eye can scan it. */
.sh-field { display: flex; flex-wrap: wrap; gap: 0 7px; margin-top: 3px; white-space: nowrap; }
.shq { display: inline-flex; align-items: baseline; gap: 3px; font-size: 9.5px; color: var(--text3); }
.shq i { font-style: normal; font-weight: 700; letter-spacing: 0.03em; }
.shq b { font-weight: 400; color: var(--text3); }
.shq em { font-style: normal; opacity: 0.75; }
.shq.best i, .shq.best b { color: var(--acc); font-weight: 700; }
.shq.best em { color: var(--acc); opacity: 1; }
/* the field belongs to the button's cell but must not be inside its hit area */
td.sh-v { padding-top: 4px; padding-bottom: 5px; }

/* ── the live strip is the ONLY place a live game renders ──   2026-09-05
   It briefly rendered twice: once in the strip and again as a band of the table
   below it, 23 identical games back to back on one screen (Will: "why do we have
   'in play' there twice?"). The band existed because the sheet had first shipped
   without live games at all; once in-play rows stopped being tappable it was
   spending ~1000px to say less than the strip already did. The strip took over
   the two numbers the band was carrying, on a third line that disappears when it
   collapses — so the pinned height is unchanged. */
.sh-lc3 { display: flex; align-items: baseline; gap: 6px; padding-top: 4px;
          font-size: 10px; white-space: nowrap; overflow: hidden; }
.sh-lc3 b { font-weight: 700; color: var(--text2); }
.sh-lc-n { font-variant-numeric: tabular-nums; color: var(--text2); }
.sh-lc-n.dim { color: var(--text3); }
.sh-lc-vs { color: var(--text3); opacity: 0.7; }
/* collapsed: the strip is a ticker again, and the third line is the first thing
   that has to go */
.sh-live.is-stuck .sh-lc3 { display: none; }

/* ── THE MATCHUP PAGE, COMPACT PASS (Will, 2026-09-05) ────────────────────────
   "There's a lot of black space here that doesn't need to be here... we don't
   need the giant flags at the top of the team, the color pieces could probably
   be half the size, we don't need the giant OSU in the middle. This design is
   just too much."
   The 08-29 rebuild fixed the CARD chrome and then spent the savings on a
   broadcast masthead: a full-bleed two-colour gradient, 30px of padding on
   each side, and the call at 58px. This pass keeps every element and halves
   the volume. Team colour survives as an edge bar and a faint tint, not a
   flag; the call is a headline, not a scoreboard; every section gap is cut to
   about two-thirds. Nothing is removed. All rules are `.mu2 .x` so they win
   on specificity over the originals above without editing them; the phone
   rules at the bottom are re-stated for the same reason. */
.mu2 .mu2-mast { background: none; border-bottom: 1px solid var(--mu2-rule);
    grid-template-columns: minmax(0,1fr) auto minmax(0,1fr); align-items: center;
    padding: 0; }
.mu2 .mu2-back { position: static; grid-column: 1 / -1; display: block;
    padding: 10px 0 0; color: var(--text3); }
.mu2 .mu2-back:hover { color: var(--acc); }
/*  colour: a bar on the outer edge and a tint that fades into the page inside
    ~200px, in place of the full-bleed gradient  */
.mu2 .mu2-sd { padding: 12px 16px 14px 18px; border-left: 5px solid rgb(var(--away-rgb, 36,42,53));
    background: linear-gradient(90deg, rgba(var(--away-rgb, 36,42,53), .22), transparent 220px); }
.mu2 .mu2-sd.r { border-left: 0; border-right: 5px solid rgb(var(--home-rgb, 36,42,53));
    padding: 12px 18px 14px 16px;
    background: linear-gradient(270deg, rgba(var(--home-rgb, 36,42,53), .22), transparent 220px); }
.mu2 .mu2-sd h1 { font-size: 21px; color: var(--text); }
.mu2 .mu2-rec { color: var(--text2); margin-top: 2px; font-size: 11.5px; }
.mu2 .mu2-call { background: none; padding: 10px 28px; min-width: 240px; }
.mu2 .mu2-call b { font-size: 30px; margin: 4px 0 3px; letter-spacing: -.03em; }
.mu2 .mu2-call s { font-size: 11.5px; }

/*  the ledger: items sit at their natural width instead of being spread to the
    edges of a grid that left a void between "moneyline" and "projected score"  */
.mu2 .mu2-ledger { padding: 10px 0; grid-template-columns: 80px minmax(0,1fr); gap: 0 18px; }
.mu2 .mu2-lab { padding-top: 5px; }
.mu2 .mu2-lgs { display: flex; flex-wrap: wrap; gap: 8px 40px; }
.mu2 .mu2-lg b { font-size: 20px; margin: 2px 0 0; }
.mu2 .mu2-meta { padding: 8px 0; }
.mu2 .mu2-note { margin-top: 10px; padding: 6px 0 6px 12px; }

/*  section rhythm: 30/34/34/26 became 16/20/22/16  */
.mu2 .mu2-canvas { padding-top: 16px; }
.mu2 h3 { margin-bottom: 10px; }
.mu2 .mu2-fine { margin-top: 8px; }
.mu2 .mu2-blk { margin-bottom: 20px; }
.mu2 .mu2-ev { margin-top: 22px; padding-top: 16px; gap: 16px 36px; }
.mu2 .mu2-sec { padding-top: 22px; margin-top: 22px; }
.mu2 .mu2-low { gap: 30px; }
.mu2 .mu2-notes { margin-top: 18px; padding-top: 14px; }
.mu2 .bkgrid td, .mu2 .bkgrid th { padding-top: 4px; padding-bottom: 4px; }
.mu2 .bkgrid .mk-pick { padding: 3px 8px; }
.mu2 .dashboard-section { margin-bottom: 0; }

/*  the trenches: series line, season note and four strips at two-thirds height  */
.mu2 .fld-h2h { padding-bottom: 8px; margin-bottom: 0; text-align: left; }
.mu2 .tr-season { margin: 8px 0 8px; }
.mu2 .tr-grid { gap: 6px 32px; }
.mu2 .tr-st { padding: 7px 0 7px 14px; }
.mu2 .tr-h b { font-size: 19px; }
.mu2 .tr-b { margin: 7px 0 4px; height: 8px; }
.mu2 .tr-chips { margin-top: 10px; }
.mu2 .mu2-sec.tr-sec, .mu2 .fld-h2h + .tr-season { margin-top: 0; }

@media (max-width: 1180px) {
    .mu2 .mu2-mast { grid-template-columns: 1fr; }
    .mu2 .mu2-sd.r { border-right: 0; border-left: 5px solid rgb(var(--home-rgb, 36,42,53));
        padding: 12px 16px 14px 18px;
        background: linear-gradient(90deg, rgba(var(--home-rgb, 36,42,53), .22), transparent 220px); }
    .mu2 .mu2-call { min-width: 0; padding: 10px 18px; text-align: left; }
    .mu2 .mu2-ledger { grid-template-columns: 1fr; gap: 6px; }
}
/*  the evidence row: eight players in ONE column ran ~400px past the power table
    and left a void under the two right-hand columns. The two teams sit side by
    side instead, so the three columns end within a row of each other.  */
.mu2 .mu2-low { grid-template-columns: 1.9fr 1fr 1fr; }
.mu2 .mu2-low .plr-grid { grid-template-columns: 1fr 1fr; gap: 0 24px; }
.mu2 .mu2-low .plr-col + .plr-col { margin-top: 0; padding-top: 0; border-top: 0; }
@media (max-width: 1180px) { .mu2 .mu2-low { grid-template-columns: 1fr; } }
@media (max-width: 700px) { .mu2 .mu2-low .plr-grid { grid-template-columns: 1fr; } }
/*  the evidence is a bare <section>, which the site-wide rule at the top of this
    file still boxes; the trenches section escaped through .dashboard-section and
    this one did not, so the page ended on the one card it had otherwise given up  */
.mu2 section.mu2-sec { background: none; border: 0; border-top: 1px solid var(--mu2-rule);
    border-radius: 0; padding: 22px 0 0; box-shadow: none; }

/* ── PHONE POLISH: the things a geometry check cannot see ──   2026-09-05
   The mobile gate proved no overflow, no overlap and no slivers, and every one
   of these still shipped. Found by running the layout against a mobile polish
   checklist rather than against my own idea of what to measure. */

/*  1. iOS ZOOMS THE PAGE when a focused input is under 16px. The stake field was
       13.3px, so tapping it to change the amount jerked the whole board — on the
       one control the slip exists to let you use. 16px is the floor, not a
       preference: below it Safari rescales the viewport and there is no opt-out
       short of disabling zoom, which is an accessibility failure of its own.  */
#slip-stake, .slip-stake input, .doss-rail input { font-size: 16px; min-height: 44px; }

/*  2. SAFE AREAS. Nothing in this stylesheet had ever referenced env(safe-area-*),
       which was harmless while the slip floated in the upper right. It docks to
       the bottom now, and measured on a 390x844 phone the "Open in DraftKings"
       button ended 30px BELOW the viewport — on a notched device that is under the
       home indicator, i.e. the primary action of the whole surface is the one
       thing you cannot reliably tap. viewport-fit=cover is already in base.html;
       this is the half that was missing.  */
.doss-rail.live { padding-bottom: env(safe-area-inset-bottom, 0px); }
.bk-board-sheet .doss-rail.live { padding-bottom: calc(8px + env(safe-area-inset-bottom, 0px)); }

/*  3. dvh, NOT vh — fixed at the source above rather than layered over. §9 of this
       file already records this bug being fixed once for the board rail: mobile
       browser chrome collapses on scroll and vh measures the LARGEST viewport, so
       a vh-capped panel is taller than the screen whenever the chrome shows. I
       reintroduced it in the slip dock, then "fixed" it by appending an override
       and leaving the wrong rule in place — which is how a stylesheet ends up with
       two answers to the same question.  */

/*  4. TOUCH TARGETS on the chrome. 94 of 143 tappable elements were under 44px —
       the week strip alone is 16 chips at 27px tall, which is both a wall of
       buttons and a row of mis-taps. The strip stays a strip (16 weeks is a real
       axis a reader moves along, and a dropdown hides where you are), but it
       becomes a proper scrollable segmented row with legal targets.  */
@media (max-width: 900px) {
  .bk-weeks { display: flex; flex-wrap: nowrap; overflow-x: auto; gap: 6px;
              -webkit-overflow-scrolling: touch; scroll-snap-type: x proximity;
              padding-bottom: 4px; }
  .bk-weeks .filter-btn { flex: none; min-height: 44px; display: inline-flex;
              align-items: center; padding: 0 14px; scroll-snap-align: start; }
  .site-header nav a { min-height: 44px; display: inline-flex; align-items: center; }
  .view-toggle .pl-chip { min-height: 44px; display: inline-flex; align-items: center; }
  /*  press feedback: touch has no hover, and a tap with no acknowledgement reads
      as a dead control  */
  a, button, summary { touch-action: manipulation; }
  .mk-pick:active, .filter-btn:active, .pl-chip:active, .slip-bk:active { opacity: .72; }
}

/*  5. THE PRIMARY ACTION MUST NOT NEED A SCROLL. Docking the slip put "Open in
       <book>" at the end of a 420px scrollable panel, so on a phone the one
       button the whole surface exists to reach sat 53px below the fold of its own
       container — reachable only by scrolling inside the dock, which nothing
       signals. It sticks to the bottom of the dock instead, above the safe-area
       inset, which is the thumb-reach band the checklist asks for. The legs and
       the book switcher scroll behind it.  */
@media (max-width: 1799px) {
  /*  .slip carries `overflow: hidden` to clip its own radius, and an overflow
      ancestor becomes the containing block for a sticky descendant — so the
      button stuck to a box that never scrolls and stayed 213px below the fold.
      The radius moves to the dock, which is the element with the corners now.  */
  .bk-board-sheet .doss-rail.live { overflow-y: auto; border-radius: 13px 13px 0 0; }
  .bk-board-sheet .doss-rail.live .slip { overflow: visible; border-radius: 0; }
  /*  PINNED TO THE DOCK, not sticky inside the slip. `position: sticky` can only
      travel within its own containing block, and the button's parent .slip-calc
      sits entirely below the fold — so it had nowhere to stick to and stayed
      213px off screen. Fixed to the dock's own bottom edge, above the safe-area
      inset, with the scroll content padded so the last leg is never hidden under
      it.  */
  .bk-board-sheet .doss-rail.live .slip-open {
      position: fixed; left: 12px; right: 12px; z-index: 70;
      bottom: calc(8px + env(safe-area-inset-bottom, 0px));
      min-height: 48px; display: flex; align-items: center; justify-content: center;
      margin-top: 0; }
  .bk-board-sheet .doss-rail.live { padding-bottom: calc(68px + env(safe-area-inset-bottom, 0px)); }
  .bk-board-sheet .doss-rail.live .slip-foot { padding-bottom: 4px; }
}
/*  the four market tabs are primary controls and were 30px  */
@media (max-width: 900px) {
  .tp-tab { min-height: 44px; display: inline-flex; align-items: center; }
}
