/* =============================================================================
   WORKBENCH TABLE VIEW STYLES
   Table-based prop display for desktop screens (1001px+)
   ============================================================================= */

/* -----------------------------------------------------------------------------
   Table Filter Bar (Wide screens only, replaces card filter rows)
   ----------------------------------------------------------------------------- */
.table-filter-bar {
  display: none; /* Hidden by default */
  align-items: center;
  flex-wrap: nowrap;
  gap: 12px;
  padding: 0;
  background: transparent;
  border: none;
  border-radius: 0;
  margin-bottom: 0;
}

@media (min-width: 1001px) {
  .table-filter-bar.active {
    display: flex;
  }
}

.table-filter-item {
  position: relative;
}

/* Search Input */
.table-filter-search-item {
  flex: 0 0 auto;
}

.table-search-wrapper {
  position: relative;
  display: flex;
  align-items: center;
}

.table-search-icon {
  position: absolute;
  left: 12px;
  color: rgba(255, 255, 255, 0.5);
  pointer-events: none;
}

.table-player-search {
  width: 200px;
  padding: 11px 36px 11px 36px;
  background: rgba(0, 211, 189, 0.08);
  border: 1px solid rgba(0, 211, 189, 0.25);
  border-radius: 8px;
  color: rgba(255, 255, 255, 0.95);
  font-size: 13px;
  outline: none;
  transition: all 0.2s ease;
}

.table-player-search::placeholder {
  color: rgba(255, 255, 255, 0.4);
}

.table-player-search:focus {
  background: rgba(0, 211, 189, 0.12);
  border-color: rgba(0, 211, 189, 0.5);
  box-shadow: 0 0 0 3px rgba(0, 211, 189, 0.1);
}

.table-player-search:not(:placeholder-shown) {
  background: rgba(0, 211, 189, 0.12);
}

.table-search-clear {
  position: absolute;
  right: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  padding: 0;
  background: rgba(255, 255, 255, 0.1);
  border: none;
  border-radius: 50%;
  color: rgba(255, 255, 255, 0.5);
  cursor: pointer;
  opacity: 0;
  transition: all 0.2s ease;
}

.table-player-search:not(:placeholder-shown) ~ .table-search-clear {
  opacity: 1;
}

.table-search-clear:hover {
  background: rgba(255, 255, 255, 0.2);
  color: rgba(255, 255, 255, 0.8);
}

/* Hide rows filtered by search */
.props-table tbody tr.search-filtered-out {
  display: none;
}

/* Cards filtered by search */
.suggested-prop.search-filtered-out {
  display: none !important;
}

.table-filter-item.table-filter-spacer {
  flex: 1;
}

.table-filter-dropdown-btn {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 11px 14px;
  background: rgba(0, 211, 189, 0.08);
  border: 1px solid rgba(0, 211, 189, 0.25);
  border-radius: 8px;
  color: rgba(255, 255, 255, 0.9);
  font-size: 13px;
  cursor: pointer;
  transition: all 0.2s ease;
  white-space: nowrap;
}

.table-filter-dropdown-btn:hover {
  background: rgba(0, 211, 189, 0.15);
  border-color: rgba(0, 211, 189, 0.4);
}

.table-filter-dropdown-btn.active {
  background: rgba(0, 211, 189, 0.2);
  border-color: rgba(0, 211, 189, 0.5);
}

.table-filter-dropdown-btn .filter-label {
  color: rgba(255, 255, 255, 0.6);
  font-weight: 500;
}

.table-filter-dropdown-btn .filter-value {
  color: #00F5D4;
  font-weight: 600;
}

.table-filter-dropdown-btn .dropdown-arrow {
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform 0.2s ease;
}

.table-filter-dropdown-btn.active .dropdown-arrow {
  transform: rotate(180deg);
}

/* Dropdown Panel */
.table-filter-dropdown {
  display: none;
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  z-index: 200;
  min-width: 240px;
  max-width: 320px;
  background: var(--theme-bg-card, #111319);
  border: 1px solid rgba(0, 211, 189, 0.25);
  border-radius: 12px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
  overflow: hidden;
}

.table-filter-dropdown.active {
  display: block;
}

.table-filter-dropdown .dropdown-content {
  padding: 8px 0;
  max-height: 320px;
  overflow-y: auto;
}

.table-filter-dropdown .dropdown-divider {
  height: 1px;
  background: rgba(0, 211, 189, 0.15);
  margin: 6px 12px;
}

.table-filter-dropdown .dropdown-option {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 16px;
  cursor: pointer;
  transition: background 0.15s ease;
  color: rgba(255, 255, 255, 0.85);
  font-size: 13px;
}

.table-filter-dropdown .dropdown-option:hover {
  background: rgba(0, 211, 189, 0.1);
}

.table-filter-dropdown .dropdown-option input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  width: 18px;
  height: 18px;
  border: 2px solid rgba(0, 211, 189, 0.4);
  border-radius: 4px;
  background: transparent;
  cursor: pointer;
  position: relative;
  flex-shrink: 0;
  transition: all 0.15s ease;
}

.table-filter-dropdown .dropdown-option input[type="checkbox"]:checked {
  background: #00F5D4;
  border-color: #00F5D4;
}

.table-filter-dropdown .dropdown-option input[type="checkbox"]:checked::after {
  content: '';
  position: absolute;
  left: 5px;
  top: 2px;
  width: 4px;
  height: 8px;
  border: solid #0a1628;
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}

/* Radio button styling for single-select options */
.table-filter-dropdown .dropdown-option input[type="radio"] {
  appearance: none;
  -webkit-appearance: none;
  width: 18px;
  height: 18px;
  border: 2px solid rgba(0, 211, 189, 0.4);
  border-radius: 50%;
  background: transparent;
  cursor: pointer;
  position: relative;
  flex-shrink: 0;
  transition: all 0.15s ease;
}

.table-filter-dropdown .dropdown-option input[type="radio"]:checked {
  background: transparent;
  border-color: #00F5D4;
}

.table-filter-dropdown .dropdown-option input[type="radio"]:checked::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  width: 8px;
  height: 8px;
  background: #00F5D4;
  border-radius: 50%;
  transform: translate(-50%, -50%);
}

.table-filter-dropdown .dropdown-option span {
  flex: 1;
  line-height: 1.3;
}

.table-filter-dropdown .dropdown-option .game-time {
  font-size: 11px;
  color: rgba(255, 255, 255, 0.5);
  display: block;
  margin-top: 2px;
}

/* Game option with team logos */
.table-filter-dropdown .dropdown-option.game-option {
  padding: 8px 16px;
}

.table-filter-dropdown .game-teams {
  display: flex;
  align-items: center;
  gap: 4px;
}

.table-filter-dropdown .team-logo-small {
  width: 18px;
  height: 18px;
  object-fit: contain;
  flex-shrink: 0;
}

.table-filter-dropdown .team-code {
  font-weight: 600;
  color: rgba(255, 255, 255, 0.9);
  font-size: 13px;
}

.table-filter-dropdown .at-symbol {
  color: rgba(255, 255, 255, 0.4);
  font-size: 12px;
  margin: 0 6px;
}

.table-filter-dropdown .game-datetime {
  font-size: 11px;
  color: rgba(255, 255, 255, 0.5);
  min-width: 75px;
  flex-shrink: 0;
}

/* Reset button - always visible, same height as filter buttons */
.table-filter-reset-btn {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 11px 14px;
  background: rgba(255, 82, 82, 0.15);
  border: 1px solid rgba(255, 82, 82, 0.35);
  border-radius: 8px;
  color: rgba(255, 120, 120, 0.95);
  font-size: 13px;
  cursor: pointer;
  transition: all 0.2s ease;
}

.table-filter-reset-btn:hover {
  background: rgba(255, 82, 82, 0.25);
  border-color: rgba(255, 82, 82, 0.5);
  color: #ff6b6b;
}

.table-filter-reset-btn .reset-icon {
  display: none;
}

/* In Parlay filter button — always visible so no DOM scan needed */
.table-filter-parlay-item {
  display: block;
}

.table-in-parlay-filter {
  display: inline-flex;
  padding: 11px 14px;
  background: transparent;
  border: 1px solid rgba(0, 211, 189, 0.25);
  border-radius: 8px;
  color: rgba(0, 211, 189, 0.9);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.2s ease;
  white-space: nowrap;
}

.table-in-parlay-filter:hover {
  background: rgba(0, 211, 189, 0.15);
  border-color: rgba(0, 211, 189, 0.6);
}

.table-in-parlay-filter.active {
  background: rgba(0, 211, 189, 0.25);
  border-color: #00D3BD;
  color: #00F5D4;
  box-shadow: 0 0 8px rgba(0, 211, 189, 0.3);
}

/* =====================================================================
   GLOBAL OVER/UNDER TOGGLE
   ===================================================================== */
.table-filter-ou-toggle {
  display: flex;
  align-items: center;
}

/* Hide O/U toggle when In Parlay filter is active */
.table-filter-ou-toggle.hidden {
  display: none;
}

/* MLB: hide the global Over/Under toggle entirely — MLB props are Over-side only
   (the build panel's "Side" filter is hidden too, see buildLogic.css). !important
   so it stays hidden regardless of the .hidden class the In-Parlay filter toggles.
   Hidden, not removed — delete this rule to bring it back. */
body.is-mlb-route .table-filter-ou-toggle {
  display: none !important;
}

.global-ou-toggle {
  display: flex;
  gap: 0;
  border-radius: 8px;
  overflow: hidden;
  border: 1px solid rgba(0, 211, 189, 0.25);
}

.global-ou-pill {
  all: unset;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 9px 14px;
  font-size: 0.8rem;
  font-weight: 600;
  color: #667;
  background: rgba(255, 255, 255, 0.03);
  cursor: pointer;
  transition: all 0.2s ease;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.global-ou-pill:first-child {
  border-right: 1px solid rgba(255, 255, 255, 0.15);
}

.global-ou-pill:hover:not(.active) {
  background: rgba(255, 255, 255, 0.08);
  color: #aaa;
}

.global-ou-pill.active {
  background: rgba(0, 211, 189, 0.15);
  color: #00D3BD;
}

.global-ou-pill--over.active {
  background: rgba(34, 197, 94, 0.15);
  color: #22c55e;
}

.global-ou-pill--under.active {
  background: rgba(239, 68, 68, 0.15);
  color: #ef4444;
}

/* ─── Global Markets toggle (MLB-only) ─────────────────────────────
   Sits in the table filter bar next to the O/U toggle. Hidden on
   non-MLB routes by the body class gate below. */
.table-filter-markets-toggle.is-mlb-only { display: none; }
body.is-mlb-route .table-filter-markets-toggle.is-mlb-only,
body.is-nba-route .table-filter-markets-toggle.is-mlb-only,
/* NFL is multi-book too, and tableView-core stamps is-nba-route for it — but
   only at TableView.init, i.e. when the board lands. Gating on the route class
   the shell already carries shows the book pills from first paint instead of
   punching a hole in the filter bar for the whole load (2026-09-04). */
body.is-nfl-route .table-filter-markets-toggle.is-mlb-only { display: flex; }
/* Prop Markets dropdown is redundant on MLB — the prop-type pill row
   under the table (HR / Hits / TB / RBIs / ...) already drives the
   same filter, so hide the dropdown on MLB routes. NBA / NFL keep
   it as the primary market filter. */
body.is-mlb-route .table-filter-markets-dropdown.is-non-mlb-only { display: none; }
.global-markets-toggle {
  display: flex; gap: 0;
  border-radius: 8px; overflow: hidden;
  border: 1px solid rgba(255,255,255,0.15);
}
.global-markets-pill {
  all: unset;
  display: flex; align-items: center; justify-content: center;
  padding: 9px 12px;
  font-size: 0.78rem; font-weight: 700;
  color: #888;
  background: rgba(255,255,255,0.03);
  cursor: pointer;
  transition: all 0.15s ease;
  letter-spacing: 0.03em;
}
.global-markets-pill + .global-markets-pill { border-left: 1px solid rgba(255,255,255,0.10); }
.global-markets-pill:hover:not(.active) { background: rgba(255,255,255,0.08); color: #ccc; }
.global-markets-pill.active[data-book="fanduel"]    { background: rgba(20,147,255,0.18);  color: #58a8ff; }
.global-markets-pill.active[data-book="draftkings"] { background: rgba(83,211,55,0.18);   color: #6fdf4d; }
.global-markets-pill.active[data-book="caesars"]    { background: rgba(244,196,48,0.18);  color: #f4d061; }
.global-markets-pill.active[data-book="betmgm"]     { background: rgba(191,142,67,0.18);  color: #d6a85e; }
.global-markets-pill.active[data-book="best"]       { background: rgba(0,211,189,0.18);   color: #00D3BD; }
/* Logo inside a global pill (FD / DK) — sized to roughly match the
   text-label cap height so the toggle row stays visually balanced
   alongside the CZR / Best text pills. */
.global-markets-pill-logo {
  height: 18px;
  width: auto;
  display: block;
}

/* ─── Per-cell Markets dropdown ────────────────────────────────────
   The cell hosts a trigger button (visible odds + book badge + caret)
   and a hidden menu anchored below it. .open on the <td> reveals the
   menu — toggled by the trigger click delegate in tableView-core. */
.cell-markets {
  position: relative;
  padding: 0;
  /* contain: layout gives each cell its own stacking context + paint
     layer. That's what stops the rows-below "water" ripple — without
     it, opening the menu forces the GPU to repaint pixels under the
     menu's box-shadow, which subtly shifts sub-pixel font rendering
     in the rows below. The trade-off is each cell now paints in its
     own layer, so siblings later in tree order would paint on top of
     an open menu — fixed via the .open z-index bump below. */
  contain: layout style;
}
.cell-markets.open {
  /* When this cell is the active dropdown, hoist its whole stacking
     context above sibling rows so the menu isn't covered by content
     in rows below it. Pairs with the inner menu's own z-index:50.
     Kept just above the other cells' z-index:0 — well below the
     sticky thead's z-index:10. Bumping into thead's stacking range
     was triggering a sticky-positioning recompute on the first row
     (the only row that's adjacent to the header), which read
     visually as the row's matchup cells shifting up a fraction of a
     pixel on click. */
  z-index: 1;
}
.cell-markets .markets-trigger {
  all: unset;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 8px; border-radius: 6px;
  cursor: pointer; line-height: 1;
}
.cell-markets .markets-trigger:hover { background: rgba(255,255,255,0.04); }
.cell-markets .markets-badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 22px; height: 16px; padding: 0 4px;
  border-radius: 4px;
  font-size: 0.62rem; font-weight: 800; letter-spacing: 0.05em;
  color: #0d111a;
}
.cell-markets .markets-badge.book-fanduel    { background: #1493ff; color: #fff; }
.cell-markets .markets-badge.book-draftkings { background: #53d337; color: #0d111a; }
.cell-markets .markets-badge.book-betmgm     { background: #bf8e43; color: #0d111a; }
.cell-markets .markets-badge.book-caesars    { background: #f4c430; color: #0d111a; }
/* Logo variant — when the badge wraps a real book PNG instead of a text
   label, strip the colored chip background so the logo reads cleanly.
   Min-width drops too so the badge sizes to the image itself. */
.cell-markets .markets-badge.with-logo {
  background: transparent;
  padding: 0;
  min-width: 0;
}
.cell-markets .markets-badge-logo {
  height: 14px;
  width: auto;
  display: block;
}
.cell-markets .markets-caret {
  font-size: 0.62rem; color: #888; transition: transform 0.15s ease;
}
.cell-markets.open .markets-caret { transform: rotate(180deg); }
.cell-markets .markets-menu {
  /* Toggle via visibility, not display. A `display: none ↔ block` flip
     was forcing the rows below to repaint as the menu appeared over
     them, producing a subtle "water" ripple from sub-pixel font shifts.
     visibility is paint-only. The compositor-layer promotion that
     composites the OPEN menu over the rows below without invalidating
     their pixels (translate3d + will-change) is scoped to `.open` below
     — NOT here. Promoting every closed menu meant one permanent GPU
     layer per row (50-120 on a full MLB board); WebKit can't keep that
     many resident tiles filled during a fast fling scroll and
     checkerboards (rows flash blank for a frame). `contain: layout` on
     the cell (above) remains the primary anti-ripple guard regardless. */
  visibility: hidden;
  pointer-events: none;
  position: absolute; top: calc(100% + 4px); left: 50%;
  transform: translateX(-50%);
  z-index: 50; min-width: 130px;
  background: #161c28; border: 1px solid rgba(255,255,255,0.10);
  border-radius: 8px; padding: 4px;
  box-shadow: 0 8px 24px rgba(0,0,0,0.4);
}
.cell-markets.open .markets-menu {
  visibility: visible;
  pointer-events: auto;
  /* Promote to its own compositor layer only while open, so the GPU
     composites the menu over the rows below without repainting them
     (the anti-ripple fix) — without paying for a per-row layer on the
     99% of menus that are closed. */
  transform: translateX(-50%) translate3d(0, 0, 0);
  will-change: transform;
}
.cell-markets .markets-option {
  all: unset;
  display: flex; align-items: center; gap: 8px;
  padding: 6px 8px; border-radius: 5px;
  font-size: 0.78rem; cursor: pointer;
  width: calc(100% - 16px);
}
.cell-markets .markets-option:hover  { background: rgba(255,255,255,0.06); }
.cell-markets .markets-option.is-active { background: rgba(0,211,189,0.10); }
.cell-markets .markets-odds { margin-left: auto; font-weight: 700; font-variant-numeric: tabular-nums; }
/* Best price across the visible books wins green; every other option
   stays white. The trigger button's odds (above) keeps the legacy
   positive/negative red/green coloring — only the dropdown rows
   highlight "this is the highest payout". */
.cell-markets .markets-odds.best  { color: #22c55e; }
.cell-markets .markets-odds.other { color: #fff; }

/* ─── Multi-book Place Parlay popup ────────────────────────────────
   Opened by the parlay container's Link button on EVERY workbench route
   (MLB, NFL, NBA — the binding in workbenchCore is unconditional), and
   since 2026-09-20 by the Link button on an upcoming SAVED parlay on
   /user/dashboard. The mlb- prefix on these class names is historical;
   this block is sport-neutral and ships on every page via workbench.css.
   Lists one option per book that quotes every leg, sorted best-first. Each
   option is a stacked row (book name, leg count, combined odds) so a
   3-leg parlay's options stack vertically — clicking opens that book's
   pre-filled multi-leg URL. */
.mlb-link-modal {
  position: fixed; inset: 0;
  background: rgba(0,0,0,0.7);
  z-index: 10000;
  display: flex; align-items: center; justify-content: center;
}
.mlb-link-modal-content {
  background: var(--bg-base, #060e1e);
  border: 1px solid rgba(255,255,255,0.10);
  border-radius: 12px;
  box-shadow: 0 20px 60px rgba(0,0,0,0.6);
  width: min(420px, 92vw); max-height: 86vh;
  display: flex; flex-direction: column; overflow: hidden;
}
.mlb-link-modal-header {
  display: flex; align-items: center; gap: 12px;
  padding: 14px 18px;
  border-bottom: 1px solid rgba(255,255,255,0.08);
}
.mlb-link-modal-title { flex: 1; font-weight: 700; font-size: 0.95rem; color: #e6edf3; }
.mlb-link-modal-close {
  all: unset;
  font-size: 1.4rem; color: #888; cursor: pointer; padding: 0 4px;
}
.mlb-link-modal-close:hover { color: #fff; }

.mlb-link-modal-body {
  display: flex; flex-direction: column; gap: 8px;
  padding: 14px 18px 18px;
}
.mlb-link-option {
  all: unset;
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border-radius: 8px;
  background: rgba(255,255,255,0.03);
  border: 1px solid rgba(255,255,255,0.06);
  cursor: pointer;
  transition: all 0.15s ease;
}
.mlb-link-option:hover { background: rgba(255,255,255,0.06); border-color: rgba(0,211,189,0.3); }
.mlb-link-option.is-best {
  background: rgba(0,211,189,0.08);
  border-color: rgba(0,211,189,0.4);
}
/* Partial-coverage rows — books that quote some but not all legs of the
   parlay. Dimmed so the eye reads "secondary option" alongside the
   fully-covered rows above. The x/n badge in the meta column already
   tells the user how many legs are available; this just makes the row
   visually quieter without hiding it. */
.mlb-link-option.is-partial { opacity: 0.7; }
.mlb-link-option.is-partial:hover { opacity: 1; }
.mlb-link-option-book {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 80px; padding: 6px 10px;
  border-radius: 6px;
  font-weight: 800; font-size: 0.78rem; letter-spacing: 0.04em;
  text-transform: uppercase;
}
.mlb-link-option-book.book-fanduel    { background: rgba(20,147,255,0.18);  color: #58a8ff; }
.mlb-link-option-book.book-draftkings { background: rgba(83,211,55,0.18);   color: #6fdf4d; }
.mlb-link-option-book.book-caesars    { background: rgba(244,196,48,0.18);  color: #f4d061; }
.mlb-link-option-book.book-betmgm     { background: rgba(191,142,67,0.18);  color: #d6a85e; }
/* Logo variant — when the book chip wraps a real PNG plus a text label,
   keep the colored chip tint so the row still reads as a "book pill", but
   slightly tighten padding so the logo + text fit cleanly. */
.mlb-link-option-book.with-logo {
  gap: 6px;
  padding: 4px 8px;
}
.mlb-link-option-logo {
  height: 18px;
  width: auto;
  display: block;
  object-fit: contain;
  flex-shrink: 0;
}
.mlb-link-option-text {
  font-weight: 800;
  font-size: 0.78rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  line-height: 1;
}
.mlb-link-option-meta {
  display: flex;
  align-items: center;
  gap: 6px;
  color: #888;
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
}
/* Coverage pill ("2/2", "5/7"). Subtle neutral tint — its job is to
   carry the count, not draw the eye. Same shape language as the book
   chip on the left so the row reads as three balanced pills. */
.mlb-link-option-coverage {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 4px 8px;
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.07);
  color: rgba(255, 255, 255, 0.85);
  font-weight: 700;
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}
/* Best / partial tag. Uppercase, accent-tinted to mirror the book
   chip's colored variant — green-teal for best (matches the row's
   .is-best border), warm amber for partial. */
.mlb-link-option-tag {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 4px 8px;
  border-radius: 6px;
  font-size: 0.7rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  line-height: 1;
}
.mlb-link-option-tag.is-best {
  background: rgba(0, 211, 189, 0.18);
  color: #00D3BD;
}
.mlb-link-option-tag.is-partial {
  background: rgba(244, 196, 48, 0.15);
  color: #f4c460;
}
/* "N MOVED" — this book only quotes some legs at a DIFFERENT number. Amber
   like PARTIAL because it is the same class of caveat, but it takes the slot
   ahead of PARTIAL: a leg at the wrong line is a worse surprise than one that
   is simply missing. */
.mlb-link-option-tag.is-moved {
  background: rgba(232, 184, 75, 0.16);
  color: #E8B84B;
}

.mlb-link-option-odds {
  font-weight: 800; font-size: 1rem; font-variant-numeric: tabular-nums;
}
.mlb-link-option-odds.positive { color: #22c55e; }
.mlb-link-option-odds.negative { color: #ef4444; }

/* ── Mobile: bigger, touch-friendly multi-book "Place Parlay" popup ──
   On phones/tablets (≤1000px) the popup is the primary tap surface, so
   scale everything up: a wider sheet, larger type, and option rows tall
   enough (~60px) to be comfortable thumb targets. Each row and the close
   button clear the 44px minimum tap target. Desktop sizing is untouched. */
@media (max-width: 1000px) {
  .mlb-link-modal-content {
    width: min(620px, 96vw);
    max-height: 90vh;
    border-radius: 18px;
  }
  .mlb-link-modal-header {
    gap: 16px;
    padding: 20px 24px;
  }
  .mlb-link-modal-title { font-size: 1.4rem; }
  .mlb-link-modal-close {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 48px; min-height: 48px;
    margin: -6px -6px -6px 0;
    font-size: 2.2rem;
  }

  .mlb-link-modal-body {
    gap: 14px;
    padding: 18px 20px 24px;
  }
  .mlb-link-option {
    gap: 16px;
    padding: 22px 18px;
    min-height: 68px;
    border-radius: 14px;
  }
  .mlb-link-option-book {
    min-width: 108px;
    padding: 11px 16px;
    border-radius: 9px;
    font-size: 1.05rem;
  }
  .mlb-link-option-book.with-logo {
    gap: 9px;
    padding: 9px 14px;
  }
  .mlb-link-option-logo { height: 30px; }
  .mlb-link-option-text { font-size: 1.05rem; }
  .mlb-link-option-meta {
    gap: 12px;
    font-size: 1.05rem;
  }
  .mlb-link-option-coverage {
    padding: 8px 13px;
    border-radius: 9px;
    font-size: 1rem;
  }
  .mlb-link-option-tag {
    padding: 8px 13px;
    border-radius: 9px;
    font-size: 0.98rem;
  }
  .mlb-link-option-odds { font-size: 1.6rem; }
}

/* Scrollbar styling for dropdown */
.table-filter-dropdown .dropdown-content::-webkit-scrollbar {
  width: 6px;
}

.table-filter-dropdown .dropdown-content::-webkit-scrollbar-track {
  background: rgba(0, 0, 0, 0.2);
}

.table-filter-dropdown .dropdown-content::-webkit-scrollbar-thumb {
  background: rgba(0, 211, 189, 0.3);
  border-radius: 3px;
}

.table-filter-dropdown .dropdown-content::-webkit-scrollbar-thumb:hover {
  background: rgba(0, 211, 189, 0.5);
}

/* -----------------------------------------------------------------------------
   Table Container
   ----------------------------------------------------------------------------- */
.props-table-container {
  display: none; /* Hidden by default, shown when table view active */
  overflow-x: auto;
  border-radius: 12px;
  background: linear-gradient(180deg, rgba(0, 211, 189, 0.04) 0%, rgba(0, 211, 189, 0.01) 100%);
  border: 1px solid rgba(0, 211, 189, 0.15);
}

.props-table-container.active {
  display: block;
}

/* -----------------------------------------------------------------------------
   Table Base Styles
   ----------------------------------------------------------------------------- */
.props-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
  min-width: 900px; /* Ensure horizontal scroll on smaller desktops */
}

/* -----------------------------------------------------------------------------
   Table Header
   ----------------------------------------------------------------------------- */
.props-table thead {
  position: sticky;
  top: 0;
  z-index: 10;
}

.props-table th {
  background: rgba(0, 211, 189, 0.12);
  color: rgba(0, 211, 189, 0.9);
  padding: 14px 10px;
  text-align: left;
  font-weight: 600;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  white-space: nowrap;
  border-bottom: none;
  user-select: none;
}

/* Custom hover tooltip for column headers. Reads from `data-tooltip`
   (not `title`) so the browser's native title bubble doesn't fire on
   top of our custom CSS one — the previous version using `title`
   produced a doubled tooltip on slow hovers when the native one's
   ~1.5s delay finally kicked in. Accessibility is covered by an
   `aria-label` set alongside `data-tooltip` for screen readers.
   Tooltip stays hidden until the user has hovered ~2s — long enough
   that brief drags / scrolls past a header don't pop tooltips, but
   short enough that a deliberate "what does this mean?" hover surfaces
   the help text. Hide is instant (no delay) so the tooltip vanishes
   the moment the cursor leaves. */
.props-table th[data-tooltip] { position: relative; }
.props-table th[data-tooltip]::after {
  content: attr(data-tooltip);
  position: absolute;
  top: calc(100% + 4px);
  left: 50%;
  transform: translateX(-50%);
  z-index: 1000;
  pointer-events: none;
  background: rgba(15, 23, 42, 0.97);
  color: #f1f5f9;
  padding: 8px 12px;
  border-radius: 6px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.5);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  text-align: center;
  line-height: 1.4;
  white-space: normal;
  width: max-content;
  max-width: 240px;
  /* Hidden state — visibility kept off so the empty box doesn't
     intercept layout. Hide transition is instant. */
  opacity: 0;
  visibility: hidden;
  transition: opacity 120ms ease 0ms, visibility 0ms linear 120ms;
}
.props-table th[data-tooltip]:hover::after {
  opacity: 1;
  visibility: visible;
  /* 1.5s delay before the tooltip appears — fires only on a deliberate
     pause, not on a brief drag-by. Visibility flips instantly at the
     start of the transition so the fade-in actually shows. */
  transition: opacity 150ms ease 1200ms, visibility 0ms linear 1200ms;
}
/* Right-edge columns (Pitch Mix is the rightmost MLB col) need the
   tooltip nudged left so it doesn't push past the viewport. */
.props-table th.col-opponent[data-tooltip]:hover::after {
  left: auto;
  right: 0;
  transform: none;
}

.props-table th.sortable {
  cursor: pointer;
  transition: background 0.15s ease;
}

.props-table th.sortable:hover {
  background: rgba(0, 211, 189, 0.2);
}

.props-table th.sorted {
  background: rgba(0, 211, 189, 0.18);
}

/* Sort indicator */
.props-table th .sort-indicator {
  display: inline-block;
  margin-left: 3px;
  font-size: 1.1em;
  opacity: 0.4;
  transition: opacity 0.15s ease, transform 0.15s ease;
}

.props-table th.sortable:hover .sort-indicator {
  opacity: 0.7;
}

.props-table th.sorted .sort-indicator {
  opacity: 1;
}

.props-table th.sorted.desc .sort-indicator {
  transform: rotate(180deg);
}

/* Column widths */
.props-table .col-grade {
  width: 55px;
  text-align: center;
}

.props-table .col-team {
  width: 100px;
  text-align: center;
}

.props-table .col-pos {
  width: 50px;
  text-align: center;
}

.props-table .col-player {
  min-width: 140px;
}

.props-table .col-prop {
  min-width: 120px;
}

.props-table .col-odds {
  width: 70px;
  text-align: center;
}

.props-table .col-opponent {
  width: 120px;
  text-align: center;
}

.props-table .col-vs-opp {
  width: 70px;
  text-align: center;
}

.props-table .col-l5 {
  width: 60px;
  text-align: center;
}

.props-table .col-l10 {
  width: 60px;
  text-align: center;
}

/* -----------------------------------------------------------------------------
   MLB-only columns (rendered only when TableView is initialized with isMLB=true)
   ----------------------------------------------------------------------------- */
.props-table .col-woba-hand,
.props-table .cell-woba-hand {
  width: 70px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.props-table .col-brl,
.props-table .cell-brl {
  width: 60px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.props-table .col-park,
.props-table .cell-park {
  width: 78px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.props-table .cell-park .park-value { font-weight: 600; }
/* No-data styling for wOBA/H · Brl% · Park is now driven by [data-tier="na"]
   below — kept centralized with the other tier rules. */

/* ── Tier color-coding (shared across all 3 MLB metric cells) ──
   Same palette + 6-tier vocabulary as .cell-opponent so the eye reads them
   consistently. Higher value = more favorable for the bettor → cooler/green;
   lower → warmer/red. The numeric value picks up the tier color, the cell
   gets a soft tint matching it. */
.props-table .cell-woba-hand[data-tier="elite"],
.props-table .cell-brl[data-tier="elite"],
.props-table .cell-park[data-tier="elite"] {
  background: rgba(0, 245, 212, 0.18);
}
.props-table .cell-woba-hand[data-tier="elite"] .woba-value,
.props-table .cell-brl[data-tier="elite"]  .brl-value,
.props-table .cell-park[data-tier="elite"] .park-value {
  color: #00F5D4;
}

.props-table .cell-woba-hand[data-tier="great"],
.props-table .cell-brl[data-tier="great"],
.props-table .cell-park[data-tier="great"] {
  background: rgba(74, 222, 128, 0.18);
}
.props-table .cell-woba-hand[data-tier="great"] .woba-value,
.props-table .cell-brl[data-tier="great"]  .brl-value,
.props-table .cell-park[data-tier="great"] .park-value {
  color: #4ade80;
}

.props-table .cell-woba-hand[data-tier="good"],
.props-table .cell-brl[data-tier="good"],
.props-table .cell-park[data-tier="good"] {
  background: rgba(163, 230, 53, 0.18);
}
.props-table .cell-woba-hand[data-tier="good"] .woba-value,
.props-table .cell-brl[data-tier="good"]  .brl-value,
.props-table .cell-park[data-tier="good"] .park-value {
  color: #a3e635;
}

.props-table .cell-woba-hand[data-tier="neutral"],
.props-table .cell-brl[data-tier="neutral"],
.props-table .cell-park[data-tier="neutral"] {
  background: rgba(250, 204, 21, 0.10);
}
.props-table .cell-woba-hand[data-tier="neutral"] .woba-value,
.props-table .cell-brl[data-tier="neutral"]  .brl-value,
.props-table .cell-park[data-tier="neutral"] .park-value {
  color: #facc15;
}

.props-table .cell-woba-hand[data-tier="poor"],
.props-table .cell-brl[data-tier="poor"],
.props-table .cell-park[data-tier="poor"] {
  background: rgba(234, 88, 12, 0.18);
}
.props-table .cell-woba-hand[data-tier="poor"] .woba-value,
.props-table .cell-brl[data-tier="poor"]  .brl-value,
.props-table .cell-park[data-tier="poor"] .park-value {
  color: #ea580c;
}

.props-table .cell-woba-hand[data-tier="bad"],
.props-table .cell-brl[data-tier="bad"],
.props-table .cell-park[data-tier="bad"] {
  background: rgba(239, 68, 68, 0.18);
}
.props-table .cell-woba-hand[data-tier="bad"] .woba-value,
.props-table .cell-brl[data-tier="bad"]  .brl-value,
.props-table .cell-park[data-tier="bad"] .park-value {
  color: #ef4444;
}

/* No-data rows — same grey tint as the Matchup N/A pill, with the value
   text shrunk + dimmed so "N/A" reads as a label rather than a number. */
.props-table .cell-woba-hand[data-tier="na"],
.props-table .cell-brl[data-tier="na"],
.props-table .cell-park[data-tier="na"] {
  background: rgba(255, 255, 255, .04);
}
.props-table .cell-woba-hand[data-tier="na"] .woba-value,
.props-table .cell-brl[data-tier="na"]  .brl-value,
.props-table .cell-park[data-tier="na"] .park-value {
  color: var(--text3, #8c8f96);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .4px;
}

/* -----------------------------------------------------------------------------
   MLB per-prop-type matchup metric columns. These swap in/out based on the
   active prop-type pill (HR / Hits / etc.). Geometry mirrors the legacy
   wOBA/H · Brl% · Park columns so the table layout doesn't shift on switch.
   ----------------------------------------------------------------------------- */
.props-table .col-avg-hand,    .props-table .cell-avg-hand,
.props-table .col-iso-hand,    .props-table .cell-iso-hand,
.props-table .col-batk-hand,   .props-table .cell-batk-hand,
.props-table .col-pitk-hand,   .props-table .cell-pitk-hand,
.props-table .col-hr9-hand,    .props-table .cell-hr9-hand,
.props-table .col-hrpa-hand,   .props-table .cell-hrpa-hand,
.props-table .col-brl-l30,     .props-table .cell-brl-l30,
.props-table .col-hpa-hand,    .props-table .cell-hpa-hand,
.props-table .col-hardhit-l30, .props-table .cell-hardhit-l30,
.props-table .col-baa-hand,    .props-table .cell-baa-hand,
.props-table .col-tb-pa-hand,  .props-table .cell-tb-pa-hand,
.props-table .col-lineup-woba, .props-table .cell-lineup-woba,
.props-table .col-matchup-mult, .props-table .cell-matchup-mult,
.props-table .col-weather-pct, .props-table .cell-weather-pct {
  width: 70px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
/* "Roof Closed" stacked label — shown in place of the ±X% value when the
   game is at a closed-roof park. Two lines sit inside the same row height
   as the numeric value; muted color signals "weather doesn't apply" rather
   than green/red coloring that would imply an actual reading. */
.props-table .cell-weather-pct .cell-weather-closed {
  display: inline-block;
  line-height: 1.35;             /* breathing room between the two lines */
  font-size: 9px;                /* drop one px so 1.35 line-height still fits row */
  font-weight: 600;
  letter-spacing: .3px;
  color: #94a3b8;
}

/* Tier color-coding — applied to every per-prop-type cell uniformly so the
   visual language stays the same across the legacy wOBA/Brl/Park trio and
   the new ISO/HR9/K%/BA cells. Mirrors the palette used above. */
.props-table .cell-avg-hand[data-tier="elite"],
.props-table .cell-iso-hand[data-tier="elite"],
.props-table .cell-batk-hand[data-tier="elite"],
.props-table .cell-pitk-hand[data-tier="elite"],
.props-table .cell-hr9-hand[data-tier="elite"],
.props-table .cell-hrpa-hand[data-tier="elite"],
.props-table .cell-brl-l30[data-tier="elite"],
.props-table .cell-hpa-hand[data-tier="elite"],
.props-table .cell-hardhit-l30[data-tier="elite"],
.props-table .cell-baa-hand[data-tier="elite"],
.props-table .cell-tb-pa-hand[data-tier="elite"],
.props-table .cell-lineup-woba[data-tier="elite"],
.props-table .cell-matchup-mult[data-tier="elite"],
.props-table .cell-weather-pct[data-tier="elite"] { background: rgba(0, 245, 212, 0.18); }
.props-table .cell-avg-hand[data-tier="elite"]  .metric-value,
.props-table .cell-iso-hand[data-tier="elite"]  .metric-value,
.props-table .cell-batk-hand[data-tier="elite"] .metric-value,
.props-table .cell-pitk-hand[data-tier="elite"] .metric-value,
.props-table .cell-hr9-hand[data-tier="elite"]  .metric-value,
.props-table .cell-hrpa-hand[data-tier="elite"] .metric-value,
.props-table .cell-brl-l30[data-tier="elite"]   .metric-value,
.props-table .cell-hpa-hand[data-tier="elite"]  .metric-value,
.props-table .cell-hardhit-l30[data-tier="elite"] .metric-value,
.props-table .cell-baa-hand[data-tier="elite"]  .metric-value,
.props-table .cell-tb-pa-hand[data-tier="elite"] .metric-value,
.props-table .cell-lineup-woba[data-tier="elite"] .metric-value,
.props-table .cell-matchup-mult[data-tier="elite"] .metric-value,
.props-table .cell-weather-pct[data-tier="elite"] .metric-value { color: #00F5D4; }

.props-table .cell-avg-hand[data-tier="great"],
.props-table .cell-iso-hand[data-tier="great"],
.props-table .cell-batk-hand[data-tier="great"],
.props-table .cell-pitk-hand[data-tier="great"],
.props-table .cell-hr9-hand[data-tier="great"],
.props-table .cell-hrpa-hand[data-tier="great"],
.props-table .cell-brl-l30[data-tier="great"],
.props-table .cell-hpa-hand[data-tier="great"],
.props-table .cell-hardhit-l30[data-tier="great"],
.props-table .cell-baa-hand[data-tier="great"],
.props-table .cell-tb-pa-hand[data-tier="great"],
.props-table .cell-lineup-woba[data-tier="great"],
.props-table .cell-matchup-mult[data-tier="great"],
.props-table .cell-weather-pct[data-tier="great"] { background: rgba(74, 222, 128, 0.18); }
.props-table .cell-avg-hand[data-tier="great"]  .metric-value,
.props-table .cell-iso-hand[data-tier="great"]  .metric-value,
.props-table .cell-batk-hand[data-tier="great"] .metric-value,
.props-table .cell-pitk-hand[data-tier="great"] .metric-value,
.props-table .cell-hr9-hand[data-tier="great"]  .metric-value,
.props-table .cell-hrpa-hand[data-tier="great"] .metric-value,
.props-table .cell-brl-l30[data-tier="great"]   .metric-value,
.props-table .cell-hpa-hand[data-tier="great"]  .metric-value,
.props-table .cell-hardhit-l30[data-tier="great"] .metric-value,
.props-table .cell-baa-hand[data-tier="great"]  .metric-value,
.props-table .cell-tb-pa-hand[data-tier="great"] .metric-value,
.props-table .cell-lineup-woba[data-tier="great"] .metric-value,
.props-table .cell-matchup-mult[data-tier="great"] .metric-value,
.props-table .cell-weather-pct[data-tier="great"] .metric-value { color: #4ade80; }

.props-table .cell-avg-hand[data-tier="good"],
.props-table .cell-iso-hand[data-tier="good"],
.props-table .cell-batk-hand[data-tier="good"],
.props-table .cell-pitk-hand[data-tier="good"],
.props-table .cell-hr9-hand[data-tier="good"],
.props-table .cell-hrpa-hand[data-tier="good"],
.props-table .cell-brl-l30[data-tier="good"],
.props-table .cell-hpa-hand[data-tier="good"],
.props-table .cell-hardhit-l30[data-tier="good"],
.props-table .cell-baa-hand[data-tier="good"],
.props-table .cell-tb-pa-hand[data-tier="good"],
.props-table .cell-lineup-woba[data-tier="good"],
.props-table .cell-matchup-mult[data-tier="good"],
.props-table .cell-weather-pct[data-tier="good"] { background: rgba(163, 230, 53, 0.18); }
.props-table .cell-avg-hand[data-tier="good"]   .metric-value,
.props-table .cell-iso-hand[data-tier="good"]   .metric-value,
.props-table .cell-batk-hand[data-tier="good"]  .metric-value,
.props-table .cell-pitk-hand[data-tier="good"]  .metric-value,
.props-table .cell-hr9-hand[data-tier="good"]   .metric-value,
.props-table .cell-hrpa-hand[data-tier="good"]  .metric-value,
.props-table .cell-brl-l30[data-tier="good"]    .metric-value,
.props-table .cell-hpa-hand[data-tier="good"]   .metric-value,
.props-table .cell-hardhit-l30[data-tier="good"] .metric-value,
.props-table .cell-baa-hand[data-tier="good"]   .metric-value,
.props-table .cell-tb-pa-hand[data-tier="good"] .metric-value,
.props-table .cell-lineup-woba[data-tier="good"] .metric-value,
.props-table .cell-matchup-mult[data-tier="good"] .metric-value,
.props-table .cell-weather-pct[data-tier="good"] .metric-value { color: #a3e635; }

.props-table .cell-avg-hand[data-tier="neutral"],
.props-table .cell-iso-hand[data-tier="neutral"],
.props-table .cell-batk-hand[data-tier="neutral"],
.props-table .cell-pitk-hand[data-tier="neutral"],
.props-table .cell-hr9-hand[data-tier="neutral"],
.props-table .cell-hrpa-hand[data-tier="neutral"],
.props-table .cell-brl-l30[data-tier="neutral"],
.props-table .cell-hpa-hand[data-tier="neutral"],
.props-table .cell-hardhit-l30[data-tier="neutral"],
.props-table .cell-baa-hand[data-tier="neutral"],
.props-table .cell-tb-pa-hand[data-tier="neutral"],
.props-table .cell-lineup-woba[data-tier="neutral"],
.props-table .cell-matchup-mult[data-tier="neutral"],
.props-table .cell-weather-pct[data-tier="neutral"] { background: rgba(250, 204, 21, 0.10); }
.props-table .cell-avg-hand[data-tier="neutral"]  .metric-value,
.props-table .cell-iso-hand[data-tier="neutral"]  .metric-value,
.props-table .cell-batk-hand[data-tier="neutral"] .metric-value,
.props-table .cell-pitk-hand[data-tier="neutral"] .metric-value,
.props-table .cell-hr9-hand[data-tier="neutral"]  .metric-value,
.props-table .cell-hrpa-hand[data-tier="neutral"] .metric-value,
.props-table .cell-brl-l30[data-tier="neutral"]   .metric-value,
.props-table .cell-hpa-hand[data-tier="neutral"]  .metric-value,
.props-table .cell-hardhit-l30[data-tier="neutral"] .metric-value,
.props-table .cell-baa-hand[data-tier="neutral"]  .metric-value,
.props-table .cell-tb-pa-hand[data-tier="neutral"] .metric-value,
.props-table .cell-lineup-woba[data-tier="neutral"] .metric-value,
.props-table .cell-matchup-mult[data-tier="neutral"] .metric-value,
.props-table .cell-weather-pct[data-tier="neutral"] .metric-value { color: #facc15; }

.props-table .cell-avg-hand[data-tier="poor"],
.props-table .cell-iso-hand[data-tier="poor"],
.props-table .cell-batk-hand[data-tier="poor"],
.props-table .cell-pitk-hand[data-tier="poor"],
.props-table .cell-hr9-hand[data-tier="poor"],
.props-table .cell-hrpa-hand[data-tier="poor"],
.props-table .cell-brl-l30[data-tier="poor"],
.props-table .cell-hpa-hand[data-tier="poor"],
.props-table .cell-hardhit-l30[data-tier="poor"],
.props-table .cell-baa-hand[data-tier="poor"],
.props-table .cell-tb-pa-hand[data-tier="poor"],
.props-table .cell-lineup-woba[data-tier="poor"],
.props-table .cell-matchup-mult[data-tier="poor"],
.props-table .cell-weather-pct[data-tier="poor"] { background: rgba(234, 88, 12, 0.18); }
.props-table .cell-avg-hand[data-tier="poor"]   .metric-value,
.props-table .cell-iso-hand[data-tier="poor"]   .metric-value,
.props-table .cell-batk-hand[data-tier="poor"]  .metric-value,
.props-table .cell-pitk-hand[data-tier="poor"]  .metric-value,
.props-table .cell-hr9-hand[data-tier="poor"]   .metric-value,
.props-table .cell-hrpa-hand[data-tier="poor"]  .metric-value,
.props-table .cell-brl-l30[data-tier="poor"]    .metric-value,
.props-table .cell-hpa-hand[data-tier="poor"]   .metric-value,
.props-table .cell-hardhit-l30[data-tier="poor"] .metric-value,
.props-table .cell-baa-hand[data-tier="poor"]   .metric-value,
.props-table .cell-tb-pa-hand[data-tier="poor"] .metric-value,
.props-table .cell-lineup-woba[data-tier="poor"] .metric-value,
.props-table .cell-matchup-mult[data-tier="poor"] .metric-value,
.props-table .cell-weather-pct[data-tier="poor"] .metric-value { color: #ea580c; }

.props-table .cell-avg-hand[data-tier="bad"],
.props-table .cell-iso-hand[data-tier="bad"],
.props-table .cell-batk-hand[data-tier="bad"],
.props-table .cell-pitk-hand[data-tier="bad"],
.props-table .cell-hr9-hand[data-tier="bad"],
.props-table .cell-hrpa-hand[data-tier="bad"],
.props-table .cell-brl-l30[data-tier="bad"],
.props-table .cell-hpa-hand[data-tier="bad"],
.props-table .cell-hardhit-l30[data-tier="bad"],
.props-table .cell-baa-hand[data-tier="bad"],
.props-table .cell-tb-pa-hand[data-tier="bad"],
.props-table .cell-lineup-woba[data-tier="bad"],
.props-table .cell-matchup-mult[data-tier="bad"],
.props-table .cell-weather-pct[data-tier="bad"] { background: rgba(239, 68, 68, 0.18); }
.props-table .cell-avg-hand[data-tier="bad"]    .metric-value,
.props-table .cell-iso-hand[data-tier="bad"]    .metric-value,
.props-table .cell-batk-hand[data-tier="bad"]   .metric-value,
.props-table .cell-pitk-hand[data-tier="bad"]   .metric-value,
.props-table .cell-hr9-hand[data-tier="bad"]    .metric-value,
.props-table .cell-hrpa-hand[data-tier="bad"]   .metric-value,
.props-table .cell-brl-l30[data-tier="bad"]     .metric-value,
.props-table .cell-hpa-hand[data-tier="bad"]    .metric-value,
.props-table .cell-hardhit-l30[data-tier="bad"]  .metric-value,
.props-table .cell-baa-hand[data-tier="bad"]    .metric-value,
.props-table .cell-tb-pa-hand[data-tier="bad"] .metric-value,
.props-table .cell-lineup-woba[data-tier="bad"] .metric-value,
.props-table .cell-matchup-mult[data-tier="bad"] .metric-value,
.props-table .cell-weather-pct[data-tier="bad"] .metric-value { color: #ef4444; }

.props-table .cell-avg-hand[data-tier="na"],
.props-table .cell-iso-hand[data-tier="na"],
.props-table .cell-batk-hand[data-tier="na"],
.props-table .cell-pitk-hand[data-tier="na"],
.props-table .cell-hr9-hand[data-tier="na"],
.props-table .cell-hrpa-hand[data-tier="na"],
.props-table .cell-brl-l30[data-tier="na"],
.props-table .cell-hpa-hand[data-tier="na"],
.props-table .cell-hardhit-l30[data-tier="na"],
.props-table .cell-baa-hand[data-tier="na"],
.props-table .cell-tb-pa-hand[data-tier="na"],
.props-table .cell-lineup-woba[data-tier="na"],
.props-table .cell-matchup-mult[data-tier="na"],
.props-table .cell-weather-pct[data-tier="na"] { background: rgba(255, 255, 255, .04); }
.props-table .cell-avg-hand[data-tier="na"]    .metric-value,
.props-table .cell-iso-hand[data-tier="na"]    .metric-value,
.props-table .cell-batk-hand[data-tier="na"]   .metric-value,
.props-table .cell-pitk-hand[data-tier="na"]   .metric-value,
.props-table .cell-hr9-hand[data-tier="na"]    .metric-value,
.props-table .cell-hrpa-hand[data-tier="na"]   .metric-value,
.props-table .cell-brl-l30[data-tier="na"]     .metric-value,
.props-table .cell-hpa-hand[data-tier="na"]    .metric-value,
.props-table .cell-hardhit-l30[data-tier="na"]  .metric-value,
.props-table .cell-baa-hand[data-tier="na"]    .metric-value,
.props-table .cell-tb-pa-hand[data-tier="na"] .metric-value,
.props-table .cell-lineup-woba[data-tier="na"] .metric-value,
.props-table .cell-matchup-mult[data-tier="na"] .metric-value {
  color: var(--text3, #8c8f96);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .4px;
}

/* -----------------------------------------------------------------------------
   MLB prop-type pill row — sits above the props-table, filters rows by
   prop_type, and swaps the middle metric column trio. Visual language
   matches the research-hub filter pills so the workbench feels of-a-piece.
   ----------------------------------------------------------------------------- */
/* Container loses the panel-style background — the pills are strong
   enough as a visual unit on their own. Flex with space-between pushes
   pills to the left, hint to the right. */
.tv-mlb-prop-pills {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  /* Symmetric vertical padding keeps the pills centred in their own box (the
     old 6px pad + 8px margin-bottom sat them ~6px from the top but ~14px from
     the table). The margin is SEPARATION FROM THE TABLE, which is a different
     job — dropping it in 6ce702dc closed the gap to 0 and the strip read as
     part of the table header. */
  padding: 10px 14px;
  /* Small: the 10px bottom padding already separates the pills from the table,
     and the strip shares the table's panel background so a large margin here
     reads as a dead band rather than as breathing room. The visible separation
     belongs ABOVE the strip, between two differently-coloured boxes. */
  margin-bottom: 4px;
}

/* Same story one row up: the filter bar sat 1px off the pills. Scoped on a
   body class, NOT .props-table-container — the bar lives in a sibling
   .glass-panel, outside that container entirely.
   2026-08-25: extended to NFL, which still had the original 1px gap (the
   filter buttons sat flush against the table header). NFL's body class is
   `is-nba-route` — that is the GENERIC multi-book class the shared tableView
   adds for any multiBook sport, not an NBA-only marker, so this covers NFL
   and NBA alike. */
body.is-mlb-route .table-filter-bar,
body.is-nba-route .table-filter-bar { margin-bottom: 18px; }
.tv-mlb-prop-pills-group {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
/* Right-side info column — color legend stacked above the click-affordance
   hint. Container collapses to fit-content + center-aligns its children so
   the hint visually anchors to the legend rather than the page edge. */
.tv-mlb-prop-pills-info {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
}
.tv-mlb-prop-pills-hint {
  font-size: 13px;
  color: var(--text2, #cbd5e1);
  letter-spacing: .2px;
  font-style: italic;
  user-select: none;
  white-space: nowrap;
}
/* Color legend — small horizontal pill swatches + labels mapping to the
   cell tier palette used throughout the table. */
.tv-mlb-prop-pills-legend {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 11px;
  color: var(--text3, #8c8f96);
  letter-spacing: .2px;
  user-select: none;
  white-space: nowrap;
}
.tv-mlb-leg-item {
  display: inline-flex;
  align-items: center;
  gap: 5px;
}
.tv-mlb-leg-dot {
  display: inline-block;
  width: 18px;
  height: 8px;
  border-radius: 4px;
  background: rgba(148, 163, 184, .5);
}
.tv-mlb-leg-dot[data-tier="great"]   { background: #4ade80; }
.tv-mlb-leg-dot[data-tier="good"]    { background: #a3e635; }
.tv-mlb-leg-dot[data-tier="neutral"] { background: #facc15; }
.tv-mlb-leg-dot[data-tier="poor"]    { background: #ea580c; }
.tv-mlb-leg-dot[data-tier="bad"]     { background: #ef4444; }
.tv-mlb-prop-pill {
  padding: 9px 22px;                /* roomier — pills feel like primary nav, not chips */
  background: rgba(148, 163, 184, .06);
  border: 1px solid rgba(255, 255, 255, .08);
  border-radius: 999px;
  color: #f1f5f9;
  font-size: 13px; font-weight: 700;
  letter-spacing: .3px;
  cursor: pointer;
  transition: color 120ms ease, background 120ms ease, border-color 120ms ease;
}
.tv-mlb-prop-pill:hover {
  border-color: rgba(255, 255, 255, .20);
}
.tv-mlb-prop-pill.is-active {
  color: #f8fafc;
  background: rgba(34, 211, 238, .15);
  border-color: rgba(34, 211, 238, .50);
}

/* MLB opponent cell — stacks team + starting pitcher line.
   Overrides the inherited `cell-opponent` width since we need room for the
   pitcher's name. Not clickable (no def-rank popup for MLB). */
.props-table .cell-opponent.is-mlb {
  /* Wider than the NBA opponent column because we render two stacked
     items (pitch-mix pill + pitcher avatar/name/hand badge) instead of
     just a defensive-rank badge. min-width sets a floor, max-width caps
     it — long names ellipsize at the 160px name-cap below rather than
     pushing the whole column wider. */
  min-width: 170px;
  max-width: 240px;
  text-align: left;
  padding: 6px 10px;
  cursor: default;
  /* Match the batter's name typography from .cell-player so the matchup
     reads as two visually equal players. */
  font-weight: 600;
  color: rgba(255, 255, 255, 0.95);
}
.props-table .cell-opponent.is-mlb .opponent-info {
  /* Plain inline-block flow. The cell's padding-left puts the pill's
     left edge at a fixed x; everything else just lines up after it via
     natural document flow + each child's own fixed width. No flex / no
     grid means nothing can shrink, stretch, or shift between rows. */
  white-space: nowrap;
  line-height: 28px;
}
.props-table .cell-opponent.is-mlb .mlb-opp-pitcher {
  display: inline-block;
  vertical-align: middle;
  white-space: nowrap;
}
.props-table .cell-opponent.is-mlb .mlb-opp-pitcher-name {
  /* Inherit weight + color from .cell-opponent.is-mlb (same as batter name).
     Single-line fallback (rare — only when the name has no space, e.g.
     a one-word handle); stacked variant is handled below. */
  display: inline-block;
  vertical-align: middle;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 160px;
}
/* Stacked first/last name — first name on top (with the hand badge
   inline beside it), last name underneath. The parent inherits
   .opponent-info's 28px line-height (set so the 28px avatar centers
   cleanly), which would push the two lines too far apart; we reset to
   a tighter line-height inside the stacked variant. */
.props-table .cell-opponent.is-mlb .mlb-opp-pitcher-name.is-stacked {
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
  line-height: 1.25;
  font-size: 13px;
}
.props-table .cell-opponent.is-mlb .mlb-opp-pitcher-fname,
.props-table .cell-opponent.is-mlb .mlb-opp-pitcher-lname {
  display: block;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 140px;
}
.props-table .cell-opponent.is-mlb .mlb-opp-pitcher-fname {
  /* First name a touch lighter so the eye lands on the last name first
     (the more identifying half of a player's name in box scores). */
  font-weight: 500;
  color: rgba(255, 255, 255, 0.85);
}
.props-table .cell-opponent.is-mlb .mlb-opp-pitcher-lname {
  font-weight: 600;
}
/* Pitcher avatar matches the batter avatar size in the Player col so the
   two players in the matchup read as visually equal. The team logo lives
   as a small overlay in the bottom-right corner instead of taking its own
   slot on the line — signals team affiliation without duplicating the
   team-code text already on the line above. */
.props-table .cell-opponent.is-mlb .tv-pitcher-avatar-wrap {
  position: relative;
  display: inline-block;
  vertical-align: middle;
  width: 28px;
  height: 28px;
  margin-right: 8px;
}
.props-table .cell-opponent.is-mlb .tv-pitcher-avatar {
  width: 28px;
  height: 28px;
  margin: 0;
  display: block;
}
.props-table .cell-opponent.is-mlb .tv-pitcher-team-logo {
  position: absolute;
  right: -3px;
  bottom: -3px;
  width: 14px;
  height: 14px;
  object-fit: contain;
  border-radius: 50%;
  background: var(--bg2, #1a1d24);
  padding: 1px;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.5);
}
.props-table .cell-opponent.is-mlb .mlb-opp-pitcher-tba {
  font-size: 10px;
  color: var(--text3, #8c8f96);
  font-style: italic;
  letter-spacing: .3px;
}

/* Pitcher-hand badge — exact same shape/size as .tv-bat-badge so the LHP/RHP
   pill in the opponent col reads as a visual peer of the LHB/RHB pill in
   the player col. */
.props-table .tv-pitch-badge {
  display: inline-block;
  margin-left: 8px;
  padding: 0 4px;
  border-radius: 3px;
  font-size: 9px;
  /* Override the .opponent-info / inherited line-height so the badge
     renders compactly — without an explicit reset it inherits the
     stacked-name's line-height and ends up bigger than intended. */
  line-height: 1.5;
  font-weight: 700;
  letter-spacing: .3px;
  background: rgba(255, 255, 255, 0.08);
  color: var(--text2, #c9ccd3);
  vertical-align: middle;
}
.props-table .tv-pitch-badge[data-hand="L"] {
  background: rgba(96, 165, 250, 0.16);
  color: #93c5fd;
}
.props-table .tv-pitch-badge[data-hand="R"] {
  background: rgba(248, 113, 113, 0.16);
  color: #fca5a5;
}

/* Pitch-mix grade pill — sits at the LEFT edge of the MLB matchup cell,
   matching the visual rhythm of the wOBA/H · Brl% · Park columns to its
   left (number-first, then context). The cell itself is tinted by the
   same tier so the matchup color reads at a glance. */
.props-table .tv-pm-pill {
  /* Fixed-size inline-block. Width / padding / left-align text is the
     only thing controlling number position. tabular-nums locks per-digit
     advance so "4.8" / "7.3" / "10.0" all occupy identical extents. */
  display: inline-block;
  vertical-align: middle;
  box-sizing: border-box;
  width: 38px;
  height: 22px;
  margin-right: 10px;
  padding: 0 0 0 8px;
  border-radius: 4px;
  font-size: 12px;
  line-height: 22px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: .3px;
  text-align: left;
  background: rgba(255, 255, 255, 0.06);
  color: var(--text2, #c9ccd3);
}
/* Pill keeps its own bolder tint so the number reads as a separate chip
   even when the cell behind it is already tinted in the same hue. */
.props-table .tv-pm-pill[data-tier="elite"]   { background: rgba(  0, 245, 212, .22); color: #00F5D4; }
.props-table .tv-pm-pill[data-tier="great"]   { background: rgba( 74, 222, 128, .26); color: #4ade80; }
.props-table .tv-pm-pill[data-tier="good"]    { background: rgba(163, 230,  53, .26); color: #a3e635; }
.props-table .tv-pm-pill[data-tier="neutral"] { background: rgba(250, 204, 21, 0.22); color: #facc15; }
.props-table .tv-pm-pill[data-tier="poor"]    { background: rgba(234, 88, 12, 0.26); color: #ea580c; }
.props-table .tv-pm-pill[data-tier="bad"]     { background: rgba(239,  68,  68, .26); color: #ef4444; }
/* No-data pill — neutral grey, smaller font so "N/A" doesn't dominate. */
.props-table .tv-pm-pill[data-tier="na"] {
  background: rgba(255, 255, 255, .08);
  color: var(--text3, #8c8f96);
  font-size: 10px;
  letter-spacing: .4px;
}

/* Cell-level tint by matchup-grade tier — matches the per-prop-type
   metric columns so the rightmost zone shares one color language. */
.props-table .cell-opponent.is-mlb[data-tier="elite"]   { background: rgba(  0, 245, 212, .18); }
.props-table .cell-opponent.is-mlb[data-tier="great"]   { background: rgba( 74, 222, 128, .18); }
.props-table .cell-opponent.is-mlb[data-tier="good"]    { background: rgba(163, 230,  53, .18); }
.props-table .cell-opponent.is-mlb[data-tier="neutral"] { background: rgba(250, 204, 21, 0.10); }
.props-table .cell-opponent.is-mlb[data-tier="poor"]    { background: rgba(234, 88, 12, 0.18); }
.props-table .cell-opponent.is-mlb[data-tier="bad"]     { background: rgba(239,  68,  68, .18); }
.props-table .cell-opponent.is-mlb[data-tier="na"]      { background: rgba(255, 255, 255, .04); }

.props-table .cell-opponent.is-mlb.clickable {
  cursor: pointer;
}
.props-table .cell-opponent.is-mlb.clickable:hover {
  /* Slight lift on hover regardless of tier — overrides the tier tint. */
  filter: brightness(1.15);
}

/* ── Pitch-mix popup overlay + modal ── */
.tv-pm-overlay {
  position: fixed; inset: 0; z-index: 9999;
  display: flex; align-items: center; justify-content: center;
  background: rgba(0, 0, 0, 0.65);
  backdrop-filter: blur(2px);
  animation: tvPmFade .15s ease-out;
}
@keyframes tvPmFade {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.tv-pm-modal {
  position: relative;
  max-width: 760px;
  width: calc(100vw - 32px);
  max-height: calc(100vh - 64px);
  overflow: auto;
  padding: 24px 24px 20px;
  border-radius: 10px;
  /* BLACK canvas. This used to be the card grey so the popup would not vanish
     into a pure-black page — but every popup now composes its content out of
     grey panels of its own, so those carry the elevation and the sheet reads
     better behind them. Separation from the page comes from the 0.65 scrim,
     the hairline border and the drop shadow, not from the fill. */
  background: #000;
  border: 1px solid rgba(255, 255, 255, 0.10);
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.75);
}
.tv-pm-close {
  position: absolute; top: 8px; right: 12px;
  background: transparent; border: 0;
  color: var(--text3, #8c8f96);
  font-size: 26px; line-height: 1;
  cursor: pointer; padding: 4px 8px;
}
.tv-pm-close:hover { color: var(--text, #e5e7eb); }
.tv-pm-loading {
  padding: 60px 0;
  text-align: center;
  color: var(--text3, #8c8f96);
  font-size: 14px;
}

/* Weather popup — wider modal so the dashboard's Q2 weather panel
   (Conditions strip + grid + Ball Flight cards) fits without crowding.
   Loading/empty states share the same vertical-padded muted style as
   the pitch-mix loader. */
.tv-pm-modal-weather {
  max-width: 1100px;
}
.tv-wx-loading,
.tv-wx-empty {
  padding: 60px 0;
  text-align: center;
  color: var(--text3, #8c8f96);
  font-size: 14px;
}

/* Info-card popup — used by Rate / Form / Park cell click-throughs.
   Compact single-column card with: title, big tier-colored value, short
   description, key-value rows, and a footer note. */
.tv-pm-modal-info {
  max-width: 480px;
  width: calc(100vw - 32px);
}

/* ── Mobile (≤1000px): enlarge the MLB prop-card stat popups ───────────────
   The Score / Hits Rate / HH% L30 / Matchup tiles on the MLB prop card each
   open a popup that shares this .tv-pm-modal shell (Rate/Form also carry
   .tv-pm-modal-info). Those tile handlers only fire at innerWidth ≤ 1000, so
   scaling the shell here is fully targeted to the mobile card experience and
   never touches the desktop table-cell popups (which open above 1000px).

   We use `zoom` rather than overriding ~60 individual font-sizes so the
   popups' tuned geometry — the radial's %-positioned nodes, the SVG form
   sparkline, the matchup grade bars, and the arsenal table — scales in
   lockstep with the text and stays visually balanced. Width/height are
   divided by the same factor so the scaled modal still fits the viewport;
   the side margin and inner padding are trimmed so content reclaims a little
   more room on narrow phones. To make it bigger/smaller, change 1.35 in all
   four spots together. */
@media (max-width: 1000px) {
  .tv-pm-modal {
    zoom: 1.35;
    /* 24px subtracted → ~12px side margins: a bit less than full width,
       between the near-edge 16px-total we had after the zoom change and the
       32px-total before it. Font sizing (the 1.35 zoom) is unchanged. */
    width: calc((100vw - 24px) / 1.35);
    max-height: calc((100vh - 16px) / 1.35);
    padding: 18px 16px 16px;
  }
  /* .tv-pm-modal-info re-declares width at equal specificity above, so
     re-assert the compensated width here or it would win and overflow. */
  .tv-pm-modal-info {
    width: calc((100vw - 24px) / 1.35);
  }
}

.tv-info-card {
  display: flex;
  flex-direction: column;
  gap: 16px;
  color: var(--text, #e5e7eb);
  font-size: 13px;
  line-height: 1.45;
}
.tv-info-head { display: flex; flex-direction: column; gap: 2px; }
/* Variant when the card carries an avatar (currently used by the Park
   popup for the team logo). Side-by-side layout with the title text. */
.tv-info-head.tv-info-head-with-avatar {
  flex-direction: row;
  align-items: center;
  gap: 12px;
}
.tv-info-head-with-avatar .tv-info-head-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;          /* lets the title truncate inside the flex row */
}
.tv-info-team-logo {
  width: 44px;
  height: 44px;
  object-fit: contain;
  flex: 0 0 auto;
}
.tv-info-title {
  font-size: 15px;
  font-weight: 700;
  letter-spacing: .2px;
}
/* Matched size + weight to the title — different visual role is carried
   by uppercase casing + the tier color, not by being smaller/thinner. */
.tv-info-sub {
  font-size: 15px;
  font-weight: 700;
  color: var(--text3, #8c8f96);
  text-transform: uppercase;
  letter-spacing: .6px;
}
/* Inline override that keeps a fragment lowercase inside an uppercased
   subtitle. Used for the trailing "s" in "LHBs / RHBs" so the acronym
   reads correctly (LHBs, not LHBS). */
.tv-info-sub .tv-info-keep-lc {
  text-transform: lowercase;
}
.tv-info-headline {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 12px 14px;
  border-radius: 8px;
  background: rgba(255,255,255,.03);
  border: 1px solid rgba(255,255,255,.06);
  white-space: nowrap;     /* keep the headline on one line */
  overflow: hidden;
  text-overflow: ellipsis;
}
.tv-info-headline-val {
  font-size: 17px;
  font-weight: 800;
  letter-spacing: -.2px;
  font-variant-numeric: tabular-nums;
  color: var(--text, #e5e7eb);
}
/* Unit text matches the val's size + weight so the headline reads as one
   cohesive phrase ("-16% Home Runs vs League Avg to LHBs"). Only the ±X%
   picks up the tier color via the data-tier rules below; the rest stays
   in the default text color. */
.tv-info-headline-unit {
  font-size: 17px;
  font-weight: 800;
  letter-spacing: -.1px;
  color: var(--text, #e5e7eb);
}
/* Tint the headline value by tier so the popup matches the cell color.
   The same tier color applies to the subtitle (e.g. "HR PARK FACTOR FOR
   LHBS" in the Park popup) so the description echoes the value visually
   — green park reads green-tag, bad park reads red-tag. */
.tv-info-card[data-tier="elite"]   .tv-info-headline-val,
.tv-info-card[data-tier="elite"]   .tv-info-sub { color: #00F5D4; }
.tv-info-card[data-tier="great"]   .tv-info-headline-val,
.tv-info-card[data-tier="great"]   .tv-info-sub { color: #4ade80; }
.tv-info-card[data-tier="good"]    .tv-info-headline-val,
.tv-info-card[data-tier="good"]    .tv-info-sub { color: #a3e635; }
.tv-info-card[data-tier="neutral"] .tv-info-headline-val,
.tv-info-card[data-tier="neutral"] .tv-info-sub { color: #facc15; }
.tv-info-card[data-tier="poor"]    .tv-info-headline-val,
.tv-info-card[data-tier="poor"]    .tv-info-sub { color: #ea580c; }
.tv-info-card[data-tier="bad"]     .tv-info-headline-val,
.tv-info-card[data-tier="bad"]     .tv-info-sub { color: #ef4444; }
.tv-info-card[data-tier="na"]      .tv-info-headline-val,
.tv-info-card[data-tier="na"]      .tv-info-sub { color: #94a3b8; }

.tv-info-desc {
  color: var(--text2, #cbd5e1);
  font-size: 12.5px;
}
.tv-info-rows {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 12px 14px;
  background: rgba(255,255,255,.02);
  border: 1px solid rgba(255,255,255,.05);
  border-radius: 8px;
}
.tv-info-rows-title {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .4px;
  text-transform: uppercase;
  color: var(--text3, #8c8f96);
}
/* Sits directly under .tv-info-rows-title — one short sentence explaining
   why the batters in this list matter for the prop. Smaller + dimmer
   than the title, with extra bottom margin so the per-batter rows feel
   visually grouped underneath it. */
.tv-info-rows-subtitle {
  font-size: 11.5px;
  line-height: 1.45;
  color: var(--text2, #c0c4cc);
  margin-bottom: 4px;
}
.tv-info-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  font-size: 12px;
}
.tv-info-row-label {
  color: var(--text3, #8c8f96);
  white-space: nowrap;
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}
.tv-info-row-val {
  color: var(--text, #e5e7eb);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  text-align: right;
  display: inline-flex;
  align-items: baseline;
  gap: 4px;
}
.tv-info-row-val-num {
  font-size: 14px;
  font-weight: 700;
}
.tv-info-row-val-unit {
  font-size: 10px;
  font-weight: 500;
  letter-spacing: .3px;
  color: var(--text3, #8c8f96);
}
/* Per-tier color for the wOBA numeric — strength signal at a glance. */
.tv-info-row-tier-elite   .tv-info-row-val-num { color: #00F5D4; }
.tv-info-row-tier-great   .tv-info-row-val-num { color: #4ade80; }
.tv-info-row-tier-good    .tv-info-row-val-num { color: #a3e635; }
.tv-info-row-tier-neutral .tv-info-row-val-num { color: #facc15; }
.tv-info-row-tier-poor    .tv-info-row-val-num { color: #ea580c; }
.tv-info-row-tier-bad     .tv-info-row-val-num { color: #ef4444; }
.tv-info-row-tier-na      .tv-info-row-val-num { color: var(--text3, #8c8f96); }
/* Player avatar for batter-breakdown rows. Up-sized from 22px so the
   batter face reads at-a-glance; pairs with the stacked first/last
   name to give each row a header-style anchor instead of one tight line. */
.tv-info-row-avatar {
  flex: 0 0 auto;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  overflow: hidden;
  background: rgba(255,255,255,.05);
  border: 1px solid rgba(255,255,255,.08);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  color: var(--text2, #c0c4cc);
}
.tv-info-row-avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* Stack first name above last name so a 3-deep list reads like a roster
   block instead of a single-line list. First line gets dimmer styling
   so the surname (the more identifying token) is the primary read. */
.tv-info-row-batter {
  display: flex;
  flex-direction: column;
  line-height: 1.15;
  min-width: 0;
  overflow: hidden;
}
.tv-info-row-batter-first {
  font-size: 11px;
  color: var(--text2, #c0c4cc);
  font-weight: 500;
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
}
.tv-info-row-batter-last {
  font-size: 13px;
  color: var(--text, #e5e7eb);
  font-weight: 600;
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
}
.tv-info-footer {
  font-size: 11px;
  color: var(--text3, #8c8f96);
  line-height: 1.5;
  padding-top: 8px;
  border-top: 1px solid rgba(255,255,255,.06);
}

/* ── Lean info card (bar-chart Rate / Form popups) ──────────────────────
   Drops the verbose description / footer in favor of a horizontal bar
   chart that compares the player's value against league baseline. The
   delta chip below converts the comparison to a single tier-colored
   percentage so the takeaway is readable in one glance. */
.tv-info-card-lean {
  display: flex;
  flex-direction: column;
  gap: 18px;
  color: var(--text, #e5e7eb);
  font-size: 13px;
}
.tv-info-card-lean .tv-info-head {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.tv-info-cmp {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 14px 14px 12px;
  background: rgba(255,255,255,.03);
  border: 1px solid rgba(255,255,255,.06);
  border-radius: 10px;
}
.tv-info-cmp-row {
  display: grid;
  grid-template-columns: 92px 1fr 60px;   /* widened so "League avg" doesn't truncate */
  align-items: center;
  gap: 12px;
}
.tv-info-cmp-label {
  font-size: 11px;
  font-weight: 600;
  color: var(--text3, #8c8f96);
  text-transform: uppercase;
  letter-spacing: .5px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tv-info-cmp-track {
  height: 12px;
  background: rgba(255,255,255,.05);
  border-radius: 6px;
  overflow: hidden;
}
.tv-info-cmp-fill {
  height: 100%;
  border-radius: 6px;
  transition: width .2s ease-out;   /* tiny anim so the bar feels populated, not static */
}
.tv-info-cmp-fill-baseline { background: rgba(148, 163, 184, .55); }
.tv-info-cmp-fill-player   { background: var(--text2, #cbd5e1); }
/* Tier-color the player bar so it visually carries the same green/red
   meaning the cell already has. */
.tv-info-cmp-row[data-tier="elite"]   .tv-info-cmp-fill-player { background: #00F5D4; }
.tv-info-cmp-row[data-tier="great"]   .tv-info-cmp-fill-player { background: #4ade80; }
.tv-info-cmp-row[data-tier="good"]    .tv-info-cmp-fill-player { background: #a3e635; }
.tv-info-cmp-row[data-tier="neutral"] .tv-info-cmp-fill-player { background: #facc15; }
.tv-info-cmp-row[data-tier="poor"]    .tv-info-cmp-fill-player { background: #ea580c; }
.tv-info-cmp-row[data-tier="bad"]     .tv-info-cmp-fill-player { background: #ef4444; }
.tv-info-cmp-row[data-tier="na"]      .tv-info-cmp-fill-player { background: #94a3b8; }
.tv-info-cmp-val {
  font-size: 13px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}

.tv-info-cmp-delta {
  text-align: center;
  font-size: 14px;
  font-weight: 700;
  letter-spacing: .3px;
  padding: 6px 0 2px;
}
/* Variant when the delta sits INSIDE the comparison box, above the bars.
   Equal space above the line (under the text) and below it (before the
   first bar) so the divider reads as a true separator centered in the
   gap, not as a footer underline glued to the text. */
.tv-info-cmp-delta-top {
  padding: 0 0 8px;
  margin-bottom: 8px;
  border-bottom: 1px solid rgba(255, 255, 255, .05);
}
/* Variant when the delta sits INSIDE the comparison box, BELOW the bars.
   Mirrored spacing of -top so the divider reads as a centered separator
   between the bars and the delta text — not glued to either. */
.tv-info-cmp-delta-bottom {
  padding: 8px 0 0;
  margin-top: 8px;
  border-top: 1px solid rgba(255, 255, 255, .05);
}
.tv-info-cmp-delta[data-tier="elite"]   { color: #00F5D4; }
.tv-info-cmp-delta[data-tier="great"]   { color: #4ade80; }
.tv-info-cmp-delta[data-tier="good"]    { color: #a3e635; }
.tv-info-cmp-delta[data-tier="neutral"] { color: #facc15; }
.tv-info-cmp-delta[data-tier="poor"]    { color: #ea580c; }
.tv-info-cmp-delta[data-tier="bad"]     { color: #ef4444; }
.tv-info-cmp-delta[data-tier="na"]      { color: #94a3b8; }

/* Multiplier sub-line below the delta — connects the bar comparison to
   the score popup's "hitter multiplier" / "form multiplier" wording so
   users can map this number to the radial chart they already know. */
.tv-info-cmp-mult {
  text-align: center;
  font-size: 12px;
  color: var(--text3, #8c8f96);
  font-variant-numeric: tabular-nums;
  letter-spacing: .2px;
  margin-top: -2px;
}

/* Short description above the bars — one factual sentence about what
   the metric measures. Replaces the multi-sentence prose paragraph the
   verbose v1 popup had. */
.tv-info-desc-short {
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--text2, #cbd5e1);
}

.tv-info-sample {
  text-align: center;
  font-size: 12px;
  color: var(--text3, #8c8f96);
  font-variant-numeric: tabular-nums;
  letter-spacing: .2px;
}

/* Player header strip — avatar on the left + title row with a batting-
   hand badge on the right. Same vocabulary the matchup popup uses, just
   a hair smaller for the info popup's narrower modal. */
.tv-info-head-row {
  display: flex;
  align-items: center;
  gap: 12px;
}
.tv-info-avatar-wrap {
  flex: 0 0 auto;
}
.tv-info-avatar {
  display: inline-block;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  overflow: hidden;
  background: rgba(255,255,255,.05);
  border: 1px solid rgba(255,255,255,.08);
  position: relative;
}
.tv-info-avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.tv-info-head-text {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.tv-info-head-text .tv-info-title {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

/* Stacked-name header — first name on top, last name on the row below
   sharing the same bold styling. The last-name row carries the bat-side
   pill, metric phrase, and pitcher-hand pill all inline so the matchup
   reads as one strip rather than three stacked subtitles. */
.tv-info-name-stack {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  line-height: 1.2;
}
.tv-info-name-first,
.tv-info-name-last,
.tv-info-metric {
  font-size: 16px;
  font-weight: 700;
  color: var(--text, #e5e7eb);
  letter-spacing: .1px;
}
.tv-info-name-row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

/* Popup-scoped LHB/RHB/SH and LHP/RHP pills. Mirror the row-level
   .tv-bat-badge / .tv-pitch-badge palette but unscoped from .props-table
   (popup is appended to body). Slightly smaller padding/font than the
   row badges so they don't dominate the header. */
.tv-info-bat-badge,
.tv-info-pitch-badge {
  display: inline-block;
  padding: 1px 6px;
  border-radius: 3px;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .35px;
  background: rgba(255, 255, 255, 0.08);
  color: var(--text2, #c9ccd3);
  vertical-align: middle;
  line-height: 1.6;
}
.tv-info-bat-badge[data-hand="L"],
.tv-info-pitch-badge[data-hand="L"] {
  background: rgba(96, 165, 250, 0.16);
  color: #93c5fd;
}
.tv-info-bat-badge[data-hand="R"],
.tv-info-pitch-badge[data-hand="R"] {
  background: rgba(248, 113, 113, 0.16);
  color: #fca5a5;
}
.tv-info-bat-badge[data-hand="S"] {
  background: rgba(167, 139, 250, 0.16);
  color: #c4b5fd;
}

/* Sample-weighting block — shows how each PA bucket (current, prior,
   league prior) contributes to the shrunk rate. Smaller and less prominent
   than the league-comparison bars above; muted so it reads as supporting
   detail, not headline. */
.tv-info-weight {
  padding: 0;
  background: rgba(255,255,255,.02);
  border: 1px solid rgba(255,255,255,.05);
  border-radius: 8px;
  /* <details> needs to be a block — flex would break the open/close
     animation since the summary becomes a flex item. Keep block layout
     and let the body div handle internal flex. */
}
.tv-info-weight-summary {
  list-style: none;            /* hide default disclosure triangle */
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 14px;
  font-size: 10.5px;
  font-weight: 600;
  color: var(--text3, #8c8f96);
  text-transform: uppercase;
  letter-spacing: .55px;
  user-select: none;
  border-radius: 8px;          /* match the box so hover bg is contained */
  transition: background .15s ease, color .15s ease;
}
.tv-info-weight-summary::-webkit-details-marker { display: none; }
.tv-info-weight-summary:hover {
  color: var(--text2, #cbd5e1);
  background: rgba(255,255,255,.03);
}
.tv-info-weight-chevron {
  font-size: 14px;
  font-weight: 400;
  line-height: 1;
  display: inline-block;
  transition: transform .18s ease-out;
  /* Heavy-chevron glyph (❯) sits a hair off-baseline; nudge for visual centering. */
  transform-origin: center;
}
.tv-info-weight[open] .tv-info-weight-chevron {
  transform: rotate(90deg);
}
.tv-info-weight-body {
  display: flex;
  flex-direction: column;
  gap: 7px;
  padding: 4px 14px 12px;      /* top padding small since summary already padded */
}
.tv-info-weight-row {
  display: grid;
  grid-template-columns: 130px 1fr 38px;
  align-items: center;
  gap: 10px;
  font-size: 11.5px;
  color: var(--text2, #cbd5e1);
}
.tv-info-weight-row[data-kind="prior"] {
  color: var(--text3, #8c8f96);   /* league-prior row is muted vs sample rows */
}
.tv-info-weight-label {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-variant-numeric: tabular-nums;
}
.tv-info-weight-track {
  height: 6px;
  background: rgba(255,255,255,.04);
  border-radius: 3px;
  overflow: hidden;
}
.tv-info-weight-fill {
  height: 100%;
  background: rgba(148, 163, 184, .85);
  border-radius: 3px;
}
.tv-info-weight-row[data-kind="prior"] .tv-info-weight-fill {
  background: rgba(148, 163, 184, .45);
}

/* Form popup — non-blend tiers. Single short note (or two-line) about
   which sample the displayed value came from. T3 (blend) uses the
   expandable .tv-info-weight block above; T1/T2/T4 just need a small
   muted line, no chevron, no expand affordance. */
.tv-info-form-sample {
  padding: 10px 14px;
  background: rgba(255, 255, 255, .02);
  border: 1px solid rgba(255, 255, 255, .05);
  border-radius: 8px;
  font-size: 12px;
  color: var(--text2, #cbd5e1);
  line-height: 1.45;
  font-variant-numeric: tabular-nums;
}
.tv-info-form-sample-note {
  font-size: 11px;
  color: var(--text3, #8c8f96);
  margin-top: 4px;
}

/* Form-trend sparkline — pure SVG, no chart library. Container holds the
   small "TREND" label, the SVG itself, and a date-range axis line. */
.tv-info-trend {
  padding: 12px 14px 10px;
  background: rgba(255, 255, 255, .02);
  border: 1px solid rgba(255, 255, 255, .05);
  border-radius: 8px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.tv-info-trend-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.tv-info-trend-title {
  font-size: 10.5px;
  font-weight: 600;
  color: var(--text3, #8c8f96);
  text-transform: uppercase;
  letter-spacing: .55px;
}
/* Directional pill — only renders when _trendDirection returns a clear
   signal. Heating = green (warmer/brighter than the comparison delta
   greens so it visually flags as a callout); Cooling = blue (not red —
   cooling can be meaningful for under bets, no need to imply "bad"). */
.tv-info-trend-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .2px;
}
.tv-info-trend-pill[data-dir="heating"] {
  background: rgba(74, 222, 128, .15);
  color: #4ade80;
  border: 1px solid rgba(74, 222, 128, .3);
}
.tv-info-trend-pill[data-dir="cooling"] {
  background: rgba(96, 165, 250, .15);
  color: #93c5fd;
  border: 1px solid rgba(96, 165, 250, .3);
}
.tv-info-trend-svg {
  width: 100%;
  height: 120px;
  display: block;
}
.tv-info-trend-svg circle {
  cursor: default;       /* native browser tooltips fire on hover */
}
/* Y-axis tick labels — small, muted, right-aligned against the plot
   left edge. League-row gets a subtle italic + dimmer color so the eye
   parses it as the reference baseline rather than a data tick. */
.tv-info-trend-tick {
  font-size: 10px;
  fill: var(--text3, #8c8f96);
  font-variant-numeric: tabular-nums;
}
.tv-info-trend-tick[data-role="league"] {
  fill: rgba(148, 163, 184, .65);
  font-style: italic;
}
.tv-info-trend-tick[data-role="peak"] {
  fill: var(--text2, #cbd5e1);     /* slightly brighter so peak reads as the "top" reference */
}
/* Current value label hovers above the last dot — bold, tier-colored
   (fill set inline in the SVG so it picks up the line color). */
.tv-info-trend-current {
  font-size: 12px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.1px;
  paint-order: stroke;
  stroke: rgba(15, 18, 24, 0.75);   /* subtle dark halo so the label reads on any line color */
  stroke-width: 2.5px;
  stroke-linejoin: round;
}
.tv-info-trend-axis {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-size: 10px;
  color: var(--text3, #8c8f96);
  font-variant-numeric: tabular-nums;
}
.tv-info-trend-axis-mid {
  font-size: 9.5px;
  font-style: italic;
  letter-spacing: .2px;
}
/* States while async fetch resolves / when there's no usable data. */
.tv-info-trend-slot,
.tv-info-trend-empty,
.tv-info-trend-loading {
  padding: 16px 14px;
  background: rgba(255, 255, 255, .02);
  border: 1px solid rgba(255, 255, 255, .05);
  border-radius: 8px;
  text-align: center;
  font-size: 11.5px;
  color: var(--text3, #8c8f96);
  line-height: 1.4;
}
.tv-info-weight-val {
  font-size: 11px;
  font-weight: 700;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.tv-info-weight-note {
  font-size: 11px;
  color: var(--text3, #8c8f96);
  line-height: 1.5;
  padding-top: 8px;
  margin-top: 4px;
  border-top: 1px solid rgba(255, 255, 255, .04);
  letter-spacing: .15px;
}
.tv-info-weight-note em {
  font-style: italic;
  color: var(--text2, #cbd5e1);   /* slightly brighter than the surrounding muted text */
}

/* The .q2-pm-* classes inside the popup body inherit from the existing
   player-dashboard Q2 styles (loaded via mlb-player-dashboard.css). The
   modal scope keeps them isolated to this overlay context. */

/* ── HR-model breakdown popup — radial layout ────────────────────────── */
.tv-mp {
  font-size: 13px;
  color: var(--text, #e5e7eb);
  font-variant-numeric: tabular-nums;
}

/* Define tier colors once so every node / center / legend dot agrees.
   .tv-mp-sheet is listed too: the palette lives on the ROOT of each popup
   variant, and the sheet layout would otherwise resolve every var() to
   nothing and render the whole breakdown colourless. */
.tv-mp-radial,
.tv-mp-sheet {
  --tier-great-line:   #4ade80;
  --tier-great-fill:   rgba( 74, 222, 128, .12);
  --tier-good-line:    #a3e635;
  --tier-good-fill:    rgba(163, 230,  53, .10);
  --tier-neutral-line: rgba(255, 255, 255, .25);
  --tier-neutral-fill: rgba(255, 255, 255, .04);
  --tier-poor-line:    #ea580c;
  --tier-poor-fill:    rgba(234, 88, 12, 0.12);
  --tier-bad-line:     #ef4444;
  --tier-bad-fill:     rgba(239,  68,  68, .14);
}

/* Stage holds the SVG connectors + absolute-positioned circles.
   Aspect ratio square so node positioning percentages stay consistent
   regardless of modal width. */
.tv-mp-stage {
  position: relative;
  width: 100%;
  max-width: 480px;
  aspect-ratio: 1 / 1;
  margin: 8px auto 0;
}
.tv-mp-connectors {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

/* Center circle — player avatar with team-logo overlay, name, big prob,
   prop label, and a hand pill underneath. */
.tv-mp-center {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  /* Both axes pinned so the box stays square regardless of content height.
     `aspect-ratio` alone gets overridden when min-content (avatar + name +
     prop + prob) exceeds the calculated height, which warps the bottom of
     the circle into an ellipse. Explicit height + overflow: hidden enforces
     the circular shape; the parent stage is itself 1:1 so 38% on each axis
     resolves to the same pixel value. */
  width: 38%;
  height: 38%;
  aspect-ratio: 1 / 1;
  overflow: hidden;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 30%, #2a3142 0%, #1a1d24 70%);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center;
  padding: 4%;
  box-sizing: border-box;
  /* Default ring; overridden per-tier below. */
  box-shadow: 0 0 0 2px var(--tier-neutral-line);
}
.tv-mp-center[data-tier="great"]   { box-shadow: 0 0 0 2px var(--tier-great-line);   background: radial-gradient(circle at 50% 30%, rgba(74,222,128,.18), #1a1d24 70%); }
.tv-mp-center[data-tier="good"]    { box-shadow: 0 0 0 2px var(--tier-good-line);    background: radial-gradient(circle at 50% 30%, rgba(163,230,53,.16), #1a1d24 70%); }
.tv-mp-center[data-tier="neutral"] { box-shadow: 0 0 0 2px var(--tier-neutral-line); }
.tv-mp-center[data-tier="poor"]    { box-shadow: 0 0 0 2px var(--tier-poor-line);    background: radial-gradient(circle at 50% 30%, rgba(234, 88, 12, 0.16), #1a1d24 70%); }
.tv-mp-center[data-tier="bad"]     { box-shadow: 0 0 0 2px var(--tier-bad-line);     background: radial-gradient(circle at 50% 30%, rgba(239,68,68,.18), #1a1d24 70%); }

.tv-mp-avatar-wrap {
  position: relative;
  width: 80px;
  height: 80px;
  margin-bottom: 4px;
  flex-shrink: 0;
}
.tv-mp-avatar-wrap .tv-mp-avatar {
  width: 80px;
  height: 80px;
  border-radius: 50%;
  object-fit: cover;
  display: block;
}
.tv-mp-avatar-wrap .tv-mp-team-logo {
  position: absolute;
  right: -4px;
  bottom: -4px;
  width: 28px;
  height: 28px;
  object-fit: contain;
  border-radius: 50%;
  background: var(--bg2, #1a1d24);
  padding: 2px;
  box-shadow: 0 0 0 1.5px rgba(0,0,0,.6);
}
.tv-mp-name-row {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  max-width: 100%;
  margin-top: 2px;
}
.tv-mp-name {
  font-size: 14px; font-weight: 700;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  max-width: 110px;
}
.tv-mp-prob {
  font-size: 26px; font-weight: 800;
  margin: 4px 0 2px;
  letter-spacing: -0.5px;
}
.tv-mp-center[data-tier="great"]   .tv-mp-prob { color: var(--tier-great-line); }
.tv-mp-center[data-tier="good"]    .tv-mp-prob { color: var(--tier-good-line); }
.tv-mp-center[data-tier="neutral"] .tv-mp-prob { color: var(--text, #e5e7eb); }
.tv-mp-center[data-tier="poor"]    .tv-mp-prob { color: var(--tier-poor-line); }
.tv-mp-center[data-tier="bad"]     .tv-mp-prob { color: var(--tier-bad-line); }
.tv-mp-prop-line {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  font-size: 11px; font-weight: 600;
  color: var(--text3, #8c8f96);
  letter-spacing: .3px;
}
.tv-mp-hand-pill {
  display: inline-block;
  padding: 1px 5px;
  border-radius: 3px;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: .3px;
  background: rgba(255, 255, 255, 0.08);
  color: var(--text2, #c9ccd3);
}
.tv-mp-hand-pill[data-hand="L"] { background: rgba(96, 165, 250, .16); color: #93c5fd; }
.tv-mp-hand-pill[data-hand="R"] { background: rgba(248, 113, 113, .16); color: #fca5a5; }
.tv-mp-hand-pill[data-hand="S"] { background: rgba(167, 139, 250, .16); color: #c4b5fd; }

/* Orbiting nodes — six circles at hexagonal positions around the center.
   Rendered as <button> so they're click + keyboard-focusable. The sub-line
   is hidden by default and revealed below the circle on .is-expanded
   (click handler in tableView-core.js toggles, single-active model). */
.tv-mp-radial .tv-mp-node {
  position: absolute;
  width: 19%;
  aspect-ratio: 1 / 1;
  border-radius: 50%;
  background: var(--bg2, #1a1d24);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center;
  padding: 1.5%;
  box-sizing: border-box;
  transform: translate(-50%, -50%);
  /* Tier-driven ring color; default = neutral. */
  box-shadow: 0 0 0 2px var(--tier-neutral-line);
  background-color: var(--tier-neutral-fill);
  /* Reset button defaults so the circle shape isn't broken by UA styles. */
  border: 0;
  font-family: inherit;
  cursor: pointer;
  outline: none;
  transition: transform .15s ease, box-shadow .15s ease;
}
.tv-mp-radial .tv-mp-node:hover {
  transform: translate(-50%, -50%) scale(1.04);
}
.tv-mp-node:focus-visible {
  box-shadow: 0 0 0 2px var(--tier-neutral-line),
              0 0 0 4px rgba(0, 211, 189, 0.55);
}
.tv-mp-radial .tv-mp-node[data-tier="great"]   { box-shadow: 0 0 0 2px var(--tier-great-line);   background-color: var(--tier-great-fill); }
.tv-mp-radial .tv-mp-node[data-tier="good"]    { box-shadow: 0 0 0 2px var(--tier-good-line);    background-color: var(--tier-good-fill); }
.tv-mp-radial .tv-mp-node[data-tier="poor"]    { box-shadow: 0 0 0 2px var(--tier-poor-line);    background-color: var(--tier-poor-fill); }
.tv-mp-radial .tv-mp-node[data-tier="bad"]     { box-shadow: 0 0 0 2px var(--tier-bad-line);     background-color: var(--tier-bad-fill); }

.tv-mp-pos-0 { top: 8%;  left: 50%; }   /* top */
.tv-mp-pos-1 { top: 30%; left: 92%; }   /* upper-right */
.tv-mp-pos-2 { top: 70%; left: 92%; }   /* lower-right */
.tv-mp-pos-3 { top: 92%; left: 50%; }   /* bottom */
.tv-mp-pos-4 { top: 70%; left: 8%;  }   /* lower-left */
.tv-mp-pos-5 { top: 30%; left: 8%;  }   /* upper-left */

.tv-mp-node-label {
  font-size: 9px; font-weight: 700;
  letter-spacing: .4px; text-transform: uppercase;
  color: var(--text3, #8c8f96);
  margin-bottom: 1px;
}
.tv-mp-node-value {
  font-size: 16px; font-weight: 800;
  color: var(--text, #e5e7eb);
  line-height: 1.1;
}
.tv-mp-radial .tv-mp-node[data-tier="great"]   .tv-mp-node-value { color: var(--tier-great-line); }
.tv-mp-radial .tv-mp-node[data-tier="good"]    .tv-mp-node-value { color: var(--tier-good-line); }
.tv-mp-radial .tv-mp-node[data-tier="poor"]    .tv-mp-node-value { color: var(--tier-poor-line); }
.tv-mp-radial .tv-mp-node[data-tier="bad"]     .tv-mp-node-value { color: var(--tier-bad-line); }
/* Sub-line: hidden by default. Revealed as a small floating chip below
   the node when the user clicks (`.is-expanded`). Anchored absolutely so
   it doesn't disturb the circle layout. */
.tv-mp-node-sub {
  display: none;
  position: absolute;
  top: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%);
  padding: 6px 10px;
  border-radius: 6px;
  background: rgba(0, 0, 0, 0.85);
  border: 1px solid rgba(255, 255, 255, 0.10);
  font-size: 10px; line-height: 1.4;
  font-weight: 500;
  color: var(--text2, #c9ccd3);
  white-space: nowrap;
  pointer-events: none;
  z-index: 10;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
}
/* Tiny arrow pointing up at the node, aligning the chip visually. */
.tv-mp-node-sub::before {
  content: '';
  position: absolute;
  top: -5px; left: 50%;
  transform: translateX(-50%);
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-bottom: 5px solid rgba(0, 0, 0, 0.85);
}
.tv-mp-radial .tv-mp-node.is-expanded {
  /* Highlight the active node so users can find their click target. */
  z-index: 5;
  transform: translate(-50%, -50%) scale(1.08);
}
.tv-mp-radial .tv-mp-node.is-expanded .tv-mp-node-sub { display: block; }
/* Bottom-row nodes need their chip to render ABOVE the circle, not below,
   or the chip falls off the stage. */
.tv-mp-node.tv-mp-pos-3 .tv-mp-node-sub,
.tv-mp-node.tv-mp-pos-2 .tv-mp-node-sub,
.tv-mp-node.tv-mp-pos-4 .tv-mp-node-sub {
  top: auto;
  bottom: calc(100% + 6px);
}
.tv-mp-node.tv-mp-pos-3 .tv-mp-node-sub::before,
.tv-mp-node.tv-mp-pos-2 .tv-mp-node-sub::before,
.tv-mp-node.tv-mp-pos-4 .tv-mp-node-sub::before {
  top: auto;
  bottom: -5px;
  border-bottom: 0;
  border-top: 5px solid rgba(0, 0, 0, 0.85);
}
.tv-mp-node-meta { color: var(--text3, #8c8f96); opacity: .8; }

/* Legend — sits beneath the radial stage, centered, but only as wide as
   its content (avoiding the full-bleed pill that visually competed with
   the radial). `width: fit-content; margin: ... auto` is the trick that
   keeps inline-flex centered horizontally. The 28px top margin gives the
   bottom OPP SP node room to breathe between it and the legend. */
.tv-mp-legend {
  display: flex; flex-wrap: wrap; align-items: center;
  width: fit-content;
  margin: 28px auto 0;
  gap: 6px 14px;
  padding: 6px 14px;
  background: rgba(255, 255, 255, .04);
  border: 1px solid rgba(255, 255, 255, .06);
  border-radius: 999px;
  font-size: 11px;
  color: var(--text3, #8c8f96);
}
.tv-mp-leg-item { gap: 6px; }
.tv-mp-leg-item { display: inline-flex; align-items: center; gap: 5px; }
.tv-mp-leg-dot {
  display: inline-block;
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--tier-neutral-line);
}
.tv-mp-leg-dot[data-tier="great"]   { background: var(--tier-great-line); }
.tv-mp-leg-dot[data-tier="good"]    { background: var(--tier-good-line); }
.tv-mp-leg-dot[data-tier="neutral"] { background: var(--tier-neutral-line); }
.tv-mp-leg-dot[data-tier="poor"]    { background: var(--tier-poor-line); }
.tv-mp-leg-dot[data-tier="bad"]     { background: var(--tier-bad-line); }

.tv-mp-foot {
  margin-top: 12px;
  font-size: 11px; line-height: 1.5;
  color: var(--text3, #8c8f96);
  text-align: center;
  max-width: 580px;
  margin-left: auto; margin-right: auto;
}
.tv-mp-empty {
  padding: 40px 0; text-align: center;
  color: var(--text3, #8c8f96); font-style: italic;
}

/* Make MLB grade cells visibly clickable when factors exist. */
.props-table .cell-grade.is-mlb-prob.clickable {
  cursor: pointer;
}
.props-table .cell-grade.is-mlb-prob.clickable:hover {
  filter: brightness(1.15);
}

/* ── Click affordance on clickable metric cells ────────────────────────
   Corner-notch pattern: a small dog-eared triangle in the top-right
   corner signals that the cell hides more detail. Persistent so it's
   discoverable at a glance, small enough to recede behind the data;
   grows + brightens on hover. Replaces the dotted-underline approach,
   which was unreliable to render across tier-tinted backgrounds.
   Scoped to cells whose value lives in .metric-value / .grade-value /
   .park-value / .woba-value / .brl-value — the same set Score, Rate,
   L30 Brl%/HH%, Park, Weather columns use. Matchup cell uses its own
   pill styling so it's intentionally excluded. */
.props-table td.clickable:has(.metric-value),
.props-table td.clickable:has(.grade-value),
.props-table td.clickable:has(.park-value),
.props-table td.clickable:has(.woba-value),
.props-table td.clickable:has(.brl-value) {
  position: relative;
}
.props-table td.clickable:has(.metric-value)::before,
.props-table td.clickable:has(.grade-value)::before,
.props-table td.clickable:has(.park-value)::before,
.props-table td.clickable:has(.woba-value)::before,
.props-table td.clickable:has(.brl-value)::before {
  content: '';
  position: absolute;
  top: 4px;
  right: 4px;
  width: 0;
  height: 0;
  border-style: solid;
  border-width: 0 6px 6px 0;
  border-color: transparent rgba(255, 255, 255, 0.45) transparent transparent;
  transition: border-color .18s ease, border-width .18s ease;
  pointer-events: none;
}
.props-table td.clickable:has(.metric-value):hover::before,
.props-table td.clickable:has(.grade-value):hover::before,
.props-table td.clickable:has(.park-value):hover::before,
.props-table td.clickable:has(.woba-value):hover::before,
.props-table td.clickable:has(.brl-value):hover::before {
  border-color: transparent #22d3ee transparent transparent;
  border-width: 0 9px 9px 0;
}

/* Bat-side badge inline in the Player cell (L / R / S). */
.props-table .tv-bat-badge {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 5px;
  border-radius: 3px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .3px;
  background: rgba(255, 255, 255, 0.08);
  color: var(--text2, #c9ccd3);
  vertical-align: middle;
}
.props-table .tv-bat-badge[data-hand="L"] {
  background: rgba(96, 165, 250, 0.16);
  color: #93c5fd;
}
.props-table .tv-bat-badge[data-hand="R"] {
  background: rgba(248, 113, 113, 0.16);
  color: #fca5a5;
}
.props-table .tv-bat-badge[data-hand="S"] {
  background: rgba(167, 139, 250, 0.16);
  color: #c4b5fd;
}

/* -----------------------------------------------------------------------------
   Table Body
   ----------------------------------------------------------------------------- */
.props-table tbody tr {
  transition: background 0.15s ease;
  border-bottom: 1px solid rgba(255, 255, 255, 0.04);
}

.props-table tbody tr:hover {
  background: rgba(0, 211, 189, 0.06);
}

.props-table tbody tr.in-parlay {
  background: rgba(0, 211, 189, 0.12);
}

.props-table tbody tr.in-parlay:hover {
  background: rgba(0, 211, 189, 0.16);
}

.props-table tbody tr.filtered-out,
.props-table tbody tr.table-filtered-out,
.props-table tbody tr.hidden-no-under,
.props-table tbody tr.hidden-parlay-side-mismatch,
.props-table tbody tr.hidden-by-platoon-filter {
  display: none;
}
/* MLB Platoon toggle (replaces the Position dropdown). Mirrors the
   sizing/colors of .table-filter-dropdown-btn so it reads as a peer
   alongside Matches / Prop Markets. No dropdown chevron since this is
   a single on/off filter — toggle state shown by .active. */
.table-filter-platoon {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 11px 14px;
  /* Neutral grey while inactive (it's a toggle, not a dropdown) — the
     teal accent is reserved for the .active state so the engaged-vs-
     idle distinction is visible at a glance. */
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 8px;
  color: rgba(255, 255, 255, 0.9);
  font-size: 13px;
  cursor: pointer;
  transition: all 0.2s ease;
  white-space: nowrap;
}
.table-filter-platoon:hover {
  background: rgba(255, 255, 255, 0.08);
  border-color: rgba(255, 255, 255, 0.16);
}
.table-filter-platoon.active {
  background: rgba(0, 211, 189, 0.2);
  border-color: rgba(0, 211, 189, 0.5);
}
.table-filter-platoon .filter-label {
  color: rgba(255, 255, 255, 0.6);
  font-weight: 500;
}
.table-filter-platoon.active .filter-label {
  color: #00F5D4;
  font-weight: 600;
}

.props-table td {
  padding: 12px 10px;
  color: rgba(255, 255, 255, 0.88);
  vertical-align: middle;
  text-align: center;
}

.props-table td.cell-player,
.props-table td.cell-prop {
  text-align: left;
}

/* -----------------------------------------------------------------------------
   Action Column (Add to Parlay Button)
   ----------------------------------------------------------------------------- */
.props-table .col-action {
  width: 90px;
  text-align: center;
  padding-left: 12px;
  padding-right: 4px;
}

.props-table .cell-action {
  text-align: center;
  padding-left: 12px;
  padding-right: 4px;
}

.props-table .table-parlay-btn {
  padding: 6px 12px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.3px;
  border: 1px solid rgba(0, 211, 189, 0.4);
  background: rgba(0, 211, 189, 0.1);
  color: #00F5D4;
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.15s ease;
  white-space: nowrap;
}

.props-table .table-parlay-btn:hover {
  background: rgba(0, 211, 189, 0.25);
  border-color: rgba(0, 211, 189, 0.6);
}

.props-table .table-parlay-btn.in-parlay {
  background: linear-gradient(135deg, #00F5D4 0%, #00D3BD 100%);
  color: #0a1628;
  border-color: #00D3BD;
  box-shadow: 0 2px 6px rgba(0, 211, 189, 0.25);
}

.props-table .table-parlay-btn.in-parlay:hover {
  background: linear-gradient(135deg, #00D3BD 0%, #00b8a5 100%);
}

/* -----------------------------------------------------------------------------
   Team Column
   ----------------------------------------------------------------------------- */
.props-table .cell-team {
  font-weight: 600;
  font-size: 13px;
}

.props-table .cell-team > * {
  display: inline-flex;
  align-items: center;
  vertical-align: middle;
}

.props-table .cell-team .table-team-logo {
  margin-right: 6px;
}

.props-table .table-team-logo {
  width: 22px;
  height: 22px;
  object-fit: contain;
  flex-shrink: 0;
}

.props-table .team-code {
  font-weight: 700;
  letter-spacing: 0.3px;
}

/* MLB table — Team column: show the LOGO only (drop the "ARI" abbreviation).
   Frees ~35px of horizontal width so the Player column stops wrapping long
   names on the wide HR view (extra Weather column squeezes it). Scoped to the
   MLB table via .is-mlb on the container; NBA/NFL keep logo + code. Reversible:
   delete this block. The "Team" header label is what floors the width, so we
   also trim this column's cell padding. */
.props-table-container.is-mlb .props-table .team-code {
  display: none;
}
.props-table-container.is-mlb .props-table .col-team {
  width: 60px;
}
.props-table-container.is-mlb .props-table th.col-team,
.props-table-container.is-mlb .props-table td.cell-team {
  padding-left: 8px;
  padding-right: 8px;
}
.props-table-container.is-mlb .props-table .cell-team .table-team-logo {
  margin-right: 0;
}

/* MLB table headers: render the authored Title Case labels instead of forcing
   ALL-CAPS. Capital letters are wider, and several columns have small fixed
   widths (Score 55 / Weather 70 / L30 Brl% 70 / Team 64) that the uppercase
   header overran, stretching the column past its content; title case lets them
   settle back toward their fixed size. Also stops "wOBA" rendering as "WOBA".
   Dropping the all-caps letter-spacing reclaims a little more. Scoped to the
   MLB table; NBA/NFL keep uppercase headers. */
.props-table-container.is-mlb .props-table th {
  text-transform: none;
  letter-spacing: normal;
  font-size: 13px; /* +1px vs base, matches the cell text. Title case reads softer
                      than all-caps, so bump for presence while keeping most of the
                      reclaimed width (headless: ~34px narrower/row than old caps). */
}

/* MLB action (leftmost) column: the parlay button always reads "Add" (title case,
   not ALL-CAPS); the in-parlay state is shown by the .in-parlay fill, not a text
   swap (see tableView-core.js:657/1227 — add/remove keys off the row's .in-parlay
   class, not the label). Because "In Parlay" never widens this column anymore, it
   can drop from the old 90px (sized for "IN PARLAY") to fit just "Add" (~47px). */
.props-table-container.is-mlb .props-table .table-parlay-btn {
  text-transform: none;
  letter-spacing: normal;
}
.props-table-container.is-mlb .props-table .col-action,
.props-table-container.is-mlb .props-table .cell-action {
  width: 72px; /* was 90px (sized for "IN PARLAY"); "Add" (~47px) only needs ~60,
                  but 72 gives the button comfortable breathing room in the cell. */
  /* Symmetric horizontal padding so the centered button sits dead-center. The
     base .col-action is 12px/4px (left/right); that asymmetry made the button
     look ~4px off to the right. */
  padding-left: 8px;
  padding-right: 8px;
}

.props-table .team-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 4px 8px;
  border-radius: 6px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.5px;
}

/* -----------------------------------------------------------------------------
   Position Column
   ----------------------------------------------------------------------------- */
.props-table .cell-pos {
  color: rgba(255, 255, 255, 0.6);
  font-size: 12px;
  font-weight: 500;
}

/* -----------------------------------------------------------------------------
   Player Column
   ----------------------------------------------------------------------------- */
.props-table .cell-player {
  font-weight: 600;
  color: rgba(255, 255, 255, 0.95);
}

.props-table .cell-player.clickable {
  cursor: pointer;
  transition: background 0.15s ease;
}

.props-table .cell-player.clickable:hover {
  background: rgba(0, 211, 189, 0.08);
}

.props-table .cell-player .tv-player-avatar {
  width: 28px;
  height: 28px;
  object-fit: cover;
  margin-right: 8px;
  vertical-align: middle;
}

.props-table .cell-player .tv-player-name {
  vertical-align: middle;
}

/* -----------------------------------------------------------------------------
   Prop Column
   ----------------------------------------------------------------------------- */
.props-table .cell-prop {
  font-weight: 500;
}

.props-table .prop-line {
  color: #00F5D4;
  font-weight: 700;
  margin-right: 6px;
}

.props-table .prop-stat {
  color: rgba(255, 255, 255, 0.7);
  font-size: 12px;
}

.props-table .prop-side-indicator {
  display: inline-block;
  width: 18px;
  height: 18px;
  line-height: 18px;
  text-align: center;
  font-size: 11px;
  font-weight: 700;
  border-radius: 4px;
  margin-right: 2px;
  vertical-align: top;
}

.props-table .prop-side-indicator.over {
  background: rgba(34, 197, 94, 0.2);
  color: #22c55e;
}

.props-table .prop-side-indicator.under {
  background: rgba(239, 68, 68, 0.2);
  color: #ef4444;
}

/* O/U Toggle with both pills visible */
.props-table .prop-side-toggle {
  display: inline-flex;
  gap: 2px;
  margin-right: 4px;
  vertical-align: middle;
}

.props-table .prop-side-pill {
  display: inline-block;
  width: 22px;
  height: 20px;
  line-height: 20px;
  text-align: center;
  font-size: 11px;
  font-weight: 700;
  border-radius: 3px;
  cursor: pointer;
  transition: all 0.15s ease;
}

/* Inactive (dimmed) pills */
.props-table .prop-side-pill.over {
  background: rgba(34, 197, 94, 0.05);
  color: rgba(34, 197, 94, 0.2);
}

.props-table .prop-side-pill.under {
  background: rgba(239, 68, 68, 0.05);
  color: rgba(239, 68, 68, 0.2);
}

/* Active pills - match the standalone indicator styling */
.props-table .prop-side-pill.over.active {
  background: rgba(34, 197, 94, 0.2);
  color: #22c55e;
}

.props-table .prop-side-pill.under.active {
  background: rgba(239, 68, 68, 0.2);
  color: #ef4444;
}

/* Hover states for inactive pills */
.props-table .prop-side-pill.over:not(.active):hover {
  background: rgba(34, 197, 94, 0.18);
  color: rgba(34, 197, 94, 0.6);
}

.props-table .prop-side-pill.under:not(.active):hover {
  background: rgba(239, 68, 68, 0.18);
  color: rgba(239, 68, 68, 0.6);
}


/* -----------------------------------------------------------------------------
   Odds Column
   ----------------------------------------------------------------------------- */
.props-table .cell-odds {
  font-weight: 600;
  font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;
  font-size: 12px;
}

.props-table .odds-value.positive {
  color: #4ade80;
}

.props-table .odds-value.negative {
  color: rgba(255, 255, 255, 0.8);
}

.props-table .odds-value.na {
  color: rgba(255, 255, 255, 0.4);
  font-style: italic;
}

/* -----------------------------------------------------------------------------
   Opponent Column (Combined: Defense Rank + Team)
   ----------------------------------------------------------------------------- */
.props-table .cell-opponent {
  text-align: center;
  padding: 8px 10px;
  background: rgba(0, 0, 0, 0.2);
  border-left: 1px solid rgba(255, 255, 255, 0.05);
  border-right: 1px solid rgba(255, 255, 255, 0.05);
}

.props-table .opponent-info {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}

.props-table .opponent-team {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.props-table .opponent-code {
  font-weight: 700;
  font-size: 13px;
  color: rgba(255, 255, 255, 0.95);
  letter-spacing: 0.3px;
}

.props-table .def-rank-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  font-size: 12px;
  font-weight: 700;
  background: transparent;
  min-width: 28px;
  line-height: 22px; /* Match logo height */
}

/* Tier backgrounds for entire opponent cell */
.props-table .cell-opponent[data-tier="elite"] {
  background: rgba(0, 245, 212, 0.18);
}
.props-table .cell-opponent[data-tier="elite"] .def-rank-badge {
  color: #00F5D4;
}

.props-table .cell-opponent[data-tier="great"] {
  background: rgba(74, 222, 128, 0.18);
}
.props-table .cell-opponent[data-tier="great"] .def-rank-badge {
  color: #4ade80;
}

.props-table .cell-opponent[data-tier="good"] {
  background: rgba(163, 230, 53, 0.18);
}
.props-table .cell-opponent[data-tier="good"] .def-rank-badge {
  color: #a3e635;
}

.props-table .cell-opponent[data-tier="neutral"] {
  background: rgba(250, 204, 21, 0.18);
}
.props-table .cell-opponent[data-tier="neutral"] .def-rank-badge {
  color: #facc15;
}

.props-table .cell-opponent[data-tier="poor"] {
  background: rgba(234, 88, 12, 0.18);
}
.props-table .cell-opponent[data-tier="poor"] .def-rank-badge {
  color: #ea580c;
}

.props-table .cell-opponent[data-tier="bad"] {
  background: rgba(239, 68, 68, 0.18);
}
.props-table .cell-opponent[data-tier="bad"] .def-rank-badge {
  color: #ef4444;
}

.props-table .cell-opponent[data-tier=""] .def-rank-badge,
.props-table .cell-opponent:not([data-tier]) .def-rank-badge {
  color: rgba(255, 255, 255, 0.3);
}

/* -----------------------------------------------------------------------------
   Hit Rate Columns (Vs Opp, L5, L10)
   ----------------------------------------------------------------------------- */
.props-table .cell-vs-opp,
.props-table .cell-l5,
.props-table .cell-l10,
.props-table .cell-season {
  text-align: center;
  font-weight: 600;
  font-size: 13px;
}

.props-table .hit-rate {
  display: inline-block;
}

/* Hit rate colors based on percentage */
.props-table .hit-rate[data-rate="excellent"] {
  color: #00F5D4;
}

.props-table .hit-rate[data-rate="good"] {
  color: #4ade80;
}

.props-table .hit-rate[data-rate="average"] {
  color: #facc15;
}

.props-table .hit-rate[data-rate="poor"] {
  color: #ea580c;
}

.props-table .hit-rate[data-rate="bad"] {
  color: #ef4444;
}

.props-table .hit-rate.na {
  color: rgba(255, 255, 255, 0.3);
}

/* -----------------------------------------------------------------------------
   Grade Cell Styling
   ----------------------------------------------------------------------------- */
.props-table .cell-grade {
  text-align: center;
  font-weight: 600;
  min-width: 50px;
}

/* Inner value reads as plain text — the colored chip-style badge has
   moved up to the cell itself so the Score column matches the full-cell
   tint style used by HR Rate / L30 BRL% / Park / Weather. */
.props-table .cell-grade .grade-value {
  display: inline-block;
  font-size: 13px;
}

/* Tier fill: cell carries the soft tint, the inner value picks up the
   matching saturated foreground. Same 0.18 opacity as the matchup-
   metric cells so the row reads as one continuous strip of tints. */
.props-table .cell-grade[data-tier="excellent"] {
  background: rgba(0, 245, 212, 0.18);
}
.props-table .cell-grade[data-tier="excellent"] .grade-value { color: #00F5D4; }

.props-table .cell-grade[data-tier="good"] {
  background: rgba(74, 222, 128, 0.18);
}
.props-table .cell-grade[data-tier="good"] .grade-value { color: #4ade80; }

.props-table .cell-grade[data-tier="average"] {
  background: rgba(250, 204, 21, 0.10);
}
.props-table .cell-grade[data-tier="average"] .grade-value { color: #facc15; }

.props-table .cell-grade[data-tier="poor"] {
  background: rgba(234, 88, 12, 0.18);
}
.props-table .cell-grade[data-tier="poor"] .grade-value { color: #ea580c; }

.props-table .cell-grade[data-tier="bad"] {
  background: rgba(239, 68, 68, 0.18);
}
.props-table .cell-grade[data-tier="bad"] .grade-value { color: #ef4444; }

.props-table .cell-grade.no-data {
  background: transparent;
}
.props-table .cell-grade.no-data .grade-value {
  color: rgba(255, 255, 255, 0.3);
}

/* Live game: the book suspended/moved the line, so the pregame model score no
   longer applies — show a pulsing LIVE badge instead (mirrors the mobile card's
   LIVE chip). pb-live-pulse keyframe is defined in prop-cards.css (global). */
.props-table .cell-grade.is-live {
  cursor: default;
}
.props-table .cell-grade.is-live .grade-value {
  color: #ff4d5e;
  font-weight: 700;
  font-size: 0.72rem;
  letter-spacing: 0.5px;
  animation: pb-live-pulse 1.6s ease-in-out infinite;
}

/* -----------------------------------------------------------------------------
   Opponent Cell Expandable Detail (Defensive Rank Info)
   ----------------------------------------------------------------------------- */
.props-table .cell-opponent.clickable {
  cursor: pointer;
  position: relative;
}

.props-table .cell-opponent.clickable:hover:not(.expanded) {
  background: rgba(0, 211, 189, 0.08);
}

.props-table .cell-opponent.clickable.no-data {
  cursor: default;
}

.props-table .cell-opponent.expanded {
  padding: 6px 8px;
}

.props-table .cell-opponent.expanded .opponent-info {
  display: none;
}

/* Expanded detail container */
.props-table .opponent-detail {
  display: none;
}

.props-table .cell-opponent.expanded .opponent-detail {
  display: block;
}

.props-table .opponent-detail-inner {
  display: flex;
  flex-direction: column;
  gap: 4px;
  text-align: left;
}

.props-table .def-stat-line {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.props-table .def-team-name {
  font-size: 12px;
  font-weight: 600;
  color: #00F5D4;
  white-space: nowrap;
}

.props-table .def-rank-pill {
  font-size: 11px;
  font-weight: 700;
  padding: 2px 6px;
  border-radius: 4px;
  background: rgba(0, 0, 0, 0.3);
}

.props-table .def-rank-pill.tier-elite {
  color: #00F5D4;
  background: rgba(0, 245, 212, 0.2);
}
.props-table .def-rank-pill.tier-great {
  color: #4ade80;
  background: rgba(74, 222, 128, 0.2);
}
.props-table .def-rank-pill.tier-good {
  color: #a3e635;
  background: rgba(163, 230, 53, 0.2);
}
.props-table .def-rank-pill.tier-neutral {
  color: #facc15;
  background: rgba(250, 204, 21, 0.20);
}
.props-table .def-rank-pill.tier-poor {
  color: #ea580c;
  background: rgba(234, 88, 12, 0.20);
}
.props-table .def-rank-pill.tier-bad {
  color: #ef4444;
  background: rgba(239, 68, 68, 0.2);
}

.props-table .def-desc {
  font-size: 11px;
  color: rgba(255, 255, 255, 0.6);
  line-height: 1.3;
}

/* -----------------------------------------------------------------------------
   Hit Rate Bar Charts (L5, L10, Vs Opp - Expandable)
   ----------------------------------------------------------------------------- */
.props-table .cell-l5.clickable,
.props-table .cell-l10.clickable,
.props-table .cell-vs-opp.clickable,
.props-table .cell-season.clickable {
  cursor: pointer;
  transition: all 0.2s ease;
}

.props-table .cell-l5.clickable:hover,
.props-table .cell-l10.clickable:hover,
.props-table .cell-vs-opp.clickable:hover,
.props-table .cell-season.clickable:hover {
  background: rgba(0, 211, 189, 0.08);
}

/* Disabled state for 0/0 or no data */
.props-table .cell-l5.no-data,
.props-table .cell-l10.no-data,
.props-table .cell-vs-opp.no-data,
.props-table .cell-season.no-data {
  cursor: default;
}

.props-table .cell-l5.no-data:hover,
.props-table .cell-l10.no-data:hover,
.props-table .cell-vs-opp.no-data:hover,
.props-table .cell-season.no-data:hover {
  background: transparent;
}

.props-table .cell-l5.expanded {
  width: 140px;
  min-width: 140px;
  background: rgba(0, 211, 189, 0.06);
}

.props-table .cell-l10.expanded {
  width: 200px;
  min-width: 200px;
  background: rgba(0, 211, 189, 0.06);
}

.props-table .cell-vs-opp.expanded {
  width: 140px;
  min-width: 140px;
  background: rgba(0, 211, 189, 0.06);
}

/* Season chart can span a full season of games -> widest expansion */
.props-table .cell-season.expanded {
  width: 220px;
  min-width: 220px;
  background: rgba(0, 211, 189, 0.06);
}

/* Shrink player and prop columns when any chart is expanded */
.props-table:has(.cell-l5.expanded) .col-player,
.props-table:has(.cell-l10.expanded) .col-player,
.props-table:has(.cell-vs-opp.expanded) .col-player,
.props-table:has(.cell-season.expanded) .col-player {
  min-width: 100px;
}

.props-table:has(.cell-l5.expanded) .col-prop,
.props-table:has(.cell-l10.expanded) .col-prop,
.props-table:has(.cell-vs-opp.expanded) .col-prop,
.props-table:has(.cell-season.expanded) .col-prop {
  min-width: 90px;
}

.props-table .hitrate-chart {
  width: 100%;
  height: 50px;
}

.props-table .l5-chart-inner {
  position: relative;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: flex-end;
}

.props-table .l5-bars {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: 4px;
  width: 100%;
  height: 100%;
  padding: 0 4px;
}

.props-table .l5-bar {
  flex: 1;
  max-width: 20px;
  min-width: 12px;
  border-radius: 3px 3px 0 0;
  position: relative;
}

.props-table .l5-bar.hit {
  background: linear-gradient(180deg, #4ade80 0%, #22c55e 100%);
}

.props-table .l5-bar.miss {
  background: linear-gradient(180deg, #f87171 0%, #ef4444 100%);
}

/* MLB postseason (founder 2026-09-28: playoff games in a card's last 10 are
   ALWAYS labeled). The L10 cell's "incl. N playoff" line (full sentence in
   its title) and, in the expanded chart, a violet ring on each playoff game
   (the dashboards' postseason colour). Emitted only for an MLB row whose
   last 10 holds playoff games (tableView-core mlbPostNote / generateBarChart). */
.props-table .cell-l10 .tv-ps-note {
  display: block;
  margin-top: 1px;
  font-size: 9px;
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: .01em;
  color: #a78bfa;
  white-space: nowrap;
}
.props-table .cell-l10.expanded .tv-ps-note {
  margin: 0 0 3px;
}
.props-table .l5-bar.is-post {
  box-shadow: inset 0 0 0 2px #a78bfa;
}
/* A 0 has no bar to ring (height 0%), so the number over the bar turns
   violet and a violet tick sits under the slot -- every playoff game stays
   visibly marked whatever it scored. */
.props-table .l5-bar.is-post .l5-bar-value {
  color: #c4b5fd;
}
.props-table .l5-bar.is-post::after {
  content: '';
  position: absolute;
  left: 1px;
  right: 1px;
  bottom: -4px;
  height: 2px;
  border-radius: 1px;
  background: #a78bfa;
}

.props-table .l5-bar-value {
  position: absolute;
  top: -14px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 9px;
  font-weight: 700;
  color: rgba(255, 255, 255, 0.85);
  white-space: nowrap;
}

/* -----------------------------------------------------------------------------
   Empty State
   ----------------------------------------------------------------------------- */
.props-table-empty {
  padding: 60px 20px;
  text-align: center;
  color: rgba(255, 255, 255, 0.5);
  font-size: 14px;
}

/* -----------------------------------------------------------------------------
   Mobile: Hide table view entirely
   ----------------------------------------------------------------------------- */
@media (max-width: 1000px) {
  .props-table-container {
    display: none !important;
  }
}

/* -----------------------------------------------------------------------------
   Compact Filter Bar Mode (progressive levels when space is tight)
   ----------------------------------------------------------------------------- */

/* Default: Show full text, hide short versions */
.global-ou-pill .ou-short {
  display: none;
}

.filter-label .label-short {
  display: none;
}

/* Level 1: Remove Matches label, Prop Markets → Props, Position → Pos */
.table-filter-bar.compact-1 .table-filter-dropdown-btn[data-dropdown="matches"] .filter-label {
  display: none;
}

.table-filter-bar.compact-1 .table-filter-dropdown-btn[data-dropdown="markets"] .filter-label .label-full,
.table-filter-bar.compact-1 .table-filter-dropdown-btn[data-dropdown="positions"] .filter-label .label-full {
  display: none;
}

.table-filter-bar.compact-1 .table-filter-dropdown-btn[data-dropdown="markets"] .filter-label .label-short,
.table-filter-bar.compact-1 .table-filter-dropdown-btn[data-dropdown="positions"] .filter-label .label-short {
  display: inline;
}

/* Level 2: Narrower search input (placeholder changed via JS), hide Reset icon */
.table-filter-bar.compact-2 .table-player-search {
  width: 130px;
}

.table-filter-bar.compact-2 .reset-icon {
  display: none;
}

/* Level 3: OVER UNDER → O U */
.table-filter-bar.compact-3 .global-ou-pill {
  padding: 8px 10px;
}

.table-filter-bar.compact-3 .global-ou-pill .ou-full {
  display: none;
}

.table-filter-bar.compact-3 .global-ou-pill .ou-short {
  display: inline;
}

/* Level 4: Horizontal scroll as last resort */
.table-filter-bar.compact-4 {
  overflow-x: auto;
  overflow-y: visible;
  -webkit-overflow-scrolling: touch;
}

.table-filter-bar.compact-4::-webkit-scrollbar {
  height: 4px;
}

.table-filter-bar.compact-4::-webkit-scrollbar-track {
  background: rgba(0, 0, 0, 0.1);
  border-radius: 2px;
}

.table-filter-bar.compact-4::-webkit-scrollbar-thumb {
  background: rgba(0, 211, 189, 0.3);
  border-radius: 2px;
}

.table-filter-bar.compact-4::-webkit-scrollbar-thumb:hover {
  background: rgba(0, 211, 189, 0.5);
}

/* ── Matchup multiplier cell + breakdown popup ──────────────────────── */
/* Width / centering / numeric font come from the shared dynamic-metric
   block above (`.cell-matchup-mult` is included alongside the per-prop
   trio cells). Only the click affordance is unique to this cell. */
.props-table .cell-matchup-mult.clickable { cursor: pointer; }
.props-table .cell-matchup-mult.clickable:hover .metric-value {
  text-decoration: underline;
  text-decoration-color: rgba(255, 255, 255, 0.35);
  text-underline-offset: 3px;
}

.tv-pm-modal--mg { max-width: 480px; }

.tv-mg-empty {
  padding: 32px 8px;
  text-align: center;
  color: var(--text3, #8c8f96);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}

/* ── Player-vs-player header ─────────────────────────────────────── */
/* Sits at the very top of the unified Matchup popup. Mirrors the
   pitcher-avatar treatment used in the table cell so the avatars +
   team-logo overlays read as the same UI vocabulary. Centered with
   tight gaps so the player blocks sit next to "vs" rather than at
   opposite ends of the modal. */
.tv-mg-vs {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 24px;
  padding: 4px 32px 14px 0;   /* right room for the absolute × close button */
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
.tv-mg-vs-side {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}
.tv-mg-vs-side--reverse {
  flex-direction: row-reverse;
  text-align: right;
}
.tv-mg-vs-side--reverse .tv-mg-vs-info { align-items: flex-end; }

/* Hand pills inside the popup — same data-hand colors as the
   table-cell badges, but redeclared here because those are
   .props-table-scoped and the popup mounts on body. */
.tv-mg-vs .tv-bat-badge,
.tv-mg-vs .tv-pitch-badge {
  display: inline-block;
  padding: 2px 7px;
  border-radius: 4px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.4px;
  background: rgba(255, 255, 255, 0.08);
  color: var(--text2, #c9ccd3);
  vertical-align: middle;
}
.tv-mg-vs .tv-bat-badge[data-hand="L"],
.tv-mg-vs .tv-pitch-badge[data-hand="L"] {
  background: rgba(96, 165, 250, 0.20);
  color: #93c5fd;
}
.tv-mg-vs .tv-bat-badge[data-hand="R"],
.tv-mg-vs .tv-pitch-badge[data-hand="R"] {
  background: rgba(248, 113, 113, 0.20);
  color: #fca5a5;
}
.tv-mg-vs .tv-bat-badge[data-hand="S"] {
  background: rgba(167, 139, 250, 0.20);
  color: #c4b5fd;
}

.tv-mg-vs-avatar-wrap {
  position: relative;
  width: 44px; height: 44px;
  flex: 0 0 44px;
}
.tv-mg-vs-avatar {
  width: 44px; height: 44px;
  border-radius: 50%;
  overflow: hidden;
  background: rgba(255, 255, 255, 0.04);
}
.tv-mg-vs-avatar img { width: 100%; height: 100%; object-fit: cover; }
.tv-mg-vs-logo {
  position: absolute;
  right: -4px; bottom: -2px;
  width: 18px; height: 18px;
  border-radius: 50%;
  background: var(--bg2, #1a1d24);
  padding: 1px;
  box-shadow: 0 0 0 1.5px var(--bg2, #1a1d24);
}

.tv-mg-vs-info {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  min-width: 0;
}
.tv-mg-vs-name {
  font-size: 15px;
  font-weight: 700;
  color: var(--text, #e5e7eb);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 200px;
}
.tv-mg-vs-sep {
  font-size: 12px;
  font-weight: 500;
  color: var(--text3, #8c8f96);
  text-transform: lowercase;
  letter-spacing: 0.5px;
  flex: 0 0 auto;
}

/* ── Matchup grade rating block (label · score · stacked bar) ─── */
.tv-mg-rating-block {
  margin-top: 14px;
  padding: 14px 12px;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.025);
  font-variant-numeric: tabular-nums;
}
.tv-mg-rating-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
}
.tv-mg-rating-label {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.8px;
  text-transform: uppercase;
  color: var(--text3, #8c8f96);
}
.tv-mg-rating-score {
  display: flex;
  align-items: baseline;
  gap: 6px;
}
.tv-mg-rating-num {
  font-size: 22px;
  font-weight: 700;
  line-height: 1;
}
.tv-mg-rating-num[data-tier="elite"]   { color: #00F5D4; }
.tv-mg-rating-num[data-tier="great"]   { color: #4ade80; }
.tv-mg-rating-num[data-tier="good"]    { color: #a3e635; }
.tv-mg-rating-num[data-tier="neutral"] { color: #facc15; }
.tv-mg-rating-num[data-tier="poor"]    { color: #ea580c; }
.tv-mg-rating-num[data-tier="bad"]     { color: #ef4444; }
.tv-mg-rating-num[data-tier="na"]      { color: var(--text3, #8c8f96); }
.tv-mg-rating-denom {
  font-size: 13px;
  font-weight: 500;
  color: var(--text3, #8c8f96);
}
.tv-mg-rating-tag {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.4px;
  margin-left: 4px;
  padding: 2px 8px;
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.06);
}
.tv-mg-rating-tag[data-tier="elite"]   { color: #00F5D4; background: rgba(  0, 245, 212, .12); }
.tv-mg-rating-tag[data-tier="great"]   { color: #4ade80; background: rgba( 74, 222, 128, .12); }
.tv-mg-rating-tag[data-tier="good"]    { color: #a3e635; background: rgba(163, 230,  53, .12); }
.tv-mg-rating-tag[data-tier="neutral"] { color: #facc15; background: rgba(250, 204, 21, 0.12); }
.tv-mg-rating-tag[data-tier="poor"]    { color: #ea580c; background: rgba(234, 88, 12, 0.12); }
.tv-mg-rating-tag[data-tier="bad"]     { color: #ef4444; background: rgba(239,  68,  68, .12); }

/* Stacked-segment bar — each segment width = component contribution
   (weight × subgrade / 100). Empty space = remaining 0–100 grade. */
.tv-mg-bar-track {
  margin-top: 12px;
  display: flex;
  width: 100%;
  height: 14px;
  border-radius: 7px;
  background: rgba(255, 255, 255, 0.06);
  overflow: hidden;
}
.tv-mg-bar-seg {
  height: 100%;
  transition: width 0.2s ease;
}
.tv-mg-bar-seg:first-child { border-top-left-radius: 7px; border-bottom-left-radius: 7px; }
.tv-mg-bar-seg + .tv-mg-bar-seg { box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.25); }

/* Legend — one chip per component, color-matched to the bar segment. */
.tv-mg-legend {
  margin-top: 12px;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 6px 16px;
}
.tv-mg-legend-item {
  display: flex;
  align-items: baseline;
  gap: 8px;
  font-size: 12px;
  min-width: 0;
}
.tv-mg-legend-dot {
  width: 10px; height: 10px;
  border-radius: 50%;
  flex: 0 0 10px;
  align-self: center;
}
.tv-mg-legend-label {
  font-weight: 600;
  color: var(--text, #e5e7eb);
  white-space: nowrap;
}
/* Raw value sits next to the label as a rectangular pill — binary
   direction signal: green if the pitcher's number favors the batter
   in this matchup, red if it favors the pitcher. Grey for neutral /
   no data. The key below the legend explains the green/red mapping. */
.tv-mg-legend-raw {
  font-weight: 700;
  white-space: nowrap;
  padding: 2px 8px;
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.05);
}
.tv-mg-legend-raw[data-direction="batter"] {
  color: #4ade80;
  background: rgba(74, 222, 128, 0.14);
}
.tv-mg-legend-raw[data-direction="pitcher"] {
  color: #ef4444;
  background: rgba(239, 68, 68, 0.14);
}
.tv-mg-legend-raw[data-direction="neutral"] { color: var(--text2, #c0c4cc); }
.tv-mg-legend-raw[data-direction="na"]      { color: var(--text3, #8c8f96); }
.tv-mg-legend-weight {
  font-size: 10px;
  font-weight: 500;
  color: var(--text3, #8c8f96);
  padding: 1px 6px;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.05);
  margin-left: auto;          /* push weight pill + sub-grade to the right */
}
.tv-mg-legend-grade {
  font-weight: 700;
  color: var(--text, #e5e7eb);
  min-width: 28px;
  text-align: right;
}

/* Key for the green/red raw-value coloring — centered below the
   legend with rectangular swatches that match the raw-value pills. */
.tv-mg-key {
  margin-top: 12px;
  display: flex;
  justify-content: center;
  gap: 20px;
  font-size: 11px;
  color: var(--text3, #8c8f96);
}
.tv-mg-key-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.tv-mg-key-swatch {
  width: 14px; height: 10px;
  border-radius: 3px;
}
.tv-mg-key-swatch[data-direction="batter"]  { background: #4ade80; }
.tv-mg-key-swatch[data-direction="pitcher"] { background: #ef4444; }

/* Arsenal section sits below the matchup-grade breakdown in the unified
   popup — async-fetched, so it shows a loader first and then the q2-pm
   pitch-by-pitch grid (same markup the standalone pitch-mix popup uses). */
.tv-mg-arsenal {
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}
.tv-mg-arsenal .tv-pm-loading {
  padding: 28px 0;
  text-align: center;
  color: var(--text3, #8c8f96);
  font-size: 13px;
}


/* ── Matches dropdown: LIVE chip for in-play games (MLB live props) ── */
.dropdown-option .game-datetime.matches-live-chip {
  color: #ff4d5e;
  font-weight: 700;
  letter-spacing: 0.5px;
  animation: pb-matches-live-pulse 1.6s ease-in-out infinite;
}
@keyframes pb-matches-live-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.5; }
}


/* Center the weather-popup loader vertically (bouncing spheres). */
.tv-wx-loading {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 140px;
}


/* ── Live-state row mirroring (MLB live props) ─────────────────────────
   The MLB live patcher mirrors each card's live-state class onto its
   table row (rows render once from the page-load snapshot and are never
   odds-patched, so state is the only truth they can show). Suspended =
   line pulled from the latest polls (may relist); withdrawn = FanDuel
   pulled the market entirely; ended = game over. The Add button stays
   clickable — workbenchCore's addToParlay guard owns refusal + the toast;
   this styling is the visual signal. NBA/NFL rows never get these
   classes (only the MLB patcher stamps them). */
.props-table tbody tr.live-suspended td:not(.cell-action),
.props-table tbody tr.live-ended td:not(.cell-action) {
  opacity: 0.55;
}
.props-table tbody tr.live-withdrawn td:not(.cell-action) {
  opacity: 0.4;
}
.props-table tbody tr.live-withdrawn .cell-odds,
.props-table tbody tr.live-withdrawn .odds-value {
  text-decoration: line-through;
}
.props-table tbody tr.live-suspended .cell-grade .grade-value::after {
  content: 'SUSP';
  display: inline-block;
  margin-left: 6px;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.5px;
  color: #e6a23c;
}
.props-table tbody tr.live-withdrawn .cell-grade .grade-value::after {
  content: 'OFF BOARD';
  display: inline-block;
  margin-left: 6px;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.5px;
  color: #ff4d5e;
}
.props-table tbody tr.live-ended .cell-grade .grade-value::after {
  content: 'FINAL';
  display: inline-block;
  margin-left: 6px;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.5px;
  color: #8c8f96;
}

/* ════════════════════════════════════════════════════════════════════
   HR / prop MODEL POPUP — sheet layout (replaces the radial wheel)
   Identity header · probability panel · sorted factor list · formula.
   The wheel gave six factors equal visual weight around a hub, so ranking
   them meant comparing circles; a sorted list with a bar each answers
   "what is driving this?" in one pass.
   Reuses the --tier-* custom properties the wheel already used, so a
   colour still means the same thing here as in the Score cell.
   ════════════════════════════════════════════════════════════════════ */
.tv-mp-sheet { display: flex; flex-direction: column; gap: 14px; }

/* ── identity ── */
.tv-mp-id { display: flex; align-items: center; gap: 14px; }
.tv-mp-id .tv-mp-avatar-wrap { position: relative; flex: none; }
.tv-mp-id .tv-mp-avatar { width: 74px; height: 74px; border-radius: 50%; overflow: hidden; }
.tv-mp-id .tv-mp-avatar img { width: 100%; height: 100%; object-fit: cover; }
.tv-mp-id .tv-mp-team-logo { position: absolute; right: -2px; bottom: -2px; width: 26px; height: 26px; object-fit: contain; }
.tv-mp-id-text { min-width: 0; }
.tv-mp-sheet .tv-mp-name { margin: 0; font-size: 1.7rem; font-weight: 800; letter-spacing: -0.02em; color: #f1f3f5; line-height: 1.1; }
.tv-mp-team { font-size: 0.86rem; font-weight: 600; color: #8b91a0; margin-top: 2px; }
.tv-mp-hand { display: flex; align-items: center; gap: 8px; margin-top: 6px; }
.tv-mp-hand-word { font-size: 0.8rem; color: #8b91a0; }

/* ── two-column body ── */
.tv-mp-grid { display: grid; grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr); gap: 14px; align-items: stretch; }
@media (max-width: 780px) { .tv-mp-grid { grid-template-columns: 1fr; } }

/* ── probability panel ──
   The baseball art is a background LAYER under a dark scrim, not a plain
   image: the scrim keeps the 3rem percentage legible whatever lands behind
   it, and the tier tint is what carries the meaning. */
.tv-mp-prob-panel {
  position: relative; overflow: hidden;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 6px; padding: 26px 18px; border-radius: 16px;
  border: 1px solid rgba(255, 255, 255, 0.07);
  /* Anchored bottom-right: the ball sits in that corner of the source art, and
     `center` cropped it out entirely on this panel's portrait-ish aspect. The
     scrim is light enough to let the seams read but still holds contrast under
     a 3.4rem number. */
  /* Scrim is a VIGNETTE, not a flat wash: nearly clear at the top-left where
     the art lives, densest behind the centred number. The source is extremely
     dark to begin with (mean luminance 14/255), so it is also exposure-boosted
     on disk — a lighter scrim alone left it invisible. */
  background:
    radial-gradient(120% 90% at 50% 52%, rgba(8, 10, 13, 0.82) 0%,
                                          rgba(8, 10, 13, 0.55) 42%,
                                          rgba(8, 10, 13, 0.22) 100%),
    url('/static/css/used-imgs/hr-model-bg.jpg') right bottom / cover no-repeat,
    #0e1014;
}
.tv-mp-prob-label { font-size: 0.7rem; font-weight: 800; letter-spacing: 0.14em; text-transform: uppercase; color: #8b91a0; }
.tv-mp-prob-big { font-size: 3.4rem; font-weight: 900; line-height: 1; letter-spacing: -0.03em; color: #e8eaed; }
.tv-mp-prob-panel[data-tier="great"]   .tv-mp-prob-big { color: var(--tier-great-line); }
.tv-mp-prob-panel[data-tier="good"]    .tv-mp-prob-big { color: var(--tier-good-line); }
.tv-mp-prob-panel[data-tier="neutral"] .tv-mp-prob-big { color: var(--tier-neutral-line); }
.tv-mp-prob-panel[data-tier="poor"]    .tv-mp-prob-big { color: var(--tier-poor-line); }
.tv-mp-prob-panel[data-tier="bad"]     .tv-mp-prob-big { color: var(--tier-bad-line); }
.tv-mp-prob-line { display: flex; align-items: center; gap: 10px; font-size: 1rem; font-weight: 700; color: #cbd5e1; }
.tv-mp-prob-line::before, .tv-mp-prob-line::after { content: ''; width: 22px; height: 1px; background: rgba(255,255,255,.18); }
/* The projection now states itself in full ("5.3 Receptions Projected"), so the
   separate muted key is gone and the single value centres in the pill. One
   span, one style -- the unit and the word "Projected" inherit the number's
   colour, weight and size rather than being a dimmer suffix. */
.tv-mp-pa {
  margin-top: 10px; display: flex; align-items: center; justify-content: center; gap: 14px;
  min-width: 230px; padding: 9px 14px; border-radius: 10px;
  border: 1px solid rgba(255, 255, 255, 0.09); background: rgba(255, 255, 255, 0.04);
}
.tv-mp-pa-v {
  font-size: 1.05rem; font-weight: 800; color: #e8eaed;
  font-variant-numeric: tabular-nums; text-align: center;
}

/* ── factor rows ── */
.tv-mp-factors { display: flex; flex-direction: column; gap: 7px; }
.tv-mp-factors-head { font-size: 0.7rem; font-weight: 800; letter-spacing: 0.12em; text-transform: uppercase; color: #8b91a0; margin-bottom: 1px; }
.tv-mp-row {
  display: grid; grid-template-columns: 34px minmax(78px, auto) minmax(0, 1fr) auto;
  align-items: center; gap: 11px; width: 100%; text-align: left;
  padding: 9px 13px; border-radius: 11px; cursor: pointer; font: inherit;
  border: 1px solid rgba(255, 255, 255, 0.07); background: rgba(255, 255, 255, 0.028);
  transition: border-color .15s ease, background .15s ease;
}
.tv-mp-row:hover { background: rgba(255, 255, 255, 0.055); border-color: rgba(255, 255, 255, 0.14); }
.tv-mp-row-ico {
  width: 34px; height: 34px; border-radius: 50%; display: flex; align-items: center; justify-content: center;
  border: 1px solid rgba(255, 255, 255, 0.12); color: #a8b0bf;
}
/* PNG alpha masks painted with currentColor, so each icon inherits whatever
   colour its context sets. -webkit- prefix included: Safari has not
   unprefixed mask-image. */
.pb-mask-ico {
  display: block; width: 18px; height: 18px; background-color: currentColor;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: center;  mask-position: center;
  -webkit-mask-size: contain;     mask-size: contain;
}
.pb-mask-ico[data-ico="hitter"]  { -webkit-mask-image: url('/static/css/used-imgs/model-icons/hitter.png');  mask-image: url('/static/css/used-imgs/model-icons/hitter.png'); }
.pb-mask-ico[data-ico="form"]    { -webkit-mask-image: url('/static/css/used-imgs/model-icons/form.png');    mask-image: url('/static/css/used-imgs/model-icons/form.png'); }
.pb-mask-ico[data-ico="matchup"] { -webkit-mask-image: url('/static/css/used-imgs/model-icons/matchup.png'); mask-image: url('/static/css/used-imgs/model-icons/matchup.png'); }
.pb-mask-ico[data-ico="park"]    { -webkit-mask-image: url('/static/css/used-imgs/model-icons/park.png');    mask-image: url('/static/css/used-imgs/model-icons/park.png'); }
.pb-mask-ico[data-ico="weather"] { -webkit-mask-image: url('/static/css/used-imgs/model-icons/weather.png'); mask-image: url('/static/css/used-imgs/model-icons/weather.png'); }
.pb-mask-ico[data-ico="exppa"]   { -webkit-mask-image: url('/static/css/used-imgs/model-icons/exppa.png');   mask-image: url('/static/css/used-imgs/model-icons/exppa.png'); }
.tv-mp-row-id { display: flex; flex-direction: column; min-width: 0; }
.tv-mp-row-name { font-size: 0.92rem; font-weight: 700; color: #e8eaed; }
.tv-mp-row-tier { font-size: 0.72rem; color: #8b91a0; }
.tv-mp-row-bar { height: 6px; border-radius: 999px; background: rgba(255, 255, 255, 0.07); overflow: hidden; }
.tv-mp-row-bar i { display: block; height: 100%; border-radius: 999px; background: #6b7280; }
.tv-mp-row-val { font-size: 1.18rem; font-weight: 800; color: #e8eaed; font-variant-numeric: tabular-nums; }
/* Tier colours: ring, bar and value move together so one glance reads. */
.tv-mp-row[data-tier="great"]   .tv-mp-row-ico { border-color: var(--tier-great-line);   color: var(--tier-great-line); }
.tv-mp-row[data-tier="good"]    .tv-mp-row-ico { border-color: var(--tier-good-line);    color: var(--tier-good-line); }
.tv-mp-row[data-tier="neutral"] .tv-mp-row-ico { border-color: var(--tier-neutral-line); color: var(--tier-neutral-line); }
.tv-mp-row[data-tier="poor"]    .tv-mp-row-ico { border-color: var(--tier-poor-line);    color: var(--tier-poor-line); }
.tv-mp-row[data-tier="bad"]     .tv-mp-row-ico { border-color: var(--tier-bad-line);     color: var(--tier-bad-line); }
.tv-mp-row[data-tier="great"]   .tv-mp-row-bar i { background: var(--tier-great-line); }
.tv-mp-row[data-tier="good"]    .tv-mp-row-bar i { background: var(--tier-good-line); }
.tv-mp-row[data-tier="neutral"] .tv-mp-row-bar i { background: var(--tier-neutral-line); }
.tv-mp-row[data-tier="poor"]    .tv-mp-row-bar i { background: var(--tier-poor-line); }
.tv-mp-row[data-tier="bad"]     .tv-mp-row-bar i { background: var(--tier-bad-line); }
.tv-mp-row[data-tier="great"]   .tv-mp-row-val { color: var(--tier-great-line); }
.tv-mp-row[data-tier="good"]    .tv-mp-row-val { color: var(--tier-good-line); }
.tv-mp-row[data-tier="neutral"] .tv-mp-row-val { color: var(--tier-neutral-line); }
.tv-mp-row[data-tier="poor"]    .tv-mp-row-val { color: var(--tier-poor-line); }
.tv-mp-row[data-tier="bad"]     .tv-mp-row-val { color: var(--tier-bad-line); }
/* The per-factor detail the wheel revealed on click — same interaction,
   kept because it is where the underlying rates and sample sizes live. */
.tv-mp-row-sub { grid-column: 2 / -1; display: none; font-size: 0.76rem; color: #8b91a0; line-height: 1.5; padding-top: 6px; }
.tv-mp-row.is-expanded .tv-mp-row-sub { display: block; }
.tv-mp-row .tv-mp-node-meta { color: #6b7280; }

/* ── formula chips ── */
.tv-mp-calc { border-top: 1px solid rgba(255, 255, 255, 0.07); padding-top: 12px; }
.tv-mp-calc-head { font-size: 0.7rem; font-weight: 800; letter-spacing: 0.12em; text-transform: uppercase; color: #8b91a0; margin-bottom: 9px; }
.tv-mp-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 7px; }
.tv-mp-chip {
  display: flex; flex-direction: column; gap: 1px; padding: 7px 13px; border-radius: 10px;
  border: 1px solid rgba(255, 255, 255, 0.08); background: rgba(255, 255, 255, 0.03);
}
.tv-mp-chip-k { font-size: 0.66rem; color: #8b91a0; white-space: nowrap; }
.tv-mp-chip-v { font-size: 0.9rem; font-weight: 800; color: #e8eaed; font-variant-numeric: tabular-nums; }
.tv-mp-chip-x { color: #4b5563; font-weight: 700; }
.tv-mp-chip[data-tier="great"]   .tv-mp-chip-v { color: var(--tier-great-line); }
.tv-mp-chip[data-tier="good"]    .tv-mp-chip-v { color: var(--tier-good-line); }
.tv-mp-chip[data-tier="neutral"] .tv-mp-chip-v { color: var(--tier-neutral-line); }
.tv-mp-chip[data-tier="poor"]    .tv-mp-chip-v { color: var(--tier-poor-line); }
.tv-mp-chip[data-tier="bad"]     .tv-mp-chip-v { color: var(--tier-bad-line); }

.tv-mp-sheet .tv-mp-foot { font-size: 0.76rem; color: #6b7280; line-height: 1.6; }
/* Untiered (the PA/BF count): no colour claim, just structure. */
.tv-mp-row[data-tier="na"] .tv-mp-row-ico { border-color: rgba(255,255,255,.14); color: #8b91a0; }
.tv-mp-row[data-tier="na"] .tv-mp-row-bar i { background: #4b5563; }
.tv-mp-row[data-tier="na"] .tv-mp-row-val { color: #cbd5e1; }
.tv-mp-chip[data-tier="na"] .tv-mp-chip-v { color: #cbd5e1; }
/* .tv-mp-node is reused on the sheet's rows ONLY as the click hook the
   existing expand handler binds to. Its wheel geometry (absolute, circular,
   19% wide, translate(-50%,-50%)) is scoped to .tv-mp-radial above; this
   reasserts flow layout in case another rule reaches it. */
.tv-mp-sheet .tv-mp-node {
  position: static; width: auto; aspect-ratio: auto; transform: none;
  border-radius: 11px; padding: 9px 13px; box-shadow: none;
}
/* The wheel clamped .tv-mp-name to fit inside the hub circle; the sheet has a
   full header row, so the name should not be truncated to "Christi…". */
.tv-mp-sheet .tv-mp-name {
  max-width: none; white-space: normal; overflow: visible; text-overflow: clip;
}
/* Empty tier word (the PA count) must not leave a gap under the label. */
.tv-mp-row-tier:empty { display: none; }

/* ==========================================================================
   NFL ANALYTICS COLUMNS (2026-08-27 rework): SEASON · AVG · USAGE
   Season reuses the shared .hit-rate pill; AVG's color IS the delta signal
   (same tier palette as hit rates — Utils.getAvgTier proximity bands);
   USAGE is the writer's self-describing label. .is-approx marks windows
   that crossed seasons or hold <3 games (the small-sample honesty rule).
   ========================================================================== */
.props-table .col-season {
  width: 65px;
  text-align: center;
}

.props-table .col-avg {
  width: 60px;
  text-align: center;
}

.props-table .col-usage {
  width: 92px;
  text-align: center;
}

.props-table .cell-season,
.props-table .cell-avg,
.props-table .cell-usage {
  text-align: center;
}

.props-table .tv-avg-value {
  display: inline-block;
  font-variant-numeric: tabular-nums;
  color: rgba(255, 255, 255, 0.75);
}

.props-table .tv-avg-value[data-rate="excellent"] { color: #00F5D4; }
.props-table .tv-avg-value[data-rate="good"]      { color: #4ade80; }
.props-table .tv-avg-value[data-rate="average"]   { color: #facc15; }
.props-table .tv-avg-value[data-rate="poor"]      { color: #ea580c; }
.props-table .tv-avg-value[data-rate="bad"]       { color: #ef4444; }

.props-table .tv-usage-value {
  display: inline-block;
  font-size: 12px;
  white-space: nowrap;
  color: rgba(255, 255, 255, 0.72);
}

/* Small/cross-season windows read as approximate, not authoritative.
   Dim the whole TD (not just the value span) so the full-cell tier tint
   below fades with it — a full-strength background under a dimmed number
   read as confident, defeating the honesty rule — review catch.
   0.75, not the old 0.55: pre-season EVERY row is cross-season, so the
   marker paints the entire SEASON/AVG columns at once and 0.55 read as
   "these two columns are broken" rather than "this row is approximate"
   (founder 2026-08-27). Once 3+ real-season games accumulate the dim
   disappears per-row naturally. */
.props-table .cell-season.is-approx,
.props-table .cell-avg.is-approx {
  opacity: 0.75;
}

/* --------------------------------------------------------------------------
   NFL full-cell tints (2026-08-27): L5 / SEASON / AVG / USAGE carry their
   tier on the TD (data-tier) and read as tinted blocks — same 0.18-opacity
   palette as .cell-grade / .cell-opponent so the row is one continuous
   strip. The saturated foreground still comes from the shared
   .hit-rate[data-rate] / .tv-avg-value[data-rate] rules; USAGE gets its
   foreground here, keyed off the TD, since its span has no data-rate.
   ONLY NFL rows ever stamp TD-level data-tier on .cell-l5 — the MLB/NBA
   templates and update paths never set it, so keying on the shared class
   is safe. --tv-tint lets the clickable-hover rule below keep the tier
   tint instead of erasing it (non-NFL cells fall back to the original
   hover teal via the var() default). */
.props-table .cell-l5[data-tier="excellent"],
.props-table .cell-season[data-tier="excellent"],
.props-table .cell-avg[data-tier="excellent"],
.props-table .cell-usage[data-tier="excellent"] {
  --tv-tint: rgba(0, 245, 212, 0.18);
  background: var(--tv-tint);
}
.props-table .cell-l5[data-tier="good"],
.props-table .cell-season[data-tier="good"],
.props-table .cell-avg[data-tier="good"],
.props-table .cell-usage[data-tier="good"] {
  --tv-tint: rgba(74, 222, 128, 0.18);
  background: var(--tv-tint);
}
.props-table .cell-l5[data-tier="average"],
.props-table .cell-season[data-tier="average"],
.props-table .cell-avg[data-tier="average"],
.props-table .cell-usage[data-tier="average"] {
  --tv-tint: rgba(250, 204, 21, 0.10);
  background: var(--tv-tint);
}
.props-table .cell-l5[data-tier="poor"],
.props-table .cell-season[data-tier="poor"],
.props-table .cell-avg[data-tier="poor"],
.props-table .cell-usage[data-tier="poor"] {
  --tv-tint: rgba(234, 88, 12, 0.18);
  background: var(--tv-tint);
}
.props-table .cell-l5[data-tier="bad"],
.props-table .cell-season[data-tier="bad"],
.props-table .cell-avg[data-tier="bad"],
.props-table .cell-usage[data-tier="bad"] {
  --tv-tint: rgba(239, 68, 68, 0.18);
  background: var(--tv-tint);
}

/* USAGE saturated foreground (span has no data-rate of its own). */
.props-table .cell-usage[data-tier="excellent"] .tv-usage-value { color: #00F5D4; }
.props-table .cell-usage[data-tier="good"]      .tv-usage-value { color: #4ade80; }
.props-table .cell-usage[data-tier="average"]   .tv-usage-value { color: #facc15; }
.props-table .cell-usage[data-tier="poor"]      .tv-usage-value { color: #ea580c; }
.props-table .cell-usage[data-tier="bad"]       .tv-usage-value { color: #ef4444; }

/* Hover keeps the tier tint on tinted cells. Scoped HARD to NFL cells:
   [data-tier] only ever exists on NFL TDs, and :not(.no-data) leaves the
   no-data:hover transparency rule in charge — without both guards this
   rule (later in the file, same 0,4,0 specificity) beat the .no-data
   transparent override for every sport and dimmed MLB/NBA's
   hover-while-expanded from 0.08 to 0.06 via the var — review catch.
   Untinted NFL cells (data-tier="") get the original hover teal via the
   var() fallback; MLB/NBA never match and keep the 3526/3541 cascade. */
.props-table .cell-l5.clickable[data-tier]:not(.no-data):hover,
.props-table .cell-season.clickable[data-tier]:not(.no-data):hover {
  background: var(--tv-tint, rgba(0, 211, 189, 0.08));
}

/* Expanded chart cells drop the tier tint for the neutral chart teal —
   re-asserted AFTER the tint block so source order beats it; the var is
   redefined too so hover-while-expanded matches. */
.props-table .cell-l5.expanded,
.props-table .cell-season.expanded {
  --tv-tint: rgba(0, 211, 189, 0.06);
  background: rgba(0, 211, 189, 0.06);
}

/* ─────────────────────────────────────────────────────────────────────────
   NFL Opportunity x Performance breakdown (2026-08-28)

   Rendered INSIDE the shared .tv-pm-modal shell (see :1681), the same shell
   MLB's model popup uses — so the overlay, the scrim, the close button and
   the <=1000px `zoom: 1.35` mobile sizing are all inherited rather than
   reimplemented. Only the BODY is NFL's, and every selector below is an
   .oxp-* class that appears nowhere else.

   Tier colours are the SAME five the Score cell uses (#00F5D4 / #4ade80 /
   #facc15 / #ea580c / #ef4444) so the popup reads as an extension of the
   number the user just clicked.
   ───────────────────────────────────────────────────────────────────────── */
.props-table .cell-grade.is-nfl-oxp.clickable { cursor: pointer; }
.props-table .cell-grade.is-nfl-oxp.clickable:hover { filter: brightness(1.25); }

/* Slightly wider than the stock info modal: two arms side by side need the
   room, and below ~560px they stack anyway. */
.tv-pm-modal-oxp { max-width: 560px; }

.oxp-panel {
  display: flex;
  flex-direction: column;
  gap: 12px;
  color: var(--text, #e5e7eb);
}
.oxp-title {
  font-size: 13px;
  font-weight: 600;
  color: rgba(255, 255, 255, 0.72);
  padding-right: 28px;            /* clears the absolutely-positioned close x */
}

/* Headline: the number, its label, and the one sentence that stops a user
   reading it as a board rank. */
.oxp-headline {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 8px;
}
.oxp-headline-score {
  font-size: 34px;
  font-weight: 700;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.oxp-headline-label {
  font-size: 14px;
  font-weight: 600;
  color: rgba(255, 255, 255, 0.85);
}
.oxp-headline-note {
  flex-basis: 100%;
  font-size: 11px;
  line-height: 1.4;
  color: rgba(255, 255, 255, 0.45);
}

/* The two arms, side by side when there is room and stacked when there is not. */
.oxp-arms {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 10px;
}
.oxp-arm {
  background: rgba(255, 255, 255, 0.035);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 7px;
  padding: 10px 12px;
}
.oxp-arm-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 7px;
}
.oxp-arm-title {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.52);
}
.oxp-arm-score {
  font-size: 19px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
/* An arm with no number reads as a muted dash — never as a 0, which beside a
   green headline is the trust bug the design forbids. */
.oxp-arm-na { color: rgba(255, 255, 255, 0.35); font-weight: 600; }

.oxp-arm-lines {
  margin: 0;
  padding-left: 16px;
  display: flex;
  flex-direction: column;
  gap: 5px;
}
.oxp-arm-lines li,
.oxp-arm-prose {
  font-size: 12.5px;
  line-height: 1.45;
  color: rgba(255, 255, 255, 0.82);
  margin: 0;
}
.oxp-arm-prose { color: rgba(255, 255, 255, 0.58); font-style: italic; }

/* CONTEXT is deliberately quieter than the arms: these sentences are on the
   card because they are interesting, and their partial correlation with
   production is ~0.000. They must not read as reasons for the number. */
.oxp-context {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding-top: 10px;
  border-top: 1px dashed rgba(255, 255, 255, 0.12);
}
.oxp-chip {
  font-size: 11.5px;
  line-height: 1.35;
  color: rgba(255, 255, 255, 0.58);
  background: rgba(255, 255, 255, 0.045);
  border-radius: 4px;
  padding: 4px 9px;
}
.oxp-chip b {
  color: rgba(255, 255, 255, 0.78);
  font-weight: 600;
  margin-right: 4px;
}
.oxp-notice {
  font-size: 12px;
  color: rgba(255, 255, 255, 0.55);
}

/* Same five tiers as the Score cell. */
.oxp-headline-score[data-tier="excellent"],
.oxp-arm-score[data-tier="excellent"] { color: #00F5D4; }
.oxp-headline-score[data-tier="good"],
.oxp-arm-score[data-tier="good"]      { color: #4ade80; }
.oxp-headline-score[data-tier="average"],
.oxp-arm-score[data-tier="average"]   { color: #facc15; }
.oxp-headline-score[data-tier="poor"],
.oxp-arm-score[data-tier="poor"]      { color: #ea580c; }
.oxp-headline-score[data-tier="bad"],
.oxp-arm-score[data-tier="bad"]       { color: #ef4444; }

/* The mobile card's Score tile opens this same popup, so it must look tappable. */
body.is-nfl-route .prop-card .grade-stat { cursor: pointer; }

/* ─────────────────────────────────────────────────────────────────────────
   NFL model sheet (2026-08-29). The LAYOUT is MLB's .tv-mp-sheet, reused
   verbatim so the two sports cannot drift apart; only the art differs.

   The football source is as dark as the baseball one was (mean luminance
   13/255) and is exposure-boosted on disk for the same reason — a lighter
   scrim alone left it invisible. Anchored bottom-right because that is where
   the ball sits in the frame; `center` crops it out on this panel's aspect.
   ───────────────────────────────────────────────────────────────────────── */
/* Founder 2026-08-29: no icons on the NFL sheet. The row is MLB's, so the
   34px icon column is reclaimed here rather than by editing the shared rule —
   MLB still renders its own icons in that slot. Tier colour still reads: it
   was never carried by the icon alone, the bar and the value move with it. */
.tv-mp-row.is-noico {
  grid-template-columns: minmax(88px, auto) minmax(0, 1fr) auto;
}
.tv-mp-row.is-noico .tv-mp-row-sub { grid-column: 1 / -1; }

.tv-mp-prob-panel.is-nfl {
  background:
    radial-gradient(120% 90% at 50% 52%, rgba(6, 12, 14, 0.80) 0%,
                                          rgba(6, 12, 14, 0.52) 42%,
                                          rgba(6, 12, 14, 0.18) 100%),
    url('/static/css/used-imgs/nfl-model-bg.jpg') right bottom / cover no-repeat,
    #08111a;
}

/* The old bespoke .mdl-* panel is gone — the sheet above replaced it. These
   two rules remain only because the Score CELL still uses them. */
.props-table .cell-grade.is-nfl-oxp.clickable { cursor: pointer; }
.props-table .cell-grade.is-nfl-oxp.clickable:hover { filter: brightness(1.25); }

/* ---- LIQUID GLASS multi-book "Place Parlay" popup (phones only, both
   sports, 2026-09-03) ----
   The sheet takes the V2 "clear" glass panel (blur is affordable: one
   modal over content) and grows to the phone's width — 920px canvas is
   ~366px on glass, matching the slip column. Each book option is a glass
   row ~104px tall (≈41px on glass); BEST = teal-tinted active glass;
   PARTIAL keeps its dimming. Sizes are canvas px (no <meta viewport>):
   title 34 / close glyph 44 / book badge 60 tall with 26px text / coverage
   + tag 24 / odds 36 mono / body padding 24. Appended LAST so file order
   wins over the ≤1000px block at ~:750; the desktop rules are untouched. */
@media (max-width: 1000px) {
  .mlb-link-modal-content {
    width: min(828px, 84.6vw);
    max-height: 90vh;
    background: linear-gradient(180deg, rgba(255,255,255,.045) 0%, rgba(255,255,255,.02) 100%);
    border: 1px solid rgba(255,255,255,.20);
    border-radius: 22px;
    box-shadow: inset 0 1px 0 rgba(255,255,255,.26), 0 8px 20px rgba(0,0,0,.55);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
  }
  .mlb-link-modal-header {
    gap: 20px;
    padding: 26px 30px;
    border-bottom: 1px solid rgba(255,255,255,.10);
  }
  .mlb-link-modal-title { font-size: 34px; color: rgba(255,255,255,.92); }
  .mlb-link-modal-close {
    min-width: 64px; min-height: 64px;
    margin: -10px -12px -10px 0;
    font-size: 44px;
    color: #8b93a0;
  }
  .mlb-link-modal-close:hover { color: #fff; }

  .mlb-link-modal-body {
    gap: 16px;
    padding: 24px;
  }
  /* Glass rows (many per sheet: tint + rim + shadow, no second blur). */
  .mlb-link-option {
    gap: 20px;
    padding: 20px 22px;
    min-height: 104px;
    box-sizing: border-box;
    border-radius: 18px;
    background: linear-gradient(180deg, rgba(255,255,255,.045) 0%, rgba(255,255,255,.02) 100%);
    border: 1px solid rgba(255,255,255,.20);
    box-shadow: inset 0 1px 0 rgba(255,255,255,.26), 0 4px 12px rgba(0,0,0,.55);
  }
  .mlb-link-option:hover {
    background: linear-gradient(180deg, rgba(255,255,255,.07) 0%, rgba(255,255,255,.035) 100%);
    border-color: rgba(255,255,255,.28);
  }
  .mlb-link-option.is-best {
    background: linear-gradient(180deg, rgba(45,212,191,.22) 0%, rgba(45,212,191,.12) 100%);
    border-color: rgba(45,212,191,.7);
    box-shadow: inset 0 1px 0 rgba(255,255,255,.14), 0 6px 18px rgba(0,0,0,.35);
  }
  /* Book badge: 60px tall, 26px text (line-height 1 + 17px pads). */
  .mlb-link-option-book {
    min-width: 150px;
    padding: 17px 20px;
    border-radius: 12px;
    font-size: 26px;
    line-height: 1;
  }
  .mlb-link-option-book.with-logo {
    gap: 12px;
    padding: 13px 18px;
  }
  .mlb-link-option-logo { height: 34px; }
  .mlb-link-option-text { font-size: 26px; }
  .mlb-link-option-meta {
    gap: 14px;
    font-size: 24px;
    color: #8b93a0;
  }
  .mlb-link-option-coverage {
    padding: 10px 14px;
    border-radius: 10px;
    font-size: 24px;
    background: rgba(255,255,255,.08);
    box-shadow: inset 0 0 0 1px rgba(255,255,255,.12);
    color: rgba(255,255,255,.92);
  }
  .mlb-link-option-tag {
    padding: 10px 14px;
    border-radius: 10px;
    font-size: 24px;
  }
  .mlb-link-option-odds {
    font-size: 36px;
    font-family: ui-monospace, "SF Mono", Menlo, Consolas, "Roboto Mono", monospace;
    letter-spacing: -0.01em;
  }
}

/* ---- DESKTOP V2 "clear" glass sportsbook link popup (>=1001px, 2026-09-03) ----
   Surfaces only — the desktop sizes at :614-747 (420px sheet, 12px rows,
   80px book badge) are kept. Sheet = glass + blur; rows = glass (tint +
   rim + shadow, no second blur); .is-best = teal-tinted active glass;
   .is-partial keeps its opacity. */
@media (min-width: 1001px) {
  .mlb-link-modal-content {
    background: linear-gradient(180deg, rgba(255,255,255,.045) 0%, rgba(255,255,255,.02) 100%), rgba(6, 10, 14, .92);
    border: 1px solid rgba(255,255,255,.20);
    border-radius: 14px;
    box-shadow: inset 0 1px 0 rgba(255,255,255,.26), 0 8px 20px rgba(0,0,0,.55);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
  }
  .mlb-link-modal-header { border-bottom: 1px solid rgba(255,255,255,.10); }
  .mlb-link-modal-title { color: rgba(255,255,255,.92); }
  .mlb-link-modal-close { color: #8b93a0; }
  .mlb-link-modal-close:hover { color: #fff; }
  .mlb-link-option {
    background: linear-gradient(180deg, rgba(255,255,255,.045) 0%, rgba(255,255,255,.02) 100%);
    border: 1px solid rgba(255,255,255,.20);
    box-shadow: inset 0 1px 0 rgba(255,255,255,.26), 0 2px 6px rgba(0,0,0,.55);
  }
  .mlb-link-option:hover {
    background: linear-gradient(180deg, rgba(255,255,255,.07) 0%, rgba(255,255,255,.035) 100%);
    border-color: rgba(255,255,255,.28);
  }
  .mlb-link-option.is-best {
    background: linear-gradient(180deg, rgba(45,212,191,.22) 0%, rgba(45,212,191,.12) 100%);
    border-color: rgba(45,212,191,.7);
    box-shadow: inset 0 1px 0 rgba(255,255,255,.14), 0 3px 9px rgba(0,0,0,.35);
  }
  .mlb-link-option-meta { color: #8b93a0; }
  .mlb-link-option-coverage {
    background: rgba(255,255,255,.08);
    box-shadow: inset 0 0 0 1px rgba(255,255,255,.12);
    color: rgba(255,255,255,.92);
  }
}
