/* ============================================================
   CuratedBets — NFL component layer
   Loads AFTER curatedbets-theme.css and public-brand.css.
   Every colour, space and type value here is a var(--*) from the
   theme. No hex is hard-coded; nothing redefines a token.

   Why NFL needs its own layer rather than reusing mlb-board-today.css:
   the MLB board is a DAY of interchangeable games and a pitcher-centric
   game page. The NFL is a WEEK of named broadcast windows and a
   two-roster game page. Those are different structures, not different
   skins, so they get different components on the same tokens.

   MOBILE FIRST. Every block below is written phone-up and widened at
   breakpoints. Tables become cards under 768px; nothing scrolls the
   page horizontally.
   ============================================================ */

/* ---------- Accessible label colour ----------
   The shared --text-faint token (#93A3B6) measures roughly 2.4:1 on the light
   board, which fails WCAG AA (4.5:1) for the 11px uppercase labels this layer
   is full of. Rather than redefine a global token that the MLB pages also
   consume, the NFL layer resolves its own label colour and uses it for every
   piece of small text that carries meaning. --text-faint is kept ONLY for
   non-informational decoration (dots, chevrons, separators), where contrast
   guidance does not apply. */
:root {
  --nfl-label: var(--cb-gray-600);
}

/* ---------- Sport rail + section tab rail: NOW SHARED, NOT RESTATED ----------
   Both used to be restated in this sheet.

   The sport rail (.cb-sportrail / .cb-sport) is nav chrome that renders on
   EVERY page of both sports, so styling it from the NFL component sheet left
   it unstyled on all four MLB pages, and — because public-brand.css's
   `.cb-nav-links a` rules outrank a bare `.cb-sport` — half-applied even here:
   the active pill kept the theme's near-white nav-link colour on top of the
   near-white pill background this sheet set, measuring 1.02:1. It now lives
   with the rest of the navigation in public-brand.css.

   The section tab rail (.cb-tabrail / .cb-tabs) is a shared board primitive
   and now comes from board-shell.css, which every sport loads. The one thing
   worth keeping from the NFL restatement was its 44px tap target, so that is
   carried in board-shell.css for both sports rather than duplicated here. */

/* ============================================================
   1. MODULE STATE
   The most important component in the NFL product. Any module with
   nothing to show renders THIS rather than a zero. Tone is about OUR
   data pipeline, never about a player or a prop, so it never borrows
   the win/loss palette.
   ============================================================ */
.nfl-state {
  display: flex;
  gap: var(--sp-3);
  align-items: flex-start;
  padding: var(--sp-5);
  border-radius: var(--radius-lg);
  border: 1px dashed var(--border-soft);
  background: var(--surface-sunken);
}
.nfl-state-dot {
  width: 8px; height: 8px; border-radius: 50%;
  margin-top: 7px; flex: none;
  background: var(--text-faint);
}
.nfl-state[data-tone="warn"] { border-color: var(--cb-caution-soft); background: var(--cb-caution-soft); }
.nfl-state[data-tone="warn"] .nfl-state-dot { background: var(--cb-caution); }
.nfl-state[data-tone="ok"] { border-style: solid; border-color: var(--border-hairline); background: var(--surface-raised); }
.nfl-state[data-tone="ok"] .nfl-state-dot { background: var(--cb-positive); }
.nfl-state-body { min-width: 0; }
.nfl-state-head {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-title);
  color: var(--text-strong);
  margin: 0;
  line-height: var(--lh-snug);
}
.nfl-state-detail {
  font-size: var(--fs-sm);
  line-height: var(--lh-relaxed);
  color: var(--text-body);
  margin: var(--sp-2) 0 0;
  max-width: 62ch;
}
.nfl-state-asof {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  color: var(--text-muted);
  margin: var(--sp-2) 0 0;
}
/* Inline variant for a chip-sized absence inside a dense row. */
.nfl-state-inline {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: var(--fs-label);
  color: var(--text-muted);
  font-weight: 600;
}
.nfl-state-inline::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: var(--text-faint); flex: none;
}
.nfl-state-inline[data-tone="warn"]::before { background: var(--cb-caution); }

/* ============================================================
   2. WEEK / WINDOW GROUPS  (NFL Today)
   ============================================================ */
.nfl-week { display: flex; flex-direction: column; gap: var(--sp-8); }

.nfl-window { margin: 0; }
.nfl-window-head {
  display: flex;
  align-items: baseline;
  gap: var(--sp-3);
  flex-wrap: wrap;
  padding-bottom: var(--sp-3);
  margin-bottom: var(--sp-4);
  border-bottom: 2px solid var(--border-hairline);
}
.nfl-window-title {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--fs-h3);
  letter-spacing: var(--ls-tight);
  color: var(--text-strong);
  margin: 0;
}
.nfl-window-count {
  font-family: var(--font-display);
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.nfl-window-note {
  font-size: var(--fs-sm);
  color: var(--text-muted);
  margin: 0;
  flex-basis: 100%;
}
/* A collapsible window on phones: Sunday Early stays open, the rest fold. */
.nfl-window > summary { list-style: none; cursor: pointer; }
.nfl-window > summary::-webkit-details-marker { display: none; }
.nfl-window > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 6px; }
.nfl-window-chev { margin-left: auto; color: var(--text-faint); transition: transform var(--dur) var(--ease-out); }
.nfl-window[open] .nfl-window-chev { transform: rotate(90deg); }

.nfl-games { display: grid; grid-template-columns: 1fr; gap: var(--sp-3); }

/* ---------- Game card ---------- */
.nfl-gc {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  padding: var(--pad-card-sm);
  border-radius: var(--radius-lg);
  border: 1px solid var(--border-hairline);
  background: var(--surface-raised);
  box-shadow: var(--shadow-sm);
  transition: transform var(--dur) var(--ease-out), box-shadow var(--dur) var(--ease-out);
}
.nfl-gc:hover { transform: translateY(-2px); box-shadow: var(--shadow-lg); }
/* One full-card anchor above the content: whole card clickable, one focus stop,
   no nested interactive elements. */
.nfl-gc-cover { position: absolute; inset: 0; z-index: 1; border-radius: var(--radius-lg); }
.nfl-gc-cover:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.nfl-gc > *:not(.nfl-gc-cover) { position: relative; z-index: 2; }

.nfl-gc-top { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-3); }
.nfl-gc-teams { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; flex-wrap: wrap; }
.nfl-gc-abbr {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 19px;
  letter-spacing: .01em;
  color: var(--text-strong);
}
.nfl-gc-at { font-size: var(--fs-label); font-weight: 700; color: var(--text-muted); }
.nfl-gc-when { display: flex; flex-direction: column; align-items: flex-end; gap: 3px; flex: none; text-align: right; }
.nfl-gc-time {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text-body);
  white-space: nowrap;
}
.nfl-gc-time.is-live { color: var(--cb-positive); }
.nfl-gc-score { font-family: var(--font-mono); font-weight: 700; font-size: var(--fs-body); color: var(--text-strong); }
.nfl-gc-status {
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.nfl-gc-meta { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.nfl-chip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 10px;
  border-radius: 999px;
  font-size: var(--fs-micro);
  font-weight: 700;
  border: 1px solid var(--border-hairline);
  background: var(--surface-sunken);
  color: var(--text-muted);
  white-space: nowrap;
}
.nfl-chip .cb-i { width: 12px; height: 12px; }
.nfl-chip.is-weather { background: var(--cb-weather-soft); color: #0d7488; border-color: transparent; }
.nfl-chip.is-indoor { background: var(--cb-gray-50); color: var(--text-muted); }
.nfl-chip.is-unknown { background: transparent; border-style: dashed; color: var(--text-muted); }
.nfl-chip.is-intl { background: var(--cb-attention-soft); color: #5b46a8; border-color: transparent; }

/* Attention block on a game card. The source count is the largest element,
   because it is the one number the product exists to report. */
.nfl-gc-attn {
  display: flex; align-items: center; gap: var(--sp-4);
  padding-top: var(--sp-3);
  border-top: 1px solid var(--border-hairline);
}
.nfl-gc-figure { display: flex; flex-direction: column; min-width: 0; }
.nfl-gc-figure b {
  font-family: var(--font-display);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-stat-md);
  line-height: 1;
  color: var(--text-strong);
}
.nfl-gc-figure span {
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-top: 5px;
}
.nfl-gc-toplist { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.nfl-gc-topitem { display: flex; align-items: baseline; gap: var(--sp-2); font-size: var(--fs-sm); }
.nfl-gc-topitem b { font-weight: 700; color: var(--text-strong); }
.nfl-gc-topitem span { color: var(--text-muted); }

/* ============================================================
   3. EXACT PROP EXPRESSION
   side + line + market, in that order, everywhere it appears.
   Over and Under share one style: neither side is "good".
   ============================================================ */
.nfl-prop { display: inline-flex; align-items: baseline; flex-wrap: wrap; gap: 6px; min-width: 0; }
.nfl-prop-side {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--fs-sm);
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--text-body);
}
.nfl-prop-line {
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: var(--fs-title);
  color: var(--text-strong);
  font-variant-numeric: tabular-nums;
}
.nfl-prop-market { font-size: var(--fs-sm); color: var(--text-muted); }

/* ============================================================
   4. RANKED ATTENTION BOARD  (Most Mentioned)
   ============================================================ */
.nfl-rank { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-3); }
/* Mobile-first: rank + identity + count on one line, the exact prop on its
   own line beneath. Laying all four cells out vertically (the naive stack)
   produced 300px rows on a phone, which is roughly one row per screen. */
.nfl-rank-item {
  position: relative;
  display: grid;
  grid-template-columns: 28px minmax(0, 1fr) auto;
  grid-template-areas:
    "num who  stat"
    "num prop prop";
  column-gap: var(--sp-3);
  row-gap: var(--sp-2);
  align-items: center;
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--radius-lg);
  border: 1px solid var(--border-hairline);
  background: var(--surface-raised);
  box-shadow: var(--shadow-sm);
  transition: transform var(--dur) var(--ease-out), box-shadow var(--dur) var(--ease-out);
}
.nfl-rank-item:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); }
.nfl-rank-cover { position: absolute; inset: 0; z-index: 1; border-radius: var(--radius-lg); }
.nfl-rank-cover:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.nfl-rank-item > *:not(.nfl-rank-cover) { position: relative; z-index: 2; }

.nfl-rank-num {
  grid-area: num;
  align-self: start;
  padding-top: 2px;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--fs-h3);
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
  text-align: center;
}
/* Podium emphasis. These mark VOLUME POSITION, never quality, so they use the
   brand's metal tones and never the win/loss palette. Each is paired with the
   rank numeral itself, so rank is never communicated by colour alone. */
/* Rank emphasis. This was a gold / silver / bronze medal ramp, which broke the
   brand in two ways: CuratedBets marks the leader with the ACCENT (see the MLB
   board's .cb-attn-item.is-lead .cb-attn-rank, which is --accent-strong), and
   the theme reserves gold explicitly — "logo / rare premium emphasis — never
   for data". A rank numeral is data. The bronze step was also the only
   hard-coded hex in this sheet, against its own header rule.

   The inset left bar is KEPT: it is an NFL-specific affordance that survives
   the mobile grid reflow, where MLB's full-width lead row does not. Only the
   colour language is brought back to the brand — leader in accent, the rest
   neutral and descending in weight, so the podium still reads at a glance.

   --text-muted (4.1:1 on the card) is used rather than the MLB board's
   --text-faint, which measures 2.58:1 and fails AA even as large text. See the
   accessibility note at the top of this sheet. */
.nfl-rank-item.is-1 { border-color: var(--cb-blue-100); box-shadow: var(--shadow-md), inset 4px 0 0 var(--accent-strong); }
.nfl-rank-item.is-1 .nfl-rank-num { color: var(--accent-strong); }
.nfl-rank-item.is-2 { box-shadow: var(--shadow-sm), inset 4px 0 0 var(--border-strong); }
.nfl-rank-item.is-2 .nfl-rank-num { color: var(--text-muted); }
.nfl-rank-item.is-3 { box-shadow: var(--shadow-sm), inset 4px 0 0 var(--border-soft); }
.nfl-rank-item.is-3 .nfl-rank-num { color: var(--text-muted); }

.nfl-rank-who { grid-area: who; display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.nfl-rank-prop { grid-area: prop; display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.nfl-rank-name {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--fs-title);
  color: var(--text-strong);
  margin: 0;
  overflow-wrap: anywhere;
}
.nfl-rank-ident { display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-2); font-size: var(--fs-label); color: var(--text-muted); }
.nfl-rank-team { font-family: var(--font-display); font-weight: 700; letter-spacing: .04em; color: var(--text-body); }
.nfl-rank-pos {
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: .05em;
  padding: 2px 6px;
  border-radius: 4px;
  background: var(--surface-sunken);
  color: var(--text-muted);
}
.nfl-rank-stat { grid-area: stat; display: flex; flex-direction: column; align-items: flex-end; gap: 3px; align-self: start; }
.nfl-rank-stat b {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--fs-stat-md);
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--cb-info);
}
.nfl-rank-item.is-1 .nfl-rank-stat b { color: var(--accent-strong); }
.nfl-rank-stat span {
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--text-muted);
  text-align: right;
}

/* ============================================================
   5. MODULE PANEL (game + player pages)
   ============================================================ */
.nfl-mod { margin-top: var(--sp-8); }
.nfl-mod-head { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--sp-4); margin-bottom: var(--sp-4); flex-wrap: wrap; }
.nfl-mod-title {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--fs-h3);
  letter-spacing: var(--ls-tight);
  color: var(--text-strong);
  margin: 0;
}
.nfl-mod-dek { font-size: var(--fs-sm); line-height: var(--lh-relaxed); color: var(--text-body); margin: 6px 0 0; max-width: 66ch; }
.nfl-mod-meta { font-family: var(--font-mono); font-size: var(--fs-micro); color: var(--text-muted); flex: none; }
/* Inline links in a module head are real tap targets on a phone, so they get a
   44px box rather than the 23px their text alone would occupy. */
.nfl-mod-head .cb-link {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  min-height: 44px;
  padding: 0 2px;
}
.nfl-mod-head .cb-link .cb-i { width: 15px; height: 15px; }
.nfl-panel {
  padding: var(--pad-card-sm);
  border-radius: var(--radius-lg);
  border: 1px solid var(--border-hairline);
  background: var(--surface-raised);
}

/* ---------- Player hero (navy zone) ---------- */
.nfl-ph-eyebrow {
  font-family: var(--font-display);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--cb-blue-300);
  margin: 0 0 var(--sp-2);
}
.nfl-ph-name {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(26px, 6vw, var(--fs-h1));
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-tight);
  color: var(--cb-hero-ink);
  margin: 0;
  overflow-wrap: anywhere;
}
.nfl-ph-ident { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin: var(--sp-3) 0 0; font-size: var(--fs-sm); color: rgba(255,255,255,.78); }
.nfl-ph-ident b { color: var(--cb-hero-ink); font-weight: 700; }
.nfl-ph-sep { color: rgba(255,255,255,.32); }

/* The selected prop. This must stay unmistakable on every scroll position,
   which is why it is a solid card in the navy zone rather than a text line. */
.nfl-ph-selected {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-4);
  margin: var(--sp-5) 0 0;
  padding: var(--sp-4);
  border-radius: var(--radius-lg);
  background: rgba(255, 255, 255, .08);
  border: 1px solid rgba(255, 255, 255, .14);
}
.nfl-ph-selected .nfl-prop-side { color: var(--cb-blue-300); }
.nfl-ph-selected .nfl-prop-line { color: var(--cb-hero-ink); font-size: var(--fs-h3); }
.nfl-ph-selected .nfl-prop-market { color: rgba(255,255,255,.8); }
.nfl-ph-sel-label {
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--cb-blue-300);
  flex-basis: 100%;
}
.nfl-ph-sel-stat { margin-left: auto; text-align: right; }
.nfl-ph-sel-stat b {
  display: block;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--fs-stat-md);
  line-height: 1;
  color: var(--cb-hero-ink);
}
.nfl-ph-sel-stat span { font-size: var(--fs-micro); text-transform: uppercase; letter-spacing: .05em; color: rgba(255,255,255,.6); }

/* Prop switcher: every exact prop this player holds, line and side intact. */
.nfl-props { display: flex; flex-direction: column; gap: var(--sp-2); margin: 0; padding: 0; list-style: none; }
.nfl-prop-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  min-height: 52px;
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--radius-md);
  border: 1px solid var(--border-hairline);
  background: var(--surface-raised);
  color: inherit;
  transition: border-color var(--dur) var(--ease-out), background var(--dur) var(--ease-out);
}
.nfl-prop-row:hover { border-color: var(--border-strong); background: var(--accent-wash); }
.nfl-prop-row:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.nfl-prop-row[aria-current="true"] {
  border-color: var(--accent);
  background: var(--accent-wash);
  box-shadow: inset 3px 0 0 var(--accent-strong);
}
.nfl-prop-row-badge {
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--accent-strong);
  display: none;
}
.nfl-prop-row[aria-current="true"] .nfl-prop-row-badge { display: inline; }
.nfl-prop-row-count { font-family: var(--font-display); font-weight: 800; font-variant-numeric: tabular-nums; color: var(--cb-info); white-space: nowrap; }

/* ---------- Status grid ---------- */
.nfl-status { display: grid; grid-template-columns: 1fr; gap: var(--sp-3); }
.nfl-status-cell {
  padding: var(--sp-4);
  border-radius: var(--radius-md);
  border: 1px solid var(--border-hairline);
  background: var(--surface-raised);
}
.nfl-status-cell.is-blank { border-style: dashed; background: var(--surface-sunken); }
.nfl-status-label {
  display: block;
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 6px;
}
.nfl-status-value { font-family: var(--font-display); font-weight: 800; font-size: var(--fs-title); color: var(--text-strong); margin: 0; }
.nfl-status-cell.is-blank .nfl-status-value { font-family: var(--font-text); font-size: var(--fs-sm); font-weight: 600; color: var(--text-muted); }
.nfl-status-detail { font-size: var(--fs-label); color: var(--text-body); margin: 6px 0 0; line-height: var(--lh-normal); }

/* ---------- Exact-line history ---------- */
.nfl-hist { display: grid; grid-template-columns: 1fr; gap: var(--sp-3); }
.nfl-hist-cell {
  padding: var(--sp-4);
  border-radius: var(--radius-md);
  border: 1px solid var(--border-hairline);
  background: var(--surface-raised);
}
.nfl-hist-scope {
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.nfl-hist-record {
  display: flex;
  align-items: baseline;
  gap: var(--sp-3);
  margin: var(--sp-2) 0 0;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}
.nfl-hist-record b { font-size: var(--fs-h3); font-weight: 700; color: var(--text-strong); }
.nfl-hist-record span { font-size: var(--fs-label); color: var(--text-muted); }
/* Direction is a WORD first. Colour is a secondary cue only, and neutral is
   explicitly neutral — never a 50% score, never a green tint. */
.nfl-hist-dir {
  display: inline-flex; align-items: center; gap: 5px;
  margin-top: var(--sp-3);
  padding: 3px 9px;
  border-radius: 999px;
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  border: 1px solid var(--border-hairline);
  background: var(--surface-sunken);
  color: var(--text-muted);
}
.nfl-hist-strength { font-size: var(--fs-micro); color: var(--text-muted); margin: var(--sp-2) 0 0; }

/* ---------- Usage ---------- */
.nfl-usage { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--sp-3); }
.nfl-usage-cell { padding: var(--sp-3); border-radius: var(--radius-md); background: var(--surface-sunken); }
.nfl-usage-label {
  display: block;
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 5px;
}
.nfl-usage-value { font-family: var(--font-display); font-weight: 800; font-size: var(--fs-h3); color: var(--text-strong); font-variant-numeric: tabular-nums; }

/* ---------- Counter-context ---------- */
.nfl-counter {
  border-left: 3px solid var(--cb-attention);
  padding-left: var(--sp-4);
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
}
.nfl-counter-item { }
.nfl-counter-label {
  font-family: var(--font-display);
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--cb-attention);
}
.nfl-counter-text { font-size: var(--fs-body); line-height: var(--lh-relaxed); color: var(--text-body); margin: 5px 0 0; }
.nfl-counter-basis { font-size: var(--fs-micro); color: var(--text-muted); margin: 5px 0 0; }

/* ---------- Market ---------- */
.nfl-market-note {
  font-size: var(--fs-label);
  color: var(--text-muted);
  margin: 0 0 var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--radius-sm);
  background: var(--surface-sunken);
}

/* Two-roster prop board (game page). Explicitly two columns rather than the
   auto-fill used for game cards: there are always exactly two teams, and
   auto-fill left a dead third column at desktop widths. */
.nfl-team-board { display: grid; grid-template-columns: 1fr; gap: var(--sp-4); }
@media (min-width: 900px) {
  .nfl-team-board { grid-template-columns: 1fr 1fr; align-items: start; }
}

/* ============================================================
   6. RESPONSIVE DATA LISTS
   Tables become definition-style cards below 768px. The mobile card
   carries EVERY cell the desktop table does — a column may not vanish
   at a narrow width.
   ============================================================ */
.nfl-dl { display: flex; flex-direction: column; gap: var(--sp-3); }
.nfl-dl-card {
  padding: var(--sp-4);
  border-radius: var(--radius-md);
  border: 1px solid var(--border-hairline);
  background: var(--surface-raised);
}
.nfl-dl-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3); margin-bottom: var(--sp-3); }
.nfl-dl-title { font-family: var(--font-display); font-weight: 800; font-size: var(--fs-title); color: var(--text-strong); margin: 0; }
.nfl-dl-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-3) var(--sp-4); }
.nfl-dl-term {
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.nfl-dl-def { font-size: var(--fs-sm); color: var(--text-body); margin: 3px 0 0; font-variant-numeric: tabular-nums; }

/* Outcome tokens carry a LETTER as well as a colour, so grade is never
   communicated by colour alone. */
.nfl-outcome {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 9px;
  border-radius: 999px;
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  border: 1px solid var(--border-hairline);
  background: var(--surface-sunken);
  color: var(--text-muted);
}
.nfl-outcome.is-win { background: var(--cb-positive-soft); color: #147a4a; border-color: transparent; }
.nfl-outcome.is-loss { background: var(--cb-negative-soft); color: #a33d1f; border-color: transparent; }
.nfl-outcome.is-push { background: var(--cb-gray-50); color: var(--text-body); }

/* ============================================================
   7. BREAKPOINTS
   ============================================================ */
@media (min-width: 560px) {
  .nfl-status { grid-template-columns: repeat(2, 1fr); }
  .nfl-hist { grid-template-columns: repeat(2, 1fr); }
  .nfl-usage { grid-template-columns: repeat(3, 1fr); }
  .nfl-gc { padding: var(--pad-card); }
  .nfl-dl-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (min-width: 768px) {
  .nfl-games { grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); }
  .nfl-hist { grid-template-columns: repeat(3, 1fr); }
  .nfl-usage { grid-template-columns: repeat(4, 1fr); }
  .nfl-status { grid-template-columns: repeat(4, 1fr); }
  .nfl-panel { padding: var(--pad-card); }
  .nfl-rank-item {
    grid-template-columns: 44px minmax(0, 1.55fr) minmax(0, 1.45fr) auto;
    grid-template-areas: "num who prop stat";
    column-gap: var(--sp-4);
    padding: var(--sp-4) var(--sp-5);
  }
  .nfl-rank-num, .nfl-rank-stat { align-self: center; padding-top: 0; }
  .nfl-window > summary { cursor: default; }
  .nfl-window-chev { display: none; }
}

@media (min-width: 1024px) {
  .nfl-games { grid-template-columns: repeat(auto-fill, minmax(380px, 1fr)); }
}

/* Below 768px every window is a real <details> the reader can fold. */
@media (max-width: 767px) {
  .nfl-window-head { margin-bottom: 0; padding-bottom: var(--sp-3); }
  .nfl-window[open] .nfl-window-head { margin-bottom: var(--sp-4); }
  .nfl-ph-sel-stat { margin-left: 0; text-align: left; }
}

/* Respect a reader who has asked for less motion. */
@media (prefers-reduced-motion: reduce) {
  .nfl-gc, .nfl-rank-item, .nfl-prop-row, .nfl-window-chev { transition: none; }
  .nfl-gc:hover, .nfl-rank-item:hover { transform: none; }
}

/* ============================================================
   8. CONTRAST
   Measured with a contrast probe against the rendered pages, not
   eyeballed.

   The root cause was ONE token, not a list of classes. The shared
   --text-muted (#6E7F94 / gray-500) and --text-faint (#93A3B6) render
   at roughly 3.7:1 and 2.4:1 on this product's light surfaces, and this
   layer leans heavily on 11-13.5px labels, so most small text on every
   NFL page failed WCAG AA (4.5:1).

   Both are darkened by one step HERE, in a sheet that only NFL pages
   load. Nothing about the MLB product changes: correcting the global
   tokens is a separate, wider decision for a separate session, and this
   file is the right blast radius for a fix the NFL pages need now.

   .signal-room (the navy command zone) declares its own values for
   these tokens at higher specificity, so the dark zone is unaffected.
   ============================================================ */
:root {
  /* --text-muted / --text-faint used to be corrected HERE, which fixed NFL and
     left every MLB page below AA. They now live in curatedbets-theme.css,
     which both sports load. Only the NFL-local label token remains. */
  --nfl-label: var(--cb-gray-600);
}

/* Accent-on-wash measures 4.45:1 — just under. Brand navy keeps the badge
   legible; selection is also carried by aria-current and the row border, so
   it is never signalled by colour alone. */
.nfl-prop-row-badge { color: var(--text-brand); }

/* The 'attention is not a recommendation' line. It is the most important
   sentence on an attention surface, so it does not sit in the faintest
   tier — it takes the muted tier and clears AA. */
.cb-board .cb-compliance-note,
.cb-board .cb-micro { color: var(--text-muted); }

/* ============================================================
   Exact-prop intelligence — attention, market, role, evidence
   Mobile-first: every rule below is the 320px layout, and the
   only widening happens in the existing breakpoints at the end.
   ============================================================ */

/* Hero: the fixture line under the prop expression. */
.nfl-ph-fixture {
  margin: var(--sp-2) 0 0;
  font-size: var(--fs-sm);
  color: rgba(255,255,255,.82);
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px;
}

/* Attention: ONE primary figure, secondary counts subordinate to it. */
.nfl-attn { display: grid; grid-template-columns: 1fr; gap: var(--sp-4); }
.nfl-attn-primary {
  padding: var(--sp-3);
  border-radius: var(--radius-md);
  background: var(--accent-wash);
}
.nfl-attn-figure {
  display: block;
  font-family: var(--font-display); font-weight: 800;
  font-size: var(--fs-h1); line-height: 1;
  color: var(--cb-info); font-variant-numeric: tabular-nums;
}
.nfl-attn-label {
  display: block; margin-top: 4px;
  font-size: var(--fs-label); font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase; color: var(--text-strong);
}
.nfl-attn-secondary {
  margin: 6px 0 0; font-size: var(--fs-sm); color: var(--text-muted);
}
.nfl-attn-side { padding: var(--sp-3); border-radius: var(--radius-md); background: var(--surface-sunken); }

/* Market track: first / current / final pregame. Scrolls INSIDE its own
   container on the narrowest screens rather than widening the page. */
.nfl-mkt-track {
  display: grid; grid-template-columns: 1fr; gap: var(--sp-3);
}
.nfl-mkt-point {
  padding: var(--sp-3); border-radius: var(--radius-md);
  background: var(--surface-sunken); min-width: 0;
}
.nfl-mkt-point.is-pending { border: 1px dashed var(--border-subtle); background: transparent; }
.nfl-mkt-label {
  display: block; font-size: var(--fs-label); font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase; color: var(--text-muted);
}
.nfl-mkt-line {
  font-family: var(--font-display); font-weight: 800; font-size: var(--fs-h3);
  color: var(--text-strong); font-variant-numeric: tabular-nums;
  margin-right: var(--sp-2);
}
.nfl-mkt-price { font-family: var(--font-mono); font-size: var(--fs-sm); color: var(--text-body); }
.nfl-mkt-at, .nfl-mkt-note { margin: 4px 0 0; font-size: var(--fs-micro); color: var(--text-muted); }
.nfl-mkt-move {
  margin: var(--sp-3) 0 0; display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px;
  font-size: var(--fs-sm); color: var(--text-body);
}
.nfl-mkt-move b {
  font-family: var(--font-display); font-weight: 800; font-size: var(--fs-h3);
  color: var(--cb-info); font-variant-numeric: tabular-nums;
}
.nfl-mkt-move.is-flat b { color: var(--text-muted); }

/* Book dispersion. A LIST on mobile, never a table. */
.nfl-mkt-books { margin-top: var(--sp-4); }
.nfl-mkt-range-value {
  display: block;
  font-family: var(--font-display); font-weight: 800; font-size: var(--fs-h3);
  color: var(--text-strong); font-variant-numeric: tabular-nums;
}
.nfl-book-list { list-style: none; margin: var(--sp-3) 0 0; padding: 0; }
.nfl-book-row {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--sp-3); padding: 10px 0;
  border-bottom: 1px solid var(--border-subtle);
  font-size: var(--fs-sm); min-width: 0;
}
.nfl-book-row:last-child { border-bottom: 0; }
.nfl-book-row.is-selected { font-weight: 700; color: var(--text-strong); }
.nfl-book-name { min-width: 0; overflow-wrap: anywhere; }
.nfl-book-line, .nfl-book-price {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums; white-space: nowrap;
}

/* Progressive disclosure, shared by books, role splits and evidence. */
.nfl-disclose { margin-top: var(--sp-4); }
.nfl-disclose > summary {
  cursor: pointer; font-size: var(--fs-sm); font-weight: 700;
  color: var(--cb-info); padding: var(--sp-2) 0;
}
.nfl-disclose > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Role in context. The BADGE is what separates a qualifying relationship from
   a descriptive one, so descriptive sentences deliberately get no badge and a
   muted treatment. */
.nfl-role-badge {
  flex: none;
  font-size: var(--fs-micro); font-weight: 800;
  letter-spacing: .06em; text-transform: uppercase;
  padding: 4px 8px; border-radius: 999px;
  background: var(--cb-attention-soft); color: #5b46a8;
}
.nfl-role-items { list-style: none; margin: var(--sp-3) 0 0; padding: 0; }
.nfl-role-sentence {
  font-size: var(--fs-sm); line-height: var(--lh-relaxed);
  color: var(--text-body); padding: 8px 0;
  border-bottom: 1px solid var(--border-subtle);
  overflow-wrap: anywhere;   /* long sentences wrap; they never overflow */
}
.nfl-role-sentence:last-child { border-bottom: 0; }
.nfl-role-sentence.is-descriptive { color: var(--text-muted); }
.nfl-role-desc { margin-top: var(--sp-4); }
.nfl-role-desc-head {
  margin: 0; font-size: var(--fs-label); font-weight: 700;
  letter-spacing: .03em; text-transform: uppercase; color: var(--text-muted);
}

/* Source evidence. */
.nfl-src-type {
  flex: none;
  font-size: var(--fs-micro); font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase;
  padding: 3px 8px; border-radius: 999px;
  background: var(--cb-gray-50); color: var(--text-muted);
}
.nfl-ev-meta { margin: var(--sp-2) 0 0; font-size: var(--fs-micro); color: var(--text-muted); }
.nfl-ev-link { color: var(--cb-info); }

/* Result. */
.nfl-test-banner {
  margin: 0 0 var(--sp-3);
  padding: var(--sp-2) var(--sp-3); border-radius: var(--radius-md);
  background: var(--cb-caution-soft, var(--cb-gray-50));
  color: var(--cb-caution, var(--text-muted));
  font-size: var(--fs-sm); font-weight: 700;
}
.nfl-result-prop { margin: 0 0 var(--sp-2); }
.nfl-result-actual {
  margin: 0 0 var(--sp-3);
  font-family: var(--font-display); font-weight: 800; font-size: var(--fs-h2);
  color: var(--text-strong); font-variant-numeric: tabular-nums;
}

/* Quiet modules: standing facts, deliberately lower contrast than the
   attention and market cards above them. */
.nfl-mod-quiet .nfl-mod-title { color: var(--text-body); }
.nfl-mod-quiet .cb-eyebrow { color: var(--text-muted); }

@media (min-width: 600px) {
  .nfl-attn { grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr) minmax(0, 1fr); align-items: start; }
  .nfl-mkt-track { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* The prop switcher is a disclosure, not a section: the page is about ONE prop
   and the other lines must not outrank it above the fold. */
.nfl-props-switch { margin-top: 0; }
.nfl-props-switch > summary { font-size: var(--fs-sm); }

/* ============================================================
   Game intelligence — index-level cards. Mobile-first; the only
   widening happens in the min-width blocks at the end.
   ============================================================ */

/* PRESEASON: unmissable, not alarming. */
.nfl-chip.is-preseason {
  background: var(--cb-attention-soft); color: #5b46a8; border-color: transparent;
  font-weight: 800; letter-spacing: .05em; text-transform: uppercase;
}

/* Top exact props — the primary section. A stack of link cards, never a table. */
.nfl-topprops, .nfl-players { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-3); }
.nfl-topprop, .nfl-player-row {
  display: grid; grid-template-columns: 1fr; gap: 6px;
  padding: var(--sp-3); border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md); background: var(--surface-raised);
  text-decoration: none; color: inherit; min-width: 0;
}
.nfl-topprop:hover, .nfl-player-row:hover { border-color: var(--border-strong); background: var(--accent-wash); }
.nfl-topprop:focus-visible, .nfl-player-row:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.nfl-topprop-who b, .nfl-player-who b { font-size: var(--fs-body); color: var(--text-strong); overflow-wrap: anywhere; }
.nfl-topprop-ident {
  font-size: var(--fs-micro); font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--text-muted); margin-left: 6px;
}
.nfl-topprop-prop { min-width: 0; }
.nfl-topprop-stats, .nfl-player-stats { display: flex; align-items: baseline; flex-wrap: wrap; gap: 6px; }
.nfl-topprop-attn b, .nfl-player-stats b {
  font-family: var(--font-display); font-weight: 800; font-size: var(--fs-h3);
  color: var(--cb-info); font-variant-numeric: tabular-nums;
}
.nfl-topprop-sub { font-size: var(--fs-micro); color: var(--text-muted); overflow-wrap: anywhere; }
.nfl-topprop-mkt { display: flex; align-items: baseline; flex-wrap: wrap; gap: 6px; }
.nfl-topprop-line {
  font-family: var(--font-display); font-weight: 800; color: var(--text-strong);
  font-variant-numeric: tabular-nums;
}
.nfl-topprop-price { font-family: var(--font-mono); font-size: var(--fs-sm); color: var(--text-body); }
.nfl-player-top { display: block; margin-top: 4px; }

/* Market activity card. */
.nfl-mkt-market {
  margin: 0 0 var(--sp-2); font-size: var(--fs-label); font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase; color: var(--text-muted);
}
.nfl-mkt-shift { margin: 0 0 var(--sp-2); display: flex; align-items: baseline; flex-wrap: wrap; gap: 8px; }
.nfl-mkt-shift b {
  font-family: var(--font-display); font-weight: 800; font-size: var(--fs-h3);
  color: var(--text-strong); font-variant-numeric: tabular-nums;
}
.nfl-mkt-book {
  font-size: var(--fs-micro); font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--text-muted);
}
.nfl-mkt-rangeline { margin: 0 0 var(--sp-2); display: flex; align-items: baseline; flex-wrap: wrap; gap: 8px; }

/* Availability + results rows. A list on every viewport. */
.nfl-avail { list-style: none; margin: 0; padding: 0; }
.nfl-avail-row {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--sp-3); padding: 10px 0; border-bottom: 1px solid var(--border-subtle);
  flex-wrap: wrap; min-width: 0;
}
.nfl-avail-row:last-child { border-bottom: 0; }
.nfl-avail-who { min-width: 0; display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px; }
.nfl-avail-state { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.nfl-avail-badge {
  font-size: var(--fs-micro); font-weight: 800; letter-spacing: .05em;
  text-transform: uppercase; padding: 3px 8px; border-radius: 999px;
  background: var(--cb-gray-50); color: var(--text-body);
}
.nfl-src-prop { display: block; margin-bottom: var(--sp-2); color: var(--cb-info); text-decoration: none; }
.nfl-src-prop:hover { text-decoration: underline; }

@media (min-width: 600px) {
  .nfl-topprop { grid-template-columns: minmax(0, 1.1fr) minmax(0, 1.1fr) minmax(0, .7fr) minmax(0, .9fr); align-items: baseline; }
  .nfl-player-row { grid-template-columns: minmax(0, 1fr) minmax(0, .5fr); align-items: baseline; }
}

/* ============================================================
   NFL Today — slate command center. Mobile-first.
   ============================================================ */

/* Ranked slate lists share the top-prop card shape from the game page. */
.nfl-slate-ranks { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-3); counter-reset: none; }
.nfl-slate-ranks > li { min-width: 0; }
.nfl-slate-rank {
  font-family: var(--font-display); font-weight: 800; font-size: var(--fs-label);
  color: var(--text-muted); font-variant-numeric: tabular-nums;
  align-self: start;
}

/* Availability chip on a game card. Neutral by design — a designation is a
   fact about availability, never a colour-coded call to action. */
.nfl-chip.is-avail {
  background: var(--cb-gray-50); color: var(--text-body);
  font-weight: 800; letter-spacing: .04em; font-size: var(--fs-micro);
}

/* Top-prop link inside a game card. Sits ABOVE the cover anchor (z-index 2 via
   the existing `.nfl-gc > *:not(.nfl-gc-cover)` rule) so it is clickable
   without being nested inside it. */
.nfl-gc-topprop {
  display: grid; gap: 3px; margin-top: var(--sp-2); padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--border-subtle); border-radius: var(--radius-md);
  background: var(--surface-sunken); text-decoration: none; color: inherit;
  min-width: 0;
}
.nfl-gc-topprop:hover { border-color: var(--border-strong); background: var(--accent-wash); }
.nfl-gc-topprop:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.nfl-gc-topprop-eyebrow {
  font-size: var(--fs-micro); font-weight: 800; letter-spacing: .06em;
  text-transform: uppercase; color: var(--text-muted);
}
.nfl-gc-topprop-body { min-width: 0; overflow-wrap: anywhere; }
.nfl-gc-topprop-body b { color: var(--text-strong); }
.nfl-gc-topprop-meta { font-size: var(--fs-micro); color: var(--text-muted); }

.nfl-mod-link {
  font-size: var(--fs-sm); font-weight: 600; color: var(--cb-info);
  text-decoration: none; white-space: nowrap;
}
.nfl-mod-link:hover { text-decoration: underline; }

@media (min-width: 600px) {
  /* The rank number becomes a leading column; the rest matches the game page. */
  .nfl-slate-ranks .nfl-topprop {
    grid-template-columns: 28px minmax(0, 1.1fr) minmax(0, 1.1fr) minmax(0, .9fr);
  }
}

/* ============================================================
   Current-week facts — provenance, freshness, practice week.
   ============================================================ */

/* WHO said it. Never a quality claim, so deliberately quiet. */
.nfl-fact-provenance {
  margin: 4px 0 0; font-size: var(--fs-micro); color: var(--text-muted);
  font-weight: 600; letter-spacing: .03em; text-transform: uppercase;
}

/* The week's practice progression. Wraps on narrow screens; never a table. */
.nfl-practice-week {
  list-style: none; margin: var(--sp-2) 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: var(--sp-2);
}
.nfl-practice-day {
  display: grid; gap: 2px; padding: 6px 10px; min-width: 0;
  border: 1px solid var(--border-subtle); border-radius: var(--radius-md);
  background: var(--surface-raised);
}
.nfl-practice-dow {
  font-size: var(--fs-micro); font-weight: 800; letter-spacing: .06em;
  text-transform: uppercase; color: var(--text-muted);
}
.nfl-practice-part {
  font-size: var(--fs-sm); font-weight: 700; color: var(--text-strong);
  overflow-wrap: anywhere;
}
/* Participation is shaded by WHAT IT IS, not by whether it is good news.
   These are three factual states, not a rating. */
.nfl-practice-part.is-dnp { color: #a33d1f; }
.nfl-practice-part.is-limited { color: #8a6a12; }
.nfl-practice-part.is-full { color: #147a4a; }

/* ============================================================
   Factual timing — chronology, market at mention, prop lineage.
   Mobile-first, like everything above: rows stack on a phone and
   only widen in the min-width block at the end of this file.

   VISUAL SEPARATION IS DELIBERATE. A lineage row (one book over
   time) and a dispersion list (many books at one instant) are
   different facts, so they get different shapes on the page —
   a reader must never mistake one for the other.
   ============================================================ */

/* "recorded" rather than "posted": a quiet qualifier, never a warning badge.
   It states which clock the time came from, and that is not a defect. */
.nfl-timing-qual {
  font-size: var(--fs-micro); font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase; color: var(--text-muted);
}

/* The compact market-at-mention line under one evidence statement. Secondary
   to the quote by design — the statement is what the card is about. */
.nfl-timing-inline {
  margin: var(--sp-2) 0 0; font-size: var(--fs-micro);
  color: var(--text-muted); overflow-wrap: anywhere;
}
.nfl-timing-inline.is-empty { font-style: italic; }
.nfl-timing-inline-label {
  font-weight: 800; letter-spacing: .04em; text-transform: uppercase;
  margin-right: var(--sp-2);
}
.nfl-timing-inline-book {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Lineage: ONE ROW PER BOOK. The book name leads every row so the numbers
   after it are visibly owned by it — the layout itself is what makes a
   stitched-together cross-book track look wrong. */
.nfl-lineage { list-style: none; margin: var(--sp-3) 0 0; padding: 0; }
.nfl-lineage-row {
  display: grid; gap: 2px; padding: 10px 0;
  border-bottom: 1px solid var(--border-subtle); min-width: 0;
}
.nfl-lineage-row:last-child { border-bottom: 0; }
.nfl-lineage-book {
  font-size: var(--fs-micro); font-weight: 800;
  letter-spacing: .06em; text-transform: uppercase; color: var(--text-muted);
}
.nfl-lineage-track {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: var(--fs-sm); color: var(--text-strong); overflow-wrap: anywhere;
}
.nfl-lineage-flat { font-size: var(--fs-micro); color: var(--text-muted); }

/* The combined chronology. An ordered list on purpose: no chart, no axis, no
   implied relationship between adjacent rows beyond the order they happened. */
.nfl-chrono { list-style: none; margin: var(--sp-3) 0 0; padding: 0; }
.nfl-chrono-row {
  display: grid; grid-template-columns: auto 1fr; gap: 2px var(--sp-3);
  padding: 8px 0; border-bottom: 1px solid var(--border-subtle);
  font-size: var(--fs-sm); min-width: 0;
}
.nfl-chrono-row:last-child { border-bottom: 0; }
.nfl-chrono-at {
  grid-row: 1 / span 2;
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  color: var(--text-muted); white-space: nowrap;
}
.nfl-chrono-label { font-weight: 700; overflow-wrap: anywhere; }
.nfl-chrono-detail {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: var(--fs-micro); color: var(--text-muted);
}
/* A source statement and a sportsbook capture are different KINDS of event and
   are shaded apart. Neither shade means good or bad. */
.nfl-chrono-row[data-kind="source_mention"] .nfl-chrono-label { color: var(--cb-info); }
.nfl-chrono-row[data-kind="kickoff"] .nfl-chrono-label {
  letter-spacing: .06em; text-transform: uppercase; color: var(--text-muted);
}

@media (min-width: 640px) {
  .nfl-lineage-row {
    grid-template-columns: minmax(0, 10rem) minmax(0, 1fr) auto;
    align-items: baseline; gap: var(--sp-3);
  }
}

/* A two-point track (mention -> final pregame). The base track is built for the
   market card's THREE states; without this the pair renders in a three-column
   grid and the empty cell reads as a state we failed to show. */
@media (min-width: 640px) {
  .nfl-mkt-track.is-pair { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* A post-kick observation shown beside pregame ones. It is DE-EMPHASISED and
   explicitly qualified, never hidden: the price is a real observation, but an
   unlabelled in-play number sitting next to "First observed" and "Final
   pregame" reads as a pregame number, which is the ambiguity this closes.
   The dashed edge borrows the existing is-pending treatment on purpose — both
   mean "this point is not part of the main series". */
.nfl-mkt-point.is-post-kick {
  border: 1px dashed var(--border-subtle);
  background: transparent;
}
.nfl-mkt-qualifier {
  display: inline-block;
  font-size: var(--fs-micro); font-weight: 800;
  letter-spacing: .04em; text-transform: uppercase;
  padding: 2px 6px; border-radius: 999px; margin-left: 4px;
  background: var(--cb-gray-50); color: var(--text-muted);
  vertical-align: baseline;
}

/* ============================================================
   What Changed. Present only when the reader supplied an
   explicit ?since= — there is no stored last visit, so this
   module's ABSENCE is the normal state.

   Deliberately quiet. A delta is a count of captured rows, not
   an alert, so nothing here is red, nothing pulses and nothing
   competes with the prop the page is actually about.
   ============================================================ */
.nfl-wc-block + .nfl-wc-block { margin-top: var(--sp-3); }
.nfl-wc-list { list-style: none; margin: var(--sp-2) 0 0; padding: 0; }
.nfl-wc-row {
  display: flex; align-items: baseline; gap: var(--sp-2);
  font-size: var(--fs-sm); padding: 3px 0;
}
/* A neutral figure. "+2" is a count of rows we captured; it is not good news
   and not bad news, so it gets weight and no colour. */
.nfl-wc-delta {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: var(--fs-md); font-weight: 800; color: var(--text-strong);
}
.nfl-wc-items { list-style: none; margin: var(--sp-3) 0 0; padding: 0; }
.nfl-wc-item {
  display: grid; gap: 2px; padding: 8px 0;
  border-bottom: 1px solid var(--border-subtle); min-width: 0;
}
.nfl-wc-item:last-child { border-bottom: 0; }
.nfl-wc-label {
  font-size: var(--fs-micro); font-weight: 800;
  letter-spacing: .06em; text-transform: uppercase; color: var(--text-muted);
}
.nfl-wc-detail {
  font-size: var(--fs-sm); color: var(--text-strong); overflow-wrap: anywhere;
}
.nfl-wc-mkt {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

@media (min-width: 640px) {
  .nfl-wc-item {
    grid-template-columns: minmax(0, 12rem) minmax(0, 1fr);
    align-items: baseline; gap: var(--sp-3);
  }
}

/* ============================================================
   Historical context. Actual values a player recorded, and the
   arithmetic over them.

   THE SAMPLE SIZE IS PART OF THE NUMBER, not a footnote — N sits
   in the window head beside the scope, at the same weight, so a
   median can never be read without its denominator in view.
   Nothing here is coloured by whether a value is high or low.
   ============================================================ */
.nfl-hist-grid { display: grid; gap: var(--sp-3); }
.nfl-hist-win {
  padding: var(--sp-3); border-radius: var(--radius-md);
  background: var(--surface-sunken); min-width: 0;
}
.nfl-hist-win-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--sp-2);
}
.nfl-hist-scope {
  font-size: var(--fs-label); font-weight: 800;
  letter-spacing: .04em; text-transform: uppercase; color: var(--text-muted);
}
.nfl-hist-n {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: var(--fs-micro); font-weight: 700; color: var(--text-muted);
  white-space: nowrap;
}
.nfl-hist-agg {
  display: flex; flex-wrap: wrap; gap: var(--sp-3);
  margin: var(--sp-2) 0 0; font-size: var(--fs-sm);
}
.nfl-hist-agg b {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: var(--fs-md); color: var(--text-strong);
}
.nfl-hist-range { color: var(--text-muted); font-family: var(--font-mono); }
/* The actual game values, oldest first. A sequence, not a chart. */
.nfl-hist-values {
  margin: var(--sp-2) 0 0;
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: var(--fs-sm); color: var(--text-body); overflow-wrap: anywhere;
}
.nfl-hist-v { color: var(--text-strong); }
.nfl-hist-position { margin: var(--sp-3) 0 0; font-size: var(--fs-sm); }
.nfl-hist-position b {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  color: var(--text-strong);
}
.nfl-hist-splits { list-style: none; margin: var(--sp-3) 0 0; padding: 0; }
.nfl-hist-split {
  display: flex; align-items: baseline; gap: var(--sp-3);
  padding: 8px 0; border-bottom: 1px solid var(--border-subtle);
  font-size: var(--fs-sm); min-width: 0;
}
.nfl-hist-split:last-child { border-bottom: 0; }
.nfl-hist-split-val {
  margin-left: auto; font-family: var(--font-mono);
  font-variant-numeric: tabular-nums; overflow-wrap: anywhere;
}

@media (min-width: 640px) {
  .nfl-hist-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* ---- Historical intelligence -------------------------------------------
   The ASSESSED view of the history rendered below it. Bands describe evidence,
   never a recommendation, so nothing here is coloured green/red for good/bad --
   the ramp runs neutral-to-emphasis by how SUBSTANTIAL the evidence is, and the
   counter group is distinguished by its heading rather than by alarm colour.
   A reader must not be able to read "supporting" as "bet this". */
.nfl-intel-group { margin-top: 1rem; }
.nfl-intel-group-title {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin: 0 0 0.5rem;
}
.nfl-intel-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.5rem; }
.nfl-intel-item {
  border: 1px solid var(--border-subtle);
  border-radius: 10px;
  padding: 0.7rem 0.8rem;
  background: var(--surface-raised);
}
.nfl-intel-row {
  display: flex;
  flex-wrap: wrap;          /* 375px: the band drops above the label rather
                               than forcing a horizontal scroll. */
  align-items: baseline;
  gap: 0.5rem;
}
.nfl-intel-band {
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  padding: 0.15rem 0.45rem;
  border-radius: 999px;
  border: 1px solid var(--border-subtle);
  color: var(--text-muted);
  white-space: nowrap;
}
.nfl-intel-band--strong { color: var(--text-strong); border-color: var(--text-muted); }
.nfl-intel-band--moderate { color: var(--text-body); }
.nfl-intel-label { font-weight: 600; color: var(--text-strong); }
.nfl-intel-headline {
  margin: 0.35rem 0 0;
  font-variant-numeric: tabular-nums;
  color: var(--text-body);
}
.nfl-intel-meta {
  margin: 0.2rem 0 0;
  font-size: 0.82rem;
  color: var(--text-muted);
  /* Long metadata wraps instead of overflowing the card at 375px. */
  overflow-wrap: anywhere;
}
.nfl-intel-why { margin-top: 0.45rem; font-size: 0.82rem; color: var(--text-muted); }
.nfl-intel-why summary { cursor: pointer; }
.nfl-intel-why ul { margin: 0.4rem 0 0; padding-left: 1.1rem; }
.nfl-intel-provenance { margin: 0.4rem 0 0; font-size: 0.78rem; }
.nfl-intel-unassessed { margin-top: 0.9rem; }

/* ============================================================
   SOURCE LEADERBOARD + SOURCE PROFILE

   Deliberately thin. The ranked list REUSES .nfl-rank / .nfl-rank-item, so a
   source row and a most-mentioned row are the same component and the podium
   treatment is the brand's existing one (leader in accent, the rest neutral and
   descending in weight) rather than a second, competing ramp. The Tracking list
   and every breakdown reuse .nfl-dl / .nfl-dl-card, and the record strip reuses
   .nfl-status-cell. Only the pieces below have no existing equivalent.

   MOBILE-FIRST, like the rest of this sheet: the filter row stacks, and the
   history list is a card stack that becomes a three-column row at 768px. There
   is no table at any width, so nothing can overflow horizontally at 375px.
   ============================================================ */

/* Filter row. Stacks on a phone, one line from 560px. */
.nfl-src-filters {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  margin: 0 0 var(--sp-5);
}
.nfl-src-field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.nfl-src-field select {
  font-family: inherit;
  font-size: var(--fs-sm);
  color: var(--text-strong);
  background: var(--surface-raised);
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius-md);
  padding: 9px 11px;
  max-width: 100%;
}
.nfl-src-field select:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.nfl-src-apply {
  align-self: flex-start;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-label);
  color: var(--surface-raised);
  background: var(--accent-strong);
  border: 0;
  border-radius: var(--radius-md);
  padding: 10px 20px;
  cursor: pointer;
}
.nfl-src-apply:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* The qualification explanation. Sits above the ranked list because a reader
   needs to know what the minimum IS before they read a rank. */
.nfl-src-gate {
  padding: var(--sp-4);
  margin: 0 0 var(--sp-5);
  border-radius: var(--radius-md);
  border: 1px solid var(--border-hairline);
  background: var(--surface-sunken);
}
.nfl-src-gate-head {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-label);
  letter-spacing: .03em;
  text-transform: uppercase;
  color: var(--text-strong);
  margin: 0;
}
.nfl-src-gate-dek {
  font-size: var(--fs-sm);
  line-height: var(--lh-relaxed);
  color: var(--text-body);
  margin: 6px 0 0;
  max-width: 72ch;
}

/* Record + sample, in the .nfl-rank-item's prop cell. */
.nfl-src-line { display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap; }
.nfl-src-line b {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--fs-title);
  font-variant-numeric: tabular-nums;
  color: var(--text-strong);
}
.nfl-src-line span, .nfl-src-meta {
  font-size: var(--fs-label);
  color: var(--text-muted);
}
.nfl-src-meta { margin: 6px 0 0; line-height: var(--lh-normal); overflow-wrap: anywhere; }

/* PRESEASON TEST marker. Neutral, never a win/loss colour: it describes OUR
   data's status, not how a source performed. */
.nfl-src-test {
  display: inline-block;
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  padding: 2px 6px;
  border-radius: 4px;
  background: var(--surface-sunken);
  color: var(--text-muted);
  border: 1px solid var(--border-hairline);
}

.nfl-src-link { color: inherit; text-decoration: none; border-bottom: 1px solid var(--border-strong); }
.nfl-src-link:hover { border-bottom-color: var(--accent-strong); }
.nfl-src-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.nfl-src-back { margin: 0 0 var(--sp-4); font-size: var(--fs-sm); }

/* Selection history. A superseded row is DIMMED and labelled, never hidden --
   and never styled like an official pick, which is the whole point. */
.nfl-src-history { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-2); }
.nfl-src-hist-item {
  display: grid;
  grid-template-columns: 1fr;
  gap: 4px;
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--radius-md);
  border: 1px solid var(--border-hairline);
  background: var(--surface-raised);
  min-width: 0;
}
.nfl-src-hist-item.is-superseded { background: var(--surface-sunken); border-style: dashed; }
.nfl-src-hist-when {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  color: var(--text-muted);
  white-space: nowrap;
}
.nfl-src-hist-what { font-size: var(--fs-sm); color: var(--text-body); overflow-wrap: anywhere; }
.nfl-src-hist-status {
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.nfl-src-hist-item:not(.is-superseded) .nfl-src-hist-status { color: var(--text-strong); }

/* The method note. Small print that a reader can still read. */
.nfl-src-note {
  margin-top: var(--sp-8);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--border-hairline);
}
.nfl-src-note p {
  font-size: var(--fs-label);
  line-height: var(--lh-relaxed);
  color: var(--text-muted);
  margin: 0 0 6px;
  max-width: 78ch;
}

@media (min-width: 560px) {
  .nfl-src-filters { flex-direction: row; align-items: flex-end; flex-wrap: wrap; }
  .nfl-src-field { flex: 1 1 200px; }
  .nfl-src-apply { align-self: auto; }
}

@media (min-width: 768px) {
  .nfl-src-hist-item {
    grid-template-columns: 170px minmax(0, 1fr) auto;
    align-items: baseline;
    column-gap: var(--sp-4);
  }
}

/* ============================================================
   12. FOOTBALL INTELLIGENCE
   Presentation for the exact-prop intelligence sections.

   Deliberately built on the MLB board's lane-and-card idiom
   (pi-lane-head / pi-signal-card / pi-ws-empty) rather than a third
   vocabulary: same spacing scale, same radii, same hairline borders,
   same badge weight and casing, same quiet empty state. NFL keeps its
   own `nfl-mod` outer shell and its own accent, so the two sports read
   as one product without either becoming the other.
   ============================================================ */

/* ---------- Lanes ---------- */
.nfl-lane-head {
  display: flex; align-items: center; gap: 7px;
  border-top: 3px solid var(--accent-strong);
  padding-top: 10px;
  margin: var(--sp-5) 0 var(--sp-3);
}
.nfl-lane-head:first-of-type { margin-top: 0; }
.nfl-lane-title {
  font-family: var(--font-display); font-weight: 800; font-size: 12.5px;
  text-transform: uppercase; letter-spacing: .03em;
  color: var(--text-strong); margin: 0;
}
/* A quiet lane is the same structure at a lower rank: a hairline instead of the
   accent bar, so a secondary lane can never read as a primary one. */
.nfl-lane-head.is-quiet { border-top: 1px solid var(--border-hairline); }
.nfl-lane-head.is-quiet .nfl-lane-title { font-size: 11px; color: var(--text-muted); }
.nfl-lane-count { font-family: var(--font-mono); font-size: 10.5px; color: var(--text-faint); }

/* ---------- Fact cards ---------- */
.nfl-fact-grid {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-3); align-items: start;
}
/* The primary grid runs three-up on a wide screen so the whole promoted set is
   one scan rather than a column to read down. */
.nfl-fact-grid.is-primary { grid-template-columns: repeat(3, minmax(0, 1fr)); }

.nfl-fact-card {
  background: var(--surface-raised);
  border: 1px solid var(--border-hairline);
  border-left: 3px solid var(--cb-blue-300);
  border-radius: var(--radius-sm);
  padding: 13px 15px;
  box-shadow: var(--shadow-xs);
  min-width: 0;
}
/* PRIMARY CARDS READ FIRST. Existing tokens only -- a heavier surface, the
   accent edge, one step more padding and the section's shadow. The VALUE is
   what grows; the supporting clause does not, because a primary card earns its
   prominence by being quicker to read, not by being bigger all over. */
.nfl-fact-card.is-primary {
  border-left-color: var(--accent-strong);
  border-color: var(--border-soft);
  padding: 15px 17px;
  box-shadow: var(--shadow-sm);
}
.nfl-fact-card.is-primary .nfl-fact-value { font-size: var(--fs-h2); }
.nfl-fact-card.is-primary .nfl-fact-value.is-verbatim { font-size: 12px; }
.nfl-fact-card.is-primary .nfl-fact-category { color: var(--text-body); }
.nfl-fact-top {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-2); margin-bottom: 6px;
}
.nfl-fact-category {
  font-family: var(--font-display); font-size: 9.5px; font-weight: 800;
  letter-spacing: .07em; text-transform: uppercase; color: var(--text-muted);
  min-width: 0; overflow-wrap: anywhere;
}
/* Sample size is a first-class part of the card, not a footnote: a figure whose
   denominator a reader has to hunt for is a figure they over-trust. */
.nfl-fact-sample {
  font-family: var(--font-mono); font-size: 10px; color: var(--text-faint);
  white-space: nowrap; flex: none;
}
/* ---------- Value first ----------
   The engine's sentence is "median 0.24, mean 0.24, n=8". The reader gets
   "24%" in display type with "8 games" underneath. Same numbers, one glance
   instead of one parse — which is the whole difference between a research
   report and a product.

   `is-verbatim` is the honest fallback: no translator recognised the shape, so
   the engine's own sentence renders at body size rather than being blown up to
   display size, where a clause set in 22px reads as a headline it is not. */
.nfl-fact-value {
  font-family: var(--font-display); font-weight: 800;
  font-size: var(--fs-h3); line-height: 1.15;
  color: var(--text-strong); margin: 0; overflow-wrap: anywhere;
  font-variant-numeric: tabular-nums;
}
.nfl-fact-value.is-verbatim {
  font-family: inherit; font-size: 12px; font-weight: 600;
  line-height: var(--lh-relaxed); color: var(--text-body);
}
.nfl-fact-support {
  font-size: 11.5px; line-height: var(--lh-normal); color: var(--text-muted);
  margin: 5px 0 0; overflow-wrap: anywhere; font-variant-numeric: tabular-nums;
}
/* What the value is OF, on the promoted card only: the family chip says which
   kind of evidence, the value says the number, and this says the measure. */
.nfl-fact-of {
  font-size: var(--fs-micro); font-weight: 700; color: var(--text-muted);
  letter-spacing: .02em;
}
.nfl-fact-partial { font-size: var(--fs-micro); color: var(--text-faint); margin: 6px 0 0; }
.nfl-fact-foot {
  display: flex; align-items: center; gap: var(--sp-2);
  flex-wrap: wrap; margin-top: 8px;
}
.nfl-fact-foot:empty { display: none; }
/* The overlap note. It is the sentence that stops a promoted card reading as an
   independent corroboration, so it is legible rather than fine print. */
.nfl-fact-overlap {
  font-size: var(--fs-micro); line-height: var(--lh-normal);
  color: var(--text-muted); margin: 8px 0 0;
  padding-top: 7px; border-top: 1px dashed var(--border-soft);
}
.nfl-fact-subs { list-style: none; margin: 8px 0 0; padding: 0; display: grid; gap: 5px; }
.nfl-fact-sub { display: flex; gap: var(--sp-2); flex-wrap: wrap; font-size: 11.5px; }
.nfl-fact-sub-label { font-weight: 700; color: var(--text-muted); flex: none; }
.nfl-fact-sub-detail { color: var(--text-body); font-variant-numeric: tabular-nums; min-width: 0; }

/* ---------- Placement badge ----------
   Rendered only where an upstream fact actually carries the meaning. Most
   football facts are undetermined, so on most props no badge appears at all
   and the page grows no empty Supporting / Counter columns. */
.nfl-badge {
  display: inline-flex; align-items: center; font-family: var(--font-display);
  font-size: 9px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
  padding: 2px 7px; border-radius: 5px; white-space: nowrap;
  background: var(--surface-sunken); color: var(--text-muted);
  border: 1px solid var(--border-hairline);
}
.nfl-badge.is-supporting { background: var(--accent-wash); color: var(--accent-strong); border-color: var(--cb-blue-100); }
.nfl-badge.is-counter { background: var(--surface-sunken); color: var(--text-strong); border-color: var(--border-strong); }

/* ---------- The overlap line above the primary grid ---------- */
.nfl-intel-overlap {
  font-size: var(--fs-label); line-height: var(--lh-relaxed);
  color: var(--text-body); margin: 0 0 var(--sp-4);
  padding: 10px 14px; border-radius: var(--radius-sm);
  border: 1px solid var(--border-hairline); background: var(--surface-sunken);
}
.nfl-intel-overlap b { font-variant-numeric: tabular-nums; color: var(--text-strong); }
.nfl-intel-jump {
  color: var(--text-link); font-weight: 700; white-space: nowrap;
  display: inline-flex; align-items: center; min-height: 24px;
}

/* ---------- Quiet empty state ----------
   A missing family is the ordinary case, not an error. One line, dashed, and
   the same size whether one family is absent or six. */
.nfl-quiet-empty {
  display: flex; align-items: center; gap: 9px;
  padding: 14px; border: 1px dashed var(--border-soft);
  border-radius: var(--radius-sm); background: var(--surface-raised);
}
.nfl-quiet-empty p { font-size: 11.5px; color: var(--text-muted); margin: 0; }
.nfl-quiet-empty .cb-i { width: 15px; height: 15px; flex: none; color: var(--text-faint); }

/* ---------- Cohort comparison ----------
   Seven repeated cards became four rows. Two numbers that only mean anything
   together belong on one line, and both sample sizes sit in the header where
   neither column can be read without its n. */
.nfl-cmp { display: grid; gap: 4px; }
.nfl-cmp-head,
.nfl-cmp-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(4.5em, auto) 10px minmax(4.5em, auto);
  gap: var(--sp-2) var(--sp-3); align-items: baseline;
}
.nfl-cmp-head {
  padding-bottom: 7px; margin-bottom: 3px;
  border-bottom: 1px solid var(--border-hairline);
}
.nfl-cmp-head .nfl-cmp-cohort,
.nfl-cmp-head .nfl-cmp-base {
  font-family: var(--font-display); font-size: 9.5px; font-weight: 800;
  letter-spacing: .06em; text-transform: uppercase; color: var(--text-muted);
  line-height: 1.35;
}
.nfl-cmp-head b { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0; }
.nfl-cmp-rows { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; }
.nfl-cmp-row { padding: 5px 0; border-bottom: 1px solid var(--border-soft); }
.nfl-cmp-row:last-child { border-bottom: 0; }
.nfl-cmp-label {
  font-size: 11.5px; font-weight: 700; color: var(--text-body);
  min-width: 0; overflow-wrap: anywhere;
}
.nfl-cmp-cohort,
.nfl-cmp-base {
  font-family: var(--font-display); font-weight: 800; font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap;
}
.nfl-cmp-cohort { color: var(--text-strong); }
/* The baseline is the reference, not the finding, so it is quieter than the
   cohort figure it is there to be read against. */
.nfl-cmp-base { color: var(--text-muted); }
.nfl-cmp-sep { color: var(--border-strong); text-align: center; }

/* ---------- Player and game context ----------
   Compact rows, not cards: these are standing facts and they should read as a
   reference strip rather than compete with the matchup intelligence above. */
.nfl-ctx-grid {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-3) var(--sp-4);
}
.nfl-ctx-cell { min-width: 0; }
.nfl-ctx-label {
  display: block; font-family: var(--font-display); font-size: 9.5px;
  font-weight: 800; letter-spacing: .07em; text-transform: uppercase;
  color: var(--text-muted); margin-bottom: 3px;
}
.nfl-ctx-value {
  font-size: var(--fs-sm); font-weight: 700; color: var(--text-strong);
  margin: 0; overflow-wrap: anywhere; font-variant-numeric: tabular-nums;
}
.nfl-ctx-support { font-size: var(--fs-micro); color: var(--text-muted); margin: 2px 0 0; }

/* ---------- Collapsed exact-line record ----------
   The count, in the largest type in the section. It replaced "LEANS OVER",
   which described the record instead of stating it. */
.nfl-hist-headline {
  font-family: var(--font-display); font-weight: 800; font-size: var(--fs-h3);
  line-height: 1.15; color: var(--text-strong); margin: 6px 0 4px;
  font-variant-numeric: tabular-nums;
}

/* ---------- Role notes ----------
   Movement and spread under the usage tiles. Never the level again — the tiles
   above already carry it. */
.nfl-role-notes { margin-top: var(--sp-4); }

/* ---------- Absent-family lists ---------- */
.nfl-absent-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 7px; }
.nfl-absent-row {
  display: grid; grid-template-columns: minmax(0, 13em) minmax(0, 1fr);
  gap: var(--sp-2) var(--sp-4); align-items: baseline;
}
.nfl-absent-label {
  font-size: var(--fs-micro); font-weight: 700; letter-spacing: .05em;
  text-transform: uppercase; color: var(--text-muted);
}
.nfl-absent-reason { font-size: 11.5px; line-height: var(--lh-normal); color: var(--text-body); }

/* ---------- Information origin ---------- */
.nfl-ev-chips { display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.nfl-origin-chip {
  display: inline-flex; align-items: center; font-family: var(--font-display);
  font-size: 9px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
  padding: 2px 7px; border-radius: 5px; white-space: nowrap;
  background: var(--surface-sunken); color: var(--text-muted);
  border: 1px solid var(--border-hairline);
}
/* An original post and an official confirmation are the two that carry their own
   weight. A repost or a citation is styled as a peer, not as a demotion: it is
   still a publication and it is still credited. UNKNOWN is dashed, because an
   unestablished relationship should look unestablished. */
.nfl-origin-chip.is-original,
.nfl-origin-chip.is-official_confirmation {
  background: var(--accent-wash); color: var(--accent-strong); border-color: var(--cb-blue-100);
}
.nfl-origin-chip.is-unknown { background: transparent; border-style: dashed; }
.nfl-origin-reason { font-size: var(--fs-micro); color: var(--text-faint); margin: 6px 0 0; }
.nfl-origin-list { list-style: none; margin: 0 0 var(--sp-3); padding: 0; display: grid; gap: 5px; }
.nfl-origin-row {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--sp-3); font-size: 11.5px; color: var(--text-body);
}
.nfl-origin-count { font-family: var(--font-mono); color: var(--text-muted); font-variant-numeric: tabular-nums; }

/* ---------- Empty market state ----------
   A finished panel, not a gap. Nothing on it is a number: a dash or a zero where
   a line belongs would be read as an observation we never made. */
/* One dashed row, the same shape as every other quiet empty on the page. An
   absent market is an ordinary state and takes the space of a sentence. */
.nfl-mkt-empty {
  display: flex; align-items: center; gap: 9px;
  padding: 12px 14px; border: 1px dashed var(--border-soft);
  border-radius: var(--radius-sm); background: var(--surface-raised);
}
.nfl-mkt-empty .cb-i { width: 16px; height: 16px; flex: none; color: var(--text-faint); }
.nfl-mkt-empty-body {
  font-size: 11.5px; color: var(--text-muted); margin: 0;
  line-height: var(--lh-normal);
}
.nfl-mkt-empty-body b { color: var(--text-strong); }

/* ---------- Hero market chip ----------
   Beside the prop, never above it. The prop is the hero; a price given top
   billing would make the page read as an offer. */
.nfl-ph-market {
  display: inline-flex; align-items: baseline; gap: 7px; flex-wrap: wrap;
  margin-top: var(--sp-3); padding: 5px 11px; border-radius: var(--radius-pill);
  border: 1px solid rgba(255, 255, 255, .22); background: rgba(255, 255, 255, .08);
  font-size: var(--fs-label); color: #fff; font-variant-numeric: tabular-nums;
}
.nfl-ph-market b { font-family: var(--font-display); font-weight: 800; }
.nfl-ph-market-label,
.nfl-ph-market-book {
  font-size: var(--fs-micro); letter-spacing: .06em; text-transform: uppercase;
  color: rgba(255, 255, 255, .72);
}
.nfl-ph-market.is-empty { border-style: dashed; color: rgba(255, 255, 255, .8); }

/* ---------- Responsive ----------
   Single column, in the same logical order. Nothing changes tier by breakpoint:
   a fact that is primary on a desktop is primary on a phone, and every
   disclosure stays reachable and operable. */
@media (max-width: 960px) {
  .nfl-fact-grid.is-primary { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 720px) {
  .nfl-fact-grid,
  .nfl-fact-grid.is-primary { grid-template-columns: minmax(0, 1fr); }
  .nfl-ctx-grid { grid-template-columns: minmax(0, 1fr); }
  /* The comparison keeps BOTH numbers on one line at every width: splitting
     cohort from baseline is exactly the reading the shape exists to prevent. */
  .nfl-cmp-head,
  .nfl-cmp-row { grid-template-columns: minmax(0, 1fr) auto 10px auto; }
  .nfl-absent-row { grid-template-columns: minmax(0, 1fr); gap: 2px; }
  .nfl-origin-row { flex-wrap: wrap; }
  .nfl-intel-jump { min-height: 44px; }
}

/* ============================================================
   WEEK NAVIGATION  (added 2026-08-29)

   NOT a second rail component. The scrolling strip, the 44px tap target, the
   flat-text tabs and the accent underline all come from `.cb-tabrail` /
   `.cb-tabs` in board-shell.css — the same primitive MLB Today uses for its
   section rail. Everything below only positions that rail and labels which
   phase it belongs to. Token-only, no restatement of the tab treatment.
   ============================================================ */
.nfl-weeknav { display: flex; flex-direction: column; gap: var(--sp-2); margin: 0 0 var(--sp-5); }
/* The phase name sits on the same baseline as the rail so the two read as one
   control. `align-items:flex-end` matches the tabs' own alignment. */
.nfl-weeknav-rail {
  display: flex; align-items: flex-end; gap: var(--sp-4);
  margin-bottom: 0;
}
.nfl-weeknav-phase {
  flex: none; padding-bottom: 12px; margin-bottom: -1px;
  font-family: var(--font-display); font-size: 11px; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase; color: var(--nfl-label);
  white-space: nowrap;
}
/* Week numbers are numerals, so they get tabular figures and a minimum width —
   otherwise "1" and "18" make the rail jump as the reader moves along it. */
.nfl-weeknav .cb-tabs a {
  font-variant-numeric: tabular-nums; min-width: 22px; justify-content: center;
}
/* Prev / next week. Reuses `.cb-hero-refresh` (board-shell.css) verbatim for
   geometry, focus and hover; this only removes the underline the navy zone's
   link styling would otherwise draw through the glyph. */
.nfl-weekstep { text-decoration: none; }

@media (max-width: 767px) {
  /* On a phone the phase label stacks above its rail rather than stealing
     width from the weeks themselves. */
  .nfl-weeknav-rail { flex-direction: column; align-items: stretch; gap: 2px; }
  .nfl-weeknav-phase { padding-bottom: 4px; margin-bottom: 0; }
}

/* ---------- Game card additions ---------- */
/* Full club names, secondary to the abbreviations directly above them. Pulled
   up against the abbreviation row so the two read as one identity block. */
.nfl-gc-names {
  margin: calc(var(--sp-4) * -1 + 2px) 0 0;
  font-size: var(--fs-sm); color: var(--nfl-label);
}
/* The canonical week key. Quietest chip in the row: it is provenance, not news. */
.nfl-chip.is-week {
  background: transparent; color: var(--nfl-label);
  letter-spacing: .04em; text-transform: uppercase;
}

/* ============================================================
   MATCHUP CARD v2 — coverage, attention, market observation
   ------------------------------------------------------------
   The card grew from "matchup + one figure row + one prop" to a compact
   intelligence block. It is a SCANNING surface, so everything below is sized
   down from the section vocabulary rather than up from the chip vocabulary:
   one 11px uppercase heading per block, one line of content, no borders except
   the single hairline that already separates the coverage row.

   `.nfl-gc` is a flex column with `gap: var(--sp-4)`. Four extra children at
   that gap would make the card twice as tall for a third more information, so
   every block below pulls itself back to sp-2 with the same negative-margin
   idiom `.nfl-gc-names` already uses — these blocks are one continuous
   intelligence readout, not four independent sections, and they should read
   that way. Nothing here changes the spacing of the rows that were already on
   the card.
   ============================================================ */

.nfl-gc-sect {
  display: flex;
  flex-direction: column;
  gap: 5px;
  margin-top: calc(var(--sp-2) - var(--sp-4));
  min-width: 0;
}

/* One heading vocabulary for every block on the card. Quieter and smaller than
   `.cb-eyebrow`: these label a line, not a section of the page. */
.nfl-gc-sechead {
  margin: 0;
  font-size: var(--fs-micro);
  font-weight: 800;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* Top attention: up to two exact props. `.nfl-gc-toplist` already existed for
   exactly this shape; only the row spacing is set here. */
.nfl-gc-sect .nfl-gc-toplist { gap: 6px; }
/* Denser than the standalone card version: two of these stack here, and the
   extra chrome is what turns a second row into a second section. */
.nfl-gc-sect .nfl-gc-topprop { margin-top: 0; padding: 6px 10px; gap: 2px; }

/* Observed books. A name and a tick, nothing else — no price, no rank, and no
   visual difference between one book and another. */
.nfl-gc-books {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1) var(--sp-3);
  font-size: var(--fs-sm);
  color: var(--text-body);
}
.nfl-gc-book { display: inline-flex; align-items: center; gap: 4px; white-space: nowrap; }
/* Neutral, never a "good" green: the tick means OBSERVED, not approved. */
.nfl-gc-book .cb-i { width: 13px; height: 13px; color: var(--text-faint); }

/* Provenance lines: when we looked, how deep the history is. */
.nfl-gc-obs,
.nfl-gc-context {
  margin: 0;
  font-size: var(--fs-micro);
  color: var(--text-muted);
  overflow-wrap: anywhere;
}
.nfl-gc-context { margin-top: calc(var(--sp-2) - var(--sp-4)); }
.nfl-gc-quiet { margin: 0; }

/* The card's affordance. A LABEL, not an anchor — the cover anchor above it is
   the only interactive element on the card and already names the destination.
   It reads as a link and inherits the card's hover so the whole surface still
   feels like one control. */
.nfl-gc-cta {
  margin-top: calc(var(--sp-2) - var(--sp-4));
  align-self: flex-start;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--cb-info);
}
.nfl-gc:hover .nfl-gc-cta { text-decoration: underline; }

@media (max-width: 480px) {
  /* On the narrowest phones the prop text and its counts stack rather than
     truncating a player's name. */
  .nfl-gc-books { gap: var(--sp-1) var(--sp-2); font-size: var(--fs-micro); }
}


/* ============================================================
   PLAYER PROP MARKET BOARD (matchup page)
   ------------------------------------------------------------
   INFORMATION-DENSE, NOT A SPORTSBOOK. The design brief for this section is
   almost entirely about restraint: the page is CuratedBets intelligence, and
   the moment the odds are the biggest thing on it, it reads as an odds screen.

   So the visual weight order here is deliberately: player name > market name >
   line > price > observation time. The line is the largest numeral in a cell
   because it is the prop's identity; the price is smaller and monospaced
   because it is an attribute of one observation. Neither ever competes with a
   player name, and no price is coloured -- a green number is a recommendation
   whatever the caption says.

   Every token below already exists in the theme. Nothing new is introduced.
   ============================================================ */

.nfl-pm { display: flex; flex-direction: column; gap: var(--sp-3); }
.nfl-pm-scope { margin: 0 0 var(--sp-3); }

.nfl-pm-player {
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius-lg);
  background: var(--surface-raised);
  box-shadow: var(--shadow-sm);
  padding: var(--pad-card-sm);
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  min-width: 0;
}

.nfl-pm-head {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-2);
  padding-bottom: var(--sp-2);
  border-bottom: 1px solid var(--border-hairline);
}
.nfl-pm-name {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--fs-title);
  color: var(--text-strong);
  text-decoration: none;
}
a.nfl-pm-name:hover { text-decoration: underline; }
a.nfl-pm-name:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
.nfl-pm-headmeta {
  margin-left: auto; font-size: var(--fs-micro); color: var(--text-muted);
  white-space: nowrap;
}

.nfl-pm-row { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.nfl-pm-market {
  margin: 0;
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-2);
  font-size: var(--fs-sm); font-weight: 700; color: var(--text-body);
}
/* A FACT, not a verdict: two books were seen at different lines. Neutral by
   design -- no colour implies one of them is the better number. */
.nfl-pm-flag {
  font-size: var(--fs-micro); font-weight: 600; color: var(--text-muted);
  border: 1px dashed var(--border-hairline); border-radius: 999px;
  padding: 1px 8px;
}

/* One CARD per observed book, sized to its content rather than to the row.
   auto-FIT with 1fr stretched two books across a 1240px row, so a cell holding
   the words "Not captured" occupied ~600px of it. auto-FILL with a bounded
   max column and `justify-content: start` keeps every book the same compact
   width and packs them from the left, so one book is one card, two books are
   two cards, and a fourth wraps to a second line on its own. */
.nfl-pm-books {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 260px));
  justify-content: start;
  gap: var(--sp-2);
}
.nfl-pm-cell {
  display: flex; flex-direction: column; gap: 3px;
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  background: var(--surface-sunken);
  min-width: 0;
}
/* NOT CAPTURED reads as a gap, not as a price of nothing. Dashed, quiet, and
   never styled like a cell that holds a number. */
.nfl-pm-cell.is-empty { background: transparent; border-style: dashed; }
.nfl-pm-book {
  font-size: var(--fs-micro); font-weight: 800; letter-spacing: .05em;
  text-transform: uppercase; color: var(--text-muted);
}
.nfl-pm-line {
  font-family: var(--font-mono); font-weight: 700;
  font-size: var(--fs-body); line-height: 1.15; color: var(--text-strong);
  font-variant-numeric: tabular-nums;
}
.nfl-pm-sides { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-3); }
.nfl-pm-side { font-size: var(--fs-micro); color: var(--text-body); white-space: nowrap; }
/* Prices are monospaced and SMALL. Deliberately never coloured: a green price
   is a recommendation however the caption is worded. */
.nfl-pm-side b {
  font-family: var(--font-mono); font-weight: 700; color: var(--text-body);
  font-variant-numeric: tabular-nums;
}
.nfl-pm-obs { font-size: var(--fs-micro); color: var(--text-faint); }
.nfl-pm-none { font-size: var(--fs-micro); color: var(--text-faint); }

/* Observation history: a drawer, not a chart. Phase 1 shows what we recorded
   and when, and stops there. */
.nfl-pm-hist > summary {
  cursor: pointer; list-style: none;
  font-size: var(--fs-micro); font-weight: 600; color: var(--cb-info);
  padding: 2px 0;
}
.nfl-pm-hist > summary::-webkit-details-marker { display: none; }
.nfl-pm-hist > summary:hover { text-decoration: underline; }
.nfl-pm-hist > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
.nfl-pm-hist-body {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--sp-3); padding: var(--sp-2) 0 0;
}
.nfl-pm-trackhead {
  margin: 0 0 4px; font-size: var(--fs-micro); font-weight: 800;
  letter-spacing: .05em; text-transform: uppercase; color: var(--text-muted);
}
.nfl-pm-points { list-style: none; margin: 0 0 4px; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.nfl-pm-points li { display: flex; align-items: baseline; gap: var(--sp-2); font-size: var(--fs-micro); }
.nfl-pm-point-line {
  font-family: var(--font-mono); font-weight: 700; color: var(--text-strong);
  font-variant-numeric: tabular-nums; min-width: 3.5em;
}
.nfl-pm-point-at { color: var(--text-muted); }

/* Between a phone and a laptop the bounded column can exceed the container;
   fall back to a single full-width card rather than overflowing. */
@media (max-width: 560px) {
  .nfl-pm-books { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 480px) {
  .nfl-pm-headmeta { margin-left: 0; width: 100%; white-space: normal; }
}

/* ---------- Source activity disclosure ----------
   Three statements are visible; the rest open in place. Both summary labels
   are in the markup and CSS shows the one matching [open] -- no JavaScript,
   and the control keeps <details>'s native keyboard and screen-reader
   behaviour. */
.nfl-src-more { margin-top: var(--sp-3); }
.nfl-src-more > summary {
  cursor: pointer;
  list-style: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  background: var(--surface-sunken);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--cb-info);
}
.nfl-src-more > summary::-webkit-details-marker { display: none; }
.nfl-src-more > summary:hover { border-color: var(--border-strong); }
.nfl-src-more > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.nfl-src-more[open] .nfl-src-more-show { display: none; }
.nfl-src-more:not([open]) .nfl-src-more-hide { display: none; }
.nfl-src-more-body { margin-top: var(--sp-3); }

/* ============================================================
   PHASE 2A — FOOTBALL INTELLIGENCE (matchup page)
   ------------------------------------------------------------
   RESEARCH DOSSIER, NOT A PICK SHEET. The whole visual brief is restraint:
   these are factual cards a reader scans, and the moment one of them is
   coloured for being large it has become an opinion.

   So there is NO conditional colour anywhere below. No green for a rising
   trend, no red for a falling one, no accent on a "good" share. Every value
   uses the same neutral ink, and the only chip with any tint at all is the
   PARTIAL COVERAGE label — which is a statement about our data, not about a
   player. That is the single rule this whole block exists to hold.

   Density is handled by making the sample text small and the label smaller,
   never by hiding the denominator: a percentage without its play count is the
   one thing these sections may not show.
   ============================================================ */

.nfl-fi-team { margin-bottom: var(--sp-4); }
.nfl-fi-teamhead {
  margin: 0 0 var(--sp-2);
  display: flex; align-items: baseline; gap: var(--sp-2);
  font-size: var(--fs-sm); font-weight: 800;
  letter-spacing: .04em; text-transform: uppercase; color: var(--text-muted);
}

/* Cards wrap into as many columns as fit. minmax keeps a card readable rather
   than letting two of them stretch across a 1240px row. */
.nfl-fi-players,
.nfl-fi-scheme,
.nfl-fi-hist {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: var(--sp-3);
}

.nfl-fi-card {
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius-lg);
  background: var(--surface-raised);
  box-shadow: var(--shadow-sm);
  padding: var(--pad-card-sm);
  display: flex; flex-direction: column; gap: var(--sp-3);
  min-width: 0;
}
.nfl-fi-cardhead {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-2);
  padding-bottom: var(--sp-2);
  border-bottom: 1px solid var(--border-hairline);
}
.nfl-fi-name {
  font-family: var(--font-display); font-weight: 800;
  font-size: var(--fs-title); color: var(--text-strong); text-decoration: none;
}
a.nfl-fi-name:hover { text-decoration: underline; }
a.nfl-fi-name:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
.nfl-fi-side { font-size: var(--fs-sm); color: var(--text-body); font-weight: 600; }
/* WHY this player is on the page. Research attention, never a forecast — so it
   is styled as a quiet note, not as a badge of merit. */
.nfl-fi-why {
  margin-left: auto; font-size: var(--fs-micro); color: var(--text-muted);
  white-space: nowrap;
}
.nfl-fi-note { margin: 0; font-size: var(--fs-sm); color: var(--text-muted); }

/* ---- factual cards ----
   CONTENT-DRIVEN, NOT COLUMN-DRIVEN. `auto-fit` + `1fr` reserved a full track
   for every column the row could hold, so a player with three display-worthy
   facts got three cards and a visible hole where a fourth would have gone —
   which reads as a missing measurement rather than as a player who simply has
   three relevant metrics.

   Flex-wrap packs from the left instead: each fact takes the width it needs
   between a readable floor and a ceiling that stops two facts stretching
   across a whole card. No filler, no reserved gap, and never a duplicated fact
   to make a row symmetrical. */
.nfl-fi-facts {
  display: flex; flex-wrap: wrap;
  gap: var(--sp-2);
}
.nfl-fi-fact {
  display: flex; flex-direction: column; gap: 2px;
  padding: var(--sp-2);
  border: 1px solid var(--border-subtle); border-radius: var(--radius-md);
  background: var(--surface-sunken);
  /* 118px is chosen against the card, not in the abstract: the player grid
     lays out ~300px columns, which leaves ~268px inside the padding, so a
     basis of 132px made two facts 4px too wide and every card silently
     collapsed to one fact per row. At 118 they pack two-across and grow to
     fill, which is what makes the stack short. */
  flex: 1 1 118px;
  max-width: 210px;
  min-width: 0;
}
.nfl-fi-factlabel {
  font-size: var(--fs-micro); font-weight: 800; letter-spacing: .05em;
  text-transform: uppercase; color: var(--text-muted);
}
.nfl-fi-factvalue {
  font-family: var(--font-mono); font-weight: 700; font-size: var(--fs-body);
  color: var(--text-strong); font-variant-numeric: tabular-nums;
}
.nfl-fi-factscope, .nfl-fi-rank { font-size: var(--fs-micro); color: var(--text-faint); }
/* The ONLY tinted chip in this block, and it describes OUR coverage. */
.nfl-fi-partial {
  display: inline-block; font-size: var(--fs-micro); font-weight: 600;
  color: var(--cb-warning, var(--text-muted));
  border: 1px solid var(--border-subtle); border-radius: 999px;
  padding: 0 7px; white-space: nowrap;
}

/* ---- recent form: values, not a chart ---- */
.nfl-fi-trends { display: flex; flex-direction: column; gap: var(--sp-2); }
.nfl-fi-trend { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.nfl-fi-trendlabel {
  font-size: var(--fs-micro); font-weight: 800; letter-spacing: .05em;
  text-transform: uppercase; color: var(--text-muted);
}
.nfl-fi-trendvals { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px; }
.nfl-fi-tv {
  font-family: var(--font-mono); font-weight: 700; font-size: var(--fs-sm);
  color: var(--text-body); font-variant-numeric: tabular-nums;
}
.nfl-fi-tsep { color: var(--text-faint); }
.nfl-fi-trendscope { font-size: var(--fs-micro); color: var(--text-faint); }

/* ---- abstentions ---- */
.nfl-fi-abstain > summary {
  cursor: pointer; list-style: none;
  font-size: var(--fs-micro); font-weight: 600; color: var(--cb-info);
}
.nfl-fi-abstain > summary::-webkit-details-marker { display: none; }
.nfl-fi-abstain > summary:hover { text-decoration: underline; }
.nfl-fi-abstain > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
.nfl-fi-abstainlist {
  margin: var(--sp-2) 0 0; padding-left: 1.1em;
  font-size: var(--fs-micro); color: var(--text-muted);
  display: flex; flex-direction: column; gap: 4px;
}
.nfl-fi-abstainlist b { color: var(--text-body); }

/* ---- scheme + historical rows ---- */
.nfl-fi-rows { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-2); }
.nfl-fi-rows > li { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.nfl-fi-rowlabel {
  font-size: var(--fs-micro); font-weight: 800; letter-spacing: .05em;
  text-transform: uppercase; color: var(--text-muted);
}
.nfl-fi-rowvalue {
  font-size: var(--fs-sm); font-weight: 600; color: var(--text-strong);
  overflow-wrap: anywhere;
}
/* The denominator. Never optional, never hidden — it is what makes the
   percentage above it a fact rather than a claim. */
.nfl-fi-rowsample { font-size: var(--fs-micro); color: var(--text-faint); }

.nfl-fi-context { margin-top: var(--sp-3); }

/* ---- per-team player disclosure ----
   Deliberately the same control as Source Activity's "show more" above it:
   one affordance vocabulary on one page. Both summary labels are in the markup
   and CSS shows the one matching [open], so it needs no JavaScript and keeps
   <details>'s native keyboard and screen-reader behaviour. */
.nfl-fi-more { margin-top: var(--sp-3); }
.nfl-fi-more > summary {
  cursor: pointer; list-style: none;
  display: inline-flex; align-items: center; gap: 6px;
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--border-subtle); border-radius: var(--radius-md);
  background: var(--surface-sunken);
  font-size: var(--fs-sm); font-weight: 600; color: var(--cb-info);
}
.nfl-fi-more > summary::-webkit-details-marker { display: none; }
.nfl-fi-more > summary:hover { border-color: var(--border-strong); }
.nfl-fi-more > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.nfl-fi-more[open] .nfl-fi-more-show { display: none; }
.nfl-fi-more:not([open]) .nfl-fi-more-hide { display: none; }
.nfl-fi-more-body { margin-top: var(--sp-3); }

/* The lane list inside the consolidated all-empty state. */
.nfl-fi-lanes {
  list-style: none; margin: var(--sp-2) 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-4);
  font-size: var(--fs-micro); color: var(--text-muted);
}
.nfl-fi-lanes b { color: var(--text-body); font-weight: 600; }

@media (max-width: 560px) {
  .nfl-fi-players, .nfl-fi-scheme, .nfl-fi-hist { grid-template-columns: minmax(0, 1fr); }
  .nfl-fi-why { margin-left: 0; width: 100%; white-space: normal; }
  /* One fact per row rather than two cramped ones. */
  .nfl-fi-fact { flex: 1 1 100%; max-width: none; }
}

/* ---- Usage coverage abstentions (player page) ----
   Same control vocabulary as the matchup page's per-player disclosure, so the
   two surfaces read as one product rather than two designs. Metrics land here
   when their observation coverage fell below the canonical floor — naming the
   abstention is the whole point, because a silently dropped tile reads as
   "he had none". */
.nfl-usage-abstain { margin-top: var(--sp-3); }
.nfl-usage-abstain > summary {
  cursor: pointer; list-style: none;
  font-size: var(--fs-micro); font-weight: 600; color: var(--cb-info);
}
.nfl-usage-abstain > summary::-webkit-details-marker { display: none; }
.nfl-usage-abstain > summary:hover { text-decoration: underline; }
.nfl-usage-abstain > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
.nfl-usage-abstainlist {
  margin: var(--sp-2) 0 0; padding-left: 1.1em;
  font-size: var(--fs-micro); color: var(--text-muted);
  display: flex; flex-direction: column; gap: 4px;
}
.nfl-usage-abstainlist b { color: var(--text-body); }

/* The coverage chip inside a usage tile. `.nfl-usage-cell` stacks its label and
   value as blocks, so the chip needs its own line and a little air — inline it
   collided with the value and read as "2.0Partial coverage". */
.nfl-usage-cell .nfl-fact-partial {
  display: table;      /* shrink-to-fit on its own line, no flex parent needed */
  margin-top: 6px;
}

/* ============================================================
   PLAYER PROP MARKET BOARD (player page)
   ------------------------------------------------------------
   The matchup board's treatment, given room. The page is scoped to one
   player, so each market gets its own titled card instead of a dense row,
   and the book cells inherit the matchup page's compact card sizing so the
   two surfaces read as one product.

   Same restraint as the matchup board: the LINE is the largest numeral,
   the price is smaller and monospaced, and no value is ever coloured. A
   green price is a recommendation whatever the caption says.
   ============================================================ */

.nfl-pm-player { gap: var(--sp-3); }
/* CLASS COLLISION, RESET DELIBERATELY AND IN FULL.
   `.nfl-pm-market` is also the matchup board's market LABEL row, styled there
   as `display:flex; flex-wrap:wrap; align-items:baseline; font-size:sm;
   font-weight:700`. Here the same name is a market CARD. Overriding only
   `display`/`flex-direction` left the rest of that rule live, and two of them
   did real damage:

     * `align-items: baseline` on a COLUMN flex container resolves to
       shrink-to-fit on the cross axis, so the book grid inside sized itself to
       its content and used about a sixth of a 1280px card. This read as a
       deliberate "compact cells" choice and was not one.
     * `font-weight: 700` inherited into every descendant, so observation
       timestamps and micro copy rendered bold.

   Every inherited property is therefore restated rather than assumed. */
.nfl-pm-market {
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius-lg);
  background: var(--surface-raised);
  box-shadow: var(--shadow-sm);
  padding: var(--pad-card-sm);
  display: flex; flex-direction: column; flex-wrap: nowrap;
  align-items: stretch; gap: var(--sp-3);
  font-size: var(--fs-body); font-weight: 400; color: var(--text-body);
  min-width: 0;
}
/* With the card now full width, four markets stacked vertically leave the
   right half of a desktop viewport empty. A two-column grid halves the section
   without touching the cells themselves.

   auto-FIT rather than a fixed `repeat(2, ...)`: a player observed in ONE
   market is the common case, and a fixed two-column track left that lone card
   at half width beside an empty column. auto-fit collapses the empty track so
   one market fills the row, two share it, and four make two rows.

   `align-items: start` keeps a short card from stretching to match a tall
   neighbour that has its observation history expanded. */
@media (min-width: 1000px) {
  .nfl-pm-player {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(420px, 1fr));
    align-items: start;
  }
}
/* The line the reader arrived on. A quiet left rule and a neutral chip —
   deliberately NOT an accent fill, which would read as "the good one". */
.nfl-pm-market.is-selected { border-left: 3px solid var(--border-strong); }
.nfl-pm-markethead {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-2);
  padding-bottom: var(--sp-2);
  border-bottom: 1px solid var(--border-hairline);
}
.nfl-pm-marketname {
  margin: 0; font-family: var(--font-display); font-weight: 800;
  font-size: var(--fs-title); color: var(--text-strong);
}
.nfl-pm-selected {
  font-size: var(--fs-micro); font-weight: 600; color: var(--text-muted);
  border: 1px solid var(--border-subtle); border-radius: 999px; padding: 1px 8px;
}
.nfl-pm-subhead {
  margin: var(--sp-4) 0 var(--sp-2);
  font-size: var(--fs-micro); font-weight: 800; letter-spacing: .05em;
  text-transform: uppercase; color: var(--text-muted);
}
.nfl-pm-nomatch { margin-top: var(--sp-2); }

/* ---- Additional source activity (attention) ----
   Leans, fades, passes and unclassified statements. Same disclosure
   vocabulary as the coverage abstentions, because both say the same kind of
   thing: here is real captured evidence that does NOT count toward the
   headline, and here is why. */
.nfl-attn-other { margin-top: var(--sp-3); }
.nfl-attn-other > summary {
  cursor: pointer; list-style: none;
  font-size: var(--fs-micro); font-weight: 600; color: var(--cb-info);
}
.nfl-attn-other > summary::-webkit-details-marker { display: none; }
.nfl-attn-other > summary:hover { text-decoration: underline; }
.nfl-attn-other > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
.nfl-attn-otherlist {
  margin: var(--sp-2) 0 var(--sp-2); padding-left: 1.1em;
  font-size: var(--fs-micro); color: var(--text-muted);
  display: flex; flex-direction: column; gap: 4px;
}
.nfl-attn-otherlist b { color: var(--text-body); }

/* Per-prop counts in the switcher: two units, visibly two lines. */
.nfl-prop-row-sub { display: block; font-size: var(--fs-micro); color: var(--text-faint); }

/* ============================================================
   PHASE C -- CONSOLIDATION
   Three new surfaces, all built from components already in this
   sheet. No new component language: the availability cards reuse
   the context grid, Recent Games is an ordinary table, and the
   methodology disclosure reuses the disclose treatment.
   ============================================================ */

/* ---------- Availability, now a top-level module ---------- */
/* One card per KNOWN fact. Unknown facts are not rendered as cards at
   all -- a grid of "Not reported" tells a reader nothing that the one
   compact sentence below it does not, and it reads as a fault list. */
.nfl-ctx-card {
  min-width: 0;
  padding: var(--sp-3);
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius-md);
  background: var(--surface-sunken);
}
.nfl-ctx-card .nfl-ctx-value {
  display: block;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--fs-title);
  color: var(--text-strong);
  margin-top: 2px;
}

/* ---------- Recent games ---------- */
/* A TABLE, because it is tabular. Numerals are tabular-figures and
   right-aligned so a column of them can be compared down the page;
   the date and opponent stay left. Nothing here is coloured by value:
   a green cell would be this page rating a performance. */
.nfl-rg-wrap { overflow-x: auto; }
.nfl-rg {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-sm);
}
.nfl-rg th,
.nfl-rg td {
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--border-hairline);
  white-space: nowrap;
}
.nfl-rg thead th {
  font-family: var(--font-display);
  font-size: var(--fs-micro);
  font-weight: 800;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-muted);
  text-align: left;
}
.nfl-rg th.is-num,
.nfl-rg td.is-num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.nfl-rg tbody tr:last-child th,
.nfl-rg tbody tr:last-child td { border-bottom: 0; }
.nfl-rg-date { color: var(--text-muted); font-variant-numeric: tabular-nums; }
.nfl-rg-opp { font-weight: 700; color: var(--text-body); }

/* ---------- Methodology, at the foot ---------- */
/* Closed by default and visually quiet. It is reference material, and
   it should not compete with the research above it for attention. */
.nfl-method > summary,
.nfl-method-summary {
  cursor: pointer;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--fs-sm);
  color: var(--text-body);
  list-style: none;
}
.nfl-method-summary::-webkit-details-marker { display: none; }
.nfl-method-summary::before {
  content: "▸ ";
  color: var(--text-muted);
}
.nfl-method[open] > .nfl-method-summary::before { content: "▾ "; }

/* ============================================================
   PLAYER PAGE VISUAL POLISH
   Presentation only. No section is added, removed, reordered or
   given new content -- every rule below changes how the existing
   modules READ, not what they say.

   The page had ten correct modules that did not yet feel like one
   product: a status fact rendered as a half-empty card, a module
   whose closing disclaimer touched the next module's eyebrow, and
   three levels of border inside the market. Hierarchy first,
   decoration never.
   ============================================================ */

/* ---- 1. SECTION RHYTHM ------------------------------------
   Sections sat 40px apart except market -> attention, which sat at
   ZERO: the market's closing compliance note ran straight into the
   next eyebrow and the two modules read as one. The gap is now a
   property of the section rather than of whatever happened to be
   the last child. */
.cb-board .nfl-mod { margin-top: var(--sp-7, 40px); }
.cb-board .nfl-mod:first-of-type { margin-top: var(--sp-6, 32px); }
/* A trailing disclaimer belongs to the module above it and needs to
   settle before the next one begins. */
.cb-board .nfl-mod > .cb-compliance-note:last-child,
.cb-board .nfl-mod > .cb-micro:last-child { margin-bottom: 0; }

/* Module heads: one scale, one spacing, every section. */
.cb-board .nfl-mod-head { margin-bottom: var(--sp-4, 16px); }
.cb-board .nfl-mod-dek {
  /* Prose is capped at a readable measure instead of running to
     whatever width the grid happens to be. */
  max-width: 62ch;
  margin-bottom: var(--sp-3, 12px);
}

/* ---- 2. AVAILABILITY: A STATUS STRIP, NOT A CARD -----------
   One status fact was rendering as a 612px card in a 1240px row,
   so half the module was empty and the fact read as heavier than it
   is. Laid out as a strip it uses the width, scans left to right,
   and stops competing with the market below it. */
#availability .nfl-ctx-grid { display: block; }
#availability .nfl-ctx-card {
  width: 100%;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-2, 8px) var(--sp-5, 24px);
  padding: var(--sp-3, 12px) var(--sp-4, 16px);
}
#availability .nfl-ctx-card > * { margin: 0; }
#availability .nfl-usage-label { flex: 0 0 auto; }
#availability .nfl-ctx-value { font-size: var(--fs-title); line-height: 1.2; }
/* Freshness and provenance are metadata about our record, so they sit
   at the end of the strip rather than under the designation. */
#availability .cb-micro { margin-left: auto; text-align: right; }

/* ---- 3. MARKET: FEWER BORDERS, SAME FACTS ------------------
   Section -> market card -> book cell was three nested borders, and
   the innermost one carried no information the background did not.
   The cell keeps its shape through surface and radius; the dashed
   NOT-CAPTURED cell keeps its border, because there the border IS
   the meaning. */
.nfl-pm-cell { border-color: transparent; }
.nfl-pm-cell.is-empty { border-color: var(--border-subtle); }
.nfl-pm-books { gap: var(--sp-2, 8px); }
/* The scope line reads as methodology, not as a headline. */
.nfl-pm-scope { color: var(--text-muted); margin-bottom: var(--sp-3, 12px); }

/* ---- 4. EMPTY STATES: COMPACT, NOT DEAD SPACE --------------
   Production's ordinary player has markets and no attention. That
   state must look deliberate rather than broken, which means small
   and quiet -- not a full-height card announcing an absence. */
.cb-board .nfl-mod > .nfl-state {
  padding: var(--sp-3, 12px) var(--sp-4, 16px);
  gap: var(--sp-3, 12px);
}
.cb-board .nfl-mod > .nfl-state .nfl-state-head { margin-bottom: 2px; }

/* ---- 5. METRIC TILES: THE NUMBER IS THE POINT --------------
   Role & opportunity and the matchup facts share one tile. The value
   leads, the label supports it, and the sample sits underneath in the
   quietest tier the theme has. */
.nfl-usage-cell { padding: var(--sp-3, 12px) var(--sp-4, 16px); }
.nfl-usage-value { line-height: 1.15; }
.nfl-usage-label {
  letter-spacing: .04em;
  text-transform: uppercase;
  font-size: var(--fs-micro);
  color: var(--text-muted);
}

/* ---- 6. RECENT GAMES: A STAT TABLE ------------------------
   Numbers align on their right edge so a column can be read down;
   the date and opponent stay left. Tabular figures stop the columns
   shivering between rows. */
.nfl-rg { font-variant-numeric: tabular-nums; }
.nfl-rg td, .nfl-rg th { padding: 7px var(--sp-3, 12px); }
.nfl-rg td:not(:first-child):not(:nth-child(2)),
.nfl-rg th:not(:first-child):not(:nth-child(2)) { text-align: right; }
.nfl-rg tbody tr + tr { border-top: 1px solid var(--border-hairline); }

/* ---- 7. HERO ---------------------------------------------
   The name was already the strongest element. It is given room to be
   that, and the metadata line is set as one quiet run rather than a
   row of competing pills. */
.cb-hero .cb-hero-title { letter-spacing: -0.02em; }

/* ---- 8. MODULE HEAD BALANCE -------------------------------
   The head is a flex row of [eyebrow + title + dek] and [meta], set
   to space-between. With neither side allowed to grow, the text block
   held its content width, the meta held its own, and the ~450px
   between them was a void that made the dek wrap to four lines while
   the timestamp drifted off toward the right edge unattached.

   The text block now takes the free space (its prose still capped at
   a readable measure by rule 1), and the meta aligns to the top so it
   reads as an annotation on the heading rather than floating at the
   vertical middle of nothing. */
.cb-board .nfl-mod-head { align-items: flex-start; gap: var(--sp-5, 24px); }
.cb-board .nfl-mod-head > :first-child { flex: 1 1 auto; min-width: 0; }
.cb-board .nfl-mod-meta { flex: 0 0 auto; text-align: right; }

/* ---- 9. SINGLE PUBLIC SPORTSBOOK --------------------------
   While one book is public, the book grid is a grid of one. Left as
   it was, the lone FanDuel cell held a ~260px auto-fill column and
   the rest of the market card was empty -- the layout still shaped
   around books that are no longer rendered.

   The cell now spans the card and lays its parts out along that width
   instead of stacking them in a narrow column: book, line and prices
   read across, and the observation stamp settles at the end. It is
   NOT made large simply because the others went away; the row is
   shorter than the three-column version it replaces. */
.nfl-pm-books.is-single { grid-template-columns: minmax(0, 1fr); }
.nfl-pm-books.is-single .nfl-pm-cell {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-2, 8px) var(--sp-5, 24px);
  padding: var(--sp-3, 12px) var(--sp-4, 16px);
}
.nfl-pm-books.is-single .nfl-pm-book { flex: 0 0 auto; }
.nfl-pm-books.is-single .nfl-pm-sides {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2, 8px) var(--sp-4, 16px);
}
/* Provenance is metadata about our record, so it ends the row rather
   than interrupting the prices. */
.nfl-pm-books.is-single .nfl-pm-obs { margin-left: auto; text-align: right; }
/* A single uncaptured book is a one-line fact, not a panel. */
.nfl-pm-books.is-single .nfl-pm-cell.is-empty { padding: var(--sp-2, 8px) var(--sp-4, 16px); }

/* A flex item cannot shrink below its content unless told to, so the
   stamp -- one unbreakable-looking run of ~210px -- pushed past the
   cell instead of wrapping inside it. `min-width: 0` lets it wrap,
   and `flex: 1 1 100%` (not basis alone) actually claims a line of
   its own on a wrapping row. */
/* EVERY observation stamp, not only the single-book one. The same run
   appears on the selected-prop card and the matchup cells, and each
   overflowed a narrow viewport for the same reason. */
.nfl-pm-obs { min-width: 0; overflow-wrap: anywhere; }

@media (max-width: 640px) {
  /* The stamp gets its own line rather than being squeezed against
     the prices. */
  /* PLAIN BLOCK FLOW ON A PHONE. The row layout is a desktop
     affordance; at this width the parts want to stack anyway, and a
     wrapping flex row was leaving the observation stamp on the first
     line and pushing it past the cell. Block flow has no line-fitting
     to get wrong. */
  .nfl-pm-books.is-single .nfl-pm-cell { display: block; }
  .nfl-pm-books.is-single .nfl-pm-cell > * { display: block; }
  .nfl-pm-books.is-single .nfl-pm-sides {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-1, 4px) var(--sp-4, 16px);
    margin-top: 2px;
  }
  .nfl-pm-books.is-single .nfl-pm-obs {
    margin: 4px 0 0;
    text-align: left;
  }
  .nfl-pm-obs { white-space: normal; }
}
