/* ═══════════════════════════════════════════════════════════
   Alpha Capture — styles.css v2.0
   Architecture: vertical scroll, 976px centered column
   Breakpoint: 820px (single-col picks/lb on narrow viewports)
   Tokens: all original preserved and extended

   ui-declutter branch, 2026-09-28: three-section stack (leaderboard,
   chart-analysis, picks) collapsed to one #section-main hosting the
   unified tab bar (LEADERBOARD/PERSONAS/PICKS). Chart panels parked
   with their supporting rules. Watermark moved from
   #section-leaderboard to .tab-panel[data-tab="leaderboard"].
═══════════════════════════════════════════════════════════ */

*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

:root {
  /* ── Color tokens — Rich Slate & Rose palette ─────────── */
  --black:        #0f172a;
  --wordmark:     #1e293b;
  --white:        #ffffff;
  --off-white:    #f8fafc;
  --border:       #e2e8f0;
  --mid-gray:     #374151;   /* ui-declutter 2026-09-28: was #64748b (slate-500). Darkened to slate-700 for legibility — light-mode muted text was reading as too faint against white. Sweeps through: tab inactive labels, wordmark tagline, rank numbers, sub-column headers, persona role labels, empty-state text, AI badge. */
  --light-gray:   #cbd5e1;
  --accent:       #e11d48;
  --border-panel: #e2e8f0;

  /* ── Typography tokens ───────────────────────────────────
     --sans    → all body text, game rows, rankings, dropdowns,
                 ticker, chart legend, leaderboard data
     --mono    → header wordmark, nav, date bars, footer (JetBrains Mono — unchanged)
     --font-id → player names, team abbreviations, numeric data
                 (Inter with tabular-nums — replaces Roboto Mono)
  ────────────────────────────────────────────────────────── */
  --sans:    'Inter', ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
             'Segoe UI', Roboto, Arial, 'Noto Sans', sans-serif;
  --mono:    'JetBrains Mono', 'Courier New', Courier, monospace;
  --font-id: 'Inter', ui-sans-serif, system-ui, sans-serif;

  /* ── Layout — new vertical scroll model ──────────────── */
  --header-h:       64px;
  --ticker-h:       80px;
  --footer-bar-h:   64.7px;
  --footer-h:       var(--footer-bar-h);

  /* Content column */
  --col-w:          1020px;       /* max content width: 1020 - 2*40 padding = 940 usable, shared by chart, leaderboard, and schedule. Widened post-Session-9 from 915 to accommodate new POS column + longer nickname column. */
  --col-pad:        40px;         /* outer horizontal padding at desktop */
  --col-pad-mobile: 20px;         /* outer horizontal padding at mobile */
  --section-pad-v:  32px;         /* top/bottom padding inside each section */

  /* Chart panel split — retained for parked trajectory to un-park cleanly */
  --chart-name-panel-w: 230px;
  --chart-gutter:       12px;

  /* Card / section tokens — used for game rows and lb rows */
  --card-pad-x:     20px;
  --row-h:          48px;         /* standard interactive row height */

  /* Section header */
  --section-header-h: 52px;

  /* Picks */
  --picks-col-w:    399px;        /* fixed width of each picks content column; middle 1fr absorbs the rest */
}

/* ── Dark theme — color token overrides ───────────────────── */
[data-theme="dark"] {
  --black:        #f1f5f9;
  --wordmark:     #e2e8f0;
  --white:        #0f172a;
  --off-white:    #1e293b;
  --border:       #334155;
  --mid-gray:     #94a3b8;
  --light-gray:   #475569;
  --accent:       #fb7185;
  --border-panel: #334155;
}

/* ── Base ─────────────────────────────────────────────── */


html, body {
  min-height: 100%;
}

/* ui-declutter 2026-09-28: scrollbar-gutter on html (where the root
   scrollbar actually lives in Safari — the earlier attempt on body
   didn't reserve space because body isn't the scrollable ancestor).
   Reserves the scrollbar's horizontal space always, so tab switches
   between panels of different heights don't shift the centered page
   column. Supported: Chrome 94+, Firefox 97+, Safari 16+. */
html {
  scrollbar-gutter: stable;
}

body {
  font-family: var(--sans);
  font-weight: 400;
  background: var(--white);
  color: var(--black);
  font-size: 14px;
  line-height: 1.5;
  overflow-x: hidden;
  overflow-y: auto;
  scrollbar-width: none;           /* Firefox */
  /* Inter font features — matches OpenRouter rendering */
  font-feature-settings: "calt" 1, "rlig" 1;
  font-variant-numeric: tabular-nums;  /* fixed-width numbers — columns align perfectly */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body::-webkit-scrollbar {
  display: none;                   /* Chrome, Safari, Edge */
}

/* ── Agent pulse animation — preserved ───────────────── */
@keyframes agent-pulse {
  0%, 100% { opacity: 0.35; }
  50%       { opacity: 0.9;  }
}
.agent-text--thinking {
  animation: agent-pulse 1.4s ease-in-out infinite;
  color: var(--mid-gray);
}

/* ── Skip link — preserved ───────────────────────────── */
.skip-link {
  position: absolute;
  left: -999px;
  top: 8px;
  background: var(--accent);
  color: #fff;
  padding: 6px 14px;
  font-size: 13px;
  z-index: 9999;
  border-radius: 2px;
  text-decoration: none;
}
.skip-link:focus { left: 8px; }

/* ── Focus styles — preserved ────────────────────────── */
*:focus { outline: none; }
*:focus-visible {
  outline: 2px solid var(--black);
  outline-offset: 3px;
  border-radius: 2px;
}
nav a:focus-visible       { outline-offset: -4px; }
.logo-link:focus-visible  { outline-offset: 2px; }
.date-caret:focus-visible { outline-offset: -3px; border-radius: 2px; }


/* ═══════════════════════════════════════════════════════════
   HEADER — full-width bar, content left-aligned with fixed padding
═══════════════════════════════════════════════════════════ */
header {
  position: sticky;
  top: 0;
  z-index: 200;
  background: var(--white);
  height: var(--header-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  border-bottom: 1px solid var(--border);
  padding: 0 40px;
}

.logo-link {
  display: flex;
  align-items: center;
  gap: 14px;
  text-decoration: none;
  flex-shrink: 0;
}
.header-logo-svg {
  width: 77px;
  height: 40px;
  display: block;
  flex-shrink: 0;
}
.wordmark {
  display: flex;
  flex-direction: column;
  line-height: 1.2;
  gap: 2px;
}
.wordmark-line {
  display: block;
  font-family: var(--mono);
  font-size: 22px;
  font-weight: 400;
  letter-spacing: 0.02em;
  text-transform: lowercase;
  color: var(--wordmark);
  white-space: nowrap;
}
.wordmark-tagline {
  display: block;
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 300;
  letter-spacing: 0.14em;
  text-transform: lowercase;
  color: var(--mid-gray);
  white-space: nowrap;
}
nav {
  margin-left: auto;
  display: flex;
  align-items: center;
}
nav a {
  display: inline-flex;
  align-items: center;
  color: var(--black);
  text-decoration: none;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 0 0 0 20px;   /* right padding removed — LOGIN sits at column right edge */
  height: var(--header-h);
  transition: color 0.18s;
  white-space: nowrap;
}
nav a:hover { color: #555; }
nav button#sm-trigger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: var(--header-h);
  padding: 0 16px;
  background: transparent;
  color: var(--black);
  border: none;
  cursor: pointer;
  flex-shrink: 0;
}


/* ═══════════════════════════════════════════════════════════
   TICKER STRIP — preserved, position sticky below header
═══════════════════════════════════════════════════════════ */
.ticker-strip {
  position: sticky;
  top: var(--header-h);
  z-index: 190;
  height: var(--ticker-h);
  border-bottom: 1px solid var(--border);
  background: var(--white);
  overflow: hidden;
  cursor: default;
  user-select: none;
  width: 100%;
}
.ticker-track {
  display: inline-flex;
  align-items: center;
  height: var(--ticker-h);
  white-space: nowrap;
  will-change: transform;
  transform: translateX(0);
  overflow: hidden;
  padding-left: 40px;
}
.ticker-strip.is-frozen .ticker-track { /* intentionally empty */ }

.ticker-msg {
  font-family: var(--sans);
  font-size: 26px;
  font-weight: 200;
  font-style: italic;
  letter-spacing: 0.01em;
  color: var(--black);
  padding: 0 2px;
}
/* MLB editorial recaps and agent stat commentary — neutral/dark. */
.ticker-msg--stat     { color: var(--black); }
.ticker-msg--agent    { color: var(--black); }

/* Session-11 (2026-08-04b): Nickname: statement split per settled item 51.
   Persona-authored messages are rendered as two inner spans inside
   .ticker-msg — the author name (colored inline from persona.color via
   ticker.js) and the message body (explicitly var(--black)). Colon+space
   between spans is bare text, inheriting .ticker-msg's black.
   No class-based color rule on .ticker-msg-author: the inline style
   attribute set by ticker.js is the source of truth for author color. */
.ticker-msg-body {
  color: var(--black);
}
.ticker-sep {
  display: inline-block;
  width: 1px;
  height: 20px;
  background: var(--light-gray);
  margin: 0 32px;
  vertical-align: middle;
}
/* Invisible interaction zones — preserved for ticker.js */
.ticker-zone {
  position: absolute;
  top: 0;
  height: 100%;
  background: transparent;
  border: none;
  cursor: default;
  padding: 0;
  z-index: 2;
}
.ticker-zone--left   { left: 0;    width: 15%; }
.ticker-zone--center { left: 15%;  width: 70%; cursor: pointer; }
.ticker-zone--right  { right: 0;   width: 15%; }


/* ═══════════════════════════════════════════════════════════
   MAIN — vertical scroll container
═══════════════════════════════════════════════════════════ */
main {
  width: 100%;
  padding: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
}


/* ═══════════════════════════════════════════════════════════
   PAGE COLUMN — centered content container
   All sections live inside this column
═══════════════════════════════════════════════════════════ */
.page-column {
  width: 100%;
  max-width: var(--col-w);
  padding: 0 var(--col-pad);
  display: flex;
  flex-direction: column;
  padding-top: 40px;
  padding-bottom: 60px;
}

/* ui-declutter (2026-09-28): #section-main is the single top-level
   section hosting the unified tab bar. Its margin-top sets the gap
   between the event switcher (NFL 2026 tab bar) and the section
   tab bar. Was three separate sections with 86px inter-gaps in the
   pre-restructure layout.

   min-height: 100vh belt-and-suspenders for the tab-switch shift:
   guarantees the section is always at least viewport-tall so shorter
   panels (PICKS, PERSONAS) don't drop below the overflow threshold
   and cause the scrollbar state to flip between tabs. Combined with
   html { scrollbar-gutter: stable } above, this pins the column
   position across tab switches. */
#section-main {
  margin-top: 24px;
  min-height: 100vh;
  position: relative;
}

/* Watermark — moved from #section-leaderboard (parked with the
   restructure) to the LEADERBOARD tab panel only. Doesn't compete
   with the picks matrix or personas detail on the other tabs.
   Positioned near the top of the panel (was top: 132px behind the
   old per-section header; that header moved out to the shared tab
   bar). Unconditional today because NFL is the only event — when a
   second event ships, move to a per-event selector. */
.tab-panel[data-tab="leaderboard"] {
  position: relative;
  --watermark-url: url("/static/img/watermarks/watermark-football.jpeg");
}
.tab-panel[data-tab="leaderboard"]::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 40px;
  height: 399px;
  background-image: var(--watermark-url, none);
  background-repeat: no-repeat;
  background-position: center center;
  background-size: auto 399px;
  opacity: 0.25;
  pointer-events: none;
  z-index: 0;
}
.tab-panel[data-tab="leaderboard"] > * {
  position: relative;
  z-index: 1;
}

/* Dark-mode watermark treatment. The source JPEG has a non-transparent
   near-white background that stamps a bright rectangle on dark bg
   without this. filter: invert flips the dark football to light; blend
   mode: lighten drops the near-white background so only the (now light)
   football shows against the dark canvas. Ported from Session 18's
   original rule on #section-leaderboard::before — that selector went
   away with the ui-declutter restructure, so the treatment moved with
   the watermark to the leaderboard tab panel. */
[data-theme="dark"] .tab-panel[data-tab="leaderboard"]::before {
  filter: invert(1) brightness(1.5);
  mix-blend-mode: lighten;
}


/* ═══════════════════════════════════════════════════════════
   SECTION — shared wrapper for all content modules
═══════════════════════════════════════════════════════════ */
.page-section {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 0;
}

/* ═══════════════════════════════════════════════════════════
   SECTION HEADER — title left, controls right
   Mirrors OpenRouter section header pattern
═══════════════════════════════════════════════════════════ */
.section-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: var(--section-header-h);
  border-bottom: 1px solid var(--border);
  margin-bottom: 0;
  padding-bottom: 0;
}
.section-header-left {
  display: flex;
  align-items: center;
  gap: 16px;
}
.section-header-right {
  display: flex;
  align-items: center;
  gap: 10px;
}
.section-title {
  font-family: var(--sans);
  font-size: 16px;
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--black);
}

/* ui-declutter (2026-09-28): panel-date-nav-row — thin right-aligned
   strip at the top of each tab panel that hosts a date nav (LEADERBOARD,
   PICKS). PERSONAS omits this strip. Only the active panel's strip is
   visible (inactive panels are display:none via .tab-panel), so no
   cross-panel state coordination needed. */
.panel-date-nav-row {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  padding-top: 12px;
  padding-bottom: 4px;
}


/* ═══════════════════════════════════════════════════════════
   EVENT SWITCHER — tab bar scoping the page to one competition
═══════════════════════════════════════════════════════════ */
.event-switch {
  display: flex;
  align-items: stretch;
  gap: 0;
  margin-bottom: 0;            /* was 36px — tightens gap above the first section */
  border-bottom: 1px solid var(--border);
}
.event-tab {
  font-family: var(--sans);
  font-size: 16px;
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--mid-gray);
  background: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;            /* sit the indicator on the container border */
  padding: 6px 22px 12px;
  cursor: pointer;
  outline: none;
  transition: color 0.15s, border-color 0.15s;
}
.event-tab:hover {
  color: var(--black);
  border-bottom-color: var(--mid-gray);   /* preview underline — same pattern as mode bar hover */
}
/* When any tab is hovered, suppress the active indicator on the non-hovered
   active tab — makes the underline feel like it's previewing a move rather
   than adding a second selection. Graceful degradation: older browsers that
   don't support :has() fall back to both lines showing, nothing breaks. */
.event-switch:has(.event-tab:hover) .event-tab.is-active:not(:hover) {
  border-bottom-color: transparent;
}
.event-tab.is-active {
  color: var(--black);
  border-bottom-color: var(--black);
}
.event-tab:focus-visible {
  outline: 2px solid var(--black);
  outline-offset: -4px;
}

/* Inactive labels — MLB (paused) and CRYPTO/HOLLYWOOD/NFL/NCAAF (planned).
   Rendered as <span> so they're visibly part of the bar but inert: no
   click handler, no hover state, no underline. Single grey tier — visual
   gradient between "paused" and "coming soon" was tried and felt noisy. */
.event-tab--inactive {
  color: var(--mid-gray);
  cursor: default;
  pointer-events: none;
}
.event-tab--inactive:hover {
  color: var(--mid-gray);
  border-bottom-color: transparent;
}
.event-switch:has(.event-tab:hover) .event-tab--inactive {
  border-bottom-color: transparent;
}


/* ═══════════════════════════════════════════════════════════
   CHART MODULE — scatter plot + right name panel
   Rules retained (though currently unused — trajectory parked
   2026-09-28) so un-parking is markup-only, no CSS restoration.
═══════════════════════════════════════════════════════════ */
.chart-module {
  display: flex;
  flex-direction: row;
  gap: var(--chart-gutter);
  width: 100%;
  padding-top: 16px;
  align-items: flex-start;
}

/* Canvas wrapper — fills remaining space after name panel */
.chart-canvas-wrap {
  flex: 1;
  min-width: 0;
  position: relative;
}

/* Canvas — fluid width, viewport-relative height.
   clamp(340px, 42vh, 480px): shrinks gracefully on small screens (15" MacBook Air
   = ~378px at 900px viewport) while preserving the cinematic 480px feel on larger
   displays. chart.js reads clientWidth via ResizeObserver — see dashboard.js note. */
#alphaChart {
  display: block;
  width: 100%;
  height: clamp(420px, 52vh, 600px);
  min-height: 420px;
}

/* Right name panel — matches canvas height exactly so labels stay in bounds. */
.chart-name-panel {
  width: var(--chart-name-panel-w);
  min-width: var(--chart-name-panel-w);
  flex-shrink: 0;
  flex-grow: 0;
  position: relative;
  height: clamp(420px, 52vh, 600px);
  min-height: 420px;
  overflow: hidden;
  box-sizing: border-box;
}

/* Individual name labels — left-anchored, full panel width */
.aln-dot {
  display: inline-block;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  margin-right: 10px;
  flex-shrink: 0;
}

.alpha-name-label {
  position: absolute;
  left: 0;
  right: 0;
  display: flex;
  align-items: baseline;
  gap: 0;
  cursor: default;
  white-space: nowrap;
  width: 100%;
  box-sizing: border-box;
  padding-left: 16px;
}

/* Color dot in each name label — 7px circle at the LEFT of the row.
   With .alpha-name-label's padding-left:16px and this dot's 7px width,
   the dot spans 16-23px with center at 19.5px — matches .alpha-tie-line's
   left:19px so tie connectors visually align beneath adjacent dots.
   align-self:center overrides the parent's align-items:baseline for the
   dot alone, so the dot vertically centers on the row instead of sitting
   at text baseline. */
.alpha-name-dot {
  display: inline-block;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  flex-shrink: 0;
  margin-right: 6px;
  align-self: center;
}

/* Post-Session-9: position column inside each name label. Sits after
   the color dot, before the nickname. Sizing mirrors LEADERBOARD's
   .lb-td-pos rule so tab-switch between panels reads as visually
   coherent (POS column same width and typography across widgets). */
.alpha-name-role {
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.06em;
  color: var(--black);
  min-width: 56px;
  text-transform: uppercase;
  flex-shrink: 0;
  padding-right: 8px;
}
/* Nickname column. Mirrors LEADERBOARD's .lb-td-player: 16px sans. */
.alpha-name-text {
  font-family: var(--sans);
  font-size: 16px;
  font-weight: 400;
  color: var(--black);
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Value cell hidden — user opted out; positions are self-explanatory
   so the numerical alpha/parity ratio adds visual clutter without
   information the chart doesn't already convey. JS templates still
   render the span (kept for potential future toggle); CSS suppresses. */
.alpha-name-value {
  display: none;
}
.aln-abbr {
  font-family: var(--sans);
  font-size: 16px;
  font-weight: 400;
  letter-spacing: 0;
  width: 100px;       /* wider budget for longer baseball names; ellipsis clips if needed */
  flex-shrink: 0;
  text-align: left;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-right: 0;    /* no ac column follows — no trailing gap needed */
}
.aln-stats {
  display: none;      /* ac column removed — panel width recovered for canvas */
}
.aln-wl {
  font-family: var(--sans);
  font-size: 10px;
  font-weight: 400;
  color: var(--black);
  letter-spacing: 0.02em;
  width: 32px;
  flex-shrink: 0;
  text-align: right;
}
.aln-sep {
  font-size: 9px;
  color: var(--light-gray);
  padding: 0 8px;
  flex-shrink: 0;
}
.aln-ac {
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 400;
  color: var(--black);
  letter-spacing: 0.02em;
  width: 32px;
  flex-shrink: 0;
  text-align: left;
}

/* Hash marks — drawn on canvas, no CSS needed */

/* Chart legend — centered below chart */
.chart-legend-wrap {
  display: flex;
  justify-content: center;
  align-items: center;
  /* Reserve the legend's rendered height (measured 43px, border-box incl.
     padding) so the slot is held from first paint. #alphaLegend is empty in
     the HTML and filled by chart.js a frame later; without this the wrap grows
     ~27px on fill and shoves the leaderboard down — the boot layout shift. */
  min-height: 43px;
  padding: 12px 0 4px;
  /* offset right by half the name panel + gutter so legend centers on canvas */
  padding-right: calc(var(--chart-name-panel-w) + var(--chart-gutter));
}
.chart-legend-row {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 0.06em;
  color: var(--black);
  line-height: 1.4;
}
.chart-legend-row--center { justify-content: center; }

/* Single containing box */
.chart-legend-box {
  display: inline-flex;
  align-items: stretch;
  border-bottom: 1px solid var(--border);
  overflow: hidden;
}

.chart-legend-sym {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 0.06em;
  color: var(--black);
  cursor: pointer;
  padding: 5px 14px;
  background: transparent;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  transition: opacity 0.2s ease, border-color 0.15s;
  white-space: nowrap;
  user-select: none;
}
.chart-legend-sym:last-child { /* no divider */ }
.chart-legend-sym:hover      { opacity: 1; }
.chart-legend-sym--active    { border-bottom-color: var(--black); color: var(--black); opacity: 1; }


/* ═══════════════════════════════════════════════════════════
   LEADERBOARD — full-width spanning header table
   RNK · PLAYER · OVERALL(4) · FAVORITE(4) · EVEN(4) · UNDERDOG(4) · TOTAL(4)
═══════════════════════════════════════════════════════════ */

.lb-table-wrap {
  width: 100%;
  overflow-x: auto;
  padding-top: 8px;
  min-height: 200px;  /* prevents layout jump if rows repopulate after a brief empty state */
}

.lb-table {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--sans);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  table-layout: fixed;
}

/* ── Column widths via <colgroup> (table-layout: fixed) ─────────
   ui-declutter 2026-09-28 regrouped bucket-first → metric-first,
   so the 12 data columns are now 4-wide × 3 metric groups (PICKS,
   WIN PCT, ALPHA) with 2 gap columns between groups. All 12 data
   cols normalized to same width so the three metric blocks are
   visually identical rectangles; gap widened so the metric groups
   read as clearly-separated clusters rather than one long strip.
     RNK 32 + POS 56 + PLAYER 138 + (46 × 12) + (76 × 2)
     = 226 + 552 + 152 = 930 (10px slack in 940 usable width).
   Data cols sized to sit safely inside the container — sum must
   stay below 940 to keep .lb-table-wrap's overflow-x: auto from
   showing a horizontal scrollbar at the bottom of the panel.
   Personas panel overrides .lb-col-rnk/pos/player widths (see
   .personas-lb-table rules further down) so those stay pinned to
   their leaderboard rendered widths on tab-switch.
   <col> widths win over any th width in the fixed-layout algorithm. */
.lb-col-rnk    { width: 32px; }
.lb-col-pos    { width: 56px; }
.lb-col-player { width: 142px; }
.lb-col-picks  { width: 46px; }
.lb-col-wpct   { width: 46px; }
.lb-col-alp    { width: 46px; }
.lb-col-gap    { width: 74px; }

.lb-th-rnk    { width: 32px; }
.lb-th-pos    { width: 56px; text-align: left; }
.lb-th-player { text-align: left; }
.lb-table th.lb-th-pos    { text-align: left; padding-left: 2px; }
.lb-table th.lb-th-player { text-align: left; padding-left: 2px; }

/* group header spanning cells */
.lb-th-group {
  text-align: center;
}

/* Groups are separated by the spacer columns (.lb-col-gap) rather than vertical
   dividers. Gap cells stay empty; the header gap carries the underline so the
   line beneath the column titles runs unbroken across the table. */
.lb-th-gap { border-bottom: 1px solid var(--border); padding: 0; }
.lb-gap    { padding: 0; }

/* Shared base hook for every leaderboard header cell. Concrete typography
   is supplied by the .lb-thead-group / .lb-thead-sub descendant rules below;
   this anchor documents the class and reserves it for future shared header
   properties without changing current specificity. */
.lb-th { box-sizing: border-box; }

/* ── Header typography ─────────────────────────────── */
.lb-thead-group th,
.lb-thead-sub th {
  font-family: var(--sans);
  font-size: 9px;
  font-weight: 400;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--mid-gray);
  padding: 8px 4px 4px;
  white-space: nowrap;
  text-align: right;
}

.lb-thead-group .lb-th-group {
  text-align: center;
  color: var(--black);
  font-family: var(--sans);
  font-weight: 400;
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding-bottom: 6px;
  border-bottom: 1px solid #e8e8e8;
}
.lb-thead-group .lb-th-rnk,
.lb-thead-group .lb-th-pos,
.lb-thead-group .lb-th-player,
.lb-thead-group .lb-th-g-col {
  border-bottom: 1px solid #e8e8e8;   /* line now runs full table width */
  vertical-align: bottom;
  padding-bottom: 6px;                /* match group cells so the line is straight */
  color: var(--black);
}

.lb-table th.lb-th-g-col {
  color: var(--black);
}

.lb-thead-sub th {
  color: var(--black);
  padding-top: 4px;
  padding-bottom: 7px;
  border-bottom: 1px solid var(--border);
}

/* ── Data rows ─────────────────────────────────────── */
.lb-table tbody tr {
  border-bottom: 1px solid #e2e2e2;   /* matches schedule's between-game line */
  transition: background-color 0.2s ease, transform 0.2s ease;
}
.lb-table tbody tr:hover {
  background-color: var(--off-white);
}

.lb-table td {
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 400;
  color: var(--black);
  text-align: right;
  padding: 9px 4px;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  vertical-align: baseline;
}

.lb-table td.lb-td-rnk {
  font-family: var(--sans);
  font-size: 10px;
  color: var(--mid-gray);
  text-align: left;
  padding-left: 0;
}
.lb-table td.lb-td-pos {
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.06em;
  /* ui-declutter follow-up (2026-09-29): POS values recede to --mid-gray
     so they match the AI-name treatment. Only AI rows carry a role_abbr
     (human rows leave the cell blank), so this change touches personas
     rows only in the leaderboard and every row in the personas panel. */
  color: var(--mid-gray);
  text-align: left;
  padding-left: 2px;
}
.lb-table td.lb-td-player {
  font-family: var(--sans);
  font-size: 16px;
  font-weight: 400;
  text-align: left;
  color: var(--black);
  padding-left: 2px;
}
.lb-table td.lb-td-dim {
  color: var(--black);
  font-size: 12px;
  text-align: right !important;
  padding-right: 12px !important;
}

/* AI tag — hidden by default, togglable */
.ac-ai-tag {
  font-family: var(--sans);
  font-size: 8px;
  font-weight: 400;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--mid-gray);
  border: 1px solid #e8e8e8;
  border-radius: 2px;
  padding: 1px 4px;
  margin-left: 5px;
  vertical-align: middle;
  position: relative;
  top: -1px;
  display: none;  /* hidden by default — reveal via .show-ai-tags on body */
}
body.show-ai-tags .ac-ai-tag { display: inline; }

/* Undefined / em-dash value */
.val-undef {
  font-size: 12px;
  font-weight: 300;
  color: #ccc;
}


/* ═══════════════════════════════════════════════════════════
   MLB PICKS — two-column game list
═══════════════════════════════════════════════════════════ */

/* Date navigation in section header */
.section-date-nav {
  display: flex;
  align-items: center;
  gap: 4px;
}
.section-date-label {
  font-family: var(--sans);
  font-size: 10px;
  font-weight: 400;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--black);
  width: 80px;
  text-align: center;
}
.date-caret {
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 400;
  color: var(--black);
  background: none;
  border: none;
  cursor: pointer;
  padding: 4px 6px;
  border-radius: 4px;
  line-height: 1;
  transition: opacity 0.2s ease, transform 0.2s ease, background-color 0.2s ease;
  letter-spacing: 0;
}
.date-caret:hover             { opacity: 1; background-color: var(--off-white); transform: scale(1.1); }
.date-caret--dead             { opacity: 0.2; cursor: default; transform: none; background-color: transparent; }
.date-caret--dead:hover       { opacity: 0.2; background-color: transparent; transform: none; }

/* Ghost caret — invisible but holds the same layout space as a real caret.
   Used in TRAJECTORY's date nav so its TO-DATE label aligns horizontally
   with FIELD's. Future C2 work will activate the right slot as a play
   button by swapping this class for an active caret class. */
.date-caret--ghost {
  visibility: hidden;
  pointer-events: none;
}
.date-caret--ghost:hover { background-color: transparent; transform: none; }




/* ═══════════════════════════════════════════════════════════
   GAME ENTRY ROWS — preserved from original, adapted
   Original buildGameEntry() output is unchanged
═══════════════════════════════════════════════════════════ */
.game-list {
  list-style: none;
  display: flex;
  flex-direction: column;
}

/* Empty-state row when a date has no scheduled games.
   Replaces the former inline cssText in schedule.js renderColumn(). */
.game-list-empty {
  padding: 20px 0;
  color: #ccc;
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.game-entry {
  display: flex;
  flex-direction: column;
  /* Both columns share identical geometry. Left padding 0 so the row
     starts flush at the column's left edge; the abbrev's -4px margin
     cancels its own box padding so the glyph itself is flush while the
     selection rectangle keeps its breathing room. Right 4px so the value
     block reaches the column's right edge. */
  padding: 8px 4px 8px 0;
  border-bottom: 1px solid #f0f0f0;
  gap: 2px;
}
.game-entry:last-child { border-bottom: none; }

.ac-player-name {
  font-family: var(--font-id);
  font-size: 15px;
  font-weight: 500;
  color: var(--black);
  letter-spacing: 0;
}
.ac-rank-tag {
  font-family: var(--sans);
  font-size: 10px;
  font-weight: 400;
  letter-spacing: 0.10em;
  color: var(--mid-gray);
  text-align: left;
  align-self: center;
}
.ac-cat-label,
.ac-totals-label {
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--black);
}
.ac-wl-val,
.ac-pct-val,
.ac-alpha-val {
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 400;
  line-height: 1.2;
  color: var(--black);
  text-align: right;
}
.ac-parity-val {
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 400;
  line-height: 1.2;
  color: var(--black);
  text-align: right;
  justify-self: end;
  width: fit-content;
  padding-left: 5px;
  padding-right: 6px;
  border-radius: 3px;
}


/* ═══════════════════════════════════════════════════════════
   FOOTER — preserved exactly
═══════════════════════════════════════════════════════════ */
.site-footer {
  background: var(--white);
  color: var(--black);
  width: 100%;
  margin-top: 0;
  border-top: 1px solid var(--border);
  height: var(--footer-h);
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.footer-bar {
  display: flex;
  align-items: center;
  padding: 0 40px;
  height: var(--footer-bar-h);
  flex-shrink: 0;
  position: relative;
}
/* Centered variant — copyright only, no event nav. Overrides the
   default left-anchor layout by centering the sole flex child. Same
   vertical rhythm (same padding, same height). */
.footer-bar--centered {
  justify-content: center;
}
.footer-copyright {
  font-family: var(--mono);
  /* Size + color mirror .g-venue-city / .g-status-val (12px, --black) so the
     footer reads as a peer of the venue/status stack instead of a lighter
     subordinate label. Lowercase + mono + wider letter-spacing preserved as
     the footer's distinguishing typographic mark. */
  font-size: 12px;
  font-weight: 300;
  letter-spacing: 0.14em;
  color: var(--black);
  text-transform: lowercase;
  white-space: nowrap;
}
/* Middle-dot separator between "alpha" and "capture". The parent's 0.14em
   letter-spacing plus normal word-spacing puts too much air around the dot;
   negative horizontal margin pulls the adjacent words back in without
   affecting the rest of the line. Tune this value if the dot still reads
   too airy or gets cramped. */
.footer-dot {
  margin: 0 -0.15em;
}


/* ═══════════════════════════════════════════════════════════
   RESPONSIVE
   820px: single-column picks and lb on narrow viewports.
   Below 820px: legacy mobile styling — mobile UA redirect is parked
   (ui-declutter 2026-09-28) so narrow-viewport desktops now hit this
   path directly rather than being punted to /m.
═══════════════════════════════════════════════════════════ */

/* Tablet landscape and desktop (820px+) — full layout */
@media (min-width: 820px) {
  .chart-module {
    flex-direction: row;
  }
}

/* Below 820px — single column picks and lb */
@media (max-width: 819px) {
  :root {
    --col-pad: var(--col-pad-mobile);
  }

  /* Picks — now a single unified table, no column override needed */

  /* Footer */
  .footer-bar {
    flex-direction: column;
    align-items: flex-start;
    gap: 20px;
    height: auto;
    padding: 16px var(--col-pad-mobile);
  }
  /* Centered variant keeps centering on mobile too. */
  .footer-bar--centered {
    align-items: center;
  }

  /* Header — tighten */
  header { padding: 0 var(--col-pad-mobile); }
}




/* ── Trajectory chart — retained (parked with the trajectory panel
   2026-09-28) so un-parking is markup-only. Currently no #trajectoryChart
   in the DOM. ───────────────────── */
#trajectoryChart {
  display: block;
  width: 100%;
  height: clamp(420px, 52vh, 600px);
  min-height: 420px;
}



/* ══════════════════════════════════════════════════════════════════
   Section-tabs — intra-section tab bars. ui-declutter (2026-09-28):
   now hosts the unified top-nav (LEADERBOARD / PERSONAS / PICKS) in
   #section-main. Rules mirror the .event-switch / .event-tab block
   above — deliberate duplication with distinct class names for the
   intentional visual parity with the top-of-page event switcher.
   ══════════════════════════════════════════════════════════════════ */

.section-tabs {
  display: flex;
  align-items: stretch;
  gap: 0;
  margin-bottom: 0;
  border-bottom: none;
}
.section-tab {
  font-family: var(--sans);
  font-size: 16px;
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--mid-gray);
  background: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  padding: 6px 22px 12px 0;
  padding-right: 22px;
  cursor: pointer;
  outline: none;
  transition: color 0.15s, border-color 0.15s;
}
.section-tab:hover {
  color: var(--black);
  border-bottom-color: var(--mid-gray);
}
.section-tabs:has(.section-tab:hover) .section-tab.is-active:not(:hover) {
  border-bottom-color: transparent;
}
.section-tab.is-active {
  color: var(--black);
  border-bottom-color: var(--black);
}
.section-tab:focus-visible {
  outline: 2px solid var(--black);
  outline-offset: -4px;
}

/* Tab panel visibility — .tab-panel is hidden by default; .is-active reveals.
   Sections that use section-tabs have exactly one panel active at a time. */
.tab-panel {
  display: none;
}
.tab-panel.is-active {
  display: block;
}

.tab-panel-placeholder {
  padding: 48px 24px;
  color: var(--mid-gray);
  font-family: var(--sans);
  font-size: 14px;
  font-style: italic;
  text-align: center;
}


/* ══════════════════════════════════════════════════════════════════
   PERSONAS panel — two-row thead mirror + body-hosted identity
   ══════════════════════════════════════════════════════════════════
   The whole panel is one .lb-table with a 4-col colgroup: RNK / POS /
   NAME (widths + typography inherited from .lb-col-* / .lb-td-*, so
   they cannot drift from LEADERBOARD) + a wide detail column.

   Thead is two rows mirroring the LEADERBOARD structure so the thead
   height and POS/NAME typography come from the shared .lb-thead-*
   rules by construction. Col 4 header cells are empty — the persona
   nickname + role now live in the body detail cell, above the
   description.

   Detail body: rowspan cell on the first tbody row containing the
   identity block (nickname + role) followed by description + lens.
   Content flows normally (no absolute positioning, no fixed height,
   no scroll bar) so the persona detail extends as tall as it needs.
   The AI rows in cols 1-3 stretch to match the cell height. Row-by-
   row Y parity with LEADERBOARD's tbody is NOT preserved on tab-
   switch; column widths and thead height still are.

   Selected persona is marked from the AI-list side by a thin
   persona-color bar on the active row's rank cell — set inline by
   personas.js on _renderList.
   ══════════════════════════════════════════════════════════════════ */

.personas-lb-table {
  /* Now sits in a flex frame beside .personas-detail-column; width
     is set on the .personas-frame rule above. Kept here for future
     shared-rule additions. */
}

/* Personas tab has no date nav (detail is not date-scoped), but the
   leaderboard tab starts with a .panel-date-nav-row that pushes its
   first three columns down by ~36px. This selector renders the same
   row structure on the personas panel invisibly, so RNK/POS/NAME
   text sits at identical Y on tab-switch. visibility:hidden (not
   display:none) preserves layout height. */
.personas-date-nav-spacer {
  visibility: hidden;
}

/* Col widths pinned to leaderboard's RENDERED widths so RNK/POS/NAME
   sit at identical X-positions on tab-switch. Not equal to the
   leaderboard's SPECIFIED widths — those are stretched by the browser.
   Math: leaderboard .lb-table has width:100% (fills 940px container),
   but its 15 specified cols sum to 930. table-layout:fixed distributes
   the 10px slack proportionally across cols, inflating each by
   940/930 ≈ 1.01075. So leaderboard's rendered widths are 32.34,
   56.60, 143.53 — not 32, 56, 142. Personas table is width:auto
   (natural width, so .personas-detail-column can flex beside it),
   so its cols render at specified px verbatim. Values below bake the
   1.01075 factor in so both tabs align pixel-for-pixel.
   If any leaderboard col width or the 940 container width changes,
   recompute: personas_col = leaderboard_col × 940 / (sum of lb cols).
   Col 4 (thead spacer) is 0 wide — it exists only so the thead can
   carry &nbsp; cells in both rows to reach the leaderboard's total
   thead height, and it contributes no visible column to tbody. */
.personas-lb-table .lb-col-rnk    { width: 32.34px; }
.personas-lb-table .lb-col-pos    { width: 56.60px; }
.personas-lb-table .lb-col-player { width: 143.53px; }
.personas-col-thead-spacer        { width: 0; }

/* Flex frame: the wrap now hosts two children side by side — the
   AI-list table (natural width from colgroup) and the detail column
   (flex: 1). Panel height = max(table height, detail height); each
   grows independently, so the detail can extend as tall as its lens
   content requires without stretching tbody rows. This is what
   guarantees row 1's rnk/pos/nickname text stays at leaderboard
   baseline Y on tab-switch. */
.personas-frame {
  display: flex;
  align-items: flex-start;
}

.personas-lb-table {
  /* Natural width from colgroup — no longer needs to fill the row. */
  width: auto;
  flex: 0 0 auto;
}

/* ui-declutter follow-up (2026-09-29): AI persona names render in
   --mid-gray to match the AI-name treatment on the leaderboard and
   picks panels. Every row in this table is a persona (all AI), so
   the rule applies unconditionally without a per-row is-ai class.
   Selector specificity (0,2,2) beats the base .lb-table td.lb-td-player
   rule (0,2,1) — no !important needed. */
.personas-lb-table tbody td.lb-td-player {
  color: var(--mid-gray);
}

/* Detail column — takes remaining horizontal space. Padding-top 56px
   aligns its content top with tbody row 1 top (thead height = 56 in
   both leaderboard and personas, so 56 of padding matches). Left/right
   padding at 48 matches the previous cell padding.
   position:relative anchors .personas-spark, which is absolute-positioned
   INSIDE the padding area so the name/description below stay at their
   original Y. */
.personas-detail-column {
  flex: 1;
  min-width: 0;
  padding: 56px 48px 12px 48px;
  text-align: left;
  position: relative;
}

/* ── Header rows ─────────────────────────────────────────────────
   Two rows mirroring the LEADERBOARD thead structure exactly:
   RNK/POS/NAME are rowspan=2 (same as leaderboard), col 4 row 1 uses
   .lb-th-group (same font 11 + padding + border as FAVORITE cells),
   col 4 row 2 inherits .lb-thead-sub th (same font 9 + padding as
   PICKS cells). Total thead height comes from the shared rules — no
   forced heights. &nbsp; content forces line-boxes to render; the
   text is hidden via color: transparent. */

.personas-th-empty {
  color: transparent;
}

/* Middle-of-header hairline removal. The .lb-th-group class on the
   col-4 row-1 empty cell gives it border-bottom: 1px solid #e8e8e8
   (the divider under FAVORITE etc. in leaderboard). Personas doesn't
   show a group label there, so the line appears as a stray cut across
   the header. Keep the 1px border but make it transparent — that
   preserves the row height contribution (thead stays 56px, matching
   leaderboard exactly) while hiding the line. Dropping the border
   entirely made the thead 1px shorter and shifted every tbody row up
   by 1px on tab-switch. */
.lb-thead-group .personas-th-empty {
  border-bottom: 1px solid transparent !important;
}

/* ── Selected-row accent ──────────────────────────────────────────
   ui-declutter follow-up (2026-09-29): persona colors are no longer
   used elsewhere in the app (leaderboard and picks now use --mid-gray
   for AI, no per-persona identity color anywhere), so the color bar
   here has nothing to tie back to and just looks decorative. Dropped
   in personas.js at the same time — no inline box-shadow is written
   anymore, so no !important is needed here.
   Selection is now signaled by:
     • active row's NAME cell in --black (vs --mid-gray for inactive AI names)
     • active row's RNK cell in --black (already in place below)
     • right-side detail panel fully swapping to the selected persona */
.personas-lb-row.is-active td.lb-td-player {
  color: var(--black);
}

/* ── Body row interactions ──────────────────────────────────────── */

.personas-lb-row {
  cursor: pointer;
}

/* Hover and active states apply to the AI-list cells only, NOT to
   the whole row — that way the personas detail cell on the right
   never picks up a background tint on hover or selection. Override
   the .lb-table tbody tr:hover base rule which would otherwise
   color the whole row. */
.personas-lb-table tbody tr:hover {
  background-color: transparent;
}
.personas-lb-table tbody tr:hover td.lb-td-rnk,
.personas-lb-table tbody tr:hover td.lb-td-pos,
.personas-lb-table tbody tr:hover td.lb-td-player {
  background-color: var(--off-white);
}
/* ui-declutter 2026-09-28: dropped the background-color shade on
   .personas-lb-row.is-active — the persona-color indicator bar on
   the NAME cell's right edge is already a specific, unambiguous
   "this is selected" signal, and the right-side detail panel
   confirms selection with a full content swap. The shade was noise
   that duplicated the same info and overlapped with the hover
   state's shade (blurring "hovered" vs "selected"). Hover shade
   above is unchanged.
   Rank color is still forced to --black on the active row so it
   doesn't fade against the (now unshaded) background. */
.personas-lb-row.is-active td.lb-td-rnk {
  color: var(--black);
}
.personas-lb-row:focus-visible {
  outline: 2px solid var(--black);
  outline-offset: -2px;
}

/* ── Detail column body cell ────────────────────────────────────── */

/* Rowspan cell containing description+lens. Vertical-align: top so
   content starts at the top of the spanned tbody area. Content flows
   normally (no absolute positioning) so the cell grows with lens
   length — the AI rows in cols 1-3 stretch to match. Consequence:
   personas tbody row heights don't match LEADERBOARD tbody row
   heights; this is by design (lens readability > row-by-row Y parity
   on tab-switch). Column widths and thead height still match.
   white-space: normal overrides .lb-table td { white-space: nowrap }
   which was preventing the identity, description, and lens from
   wrapping. */
/* (retired) personas-td-detail rules: the detail content used to live
   in a rowspan tbody cell. It now lives in .personas-detail-column as
   a sibling div, so cell-scoped rules are no longer needed. */

/* In-body identity block — the nickname + role_label that used to
   live in the thead. No color accent on the border (color affordance
   is now on the selected row's rank cell instead). */
.personas-detail-header {
  margin-bottom: 20px;
}
.personas-detail-name {
  font-family: var(--sans);
  font-size: 20px;
  font-weight: 500;
  letter-spacing: 0.01em;
  color: var(--black);
  line-height: 1.15;
  text-align: left !important;
  white-space: normal;
  word-wrap: break-word;
  overflow-wrap: break-word;
}
.personas-detail-role {
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--mid-gray);
  margin-top: 4px;
  text-align: left !important;
  white-space: normal;
  word-wrap: break-word;
  overflow-wrap: break-word;
}

.personas-detail-description {
  font-family: var(--sans);
  font-size: 15px;
  margin: 0 0 24px 0;
  color: var(--wordmark);
  line-height: 1.55;
  text-align: left !important;
  white-space: normal;
  word-wrap: break-word;
  overflow-wrap: break-word;
}

/* Per-persona alpha-over-season sparkline (2026-09-29). Absolutely
   positioned INSIDE .personas-detail-column's padding-top:56px area so
   the name/description below don't shift. Occupies the horizontal
   space between the column's left/right padding edges (48px each).
   Height 48px leaves 8px of breathing room to the persona name below.
   Skipped by personas.js for meta personas (no series) or when
   /chart-data/history failed to load. */
.personas-spark {
  position: absolute;
  top: 0;
  left: 48px;
  right: 48px;
  height: 48px;
}
.personas-spark-canvas {
  display: block;
  width: 100%;
  height: 48px;
}

/* Endpoint value — leaderboard's ALPHA-AVG treatment, same rule shape
   as .lb-td-alp (15px teal, tabular-nums). transform: translateY(-50%)
   vertically centers the span on the endpoint-y set inline. Cannot use
   .lb-td-alp directly because that rule is scoped to .lb-table td. */
.personas-spark-value {
  position: absolute;
  font-family: var(--sans);
  font-size: 15px;
  font-weight: 400;
  color: #0e7490;
  font-variant-numeric: tabular-nums;
  transform: translateY(-50%);
  white-space: nowrap;
  pointer-events: none;
}

/* End date — sits directly below the endpoint value at the same left
   edge (left-aligned to the value, per 2026-09-29 direction). Position
   is set inline by personas.js after canvas dimensions are known.
   Quiet gray, 10px — same size as the trajectory chart's x-labels. */
.personas-spark-date {
  position: absolute;
  font-family: var(--sans);
  font-size: 10px;
  font-weight: 400;
  color: var(--mid-gray);
  pointer-events: none;
  white-space: nowrap;
}

/* Lens markdown output — h4 / p / ol. */

.personas-detail-lens {
  font-family: var(--sans);
  font-size: 14px;
  color: var(--black);
  line-height: 1.55;
  text-align: left !important;
  white-space: normal;
  word-wrap: break-word;
  overflow-wrap: break-word;
}
.personas-detail-lens h4 {
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--mid-gray);
  margin: 20px 0 8px 0;
  padding-bottom: 4px;
  border-bottom: 1px solid var(--border);
}
.personas-detail-lens h4:first-child {
  margin-top: 0;
}
.personas-detail-lens p {
  margin: 8px 0;
  color: var(--black);
}
.personas-detail-lens ol {
  padding-left: 22px;
  margin: 8px 0;
}
.personas-detail-lens ol li {
  margin: 4px 0;
  color: var(--black);
}

.personas-detail-empty {
  font-family: var(--sans);
  font-size: 13px;
  font-style: italic;
  color: var(--mid-gray);
  padding: 24px 0;
}

.personas-lb-empty {
  padding: 24px 12px !important;
  font-family: var(--sans);
  font-size: 13px !important;
  font-style: italic;
  color: var(--mid-gray) !important;
  text-align: left !important;
}

/* ── Mobile / narrow-viewport fallback ─────────────────────────── */
/* Cell padding shrinks below 820px so the identity block and lens
   content aren't crammed against the narrow left column. */
@media (max-width: 820px) {
  .personas-td-detail {
    padding: 12px !important;
  }
}


/* ═══════════════════════════════════════════════════════════
   CUSTOM CURSOR — dot + hover-ring pattern (calethompson.com-inspired)

   Wrapped in @media (hover: hover) and (pointer: fine) so touch
   devices AND touchscreen laptops keep their native cursor. cursor.js
   also bails on (hover: none); this CSS gate is the belt+suspenders.

   Default state:  8px dot follows the pointer directly.
   Hover state:    dot shrinks (scale 0.5), 24px ring scales in.

   Interactive elements are wired via JS class toggling on `.cursor-hover`
   on the cursor element itself (not the body — cleaner scoping).
═══════════════════════════════════════════════════════════ */
@media (hover: hover) and (pointer: fine) {
  /* Hide the native cursor everywhere. Input fields keep the text
     I-beam because typing without one is disorienting. */
  * { cursor: none !important; }
  input, textarea, [contenteditable="true"] { cursor: text !important; }

  .custom-cursor {
    position: fixed;
    top: 0; left: 0;
    width: 0; height: 0;
    pointer-events: none;
    z-index: 9999;
    /* Transition on opacity for the leave/enter window handlers. */
    transition: opacity 0.15s ease;
  }

  .custom-cursor::before {
    content: "";
    position: absolute;
    top: 0; left: 0;
    width: 8px; height: 8px;
    border-radius: 50%;
    background: var(--black);
    transform: translate(-50%, -50%) scale(1);
  }

  .custom-cursor::after {
    content: "";
    position: absolute;
    top: 0; left: 0;
    width: 24px; height: 24px;
    border-radius: 50%;
    border: 1px solid var(--black);
    background: transparent;
    transform: translate(-50%, -50%) scale(0);
    opacity: 0;
  }

  /* Hover state: dot shrinks, ring expands + fades in. */
  .custom-cursor.cursor-hover::before {
    transform: translate(-50%, -50%) scale(0.5);
  }
  .custom-cursor.cursor-hover::after {
    transform: translate(-50%, -50%) scale(1);
    opacity: 1;
  }

  /* Transitions gated on prefers-reduced-motion — accessibility
     hygiene. Without this the scale + opacity changes are instant
     for users who've opted out of motion. */
  @media (prefers-reduced-motion: no-preference) {
    .custom-cursor::before {
      transition: transform 0.15s ease;
    }
    .custom-cursor::after {
      transition: transform 0.15s ease, opacity 0.15s ease;
    }
  }
}


/* ═══════════════════════════════════════════════════════════
   Header Sign-In/Sign-Up button — slash spacing.
   Uses margin on a wrapping <span class="btn-slash"> so we can
   tune the gap without editing text in template + JS. 0.15em ≈
   half a space width in Inter/JBM at header sizing. Adjust here.
   Selector is `nav .btn-slash` (not `nav a .btn-slash`) because
   auth_modal.js replaces the header <a> with a <button> at boot,
   so the `a` in the selector would never match after page load.
   Same selector also covers mobile's <nav class="m-nav"> button
   so the slash spacing matches across desktop and mobile.
═══════════════════════════════════════════════════════════ */
nav .btn-slash {
  margin: 0 0.15em;
}

/* .lb-td-alp — the row's primary scoreboard number: 15px teal.
   Applied to ALPHA-AVG only (the fourth cell of the ALPHA metric
   group). All other data cells stay at the base .lb-table td
   styling (12px dark). Original scope was every ALPHA cell
   (Session 24); narrowed to ALPHA-AVG only in the ui-declutter
   restructure so the eye lands on one anchor number per row.
   Dark-mode override lives in dark_theme.css. */
.lb-table td.lb-td-alp {
  font-size: 15px;
  color: #0e7490;
}
