/* cbb-system dashboard — hand-written CSS, token-driven.
 *
 * No framework. The subject's real material is the data: dense, numeric, comparative. So
 * the design leans on tabular figures, hairline rules and a single accent, with color used
 * to *encode* (gender, provisional, site) rather than to decorate. Light theme only in v1;
 * a dark scheme is a token swap once the identity settles.
 *
 * Tokens are declared once on :root so a later DESIGN.md can lint/replace them wholesale.
 * The dark scheme is a token override keyed on `data-theme="dark"` — the whole theme is
 * those 13 values, because every rule reads a token and the SVG uses classes rather than
 * inline colors. The attribute is set by the masthead's toggle and remembered in
 * `localStorage`; a small pre-paint script resolves the initial value (stored choice, else
 * the OS preference) so there is no flash of the wrong theme.
 *
 * Dark is keyed on the attribute and NOT on `prefers-color-scheme`, deliberately: the OS
 * preference is only the *default*, and a user who presses the button has overridden it —
 * a media query cannot be overridden, so it can only be the default, never the switch.
 */
:root {
  color-scheme: light;
  --bg: #fbfaf7;
  --surface: #ffffff;
  --ink: #16181d;
  --ink-muted: #6a7076;
  --rule: #e3e1db;
  --rule-strong: #c9c6be;
  --accent: #1f6f4a;        /* the single accent: links, active sort, marks */
  --accent-soft: #eaf3ed;
  --on-accent: #ffffff;     /* text on an --accent fill (the filter button) */
  --warn: #8a5a00;
  --women: #7a3f9d;
  --mens: #1f5f8b;
  --chart-5: #b06a2c;
  /* The context series: the many faint lines on the top-25 chart. Its own token, NOT
     --rule-strong — a hairline rule and a data line are different jobs, and the rule token
     measures 1.71:1 against --surface, below the 3:1 non-text floor. This value holds ~4.3:1
     against the surface with no opacity applied. */
  --series-context: #7d7a73;
  --mono: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, monospace;
  --sans: -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
  --r: 6px;
  --measure: 1180px;
}

/* Dark scheme: the same 13 tokens, re-picked for a dark ground. The chart series tokens
 * are *strokes on --surface*, so they are lightened enough to hold contrast against it
 * rather than simply inverted (an inverted #1f5f8b is nearly black and reads as a rule). */
:root[data-theme="dark"] {
  color-scheme: dark;
  --bg: #121419;
  --surface: #191c23;
  --ink: #e7e9ec;
  --ink-muted: #99a1aa;
  --rule: #2a2f37;
  --rule-strong: #3e4550;
  --accent: #4fbf87;
  --accent-soft: #17301f;
  --on-accent: #0b0d11;   /* dark text on the bright accent fill */
  --warn: #d8a44a;
  --women: #bd8fe0;
  --mens: #6aaee0;
  --chart-5: #d9915c;
  --series-context: #747c88;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

main { max-width: var(--measure); margin: 0 auto; padding: 1.5rem 1.25rem 3rem; }

/* ---- masthead ------------------------------------------------------------ */
.masthead {
  display: flex; align-items: baseline; gap: 1.25rem; flex-wrap: wrap;
  max-width: var(--measure); margin: 0 auto; padding: 1rem 1.25rem;
  border-bottom: 2px solid var(--ink);
}
.wordmark { font-weight: 700; letter-spacing: -0.02em; font-size: 1.15rem; text-decoration: none; color: var(--ink); }
.wordmark .dot { color: var(--accent); padding: 0 1px; }

/* The panel is a positioning wrapper on mobile and *transparent* on desktop: `display:
   contents` makes its children direct flex items of the masthead, so nothing about the
   desktop layout is nested or absolute. One markup tree, two layouts. The drawer's own
   chrome (its head and the backdrop) exists only in the narrow layout. */
.nav-panel { display: contents; }
.nav-panel-head, .nav-backdrop { display: none; }
.nav { display: flex; gap: 1rem; }
.nav a { color: var(--ink-muted); text-decoration: none; }
.nav a:hover { color: var(--accent); }
.caveat { margin-left: auto; color: var(--ink-muted); font-size: 0.8rem; font-family: var(--mono); }
.theme-toggle { font: inherit; font-size: 0.8rem; line-height: 1; padding: 0.3rem 0.5rem; border: 1px solid var(--rule-strong); border-radius: var(--r); background: var(--surface); color: var(--ink-muted); cursor: pointer; }
.theme-toggle:hover { color: var(--accent); border-color: var(--accent); }
.theme-toggle .icon-dark { display: none; }
:root[data-theme="dark"] .theme-toggle .icon-dark { display: inline; }
:root[data-theme="dark"] .theme-toggle .icon-light { display: none; }

/* The hamburger exists only in the narrow layout; the button is display:none above the
   breakpoint so nothing focusable is hidden-but-present on desktop. */
.nav-toggle { display: none; }

/* ---- typography ---------------------------------------------------------- */
h1 { font-size: 1.5rem; margin: 0 0 0.35rem; letter-spacing: -0.02em; }
h2 { font-size: 1.02rem; margin: 1.75rem 0 0.5rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-muted); }
a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 2px; }
code, .mono { font-family: var(--mono); font-size: 0.9em; }
.muted { color: var(--ink-muted); }
.mascot { color: var(--ink-muted); font-weight: 400; }
.at { color: var(--accent); }
.lede p { color: var(--ink-muted); max-width: 56ch; }
.note, .legend { color: var(--ink-muted); font-size: 0.84rem; max-width: 56ch; }

/* ---- stat strip ---------------------------------------------------------- */
.stats { display: flex; flex-wrap: wrap; gap: 0.5rem 1.5rem; padding: 1rem 0; border-block: 1px solid var(--rule); }
.stat { display: flex; flex-direction: column; min-width: 6rem; }
.stat .n { font-size: 1.4rem; font-variant-numeric: tabular-nums; letter-spacing: -0.02em; }
.stat .k { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--ink-muted); }

/* ---- tables -------------------------------------------------------------- */
table.grid { width: 100%; border-collapse: collapse; margin: 0.5rem 0 1rem; }
table.grid th, table.grid td { padding: 0.35rem 0.55rem; border-bottom: 1px solid var(--rule); text-align: left; vertical-align: baseline; }
table.grid thead th { border-bottom: 2px solid var(--rule-strong); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--ink-muted); white-space: nowrap; }
table.grid tbody tr:hover { background: var(--accent-soft); }
/* A game row is a card toggle: the whole row opens its card, so it reads as clickable —
   but not so loudly that the numbers stop being readable. */
table.grid tbody tr[hx-get] { cursor: pointer; }
table.grid tbody tr[hx-get]:focus-within { outline: 2px solid var(--accent); outline-offset: -2px; }
/* Inside a clickable row, a real link keeps the pointer so it does not look like row-click. */
table.grid tbody tr[hx-get] a { cursor: pointer; }
table.grid th.num, table.grid td.num { text-align: right; font-variant-numeric: tabular-nums; font-family: var(--mono); }
table.grid th a { color: inherit; text-decoration: none; }
table.grid th a.active { color: var(--accent); text-decoration: underline; }
table.compact th, table.compact td { padding: 0.3rem 0.5rem; }
.sigma-h { color: var(--ink-muted); }

/* The matchup is a link to the game's model page — the gesture that means "this game". */
a.matchup { font-weight: 600; }
a.matchup:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 2px; }

/* ---- badges / encodings -------------------------------------------------- */
.badge {
  display: inline-block; font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.05em;
  padding: 0.05rem 0.32rem; border-radius: 3px; border: 1px solid var(--rule-strong);
  color: var(--ink-muted); vertical-align: middle; margin-left: 0.3rem;
}
.badge.site { border-color: var(--warn); color: var(--warn); }
/* A vertical rule marking an axis boundary (e.g. where the tournament starts). Dashed and
   muted so it reads as a reference line, never as data. */
.axis-rule { stroke: var(--rule-strong); stroke-width: 1; stroke-dasharray: 3 3; }
/* Snap-to-cutoff links beside the run picker: plain anchors, so they need no JS. */
.snap-links { font-size: 0.82rem; color: var(--ink-muted); display: inline-flex; gap: 0.3rem; align-items: baseline; flex-wrap: wrap; }
.snap-links a { color: var(--accent); text-decoration: none; border-bottom: 1px dotted var(--accent); }
.snap-links a.active { font-weight: 600; }
/* A tournament result: the accent's "this was earned" colour, distinct from the prov
   warning, so a badge never reads as a data-quality caveat. */
.badge.tournament { border-color: var(--accent); color: var(--accent); }
.gender { text-transform: uppercase; font-size: 0.72rem; letter-spacing: 0.06em; font-weight: 600; }
.gender.mens { color: var(--mens); }
.gender.womens { color: var(--women); }
.type { font-family: var(--mono); font-size: 0.8rem; color: var(--ink-muted); }
a.champion { font-weight: 600; text-decoration: none; }
a.champion::before { content: "★ "; color: var(--accent); font-size: 0.85em; }
a.champion:hover { text-decoration: underline; }

/* The unit cell on the team page's ratings table: prose beside a number, so it is muted and
   does not compete with the tabular figures. */
.unit { color: var(--ink-muted); font-size: 0.82rem; }
.ok { color: var(--accent); }
.gap { color: var(--warn); }
.empty { border-left: 3px solid var(--rule-strong); padding: 0.5rem 0 0.5rem 0.8rem; color: var(--ink-muted); max-width: 84ch; }
/* A caveat about what a page can and cannot say — distinct from a warning (--warn) and
   from an absence (.empty), because it is a statement about the data's shape. */
.notice { border-left: 3px solid var(--accent); padding: 0.5rem 0 0.5rem 0.8rem; color: var(--ink-muted); max-width: 92ch; margin: 0.6rem 0; }

/* ---- filters ------------------------------------------------------------- */
.filters { display: flex; flex-wrap: wrap; gap: 0.75rem 1rem; align-items: end; padding: 0.9rem 0; border-bottom: 1px solid var(--rule); margin-bottom: 0.5rem; }
.filters label { display: flex; flex-direction: column; gap: 0.2rem; font-size: 0.74rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--ink-muted); }
.filters label.check { flex-direction: row; align-items: center; gap: 0.35rem; text-transform: none; letter-spacing: 0; font-size: 0.84rem; }
.filters select, .filters input { font: inherit; padding: 0.28rem 0.4rem; border: 1px solid var(--rule-strong); border-radius: var(--r); background: var(--surface); color: var(--ink); }
.filters button { font: inherit; padding: 0.35rem 0.9rem; border-radius: var(--r); border: 1px solid var(--accent); background: var(--accent); color: var(--on-accent); cursor: pointer; }
.filters button:hover { filter: brightness(1.08); }

/* ---- run provenance strip ------------------------------------------------ */
.run-strip { display: flex; flex-wrap: wrap; gap: 0.3rem 0.9rem; font-size: 0.82rem; padding: 0.5rem 0; border-bottom: 1px solid var(--rule); }
.run-strip .k { text-transform: uppercase; letter-spacing: 0.06em; font-size: 0.7rem; color: var(--ink-muted); align-self: center; }
.run-strip .v { font-family: var(--mono); }

/* ---- layout helpers ------------------------------------------------------ */
.two-col { display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); gap: 2rem; }
.card { border: 1px solid var(--rule); border-radius: var(--r); padding: 0.5rem 1rem 1rem; background: var(--surface); }
.final-score { font-size: 2rem; font-variant-numeric: tabular-nums; margin: 0.3rem 0; }

/* ---- chart --------------------------------------------------------------- */
.chart-wrap { margin: 0.5rem 0; }
.chart { width: 100%; height: 190px; display: block; background: var(--surface); border: 1px solid var(--rule); border-radius: var(--r); }
.chart-wrap.tall .chart { height: 420px; }
.chart polyline.series-primary { stroke: var(--accent); stroke-width: 2; }
.chart .chart-band { fill: var(--accent); fill-opacity: 0.14; stroke: none; }
/* The warm-up fade: a translucent neutral wash marking "not yet calibrated". Kept off the
   series palette (it qualifies, it does not encode), and light enough that the lines under
   it stay readable — the burn-in is the finding, not a region to hide. */
.chart rect.warmup-shade { fill: var(--ink-muted); fill-opacity: 0.10; stroke: none; }
.chart polyline.series-a { stroke: var(--mens); stroke-width: 1.6; }
.chart polyline.series-b { stroke: var(--women); stroke-width: 1.6; }
.chart polyline.series-c { stroke: var(--warn); stroke-width: 1.6; }
.chart polyline.series-d { stroke: var(--accent); stroke-width: 1.6; }
.chart polyline.series-e { stroke: var(--chart-5); stroke-width: 1.6; }
.chart polyline.series-context { stroke: var(--series-context); stroke-width: 1; }
/* A persistent legend: the highlighted lines keyed by color beside the chart, in the same
   order the table below is ranked. HTML text, never SVG (preserveAspectRatio="none" would
   distort it), so the mapping from color to team is readable without hovering. */
.chart-legend { list-style: none; margin: 0.4rem 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: 0.2rem 1rem; font-size: 0.82rem; }
.chart-legend li { display: flex; align-items: center; gap: 0.35rem; }
.chart-legend .swatch { width: 0.8rem; height: 0.35rem; border-radius: 2px; background: var(--series-context); }
.chart-legend li.series-a .swatch { background: var(--mens); }
.chart-legend li.series-b .swatch { background: var(--women); }
.chart-legend li.series-c .swatch { background: var(--warn); }
.chart-legend li.series-d .swatch { background: var(--accent); }
.chart-legend li.series-e .swatch { background: var(--chart-5); }
.chart-wrap figcaption { color: var(--ink-muted); font-size: 0.8rem; margin-top: 0.3rem; max-width: 52ch; }

/* ---- chart hover readout ------------------------------------------------- */
/* The SVG is stretched by CSS (preserveAspectRatio="none"), so text inside it would be
   distorted. Every label for a point therefore lives in HTML beside the chart, never in the
   SVG: the hit areas are invisible and only the readout is read. */
.trend-wrap { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: 1rem; align-items: start; }
@media (max-width: 900px) { .trend-wrap { grid-template-columns: 1fr; } }
.chart .hover-station { cursor: crosshair; }
.chart .hover-band { fill: transparent; pointer-events: all; }
.chart .hover-station:hover .hover-band { fill: var(--accent); fill-opacity: 0.06; }
.readout-panel { position: sticky; top: 0.5rem; background: var(--surface); border: 1px solid var(--rule); border-radius: var(--r); padding: 0.6rem 0.7rem; }
.readout-panel h2 { margin: 0 0 0.4rem; font-size: 0.82rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-muted); }
.readout-hint { color: var(--ink-muted); font-size: 0.82rem; margin: 0.2rem 0; }
.readout-head { display: flex; flex-wrap: wrap; gap: 0.15rem 0.5rem; align-items: baseline; padding-bottom: 0.35rem; border-bottom: 1px solid var(--rule); margin-bottom: 0.35rem; }
.readout-head .k { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--ink-muted); }
.readout-head .v { font-variant-numeric: tabular-nums; font-size: 0.84rem; }
.readout-list { list-style: none; margin: 0; padding: 0; max-height: 22rem; overflow-y: auto; }
.readout-list li { display: grid; grid-template-columns: 1.4rem 0.7rem minmax(0, 1fr) auto; gap: 0.4rem; align-items: center; padding: 0.12rem 0; font-size: 0.86rem; }
.readout-list .rank { color: var(--ink-muted); font-variant-numeric: tabular-nums; text-align: right; }
.readout-list .swatch { width: 0.7rem; height: 0.55rem; border-radius: 2px; background: var(--series-context); }
.readout-list li.series-a .swatch { background: var(--mens); }
.readout-list li.series-b .swatch { background: var(--women); }
.readout-list li.series-c .swatch { background: var(--warn); }
.readout-list li.series-d .swatch { background: var(--accent); }
.readout-list li.series-e .swatch { background: var(--chart-5); }
/* A row whose series is neither highlighted nor context still needs a swatch color that is not
   a hairline gray: the default above is the context token, which is what an unscored row is. */
.readout-list .value { font-variant-numeric: tabular-nums; color: var(--ink); }
.readout-list a { color: var(--ink); text-decoration: none; }
.readout-list a:hover { text-decoration: underline; }

/* ---- pickers & navigation ------------------------------------------------ */
.picker { border-bottom: none; padding-bottom: 0.25rem; }
.picker input { min-width: 13rem; }
.season-nav { display: flex; flex-wrap: wrap; gap: 0.25rem 0.6rem; align-items: baseline; padding: 0.4rem 0; border-bottom: 1px solid var(--rule); font-size: 0.9rem; }
.season-nav .k { text-transform: uppercase; letter-spacing: 0.06em; font-size: 0.7rem; color: var(--ink-muted); }
.season-nav a { text-decoration: none; }
.season-nav a.active { color: var(--accent); font-weight: 600; text-decoration: underline; }
.note a.active { color: var(--accent); font-weight: 600; text-decoration: underline; }

/* ---- colophon ------------------------------------------------------------ */
.colophon { max-width: var(--measure); margin: 0 auto; padding: 1rem 1.25rem 2rem; border-top: 1px solid var(--rule); color: var(--ink-muted); font-size: 0.8rem; }
.colophon p { max-width: 56ch; }

/* ---- narrow screens ------------------------------------------------------ *
 * The masthead was the one thing that overflowed a phone: five nav links, the caveat and
 * the theme button on one baseline line. Below 720px the bar is a hamburger (left) and the
 * wordmark, and everything else slides in from the left as an off-canvas drawer.
 *
 * The drawer is `position: fixed`, taken out of flow — so the masthead keeps its height and
 * the page behind it never reflows — and slid by `transform`, which the compositor handles
 * (no layout on each frame). `visibility` gates it for assistive tech and for tab order, so
 * a closed drawer has no focusable links off-screen. Hidden by default is a CSS rule: the
 * panel reads with JavaScript off because the drawer, closed, is simply not there.
 *
 * Wrapped tables stay wrapped tables (the alternative is a card layout that loses the
 * column comparison the subject is about); they scroll horizontally inside their own box.
 */
@media (max-width: 720px) {
  .masthead { align-items: center; gap: 0.75rem; padding: 0.75rem 1rem; }
  .nav-toggle {
    display: inline-flex; flex-direction: column; justify-content: center; gap: 4px;
    width: 2.75rem; height: 2.75rem; padding: 0.6rem; flex: none;
    border: 1px solid var(--rule-strong); border-radius: var(--r);
    background: var(--surface); cursor: pointer;
  }
  .nav-toggle .bar { display: block; height: 2px; background: var(--ink); border-radius: 1px; }
  .nav-toggle[aria-expanded="true"] { border-color: var(--accent); }
  .nav-toggle[aria-expanded="true"] .bar { background: var(--accent); }

  .nav-panel {
    display: flex; flex-direction: column; gap: 0;
    position: fixed; top: 0; left: 0; bottom: 0; width: min(76vw, 300px); z-index: 20;
    padding: 0.9rem 1rem 1.5rem; background: var(--surface);
    border-right: 1px solid var(--rule); box-shadow: 2px 0 18px rgb(0 0 0 / 0.18);
    overflow-y: auto; overscroll-behavior: contain;
    transform: translateX(-100%); visibility: hidden;
    /* Only `transform` animates. `visibility` is *stepped*: delayed until the slide-out
       finishes when closing (so the drawer stays painted), instant when opening (so a
       closed drawer is out of the tab order but an open one is focusable on frame zero —
       transitioning it instead would leave it `hidden` for the whole animation). */
    transition: transform 0.18s ease, visibility 0s linear 0.18s;
  }
  /* The backdrop is the header's following sibling; the open state lives on the header. */
  .nav-backdrop { position: fixed; inset: 0; z-index: 10; background: rgb(0 0 0 / 0.42); }
  [data-nav-root][data-nav-open] ~ .nav-backdrop { display: block; }
  [data-nav-root][data-nav-open] .nav-panel {
    transform: translateX(0); visibility: visible;
    transition: transform 0.18s ease, visibility 0s;
  }

  .nav-panel-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.75rem; }
  .nav-panel-title { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--ink-muted); }
  .nav-close { width: 2.5rem; height: 2.5rem; font-size: 1.4rem; line-height: 1; background: none; border: 0; color: var(--ink-muted); cursor: pointer; }
  .nav-close:hover { color: var(--accent); }

  .nav { flex-direction: column; gap: 0; }
  .nav a { padding: 0.7rem 0.25rem; border-bottom: 1px solid var(--rule); }
  /* Touch targets: 44px is the smallest comfortable hit. */
  .nav-panel .caveat { margin: 0.9rem 0 0; font-size: 0.75rem; }
  .nav-panel .theme-toggle { align-self: flex-start; margin-top: 0.6rem; min-height: 2.75rem; min-width: 2.75rem; padding: 0.6rem 0.9rem; }

  .two-col { grid-template-columns: 1fr; gap: 1rem; }
  table.grid { font-size: 0.85rem; }
  /* A wide table scrolls in its own box rather than stretching the page. */
  .table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  h1 { font-size: 1.3rem; }
  main { padding: 1.1rem 0.9rem 2.5rem; }
  .colophon { padding: 0.9rem 0.9rem 1.75rem; }
}
@media (prefers-reduced-motion: reduce) { * { transition: none !important; animation: none !important; } }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* The warm-up toggle inside a chart caption: a small, quiet inline control, not a new nav. */
.warmup-toggle { display: inline-block; margin-left: 0.4rem; white-space: nowrap; }
.warmup-toggle a { color: var(--accent); }
