/* ════════════════════════════════════════════════════════════════════
   NHL ODDS TOOL — odds screen and book screen

   Laid out the way Data Golf lays out its betting tools, in this site's own
   type and colour: the title with a view switch under it, then instrument
   panels (a caption bar naming the control, the control flush beneath it),
   then dense bordered tables whose label column is shaded so the prices
   read as the body of the sheet.

   Order on the page, top to bottom, is the order you use it in:
     view switch → books → game → match markets → prop market → prop table.

   Selection reads the same way everywhere: whatever is on is white (or
   tinted, for the view switch) with a blue mark — a filled box, a filled
   dot, a rule along the foot — and whatever is off is the panel's tint.
   ════════════════════════════════════════════════════════════════════ */

/* The best-price mark, named here because only the board uses it.
   Deliberately warm: amber is the one hue on this page that reads at a
   glance and is neither the blue of selection nor the green of .model-edge
   — the other mark that can land on the very same cell, meaning something
   else entirely (a model edge is an opinion; the best price is a fact). */
:root {
  --best-wash: #FEF3C7;
  --best-ink:  #92400E;
  /* The board surfaces (--board-*, --name-col) are in main.css, shared
     with the lineup, player and team pages. */
}

/* ── Page head: controls, title, view switch ───────────────────────── */
.odds-tool-head {
  max-width: var(--page-max-wide);
  margin: 0 auto 18px;
  padding: 0 20px;
}
.odds-tool-head__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 6px 20px;
  padding: 4px 0 10px;
  border-bottom: 1px solid var(--board-rule);
}
.odds-tool-head__main { padding-top: 14px; }
.odds-tool-head h1 {
  margin: 0 0 4px;
  color: var(--board);
  font-family: var(--font-display);
  font-size: 28px;
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -.005em;
}
.odds-tool-head__lede {
  max-width: 75ch;
  margin: 0;
  color: var(--twill);
  font-size: 13.5px;
  line-height: 1.5;
}

/* The view switch, as Data Golf does it: a radio pair under the title. The
   current screen gets a filled dot and a light tint; the other is plain
   text with an empty ring. Quiet on purpose — it is a setting of the tool,
   not a headline, and the title above it already names the screen. */
.odds-screen-switch {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-top: 10px;
}
.odds-screen-switch__option {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 4px 10px 4px 8px;
  border-radius: var(--radius-s);
  color: var(--ink);
  font-size: 13.5px;
  line-height: 1.4;
  text-decoration: none;
  transition: background-color .12s ease, color .12s ease;
}
.odds-screen-switch__radio {
  flex: 0 0 auto;
  width: 13px;
  height: 13px;
  box-sizing: border-box;
  border: 1.5px solid #A3ACB5;
  border-radius: 50%;
  background: var(--sheet);
}
.odds-screen-switch__option:hover { background: var(--board-tint); color: var(--ink-strong); text-decoration: none; }
.odds-screen-switch__option:hover .odds-screen-switch__radio { border-color: var(--twill); }
.odds-screen-switch__option.is-active { background: var(--board-tint-2); color: var(--board); font-weight: 600; cursor: default; }
.odds-screen-switch__option.is-active .odds-screen-switch__radio {
  border-color: var(--blue-line);
  background: var(--blue-line);
  box-shadow: inset 0 0 0 2px var(--sheet);
}
.odds-screen-switch__option:focus-visible { outline: 2px solid var(--blue-line); outline-offset: 1px; }

/* ── Auto-refresh ───────────────────────────────────────────────────── */
.auto-refresh-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 12.5px;
  color: var(--ink);
}
.auto-refresh-toggle {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  user-select: none;
}
.auto-refresh-toggle input { position: absolute; opacity: 0; pointer-events: none; }
.auto-refresh-toggle__track {
  position: relative;
  flex-shrink: 0;
  width: 30px;
  height: 16px;
  border-radius: 999px;
  background: #C9CED4;
  transition: background-color .18s ease;
}
.auto-refresh-toggle__thumb {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--sheet);
  box-shadow: 0 1px 2px rgba(16, 24, 32, .25);
  transition: transform .18s ease;
}
.auto-refresh-toggle input:checked + .auto-refresh-toggle__track { background: var(--gain); }
.auto-refresh-toggle input:checked + .auto-refresh-toggle__track .auto-refresh-toggle__thumb { transform: translateX(14px); }
.auto-refresh-toggle input:focus-visible + .auto-refresh-toggle__track { outline: 2px solid var(--blue-line); outline-offset: 2px; }
.auto-refresh-toggle__label { color: var(--ink-strong); }
.auto-refresh-status {
  padding-left: 10px;
  border-left: 1px solid var(--board-rule);
  color: var(--twill);
  font-family: var(--font-data);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}

/* ── Odds format ────────────────────────────────────────────────────── */
/* Decimal / American / Implied. Built by static/js/odds-format.js into the
   empty host; it sits beside auto-refresh because both are settings of the
   tool rather than of the table. Each option carries a sample of evens so the
   choice explains itself. */
.odds-format-setting {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: auto;
  font-size: 12.5px;
}
.odds-format-setting__label { color: var(--twill); }
.odds-format-switch {
  display: inline-flex;
  padding: 2px;
  border: 1px solid var(--board-rule);
  border-radius: var(--radius-s);
  background: var(--sheet);
}
.odds-format-switch__option {
  display: inline-flex;
  align-items: baseline;
  gap: 5px;
  padding: 3px 9px;
  border: 0;
  border-radius: 3px;
  background: transparent;
  color: var(--ink);
  font: inherit;
  line-height: 1.4;
  cursor: pointer;
  transition: background-color .12s ease, color .12s ease;
}
.odds-format-switch__sample {
  color: var(--twill);
  font-family: var(--font-data);
  font-size: 10.5px;
  font-variant-numeric: tabular-nums;
}
.odds-format-switch__option:hover { background: var(--board-tint); color: var(--ink-strong); }
.odds-format-switch__option[aria-pressed="true"] {
  background: var(--board-tint-2);
  color: var(--board);
  font-weight: 600;
  cursor: default;
}
.odds-format-switch__option[aria-pressed="true"] .odds-format-switch__sample { color: var(--board); }
.odds-format-switch__option:focus-visible { outline: 2px solid var(--blue-line); outline-offset: 1px; }
@media (max-width: 640px) {
  /* Crumbs, format and refresh each get a line; the samples go, the names
     are enough on a phone. */
  .odds-format-setting { margin-left: 0; }
  .odds-format-switch__sample { display: none; }
}

/* ── Workspace ──────────────────────────────────────────────────────── */
.odds-workspace {
  --twill: #586572;
  max-width: var(--page-max-wide);
  margin-inline: auto;
  padding: 0 20px 24px;
  font-family: var(--font-body);
}
.odds-load-error {
  margin-bottom: 14px;
  padding: 12px 14px;
  border: 1px solid #D6A033;
  border-radius: var(--radius-s);
  background: #FFF7E6;
  color: #5C3A00;
  font-weight: 600;
}
.odds-noscript-matchups { margin: 12px 0 0; padding-left: 20px; }
/* The signup strip sits at the top of the workspace, in line with the panels. */
.odds-workspace .premium-gate { margin: 0 0 16px; }
.odds-empty-state {
  margin: 0;
  padding: 16px;
  border: 1px solid var(--board-rule);
  background: var(--sheet);
  color: var(--ink);
  font-size: 13px;
}

/* ── Instrument panels ─────────────────────────────────────────────── */
.odds-panel {
  margin: 0 0 16px;
  border: 1px solid var(--board-rule);
  background: var(--sheet);
}
.odds-panel__bar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 4px 14px;
  min-height: 30px;
  padding: 4px 12px;
  border-bottom: 1px solid var(--board-rule);
  background: var(--board-tint);
  color: var(--twill);
  font-size: 11.5px;
}
.odds-panel__title {
  margin: 0 auto 0 0;
  color: var(--ink-strong);
  font-family: var(--font-display);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .06em;
  line-height: 1.4;
  text-transform: uppercase;
}
.odds-preference-status { color: var(--twill); }
.odds-preference-status a { color: var(--blue-line); font-weight: 600; text-decoration: underline; }
.odds-book-controls__count {
  padding-left: 14px;
  border-left: 1px solid var(--board-rule);
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
#show-all-bookies {
  padding: 0;
  border: 0;
  background: none;
  color: var(--blue-line);
  font: inherit;
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
#show-all-bookies[hidden] { display: none; }
#show-all-bookies:hover { color: var(--goal-red); }
#show-all-bookies:focus-visible { outline: 2px solid var(--blue-line); outline-offset: 3px; }
.odds-empty-books {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding-left: 14px;
  border-left: 1px solid var(--board-rule);
  color: var(--ink);
  cursor: pointer;
  white-space: nowrap;
}
.odds-empty-books input { margin: 0; accent-color: var(--blue-line); }

/* Book tiles. On: white, a blue rule along the foot, a filled box. Off:
   the panel's tint, an empty box and the logo dimmed. The logo used to stay
   at full colour when off, on the grounds that a grey logo reads as "this
   book is down" — but with nothing else changing, nine full-colour logos
   read as nine books on, and which ones were actually on the table was
   the thing people could not see. The box beside the logo is what makes
   the dim read as "not picked" rather than "not working". */
.odds-bookie-strip {
  display: grid;
  grid-template-columns: repeat(var(--book-choice-count, 9), minmax(0, 1fr));
}
.odds-bookie-choice { position: relative; min-width: 0; cursor: pointer; }
.odds-bookie-choice + .odds-bookie-choice .odds-bookie-choice__face { border-left: 1px solid var(--board-rule); }
.odds-bookie-choice input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.odds-bookie-choice__face {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 44px;
  padding: 0 8px;
  background: var(--board-tint);
  box-shadow: inset 0 -3px transparent;
  transition: background-color .12s ease;
}
.odds-bookie-choice img {
  display: block;
  width: 96px;
  min-width: 0;
  height: 24px;
  object-fit: contain;
  opacity: .42;
  filter: saturate(.55);
  transition: opacity .12s ease, filter .12s ease;
}
.odds-bookie-choice__mark {
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  box-sizing: border-box;
  border: 1.5px solid #A3ACB5;
  border-radius: 3px;
  background: var(--sheet) center / 10px 10px no-repeat;
}
.odds-bookie-choice__mark.is-radio { border-radius: 50%; }
.odds-bookie-choice:hover .odds-bookie-choice__face { background: var(--board-tint-2); }
.odds-bookie-choice:hover img { opacity: .75; filter: none; }
.odds-bookie-choice input:checked + .odds-bookie-choice__face {
  background: var(--sheet);
  box-shadow: inset 0 -3px var(--blue-line);
}
.odds-bookie-choice input:checked + .odds-bookie-choice__face img { opacity: 1; filter: none; }
.odds-bookie-choice input:checked + .odds-bookie-choice__face .odds-bookie-choice__mark {
  border-color: var(--blue-line);
  background-color: var(--blue-line);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E%3Cpath d='M1.8 5.2 4 7.3 8.3 2.8' fill='none' stroke='%23fff' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}
.odds-bookie-choice input:checked + .odds-bookie-choice__face .odds-bookie-choice__mark.is-radio {
  background-image: none;
  box-shadow: inset 0 0 0 2.5px var(--sheet);
}
.odds-bookie-choice input:focus-visible + .odds-bookie-choice__face { outline: 2px solid var(--blue-line); outline-offset: -3px; position: relative; z-index: 1; }
.odds-bookie-choice input:disabled + .odds-bookie-choice__face { cursor: not-allowed; }

/* ── Game rail ──────────────────────────────────────────────────────── */
.odds-workspace .pre-load { position: relative; }
/* The rail scrolls and usually has a game half-cut at the right edge; the
   fade says so rather than leaving it looking like a rendering fault. */
.odds-workspace .pre-load::before,
.odds-workspace .pre-load::after {
  content: '';
  position: absolute;
  z-index: 1;
  top: 0;
  bottom: 6px;
  width: 32px;
  opacity: 0;
  pointer-events: none;
  transition: opacity .15s ease;
}
.odds-workspace .pre-load::before { left: 0; background: linear-gradient(to left, rgba(255, 255, 255, 0), var(--sheet)); }
.odds-workspace .pre-load::after { right: 0; background: linear-gradient(to right, rgba(255, 255, 255, 0), var(--sheet)); }
.odds-workspace .pre-load.can-scroll-prev::before,
.odds-workspace .pre-load.can-scroll-next::after { opacity: 1; }
/* Arrows for a mouse, which has no sideways scroll of its own. */
.match-rail-nav {
  position: absolute;
  z-index: 2;
  top: calc(50% - 3px);
  transform: translateY(-50%);
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  padding: 0 0 3px;
  border: 1px solid var(--board-rule);
  border-radius: 50%;
  background: var(--sheet);
  box-shadow: 0 2px 8px rgba(16, 24, 32, .14);
  color: var(--ink-strong);
  font: 400 26px/1 var(--font-body);
  cursor: pointer;
}
.match-rail-nav[hidden] { display: none; }
.match-rail-nav--prev { left: -6px; }
.match-rail-nav--next { right: -6px; }
.match-rail-nav:hover { background: var(--board-tint); color: var(--board); }
.match-rail-nav:focus-visible { outline: 2px solid var(--blue-line); outline-offset: 2px; }
/* A touch screen swipes the rail; arrows there only cover games. */
@media (hover: none) { .match-rail-nav { display: none; } }
.match-selector-container {
  display: flex;
  gap: 6px;
  margin: 0 0 6px;
  padding: 2px 32px 8px 2px;
  overflow-x: auto;
  scrollbar-width: thin;
}
.match-selector-item {
  appearance: none;
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  gap: 8px;
  padding: 7px 14px;
  border: 1px solid var(--board-rule);
  border-radius: var(--radius-m);
  background: var(--sheet);
  color: var(--ink-strong);
  font: 600 14px var(--font-body);
  white-space: nowrap;
  cursor: pointer;
  transition: background-color .12s ease, border-color .12s ease;
}
.match-selector-item:hover { background: var(--board-tint); border-color: #CFCBC2; }
/* An outline, not an underline: a rule under a rounded pill is clipped by
   its own corners. */
.match-selector-item.active {
  border-color: var(--board);
  box-shadow: inset 0 0 0 1px var(--board);
  background: var(--sheet);
  color: var(--board);
}
.match-selector-item:focus-visible { outline: 2px solid var(--blue-line); outline-offset: 2px; }
.match-selector-logo { width: 26px; height: 26px; flex-shrink: 0; object-fit: contain; }
.match-selector-acro { letter-spacing: .02em; font-variant-numeric: tabular-nums; }
.match-selector-at { color: var(--twill); font-size: 12px; font-weight: 400; }
.match-selector-time {
  margin-left: 2px;
  padding-left: 9px;
  border-left: 1px solid var(--board-rule);
  color: var(--twill);
  font-size: 12px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* ── Section heads ──────────────────────────────────────────────────── */
.odds-section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 4px 16px;
  margin: 22px 0 8px;
  scroll-margin-top: 20px;
}
.odds-section-title {
  margin: 0;
  color: var(--board);
  font-family: var(--font-display);
  font-size: 19px;
  font-weight: 700;
  line-height: 1.2;
}
.odds-section-title__fixture {
  margin-left: 8px;
  color: var(--twill);
  font-size: 15px;
  font-weight: 600;
}
.odds-section-title__time {
  margin-left: 8px;
  color: var(--twill);
  font-size: 13px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}
.odds-lineup-link { color: var(--blue-line); font-size: 12.5px; font-weight: 600; }
.odds-lineup-link[hidden] { display: none; }

/* The exchanges' market-price caveat, and the asterisk on their logos that
   points at it. Twill, not goal-red: it is a footnote, not live money. */
.exchange-fee-note {
  margin: 0 0 10px;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--twill);
}
.exchange-fee-note[hidden] { display: none; }
.exchange-fee-note strong { color: var(--ink); font-weight: 600; }
.mob-head__fee {
  margin-left: 2px;
  font-size: 12px;
  font-weight: 700;
  color: var(--twill);
  vertical-align: top;
}
.odds-lineup-link:hover { color: var(--goal-red); }

/* The early-season model caveat above the match board. */
.odds-board-note {
  margin: 0 0 10px;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--twill);
}

/* ── Match board ────────────────────────────────────────────────────
   A market is a block of two rows, one per side. Market, payout and the
   movement chart span the block; each side's prices sit on its own row. */
.match-odds-board { margin: 0; overflow-x: auto; }
.mob-table {
  /* Horizontal room is bought from the live column count, not guessed. */
  min-width: calc(372px + var(--match-bookie-count, 7) * 80px);
  border: 1px solid var(--board-rule);
  background: var(--sheet);
}
.mob-group {
  --mob-market-w: 132px;
  --mob-side-w: 78px;
  display: grid;
  grid-template-columns:
    var(--mob-market-w) var(--mob-side-w) 78px 84px
    repeat(var(--match-bookie-count, 7), minmax(80px, 1fr));
  border-bottom: 1px solid var(--board-rule);
}
.mob-group:last-child { border-bottom: 0; }
.mob-group--head { background: var(--board-tint); }
.mob-head {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 40px;
  padding: 4px 6px;
  color: var(--twill);
  font-family: var(--font-display);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .05em;
  text-transform: uppercase;
}
.mob-group--head .mob-market { justify-content: center; }
.mob-market {
  grid-row: span 2;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 2px;
  padding: 6px 12px;
  background: var(--name-col);
}
.mob-group--head .mob-market { grid-row: auto; align-items: flex-start; padding-left: 12px; }
.mob-market__name { color: var(--ink-strong); font-size: 13px; font-weight: 600; line-height: 1.25; }
.mob-market__line { color: var(--twill); font-family: var(--font-data); font-size: 11px; }
.mob-side {
  display: flex;
  align-items: center;
  gap: 6px;
  min-height: 32px;
  padding: 0 10px;
  border-right: 1px solid var(--board-rule);
  background: var(--name-col);
  color: var(--ink-strong);
  font-size: 12.5px;
  font-weight: 600;
}
.mob-side__logo { width: 18px; height: 18px; object-fit: contain; }
.mob-side + .mob-cell { border-left: 0; }
.mob-cell {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
  padding: 3px 6px;
  border-left: 1px solid var(--board-rule-soft);
}
.mob-group--head .mob-cell { border-left-color: var(--board-rule); }
/* The rule between a market's two sides is lighter than the one between
   markets, so the pair reads as one block. */
.mob-group > .is-first { border-bottom: 1px dotted var(--board-rule); }
.mob-payout {
  grid-row: span 2;
  color: var(--ink);
  font-family: var(--font-data);
  font-size: 12px;
}
.mob-odd {
  min-width: 52px;
  padding: 3px 6px;
  border-radius: 3px;
  color: var(--ink-strong);
  font-family: var(--font-data);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  text-align: center;
  white-space: nowrap;
}
.mob-odd.best { background: var(--best-wash); color: var(--best-ink); font-weight: 600; }
.mob-best .mob-odd { color: var(--best-ink); font-weight: 600; }
/* The brands' own marks come in every shape, from bet365's badge to
   Polymarket's long wordmark. Each file is drawn on the same 4:1 canvas
   at roughly the same inked area (static/img/bookies), so here they all
   take one box and still read at one size. */
.bookie-logo {
  display: block;
  width: 100%;
  max-width: 100px;
  height: 25px;
  margin: 0 auto;
  object-fit: contain;
}

/* ── Movement column (book screen) ───────────────────────────────────
   Every market states its own movement where it sits, so the board
   answers "did this move" without a click. */
.mob-move {
  grid-row: span 2;
  position: relative;
  flex-direction: column;
  align-items: stretch;
  justify-content: center;
  gap: 2px;
  padding: 5px 10px;
}
.mob-spark { display: block; width: 100%; height: 46px; overflow: visible; touch-action: none; }
.mob-spark:focus-visible { outline: 2px solid var(--blue-line); outline-offset: 2px; }
/* Even money. Every price row is drawn against this same line, so a glance
   down the column says which way each market sits without reading a number. */
.mob-spark__ref { stroke: var(--twill); stroke-width: 1; stroke-dasharray: 2 4; opacity: .38; vector-effect: non-scaling-stroke; }
.mob-spark__cursor { stroke: var(--board); stroke-width: 1; stroke-dasharray: 2 3; vector-effect: non-scaling-stroke; }
/* SVG elements ignore the HTML `hidden` attribute, so idleness is a class. */
.mob-spark__cursor.is-idle { visibility: hidden; }
/* The marks under the pointer, ringed so the numbers in the tooltip can be
   tied to the points they came from. */
.mob-spark__hit { fill: none; stroke-width: 2; vector-effect: non-scaling-stroke; }
.mob-spark__hit.is-idle { visibility: hidden; }
.mob-spark__hit--away { stroke: var(--blue-line); }
.mob-spark__hit--home { stroke: var(--goal-red); }
.mob-spark__hit--line { stroke: var(--board); }
.mob-spark__trend { fill: none; stroke-width: 1; opacity: .4; vector-effect: non-scaling-stroke; }
.mob-spark__trend--away { stroke: var(--blue-line); }
.mob-spark__trend--home { stroke: var(--goal-red); }
.mob-spark__trend--line { stroke: var(--board); }
.mob-spark__dot { opacity: .7; }
.mob-spark__dot--away { fill: var(--blue-line); }
.mob-spark__dot--home { fill: var(--goal-red); }
.mob-spark__dot--line { fill: var(--board); }
/* The standing price. Filled white with its series colour around it so it
   stays findable inside a dense cluster. */
.mob-spark__last { fill: var(--sheet); stroke-width: 2; vector-effect: non-scaling-stroke; }
.mob-spark__last--away { stroke: var(--blue-line); }
.mob-spark__last--home { stroke: var(--goal-red); }
.mob-spark__last--line { stroke: var(--board); }
.mob-spark__reflabel { font-family: var(--font-data); font-size: 8px; fill: var(--twill); }
/* A prop line move: where it happened, and the line the book moved to. */
.mob-spark__linechange { stroke: var(--ink-strong); stroke-width: 1; stroke-dasharray: 3 3; opacity: .55; vector-effect: non-scaling-stroke; }
.mob-spark__linelabel { font-family: var(--font-data); font-size: 8.5px; font-weight: 600; fill: var(--ink-strong); }

/* The read-out, at the point rather than at the bottom of the cell. */
.mob-move__tip {
  position: absolute;
  top: 4px;
  z-index: 3;
  display: flex;
  flex-direction: column;
  gap: 1px;
  margin-left: 12px;
  padding: 6px 9px;
  border: 1px solid var(--board-rule);
  border-radius: var(--radius-s);
  background: var(--sheet);
  box-shadow: 0 2px 8px rgba(16, 24, 32, .14);
  font-size: 11px;
  line-height: 1.45;
  white-space: nowrap;
  pointer-events: none;
}
/* Past the middle of the chart it would run off the end, so it flips. */
.mob-move__tip.is-flipped { margin-left: 0; transform: translateX(calc(-100% - 12px)); }
.mob-move__tip[hidden] { display: none; }
.mob-move__tip-time { color: var(--twill); font-family: var(--font-data); font-size: 10px; }
.mob-move__tip-row { display: flex; justify-content: space-between; gap: 14px; }
.mob-move__tip-key { font-weight: 600; }
.mob-move__tip-key--away { color: var(--blue-line); }
.mob-move__tip-key--home { color: var(--goal-red); }
.mob-move__tip-key--line { color: var(--board); }
.mob-move__tip-val { color: var(--ink-strong); font-family: var(--font-data); }
.mob-move__foot { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.mob-move__read {
  min-width: 0;
  overflow: hidden;
  color: var(--twill);
  font-family: var(--font-data);
  font-size: 10px;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.mob-move__delta {
  display: flex;
  align-items: baseline;
  gap: 4px;
  color: var(--twill);
  font-family: var(--font-data);
  font-size: 10px;
  white-space: nowrap;
}
.mob-move__label { color: var(--twill); font-family: var(--font-body); font-weight: 600; }
.mob-move__read--line { color: var(--ink-strong); font-weight: 600; }
.mob-move__now { color: var(--ink-strong); font-weight: 600; }
.mob-move__open { color: var(--twill); }
.mob-move__delta--up .mob-move__arrow { color: var(--gain); }
.mob-move__delta--down .mob-move__arrow { color: var(--goal-red); }
.mob-move__delta--wave .mob-move__arrow { color: var(--ink-strong); }
.mob-move__delta--flat .mob-move__arrow { color: var(--twill); }
.mob-move__none { color: var(--twill); font-size: 11px; font-style: italic; }
.mob-move-head { justify-content: flex-start; padding-left: 12px; }

/* The same chart on a prop row, one per player: shorter, since a row is one
   market line where the match board gives each market two. Qualified with
   .cell, whose centring comes later in this file and would otherwise centre
   the read-out on the cell and spill it over the prices beside it. */
.cell.prop-move {
  position: relative;
  flex-direction: column;
  align-items: stretch;
  justify-content: center;
  gap: 1px;
  padding: 4px 10px;
}
.prop-move .mob-spark { height: 36px; }
.prop-move-head { justify-content: flex-start; padding-left: 12px; }

/* ── Prop market chooser ─────────────────────────────────────────────
   Same panel shape as the book chooser. Half the width of the page: six
   words do not need 1400px, and a switch stretched that far stops reading
   as one control. */
.odds-market-panel { max-width: 760px; }
.odds-filter-container {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
}
.odds-filter-container .filter-btn {
  appearance: none;
  margin: 0;
  padding: 10px 8px;
  border: 0;
  background: var(--board-tint);
  box-shadow: inset 0 -3px transparent;
  color: var(--ink);
  font: 600 13px var(--font-body);
  white-space: nowrap;
  cursor: pointer;
  transition: background-color .12s ease;
}
.odds-filter-container .filter-btn + .filter-btn { border-left: 1px solid var(--board-rule); }
.odds-filter-container .filter-btn:hover { background: var(--board-tint-2); color: var(--ink-strong); }
.odds-filter-container .filter-btn.active {
  background: var(--sheet);
  box-shadow: inset 0 -3px var(--blue-line);
  color: var(--board);
}
.odds-filter-container .filter-btn:focus-visible { outline: 2px solid var(--blue-line); outline-offset: -3px; }

/* ── Legend + explainer ─────────────────────────────────────────────── */
.model-legend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 18px;
  margin: 0 0 10px;
}
.model-legend__keys {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  margin: 0;
  padding: 0;
  list-style: none;
  color: var(--ink);
  font-size: 12.5px;
}
.model-legend__keys li { display: inline-flex; align-items: center; gap: 6px; }
.model-legend__swatch {
  display: inline-block;
  width: 14px;
  height: 14px;
  border-radius: 3px;
  background: #EAF7EF;
  box-shadow: inset 0 0 0 1px #BFE3CD;
  vertical-align: -2px;
}
/* A colour key, not a number: a sample price here read as a real one. */
.model-legend__swatch--best { background: var(--best-wash); box-shadow: inset 0 0 0 1px #F0D48A; }
.model-info { margin-left: auto; }
.model-info > summary {
  color: var(--blue-line);
  font-size: 12.5px;
  font-weight: 600;
  text-align: right;
  cursor: pointer;
}
.model-info > summary:hover { color: var(--goal-red); }
.model-info > summary:focus-visible { outline: 2px solid var(--blue-line); outline-offset: 2px; }
/* Open, it takes the full row under the legend; the summary stays where
   it was clicked. */
.model-info[open] { flex-basis: 100%; margin-left: 0; }
.model-info__body {
  margin-top: 8px;
  padding: 2px 16px 12px;
  border: 1px solid var(--board-rule);
  background: var(--board-page);
  color: var(--ink);
  font-size: 13px;
  line-height: 1.55;
}
.model-info__body p { max-width: 80ch; margin: 10px 0 0; color: var(--ink); }
.model-info__body a { color: var(--blue-line); font-weight: 600; }
/* Its own row under the keys, quieter than them: a caveat, not a key. */
.model-legend__note {
  flex-basis: 100%;
  margin: 0;
  color: var(--twill);
  font-size: 12px;
}
.model-info__stamp:empty { display: none; }
.model-info__stamp { color: var(--twill); font-size: 12px; }

/* Same vocabulary as the lineup tab: fill level reads as certainty, and the
   glyph carries the state without relying on colour. */
.model-symbol { flex: 0 0 auto; margin-right: 5px; font-size: 11px; line-height: 1; }
.model-symbol--confirmed { color: #1F8A4C; }
.model-symbol--projected { color: #B3801A; }
.model-legend .model-symbol { margin-right: 0; }

/* ── Player prop table ──────────────────────────────────────────────── */
.player-odds-scroll {
  width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  border: 1px solid var(--board-rule);
  background: var(--sheet);
}
.player-odds-scroll .odds-empty-state { border: 0; }
.table-header,
.table-row,
.alt-row {
  display: grid;
  /* Player · Line · Fair O/U · Payout · Best · one column per book. */
  grid-template-columns:
    minmax(214px, 1.8fr) 64px 100px 76px 100px
    repeat(var(--bookie-count, 7), minmax(90px, 1fr));
  /* Room bought from the live column count, not guessed. */
  min-width: calc(554px + var(--bookie-count, 7) * 90px);
}
.table-header {
  position: relative;
  background: var(--board-tint);
  border-bottom: 1px solid var(--board-rule);
}
.table-header[hidden] { display: none; }
.header-cell,
.cell {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-width: 0;
  padding: 4px 8px;
  font-size: 13px;
}
.header-cell {
  min-height: 40px;
  color: var(--twill);
  font-family: var(--font-display);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .05em;
  text-transform: uppercase;
}
.header-cell[data-sort] { cursor: pointer; }
.header-cell[data-sort]:hover { color: var(--ink-strong); }
.header-cell.is-sorted { color: var(--board); }
.header-cell[data-sort]:focus-visible { outline: 2px solid var(--blue-line); outline-offset: -3px; }
.filter-icon { display: inline-flex; margin-left: 5px; opacity: .45; }
.header-cell.is-sorted .filter-icon { opacity: 1; }
.bookie-head { padding: 6px 4px; border-left: 1px solid var(--board-rule); }
/* The price order, once, over the block of prices it describes. */
.header-sub {
  padding: 0 8px 5px;
  color: var(--twill);
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
}
.header-sub--books {
  padding-top: 4px;
  border-top: 1px solid var(--board-rule);
  text-align: center;
}
.player-col { justify-content: flex-start; }
.line-col { justify-content: center; }
.odds-col { display: flex; flex-direction: column; align-items: center; justify-content: center; }

.player-row-group { border-bottom: 1px solid var(--board-rule-soft); }
.player-row-group:last-child { border-bottom: 0; }
.table-row { min-height: 34px; background: var(--sheet); }
/* Faint banding. Seven pairs of prices on one row is a lot of horizontal
   tracking; the band is the cheapest way to keep an eye on one player's row
   all the way across. Kept under the hover tint so hover still wins. */
.player-row-group:nth-of-type(even) > .table-row { background: var(--board-zebra); }
.table-row.expandable { cursor: pointer; transition: background-color .12s ease; }
.player-row-group > .table-row:hover { background: var(--board-tint); }
.player-row-group.open > .table-row { background: var(--board-tint-2); }
.table-row.expandable:focus-visible { outline: 2px solid var(--blue-line); outline-offset: -2px; }

/* The name column is shaded, like the market column on the board, and
   stays put when the prices scroll sideways — on a phone the table is
   wider than the screen, and prices without a name are just numbers. */
.table-header .player-col,
.table-row .player-col,
.alt-spacer-col:first-child {
  position: sticky;
  left: 0;
  z-index: 1;
  border-right: 1px solid var(--board-rule);
  background: var(--name-col);
}
.table-header .player-col { background: var(--board-tint); }
.player-row-group > .table-row:hover .player-col { background: var(--board-tint-2); }
.player-row-group.open > .table-row .player-col { background: #E6E3DC; }
.alt-lines-panel .alt-spacer-col:first-child { background: var(--board-tint); }

.player-team_small { width: 20px; height: auto; margin-right: 6px; vertical-align: middle; }
/* Who the row is before reading the name, drawn as the lineup sheets draw a
   player (round headshot on a tint, face kept on a top crop, the number in
   the data face) with the home spotlight's meta line: logo, number, position. */
.player-id { display: flex; align-items: center; gap: 8px; min-width: 0; }
.player-mug {
  flex: 0 0 30px;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--board-tint-2);
  object-fit: cover;
  object-position: top;
}
.player-id__text { display: flex; flex-direction: column; min-width: 0; line-height: 1.25; }
.player-id__name { display: flex; align-items: center; min-width: 0; }
.player-id__meta {
  display: flex;
  align-items: center;
  gap: 5px;
  color: var(--twill);
  font: 400 10.5px/1.3 var(--font-data);
  white-space: nowrap;
}
.player-id__meta .player-team_small { width: 15px; height: 15px; margin: 0; object-fit: contain; }
span + .player-id__pos::before { content: "·"; margin-right: 5px; }
.player-link {
  overflow: hidden;
  color: var(--ink-strong);
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
  text-overflow: ellipsis;
  white-space: nowrap;
}
a.player-link:hover,
a.player-link:focus { color: var(--goal-red); text-decoration: underline; }
.statistics-icon { display: inline-block; width: 16px; height: 16px; margin-left: 8px; vertical-align: middle; }
.row-chevron { flex-shrink: 0; margin-right: 5px; color: var(--twill); transition: transform .2s ease; }
.player-row-group.open .row-chevron { transform: rotate(180deg); color: var(--ink); }

.line-value { color: var(--ink-strong); font-family: var(--font-data); font-size: 13px; font-weight: 600; }
.alt-line-badge {
  display: inline-block;
  margin-left: 5px;
  padding: 0 5px;
  border-radius: 8px;
  background: var(--board-tint-2);
  color: var(--ink);
  font-size: 10.5px;
  font-weight: 600;
  line-height: 1.5;
}
.player-row-group.open .alt-line-badge { background: #DFDBD3; }
.model-col { flex-direction: column; gap: 2px; }
.model-fair { color: var(--ink); font-family: var(--font-data); font-size: 12px; white-space: nowrap; }
.model-locked {
  padding: 2px 8px;
  border: 1px solid #C9D6E6;
  border-radius: 999px;
  color: var(--blue-line);
  font-size: 11.5px;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}
.model-locked:hover { border-color: var(--blue-line); text-decoration: none; }

/* Rows the tier does not get: placeholder rows, blurred, with the way in
   over them. The block is as wide as the rows so the card can stay
   centred in the visible part of the table while it scrolls sideways. */
.locked-rows {
  position: relative;
  width: max-content;
  min-width: 100%;
  border-top: 1px solid var(--board-rule-soft);
}
.locked-rows__ghost {
  filter: blur(3px);
  user-select: none;
  pointer-events: none;
}
.locked-rows__mug {
  flex: none;
  width: 24px;
  height: 24px;
  margin-right: 8px;
  border-radius: 50%;
  background: var(--board-tint-2);
}
.locked-rows__gate {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  background: linear-gradient(to bottom, rgba(255, 255, 255, 0), rgba(255, 255, 255, .3));
}
.locked-rows__card {
  position: sticky;
  /* Centred in the scrollport, not in the (wider) row. */
  left: max(12px, calc(50% - 200px));
  box-sizing: border-box;
  width: min(400px, calc(100vw - 56px));
  padding: 16px 18px;
  border: 1px solid var(--board-rule);
  border-radius: 6px;
  background: var(--sheet);
  box-shadow: 0 6px 24px rgba(20, 33, 50, .12);
  text-align: center;
}
.locked-rows__count {
  margin: 0 0 4px;
  color: var(--board);
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 700;
}
.locked-rows__lead {
  margin: 0 0 12px;
  color: var(--ink);
  font-size: 13px;
  line-height: 1.5;
}
.locked-rows__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 8px 14px;
  margin: 0;
}
.cell.payout-col { color: var(--ink); font-family: var(--font-data); font-size: 12px; }

.cell.odds-col {
  flex-direction: row;
  align-items: stretch;
  gap: 3px;
  padding: 4px 6px;
  border-left: 1px solid var(--board-rule-soft);
}
.cell.odds-col .model-edge-wrap { display: flex; flex: 1 1 0; align-items: center; justify-content: center; min-width: 0; }
.over-odds,
.under-odds {
  width: 100%;
  padding: 3px 0;
  border-radius: 3px;
  color: var(--ink-strong);
  font-family: var(--font-data);
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
  text-align: center;
}
/* Best price on the row. */
.over-odds.best,
.under-odds.best { background: var(--best-wash); color: var(--best-ink); font-weight: 600; }
.model-edge-wrap { width: 100%; border-radius: 3px; }
.model-edge-wrap.model-edge { background: #EAF7EF; box-shadow: inset 0 0 0 1px #BFE3CD; }

.best-col { flex-direction: row; align-items: center; gap: 3px; }
.cell.best-col { align-items: center; border-left: 1px solid var(--board-rule-soft); }
.best-pair {
  flex: 1 1 0;
  min-width: 0;
  color: var(--best-ink);
  font-family: var(--font-data);
  font-size: 12.5px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  text-align: center;
}

/* ── Alternative lines, opened under a player's row ─────────────────── */
/* Smooth expand using the grid-template-rows trick (no fixed max-height). */
.alt-lines-panel {
  display: grid;
  grid-template-rows: 0fr;
  background: var(--board-tint);
  transition: grid-template-rows .22s ease;
}
.player-row-group.open .alt-lines-panel { grid-template-rows: 1fr; }
.alt-lines-inner { min-height: 0; overflow: hidden; }
.alt-lines-table { padding: 4px 0 8px; border-top: 1px dashed var(--board-rule); }
.alt-row { align-items: center; }
.alt-row:hover { background: var(--board-tint-2); }
.alt-line-col {
  padding: 4px 8px;
  color: var(--ink-strong);
  font-family: var(--font-data);
  font-size: 12px;
  font-weight: 600;
  text-align: center;
}
.alt-model-col { color: var(--ink); font-weight: 400; white-space: nowrap; }
/* Set like the payout on the row above it, not like the line beside it. */
.alt-line-col.payout-col { color: var(--ink); font-size: 12px; font-weight: 400; }
.alt-bookie-col {
  display: flex;
  align-items: stretch;
  justify-content: center;
  gap: 3px;
  padding: 2px 6px;
  font-size: 12px;
}
.alt-bookie-col .model-edge-wrap { display: flex; flex: 1 1 0; align-items: center; justify-content: center; min-width: 0; }
.alt-bookie-col .over-odds,
.alt-bookie-col .under-odds { font-size: 12px; }
.alt-spacer-col { align-self: stretch; min-width: 0; }
.alt-best-col { display: flex; align-items: center; gap: 3px; padding: 2px 6px; }
.alt-best-col .best-pair { color: var(--twill); font-size: 11.5px; font-weight: 400; }
.alt-lines-empty { padding: 10px 14px; color: var(--twill); font-size: 12px; font-style: italic; }

/* ── Movement arrows (auto-refresh, book screen) ────────────────────── */
.odds-arrow {
  display: inline-block;
  margin-left: 3px;
  font-size: 9px;
  font-variant-numeric: normal;
  line-height: 1;
  vertical-align: middle;
}
.odds-arrow.up { color: var(--gain); }
.odds-arrow.down { color: var(--goal-red); }

/* ── Footnote ───────────────────────────────────────────────────────── */
.odds-tool-footnote { margin: 16px 0 0; color: var(--twill); font-size: 12.5px; }
.odds-tool-footnote a { color: var(--blue-line); font-weight: 600; }
.odds-tool-footnote a:hover { color: var(--goal-red); }

/* ── Book screen ──────────────────────────────────────────────────────
   One book, so there is no best price to mark; payout is this book's own two
   sides. The name, line and price columns keep the widths their content
   needs and the movement chart takes whatever is left, so a wide screen
   buys a longer chart rather than a stretched name column. */
.book-screen .mob-table { min-width: 0; }
.book-screen .mob-group {
  grid-template-columns: var(--mob-market-w) var(--mob-side-w) 78px minmax(96px, 120px) minmax(220px, 1fr);
}
.book-screen .player-odds-scroll { box-sizing: border-box; }
.book-screen .table-header,
.book-screen .table-row,
.book-screen .alt-row {
  grid-template-columns: minmax(200px, 260px) 72px 100px 80px 150px minmax(240px, 1fr);
  min-width: 842px;
}
.book-screen .bookie-head { gap: 3px; }
.bookie-head__sides {
  color: var(--twill);
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: .06em;
}
.book-screen .prop-move-head { border-left: 1px solid var(--board-rule); }
.book-screen .mob-odd.best,
.book-screen .over-odds.best,
.book-screen .under-odds.best { background: transparent; color: inherit; font-weight: 400; }

/* ── Narrow widths ────────────────────────────────────────────────── */
/* Below this the nine tiles stop fitting on one line; one scrolling row
   costs 44px, where a wrapped grid cost up to 160px before a single price. */
@media (max-width: 900px) {
  .odds-bookie-strip { display: flex; overflow-x: auto; scrollbar-width: thin; }
  .odds-bookie-choice { flex: 0 0 116px; }
  /* The board scrolls sideways here, so its label columns hold still. */
  .mob-group { --mob-market-w: 104px; --mob-side-w: 66px; }
  .mob-market { position: sticky; left: 0; z-index: 1; }
  .mob-side { position: sticky; left: var(--mob-market-w); z-index: 1; }
  .mob-group--head .mob-market, .mob-group--head .mob-side { background: var(--board-tint); }
}
@media (max-width: 640px) {
  .odds-tool-head { padding: 0 2px; margin-bottom: 14px; }
  .odds-tool-head h1 { font-size: 24px; }
  .odds-tool-head__lede { font-size: 13px; }
  .auto-refresh-toggle__label { font-size: 12px; }
  .odds-workspace { padding: 0 2px 16px; }
  .odds-preference-status { display: none; }
  .odds-bookie-choice { flex-basis: 100px; }
  .odds-bookie-choice img { width: 76px; height: 19px; }
  .match-selector-item { padding: 6px 10px; font-size: 13px; gap: 6px; }
  .match-selector-logo { width: 22px; height: 22px; }
  .odds-section-title { font-size: 17px; }
  .odds-market-panel { max-width: none; }
  .odds-filter-container { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .odds-filter-container .filter-btn:nth-child(4) { border-left: 0; }
  .odds-filter-container .filter-btn:nth-child(n+4) { border-top: 1px solid var(--board-rule); }
  .model-info { margin-left: 0; }
  .model-info > summary { text-align: left; }
  .mob-move { padding: 4px 6px; }
  .table-header,
  .table-row,
  .alt-row {
    grid-template-columns:
      minmax(160px, 1.4fr) 64px 88px 64px 88px
      repeat(var(--bookie-count, 7), minmax(88px, 1fr));
    min-width: calc(464px + var(--bookie-count, 7) * 88px);
  }
  .book-screen .table-header,
  .book-screen .table-row,
  .book-screen .alt-row {
    grid-template-columns: 150px 64px 76px 64px 100px minmax(180px, 1fr);
    min-width: 634px;
  }
  .cell.prop-move { padding: 3px 6px; }
  .header-cell, .cell { padding: 4px 6px; font-size: 12px; }
  .player-team_small { width: 16px; margin-right: 4px; }
  .player-id { gap: 6px; }
  .player-mug { flex-basis: 24px; width: 24px; height: 24px; }
  .player-id__meta .player-team_small { width: 13px; height: 13px; }
  .player-link { font-size: 12.5px; }
  .mob-group { --mob-market-w: 92px; --mob-side-w: 60px; }
  .mob-market { padding: 6px 8px; }
  .mob-market__name { font-size: 12px; }
  .mob-side { padding: 0 6px; font-size: 12px; }
  .book-screen .mob-group { grid-template-columns: var(--mob-market-w) var(--mob-side-w) 64px 72px minmax(150px, 1fr); }
}
