
:root{
  color-scheme: dark;
  --ink-rgb: 255,255,255;
  --hero-fade-rgb: 10,11,13;
  --cta-bg: var(--accent-fill);
  --cta-border: transparent;
  --cta-color: var(--on-accent);
  --star-idle: var(--text-mute);
  --card-yellow: var(--accent-fill);
  --card-ring: transparent;
  --star-on: var(--accent);
  --hero-shadow: 0 10px 22px rgba(0,0,0,0.5);
  --bar-bg: rgba(19,20,24,0.82);
  --seg-track: rgba(var(--ink-rgb),0.06);
  --seg-thumb: rgba(var(--ink-rgb),0.13);
  --seg-thumb-shadow: 0 1px 2px rgba(0,0,0,0.35);
  --bg: #0A0B0D;
  --surface: #16171B;
  --surface-2: #1C1D21;
  --sheet: #18191D;
  --text: #F3F4F6;
  --text-sub: #94969E;
  --text-mute: #64666E;
  --hairline: rgba(var(--ink-rgb),0.07);
  --hairline-strong: rgba(var(--ink-rgb),0.14);
  --accent: #D9B45B;
  --accent-fill: #D9B45B;
  --accent-soft: rgba(217,180,91,0.14);
  --tab-pill: rgba(217,180,91,0.16);
  --accent-border: rgba(217,180,91,0.35);
  --win: #5FB88A;
  --win-soft: rgba(95,184,138,0.14);
  --loss: #D97066;
  --loss-soft: rgba(217,112,102,0.14);
  --draw: #B8A369;
  --draw-soft: rgba(184,163,105,0.16);
  --live: #E5484D;
  --provisional: #7C9CD9;
  --provisional-soft: rgba(124,156,217,0.16);
  --provisional-border: rgba(124,156,217,0.38);
  /* Leaderboard-only (js/overall.js, css below) — a few extra ink/rank
     tiers the design_handoff_leaderboard spec calls for that don't map
     onto an existing token above without either flattening a
     distinction the design deliberately makes (leader vs. non-leader
     total ink; rank 2-3 vs. rank 4+) or reusing a token at the wrong
     opacity (the rank-1 row wash is a much fainter accent than
     --accent-soft, which is already spoken for elsewhere). */
  --lb-ink-strong: #FFFFFF;
  --lb-ink-2: #E6E7EB;
  --lb-ink-3: #C7C9D1;
  --lb-gap: #8E9098;
  --lb-rank-mid: #9C9EA6;
  --lb-rank-low: #5E6068;
  --lb-stroke: #4A4C54;
  --lb-divider: rgba(var(--ink-rgb),0.05);
  --lb-accent-wash: rgba(217,180,91,0.07);
  --lb-accent-wash-border: rgba(217,180,91,0.30);
  --record: #9AA5B5;
  --record-soft: rgba(154,165,181,0.16);
  --badge-surface: #E9E6DE;
  --nav-h: 58px;
  /* Body's own horizontal padding — pulled into a variable so
     .standings-filter-row (see below) can bleed its sticky background
     out to the real screen edges instead of stopping at this inset,
     and stay in sync with the narrower value the max-width:700px
     breakpoint below swaps in, without restating body's own rule
     there. */
  --page-pad: 24px;
}

/* Appearance setting (js/settings.js): data-theme="light" forces light,
   "dark" forces dark, and "auto" (no attribute rule) follows the OS. The
   token list is written twice because CSS can't share one rule between a
   selector and a media query. */
:root[data-theme="light"]{
  color-scheme: light;
  --ink-rgb: 20,22,28;
  --hero-fade-rgb: 244,243,239;
  --cta-bg: var(--accent-fill);
  --cta-border: transparent;
  --cta-color: #16171B;
  --star-idle: #7C7E87;
  --card-yellow: #F2C315;
  --card-ring: rgba(20,22,28,0.18);
  --star-on: #D9A20F;
  --hero-shadow: 0 8px 18px rgba(20,22,28,0.22);
  --bar-bg: rgba(250,250,248,0.85);
  --seg-thumb: #FFFFFF;
  --seg-thumb-shadow: 0 1px 3px rgba(20,22,28,0.16), 0 0 0 0.5px rgba(20,22,28,0.06);
  --bg: #F4F3EF;
  --surface: #FFFFFF;
  --surface-2: #ECEAE4;
  --sheet: #FFFFFF;
  --text: #16171B;
  --text-sub: #5B5D66;
  --text-mute: #8A8C94;
  --accent: #85660C;
  --accent-fill: #E2B84A;
  --accent-soft: rgba(154,119,22,0.12);
  --tab-pill: rgba(154,119,22,0.16);
  --accent-border: rgba(154,119,22,0.4);
  --win: #2E8A5C;
  --win-soft: rgba(46,138,92,0.12);
  --loss: #C2453B;
  --loss-soft: rgba(194,69,59,0.12);
  --draw: #8A7430;
  --draw-soft: rgba(138,116,48,0.14);
  --provisional: #4A6FB8;
  --provisional-soft: rgba(74,111,184,0.12);
  --provisional-border: rgba(74,111,184,0.38);
  --lb-ink-strong: #0B0C0F;
  --lb-ink-2: #22242A;
  --lb-ink-3: #3F414A;
  --lb-gap: #6B6D76;
  --lb-rank-mid: #6B6D76;
  --lb-rank-low: #9A9CA4;
  --lb-stroke: #C9C7BF;
  --lb-accent-wash: rgba(154,119,22,0.07);
  --lb-accent-wash-border: rgba(154,119,22,0.30);
  --record: #56617A;
  --record-soft: rgba(86,97,122,0.12);
}
@media (prefers-color-scheme: light){
  :root[data-theme="auto"]{
    color-scheme: light;
  --ink-rgb: 20,22,28;
  --hero-fade-rgb: 244,243,239;
  --cta-bg: var(--accent-fill);
  --cta-border: transparent;
  --cta-color: #16171B;
  --star-idle: #7C7E87;
  --card-yellow: #F2C315;
  --card-ring: rgba(20,22,28,0.18);
  --star-on: #D9A20F;
  --hero-shadow: 0 8px 18px rgba(20,22,28,0.22);
  --bar-bg: rgba(250,250,248,0.85);
  --seg-thumb: #FFFFFF;
  --seg-thumb-shadow: 0 1px 3px rgba(20,22,28,0.16), 0 0 0 0.5px rgba(20,22,28,0.06);
  --bg: #F4F3EF;
  --surface: #FFFFFF;
  --surface-2: #ECEAE4;
  --sheet: #FFFFFF;
  --text: #16171B;
  --text-sub: #5B5D66;
  --text-mute: #8A8C94;
  --accent: #85660C;
  --accent-fill: #E2B84A;
  --accent-soft: rgba(154,119,22,0.12);
  --tab-pill: rgba(154,119,22,0.16);
  --accent-border: rgba(154,119,22,0.4);
  --win: #2E8A5C;
  --win-soft: rgba(46,138,92,0.12);
  --loss: #C2453B;
  --loss-soft: rgba(194,69,59,0.12);
  --draw: #8A7430;
  --draw-soft: rgba(138,116,48,0.14);
  --provisional: #4A6FB8;
  --provisional-soft: rgba(74,111,184,0.12);
  --provisional-border: rgba(74,111,184,0.38);
  --lb-ink-strong: #0B0C0F;
  --lb-ink-2: #22242A;
  --lb-ink-3: #3F414A;
  --lb-gap: #6B6D76;
  --lb-rank-mid: #6B6D76;
  --lb-rank-low: #9A9CA4;
  --lb-stroke: #C9C7BF;
  --lb-accent-wash: rgba(154,119,22,0.07);
  --lb-accent-wash-border: rgba(154,119,22,0.30);
  --record: #56617A;
  --record-soft: rgba(86,97,122,0.12);
  }
}

*{ box-sizing: border-box; margin:0; padding:0; -webkit-tap-highlight-color: transparent; }

html{ background: var(--bg); }

/* This app runs as an installed iOS PWA with a translucent status bar
   (apple-mobile-web-app-status-bar-style: black-translucent, in
   index.html) — the notch/status-bar strip is real page content, not
   opaque OS chrome, so anything that scrolls to the top of the
   document is visible right through it. body's own top padding
   (env(safe-area-inset-top), below) normally keeps content clear of
   that strip, but .standings-filter-row's sticky positioning
   (top: env(safe-area-inset-top), further down this file) leaves that
   exact strip briefly unmanaged during iOS's scroll-repaint of a
   sticky element — a stale row from just before it can flash through
   for a frame. A `position: fixed` cover can't be affected by that
   scroll-repaint at all (it isn't part of the scrolling layer), so it
   guarantees that strip always shows solid background regardless of
   what the sticky element underneath is doing mid-scroll. */
/* ==== Design tokens: scales (UI consistency pass) ====
   New rules should reach for these instead of literal values. Existing
   rules migrate over incrementally. */
:root{
  --font-display: 'Space Grotesk', sans-serif;
  --font-ui: 'Manrope', sans-serif;
  --fs-10: 10px; --fs-11: 11px; --fs-12: 12px; --fs-13: 13px; --fs-15: 15px;
  --fs-17: 17px; --fs-20: 20px; --fs-24: 24px; --fs-30: 30px;
  --track-tight: -0.02em; --track-snug: -0.01em;
  --track-tag: 0.06em; --track-label: 0.08em;
  --r-xs: 6px; --r-sm: 10px; --r-md: 14px; --r-lg: 20px; --r-sheet: 28px; --r-pill: 999px;
  --s-1: 4px; --s-2: 8px; --s-3: 12px; --s-4: 16px; --s-5: 20px; --s-6: 24px;
  --dur-press: 120ms; --dur-ui: 200ms; --dur-move: 320ms;
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  /* iOS's own sheet curve: fast out, long settle, no overshoot (a bottom
     sheet that overshoots lifts off the bottom edge). SHEET_EASE in
     js/utils.js mirrors it. */
  --ease-sheet: cubic-bezier(0.32, 0.72, 0, 1);
  --live-stripe: repeating-linear-gradient(135deg, var(--provisional) 0 3px, var(--provisional-soft) 3px 6px);
  --risk-stripe: repeating-linear-gradient(135deg, var(--loss) 0 3px, color-mix(in srgb, var(--loss) 35%, transparent) 3px 6px);
  --text-strong: #FFFFFF;
  --on-accent: #0A0B0D;
  --hover: rgba(var(--ink-rgb), 0.04);
  --press: rgba(var(--ink-rgb), 0.07);
  --live-soft: rgba(229, 72, 77, 0.12);
  --live-border: rgba(229, 72, 77, 0.36);
  --focus-ring: 0 0 0 2px var(--bg), 0 0 0 4px var(--accent);
}
[data-theme="light"]{
  --text-strong: #0B0C0F;
  --on-accent: #16171B;
  --live-soft: rgba(229, 72, 77, 0.10);
}
@media (prefers-color-scheme: light){
  :root[data-theme="auto"]{
    --text-strong: #0B0C0F;
    --on-accent: #16171B;
    --live-soft: rgba(229, 72, 77, 0.10);
  }
}

.safe-area-top{
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: env(safe-area-inset-top);
  background: var(--bg);
  z-index: 1000;
  pointer-events: none;
}

body{
  background: var(--bg);
  color: var(--text);
  font-family: 'Manrope', sans-serif;
  padding: calc(env(safe-area-inset-top) + var(--page-pad)) var(--page-pad) calc(var(--nav-h) + var(--page-pad) + env(safe-area-inset-bottom));
  min-height: 100vh;
  overscroll-behavior-y: contain;
}

.board{
  max-width: 1400px;
  margin: 0 auto;
}

.page-header{
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding-bottom: 14px;
}

.page-header-top{
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  row-gap: 8px;
}

.app-logo-link{
  flex: 0 0 36px;
  display: block;
  cursor: pointer;
}

.app-logo{
  flex: 0 0 36px;
  width: 36px;
  height: 36px;
  border-radius: 11px;
  display: block;
}

.page-header h1{
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: var(--fs-30);
  letter-spacing: -0.5px;
  line-height: 1;
}

.page-sub{
  font-size: var(--fs-13);
  color: var(--text-sub);
  font-weight: 500;
}

/* Ghost button — invisible fill until touched. Sits in .page-header-top right before the identity
   circle (js/identity.js): margin-left:auto pushes this chip (and the
   circle after it) to the row's right edge as one cluster; the sibling
   rule below cancels .picker-hit's OWN margin-left:auto so the two
   don't each grab their own share of the leftover space and end up
   pushed apart instead of clustered together. */
.scope-chip{
  flex: 0 0 auto;
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 5px;
  font-family: 'Manrope', sans-serif;
  font-size: var(--fs-12);
  font-weight: 700;
  color: var(--text-sub);
  background: transparent;
  border: none;
  border-radius: 8px;
  padding: 6px 9px;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}

.scope-chip:hover{ background: var(--surface-2); color: var(--accent); }

.scope-chip svg{ width: 12px; height: 12px; }

/* When the scope chip precedes it (Scores tab only — see index.html),
   .picker-hit gives up its own margin-left:auto so the chip's auto
   margin is the only one absorbing space; otherwise flexbox splits the
   leftover space between both auto margins and pushes the two apart
   instead of clustering them. Every other tab has no .scope-chip, so
   .picker-hit's default margin-left:auto (above) still applies there. */
.scope-chip + .picker-hit{ margin-left: 0; }

/* Settings control (js/identity.js, js/settings.js) — an outline-only gear,
   idle/hover language borrowed from .modal-close below (transparent
   until touched, a faint surface tint on hover) rather than a filled,
   colored badge, so it reads as a quiet corner control rather than a
   decoration competing with real team crests. Present in every view's
   header now (not just Teams', like the old <select> picker this
   replaced), opening the switcher sheet (#identity-sheet-overlay in
   index.html) instead of a native dropdown, since the sheet needs to
   show full names + which one is currently active — more than a
   dropdown option list can carry on its own. */
.picker-hit{
  flex: 0 0 auto;
  margin-left: auto;
  display: flex;
  align-items: center;
  background: none;
  border: none;
  cursor: pointer;
  padding: 3px;
  border-radius: 999px;
}

.settings-icon{
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  color: var(--text-sub);
  transition: color 0.15s ease, background 0.15s ease;
}

.settings-icon svg{ width: 20px; height: 20px; }

.picker-hit:hover .settings-icon{
  background: rgba(var(--ink-rgb),0.06);
  color: var(--text);
}

/* The one unread-count pill: the tab bar's chat badge and the Points
   tab's Activity segment (segmentedControlHtml's `badge`) both use it. */
.count-badge{
  display: inline-block;
  box-sizing: border-box;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: 8px;
  background: var(--live);
  color: #fff;
  font-family: 'Space Grotesk', sans-serif;
  font-size: var(--fs-10);
  font-weight: 700;
  line-height: 16px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

/* Chat entry point (js/chat.js) — the center button in the tab bar
   (.tab-btn.chat-hit, see .tab-bar below). The badge hangs off the icon's
   top-right corner via .tab-icon, not off the full-width button. */
.chat-badge{
  display: none;
  position: absolute;
  top: -6px;
  right: 4px;
  box-shadow: 0 0 0 2px var(--bg);
}
.chat-badge.show{ display: block; }

/* Shown under a view's header while it's displaying someone else's
   board via a ?team= link (a "peek" — see setDraftTeam's comment in
   js/board.js) rather than your own. Reuses .prior-season-note's
   accent-callout language below so it reads as "worth noticing" without
   implying an error. */
.peek-banner{
  display: none;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  background: var(--accent-soft);
  border: 1px solid var(--accent-border);
  border-radius: 10px;
  padding: 10px 12px;
  margin-bottom: 14px;
  font-size: var(--fs-13);
  font-weight: 600;
  color: var(--accent);
}

.peek-banner.show{ display: flex; }

.peek-banner button{
  flex: 0 0 auto;
  min-height: 32px;
  padding: 0 12px;
  font-family: var(--font-ui);
  font-size: var(--fs-12);
  font-weight: 700;
  color: var(--on-accent);
  background: var(--accent-fill);
  border: none;
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: transform var(--dur-press) var(--ease-out);
}

/* ---- League filter chips (mobile jump-nav) ---- */
.filter-chips{
  display: flex;
  gap: 8px;
  overflow-x: auto;
  padding: 6px 2px 18px;
  scrollbar-width: none;
}

.filter-chips::-webkit-scrollbar{ display: none; }

.filter-chip{
  flex: 0 0 auto;
  font-family: 'Manrope', sans-serif;
  font-size: var(--fs-13);
  font-weight: 600;
  letter-spacing: 0.1px;
  color: var(--text-sub);
  background: var(--surface);
  border: 1px solid var(--hairline-strong);
  border-radius: 999px;
  padding: 8px 16px;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--dur-ui) var(--ease-out), border-color var(--dur-ui) var(--ease-out), color var(--dur-ui) var(--ease-out);
}

.filter-chip:active{
  background: var(--press);
  color: var(--text);
}

/* Persistent selection (Standings' league filter) rather than the
   touch feedback above — filled solid so it reads as "on" even after
   you lift your finger, not just a footprint from the last :active tap. */
/* Compact density, for a chip row that has to fit one phone width
   (Points > Activity's four filters). */
.filter-chips.sm{ gap: 6px; }
.filter-chips.sm .filter-chip{ font-size: var(--fs-12); font-weight: 700; padding: 6px 11px; }
.filter-chip.active{
  background: var(--accent-fill);
  border-color: var(--accent-fill);
  color: var(--on-accent);
}

.leagues{
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 20px;
}

.league{
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 20px;
  overflow: hidden;
  scroll-margin-top: 16px;
}

.league-tab{
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: var(--fs-15);
  letter-spacing: -0.2px;
  padding: 15px 18px;
  border-bottom: 1px solid var(--hairline);
  display:flex;
  align-items:center;
  justify-content: space-between;
}

.league-tab-left{
  display:flex;
  align-items:center;
  gap: 10px;
}

/* Standings-only header layout: the title gets its own top line (it
   can run long, e.g. "English Premier League") with the season
   right-aligned alongside it, and the prior-season note (MLB/WNBA
   only) sits on its own line below — see leagueBlockHtml in
   js/board.js. The Teams tab keeps the same title/season pairing on
   one line (see renderBoard in js/board.js) since it has nothing
   below it to stack. */
.league-tab.standings-league-tab{
  flex-direction: column;
  align-items: stretch;
  gap: 8px;
}

.league-tab-top{
  display:flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
}

.league-tab .n{
  font-family: 'Manrope', sans-serif;
  font-size: var(--fs-12);
  font-weight: 700;
  color: var(--text-sub);
  letter-spacing: normal;
}

/* MLB/WNBA-only heads-up (see PRIOR_SEASON_DISPLAY_LEAGUES in
   js/data.js): the records below are real, but they're last season's
   — drafted teams don't start scoring until '27. Boxed as a contained
   callout (same accent-soft/accent-border banner treatment as
   .ob-sim-banner) rather than bare bold text, so it reads as a
   pronounced but self-contained aside instead of shouting inline with
   the surrounding content — easy to misread as live scoring if
   skimmed. Lives as a third line inside .league-tab.standings-league-
   tab's own column/gap, and as a note above the modal body in the
   team modal. */
.prior-season-note{
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--accent-soft);
  border: 1px solid var(--accent-border);
  border-radius: 10px;
  padding: 10px 12px;
  font-size: var(--fs-12);
  font-weight: 600;
  color: var(--accent);
  line-height: 1.4;
  margin-bottom: 14px;
}

.team{
  display:flex;
  align-items:center;
  gap: 14px;
  padding: 14px 18px;
  position: relative;
  min-height: 44px;
}

.team + .team{
  border-top: 1px solid rgba(var(--ink-rgb),0.06);
}

.badge{
  position: relative;
  flex: 0 0 44px;
  width: 44px;
  height: 44px;
  display:flex;
  align-items:center;
  justify-content:center;
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: var(--fs-15);
  letter-spacing: 0.2px;
  border-radius: 13px;
  border: 1px solid rgba(var(--ink-rgb),0.14);
  overflow: hidden;
}

/* Real crests render bare — no backdrop, same as the Team Page's
   .crest-bare — with a drop-shadow standing in for contrast so a dark,
   thin-lined crest (e.g. the Padres' brown "SD", a fully transparent
   PNG with no built-in backing shape) doesn't wash into the dark page
   behind it (see teamBadgeHtml in js/utils.js). */
.badge.badge-crest{
  background: transparent;
  border-color: transparent;
}

.badge img{
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  padding: 2px;
  box-sizing: border-box;
  filter: drop-shadow(0 2px 5px rgba(0,0,0,0.55));
}

.team-name{
  font-weight: 700;
  font-size: var(--fs-17);
  line-height: 1.15;
  letter-spacing: -0.1px;
}

.team-sub{
  font-size: var(--fs-12);
  color: var(--text-sub);
  font-weight: 500;
  letter-spacing: 0.1px;
  margin-top: 1px;
}

@media (max-width: 1100px){
  .leagues{ grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 700px){
  :root{ --page-pad: 16px; }
  .leagues{ grid-template-columns: 1fr; gap: 16px; }
}

/* ---- Interactive team rows ---- */
.team.clickable{
  cursor: pointer;
  transition: background 0.15s ease;
}

.team.clickable:hover{
  background: rgba(var(--ink-rgb),0.03);
}

.team.clickable:active{
  background: rgba(var(--ink-rgb),0.05);
}

/* Deliberately not flex:1 — a growing team-main would fill the row,
   leaving the favorite star (its next sibling) stranded out by the
   status column instead of hugging the name/sub text it's actually
   marking. Shrinks instead of grows (min-width:0 lets it wrap rather
   than overflow on a long name), and .status-slot's own margin-left:
   auto still soaks up whatever space is left, keeping it pinned to
   the row's right edge either way. */
.team-main{
  flex: 0 1 auto;
  min-width: 0;
}

/* Favorite toggle (js/favorites.js) — sits between the team's own
   info and its status column. Same idle/hover language as .id-circle
   above: transparent until touched, filled gold only once favorited,
   never a background/border pill. */
.favorite-star{
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  border: none;
  background: transparent;
  border-radius: 999px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  color: var(--star-idle);
  transition: color 0.15s ease, background 0.15s ease, transform 0.15s cubic-bezier(0.34,1.56,0.64,1);
}

.favorite-star svg{ width: 18px; height: 18px; }

.favorite-star:hover{ background: rgba(var(--ink-rgb),0.06); color: var(--text-sub); }

.favorite-star.active{ color: var(--star-on); }

.favorite-star:active{ transform: scale(1.18); }

/* Read-only indicator (favoriteMarkHtml) — taps fall through to the row. */
.favorite-mark{ pointer-events: none; cursor: default; }

/* Right-hand status column: a small uppercase label over a bolder
   value (day/LIVE/FINAL over time/score) rather than a colored pill —
   see renderRowStatus in js/live-data.js. */
.status-slot{
  flex: 0 0 auto;
  margin-left: auto;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
  white-space: nowrap;
}

.meta-label{
  font-family: 'Manrope', sans-serif;
  font-size: var(--fs-10);
  font-weight: 800;
  letter-spacing: var(--track-tag);
  text-transform: uppercase;
  color: var(--text-mute);
  display: flex;
  align-items: center;
  gap: 4px;
}
.meta-label.live{ color: var(--live); }

.meta-value{
  font-family: 'Space Grotesk', sans-serif;
  font-size: var(--fs-15);
  font-weight: 700;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.meta-value.w{ color: var(--win); }
.meta-value.l{ color: var(--loss); }
.meta-value.d{ color: var(--draw); }

/* Clickable status slots (both a live game and a just-finished result
   can open Game Details — see paintStatusSlot in js/live-data.js) share
   the cursor/chevron layout, but hover differently: a live score turning
   red on hover reinforces "live", while a finished W/L/D already has its
   own result color (see .meta-value.w/.l/.d above) — underlining it
   instead reads as "clickable" without implying a color change. */
.status-slot.linkable{ cursor: pointer; }
.status-slot.linkable .meta-value{ display: flex; align-items: center; gap: 3px; }
.status-slot.linkable .chev{ color: var(--text-mute); font-size: var(--fs-12); }
.status-slot.linkable.live:hover .meta-value{ color: var(--live); }
.status-slot.linkable:not(.live):hover .meta-value{ text-decoration: underline; }

/* Small pulsing dot next to the LIVE label — the only motion on the
   board, so it's what actually reads as "in progress" at a glance. */
.dot{
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}
.dot.pulse{ animation: status-dot-pulse 1.4s ease-in-out infinite; }
@keyframes status-dot-pulse{
  0%, 100%{ opacity: 1; }
  50%{ opacity: 0.35; }
}
@media (prefers-reduced-motion: reduce){
  .dot.pulse{ animation: none; }
}

/* ---- Live Now: empty state ---- */
.empty-panel{ display:flex; flex-direction:column; align-items:center; text-align:center; gap:10px; padding: 40px 20px 26px; color: var(--text-sub); }
.empty-title{ font-family:'Space Grotesk', sans-serif; font-weight:700; font-size:var(--fs-17); color:var(--text); }
.empty-sub{ font-size:var(--fs-13); line-height:1.5; max-width:270px; }

/* ============================================================
   Today tab (js/live-now.js) — replaces the old "Live Now" game-card
   layout above.

   The layout is a single day timeline: a fixed left gutter holding the
   time (or LIVE, or F), a hairline rail with a status node on it, and
   the matchup card hung off that rail. Two teams per card, each a
   badge + name + owner + score on its own line — no center score
   column, so a long club name has the full card width instead of a
   third of it.
   ============================================================ */

/* ---- Day navigation ---- */
.tg-daynav{
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 6px 0 12px;
}

.tg-arrow{
  flex: 0 0 auto;
  border: none;
  background: none;
  color: var(--text-mute);
  font-size: var(--fs-24);
  line-height: 1;
  cursor: pointer;
  font-family: inherit;
  /* 44px hit target (see the app's own minimum) without a 44px-tall
     visual button — the chevron itself stays small and quiet. */
  padding: 11px 14px;
}

.tg-arrow:hover{ color: var(--text); }

.tg-daynav-center{
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
}

.tg-day{
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: var(--fs-17);
  letter-spacing: -0.2px;
}

.tg-date{
  font-size: var(--fs-10);
  font-weight: 800;
  letter-spacing: var(--track-tag);
  text-transform: uppercase;
  color: var(--text-mute);
}

/* Reads as "you are here on the calendar" — the only accent mark in
   the header, so arrowing away from today still looks anchored. */
.tg-day-underline{
  width: 34px;
  height: 2px;
  border-radius: 2px;
  background: var(--accent);
  margin-top: 3px;
}

/* ---- Generic sliding segmented control (js/utils.js's
   segmentedControlHtml) ----
   Shared by the Scores tab's Live/Upcoming/All and every Standings tab
   toggle (League/Drafted, Conference/Drafted, Divisions/Conference) —
   one implementation instead of N hand-rolled ports of the same
   sliding-thumb interaction. A recessed track with a raised
   thumb (iOS-style) rather than an accent fill: it reads the same in
   light and dark, and stays quieter than the gold filter chips. Segment count is arbitrary (2 for a plain
   League/Drafted toggle, 3 for e.g. NFL's AFC/NFC/Drafted) — the
   thumb's width/position are set inline per-render since this CSS has
   no fixed segment count to divide by. */
.seg{
  position: relative;
  display: flex;
  background: var(--seg-track);
  border-radius: 11px;
  padding: 3px;
  margin-bottom: 6px;
}

.seg-thumb{
  position: absolute;
  top: 3px;
  bottom: 3px;
  left: 3px;
  box-sizing: border-box;
  border-radius: 8px;
  background: var(--seg-thumb);
  box-shadow: var(--seg-thumb-shadow);
  transition: transform 0.34s cubic-bezier(0.22, 1, 0.36, 1);
}

@media (prefers-reduced-motion: reduce){
  .seg-thumb{ transition: none; }
}

.seg-btn{
  position: relative;
  flex: 1;
  border: none;
  background: none;
  padding: 6px 0;
  font-family: 'Manrope', sans-serif;
  font-size: var(--fs-13);
  font-weight: 700;
  color: var(--text-sub);
  cursor: pointer;
  min-height: 34px;
}

.seg-btn.active{ color: var(--text); }

/* Standings tab context: .seg drops into the existing
   .standings-toggle/.standings-subtoggle wrapper (which already
   supplies this card's own padding/border-bottom/nested-row rules —
   see those classes below), replacing the flex row of separate
   .toggle-btn pills that used to live directly inside it. flex:1 makes
   the control fill that row the same way the old button row did;
   margin-bottom is the wrapper's job here, not the control's own. */
.standings-toggle .seg{ flex: 1; margin-bottom: 0; }

/* ---- Section headers (Live now, then one per league) ---- */
.tg-section{ margin-bottom: 8px; }

.tg-section-head{
  display: flex;
  align-items: center;
  gap: 8px;
  /* Indented past the time gutter so the label starts where the cards
     do, not where the clock does. */
  padding: 12px 0 8px 62px;
}

.tg-section-label{
  font-family: 'Manrope', sans-serif;
  font-size: var(--fs-10);
  font-weight: 800;
  letter-spacing: var(--track-tag);
  text-transform: uppercase;
  color: var(--text);
}


.tg-section-rule{
  flex: 1;
  height: 1px;
  background: rgba(var(--ink-rgb), 0.06);
}

/* ---- One game on the rail ---- */
.tg-row{
  position: relative;
  display: grid;
  grid-template-columns: 46px minmax(0, 1fr);
  gap: 16px;
  padding: 2px 0 14px;
}

.tg-rail{
  text-align: right;
  padding-top: 2px;
}

.tg-rail-top{
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: var(--fs-13);
  letter-spacing: -0.2px;
  color: var(--text-sub);
}

.tg-rail-top.live{ color: var(--live); }

/* Scheduled time only (not live/final) — matches the blue
   .tg-node.pre dot: bigger and bolder than the quieter final/live
   labels since a scheduled game's kickoff time is this rail's whole
   point, not a secondary detail. */
.tg-rail-top.pre{
  font-size: var(--fs-15);
  color: var(--provisional);
}

.tg-rail-bot{
  font-family: 'Manrope', sans-serif;
  font-size: var(--fs-10);
  font-weight: 800;
  letter-spacing: var(--track-tag);
  text-transform: uppercase;
  color: var(--text-mute);
  margin-top: 3px;
}

.tg-rail-bot.pre{
  font-size: var(--fs-11);
  font-weight: 700;
  letter-spacing: 0;
  color: var(--provisional);
  opacity: 0.75;
}

/* The spine. Runs the full height of each row so consecutive games
   read as one continuous day rather than separate cards. */
.tg-line{
  position: absolute;
  left: 54px;
  top: 8px;
  bottom: 0;
  width: 1px;
  background: rgba(var(--ink-rgb), 0.08);
}

/* The node sits ON the rail; its bg ring is the page background, so
   the line appears to pass behind it. */
.tg-node{
  position: absolute;
  left: 50px;
  top: 6px;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  box-shadow: 0 0 0 4px var(--bg);
  background: var(--text-mute);
}

.tg-node.live{ background: var(--live); }
.tg-node.pre{ background: var(--provisional); }

/* Expanding ring on a live node only — the same "only motion on the
   board" restraint .dot.pulse already sets, just at the one place this
   view most needs it. */
.tg-node.live::after{
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: var(--live);
  animation: tg-node-ring 2s ease-out infinite;
}

@keyframes tg-node-ring{
  0%{ transform: scale(1); opacity: 0.55; }
  70%, 100%{ transform: scale(2.6); opacity: 0; }
}

@media (prefers-reduced-motion: reduce){
  .tg-node.live::after{ animation: none; }
}

.tg-card{
  margin-left: 8px;
  border-radius: 14px;
  border: 1px solid var(--hairline);
  background: var(--surface);
  padding: 11px 13px;
  display: flex;
  flex-direction: column;
  gap: 9px;
}

/* A live card is tinted from the top rather than outlined in red — the
   red border alone read as an error state next to the app's own
   --loss-colored rows. */
.tg-card.live{
  border-color: rgba(229, 72, 77, 0.32);
  background: radial-gradient(120% 140% at 50% -20%, rgba(229, 72, 77, 0.10), var(--surface) 62%);
}

/* Preseason / playoff-round label (seasonTagFor in js/live-now.js) —
   a quiet eyebrow above the two team lines. Preseason stays muted since
   those games never count; a playoff round gets the accent. */
.tg-tag{
  margin-bottom: -3px;
  font-family: 'Manrope', sans-serif;
  font-size: var(--fs-10);
  font-weight: 800;
  letter-spacing: var(--track-tag);
  text-transform: uppercase;
  color: var(--text-sub);
}
.tg-tag.post{ color: var(--accent); }

/* The click target is the whole .tg-row (rail/time-gutter included, see
   gameHtml in js/live-now.js), not just this card, so the "Final" or
   "7:40 PM" text off to the side opens Game Details too, not only the
   two team lines — the hover highlight stays on just the card, though,
   since that's the part that visually reads as "this game". */
.tg-card{ transition: background 0.15s ease; }
.tg-row.clickable{ cursor: pointer; }
.tg-row.clickable:hover .tg-card{ background: rgba(var(--ink-rgb), 0.03); }

.tg-side{
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.tg-side .badge{
  flex: 0 0 26px;
  width: 26px;
  height: 26px;
  font-size: var(--fs-10);
  border-radius: 8px;
}

/* Both the badge and the name open the team modal (openTeamModal) —
   plain buttons with no chrome of their own, so the row still looks
   like a row and not a toolbar. */
.tg-badge-btn,
.tg-label{
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  font-family: inherit;
  color: inherit;
}

.tg-badge-btn{ flex: 0 0 auto; display: flex; }

.tg-label{
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: baseline;
  gap: 7px;
  text-align: left;
}

/* AP Top 25 rank, sitting just before the name. Small and muted so it
   reads as a prefix, not a second name; tabular so 1 and 25 align. */
.tg-rank{
  flex: 0 0 auto;
  margin-right: -3px;
  font-size: var(--fs-11);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--text-sub);
}

.tg-name{
  font-weight: 700;
  font-size: var(--fs-13);
  letter-spacing: -0.1px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The losing side of a finished game. --text-sub, not --text-mute:
   still clearly secondary, still above 4.5:1 on --surface. */
.tg-name.dim,
.tg-score.dim{ color: var(--text-sub); }

/* Owner designation. Same weight and case as the Standings tab's
   .team-sub owner line, kept inline behind a hairline so the row's
   layout is unchanged. */
.tg-owner{
  flex: 0 0 auto;
  font-family: 'Manrope', sans-serif;
  font-size: var(--fs-12);
  font-weight: 500;
  letter-spacing: 0.1px;
  color: var(--text-sub);
  white-space: nowrap;
  padding-left: 7px;
  border-left: 1px solid var(--hairline-strong);
}

.tg-owner:empty{ display: none; }

/* Shrunk to fit this compact row (the default 30px/18px is sized for
   the Teams tab's taller cards) — same idle/filled-gold behavior. */
.tg-side .favorite-star{ width: 22px; height: 22px; }
.tg-side .favorite-star svg{ width: 13px; height: 13px; }

.tg-score{
  flex: 0 0 auto;
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: var(--fs-17);
  font-variant-numeric: tabular-nums;
}

/* ---- Empty state ----
   Reuses .empty-panel/.empty-title/.empty-sub as-is; only the old
   basketball emoji is replaced (it was the one piece of the old view
   that didn't match anything else in the app). */
.tg-empty-ring{
  width: 46px;
  height: 46px;
  border-radius: 50%;
  border: 1.5px dashed var(--hairline-strong);
}

/* ---- Modal ---- */
.modal-overlay{
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(6,7,9,0.6);
  align-items: center;
  justify-content: center;
  padding: 24px;
  z-index: 300;
}

.modal-overlay.open{
  display: flex;
}

.modal{
  background: var(--sheet);
  border: 1px solid var(--hairline-strong);
  border-radius: 20px;
  box-shadow: 0 24px 64px rgba(0,0,0,0.5);
  max-width: 400px;
  width: 100%;
  max-height: 85vh;
  overflow-y: auto;
  /* Scrolling past either end of a sheet's content stays in the sheet
     rather than chaining out to the (locked) page behind it. */
  overscroll-behavior: contain;
}

@media (max-width: 700px){
  .modal-overlay{
    align-items: flex-end;
    padding: 0;
  }

  .modal{
    max-width: none;
    /* Tall content (an MLB box score) tops out well short of the status
       bar: at most 80% of the screen, and always leaving a strip of the
       dimmed page showing above it. */
    max-height: 80vh;
    max-height: min(80dvh, calc(100dvh - env(safe-area-inset-top) - 88px));
    border-left: none;
    border-right: none;
    border-bottom: none;
    border-radius: 28px 28px 0 0;
    box-shadow: 0 -24px 64px rgba(0,0,0,0.55);
    padding-bottom: env(safe-area-inset-bottom);
    animation: sheet-up 0.22s ease-out;
    /* Swipe-to-dismiss (see enableSheetSwipeToDismiss in js/utils.js)
       drives transform directly while dragging (transition: none) and
       clears it on release, falling back to this for the snap-back. */
    transition: transform 0.45s var(--ease-sheet);
  }

  .modal::before{
    content: '';
    display: block;
    width: 36px;
    height: 4px;
    border-radius: 4px;
    background: rgba(var(--ink-rgb),0.18);
    margin: 10px auto 0;
  }
}

@keyframes sheet-up{
  from{ transform: translateY(24px); opacity: 0; }
  to{ transform: translateY(0); opacity: 1; }
}

.modal-accent{
  height: 6px;
  width: 100%;
}

.modal-head{
  display: flex;
  align-items: center;
  gap: 13px;
  padding: 18px 22px 16px;
  position: relative;
}

.modal-head .badge{
  flex: 0 0 40px;
  width: 40px;
  height: 40px;
  font-size: var(--fs-13);
}

.modal-head h2{
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-20);
  letter-spacing: var(--track-snug);
  line-height: 1.2;
}

.modal-head .modal-sub{
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-11);
  color: var(--text-sub);
  font-weight: 500;
  margin-top: 3px;
}

.modal-close{
  position: absolute;
  top: 16px;
  right: 16px;
  width: 30px;
  height: 30px;
  border-radius: 999px;
  background: rgba(var(--ink-rgb),0.06);
  border: none;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-sub);
  cursor: pointer;
  padding: 0;
}

.modal-close svg{ width: 14px; height: 14px; }

.modal-close:hover{ color: var(--text); background: rgba(var(--ink-rgb),0.1); }

/* Team modal head: the favorite star sits beside .modal-close (see
   openTeamModal in js/live-data.js) — this wrapper takes over the
   absolute corner positioning so .modal-close can drop its own
   (still used standalone everywhere else the class appears, e.g. the
   identity-switcher and Scores-scope sheets in index.html). */
.modal-actions{
  position: absolute;
  top: 16px;
  right: 16px;
  display: flex;
  align-items: center;
  gap: 6px;
}

.modal-actions .modal-close{ position: static; top: auto; right: auto; }

/* ---- Bottom-sheet rows (js/identity.js's "Who are you?" switcher and
   js/live-now.js's "Show which teams?" scope sheet both use this same
   set) ---- */
.sheet-title-row{
  /* The containing block for .modal-close — .modal itself is static, so
     without this the × was placed against the viewport, off the sheet. */
  position: relative;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  padding: 18px 22px 12px;
}

.sheet-title{
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-20);
  letter-spacing: var(--track-snug);
  line-height: 1.2;
}

/* Only the scope sheet uses this (explaining that rows combine); the
   identity sheet's title stands alone. */
.sheet-title-sub{
  font-size: var(--fs-12);
  color: var(--text-mute);
  margin-top: 4px;
  max-width: 240px;
  line-height: 1.4;
}

.sheet-row{
  display: flex;
  align-items: center;
  width: 100%;
  background: none;
  border: none;
  text-align: left;
  cursor: pointer;
  padding: 12px 22px;
  color: var(--text);
  font-family: 'Manrope', sans-serif;
  font-size: var(--fs-15);
  font-weight: 600;
  min-height: 44px;
}

.sheet-row-text{ flex: 1; }

.sheet-desc{
  font-size: var(--fs-12);
  font-weight: 500;
  color: var(--text-mute);
  margin-top: 1px;
}

.sheet-row:hover{ background: rgba(var(--ink-rgb),0.03); }

.sheet-row.active{ color: var(--accent); font-weight: 700; }

.sheet-row + .sheet-row{ border-top: 1px solid rgba(var(--ink-rgb),0.06); }

/* Same empty-ring/filled-check swap as .tracker-check in
   js/league-facts.js's achievement tracker — reused here for "current
   identity" instead of a colored avatar. */
.sheet-check{
  flex: 0 0 auto;
  margin-left: auto;
  width: 20px;
  height: 20px;
  border-radius: 999px;
  border: 1.5px solid rgba(var(--ink-rgb),0.18);
  display: flex;
  align-items: center;
  justify-content: center;
}

.sheet-check svg{ width: 11px; height: 11px; }

.sheet-row.active .sheet-check{ background: var(--accent-fill); border-color: transparent; }

/* ---- Welcome / Add-to-Home-Screen guide (js/identity.js). Reuses
   .modal + .sheet-row + .modal-cta; only the header, numbered steps
   and footer are new. ---- */
.welcome-head{ padding: 22px 22px 12px; }

.welcome-eyebrow{
  font-size: var(--fs-11);
  font-weight: 700;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--accent);
}

.welcome-title{
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: var(--fs-24);
  letter-spacing: -0.5px;
  margin-top: 4px;
}

.welcome-sub{
  font-size: var(--fs-13);
  line-height: 1.45;
  color: var(--text-sub);
  margin-top: 6px;
}

.welcome-names{ border-top: 1px solid var(--hairline); }
.welcome-chev{ margin-left: auto; color: var(--text-mute); font-size: var(--fs-20); line-height: 1; }

.welcome-steps{
  list-style: none;
  padding: 6px 22px 0;
}

.welcome-steps li{
  display: flex;
  gap: 12px;
  align-items: flex-start;
  padding: 10px 0;
}

.welcome-step-num{
  flex: 0 0 auto;
  width: 24px;
  height: 24px;
  border-radius: 999px;
  background: var(--accent-soft);
  border: 1px solid var(--accent-border);
  color: var(--accent);
  font-size: var(--fs-12);
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
}

.welcome-step-text{ font-size: var(--fs-15); line-height: 1.5; padding-top: 1px; }
.welcome-step-text b{ font-weight: 700; }

.welcome-step-alt{
  display: block;
  margin-top: 4px;
  font-size: var(--fs-12);
  color: var(--text-mute);
}

.welcome-inline-icon{
  width: 16px;
  height: 16px;
  vertical-align: -3px;
  color: var(--accent);
}

.welcome-note{
  margin: 6px 22px 0;
  font-size: var(--fs-12);
  line-height: 1.45;
  color: var(--text-mute);
}

.welcome-actions{ padding: 4px 22px 22px; }
#welcome-content > .modal-cta{ width: auto; margin: 4px 22px 0; }

.welcome-skip{
  display: block;
  width: 100%;
  min-height: 44px;
  margin-top: 4px;
  background: none;
  border: none;
  color: var(--text-mute);
  font-family: 'Manrope', sans-serif;
  font-size: var(--fs-13);
  font-weight: 600;
  cursor: pointer;
}

.stat-strip{
  display: flex;
  border-top: 1px solid var(--hairline);
  border-bottom: 1px solid var(--hairline);
}

.stat-cell{
  flex: 1;
  text-align: center;
  padding: 14px 6px;
}

.stat-cell + .stat-cell{
  border-left: 1px solid var(--hairline);
}

.stat-cell .num{
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: var(--fs-20);
  letter-spacing: -0.3px;
}

.stat-cell .lbl{
  font-size: var(--fs-10);
  font-weight: 600;
  color: var(--text-mute);
  text-transform: uppercase;
  letter-spacing: var(--track-tag);
  margin-top: 3px;
}

.modal-body{
  padding: 18px 22px 22px;
}

.modal-section-title{
  font-size: var(--fs-11);
  font-weight: 700;
  color: var(--text-mute);
  text-transform: uppercase;
  letter-spacing: var(--track-label);
  margin-bottom: 8px;
}

.form-list{
  margin-bottom: 20px;
}

.form-item{
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 8px 0;
}

.form-pill{
  flex: 0 0 20px;
  height: 20px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: var(--fs-10);
}

.form-pill.w{ background: var(--win-soft); color: var(--win); }
.form-pill.d{ background: var(--draw-soft); color: var(--draw); }
.form-pill.l{ background: var(--loss-soft); color: var(--loss); }

/* Last-5 form row (EPL, ahead of the detailed match line below it) —
   same .form-pill circles as the detailed row, just side by side with
   no detail text. */
.form-strip{
  display: flex;
  gap: 6px;
  margin-bottom: 10px;
}

.form-detail{
  font-size: var(--fs-13);
  font-weight: 600;
  flex: 1;
}

.form-detail .opp{
  display: block;
}

.form-detail .meta{
  color: var(--text-sub);
  font-weight: 500;
  font-size: var(--fs-12);
  margin-top: 1px;
}

/* Right-hand column on a "Most Recent Result" row that has a
   boxscore-link (see renderForm in js/live-data.js) — score on top,
   the link right under it, both right-aligned as one unit at the far
   edge of the row (.form-detail's flex:1 above pushes it there, same
   as it already pushes a lone .form-score on a link-less row). */
.form-right{
  text-align: right;
}

.form-right .boxscore-link{
  justify-content: flex-end;
  margin-top: 2px;
}

.form-score{
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: var(--fs-13);
}

.next-match{
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.next-match .nm-teams{
  font-weight: 700;
  font-size: var(--fs-15);
}

.next-match .nm-when{
  font-size: var(--fs-11);
  color: var(--text-sub);
  font-weight: 500;
  margin-top: 2px;
}

/* Venue + broadcast (EPL, from ESPN's real schedule data — see
   renderNext in js/live-data.js). Its own line under nm-when rather
   than folded in, since kickoff time + venue + network together can
   run long ("Fri, Sep 12 at 10:00 AM EDT · Home · Anfield · Peacock"). */
.next-match .nm-venue{
  font-size: var(--fs-11);
  color: var(--text-mute);
  font-weight: 500;
  margin-top: 1px;
}

/* Same Game Details sheet off both the LIVE line and the "Most Recent
   Result" row (see renderNext/renderForm in js/live-data.js) — a plain
   text link rather than a pill, so it reads as a lightweight inline
   action next to an already-busy row (score/period, or form-pill +
   opponent + score) instead of competing with it as its own chip. */
.boxscore-link{
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 2px;
  font-family: 'Manrope', sans-serif;
  font-size: var(--fs-12);
  font-weight: 700;
  color: var(--accent);
  cursor: pointer;
  white-space: nowrap;
}

:root[data-theme="light"] .boxscore-link{ font-weight: 800; }

.boxscore-link:hover{ text-decoration: underline; }

.boxscore-link .chev{ font-size: var(--fs-13); }

/* ---- Game Details sheet — a second, wider overlay stacked on top of
   the team modal (see openGameDetail/closeGameDetail in
   js/live-data.js). Reuses .modal-overlay/.modal's own bottom-sheet
   behavior at mobile widths; only the desktop max-width differs. ---- */
.modal-overlay.stacked{ z-index: 310; }

.modal.modal-wide{ max-width: 560px; }
.gd-loading{ min-height: 100vh; }

.gd-head{
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 18px 22px 14px;
  position: relative;
}

.gd-head.with-back{ padding-left: 50px; }

.gd-back{
  position: absolute;
  top: 16px;
  left: 16px;
  width: 30px;
  height: 30px;
  border-radius: 999px;
  background: rgba(var(--ink-rgb),0.06);
  border: none;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-sub);
  cursor: pointer;
  padding: 0;
}
.gd-back svg{ width: 16px; height: 16px; }

.gd-back:hover{ color: var(--text); background: rgba(var(--ink-rgb),0.1); }

.gd-title{
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-20);
  letter-spacing: var(--track-snug);
  line-height: 1.2;
}

/* Space Grotesk + uppercase/letter-spacing to match .gd-score-title
   below it — previously plain Manrope body text sitting directly under
   a Space Grotesk title, which read as an unrelated leftover rather
   than part of the same header block. Same small-caps-label treatment
   this app already uses for section headers elsewhere
   (.modal-section-title: "TOP PLAYS", "BATTING", etc.), so "FINAL/OT"
   (or, live, the pulsing-dot tag + period detail — see .gd-live-tag
   below) reads as a caption under the score rather than a mismatched
   status string. */
.gd-sub{
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: 'Space Grotesk', sans-serif;
  font-size: var(--fs-11);
  font-weight: 700;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--text-sub);
  margin-top: 4px;
}

/* The score IS the header title now (see renderGameDetail in
   js/live-data.js — an upcoming game with no score yet gets the same
   header, minus the scores; see .no-score below). Both teams sit side by
   side — crest, full name, score — with no separator between them: the
   win/loss color contrast (below) already tells the two sides apart, so
   a dash or rule between them was just visual noise. Wraps to two lines
   on a narrow phone width rather than clipping, since a full name (vs.
   the old bare abbreviation) is more likely to run out of room next to
   its opponent. A team ahead on the scoreboard gets --text (full
   brightness) + bold; behind or tied stays --text-mute, same "winner
   reads brighter" convention the team modal's own form-ticker dots
   already use elsewhere. */
.gd-score-title{
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 9px;
  font-family: 'Space Grotesk', sans-serif;
}

.gd-score-team{
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-15);
  font-weight: 600;
  color: var(--text);
  letter-spacing: 0.2px;
}

/* Team crest in the score header — shrunk from the shared 44px .badge
   (built for a full team row) to sit inline next to a team's name and
   score, same "scope a smaller size to its own parent" pattern as the
   Team Page's 32px standings-row crest above. */
.gd-score-team .badge{
  flex: 0 0 20px;
  width: 20px;
  height: 20px;
  border-radius: 6px;
  font-size: var(--fs-10);
}

.gd-score-team b{
  font-size: var(--fs-24);
  font-weight: 700;
  letter-spacing: -0.3px;
}

.gd-score-team.lost{ color: var(--text-mute); }

/* Upcoming game — no score, so the names carry the header on their own
   at the old plain title's size, with a muted "at" between the sides. */
.gd-score-title.no-score .gd-score-team{ font-size: var(--fs-17); }
.gd-score-title.no-score .gd-score-team .badge{
  flex-basis: 24px;
  width: 24px;
  height: 24px;
  font-size: var(--fs-10);
}
.gd-at{
  font-size: var(--fs-13);
  font-weight: 600;
  color: var(--text-mute);
}

/* Game Details header's live indicator — same pulsing-dot treatment as
   the Teams tab's .status-slot .meta-label.live, in place of the old
   solid green .live-badge pill, so "live" reads the same everywhere. */
.gd-live-tag{
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: var(--live);
  font-weight: 800;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
}

.gd-situation{
  background: var(--surface-2);
  border: 1px solid var(--hairline);
  border-radius: 9px;
  padding: 8px 12px;
  font-size: var(--fs-12);
  font-weight: 600;
  margin-bottom: 16px;
}

/* Recap photo + "Watch highlights" link-out — see the media block in
   renderGameDetail (js/live-data.js). A plain rounded photo, not a
   video player: kept to one small optional block so an already-dense
   sheet (linescore, situation, boxscore) doesn't get heavier. */
.gd-media{ margin-bottom: 16px; }

.gd-photo{
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: 10px;
  border: 1px solid var(--hairline);
}

.gd-recap-headline{
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: var(--fs-15);
  line-height: 1.3;
  letter-spacing: -0.1px;
  margin-top: 10px;
}

.gd-recap-summary{
  font-size: var(--fs-12);
  line-height: 1.5;
  color: var(--text-sub);
  margin-top: 4px;
}

.gd-highlights-link{ margin-top: 8px; text-decoration: none; }

/* MLB-only Top Plays — see the topPlayHtml block in renderGameDetail
   (js/live-data.js). A real embedded player (unlike .gd-photo/
   .gd-highlights-link above), since these are specific curated clips
   rather than ESPN's whole-game reel — tap-to-play only, background
   stays plain black until then so it doesn't visually compete with the
   photo above it. Up to 3 clips share this ONE player (switched via the
   thumbnail rail below it) rather than stacking a video per clip, so
   the sheet's height cost stays the same as a single clip regardless of
   how many plays are available. */
.gd-topplay{ margin-bottom: 16px; }

.gd-topplay-video{
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: 10px;
  border: 1px solid var(--hairline);
  background: #000;
}

.gd-topplay-caption{
  font-size: var(--fs-12);
  font-weight: 600;
  color: var(--text-sub);
  margin-top: 6px;
}

.gd-topplay-rail{
  display: flex;
  gap: 6px;
  margin-top: 8px;
}

.gd-topplay-thumb{
  flex: 1 1 0;
  aspect-ratio: 16 / 9;
  border-radius: 6px;
  border: 1.5px solid transparent;
  background-color: var(--surface-2);
  background-size: cover;
  background-position: center;
  cursor: pointer;
  padding: 0;
  opacity: 0.55;
}

.gd-topplay-thumb:hover{ opacity: 0.8; }

.gd-topplay-thumb.active{
  opacity: 1;
  border-color: var(--accent);
}

/* MLB-only decisions line (W/L/SV) — see the decisionsHtml block in
   renderGameDetail (js/live-data.js). Sits right under the linescore,
   same spot a real broadcast box score puts it. Small inline badges
   reuse the app's existing win/loss color tokens (same ones the
   "Most Recent Result" form ticker already uses) rather than
   introducing a new color pairing. */
.gd-decisions{
  display: flex;
  flex-wrap: wrap;
  gap: 4px 14px;
  margin: 10px 0 14px;
  font-size: var(--fs-12);
  color: var(--text-sub);
}

.gd-decision{ display: inline-flex; align-items: center; gap: 5px; }

.gd-decision b{
  font-size: var(--fs-10);
  font-weight: 800;
  letter-spacing: 0.3px;
  color: var(--bg);
  border-radius: 4px;
  padding: 1px 4px;
}

.gd-decision b.win{ background: var(--win); }
.gd-decision b.loss{ background: var(--loss); }
.gd-decision b.save{ background: var(--accent); }

.gd-decision-record{ color: var(--text-mute); }

/* MLB-only venue/attendance/duration footer — see the gameInfoHtml
   block in renderGameDetail. Deliberately the least visually prominent
   thing in the sheet (smallest size, muted color, sits after the full
   boxscore) — informational, not something worth competing for
   attention with the plays/stats above it. */
.gd-gameinfo{
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid var(--hairline);
  font-size: var(--fs-11);
  color: var(--text-mute);
  text-align: center;
}

/* Only the linescore/box tables scroll horizontally if a narrow phone
   can't fit every inning column — the sheet itself never does (see the
   artifact-design responsive rule this app's own mockup work surfaced). */
.box-scroll{ overflow-x: auto; }

/* The away | Team | home switch under the linescore — the same sliding
   .seg control as the Standings tab, dropped into a .standings-toggle
   wrapper so it fills the row, but repositioned as inline content
   rather than a full-width section header, since .modal-body already
   carries its own padding here. Doubled class so it outranks the
   generic .standings-toggle rule further down this file, which would
   otherwise put back that header's padding and bottom border. */
.standings-toggle.gd-team-toggle{
  margin: 16px 0 14px;
  padding: 0;
  border-bottom: none;
}

/* ---- EPL's Game Details body (see the isSoccer branch in
   renderGameDetail, js/live-data.js) — goals/cards split into each
   team's own column instead of the linescore+box-table every other
   GAME_DETAIL_LEAGUES entry renders, since soccer has no innings/
   quarters to anchor a linescore to. ---- */
.gd-split{
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px;
  margin-top: 4px;
}

.gd-split-head{
  display: flex;
  align-items: center;
  gap: 7px;
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: var(--fs-13);
  margin-bottom: 10px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--hairline);
}

.gd-split-dot{ width: 7px; height: 7px; border-radius: 50%; flex: 0 0 7px; }
.gd-split-dot.home{ background: var(--accent); }
.gd-split-dot.away{ background: var(--text-mute); }

.gd-event{
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 6px 0;
  font-size: var(--fs-12);
  font-weight: 600;
}

.gd-event-min{
  flex: 0 0 auto;
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: var(--fs-11);
  color: var(--text-mute);
  min-width: 26px;
}

.gd-event-who{ color: var(--text); overflow-wrap: anywhere; }

.gd-ball-icon{ width: 12px; height: 12px; flex: 0 0 12px; color: var(--text-sub); }
.gd-ball-icon svg{ width: 100%; height: 100%; display: block; }

/* Same shape both goal/card markers share isn't the point here — a
   card reads as a card (portrait rectangle, tilted like a referee's
   own gesture) rather than another circular badge. Colors reuse
   existing tokens rather than introducing new ones: accent gold
   already reads as "yellow" and the live-red already reads as
   "stop/alert". */
.gd-card-chip{
  width: 9px; height: 13px; border-radius: 2px; flex: 0 0 9px;
  transform: rotate(-8deg);
  box-shadow: 0 0 0 1px var(--card-ring);
}
.gd-card-chip.y{ background: var(--card-yellow); }
.gd-card-chip.r{ background: var(--live); }

.gd-event-empty{
  font-size: var(--fs-12); color: var(--text-mute); font-weight: 500; padding: 6px 0;
}

/* ---- NHL scoring summary (hockeyGoalsHtml in js/live-data.js) —
   one row per goal under its period label, reusing .gd-event-min /
   .gd-event-who from the soccer split above for the clock and scorer. */
.gd-goal-period{
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: var(--fs-11);
  color: var(--text-sub);
  padding: 8px 0 2px;
}

.gd-goal{
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 6px 0;
  font-size: var(--fs-12);
  font-weight: 600;
  border-bottom: 1px solid var(--hairline);
}
.gd-goal .gd-event-min{ padding-top: 1px; min-width: 32px; }

.gd-goal-team{
  flex: 0 0 34px;
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: var(--fs-11);
  color: var(--text-sub);
  padding-top: 1px;
}

.gd-goal-body{ flex: 1; min-width: 0; }

.gd-goal-assists{
  font-size: var(--fs-11);
  font-weight: 500;
  color: var(--text-sub);
  margin-top: 2px;
}

.gd-goal-tag{
  font-size: var(--fs-10);
  font-weight: 800;
  letter-spacing: 0.4px;
  color: var(--accent);
}

.gd-goal-score{
  flex: 0 0 auto;
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: var(--fs-12);
  font-variant-numeric: tabular-nums;
  color: var(--text);
}

/* Team totals comparison (teamStatsHtml) — away | stat | home. */
.gd-teamstats{
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-12);
  font-variant-numeric: tabular-nums;
}
.gd-teamstats th, .gd-teamstats td{
  padding: 6px 4px;
  border-bottom: 1px solid var(--hairline);
  font-weight: 700;
  color: var(--text);
}
.gd-teamstats th{ font-size: var(--fs-10); letter-spacing: 0.3px; color: var(--text-mute); }
.gd-teamstats th:first-child, .gd-teamstats td:first-child{ text-align: left; }
.gd-teamstats th:last-child, .gd-teamstats td:last-child{ text-align: right; }
.gd-teamstats td.label{ text-align: center; font-weight: 500; color: var(--text-sub); }

.linescore-table{
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-11);
  font-variant-numeric: tabular-nums;
}

.linescore-table th, .linescore-table td{
  padding: 6px 5px;
  text-align: center;
  color: var(--text-sub);
  border-bottom: 1px solid var(--hairline);
}

.linescore-table th{ font-weight: 700; color: var(--text-mute); font-size: var(--fs-10); letter-spacing: 0.3px; }
.linescore-table td.team{ text-align: left; font-weight: 700; color: var(--text); }
.linescore-table td.tot{ font-weight: 700; color: var(--text); }

.box-table{
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-11);
  font-variant-numeric: tabular-nums;
}

.box-table th, .box-table td{
  padding: 6px 6px;
  text-align: right;
  border-bottom: 1px solid var(--hairline);
}

.box-table th{ color: var(--text-mute); font-weight: 700; font-size: var(--fs-10); letter-spacing: 0.3px; }
.box-table td.name{ text-align: left; color: var(--text); font-weight: 600; }
.box-table td{ color: var(--text-sub); }

.scoring-list{
  display: flex;
  flex-direction: column;
}

.scoring-item{
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 9px 0;
}

.scoring-item + .scoring-item{
  border-top: 1px solid rgba(var(--ink-rgb),0.055);
}

.scoring-label{
  font-size: var(--fs-13);
  font-weight: 600;
}

.scoring-value{
  flex: 0 0 auto;
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: var(--fs-15);
  text-align: right;
  white-space: nowrap;
}

/* Plain green/red numbers, no pill — same treatment as .ob-rule-pts on
   the drafter breakdowns. */
.scoring-value.pos{ color: var(--win); }
.scoring-value.neg{ color: var(--loss); }

/* ---- Scoring page (js/scoring-page.js) ----
   The filter-chip-selected league's rules, reusing openLeagueModal's own
   content shape (accent bar, heading, .scoring-list) without the modal
   chrome around it — see that function in js/board.js, which still
   backs the Standings tab's per-league popup unchanged. */
.scoring-page-accent{
  height: 6px;
  width: 100%;
  border-radius: 6px;
  margin-bottom: 16px;
}
.scoring-page-title{
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: var(--fs-20);
  letter-spacing: -0.3px;
}
.scoring-page-sub{
  font-size: var(--fs-11);
  color: var(--text-sub);
  font-weight: 500;
  margin: 3px 0 18px;
}

/* ---- Season tracker (achievement checklist, in team modal) ----
   The head (title + "Earned so far" summary + chevron) stays visible
   whether the body (the checklist itself) is collapsed or not — only
   trackerSectionHtml's `expanded` flag decides whether tracker-body
   renders at all, so there's no hidden-but-present markup to fight
   with in CSS. Sits under its own top margin (see #tracker-section
   below) so it doesn't crowd the Next Match/Game section right above it. */
.tracker-head{
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  cursor: pointer;
}

#tracker-section{
  margin-top: 14px;
}

.tracker-total{
  font-size: var(--fs-11);
  color: var(--text-sub);
  font-weight: 600;
}

.tracker-total b{
  color: var(--text);
  font-family: 'Space Grotesk', sans-serif;
  /* Explicit, not inherited — without this, the <b> tag's default
     "bolder" keyword resolves relative to .tracker-total's own 600,
     which lands on 900 (the CSS bolder-keyword table steps 600->900),
     noticeably heavier than the 700 used everywhere else in the app
     for an emphasized Space Grotesk number (.form-score, .tracker-value,
     .next-match .nm-teams) — that mismatch is what read as "too big". */
  font-weight: 700;
}

.tracker-chevron{
  flex: 0 0 16px;
  width: 16px;
  height: 16px;
  color: var(--text-mute);
  transition: transform 0.18s ease;
}

.tracker-chevron.open{
  transform: rotate(180deg);
}

.tracker-body{
  margin-top: 12px;
}

.tracker-list{
  display: flex;
  flex-direction: column;
  margin-bottom: 4px;
}

.tracker-item{
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 11px 2px;
  cursor: pointer;
  border: none;
  background: none;
  width: 100%;
  text-align: left;
  font-family: inherit;
  min-height: 44px;
}

.tracker-item + .tracker-item{
  border-top: 1px solid rgba(var(--ink-rgb),0.055);
}

.tracker-check{
  flex: 0 0 20px;
  width: 20px;
  height: 20px;
  border-radius: 999px;
  border: 1.5px solid rgba(var(--ink-rgb),0.18);
  display: flex;
  align-items: center;
  justify-content: center;
}

.tracker-check svg{ width: 11px; height: 11px; }

.tracker-item.achieved .tracker-check{
  background: var(--win);
  border-color: transparent;
}

.tracker-label{
  flex: 1;
  font-size: var(--fs-13);
  font-weight: 600;
  color: var(--text-sub);
}

.tracker-item.achieved .tracker-label{
  color: var(--text);
}

.tracker-value{
  flex: 0 0 auto;
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: var(--fs-11);
  padding: 2px 8px;
  border-radius: 999px;
  white-space: nowrap;
  border: 1.5px solid rgba(var(--ink-rgb),0.12);
  color: var(--text-mute);
  background: transparent;
}

.tracker-item.achieved .tracker-value.pos{
  background: var(--win-soft);
  color: var(--win);
  border-color: transparent;
}

.tracker-item.achieved .tracker-value.neg{
  background: var(--loss-soft);
  color: var(--loss);
  border-color: transparent;
}

/* Rank-based rules (e.g. "2nd in EPL") that currently apply — amber
   instead of the green/red used for a real, locked-in fact, since
   these read straight off today's table and can still change before
   the season ends. */
.tracker-item.provisional .tracker-check{
  background: var(--provisional);
  border-color: transparent;
}

.tracker-item.provisional .tracker-label{ color: var(--text); }

.tracker-item.provisional .tracker-value{
  background: var(--provisional-soft);
  color: var(--provisional);
  border-color: transparent;
}


/* "10 locked · +2 live" beside the projected total — the same split
   (and Live color) the Points tab shows for a drafter. */
.tracker-split{
  display: inline-flex;
  gap: 8px;
  margin-left: 10px;
  padding-left: 10px;
  border-left: 1px solid rgba(var(--ink-rgb),0.12);
}
.tracker-split .lv{ color: var(--provisional); }
.tracker-split .risk{ color: var(--loss); }

.tracker-item.readonly{ cursor: default; }

/* ---- League Facts (marked from the admin page, js/admin.js) ---- */
.league-facts-list{
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.fact-row + .fact-row{
  padding-top: 14px;
  border-top: 1px solid rgba(var(--ink-rgb),0.055);
}

.fact-row-top{
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
}

.fact-label{
  flex: 1;
  font-size: var(--fs-13);
  font-weight: 600;
}

.fact-pts{
  flex: 0 0 auto;
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: var(--fs-13);
  padding: 3px 9px;
  border-radius: 20px;
  white-space: nowrap;
}

.fact-pts.pos{ background: var(--win-soft); color: var(--win); }
.fact-pts.neg{ background: var(--loss-soft); color: var(--loss); }

.fact-chips{
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 8px;
}

.fact-chip{
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-12);
  font-weight: 700;
  color: var(--text);
  background: rgba(var(--ink-rgb),0.05);
  border: 1px solid var(--hairline-strong);
  border-radius: 999px;
  padding: 4px 8px 4px 4px;
}

.fact-chip-badge{
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: var(--fs-10);
  border-radius: 7px;
  border: 1px solid rgba(var(--ink-rgb),0.14);
}

.fact-chip-owner{
  color: var(--text-sub);
  font-weight: 600;
}

.fact-chip-x{
  border: none;
  background: none;
  color: var(--text-mute);
  font-size: var(--fs-15);
  line-height: 1;
  cursor: pointer;
  padding: 0 0 0 2px;
  font-family: inherit;
}

.fact-chip-x:hover{ color: var(--loss); }

.fact-empty{
  font-size: var(--fs-12);
  color: var(--text-mute);
  font-style: italic;
}

.fact-picker{
  width: 100%;
  font-family: inherit;
  font-size: var(--fs-13);
  font-weight: 600;
  color: var(--text-sub);
  background: rgba(var(--ink-rgb),0.05);
  border: 1px solid var(--hairline-strong);
  border-radius: 10px;
  padding: 8px 10px;
}

/* ---- Commissioner page (js/admin.js) ---- */
.admin-gate{
  max-width: 320px;
  margin: 48px auto 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
  text-align: center;
}

.admin-gate-title{
  font-size: var(--fs-15);
  font-weight: 700;
  color: var(--text-sub);
  margin-bottom: 4px;
}

.admin-gate-input{
  width: 100%;
  font-family: inherit;
  font-size: 16px;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--hairline-strong);
  border-radius: 10px;
  padding: 12px 14px;
  text-align: center;
}

.admin-gate-error{
  font-size: var(--fs-12);
  color: var(--loss);
}

.admin-gate-btn{
  min-height: 44px;
  background: var(--accent-soft);
  border: 1px solid var(--accent-border);
  border-radius: 10px;
  color: var(--accent);
  font-family: 'Manrope', sans-serif;
  font-size: var(--fs-13);
  font-weight: 700;
  cursor: pointer;
}

.admin-toolbar{
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 6px;
}

.admin-logout{
  background: transparent;
  border: none;
  color: var(--text-mute);
  font-family: 'Manrope', sans-serif;
  font-size: var(--fs-13);
  font-weight: 600;
  min-height: 36px;
  cursor: pointer;
}
.admin-logout:hover{ color: var(--text-sub); }

.admin-league{
  border-top: 2px solid var(--hairline-strong);
  padding-top: 16px;
  margin-top: 22px;
}
.admin-league:first-of-type{ margin-top: 0; }

.admin-league-title{
  font-size: var(--fs-15);
  font-weight: 800;
  margin: 0 0 14px;
}

.admin-adj-list{
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.admin-adj-row{
  display: grid;
  grid-template-columns: 1fr 60px 1fr auto;
  align-items: center;
  gap: 6px;
}

.admin-adj-team{
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-12);
  font-weight: 600;
  color: var(--text);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.admin-adj-pts, .admin-adj-note{
  font-family: inherit;
  font-size: 16px;
  color: var(--text);
  background: rgba(var(--ink-rgb),0.05);
  border: 1px solid var(--hairline-strong);
  border-radius: 8px;
  padding: 7px 8px;
  min-width: 0;
}

.admin-adj-save{
  background: transparent;
  border: 1px solid var(--hairline-strong);
  border-radius: 8px;
  color: var(--accent);
  font-family: 'Manrope', sans-serif;
  font-size: var(--fs-12);
  font-weight: 700;
  padding: 7px 10px;
  cursor: pointer;
}
.admin-adj-save:hover{ border-color: var(--accent-border); background: var(--accent-soft); }

/* Draft section: the live room's status as label/value rows. */
#admin-content .seg{ margin-bottom: 16px; }
.admin-status{
  display: flex;
  flex-direction: column;
  border: 1px solid var(--hairline);
  border-radius: 12px;
  background: var(--surface);
}
.admin-status-row{
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 14px;
  font-size: var(--fs-13);
}
.admin-status-row + .admin-status-row{ border-top: 1px solid var(--hairline); }
.admin-status-label{ color: var(--text-sub); font-weight: 600; }
.admin-status-value{ color: var(--text); font-weight: 700; text-align: right; }
.admin-status-value[data-state="ok"]{ color: var(--win); }
.admin-status-value[data-state="warn"]{ color: var(--accent); }
.admin-status-value[data-state="live"]{ color: var(--loss); }
.admin-draft-cta{ width: 100%; margin-top: 14px; }
.admin-status-note{
  margin: 10px 0;
  font-size: var(--fs-12);
  color: var(--text-mute);
  line-height: 1.45;
}

/* ---- Live data additions ---- */

/* Modal-head season-phase badge (see seasonStatus/renderSeasonBadge in
   js/live-data.js) — same soft-badge shape as .zone-tag below, one tint
   per phase so Pre/In/Post-Season and Season Complete read apart at a
   glance without needing the label alone to carry it. */
.season-badge{
  display: inline-block;
  font-family: 'Manrope', sans-serif;
  font-size: var(--fs-10);
  font-weight: 700;
  letter-spacing: 0.3px;
  border-radius: 20px;
  padding: 2px 7px;
  vertical-align: middle;
  white-space: nowrap;
}
.season-badge.pre{ color: var(--provisional); background: var(--provisional-soft); }
.season-badge.in{ color: var(--win); background: var(--win-soft); }
.season-badge.post{ color: var(--accent); background: var(--accent-soft); }
.season-badge.complete{ color: var(--record); background: var(--record-soft); }

/* EPL qualification-zone tag (Champions League/Europa League/
   Relegation) — color and background come from ESPN's own note.color
   per team (see softZoneTint/renderStats in js/live-data.js): a
   low-alpha tint of that color behind full-strength text, same
   soft-badge look as .season-badge above, rather than a solid pastel
   fill. */
.zone-tag{
  display: inline-block;
  font-family: 'Manrope', sans-serif;
  font-size: var(--fs-10);
  font-weight: 700;
  letter-spacing: 0.3px;
  border-radius: 20px;
  padding: 2px 7px;
  vertical-align: middle;
  white-space: nowrap;
}

.no-live-note{
  font-size: var(--fs-13);
  color: var(--text-sub);
  font-style: italic;
  line-height: 1.5;
  padding: 6px 0 10px;
}

.loading-note{
  font-size: var(--fs-13);
  color: var(--text-sub);
  padding: 4px 0;
}

/* ---- Standings view (real per-league tables) ---- */
/* Pinned so the league filter stays reachable while scrolling a long
   table — offset by the safe-area inset (not a flat 0) so it settles
   below the notch/status bar instead of sliding under it.
   Bleeds out to the actual screen edges via a negative margin matching
   body's own horizontal padding (--page-pad), then re-adds that as
   padding so the chips inside still line up with everything else on
   the page — without this, the sticky bar's opaque background stopped
   short of the edges (inset by body's padding like everything else),
   and standings rows scrolling up underneath it were visible through
   that gap on iOS Safari, which also never fully repaints a plain
   `position: sticky` element as its own layer during scroll — the
   translateZ(0) below forces that, which is the standard fix for
   content flashing/bleeding through a sticky bar on iOS.
   That alone still isn't enough during fast/momentum scrolling: iOS
   can lose the paint-order race and let the row a division section
   ends on (e.g. AL East's last-place team) render above this bar for
   a frame instead of behind it — reported as a whole row briefly
   floating above the filter pills, overlapping the status bar. Two
   more layers of defense against that: `isolation` scopes this
   element's z-index to its own stacking context instead of leaving it
   to compete with whatever stacking contexts the row cards above
   happen to create, and `will-change` promotes it to a persistent
   compositor layer up front rather than one iOS decides to allocate
   (or not) only once scrolling starts. See also .safe-area-top further
   up this file, which independently covers the notch/status-bar strip
   itself — a `position: fixed` layer that can't be affected by any of
   this scroll-repaint business at all — as a last line of defense. */
.standings-filter-row{
  position: sticky;
  top: env(safe-area-inset-top);
  z-index: 5;
  margin: 0 calc(-1 * var(--page-pad));
  padding: 0 var(--page-pad);
  background: var(--bg);
  transform: translateZ(0);
  -webkit-transform: translateZ(0);
  will-change: transform;
  isolation: isolate;
}

.standings-toggle{
  display: flex;
  gap: 6px;
  padding: 8px 18px;
  border-bottom: 1px solid var(--hairline);
}

/* NFL's second toggle row (Divisions/Full Conference), stacked right
   under the first (AFC/NFC/Person) — pulled closer so the pair reads as
   one nested choice ("which conference, then how to view it") instead
   of two unrelated toggle bars. The first row's own border-bottom would
   otherwise land in the seam between the two rows, reading as a stray
   line cutting behind the pills instead of a clean divider before the
   team list — so drop it whenever a subtoggle row follows. */
.standings-toggle:has(+ .standings-subtoggle){
  border-bottom: none;
}

.standings-subtoggle{
  padding-top: 0;
}

.standings-grid{
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 20px;
}

@media (max-width: 900px){
  .standings-grid{ grid-template-columns: 1fr; }
}

.standings-row{
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 18px;
  min-height: 44px;
}

.standings-row.clickable{ cursor: pointer; }
.standings-row.clickable:hover{ background: rgba(var(--ink-rgb),0.03); }

.standings-row + .standings-row{
  border-top: 1px solid rgba(var(--ink-rgb),0.06);
}

.standings-row .team-name{ font-size: var(--fs-15); }

.standings-rank{
  flex: 0 0 18px;
  text-align: center;
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: var(--fs-13);
  color: var(--text-mute);
}

/* NFL Standings' "Divisions" view: a small label row ("AFC North")
   ahead of that division's 4 team rows, since — unlike EPL's single
   table or CFB's flat Top 25 — there's no one ranking that spans all
   32 teams. */
.standings-group-header{
  font-family: 'Manrope', sans-serif;
  font-size: var(--fs-11);
  font-weight: 700;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--text-mute);
  background: rgba(var(--ink-rgb),0.02);
  padding: 10px 18px 6px;
}

.standings-group-header + .standings-row{ border-top: none; }

/* Drafted view's combined-record stat — no pill (see the Standings-tab
   exploration: same move away from pills as the Teams tab's status
   column), two-tier instead: the real W-D-L/W-L record as the bold
   primary line, the derived stat (league points or win%) called out
   separately underneath in the same "record" blue-gray (not the win/
   loss colors) so it still reads as its own signal. The League view's
   row reuses this same class for its now-matching right-side record —
   see js/standings-flat.js/-epl.js/-cfb.js/-nfl.js/-wnba.js. Its owner
   label sits under the team name as a second plain .team-sub line
   instead (same treatment as the Drafted view's "Chiefs · Bengals ·
   Bears" teams-list line), not its own gold/pill styling — an
   always-on-every-row attribution reads as secondary metadata here,
   not the row's point. */
.person-record-chip{
  margin-left: auto;
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 1px;
  white-space: nowrap;
}
.person-record-primary{
  font-family: 'Space Grotesk', sans-serif;
  font-size: var(--fs-15);
  font-weight: 700;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.person-record-secondary{
  font-family: 'Manrope', sans-serif;
  font-size: var(--fs-11);
  font-weight: 800;
  letter-spacing: 0.4px;
  color: var(--record);
}

/* ---- Points view (cross-drafter standings, js/overall.js) ----
   Ranked by Projected = Locked + Live. A "You" hero, a Table | Activity
   switch, a quick sheet per drafter and the pushed per-drafter
   breakdown. Every Locked/Live visual goes through .split-bar /
   .split-swatch / .pts-tag, so the two kinds of points read the same
   everywhere (Compare and the team modal too). See
   docs/points-ux-plan.md. */

/* -- Sub row under the Points header. The Scoring entry point is the
   full-width button at the bottom of the page (.ob-scoring-btn). -- */
.page-sub-row{
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

/* TEMPORARY: a preview aid for showing the page's shape before the
   season produces real results. Safe to delete this block (and the
   matching "TEMPORARY" block in js/overall.js, and the toggle markup in
   index.html) once real data makes it unnecessary. */
.ob-sim-banner{
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 14px;
  background: var(--accent-soft);
  border: 1px solid var(--accent-border);
  border-radius: 10px;
  padding: 10px 12px;
  font-size: var(--fs-12);
  font-weight: 600;
  color: var(--accent);
}

/* -- Locked / Live primitives --
   Solid ink = Locked, blue hatch = Live, red hatch = Live at risk
   (negative). Texture, not just hue, so it reads before color does. */
.split-bar{
  display: flex;
  height: var(--split-h, 8px);
  border-radius: 99px;
  background: rgba(var(--ink-rgb), 0.06);
  overflow: hidden;
  min-width: 0;
}
.split-bar.lg{ --split-h: 12px; }
.split-bar.sm{ --split-h: 8px; }
.split-bar.xs{ --split-h: 6px; }
.split-bar > span{ display: block; height: 100%; flex: none; }
.split-bar .lk{ background: var(--text); }
.split-bar .lv, .split-swatch.lv{ background: var(--live-stripe); }
.split-bar .lv.risk, .split-swatch.lv.risk{ background: var(--risk-stripe); }
.split-swatch{ display: inline-block; width: 10px; height: 10px; border-radius: 3px; flex: none; }
.split-swatch.lk{ background: var(--text); }
.split-swatch.lv{ background-size: 6px 6px; }

.pts-tag.live{ color: var(--provisional); background: var(--provisional-soft); box-shadow: inset 0 0 0 1px var(--provisional-border); }
.pts-tag.locked{ color: var(--accent); background: var(--accent-soft); }
.pts-tag.lock-in{ color: var(--on-accent); background: var(--accent-fill); }
.pts-tag.rank{ color: var(--text-sub); background: rgba(var(--ink-rgb), 0.06); }
.tracker-label .pts-tag{ margin-left: 6px; }

.ob-move{ display: inline-block; font-size: var(--fs-11); font-weight: 800; white-space: nowrap; } /* inline-block so the re-rank pop can scale it */
.ob-move.up{ color: var(--win); }
.ob-move.down{ color: var(--loss); }

/* -- Hero -- */
.ob-hero{
  display: flex;
  flex-direction: column;
  gap: 14px;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 18px;
  padding: 16px;
  margin-bottom: 14px;
}
.ob-hero-top{ display: flex; justify-content: space-between; align-items: flex-end; gap: 12px; }
.ob-hero-left{ display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.ob-hero-rankline{ display: flex; align-items: baseline; gap: 8px; }
.ob-hero-rank, .ob-hero-total{
  font-family: var(--font-display);
  font-size: 40px;
  font-weight: 700;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.ob-hero-rank{ color: var(--accent); }
.ob-hero-rankline .ob-move{ font-size: var(--fs-12); }
.ob-hero-total-label{ font-size: var(--fs-12); font-weight: 600; color: var(--text-sub); }
.ob-hero-right{ display: flex; flex-direction: column; align-items: flex-end; gap: 2px; }
.ob-hero-total-label{ font-size: var(--fs-11); font-weight: 700; }
.ob-split{ display: flex; flex-direction: column; gap: 8px; }
.ob-split-legend{ display: flex; justify-content: space-between; font-size: var(--fs-12); font-weight: 700; color: var(--text-sub); }
.ob-split-legend > span{ display: flex; align-items: center; gap: 6px; }
.ob-split-legend .lv{ color: var(--provisional); }
.ob-split-legend .risk{ color: var(--loss); }
.ob-ladder{ display: flex; flex-direction: column; gap: 2px; border-top: 1px solid var(--hairline); padding-top: 8px; }
.ob-ladder-row{
  display: grid;
  grid-template-columns: 22px 58px minmax(0, 1fr) 26px 30px;
  gap: 8px;
  align-items: center;
  padding: 6px 0;
  background: none;
  border: none;
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.ob-ladder-rank{ font-family: var(--font-display); font-size: var(--fs-12); font-weight: 700; color: var(--text-mute); }
.ob-ladder-name{ font-size: var(--fs-13); font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ob-ladder-row.me .ob-ladder-name{ color: var(--accent); }
.ob-ladder-row .split-bar .lk{ background: var(--lb-rank-mid); }
.ob-ladder-row.me .split-bar .lk{ background: var(--accent-fill); }
.ob-ladder-total{ font-family: var(--font-display); font-size: 14px; font-weight: 700; text-align: right; }
.ob-ladder-gap{ text-align: right; }
.ob-gap{ font-size: var(--fs-11); font-weight: 800; }
.ob-gap.ahead{ color: var(--loss); }
.ob-gap.behind{ color: var(--win); }
.ob-hero-explain{ font-size: var(--fs-12); font-weight: 600; color: var(--text-mute); line-height: 1.45; text-wrap: pretty; }

/* -- Table | Activity switch -- */
.ob-seg{ margin-bottom: 14px; }
.ob-seg .seg{ margin-bottom: 0; }
.seg-btn .count-badge{ margin-left: 6px; vertical-align: 1px; }

/* -- Table -- */
.ob-table{
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 16px;
  overflow: hidden;
}
.ob-table-row{
  display: grid;
  grid-template-columns: 26px minmax(0, 1fr) 38px 34px 38px;
  gap: 8px;
  align-items: center;
  width: 100%;
  padding: 11px 14px;
  background: none;
  border: none;
  border-bottom: 1px solid var(--hairline);
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.ob-table-row:last-child{ border-bottom: none; }
.ob-table-row.head{
  padding: 9px 14px;
  border-bottom-color: var(--hairline-strong);
  font-size: var(--fs-10);
  font-weight: 800;
  letter-spacing: var(--track-tag);
  text-transform: uppercase;
  color: var(--text-mute);
  cursor: default;
}
.ob-table-row.head > span:nth-child(n+3){ text-align: right; }
.ob-table-row.head .lv{ color: var(--provisional); }
.ob-table-row.head .pj{ color: var(--text); }
.ob-table-row.leader{ background: var(--lb-accent-wash); }
.ob-rank{ font-family: var(--font-display); font-size: var(--fs-13); font-weight: 700; color: var(--lb-rank-low); }
.ob-rank.rank-mid{ color: var(--lb-rank-mid); }
.ob-rank.rank-1{ color: var(--accent); }
.ob-table-name{ display: flex; align-items: center; gap: 7px; min-width: 0; }
.ob-table-name-text{ font-size: var(--fs-15); font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ob-table-row.current .ob-table-name-text{ color: var(--accent); }
.ob-table-locked, .ob-table-live, .ob-table-proj{ text-align: right; font-weight: 700; }
.ob-table-locked{ font-family: var(--font-display); font-size: 14px; color: var(--text-sub); }
.ob-table-live{ font-size: var(--fs-12); color: var(--provisional); }
.ob-table-live.zero{ color: var(--text-mute); }
.ob-table-live.neg{ color: var(--loss); }
.ob-table-proj{ font-family: var(--font-display); font-size: 18px; color: var(--text); }

/* -- Quick sheet (#ob-sheet-overlay) -- */
.ob-sheet-head{ align-items: flex-end; padding-right: 60px; }
.ob-sheet-head > div:first-child{ min-width: 0; }
.ob-sheet-head .ob-detail-eyebrow{ white-space: nowrap; }
.ob-sheet-name{ font-size: 26px; margin-top: 3px; }
.ob-sheet-total{ display: flex; flex-direction: column; align-items: flex-end; gap: 1px; flex: none; }
.ob-sheet-total-num{ font-family: var(--font-display); font-size: 32px; font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums; }
.ob-sheet-total-split{ font-size: var(--fs-11); font-weight: 700; color: var(--text-sub); white-space: nowrap; }
.ob-sheet-leagues{ display: flex; flex-direction: column; gap: 9px; padding: 4px 22px 16px; }
.ob-sheet-league{ display: grid; grid-template-columns: 130px minmax(0, 1fr) 30px; gap: 10px; align-items: center; }
.ob-sheet-league-name{ font-size: var(--fs-13); font-weight: 700; }
.ob-sheet-league-pts{ font-family: var(--font-display); font-size: var(--fs-15); font-weight: 700; text-align: right; }
.ob-sheet-league-pts.neg{ color: var(--loss); }
.ob-sheet-empty{ font-size: var(--fs-13); color: var(--text-sub); }
.ob-sheet-actions{ display: grid; grid-template-columns: 1fr 1fr; gap: 8px; padding: 0 22px 22px; }
.ob-sheet-actions .modal-cta{ margin-top: 0; }

/* -- Breakdown additions -- */
.ob-detail-split{ margin-bottom: 20px; }
.ob-stat-row{ display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.ob-stat-row .stat-tile{ border-radius: 12px; padding: 10px 11px; }
.ob-stat-row .stat-tile .lbl{ margin: 0 0 3px; }
.ob-stat-row .stat-tile .num{ font-size: var(--fs-17); }
.ob-stat-row .stat-tile .num.lv{ color: var(--provisional); }
.ob-stat-row .stat-tile .num.neg{ color: var(--loss); }
.ob-stat-row .stat-tile .ob-move{ font-size: inherit; font-weight: 700; }
.ob-section-split{ display: flex; justify-content: space-between; align-items: baseline; gap: 12px; }
.ob-section-note{ font-size: var(--fs-12); font-weight: 800; letter-spacing: 0; text-transform: none; }
.ob-section-note.lv{ color: var(--provisional); }
.ob-section-note.risk{ color: var(--loss); }
.ob-section-note.locked{ color: var(--accent); }






.ob-section-title{
  font-size: var(--fs-11);
  font-weight: 700;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--text-sub);
  padding: 0 2px 10px;
}

.ob-detail-link{
  display: block;
  width: 100%;
  margin-top: 14px;
  min-height: 44px;
  background: transparent;
  border: 1px solid var(--hairline-strong);
  border-radius: 10px;
  color: var(--accent);
  font-family: 'Manrope', sans-serif;
  font-size: var(--fs-13);
  font-weight: 700;
  cursor: pointer;
}
.ob-detail-link:hover{
  border-color: var(--accent-border);
  background: var(--accent-soft);
}

/* -- Detail -- */
.ob-back{
  display: flex;
  align-items: center;
  gap: 4px;
  background: transparent;
  border: none;
  color: var(--text-sub);
  font-family: var(--font-ui);
  font-size: var(--fs-13);
  font-weight: 700;
  min-height: 44px;
  padding: 6px 8px 6px 2px;
  border-radius: var(--r-sm);
  cursor: pointer;
}
.ob-back svg{ width: 17px; height: 17px; }
.ob-back:hover{ color: var(--text); }

.ob-detail-head{
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: end;
  gap: 16px;
  padding: 6px 2px 20px;
}
.ob-detail-left{ min-width: 0; }
.ob-detail-eyebrow{
  font-size: var(--fs-11);
  font-weight: 700;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--accent);
}
.ob-detail-eyebrow.mute{ font-weight: 800; color: var(--text-mute); }
.ob-detail-name.current{ color: var(--accent); }
.ob-detail-name{
  font-family: 'Space Grotesk', sans-serif;
  font-size: var(--fs-30);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.05;
  color: var(--text);
  margin: 7px 0 0;
}
.ob-detail-meta{
  font-size: var(--fs-13);
  color: var(--text-sub);
  margin-top: 8px;
}
.ob-detail-right{ text-align: right; flex: none; }
.ob-detail-total{
  font-family: 'Space Grotesk', sans-serif;
  font-size: 46px;
  font-weight: 700;
  line-height: 0.9;
  color: var(--text);
}
.ob-detail-total-label{
  font-size: var(--fs-11);
  font-weight: 700;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--text-sub);
  margin-top: 7px;
}

/* Provisional banner — the only place a live-table number surfaces,
   texture (hatch), not just hue, so it reads before color is parsed. */

.ob-cards{ display: flex; flex-direction: column; gap: 6px; }
.ob-card{
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 14px;
  overflow: hidden;
}
.ob-card-head{
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr) auto;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 44px;
  padding: 13px 14px;
  background: transparent;
  border: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
  -webkit-appearance: none;
}
.ob-card-pts,
.ob-rule-pts{
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  white-space: nowrap;
  color: var(--text);
}
.ob-card-pts{ font-size: 18px; text-align: left; }
.ob-rule-pts{ font-size: var(--fs-15); text-align: right; }
.ob-card-pts.neg, .ob-rule-pts.neg{ color: var(--loss); }
.ob-rule-pts.live{ color: var(--provisional); }

.ob-card-main{ min-width: 0; }
.ob-card-title{
  font-family: 'Space Grotesk', sans-serif;
  font-size: var(--fs-15);
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--text);
}
.ob-card-sub{
  font-size: var(--fs-12);
  color: var(--text-sub);
  margin-top: 4px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.ob-card-right{ display: flex; align-items: center; gap: 12px; }
.ob-card-bar{ width: 64px; }
.ob-card-chevron{
  flex: none;
  stroke: var(--lb-stroke);
  transition: transform 140ms ease;
}
.ob-card.expanded .ob-card-chevron{ transform: rotate(90deg); }

.ob-card-body{
  border-top: 1px solid var(--hairline);
  padding: 4px 14px 12px;
}
.ob-rule{
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 12px;
  padding: 10px 0;
  border-bottom: 1px solid var(--lb-divider);
  cursor: pointer;
}
.ob-rule:last-child{ border-bottom: none; }
.ob-rule-main{ min-width: 0; }
.ob-rule-label{
  font-size: var(--fs-13);
  font-weight: 600;
  color: var(--text);
  line-height: 1.3;
  text-wrap: pretty;
}
.ob-rule-meta{
  display: flex;
  align-items: center;
  gap: 7px;
  flex-wrap: wrap;
  margin-top: 5px;
}
.ob-rule-meta span:first-child{
  font-size: var(--fs-12);
  color: var(--text-sub);
}

.ob-idle-block{
  margin-top: 14px;
  background: rgba(var(--ink-rgb), 0.025);
  border: 1px dashed var(--hairline-strong);
  border-radius: 12px;
  padding: 12px 14px;
}
.ob-idle-title{
  font-size: var(--fs-11);
  font-weight: 700;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--text-sub);
}
.ob-idle-body{
  font-size: var(--fs-13);
  color: var(--text-sub);
  margin-top: 6px;
  line-height: 1.45;
  text-wrap: pretty;
}

/* ---- Views + bottom tab bar ---- */
.view{ display: none; }
.view.active{ display: block; }

/* Total height is --nav-h PLUS the safe-area inset, not just --nav-h
   with the inset squeezed inside it (which is what a plain `height:
   var(--nav-h)` gave, since everything here is box-sizing: border-box —
   padding-bottom ate into the box instead of extending it). That left
   the tab icons/labels cramped into less than --nav-h of real space on
   any notched/home-indicator iPhone, which read as the bar looking
   short/cut off. */
.tab-bar{
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  height: calc(var(--nav-h) + env(safe-area-inset-bottom));
  padding-bottom: env(safe-area-inset-bottom);
  background: var(--bar-bg);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border-top: 1px solid var(--hairline);
  display: flex;
  z-index: 200;
}

.tab-btn{
  flex: 1;
  border: none;
  background: none;
  color: var(--text-sub);
  cursor: pointer;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
}

.tab-btn svg{ width: 19px; height: 19px; }
.tab-icon{
  position: relative;
  display: flex;
  padding: 3px 15px;
  border-radius: 999px;
  transition: background 0.2s ease, color 0.2s ease;
}


.tab-label{
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: var(--fs-10);
  letter-spacing: 0.1px;
}

/* ============================================================
   Team Page (js/team-page.js) — the standings row's crest shrinks to
   32px per the design's Design Decision #2 (everything else about
   .standings-row/.badge-crest stays exactly as-is, so this is scoped
   here rather than touching the shared .badge rule everywhere else
   still uses at 44px).
   ============================================================ */
.standings-row .badge{
  flex: 0 0 32px;
  width: 32px;
  height: 32px;
  border-radius: 9px;
  font-size: var(--fs-11);
}

/* Slide-in entrance for a pushed Team Page/full-screen — applied once
   via JS on open (see openTeamPage/openFullSchedule in js/team-page.js)
   rather than a permanent .view rule, so Board/Standings/Overall keep
   their existing instant switch. */
@keyframes view-push-in{
  from{ transform: translateX(34px); opacity: 0; }
  to{ transform: translateX(0); opacity: 1; }
}
.view-push-in{ animation: view-push-in 0.34s cubic-bezier(0.22, 0.7, 0.25, 1); }
@media (prefers-reduced-motion: reduce){ .view-push-in{ animation: none; } }

.team-page-nav{
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 2px 16px 10px;
}
.team-page-back{
  display: flex;
  align-items: center;
  gap: 4px;
  border: none;
  background: none;
  color: var(--text-sub);
  font-family: var(--font-ui);
  font-size: var(--fs-13);
  font-weight: 700;
  cursor: pointer;
  min-height: 44px;
  padding: 6px 8px 6px 2px;
  border-radius: var(--r-sm);
}
.team-page-back:hover{ color: var(--text); }
.team-page-back svg{ width: 17px; height: 17px; }
.team-page-actions{ display: flex; align-items: center; gap: 6px; }

.team-hero{
  position: relative;
  overflow: hidden;
  padding: 10px 20px 20px;
}
.team-hero-orb{
  position: absolute;
  right: -46px; top: -30px;
  width: 190px; height: 190px;
  border-radius: 50%;
  filter: blur(2px);
  pointer-events: none;
}
.team-hero-scrim{
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(var(--hero-fade-rgb),0) 40%, rgba(var(--hero-fade-rgb),0.85) 100%);
  pointer-events: none;
}
.team-hero-row{
  position: relative;
  display: flex;
  align-items: center;
  gap: 16px;
}
.crest-bare{
  flex: 0 0 auto;
  object-fit: contain;
  background: none;
}
.team-hero .crest-bare{ width: 82px; height: 82px; filter: drop-shadow(var(--hero-shadow)); }
.team-hero-name{
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: var(--fs-30);
  letter-spacing: -0.9px;
  line-height: 1.02;
  text-wrap: balance;
}
.team-hero-meta{
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 7px;
  margin-top: 8px;
  font-size: var(--fs-11);
  font-weight: 600;
  color: var(--text-sub);
}
.team-hero-meta .status-pill{
  font-size: var(--fs-10);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: var(--track-tag);
  color: var(--win);
  background: var(--win-soft);
  border-radius: 6px;
  padding: 3px 6px;
}

.game-card{
  margin: 16px 20px 0;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 16px;
  padding: 14px 15px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
.game-card.live{ border-color: rgba(229,72,77,0.4); }
.game-card-eyebrow{
  font-size: var(--fs-10);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: var(--track-tag);
  color: var(--text-mute);
  display: flex;
  align-items: center;
  gap: 6px;
}
.game-card.live .game-card-eyebrow{ color: var(--live); }

.tab-body{ padding: 14px 20px 26px; min-height: 330px; }

.news-card{
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 14px;
  padding: 13px 14px;
  cursor: pointer;
}
.news-card + .news-card{ margin-top: 10px; }
.news-card:hover{ background: var(--surface-2); }
.news-card .headline{ font-size: var(--fs-15); font-weight: 700; line-height: 1.3; text-wrap: pretty; }
.news-card .news-meta{ font-size: var(--fs-11); font-weight: 700; text-transform: uppercase; letter-spacing: var(--track-label); color: var(--text-mute); margin-top: 8px; }
.news-footer-note{ text-align: center; font-size: var(--fs-11); font-weight: 600; color: var(--text-mute); margin-top: 4px; }

@keyframes skel{ 0%, 100%{ opacity: 1; } 50%{ opacity: 0.4; } }
.skel-bar{ background: rgba(var(--ink-rgb),0.07); border-radius: 6px; height: 13px; animation: skel 1.5s ease-in-out infinite; }
.skel-bar.meta{ background: rgba(var(--ink-rgb),0.05); border-radius: 5px; height: 9px; }
@media (prefers-reduced-motion: reduce){ .skel-bar{ animation: none; } }

.empty-state{
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 10px;
  padding: 40px 34px 44px;
}
.empty-state svg{ width: 26px; height: 26px; stroke: var(--text-mute); }
.empty-state .title{ font-size: var(--fs-13); font-weight: 700; }
.empty-state .body{ font-size: var(--fs-12); font-weight: 500; color: var(--text-sub); line-height: 1.5; text-wrap: pretty; }

.stat-grid{ display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.stat-tile{ background: var(--surface); border: 1px solid var(--hairline); border-radius: 14px; padding: 13px 14px; }
.stat-tile .num{ font-family: 'Space Grotesk', sans-serif; font-weight: 700; font-size: var(--fs-24); letter-spacing: -0.4px; }
.stat-tile .lbl{ font-size: var(--fs-10); font-weight: 700; text-transform: uppercase; letter-spacing: var(--track-tag); color: var(--text-mute); margin-top: 3px; }

.split-card{ background: var(--surface); border: 1px solid var(--hairline); border-radius: 14px; margin-top: 16px; }
.split-row{ display: flex; align-items: center; justify-content: space-between; padding: 12px 14px; }
.split-row + .split-row{ border-top: 1px solid rgba(var(--ink-rgb),0.06); }
.split-label{ font-size: var(--fs-13); font-weight: 600; }
.split-values{ display: flex; align-items: center; gap: 14px; }
.split-record{ font-family: 'Space Grotesk', sans-serif; font-weight: 700; font-size: var(--fs-13); }

.player-row{ display: flex; align-items: center; gap: 12px; padding: 10px 0; }
.player-row + .player-row{ border-top: 1px solid rgba(var(--ink-rgb),0.06); }
.number-chip{
  flex: 0 0 32px; width: 32px; height: 32px;
  border-radius: 10px;
  background: var(--surface-2);
  border: 1px solid var(--hairline);
  display: flex; align-items: center; justify-content: center;
  font-family: 'Space Grotesk', sans-serif; font-weight: 700; font-size: var(--fs-12);
  color: var(--text-sub);
}
.player-main{ flex: 1; min-width: 0; }
.player-name{ font-size: var(--fs-13); font-weight: 700; display: flex; align-items: center; gap: 7px; }
.player-sub{ font-size: var(--fs-12); font-weight: 500; color: var(--text-sub); margin-top: 1px; }
.player-tag{
  font-size: var(--fs-10); font-weight: 800; text-transform: uppercase; letter-spacing: var(--track-tag);
  border-radius: 5px; padding: 2px 5px;
}
.player-tag.out{ color: var(--loss); background: var(--loss-soft); }
.player-tag.doubtful{ color: var(--loss); background: var(--loss-soft); }
.player-tag.questionable{ color: var(--draw); background: var(--draw-soft); }
.player-stat{ text-align: right; font-size: var(--fs-12); font-weight: 600; color: var(--text-sub); white-space: nowrap; }
.player-stat .sub{ font-size: var(--fs-11); color: var(--text-mute); margin-top: 2px; }
/* Stats tab "Team leaders" rows (js/team-page.js's leaderRowsHtml) — the
   number chip carries the stat's abbreviation instead of a jersey. */
.number-chip.leader-chip{ flex-basis: 40px; width: 40px; font-size: var(--fs-10); letter-spacing: 0.2px; }
.leader-value{ font-family: 'Space Grotesk', sans-serif; font-weight: 700; font-size: var(--fs-17); white-space: nowrap; }

/* NFL Roster tab: real depth-chart grid (js/team-page.js's
   depthChartGridHtml) — one row per charted position slot, one column
   per depth level. Same horizontal-scroll idiom as .filter-chips
   above, since a full O-line-to-receivers row is wider than a phone
   screen; the position-label column stays pinned via sticky so it's
   still readable mid-scroll. */
.depth-chart-wrap{ overflow-x: auto; scrollbar-width: none; margin-top: 8px; }
.depth-chart-wrap::-webkit-scrollbar{ display: none; }
.depth-chart{ display: grid; column-gap: 10px; }
.depth-chart-pos{
  position: sticky; left: 0; z-index: 1;
  background: var(--bg);
  display: flex; align-items: center;
  font-size: var(--fs-11); font-weight: 800; color: var(--text-sub);
  text-transform: uppercase; letter-spacing: var(--track-label);
  padding: 9px 8px 9px 0;
  border-bottom: 1px solid var(--hairline);
}
.depth-chart-cell{
  display: flex; flex-direction: column; justify-content: center; gap: 3px;
  min-width: 0; padding: 9px 0;
  border-bottom: 1px solid var(--hairline);
}
.depth-chart-player{ font-size: var(--fs-12); font-weight: 600; overflow-wrap: break-word; }
.depth-chart-player .num{ color: var(--text-mute); font-weight: 700; margin-right: 4px; }
.depth-chart-cell .player-tag{ align-self: flex-start; }

.placeholder-tab{
  text-align: center;
  padding: 40px 20px;
  font-size: var(--fs-13);
  color: var(--text-sub);
  line-height: 1.5;
}

/* Trimmed team modal's hand-off to the Team Page (js/live-data.js's
   openTeamModal) — same accent-soft/accent-border "callout" recipe
   .prior-season-note/.ob-sim-banner already use, shaped into a
   full-width button instead of a text banner. */
.modal-cta{
  display: block;
  width: 100%;
  min-height: 44px;
  margin-top: 18px;
  background: var(--cta-bg);
  border: 1px solid var(--cta-border);
  border-radius: 12px;
  color: var(--cta-color);
  font-family: 'Manrope', sans-serif;
  font-size: var(--fs-13);
  font-weight: 700;
  cursor: pointer;
}
.modal-cta.secondary{
  background: transparent;
  border-color: var(--hairline-strong);
  color: var(--text);
}
/* Points tab: the way into the Scoring page, under the table. */
.ob-scoring-btn{
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}
.ob-scoring-btn svg{ color: var(--accent); }
.modal-cta-note{
  text-align: center;
  font-size: var(--fs-11);
  font-weight: 600;
  color: var(--text-mute);
  margin-top: 8px;
}

/* Selected tab: full-strength icon and label over the one shared gold
   pill (.tab-pill, under "View transitions" below) that springs between
   tabs, instead of each icon recoloring on its own. */
.tab-btn.active{ color: var(--text); }

/* ============================================================
   Chat screen (js/chat.js) — the Chat tab (#view-chat). Unlike the
   other views it doesn't flow in the page: it's fixed, sitting between
   the top of the screen and the tab bar (z-index 200, which stays above
   it). With the keyboard down that's plain CSS (top/bottom below); only
   while the keyboard is up does JS size it from window.visualViewport
   so the keyboard shrinks it instead of covering the composer.
   ============================================================ */
.chat-screen{
  position: fixed;
  left: 0;
  right: 0;
  top: 0;
  bottom: calc(var(--nav-h) + env(safe-area-inset-bottom));
  z-index: 190;
  background: var(--bg);
  flex-direction: column;
}
.chat-screen.view.active{ display: flex; }

/* Set on <html> while the keyboard is up on the Chat tab (js/chat.js's
   syncViewport): the tab bar gets out of the way so the composer sits
   right on the keys. No scroll lock here on purpose — see
   guardTouchScroll in js/chat.js for why and what replaces it. */
html.chat-kb .tab-bar{ display: none; }

/* Same padding the page body gives every other view's .page-header, so
   the logo, title and identity circle land in exactly the same spot when
   you switch tabs. The hairline marks where the messages scroll under. */
.chat-head{
  flex: 0 0 auto;
  padding: calc(env(safe-area-inset-top) + var(--page-pad)) var(--page-pad) 0;
  border-bottom: 1px solid var(--hairline);
}
/* Connection status sits where other views put their .scope-chip:
   leading the right-hand cluster (margin-left:auto), flush against the
   identity circle — see .scope-chip + .picker-hit above. */
.chat-status{
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-12);
  font-weight: 600;
  color: var(--text-mute);
}
.chat-status + .picker-hit{ margin-left: 0; }
.chat-status::before{
  content: '';
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--text-mute);
}
.chat-status[data-state="open"]{ color: var(--text-sub); }
.chat-status[data-state="open"]::before{ background: var(--win); }

.chat-list{
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  display: flex;
  flex-direction: column;
  padding: 12px max(16px, calc((100% - 720px) / 2)) 8px;
}
/* margin-top:auto (not justify-content:flex-end) so a short conversation
   sits at the bottom next to the composer but a long one still scrolls
   normally from the top. */
.chat-list > :first-child{ margin-top: auto; }

.chat-empty{
  margin: auto;
  text-align: center;
  font-size: var(--fs-13);
  font-weight: 500;
  color: var(--text-mute);
  line-height: 1.5;
}
.chat-day{
  align-self: center;
  margin: 14px 0 6px;
  font-size: var(--fs-11);
  font-weight: 700;
  letter-spacing: 0.3px;
  color: var(--text-mute);
}
.chat-meta{
  display: flex;
  align-items: baseline;
  gap: 7px;
  margin: 10px 4px 3px;
}
.chat-meta.mine{ align-self: flex-end; }
.chat-name{ font-size: var(--fs-12); font-weight: 800; color: var(--text-sub); }
.chat-time{ font-size: var(--fs-11); font-weight: 600; color: var(--text-mute); }
.chat-bubble{
  align-self: flex-start;
  max-width: min(82%, 520px);
  margin-top: 2px;
  padding: 8px 12px;
  border-radius: 16px 16px 16px 5px;
  background: var(--surface-2);
  font-size: var(--fs-15);
  font-weight: 500;
  line-height: 1.38;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.chat-bubble.mine{
  align-self: flex-end;
  border-radius: 16px 16px 5px 16px;
  background: var(--accent-soft);
  border: 1px solid var(--accent-border);
  padding: 7px 11px;
}

.chat-composer{
  flex: 0 0 auto;
  display: flex;
  align-items: flex-end;
  gap: 8px;
  padding: 8px max(12px, calc((100% - 720px) / 2)) 10px;
  border-top: 1px solid var(--hairline);
  background: var(--bg);
}
.chat-composer textarea{
  flex: 1 1 auto;
  min-width: 0;
  max-height: 120px;
  resize: none;
  padding: 9px 14px;
  border-radius: 20px;
  border: 1px solid var(--hairline-strong);
  background: var(--surface);
  color: var(--text);
  font-family: 'Manrope', sans-serif;
  /* 16px minimum — anything smaller makes iOS zoom the page on focus. */
  font-size: 16px;
  font-weight: 500;
  line-height: 1.3;
  outline: none;
}
.chat-composer textarea:focus{ border-color: var(--accent-border); }
.chat-composer textarea::placeholder{ color: var(--text-mute); }
.chat-send{
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border: none;
  border-radius: 50%;
  background: var(--accent-fill);
  color: var(--on-accent);
  cursor: pointer;
}
.chat-send svg{ width: 20px; height: 20px; }

/* ---- GIFs in chat (js/gifs.js, js/gif-picker.js) ---- */

/* A GIF message: no bubble, just the image with the same corner shapes
   as a text bubble. aspect-ratio is set inline from the GIF's own
   dimensions so its space is reserved before it loads. */
.chat-gif{
  position: relative;
  /* Not shrinkable: the list is a fixed-height flex column, and this box
     has no intrinsic content height (its img is absolutely positioned)
     and overflow:hidden (so no min-height:auto floor either) — left
     alone it collapses to 0 tall as soon as the conversation is long
     enough to overflow. */
  flex: none;
  align-self: flex-start;
  width: min(68%, 240px);
  max-height: 320px;
  margin-top: 2px;
  border-radius: 16px 16px 16px 5px;
  overflow: hidden;
  background: var(--surface-2);
}
.chat-gif.mine{
  align-self: flex-end;
  border-radius: 16px 16px 5px 16px;
}
.chat-gif img,
.gif-cell img{
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ---- Reactions (js/chat.js) ---- */

/* Tap a message to open its picker: iOS only fires click on a plain div
   that says it's clickable, and the tap flash would otherwise paint over
   the bubble. */
.chat-bubble[data-msg],
.chat-gif[data-msg]{
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.chat-react-bar,
.chat-reactions{
  flex: none;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  align-self: flex-start;
  max-width: min(92%, 520px);
  margin-top: 4px;
}
.chat-react-bar.mine,
.chat-reactions.mine{
  align-self: flex-end;
  justify-content: flex-end;
}
.chat-react-bar{
  gap: 2px;
  padding: 3px;
  border-radius: 999px;
  background: var(--surface);
  border: 1px solid var(--hairline-strong);
}
.chat-react-opt{
  width: 36px;
  height: 36px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  font-size: var(--fs-20);
  line-height: 1;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.chat-react-opt:hover{ background: rgba(var(--ink-rgb),0.08); }
.chat-react-opt.on{ background: var(--accent-soft); box-shadow: inset 0 0 0 1px var(--accent-border); }
.chat-react-pill{
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: 26px;
  padding: 0 9px 0 7px;
  border-radius: 999px;
  border: 1px solid var(--hairline-strong);
  background: var(--surface-2);
  color: var(--text-sub);
  font-size: var(--fs-13);
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.chat-react-pill span{ font-size: var(--fs-12); font-variant-numeric: tabular-nums; }

/* A newly arrived message (and an opened reaction picker) eases in from
   its own side. js/chat.js's renderList adds .chat-in only to rows it
   just created, never to the history painted when the tab opens, and
   skips it entirely under reduced motion. */
@media (prefers-reduced-motion: no-preference){
  .chat-in{ animation: chat-in 240ms var(--ease-out) both; transform-origin: bottom left; }
  .chat-in.mine{ transform-origin: bottom right; }
  .chat-react-bar.chat-in{ animation: chat-react-in 200ms var(--ease-spring) both; }
  .gif-panel.open{ animation: gif-panel-in 220ms var(--ease-out); }
}
@keyframes chat-in{ from{ opacity: 0; transform: translateY(8px) scale(0.96); } }
@keyframes chat-react-in{ from{ opacity: 0; transform: translateY(-4px) scale(0.9); } }
@keyframes gif-panel-in{ from{ opacity: 0; transform: translateY(12px); } }
.chat-react-pill.on{
  background: var(--accent-soft);
  border-color: var(--accent-border);
  color: var(--text);
}

.chat-gif-btn{
  flex: 0 0 auto;
  align-self: flex-end;
  height: 38px;
  padding: 0 12px;
  border-radius: 19px;
  border: 1px solid var(--hairline-strong);
  background: none;
  color: var(--text-sub);
  font-family: 'Space Grotesk', sans-serif;
  font-size: var(--fs-12);
  font-weight: 700;
  letter-spacing: 0.5px;
  cursor: pointer;
}
.chat-gif-btn[hidden]{ display: none; }
.chat-gif-btn.active{
  color: var(--accent);
  border-color: var(--accent-border);
  background: var(--accent-soft);
}

/* Sits between the message list and the composer while open, taking its
   height out of the list's. Taller while the keyboard is up (typing a
   search) since results are what you're looking at then. */
.gif-panel{
  display: none;
  flex: 0 0 auto;
  height: 44%;
  flex-direction: column;
  padding: 8px max(12px, calc((100% - 720px) / 2)) 0;
  border-top: 1px solid var(--hairline);
  background: var(--bg);
}
.gif-panel.open{ display: flex; }
.chat-screen.kb-open .gif-panel{ height: 62%; }

.gif-search-row{
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
}
#gif-search{
  flex: 1 1 auto;
  min-width: 0;
  padding: 8px 14px;
  border-radius: 18px;
  border: 1px solid var(--hairline-strong);
  background: var(--surface);
  color: var(--text);
  font-family: 'Manrope', sans-serif;
  /* 16px minimum, same iOS-zoom reason as the composer's textarea. */
  font-size: 16px;
  font-weight: 500;
  outline: none;
  -webkit-appearance: none;
  appearance: none;
}
#gif-search:focus{ border-color: var(--accent-border); }
#gif-search::placeholder{ color: var(--text-mute); }
.gif-close{
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border: none;
  border-radius: 50%;
  background: none;
  color: var(--text-sub);
  cursor: pointer;
}
.gif-close:hover{ background: rgba(var(--ink-rgb),0.06); color: var(--text); }
.gif-close svg{ width: 18px; height: 18px; }

.gif-grid{
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
  align-items: start;
}
.gif-col{
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}
.gif-cell{
  position: relative;
  flex: none;
  display: block;
  width: 100%;
  padding: 0;
  border: none;
  border-radius: 10px;
  overflow: hidden;
  background: var(--surface-2);
  cursor: pointer;
}
.gif-status{
  flex: 0 0 auto;
  padding: 8px 0;
  text-align: center;
  font-size: var(--fs-13);
  font-weight: 600;
  color: var(--text-mute);
}
.gif-retry{
  font-family: 'Manrope', sans-serif;
  font-size: var(--fs-13);
  font-weight: 800;
  color: var(--accent);
  background: none;
  border: none;
  text-decoration: underline;
  cursor: pointer;
}
.gif-attribution{
  flex: 0 0 auto;
  padding: 6px 0 4px;
  text-align: center;
  font-size: var(--fs-11);
  font-weight: 700;
  letter-spacing: 0.3px;
  color: var(--text-mute);
}

/* ---- Settings page (#view-settings, js/identity.js) ----
   One scrolling column of cards pushed in from the header gear. Every
   control saves on tap and repaints in place. */
.settings-page{
  max-width: 560px;
  margin: 0 auto;
  padding: 0 4px 40px;
  display: flex;
  flex-direction: column;
  gap: 24px;
}

/* Same header as every other page (logo + h1; no gear, since this is
   where it leads), with the back row under it like the Commissioner page's.
   .set-head keeps the two together as one item of the page's 24px-gap
   column. */
.set-head .page-header{ padding-bottom: 4px; }

.set-identity{
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 16px;
  border-radius: var(--r-lg);
  background: var(--surface);
  border: 1px solid var(--hairline);
  color: var(--text);
  font-family: var(--font-ui);
  text-align: left;
  cursor: pointer;
}
.set-mono{
  flex: none;
  width: 56px;
  height: 56px;
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 800;
  font-size: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.set-identity-text{ flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.set-identity-name{ font-weight: 800; font-size: 20px; letter-spacing: -0.01em; }
.set-identity-switch{ font-size: 13px; font-weight: 700; color: var(--accent); }

.set-section{ display: flex; flex-direction: column; gap: 10px; }
.set-label{
  font-size: 11px;
  font-weight: 700;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--text-mute);
}

.set-themes{ display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.set-theme{
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 8px;
  padding: 8px;
  border-radius: var(--r-md);
  background: var(--surface);
  border: 1.5px solid transparent;
  font-family: var(--font-ui);
  text-align: left;
  cursor: pointer;
  transition: border-color 0.15s ease;
}
.set-theme.on{ border-color: var(--accent); }
.set-swatch{ height: 56px; border-radius: 8px; border: 1px solid var(--hairline); }
.set-theme-label{ font-size: 13px; font-weight: 700; color: var(--text-sub); transition: color 0.15s ease; }
.set-theme.on .set-theme-label{ color: var(--text); }

.set-chips{ display: flex; flex-wrap: wrap; gap: 8px; }
.set-chip{
  font-family: var(--font-ui);
  font-size: 14px;
  font-weight: 700;
  padding: 9px 15px;
  border-radius: 999px;
  background: var(--surface);
  color: var(--text);
  border: 1px solid transparent;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.set-chip.on{ background: var(--accent-soft); color: var(--accent); border-color: var(--accent-border); }

.set-row{
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  padding: 14px;
  border: none;
  border-radius: var(--r-md);
  background: var(--surface);
  color: var(--text);
  font-family: var(--font-ui);
  text-align: left;
  cursor: pointer;
}
.set-row-text{ display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.set-row-title{ font-size: 15px; font-weight: 700; }
.set-row-sub{ font-size: 13px; color: var(--text-sub); }
.set-chev{ color: var(--text-mute); font-size: var(--fs-20); }

.set-tiles{ display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.set-tile{
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 14px;
  border: none;
  border-radius: var(--r-md);
  background: var(--surface);
  color: var(--text);
  font-family: var(--font-ui);
  text-align: left;
  cursor: pointer;
}
.set-tile-sub{ font-size: 12px; color: var(--text-sub); }

.set-foot{ font-size: 12px; color: var(--text-mute); text-align: center; }
.set-version{ margin-top: -14px; font-size: var(--fs-10); font-weight: 600; letter-spacing: 0.2px; opacity: 0.6; }

/* Light theme: labels one step darker for contrast, chips get an edge
   against the pale page. */
html[data-theme="light"] .set-label{ color: var(--text-sub); }
html[data-theme="light"] .set-chip:not(.on){ border-color: var(--hairline); }
@media (prefers-color-scheme: light){
  html[data-theme="auto"] .set-label{ color: var(--text-sub); }
  html[data-theme="auto"] .set-chip:not(.on){ border-color: var(--hairline); }
}

.switch{
  flex: 0 0 auto;
  position: relative;
  width: 44px;
  height: 26px;
  border-radius: 999px;
  border: none;
  background: rgba(var(--ink-rgb),0.16);
  cursor: pointer;
  transition: background 0.2s ease;
}

.switch::after{
  content: '';
  position: absolute;
  top: 2px;
  left: 2px;
  width: 22px;
  height: 22px;
  border-radius: 999px;
  background: #fff;
  transition: transform 0.2s ease;
}

.switch.on{ background: var(--accent-fill); }
.switch.on::after{ transform: translateX(18px); }


/* ==== UI consistency pass — interaction layer ====
   Appended last so it layers over the component rules above. */

/* Press feedback (R3). Card surfaces get a tint overlay via
   background-image so their own background color survives. */
.ob-table-row, .news-card, .tg-card, .game-card, .ob-card-head,
.standings-row.clickable, .sheet-row, .team.clickable{
  transition: background-color var(--dur-ui) var(--ease-out), border-color var(--dur-ui) var(--ease-out), transform var(--dur-press) var(--ease-out);
}
.news-card:active, .tg-row.clickable:active .tg-card{
  background-image: linear-gradient(var(--press), var(--press));
  transform: scale(0.985);
}
.standings-row.clickable:active, .sheet-row:active, .ob-card-head:active{ background-color: var(--press); }

.modal-cta, .admin-gate-btn, .ob-detail-link, .admin-adj-save, .chat-send,
.scope-chip, .ob-back, .team-page-back, .gd-back, .modal-close, .seg-btn{
  transition: background-color var(--dur-ui) var(--ease-out), color var(--dur-ui) var(--ease-out), transform var(--dur-press) var(--ease-out);
}
.modal-cta:active, .admin-gate-btn:active, .ob-detail-link:active, .admin-adj-save:active,
.chat-send:active, .peek-banner button:active{ transform: scale(0.97); }
.scope-chip:active, .ob-back:active, .team-page-back:active{ background-color: var(--press); }
.gd-back:active, .modal-close:active, .picker-hit:active .settings-icon{ transform: scale(0.92); }
.tab-btn:active .tab-icon{ transform: scale(0.94); }

/* Keyboard focus (R4) */
:where(button, a, [role="button"], [role="switch"], [tabindex]):focus-visible{
  outline: none;
  box-shadow: var(--focus-ring);
}
:where(input, textarea, select):focus-visible{
  outline: none;
  border-color: var(--accent-border);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

/* Tab switch fade (R5) — opacity only so sticky/fixed children are
   unaffected. Pushed views keep their own slide-in. */
@keyframes view-in{ from{ opacity: 0; } to{ opacity: 1; } }
.board > .view.active:not(.view-push-in){ animation: view-in 180ms var(--ease-out); }

/* Sticky peek banner (R7). Opaque base under the tonal wash so content
   doesn't show through while scrolling. Standings already pins its
   own filter row at this offset, so the banner stays static there. */
.peek-banner{
  position: sticky;
  top: calc(env(safe-area-inset-top) + 8px);
  z-index: 6;
  background: linear-gradient(var(--accent-soft), var(--accent-soft)), var(--bg);
}
#view-standings .peek-banner{ position: static; }

/* Tabular numerals on every number column (R10) */
.standings-row, .person-record-chip, .league-tab .n,
.ob-rank, .ob-detail-total, .ob-card-pts, .ob-rule-pts, .ob-table-row, .ob-ladder-row,
.stat-cell .num, .stat-tile .num, .form-score, .tracker-total, .tracker-value,
.scoring-value, .fact-pts, .tg-score, .tg-rail-top, .gd-score-team b,
.linescore-table, .box-table, .gd-teamstats, .chat-time, .chat-badge{
  font-variant-numeric: tabular-nums;
}

/* Skeleton placeholders (R6) — shapes match .standings-row and the
   team modal's form/next-match blocks so nothing jumps on load. */
.skel-rows{ display: flex; flex-direction: column; }
.skel-row{ display: flex; align-items: center; gap: 12px; padding: 12px 18px; min-height: 44px; }
.skel-row + .skel-row{ border-top: 1px solid var(--hairline); }
.skel-dot{ flex: 0 0 28px; height: 28px; border-radius: 8px; background: rgba(var(--ink-rgb),0.07); animation: skel 1.5s ease-in-out infinite; }
.skel-row .skel-bar{ flex: 0 1 var(--w, 50%); }
.skel-row .skel-bar.end{ flex: 0 0 34px; margin-left: auto; }
.skel-lines{ display: flex; flex-direction: column; gap: 10px; padding: 4px 0; }
.skel-lines .skel-bar{ width: var(--w, 100%); }

@media (prefers-reduced-motion: reduce){
  .board > .view.active:not(.view-push-in){ animation: none; }
  .skel-dot{ animation: none; }
  .ob-row:active, .news-card:active, .tg-row.clickable:active .tg-card,
  .modal-cta:active, .admin-gate-btn:active, .ob-detail-link:active, .admin-adj-save:active,
  .chat-send:active, .peek-banner button:active, .gd-back:active, .modal-close:active,
  .picker-hit:active .settings-icon, .tab-btn:active .tab-icon{ transform: none; }
}


/* ==== Tags: one shape for every status pill (R9) ====
   season-badge, zone-tag, pts-tag and status-pill all share the same
   recipe; each keeps only its own color. */
.season-badge, .zone-tag, .pts-tag, .status-pill{
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-family: var(--font-ui);
  font-size: var(--fs-10);
  font-weight: 800;
  line-height: 1;
  letter-spacing: var(--track-tag);
  text-transform: uppercase;
  border-radius: var(--r-xs);
  padding: 4px 6px;
  vertical-align: middle;
  white-space: nowrap;
}

/* ============================================================
   Head to head (Compare) — see js/compare.js. Every colour here is an
   existing token so the light theme needs no extra rules.
   ============================================================ */
.ob-back-row{ display: flex; align-items: center; justify-content: space-between; }
.cmp-btn{
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 36px; padding: 0 12px;
  background: transparent;
  border: 1px solid var(--hairline-strong);
  border-radius: 10px;
  color: var(--accent);
  font-family: var(--font-ui); font-size: var(--fs-13); font-weight: 700;
  cursor: pointer;
}
.cmp-btn:hover{ background: var(--accent-soft); border-color: var(--accent-border); }

.cmp-eyebrow{ margin: 4px 2px 12px; }
.cmp-head{ padding: 16px 16px 14px; margin-bottom: 22px; }
.cmp-head-grid{ display: grid; grid-template-columns: 1fr auto 1fr; align-items: end; gap: 8px; }
.cmp-side{ min-width: 0; }
.cmp-side.r{ text-align: right; }
.cmp-side-label{
  font-size: var(--fs-11); font-weight: 700; letter-spacing: var(--track-label);
  text-transform: uppercase; color: var(--text-sub);
}
.cmp-side-name{
  display: inline-flex; align-items: center; gap: 4px;
  font-family: 'Space Grotesk', sans-serif; font-size: 22px; font-weight: 700;
  letter-spacing: -0.02em; margin: 6px 0 2px; color: var(--text);
  background: none; border: none; padding: 0; max-width: 100%;
}
.cmp-side-name.a{ color: var(--accent); }
.cmp-side-name.b{ cursor: pointer; }
.cmp-side-total{
  font-family: 'Space Grotesk', sans-serif; font-size: 44px; font-weight: 700;
  line-height: 1; color: var(--text);
}
.cmp-side-total.b{ color: var(--lb-ink-2); }
.cmp-mid{ display: flex; flex-direction: column; align-items: center; gap: 6px; padding-bottom: 4px; }
.cmp-gap-pill{
  font-family: 'Space Grotesk', sans-serif; font-size: var(--fs-17); font-weight: 700;
  padding: 4px 12px; border-radius: 999px;
}
.cmp-gap-pill.pos{ color: var(--win); background: var(--win-soft); }
.cmp-gap-pill.neg{ color: var(--loss); background: var(--loss-soft); }
.cmp-gap-pill.zero{ color: var(--text-sub); background: rgba(var(--ink-rgb),0.06); }
.cmp-head-foot{
  display: flex; align-items: center; gap: 8px;
  margin-top: 14px; padding-top: 12px;
  border-top: 1px solid var(--hairline);
  font-size: var(--fs-13); color: var(--text-sub);
}
.cmp-head-foot strong{ color: var(--text); font-weight: 700; }
.cmp-head-foot-text{ flex: 1; min-width: 0; }
.cmp-change{
  background: none; border: none; padding: 6px 0 6px 8px; cursor: pointer;
  color: var(--accent); font-family: var(--font-ui); font-size: var(--fs-12); font-weight: 700;
}

.cmp-title-row{ display: flex; justify-content: space-between; align-items: baseline; gap: 12px; padding: 0 2px; margin-bottom: 8px; }
.cmp-title-note{ font-size: var(--fs-11); font-weight: 600; letter-spacing: 0; text-transform: none; color: var(--text-mute); }
.cmp-card{ padding: 2px 16px; margin-bottom: 22px; }

.cmp-race{ padding: 12px 0; border-bottom: 1px solid var(--lb-divider); display: flex; flex-direction: column; gap: 9px; }
.cmp-race:last-of-type{ border-bottom: none; }
.cmp-race-top{ display: flex; align-items: center; gap: 8px; }
.cmp-league-dot{ width: 8px; height: 8px; border-radius: 2px; flex: none; display: inline-block; }
.cmp-race-name{ font-family: 'Space Grotesk', sans-serif; font-size: 14px; font-weight: 600; flex: 1; min-width: 0; }
.cmp-chip{
  font-size: 10.5px; font-weight: 700; padding: 2px 6px; border-radius: 5px;
  border: 1px solid transparent; white-space: nowrap;
}
.cmp-chip.prov{ color: var(--provisional); background: var(--provisional-soft); border-color: var(--provisional-border); }
.cmp-chip.locked{ color: var(--accent); background: var(--accent-soft); border-color: var(--accent-border); }
.cmp-chip.other{ color: var(--text-sub); border-color: var(--hairline-strong); }
.cmp-race-bar{ display: grid; grid-template-columns: 52px 1fr 52px; align-items: center; gap: 12px; }
.cmp-race-val{ font-family: 'Space Grotesk', sans-serif; font-size: 15px; font-weight: 700; color: var(--lb-ink-2); white-space: nowrap; }
.cmp-race-val.r{ text-align: right; }
.cmp-race-val.hold{ color: var(--accent); }
.cmp-race-val.flat{ color: var(--text-sub); }
.cmp-tug{ display: flex; gap: 2px; height: 6px; }
.cmp-tug > span{ display: block; height: 100%; }
.cmp-tug-l{ border-radius: 3px 0 0 3px; }
.cmp-tug-r{ flex: 1; border-radius: 0 3px 3px 0; }
.cmp-tug .hold{ background: var(--accent); }
.cmp-tug .dim{ background: var(--lb-stroke); }
.cmp-tug .none-l{ background: var(--lb-stroke); }
.cmp-tug .none-r{ background: rgba(var(--ink-rgb),0.12); }
.cmp-foot-note, .cmp-empty{ padding: 12px 0; font-size: var(--fs-12); color: var(--text-mute); }

.cmp-gap-row{
  display: grid; grid-template-columns: 1fr 64px 50px 44px; align-items: center; gap: 4px;
  padding: 12px 0; border-bottom: 1px solid var(--lb-divider);
  font-size: var(--fs-13); font-weight: 600;
}
.cmp-gap-row.head{
  padding: 12px 0 8px; font-size: var(--fs-10); font-weight: 700;
  letter-spacing: var(--track-tag); text-transform: uppercase; color: var(--text-mute);
}
.cmp-gap-row.head span:not(:first-child){ text-align: right; }
.cmp-gap-league{ display: flex; align-items: center; gap: 8px; min-width: 0; font-family: 'Space Grotesk', sans-serif; font-size: 14px; }
.cmp-num{ text-align: right; font-family: 'Space Grotesk', sans-serif; font-size: 14px; font-weight: 700; display: block; }
.cmp-net .cmp-num{ font-size: 15px; }
.cmp-num.pos, .cmp-net-total.pos{ color: var(--win); }
.cmp-num.neg, .cmp-net-total.neg{ color: var(--loss); }
.cmp-num.zero, .cmp-net-total.zero{ color: var(--text-mute); }
.cmp-gap-foot{ display: flex; justify-content: space-between; align-items: center; padding: 14px 0; font-size: var(--fs-13); color: var(--text-sub); }
.cmp-net-total{ font-family: 'Space Grotesk', sans-serif; font-size: 20px; font-weight: 700; }

/* Compact bar that replaces the big header once it scrolls away. Takes
   no layout space (negative bottom margin) so nothing jumps. */
.cmp-sticky{
  position: sticky; top: env(safe-area-inset-top); z-index: 6;
  display: flex; align-items: center; gap: 8px;
  height: 48px; margin: 0 calc(-1 * var(--page-pad)) -48px; padding: 0 var(--page-pad);
  background: var(--bar-bg);
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--hairline);
  opacity: 0; pointer-events: none; transition: opacity 0.15s ease;
  transform: translateZ(0);
  font-family: 'Space Grotesk', sans-serif; font-size: 15px; font-weight: 700;
}
.cmp-sticky.show{ opacity: 1; pointer-events: auto; }
.cmp-sticky-back{ background: none; border: none; color: var(--text-sub); padding: 0 4px 0 0; display: flex; }
.cmp-sticky-back svg{ width: 17px; height: 17px; }
.cmp-sticky-a{ color: var(--accent); }
.cmp-sticky-b{ color: var(--lb-ink-2); }
.cmp-sticky-gap{ font-size: 12px; }
.cmp-sticky-gap.pos{ color: var(--win); }
.cmp-sticky-gap.neg{ color: var(--loss); }
.cmp-sticky-gap.zero{ color: var(--text-mute); }
.cmp-sticky .cmp-change{ margin-left: auto; }

/* Picker sheet rows */
.cmp-pick-list{ padding: 0 12px 16px; }
.cmp-pick{
  display: grid; grid-template-columns: 26px 1fr auto auto; align-items: center; gap: 10px;
  width: 100%; min-height: 50px; padding: 0 10px;
  background: none; border: none; border-bottom: 1px solid var(--lb-divider); border-radius: 12px;
  text-align: left; cursor: pointer; color: var(--text);
}
.cmp-pick.current, .cmp-pick:hover{ background: rgba(var(--ink-rgb),0.05); }
.cmp-pick-rank{ font-size: var(--fs-13); font-weight: 700; color: var(--lb-rank-low); }
.cmp-pick-name{ font-family: 'Space Grotesk', sans-serif; font-size: var(--fs-17); font-weight: 600; }
.cmp-pick-gap{ font-size: var(--fs-12); font-weight: 600; color: var(--text-sub); }
.cmp-pick-total{ font-family: 'Space Grotesk', sans-serif; font-size: var(--fs-17); font-weight: 700; color: var(--lb-ink-2); min-width: 22px; text-align: right; }

/* Same race cards */
.cmp-same{ padding: 14px 16px 12px; margin-bottom: 10px; }
.cmp-same .cmp-race-top{ margin-bottom: 4px; }
.cmp-chip-caps{ font-size: var(--fs-10); letter-spacing: var(--track-tag); text-transform: uppercase; }
.cmp-team{
  display: grid; grid-template-columns: 28px 1fr auto; align-items: center; gap: 12px;
  width: 100%; padding: 8px 0; background: none; border: none; text-align: left; cursor: pointer; color: var(--text);
}
.cmp-badge{ width: 28px; height: 28px; display: block; }
.cmp-badge .badge{ width: 28px; height: 28px; border-radius: 8px; font-size: 9px; }
.cmp-team-name{ font-family: 'Space Grotesk', sans-serif; font-size: 15px; font-weight: 600; min-width: 0; }
.cmp-team-owner{ font-weight: 500; color: var(--text-sub); }
.cmp-team-owner.a{ color: var(--accent); }
.cmp-team-rec{ font-size: var(--fs-13); font-weight: 600; color: var(--text-sub); white-space: nowrap; }
.cmp-same-note{ margin-top: 4px; font-size: var(--fs-12); color: var(--text-sub); line-height: 1.45; }

/* ============================================================
   Activity feed — see js/activity.js. Existing tokens only.
   ============================================================ */
.act-tile{
  width: 30px; height: 30px; border-radius: 9px; flex: none;
  display: flex; align-items: center; justify-content: center;
  font-family: 'Space Grotesk', sans-serif; font-size: 9.5px; font-weight: 700;
}
.act-tile.rank{ background: var(--accent-soft); color: var(--accent); font-size: 12px; }
.act-body{ display: flex; flex-direction: column; gap: 3px; min-width: 0; text-align: left; }
.act-title{ font-size: var(--fs-13); font-weight: 600; color: var(--text); line-height: 1.3; }
.act-sub{ font-size: 11.5px; color: var(--text-sub); }
.act-chips{ display: flex; flex-wrap: wrap; gap: 5px; margin-top: 1px; }
.act-chips:empty{ display: none; }
.act-chip{ font-size: var(--fs-11); font-weight: 700; padding: 2px 6px; border-radius: 6px; border: 1px solid transparent; }
.act-chip.prov{ color: var(--provisional); background: var(--provisional-soft); border-color: var(--provisional-border); }
.act-chip.win{ color: var(--win); background: var(--win-soft); }
.act-chip.loss{ color: var(--loss); background: var(--loss-soft); }
.act-chip.rank{ color: var(--lb-ink-2); background: rgba(var(--ink-rgb),0.06); }
.act-time{ font-size: var(--fs-11); font-weight: 600; color: var(--text-mute); }

/* Home: one slim link row into Points > Activity */
#activity-home:empty{ display: none; }
.act-dot{ width: 7px; height: 7px; border-radius: 50%; background: var(--accent); flex: none; }
.act-link{
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
  align-items: center;
  width: 100%;
  margin-bottom: 16px;
  padding: 11px 14px;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 12px;
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.act-link.unseen{ grid-template-columns: 8px minmax(0, 1fr) auto; }
.act-link-body{ display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.act-link-title{ font-size: var(--fs-13); font-weight: 700; }
.act-link.unseen .act-link-title{ font-weight: 800; }
.act-link-sub{ font-size: var(--fs-12); font-weight: 600; color: var(--text-sub); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.act-link-go{ font-size: var(--fs-12); font-weight: 800; color: var(--text-sub); white-space: nowrap; }
.act-link.unseen .act-link-go{ color: var(--accent); }

/* Points > Activity */
.act-filters{ padding-bottom: 14px; }
.act-group{ padding: 0; overflow: hidden; margin-bottom: 14px; }
.act-row{
  display: grid; grid-template-columns: 34px minmax(0, 1fr) auto; gap: 10px; align-items: start;
  width: 100%; padding: 12px 14px; background: none; border: none;
  border-bottom: 1px solid var(--hairline); cursor: pointer; text-align: left; color: var(--text); font: inherit;
}
.act-row:last-child{ border-bottom: none; }
.act-row.lock{ background: var(--lb-accent-wash); }
.act-row.compact{ align-items: center; padding: 11px 14px; cursor: default; }
.act-row .act-tile{ width: 34px; height: 34px; font-size: var(--fs-10); }
.act-row .pts-tag{ align-self: flex-start; }
.act-row .act-title{ font-size: 14px; font-weight: 700; }
.act-row.compact .act-title{ font-size: var(--fs-13); }
.act-right{ display: flex; flex-direction: column; align-items: flex-end; gap: 2px; }
.act-delta{ font-family: var(--font-display); font-size: 18px; font-weight: 700; line-height: 1.1; white-space: nowrap; }
.act-row.compact .act-delta{ font-size: 16px; }
.act-delta.live, .act-delta-inline.live{ color: var(--provisional); }
.act-delta.risk, .act-delta-inline.risk{ color: var(--loss); }
.act-delta.lock, .act-delta-inline.lock{ color: var(--accent); }
.act-delta.up, .act-delta-inline.up{ color: var(--win); }
.act-delta.down, .act-delta-inline.down{ color: var(--loss); }
.act-chip.locked{ color: var(--accent); background: var(--accent-soft); }
.act-foot{ font-size: var(--fs-12); font-weight: 600; color: var(--text-mute); text-align: center; padding: 4px 0 8px; }

/* ============================================================
   Draft room (js/draft.js) — #view-draft.
   A full-screen view like Chat: fixed-positioned, with each column
   scrolling on its own. Built entirely on the shared tokens above, so
   the light theme comes for free. Wide screens get three columns
   (Available | Board | Roster+Queue); under 1180px the roster/queue
   column shares the left slot with Available behind a tab switch; the
   phone layout proper arrives with Phase E of docs/draft-room-plan.md.
   ============================================================ */
.draft-screen{
  position: fixed;
  left: 0; right: 0; top: 0;
  bottom: calc(var(--nav-h) + env(safe-area-inset-bottom));
  z-index: 190;
  background: var(--bg);
  flex-direction: column;
}
.draft-screen.view.active{ display: flex; }
.draft-head{
  flex: 0 0 auto;
  padding: calc(env(safe-area-inset-top) + var(--page-pad)) var(--page-pad) 0;
  border-bottom: 1px solid var(--hairline);
}
.draft-head .page-header{ padding-bottom: 10px; }
.draft-status{
  margin-left: auto;
  display: flex; align-items: center; gap: 7px;
  height: 28px; padding: 0 12px;
  border-radius: var(--r-pill);
  background: var(--seg-track);
  font-size: var(--fs-12); font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}
.draft-status i{ width: 7px; height: 7px; border-radius: 50%; flex: 0 0 auto; }
.draft-status[hidden]{ display: none; }
.draft-status:not([hidden]) + .picker-hit{ margin-left: 8px; }
/* Phones: the chip drops to its own line under the title (the ::after is
   a full-width line break inside the wrapping header row), smaller, so
   the title row keeps the Settings gear in the top-right corner. */
@media (max-width: 700px){
  .draft-head .page-header-top::after{ content: ''; order: 9; flex-basis: 100%; height: 0; }
  .draft-head .draft-status{ order: 10; margin-left: 0; height: 22px; padding: 0 9px; gap: 6px; font-size: var(--fs-11); }
  .draft-head .draft-status i{ width: 6px; height: 6px; }
  .draft-head .draft-status:not([hidden]) + .picker-hit{ margin-left: auto; }
}
.draft-body{ flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }
.dr-connecting{ padding: 60px 24px; text-align: center; color: var(--text-sub); font-size: var(--fs-15); }
.dr-dim{ color: var(--text-mute); }
.draft-toast{
  position: fixed; left: 50%; bottom: calc(var(--nav-h) + env(safe-area-inset-bottom) + 18px);
  transform: translate(-50%, 12px); opacity: 0; pointer-events: none;
  max-width: min(90vw, 420px); padding: 10px 16px;
  background: var(--sheet); color: var(--text);
  border: 1px solid var(--hairline-strong); border-radius: var(--r-md);
  font-size: var(--fs-13); font-weight: 600; z-index: 400;
  transition: opacity var(--dur-ui) var(--ease-out), transform var(--dur-ui) var(--ease-out);
}
.draft-toast.show{ opacity: 1; transform: translate(-50%, 0); }

/* Buttons */
.dr-btn{
  height: 34px; padding: 0 14px;
  border-radius: var(--r-sm); border: 1px solid var(--hairline-strong);
  background: var(--seg-track); color: var(--text);
  font: inherit; font-size: var(--fs-13); font-weight: 600; cursor: pointer;
  transition: transform var(--dur-press) var(--ease-out), background var(--dur-ui) var(--ease-out);
}
.dr-btn:active{ transform: scale(0.97); }
.dr-btn[disabled]{ opacity: 0.4; pointer-events: none; }
.dr-btn-primary{ height: 44px; padding: 0 22px; border-radius: 12px; background: var(--accent-fill); border-color: transparent; color: var(--on-accent); font-size: var(--fs-15); font-weight: 700; }
.dr-btn-gold{ background: var(--accent-soft); border-color: var(--accent-border); color: var(--accent); }

/* Lobby */
.dr-lobby{ max-width: 720px; margin: 0 auto; padding: 40px 20px 60px; display: flex; flex-direction: column; gap: 22px; }
.dr-eyebrow{ font-size: var(--fs-11); font-weight: 700; letter-spacing: 0.08em; color: var(--text-mute); display: flex; align-items: center; gap: 8px; }
.dr-lobby .dr-eyebrow, .dr-eyebrow.gold{ color: var(--accent); }
.dr-lobby-title{ font-family: 'Space Grotesk', sans-serif; font-size: 40px; font-weight: 700; letter-spacing: -0.025em; line-height: 1.05; margin: 0; }
.dr-lobby-copy{ margin: 0; max-width: 560px; font-size: var(--fs-15); line-height: 1.5; color: var(--text-sub); }
.dr-card{ background: var(--surface); border: 1px solid var(--hairline); border-radius: var(--r-lg); overflow: hidden; }
.dr-card-head{ display: flex; justify-content: space-between; align-items: baseline; padding: 14px 18px; border-bottom: 1px solid var(--hairline); }
.dr-card-head h3{ margin: 0; font-size: var(--fs-17); font-weight: 700; }
.dr-order-row{ display: grid; grid-template-columns: 44px 1fr auto; align-items: center; min-height: 48px; padding: 0 18px; transition: background 0.3s; border-bottom: 1px solid var(--hairline); }
.dr-order-row:last-child{ border-bottom: 0; }
.dr-order-row.shown{ background: var(--seg-track); }
.dr-order-row.me{ background: var(--accent-soft); }
.dr-order-n{ font-size: 18px; font-weight: 800; font-variant-numeric: tabular-nums; }
.dr-order-name{ font-size: var(--fs-17); font-weight: 600; }
.dr-you{ font-size: var(--fs-11); font-weight: 800; letter-spacing: 0.06em; color: var(--accent); }
.dr-first-picks{ font-size: var(--fs-13); color: var(--text-sub); font-variant-numeric: tabular-nums; }
.dr-actions{ display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.dr-actions-sub{ gap: 12px; }
.dr-bot-actions{ padding: 14px 18px; margin: 0; }
.dr-bot-tag{ font-size: var(--fs-11); font-weight: 800; letter-spacing: var(--track-label); color: var(--text-mute); }
.dr-inline{ display: flex; align-items: center; gap: 8px; font-size: var(--fs-13); color: var(--text-sub); }
.dr-inline select{ height: 34px; border-radius: var(--r-sm); border: 1px solid var(--hairline-strong); background: var(--surface); color: var(--text); padding: 0 8px; font: inherit; }
.dr-wait{ font-size: var(--fs-13); color: var(--text-sub); }

/* Live room layout */
.dr-layout{
  height: 100%;
  display: grid;
  grid-template-columns: var(--dr-left, minmax(280px, 340px)) minmax(0, 1fr) var(--dr-right, minmax(260px, 300px));
  grid-template-areas: "left center right";
  transition: grid-template-columns var(--dur-move) var(--ease-out);
  min-height: 0;
}
.dr-tabs{ display: none; }
.dr-col{ min-height: 0; min-width: 0; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; padding: 14px 16px; }
.dr-left{ grid-area: left; border-right: 1px solid var(--hairline); display: flex; flex-direction: column; gap: 10px; }
.dr-center{ grid-area: center; display: flex; flex-direction: column; gap: 10px; padding: 14px 16px 0; overflow: hidden; }
.dr-right{ grid-area: right; border-left: 1px solid var(--hairline); }
@media (max-width: 1179px){
  .dr-layout{ grid-template-columns: var(--dr-side, minmax(270px, 320px)) minmax(0, 1fr); grid-template-areas: "tabs center" "side center"; grid-template-rows: auto 1fr; }
  .dr-tabs{ grid-area: tabs; display: grid; grid-template-columns: 1fr 1fr; gap: 2px; padding: 10px 16px 0; border-right: 1px solid var(--hairline); }
  .dr-left, .dr-right{ grid-area: side; border: 0; border-right: 1px solid var(--hairline); }
  .dr-layout[data-left-tab="available"] .dr-right{ display: none; }
  .dr-layout[data-left-tab="team"] .dr-left{ display: none; }
  .dr-tab{ height: 36px; border: 0; border-radius: var(--r-sm); background: var(--seg-track); color: var(--text-sub); font: inherit; font-size: var(--fs-13); font-weight: 600; cursor: pointer; }
  .dr-tab.on{ background: var(--seg-thumb); color: var(--text); }
}
.dr-col-head{ display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.dr-col-head h2{ margin: 0; font-size: var(--fs-17); font-weight: 700; }
.dr-section-head{
  position: sticky; top: -6px; z-index: 2;
  display: flex; align-items: center; gap: 6px;
  margin: 0 -8px; padding: 12px 16px 6px;
  background: var(--bg); border-bottom: 1px solid var(--hairline);
  font-size: var(--fs-12); font-weight: 700; letter-spacing: 0.04em; color: var(--text-sub);
}
.dr-section-head i{ width: 6px; height: 6px; border-radius: 1px; }
.dr-section-head span{ margin-left: auto; font-weight: 600; letter-spacing: 0; color: var(--text-mute); }
.dr-search{ flex: 0 0 auto; width: 100%; height: 40px; padding: 0 12px; border-radius: var(--r-sm); border: 1px solid var(--hairline-strong); background: var(--surface); color: var(--text); font: inherit; font-size: 16px; }
.dr-search::placeholder{ color: var(--text-mute); }

/* Available: league tabs (a narrowing filter, so the selected tab is accent) */
.dr-ltabs-wrap{ flex: 0 0 auto; position: relative; margin-left: -16px; }
.dr-ltabs{
  display: flex; flex-wrap: nowrap; gap: 2px;
  overflow-x: auto; scrollbar-width: none;
  padding-left: 16px;
  border-bottom: 1px solid var(--hairline);
}
/* Fade whichever edge has tabs cut off (set by syncLeagueTabs) */
.dr-ltabs-wrap.more-r .dr-ltabs{
  -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 48px), transparent calc(100% - 14px));
  mask-image: linear-gradient(90deg, #000 calc(100% - 48px), transparent calc(100% - 14px));
}
.dr-ltabs-wrap.more-l .dr-ltabs{
  -webkit-mask-image: linear-gradient(90deg, transparent 30px, #000 64px);
  mask-image: linear-gradient(90deg, transparent 30px, #000 64px);
}
.dr-ltabs-wrap.more-l.more-r .dr-ltabs{
  -webkit-mask-image: linear-gradient(90deg, transparent 30px, #000 64px, #000 calc(100% - 48px), transparent calc(100% - 14px));
  mask-image: linear-gradient(90deg, transparent 30px, #000 64px, #000 calc(100% - 48px), transparent calc(100% - 14px));
}
.dr-ltabs-arrow{
  position: absolute; top: 0; bottom: 1px; z-index: 1; width: 26px;
  display: none; align-items: center; justify-content: center;
  padding: 0; border: 0; background: none; color: var(--text-sub); cursor: pointer;
}
.dr-ltabs-arrow:hover{ color: var(--text); }
.dr-ltabs-arrow.l{ left: 12px; }
.dr-ltabs-arrow.r{ right: 0; }
.dr-ltabs-wrap.more-l .dr-ltabs-arrow.l,
.dr-ltabs-wrap.more-r .dr-ltabs-arrow.r{ display: flex; }
.dr-ltabs::-webkit-scrollbar{ display: none; }
.dr-ltab{
  flex: 0 0 auto; display: inline-flex; align-items: center; gap: 5px;
  height: 36px; padding: 0 8px; margin-bottom: -1px;
  border: 0; border-bottom: 2px solid transparent; background: none;
  color: var(--text-sub); font: inherit; font-size: var(--fs-13); font-weight: 700; white-space: nowrap; cursor: pointer;
}
.dr-ltab span{ color: var(--text-mute); font-size: var(--fs-11); font-weight: 600; font-variant-numeric: tabular-nums; }
.dr-ltab:hover{ color: var(--text); }
.dr-ltab.on, .dr-ltab.on span{ color: var(--accent); }
.dr-ltab.on{ border-bottom-color: var(--accent); }

/* Available: scope row — Conference / Division menus, or a hint, then sort */
.dr-scope{ flex: 0 0 auto; position: relative; z-index: 25; display: flex; align-items: center; gap: 6px; min-height: 32px; }
.dr-scope-hint{ font-size: var(--fs-12); color: var(--text-mute); }
.dr-dd{ position: relative; min-width: 0; }
.dr-dd-sort{ margin-left: auto; flex: 0 0 auto; }
.dr-dd-btn, .dr-sort-btn{
  display: inline-flex; align-items: center; gap: 6px; max-width: 100%;
  height: 32px; padding: 0 10px; border-radius: var(--r-sm);
  font: inherit; font-size: var(--fs-12); font-weight: 700; white-space: nowrap; cursor: pointer;
}
.dr-dd-btn{ border: 1px solid transparent; background: var(--seg-track); color: var(--text); }
.dr-dd-btn.on{ background: var(--accent-soft); border-color: var(--accent-border); color: var(--accent); }
.dr-sort-btn{ padding: 0 8px 0 10px; border: 0; background: none; color: var(--text-sub); }
.dr-sort-btn:hover{ background: var(--seg-track); color: var(--text); }
.dr-dd-btn svg, .dr-sort-btn svg{ flex: 0 0 auto; }
.dr-menu{
  position: absolute; top: 38px; left: 0; min-width: 200px; max-height: 340px; overflow-y: auto;
  padding: 4px; display: flex; flex-direction: column; gap: 1px;
  background: var(--sheet); border: 1px solid var(--hairline-strong); border-radius: 12px;
  box-shadow: 0 12px 32px rgba(0,0,0,0.5);
}
.dr-dd-sort .dr-menu{ left: auto; right: 0; width: 210px; min-width: 0; }
.dr-menu-item{
  flex: 0 0 auto; display: flex; align-items: center; justify-content: space-between; gap: 12px;
  height: 36px; padding: 0 10px; border: 0; border-radius: 8px; background: transparent;
  color: var(--text); font: inherit; font-size: var(--fs-13); font-weight: 600; text-align: left; white-space: nowrap; cursor: pointer;
}
.dr-menu-item:hover{ background: var(--seg-track); }
.dr-menu-item.on{ background: var(--accent-soft); color: var(--accent); }
.dr-menu-item.empty{ opacity: 0.45; }
.dr-menu-n{ color: var(--text-mute); font-variant-numeric: tabular-nums; }
.dr-menu-sort{ height: auto; flex-direction: column; align-items: flex-start; gap: 1px; padding: 8px 10px; }
.dr-menu-sort small{ font-size: var(--fs-11); font-weight: 500; color: var(--text-mute); }
/* Click-away layer behind an open menu (the scope row sits above it). */
.dr-menu-back{ position: fixed; inset: 0; z-index: -1; }
.dr-link{ border: 0; padding: 0; background: none; color: var(--accent); font: inherit; font-weight: 700; cursor: pointer; }

/* Tiles */
.dr-tile{ position: relative; flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; font-weight: 800; letter-spacing: 0.01em; overflow: hidden; box-shadow: inset 0 0 0 1px rgba(255,255,255,0.12); }
.dr-tile-md{ width: 32px; height: 32px; border-radius: 8px; font-size: 9px; }
.dr-tile-sm{ width: 30px; height: 30px; border-radius: 7px; font-size: 9px; }
.dr-tile-xs{ width: 18px; height: 18px; border-radius: 5px; font-size: 7px; }
.dr-tile img{ position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; padding: 2px; box-sizing: border-box; background: #F1F2F4; }
.dr-tile-xs img{ padding: 1px; }
.dr-tile.has-crest .dr-tile-abbr{ visibility: hidden; }

/* Pool rows */
.dr-pool{ display: flex; flex-direction: column; gap: 2px; flex: 1 1 auto; min-height: 0; padding-top: 6px; border-top: 1px solid var(--hairline); }
/* Desktop/tablet: the list scrolls on its own under the search, tabs and scope row. */
.dr-left{ overflow: hidden; }
.dr-left .dr-pool{ overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; scrollbar-width: none; margin: 0 -8px; padding: 6px 8px 12px; }
.dr-left .dr-pool::-webkit-scrollbar{ display: none; }
.dr-row{ flex: 0 0 auto; display: flex; align-items: center; gap: 10px; padding: 6px 8px; border-radius: var(--r-sm); }
.dr-row:hover{ background: var(--seg-track); }
.dr-row.dim{ opacity: 0.4; }
.dr-row-main{ flex: 1 1 auto; min-width: 0; }
.dr-row-name{ font-size: var(--fs-15); font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dr-row-meta{ display: flex; align-items: center; gap: 5px; font-size: var(--fs-11); color: var(--text-mute); white-space: nowrap; overflow: hidden; font-variant-numeric: tabular-nums; }
.dr-row-meta i{ flex: 0 0 auto; width: 6px; height: 6px; border-radius: 1px; }
.dr-row-group{
  min-width: 0; overflow: hidden; text-overflow: ellipsis;
  border: 0; padding: 0; background: none; color: var(--text-sub); font: inherit; cursor: pointer;
  text-decoration: underline dotted; text-underline-offset: 2px;
}
.dr-row-group:hover{ color: var(--text); }
.dr-star{
  flex: 0 0 auto; width: 36px; height: 36px; border: 0; border-radius: var(--r-sm); background: none;
  color: var(--star-idle); cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
}
.dr-star svg{ width: 18px; height: 18px; }
.dr-star:hover{ background: var(--seg-track); }
.dr-star.on{ color: var(--star-on); }
.dr-star.on svg{ fill: currentColor; }
.dr-full{ flex: 0 0 auto; font-size: var(--fs-11); font-weight: 700; color: var(--text-mute); width: 64px; text-align: center; white-space: nowrap; }
.dr-draft-btn{ flex: 0 0 auto; width: 64px; height: 36px; border-radius: var(--r-sm); border: 1px solid var(--accent-border); background: var(--accent-soft); color: var(--accent); font: inherit; font-size: var(--fs-13); font-weight: 700; cursor: pointer; }
.dr-draft-btn.wide{ width: 100%; height: 36px; margin-top: 8px; }
.dr-showall{
  flex: 0 0 auto; align-self: flex-start; margin: 4px 0 6px; height: 36px; padding: 0 8px;
  border: 0; border-radius: var(--r-sm); background: none;
  color: var(--text-sub); font: inherit; font-size: var(--fs-12); font-weight: 700; text-align: left; cursor: pointer;
}
.dr-showall:hover{ background: var(--seg-track); color: var(--text); }
.dr-writein{ margin-top: 8px; padding: 12px; border: 1px dashed var(--hairline-strong); border-radius: var(--r-md); font-size: var(--fs-13); color: var(--text-sub); line-height: 1.4; }
.dr-writein-btns{ display: flex; gap: 8px; margin-top: 10px; }

/* Center: on the clock */
.dr-clock-card{ display: flex; justify-content: space-between; align-items: center; gap: 16px; flex-wrap: wrap; padding: 14px 18px; border-radius: var(--r-lg); background: var(--surface); border: 1px solid var(--hairline); flex: 0 0 auto; }
.dr-clock-card.mine{ background: var(--accent-soft); border-color: var(--accent-border); }
.dr-clock-card.done{ justify-content: flex-start; }
.dr-clock-name{ font-family: 'Space Grotesk', sans-serif; font-size: 28px; font-weight: 700; letter-spacing: -0.01em; line-height: 1.15; }
.dr-clock-sub{ font-size: var(--fs-12); color: var(--text-sub); font-variant-numeric: tabular-nums; margin-top: 2px; }
.dr-done-title{ font-size: var(--fs-30); font-weight: 800; letter-spacing: -0.02em; margin-top: 4px; }
.dr-badge{ font-size: var(--fs-11); padding: 2px 7px; border-radius: 999px; background: var(--accent-soft); border: 1px solid var(--accent-border); color: var(--accent); letter-spacing: 0.04em; }
.dr-timer-box{ text-align: right; }
/* Round / pick sits with the timer: "where we are" next to "how long is left". */
.dr-clock-pick{ font-size: var(--fs-12); font-weight: 600; color: var(--text-sub); font-variant-numeric: tabular-nums; white-space: nowrap; }
.dr-timer-box .dr-clock-pick{ font-size: var(--fs-11); margin-bottom: 2px; }
.dr-timer{ font-size: 34px; font-weight: 700; font-variant-numeric: tabular-nums; line-height: 1.1; }
.dr-timer.low{ color: var(--accent); }
.dr-timer.over{ color: var(--loss); }
.dr-bar{ width: 170px; max-width: 100%; height: 4px; margin: 6px 0 0 auto; border-radius: 2px; background: var(--seg-track); overflow: hidden; }
.dr-bar span{ display: block; height: 100%; background: var(--text-sub); }
.dr-paused{ padding: 10px 14px; border-radius: var(--r-sm); background: var(--seg-track); font-size: var(--fs-13); color: var(--text-sub); }

/* Board */
.dr-board-scroll{ position: relative; flex: 1 1 auto; min-height: 0; overflow: auto; overscroll-behavior: contain; margin: 0 -16px; padding: 0 16px 16px; -webkit-overflow-scrolling: touch; }
.dr-grid{ min-width: 1040px; display: flex; flex-direction: column; gap: 4px; }
.dr-grid-head, .dr-round{ display: grid; grid-template-columns: 30px repeat(var(--cols), minmax(0, 1fr)); gap: 4px; }
.dr-grid-head{ position: sticky; top: 0; z-index: 2; background: var(--bg); padding: 4px 0 6px; }
.dr-bh{ text-align: center; font-size: var(--fs-13); font-weight: 600; color: var(--text-sub); padding: 6px 4px; border-bottom: 2px solid transparent; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dr-bh.me{ color: var(--accent); }
.dr-bh.clock{ border-bottom-color: var(--accent); color: var(--text); }
.dr-round-n{ display: flex; flex-direction: column; align-items: center; justify-content: center; font-size: var(--fs-12); font-weight: 700; color: var(--text-sub); font-variant-numeric: tabular-nums; }
.dr-round-n small{ font-size: var(--fs-11); color: var(--text-mute); }
.dr-cell{ height: 54px; border-radius: var(--r-xs); padding: 5px 7px; background: var(--surface); border: 1px solid var(--hairline); display: flex; flex-direction: column; justify-content: space-between; min-width: 0; }
.dr-cell-top{ display: flex; justify-content: space-between; align-items: center; font-size: var(--fs-11); font-weight: 700; color: var(--text-mute); font-variant-numeric: tabular-nums; }
.dr-cell-team{ display: flex; align-items: center; gap: 6px; font-size: var(--fs-12); font-weight: 600; min-width: 0; }
.dr-cell-team span:last-child{ white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dr-cell.empty{ background: transparent; }
.dr-cell.empty.mine{ background: var(--accent-soft); border-color: transparent; }
.dr-cell.filled.mine{ border-color: var(--accent-border); }
.dr-cell.current{ background: var(--accent-soft); border-color: var(--accent); }
.dr-cell-clock{ font-size: var(--fs-11); font-weight: 700; color: var(--accent); }
.dr-cell-traded{ font-size: var(--fs-11); font-weight: 600; color: var(--text-sub); }

/* Right column */
.dr-roster-pick{ position: relative; display: inline-flex; align-items: center; min-width: 0; margin-left: auto; }
.dr-roster-pick svg{ position: absolute; right: 10px; pointer-events: none; color: var(--text-mute); }
.dr-roster-pick select{
  appearance: none; -webkit-appearance: none; max-width: 100%;
  height: 32px; padding: 0 26px 0 10px; border: 1px solid var(--hairline-strong); border-radius: var(--r-sm);
  background: var(--surface); color: var(--text); font: inherit; font-size: var(--fs-13); font-weight: 600; cursor: pointer;
}
.dr-roster-pick select:hover, .dr-roster-pick select:focus-visible{ background: var(--seg-thumb); }
.dr-roster-row{ display: grid; grid-template-columns: 44px 1fr auto; align-items: center; gap: 8px; padding: 6px 0; }
.dr-roster-row.full{ opacity: 0.55; }
.dr-roster-lg{ font-size: var(--fs-11); font-weight: 800; letter-spacing: 0.04em; }
.dr-slots{ display: flex; gap: 5px; }
.dr-slot{ box-sizing: border-box; width: 30px; height: 30px; border-radius: var(--r-xs); border: 1px dashed var(--hairline-strong); }
.dr-slot-team{ flex: 0 0 auto; display: inline-flex; padding: 0; border: 0; background: none; border-radius: var(--r-xs); cursor: pointer; }
.dr-slot-team:focus-visible{ outline: 2px solid var(--accent); outline-offset: 2px; }
.dr-slot-team .dr-tile{ border-radius: var(--r-xs); }
.dr-tip{
  position: fixed; z-index: 600; pointer-events: none;
  display: flex; flex-direction: column; gap: 1px; max-width: 220px;
  padding: 6px 10px; border-radius: var(--r-sm);
  background: var(--sheet); border: 1px solid var(--hairline-strong); box-shadow: 0 8px 24px rgba(0,0,0,0.4);
  opacity: 0; transform: translateY(2px);
  transition: opacity var(--dur-ui) var(--ease-out), transform var(--dur-ui) var(--ease-out);
}
.dr-tip.show{ opacity: 1; transform: none; }
.dr-tip b{ font-size: var(--fs-13); font-weight: 700; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dr-tip span{ font-size: var(--fs-11); color: var(--text-mute); font-variant-numeric: tabular-nums; white-space: nowrap; }
.dr-roster-n{ font-size: var(--fs-12); color: var(--text-mute); font-variant-numeric: tabular-nums; }
.dr-queue-head{ margin-top: 22px; }
.dr-empty{ margin-top: 10px; padding: 14px; border: 1px dashed var(--hairline-strong); border-radius: var(--r-md); font-size: var(--fs-12); line-height: 1.45; color: var(--text-mute); }
.dr-q{ margin-top: 8px; padding: 6px 8px 6px 4px; border-radius: var(--r-sm); background: var(--surface); border: 1px solid var(--hairline); }
.dr-q:focus-visible{ outline: 2px solid var(--accent); outline-offset: 1px; }
.dr-q.dragging{ opacity: 0.4; }
.dr-q.top{ background: var(--accent-soft); border-color: var(--accent-border); }
.dr-q.dim{ opacity: 0.55; }
.dr-q-row{ display: flex; align-items: center; gap: 8px; }
.dr-q-i{ width: 14px; font-size: var(--fs-11); color: var(--text-mute); font-variant-numeric: tabular-nums; }
.dr-q-grip{ flex: 0 0 auto; width: 16px; height: 32px; display: inline-flex; align-items: center; justify-content: center; color: var(--text-mute); cursor: grab; }
.dr-q-main{ flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.dr-q-name{ min-width: 0; font-size: var(--fs-13); font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dr-tag{ font-size: var(--fs-11); font-weight: 700; color: var(--text-mute); white-space: nowrap; }
.dr-tag.gold{ color: var(--accent); }
.dr-tag.dim{ opacity: 0.7; }
.dr-q-ctl{ display: flex; flex: 0 0 auto; }
.dr-q-ctl button{
  width: 32px; height: 32px; border: 0; border-radius: 8px; background: none; color: var(--text-mute); cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
}
.dr-q-ctl button:first-child:not(:last-child){ color: var(--text-sub); }
.dr-q-ctl button:hover{ background: var(--seg-track); color: var(--text); }
.dr-q .dr-draft-btn.wide{ margin: 8px 0 2px 4px; width: calc(100% - 4px); }

/* Draft room: commissioner bar, modals, proxy pick */
.draft-comm{
  flex: 0 0 auto; display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 8px var(--page-pad); border-bottom: 1px solid var(--hairline);
}
.draft-comm[hidden]{ display: none; }
/* Phones: one row that scrolls sideways instead of wrapping into three. */
@media (max-width: 700px){
  .draft-comm{ flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
  .draft-comm::-webkit-scrollbar{ display: none; }
  .draft-comm > *{ flex: 0 0 auto; }
}
.dm-proxy .dr-proxy-btn{ width: 100%; }
.dm-brow.editable{ cursor: pointer; }
.dr-modal-card{ margin: 0; }
.dr-comm-label{ font-size: var(--fs-11); font-weight: 700; letter-spacing: 0.06em; color: var(--text-mute); margin-right: 4px; }
.dr-btn-ghost{ background: transparent; color: var(--text-sub); }
.dr-btn-red{ background: var(--loss-soft); border-color: transparent; color: var(--loss); }
.dr-proxy-btn{ margin-top: 10px; height: 32px; }
.dr-proxy-note{ padding: 8px 12px; border-radius: var(--r-sm); background: var(--accent-soft); color: var(--accent); font-size: var(--fs-12); font-weight: 600; flex: 0 0 auto; }
.dr-cell.editable{ cursor: pointer; }
.dr-cell.editable:hover{ border-color: var(--hairline-strong); }
/* The draft room's modals ride the shared .modal-overlay/.modal sheet
   (a bottom sheet on phones); this only lifts it over the draft view
   and lays out the body. */
.modal-overlay.dr-modal-back{ z-index: 500; }
.modal.dr-modal{
  max-width: 460px; padding: 22px;
  display: flex; flex-direction: column; gap: 14px;
}
/* Tall bodies (the bot list) scroll the sheet rather than squashing a card. */
.modal.dr-modal > *{ flex-shrink: 0; }
@media (max-width: 700px){
  .modal.dr-modal{ max-width: none; padding: 0 20px calc(20px + env(safe-area-inset-bottom)); }
  /* The grabber sits in the flex column; pull it into the top gap. */
  .modal.dr-modal::before{ flex: 0 0 auto; margin-bottom: 4px; }
}
.dr-modal h3{ margin: 0; font-size: var(--fs-20); font-weight: 700; }
.dr-modal p{ margin: 0; font-size: var(--fs-13); line-height: 1.5; color: var(--text-sub); }
.dr-modal-team{ display: flex; align-items: center; gap: 12px; }
.dr-modal-team b{ display: block; font-size: var(--fs-15); }
.dr-modal-team span{ font-size: var(--fs-12); color: var(--text-sub); }
.dr-modal-btns{ display: flex; flex-direction: column; gap: 8px; }
.dr-modal-btns .dr-btn{ height: 40px; }
.dr-trade-grid{ display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.dr-trade-col{ display: flex; flex-direction: column; gap: 8px; }
.dr-trade-col select{ height: 38px; border-radius: var(--r-sm); border: 1px solid var(--hairline-strong); background: var(--surface); color: var(--text); padding: 0 8px; font: inherit; font-size: 16px; }
.dr-trade-preview{ padding: 10px 12px; border-radius: 10px; background: var(--seg-track); font-size: var(--fs-13); font-weight: 600; font-variant-numeric: tabular-nums; }

/* Draft room: phone shell (<=700px) — a compact clock over Pick / Board / My team */
.dm{ display: block; padding-bottom: 24px; }
.dm-top{ position: sticky; top: 0; z-index: 5; background: var(--bg); padding: 10px 16px 0; display: flex; flex-direction: column; gap: 10px; }
.dm-top .dr-clock-card{ padding: 10px 14px; gap: 8px; flex-wrap: nowrap; align-items: flex-end; }
.dm-top .dr-clock-name{ font-size: 20px; }
.dm-top .dr-clock-sub{ font-size: var(--fs-11); }
.dm-top .dr-timer{ font-size: 24px; }
.dm-top .dr-bar{ width: 100px; margin-top: 4px; }
.dm-top .dr-paused{ margin-top: 0; }
.dm-tabs{ display: grid; grid-template-columns: repeat(3, 1fr); gap: 2px; padding: 3px; border-radius: 12px; background: var(--seg-track); margin-bottom: 8px; }
.dm-tab{ height: 40px; border: 0; border-radius: 9px; background: transparent; color: var(--text-sub); font: inherit; font-size: var(--fs-13); font-weight: 600; cursor: pointer; }
.dm-tab.on{ background: var(--seg-thumb); color: var(--text); }
.dm-pane{ display: none; padding: 4px 16px 0; flex-direction: column; gap: 10px; }
.dm[data-tab="pick"] .dm-pane[data-pane="pick"],
.dm[data-tab="board"] .dm-pane[data-pane="board"],
.dm[data-tab="team"] .dm-pane[data-pane="team"]{ display: flex; }
.dm .dr-search{ height: 44px; }
.dm .dr-ltab{ height: 40px; }
.dm .dr-scope{ min-height: 40px; }
.dm .dr-dd-btn, .dm .dr-sort-btn{ height: 40px; }
/* Phone: menus open full width under the scope row. */
.dm .dr-dd{ position: static; }
.dm .dr-menu, .dm .dr-dd-sort .dr-menu{ top: 46px; left: 0; right: 0; width: auto; min-width: 0; }
.dm .dr-menu-item{ height: 44px; }
.dm .dr-menu-sort{ height: auto; padding: 10px; }
.dm .dr-q-ctl button{ width: 44px; height: 44px; }
/* The phone pane scrolls the whole page under a sticky clock, so league heads don't stick. */
.dm .dr-section-head{ position: static; }
.dm .dr-row{ min-height: 56px; }
.dm .dr-draft-btn{ width: 68px; height: 44px; border-radius: 10px; font-size: var(--fs-13); }
.dm .dr-star{ width: 44px; height: 44px; }
.dm .dr-star svg{ width: 20px; height: 20px; }
.dm-from-queue{ display: flex; flex-direction: column; gap: 6px; padding: 10px; border-radius: var(--r-md); background: var(--accent-soft); border: 1px solid var(--accent-border); }
.dm-qrow{ display: flex; align-items: center; gap: 10px; min-height: 56px; }
.dm-brow{ display: grid; grid-template-columns: 42px 74px 1fr; align-items: center; gap: 6px; min-height: 46px; padding: 0 8px; border-bottom: 1px solid var(--hairline); font-size: var(--fs-13); }
.dm-brow.cur{ background: var(--accent-soft); border-radius: var(--r-sm); border-bottom-color: transparent; }
.dm-brow.mine .dm-b-owner{ color: var(--accent); font-weight: 700; }
.dm-b-label{ color: var(--text-mute); font-variant-numeric: tabular-nums; font-size: var(--fs-12); }
.dm-b-owner{ color: var(--text-sub); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dm-b-team{ display: flex; align-items: center; gap: 8px; min-width: 0; }
.dm-b-name{ font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dm-b-lg{ margin-left: auto; font-size: var(--fs-11); font-weight: 700; }
.dm-b-clock{ font-weight: 700; color: var(--accent); }

/* "Draft is live" banner on every page but the draft room (js/draft-live.js):
   top of .board, and under the Chat header. The whole strip is the button. */
.draft-live-slot[hidden]{ display: none; }
.draft-live-slot{ margin: 0 0 14px; }
.chat-head .draft-live-slot{ margin: 2px 0 12px; }
html.chat-kb .chat-head .draft-live-slot{ display: none; }
.draft-live{
  width: 100%; min-height: 48px; display: flex; align-items: center; gap: 10px;
  padding: 8px 8px 8px 14px; border-radius: var(--r-md);
  border: 1px solid var(--accent-border); background: var(--accent-soft); color: var(--text);
  font: inherit; text-align: left; cursor: pointer;
  transition: transform var(--dur-press) var(--ease-out);
}
.draft-live:active{ transform: scale(0.985); }
.draft-live-dot{ flex: 0 0 auto; width: 8px; height: 8px; border-radius: 50%; background: var(--live); animation: draft-live-pulse 1.6s ease-in-out infinite; }
.draft-live[data-kind="paused"] .draft-live-dot{ background: var(--text-sub); animation: none; }
.draft-live-text{ flex: 1 1 auto; min-width: 0; display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 8px; row-gap: 1px; }
.draft-live-text b{ font-size: var(--fs-13); font-weight: 700; white-space: nowrap; }
.draft-live-text span{ font-size: var(--fs-12); color: var(--text-sub); font-variant-numeric: tabular-nums; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.draft-live-cta{
  flex: 0 0 auto; display: inline-flex; align-items: center; gap: 4px;
  height: 32px; padding: 0 10px 0 12px; border-radius: var(--r-sm);
  background: var(--accent-soft); border: 1px solid var(--accent-border); color: var(--accent);
  font-size: var(--fs-12); font-weight: 700; white-space: nowrap;
}
/* Your pick: the loudest version, so it reads at a glance. */
.draft-live[data-kind="mine"]{ background: var(--accent-fill); border-color: transparent; color: var(--on-accent); }
.draft-live[data-kind="mine"] .draft-live-dot{ background: var(--on-accent); }
.draft-live[data-kind="mine"] .draft-live-text span{ color: var(--on-accent); opacity: 0.75; }
.draft-live[data-kind="mine"] .draft-live-cta{ background: var(--on-accent); border-color: transparent; color: var(--accent-fill); }
@keyframes draft-live-pulse{ 0%, 100%{ opacity: 1; } 50%{ opacity: 0.35; } }
@media (prefers-reduced-motion: reduce){ .draft-live-dot{ animation: none; } }

/* Notice while an older draft class is showing (js/season-switcher.js) */
.season-banner{
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin: 0 0 14px; padding: 9px 12px;
  border-radius: var(--r-sm); background: var(--accent-soft); border: 1px solid var(--accent-border);
  font-size: var(--fs-12); font-weight: 600; color: var(--accent);
}
.season-banner button{
  flex: 0 0 auto; height: 28px; padding: 0 10px; border-radius: 8px;
  border: 1px solid var(--accent-border); background: transparent; color: var(--accent);
  font: inherit; font-size: var(--fs-12); font-weight: 700; cursor: pointer;
}

/* Draft room: collapsible panels. A side column folds to a 44px rail (caret, rotated
   label, live count) and the board takes the space.
   Wide screens fold Available and the roster/queue independently; under 1180px
   they share one side slot, and it folds when the panel showing in it is folded. */
.dr-caret{
  flex: 0 0 auto; width: 32px; height: 32px; border: 0; border-radius: var(--r-sm);
  background: var(--seg-track); color: var(--text-sub);
  font-size: 18px; line-height: 1; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background var(--dur-ui) var(--ease-out), color var(--dur-ui) var(--ease-out);
}
.dr-caret:hover{ background: var(--seg-thumb); color: var(--text); }
.dr-col-head .dr-caret{ margin-left: 4px; }
.dr-col-head{ align-items: center; }
.dr-col-head .dr-dim{ margin-left: auto; }

.dr-rail{
  display: none; flex: 1 1 auto; min-height: 0; width: 100%;
  flex-direction: column; align-items: center; gap: 10px;
  padding: 10px 0; border: 0; background: none; color: var(--text-sub);
  font: inherit; cursor: pointer;
}
.dr-rail:hover .dr-caret{ background: var(--seg-thumb); color: var(--text); }
.dr-rail-label{
  writing-mode: vertical-rl; transform: rotate(180deg);
  font-size: var(--fs-12); font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
}
.dr-rail-count{ font-size: var(--fs-11); font-weight: 700; color: var(--text-mute); font-variant-numeric: tabular-nums; }

.dr-layout[data-collapsed~="left"]{ --dr-left: 44px; }
.dr-layout[data-collapsed~="right"]{ --dr-right: 44px; }
.dr-layout[data-collapsed~="left"] .dr-left,
.dr-layout[data-collapsed~="right"] .dr-right{ padding: 6px 0; overflow: hidden; }
.dr-layout[data-collapsed~="left"] .dr-left > :not(.dr-rail),
.dr-layout[data-collapsed~="right"] .dr-right > :not(.dr-rail){ display: none; }
.dr-layout[data-collapsed~="left"] .dr-left .dr-rail,
.dr-layout[data-collapsed~="right"] .dr-right .dr-rail{ display: flex; }
@media (max-width: 1179px){
  .dr-layout[data-left-tab="available"][data-collapsed~="left"],
  .dr-layout[data-left-tab="team"][data-collapsed~="right"]{ --dr-side: 44px; }
  .dr-layout[data-left-tab="available"][data-collapsed~="left"] .dr-tabs,
  .dr-layout[data-left-tab="team"][data-collapsed~="right"] .dr-tabs{ visibility: hidden; padding: 0; }
  /* The narrow layout has one side slot, so the roster's own rail belongs there too. */
  .dr-layout[data-left-tab="team"][data-collapsed~="right"] .dr-right{ padding: 6px 0; }
}

/* On the clock: a one-line strip on desktop and tablet (the phone shell has its own card) */
.dr-clock-card.strip{
  flex-wrap: nowrap; justify-content: flex-start; align-items: center; gap: 14px;
  padding: 8px 16px; min-height: 52px;
}
.dr-clock-card.strip .dr-eyebrow{ white-space: nowrap; }
.dr-clock-card.strip .dr-clock-name{ font-size: var(--fs-20); white-space: nowrap; }
.dr-clock-card.strip .dr-clock-sub{ margin: 0; white-space: nowrap; }
.dr-clock-card.strip .dr-proxy-btn{ margin: 0 0 0 4px; height: 30px; }
.dr-strip-timer{ margin-left: auto; display: flex; align-items: center; gap: 12px; }
.dr-download-btn{ flex: 0 0 auto; display: inline-flex; align-items: center; gap: 6px; margin-left: auto; white-space: nowrap; }
.dr-strip-timer .dr-timer{ font-size: 26px; }
.dr-strip-timer .dr-bar{ width: 90px; margin: 0; }

/* ============================================================
   View transitions (js/motion.js) — the directional tab slide and the
   team page push/pop. `html[data-nav]` picks the
   keyframes; with no data-nav (Draft, Admin, Scoring) it's a plain
   crossfade. Without View Transitions, or with reduced motion, none of
   this runs and the older CSS fades below keep working as before.
   ============================================================ */
@media (prefers-reduced-motion: no-preference){
  ::view-transition-old(root),
  ::view-transition-new(root){ animation-duration: 380ms; animation-timing-function: var(--ease-out); animation-fill-mode: both; }
  html[data-nav="fwd"]::view-transition-old(root){ animation-name: vt-out-left; animation-duration: 240ms; }
  html[data-nav="fwd"]::view-transition-new(root){ animation-name: vt-in-right; }
  html[data-nav="back"]::view-transition-old(root){ animation-name: vt-out-right; animation-duration: 240ms; }
  html[data-nav="back"]::view-transition-new(root){ animation-name: vt-in-left; }

  html[data-nav="push"]::view-transition-old(root){ animation: vt-push-old 400ms cubic-bezier(0.22, 0.7, 0.25, 1) both; }
  html[data-nav="push"]::view-transition-new(root){ animation: vt-push-new 400ms cubic-bezier(0.22, 0.7, 0.25, 1) both; }
  html[data-nav="pop"]::view-transition-old(root){ animation: vt-pop-old 340ms cubic-bezier(0.22, 0.7, 0.25, 1) both; z-index: 1; }
  html[data-nav="pop"]::view-transition-new(root){ animation: vt-pop-new 340ms cubic-bezier(0.22, 0.7, 0.25, 1) both; }

  /* Where View Transitions exist they replace the tab fade (R5) and the
     team views' slide-in (.view-push-in) — both would otherwise play a
     second time inside the new snapshot, and restart when data-nav
     clears. The Points detail's own .view-push-in is untouched. */
  @supports (view-transition-name: none){
    .board > .view.active:not(.view-push-in),
    .board > .view.view-push-in{ animation: none; }
  }
}
@keyframes vt-out-left{ to{ opacity: 0; transform: translateX(-36px); } }
@keyframes vt-out-right{ to{ opacity: 0; transform: translateX(36px); } }
@keyframes vt-in-right{ from{ opacity: 0; transform: translateX(36px); } }
@keyframes vt-in-left{ from{ opacity: 0; transform: translateX(-36px); } }
@keyframes vt-push-old{ to{ transform: translateX(-28%); filter: brightness(0.55); } }
@keyframes vt-push-new{ from{ transform: translateX(100%); } }
@keyframes vt-pop-old{ to{ transform: translateX(100%); } }
@keyframes vt-pop-new{ from{ transform: translateX(-28%); filter: brightness(0.55); } }

/* Standings row ↔ Team page container transform (js/team-page.js,
   expandFromRow/collapseToRow). While it runs the team page is a fixed
   layer over the Standings view, at exactly its in-flow spot at scroll 0:
   the view's own column (--tp-l/--tp-w), pushed down by --tp-t, with the
   screen around it painted --bg. The clip-path that grows it out of the
   row is animated on it from JS. .tp-still holds off .view-push-in, which
   would otherwise restart whenever the layer's display changes. */
.view.tp-layer{
  display: block;
  position: fixed; top: 0; bottom: 0; left: var(--tp-l); width: var(--tp-w);
  border-top: var(--tp-t) solid transparent; box-sizing: border-box;
  overflow: hidden;
  background: var(--bg); box-shadow: 0 0 0 100vmax var(--bg);
  z-index: 150;
}
.view.tp-under{ display: block; }
.view.tp-layer, .view.tp-still{ animation: none !important; }
#tp-fx{ position: fixed; inset: 0; z-index: 151; pointer-events: none; }
#tp-fx > *{ position: fixed; margin: 0; box-sizing: border-box; }
#tp-fx .tp-veil{ inset: 0; }
#tp-fx .tp-ghost{ background: transparent; }
#tp-fx .tp-fly{ flex: none; transform-origin: 0 0; }

/* The tab bar and the notch cover hold still while the page moves. Their
   "new" image is live, so the pill's own transition plays through it. */
.tab-bar{ view-transition-name: tab-bar; }
.safe-area-top{ view-transition-name: safe-top; }
::view-transition-old(tab-bar), ::view-transition-old(safe-top){ display: none; }
::view-transition-new(tab-bar), ::view-transition-new(safe-top){ animation: none; }

/* One gold pill behind the active tab, springing between slots. --tab-i
   and .no-pill are set by paintTabPill in js/board.js. */
.tab-bar{ --tab-i: 0; }
.tab-btn{ position: relative; }
.tab-pill{
  position: absolute;
  top: 6px;
  left: calc(var(--tab-i) * 20%);
  width: 20%;
  height: 30px;
  display: flex;
  justify-content: center;
  pointer-events: none;
  transition: left 420ms var(--ease-spring), opacity var(--dur-ui) var(--ease-out);
}
.tab-pill::before{ content: ""; width: 46px; height: 30px; border-radius: 15px; background: var(--tab-pill); }
.tab-bar.no-pill .tab-pill{ opacity: 0; }
@media (prefers-reduced-motion: reduce){ .tab-pill{ transition: none; } }

/* ---- Launch splash (js/launch-splash.js) ----
   Geometry is the 512px app icon scaled to a 200px box. Colors follow the
   theme the inline <head> script sets on <html> (data-theme="light" |
   "auto" | none = dark). Ink and square are sampled from the header logo
   PNGs, so the mark and the real logo match when the mark lands on it. The
   light ground equals the light --bg, so the reveal has no visible edge.
   The iOS system launch screen (manifest background_color) stays dark. */
#launch-splash{
  --ls-bg: #0A0B0D; --ls-ink: #F3F2EF; --ls-sq: #DC7D00;
  position: fixed; inset: 0; z-index: 10000;
}
html[data-theme="light"] #launch-splash{ --ls-bg: #F4F3EF; --ls-ink: #0B0C0F; }
@media (prefers-color-scheme: light){
  html[data-theme="auto"] #launch-splash{ --ls-bg: #F4F3EF; --ls-ink: #0B0C0F; }
}
#launch-splash .ls-bg{ position: absolute; inset: 0; background: var(--ls-bg); }
#launch-splash .ls-stage{ position: absolute; left: 50%; top: 50%; width: 200px; height: 200px; margin: -100px 0 0 -100px; }
#launch-splash .ls-logo{ position: absolute; inset: 0; transform: translateY(-26px); transform-origin: 50% 50%; }
/* Brackets: a clip window (.ls-tl/.ls-br) around the ink (<i>), slid in
   opposite directions by the splash script to draw each from its corner.
   Starting offsets here match its first frame so nothing shows early. */
#launch-splash .ls-tl,
#launch-splash .ls-br{ position: absolute; width: 45px; height: 45px; overflow: hidden; }
#launch-splash .ls-tl > i,
#launch-splash .ls-br > i{ position: absolute; inset: 0; box-sizing: border-box; }
#launch-splash .ls-tl{ left: 43px; top: 43px; transform: translate(-100%, -100%); }
#launch-splash .ls-tl > i{ border-top: 13px solid var(--ls-ink); border-left: 13px solid var(--ls-ink); border-top-left-radius: 13px; transform: translate(100%, 100%); }
#launch-splash .ls-br{ left: 112px; top: 112px; transform: translate(100%, 100%); }
#launch-splash .ls-br > i{ border-bottom: 13px solid var(--ls-ink); border-right: 13px solid var(--ls-ink); border-bottom-right-radius: 13px; transform: translate(-100%, -100%); }
#launch-splash .ls-sq{ position: absolute; left: 79.5px; top: 79.5px; width: 41px; height: 41px; border-radius: 9px; background: var(--ls-sq); transform: scale(0); }
#launch-splash .ls-word{
  position: absolute; left: 50%; top: 152px; transform: translateX(-50%);
  display: flex; font-family: 'Space Grotesk', sans-serif; font-size: 30px; font-weight: 700;
  letter-spacing: 0.01em; line-height: 1; color: var(--ls-ink); white-space: nowrap;
}
#launch-splash .ls-word > span{ display: block; overflow: hidden; padding: 2px 0 4px; }
#launch-splash .ls-word > span > span{ display: block; transform: translateY(110%); }
@media (prefers-reduced-motion: reduce){ #launch-splash{ display: none; } }

/* Light header logo (inverse of the app icon), so the header and the splash
   mark match the theme. `content` on an <img> swaps its source, so
   js/page-header.js needs no change. */
html[data-theme="light"] .app-logo{ content: url(../icons/logo-header-light.png); }
@media (prefers-color-scheme: light){
  html[data-theme="auto"] .app-logo{ content: url(../icons/logo-header-light.png); }
}

/* ============================================================
   Sheet motion (phones). The page behind a sheet stays still under the
   dimmed overlay (a card-stack recede read as the background jumping).
   Sheets open/close through openSheetOverlay/closeSheetOverlay:
   .entering while they slide up and their rows stagger in, .closing
   while they slide down. Fill modes stay off the resting state so the
   swipe-to-dismiss drag (an inline transform) is never overridden.
   With reduced motion, the older .modal sheet-up above still applies.
   ============================================================ */
@media (max-width: 700px) and (prefers-reduced-motion: no-preference){
  .modal-overlay{ transition: background-color 0.45s var(--ease-sheet); }

  .modal-overlay.open{ animation: overlay-in 380ms ease backwards; }
  .modal-overlay.open .modal{ animation: sheet-spring 500ms var(--ease-sheet) backwards; }
  .modal-overlay.closing{ animation: overlay-out 280ms ease forwards; }
  .modal-overlay.closing .modal{ animation: sheet-down 280ms cubic-bezier(0.32, 0, 0.67, 0) forwards; }

  .modal-overlay.entering :is(.ob-sheet-league, .cmp-pick-list > *, #identity-sheet-rows > *){ animation: sheet-row-in 420ms var(--ease-out) 385ms backwards; }
  .modal-overlay.entering :is(.ob-sheet-league, .cmp-pick-list > *, #identity-sheet-rows > *):nth-child(1){ animation-delay: 160ms; }
  .modal-overlay.entering :is(.ob-sheet-league, .cmp-pick-list > *, #identity-sheet-rows > *):nth-child(2){ animation-delay: 205ms; }
  .modal-overlay.entering :is(.ob-sheet-league, .cmp-pick-list > *, #identity-sheet-rows > *):nth-child(3){ animation-delay: 250ms; }
  .modal-overlay.entering :is(.ob-sheet-league, .cmp-pick-list > *, #identity-sheet-rows > *):nth-child(4){ animation-delay: 295ms; }
  .modal-overlay.entering :is(.ob-sheet-league, .cmp-pick-list > *, #identity-sheet-rows > *):nth-child(5){ animation-delay: 340ms; }
}
@keyframes overlay-in{ from{ background-color: rgba(6,7,9,0); } }
@keyframes overlay-out{ to{ background-color: rgba(6,7,9,0); } }
@keyframes sheet-spring{ from{ transform: translateY(100%); } to{ transform: translateY(0); } }
@keyframes sheet-down{ to{ transform: translateY(100%); } }
@keyframes sheet-row-in{ from{ opacity: 0; transform: translateY(14px); } }

/* ============================================================
   Split bars that build (js/overall.js, obGrowBars). Entering the Points
   tab or opening a drafter's sheet fills each Locked/Live bar from zero:
   Locked first, then the Live stripe, 60ms further per --row. bar-grow
   has no `to` frame, so each segment grows to its own inline width.
   --grow-skip fast-forwards a bar that was re-rendered mid-fill.
   ============================================================ */
@media (prefers-reduced-motion: no-preference){
  .split-bar.grow > span{ animation: bar-grow 560ms var(--ease-out) backwards; animation-delay: calc(120ms + var(--row, 0) * 60ms - var(--grow-skip, 0ms)); }
  .split-bar.grow > .lv{ animation-delay: calc(230ms + var(--row, 0) * 60ms - var(--grow-skip, 0ms)); }
}
@keyframes bar-grow{ from{ width: 0; } }

/* ============================================================
   Odometer scores (js/live-now.js, odometerHtml). When a refresh finds a
   live game's score changed, each digit rolls on a 0-9 strip to its new
   value and the card flashes a gold ring. The strips are aria-hidden;
   .odo-sr carries the real score for screen readers. The gold wash is an
   inset shadow because a live card's background is a gradient that
   would cover a background-color change.
   ============================================================ */
.odo-sr{ position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.tg-score[data-scored]{ position: relative; }
.tg-score .odo-d{ display: inline-block; height: 1em; line-height: 1; overflow: hidden; vertical-align: -0.12em; }
.tg-score .odo-strip{ display: flex; flex-direction: column; transform: translateY(calc(var(--n) * -1em)); transition: transform 700ms var(--ease-spring); }
.tg-score .odo-strip > span{ display: block; height: 1em; }
.tg-card.just-scored{ animation: just-scored 1500ms ease-out; }
@keyframes just-scored{
  0%  { box-shadow: 0 0 0 0 rgba(217,180,91,0), inset 0 0 0 999px rgba(217,180,91,0); }
  18% { box-shadow: 0 0 0 2px rgba(217,180,91,0.9), inset 0 0 0 999px rgba(217,180,91,0.08); }
  100%{ box-shadow: 0 0 0 0 rgba(217,180,91,0), inset 0 0 0 999px rgba(217,180,91,0); }
}
@media (prefers-reduced-motion: reduce){ .tg-score .odo-strip{ transition: none; } .tg-card.just-scored{ animation: none; } }
