/* Resolve Projections — visual language matches the physics_detector
   design system used across all Resolve apps (deep purple shell,
   gold accent, system sans, lowercase labels). */

/* Aesthetic pass 2026-08-21: onto the house type, so projections reads as the
   same property as resolveresearcher.com and deepdive. Didot and Avenir Next are
   macOS system faces and cannot be served, so they sit first in each stack and
   Mac visitors get the originals; Bodoni Moda (same Didone family) and Mulish
   (same geometric-humanist proportions) are their nearest servable relatives and
   are what everyone else receives. The typewriter face (Chivo Mono) is retired:
   Billy, 2026-10-01, the house rule the app keeps too. --font-meta names the
   reading face now (2026-10-31, below), so the small labels and figures that
   kept it on the home tables and elsewhere read in Avenir Next.
   Loaded centrally here so every page inherits it (no per-page <link> needed). */
@import url('https://fonts.googleapis.com/css2?family=Bodoni+Moda:opsz,wght@6..96,400&family=Mulish:wght@400;500;600;700&display=swap');

/* Symbol/glyph fallback (2026-07-26): the platform monospace fonts on mobile
   (SF Mono / Roboto Mono) lack box-drawing, geometric shapes, arrows and status
   marks used throughout the tables (sort carets ▾▴, dividers ─, ● ★ ✓ ✗ → ≥) —
   they render as tofu boxes on phones while desktop falls back to Consolas which
   has them. This subset of DejaVu Sans Mono (freely embeddable) supplies ONLY
   those glyphs; the unicode-range keeps it from ever touching letters/digits, so
   it sits harmlessly at the end of every font stack below. */
@font-face {
  font-family: "Resolve Glyphs";
  src: url("/static/resolve-glyphs.woff2") format("woff2");
  font-display: swap;
  unicode-range: U+2190-21FF, U+2200-22FF, U+2500-259F, U+25A0-25FF, U+2605-2606, U+2713, U+2717;
}

:root {
  /* Sage palette migration 2026-06-25: charcoal bg + sage accent.
     CTA purple intentionally kept as visual differentiator. */
  /* ⛔ THESE WERE ALL THE SAME VALUE. Six surface tokens every one of which
     resolved to #1E1A22, so a card, an inset and the page were indistinguishable
     and every panel on the site depended entirely on its border to exist. The
     steps below are small on purpose: borders still do the separating, the
     surfaces just stop pretending to be one flat sheet. */
  --bg-page:        #201825;
  --bg-raised:      #2D2034;
  --bg-sidebar:     #2D2034;
  --bg-card:        #2D2034;
  --bg-inset:       #37263F;
  --bg-elevated:    #37263F;
  /* Row-hover tint — transparent lavender to keep the theme reading through.
     Dedicated var so changing it never disturbs the 32 other uses of bg-inset. */
  --row-hover: rgba(122, 173, 142, 0.12);
  --border:         #563B66;
  --border-dashed:  #6D4A81;

  --text-primary:   #C8DACE;
  /* ⛔ Same story as the light three in theme.css: tuned against the page ground
     only. On a card or elevated row (#241F2B, #2A2431) they read 4.38 / 3.49 /
     2.80 and all three failed. Retuned 2026-08-25 against the LIGHTEST surface
     they can land on, so each ratio below is the worst case. */
  --text-secondary: #9FAEA5;   /* 6.00:1 on elevated, 7.44 on page */
  --text-tertiary:  #909D94;   /* 4.92:1 on elevated, 6.10 on page */
  --text-faint:     #8C9890;   /* 4.64:1 on elevated, 5.75 on page */

  --gold:           #7AAD8E;
  --gold-hover:     #8BBF9F;
  --gold-text-soft: #739E84;
  --on-gold:        #201825;

  /* Category letter grades — LIFTED VERBATIM from the Resolve Leagues app
     (`static_nba/styles.css`, dark base). The two products share this base
     palette exactly, so a grade means the same thing and LOOKS the same on
     both. The scale they colour is `catLetterFromZ` in the Leagues
     `grades.js`; if that scale ever moves, it moves in both places or a
     player reads A+ on one board and A on the other. */
  --grade-anchor:      #B38ACC;   /* A+  purple        */
  --grade-cornerstone: #64A973;   /* A   green         */
  --grade-strong:      #9A9F4E;   /* B   yellow-green  */
  --grade-solid:       #B89547;   /* C   yellow        */
  --grade-decent:      #CE8A5A;   /* D   orange        */
  --grade-wrong:       #D78380;   /* F   red           */

  /* ⛔ THE CTA PURPLE IS GONE. It was the last survivor of the pre-sage palette
     and it was the single loudest color on the site, which meant the one
     accent rule ("sage is the only bright thing") was false on every page that
     had a button. The shadows go with it: house rule is borders, not shadows. */
  --cta-bg:         var(--gold);
  --cta-rest-shadow: none;
  --cta-glow:       none;

  /* Didot at weight 400 ONLY — never bold it. The thin/thick contrast is its
     whole character and faux-bold destroys it. Size gives it weight. */
  --font-display: Didot, "Didot LT STD", "Bodoni Moda", "Big Caslon", "Playfair Display", Georgia, serif;
  --font-sans:   "Avenir Next", Avenir, "Mulish", "Helvetica Neue", Helvetica, Arial, "Resolve Glyphs", sans-serif;
  /* THE TYPEWRITER FACE IS RETIRED (Billy 2026-10-01; finished 2026-10-31, the
     review of the home tables: "5-1", "vs sac" and "tonight's surest picks" were
     still in it). The variable keeps its name so the ~280 places that ask for it
     needn't change; it names the reading face, and tables keep their figures in
     columns with tabular figures (below) rather than a monospaced face. */
  --font-meta:   "Avenir Next", Avenir, "Mulish", "Helvetica Neue", Helvetica, Arial, "Resolve Glyphs", sans-serif;
  /* --font-mono is an alias for --font-meta, 2026-08-25. It used to name the
     PLATFORM typewriter face, so every page on the site asked the browser to
     download Chivo Mono and then set its own numbers, seeds, scores and keys in
     SF Mono or Consolas instead: the download was wasted and no two platforms
     matched. Roughly seven hundred elements on one page alone. (Since
     2026-10-31 the meta face is the reading face; see --font-meta.) Aliased rather than copied so the two can never drift apart again.
     ⛔ CONTROLS STILL TAKE THE BODY FACE. The house style bans a typewriter
     face on a button, tab or pill, and --font-button is what they point at.
     Do not point a control at either of these two. */
  --font-mono:   var(--font-meta);
  --font-button: var(--font-sans);
  /* --font-label is what COLUMN HEADERS take, 2026-08-29 (Billy). It is the
     body face, not the typewriter one: shown both ways side by side, he picked
     Avenir. This REVERSES the 08-27 tables-and-decks decision that put every
     header on lowercase Chivo Mono — deliberately, not by drift.
     ⛔ It is only for headers and column labels. Numbers, keys, badges,
     eyebrows and datelines stay on --font-meta; that is still the house face
     for a figure, and tabular digits are the whole reason it is there. */
  --font-label:  var(--font-sans);
  --radius-button: 11px;
  --radius-card:   16px;
  --radius-pill:   22px;

  /* Semantic colors — use these (vs hardcoded RGBA) so light-mode
     overrides in theme.css apply automatically. */
  --success-text:   #72A87D;
  --success-bg: rgba(114, 168, 125, 0.15);
  --success-border: rgba(114, 168, 125, 0.35);
  --warning-text:   #B4985C;
  --warning-bg: rgba(180, 152, 92, 0.12);
  --warning-border: rgba(180, 152, 92, 0.30);
  --danger-text:    #D38784;
  --danger-bg: rgba(211, 135, 132, 0.12);
  --danger-border: rgba(211, 135, 132, 0.30);

  /* Subtle sage tint used by .hl table cells and similar accents. */
  --gold-tint: rgba(122, 173, 142, 0.08);
  --gold-tint-strong: rgba(122, 173, 142, 0.14);
}

/* ── House rules, 2026-08-21 ──────────────────────────────────────────
   NO ITALICS, ANYWHERE. Billy's standing copy rule across every property.
   Emphasis is carried by color, never by slanting the type. This covers the
   elements that default to italic; the explicit `font-style: italic`
   declarations elsewhere in this sheet were removed at the same time. */
em, i, cite, dfn, var, address, blockquote, q { font-style: normal; }

/* Headings take the Didone, at 400, always. Size is what gives a Didone
   heading its weight; weight is what destroys it. */
h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 400;
  line-height: 1.1;
  letter-spacing: -.018em;
}

/* One label style on the whole site: lowercase, wide, the meta face, accent. */
.rr-label {
  font-family: var(--font-meta);
  font-size: 10.5px; font-weight: 500;
  letter-spacing: .17em; text-transform: lowercase;
  color: var(--gold);
}
.rr-label.quiet { color: var(--text-faint); }

* { box-sizing: border-box; }
/* every table's figures in columns: tabular figures, the house rule, now that no table leans on a
   monospaced face for it (2026-10-31) */
table { font-variant-numeric: tabular-nums; }
html, body {
  margin: 0; padding: 0;
  font-family: var(--font-sans);
  font-size: 15px; line-height: 1.5;
  background: var(--bg-page);
  color: var(--text-primary);
  -webkit-font-smoothing: antialiased;
}
a { color: inherit; text-decoration: none; }
button { font-family: var(--font-button); cursor: pointer; }
button { -webkit-appearance: none; }

/* ── Advanced Resolve Metrics page — per-sport cards explainer ── */
.adv-layout {
  max-width: 1080px;
  margin: 0 auto;
  padding: 32px 28px 64px;
}
/* Page hero title. Didot at 400, which is the only weight it is allowed: the
   thin-to-thick contrast is the whole character of the face and faux bold
   flattens it. Size carries the weight instead.
   ⛔ This used to be 600 with a four-layer glow (and a six-layer one in light).
   The house rule is borders, never shadows; do not reinstate either. */
.adv-page-title {
  font-family: var(--font-display);
  font-size: clamp(40px, 5.5vw, 64px);
  line-height: 1.05;
  letter-spacing: -.025em;
  font-weight: 400;
  color: var(--gold);
  margin: 8px 0 24px;
  text-shadow: none;
}
/* ⛔ The accent word used to be a loose violet (#a59ad0 dark, #6E45B0 light)
   that appears nowhere else on the site. It is the accent's job, so it takes
   the accent token and follows the theme. */
.adv-page-title-accent {
  color: var(--gold);
}
@media (max-width: 720px) {
  .adv-page-title {
    font-size: clamp(32px, 8vw, 42px);
    margin: 4px 0 18px;
  }
}

/* The page head. ⛔ This used to be a filled card with a 16px radius; nothing
   else on the site introduces itself inside a container. It is now the same
   plain head the sport home pages use. */
.adv-intro {
  background: none;
  border: 0;
  border-radius: 0;
  padding: 0;
  margin-bottom: 30px;
  max-width: 76ch;
}
.adv-intro h1 {
  font-family: var(--font-display);
  font-size: 24px; font-weight: 400;
  color: var(--gold); letter-spacing: -.01em;
  margin: 0 0 8px;
}
.adv-intro p {
  font-size: 14px; color: var(--text-secondary);
  margin: 6px 0 0; max-width: 70ch; line-height: 1.6;
}
.adv-intro p em { color: var(--gold); }
.adv-intro-notes {
  margin: 16px 0 0; padding: 0 0 0 20px;
  max-width: 70ch;
}
.adv-intro-notes li {
  font-size: 13.5px; color: var(--text-secondary);
  line-height: 1.6; margin-bottom: 6px;
}
.adv-intro .adv-counter {
  font-family: var(--font-button); font-size: 11px;
  color: var(--text-tertiary); letter-spacing: .5px;
  text-transform: uppercase; margin-top: 12px;
}
.adv-grid {
  display: grid; gap: 18px;
  grid-template-columns: repeat(auto-fit, minmax(360px, 1fr));
}
/* ── the metric decks, restored 2026-08-27 — DESKTOP ONLY ──────────────────
   2026-08-25 removed the hover-fan decks in favor of the house ledger.
   Billy asked for the decks BACK on desktop, with the phone keeping the
   ledger — so both trees render and this breakpoint decides which shows.
   Differences from the 08-25 originals: no drop shadows (house rule: borders
   do the separating), card labels use --font-meta lowercase (uppercase
   --font-button was retired with the redesign), no mobile swipe carousel,
   and the breakpoint is 780px to match the ledger's existing rules. */
/* Two piles, each statically stacked Ringer-style. Hover a pile to spread its
   cards (alternating left/right around its top card). */
.adv-hero-wrap {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  gap: 80px;
  margin: 24px auto 0;
  flex-wrap: wrap;
}
.adv-hero-deck {
  position: relative;
  width: 360px;
  max-width: 100%;
  min-height: 360px;
  z-index: 1;
  transition: z-index 0s linear .45s;
}
.adv-hero-deck:hover { z-index: 10; transition-delay: 0s; }
.adv-hero-deck .adv-card {
  position: absolute;
  top: 0; left: 0;
  width: 100%;
  min-height: 360px;
  max-height: 360px;
  overflow: hidden;
  cursor: pointer;
  transition: max-height .35s ease,
              transform .45s cubic-bezier(.25, .8, .25, 1),
              border-color .25s ease;
}
/* Subtle deck peek — each card behind shifts a few px down-right */
.adv-hero-deck .adv-card:nth-child(2) { transform: translate(4px, 4px); }
.adv-hero-deck .adv-card:nth-child(3) { transform: translate(8px, 8px); }
.adv-hero-deck .adv-card:nth-child(4) { transform: translate(12px, 12px); }
.adv-hero-deck .adv-card:nth-child(5) { transform: translate(16px, 16px); }
/* Hover spreads — alternating left/right so cards fan around center.
   Every spread is multiplied by --fan-scale (set per-deck by advanced-metrics.js
   from the room actually available): 4K → 1.0 (design intact), laptop/iPad → shrinks
   so the outermost card lands just inside the viewport instead of flying off-screen. */
.adv-hero-deck:hover .adv-card:nth-child(2) { transform: translateX(calc(-90% * var(--fan-scale, 1))); }
.adv-hero-deck:hover .adv-card:nth-child(3) { transform: translateX(calc(90% * var(--fan-scale, 1))); }
.adv-hero-deck:hover .adv-card:nth-child(4) { transform: translateX(calc(-180% * var(--fan-scale, 1))); }
.adv-hero-deck:hover .adv-card:nth-child(5) { transform: translateX(calc(180% * var(--fan-scale, 1))); }
/* Edge-aware hover fan (tagged by advanced-metrics.js) */
.adv-hero-deck.adv-deck-edge-left:hover  .adv-card:nth-child(2) { transform: translateX(calc(90% * var(--fan-scale, 1))); }
.adv-hero-deck.adv-deck-edge-left:hover  .adv-card:nth-child(3) { transform: translateX(calc(180% * var(--fan-scale, 1))); }
.adv-hero-deck.adv-deck-edge-left:hover  .adv-card:nth-child(4) { transform: translateX(calc(270% * var(--fan-scale, 1))); }
.adv-hero-deck.adv-deck-edge-left:hover  .adv-card:nth-child(5) { transform: translateX(calc(360% * var(--fan-scale, 1))); }
.adv-hero-deck.adv-deck-edge-right:hover .adv-card:nth-child(2) { transform: translateX(calc(-90% * var(--fan-scale, 1))); }
.adv-hero-deck.adv-deck-edge-right:hover .adv-card:nth-child(3) { transform: translateX(calc(-180% * var(--fan-scale, 1))); }
.adv-hero-deck.adv-deck-edge-right:hover .adv-card:nth-child(4) { transform: translateX(calc(-270% * var(--fan-scale, 1))); }
.adv-hero-deck.adv-deck-edge-right:hover .adv-card:nth-child(5) { transform: translateX(calc(-360% * var(--fan-scale, 1))); }
/* collapsed cards fade at the base; hovering one unfolds it */
.adv-hero-deck .adv-card::after {
  content: '';
  position: absolute;
  bottom: 0; left: 0; right: 0;
  height: 70px;
  background: linear-gradient(to bottom, transparent, var(--bg-card) 85%);
  pointer-events: none;
  transition: opacity .2s ease;
  z-index: 1;
}
.adv-hero-deck .adv-card:hover {
  max-height: 1200px;
  /* !important needed: advanced-metrics.js sets inline z-index per card. */
  z-index: 100 !important;
}
.adv-hero-deck .adv-card:hover::after { opacity: 0; }

.adv-card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  padding: 20px 22px;
  display: flex; flex-direction: column;
  text-decoration: none; color: inherit;
  transition: border-color .15s ease;
}
.adv-card:hover { border-color: var(--gold); }
.adv-card-cta {
  font-family: var(--font-meta); font-size: 11px;
  color: var(--gold); letter-spacing: .13em;
  margin-top: auto; padding-top: 14px;
  display: flex; align-items: center; gap: 6px;
  transition: gap .15s ease;
}
.adv-card:hover .adv-card-cta { gap: 10px; }
/* card tone variants — randomized per page-load */
.adv-card.adv-card--t0 { background: color-mix(in srgb, var(--bg-card) 92%, #ffb98a 8%);
  border-color: color-mix(in srgb, var(--border) 60%, #ffb98a 40%); }
.adv-card.adv-card--t1 { background: color-mix(in srgb, var(--bg-card) 92%, #98c0d8 8%);
  border-color: color-mix(in srgb, var(--border) 60%, #98c0d8 40%); }
.adv-card.adv-card--t2 { background: color-mix(in srgb, var(--bg-card) 92%, #100818 8%);
  border-color: color-mix(in srgb, var(--border) 60%, #4a2e58 40%); }
.adv-card.adv-card--t3 { background: color-mix(in srgb, var(--bg-card) 92%, #0a1418 8%);
  border-color: color-mix(in srgb, var(--border) 60%, #2a4858 40%); }
/* card content type — meta face, lowercase (the 08-25 originals used the
   retired uppercase --font-button) */
.adv-card-head { display: flex; align-items: baseline; gap: 10px; margin-bottom: 12px; }
.adv-card-name { font-size: 17px; font-weight: 600; color: var(--text-primary); margin: 0; flex: 1;
  font-family: var(--font-sans); }
.adv-card-units { font-size: 11px; font-family: var(--font-meta); color: var(--text-tertiary); letter-spacing: .06em; }
.adv-card-prov { font-family: var(--font-meta); font-size: 10.5px; letter-spacing: .1em;
  color: var(--text-tertiary); margin: -6px 0 10px; }
.adv-card-short { font-size: 14px; color: var(--text-secondary); margin: 0 0 14px;
  padding-bottom: 12px; border-bottom: 1px solid var(--border); }
.adv-card-h { font-family: var(--font-meta); font-size: 10.5px; color: var(--gold);
  letter-spacing: .13em; margin: 14px 0 4px; }
.adv-card-body { font-size: 13.5px; color: var(--text-primary); margin: 0; line-height: 1.55; }
/* the /advanced page reads at +20% like its ledger counterpart */
.adv-page .adv-card-name { font-size: 20.4px; }
.adv-page .adv-card-short { font-size: 16.8px; }
.adv-page .adv-card-body { font-size: 16.2px; }
.adv-page .adv-card-h { font-size: 12.6px; }
.adv-page .adv-card-cta { font-size: 13.2px; }
.adv-page .adv-card-prov { font-size: 12.6px; }
/* the breakpoint gates LAST, so they outrank the base display rules above */
@media (min-width: 781px) { .adv-page .adv-ledger { display: none; } }
@media (max-width: 780px) { .adv-hero-wrap { display: none !important; } }

/* single-metric stub page (Phase 1d placeholder) */
.adv-stub {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  padding: 32px 36px;
  max-width: 880px;
  margin: 0 auto;
}
.adv-stub-head { margin-bottom: 24px; padding-bottom: 18px; border-bottom: 1px solid var(--border); }
.adv-stub-head h1 {
  font-size: 28px; color: var(--gold); margin: 0 0 8px;
  letter-spacing: -.01em; font-weight: 600;
}
.adv-stub-sub {
  font-family: var(--font-button); font-size: 11px;
  color: var(--text-tertiary); letter-spacing: .5px;
  text-transform: uppercase;
}
.adv-stub-tag {
  font-size: 15px; color: var(--text-secondary); margin: 12px 0 0;
}
.adv-stub-h {
  font-family: var(--font-button); font-size: 10.5px;
  color: var(--gold); letter-spacing: .8px;
  text-transform: uppercase; margin: 22px 0 6px;
}
.adv-stub-body {
  font-size: 14.5px; color: var(--text-primary);
  margin: 0; line-height: 1.65;
}
.adv-stub-placeholder {
  margin-top: 36px; padding: 36px 24px;
  border: 1px dashed var(--border-dashed);
  border-radius: var(--radius-card);
  text-align: center;
}
.adv-stub-placeholder h3 {
  font-size: 17px; color: var(--text-primary); margin: 14px 0 8px;
}
.back-link {
  color: var(--gold); text-decoration: none;
  font-family: var(--font-button); font-size: 12px;
  letter-spacing: .4px;
}
.back-link:hover { text-decoration: underline; }

/* Per-player × metric grid (Phase 2) */
.adv-grid-section {
  margin: 48px 0 60px;
  padding-top: 28px;
  border-top: 1px solid var(--border);
}
.adv-grid-head { margin-bottom: 16px; }
.adv-grid-title {
  font-family: var(--font-display);
  font-size: 27px; font-weight: 400; color: var(--text-primary);
  letter-spacing: -.01em; margin: 0 0 6px;
}
.adv-grid-sub {
  font-size: 13.5px; color: var(--text-secondary);
  margin: 0; max-width: 78ch; line-height: 1.55;
}
.adv-grid-wrap {
  overflow-x: auto;
  background: var(--bg-card);
  border: 0.5px solid var(--border);
  border-radius: var(--radius-card);
}
.adv-grid-table {
  width: 100%; border-collapse: collapse;
  font-size: 13.5px;
  font-family: var(--font-sans);   /* Billy #3: match .proj-table (sans, not mono) */
  /* Static column widths: auto-layout re-measured the visible rows on every
     sort/paginate, so widths jittered. Fixed layout + <colgroup> (built by
     advanced-metric-grid.js) locks them regardless of which values are on-screen. */
  table-layout: fixed;
}
.adv-grid-table col.adv-col-rank { width: 46px; }
.adv-grid-table col.adv-col-name { width: 190px; }
.adv-grid-table col.adv-col-num  { width: 76px; }
/* Tennis reuses .adv-grid-table but has its own SSR board + column set and no
   colgroup — keep it on auto layout so fixed-width doesn't squash its columns. */
.adv-grid-table.adv-tennis-table { table-layout: auto; }
.adv-grid-table th, .adv-grid-table td {
  padding: 7px 10px;
  text-align: right;
  white-space: nowrap;
  border-bottom: 1px solid var(--border);
  font-variant-numeric: tabular-nums;  /* keep columns aligned now that digits aren't monospaced */
}
/* Safety net for the rare over-wide identity cell (long player name) — clip with
   an ellipsis instead of forcing a reflow. Numeric headers are short, so this
   never touches them. */
.adv-grid-table td, .adv-grid-table tbody th { overflow: hidden; text-overflow: ellipsis; }
/* Column headers only — scoped to thead so it doesn't apply to the new
   <th scope="row"> cells in tbody (would render player names as uppercase
   button-font with bg-raised square, blocking row hover). */
/* Column headings are keys, so they take the meta face, lowercase and tracked
   out — the same treatment the projection tables already carry. ⛔ They used to
   be the body face at 600 in uppercase, which is the one place on the site the
   two table families disagreed. */
.adv-grid-table thead th {
  position: sticky; top: 0; z-index: 2;
  background: var(--bg-raised);
  font-family: var(--font-label);
  font-size: 11.5px;
  font-weight: 600;
  color: var(--text-secondary);
  letter-spacing: .06em;
  text-transform: uppercase;
  cursor: pointer;
  user-select: none;
  border-bottom: 1px solid var(--border);
}
.adv-grid-table thead th:hover { color: var(--gold); }
.adv-grid-table th.left, .adv-grid-table td.left { text-align: left; }
.adv-grid-head-link {
  color: inherit; text-decoration: none;
}
.adv-grid-head-link:hover { color: var(--gold); text-decoration: underline; }
.adv-grid-sort-arrow {
  margin-left: 4px; color: var(--gold);
}
.adv-grid-table tr:hover td { background: var(--row-hover); }
.adv-grid-table td.adv-grid-empty { color: var(--text-tertiary); }
/* 7.4 — background consistency: the identity columns (Player + related) sit on
   the plain card surface, so the metric columns must match. Previously these
   carried a faint purple/gold wash that made the right-hand columns read as a
   different color than the leftmost ~5. Unified to var(--bg-card). */
.adv-grid-side-defense,
.adv-grid-side-offense {
  background: var(--bg-card);
}
.adv-grid-table th.adv-grid-side-defense,
.adv-grid-table th.adv-grid-side-offense {
  background: var(--bg-raised);
}

/* grid pagination — 50 rows per page */
.adv-grid-pagination {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 18px;
  padding: 16px 12px;
  background: var(--bg-card);
  border-top: 1px solid var(--border);
  font-family: var(--font-meta);
  font-size: 12px;
}
.adv-grid-page-btn {
  font-family: var(--font-button);
  font-size: 13px;
  letter-spacing: .01em;
  text-transform: lowercase;
  padding: 8px 16px;
  min-height: 44px;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--radius-card, 8px);
  color: var(--text-secondary);
  cursor: pointer;
  transition: color .15s, border-color .15s, background .15s;
}
.adv-grid-page-btn:hover:not(:disabled) {
  color: var(--gold);
  border-color: var(--gold);
  background: var(--bg-inset);
}
.adv-grid-page-btn:disabled {
  opacity: .35;
  cursor: not-allowed;
}
.adv-grid-page-info {
  color: var(--text-tertiary);
  letter-spacing: .04em;
  white-space: nowrap;
}

/* Per-metric ranking page (Phase 3) */
.adv-stub-titlerow {
  display: flex; align-items: baseline; gap: 12px;
  margin-bottom: 8px;
}
.adv-stub-titlerow h1 { margin: 0; flex: 1; }
.adv-stub-placeholder { /* legacy — kept for fallback */ }

.adv-ranking-section {
  margin: 36px auto 60px;
  max-width: 1100px;
}
.adv-ranking-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; padding: 0 4px 10px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 14px;
}
/* #4 current/all-time toggle on per-metric ranking pages (mirrors tennis toggle) */
.adv-rank-toggle {
  display: inline-flex; margin-left: auto; align-self: center;
  border: 1px solid var(--border); border-radius: 8px; overflow: hidden;
}
.adv-rank-filter-btn {
  background: transparent; border: none; cursor: pointer;
  font-family: var(--font-button); font-size: 11.5px; letter-spacing: .04em;
  color: var(--text-tertiary); padding: 7px 16px;
}
.adv-rank-filter-btn + .adv-rank-filter-btn { border-left: 1px solid var(--border); }
.adv-rank-filter-btn:hover { color: var(--text-secondary); }
.adv-rank-filter-btn.active { background: var(--gold); color: #201825; font-weight: 600; }
html[data-theme="light"] .adv-rank-filter-btn.active { color: #f2f3ee; }
.adv-ranking-title {
  font-size: 20px; font-weight: 600; color: var(--text-primary); margin: 0;
}
.adv-ranking-meta {
  font-family: var(--font-button); font-size: 11px;
  color: var(--text-tertiary); letter-spacing: .5px;
  text-transform: uppercase;
}
.adv-ranking-wrap {
  overflow-x: auto;
  background: var(--bg-card);
  border: 0.5px solid var(--border);
  border-radius: var(--radius-card);
}
.adv-ranking-table {
  width: 100%; border-collapse: collapse;
  font-size: 13.5px; font-family: var(--font-sans);   /* Billy #3: match .proj-table (sans, not mono) */
  table-layout: fixed;   /* lock column widths across sorts (see .adv-grid-table note) */
}
.adv-ranking-table col.adv-col-rank { width: 46px; }
.adv-ranking-table col.adv-col-name { width: 190px; }
.adv-ranking-table col.adv-col-num  { width: 76px; }
.adv-ranking-table th, .adv-ranking-table td {
  padding: 7px 10px;
  text-align: right;
  white-space: nowrap;
  border-bottom: 1px solid var(--border);
  font-variant-numeric: tabular-nums;  /* keep columns aligned now that digits aren't monospaced */
}
.adv-ranking-table td, .adv-ranking-table tbody th { overflow: hidden; text-overflow: ellipsis; }
/* Column headers ONLY — scoped to thead so the tbody <th scope="row"> player-name
   cells don't inherit the uppercase mono button-font (they should read like the
   .proj-table player column). Matches the .adv-grid-table thead scoping. */
.adv-ranking-table thead th {
  position: sticky; top: 0; z-index: 2;
  background: var(--bg-raised);
  font-family: var(--font-button);
  font-size: 10.5px; font-weight: 600;
  color: var(--text-secondary);
  letter-spacing: .5px; text-transform: uppercase;
  border-bottom: 1px solid var(--border);
  cursor: pointer; user-select: none;
}
.adv-ranking-table thead th:hover { color: var(--gold); }
/* Row-identifier (player name) = sans body font, like .proj-table's name column. */
.adv-ranking-table tbody th {
  text-align: left;
  font-family: var(--font-sans);
  font-size: 13.5px; font-weight: 600;
  color: var(--text-primary);
  text-transform: none; letter-spacing: 0;
}
.adv-ranking-table th.left, .adv-ranking-table td.left { text-align: left; }
.adv-ranking-table th.hl, .adv-ranking-table td.hl {
  background: rgba(212, 175, 55, 0.08);
  color: var(--text-primary);
  font-weight: 600;
}
.adv-ranking-table tr:hover td { background: var(--row-hover); }
.adv-ranking-table tr:hover td.hl { background: rgba(212, 175, 55, 0.16); }
/* status pill, now carried on a ledger row */
.adv-badge {
  font-family: var(--font-meta); font-size: 10px; font-weight: 500;
  text-transform: lowercase; letter-spacing: .13em;
  padding: 3px 8px; border-radius: var(--radius-pill);
  flex: none; white-space: nowrap;
}
.badge-live { background: var(--gold); color: var(--bg-page); }
.badge-dev { background: var(--bg-inset); color: var(--gold); border: 1px solid var(--border-dashed); }
.badge-design { background: var(--bg-inset); color: var(--text-tertiary); border: 1px solid var(--border-dashed); }
.adv-empty {
  text-align: center; padding: 60px 20px;
  background: var(--bg-card);
  border: 1px dashed var(--border-dashed);
  border-radius: var(--radius-card);
}
.adv-empty-icon {
  font-family: var(--font-button); font-size: 24px;
  color: var(--text-tertiary); letter-spacing: 6px;
}
.adv-empty h3 {
  font-size: 17px; color: var(--text-primary);
  margin: 14px 0 8px; font-weight: 600;
}
.adv-empty-text {
  font-size: 13.5px; color: var(--text-secondary);
  max-width: 56ch; margin: 0 auto; line-height: 1.6;
}

/* tabbed sections: Offense / Defense / Team-Coach */
.adv-tabs {
  display: flex; gap: 4px;
  margin: 28px 0 0;
  border-bottom: 1px solid var(--border);
  padding-bottom: 0;
}
.adv-tab-btn {
  font-family: var(--font-button); font-size: 12px;
  color: var(--text-secondary);
  background: transparent; border: none;
  padding: 12px 18px; cursor: pointer;
  letter-spacing: .3px;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  transition: color .15s ease, border-color .15s ease;
}
.adv-tab-btn:hover { color: var(--gold); }
.adv-tab-btn.active {
  color: var(--gold);
  border-bottom-color: var(--gold);
}
.adv-tab-content { padding-top: 24px; }

/* in-development footer */
.adv-indev-footer {
  margin: 56px 0 60px;
  padding-top: 28px;
  border-top: 1px dashed var(--border-dashed);
}
.adv-indev-head { margin-bottom: 16px; }
.adv-indev-title {
  font-size: 16px; font-weight: 600;
  color: var(--text-secondary);
  font-family: var(--font-button);
  letter-spacing: .5px; text-transform: uppercase;
  margin: 0 0 4px;
}
.adv-indev-sub {
  font-size: 13px; color: var(--text-tertiary);
  margin: 0; max-width: 70ch;
}

/* side-grouped card sections (legacy — kept for fallback) */
.adv-side-section { margin: 32px 0 0; }
.adv-side-section:first-of-type { margin-top: 8px; }
/* Section band: hairline, label, hairline. Same shape as .hub-rule on the sport
   home pages, so the ledger below it sits in the same furniture. The metric
   count rides inside the label rather than floating at the right margin. */
.adv-side-head {
  display: flex; align-items: center; gap: 16px;
  margin: 40px 0 4px; padding: 0; border: 0;
}
.adv-side-head::before, .adv-side-head::after {
  content: ""; flex: 1 1 auto; height: 1px; background: var(--border);
}
.adv-side-title {
  flex: none; margin: 0;
  font-family: var(--font-meta); font-size: 10.5px; font-weight: 500;
  letter-spacing: .17em; text-transform: lowercase; color: var(--gold);
}

/* the ledger, on the advanced pages. Everything else it needs is already in
   .hub-ledger / .lg-row further down this file. */
.adv-ledger { margin: 6px 0 8px; }
@media (max-width: 780px) {
  /* name and arrow share the first line, the description takes the second */
  .adv-ledger .lg-row  { align-items: center; gap: 4px 14px; padding: 16px 6px; }
  .adv-ledger .lg-name { order: 0; }
  .adv-ledger .lg-go   { order: 1; }
  .adv-ledger .lg-meta { order: 2; flex: 1 1 100%; }
  .adv-ledger .lg-desc { order: 3; }
  .adv-side-head       { margin-top: 26px; }
}

/* ============================================================================
   7.5 — Supporting-copy scale-up (+20%) on the /advanced page ONLY.
   Scoped to .adv-page (added to <main> in advanced.html). Deliberately does
   NOT touch .adv-grid-table / .adv-ranking-table (data-table text stays put),
   and does NOT apply to the individual metric detail / player-card pages
   (they use .adv-main WITHOUT .adv-page, so these rules never match them).
   Values are the base font-size × 1.2.
   ============================================================================ */
/* intro block */
.adv-page .adv-intro h1        { font-size: 28.8px; }   /* 24  → 28.8 */
.adv-page .adv-intro p         { font-size: 16.8px; }   /* 14  → 16.8 */
.adv-page .adv-intro-notes li  { font-size: 16.2px; }   /* 13.5→ 16.2 */
.adv-page .adv-intro .adv-counter { font-size: 13.2px; } /* 11 → 13.2 */
/* grid section subhead + title (heading copy, not the table body) */
.adv-page .adv-grid-title      { font-size: 32.4px; }   /* 27  → 32.4 */
.adv-page .adv-grid-sub        { font-size: 16.2px; }   /* 13.5→ 16.2 */
/* tab nav */
.adv-page .adv-tab-btn         { font-size: 14.4px; }   /* 12  → 14.4 */
/* ⛔ .adv-side-title is NOT scaled here any more. It is now a band label in the
   meta face at a fixed 10.5px, the same size the sport home pages use; scaling
   it broke the rhythm against .hub-rule. The metric-card entries that used to
   sit here went with the cards. */
/* the ledger's supporting copy */
.adv-page .adv-ledger .lg-desc { font-size: 15px; }     /* 13.5→ 15 */
/* empty-state copy */
.adv-page .adv-empty-text      { font-size: 16.2px; }   /* 13.5→ 16.2 */
/* glossary supporting copy (base rules live in advanced.html <style>) */
.adv-page .adv-glossary summary        { font-size: 14.4px; }  /* 12   → 14.4 */
.adv-page .adv-glossary-intro          { font-size: 16.8px; }  /* 14   → 16.8 */
.adv-page .adv-glossary-side           { font-size: 12.6px; }  /* 10.5 → 12.6 */
.adv-page .adv-glossary-term-name      { font-size: 24px; }    /* 20   → 24   */
.adv-page .adv-glossary-term-internal  { font-size: 12.6px; }  /* 10.5 → 12.6 */
.adv-page .adv-glossary-term-tagline   { font-size: 16.2px; }  /* 13.5 → 16.2 */
.adv-page .adv-glossary-term-what,
.adv-page .adv-glossary-term-interpret { font-size: 16.2px; }  /* 13.5 → 16.2 */
.adv-page .adv-glossary-term-meta      { font-size: 12.6px; }  /* 10.5 → 12.6 */

/* prose explainer section at bottom of page */
.adv-prose-section {
  margin: 48px 0 60px;
  padding-top: 28px;
  border-top: 1px solid var(--border);
}
.adv-prose-head { margin-bottom: 22px; }
.adv-prose-title {
  font-family: var(--font-display);
  font-size: 27px; font-weight: 400; color: var(--text-primary);
  letter-spacing: -.01em; margin: 0 0 6px;
}
.adv-prose-sub {
  font-size: 13.5px; color: var(--text-secondary);
  margin: 0; max-width: 72ch; line-height: 1.55;
}
.adv-prose-side {
  font-family: var(--font-button); font-size: 11px;
  color: var(--gold); letter-spacing: .8px;
  text-transform: uppercase; margin: 28px 0 12px;
  padding-bottom: 6px; border-bottom: 1px dashed var(--border-dashed);
}
.adv-prose-item { margin: 16px 0 20px; max-width: 78ch; }
.adv-prose-name {
  font-size: 15px; font-weight: 600; color: var(--text-primary);
  margin: 0 0 6px; display: flex; gap: 10px; align-items: baseline;
}
.adv-prose-status {
  font-family: var(--font-button); font-size: 9.5px;
  color: var(--gold); letter-spacing: .6px;
  text-transform: uppercase; padding: 2px 7px;
  border: 1px solid var(--border-dashed); border-radius: var(--radius-pill);
  background: var(--bg-inset);
}
.adv-prose-text {
  font-size: 14px; color: var(--text-secondary);
  margin: 0; line-height: 1.65;
}


/* ── The top bar ──────────────────────────────────────────────
   Its rules are not in this file any more. Since 2026-10-22 every page carries
   the bar every Resolve property shares: bar3.css (byte-identical to the main
   site's) plus bar-sports.css (this site's colour names mapped onto it), built
   from api/routes/_chrome.py. The old name panel, page tabs, dropdowns and
   phone drawer that were styled here are gone with their markup. */


.board-toc {
  display: flex; gap: 10px; flex-wrap: wrap; margin-top: 16px;
}
.board-toc-pill {
  display: flex; flex-direction: column; gap: 2px;
  background: var(--bg-inset); border: 1px solid var(--border-dashed);
  border-radius: 10px; padding: 10px 14px;
  text-decoration: none; color: inherit;
  transition: border-color .12s, background .12s, transform .12s;
  min-width: 180px;
}
.board-toc-pill:hover { border-color: var(--gold); background: var(--bg-card); transform: translateY(-1px); }
.board-toc-label {
  font-family: var(--font-button); font-size: 11px; font-weight: 600;
  letter-spacing: .5px; text-transform: uppercase; color: var(--gold);
}
.board-toc-sub {
  font-family: var(--font-mono); font-size: 11.5px; color: var(--text-tertiary);
}
.tournament-hero {
  background: var(--bg-card); border: 1px solid var(--border);
  border-radius: var(--radius-card); padding: 22px 26px;
  margin: 0 0 22px;
}
.tournament-hero-inner {
  display: flex; gap: 28px; align-items: stretch;
  flex-wrap: wrap; justify-content: space-between;
}
.tournament-hero .eyebrow {
  font-family: var(--font-button); font-size: 10.5px;
  letter-spacing: .35px; text-transform: uppercase;
  color: var(--text-tertiary);
  display: block; margin-bottom: 6px;
}
.tournament-hero h1 {
  font-size: 26px; color: var(--gold); margin: 0 0 6px;
  font-weight: 600; letter-spacing: -0.01em;
}
.tournament-hero-venue {
  font-size: 13.5px; color: var(--text-secondary); margin: 0;
}
.tournament-hero-top3 { min-width: 240px; text-align: right; }
.top3-row { display: flex; gap: 14px; justify-content: flex-end; flex-wrap: wrap; }
.top3-row .top3-pick {
  background: var(--bg-inset); border: 1px solid var(--border-dashed);
  border-radius: 8px; padding: 8px 12px;
  display: flex; flex-direction: column; gap: 2px; min-width: 90px;
}
.top3-row .top3-name { font-family: var(--font-mono); font-size: 12px; color: var(--text-primary); }
.top3-row .top3-pct { font-family: var(--font-mono); font-size: 14px; color: var(--gold); font-weight: 600; }
@media (max-width: 720px) {
  .tournament-hero-inner { flex-direction: column; }
  .tournament-hero-top3 { text-align: left; }
  .top3-row { justify-content: flex-start; }
}
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

/* ── Main ────────────────────────────────────────────────────── */

main { padding: 22px 24px; max-width: 1500px; margin: 0 auto; }

.search-controls {
  display: flex; gap: 12px; align-items: center; flex-wrap: wrap;
  margin-bottom: 14px;
}
input, select {
  font-family: inherit; font-size: 14px;
  background: var(--bg-inset);
  border: 1px solid var(--border);
  border-radius: var(--radius-button);
  padding: 7px 10px;
  color: var(--text-primary);
}
input::placeholder { color: var(--text-faint); }
input:focus, select:focus {
  outline: 0;
  border-color: var(--gold);
  box-shadow: 0 0 0 2px rgba(255, 214, 98, 0.18);
}
#search { flex: 1; min-width: 220px; max-width: 340px; }

.proj-table-wrap {
  background: var(--bg-card);
  border: 0.5px solid var(--border);
  border-radius: var(--radius-card);
  overflow: auto;
  max-height: 78vh;
}
.proj-table {
  width: 100%;
  border-collapse: collapse;
}
/* Headers are the site's label style: the meta face, lowercase, wide. They used to
   be UPPERCASE at 600, which shouts a column name louder than the number under
   it and is the opposite of what a projection table is for. */
/* ── The page head, 2026-08-29 ─────────────────────────────────────────
   Title left, dateline right on the same baseline, then one line about the
   state of the thing. Settled on /usopen and shared from here so the sibling
   pages cannot drift apart — the tennis pair uses it today and the golf and
   baseball pages on Billy's list follow.

   ⛔ No summary paragraph under the title. The two written sentences that
   used to sit there were retired 08-29: a head says what this is and where
   things stand, and the numbers argue for themselves below it. */
.page-head { margin: 0 0 22px; }
.page-headline {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px 28px; flex-wrap: wrap;
}
.page-title {
  font-family: var(--font-display); font-weight: 400; font-size: 40px;
  letter-spacing: -.018em; color: var(--gold); margin: 0; line-height: 1.08;
}
.page-dateline {
  font-family: var(--font-sans); font-size: 12px; font-weight: 600;
  letter-spacing: .06em; text-transform: uppercase; color: var(--text-tertiary);
  margin: 0; text-align: right;
}
.page-status { font-size: 13.5px; font-weight: 600; color: var(--text-tertiary); margin: 12px 0 0; }
.page-status b { color: var(--gold); font-weight: 600; }

/* Section head to match: display-face title, a quiet note to its right. */
.page-sec { margin: 34px 0 0; }
.page-sec-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  border-bottom: 1px solid var(--border); padding: 0 3px 9px; margin: 0 0 14px;
}
.page-sec-head h2 {
  font-family: var(--font-display); font-weight: 400; font-size: 26px;
  color: var(--text-primary); margin: 0; letter-spacing: -.01em;
}
.page-sec-head span { font-size: 12.5px; font-weight: 600; color: var(--text-tertiary); }

/* Text tabs, the sub-nav manner — never filled pills or segmented buttons. */
.page-tabs {
  display: flex; gap: 22px; align-items: baseline; flex-wrap: wrap;
  border-bottom: 1px solid var(--border); padding-bottom: 9px; margin: 26px 0 0;
}
.page-tab {
  font-family: var(--font-sans); font-size: 14px; font-weight: 600;
  color: var(--text-tertiary); cursor: pointer; padding-bottom: 7px; margin-bottom: -10px;
  background: none; border: 0; border-bottom: 2px solid transparent;
  transition: color .12s, border-color .12s;
}
.page-tab:hover { color: var(--gold); }
.page-tab.on { color: var(--gold); border-bottom-color: var(--gold); }

/* An empty state is a sentence, set like one. `.proj-table td` sets
   text-align:right and outranks a bare class, hence the second selector. */
.page-empty, .proj-table td.page-empty {
  text-align: center; padding: 26px 14px; color: var(--text-tertiary);
  font-size: 14.5px; font-family: var(--font-sans);
}

@media (max-width: 780px) {
  .page-title { font-size: 32px; }
  .page-dateline { text-align: left; }
}

/* Golf's live scores page kept a 32px title on a phone while every other sport's read 28.9px
   (Billy said yes on 2026-11-01 to it matching; the look-alike check's L19). The 28.9 is not a
   size anyone wrote: it is clamp(24px, 7.4vw, 32px), which day-stepper.js puts on the title it
   stands the day stepper beside. That script needs the day chips to mount, and golf's live page
   is a leaderboard with no days, so it never ran there and the title stayed at the full 32. The
   same clamp, at the same width the stepper uses, so the two read alike. */
@media (max-width: 720px) {
  #tw-name.page-title { font-size: clamp(24px, 7.4vw, 32px); line-height: 1.1; }
}

/* .draft-table joined the shared table in the look-alike pass (Billy 2026-10-30, L5/L6): the nba
   board kept its own copy of these rules, which drifted to 13.5px cells at every width and no
   tabular figures, so its numbers did not line up in their columns and a phone read computer-size
   type. It is one of the family now; only what is genuinely the board's own is still scoped to it
   (the tier chip, the highlighted column, the header's z-index over the frozen name). */
.proj-table thead th,
.draft-table thead th {
  background: var(--bg-page);
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  text-align: right;
  padding: 12px 14px;
  font-family: var(--font-label);
  font-weight: 600;
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--text-secondary);
  position: sticky; top: 0; z-index: 1;
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}
.proj-table thead th.left,
.draft-table thead th.left { text-align: left; }
.proj-table thead th:hover,
.draft-table thead th:hover { color: var(--gold); }
.proj-table thead th.sort-asc::after  { content: " ▲"; font-size: 0.75em; color: var(--gold); }
.proj-table thead th.sort-desc::after { content: " ▼"; font-size: 0.75em; color: var(--gold); }

.proj-table td,
.draft-table td {
  /* Match the row-divider on the <th scope="row"> name column (1px var(--border))
     so the divider is one continuous, consistent line across the full row. Was
     0.5px var(--bg-inset) = thinner + invisible in dark mode, so the line appeared
     to change under the name column. */
  border-bottom: 1px solid var(--border-dashed);
  padding: 12px 14px;
  text-align: right;
  font-size: 14.5px;
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
}
.proj-table td.left,
.draft-table td.left { text-align: left; }
/* ⛔ FIGURES ARE NOT DECORATION. --gold-text-soft painted every number in a
   muted sage, which made the whole grid quieter than the row labels beside it.
   Numbers are the content on this site; they take full ink. */
.proj-table td.num {
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
}

/* B.6 — NFL teams table: left-align all cells to the header's left edge. Scoped
   to .nfl-teams-table so other sports keep their right-aligned numerics. Row
   dividers now inherit the canonical .proj-table td rule (1px var(--border)) so
   the divider weight matches every other table site-wide. */
.proj-table.nfl-teams-table th,
.proj-table.nfl-teams-table td { text-align: left; }
/* Batch 15 (spec 4c/6.3/7/8.2) — extend the same left-align convention to the
   NBA power-ratings, NBA + NFL player-projection, and NBA team tables: each
   column's values share a left edge with its header. NFL team (8.1) already
   uses .nfl-teams-table above and is confirmed good as-is. */
.proj-table.nba-ratings-table th,
.proj-table.nba-ratings-table td,
.proj-table.nfl-position-table th,
.proj-table.nfl-position-table td,
.proj-table.nba-players-table th,
.proj-table.nba-players-table td,
.proj-table.nba-teams-table th,
.proj-table.nba-teams-table td,
.proj-table.nba-draftboard-table th,
.proj-table.nba-draftboard-table td { text-align: left; }
/* Batch 15 (8.3) — "how these are projected" methodology link for the player /
   team projection pages that lacked one. Mirrors nfl-teams' .teams-method-link. */
.proj-method-row { margin: 0 2px 14px; }
.proj-method-row a { color: var(--text-tertiary); font-size: 12.5px; text-decoration: none; transition: color .15s ease; }
.proj-method-row a:hover { color: var(--gold); }
.proj-table tbody tr:hover { background: var(--row-hover); }

.pos-pill {
  display: inline-block;
  padding: 2px 8px;
  border-radius: var(--radius-pill);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .4px;
  background: var(--bg-inset);
  border: 0.5px solid var(--border);
  text-transform: uppercase;
}
.pos-QB  { color: #C8A8E8; border-color: #6F3E9D; }
.pos-RB  { color: #E8A87C; border-color: #B97A4F; }
.pos-WR  { color: #64A973; border-color: #5F7A50; }
.pos-TE  { color: #B89547; border-color: #8A7B3E; }
.pos-K   { color: #9A8DB4; border-color: #5A4F75; }
.pos-DEF { color: #D78380; border-color: #844232; }
.pos-DL  { color: #B4A5E8; border-color: #6E5FB0; }
.pos-LB  { color: #88C9C2; border-color: #4F8580; }
.pos-DB  { color: #E0A8C7; border-color: #94587A; }
/* NBA 3-position scheme */
.pos-Guard   { color: #A8B8E8; border-color: #5A6FB0; }
.pos-Forward { color: #E8A87C; border-color: #B97A4F; }
.pos-Center  { color: #B89547; border-color: #8A7B3E; }
/* Light mode: the pill tints above are tuned for a dark background and wash
   out on the lilac light palette. Darken position labels (PG/SG/SF/PF/C and
   the Guard/Forward/Center pills) to a legible dark plum. Shared rule covers
   both the Players and Playoff Stats tables. */
html[data-theme="light"] .pos-pill {
  color: #1F2E26;
  border-color: var(--border);
}

/* ── Staleness banner (between-playoffs notice) ──────────────── */

.staleness-banner {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 22px;
  margin: 16px 28px 0;
  background: rgba(255, 214, 98, 0.10);
  border: 0.5px solid rgba(255, 214, 98, 0.35);
  border-radius: var(--radius-card);
  color: var(--text-secondary);
  font-size: 13px;
  letter-spacing: .1px;
}
.staleness-banner i { color: var(--gold); font-size: 16px; flex-shrink: 0; }

/* ── NFL IDP position chips (sub-filter on /idp) ─────────────── */

.idp-position-chips,
.position-chips {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
.idp-position-chips { padding: 14px 28px 0; }
.position-chips { padding: 0; align-items: center; }
.idp-chip,
.position-chip {
  display: inline-flex; align-items: center;
  padding: 6px 14px;
  background: var(--bg-card);
  color: var(--text-secondary);
  border: 0.5px solid var(--border);
  border-radius: var(--radius-pill);
  font: inherit;
  font-size: 12px;
  letter-spacing: .6px;
  text-transform: uppercase;
  cursor: pointer;
  transition: border-color .12s, color .12s, background .12s;
}
.idp-chip:hover,
.position-chip:hover { color: var(--text-primary); border-color: var(--gold); }
.idp-chip.active,
.position-chip.active {
  background: var(--gold);
  color: var(--bg-page);
  border-color: var(--gold);
  font-weight: 700;
}

/* ── NFL: bye-week row tint + aggregation-note + team-row note ── */

.proj-table tr.row-bye td { opacity: .45; }
.aggregation-note {
  font-size: 12px;
  color: var(--text-tertiary);
  margin: 0;
}

/* ── NBA home page (cards layout) ────────────────────────────── */

.nba-home {
  max-width: 960px;
  margin: 0 auto;
  padding: 56px 28px 80px;
}
.nba-hero {
  text-align: left;
  padding-bottom: 40px;
  border-bottom: 0.5px solid var(--border);
  margin-bottom: 0; /* image-backed .nba-mid starts immediately below break line */
}

/* Image-backed mid section: image meets natural break lines above + below.
   All sport-mids share styles; only the background image url differs. */
.nba-mid, .wnba-mid, .nfl-mid, .mlb-mid, .nhl-mid, .futbol-mid, .pga-mid {
  position: relative;
  padding: 48px 0;
  margin-bottom: 0;
}
.nba-mid::before, .wnba-mid::before, .nfl-mid::before,
.mlb-mid::before, .nhl-mid::before, .futbol-mid::before, .pga-mid::before {
  content: '';
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  mask-image: linear-gradient(to right, transparent 0%, black 25%, black 75%, transparent 100%);
  -webkit-mask-image: linear-gradient(to right, transparent 0%, black 25%, black 75%, transparent 100%);
  opacity: 0.575;
  z-index: 0;
  pointer-events: none;
}
.nba-mid::before    { background-image: url('/static/nba-bg.jpg'); }
.wnba-mid::before   { background-image: url('/static/wnba-bg.jpg'); }
.nfl-mid::before    { background-image: url('/static/nfl-bg.jpg'); }
.mlb-mid::before    { background-image: url('/static/mlb-bg.jpg'); }
.nhl-mid::before    { background-image: url('/static/nhl-bg.jpg'); }
.futbol-mid::before { background-image: url('/static/futbol-bg.jpg'); }
.pga-mid::before    { background-image: url('/static/pga-bg.jpg'); }
.nba-mid > *, .wnba-mid > *, .nfl-mid > *,
.mlb-mid > *, .nhl-mid > *, .futbol-mid > *, .pga-mid > * { position: relative; z-index: 1; }
/* Mobile: narrow the horizontal fade so the bg picture stays mostly visible
   at iPhone widths (375px). Desktop 20% fade × 2 sides = 150px lost on 375px. */
@media (max-width: 720px) {
  .nba-mid::before, .wnba-mid::before, .nfl-mid::before,
  .mlb-mid::before, .nhl-mid::before, .futbol-mid::before, .pga-mid::before {
    mask-image: linear-gradient(to right, transparent 0%, black 8%, black 92%, transparent 100%);
    -webkit-mask-image: linear-gradient(to right, transparent 0%, black 8%, black 92%, transparent 100%);
  }
  .nba-mid, .wnba-mid, .nfl-mid, .mlb-mid, .nhl-mid, .futbol-mid, .pga-mid {
    padding: 24px 0;
  }
}

/* Click-to-expand position group (NFL) — <details> styled to look like .hub-link */
.hub-link-group {
  border-bottom: 0.5px solid var(--bg-page);
}
.hub-link-group > summary {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 8px;
  color: var(--gold);
  font-size: 35px; font-weight: 700;
  text-decoration: none;
  cursor: pointer;
  list-style: none;
  text-shadow:
    0 0 4px var(--bg-page),
    0 0 8px var(--bg-page),
    0 2px 6px rgba(0, 0, 0, 0.85);
  transition: color .15s, padding-left .15s;
}
.hub-link-group > summary::-webkit-details-marker { display: none; }
.hub-link-group > summary > i {
  color: var(--gold); font-size: 28px;
  text-shadow:
    0 0 4px var(--bg-page),
    0 0 8px var(--bg-page),
    0 2px 6px rgba(0, 0, 0, 0.85);
  transition: transform .2s ease;
}
.hub-link-group[open] > summary > i { transform: rotate(90deg); }
.hub-link-group > summary:hover { padding-left: 14px; }
.hub-link-children {
  padding-left: 20px;
}
.hub-link-children .hub-link {
  font-size: 17px;
  border-bottom-color: transparent;
}
.hub-link-children .hub-link:last-child {
  border-bottom-color: var(--bg-page);
}

/* === Sticky first column on horizontally-scrolling tables ===========
   Anchors the player/team name so users don't lose their row when
   scrolling right across the wide stat columns. Applies to:
     - .proj-table        (per-sport projection tables)
     - .adv-grid-table    (advanced player × metric grid)
     - .adv-ranking-table (per-metric ranking page)
   Stacking strategy:
     - sticky-top header cells (existing):  z-index 1 or 2
     - sticky-left body cells (new):        z-index 1
     - top-left intersection (new):         z-index 3 (above both axes)
*/
.proj-table th:first-child,
.proj-table td:first-child,
.adv-grid-table th:first-child,
.adv-grid-table td:first-child,
.adv-ranking-table th:first-child,
.adv-ranking-table td:first-child {
  position: sticky;
  left: 0;
}
/* Opaque background on body cells so scrolling columns pass behind, not through */
.proj-table td:first-child,
.adv-grid-table td:first-child,
.adv-ranking-table td:first-child {
  background: var(--bg-card);
  z-index: 1;
}
/* Row hover — keep sticky cell matched to the rest of the row */
.proj-table tbody tr:hover td:first-child,
.adv-grid-table tbody tr:hover td:first-child,
.adv-ranking-table tr:hover td:first-child {
  background: var(--row-hover);
}
/* Top-left intersection — must outrank both sticky-top and sticky-left */
.proj-table thead th:first-child,
.adv-grid-table thead th:first-child,
.adv-ranking-table thead th:first-child {
  z-index: 3;
}
/* Subtle right edge so the user sees where the frozen column ends */
.proj-table td:first-child,
.proj-table th:first-child,
.adv-grid-table td:first-child,
.adv-grid-table th:first-child,
.adv-ranking-table td:first-child,
.adv-ranking-table th:first-child {
  border-right: 0.5px solid var(--border);
}
/* Draft board exception — its first column is the board rank (#), not the
   player, so freezing only column one froze a number and let the NAME scroll
   away. A league can now switch on 13 categories, so that scroll is long and
   the name is exactly what you need kept. Freeze both: a fixed-width # column
   gives the name cell a stable offset to sit at. */
.proj-table.nba-draftboard-table th:first-child,
.proj-table.nba-draftboard-table td:first-child { width: 46px; min-width: 46px; border-right: 0; }
/* Columns 2 and 3 are the player and VALUE — who, and how good. They are the
   pair you read every other column AGAINST, so both ride along at the fold.
   The offsets come from JS (renderDraft → freezeLeftEdge): the name column has
   a min-width but grows with the viewport, so they cannot be written here. */
.proj-table.nba-draftboard-table tbody th:nth-child(2),
.proj-table.nba-draftboard-table thead th:nth-child(2),
.proj-table.nba-draftboard-table tbody td:nth-child(3),
.proj-table.nba-draftboard-table thead th:nth-child(3) {
  position: sticky;
  background: var(--bg-card);
  z-index: 1;
}
.proj-table.nba-draftboard-table tbody th:nth-child(2),
.proj-table.nba-draftboard-table thead th:nth-child(2) { left: var(--freeze-1, 46px); }
.proj-table.nba-draftboard-table tbody td:nth-child(3),
.proj-table.nba-draftboard-table thead th:nth-child(3) {
  left: var(--freeze-2, 270px);
  /* A border alone is not enough at the fold: the column passing beyond it
     reads as broken layout. The shadow makes it read as content passing under. */
  border-right: 0.5px solid var(--border);
  box-shadow: 11px 0 14px -7px rgba(0, 0, 0, .62);
}
/* The header strip is --bg-page, not --bg-card: a frozen header cell that
   borrowed the body colour would read as a seam down the header row. */
.proj-table.nba-draftboard-table thead th:nth-child(2),
.proj-table.nba-draftboard-table thead th:nth-child(3) { z-index: 3; background: var(--bg-page); }
.proj-table.nba-draftboard-table tbody tr:hover th:nth-child(2),
.proj-table.nba-draftboard-table tbody tr:hover td:nth-child(3) { background: var(--row-hover); }
/* === end sticky first column ====================================== */

/* === SEO TABLES — Gemini-blueprint semantics, visually invisible ====
   Goal: emit <caption>, <th scope="col">, <th scope="row">, data-metric=
   attrs so AI crawlers can parse the table without seeing any visual
   change from the human-facing render. */

/* 1. Captions: visually hidden, still readable by bots + screen readers */
.proj-table caption,
.adv-grid-table caption,
.adv-ranking-table caption {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* 2. <th scope="row"> in tbody: must visually match <td> exactly so the
      semantic upgrade is invisible. Mirrors .proj-table td block above.
      draft-table + sched-table joined the list in the tables pass follow-up:
      their row identifiers (prospects, teams) take the same Didone treatment
      every other table's names get. */
.proj-table tbody th,
.draft-table tbody th,
.sched-table tbody th,
.adv-grid-table tbody th,
.adv-ranking-table tbody th {
  font-weight: 400;
  text-align: left;
  color: var(--text-primary);
  background: var(--bg-card);
  padding: 9px 14px;
  /* 7.3/7.6 — match the row-divider used on every <td> (line ~425) so the
     player-names column's bottom border is continuous across the full row.
     Was var(--bg-inset), which equals the cell bg in dark mode → invisible. */
  border-bottom: 1px solid var(--border-dashed);
  /* The row label is the one place the Didone appears inside a table, and it
     is what makes a projection grid read as a document rather than a export. */
  font-family: var(--font-display);
  font-size: 20px;
  letter-spacing: -.01em;
  padding: 12px 14px;
  /* A Didone at 20px needs the room. Without a floor the name column collapses
     to the width of the shortest name and every long one wraps to two lines,
     which doubles the row height of half the table. */
  min-width: 224px;
}

/* 3. Extend first-column body cell rules that only matched td:first-child.
      The new row-header is <th scope="row">, so add tbody th:first-child
      to every selector that used to be td:first-child for body styling. */
.proj-table tbody th:first-child,
.draft-table tbody th:first-child,
.adv-grid-table tbody th:first-child,
.adv-ranking-table tbody th:first-child {
  background: var(--bg-card);
  z-index: 1;
}
.proj-table tbody tr:hover th:first-child,
.draft-table tbody tr:hover th:first-child,
.adv-grid-table tbody tr:hover th:first-child,
.adv-ranking-table tr:hover th:first-child {
  background: var(--row-hover);
}

/* The two wnba tables carry a rank column first, so their row label is the
   SECOND cell and the :first-child hover rules above miss it. Without this the
   name keeps --bg-card while the rest of the row lifts, which reads as a hole
   in the row. Same fix, same reason, as the draft board's nth-child(2) above. */
.proj-table.wnba-players-table tbody tr:hover th,
.proj-table.wnba-teams-table tbody tr:hover th {
  background: var(--row-hover);
}

/* Tables-pass follow-up (Billy: EVERY table wears the /players clothes) —
   scoped deltas for the two joiners that are not entity grids at full size:

   · .percat-table (the /tools trade + add/drop result strips): the row label
     is a stat CATEGORY, not an entity, so it keeps body type instead of the
     20px Didone, and drops the 224px name-column floor a nine-row strip
     doesn't need. The wrap carries data-tt="off" — no search bar on a strip.
   · .sched-table (the NFL schedule matrix): team abbreviations take the
     Didone like every ratings page, but sized for a 19-column grid, without
     the name-column floor, and keeping their sticky-left card background. */
.proj-table.percat-table tbody th {
  font-family: var(--font-sans);
  font-size: 13.5px;
  letter-spacing: 0;
  min-width: 0;
}
.sched-table tbody th {
  font-size: 17px;
  min-width: 0;
  position: sticky; left: 0;
  background: var(--bg-page);
  z-index: 1;
}
.sched-table tbody tr:hover th {
  background: var(--row-hover);
}

/* 4. Add hover to the two table classes that didn't have it (draft-table,
      sched-table) — uses the same --row-hover var for consistency. */
.draft-table tbody tr:hover,
.sched-table tbody tr:hover {
  background: var(--row-hover);
}
.draft-table tbody tr:hover td:first-child,
.draft-table tbody tr:hover th:first-child,
.sched-table tbody tr:hover td:first-child,
.sched-table tbody tr:hover th:first-child {
  background: var(--row-hover);
}
/* The wnba board puts the board rank first, so its row label is the SECOND cell and the
   :first-child rules above miss it. Without this the name keeps --bg-card while the rest of the
   row lifts, which reads as a hole in the row. Same reason as the nba board's nth-child(2). */
.proj-table.wnba-draft-table tbody tr:hover th {
  background: var(--row-hover);
}
/* === end SEO tables ============================================== */
.nba-hero .eyebrow {
  display: inline-block;
  font-size: 15px; font-weight: 600;
  letter-spacing: 2.2px;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: 18px;
}
.nba-hero .hero-title {
  font-size: clamp(49px, 8.1vw, 76px);
  line-height: 1;
  letter-spacing: -1px;
  font-weight: 400;
  color: var(--gold);
  margin: 0 0 18px;
}
/* ⛔ REMOVED 2026-08-25: .hero-glow, the last surviving copy of the lilac halo
   that used to sit behind .adv-page-title. No page carries the span any more, so
   the rules were dead as well as against the house rule of borders, not shadows.
   The only page still using .nba-hero at all is ncaa-wcbb.html, whose heading is
   included in the 400 above; that page was NOT otherwise part of this pass. */
.nba-hero .hero-tagline {
  max-width: 58ch;
  color: var(--text-secondary);
  font-size: 20px;
  line-height: 1.6;
  margin: 0;
}

.nba-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 16px;
}

/* sport hub — single CTA button + list-of-links replacement for the old card grid */
.hub-cta {
  display: flex; justify-content: center;
  gap: 14px; flex-wrap: wrap;
  margin: 0 auto 40px;
}
.hub-btn-primary {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 14px 26px;
  background: var(--gold);
  color: var(--bg-page);
  font-size: 15px; font-weight: 600;
  letter-spacing: .2px;
  border-radius: 8px;
  text-decoration: none;
  transition: filter .15s, transform .15s;
}
.hub-btn-primary i { font-size: 17px; }
.hub-btn-primary:hover { filter: brightness(1.08); transform: translateY(-1px); }

.hub-sections {
  max-width: 620px;
  margin: 0 auto;
  display: flex; flex-direction: column;
}
.hub-sections-label {
  font-family: var(--font-mono);
  font-size: 15px; font-weight: 700; letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--gold);
  text-shadow:
    0 0 3px var(--bg-page),
    0 0 6px var(--bg-page),
    0 1px 4px rgba(0, 0, 0, 0.85);
  text-align: center;
  padding-bottom: 14px;
  margin-bottom: 8px;
  border-bottom: 0.5px solid var(--border);
}
/* B.2 — NFL home: top-level section headers match the Positions summary (35px),
   bringing the larger .hub-link headers down. Scoped to .nfl-mid so other sports
   and the positions-dropdown children (.hub-link-children .hub-link) are untouched. */
.nfl-mid .hub-sections > .hub-link { font-size: 35px; }
/* B.2b — NBA home: match NFL's 35px section headers so the two flagship home
   pages read at the same scale. Same (0,3,0) scoping as .nfl-mid, so it also
   holds on mobile (out-specifies the 22px base .hub-link). */
.nba-mid .hub-sections > .hub-link { font-size: 35px; }
.hub-link {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 8px;
  color: var(--gold);
  font-size: 49px; font-weight: 700;
  text-decoration: none;
  border-bottom: 0.5px solid var(--bg-page);
  text-shadow:
    0 0 4px var(--bg-page),
    0 0 8px var(--bg-page),
    0 2px 6px rgba(0, 0, 0, 0.85);
  transition: color .15s, padding-left .15s;
}
.hub-link i {
  color: var(--gold); font-size: 28px;
  text-shadow:
    0 0 4px var(--bg-page),
    0 0 8px var(--bg-page),
    0 2px 6px rgba(0, 0, 0, 0.85);
  transition: color .15s, transform .15s;
}
.hub-link:hover { color: var(--gold); padding-left: 14px; }
.hub-link:hover i { color: var(--gold); transform: translateX(4px); }
.hub-link:last-child { border-bottom: 0; }

/* Light-mode: olive accent on lilac bg (matches sage on charcoal in dark).
   Text color shifts gold→olive automatically since --gold IS olive in light. */
html[data-theme="light"] .hub-sections-label,
html[data-theme="light"] .hub-link,
html[data-theme="light"] .hub-link i,
html[data-theme="light"] .hub-link-group > summary,
html[data-theme="light"] .hub-link-group > summary > i {
  color: var(--gold);
}
/* Hover stays olive */
html[data-theme="light"] .hub-link:hover,
html[data-theme="light"] .hub-link:hover i,
html[data-theme="light"] .hub-link-group > summary:hover,
html[data-theme="light"] .hub-link-group > summary:hover > i {
  color: var(--gold);
}
/* NBA/NFL drafter button (.hub-btn-primary): olive bg + lilac text (matches
   apex .chip.primary pattern: accent fill + bg-color text). */
html[data-theme="light"] .hub-btn-primary {
  background: var(--gold);
  color: var(--bg-page);
}

/* ─── dark-mode invert on hub-link family (sage palette 2026-06-25)
   Goal: legibility OVER the bg picture. Charcoal text + thin sage outline
   + sage halo glow. Letters punch dark against the photo; sage halo
   stops them from disappearing into the dark bg. */
.hub-link,
.hub-sections-label,
.hub-link-group > summary,
.hub-link i,
.hub-link-group > summary > i {
  color: var(--bg-page);
  /* text-stroke disabled 2026-06-26 — uncomment to bring back the sage outline */
  /* -webkit-text-stroke: 0.20px var(--gold); */
  text-shadow:
    0 0 4px  var(--gold),
    0 0 8px  var(--gold),
    0 0 20px rgba(122,173,142,.35),
    0 2px 6px rgba(0,0,0,.90);
}
.hub-link:hover, .hub-link:hover i,
.hub-link-group > summary:hover,
.hub-link-group > summary:hover > i {
  color: var(--bg-page);
}
.hub-btn-primary {
  border: 0.5px solid var(--bg-page);
  box-shadow:
    0 0 20px rgba(122,173,142,.30),
    0 0 6px  rgba(122,173,142,.40);
}
html[data-theme="light"] .hub-link,
html[data-theme="light"] .hub-sections-label,
html[data-theme="light"] .hub-link-group > summary,
html[data-theme="light"] .hub-link i,
html[data-theme="light"] .hub-link-group > summary > i {
  /* text-stroke disabled 2026-06-26 — uncomment to bring back the lavender outline */
  /* -webkit-text-stroke: 0.20px var(--bg-page); */
  text-shadow:
    0 0 4px  var(--bg-page),
    0 0 8px  var(--bg-page),
    0 0 20px rgba(232,215,241,.35),
    0 2px 6px rgba(0,0,0,.90);
}
html[data-theme="light"] .hub-btn-primary {
  box-shadow:
    0 0 20px rgba(58,71,34,.30),
    0 0 6px  rgba(58,71,34,.40);
}

/* divider between hub blocks */
.hub-divider {
  border: 0;
  border-top: 0.5px solid var(--border);
  margin: 0 auto 56px;
  max-width: 720px;
}

/* shared block heading for hub-postings + hub-proof */
.hub-block-head {
  font-family: var(--font-mono);
  font-size: 11px; letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--text-faint);
  text-align: center;
  margin-bottom: 28px;
}

/* release notes / postings */
.hub-postings {
  max-width: 1040px;
  margin: 0 auto;
}
.hub-postings-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 14px;
}
.hub-post {
  display: flex; flex-direction: column;
  padding: 18px 20px;
  background: var(--bg-card);
  border: 0.5px solid var(--border);
  border-radius: var(--radius-card);
  transition: border-color .15s, background .15s;
}
.hub-post:hover { border-color: var(--gold); background: var(--bg-inset); }
.hub-post.placeholder {
  border-style: dashed;
  border-color: var(--border-dashed);
  background: transparent;
}
.hub-post.placeholder:hover {
  border-color: var(--border-dashed); background: transparent;
}
.hub-post .post-date {
  font-family: var(--font-mono);
  font-size: 11px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--text-faint);
}
.hub-post h4 {
  font-size: 15px; font-weight: 600; color: var(--text-tertiary);
  letter-spacing: -.005em;
  margin: 8px 0 6px;
  font-weight: 400;
}
.hub-post p {
  font-size: 13px; color: var(--text-faint);
}

/* proven accuracy / social proof */
.hub-proof {
  max-width: 1040px;
  margin: 0 auto;
}
.hub-proof-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 16px;
}
.hub-proof-card {
  padding: 28px 24px;
  background: var(--bg-card);
  border: 0.5px solid var(--border);
  border-radius: var(--radius-card);
  text-align: center;
}
.hub-proof-number {
  font-size: 42px;
  font-weight: 700;
  color: var(--gold);
  letter-spacing: -.02em;
  line-height: 1;
  margin-bottom: 14px;
}
.hub-proof-label {
  font-size: 15px;
  color: var(--text-primary);
  line-height: 1.4;
  margin-bottom: 12px;
}
.hub-proof-meta {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .04em;
  color: var(--text-faint);
  line-height: 1.5;
}

@media (max-width: 620px) {
  .hub-btn-primary { padding: 12px 20px; font-size: 14px; }
  .hub-link { font-size: 22px; padding: 14px 10px; }
  .hub-link i { font-size: 20px; }
  /* NFL positions <details> dropdown — was stuck at desktop 25px on mobile */
  .hub-link-group > summary { font-size: 22px; padding: 14px 10px; }
  .hub-link-group > summary > i { font-size: 20px; }
  /* NFL sections list: its <a> siblings render at 35px on mobile because
     `.nfl-mid .hub-sections > .hub-link` (0,3,0) out-specifies the base
     `.hub-link` 22px above. The positions <summary> only got the 22px rule,
     so it looked smaller. Match it to the siblings — scoped to .nfl-mid so
     futbol's summary + siblings stay matched at 22px. */
  .nfl-mid .hub-sections > .hub-link-group > summary { font-size: 35px; }
  .hub-link-children { padding-left: 14px; }
  .hub-link-children .hub-link { font-size: 15px; padding: 12px 8px; }
  /* SECTIONS label scaling */
  .hub-sections-label { font-size: 13px; letter-spacing: .18em; padding-bottom: 10px; }
  .hub-sections { max-width: 100%; }
  .hub-cta { margin: 0 auto 28px; }
  .hub-divider { margin: 36px auto; }
  .hub-proof-number { font-size: 36px; }
  .hub-proof-card { padding: 20px 16px; }
  .hub-proof-label { font-size: 14px; }
  .hub-proof-meta { font-size: 10.5px; }
  .hub-block-head { margin-bottom: 18px; }
  .hub-post { padding: 14px 16px; }
  .hub-post h4 { font-size: 14px; }
  .hub-post p { font-size: 12.5px; }
}
.nba-card {
  display: flex;
  flex-direction: column;
  padding: 24px 22px 20px;
  background: var(--bg-card);
  border: 0.5px solid var(--border);
  border-radius: var(--radius-card);
  color: inherit;
  text-decoration: none;
  transition: border-color .15s, background .15s, transform .15s;
  position: relative;
}
.nba-card:hover {
  border-color: var(--gold);
  background: var(--bg-inset);
  transform: translateY(-2px);
}
.nba-card.coming { opacity: .65; }
.nba-card.coming:hover {
  transform: none;
  border-color: var(--border);
  background: var(--bg-card);
  cursor: default;
}
.nba-card.coming .nba-card-cta { display: none; }
.nba-card-icon {
  width: 40px; height: 40px;
  display: flex; align-items: center; justify-content: center;
  background: var(--bg-inset);
  color: var(--gold);
  border-radius: var(--radius-button);
  font-size: 20px;
  margin-bottom: 14px;
}
.nba-card h2 {
  font-size: 21px;
  font-weight: 400;
  color: var(--text-primary);
  margin: 0 0 6px;
  letter-spacing: -.01em;
}
.nba-card p {
  font-size: 13.5px;
  color: var(--text-secondary);
  margin: 0 0 14px;
  flex: 1;
  line-height: 1.55;
}
.nba-card-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  font-size: 11px;
  font-family: var(--font-mono);
  letter-spacing: .8px;
  text-transform: uppercase;
  color: var(--text-faint);
  padding-top: 12px;
  border-top: 0.5px solid var(--border);
}
.nba-card-meta .dot { opacity: .6; }
.nba-card-cta {
  margin-top: 14px;
  display: flex; align-items: center; gap: 6px;
  font-size: 11px; font-family: var(--font-mono);
  letter-spacing: .9px; text-transform: uppercase;
  color: var(--gold);
  opacity: 0;
  transform: translateX(-4px);
  transition: opacity .15s, transform .15s;
}
.nba-card:hover .nba-card-cta { opacity: 1; transform: translateX(0); }

/* ── Stub page (NBA / NHL "coming soon") ─────────────────────── */

.stub-card {
  background: var(--bg-card);
  border: 0.5px solid var(--border);
  border-radius: var(--radius-card);
  padding: 48px;
  text-align: center;
  max-width: 560px;
  margin: 60px auto;
}
.stub-card .icon { font-size: 56px; color: var(--gold); margin-bottom: 20px; }
.stub-card h2 {
  font-size: 22px; font-weight: 700;
  color: var(--text-primary);
  margin: 0 0 12px;
  letter-spacing: -.2px;
}
.stub-card p {
  font-size: 14px;
  color: var(--text-secondary);
  line-height: 1.6;
  margin: 0 0 24px;
}
.stub-card .eyebrow {
  display: inline-block;
  font-size: 11px; font-weight: 600;
  color: var(--gold);
  background: var(--bg-inset);
  border-radius: var(--radius-pill);
  padding: 5px 14px;
  letter-spacing: .6px;
  text-transform: uppercase;
  margin-bottom: 18px;
}
.stub-card .stub-link-line {
  font-size: 13px; color: var(--text-tertiary);
  margin: 18px 0 0; padding-top: 16px;
  border-top: 1px solid var(--border);
}
.stub-card .stub-link-line a { color: var(--gold); text-decoration: none; }
.stub-card .stub-link-line a:hover { text-decoration: underline; }

/* ── Loading + error states ──────────────────────────────────── */

.state-msg {
  padding: 32px;
  text-align: center;
  font-size: 14px;
  color: var(--text-faint);
}
.state-msg.error { color: #D78380; }


/* === Mobile responsive enhancements (added 2026-06-22) =============
   Applies a comprehensive set of mobile rules across every sport page
   that uses this shared stylesheet. Built around the existing 720px
   breakpoint plus a 380px ultra-narrow break for tiny phones. */

@media (max-width: 720px) {

  /* ── Main containers ── */
  main { padding: 16px 12px; max-width: 100%; }
  .nba-home { padding: 32px 16px 48px; max-width: 100%; }

  /* ── Hero ── */
  .nba-hero { padding-bottom: 24px; margin-bottom: 28px; }
  .nba-hero .eyebrow { font-size: 10px; margin-bottom: 12px; letter-spacing: 1.8px; }
  .nba-hero .hero-tagline { font-size: 14px; line-height: 1.55; max-width: none; }

  /* ── Card grids — always single column on mobile ── */
  .nba-cards { grid-template-columns: 1fr; gap: 12px; }
  .nba-card { padding: 18px 16px 16px; }
  .nba-card-icon { width: 36px; height: 36px; font-size: 18px; margin-bottom: 10px; }
  .nba-card h2 { font-size: 19px; }
  .nba-card p { font-size: 13px; line-height: 1.5; }
  .nba-card-meta { font-size: 10.5px; letter-spacing: .6px; }
  .nba-card-cta { opacity: 1; transform: none; font-size: 10.5px; }

  /* ── Projection / advanced tables — horizontal scroll affordance ── */
  .proj-table-wrap,
  .adv-grid-wrap,
  .adv-ranking-wrap {
    max-height: none;
    -webkit-overflow-scrolling: touch;
    border-radius: 8px;
    /* right-edge fade hint that there's more to swipe to */
    box-shadow: inset -10px 0 12px -10px rgba(0, 0, 0, .45);
  }
  .proj-table th,
  .draft-table th,
  .adv-grid-table th,
  .adv-ranking-table th {
    padding: 10px 8px;
    font-size: 10px;
    letter-spacing: .4px;
  }
  .proj-table td,
  .draft-table td,
  .adv-grid-table td,
  .adv-ranking-table td {
    padding: 8px 8px;
    font-size: 12px;
  }
  /* Sticky-col on mobile: rely on the universal first-child rules (lines ~1013)
     for position/bg; just keep hover bg matched for visual continuity. */
  .proj-table tbody tr:hover td:first-child,
  .adv-grid-table tbody tr:hover td:first-child,
  .adv-ranking-table tbody tr:hover td:first-child {
    background: var(--row-hover);
  }

  /* Search controls stack vertically; inputs fill the row. */
  .search-controls {
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
  }
  .search-controls > * { width: 100%; max-width: none; }
  #search { max-width: none; min-width: 0; }

  /* WC tables (futbol pages) same treatment */
  .wc-wrap { -webkit-overflow-scrolling: touch; }
  .wc-table th, .wc-table td { padding: 6px 7px; font-size: 11px; }
  .wc-table th.left:first-of-type,
  .wc-table td.left:first-of-type {
    position: sticky; left: 0;
    background: var(--bg-card);
    z-index: 1;
    box-shadow: 1px 0 0 0 var(--border);
  }
  .wc-table th.left:first-of-type {
    background: var(--bg-raised);
    z-index: 3;
  }

  /* WC two-column rows collapse to single column */
  .wc-row-2col { grid-template-columns: 1fr; gap: 28px; }

  /* "Show all / show less" toggle injected by mobile.js */
  .mobile-row-toggle {
    display: block;
    width: 100%;
    padding: 12px;
    margin-top: 4px;
    background: var(--bg-card);
    border: 0.5px solid var(--border);
    border-radius: 8px;
    color: var(--gold);
    font-family: var(--font-mono);
    font-size: 12px;
    letter-spacing: .5px;
    text-transform: lowercase;
    cursor: pointer;
    text-align: center;
    transition: background .12s, border-color .12s;
  }
  .mobile-row-toggle:hover,
  .mobile-row-toggle:focus-visible {
    background: var(--bg-inset);
    border-color: var(--gold);
    outline: none;
  }
}

/* Ultra-narrow phones (<= 380px) — shrink hero title. */
@media (max-width: 380px) {
  .nba-hero .hero-title { font-size: 30px; }
  .nba-hero .hero-tagline { font-size: 13.5px; }
}
/* === end mobile responsive enhancements ============================ */

/* /fantasy — full-width table, watch lists spanning the page underneath.
   NOTE: `main` caps at 1500px (see ~L1108). Anything inside it is bounded by
   that cap, so widening the layout has to be done on `main` itself, scoped to
   this page via body.page-fantasy — never on the global rule, which the seven
   sibling position pages share. */
body.page-fantasy main { max-width: 2100px; padding-left: 20px; padding-right: 20px; }

/* One row across the full page width: table | Fades | Due For a Bump.
   The table column is minmax(0,1fr) so it absorbs every pixel of slack — the
   rails are fixed, so a wider page widens ONLY the table. */
.fantasy-layout {
  display: grid; grid-template-columns: minmax(0, 1fr) 330px 330px;
  gap: 34px; align-items: start;
}
.fantasy-main { min-width: 0; }     /* lets the table scroll instead of blowing out */
.watch-lists { display: contents; } /* the two lists become columns of that same row */
.watch-col { min-width: 0; }

/* Not enough room for three across — table on top, lists side by side beneath. */
@media (max-width: 1280px) {
  .fantasy-layout { display: block; }
  .watch-lists { display: grid; grid-template-columns: 1fr 1fr; gap: 40px; margin-top: 38px; }
}
@media (max-width: 760px) { .watch-lists { grid-template-columns: 1fr; gap: 30px; } }

/* --- Alignment ------------------------------------------------------------
   Every vertical measurement below is an EXACT height, never a min-height.
   min-height was the original bug: the natural row is ~104px, so a 84px floor
   never bound and rows whose reason wrapped to one line came up short, offsetting
   every divider below it. Fixed line-height + fixed height on each part means
   the two columns' headings, list starts and cut lines land on identical y. */
.watch-head {
  font-size: 20px; font-weight: 800; letter-spacing: .2px; margin: 0 0 4px;
  line-height: 26px; height: 26px; box-sizing: content-box; white-space: nowrap;
  padding-bottom: 8px; border-bottom: 2px solid var(--border);
}
.watch-head-fade { color: var(--danger-text);  border-bottom-color: rgba(210,122,122,.35); }
.watch-head-bump { color: var(--warning-text); border-bottom-color: rgba(210,178,90,.35); }
.watch-sub {
  font-size: 12.5px; color: var(--text-secondary); margin: 8px 0 14px;
  /* exactly two lines RESERVED (not min-height) so both lists start at the
     same y whether the blurb wraps to one line or two */
  line-height: 18px; height: 36px; overflow: hidden;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.watch-list { list-style: none; margin: 0; padding: 0; }
.watch-item {
  display: grid; grid-template-columns: 22px 1fr auto; grid-template-areas:
    "rank name proj" ".  meta meta" ".  why  why";
  gap: 2px 12px; padding: 12px 0; border-bottom: 1px solid var(--border);
}
.watch-item:last-child { border-bottom: none; }
.watch-rank { grid-area: rank; font-family: var(--font-mono); font-size: 12px;
  line-height: 22px; color: var(--text-secondary); }
.watch-name { grid-area: name; font-weight: 600; font-size: 15px; line-height: 22px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.watch-proj { grid-area: proj; font-family: var(--font-mono); font-size: 13px; line-height: 22px;
  color: var(--gold); white-space: nowrap; }
.watch-meta { grid-area: meta; font-size: 11.5px; line-height: 16px; color: var(--text-secondary);
  text-transform: uppercase; letter-spacing: .4px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.watch-why  { grid-area: why;  font-size: 12.5px; color: var(--text-secondary);
  /* two lines RESERVED, so a one-line reason cannot shorten its row and knock
     every divider below it out of step — that was the original offset bug */
  line-height: 18px; height: 36px; margin-top: 4px; overflow: hidden;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
/* row = 12 + 22 + 2 + 16 + 2 + 4 + 36 + 12 + 1px rule = 107px, content-independent */
.watch-empty { color: var(--text-secondary); font-size: 13px; padding: 10px 0; }


/* ── The sport home page: the ledger ──────────────────────────────
   Every way into a sport is one line: icon, name, what it is, how much of it.
   Chosen because the count varies wildly — football has six, college has
   fourteen, the NWSL page has one — and a list cannot come out lopsided the way
   a grid of cards can. It also rhymes with the table pages, which are rows too.

   ⛔ This block sits at the END of the file on purpose. See the note under
   "The bar's collapse order" — a later plain rule beats an earlier media query,
   and several of the names here are also used further up. */

/* `main` carries 22px of padding from a rule further up the file. Left in
   place it pushes the opening section 22px past the fold on every sport, which
   is exactly the thing this layout exists to avoid. */
.sport-home { display: block; padding: 0; margin: 0; max-width: none; }

/* the opening. Exactly one screen, contents centered in it, so the next band
   always starts AT the fold and never through it. */
.hub-top {
  position: relative;
  min-height: calc(100vh - 58px);
  display: flex; flex-direction: column; justify-content: center;
  padding: 40px 22px;
}
.hub-wash { position: absolute; inset: 0; overflow: hidden; z-index: 0; pointer-events: none; }
.hub-wash::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--bg-raised) 70%, transparent) 0%,
    var(--bg-page) 92%);
}
/* Seven sports have a background image and six do not, so the image is turned
   right down to a texture: the two cases have to look like the same page.
   ⚠️ nfl-bg.jpg is a SOCCER stadium. Known, flagged, not yet replaced. */
.hub-photo .hub-wash::before {
  content: ""; position: absolute; inset: -8% 0 0;
  background-position: center 46%; background-size: cover; background-repeat: no-repeat;
  filter: grayscale(1) contrast(.6) brightness(.42); opacity: .5;
}
html[data-theme="light"] .hub-photo .hub-wash::before {
  filter: grayscale(1) contrast(.32) brightness(1.75); opacity: .26;
}
.hub-top[data-sport="nfl"]    .hub-wash::before { background-image: url('/static/nfl-bg.jpg'); }
.hub-top[data-sport="nba"]    .hub-wash::before { background-image: url('/static/nba-bg.jpg'); }
.hub-top[data-sport="wnba"]   .hub-wash::before { background-image: url('/static/wnba-bg.jpg'); }
.hub-top[data-sport="mlb"]    .hub-wash::before { background-image: url('/static/mlb-bg.jpg'); }
.hub-top[data-sport="nhl"]    .hub-wash::before { background-image: url('/static/nhl-bg.jpg'); }
.hub-top[data-sport="futbol"] .hub-wash::before { background-image: url('/static/futbol-bg.jpg'); }
.hub-top[data-sport="pga"]    .hub-wash::before { background-image: url('/static/pga-bg.jpg'); }

.hub-open { position: relative; z-index: 1; max-width: 1180px; margin: 0 auto;
            width: 100%; text-align: center; }
.hub-eyebrow {
  margin: 0; font-family: var(--font-meta); font-size: 10.5px; font-weight: 500;
  letter-spacing: .17em; text-transform: lowercase; color: var(--gold);
}
.hub-title {
  margin: 14px 0 0; font-family: var(--font-display); font-weight: 400;
  font-size: clamp(44px, 7.2vw, 82px); line-height: 1.02; letter-spacing: -.025em;
  text-wrap: balance;
}
.hub-title .q { color: var(--text-tertiary); }
.hub-title .s { color: var(--gold); }
.hub-tag {
  margin: 18px auto 0; max-width: 54ch; color: var(--text-secondary);
  font-size: 16.5px; line-height: 1.6;
}
.hub-acts { display: flex; justify-content: center; gap: 12px; margin-top: 28px; flex-wrap: wrap; }
.hub-btn {
  display: inline-flex; align-items: center; justify-content: center;
  height: 44px; padding: 0 22px; border-radius: var(--radius-pill);
  border: 1px solid var(--border); color: var(--text-secondary);
  font-family: var(--font-sans); font-size: 14px; font-weight: 600; letter-spacing: .03em;
  text-decoration: none; transition: color .15s ease, border-color .15s ease;
}
.hub-btn:hover { color: var(--text-primary); border-color: var(--gold); }
.hub-btn.primary { background: var(--gold); color: var(--on-gold); border-color: var(--gold); }
.hub-btn.primary:hover { color: var(--on-gold); opacity: .9; }

.hub-body { max-width: 1180px; margin: 0 auto; padding: 0 22px 24px; }
.hub-rule { display: flex; align-items: center; gap: 16px; margin: 58px 0 20px; }
.hub-rule span {
  flex: none; font-family: var(--font-meta); font-size: 10.5px; font-weight: 500;
  letter-spacing: .17em; text-transform: lowercase; color: var(--gold);
}
.hub-rule::before, .hub-rule::after {
  content: ""; flex: 1 1 auto; height: 1px; background: var(--border);
}

/* the ledger itself */
.hub-ledger { border-top: 1px solid var(--border); }
.lg-row {
  display: flex; align-items: baseline; gap: 18px;
  padding: 19px 6px; border-bottom: 1px solid var(--border-dashed);
  text-decoration: none; color: inherit;
  transition: background .13s ease, padding .13s ease;
}
a.lg-row:hover, .lg-row:hover { background: var(--bg-raised); padding-left: 14px; padding-right: 14px; }
.lg-row > i {
  flex: none; width: 24px; text-align: center; font-size: 19px;
  color: var(--gold); position: relative; top: 3px;
}
.lg-name {
  /* wide enough for the longest name on the site ("nwsl 2026 season
     projection") to stay on one line, so the rows keep an even rhythm */
  flex: 0 0 clamp(180px, 26vw, 336px);
  font-family: var(--font-display); font-weight: 400; font-size: 25px;
  line-height: 1.15; letter-spacing: -.01em; color: var(--text-primary);
  text-decoration: none;
}
a.lg-name:hover { color: var(--gold); }
.lg-desc { flex: 1 1 auto; min-width: 0; color: var(--text-secondary); font-size: 13.5px; line-height: 1.55; }
.lg-kids { display: flex; flex-wrap: wrap; gap: 4px 14px; margin-top: 8px; }
.lg-kids a {
  font-family: var(--font-meta); font-size: 10.5px; letter-spacing: .1em;
  text-transform: lowercase; color: var(--text-faint); text-decoration: none;
  transition: color .12s ease;
}
.lg-kids a:hover { color: var(--gold); }
.lg-meta {
  flex: none; white-space: nowrap;
  font-family: var(--font-meta); font-size: 10.5px; font-weight: 500;
  letter-spacing: .13em; text-transform: lowercase; color: var(--text-faint);
}
.lg-go { flex: none; color: var(--text-faint); transition: color .13s ease, transform .13s ease; }
.lg-row:hover .lg-go { color: var(--gold); transform: translateX(3px); }
.lg-row:hover .lg-meta { color: var(--gold); }

@media (max-width: 780px) {
  .lg-row { flex-wrap: wrap; gap: 6px 14px; }
  .lg-name { flex: 1 1 auto; font-size: 23px; }
  .lg-desc { flex: 1 1 100%; }
}

/* the track record. Honestly headed: these are the model's results across the
   whole site, not this sport's — every sport currently shows the same three. */
.hub-stats {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  border: 1px solid var(--border); border-radius: var(--radius-card);
  overflow: hidden; text-align: center;
}
.hub-stat { padding: 22px 18px; border-right: 1px solid var(--border-dashed); }
.hub-stat:last-child { border-right: 0; }
.hub-stat b {
  display: block; font-family: var(--font-display); font-weight: 400;
  font-size: 36px; line-height: 1; color: var(--text-primary);
}
.hub-stat span { display: block; margin-top: 9px; color: var(--text-secondary); font-size: 12.5px; }
.hub-stat i {
  display: block; margin-top: 8px; font-style: normal;
  font-family: var(--font-meta); font-size: 9.5px; letter-spacing: .09em;
  color: var(--text-faint); line-height: 1.6;
}
.hub-stats-note {
  margin: 12px 0 0; text-align: center; color: var(--text-faint); font-size: 12.5px;
}

/* release notes, carried over so its script keeps writing into it */
.sport-home .hub-postings { margin: 0; }
.sport-home .hub-postings .hub-block-head { display: none; }
.sport-home .hub-postings-grid {
  display: grid; gap: 14px; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}
.sport-home .hub-post {
  background: var(--bg-raised); border: 1px solid var(--border);
  border-radius: var(--radius-card); padding: 20px;
}
.sport-home .hub-post h4 {
  margin: 8px 0 0; font-family: var(--font-display); font-weight: 400; font-size: 21px;
}
.sport-home .hub-post p { margin: 10px 0 0; color: var(--text-secondary); font-size: 13px; line-height: 1.6; }
.sport-home .hub-post .post-date {
  font-family: var(--font-meta); font-size: 10px; letter-spacing: .13em; color: var(--gold);
}
.sport-home .hub-post.placeholder { opacity: .68; }

/* ── The table pages: the head ────────────────────────────────────
   Pages of numbers used to open straight onto a control row and a table, with
   nothing naming them but the chip in the menu bar. They now open with a
   centered head: the sport, the page's name, and one line taken from the page's
   own <meta name="description">.

   ⛔ DETAIL pages deliberately do NOT get this. A page that loads one player,
   one team or one match builds its own title at runtime from the data; a static
   "player" heading above it either duplicates or contradicts what loads. The
   pages that get a head are the ones where the list IS the page. */

.tbl-head {
  max-width: 1180px; margin: 0 auto; padding: 34px 0 26px; text-align: center;
}
.tbl-eyebrow {
  margin: 0; font-family: var(--font-meta); font-size: 10.5px; font-weight: 500;
  letter-spacing: .17em; text-transform: lowercase; color: var(--gold);
}
.tbl-title {
  margin: 11px 0 0; font-family: var(--font-display); font-weight: 400;
  font-size: clamp(32px, 4.6vw, 52px); line-height: 1.05; letter-spacing: -.022em;
  color: var(--text-primary); text-wrap: balance;
}
.tbl-sub {
  margin: 13px auto 0; max-width: 58ch;
  color: var(--text-secondary); font-size: 14.5px; line-height: 1.55;
}
.tbl-note { margin: 14px 0 0; }
.tbl-note a {
  font-family: var(--font-meta); font-size: 10.5px; font-weight: 500;
  letter-spacing: .13em; text-transform: lowercase;
  color: var(--text-faint); text-decoration: none; transition: color .15s ease;
}
.tbl-note a:hover { color: var(--gold); }
.tbl-note a::after { content: " \2192"; }

/* the controls follow the head, so they center with it */
.tbl-page .search-controls,
.tbl-page .table-tools {
  justify-content: center; margin-bottom: 20px;
}
@media (max-width: 720px) {
  .tbl-head { padding: 24px 0 18px; }
  .tbl-page .search-controls, .tbl-page .table-tools { justify-content: flex-start; }
}

/* ══ Every pressable control is a pill (Billy, 2026-10-30) ══════════════════
   "all buttons should be pills site-wide", on every Resolve site and in the app.
   The rule: a control with a box or a fill gets fully round ends; a square
   icon-only control comes out as a circle. Inputs, selects, cards, panels and
   badges keep their corners, and so do the underlined text tabs (they have no
   box; see the tab rule above, which still stands).
   !important because this sheet loads BEFORE bar3.css, every page's inline
   <style> and the styles the table scripts inject. The radius tokens are left
   alone on purpose: --radius-button also rounds inputs and --radius-pill also
   rounds badges and info bars. The bar's own pills are in bar3.css, the
   family kit, since 2026-10-30. */
.adv-grid-page-btn, .adv-rank-toggle, .adv-tennis-toggle, .hub-btn-primary,
.mobile-row-toggle, .cs-pt, .theme-toggle, .tt-export, .proj-collapse-toggle,
.rt-preview-btn, .rrp-btn, .nf-acts a, .ts-chip, .ts-chip-btn,
.sort-toggle button, .view-toggle, .view-btn, .side-toggle, .csv-btn, .addbtn {
  border-radius: 999px !important;
}
