/* sports/assets/sports.css -- shared by the multi-sport landing page and
   sport apps. Tokens copied from model_dashboard_v2.html (copied, not
   shared, so editing either side can never restyle the other). */
:root{
  --bg:#0A0C10; --panel:#12151C; --panel-raised:#191D27; --line:#262B37; --line-soft:#1C2029;
  --text:#F2F0E9; --text-dim:#9BA1AF; --text-faint:#606676;
  --gold:#D9A72E; --gold-bright:#EAC061; --gold-dim:#96792E; --gold-wash:rgba(217,167,46,0.12);
  --blue:#2EA8FF; --blue-wash:rgba(46,168,255,0.12);
  --green:#4FAE7E; --green-wash:rgba(79,174,126,0.14); --red:#DA6F62; --red-wash:rgba(218,111,98,0.14);
  --purple:#9A87C4;
  --radius-sm:5px; --radius-md:8px; --radius-lg:12px;
  --shadow-card:0 4px 16px rgba(0,0,0,0.35), 0 1px 2px rgba(0,0,0,0.3);
  --shadow-pop:0 16px 40px rgba(0,0,0,0.5);
  --wash-04:rgba(255,255,255,.04);
  --zebra-wash:rgba(255,255,255,.025);
}
/* Light theme re-balanced (2026-10-06, per Tony: "the current Light
   theme is significantly too bright" -- he ran this past Gemini and
   picked its "Elevated Slate Architecture" option). Same diagnosis
   either way: --bg and --panel-raised used to sit almost on top of each
   other (#F2F5F8 vs #EDF2F6, barely distinguishable), so white panels
   never read as elevated above the canvas -- just more white next to
   slightly-less-white. Re-ordered so panel-raised (sunken fills: inputs,
   detail-expand rows) sits BETWEEN the muted canvas and the bright white
   card surfaces, not darker than the canvas it's supposed to sit on top
   of. --line darkened for real border definition (Gemini's "unanchored
   data grids" point); gold/green/red/blue accents untouched -- the
   brightness complaint was about canvas/panel contrast, not the
   existing brand accent, which Tony didn't ask to change. */
:root[data-theme="light"]{
  --bg:#E7ECF1; --panel:#FFFFFF; --panel-raised:#F1F5F9; --line:#CBD5E1; --line-soft:#E2E8F0;
  --text:#172033; --text-dim:#65748A; --text-faint:#7C8CA0;
  --gold:#8F6A1E; --gold-bright:#70500F; --gold-dim:#C9A24A; --gold-wash:rgba(217,167,46,0.10);
  --blue:#0A6CB8; --blue-wash:rgba(10,108,184,0.10);
  --green:#358058; --green-wash:rgba(53,128,88,0.12); --red:#B8412F; --red-wash:rgba(184,65,47,0.12);
  --purple:#6E5AA8;
  --shadow-card:0 4px 16px rgba(20,20,30,0.10), 0 1px 2px rgba(20,20,30,0.06);
  --shadow-pop:0 16px 40px rgba(20,20,30,0.16);
  --wash-04:rgba(20,20,30,.05);
  --zebra-wash:rgba(15,23,42,.035);
}
*{ box-sizing:border-box; }
html,body{ margin:0; }
body{ background:var(--bg); color:var(--text); font-family:'Space Grotesk',sans-serif; font-size:14px; }
/* CONFIRMED REAL GAP: no scrollbar theming existed anywhere, so every
   scrollable area (the Player Pool table, .pool-scroll, the page itself)
   used the browser's stock light-grey scrollbar -- jarring against an
   all-dark panel. Firefox uses scrollbar-color/-width; everything else
   (Chrome/Edge/Safari) uses the ::-webkit-scrollbar pseudo-elements. */
*{ scrollbar-width:thin; scrollbar-color:var(--line) transparent; }
::-webkit-scrollbar{ width:9px; height:9px; }
::-webkit-scrollbar-track{ background:transparent; }
::-webkit-scrollbar-thumb{ background:var(--line); border-radius:5px; border:2px solid var(--bg); background-clip:padding-box; }
::-webkit-scrollbar-thumb:hover{ background:var(--text-faint); }
.mono{ font-family:'IBM Plex Mono',monospace; }
a{ color:var(--blue); }
[hidden]{ display:none !important; }

/* ---------- top nav ---------- */
.topnav{ display:flex; align-items:center; gap:8px; padding:12px 24px; background:var(--panel);
  border-bottom:1px solid var(--line); box-shadow:0 1px 0 var(--gold-dim); position:sticky; top:0; z-index:100; flex-wrap:wrap; }
.brand{ display:inline-flex; align-items:center; gap:8px; font-weight:700; font-size:17px; color:var(--text);
  text-decoration:none; margin-right:14px; white-space:nowrap; }
.brand img{ width:24px; height:24px; object-fit:contain; }
.brand .gold{ color:var(--gold); }
.nav-tabs{ display:flex; align-items:center; flex-wrap:wrap; }
.nav-link{ display:inline-flex; align-items:center; gap:6px; background:transparent; border:none;
  border-bottom:2px solid transparent; color:var(--text-dim); font:500 13px 'Space Grotesk',sans-serif;
  padding:8px 12px 7px; cursor:pointer; white-space:nowrap; text-decoration:none; }
.nav-link svg{ width:14px; height:14px; opacity:.65; }
.nav-link:hover{ color:var(--text); }
.nav-link.active{ color:var(--gold-bright); border-bottom-color:var(--gold); font-weight:600; }
.nav-link.active svg{ opacity:1; }
.nav-right{ margin-left:auto; display:flex; align-items:center; gap:10px; }
.theme-toggle{ width:32px; height:32px; border-radius:50%; background:var(--panel-raised); border:1px solid var(--line);
  color:var(--text-dim); display:flex; align-items:center; justify-content:center; cursor:pointer; }
.theme-toggle:hover{ border-color:var(--gold-dim); color:var(--gold-bright); }
.theme-toggle svg{ width:16px; height:16px; }
.acct{ font-size:12px; color:var(--text-dim); }
.acct a{ color:var(--text-dim); }

/* Sports dropdown */
.sports-menu{ position:relative; }
.sports-btn{ display:inline-flex; align-items:center; gap:8px; background:var(--gold-wash); border:1px solid var(--gold-dim);
  color:var(--gold-bright); font:600 13px 'Space Grotesk',sans-serif; padding:7px 12px; border-radius:20px; cursor:pointer; }
.sports-btn .caret{ font-size:10px; opacity:.8; }
.sports-dd{ position:absolute; top:calc(100% + 8px); left:0; min-width:240px; background:var(--panel); border:1px solid var(--line);
  border-radius:var(--radius-md); box-shadow:var(--shadow-pop); padding:6px; z-index:200; }
.sports-dd a, .sports-dd span{ display:flex; align-items:center; justify-content:space-between; gap:12px; padding:9px 10px;
  border-radius:var(--radius-sm); color:var(--text); text-decoration:none; font-size:13px; }
.sports-dd a:hover{ background:var(--wash-04); }
.sports-dd a.current{ color:var(--gold-bright); }
.sports-dd span{ color:var(--text-faint); cursor:default; }
.sports-dd .dd-head{ font-size:10px; color:var(--text-faint); text-transform:uppercase; letter-spacing:.08em; padding:8px 10px 4px; }
.sports-dd hr{ border:none; border-top:1px solid var(--line-soft); margin:4px 0; }

/* ---------- badges ---------- */
.badge{ font:600 10px 'IBM Plex Mono',monospace; padding:2px 8px; border-radius:20px; letter-spacing:.03em; white-space:nowrap; }
.badge.live{ background:var(--green-wash); color:var(--green); }
.badge.beta{ background:var(--blue-wash); color:var(--blue); }
.badge.soon{ background:var(--wash-04); color:var(--text-faint); }
.badge.gold{ background:var(--gold-wash); color:var(--gold-bright); }
.badge.red{ background:var(--red-wash); color:var(--red); }

/* ---------- layout ---------- */
/* No max-width/centering -- matches the real V2 NFL dashboard (body{
   padding:0 14px 40px }, no cap at all), per Tony: "in v2, theres no
   padding on the left and right of the screen... I don't like wasted
   space." A 1280px cap was leaving wide gutters on anything past a
   laptop-width window, which is also what forced the Player Pool table
   into a horizontal scroll it didn't need. */
main{ padding:20px 14px 40px; }
/* CONFIRMED REAL BUG found while chasing the "no gap" ask: a
   position:sticky element with a negative top margin (the first attempt
   at closing this gap) breaks the browser's own sticky-offset math --
   it was pushing the *next* sibling (the control-panel grid) up off the
   top of the viewport entirely, not just closing the gap. Zeroing
   main's own top padding instead, only while the Lineups tab is the
   visible one, avoids touching .wsbar's box model at all. */
main:has(> section[data-page="lineups"]:not([hidden])){ padding-top:0; }
.card{ background:var(--panel); border:1px solid var(--line); border-radius:var(--radius-lg); padding:18px; box-shadow:var(--shadow-card); }
.card h2, .section-title{ font-size:15px; font-weight:600; margin:0 0 4px; }
.card .sub, .sub{ color:var(--text-dim); font-size:12px; margin:0 0 14px; line-height:1.5; }
.grid{ display:grid; gap:14px; }
.grid.cols-2{ grid-template-columns:repeat(auto-fit, minmax(380px, 1fr)); }
.grid.cols-3{ grid-template-columns:repeat(auto-fit, minmax(280px, 1fr)); }
.grid.cols-4{ grid-template-columns:repeat(auto-fill, minmax(200px, 1fr)); }
.grid > *{ min-width:0; }
.stack{ display:flex; flex-direction:column; gap:16px; }
.notice{ padding:14px 16px; border-radius:var(--radius-md); background:var(--gold-wash); border:1px solid var(--gold-dim); line-height:1.5; }
.notice.err{ background:var(--red-wash); border-color:var(--red); }
.notice.pick-banner{ font-size:12.5px; }
.empty{ color:var(--text-faint); padding:18px 0; text-align:center; }

.metric .label{ font-size:11px; color:var(--text-dim); text-transform:uppercase; letter-spacing:.06em; }
.metric .value{ font:600 24px 'IBM Plex Mono',monospace; margin-top:6px; }
.metric .detail{ font-size:12px; color:var(--text-faint); margin-top:3px; }

/* ---------- controls ---------- */
.btn{ font:700 13px 'Space Grotesk',sans-serif; background:var(--gold); color:#0A0C10; border:none; border-radius:var(--radius-sm);
  padding:9px 14px; cursor:pointer; text-decoration:none; display:inline-block; }
.btn:disabled{ opacity:.5; cursor:default; }
.btn.ghost{ background:transparent; color:var(--text-dim); border:1px solid var(--line); font-weight:500; }
.btn.ghost:hover{ color:var(--text); border-color:var(--gold-dim); }
.chip{ font:500 12px 'IBM Plex Mono',monospace; padding:6px 11px; border-radius:20px; border:1px solid var(--line);
  background:transparent; color:var(--text-dim); cursor:pointer; }
.chip.active{ background:var(--gold-wash); border-color:var(--gold-dim); color:var(--gold-bright); }
input[type=text], input[type=search], input[type=number], select{ font:13px 'IBM Plex Mono',monospace; padding:8px 10px; background:var(--panel-raised);
  border:1px solid var(--line); color:var(--text); border-radius:var(--radius-sm); }
input:focus, select:focus{ outline:none; border-color:var(--gold-dim); }
/* CONFIRMED REAL BUG: input[type=number] was never in the dark-input
   list above, so the Lineups tab's Lineups/Max Exposure/Min Unique
   fields rendered as the browser's stock white number input against an
   otherwise all-dark panel. */
input[type=file]::file-selector-button{ font:600 12px 'IBM Plex Mono',monospace; padding:6px 10px; margin-right:8px;
  background:var(--panel-raised); border:1px solid var(--line); color:var(--text-dim); border-radius:var(--radius-sm); cursor:pointer; }
input[type=file]::file-selector-button:hover{ color:var(--text); border-color:var(--line); background:var(--panel); }
.toolbar{ display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin-bottom:12px; }
.toolbar .grow{ flex:1; }

/* ---------- tables ---------- */
.tbl-wrap{ overflow-x:auto; }
table{ width:100%; border-collapse:collapse; font-size:13px; }
th{ text-align:left; font-size:11px; font-weight:500; color:var(--text-dim); text-transform:uppercase; letter-spacing:.05em;
  padding:8px 10px; border-bottom:1px solid var(--line); white-space:nowrap; user-select:none; }
th.sortable{ cursor:pointer; }
th.sortable:hover{ color:var(--text); }
th.sorted{ color:var(--gold-bright); }
td{ padding:7px 10px; border-bottom:1px solid var(--line-soft); white-space:nowrap; }
td.num, th.num{ text-align:right; font-family:'IBM Plex Mono',monospace; }
/* Zebra striping (2026-10-06, per Tony's Light theme pass -- Gemini's
   "Unanchored Data Grids" point: dense rows bleeding together). Row-
   level, same selector weight as the picking-state row classes below
   (.afford-fit/.afford-over/.pick-ineligible), which stay a class
   heavier (.lineup-table + the state class) and so always win out over
   this plain nth-child tint regardless of source order. */
table tbody tr:nth-child(even){ background:var(--zebra-wash); }
tr:hover td{ background:var(--wash-04); }
td.flags{ white-space:normal; min-width:220px; color:var(--text-dim); font-size:12px; }
.pos{ font:600 11px 'IBM Plex Mono',monospace; color:var(--text-dim); }
.team{ font:500 12px 'IBM Plex Mono',monospace; }
.dim{ color:var(--text-faint); }
.good{ color:var(--green); } .bad{ color:var(--red); } .gold-t{ color:var(--gold-bright); }

/* ---------- anonymous teaser (Projections preview) ---------- */
/* Filler rows are fake/masked cell text sent as-is by the server -- never
   real data hidden with CSS -- so blurring them here leaks nothing. */
.teaser-row td{ color:var(--text-faint); filter:blur(2px); user-select:none; }
input:disabled, select:disabled{ opacity:.5; cursor:not-allowed; }
#teaserNotice button{ margin-left:4px; }

/* ---------- content pages (How To DFS) ---------- */
.content-page{ background:var(--panel); border:1px solid var(--line); border-radius:var(--radius-lg); box-shadow:var(--shadow-card);
  padding:32px 40px 40px; max-width:780px; margin:0 auto; }
.content-page h1{ font-size:22px; font-weight:700; margin:0 0 6px; }
.content-page h2{ font-size:15px; font-weight:600; color:var(--gold); margin:28px 0 8px; }
.content-page h3{ font-size:13px; font-weight:600; margin:16px 0 4px; }
.content-page p{ font-size:13px; line-height:1.7; color:var(--text-dim); margin:0 0 10px; }
.content-page ul, .content-page ol{ font-size:13px; line-height:1.7; color:var(--text-dim); margin:6px 0 14px; padding-left:22px; }
.content-page li{ margin-bottom:4px; }
.content-page strong{ color:var(--text); }
.content-page .tag-cash{ color:var(--blue); font-weight:600; }
.content-page .tag-gpp{ color:var(--gold); font-weight:600; }
.content-page .callout{ border-left:3px solid var(--gold); background:var(--gold-wash); padding:12px 14px; border-radius:0 var(--radius-sm) var(--radius-sm) 0;
  font-size:13px; line-height:1.6; color:var(--text-dim); margin:14px 0; }
.content-page table.kv{ width:auto; min-width:320px; margin:8px 0 14px; }
.content-page table.kv th, .content-page table.kv td{ font-size:12.5px; }

@media (max-width:720px){
  .topnav{ padding:10px 16px; }
  main{ padding:16px; }
  .grid.cols-2, .grid.cols-3{ grid-template-columns:1fr; }
  .sec-head h2{ font-size:22px; }
  .content-page{ padding:22px 18px 28px; }
  .content-page table.kv{ min-width:0; width:100%; }
  .nav-link{ padding:7px 9px; font-size:12.5px; }
  /* one scrollable row of tabs under the brand/menu row */
  .nav-tabs{ order:3; width:100%; flex-wrap:nowrap; overflow-x:auto; scrollbar-width:none; margin:0 -4px; }
  .nav-tabs::-webkit-scrollbar{ display:none; }
}

/* ---------- sport app pages (moved from app.html) ---------- */
  .notice{ margin-bottom:16px; }
.slatebar{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin-bottom:18px; }
.slatebar h1{ font-size:22px; margin:0 12px 0 0; }
.slatebar .meta{ color:var(--text-dim); font-size:12px; font-family:'IBM Plex Mono',monospace; }
/* Embedded context (2026-09-30, per Tony: relocated into the top of the
   builder's control panel on the Lineups tab -- see showTab()). A touch
   smaller, with its own divider since it's now sitting above other
   control-group rows instead of alone at the top of the page. */
#slatebarAnchor .slatebar{ margin-bottom:14px; padding-bottom:14px; border-bottom:1px solid var(--line-soft); }
#slatebarAnchor .slatebar h1{ font-size:17px; }
/* Slate picker "pill" (2026-09-30, per Tony's own mockup Slatepill1.jpg):
   a rounded, softly-glowing button instead of a native <select> -- per
   Tony, the old one "looks like a dropdown straight from a SQL
   database." Space Grotesk (the UI sans, not the mono data font) at a
   confident size -- this is chrome, not a data table. */
.slate-pill-wrap{ position:relative; }
.slate-pill{ display:flex; align-items:center; gap:10px; background:var(--panel-raised); border:1px solid var(--line);
  border-radius:24px; padding:9px 16px; font:600 14px 'Space Grotesk',sans-serif; color:var(--text); cursor:pointer;
  box-shadow:0 0 0 1px transparent, 0 4px 18px -6px var(--sport-glow); transition:box-shadow .15s, border-color .15s; }
.slate-pill:hover{ border-color:var(--sport-accent); box-shadow:0 0 0 1px var(--sport-accent), 0 4px 20px -4px var(--sport-glow); }
.slate-pill svg{ flex:0 0 auto; width:15px; height:15px; color:var(--sport-accent); }
.slate-pill-dim{ color:var(--text-faint); font-weight:400; }
.slate-pill-caret{ font-size:11px; color:var(--text-faint); transition:transform .15s; }
.slate-pill[aria-expanded="true"] .slate-pill-caret{ transform:rotate(180deg); color:var(--sport-accent); }
.slate-pill-solo{ cursor:default; }
.slate-pill-solo:hover{ border-color:var(--line); box-shadow:0 0 0 1px transparent, 0 4px 18px -6px var(--sport-glow); }
.slate-pill-solo .slate-pill-caret{ display:none; }
.slate-pill-menu{ position:absolute; top:calc(100% + 8px); left:0; min-width:280px; max-height:360px; overflow-y:auto; z-index:40;
  background:var(--panel); border:1px solid var(--line); border-radius:var(--radius-md); box-shadow:var(--shadow-pop); padding:6px; }
.slate-pill-item{ display:flex; align-items:center; width:100%; text-align:left; gap:4px; padding:9px 10px; font:500 13px 'Space Grotesk',sans-serif;
  color:var(--text-dim); background:none; border:none; border-radius:var(--radius-sm); cursor:pointer; }
.slate-pill-item:hover{ background:var(--wash-04); color:var(--text); }
.slate-pill-item.current{ color:var(--sport-accent); background:var(--sport-wash); }

.play{ display:flex; align-items:center; justify-content:space-between; gap:10px; padding:8px 0; border-bottom:1px solid var(--line-soft); }
.play:last-child{ border-bottom:none; }
.play .who{ min-width:0; }
.play .nm{ font-weight:600; font-size:13px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.play .ctx{ font:11px 'IBM Plex Mono',monospace; color:var(--text-faint); }
.play .nums{ text-align:right; font:12px 'IBM Plex Mono',monospace; white-space:nowrap; }
.play .nums b{ font-size:14px; color:var(--text); }

.stack-row .players{ font-size:12px; color:var(--text-dim); white-space:normal; line-height:1.5; }
.group-head{ font:600 11px 'IBM Plex Mono',monospace; color:var(--gold); letter-spacing:.06em; margin:4px 0 2px; }

.ss-picker{ display:flex; gap:8px; flex-wrap:wrap; align-items:center; }
.ss-picker input{ min-width:260px; flex:1; }
.ss-chips{ display:flex; gap:6px; flex-wrap:wrap; margin-top:10px; }
.ss-chip{ display:inline-flex; align-items:center; gap:6px; background:var(--panel-raised); border:1px solid var(--line);
  border-radius:20px; padding:5px 6px 5px 12px; font-size:13px; }
.ss-chip button{ background:none; border:none; color:var(--text-faint); cursor:pointer; font-size:14px; }
/* Centered empty-state card, not a full-width bar -- CONFIRMED REAL
   ISSUE per Tony's design review: the old .card.empty stretched to the
   width of whatever grid track it sat in (the full page), reading like
   a failed-to-load table row instead of deliberate empty-state UI. */
.ss-empty{ max-width:420px; margin:56px auto; padding:34px 30px; text-align:center;
  background:var(--panel); border:1px solid var(--line); border-radius:var(--radius-lg); box-shadow:var(--shadow-card); }
.ss-empty-icon{ width:48px; height:48px; margin:0 auto 16px; border-radius:50%; display:flex; align-items:center; justify-content:center;
  background:var(--sport-wash); color:var(--sport-accent); }
.ss-empty-icon svg{ width:22px; height:22px; }
.ss-empty h3{ font-size:15px; font-weight:700; margin:0 0 6px; color:var(--text); }
.ss-empty p{ font-size:12.5px; color:var(--text-dim); line-height:1.6; margin:0; }
.ss-card{ position:relative; }
.ss-card .nm{ font-size:17px; font-weight:700; }
.ss-card .ctx{ font:12px 'IBM Plex Mono',monospace; color:var(--text-dim); margin:2px 0 12px; }
.ss-card .kv{ display:grid; grid-template-columns:repeat(3, 1fr); gap:8px; margin-bottom:12px; }
.ss-card .kv div{ background:var(--panel-raised); border-radius:var(--radius-sm); padding:8px; }
.ss-card .kv .l{ font-size:10px; color:var(--text-faint); text-transform:uppercase; letter-spacing:.06em; }
.ss-card .kv .v{ font:600 15px 'IBM Plex Mono',monospace; margin-top:2px; }
.ss-card .verdicts{ display:flex; gap:6px; margin-bottom:10px; min-height:20px; }
.ss-card.pick{ border-color:var(--gold-dim); }
.bars{ display:flex; align-items:flex-end; gap:3px; height:54px; margin:6px 0 4px; }
.bars div{ flex:1; background:var(--blue); opacity:.75; border-radius:2px 2px 0 0; min-height:2px; }
.flag-list{ font-size:12px; color:var(--text-dim); line-height:1.6; margin:0; padding-left:16px; }

.home-hero{ display:grid; grid-template-columns:1.2fr 1fr; gap:16px; margin-bottom:16px; }
.home-hero .card h2{ font-size:18px; }
.checklist{ margin:0; padding:0; list-style:none; }
/* Interactive checklist (2026-09-30, per Tony's design pass): "make it
   feel like a functional tool rather than blog content." Checked state
   persists per sport via localStorage -- see renderChecklist() in app.js. */
.ck-item{ display:flex; align-items:flex-start; gap:10px; padding:8px 2px; font-size:13px; color:var(--text-dim);
  line-height:1.5; cursor:pointer; user-select:none; border-bottom:1px solid var(--line-soft); }
.ck-item:last-child{ border-bottom:none; }
.ck-box{ flex:0 0 16px; width:16px; height:16px; margin-top:1px; border:1.5px solid var(--line); border-radius:4px; position:relative; transition:background .12s, border-color .12s; }
.ck-item:hover .ck-box{ border-color:var(--sport-accent); }
.ck-item.done{ color:var(--text-faint); text-decoration:line-through; text-decoration-color:var(--line); }
.ck-item.done .ck-box{ background:var(--sport-accent); border-color:var(--sport-accent); }
.ck-item.done .ck-box::after{ content:''; position:absolute; left:4.5px; top:1.5px; width:4px; height:8px;
  border:solid var(--bg); border-width:0 2px 2px 0; transform:rotate(40deg); }
@media (max-width:900px){ .home-hero{ grid-template-columns:1fr; } }

/* =====================================================================
   Sport accent themes (per Tony, 2026-09-24 -- a style direction from a
   marketing session): BinkEngine stays dark slate + gold everywhere, and
   each sport adds ONE accent used for glow borders, tab highlights,
   badge tags and (2026-09-30 on) primary buttons and highlight text too
   -- kept low-opacity (~15-25% alpha glows, 1px borders) so it reads as
   "which sport am I in" without fighting the brand.
   Light theme uses a darker shade of the same hue so text stays readable.
   ===================================================================== */
:root{ --sport-accent:var(--gold); --sport-glow:rgba(217,167,46,0.22); --sport-wash:rgba(217,167,46,0.10); }
.sport-theme-nfl{ --sport-accent:#FFB800; --sport-glow:rgba(255,184,0,0.22);  --sport-wash:rgba(255,184,0,0.08); }
.sport-theme-mlb{ --sport-accent:#F97316; --sport-glow:rgba(249,115,22,0.22); --sport-wash:rgba(249,115,22,0.08); }
.sport-theme-nhl{ --sport-accent:#38BDF8; --sport-glow:rgba(56,189,248,0.22); --sport-wash:rgba(56,189,248,0.08); }
.sport-theme-nba{ --sport-accent:#FF8C00; --sport-glow:rgba(255,140,0,0.22);  --sport-wash:rgba(255,140,0,0.08); }
.sport-theme-pga{ --sport-accent:#10B981; --sport-glow:rgba(16,185,129,0.22); --sport-wash:rgba(16,185,129,0.08); }
.sport-theme-ufc{ --sport-accent:#EF4444; --sport-glow:rgba(239,68,68,0.22);  --sport-wash:rgba(239,68,68,0.08); }
:root[data-theme="light"] .sport-theme-nfl{ --sport-accent:#A16207; --sport-glow:rgba(161,98,7,0.16); --sport-wash:rgba(161,98,7,0.07); }
:root[data-theme="light"] .sport-theme-mlb{ --sport-accent:#C2410C; --sport-glow:rgba(194,65,12,0.16); --sport-wash:rgba(194,65,12,0.07); }
:root[data-theme="light"] .sport-theme-nhl{ --sport-accent:#0369A1; --sport-glow:rgba(3,105,161,0.16); --sport-wash:rgba(3,105,161,0.07); }
:root[data-theme="light"] .sport-theme-nba{ --sport-accent:#B45309; --sport-glow:rgba(180,83,9,0.16); --sport-wash:rgba(180,83,9,0.07); }
:root[data-theme="light"] .sport-theme-pga{ --sport-accent:#047857; --sport-glow:rgba(4,120,87,0.16); --sport-wash:rgba(4,120,87,0.07); }
:root[data-theme="light"] .sport-theme-ufc{ --sport-accent:#B91C1C; --sport-glow:rgba(185,28,28,0.16); --sport-wash:rgba(185,28,28,0.07); }

/* Badge tag: thin accent border, accent text, soft glow */
.sport-badge{ display:inline-block; font:600 10.5px 'IBM Plex Mono',monospace; padding:2px 8px; border-radius:20px; white-space:nowrap;
  border:1px solid var(--sport-accent); color:var(--sport-accent); background:var(--sport-wash);
  box-shadow:0 0 10px var(--sport-glow); margin:1px 2px 1px 0; }
.flag-txt{ color:var(--text-dim); font-size:12px; margin-right:6px; }
.flag-row{ display:flex; flex-wrap:wrap; gap:4px; align-items:center; }

/* Sport pages: the accent takes over tab highlights, the Sports pill,
   filter chips, buttons and a 1px glow on cards. Buttons used to stay
   brand gold everywhere -- changed 2026-09-30 per Tony: "Not all buttons
   have to be gold. We can work within the sports theme colors." Now the
   Lineups tab's contest-type/position/depth-chart chips, the primary
   Build Lineups CTA, and the pool's Lock icon all pick up each sport's
   own accent instead of a blanket gold, so NHL reads cyan, MLB orange,
   PGA green, UFC red, etc. Semantic colors (red=exclude/bust, green=good)
   are untouched -- this only covers the brand highlight color. */
body[class*="sport-theme-"] .nav-link.active{ color:var(--sport-accent); border-bottom-color:var(--sport-accent);
  text-shadow:0 0 12px var(--sport-glow); }
body[class*="sport-theme-"] .topnav{ box-shadow:0 1px 0 var(--sport-accent), 0 6px 18px -10px var(--sport-glow); }
body[class*="sport-theme-"] .sports-btn{ background:var(--sport-wash); border-color:var(--sport-accent); color:var(--sport-accent);
  box-shadow:0 0 10px var(--sport-glow); }
body[class*="sport-theme-"] .chip.active{ background:var(--sport-wash); border-color:var(--sport-accent); color:var(--sport-accent);
  box-shadow:0 0 8px var(--sport-glow); }
body[class*="sport-theme-"] main .card{ border-color:color-mix(in srgb, var(--sport-accent) 18%, var(--line)); }
body[class*="sport-theme-"] main .card:hover{ box-shadow:var(--shadow-card), 0 0 14px var(--sport-glow); }
body[class*="sport-theme-"] th.sorted{ color:var(--sport-accent); }
body[class*="sport-theme-"] .group-head{ color:var(--sport-accent); }
body[class*="sport-theme-"] .ss-card.pick{ border-color:var(--sport-accent); box-shadow:0 0 14px var(--sport-glow); }
body[class*="sport-theme-"] .bars div{ background:var(--sport-accent); opacity:.7; }
body[class*="sport-theme-"] .contest-btn:hover{ border-color:var(--sport-accent); color:var(--text); }
body[class*="sport-theme-"] .contest-btn.active{ background:var(--sport-wash); border-color:var(--sport-accent); color:var(--sport-accent);
  box-shadow:0 0 8px var(--sport-glow); }
body[class*="sport-theme-"] .run-btn{ background:linear-gradient(180deg, color-mix(in srgb, var(--sport-accent) 82%, white), var(--sport-accent));
  color:#0A0C10; box-shadow:0 2px 8px var(--sport-glow); }
body[class*="sport-theme-"] .run-btn:hover{ box-shadow:0 5px 14px var(--sport-glow); }
/* The sport-themed gradient above out-ranks .run-btn:disabled, so a disabled build button
   (mid-build, or the free preview) still looked live (2026-10-13 review). */
body[class*="sport-theme-"] .run-btn:disabled{ background:var(--panel-raised); color:var(--text-faint); box-shadow:none; filter:none; transform:none; }
body[class*="sport-theme-"] .gold-t{ color:var(--sport-accent); }
body[class*="sport-theme-"] .btn:not(.ghost){ background:var(--sport-accent); }
body[class*="sport-theme-"] input:focus, body[class*="sport-theme-"] select:focus{ border-color:var(--sport-accent); }
.slatebar h1 .dot{ display:inline-block; width:9px; height:9px; border-radius:50%; background:var(--sport-accent);
  box-shadow:0 0 10px var(--sport-accent); margin-right:10px; vertical-align:middle; }
.sdot{ display:inline-block; width:7px; height:7px; border-radius:50%; background:var(--sport-accent);
  box-shadow:0 0 8px var(--sport-glow); margin-right:9px; vertical-align:middle; font-style:normal; }
.sports-btn .cur-sport{ font:700 11px 'IBM Plex Mono',monospace; padding:1px 7px; border-radius:10px; background:var(--sport-glow); }

/* =====================================================================
   Per-sport "pizzazz" (2026-09-30, per Tony: "any way to add a little
   pizzazz... same feel but each adds their own little something extra").
   Two small, cheap additions, both pure CSS, neither touching layout:
   1. The slatebar dot gets a sport-specific pulse rhythm instead of a
      static glow -- NHL quick, MLB unhurried, NBA a dribble-bounce, PGA
      a slow calm breathe, UFC a sharp strobe-flash. It's the one element
      guaranteed visible on every single page of that sport, and it's
      purely decorative (never used as a live/status indicator), so
      animating it carries no risk of being misread as a status change.
   2. A faint (8% opacity) line-art sport emblem watermarked into the
      corner of the Home tab's hero card -- hockey stick + puck, a
      stitched baseball, a basketball, a golf flag, the UFC octagon.
      Drawn in the same stroke-only style as the nav icons up top (fill:
      none, rounded caps/joins) so it reads as part of the same design
      system instead of a bolted-on illustration, and kept low-opacity
      so it never competes with the actual numbers on the card.
   ===================================================================== */
@keyframes dotPulse{ 0%,100%{ opacity:1; transform:scale(1); } 50%{ opacity:.55; transform:scale(.82); } }
@keyframes dotBounce{ 0%,100%{ transform:scale(1); } 40%{ transform:scale(1.3); } 60%{ transform:scale(.85); } }
@keyframes dotFlash{ 0%,49%{ opacity:1; } 50%,100%{ opacity:.35; } }
.slatebar h1 .dot{ animation:dotPulse 2.2s ease-in-out infinite; }
body.sport-theme-nhl .slatebar h1 .dot{ animation-duration:1.1s; }
body.sport-theme-mlb .slatebar h1 .dot{ animation-duration:2.8s; }
body.sport-theme-nba .slatebar h1 .dot{ animation:dotBounce 1.3s cubic-bezier(.34,1.56,.64,1) infinite; }
body.sport-theme-pga .slatebar h1 .dot{ animation-duration:3.4s; }
body.sport-theme-ufc .slatebar h1 .dot{ animation:dotFlash .7s steps(2,end) infinite; }
@media (prefers-reduced-motion: reduce){ .slatebar h1 .dot{ animation:none; } }

/* Watermark tried and scrapped (2026-09-30, per Tony, who'd run this by
   Gemini and agreed): a literal sport-surface graphic behind the page --
   even shaded, even faint -- read as a mid-2000s fantasy-sports site
   rather than a commercial analytics tool. It also broke up the dark
   canvas unevenly (a diagonal edge cutting through a gutter between
   cards), which fought the grid instead of supporting it. Replaced with
   a genuinely ambient sport-identity cue: a soft radial wash of
   --sport-accent in the top corner, low enough (4%) that it reads as
   lighting, not as a shape. No icon, no silhouette, nothing to parse --
   same idea as the existing card-hover glow, just always-on and faint. */
body[class*="sport-theme-"]{
  /* Explicit pixel radius + background-attachment:fixed, not percentages
     -- percentages resolve against the full scrollable document height,
     which varies a lot page to page (an empty Start/Sit vs. a long
     Insights page), so the wash would balloon or shrink depending on
     which tab you're on. Fixed attachment also keeps it pinned to the
     viewport corner instead of scrolling away. */
  background-image:radial-gradient(900px circle at 85% 0%, var(--sport-wash) 0%, transparent 60%);
  background-attachment:fixed; background-repeat:no-repeat; }

/* ---------- account area (log in / sign up / log out) ---------- */
.acct{ display:flex; align-items:center; gap:8px; position:relative; }
.acct-name{ font-size:13px; color:var(--text); }
.acct-btn{ padding:7px 12px; font-size:12.5px; }
.acct-ico, .pop-badge{ display:none; }   /* phone-only (refresh.css): icon Account button, tier badge in the menu */
.login-pop{ position:absolute; right:0; top:calc(100% + 10px); width:280px; background:var(--panel); border:1px solid var(--line);
  border-radius:var(--radius-md); box-shadow:var(--shadow-pop); padding:16px; z-index:300; }
.login-pop h3{ margin:0 0 10px; font-size:15px; }
.login-pop form{ display:grid; gap:10px; }
.login-pop label{ display:grid; gap:4px; font-size:11px; color:var(--text-dim); text-transform:uppercase; letter-spacing:.05em; }
.login-pop input{ font:13px 'IBM Plex Mono',monospace; padding:8px 10px; background:var(--panel-raised); border:1px solid var(--line);
  color:var(--text); border-radius:var(--radius-sm); text-transform:none; letter-spacing:0; }
.login-links{ display:flex; justify-content:space-between; font-size:12px; }
.login-links a{ color:var(--text-dim); }
.login-note{ font-size:12px; color:var(--red); min-height:14px; }
.login-note.ok{ color:var(--green); }
.login-pop [data-form]{ display:grid; gap:10px; }
.login-pop [data-form][hidden]{ display:none; }
.login-pop label.login-check{ display:flex; align-items:flex-start; gap:8px; text-transform:none; letter-spacing:0; font-size:12px; line-height:1.4; }
.login-pop label.login-check input{ width:auto; margin:2px 0 0; padding:0; flex-shrink:0; }
.login-pop label.login-check a, .login-msg a{ color:var(--gold); }
.login-msg{ margin:0; font-size:12.5px; color:var(--text-dim); line-height:1.45; overflow-wrap:anywhere; }
/* Email-link landings (verified / bad link) -- see nav.js handleEmailLinks. */
.nav-banner{ display:flex; align-items:center; justify-content:space-between; gap:12px; margin:12px auto 0; max-width:1100px;
  width:calc(100% - 32px); padding:10px 14px; border:1px solid var(--green); background:var(--green-wash); color:var(--text);
  border-radius:var(--radius-md); font-size:13px; }
.nav-banner.bad{ border-color:var(--red); background:var(--red-wash); }
.nav-banner button{ background:none; border:0; color:var(--text-dim); font-size:18px; line-height:1; cursor:pointer; }
/* Phones: the log-in / sign-up form spans the screen with a 12px gutter instead of hanging
   off the account button (it ran 1px past the left edge at 390px). */
@media (max-width:720px){ .login-pop{ position:fixed; left:12px; right:12px; top:64px; width:auto; max-height:calc(100vh - 80px); overflow:auto; } }
.icon-btn{ background:transparent; border:1px solid var(--line); color:var(--text-dim); border-radius:var(--radius-sm);
  padding:4px 8px; cursor:pointer; font-size:12px; }
.icon-btn:hover{ color:var(--red); border-color:var(--red); }
input[type=date]{ font:13px "IBM Plex Mono",monospace; padding:8px 10px; background:var(--panel-raised); border:1px solid var(--line); color:var(--text); border-radius:var(--radius-sm); }

/* ---------- lineup builder ---------- */
.lb-controls{ display:grid; gap:12px; }
.lb-row{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
.lb-label{ font-size:11px; color:var(--text-dim); text-transform:uppercase; letter-spacing:.05em; min-width:74px; }
.lb-chips{ display:flex; gap:6px; flex-wrap:wrap; }
.lb-row input[type=number]{ width:74px; font:13px 'IBM Plex Mono',monospace; padding:7px 9px; background:var(--panel-raised);
  border:1px solid var(--line); color:var(--text); border-radius:var(--radius-sm); }
.lb-row input[type=range]{ width:160px; accent-color:var(--sport-accent); }
.lb-check{ font-size:13px; color:var(--text-dim); display:flex; align-items:center; gap:6px; }
/* Min-Max Salary slider (2026-10-01, per Tony) -- two overlaid native
   range inputs sharing one visual track underneath, the standard
   no-dependency way to get a two-thumb slider. Each input keeps its
   real hit-testing (so keyboard/touch dragging still works); only its
   own rendered track is made transparent so the shared fill bar shows
   through instead. */
.dual-range{ position:relative; height:26px; }
.dual-range input[type=range]{ position:absolute; left:0; top:9px; width:100%; margin:0; height:16px;
  -webkit-appearance:none; appearance:none; background:transparent; pointer-events:none; z-index:2; }
.dual-range input[type=range]::-webkit-slider-runnable-track{ -webkit-appearance:none; background:transparent; height:4px; }
.dual-range input[type=range]::-webkit-slider-thumb{ -webkit-appearance:none; pointer-events:auto; width:15px; height:15px;
  margin-top:-5.5px; border-radius:50%; background:var(--sport-accent); border:2px solid var(--panel); box-shadow:0 1px 3px rgba(0,0,0,.4); cursor:pointer; }
.dual-range input[type=range]::-moz-range-track{ background:transparent; height:4px; border:none; }
.dual-range input[type=range]::-moz-range-thumb{ pointer-events:auto; width:13px; height:13px; border-radius:50%;
  background:var(--sport-accent); border:2px solid var(--panel); box-shadow:0 1px 3px rgba(0,0,0,.4); cursor:pointer; }
/* Inset 7px on each side, NOT flush to the container edge (2026-10-02,
   per Tony: "the right side of the slider bar looks off... it leaves a
   corner showing" -- the real cause: a native thumb's travel range is
   inset by its own half-width from the input's edges, so a fill bar
   drawn edge-to-edge at 0%-100% overshoots past where the thumb (at
   max) actually sits. 7px ~= the real webkit/moz thumb radius (15px/13px
   wide), so .dual-range-fill below -- a child of this track, its
   percentages scoped to THIS inset box -- now ends exactly under the
   thumb instead of poking out past it. */
.dual-range-track{ position:absolute; left:7px; right:7px; top:11px; height:4px; border-radius:2px; background:var(--line); pointer-events:none; }
.dual-range-fill{ position:absolute; top:0; height:4px; border-radius:2px; background:var(--sport-accent); }
/* CONFIRMED REAL BUG fixed here (2026-10-04, per Tony: "the Pools spill
   over behind the player pool" / "truncate [a long name] or spill it
   onto a second row"): this used to be min-width:110px + the browser's
   default white-space:normal-but-never-actually-wrapping-in-practice
   combo, so a 9-slot classic roster (or just one long name) grew the
   table past its panel with nothing to stop it. #tLineups now has a
   table-layout:fixed colgroup sized to the panel (see renderLineups()),
   so a cell can never grow its column -- word-break lets a long name
   wrap onto a second line inside its own fixed-width cell instead.*/
.lb-cell{ min-width:0; font-size:12.5px; line-height:1.3; white-space:normal; word-break:break-word; overflow:hidden; cursor:pointer; }
.lb-cell:hover{ background:var(--sport-wash); }
/* Armed for an inline swap (2026-10-06 v2, per Tony: "Can just click a
   name, and then click a replacement" -- no separate editor view, so the
   grid itself needs to show which cell a Player Pool click will fill). */
.lb-cell.lb-cell-armed{ background:var(--gold-wash); box-shadow:inset 0 0 0 1px var(--gold-dim); }

/* =====================================================================
   consolidatedLineups sports -- ported directly from the live V2 NFL
   dashboard (model_dashboard_v2.html), same classes/structure, not a
   re-guess from a screenshot. Team logos: ESPN's public CDN
   (a.espncdn.com/i/teamlogos/<sport>/500/<code>.png), same host/pattern
   V2 already uses for NFL, verified reachable for nhl/mlb/nba too.
   ===================================================================== */

/* ---------- team logos (schedule strip + dense table rows) ---------- */
.slate-team-logo{ width:30px; height:30px; object-fit:contain; flex-shrink:0; border-radius:50%; background:var(--wash-04); }
.pool-team-logo{ width:18px; height:18px; object-fit:contain; flex-shrink:0; border-radius:50%; background:var(--wash-04); vertical-align:middle; }
.pool-team-logo-fallback{ width:18px; height:18px; border-radius:50%; flex-shrink:0; background:var(--panel); border:1px solid var(--line);
  display:inline-flex; align-items:center; justify-content:center; font:700 7px 'IBM Plex Mono',monospace; color:var(--text-dim); vertical-align:middle; }
.slate-team-logo-fallback{ width:30px; height:30px; border-radius:50%; flex-shrink:0; background:var(--panel); border:1px solid var(--line);
  display:flex; align-items:center; justify-content:center; font:700 10px 'IBM Plex Mono',monospace; color:var(--text-dim); }

/* ---------- schedule strip ---------- */
/* top is set by syncWsbarTop() (app.js), not hardcoded -- CONFIRMED REAL
   BUG this fixes: with both .topnav and .wsbar pinned to top:0, they
   competed for the same spot on scroll (the nav's own higher z-index
   just let it win, sliding over/hiding the schedule strip instead of
   sitting below it). 2026-09-30 per Tony, matching V2's own
   #weekScheduleBar: "we have a floating panel and a minimize button on
   v2. Let's get that worked in." */
.wsbar{ position:sticky; z-index:15; background:var(--bg); border-bottom:1px solid var(--line); padding:8px 0 10px; margin:0 0 22px; }
.wsbar-row{ display:flex; gap:8px; overflow-x:auto; overflow-y:visible; padding-bottom:2px; }
.ws-empty{ font-size:11px; color:var(--text-faint); padding:8px 2px; }
/* Mini View toggle, in the nav now (#navMiniViewBtn) -- matches V2's
   real placement. Same circular-button treatment as .theme-toggle right
   next to it. */
.nav-mini-toggle{ width:30px; height:30px; border-radius:50%; background:var(--panel-raised); border:1px solid var(--line);
  color:var(--text-faint); cursor:pointer; display:flex; align-items:center; justify-content:center; }
.nav-mini-toggle:hover{ color:var(--text); border-color:var(--sport-accent); }
.nav-mini-toggle.active{ color:var(--sport-accent); border-color:var(--sport-accent); background:var(--sport-wash); }

/* ---------- BinkEngine status pill (2026-10-06) ----------
   Same click-to-open-popover shape as the live V2 NFL dashboard's own
   #engineStatusBar/setEngineStatus (read-only reference) -- dot color/
   pulse is theme-neutral (gold/green/red), same as NFL's, not tinted by
   the active sport's accent, since it reports build/engine state, not
   sport identity. */
@keyframes engineStatusPulse{ 0%,100%{ opacity:1; } 50%{ opacity:.35; } }
.dot-pulse{ animation: engineStatusPulse 1.1s ease-in-out infinite; }
#engineStatusPopoverWrap{ position:relative; display:inline-block; }
#engineStatusBar{ display:flex; align-items:center; gap:8px; background:none; border:1px solid transparent;
  border-radius:999px; padding:6px 12px; font-size:11px; color:var(--text-dim); cursor:pointer;
  font-family:'IBM Plex Mono',monospace; white-space:nowrap; }
#engineStatusBar:hover{ border-color:var(--line); background:var(--panel-raised); color:var(--text); }
#engineStatusBar .dot{ width:8px; height:8px; border-radius:50%; background:var(--green); flex-shrink:0; }
#engineStatusLabel{ max-width:150px; overflow:hidden; text-overflow:ellipsis; display:inline-block; vertical-align:bottom; }
#engineStatusPopover{ position:absolute; top:calc(100% + 8px); right:0; width:250px; background:var(--panel-raised);
  border:1px solid var(--line); border-radius:var(--radius-md); padding:14px 16px;
  box-shadow:var(--shadow-pop); z-index:60; }
.engine-status-row{ display:flex; align-items:center; justify-content:space-between; font-size:11.5px; padding:3px 0; color:var(--text); }
.engine-status-divider{ border-top:1px solid var(--line-soft); margin:8px 0; }

.ws-mini-row{ display:flex; align-items:center; gap:8px; flex-shrink:0; background:var(--panel); border:1px solid var(--line);
  border-radius:var(--radius-sm); padding:6px 12px; white-space:nowrap; }
.ws-mini-name{ font-size:11px; color:var(--text); font-weight:600; }
.ws-mini-at{ font-size:9px; color:var(--text-faint); }
.ws-mini-stat{ font-size:10.5px; font-family:'IBM Plex Mono',monospace; font-weight:600; margin-left:4px; padding-left:8px; border-left:1px solid var(--line-soft); }
.ws-card{ position:relative; width:150px; flex-shrink:0; background:var(--panel); border:1px solid var(--line); border-radius:var(--radius-md); padding:8px 9px; }
.ws-kickoff{ font-size:9px; color:var(--text-faint); font-family:'IBM Plex Mono',monospace; text-align:center; margin-bottom:6px; }
.ws-matchup{ display:flex; align-items:flex-start; justify-content:center; gap:7px; margin-bottom:7px; }
.ws-team{ display:flex; flex-direction:column; align-items:center; gap:2px; width:52px; }
.ws-matchup .ws-abbr{ font-size:10px; font-weight:700; color:var(--text); font-family:'IBM Plex Mono',monospace; }
.ws-matchup .ws-at{ font-size:9px; color:var(--text-faint); align-self:center; margin-top:11px; }
.ws-score{ font-size:13px; font-weight:800; color:var(--text); font-family:'IBM Plex Mono',monospace; line-height:1.2; min-height:15px; }
.ws-live{ font-size:9px; font-weight:600; text-align:center; margin-top:5px; margin-bottom:5px; }
.ws-metarow{ display:flex; gap:6px; padding-top:7px; border-top:1px solid var(--line-soft); }
.ws-metacell{ flex:1; text-align:center; border-radius:5px; padding:3px 0; }
.ws-metalabel{ font-size:7.5px; color:var(--text-faint); text-transform:uppercase; letter-spacing:.05em; margin-bottom:1px; }
.ws-metaval{ font-size:10.5px; font-weight:700; font-family:'IBM Plex Mono',monospace; }
.ws-card{ cursor:pointer; }
.ws-card.open{ border-color:var(--sport-accent); }

/* ---------- schedule-card click-to-expand: last 5 games recap ----------
   Same floating-dropdown-under-the-card approach as the live V2 NFL
   dashboard's weather-at-kickoff (#wsDropdownHost is a sibling of
   wsbar-row, not a child -- a child would clip under that row's own
   horizontal scrollbar), same real recent-form content every sport
   gets, PLUS a real kickoff weather section for NFL (see app.js's
   wsWeatherHtml -- indoor sports/games with no weather field just never
   render that block). */
.ws-dropdown{ position:absolute; width:280px; background:var(--panel-raised); border:1px solid var(--line);
  border-radius:var(--radius-md); box-shadow:var(--shadow-pop); padding:11px; z-index:30; cursor:default; }
.ws-dd-close{ position:absolute; top:8px; right:8px; width:18px; height:18px; border-radius:50%; background:var(--panel);
  display:flex; align-items:center; justify-content:center; cursor:pointer; color:var(--text-faint); font-size:11px; line-height:1; }
.ws-dd-close:hover{ background:var(--line); color:var(--text); }
.ws-dd-label{ font-size:8.5px; color:var(--text-faint); text-transform:uppercase; letter-spacing:.04em; margin-bottom:7px; }
.ws-dd-cols{ display:flex; gap:12px; }
.ws-dd-col{ flex:1; min-width:0; }
.ws-dd-team{ font-size:10px; font-weight:700; color:var(--text); font-family:'IBM Plex Mono',monospace; margin-bottom:4px; }
.ws-dd-row{ font-size:10px; font-family:'IBM Plex Mono',monospace; color:var(--text-dim); line-height:1.6; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.ws-dd-wl{ font-weight:700; margin-right:2px; }
.ws-dd-wl.w{ color:var(--green); }
.ws-dd-wl.l{ color:var(--red); }
.ws-dd-empty{ font-size:10px; color:var(--text-faint); }
.ws-dd-wx{ font-size:10px; font-family:'IBM Plex Mono',monospace; color:var(--text); line-height:1.5; margin-bottom:10px; }

/* ---------- control panel (Build / Data boxes above the pools) ---------- */
.control-panel{ background:var(--panel); border:1px solid var(--line); border-radius:var(--radius-md); box-shadow:var(--shadow-card);
  padding:20px 22px; margin-bottom:22px; display:flex; align-items:flex-end; flex-wrap:wrap; }
.control-group{ background:var(--panel-raised); border:1px solid var(--line-soft); border-radius:var(--radius-sm); padding:11px 16px; margin:0 10px 10px 0; }
.control-group .label{ font-size:10.5px; color:var(--text-dim); margin-bottom:8px; font-weight:600; letter-spacing:.04em; text-transform:uppercase; }
.contest-type-fixed{ width:280px; flex:0 0 280px; }
.export-disabled{ opacity:.45; pointer-events:none; }
.contest-buttons{ display:flex; flex-wrap:wrap; row-gap:6px; }
.contest-btn{ background:var(--panel); border:1px solid var(--line); color:var(--text-dim); font:500 11px 'IBM Plex Mono',monospace;
  padding:8px 13px; cursor:pointer; margin-right:6px; border-radius:var(--radius-sm); transition:all .13s; }
.contest-btn:hover{ border-color:var(--gold-dim); color:var(--text); background:var(--panel-raised); }
.contest-btn.active{ background:var(--gold-wash); border-color:var(--gold); color:var(--gold-bright); font-weight:600; }
#poolPosTabs{ flex-wrap:nowrap; gap:4px; }
#poolPosTabs .contest-btn{ flex:1; padding:6px 4px; font-size:10.5px; margin-right:0; text-align:center; }
#ownSourceTabs, #projSourceTabs{ flex-wrap:nowrap; gap:4px; }
#ownSourceTabs .contest-btn, #projSourceTabs .contest-btn{ flex:1; padding:6px 4px; font-size:10.5px; margin-right:0; text-align:center; white-space:nowrap; }
.run-btn{ background:linear-gradient(180deg, var(--gold-bright), var(--gold)); border:none; color:#1A1305; font:700 13px 'Space Grotesk',sans-serif;
  padding:10px 22px; cursor:pointer; border-radius:var(--radius-sm); margin-right:10px; box-shadow:0 2px 8px rgba(212,169,74,0.28); transition:transform .1s, box-shadow .1s, filter .1s; }
.run-btn:hover{ filter:brightness(1.06); transform:translateY(-1px); box-shadow:0 5px 14px rgba(212,169,74,0.38); }
.run-btn:disabled{ background:var(--panel-raised); color:var(--text-faint); cursor:not-allowed; box-shadow:none; transform:none; }
.run-status{ font-size:12px; color:var(--text-dim); margin-left:16px; font-family:'IBM Plex Mono',monospace; }
.run-status.error{ color:var(--red); } .run-status.success{ color:var(--green); }
/* CONFIRMED REAL BUG: .refresh-btn (Lock/Exclude/Clear Locks/Download
   CSV) had no CSS at all, so it rendered as the browser's stock white
   <button> next to an otherwise fully dark panel. */
.refresh-btn{ background:var(--panel-raised); border:1px solid var(--line); color:var(--text-dim); font:600 11.5px 'IBM Plex Mono',monospace;
  padding:7px 12px; cursor:pointer; border-radius:var(--radius-sm); transition:all .13s; }
.refresh-btn:hover{ border-color:var(--sport-accent, var(--gold-dim)); color:var(--text); background:var(--panel); }
.refresh-btn:disabled{ color:var(--text-faint); cursor:not-allowed; opacity:.55; }

/* ---------- Lineup Pool / Player Pool panels ---------- */
.panel-row{ display:grid; grid-template-columns:1.3fr 1fr; gap:18px; margin-bottom:18px; align-items:start; }
.panel-row > .panel{ min-width:0; }
@media (max-width:1100px){ .panel-row{ grid-template-columns:1fr; } }
.panel{ background:var(--panel); border:1px solid var(--line); border-radius:var(--radius-md); box-shadow:var(--shadow-card); padding:19px 21px; }
.panel h2{ font-size:14px; font-weight:700; margin:0 0 5px; display:flex; justify-content:space-between; align-items:center; }
.lineup-table{ width:100%; border-collapse:separate; border-spacing:0; margin-top:10px; }
/* Scoped to #tLineups specifically (the Lineup Pool table), not the
   single-lineup editor's own .lineup-table (different column shape,
   no colgroup) -- see renderLineups()'s colgroup for the widths. */
#tLineups{ table-layout:fixed; margin-top:0; }
/* Per Tony (2026-10-04): "add a vertical scroll bar if we exceed 20
   lineups. Dont need it to scroll all the way down on a 150 build." --
   ~1400px is roughly 20 rows for a long-name sport (UFC fighters wrap to
   2 lines often, ~78px/row); shorter-name sports fit more like 25-30
   rows before scrolling, not a precise row-count cutoff either way.
   Sticky header matches the Player Pool's own .pool-scroll pattern. */
.lineup-scroll{ max-height:1400px; overflow-y:auto; margin-top:10px; border:1px solid var(--line); border-radius:var(--radius-md); }
/* No <thead> here (renderLineups() writes a plain first <tr> into the
   table), so the sticky target is that row's own cells directly. */
.lineup-scroll tr:first-child th{ position:sticky; top:0; z-index:1; }
.lineup-table th{ text-align:left; font-size:10px; color:var(--text-dim); font-weight:700; padding:9px 10px; border-bottom:1px solid var(--line);
  background:var(--panel-raised); text-transform:uppercase; letter-spacing:.05em; }
.lineup-table th:not(:last-child){ border-right:1px solid var(--line-soft); }
.lineup-table td{ padding:9.5px 10px; font-size:12px; border-bottom:1px solid var(--line-soft); }
.lineup-table td:not(:last-child){ border-right:1px solid var(--line-soft); }
.h-scroll{ overflow-x:auto; }
.pool-scroll{ max-height:680px; overflow-y:auto; overflow-x:auto; border:1px solid var(--line); border-radius:var(--radius-md); }
/* table-layout:auto (not fixed) + an explicit per-column <colgroup> from
   renderProj() -- CONFIRMED REAL BUG this fixes: table-layout:fixed with
   no colgroup divides all ~14 columns evenly across whatever width the
   panel-row grid track hands this panel (as little as ~500px), crushing
   every column to a few px and truncating every value to 1-2 characters
   with headers overlapping. Real per-column min-widths + overflow-x:auto
   lets the table scroll horizontally past the core columns instead of
   crushing all of them -- the same fallback pattern V2's own narrow-
   container CSS uses (model_dashboard_v2.html's mobile .pool-scroll
   rules), applied here since this panel is comparably narrow. */
/* width:100% (was auto), 2026-09-30 per Tony: "Player pool needs to not
   have the wasted space on the right hand side of it" -- CONFIRMED REAL
   BUG: with width:auto the table only ever took the width its own
   content needed (the 8 core columns, ~550px) and never grew to fill a
   wider panel, leaving a dead gap on the right in anything wider than
   that. table-layout:auto + width:100% still uses each column's
   min-content width as a floor (so it won't crush below legible, and
   still scrolls on a narrow panel) but now stretches to fill the
   container when there's room instead of stopping short. */
.pool-scroll table{ margin-top:0; table-layout:auto; width:100%; }
.pool-scroll thead th{ position:sticky; top:0; background:var(--panel-raised); z-index:1; }
#tProj td{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
#tProj th{ white-space:nowrap; text-align:center; }
/* CONFIRMED REAL BUG this fixes (Tony, 2026-10-05: "Some long names
   causing a horizontal scroll"): table-layout:auto (the deliberate fix
   two comments up, for a narrow-panel column-crushing bug) computes each
   column's width from its content's PREFERRED (single-line) width --
   with every #tProj td forced white-space:nowrap above, a long name's
   full one-line width became a candidate for the Player column's width,
   growing the whole table past the panel. Wrapping just the name cell
   (every other column stays nowrap -- numbers/short labels don't have
   this problem) keeps a long name on 2 lines instead of widening the
   column, so table-layout:auto's own width computation never sees that
   long single-line candidate in the first place. */
#tProj td.pool-name-cell{ white-space:normal; overflow-wrap:break-word; }
/* Click-to-expand row detail (Floor/Ceiling/Recent/Notes) -- same idea as
   V2's poolDetailRowHtml: those don't need to be permanent columns eating
   width every row, just a click away. Per Tony: "I can see baseball has a
   notes section. Not needed. Or we can add it to an expanded player view
   like we did with the NFL." */
.pool-name-cell{ cursor:pointer; }
.pool-name-cell:hover{ background:var(--panel-raised); }
.pool-expand-caret{ display:inline-block; width:11px; color:var(--text-faint); font-size:9px; }
#tProj .pool-detail-row td{ background:var(--panel-raised); white-space:normal; overflow:visible; padding:12px 16px; }
.pool-detail-tiles{ display:grid; grid-template-columns:repeat(auto-fit, minmax(90px, 1fr)); gap:8px; }
.pool-stat-tile{ background:var(--panel); border:1px solid var(--line); border-radius:var(--radius-sm); padding:8px 10px; }
.pool-stat-tile .l{ font-size:9.5px; color:var(--text-faint); text-transform:uppercase; letter-spacing:.04em; margin-bottom:3px; }
.pool-stat-tile .v{ font-size:14px; font-weight:600; }
.pool-gamelog{ margin-top:10px; overflow-x:auto; }
.pool-gamelog table{ width:auto; min-width:320px; border-collapse:collapse; font-variant-numeric:tabular-nums; }
.pool-gamelog th{ font-size:9.5px; color:var(--text-faint); text-transform:uppercase; letter-spacing:.04em; text-align:right; padding:3px 9px; border-bottom:1px solid var(--line); }
.pool-gamelog td{ font-size:12px; text-align:right; padding:3px 9px; border-bottom:1px solid var(--line); }
.pool-gamelog th:first-child, .pool-gamelog td:first-child, .pool-gamelog th:nth-child(2), .pool-gamelog td:nth-child(2){ text-align:left; }
.pool-gamelog tr:last-child td{ border-bottom:0; }
.pool-gamelog td.dk{ font-weight:600; }
.pool-gamelog td.mt{ white-space:nowrap; }
.pool-gamelog td.res-w{ color:var(--good, #3fb97c); }
.pool-gamelog td.res-l{ color:var(--text-faint); }
/* Player card modal (2026-10-10, per Tony: DK-style card on name click) */
.pcard-overlay{ position:fixed; inset:0; z-index:120; background:rgba(0,0,0,.55); display:flex; align-items:flex-start; justify-content:center; padding:6vh 16px 16px; overflow-y:auto; }
.pcard{ position:relative; width:min(680px, 100%); background:var(--panel); border:1px solid var(--line); border-radius:var(--radius-md); padding:18px 20px 16px; box-shadow:0 18px 48px rgba(0,0,0,.5); }
.pcard-close{ position:absolute; top:10px; right:12px; background:none; border:0; color:var(--text-faint); font-size:22px; line-height:1; cursor:pointer; padding:4px; }
.pcard-close:hover{ color:var(--text); }
.pcard-logo{ width:48px; height:48px; flex:0 0 auto; }
.pcard-name{ font-size:20px; font-weight:700; line-height:1.1; }
.pcard-oprk{ font-size:10.5px; letter-spacing:.03em; }
.pcard-season{ display:flex; gap:0; background:var(--panel-raised); border:1px solid var(--line); border-radius:var(--radius-sm); margin-bottom:10px; overflow-x:auto; }
.pcard-sstat{ flex:1 1 0; min-width:68px; text-align:center; padding:8px 6px; border-right:1px solid var(--line); }
.pcard-sstat:last-child{ border-right:0; }
.pcard-sstat .l{ font-size:9.5px; color:var(--text-faint); text-transform:uppercase; letter-spacing:.05em; }
.pcard-sstat .v{ font-size:16px; font-weight:700; margin-top:2px; font-variant-numeric:tabular-nums; }
.pcard-proj{ margin-bottom:4px; }
.pcard-rank{ display:inline-block; font-size:9.5px; font-weight:700; line-height:1; padding:2px 4px; border-radius:4px; vertical-align:3px; cursor:help; }
.pcard-rank.rk-elite{ background:rgba(63,185,124,.22); color:var(--good, #3fb97c); }
.pcard-rank.rk-good{ background:rgba(63,185,124,.12); color:var(--good, #3fb97c); opacity:.85; }
.pcard-rank.rk-mid{ background:var(--panel); color:var(--text-faint); border:1px solid var(--line); }
.pcard-rank.rk-faint{ background:none; color:var(--text-faint); opacity:.6; }
.pcard-log-label{ font-size:10px; color:var(--text-faint); text-transform:uppercase; letter-spacing:.06em; margin:10px 0 2px; }
.pcard-empty{ font-size:12px; color:var(--text-faint); padding:8px 0; }
.pcard-foot{ display:flex; align-items:center; justify-content:space-between; border-top:1px solid var(--line); margin-top:14px; padding-top:12px; }
.pcard-foot-sal{ font-size:16px; font-weight:700; }
.pcard-foot-pos{ font-size:11px; color:var(--text-faint); margin-left:8px; font-weight:400; }
.pcard-add{ font-size:13px; padding:8px 18px; }
.pcard-add[disabled]{ opacity:.45; cursor:not-allowed; }
@media (max-width:560px){ .pcard-overlay{ padding:3vh 8px 8px; } .pcard{ padding:14px 12px 12px; } }
.stack-rules-dropdown{ position:absolute; top:calc(100% + 8px); left:0; right:0; z-index:40; background:var(--panel); border:1px solid var(--line);
  border-radius:var(--radius-md); padding:16px 18px 18px; box-shadow:0 12px 32px rgba(0,0,0,.45); max-height:min(480px, 70vh); overflow-y:auto; }
.stack-rules-summary{ font-size:11px; color:var(--text-faint); }

/* ---------- Single-lineup editor (pencil icon on a Lineup Pool row) ---------- */
/* Folded into the existing "#" cell rather than its own trailing column --
   a dedicated column pushed showdown slates' already-wide CPT+5xUTIL
   tables past the panel width, forcing horizontal scroll on Lineup Pool,
   which Tony explicitly ruled out (2026-09-30: "Lineup pool shouldn't have
   a horizontal scroll. Just show players."). */
/* Just Pin over Edit, no lineup number (2026-10-15, Tony: "take out the
   row count... just put the pin and edit buttons there. Saves space") --
   a fixed 30px column (renderLineups' colgroup). Side by side they'd need
   43px; the old ~4% column was 37px, so Edit hung into the QB cell. */
#tLineups td.lineup-num-cell{ padding:6px 0; text-align:center; vertical-align:middle; }
.lineup-num-cell .lineup-pin-btn, .lineup-num-cell .lineup-edit-btn{ display:block; margin:0 auto; }
.lineup-num-cell .lineup-edit-btn{ margin-top:4px; }
/* "+ Add a lineup" -- the Lineup Pool's own Hand Build row. */
#tLineups tr.lb-add-row td{ padding:8px 10px; border-bottom:none; }
.lb-add-btn{ background:transparent; border:1px dashed var(--line); color:var(--text-dim); border-radius:var(--radius-sm);
  font:600 12px 'Space Grotesk',sans-serif; padding:7px 14px; cursor:pointer; transition:all .13s; }
.lb-add-btn:hover{ border-color:var(--sport-accent, var(--gold-dim)); color:var(--text); background:var(--panel-raised); }
.lineup-pin-btn{ background:transparent; border:1px solid var(--line); color:var(--text-dim); border-radius:var(--radius-sm);
  width:20px; height:20px; line-height:18px; padding:0; font-size:10px; cursor:pointer; transition:all .13s; flex:none;
  filter:grayscale(1); opacity:.55; }
.lineup-pin-btn:hover{ opacity:1; border-color:var(--sport-accent, var(--gold-dim)); background:var(--panel-raised); }
.lineup-pin-btn.pinned{ filter:none; opacity:1; border-color:var(--sport-accent); background:var(--sport-wash); }
.lineup-edit-btn{ background:transparent; border:1px solid var(--line); color:var(--text-dim); border-radius:var(--radius-sm);
  width:20px; height:20px; line-height:18px; padding:0; font-size:10.5px; cursor:pointer; transition:all .13s; flex:none; }
.lineup-edit-btn:hover{ border-color:var(--sport-accent, var(--gold-dim)); color:var(--text); background:var(--panel-raised); }
.sl-toolbar{ display:flex; align-items:center; flex-wrap:wrap; gap:10px; margin-top:10px; }
.sl-budget{ margin-left:auto; font-size:12px; font-family:'IBM Plex Mono',monospace; color:var(--text-dim); }
.sl-budget b{ color:var(--text); }
.sl-budget.over{ color:var(--red); }
.sl-budget.over b{ color:var(--red); }
.sl-multiremove-bar{ display:flex; align-items:center; gap:10px; margin-top:10px; padding:10px 14px; background:var(--red-wash);
  border:1px solid var(--red); border-radius:var(--radius-sm); }
#singleLineupView .lineup-table tr.sl-row{ cursor:pointer; }
#singleLineupView .lineup-table tr.sl-row:hover td{ background:var(--wash-04); }
#singleLineupView .lineup-table tr.sl-row.active td{ background:var(--gold-wash); }
#singleLineupView .lineup-table tr.sl-row.marked td{ background:var(--red-wash); }
.sl-remove-btn{ background:transparent; border:none; color:var(--red); cursor:pointer; font-size:11px; padding:2px 4px; }
.sl-remove-btn:hover{ opacity:.7; }
#singleLineupView .pool-detail-tiles{ margin-top:12px; }

/* ---------- Lock/Pool/Exclude icon buttons (Player Pool rows) ---------- */
.pick-col{ width:30px; }
.pick-btn{ background:transparent; border:none; color:var(--text-faint); cursor:pointer; font-size:13px; padding:2px; line-height:1; }
.pick-btn:hover{ color:var(--text); }
.pick-btn.pick-on-pool{ color:var(--sport-accent); }
.pick-btn.pick-on-exclude{ color:var(--red); }
/* Quick add (+) (2026-10-14, per Tony): a fixed 22px circle so the
   column never changes width between idle and armed. Idle = faint and
   inert; armed = filled in the row's fit color (green fits the budget,
   red is over it -- same tint as the row). */
.quick-add-btn{ width:22px; height:22px; border-radius:50%; border:1px solid var(--line); font-size:15px; font-weight:700;
  padding:0; display:inline-flex; align-items:center; justify-content:center; vertical-align:middle; }
.quick-add-btn:disabled{ opacity:.35; cursor:default; }
.quick-add-btn:disabled:hover{ color:var(--text-faint); }
.quick-add-btn.qa-on{ color:var(--green); border-color:var(--green); background:var(--green-wash); }
.quick-add-btn.qa-on:hover{ background:var(--green); color:var(--panel); }
.afford-over .quick-add-btn.qa-on{ color:var(--red); border-color:var(--red); background:var(--red-wash); }
.afford-over .quick-add-btn.qa-on:hover{ background:var(--red); color:var(--panel); }
/* Lock toggle switch (2026-10-06 v2, replacing the lock-icon SVG above
   per Tony: "I hate the lock icon.. lets redo.. Since we have the
   space... why not instead of the 'lock icon' we just put a little
   slider?" -- matching the reference image he saved (a pill track +
   round thumb that slides side to side, track recoloring to show
   state), using the app's own gold=Lock color instead of the
   reference's blue. */
.pick-btn-lock{ vertical-align:middle; }
.lock-switch-track{ display:inline-block; width:28px; height:15px; border-radius:999px;
  background:var(--line); border:1px solid var(--line); position:relative; vertical-align:middle;
  transition:background .15s ease, border-color .15s ease; }
.lock-switch-thumb{ position:absolute; top:1px; left:1px; width:11px; height:11px; border-radius:50%;
  background:var(--panel); box-shadow:0 1px 2px rgba(0,0,0,.35); transition:transform .15s ease; }
.pick-btn-lock:hover .lock-switch-track{ border-color:var(--gold-dim); }
.pick-btn.pick-on-lock .lock-switch-track{ background:var(--gold); border-color:var(--gold); }
.pick-btn.pick-on-lock .lock-switch-thumb{ transform:translateX(13px); }
/* Name highlight, not a row tint (2026-10-05, per Tony, replacing the
   previous round's whole-row version: "Im ok without the row
   highlighting for this. Maybe just highlight the star and the player
   name? Lock can be gold, pool can be the same highlight color of the
   sport, and exclude maybe a small strike through the name" -- frees up
   red/green on the row itself for the salary-fit tint below, which
   needed it more). */
.pool-name-cell.pick-name-lock strong{ color:var(--gold-bright); }
.pool-name-cell.pick-name-pool strong{ color:var(--sport-accent); }
.pool-name-cell.pick-name-exclude strong{ color:var(--text-faint); text-decoration:line-through; }
/* Salary-fit row tint, single-lineup editing only (2026-10-05, per Tony:
   "We're missing a piece from our NFL lineup builder... it will show in
   the player pool, those who will and won't fit within the salary. So
   it flags green when we can pick them and red when we don't" -- same
   mechanic as the live V2 NFL dashboard's activeEditSlot row coloring). */
.lineup-table tbody tr.afford-fit{ background:var(--green-wash); }
.lineup-table tbody tr.afford-over{ background:var(--red-wash); }
/* Wrong position type for the armed slot (2026-10-06 v2, per Tony:
   "Forcing it either with the same 'type' so in NFL i couldn't click a
   WR in a RB spot") -- dimmed and inert, same picking mode as above. */
.lineup-table tbody tr.pick-ineligible{ opacity:.35; }
.lineup-table tbody tr.pick-ineligible .pool-name-cell{ cursor:not-allowed; pointer-events:none; }

/* ---------- Click-to-edit FPTS cell (Player Pool's Proj column) ---------- */
.fpts-cell{ cursor:pointer; }
.fpts-cell:hover{ background:var(--panel-raised); }
.fpts-cell.fpts-edited{ background:var(--blue-wash); }
.fpts-edit-dot{ color:var(--blue); font-size:7px; vertical-align:middle; }
.fpts-edit-input{ width:100%; box-sizing:border-box; text-align:right; font-family:'IBM Plex Mono',monospace;
  font-size:12px; font-weight:600; background:var(--panel); color:var(--text); border:1px solid var(--blue);
  border-radius:4px; padding:2px 4px; }
/* 2026-10-07, per Tony: "you cant see the actual number you're changing.
   its covered by the arrows" -- the Proj column is ~64px and a generic
   input rule padded the box to 8px 10px, leaving ~23px for "26.97" under
   the spinner. While editing, the box floats over the cell at a fixed
   80px (number + arrows both visible), right-aligned to the cell, so the
   table never reflows when you click in or out. */
#tProj td.fpts-cell.fpts-editing{ position:relative; }
#tProj td.fpts-cell.fpts-editing .fpts-edit-input{ position:absolute; right:4px; top:50%; transform:translateY(-50%);
  width:80px; z-index:2; padding:3px 4px; font-size:12px; box-shadow:0 2px 8px rgba(0,0,0,.35); }

/* ---------- Player Pool: Opp (Rank), Stack, Lev, columns editor (2026-10-03) ---------- */
.opp-rank{ font-size:10px; color:var(--text-dim); }
.opp-rank-hard{ color:var(--red); }
.opp-rank-easy{ color:var(--green); }
.stack-cb{ accent-color:var(--sport-accent); cursor:pointer; margin:0; vertical-align:middle; }
.lev-pill{ display:inline-block; min-width:30px; padding:1px 6px; border-radius:999px; font-size:11px; text-align:center;
  background:var(--line-soft); color:var(--text-dim); }
.lev-pill.lev-pos{ background:var(--green-wash); color:var(--green); }
.lev-pill.lev-neg{ background:var(--red-wash); color:var(--red); }
/* Extra columns widen the table so .pool-scroll scrolls sideways instead
   of squeezing the base columns down to "…". */
#tProj.pool-wide{ width:max-content; min-width:100%; }
.col-editor{ position:relative; display:inline-block; }
.col-editor-menu{ position:absolute; top:calc(100% + 6px); left:10px; z-index:30; width:220px; max-height:360px; overflow-y:auto;
  background:var(--panel-raised); border:1px solid var(--line); border-radius:var(--radius-md); padding:8px 10px;
  box-shadow:0 10px 28px rgba(0,0,0,.35); }
.col-editor-sec{ font-size:10px; letter-spacing:.06em; text-transform:uppercase; color:var(--text-faint); margin:6px 0 4px; }
.col-editor-sec:first-child{ margin-top:0; }
.col-editor-opt{ display:flex; align-items:center; gap:8px; font-size:12px; color:var(--text); padding:3px 2px; cursor:pointer; }
.col-editor-opt input{ accent-color:var(--sport-accent); margin:0; }
.col-editor-reset{ margin-top:8px; width:100%; background:transparent; border:1px solid var(--line); border-radius:var(--radius-sm);
  color:var(--text-dim); font-size:11px; padding:5px 0; cursor:pointer; }
.col-editor-reset:hover{ color:var(--text); border-color:var(--text-faint); }

/* ---------- Position Rule Set (Lineups build panel, NFL) ---------- */
.rules-toggle{ display:flex; align-items:center; gap:10px; width:100%; background:transparent; border:1px solid var(--line);
  border-radius:var(--radius-sm); padding:8px 10px; cursor:pointer; color:var(--text); text-align:left; }
.rules-toggle:hover{ border-color:var(--gold-dim); }
.rules-summary{ font-size:11px; color:var(--text-faint); flex:1; }
.rules-chevron{ color:var(--text-faint); font-size:11px; }
#lbRulesBody{ border:1px solid var(--line); border-top:none; border-radius:0 0 var(--radius-sm) var(--radius-sm); padding:10px; }
.rules-toggle[aria-expanded="true"]{ border-radius:var(--radius-sm) var(--radius-sm) 0 0; }
.rule-row{ display:flex; flex-wrap:wrap; align-items:center; gap:6px; padding:8px 0; border-bottom:1px solid var(--line-soft); }
.rule-row:first-child{ padding-top:0; }
.rule-row.rule-off .rule-text, .rule-row.rule-off select, .rule-row.rule-off input, .rule-row.rule-off .rule-pos{ opacity:.55; }
.rule-text{ font-size:12px; color:var(--text-dim); }
.rule-row select.num-input{ width:auto; padding:3px 6px; font-size:12px; }
.rule-row .rule-count{ width:48px; padding:3px 6px; font-size:12px; }
.rule-pos{ background:transparent; border:1px solid var(--line); border-radius:999px; color:var(--text-dim); font:600 11px 'IBM Plex Mono',monospace;
  padding:3px 9px; cursor:pointer; }
.rule-pos.active{ background:var(--sport-wash); border-color:var(--sport-accent); color:var(--sport-accent); }
.rule-remove{ margin-left:auto; background:transparent; border:none; color:var(--text-faint); font-size:16px; line-height:1; cursor:pointer; padding:0 4px; }
.rule-remove:hover{ color:var(--red); }
.pool-toolbar{ display:flex; flex-wrap:wrap; align-items:center; gap:8px; }
.pool-toolbar .col-editor-menu{ left:0; }

/* ---------- Boom / Bust arrows (Player Pool, 2026-10-03) ---------- */
.bb-nowrap{ white-space:nowrap; }
.bb-arrow{ font-size:9px; margin-left:4px; cursor:help; vertical-align:1px; }
.bb-arrow.bb-boom{ color:var(--green); }
.bb-arrow.bb-bust{ color:var(--red); }

/* ---------- Insights: Exposure & Build Tuning (2026-10-03) ---------- */
.exp-tab-n{ font-size:10px; color:var(--text-faint); margin-left:2px; }
.contest-btn.active .exp-tab-n{ color:inherit; opacity:.75; }
.exposure-scroll{ max-height:520px; overflow-y:auto; }
.exposure-scroll thead th{ position:sticky; top:0; background:var(--panel-raised); z-index:1; }
.exp-bar-cell{ white-space:nowrap; }
.exp-bar{ display:inline-block; width:110px; height:6px; border-radius:999px; background:var(--line-soft); vertical-align:middle; margin-right:8px; overflow:hidden; }
.exp-bar-fill{ height:100%; background:var(--sport-accent); border-radius:999px; }
.exp-bar-fill.over{ background:var(--red); }
.exp-pct{ font-size:12px; display:inline-block; width:38px; text-align:right; }
.exp-pct.over{ color:var(--red); }
.exp-max-input{ width:52px; padding:3px 6px; font-size:12px; text-align:right; }
.exp-max-input.set{ border-color:var(--sport-accent); color:var(--sport-accent); }
.exp-foot{ display:flex; align-items:center; gap:10px; margin-top:8px; min-height:28px; }
.exp-foot .mono{ font-size:11px; color:var(--text-dim); }

/* Edited FPTS read blue, not the normal gold (2026-10-03, per Tony: "the
   color of the text when we manually change FPTS... is the same gold as
   it normally shows"). */
#tProj td.fpts-cell.fpts-edited, #tProj td.fpts-cell.fpts-edited strong{ color:var(--blue); }
#tExposure{ table-layout:fixed; width:100%; }
#tExposure td:first-child{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.exp-layout:not([hidden]){ display:grid; grid-template-columns:minmax(0, 1fr) 320px; gap:20px; align-items:start; }
.exp-games{ border:1px solid var(--line); border-radius:var(--radius-md); padding:12px 14px; background:var(--panel-raised); max-height:600px; overflow-y:auto; }
.exp-game-row{ display:grid; grid-template-columns:96px 1fr 70px; align-items:center; gap:8px; padding:5px 0; font-size:12px; }
.exp-game-row .exp-bar{ width:100%; margin:0; }
.exp-game-name{ white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.exp-game-n{ text-align:right; font-size:11px; }
@media (max-width: 900px){ .exp-layout:not([hidden]){ grid-template-columns:1fr; } }
.exp-new{ display:inline-block; font-size:9px; font-weight:700; letter-spacing:.04em; padding:1px 5px; border-radius:999px; background:var(--green-wash); color:var(--green); }
.exp-row-new td:first-child{ color:var(--green); }
.exp-dropped{ display:flex; flex-wrap:wrap; align-items:center; gap:6px; margin-top:8px; font-size:12px; }
.exp-dropped:empty{ display:none; }
.exp-dropped-chip{ padding:2px 8px; border:1px solid var(--line); border-radius:999px; color:var(--text-dim); text-decoration:line-through; text-decoration-color:var(--red); }
.exp-dropped-chip .dim{ text-decoration:none; }
.stack-bb{ color:var(--sport-accent); white-space:nowrap; }
.lb-cell-empty{ color:var(--text-faint); }
/* Lineup Pool cell 2nd line: the Player Pool's team/salary type (IBM Plex Mono 500), a size down (10/15). */
.lb-sub{ font:500 11px 'IBM Plex Mono',monospace; color:var(--text-dim); margin-top:1px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
/* 6px cell padding in the Lineup Pool (10/15, Tony: "most salaries are spilling onto a second line making each
   player 4 lines"): with 10px, a 9-slot classic row left ~82px per cell, under the ~95px a bold 16-letter name
   or the 79px "$7,500 · BUF" line needs. The salary line never wraps (ellipsis, salary first so it survives);
   long names still may. */
#tLineups td.lb-cell{ padding:6px; }
#tLineups td.num, #tLineups th.num{ padding-left:6px; padding-right:6px; }
.lb-cell-empty .lb-sub{ color:var(--text-faint); }

/* Inactives panels (Home tab): each of the three cards scrolls its own
   list instead of stretching the page into one massive column -- same
   reasoning as .pool-scroll on the Player Pool. */
.inactives-scroll{ max-height:320px; overflow-y:auto; padding-right:4px; }
.pcard-hist{ width:100%; height:150px; display:block; background:var(--panel-raised); border:1px solid var(--line); border-radius:var(--radius-sm); }
.pcard-hist-bar{ fill:var(--accent, #5b8dd9); opacity:.75; }
.pcard-hist-bar:hover{ opacity:1; }
.pcard-hist-line{ stroke-width:1.5; stroke-dasharray:4 3; }
.pcard-hist-line.m-floor{ stroke:var(--text-faint); }
.pcard-hist-line.m-proj{ stroke:var(--text); stroke-dasharray:none; }
.pcard-hist-line.m-ceil{ stroke:var(--good, #3fb97c); }
.pcard-hist-mark{ font-size:9px; fill:var(--text-faint); }
.pcard-hist-mark.m-proj{ fill:var(--text); }
.pcard-hist-mark.m-ceil{ fill:var(--good, #3fb97c); }
.pcard-hist-tick{ font-size:8.5px; fill:var(--text-faint); }
.pcard-hist-bar.zone-boom{ fill:var(--good, #3fb97c); }
.pcard-hist-bar.zone-bust{ opacity:.35; }
.ph-range{ fill:var(--accent, #5b8dd9); opacity:.3; }
.ph-proj{ stroke:var(--text); stroke-width:2; }
.ph-grid{ stroke:var(--line); stroke-width:1; }
.ph-act.ph-hit{ fill:var(--good, #3fb97c); }
.ph-act.ph-mid{ fill:var(--text-faint); }
.ph-act.ph-miss{ fill:var(--bad, #d9534f); }
.pcard-weeks{ display:flex; flex-wrap:wrap; gap:6px; margin-bottom:10px; }
.pcard-weeks .contest-btn{ min-width:46px; }
.pool-stat-tile .v.ph-hit{ color:var(--good, #3fb97c); }
.pool-stat-tile .v.ph-miss{ color:var(--bad, #d9534f); }
.pcard-hist-act{ stroke-width:2.5; }
.pcard-hist-act.ph-hit{ stroke:var(--good, #3fb97c); }
.pcard-hist-act.ph-mid{ stroke:var(--text-dim); }
.pcard-hist-act.ph-miss{ stroke:var(--bad, #d9534f); }
.pcard-hist-actlab{ font-size:10px; font-weight:700; paint-order:stroke; stroke:var(--panel-raised); stroke-width:3px; }
.pcard-hist-actlab.ph-hit{ fill:var(--good, #3fb97c); }
.pcard-hist-actlab.ph-mid{ fill:var(--text-dim); }
.pcard-hist-actlab.ph-miss{ fill:var(--bad, #d9534f); }
.ph-col{ cursor:pointer; }
.ph-hitarea{ fill:transparent; }
.ph-col:hover .ph-hitarea{ fill:var(--text-faint); fill-opacity:.08; }
.ph-col.ph-sel .ph-hitarea{ fill:var(--sport-accent, var(--gold)); fill-opacity:.09; }
/* Player card layout "Headline" (2026-10-21, Tony's pick of three mockups):
   headline projection + range gauge + salary-multiple split bar + histogram
   + sim stat tiles, with the game log and projection history as fold-outs. */
.pcard-hero{ display:flex; align-items:flex-start; justify-content:space-between; gap:16px; margin-bottom:6px; padding-right:26px; }
.pcard-id{ display:flex; gap:12px; align-items:center; min-width:0; }
.pcard-who{ min-width:0; }
.pcard-meta{ font-size:12px; color:var(--text-dim); margin-top:5px; display:flex; flex-wrap:wrap; gap:4px 10px; align-items:center; }
.pcard-meta b{ color:var(--text); font-weight:600; }
.pcard-pos{ display:inline-block; font:600 10px 'IBM Plex Mono',monospace; letter-spacing:.04em; padding:2px 7px; border-radius:4px; border:1px solid currentColor; line-height:1.3; color:var(--text-dim); }
.pcard-pos.pos-QB{ color:var(--gold); } .pcard-pos.pos-RB{ color:var(--green); } .pcard-pos.pos-WR{ color:var(--blue); } .pcard-pos.pos-TE{ color:var(--purple); }
.pcard-num{ text-align:right; flex:0 0 auto; }
.pcard-num .v{ font-size:38px; font-weight:700; line-height:1; letter-spacing:-.02em; font-variant-numeric:tabular-nums; }
.pcard-num .l{ font-size:9.5px; color:var(--text-faint); text-transform:uppercase; letter-spacing:.06em; margin-top:3px; }
.pcard-flags{ margin:2px 0 6px; }
.pcard-gauge{ margin:6px 0 8px; }
.pcard-gauge .g-row{ position:relative; height:15px; font-size:9.5px; color:var(--text-dim); }
.pcard-gauge .g-lab{ position:absolute; top:0; white-space:nowrap; line-height:15px; }
.pcard-gauge .g-before{ padding-right:5px; }
.pcard-gauge .g-after{ padding-left:5px; }
.pcard-gauge .g-mid{ transform:translateX(-50%); color:var(--gold); font-family:'IBM Plex Mono',monospace; }
.pcard-gauge .g-mid b{ font-weight:600; }
.pcard-gauge .g-track{ position:relative; height:10px; border-radius:5px; background:var(--panel-raised); border:1px solid var(--line); margin:2px 0; }
.pcard-gauge .g-band{ position:absolute; top:0; bottom:0; background:var(--accent, #5b8dd9); opacity:.55; border-radius:5px; }
.pcard-gauge .g-tick{ position:absolute; top:-4px; bottom:-4px; width:2.5px; transform:translateX(-50%); background:var(--text); border-radius:1px; }
.pcard-gauge .g-tick.g-mult{ top:-2px; bottom:-2px; width:1.5px; background:var(--gold); }
.pcard-split{ margin:0 0 4px; }
.pcard-splitbar{ display:flex; height:16px; border-radius:4px; overflow:hidden; border:1px solid var(--line); background:var(--panel-raised); }
.pcard-splitbar span{ display:flex; align-items:center; justify-content:center; font:600 9.5px 'IBM Plex Mono',monospace; overflow:hidden; white-space:nowrap; min-width:0; flex:0 0 auto; }
.pcard-splitbar .s-u3{ background:var(--red-wash); color:var(--red); }
.pcard-splitbar .s-mid{ color:var(--text-faint); }
.pcard-splitbar .s-x4{ background:var(--green-wash); color:var(--green); }
.pcard-legend{ display:grid; grid-template-columns:repeat(3, minmax(0, 1fr)); gap:8px; margin-top:8px; }
.pcard-leg{ border:1px solid var(--line); border-radius:var(--radius-sm); padding:7px 10px; cursor:help; display:flex; justify-content:space-between; align-items:baseline; gap:6px; min-width:0; }
.pcard-leg .l{ font-size:10.5px; color:var(--text-dim); white-space:nowrap; }
.pcard-leg .v{ font-size:15px; font-weight:700; font-variant-numeric:tabular-nums; }
.pcard-leg .v.ph-hit{ color:var(--good, #3fb97c); }
.pcard-leg .v.ph-miss{ color:var(--bad, #d9534f); }
.pcard-leg.ph-hit{ border-color:rgba(63,185,124,.45); }
.pcard-leg.ph-miss{ border-color:rgba(217,83,79,.45); }
.pcard-hist-mult{ stroke:var(--gold); stroke-width:1.2; stroke-dasharray:2 3; }
.pcard-hist-multlab{ font:600 9px 'IBM Plex Mono',monospace; fill:var(--gold); paint-order:stroke; stroke:var(--panel-raised); stroke-width:3px; }
.pcard-simgrid{ display:grid; grid-template-columns:repeat(auto-fit, minmax(150px, 1fr)); gap:8px; }
.pcard-stile{ background:var(--panel-raised); border:1px solid var(--line); border-radius:var(--radius-sm); padding:8px 10px; min-width:0; }
.pcard-stile .l{ font-size:9.5px; color:var(--text-faint); text-transform:uppercase; letter-spacing:.05em; }
.pcard-stile .v{ font-size:20px; font-weight:700; line-height:1.15; margin-top:2px; font-variant-numeric:tabular-nums; }
.pcard-stile .v small{ font-size:10px; font-weight:500; color:var(--text-faint); margin-left:4px; }
.pcard-stile .q{ display:grid; grid-template-columns:repeat(4, 1fr); gap:2px; margin-top:6px; font-size:10.5px; color:var(--text-dim); font-variant-numeric:tabular-nums; }
.pcard-stile .q i{ display:block; font-style:normal; font-size:8.5px; color:var(--text-faint); text-transform:uppercase; letter-spacing:.04em; }
.pcard-rates{ display:flex; flex-wrap:wrap; gap:6px; margin-top:8px; }
.pcard-rate{ font-size:11.5px; color:var(--text-dim); border:1px solid var(--line); border-radius:20px; padding:3px 10px; cursor:help; }
.pcard-rate b{ color:var(--text); font-variant-numeric:tabular-nums; margin-left:4px; }
.pcard-fold{ border-top:1px solid var(--line); margin-top:12px; padding-top:2px; }
.pcard-fold summary{ cursor:pointer; list-style:none; display:flex; align-items:center; gap:8px; padding:8px 0; font-size:12.5px; font-weight:700; }
.pcard-fold summary::-webkit-details-marker{ display:none; }
.pcard-fold summary::before{ content:''; width:6px; height:6px; border-right:1.5px solid var(--text-faint); border-bottom:1.5px solid var(--text-faint); transform:rotate(-45deg); transition:transform .15s; flex:0 0 auto; }
.pcard-fold[open] summary::before{ transform:rotate(45deg); }
.pcard-fold summary span{ font-size:10px; font-weight:500; color:var(--text-faint); text-transform:uppercase; letter-spacing:.06em; }
@media (prefers-reduced-motion: reduce){ .pcard-fold summary::before{ transition:none; } }
@media (max-width:560px){ .pcard-num .v{ font-size:30px; } .pcard-legend{ grid-template-columns:1fr; } .pcard-gauge .g-mid b{ display:none; } }

/* Lineups tab top row: Build panel + Data panel. Same 1.3/1 split and gap as
   .panel-row below so both rows share one column edge, and the Build row's
   first line (Contest/Lineups/Salary/Unique/Double TE) fits at 1920 wide.
   Stacks under 1100px, same as .panel-row. */
.lb-top{ display:grid; grid-template-columns:minmax(0, 1.3fr) minmax(0, 1fr); gap:18px; margin-bottom:22px; }
.lb-top > *{ min-width:0; }
@media (max-width:1100px){ .lb-top{ grid-template-columns:1fr; } }

/* ---------- section headings (homepage + My Results) ---------- */
.sec-head{ display:flex; align-items:flex-end; justify-content:space-between; gap:16px; margin-bottom:18px; flex-wrap:wrap; }
.sec-head .eyebrow, .eyebrow{ font:600 11px 'IBM Plex Mono',monospace; color:var(--gold); letter-spacing:.12em; text-transform:uppercase; }
.sec-head h2{ font-size:26px; margin:6px 0 0; letter-spacing:-.01em; }
.sec-head p{ color:var(--text-dim); margin:6px 0 0; max-width:640px; line-height:1.55; }
.sec-head a{ color:var(--gold-bright); font-size:13px; font-weight:600; text-decoration:none; }
.page-head{ margin:10px 0 18px; }
.page-head h1{ font-size:26px; margin:0 0 6px; }
.page-head p{ color:var(--text-dim); margin:0; font-size:14px; }

/* ---------- My Results + track record (sports/assets/results.js) ----------
   Same markup on /sports#results and every sport page's My Results tab.
   Order: track record first, then your record, then the explainer. */
.res-head{ display:flex; align-items:flex-end; justify-content:space-between; gap:16px; flex-wrap:wrap; }
.res-head .res-all{ font-weight:600; font-size:13px; text-decoration:none; white-space:nowrap; }
.res-mine-head{ margin-top:30px; }
.res-form{ display:grid; gap:10px; }
.res-form .row{ display:grid; grid-template-columns:repeat(4, minmax(0, 1fr)); gap:10px; }
.res-form .row > *{ min-width:0; }
.res-form .rf-wide{ grid-column:span 2; }
.res-form input, .res-form select, .res-form .btn{ width:100%; }
.res-form .res-status{ font-size:12px; }
.res-form .res-status:empty{ display:none; }
/* Five fixed tracks: auto-fill left empty tracks to the right of ROI. */
.res-tiles{ display:grid; grid-template-columns:repeat(5, minmax(0, 1fr)); gap:12px; margin-bottom:16px; }
.res-pair{ margin-bottom:16px; }
/* Nothing logged yet: one card (copy | form) instead of empty tiles + tables. */
.res-first{ display:grid; grid-template-columns:minmax(240px, 1fr) minmax(0, 2fr); gap:28px; align-items:center; }
.res-first.no-form{ display:block; }
.res-first .rf-copy h2{ margin:0 0 6px; }
.res-first .rf-copy .sub{ margin:0; }
.res-explain{ margin-top:30px; }
.res-explain .sub{ margin:10px 0 0; }
/* Rows of 3 (admins: every sport), the public pair side by side, or one
   wide stat strip on a sport's own tab. */
.record-grid{ display:grid; grid-template-columns:repeat(3, minmax(0, 1fr)); gap:14px; }
.record-grid.is-pair{ grid-template-columns:repeat(2, minmax(0, 1fr)); }
.record-grid.is-one{ grid-template-columns:minmax(0, 1fr); }
.record-card{ border-color:color-mix(in srgb, var(--sport-accent) 28%, var(--line)) !important; text-decoration:none; color:var(--text); }
.record-card .rc-top{ display:flex; justify-content:space-between; align-items:center; }
.record-card .rc-league{ font-weight:700; font-size:20px; display:flex; align-items:center; }
.record-card .rc-badges{ display:flex; gap:6px; align-items:center; }
.record-card .rc-private{ background:transparent; border:1px dashed var(--line); color:var(--text-faint); }
.record-card .kv{ display:grid; grid-template-columns:repeat(3, minmax(0, 1fr)); gap:12px 10px; margin-top:14px; }
.record-grid.is-one .kv{ grid-template-columns:repeat(6, minmax(0, 1fr)); }
.record-card .kv .l{ font-size:10px; color:var(--text-faint); text-transform:uppercase; letter-spacing:.06em; }
.record-card .kv .v{ font:600 18px 'IBM Plex Mono',monospace; margin-top:2px; }
.record-card .rc-foot{ margin:12px 0 0; }
.record-card .rc-link{ display:inline-block; margin-top:10px; font-weight:600; font-size:13px; text-decoration:none; }
@media (max-width:1100px){
  .record-grid{ grid-template-columns:repeat(2, minmax(0, 1fr)); }
  .res-tiles{ grid-template-columns:repeat(3, minmax(0, 1fr)); }
}
@media (max-width:900px){
  .record-grid.is-one .kv{ grid-template-columns:repeat(3, minmax(0, 1fr)); }
  .res-first{ grid-template-columns:1fr; gap:14px; }
}
@media (max-width:760px){
  .record-grid, .record-grid.is-pair{ grid-template-columns:1fr; }
  .res-tiles{ grid-template-columns:repeat(2, minmax(0, 1fr)); }
  .res-form .row{ grid-template-columns:repeat(2, minmax(0, 1fr)); }
}
