/* ============================================================================
   TRACKR — Global Design Polish v2
   Single source of truth layered on top of every page.

   Design pass v2 (2026-04-26):
   1. Vignette removed — flat backgrounds, no decorative radial overlays
   2. Card depth — one shared shadow/border system, consistent across pages
   3. Tabular numerals — figures align in columns for P&L, odds, stats
   4. 3-colour system — accent (brand), positive (green wins), negative (red losses)
   5. Typography pass — tighter hierarchy, refined letter-spacing
   6. Unified bet card — .bet-card primitive used by all bet displays
   ========================================================================= */

/* ---- Inter font (variable) ---- */
@import url('https://rsms.me/inter/inter.css');

/* ============================================================================
   1. SHARED TOKENS
   ========================================================================= */
:root {
  --ease-out: cubic-bezier(.16,1,.3,1);
  --ease-spring: cubic-bezier(.34,1.56,.64,1);
  --ease-soft: cubic-bezier(.4,0,.2,1);

  /* Unified shadow scale */
  --shadow-xs: 0 1px 1px rgba(0,0,0,.12);
  --shadow-sm: 0 1px 2px rgba(0,0,0,.18), 0 1px 1px rgba(0,0,0,.08);
  --shadow-md: 0 4px 12px rgba(0,0,0,.22), 0 1px 3px rgba(0,0,0,.16);
  --shadow-lg: 0 10px 28px rgba(0,0,0,.32), 0 2px 6px rgba(0,0,0,.18);
  --shadow-glow: 0 0 0 1px var(--accent), 0 6px 22px var(--accent-dim);

  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 16px;

  /* 3-colour system: accent (already in theme) + positive + negative */
  --positive: #3fb950;
  --positive-dim: rgba(63,185,80,.15);
  --positive-text: #56d364;
  --negative: #f85149;
  --negative-dim: rgba(248,81,73,.15);
  --negative-text: #ff7b72;

  /* ──────────────────────────────────────────────────────────────────
     SEMANTIC STATE TOKENS (2026-04-29 v3)

     Single source of truth for colour-by-state. The rule: tan / amber /
     yellow is reserved EXCLUSIVELY for `pending` family states (a bet
     awaiting result, the next race off, awaiting dividend). Every other
     "warning-ish" use that previously stole the amber palette (EW, R4,
     mid-CLV, mid-volume, race-status WAITING, etc) now uses neutral or
     blue/slate so the operator's eye is drawn ONLY to things that need
     attention.

     Naming:
       --state-X      base colour (text, icon, primary stroke)
       --state-X-bg   tinted background (chips, card body wash)
       --state-X-bd   border colour (chip outline, card left strip)
     ────────────────────────────────────────────────────────────────── */

  /* PENDING — the only state allowed to use tan/amber. Reserved. */
  --state-pending:    #fbbf24;          /* amber-400 — operator attention */
  --state-pending-bg: rgba(251,191,36,.10);
  --state-pending-bd: rgba(251,191,36,.35);

  /* AWAITING (awaiting dividend / awaiting reconciliation). Same family
     as pending so the operator scans them as a single visual class. */
  --state-awaiting:    #fbbf24;
  --state-awaiting-bg: rgba(251,191,36,.08);
  --state-awaiting-bd: rgba(251,191,36,.25);

  /* WON — green. */
  --state-won:    var(--positive);
  --state-won-bg: var(--positive-dim);
  --state-won-bd: rgba(63,185,80,.40);

  /* LOST — red. */
  --state-lost:    var(--negative);
  --state-lost-bg: var(--negative-dim);
  --state-lost-bd: rgba(248,81,73,.35);

  /* PLACED — blue (separate from won/lost so the eye reads "partial"). */
  --state-placed:    #58a6ff;
  --state-placed-bg: rgba(88,166,255,.12);
  --state-placed-bd: rgba(88,166,255,.35);

  /* VOID — grey. Calm, no urgency. */
  --state-void:    #8b949e;
  --state-void-bg: rgba(139,148,158,.10);
  --state-void-bd: rgba(139,148,158,.30);

  /* NEUTRAL — for "ok-but-not-special" metrics that previously used
     yellow as a "medium" rating. Use for mid-CLV, mid-volume, etc. */
  --state-neutral:    #c9d1d9;
  --state-neutral-bg: rgba(201,209,217,.06);
  --state-neutral-bd: rgba(201,209,217,.20);

  /* INFO — for non-pending status pills (race-status WAITING, "soft to
     firm", going changes, etc). Cool blue/indigo so it doesn't compete
     with the pending family. */
  --state-info:    #818cf8;            /* indigo-400 */
  --state-info-bg: rgba(129,140,248,.12);
  --state-info-bd: rgba(129,140,248,.35);

  /* WARN-MUTED — only when something is actually broken / R4 deduction
     applied / data quality issue. Muted rose so it's distinct from both
     LOST (urgent red) and PENDING (attention amber). */
  --state-warn:    #f472b6;            /* pink-400, muted */
  --state-warn-bg: rgba(244,114,182,.10);
  --state-warn-bd: rgba(244,114,182,.30);

  /* EW BADGE — was using amber. Now slate-blue: bet type metadata, not
     a state, not pending. */
  --state-ew:    #60a5fa;              /* blue-400 */
  --state-ew-bg: rgba(96,165,250,.10);
  --state-ew-bd: rgba(96,165,250,.30);
}

[data-theme="light"] {
  --shadow-xs: 0 1px 1px rgba(0,0,0,.04);
  --shadow-sm: 0 1px 2px rgba(31,35,40,.06), 0 1px 1px rgba(31,35,40,.04);
  --shadow-md: 0 4px 12px rgba(31,35,40,.08), 0 1px 3px rgba(31,35,40,.06);
  --shadow-lg: 0 10px 28px rgba(31,35,40,.12), 0 2px 6px rgba(31,35,40,.06);
  --positive: #1a7f37;
  --positive-dim: rgba(26,127,55,.10);
  --positive-text: #1a7f37;
  --negative: #cf222e;
  --negative-dim: rgba(207,34,46,.10);
  --negative-text: #cf222e;

  /* Light-theme equivalents — same hue families, deeper tones. */
  --state-pending:    #b45309;          /* amber-700 */
  --state-pending-bg: rgba(180,83,9,.08);
  --state-pending-bd: rgba(180,83,9,.30);
  --state-awaiting:    #b45309;
  --state-awaiting-bg: rgba(180,83,9,.06);
  --state-awaiting-bd: rgba(180,83,9,.20);
  --state-won:    var(--positive);
  --state-won-bg: var(--positive-dim);
  --state-won-bd: rgba(26,127,55,.30);
  --state-lost:    var(--negative);
  --state-lost-bg: var(--negative-dim);
  --state-lost-bd: rgba(207,34,46,.25);
  --state-placed:    #0969da;
  --state-placed-bg: rgba(9,105,218,.08);
  --state-placed-bd: rgba(9,105,218,.30);
  --state-void:    #656d76;
  --state-void-bg: rgba(101,109,118,.08);
  --state-void-bd: rgba(101,109,118,.25);
  --state-neutral:    #1f2328;
  --state-neutral-bg: rgba(31,35,40,.04);
  --state-neutral-bd: rgba(31,35,40,.15);
  --state-info:    #4f46e5;
  --state-info-bg: rgba(79,70,229,.08);
  --state-info-bd: rgba(79,70,229,.30);
  --state-warn:    #be185d;
  --state-warn-bg: rgba(190,24,93,.08);
  --state-warn-bd: rgba(190,24,93,.25);
  --state-ew:    #1f6feb;
  --state-ew-bg: rgba(31,111,235,.08);
  --state-ew-bd: rgba(31,111,235,.25);
}

/* ─── Reusable status pill primitives ─────────────────────────────
   Use these instead of hand-rolling per-component pill styling. The
   .pill class shape; the .pill--<state> modifier paints. */
.pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  line-height: 1.2;
  white-space: nowrap;
  border: 1px solid transparent;
  font-variant-numeric: tabular-nums;
}
.pill--pending  { color: var(--state-pending);  background: var(--state-pending-bg);  border-color: var(--state-pending-bd); }
.pill--awaiting { color: var(--state-awaiting); background: var(--state-awaiting-bg); border-color: var(--state-awaiting-bd); }
.pill--won      { color: var(--state-won);      background: var(--state-won-bg);      border-color: var(--state-won-bd); }
.pill--lost     { color: var(--state-lost);     background: var(--state-lost-bg);     border-color: var(--state-lost-bd); }
.pill--placed   { color: var(--state-placed);   background: var(--state-placed-bg);   border-color: var(--state-placed-bd); }
.pill--void     { color: var(--state-void);     background: var(--state-void-bg);     border-color: var(--state-void-bd); }
.pill--neutral  { color: var(--state-neutral);  background: var(--state-neutral-bg);  border-color: var(--state-neutral-bd); }
.pill--info     { color: var(--state-info);     background: var(--state-info-bg);     border-color: var(--state-info-bd); }
.pill--warn     { color: var(--state-warn);     background: var(--state-warn-bg);     border-color: var(--state-warn-bd); }
.pill--ew       { color: var(--state-ew);       background: var(--state-ew-bg);       border-color: var(--state-ew-bd); }

/* ============================================================================
   2. TYPOGRAPHY (item 5)
   ========================================================================= */
html { -webkit-text-size-adjust: 100%; text-rendering: optimizeLegibility; }
body {
  font-family: 'Inter var', 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif !important;
  font-feature-settings: 'cv11','ss01','ss03','cv02';
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  letter-spacing: -0.005em;
}

h1, h2, h3, h4, .h1, .h2, .h3 {
  letter-spacing: -0.022em;
  font-feature-settings: 'cv11','ss01';
}
h1, .h1 { font-weight: 700; line-height: 1.15; }
h2, .h2 { font-weight: 700; line-height: 1.2; }
h3, .h3 { font-weight: 600; line-height: 1.25; }
h4       { font-weight: 600; line-height: 1.3; }

::selection { background: var(--accent); color: #fff; }

/* ============================================================================
   3. TABULAR NUMERALS (item 3)
   Figures line up in columns — P&L, odds, stats, dates
   ========================================================================= */
.tabular,
.num,
.kpi-value,
.metric-value,
.stat-value,
.bet-pl,
.bet-odds,
.bet-stake,
table td,
table th,
.font-mono,
input[type="number"],
[class*="profit"],
[class*="-pl"],
[class*="-roi"],
[class*="-odds"],
[class*="-stake"] {
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1, 'cv11' 1;
}

/* ============================================================================
   4. NO VIGNETTE (item 1)
   Backgrounds stay flat — no decorative radial gradients on app pages.
   Marketing pages (landing, track-record, wealth) keep theirs locally.
   ========================================================================= */
/* Body radial overlay removed — was creating uneven brightness on dashboards */

/* ============================================================================
   5. CARDS — UNIFIED DEPTH (item 2)
   ========================================================================= */
.card,
.kpi,
.card-elevated {
  box-shadow: var(--shadow-sm);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  transition: transform .25s var(--ease-out),
              box-shadow .25s var(--ease-out),
              border-color .2s;
}
.card:hover,
.card-elevated:hover {
  box-shadow: var(--shadow-md);
  border-color: var(--border-light);
}
.kpi {
  background-image: linear-gradient(180deg, rgba(255,255,255,.012), transparent 40%);
}
[data-theme="light"] .kpi {
  background-image: linear-gradient(180deg, rgba(0,0,0,.012), transparent 40%);
}

/* ============================================================================
   6. BET CARD UNIFIED PRIMITIVE (item 6)
   Used by dashboard live-bets, database table rows, tipster detail.
   Consistent padding, hover, status colour, silk size.
   ========================================================================= */
.bet-card {
  background: var(--bet-card-bg, var(--card));
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 12px 14px;
  transition: background .15s var(--ease-soft),
              border-color .15s,
              transform .15s var(--ease-spring),
              box-shadow .2s;
  display: flex;
  align-items: center;
  gap: 10px;
}
.bet-card:hover {
  background: var(--elevated);
  border-color: var(--border-light);
  box-shadow: var(--shadow-sm);
}

/* Status accent strip on bet cards — left border colour. Bound to the
   semantic state tokens. PENDING gets the only amber colour by design;
   the rest stay calm. WON keeps green, LOST keeps red, PLACED is blue
   so it reads as "partial" not as "won". VOID is grey. */
.bet-card[data-status="won"]     { border-left: 3px solid var(--state-won); }
.bet-card[data-status="lost"]    { border-left: 3px solid var(--state-lost); }
.bet-card[data-status="placed"]  { border-left: 3px solid var(--state-placed); }
.bet-card[data-status="void"]    { border-left: 3px solid var(--state-void); }
.bet-card[data-status="pending"] { border-left: 3px solid var(--state-pending); }
/* Settled card body discipline — strip + result/PL still carry the
   status colour, but the card body itself stays calm so a 30-bet day
   doesn't look like a wall of urgent red. */
.bet-card[data-status="lost"],
.bet-card[data-status="placed"],
.bet-card[data-status="void"],
.bet-card[data-status="won"]     { background: var(--card); }
/* Pending cards keep a very subtle amber wash so they're noticeably
   different from settled cards at a glance — but the wash is small
   enough that 5 pending cards in a row don't feel oppressive. */
.bet-card[data-status="pending"] {
  background: linear-gradient(90deg, var(--state-pending-bg) 0%, var(--card) 60%);
}

/* P&L colour helpers — applied via class to any number element */
.pl-positive, .text-positive { color: var(--positive-text); }
.pl-negative, .text-negative { color: var(--negative-text); }
.pl-neutral,  .text-neutral  { color: var(--muted); }

/* ============================================================================
   7. SCROLLBAR / FOCUS / FORM STATES
   ========================================================================= */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--border);
  border-radius: 10px;
  border: 2px solid transparent;
  background-clip: padding-box;
  transition: background .2s;
}
::-webkit-scrollbar-thumb:hover { background: var(--muted); background-clip: padding-box; }
* { scrollbar-color: var(--border) transparent; scrollbar-width: thin; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}
button:focus-visible, a:focus-visible, [role="button"]:focus-visible {
  box-shadow: 0 0 0 3px var(--accent-dim);
}
input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: none;
  border-color: var(--accent) !important;
  box-shadow: 0 0 0 3px var(--accent-dim);
}

input, select, textarea {
  transition: border-color .15s, box-shadow .15s, background .2s;
}

input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
input:-webkit-autofill:active,
textarea:-webkit-autofill,
select:-webkit-autofill {
  -webkit-text-fill-color: var(--text) !important;
  -webkit-box-shadow: 0 0 0 1000px var(--elevated) inset !important;
  caret-color: var(--text) !important;
  border-color: var(--border) !important;
  transition: background-color 9999s ease-in-out 0s, color 9999s ease-in-out 0s;
}

/* ============================================================================
   8. BUTTONS
   ========================================================================= */
.btn, button.btn, a.btn {
  transition: transform .15s var(--ease-spring), box-shadow .2s, background .2s, color .2s, border-color .2s, filter .2s;
  will-change: transform;
}
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(0) scale(.98); }
.btn-primary {
  box-shadow: 0 4px 14px var(--accent-dim);
}
.btn-primary:hover {
  box-shadow: 0 6px 20px var(--accent-dim), 0 0 0 1px var(--accent);
  filter: brightness(1.05);
}
.btn-primary:active { box-shadow: 0 2px 6px var(--accent-dim); }

/* ============================================================================
   9. TABLES — zebra, sticky header, hover
   ========================================================================= */
.tbl thead th, table thead th {
  position: sticky; top: 0;
  background: var(--card);
  backdrop-filter: blur(6px);
  z-index: 1;
  font-variant-numeric: tabular-nums;
}
.tbl tbody tr, table tbody tr { transition: background .12s; }
.tbl tbody tr:hover, table tbody tr:hover { background: var(--elevated); }

/* ============================================================================
   10. STATUS BADGES (using 3-colour system)
   ========================================================================= */
.badge-won, .pill-won, .status-won,
[data-status="won"] .status-pill {
  color: var(--positive-text);
  background: var(--positive-dim);
  border: 1px solid var(--positive);
}
.badge-lost, .pill-lost, .status-lost,
[data-status="lost"] .status-pill {
  color: var(--negative-text);
  background: var(--negative-dim);
  border: 1px solid var(--negative);
}
.badge-placed, .pill-placed, .status-placed {
  color: var(--accent);
  background: var(--accent-dim);
  border: 1px solid var(--accent);
}
.badge-pending, .pill-pending, .status-pending {
  color: var(--muted);
  background: var(--elevated);
  border: 1px solid var(--border);
}

.verified, .badge, .pill, .chip {
  transition: transform .15s var(--ease-spring), box-shadow .2s;
}

/* ============================================================================
   11. SKELETON LOADERS
   ========================================================================= */
@keyframes trackrShimmer {
  0% { background-position: -400px 0; }
  100% { background-position: 400px 0; }
}
.skeleton, .shimmer {
  background: linear-gradient(90deg, var(--elevated) 0%, var(--border) 40%, var(--elevated) 80%);
  background-size: 800px 100%;
  animation: trackrShimmer 1.4s linear infinite;
  border-radius: 8px;
}

/* ============================================================================
   12. ENTRANCE ANIMATION
   ========================================================================= */
@keyframes trackrFadeUp {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
.card, .kpi, .hero, .grid > * {
  animation: trackrFadeUp .45s var(--ease-out) both;
}
.grid > *:nth-child(1) { animation-delay: 0ms; }
.grid > *:nth-child(2) { animation-delay: 40ms; }
.grid > *:nth-child(3) { animation-delay: 80ms; }
.grid > *:nth-child(4) { animation-delay: 120ms; }
.grid > *:nth-child(5) { animation-delay: 160ms; }
.grid > *:nth-child(6) { animation-delay: 200ms; }

/* ============================================================================
   13. ACCENT STRIPE (nav bottom)
   ========================================================================= */
.accent-stripe, .stripe, .trackr-accent-stripe {
  background: linear-gradient(90deg, transparent, var(--accent) 25%, var(--accent) 75%, transparent) !important;
  position: relative;
}
.accent-stripe::after, .stripe::after, .trackr-accent-stripe::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, var(--accent-dim) 50%, transparent);
  filter: blur(6px);
  opacity: .8;
  pointer-events: none;
}

/* ============================================================================
   14. NAV / LINKS
   ========================================================================= */
.nav { box-shadow: 0 1px 0 var(--border), 0 4px 16px rgba(0,0,0,.08); }
.nav-link { transition: color .15s, background .15s, transform .15s; }
.nav-link:hover { transform: translateY(-1px); }

a:not(.btn):not(.nav-link):not(.brand):not([class*="badge"]):hover {
  text-decoration-color: var(--accent);
}

/* TRACKR brand mark — used in shared nav (_nav.html) and dashboard nav.
   PNG is 720x260; lock height, let width scale proportionally. */
.trackr-nav-logo {
  height: 26px;
  width: auto;
  display: block;
  object-fit: contain;
  user-select: none;
  -webkit-user-drag: none;
}
@media (max-width: 480px) {
  .trackr-nav-logo { height: 22px; }
}

/* ============================================================================
   15. ACCESSIBILITY — reduced motion (strengthened Apr 2026)
   ========================================================================= */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ============================================================================
   16. THEMED DIALOG (TrackrUI.confirm / .alert) — used everywhere instead
       of native window.confirm / window.alert. Lives in trackr-ui.js.
   ========================================================================= */
.trackr-dialog-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(4px);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 9999;
  opacity: 0;
  pointer-events: none;
  transition: opacity .18s var(--ease-out, ease-out);
}
.trackr-dialog-overlay.open {
  opacity: 1;
  pointer-events: auto;
}
.trackr-dialog {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 20px 22px;
  max-width: 420px;
  width: calc(100vw - 32px);
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.4);
  transform: translateY(8px) scale(0.98);
  transition: transform .18s var(--ease-out, ease-out);
}
.trackr-dialog-overlay.open .trackr-dialog {
  transform: translateY(0) scale(1);
}
.trackr-dialog-title {
  font-size: 16px;
  font-weight: 700;
  color: var(--text);
  margin: 0 0 10px;
}
.trackr-dialog-body {
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--muted);
  margin-bottom: 18px;
  white-space: pre-wrap;
}
.trackr-dialog-actions {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
}
.trackr-dialog-btn {
  padding: 8px 16px;
  border-radius: 8px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  border: 1px solid var(--border);
  background: var(--elevated);
  color: var(--text);
  transition: all .15s ease;
}
.trackr-dialog-btn:hover {
  border-color: var(--border-light, var(--border));
  background: var(--card);
}
.trackr-dialog-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.trackr-dialog-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #0a1610;
}
.trackr-dialog-primary:hover {
  filter: brightness(1.08);
  background: var(--accent);
  border-color: var(--accent);
}
.trackr-dialog-danger {
  background: rgba(248, 81, 73, 0.92);
  border-color: rgba(248, 81, 73, 1);
  color: #fff;
}
.trackr-dialog-danger:hover {
  filter: brightness(1.08);
  background: rgba(248, 81, 73, 1);
  border-color: rgba(248, 81, 73, 1);
}

/* Async-button pending dot (TrackrUI.runAsync) */
.trackr-btn-pending {
  display: inline-block;
  animation: trackrBtnPulse 1s ease-in-out infinite;
}
@keyframes trackrBtnPulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: 0.4; transform: scale(0.8); }
}
@media (prefers-reduced-motion: reduce) {
  .trackr-btn-pending { animation: none; }
}

/* ============================================================================
   17. NATIVE SELECT STYLING (item 14)
   Cross-browser: replace ugly native arrow with consistent chevron.
   ========================================================================= */
select {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  background-color: var(--elevated);
  background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%238b949e' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'/%3e%3c/svg%3e");
  background-repeat: no-repeat;
  background-position: right 10px center;
  background-size: 12px;
  padding-right: 30px !important;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  cursor: pointer;
}
select:hover { border-color: var(--border-light); }
select::-ms-expand { display: none; }
select option {
  background: var(--card);
  color: var(--text);
}

/* ============================================================================
   18. SKELETON POLISH (item 18)
   Already-defined .skeleton/.shimmer — add more presets.
   ========================================================================= */
.skeleton-text  { height: 1em; width: 100%; margin: 4px 0; }
.skeleton-line  { height: 12px; border-radius: 4px; margin: 6px 0; }
.skeleton-pill  { height: 22px; width: 70px; border-radius: 11px; }
.skeleton-card  { height: 64px; border-radius: var(--radius-md); margin-bottom: 8px; }
.skeleton-circle{ width: 32px; height: 32px; border-radius: 50%; }

/* ============================================================================
   19. REFRESH BUTTON SPINNER (item 19)
   Add `data-loading="true"` to any refresh button to spin its child SVG.
   ========================================================================= */
@keyframes trackrSpin { to { transform: rotate(360deg); } }
[data-loading="true"] svg,
button.is-refreshing svg,
.refresh-btn.is-refreshing svg {
  animation: trackrSpin .8s linear infinite;
  transform-origin: 50% 50%;
}
[data-loading="true"] {
  pointer-events: none;
  opacity: 0.7;
}

/* Tooltip primitive for refresh + other icon-only buttons */
[data-tooltip] { position: relative; }
[data-tooltip]::after {
  content: attr(data-tooltip);
  position: absolute;
  bottom: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%) translateY(2px);
  background: var(--elevated);
  color: var(--text);
  font-size: 11px;
  font-weight: 500;
  padding: 4px 8px;
  border-radius: 6px;
  border: 1px solid var(--border);
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity .15s var(--ease-soft), transform .15s var(--ease-out);
  z-index: 1000;
  box-shadow: var(--shadow-sm);
}
[data-tooltip]:hover::after,
[data-tooltip]:focus-visible::after {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* ============================================================================
   20. SETTINGS GROUP SPACING (item 20)
   Consistent vertical rhythm for label/control pairs in settings panels.
   ========================================================================= */
.settings-group {
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.settings-row {
  display: grid;
  grid-template-columns: minmax(140px, 1fr) 2fr;
  gap: 16px;
  align-items: center;
  padding: 12px 0;
  border-bottom: 1px solid var(--border);
}
.settings-row:last-child { border-bottom: none; }
.settings-row label {
  font-size: 13px;
  font-weight: 500;
  color: var(--text);
}
.settings-row .hint {
  font-size: 11px;
  color: var(--muted);
  margin-top: 2px;
}
.settings-section {
  margin-bottom: 28px;
}
.settings-section h3 {
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  margin: 0 0 10px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border-light);
}

/* ============================================================================
   21. EMPTY STATES (item 11)
   Centered, friendly, with optional icon.
   ========================================================================= */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 32px 16px;
  text-align: center;
  color: var(--muted);
  gap: 8px;
}
.empty-state .empty-icon {
  font-size: 28px;
  opacity: 0.6;
  margin-bottom: 4px;
}
.empty-state .empty-title {
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
}
.empty-state .empty-msg {
  font-size: 12px;
  color: var(--muted);
  max-width: 320px;
}
.empty-state .empty-action {
  margin-top: 12px;
}

/* Inline (compact) variant for table rows / small containers */
.empty-state-inline {
  padding: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  color: var(--muted);
  font-size: 13px;
}

/* ============================================================================
   22. MOBILE COMPACTION
   ========================================================================= */
@media (max-width: 640px) {
  h1, .h1 { font-size: clamp(22px, 6vw, 28px) !important; }
  h2, .h2 { font-size: clamp(18px, 5vw, 22px) !important; }
  .card, .kpi { border-radius: 12px; }
  .bet-card { padding: 10px 12px; gap: 8px; }
}

/* ============================================================================
   23. GLOBAL DESIGN SYSTEM PRIMITIVES (added 2026-04-28)
   All `tk-*` prefixed classes are namespaced shared primitives. Use these
   in NEW components to guarantee dark/light mode parity and consistent
   motion. Existing inline styles on individual pages remain — these are
   additive, not a forced replacement.

   Animation tokens are reused from earlier blocks (--ease-out, --ease-spring,
   --shadow-*, --radius-*).
   ========================================================================= */

/* ---- Segmented control ---- */
.tk-seg {
  display: inline-flex;
  background: var(--elevated);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 3px;
  gap: 2px;
  flex-wrap: nowrap;
}
.tk-seg-btn {
  background: transparent;
  border: none;
  color: var(--muted);
  font-size: 12px;
  font-weight: 600;
  padding: 6px 12px;
  border-radius: 7px;
  cursor: pointer;
  transition: background .15s var(--ease-out, ease-out), color .15s, transform .12s var(--ease-spring, ease-out);
  white-space: nowrap;
  font: inherit; /* respect inherited font-family */
  font-weight: 600;
  font-size: 12px;
  line-height: 1;
}
.tk-seg-btn:hover { color: var(--text); }
.tk-seg-btn:active { transform: scale(.97); }
.tk-seg-btn.active {
  background: var(--card);
  color: var(--text);
  box-shadow: var(--shadow-xs);
}
[data-theme="light"] .tk-seg-btn.active { box-shadow: 0 1px 2px rgba(31,35,40,.06); }

/* ---- Filter chip with built-in close button ---- */
.tk-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--elevated);
  border: 1px solid var(--border);
  color: var(--text);
  font-size: 11.5px;
  font-weight: 600;
  padding: 4px 6px 4px 10px;
  border-radius: 999px;
  transition: background .12s, border-color .12s;
  animation: trackrFadeUp .18s var(--ease-out, ease-out);
}
.tk-chip:hover { border-color: var(--border-light); }
.tk-chip .tk-chip-key {
  color: var(--muted);
  font-weight: 500;
  margin-right: 2px;
}
.tk-chip-close {
  background: transparent;
  border: none;
  cursor: pointer;
  color: var(--muted);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px; height: 18px;
  border-radius: 50%;
  transition: background .12s, color .12s;
}
.tk-chip-close:hover { background: var(--border); color: var(--text); }

.tk-clear-all {
  background: transparent;
  border: none;
  color: var(--muted);
  font-size: 11.5px;
  font-weight: 600;
  cursor: pointer;
  padding: 4px 8px;
  border-radius: 8px;
  transition: color .12s, background .12s;
  font-family: inherit;
}
.tk-clear-all:hover { color: var(--negative-text); background: var(--negative-dim); }

/* ---- Filter toolbar ---- */
.tk-toolbar {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.tk-toolbar-row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.tk-toolbar-label {
  font-size: 10px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 600;
  min-width: 56px;
}

/* ---- Polished search input ---- */
.tk-search {
  position: relative;
  flex: 1;
  min-width: 160px;
  max-width: 280px;
}
.tk-search > svg {
  position: absolute; left: 10px; top: 50%; transform: translateY(-50%);
  color: var(--subtle); width: 14px; height: 14px;
  pointer-events: none;
}
.tk-search input {
  width: 100%;
  background: var(--elevated);
  border: 1px solid var(--border);
  border-radius: 10px;
  color: var(--text);
  padding: 7px 10px 7px 32px;
  font-size: 12.5px;
  font-weight: 500;
  height: 36px;
  outline: none;
  transition: border-color .15s, box-shadow .15s;
  font-family: inherit;
}
.tk-search input::placeholder { color: var(--subtle); }
.tk-search input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-dim);
}

/* ---- Custom select (matches search/seg height) ---- */
.tk-select {
  background: var(--elevated);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 7px 30px 7px 12px;
  font-size: 12.5px;
  font-weight: 500;
  outline: none;
  cursor: pointer;
  transition: border-color .15s, box-shadow .15s;
  height: 36px;
  min-width: 140px;
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  background-repeat: no-repeat;
  background-position: right 8px center;
  background-size: 14px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238b949e' stroke-width='2'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M19 9l-7 7-7-7'/%3E%3C/svg%3E");
  font-family: inherit;
}
.tk-select:hover { border-color: var(--border-light); }
.tk-select:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-dim);
}

/* ---- Drawer (right-side panel + bottom sheet variant) ---- */
.tk-drawer-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.55);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  z-index: 60;
  opacity: 0;
  pointer-events: none;
  transition: opacity .18s var(--ease-out, ease-out);
}
.tk-drawer-overlay.open {
  opacity: 1;
  pointer-events: auto;
}
.tk-drawer {
  background: var(--card);
  border-left: 1px solid var(--border);
  box-shadow: -10px 0 28px rgba(0,0,0,.32);
  height: 100%;
  width: 100%;
  max-width: 520px;
  margin-left: auto;
  display: flex;
  flex-direction: column;
  transform: translateX(24px);
  transition: transform .24s var(--ease-out, ease-out);
}
.tk-drawer-overlay.open .tk-drawer { transform: translateX(0); }

.tk-drawer-header {
  padding: 16px 18px;
  border-bottom: 1px solid var(--border);
  background: var(--card);
  position: sticky; top: 0; z-index: 5;
}
.tk-drawer-body { flex: 1; overflow-y: auto; padding: 0; }
.tk-drawer-footer {
  padding: 12px 18px;
  border-top: 1px solid var(--border);
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.tk-drawer-close {
  width: 32px; height: 32px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 8px;
  background: transparent;
  border: 1px solid var(--border);
  color: var(--muted);
  cursor: pointer;
  transition: background .12s, color .12s;
}
.tk-drawer-close:hover { background: var(--elevated); color: var(--text); }

/* ---- Modal (centered) ---- */
.tk-modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.55);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  opacity: 0;
  pointer-events: none;
  transition: opacity .18s var(--ease-out, ease-out);
}
.tk-modal-overlay.open { opacity: 1; pointer-events: auto; }
.tk-modal {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: var(--shadow-lg);
  width: 100%;
  max-width: 480px;
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  transform: translateY(8px) scale(.98);
  transition: transform .2s var(--ease-out, ease-out);
}
.tk-modal-overlay.open .tk-modal { transform: translateY(0) scale(1); }
.tk-modal-header {
  padding: 16px 18px;
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.tk-modal-body { flex: 1; overflow-y: auto; padding: 16px 18px; }
.tk-modal-footer {
  padding: 12px 18px;
  border-top: 1px solid var(--border);
  display: flex;
  gap: 8px;
  justify-content: flex-end;
}

/* ---- Unified odds-display block ----
   Use as: <span class="tk-odds tk-odds--steam">2.85 ↓+8%</span>
   Variants: --steam (positive/shortening), --drift (negative/lengthening),
            --flat (neutral), --pending (no live yet). */
.tk-odds {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 9px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 700;
  border: 1px solid var(--border);
  background: var(--elevated);
  color: var(--text);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
  white-space: nowrap;
  transition: background .2s, border-color .2s, transform .15s var(--ease-spring, ease-out);
}
.tk-odds--steam   { color: var(--positive-text); background: var(--positive-dim); border-color: var(--positive); }
.tk-odds--drift   { color: var(--negative-text); background: var(--negative-dim); border-color: var(--negative); }
.tk-odds--flat    { color: var(--text); background: var(--elevated); border-color: var(--border); }
.tk-odds--pending { color: var(--muted); background: var(--elevated); border-color: var(--border); border-style: dashed; }
.tk-odds--bog     { color: var(--positive-text); background: var(--positive-dim); border-color: var(--positive); border-width: 1.5px; }

.tk-odds-label {
  font-size: 9px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .07em;
  opacity: .82;
}
.tk-odds-value { font-weight: 700; }
.tk-odds-move {
  font-size: 10px;
  font-weight: 600;
  opacity: .85;
}
.tk-odds-live-dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: currentColor;
  animation: tkLiveDotPulse 1.6s ease-in-out infinite;
}
@keyframes tkLiveDotPulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: .35; transform: scale(.78); }
}
@media (prefers-reduced-motion: reduce) {
  .tk-odds-live-dot { animation: none; opacity: .9; }
}

/* ---- Odds row (groups multiple .tk-odds together cleanly) ---- */
.tk-odds-row {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  font-variant-numeric: tabular-nums;
}

/* ---- Compact sparkline (bet price tracking graph) ---- */
.tk-sparkline {
  display: inline-block;
  width: 36px;
  height: 14px;
  vertical-align: middle;
  opacity: .85;
}
.tk-sparkline polyline { stroke-linejoin: round; stroke-linecap: round; }
@media (max-width: 639px) {
  .tk-sparkline { width: 28px; height: 12px; }
}

/* ---- Page header (consistent across all pages) ---- */
.tk-page-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 18px;
}
.tk-page-title {
  font-size: clamp(20px, 3vw, 26px);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.15;
}
.tk-page-subtitle {
  font-size: 13px;
  color: var(--muted);
  margin-top: 4px;
  font-weight: 500;
}
.tk-page-actions {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
}

/* ---- Standardised hover for cards (subtle) ---- */
.tk-card-hover {
  transition: transform .14s var(--ease-out, ease-out), box-shadow .16s, border-color .16s;
}
.tk-card-hover:hover {
  transform: translateY(-1px);
  box-shadow: var(--shadow-md);
  border-color: var(--border-light);
}

/* ---- Themed select wrapper for legacy <select>s ---- */
/* Pages that wrap a native select in `.tk-select-wrap` get the same
   chevron + height as .tk-select without changing the underlying markup. */
.tk-select-wrap {
  position: relative;
  display: inline-block;
}
.tk-select-wrap select {
  background: var(--elevated);
  height: 36px;
  border-radius: 10px;
  padding: 7px 30px 7px 12px;
  font-size: 12.5px;
}

/* ============================================================================
   24. PRICE-CHANGE FLASH ANIMATIONS (for live odds value)
   Steam = price shortening = good = green flash (subtle).
   Drift = price lengthening = bad = red flash (subtle).
   ========================================================================= */
@keyframes tkOddsFlashSteam {
  0%   { background-color: transparent; }
  20%  { background-color: var(--positive-dim); box-shadow: 0 0 0 2px var(--positive-dim); }
  100% { background-color: transparent; box-shadow: none; }
}
@keyframes tkOddsFlashDrift {
  0%   { background-color: transparent; }
  20%  { background-color: var(--negative-dim); box-shadow: 0 0 0 2px var(--negative-dim); }
  100% { background-color: transparent; box-shadow: none; }
}
.tk-odds-flash-steam { animation: tkOddsFlashSteam 1.2s ease-out 1; }
.tk-odds-flash-drift { animation: tkOddsFlashDrift 1.2s ease-out 1; }
@media (prefers-reduced-motion: reduce) {
  .tk-odds-flash-steam, .tk-odds-flash-drift { animation: none; }
}

/* ============================================================================
   25. PERCEIVED-PERFORMANCE TWEAKS
   - Reduce layout shift on cards waiting for data: min-height-aware skeletons
   - Defer non-critical animation-delay stagger when there are many siblings
   - Restrict animations on tables with >50 rows to avoid jank
   ========================================================================= */
.skeleton[data-min-h] { min-height: var(--min-h, 64px); }

/* Stop the .grid > * stagger getting silly past 8 items — diminishing returns
   and on big lists the cumulative delay is noticeable. */
.grid > *:nth-child(n+9) { animation-delay: 240ms !important; }

/* Tables with many rows: don't run fade-up on each row */
table.tk-no-row-anim tbody tr { animation: none; }

/* ============================================================================
   26. VISIBLE POLISH PASS (added 2026-04-28)
   Concrete improvements you'll see on first hard-refresh. Keeps existing
   markup unchanged — these styles enhance shared classes already in use
   across the app.
   ========================================================================= */

/* Bet card refinement — slightly tighter borders, gentler hover lift, and
   a soft inner highlight on the top edge so cards feel layered. Replaces
   the previous flat-then-dim hover with something more deliberate. */
.bet-card {
  position: relative;
}
.bet-card::before {
  content: '';
  position: absolute;
  top: 0; left: 12px; right: 12px;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.06), transparent);
  pointer-events: none;
  border-radius: 1px;
}
[data-theme="light"] .bet-card::before {
  background: linear-gradient(90deg, transparent, rgba(0,0,0,.04), transparent);
}
.bet-card:hover {
  border-color: var(--border-light);
  background: var(--elevated);
  transform: translateY(-1px);
  box-shadow: var(--shadow-sm);
}

/* Pending bet card on the dashboard — give it a calm, dedicated look so
   pending vs settled is unmistakable at a glance. The status accent strip
   on the LEFT (.bet-card[data-status="pending"]) is already there; we add
   a subtle panel tint here. */
.bet-card[data-status="pending"],
[data-status="pending"].bet-card {
  background: var(--bet-card-bg, var(--card));
}

/* Live-odds block — give it a tiny inner-shadow so it visibly sits on top
   of the bet card instead of looking flat. Plus tighter padding. */
.tk-odds {
  padding: 4px 10px;
  box-shadow: inset 0 0 0 1px transparent;
  transition: background .2s, border-color .2s, box-shadow .2s, transform .15s var(--ease-spring, ease-out);
}
.tk-odds:hover { transform: translateY(-1px); }
.tk-odds--steam { box-shadow: inset 0 0 0 1px rgba(63,185,80,.10); }
.tk-odds--drift { box-shadow: inset 0 0 0 1px rgba(248,81,73,.10); }
[data-theme="light"] .tk-odds--steam { box-shadow: inset 0 0 0 1px rgba(26,127,55,.10); }
[data-theme="light"] .tk-odds--drift { box-shadow: inset 0 0 0 1px rgba(207,34,46,.10); }

/* Page header polish — when a page uses .tk-page-header we get a hairline
   accent strip below the title row, picking up the brand colour subtly. */
.tk-page-header {
  position: relative;
  padding-bottom: 16px;
}
.tk-page-header::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1px;
  background: linear-gradient(90deg, var(--accent-dim), transparent 60%);
  opacity: .6;
}

/* Card entrance: small overshoot easing instead of flat ease-out — feels
   alive without being bouncy. Already wired to fade-up animation. */
@keyframes trackrFadeUpRefined {
  0%   { opacity: 0; transform: translateY(8px); }
  60%  { opacity: 1; transform: translateY(-2px); }
  100% { opacity: 1; transform: translateY(0); }
}
.card, .kpi {
  animation-name: trackrFadeUpRefined;
  animation-duration: .42s;
  animation-timing-function: var(--ease-out);
  animation-fill-mode: both;
}

/* Drawer / modal — softer overlay blur so the content underneath stays
   recognisable but unfocused. */
.tk-drawer-overlay,
.tk-modal-overlay,
.trackr-dialog-overlay,
.modal-overlay {
  backdrop-filter: blur(6px) saturate(.95);
  -webkit-backdrop-filter: blur(6px) saturate(.95);
}

/* Better-feeling button defaults that don't override .btn-primary etc */
.btn, button.btn, a.btn {
  border-radius: var(--radius-sm);
  font-weight: 600;
  letter-spacing: -0.005em;
}

/* Row-density toggle helper — pages can opt-in by adding `.tk-dense` to a
   table to tighten cells without rewriting the markup. */
table.tk-dense th,
table.tk-dense td { padding: 8px 10px !important; font-size: 12.5px !important; }

/* ============================================================================
   TRACKR shared design system — buttons, modals, segmented controls, inputs.
   Added 2026-04-29 as part of the Edit Bet modal overhaul + button audit.

   These classes replace bespoke per-modal styling so every dialog across the
   site shares one visual language. Pages that haven't been retrofitted yet
   keep working — the new classes are additive, not breaking.

   All tokens are theme-aware via existing CSS custom properties — no
   hardcoded blues, no white backgrounds in dark mode, no leaked Twitter-
   blue rgba(29,155,240,…) anywhere.
   ============================================================================ */

/* ---- Buttons ---- */
.tk-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 9px 16px; min-height: 38px;
  border-radius: 10px;
  border: 1px solid transparent;
  font-size: 13px; font-weight: 600; line-height: 1;
  letter-spacing: -0.005em;
  cursor: pointer;
  transition: background-color 0.15s ease, border-color 0.15s ease,
              color 0.15s ease, transform 0.08s ease, box-shadow 0.15s ease;
  white-space: nowrap;
  user-select: none;
}
.tk-btn:active:not(:disabled) { transform: scale(0.97); }
.tk-btn:disabled { opacity: 0.55; cursor: not-allowed; }
.tk-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.tk-btn svg { width: 14px; height: 14px; flex-shrink: 0; }

.tk-btn--primary {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
  box-shadow: 0 1px 2px rgba(63, 185, 80, 0.18);
}
.tk-btn--primary:hover:not(:disabled) { filter: brightness(1.08); box-shadow: 0 4px 12px rgba(63, 185, 80, 0.25); }

.tk-btn--secondary {
  background: var(--elevated);
  color: var(--text);
  border-color: var(--border);
}
.tk-btn--secondary:hover:not(:disabled) {
  background: var(--card);
  border-color: var(--accent-dim, rgba(63,185,80,0.20));
}

.tk-btn--danger {
  background: rgba(248, 81, 73, 0.10);
  color: var(--negative-text, #ff7b72);
  border-color: rgba(248, 81, 73, 0.28);
}
.tk-btn--danger:hover:not(:disabled) {
  background: rgba(248, 81, 73, 0.16);
  border-color: rgba(248, 81, 73, 0.42);
}

.tk-btn--ghost {
  background: transparent; color: var(--muted); border-color: transparent;
}
.tk-btn--ghost:hover:not(:disabled) { background: var(--elevated); color: var(--text); }

.tk-btn--sm { padding: 6px 11px; min-height: 30px; font-size: 12px; border-radius: 8px; }
.tk-btn--lg { padding: 11px 20px; min-height: 44px; font-size: 14px; border-radius: 12px; }
.tk-btn--block { width: 100%; }

/* Loading + success states (toggle via data-loading / data-success) */
.tk-btn[data-loading] { pointer-events: none; position: relative; color: transparent !important; }
.tk-btn[data-loading]::after {
  content: ''; position: absolute; top: 50%; left: 50%;
  width: 14px; height: 14px; margin: -7px 0 0 -7px;
  border: 2px solid #fff; border-top-color: transparent;
  border-radius: 50%; animation: tkBtnSpin 0.7s linear infinite;
}
.tk-btn--secondary[data-loading]::after,
.tk-btn--ghost[data-loading]::after { border-color: var(--text); border-top-color: transparent; }
.tk-btn--danger[data-loading]::after { border-color: var(--negative-text, #ff7b72); border-top-color: transparent; }
@keyframes tkBtnSpin { to { transform: rotate(360deg); } }
.tk-btn[data-success] {
  background: var(--positive-dim) !important;
  color: var(--positive-text) !important;
  border-color: rgba(63, 185, 80, 0.35) !important;
  pointer-events: none;
}

/* ---- Inputs / selects — DARK THEME by default, light theme inherits via tokens.
   Critical: NO white backgrounds. All form fields use --elevated which is
   #1c2333 in dark mode and #f0f3f6 in light mode. Browsers' default white
   inputs get explicitly overridden.
*/
.tk-input,
.tk-input:focus {
  background: var(--elevated);
  color: var(--text);
}
.tk-input {
  width: 100%;
  padding: 10px 12px;
  border-radius: 10px;
  border: 1px solid var(--border);
  font-size: 13px;
  line-height: 1.4;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  /* color-scheme tells the browser to render its native UI (date/time
     pickers, autofill, dropdown chevron) in the matching theme so we
     don't get white pickers on dark inputs. */
  color-scheme: dark light;
}
.tk-input::placeholder { color: var(--muted); opacity: 0.6; }
.tk-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-dim, rgba(63,185,80,0.16));
}
.tk-input--accent {
  border-color: rgba(63,185,80,0.40);
  box-shadow: 0 0 0 1px rgba(63,185,80,0.10);
}
.tk-input--accent:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-dim, rgba(63,185,80,0.20));
}
/* Compact variant — used inside leg-edit cards where vertical space matters */
.tk-input--sm {
  padding: 6px 9px;
  font-size: 12px;
  border-radius: 8px;
  font-variant-numeric: tabular-nums;
}

/* ---- Leg edit card (modal — settled & pending DOUBLE/TREBLE/TRIXIE) ---- */
.leg-edit-card {
  background: var(--elevated);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  transition: border-color 0.15s ease;
}
.leg-edit-card:hover { border-color: var(--border-light, var(--border)); }
.leg-edit-card__header {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}
.leg-edit-card__num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 22px; height: 22px;
  border-radius: 999px;
  background: rgba(63,185,80,0.15);
  color: var(--accent);
  border: 1px solid rgba(63,185,80,0.30);
  font-size: 10px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.leg-edit-card__horse {
  font-weight: 600;
  font-size: 13px;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex: 1 1 auto;
  min-width: 0;
}
.leg-edit-card__meta {
  font-size: 10px;
  color: var(--subtle);
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
}
.leg-edit-card__odds {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}
.leg-settlement-grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1.4fr;
  gap: 8px;
  padding-top: 8px;
  border-top: 1px dashed var(--border);
}
@media (max-width: 480px) {
  .leg-edit-card__odds { grid-template-columns: 1fr; }
  .leg-settlement-grid { grid-template-columns: 1fr 1fr; }
  .leg-settlement-grid > div:nth-child(3) { grid-column: 1 / -1; }
  .leg-edit-card__meta { display: none; }
}
/* Native date/time/number-spin styling in webkit — keep dark */
.tk-input::-webkit-calendar-picker-indicator { filter: invert(0.6); cursor: pointer; }
[data-theme="light"] .tk-input::-webkit-calendar-picker-indicator { filter: none; }
.tk-input::-webkit-inner-spin-button,
.tk-input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }

/* Select chevron — drawn via SVG-as-background since native <select>
   chevrons stay system-coloured. */
select.tk-input {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%238b949e' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
  background-repeat: no-repeat;
  background-position: right 10px center;
  padding-right: 32px;
  cursor: pointer;
}

.tk-label {
  display: block;
  font-size: 10px; font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 6px;
}
.tk-label--accent { color: var(--accent); }
.tk-label-row { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; }
.tk-hint {
  font-size: 9px; color: var(--muted);
  margin-top: 4px;
  text-transform: uppercase; letter-spacing: 0.06em;
}

/* ---- Segmented control (used for result selector etc.) ---- */
.tk-segmented {
  display: flex;
  background: var(--elevated);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
}
.tk-segmented-btn {
  flex: 1; min-width: 0;
  padding: 9px 8px;
  background: transparent; border: 0;
  border-left: 1px solid var(--border);
  color: var(--muted);
  font-size: 11px; font-weight: 700;
  letter-spacing: 0.05em; text-transform: uppercase;
  cursor: pointer; white-space: nowrap;
  transition: background 0.15s ease, color 0.15s ease;
}
.tk-segmented-btn:first-child { border-left: 0; }
.tk-segmented-btn:hover { background: var(--card); color: var(--text); }
.tk-segmented-btn.is-active,
.tk-segmented-btn[aria-pressed="true"] {
  background: var(--accent-dim, rgba(63,185,80,0.16));
  color: var(--accent);
}
.tk-segmented-btn--won.is-active    { background: var(--positive-dim); color: var(--positive-text); }
.tk-segmented-btn--placed.is-active { background: rgba(245, 158, 11, 0.16); color: #fbbf24; }
.tk-segmented-btn--lost.is-active   { background: var(--negative-dim); color: var(--negative-text); }
.tk-segmented-btn--void.is-active   { background: rgba(148,163,184,0.16); color: #94a3b8; }
@media (max-width: 639px) {
  .tk-segmented-btn { padding: 10px 6px; font-size: 10px; }
}

/* ---- Modal / drawer / bottom sheet ---- */
.tk-modal {
  position: fixed; inset: 0; z-index: 50;
  display: flex; align-items: center; justify-content: center;
  padding: 16px;
  background: rgba(0,0,0,0.55);
  backdrop-filter: blur(6px) saturate(0.95);
  -webkit-backdrop-filter: blur(6px) saturate(0.95);
}
.tk-modal.hidden { display: none !important; }
.tk-modal-card {
  width: 100%; max-width: 480px;
  max-height: 92vh;
  display: flex; flex-direction: column;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 16px;
  box-shadow: 0 24px 60px -12px rgba(0,0,0,0.55);
  animation: tkModalSlideIn 0.22s cubic-bezier(0.16, 1, 0.3, 1);
  overflow: hidden;
}
.tk-modal-card--md { max-width: 560px; }
.tk-modal-card--lg { max-width: 720px; }
@keyframes tkModalSlideIn {
  from { opacity: 0; transform: translateY(8px) scale(0.985); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
.tk-modal-header {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 16px 20px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.tk-modal-title {
  font-size: 15px; font-weight: 700; color: var(--text);
  letter-spacing: -0.01em;
  display: flex; align-items: center; gap: 10px;
}
.tk-modal-subtitle { font-size: 11px; color: var(--muted); margin-top: 2px; }
.tk-modal-icon {
  width: 32px; height: 32px;
  border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
  background: var(--accent-dim, rgba(63,185,80,0.14));
  color: var(--accent);
  flex-shrink: 0;
}
.tk-modal-icon svg { width: 16px; height: 16px; }
.tk-modal-close {
  width: 32px; height: 32px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: background 0.15s ease, color 0.15s ease;
  flex-shrink: 0;
}
.tk-modal-close:hover { background: var(--elevated); color: var(--text); }
.tk-modal-close svg { width: 16px; height: 16px; }
.tk-modal-body {
  padding: 18px 20px;
  overflow-y: auto;
  flex: 1 1 auto;
}
.tk-modal-body > * + * { margin-top: 14px; }
.tk-modal-footer {
  display: flex; align-items: center; gap: 8px;
  padding: 12px 20px;
  border-top: 1px solid var(--border);
  background: var(--card);
  flex-shrink: 0;
  position: sticky; bottom: 0;
}
.tk-modal-footer .tk-btn { flex: 1; }
.tk-modal-footer .tk-btn--ghost,
.tk-modal-footer .tk-btn--danger { flex: 0 0 auto; }

/* Mobile bottom-sheet */
@media (max-width: 639px) {
  .tk-modal { align-items: flex-end; padding: 0; }
  .tk-modal-card {
    max-width: 100%;
    border-radius: 16px 16px 0 0;
    max-height: 92vh;
    animation: tkModalSlideUp 0.26s cubic-bezier(0.16, 1, 0.3, 1);
  }
  @keyframes tkModalSlideUp {
    from { transform: translateY(100%); opacity: 0; }
    to   { transform: translateY(0);    opacity: 1; }
  }
  .tk-modal-header { padding: 14px 16px; }
  .tk-modal-body { padding: 14px 16px; }
  .tk-modal-footer { padding: 12px 16px; }
}

/* ---- Stake stepper (used inside Edit Bet) ---- */
.tk-stepper {
  display: flex; align-items: stretch;
  background: var(--elevated);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.tk-stepper:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-dim, rgba(63,185,80,0.16));
}
.tk-stepper button {
  background: transparent; border: 0; padding: 0 14px;
  color: var(--muted);
  font-size: 18px; font-weight: 700; line-height: 1;
  cursor: pointer; user-select: none;
  transition: background 0.12s ease, color 0.12s ease;
}
.tk-stepper button:hover { background: var(--card); color: var(--accent); }
.tk-stepper button:active { transform: scale(0.92); }
.tk-stepper input {
  flex: 1; min-width: 0;
  padding: 10px 6px; text-align: center;
  background: transparent; border: 0; outline: none;
  color: var(--text);
  font-size: 14px; font-weight: 600;
  font-variant-numeric: tabular-nums;
  -moz-appearance: textfield;
  color-scheme: dark light;
}
.tk-stepper input::-webkit-outer-spin-button,
.tk-stepper input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

@media (prefers-reduced-motion: reduce) {
  .tk-modal-card { animation: none; }
  .tk-btn, .tk-input, .tk-segmented-btn, .tk-stepper { transition: none; }
}

/* ============================================================================
   Bet-card Edit button — corner-pinned, uniform (rewritten 2026-05-20).
   Iteration history:
     v1: bright green filled pill, competed with WON/LOST + profit
     v2: ghost pill with "Edit" text, wrapped onto its own line
     v3: icon-only 22×22 inline at the end of the pills row
   This version: a single 28×28 icon button absolutely pinned to the
   top-right corner of EVERY bet card — single + multi, mobile +
   desktop, identical position. It no longer participates in the card's
   flex layout, so it can't push pills, wrap, or add card height.
   Quiet at rest, accent green on hover/focus. One class, reused
   everywhere, so placement is genuinely uniform.
*/
.bet-edit-corner {
  position: absolute;
  top: 6px;
  right: 6px;
  z-index: 3;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  min-height: 0;
  padding: 0;
  border-radius: 7px;
  background: var(--elevated);
  color: var(--muted);
  border: 1px solid var(--border);
  cursor: pointer;
  opacity: 0.75;
  transition: opacity .15s ease, color .15s ease, background-color .15s ease,
              border-color .15s ease, transform .08s ease;
}
.bet-edit-corner svg {
  width: 13px;
  height: 13px;
  flex-shrink: 0;
}
.bet-edit-corner:hover {
  opacity: 1;
  color: var(--accent);
  background: var(--accent-dim, rgba(63, 185, 80, 0.10));
  border-color: rgba(63, 185, 80, 0.40);
}
.bet-edit-corner:focus-visible {
  opacity: 1;
  outline: none;
  color: var(--accent);
  border-color: rgba(63, 185, 80, 0.55);
  box-shadow: 0 0 0 2px rgba(63, 185, 80, 0.20);
}
.bet-edit-corner:active { transform: scale(0.92); }
/* Card hover brings it fully solid so it reads as interactive. */
[data-bet-id]:hover .bet-edit-corner { opacity: 1; }

/* ============================================================================
   Multiple bet card (renamed + restyled 2026-04-29).
   Less purple, more TRACKR green/dark. Three sections:
   - .multi-header  — kind tag + status + leg summary + value/profit
   - .multi-legs    — per-leg rows with status badges + odds breakdown
   - .multi-footer  — combined odds + stake + bet type + edit
*/
.multi-card {
  position: relative;
  border-radius: 10px;
  background: var(--card);
  border: 1px solid var(--border);
  overflow: hidden;
  display: flex; flex-direction: column;
}
/* Left accent strip — colour by status, NOT by kind */
.multi-card::before {
  content: '';
  position: absolute;
  top: 0; left: 0; bottom: 0;
  width: 3px;
  border-radius: 10px 0 0 10px;
}
/* Multi-card status strips — bound to semantic state tokens.
   Pending is the only amber-family use here. */
.multi-strip--won::before     { background: var(--state-won); }
.multi-strip--lost::before    { background: var(--state-lost); }
.multi-strip--placed::before  { background: var(--state-placed); }
.multi-strip--void::before    { background: var(--state-void); }
.multi-strip--pending::before { background: var(--state-pending); }
.multi-strip--neutral::before { background: var(--border-light, var(--border)); }

.multi-header {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; flex-wrap: wrap;
  padding: 8px 12px 8px 14px;
  border-bottom: 1px solid var(--border);
}
.multi-header-left { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; min-width: 0; }
.multi-header-right { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }

/* DOUBLE / TREBLE / TRIXIE kind tag — was vivid purple, now neutral
   so the card reads as ONE bet (per spec) rather than as a separate
   mini-dashboard. The kind information stays available to the eye but
   doesn't compete with status colour for attention. */
.multi-kind {
  display: inline-flex; align-items: center;
  padding: 2px 7px;
  border-radius: 4px;
  background: var(--elevated);
  color: var(--muted);
  border: 1px solid var(--border);
  font-size: 9px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.10em;
}
.multi-kind--rf {
  background: rgba(34, 211, 238, 0.08);
  color: #67e8f9;
  border-color: rgba(34, 211, 238, 0.20);
}
.multi-status {
  font-size: 10px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.06em;
}
.multi-leg-summary {
  font-size: 10.5px; color: var(--muted);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}
/* Next-leg countdown — legitimate pending use, kept amber. */
.multi-next-time {
  font-size: 10.5px;
  padding: 2px 7px;
  border-radius: 4px;
  background: var(--state-pending-bg);
  color: var(--state-pending);
  border: 1px solid var(--state-pending-bd);
  font-weight: 600;
  white-space: nowrap;
}
.multi-value {
  font-size: 14px; font-weight: 800;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}
.multi-value-potential {
  font-size: 11px; color: var(--muted);
}
.multi-value-potential strong { color: var(--text); font-weight: 800; }
/* R4 deduction — was amber (collided with pending). Now uses warn-rose
   so it reads as "data-quality / deduction" without stealing attention
   from genuine pending bets. */
.multi-r4 {
  padding: 1px 5px; border-radius: 4px;
  font-size: 9px; font-weight: 700;
  background: var(--state-warn-bg);
  color: var(--state-warn);
  border: 1px solid var(--state-warn-bd);
}

.multi-legs {
  padding: 6px 10px 8px;
  display: flex; flex-direction: column; gap: 2px;
}
/* Legs sit INSIDE the parent multi-card — they are children, not siblings.
   Removed the leg's outer border so it doesn't double-stack with the
   parent border. The left status strip alone signals the leg state, and
   a faint divider (handled by .multi-leg + .multi-leg below) keeps the
   rows visually separable. Background sits flush with the parent so the
   legs feel attached, not floating. */
.multi-leg {
  border-radius: 6px;
  background: transparent;
  border-left: 3px solid var(--border-light, var(--border));
  padding: 6px 9px;
  display: flex; flex-direction: column; gap: 4px;
  position: relative;
}
.multi-leg + .multi-leg::before {
  content: '';
  position: absolute;
  top: -1px; left: 12px; right: 0;
  height: 1px;
  background: var(--border);
  opacity: 0.45;
}
.multi-leg--won     { border-left-color: var(--state-won); }
.multi-leg--lost    { border-left-color: var(--state-lost); }
.multi-leg--placed  { border-left-color: var(--state-placed); }
.multi-leg--void    { border-left-color: var(--state-void); opacity: 0.85; }
.multi-leg--pending { border-left-color: var(--state-pending); }
/* NEXT — the next leg to run. Pending family but emphasised. */
.multi-leg--next {
  border-left-color: var(--state-pending);
  box-shadow: 0 0 0 1px var(--state-pending-bd);
}

.multi-leg-row {
  display: flex; align-items: center; gap: 8px;
}
.multi-leg-info { display: flex; align-items: center; gap: 7px; flex: 1; min-width: 0; }
.multi-leg-text { min-width: 0; flex: 1; }
.multi-leg-horse {
  font-size: 12.5px; font-weight: 700;
  color: var(--text);
  line-height: 1.15;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.multi-leg-meta {
  display: flex; align-items: center; gap: 4px;
  font-size: 10px; color: var(--muted);
  margin-top: 1px;
  font-variant-numeric: tabular-nums;
}
.multi-leg-meta-sep { color: var(--subtle, var(--muted)); opacity: 0.5; }

.multi-leg-status {
  flex-shrink: 0;
  padding: 2px 7px;
  border-radius: 999px;
  font-size: 9.5px; font-weight: 800;
  text-transform: uppercase; letter-spacing: 0.06em;
  background: var(--card);
  border: 1px solid var(--border);
  color: var(--muted);
}
.multi-leg-status--won     { background: var(--state-won-bg);     color: var(--state-won);     border-color: var(--state-won-bd); }
.multi-leg-status--lost    { background: var(--state-lost-bg);    color: var(--state-lost);    border-color: var(--state-lost-bd); }
.multi-leg-status--pending { background: var(--state-pending-bg); color: var(--state-pending); border-color: var(--state-pending-bd); }
.multi-leg-status--gray    { background: var(--state-void-bg);    color: var(--state-void);    border-color: var(--state-void-bd); }

.multi-leg-odds {
  display: flex; align-items: center; gap: 5px;
  font-size: 10.5px;
  font-variant-numeric: tabular-nums;
  padding-left: 35px;   /* line up with horse name (silk 28 + gap 7) */
  color: var(--muted);
}
.multi-leg-odds-adv { color: var(--text); font-weight: 600; }
.multi-leg-odds-sp { color: var(--text); font-weight: 600; }
.multi-leg-odds-mine {
  color: var(--accent); font-weight: 700;
  padding: 1px 5px;
  border-radius: 4px;
  background: rgba(63, 185, 80, 0.10);
}
.multi-leg-odds-sep { color: var(--subtle, var(--muted)); opacity: 0.5; }

/* "+" between legs is redundant now that legs share a divider line
   (see .multi-leg + .multi-leg::before above). Kept the rule but hidden
   so the existing template markup doesn't break. */
.multi-leg-link {
  display: none;
}

.multi-footer {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px; flex-wrap: wrap;
  padding: 7px 12px 7px 14px;
  border-top: 1px solid var(--border);
  background: var(--card);
  font-size: 10.5px;
}
.multi-footer-left { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; min-width: 0; }
.multi-footer-sep { color: var(--subtle, var(--muted)); opacity: 0.5; margin: 0 1px; }

.multi-odds-tag {
  padding: 2px 7px;
  border-radius: 4px;
  background: var(--elevated);
  color: var(--text);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.multi-odds-arrow { color: var(--subtle, var(--muted)); }
.multi-odds-mine {
  padding: 2px 7px;
  border-radius: 4px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.multi-odds-mine--better { background: rgba(63, 185, 80, 0.12); color: var(--accent); }
.multi-odds-mine--worse  { background: rgba(248, 81, 73, 0.10); color: var(--negative-text, #f87171); }
.multi-stake {
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.multi-bet-type {
  padding: 1px 6px;
  border-radius: 4px;
  font-size: 9.5px; font-weight: 700;
  background: var(--elevated);
  color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.06em;
}
.multi-bet-type--ew { background: var(--state-ew-bg); color: var(--state-ew); border: 1px solid var(--state-ew-bd); }
.multi-bet-type--rf { background: var(--state-info-bg); color: var(--state-info); border: 1px solid var(--state-info-bd); }

@media (max-width: 639px) {
  .multi-header { padding: 7px 10px; }
  .multi-legs { padding: 6px 8px; }
  .multi-footer { padding: 7px 10px; font-size: 10px; }
  .multi-leg-odds { padding-left: 31px; }
}

/* ============================================================================
   BFEX first-capture proof pill (rewritten 2026-05-18 — premium pass)
   ============================================================================
   Compact informational chip on every pending bet card showing the immutable
   first BFEX best-back odds + capture timestamp + speed-from-bet-save.

   Design language:
     • Soft tinted backdrop (status colour at ~6% opacity) instead of a
       hard outline so the chip reads as INFORMATION, not a button.
     • Left-accent bar (3px) carries the status colour at full saturation.
       This is the only saturated edge — eyes anchor to it instantly.
     • Drops the redundant cp-status chip (the inline speed already says
       the same thing) — handled via CSS, JS stays untouched.
     • Dot is now a tiny halo'd status puck (with a subtle ring) rather
       than a 5px speck that disappears against the backdrop.
     • Tighter typography — odds get prominence, label + time + speed sit
       as quiet metadata around them.

   Status colours:
     fast  — accent green (captured in <2s — feed healthy)
     late  — amber       (2-10s — market may have moved)
     stale — red-dim     (>10s OR feed quiet)
     none  — neutral     (no anchor — pipeline pending)
*/
.capture-proof {
  --cp-accent: var(--muted);
  --cp-tint: transparent;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 5px 11px 5px 9px;
  border-radius: 8px;
  background:
    linear-gradient(90deg, var(--cp-tint) 0%, transparent 70%),
    var(--elevated);
  border: 1px solid var(--border);
  border-left: 3px solid var(--cp-accent);
  font-size: 11px;
  font-weight: 600;
  color: var(--muted);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.003em;
  line-height: 1.25;
  transition: background .18s ease, border-color .18s ease, transform .15s ease;
}
.capture-proof:hover {
  border-color: var(--border-light);
}
.capture-proof .cp-dot {
  display: inline-block;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--cp-accent);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--cp-accent) 18%, transparent);
  flex-shrink: 0;
}
.capture-proof .cp-label {
  font-size: 9.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--muted);
  opacity: 0.95;
}
.capture-proof .cp-odds {
  font-weight: 800;
  color: var(--text);
  font-size: 12.5px;
  letter-spacing: -0.01em;
}
.capture-proof .cp-time {
  color: var(--muted);
  font-size: 10.5px;
  font-weight: 500;
  opacity: 0.85;
}
.capture-proof .cp-speed {
  color: var(--cp-accent);
  font-size: 10px;
  font-weight: 700;
  opacity: 0.95;
}
/* Hide the redundant status chip — speed + label colour already
   communicate fast/late/stale state. Keep the markup so historical
   JS doesn't need rewriting and JAWS still reads it via tooltip. */
.capture-proof .cp-status {
  display: none;
}

/* Tone variants — drive the --cp-accent and --cp-tint custom props.
   Single source of truth: change once here, the dot/accent-bar/speed
   chip all update in unison. */
.capture-proof--fast {
  --cp-accent: #3fb950;
  --cp-tint:   rgba(63, 185, 80, 0.07);
}
.capture-proof--late {
  --cp-accent: #fbbf24;
  --cp-tint:   rgba(245, 158, 11, 0.07);
}
.capture-proof--stale {
  --cp-accent: var(--negative-text, #ff7b72);
  --cp-tint:   rgba(248, 81, 73, 0.06);
}
.capture-proof--none {
  --cp-accent: var(--muted);
  --cp-tint:   transparent;
  opacity: 0.7;
}
.capture-proof--none .cp-dot {
  animation: capturePending 1.6s ease-in-out infinite;
  box-shadow: none;
}
@keyframes capturePending {
  0%, 100% { opacity: 0.35; transform: scale(0.9); }
  50%      { opacity: 1;    transform: scale(1.05); }
}

@media (max-width: 420px) {
  /* On very narrow screens hide the captured-at time so the chip stays
     on a single line. Speed stays — it's the freshness signal. */
  .capture-proof .cp-time { display: none; }
  .capture-proof { padding: 5px 9px 5px 8px; gap: 6px; }
  .capture-proof .cp-odds { font-size: 12px; }
}

@media (prefers-reduced-motion: reduce) {
  .capture-proof--none .cp-dot { animation: none; }
  .capture-proof { transition: none; }
}

/* Bet-card saved-flash — brief green pulse on the just-saved card so
   the user gets immediate feedback that their amend landed on this
   specific bet, before the silent background refresh finishes. */
.bet-card-saved-flash {
  animation: betCardSavedFlash 0.8s cubic-bezier(0.16, 1, 0.3, 1);
  position: relative;
  z-index: 1;
}
@keyframes betCardSavedFlash {
  0%   { box-shadow: 0 0 0 0 rgba(63, 185, 80, 0.55); }
  40%  { box-shadow: 0 0 0 6px rgba(63, 185, 80, 0.20); }
  100% { box-shadow: 0 0 0 0 rgba(63, 185, 80, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .bet-card-saved-flash { animation: none; }
}

/* Visible focus ring upgrade — keeps a11y but feels less aggressive than
   the default Chrome blue */
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  box-shadow: 0 0 0 4px var(--accent-dim);
}

/* ============================================================================
   Tipster identity — clean uppercase text treatments (rewritten 2026-04-29 v2)
   ============================================================================
   The previous "badge" approach (text-inside-pill) read as a duplicated
   chip+name combo. This version uses pure type — uppercase letters,
   subtle green accent underline + small mono kicker. Each tipster gets
   slightly different typography so they feel premium and individual but
   still belong to one design system.

   Markup (emitted by TrackrUI.tipsterMark / .tipsterFull):
     <span class="tipster-id tipster-id--{trt|stride|tyrrells}">TRT</span>

   Used directly in section headers, tipster filter pills, table cells,
   and modal headers. No image, no pill background, no chip+name duplication.
*/

/* Legacy class shims — old call-sites using .tipster-mark/-cell/-header
   should now look identical to the new .tipster-id treatment without
   needing markup edits everywhere. */
.tipster-mark,
.tipster-mark-cell,
.tipster-mark-header,
.tipster-full,
.tipster-full-header,
.tipster-badge,
.tipster-badge--mark,
.tipster-badge--full {
  display: inline-flex;
  align-items: center;
  vertical-align: middle;
  background: transparent !important;
  border: 0 !important;
  padding: 0 !important;
  min-height: 0 !important;
  box-shadow: none !important;
}

/* 2026-04-29 v3 — uniform professional sans-serif treatment.
   Previous version mixed ui-sans-serif (TRT/STRIDE) with ui-serif
   (TYRRELLS) which felt like a random font dropped beside the
   dashboard. New rule: ONE family across all tipsters, varied only by
   subtle letter-spacing. STRIDE letter-spacing is tightened on small
   screens so the row doesn't push past 360px. */
.tipster-id {
  display: inline-flex;
  align-items: baseline;
  vertical-align: middle;
  color: var(--text);
  font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Inter var", "Inter", "Segoe UI", sans-serif;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.10em;
  line-height: 1;
  white-space: nowrap;
  font-feature-settings: 'cv11', 'ss01', 'tnum';
  /* Subtle green underline from the tipster's accent. */
  position: relative;
  padding-bottom: 2px;
}
.tipster-id::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1px;
  background: linear-gradient(90deg, var(--accent), transparent 75%);
  opacity: 0.45;
}
.tipster-id:hover::after { opacity: 0.85; }

/* Per-tipster nuances — kept SUBTLE. Same family, just controlled
   tracking differences so each tipster reads distinct without feeling
   gimmicky. */
.tipster-id--trt {
  letter-spacing: 0.14em;
  font-weight: 800;
}
.tipster-id--stride {
  letter-spacing: 0.18em;   /* slightly wider, NOT 0.30em — that overflowed */
  font-weight: 700;
}
.tipster-id--tyrrells {
  letter-spacing: 0.08em;   /* tighter because TYRRELLS RACING is two words */
  font-weight: 700;
}

/* Mobile — clamp letter-spacing further so STRIDE / TYRRELLS RACING
   never push the row past 360px viewport. */
@media (max-width: 480px) {
  .tipster-id { letter-spacing: 0.06em !important; }
  .tipster-id--tyrrells { font-size: 0.92em; }
}

/* Plaintext fallback for unknown tipsters — same look-and-feel so the
   grid stays consistent even when we don't have a styled treatment. */
.tipster-id-fallback {
  font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
  font-weight: 700;
  font-size: 0.95em;
  color: var(--muted);
  letter-spacing: 0.02em;
}

/* Active-state inside a filter chip — inherits the chip's text colour
   (which goes white on the green active pill) so the type stays bold
   against the accent background. The green underline disappears since
   it would clash with the chip background. */
.tipster-seg .tipster-btn.active .tipster-id,
.db-seg .db-seg-btn.active .tipster-id { color: inherit; }
.tipster-seg .tipster-btn.active .tipster-id::after,
.db-seg .db-seg-btn.active .tipster-id::after { display: none; }

/* Section-header sizing — used inside .tipster-section-header on the
   live bets dashboard. Larger and bolder so each tipster feels like a
   real section divider instead of a tiny chip. */
.tipster-id--header { font-size: 14px; }
.tipster-id--header.tipster-id--stride { font-size: 13px; letter-spacing: 0.34em; }
@media (max-width: 639px) {
  .tipster-id--header { font-size: 12.5px; letter-spacing: 0.14em; }
  .tipster-id--header.tipster-id--stride { font-size: 11.5px; letter-spacing: 0.26em; }
}

/* Full variant for tipster_detail page header — bigger size + small
   kicker tagline below. Uses the same per-tipster tracking rules. */
.tipster-id--full {
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  padding-bottom: 6px;
}
.tipster-id--full .tipster-id-text {
  font-size: 32px;
  color: var(--accent);
  letter-spacing: inherit;
  font-weight: inherit;
  font-variant-caps: inherit;
  text-transform: inherit;
}
.tipster-id--full .tipster-id-kicker {
  font-size: 10px;
  font-weight: 600;
  color: var(--muted);
  letter-spacing: 0.20em;
  text-transform: uppercase;
}
.tipster-id--full::after {
  height: 2px;
  background: linear-gradient(90deg, var(--accent), transparent 60%);
}
@media (max-width: 639px) {
  .tipster-id--full .tipster-id-text { font-size: 24px; }
}

/* When inside a filter chip / segment / cell that doesn't override colour,
   pick up the TRACKR green so the mark feels branded but consistent. */
.tipster-seg .tipster-btn .tipster-mark,
.db-seg .db-seg-btn .tipster-mark,
.tipster-mark-header,
.tipster-mark-cell {
  color: var(--accent);
  opacity: 0.9;
}
/* Active filter chip uses --accent as its background — inverting the mark
   colour so it stays visible against the green pill. */
.tipster-seg .tipster-btn.active .tipster-mark,
.db-seg .db-seg-btn.active .tipster-mark {
  color: var(--card);   /* inverted: dark on green */
  opacity: 1;
}

/* Inline tipster name + mark layout. Used in table cells, group headers,
   and anywhere the mark sits next to the name. */
.tipster-name-row {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
  min-width: 0;
}

/* Full wordmark — used on tipster_detail and reports. */
.tipster-full {
  display: inline-block;
  height: 36px;            /* default; pages can override */
  width: auto;
  vertical-align: middle;
  color: var(--text);      /* the SVG uses currentColor for fills */
}
.tipster-full-header { height: 48px; }

/* Mobile: shrink marks slightly + drop one on filter chips if names
   threaten to wrap. Keep tap target ≥ 44px from existing chip rule. */
@media (max-width: 639px) {
  .tipster-mark { width: 14px; height: 14px; }
  .tipster-mark-header { width: 14px; height: 14px; }
  .tipster-full-header { height: 36px; }
  /* On very narrow screens hide the chip mark to preserve text legibility.
     The text label remains, so identification is fine. */
  @media (max-width: 380px) {
    .tipster-seg .tipster-btn .tipster-mark,
    .db-seg .db-seg-btn .tipster-mark { display: none; }
  }
}

/* Reduced motion: nothing to do (no animations on logos), but ensure mask
   doesn't trigger any layout shift on render. */
@media (prefers-reduced-motion: reduce) {
  .tipster-mark { transition: none; }
}
