:root {
  /* Dark mode: slate neutrals (bg/surface/line/chalk — a muted blue-gray,
     less saturated than PitchPulse Pro's navy) with a blue / orange team
     pair on top — blue (#1db1ff) is the primary accent and Home, orange
     (#ff6b35) is Away. The two are near-complementary, so neither side
     outweighs the other, and the cool base lets both read cleanly.
     --gf-tint/--ga-tint/--good/--bad stay conventional green/red
     (small-scale data signals, not brand color); --pro (violet) is
     unchanged. --amber-true is genuine amber. */
  --bg: #12171d;
  --bg-deep: #0d1116;
  --surface: #1b2129;
  --surface-raised: #252c36;
  --line: #333c48;
  --chalk: #f2f4f6;
  --chalk-muted: #a0aab6;
  --amber: #1db1ff;
  --amber-dim: rgba(29, 177, 255, 0.22);
  --home: #1db1ff;
  --away: #ff6b35;
  --draw: #f5c842;
  --copper: #b97d4d;
  /* Genuinely amber (orange-gold), unlike --amber above which is blue (the
     token name predates the palette and was never renamed — renaming it
     would mean re-touching every primary button/tab/focus ring in the
     file, so it's left alone). Use this one when "amber" needs to mean
     amber. */
  --amber-true: #ffb428;
  --amber-true-dim: rgba(255, 180, 40, 0.32);
  /* Match Log score chips (Form Check / Market Expected) — kept clear of the
     home blue / away orange of the λ chip and the good/bad green/red used for
     agreement, so each read has its own colour. */
  --form-score: #2dd4bf;
  --mkt-score: #ffb428;
  --gf-tint: rgba(0, 212, 139, 0.35);
  --ga-tint: rgba(255, 68, 102, 0.35);
  --home-dim: rgba(29, 177, 255, 0.16);
  --draw-dim: rgba(245, 200, 66, 0.16);
  --away-dim: rgba(255, 107, 53, 0.16);
  --good: #00d48b;
  --bad: #ff4466;
  --brand-pitch: #f2f4f6;
  --brand-pulse: #1db1ff;
  --pro: #9b7ff0;
  --pro-dim: rgba(155, 127, 240, 0.35);
  --pro-tint: rgba(155, 127, 240, 0.08);
  --track: rgba(255, 255, 255, 0.08);
  --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.4), 0 8px 24px -12px rgba(0, 0, 0, 0.55), 0 32px 64px -30px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.045);
  --shadow-card-hover: 0 2px 4px rgba(0, 0, 0, 0.45), 0 14px 32px -14px rgba(0, 0, 0, 0.65), 0 40px 80px -32px rgba(0, 0, 0, 0.55), inset 0 1px 0 rgba(255, 255, 255, 0.06);
  --pitch-stripe-a: rgba(255, 255, 255, 0.05);
  --pitch-stripe-b: rgba(255, 255, 255, 0.105);
  --pitch-mark: rgba(255, 255, 255, 0.2);
  /* New: depth layers for the background upgrade below — a faint cool-blue
     floodlight halo centered on the pitch, and a corner vignette so the
     viewport reads as lit from the middle rather than flat-shaded. */
  --pitch-glow: rgba(29, 177, 255, 0.08);
  --pitch-vignette: rgba(0, 0, 0, 0.5);
  /* Glass layer: translucent stand-ins for bg-deep/bg/surface-raised, used
     by the header and sticky tabs so the textured backdrop shows through,
     softly blurred, instead of those bars sitting as flat opaque banners
     disconnected from the pitch behind them. Button gradient top-stop for
     the same reason primary actions get one now instead of a flat fill. */
  --head-glass-a: rgba(13, 17, 22, 0.78);
  --head-glass-b: rgba(18, 23, 29, 0.72);
  --surface-glass: rgba(37, 44, 54, 0.7);
  --primary-grad-top: #5cc4ff;
  /* Text/icon color that sits ON the primary accent (active tab, primary
     button, pressed steppers, VS badge). Dark charcoal on the bright blue
     in dark mode; white on the deeper blue in light mode. */
  --on-accent: #0d1116;
  --font-display: "Inter", -apple-system, BlinkMacSystemFont, sans-serif;
  --font-body: "Inter", -apple-system, BlinkMacSystemFont, sans-serif;
  --font-mono: "JetBrains Mono", "SFMono-Regular", Menlo, Consolas, monospace;
  --font-tagline: "Orbitron", "JetBrains Mono", var(--font-mono);
  --radius: 8px;
  --radius-pill: 999px;
  /* Fine film-grain, layered over the pitch background at a low opacity
     with an overlay blend (see .pitch-lines) so it reads as texture, not
     visible speckling — the difference between a flat fill and a surface. */
  --noise-texture: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0.5 0 0 0 0 0.5 0 0 0 0 0.5 0 0 0 0.05 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

html.light {
  /* Light mode: cool blue-gray neutrals (the light-side match for the dark
     slate theme) with the same blue / orange pair as dark mode, deepened
     for AA contrast (blue #0069d6, orange #c93c00 — both >= 4.5:1 on
     --bg). The brighter #1db1ff / #ff6b35 used in dark mode don't clear
     AA on a light background. --draw and --good below get the same
     treatment — the dark-mode values (#f5c842, #00d48b) cleared AA fine,
     but carried over unchanged they landed at 2.57:1 and 3.62:1 here,
     the first failing outright and the second passing only for large
     text. Both are used as real body-text color (Draw %, Best Bet %,
     Hit Rate, EV %), not just decoration, so both are darkened here to
     >= 4.5:1 same as home/away. */
  --bg: #f1f3f6;
  --bg-deep: #e4e8ed;
  --surface: #ffffff;
  --surface-raised: #f7f8fa;
  --line: #d9dee5;
  --chalk: #141a21;
  --chalk-muted: #58636f;
  --amber: #0069d6;
  --amber-dim: rgba(0, 105, 214, 0.2);
  --home: #0069d6;
  --away: #c93c00;
  --draw: #8d6700;
  --copper: #a05a26;
  /* Same reasoning as the dark-theme block above — genuinely amber, unlike
     --amber which is blue. Deepened for AA contrast on a light background. */
  --amber-true: #a85c00;
  --amber-true-dim: rgba(168, 92, 0, 0.28);
  --form-score: #0f766e;
  --mkt-score: #a85c00;
  --good: #007e44;
  --bad: #d6003a;
  --home-dim: rgba(0, 105, 214, 0.14);
  --draw-dim: rgba(196, 144, 0, 0.14);
  --away-dim: rgba(201, 60, 0, 0.14);
  --brand-pitch: #0069d6;
  --brand-pulse: #c93c00;
  --pro: #8462c9;
  --pro-dim: rgba(132, 98, 201, 0.28);
  --pro-tint: rgba(132, 98, 201, 0.07);
  --track: rgba(20, 26, 33, 0.07);
  --shadow-card: 0 1px 2px rgba(20, 26, 33, 0.06), 0 6px 20px -10px rgba(20, 26, 33, 0.18), 0 28px 56px -32px rgba(20, 26, 33, 0.14), inset 0 1px 0 rgba(255, 255, 255, 0.6);
  --shadow-card-hover: 0 2px 4px rgba(20, 26, 33, 0.08), 0 12px 28px -12px rgba(20, 26, 33, 0.24), 0 34px 68px -34px rgba(20, 26, 33, 0.18), inset 0 1px 0 rgba(255, 255, 255, 0.7);
  --pitch-stripe-a: rgba(20, 26, 33, 0.055);
  --pitch-stripe-b: rgba(20, 26, 33, 0.115);
  --pitch-mark: rgba(20, 26, 33, 0.22);
  --pitch-glow: rgba(0, 105, 214, 0.07);
  --pitch-vignette: rgba(20, 26, 33, 0.12);
  --head-glass-a: rgba(241, 243, 246, 0.74);
  --head-glass-b: rgba(247, 248, 250, 0.68);
  --surface-glass: rgba(247, 248, 250, 0.72);
  --primary-grad-top: #0a78e0;
  --on-accent: #ffffff;
}
html.light .theme-icon.sun { display: none; }
html.light .theme-icon.moon { display: block; }
.theme-icon.moon { display: none; }

* { box-sizing: border-box; }

/* Safety-net focus ring: covers any focusable element (buttons, tabs, links)
   that doesn't already define its own focus treatment. Uses :focus-visible
   so it only shows for keyboard navigation, not every mouse click. */
a:focus-visible, button:focus-visible, [tabindex]:focus-visible {
  outline: 2px solid var(--amber);
  outline-offset: 2px;
  border-radius: 4px;
}

html { -webkit-text-size-adjust: 100%; }

/* ---------- Final premium-feel polish ----------
   A handful of small, broadly-shared details rather than a per-component
   pass — the kind of thing you don't consciously notice individually, but
   whose absence reads as "web page" instead of "native app". */

/* Kills the default gray/blue tap-flash rectangle Android/iOS Safari draws
   on any tappable element — harmless on non-interactive ones too, so it's
   safe to apply everywhere rather than hunting down every button/tab/card
   individually. Paired with touch-action below so every tap responds with
   only each element's own custom hover/press animation, not a system one
   layered on top of it. */
* { -webkit-tap-highlight-color: transparent; }
a, button, input, select, textarea, label, [role="button"], [onclick],
.tab, .btn, .o-tile, .split-pill, .card-icon-badge, .step-btn {
  touch-action: manipulation;
}

/* Branded text selection — the pale blue tint below reads as "designed",
   not the browser's default OS-blue highlight clashing with the app's own
   palette. Kept subtle: this is a utility, not a decoration. */
::selection { background: var(--amber-dim); color: var(--chalk); }

/* Slim themed scrollbar for the few places content actually scrolls inside
   a fixed-height box (modals, the Match Log list) — Firefox via the
   standard property, WebKit/Blink via the pseudo-elements. Falls back to
   the OS default anywhere neither applies, which is harmless. */
* { scrollbar-width: thin; scrollbar-color: var(--line) transparent; }
*::-webkit-scrollbar { width: 8px; height: 8px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb { background: var(--line); border-radius: var(--radius-pill); border: 2px solid transparent; background-clip: padding-box; }
*::-webkit-scrollbar-thumb:hover { background: var(--chalk-muted); background-clip: padding-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--chalk);
  font-family: var(--font-body);
  line-height: 1.5;
  min-height: 100vh;
  position: relative;
}

/* Background, now layered instead of flat: mowed pitch stripes as before,
   plus a faint floodlight glow centered on the pitch and a soft vignette
   toward the viewport edges — so the room reads as lit from the middle,
   with genuine depth, rather than one uniform fill — and a fine grain
   layer on top (blended with `overlay`) for a physical, printed-surface
   feel instead of a flat digital one. All four layers sit at low enough
   opacity to stay a backdrop, never competing with the cards on top of
   them. Everything here sits behind every card's solid surface, so it
   only ever shows in the gutters and the gaps between cards, and stays
   fixed to the viewport rather than scrolling with the page, like a
   stadium backdrop rather than part of the content. */
.pitch-lines {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background-color: var(--bg);
  background-image:
    var(--noise-texture),
    radial-gradient(ellipse 900px 700px at 50% 50%, var(--pitch-glow), transparent 70%),
    radial-gradient(ellipse 140% 100% at 50% 50%, transparent 55%, var(--pitch-vignette) 100%),
    repeating-linear-gradient(
      180deg,
      var(--pitch-stripe-a) 0px,
      var(--pitch-stripe-a) 64px,
      var(--pitch-stripe-b) 64px,
      var(--pitch-stripe-b) 128px
    );
  background-repeat: repeat, no-repeat, no-repeat, repeat;
  background-blend-mode: overlay, normal, normal, normal;
}

/* Halfway line + centre circle, fixed to the viewport's actual centre. */
.pitch-halfway {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 2px;
  background: var(--pitch-mark);
  transform: translateX(-50%);
}
.pitch-center-circle {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 130px;
  height: 130px;
  border: 2px solid var(--pitch-mark);
  border-radius: 50%;
  transform: translate(-50%, -50%);
  /* Slight glow so the circle reads as the floodlit centre of the
     backdrop, echoing the radial glow layer in .pitch-lines rather than
     sitting as a flat outline. */
  box-shadow: 0 0 40px 6px var(--pitch-glow);
}
.pitch-center-circle::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 8px;
  height: 8px;
  background: var(--pitch-mark);
  border-radius: 50%;
  transform: translate(-50%, -50%);
}

.pitch-goal-area, .pitch-six-yard {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  height: min(360px, 70vh);
  width: 100px;
  border: 2px solid var(--pitch-mark);
}
.pitch-six-yard { height: min(170px, 34vh); width: 42px; }
.pitch-goal-area-left, .pitch-six-yard-left { left: 0; border-left: none; border-radius: 0 4px 4px 0; }
.pitch-goal-area-right, .pitch-six-yard-right { right: 0; border-right: none; border-radius: 4px 0 0 4px; }

/* The goal itself: a short goal-line segment with a post at each end,
   sitting right on the goal line (not the wider penalty markings). */
.pitch-post {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  height: min(90px, 18vh);
  width: 3px;
  background: var(--pitch-mark);
}
.pitch-post-left { left: 0; }
.pitch-post-right { right: 0; }
.pitch-post span {
  position: absolute;
  height: 3px;
  width: 14px;
  background: var(--pitch-mark);
}
.pitch-post span:first-child { top: 0; }
.pitch-post span:last-child { bottom: 0; }
.pitch-post-left span { left: 0; }
.pitch-post-right span { right: 0; }

.wrap {
  max-width: 880px;
  margin: 0 auto;
  padding: 0 20px;
  position: relative;
  z-index: 1;
}

@media (min-width: 1200px) {
  /* Tally fields are already width-capped and centered (see the
     .season-tally-field/.form-tally-field rule below), so a wider column
     just gives every card more breathing room instead of stretching
     inputs into odd shapes. */
  .wrap { max-width: 1040px; }
}

/* Blue -> orange ribbon (Home blue on the left, Away orange on the right).
   Each colour holds solid for 40% of the width with a short blend between,
   so the ends read as the app's actual blue/orange defaults. The old sweep
   ran in OKLCH, which travels around the hue wheel (blue -> violet -> pink ->
   orange) and put a pink band across the middle. Plain sRGB with a narrow
   blend zone never leaves the blue/orange family. Shared by the tab strip
   and the Inputs-card spines so they always match. (The tab strip itself now
   uses --tab-underline below instead.) */
:root { --agree-mid: #8cc255; } /* between --good and --amber-true: the "2 of 3" step */
html.light { --agree-mid: #5c7523; }
:root { --ribbon-blue-orange: linear-gradient(90deg, var(--home) 0%, var(--home) 40%, var(--away) 60%, var(--away) 100%); }
/* Active-tab underline: Home blue for most of the width with a short Away
   orange accent at the trailing edge (plain sRGB, same reasoning as the
   ribbon above — never travels through pink). */
:root { --tab-underline: linear-gradient(90deg, var(--home) 0%, var(--home) 80%, var(--away) 92%, var(--away) 100%); }
/* How far the active-tab underline floats above the strip's bottom edge.
   Flush (0) read as crowding the border while sitting well clear of the
   label, so it's lifted a few px to balance the two gaps. Scaled with the
   tab padding: a touch more on wide screens, less on the tightest phones. */
:root { --tab-underline-lift: 3px; }

/* ---------- tabs ---------- */
.tabs {
  display: flex;
  align-items: center;
  /* Underline-style tabs: the strip is just the glass surface — the active
     tab carries its own blue -> orange underline (see .tab::after), so no
     ribbon runs along the strip's edge any more. No bottom padding on the
     strip itself; the underline is lifted off its bottom edge by
     --tab-underline-lift (see .tab::after). */
  background: var(--surface-glass, var(--surface-raised, var(--surface)));
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  backdrop-filter: blur(14px) saturate(140%);
  border: 1px solid var(--amber-dim);
  border-radius: var(--radius);
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.35), 0 0 0 1px rgba(29, 177, 255, 0.08);
  overflow-x: auto;
  scrollbar-width: none;
  position: sticky;
  top: 0;
  z-index: 99;
  padding: 8px 8px 0;
  gap: 6px;
  margin: 14px 0 20px;
  /* Forces its own GPU compositing layer. Some Android WebViews (MIUI's
     browser in particular) mis-paint the gap above a sticky element that
     also uses backdrop-filter — the sticky box can visually detach from
     its scroll position by a stray blank region until the next repaint.
     Promoting it to its own layer up front avoids that repaint hand-off. */
  transform: translateZ(0);
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .tabs { background: var(--surface-raised, var(--surface)); }
}
.tabs::-webkit-scrollbar { display: none; }
.tab {
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 0.4px;
  padding: 11px 16px 13px; /* extra bottom room for the underline */
  color: var(--chalk-muted);
  cursor: pointer;
  border-radius: 10px 10px 0 0;
  white-space: nowrap;
  background: transparent;
  border: 0;
  position: relative;
  transition: color 0.15s ease, background 0.15s ease, border-color 0.15s ease, transform 0.15s cubic-bezier(0.16, 1, 0.3, 1);
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  user-select: none;
}
.tab-icon { flex-shrink: 0; width: 14px; height: 14px; }
/* The underline spans the tab's full width (icon + label + padding). Hidden
   until active; a faint preview of it shows on hover. */
.tab::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: var(--tab-underline-lift);
  height: 3px;
  border-radius: 3px; /* floats clear of the edge now, so round both sides */
  background: var(--tab-underline);
  opacity: 0;
  transform: scaleX(0.4);
  transition: opacity 0.18s ease, transform 0.22s cubic-bezier(0.16, 1, 0.3, 1);
}
.tab:hover { color: var(--chalk); }
.tab:hover::after { opacity: 0.35; transform: scaleX(1); }
.tab:active { transform: scale(0.96); }
.tab.active { color: var(--home); }
.tab.active::after { opacity: 1; transform: scaleX(1); }
@media (prefers-reduced-motion: reduce) {
  .tab::after { transition: none; }
}

/* Above the mobile tightening breakpoint below, let the 4 tabs share the
   strip's full width evenly instead of hugging their own content and
   leaving the remainder as dead space on wider screens — each tab grows
   equally (flex: 1 1 0) and centers its icon+label, with a modest type
   bump so the extra room actually gets used rather than just padding. */
@media (min-width: 561px) {
  .tabs { gap: 8px; }
  .tab { flex: 1 1 0; justify-content: center; font-size: 11.5px; padding: 12px 13px 14px; }
}
@media (min-width: 1200px) {
  :root { --tab-underline-lift: 4px; }
  .tabs { gap: 10px; padding: 10px 10px 0; }
  .tab { font-size: 12.5px; padding: 14px 17px 16px; gap: 8px; letter-spacing: 0.5px; }
  .tab-icon { width: 15px; height: 15px; }
}

/* Four tabs (INPUTS / MODEL COMPARISON / VERDICT / HELP & FAQ) don't all fit at
   comfortable size below ~560px, forcing a horizontal scroll on first
   load. Tighten padding, gap, and type size progressively so the full
   set sits flush without scrolling on typical phone widths. */
@media (max-width: 560px) {
  /* Tighter margins too, not just padding/type — on a phone the stats
     strip + tabs sit above every bit of actual content, so trimming their
     vertical footprint here is what actually shortens the page, not just
     the tabs' own internal padding. */
  .tabs { padding: 5px 5px 0; gap: 3px; margin: 10px 0 14px; }
  .tab { padding: 8px 10px 10px; font-size: 10px; gap: 4px; letter-spacing: 0.15px; }
  .tab-icon { width: 11px; height: 11px; }
}
@media (max-width: 400px) {
  :root { --tab-underline-lift: 2px; }
  .tab { padding: 7px 8px 9px; font-size: 9.5px; gap: 3px; }
  .tab-icon { width: 10px; height: 10px; }
}

/* ---------- sections (tab panels) ---------- */
.section { display: none; }
.section.active { display: block; animation: tabFadeIn 0.28s ease; }
@keyframes tabFadeIn {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .section.active { animation: none; }
}

/* ---------- manage leagues (custom league add/edit/import/export) ---------- */
.lgm-accordion {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  margin-top: 10px;
  background: var(--bg-deep);
  transition: border-color 0.2s ease;
}
.lgm-accordion.open { border-color: var(--amber-dim); }
.lgm-header {
  width: 100%;
  display: flex;
  align-items: center;
  padding: 9px 12px;
  background: transparent;
  border: none;
  cursor: pointer;
  font-family: var(--font-body);
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--chalk-muted);
  transition: background 0.15s ease, color 0.15s ease;
}
.lgm-header:hover { background: rgba(29, 177, 255, 0.06); color: var(--amber); }
.lgm-icon { display: inline-flex; width: 12px; height: 12px; margin-right: 7px; flex-shrink: 0; color: var(--chalk-muted); }
.lgm-header:hover .lgm-icon { color: var(--amber); }
.lgm-accordion.open .lgm-vbar { transform: scaleY(0); opacity: 0; transform-origin: 5.5px 5.5px; transition: transform 0.2s ease, opacity 0.15s ease; }
.lgm-vbar { transform-origin: 5.5px 5.5px; transition: transform 0.2s ease, opacity 0.15s ease; }
.lgm-body { max-height: 0; overflow: hidden; opacity: 0; padding: 0 8px; transition: max-height 0.3s ease, opacity 0.2s ease, padding 0.25s ease; }
.lgm-accordion.open .lgm-body { max-height: 100px; opacity: 1; padding: 8px 8px 10px; }
.lg-row-grid { display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; gap: 6px; }

.lg-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  background: var(--surface);
  border: 1px solid var(--line);
  color: var(--chalk-muted);
  font-family: var(--font-body);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.3px;
  padding: 7px 8px;
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.15s ease;
  white-space: nowrap;
}
.lg-btn:hover { border-color: var(--amber); color: var(--amber); }
.lg-btn:active { transform: scale(0.94); }
.lg-btn.lg-btn-accent { border-color: var(--amber-dim); color: var(--amber); }
.lg-btn.lg-btn-danger { padding: 6px 10px; font-size: 10px; }
.lg-btn.lg-btn-danger:hover { border-color: var(--bad); color: var(--bad); }

.lg-status-row { display: flex; align-items: center; gap: 8px; margin-top: 8px; flex-wrap: wrap; }
.lg-custom-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--good);
  background: rgba(0, 212, 139, 0.12);
  border: 1px solid rgba(0, 212, 139, 0.3);
  padding: 4px 8px;
  border-radius: 5px;
}
#lg-save-msg { font-size: 11px; font-weight: 600; }

.lg-add-form { max-height: 0; overflow: hidden; opacity: 0; transition: max-height 0.3s ease, opacity 0.2s ease, margin 0.25s ease; }
.lg-add-form.open { max-height: 400px; opacity: 1; margin-top: 10px; }
.lg-add-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; background: var(--bg-deep); border: 1px solid var(--line); border-radius: var(--radius); padding: 12px; }
.lg-add-form .field { display: flex; flex-direction: column; gap: 5px; }
.lg-add-form .field label { font-size: 10px; font-weight: 700; letter-spacing: 0.4px; text-transform: uppercase; color: var(--chalk-muted); }
.lg-input {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 6px;
  color: var(--chalk);
  font-family: var(--font-body);
  font-size: 14px;
  padding: 8px 10px;
  width: 100%;
}
.lg-input:focus { outline: none; border-color: var(--amber-dim); }
.lg-add-actions { display: flex; gap: 8px; margin-top: 10px; }
.lg-add-actions .lg-btn { flex: 1; padding: 9px; }
#lg-add-error { font-size: 11px; color: var(--bad); margin-top: 8px; display: none; }
@media (max-width: 480px) {
  .lg-row-grid { grid-template-columns: 1fr 1fr; }
  .lg-add-grid { grid-template-columns: 1fr; }
}

/* ---------- header ----------
   One compact row: logo left, computed-stats strip centered, actions right —
   mirrors ScoreMatrix's single-bar header instead of a two-tier stack. */
.site-head {
  border-bottom: 1px solid var(--line);
  background: linear-gradient(180deg, var(--head-glass-a), var(--head-glass-b));
  -webkit-backdrop-filter: blur(20px) saturate(140%);
  backdrop-filter: blur(20px) saturate(140%);
  position: relative;
  z-index: 1;
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.04) inset, 0 12px 28px -18px rgba(0, 0, 0, 0.55);
}
/* Browsers without backdrop-filter support fall back to a fully opaque
   header (same gradient, no transparency) instead of see-through text. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .site-head { background: linear-gradient(180deg, var(--bg-deep), var(--bg)); }
}
/* Hairline gradient accent across the very top edge — the kind of detail that
   reads as "designed" rather than default-browser-chrome. */
.site-head::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--home) 20%, var(--home) 42%, var(--away) 58%, var(--away) 80%, transparent);
  opacity: 0.55;
}
html.light .site-head::before { opacity: 0.35; }
.site-head-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding-top: calc(12px + env(safe-area-inset-top));
  padding-bottom: 12px;
  min-height: 64px;
}
.brand { display: flex; align-items: stretch; gap: 8px; flex-shrink: 1; min-width: 0; }
.brand-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; overflow: hidden; }
.brand-mark {
  color: var(--home);
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
  margin-left: 6px;
  vertical-align: middle;
  filter: drop-shadow(0 0 6px var(--amber-dim));
}
.pulse-line {
  stroke-dasharray: 74 74;
  stroke-dashoffset: 74;
  animation: pulseSweep 2.4s linear infinite;
}
@keyframes pulseSweep {
  to { stroke-dashoffset: -74; }
}
@media (prefers-reduced-motion: reduce) {
  .pulse-line { animation: none; stroke-dashoffset: 0; }
}
.install-toast {
  position: fixed;
  left: 50%;
  bottom: calc(18px + env(safe-area-inset-bottom));
  transform: translateX(-50%);
  z-index: 60;
  display: flex;
  align-items: center;
  gap: 12px;
  max-width: min(420px, calc(100vw - 24px));
  padding: 12px 14px;
  border-radius: 14px;
  background: var(--surface-raised);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-card-hover);
  animation: installToastIn 0.25s ease-out;
}
.install-toast.hidden { display: none; }
.install-toast-icon {
  flex-shrink: 0;
  display: inline-flex;
  color: var(--home);
  filter: drop-shadow(0 0 6px var(--amber-dim));
}
.install-toast-body {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  font-size: 12.5px;
  line-height: 1.35;
  color: var(--chalk-muted);
}
.install-toast-body strong {
  font-size: 13.5px;
  color: var(--chalk);
}
.install-toast-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
  margin-left: auto;
}
@keyframes installToastIn {
  from { opacity: 0; transform: translateX(-50%) translateY(10px); }
  to { opacity: 1; transform: translateX(-50%) translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .install-toast { animation: none; }
}
.guard-toast-icon {
  color: var(--amber);
  filter: drop-shadow(0 0 6px var(--amber-dim));
}
.guard-toast .install-toast-body { font-size: 12.5px; }
h1 {
  font-family: var(--font-tagline);
  font-weight: 800;
  font-size: 26px;
  letter-spacing: -0.3px;
  margin: 0;
  white-space: nowrap;
}
.brand-pitch, .brand-pulse {
  /* repeat-x (not no-repeat): the sweep used to slide a 220%-wide image past
     the word with nothing behind it, so for parts of every cycle the first or
     last letters had no background and, with transparent text fill, simply
     vanished (e.g. "itchPulse"). Both gradients start and end on the base
     colour, so the tile wraps seamlessly. */
  background-repeat: repeat-x;
  background-size: 220% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  animation: brandShimmer 3.2s ease-in-out infinite;
}
.brand-pitch {
  background-image: linear-gradient(100deg, var(--brand-pitch) 32%, var(--brand-pulse) 50%, var(--brand-pitch) 68%);
}
.brand-pulse {
  background-image: linear-gradient(100deg, var(--brand-pulse) 32%, var(--brand-pitch) 50%, var(--brand-pulse) 68%);
  animation-delay: 0.2s;
}
@keyframes brandShimmer {
  /* Travels exactly one tile width (2.2 x the word: 100% -> -83.333% at a
     220% image size), so the loop restarts on an identical frame. */
  0% { background-position: 100% 0; }
  100% { background-position: -83.333% 0; }
}
@media (prefers-reduced-motion: reduce) {
  .brand-pitch, .brand-pulse { animation: none; background-position: 0 0; }
}
/* Sport-family badge — distinguishes this edition now that a
   this is the Ice Hockey edition.
   Sits inline with the h1, not in .brand-tag, since it's a fixed identity
   marker for this build, not the rotating/shimmering tagline. */
.sport-badge {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  margin-left: 8px;
  padding: 2px 7px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--line);
  background: var(--surface-raised);
  font-family: var(--font-tagline);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.3px;
  color: var(--chalk-muted);
  white-space: nowrap;
  vertical-align: middle;
}
.brand-tag {
  font-family: var(--font-tagline);
  font-size: 9px;
  font-weight: 700;
  font-style: normal;
  letter-spacing: 0.5px;
  text-transform: none;
  color: var(--chalk-muted);
  opacity: 0.8;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
/* ---------- buttons ---------- */
.btn {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 14px;
  border-radius: var(--radius);
  padding: 11px 22px;
  border: 1px solid transparent;
  cursor: pointer;
  /* Smooth deceleration curve rather than the browser's linear-ish default
     "ease" — noticeable on the press/release scale (used on nearly every
     tap in the app), even though the individual timing is unchanged. */
  transition: transform 0.15s cubic-bezier(0.16, 1, 0.3, 1), background 0.15s ease, border-color 0.15s ease;
}
.btn:active { transform: scale(0.97); }
.btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
  filter: none;
  box-shadow: none;
  transform: none !important;
}
.btn:disabled:active { transform: none; }
.btn.primary {
  background: linear-gradient(180deg, var(--primary-grad-top), var(--amber));
  color: var(--on-accent);
  font-weight: 700;
  box-shadow: 0 4px 14px -4px var(--amber-dim), inset 0 1px 0 rgba(255, 255, 255, 0.3);
  transition: box-shadow 0.15s ease, transform 0.15s cubic-bezier(0.16, 1, 0.3, 1), filter 0.15s ease;
}
.btn.primary:hover { filter: brightness(1.12) saturate(1.05); box-shadow: 0 6px 18px -4px var(--amber-dim), inset 0 1px 0 rgba(255, 255, 255, 0.35); }
.btn.primary:active { transform: scale(0.98); }

/* Loading skeleton: shown on header stat values during the Calculate button's
   spin, so the strip signals "updating" instead of sitting on stale numbers. */
.stat-skeleton {
  color: transparent !important;
  border-radius: 4px;
  background: linear-gradient(90deg, var(--line) 25%, var(--surface-raised) 50%, var(--line) 75%);
  background-size: 200% 100%;
  animation: skeletonShimmer 1.1s ease-in-out infinite;
  display: inline-block;
  min-width: 2.4em;
}
@keyframes skeletonShimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}
@media (prefers-reduced-motion: reduce) {
  .stat-skeleton { animation: none; background-position: 0 0; }
}
.btn.primary { position: relative; }
.btn.primary .btn-spinner { display: none; }
.btn.primary.loading { cursor: default; opacity: 0.85; }
.btn.primary.loading .btn-label { visibility: hidden; }
.btn.primary.loading .btn-spinner {
  display: block;
  position: absolute;
  left: 50%;
  top: 50%;
  width: 18px;
  height: 18px;
  margin: -9px 0 0 -9px;
  border: 2px solid rgba(11, 15, 20, 0.3);
  border-top-color: var(--on-accent);
  border-radius: 50%;
  animation: btn-spin 0.6s linear infinite;
}
@keyframes btn-spin { to { transform: rotate(360deg); } }
html.light .btn.primary .btn-spinner { border-color: rgba(255, 255, 255, 0.35); border-top-color: #fff; }
@media (prefers-reduced-motion: reduce) {
  .btn.primary.loading .btn-spinner { animation: none; }
}
.btn.ghost { background: transparent; color: var(--chalk); border-color: var(--line); }
.btn.ghost:hover { border-color: var(--amber-dim); }
.hidden { display: none !important; }
.head-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
.head-actions .btn:not(.icon-btn) { padding: 8px 14px; font-size: 12px; }
.btn.icon-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  padding: 0;
  border-radius: 10px;
  transition: transform 0.12s ease, background 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}
.btn.icon-btn:hover {
  background: var(--track);
  box-shadow: 0 0 0 3px var(--amber-dim);
  transform: translateY(-1px);
}
.head-actions .btn.ghost:not(.icon-btn):hover {
  background: var(--track);
  box-shadow: 0 4px 12px -6px rgba(0, 0, 0, 0.4);
}

/* ---------- head-to-head comparison card ----------
   One shared grid instead of two independent cards: team names flank a VS
   badge, then a GF row and a GA row each put the Home value on the left and
   Away value on the right of a center stat pill, with a proportional bar
   underneath and a "leader" glow on whichever side is winning that stat. */
.h2h-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  grid-template-areas:
    "homeName vs      awayName"
    "seasonHeader seasonHeader seasonHeader"
    "seasonExplainer seasonExplainer seasonExplainer"
    "seasonFields seasonFields seasonFields"
    "sectionDivider sectionDivider sectionDivider"
    "formHeader formHeader formHeader"
    "formExplainer formExplainer formExplainer"
    "formFields formFields formFields";
  column-gap: 9px;
  row-gap: 8px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 18px;
  box-shadow: var(--shadow-card);
  margin-bottom: 20px;
  transition: box-shadow 0.2s ease;
}
.h2h-card:hover { box-shadow: var(--shadow-card-hover); }
.team-card { display: contents; }

/* Emblem + name + Elo pill share this row. Emblem and Elo pill stay
   vertically centered against the name. Home/Away mirror each other:
   same template, emblem/elo columns swapped left-right. */
.h2h-name-home, .h2h-name-away {
  display: grid;
  grid-template-rows: auto auto;
  column-gap: 8px;
  row-gap: 4px;
  padding-bottom: 12px;
  border-bottom: 2px solid var(--line);
  min-width: 0;
}
.h2h-name-home {
  grid-area: homeName;
  border-bottom-color: var(--home);
  grid-template-columns: 30px 1fr auto;
  grid-template-areas: "emblem name elo";
}
.h2h-name-away {
  grid-area: awayName;
  border-bottom-color: var(--away);
  grid-template-columns: auto 1fr 30px;
  grid-template-areas: "elo name emblem";
}
.h2h-name-home .side-emblem, .h2h-name-away .side-emblem { grid-area: emblem; align-self: center; justify-self: center; }
.h2h-name-home .team-name, .h2h-name-away .team-name { grid-area: name; }
.h2h-name-home .elo-pill, .h2h-name-away .elo-pill { grid-area: elo; align-self: center; }

.side-emblem { width: 30px; height: 35px; flex-shrink: 0; }
.team-name {
  background: transparent;
  border: none;
  border-bottom: 1px solid transparent;
  color: var(--chalk);
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 700;
  width: 100%;
  min-width: 0;
  padding: 2px 0;
}
.h2h-name-away .team-name { text-align: right; }
.team-name:focus { outline: none; border-bottom-color: var(--amber-dim); }

/* Elo pill — sits at the inner edge of each team-name row (far right for
   Home, far left for Away, i.e. nearest the VS badge). Always live, no
   separate on/off switch — left blank (placeholder shows "1500") it has
   no effect; it only nudges the model once BOTH sides carry a value. */
.elo-pill {
  display: flex;
  align-items: center;
  gap: 4px;
  height: 24px;
  padding: 0 7px;
  border-radius: var(--radius-pill);
  background: var(--bg-deep);
  border: 1px solid var(--line);
  flex-shrink: 0;
}
.elo-pill-home { border-color: var(--home); }
.elo-pill-away { border-color: var(--away); }
.elo-pill-abbr {
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.3px;
  text-transform: uppercase;
  white-space: nowrap;
}
.elo-pill-home .elo-pill-abbr { color: var(--home); }
.elo-pill-away .elo-pill-abbr { color: var(--away); }
.elo-pill-input {
  width: 38px;
  background: transparent;
  border: none;
  color: var(--chalk);
  font-family: var(--font-mono);
  font-weight: 800;
  font-size: 12px;
  padding: 0;
  text-align: center;
}
.elo-pill-input:focus { outline: none; }
.elo-pill-input::placeholder { color: var(--chalk-muted); font-weight: 600; }

.h2h-vs-wrap {
  grid-area: vs;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  margin-bottom: 8px;
}
.h2h-vs {
  align-self: center;
  justify-self: center;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--home), var(--away));
  color: var(--on-accent);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-weight: 800;
  font-size: 11px;
  letter-spacing: 0.5px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
  flex-shrink: 0;
}
/* Match kickoff time — subtle, sits right under the VS badge since that's
   the natural visual center of the fixture. Optional: leaving it blank
   just means this entry won't have a kickoff time to sort the Match Log
   by (see kickoffTime in logMatchEntry / renderMatchLog's sort).
   Two small HH/MM boxes with a static ":" (see the kickoff-time-part
   handlers in app.js) instead of a native <input type="time">, which on
   mobile opens a scroll-wheel picker rather than letting you just type
   the digits — same reasoning as the form-tally mp/gf/ga boxes above. */
.kickoff-time-group { display: flex; align-items: center; justify-content: center; gap: 2px; }
.kickoff-time-part {
  width: 26px;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  color: var(--chalk-muted);
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 2px 3px;
  text-align: center;
}
.kickoff-time-part:focus { outline: none; border-color: var(--amber-dim); color: var(--chalk); }
.kickoff-time-sep { color: var(--chalk-muted); font-family: var(--font-mono); font-size: 10px; font-weight: 600; }

.hint { color: var(--chalk-muted); font-size: 12px; margin: 0; }
.match-rows { display: contents; }

/* ---------- Core Team Stats / Form Check input blocks ----------
   Each block is: header row (title left, status chip right) → one-line
   explainer → the two sides' mp/gf/ga boxes. The boxes span the card's full
   width as two halves (Home left, Away right) rather than sitting in the
   1fr/auto/1fr name columns — the middle VS column is dead space in these
   rows, and giving the boxes that width is what lets them carry real
   captions ("Played / Scored / Conceded") instead of bare MP/GF/GA.

   Colour carries meaning here, not decoration: Scored is green and Conceded
   is red everywhere else in the app (GF/GA), Played stays neutral. A box
   picks up its colour once something is typed in it, so a half-filled row
   shows at a glance what's still missing. */
.match-rows[data-rows="home"] .season-tally-field { grid-area: seasonFields; justify-self: start; }
.match-rows[data-rows="away"] .season-tally-field { grid-area: seasonFields; justify-self: end; }
.match-rows[data-rows="home"] .form-tally-field { grid-area: formFields; justify-self: start; }
.match-rows[data-rows="away"] .form-tally-field { grid-area: formFields; justify-self: end; }
.season-tally-field, .form-tally-field { width: calc(50% - 8px); min-width: 0; }
/* Vertical divider between the Home and Away rectangles, centred in the gap
   between them (the 16px left by the two half-width fields) and fading out
   at both ends. Drawn from the Home field so Away needs no extra markup. */
.match-rows[data-rows="home"] .season-tally-field,
.match-rows[data-rows="home"] .form-tally-field { position: relative; }
.match-rows[data-rows="home"] .season-tally-field::after,
.match-rows[data-rows="home"] .form-tally-field::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  right: -8.5px;
  width: 1px;
  pointer-events: none;
  background: linear-gradient(to bottom,
    transparent,
    color-mix(in srgb, var(--chalk-muted) 60%, transparent) 20%,
    color-mix(in srgb, var(--chalk-muted) 60%, transparent) 80%,
    transparent);
}
.season-tally-group, .form-tally-group {
  display: flex;
  align-items: stretch;
  justify-content: center;
  gap: 10px;
  width: 100%;
  margin-inline: auto;
  box-sizing: border-box;
  /* Rectangle enclosing each set of three boxes. Core Team Stats gets a
     side-tinted one (blue Home / orange Away, same tokens as the emblems);
     Form Check gets a plain neutral one — see the rules below. */
  padding: 9px 8px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: color-mix(in srgb, var(--chalk) 3%, transparent);
}
.season-tally-group[data-side="home"] {
  border-color: color-mix(in srgb, var(--home) 45%, transparent);
  background: color-mix(in srgb, var(--home) 11%, transparent);
}
.season-tally-group[data-side="away"] {
  border-color: color-mix(in srgb, var(--away) 45%, transparent);
  background: color-mix(in srgb, var(--away) 11%, transparent);
}

/* Which games the numbers come from — coloured by side so it reads as
   belonging to the emblem/name above, and it's the one rule new users most
   often get wrong (home games for Home, away games for Away). */
.tally-venue {
  display: block;
  margin-bottom: 7px;
  text-align: center;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.1px;
  line-height: 1.2;
}
.tally-venue-home { color: var(--home); }
.tally-venue-away { color: var(--away); }

.tally-box {
  --tb: var(--chalk-muted);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  flex: 1 1 0;
  min-width: 0;
  min-height: 56px;
  padding: 7px 2px 5px;
  background: var(--bg-deep);
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.28);
  transition: border-color 0.15s ease, background-color 0.15s ease, box-shadow 0.15s ease;
  touch-action: manipulation;
  cursor: text;
}
.tally-gf { --tb: var(--good); }
.tally-ga { --tb: var(--bad); }
/* Form Check is the quieter, optional tally: its GF / GA boxes stay neutral
   (label + filled tint) instead of the green / red used in Core Team Stats. */
.form-tally-group .tally-gf,
.form-tally-group .tally-ga { --tb: var(--chalk-muted); }
.tally-box:active { background: var(--surface-raised); }
.tally-box:focus-within {
  border-color: var(--amber);
  box-shadow: 0 0 0 3px var(--amber-dim);
}
/* Filled: tinted with the box's own colour. :placeholder-shown is false as
   soon as the box holds a value (typed, restored, or reloaded from a log
   entry), so this needs no JS. */
.tally-box:has(input:not(:placeholder-shown)) {
  border-color: color-mix(in srgb, var(--tb) 55%, var(--line));
  background: color-mix(in srgb, var(--tb) 8%, var(--bg-deep));
}
.tally-box-label {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--tb);
  line-height: 1;
  white-space: nowrap;
}
.tally-box input {
  background: transparent;
  border: none;
  color: var(--chalk);
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 18px;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
  width: 100%;
  min-width: 0;
  text-align: center;
  touch-action: manipulation;
}
.tally-box input:focus { outline: none; }
.tally-box input::placeholder {
  color: color-mix(in srgb, var(--chalk-muted) 34%, transparent);
  font-weight: 600;
}
html.light .tally-box { box-shadow: inset 0 1px 3px rgba(20, 26, 33, 0.12); }
html.light .tally-box:focus-within { box-shadow: 0 0 0 3px var(--amber-dim); }

/* Section explainer — sits directly under its header, left-aligned like the
   header, so each block reads title → what it's for → boxes. */
.h2h-section-explainer {
  margin: -3px 0 2px;
  padding: 0;
  max-width: 62ch;
  color: var(--chalk-muted);
  font-size: 12px;
  line-height: 1.45;
  text-align: left;
}
.h2h-section-explainer.season-explainer { grid-area: seasonExplainer; }
.h2h-section-explainer.form-explainer { grid-area: formExplainer; }

/* Rule between the two blocks — a soft fade instead of a hard bar, with
   room on both sides so they still read as separate, independent inputs. */
.h2h-section-divider {
  grid-area: sectionDivider;
  height: 1px;
  margin: 12px 0 6px;
  background: linear-gradient(90deg, transparent, var(--line) 14%, var(--line) 86%, transparent);
}

/* Section header: title on the left, Required/Optional chip on the right. */
.h2h-section-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin: 0;
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 700;
  color: var(--chalk);
  letter-spacing: 0.1px;
  text-align: left;
}
.h2h-section-header.season-header { grid-area: seasonHeader; }
.h2h-section-header.form-header { grid-area: formHeader; }
.h2h-section-header .section-title { display: inline-flex; align-items: center; gap: 8px; }
.h2h-section-header .card-icon-badge { color: var(--chalk-muted); }
.header-tag { font-size: 11px; font-weight: 700; letter-spacing: 0.2px; }
.header-tag-required { color: var(--bad); }
.header-tag-optional { color: var(--chalk-muted); }
/* Chip version, scoped to these two headers only — Bookmaker Odds reuses
   .header-tag as plain text. The chip flips to a green "✓ Ready" once every
   box in its block is filled (pure CSS, driven by :placeholder-shown). */
.h2h-section-header .header-tag {
  --tag-c: var(--amber-true);
  display: inline-flex;
  align-items: center;
  padding: 5px 11px;
  line-height: 1;
  border: 1px solid color-mix(in srgb, var(--tag-c) 55%, transparent);
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--tag-c) 12%, transparent);
  color: var(--tag-c);
  white-space: nowrap;
  transition: color 0.2s ease, background-color 0.2s ease, border-color 0.2s ease;
}
.h2h-section-header .header-tag-optional { --tag-c: var(--chalk-muted); }
.h2h-section-header .tag-done { display: none; }
.h2h-card:not(:has(.season-tally-part:placeholder-shown)) .season-header .header-tag,
.h2h-card:not(:has(.form-tally-part:placeholder-shown)) .form-header .header-tag { --tag-c: var(--good); }
.h2h-card:not(:has(.season-tally-part:placeholder-shown)) .season-header .tag-idle,
.h2h-card:not(:has(.form-tally-part:placeholder-shown)) .form-header .tag-idle { display: none; }
.h2h-card:not(:has(.season-tally-part:placeholder-shown)) .season-header .tag-done,
.h2h-card:not(:has(.form-tally-part:placeholder-shown)) .form-header .tag-done { display: inline; }

@media (max-width: 480px) {
  /* Score entry is the most-tapped part of the app on phones — give the
     GF/GA fields real thumb-sized targets instead of squeezing it down
     with everything else. */
  .h2h-card { padding: 14px; column-gap: 8px; row-gap: 6px; }
  /* The middle column is shared by every row (VS badge, kickoff time,
     AND the League/Cup tally / Form tally pills below) — CSS Grid sizes
     one shared track per column across all rows. A bare `auto` track
     can't shrink past its widest row's min-content, and the pill labels
     (white-space: nowrap) were by far the widest thing ever in that
     column, so the track locked in around ~135px wide on a ~335px-wide
     card — leaving barely 45px, after the emblem, for the actual name
     input on each side. minmax(0, auto) lets the track's automatic
     minimum be 0 instead of that content-driven floor, so the two name
     columns can claim their fair share; the pill labels are allowed to
     wrap under their own max-width below so they still read fine at
     whatever width the track ends up with, rather than forcing it wide. */
  .h2h-card { grid-template-columns: minmax(0, 1fr) minmax(0, auto) minmax(0, 1fr); }
  .h2h-vs { width: 32px; height: 32px; font-size: 10px; }
  .side-emblem { width: 22px; height: 26px; }
  /* Emblem + name + Elo pill sharing one row still left the name only
     ~50-60px on a typical narrow phone — not enough for "Home Team" even
     at 12.5px, so it kept falling back on the ellipsis clip. Rather than
     keep shaving pixels off emblem/pill, drop the Elo pill onto its own
     row below emblem+name — name now only has to share its row with the
     small emblem, which frees the vast majority of the column's width
     for it. */
  .h2h-name-home, .h2h-name-away {
    display: grid;
    align-items: center;
    column-gap: 6px;
    row-gap: 4px;
  }
  /* Fixed 22px for the emblem track (not "auto") — matches .side-emblem's
     own width below on purpose. With "auto", the Elo pill's row ("elo
     elo" spans both columns) pulled that column's width up toward the
     pill's own min-content size to help fit it — auto tracks absorb part
     of a spanning item's minimum width before a flexible (1fr) track
     takes any, even though the pill spans the full row either way. That
     silently ate most of the name column's space (down to ~30-50px
     regardless of screen width) and clipped the team name to a few
     characters. A fixed-length track isn't resized by a spanning item's
     content, so the name column now gets its real 1fr share. Home and
     Away mirror each other (emblem left vs. right), so the two fixed/1fr
     tracks are swapped between them to match. */
  .h2h-name-home { grid-template-columns: 22px 1fr; }
  .h2h-name-away { grid-template-columns: 1fr 22px; }
  /* Two-row layout on mobile: emblem+name share the top row, Elo pill
     gets its own row below, justified to the same side as the emblem so
     Home and Away mirror each other. */
  .h2h-name-home { grid-template-areas: "emblem name" "elo elo"; }
  .h2h-name-away { grid-template-areas: "name emblem" "elo elo"; }
  .h2h-name-home .side-emblem, .h2h-name-away .side-emblem { grid-area: emblem; }
  .h2h-name-home .team-name, .h2h-name-away .team-name { grid-area: name; }
  .h2h-name-home .elo-pill, .h2h-name-away .elo-pill { grid-area: elo; }
  .h2h-name-home .elo-pill { justify-self: end; }
  .h2h-name-away .elo-pill { justify-self: start; }
  /* The pill no longer competes with name for width, so it can keep its
     abbreviation label and normal size — only the emblem still needs to
     stay trimmed above. Team name inputs: smaller at rest so "Home
     Team"/"Away Team" (or a name close to that length) fits without
     spilling past the card edge. Ellipsis stays as a safety net for
     anything still too long (custom names up to 24 chars). Bumped back
     to 16px on :focus, since iOS Safari zooms the whole page in when a
     focused input's font-size is under 16px. */
  .team-name {
    font-size: 12.5px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .team-name:focus { font-size: 16px; }
}

/* Narrower phones: tighten the rectangle around each set of boxes. */
@media (max-width: 380px) {
  .season-tally-group, .form-tally-group { padding: 7px 6px; gap: 7px; }
  .tally-box-label { letter-spacing: 0.3px; }
}
@media (max-width: 350px) {
  .tally-venue { font-size: 10.5px; }
}

@media (min-width: 640px) {
  /* On wide screens the boxes otherwise stretch across half the card and
     end up as huge, oddly elongated tiles. Cap each side's group and centre
     it in its half, so each reads as a tight, deliberate input. Desktop has
     the room mobile doesn't, so the boxes get extra breathing room here —
     a wider gap/padding than the shared base rule (and well past the
     narrow-phone tightening below 380px) — on top of the cap above. */
  .season-tally-group, .form-tally-group { max-width: 300px; gap: 14px; padding: 10px; }
  .tally-box:hover { border-color: var(--amber-dim); }
  .tally-box:focus-within:hover { border-color: var(--amber); }
}

/* ---------- shared number-input stepper ----------
   Every number input (match rows, league avg, O/U line) gets larger custom
   +/- buttons instead of the tiny native browser spinner, and a centered value. */
.stepper { display: flex; align-items: stretch; }
.step-btn {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--surface);
  border: 1px solid var(--line);
  color: var(--chalk-muted);
  font-family: var(--font-body);
  font-size: 18px;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  user-select: none;
  transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease, transform 0.1s ease;
}
.step-btn:hover { color: var(--chalk); border-color: var(--amber-dim); }
.step-btn:active { transform: scale(0.92); background: var(--amber); border-color: var(--amber); color: var(--on-accent); }
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
input[type="number"] { -moz-appearance: textfield; }

/* ---------- league baseline ----------
   Most of the card is collapsed behind an Advanced toggle by default, so
   this is now a stacked column (header → toggle → summary or full panel)
   rather than the old side-by-side row. */
.league-bar {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 16px 18px 18px;
  margin-bottom: 16px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  box-shadow: var(--shadow-card);
}
.league-bar-head h2 {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-display);
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  margin: 0 0 4px;
}
.league-bar-head .hint { margin: 0; }

.info-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  margin-left: 2px;
  padding: 0;
  border: none;
  background: none;
  color: var(--chalk-muted);
  font-size: 13px;
  line-height: 1;
  cursor: pointer;
  border-radius: 50%;
  transition: color 0.15s ease;
}
.info-btn:hover, .info-btn:focus-visible, .info-btn[aria-expanded="true"] {
  color: var(--amber);
  outline: none;
}
.info-tooltip {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  z-index: 5;
  width: min(320px, 82vw);
  background: var(--bg-deep);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 10px 12px;
  font-family: var(--font-body);
  font-size: 12px;
  font-weight: 400;
  line-height: 1.5;
  text-transform: none;
  letter-spacing: normal;
  color: var(--chalk-muted);
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.25);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: opacity 0.12s ease, transform 0.12s ease, visibility 0.12s;
}
.info-tooltip.open {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

/* Section-header icon — plain, subtle glyph fronting each Inputs-tab card
   title (no chip/enclosure), so it reads as a quiet marker rather than a
   decoration competing with the data itself. */
.card-icon-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  color: var(--chalk-muted);
}

/* Standalone header above the Team Form card (that card has no header of
   its own — it's a grid, not a .league-bar), spaced to sit as its own
   block rather than crowd the Clear Fields row above it. position:
   relative so the "About Team Form" .info-tooltip anchors off this
   header rather than the page. */
.h2h-card-head { margin: 0 0 12px; position: relative; }
/* League Baseline header — moved outside its card, same standalone
   pattern as .h2h-card-head above Team Form: a .league-bar-head sitting
   before the section rather than inside it. */
.league-baseline-head { margin: 0 0 12px; position: relative; }

/* Thin brand-gradient spine along the top of every Inputs-tab data card,
   tying League Baseline / Team Form / Markets View together as one flow.
   Previously these cards clipped overflow to keep the spine's square
   corners from poking past the card's rounded corners — but that also
   clipped anything else that needs to escape the card's bounds, like
   info tooltips (see .info-tooltip), cutting them off instead of
   letting them float above the content below. Rounding the spine itself
   achieves the same corner-matching without clipping the whole card. */
.league-bar,
.h2h-card {
  position: relative;
}
.league-bar::before,
.h2h-card::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  border-radius: var(--radius) var(--radius) 0 0;
  background: var(--ribbon-blue-orange);
}

/* Advanced toggle row */
.lg-toggle-row { display: flex; align-items: center; gap: 10px; }
.toggle-switch { position: relative; display: inline-block; width: 36px; height: 20px; flex-shrink: 0; }
.toggle-switch input { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; z-index: 1; }
.toggle-slider {
  position: absolute;
  inset: 0;
  background: var(--bg-deep);
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  transition: background 0.2s ease, border-color 0.2s ease;
}
.toggle-slider::before {
  content: '';
  position: absolute;
  width: 14px;
  height: 14px;
  left: 2px;
  top: 2px;
  background: var(--chalk-muted);
  border-radius: 50%;
  transition: transform 0.2s ease, background 0.2s ease;
}
.toggle-switch input:checked + .toggle-slider { background: var(--amber-dim); border-color: var(--amber); }
.toggle-switch input:checked + .toggle-slider::before { transform: translateX(16px); background: var(--amber); }
.toggle-switch input:focus-visible + .toggle-slider { outline: 2px solid var(--amber-dim); outline-offset: 2px; }
.toggle-switch input:disabled { cursor: not-allowed; }
.toggle-switch input:disabled + .toggle-slider { cursor: not-allowed; opacity: 0.6; }
.toggle-label { font-size: 13px; font-weight: 600; color: var(--chalk-muted); }

/* Collapsed summary line */
.league-default-display {
  font-size: 13px;
  color: var(--chalk-muted);
  padding: 2px 0 0;
}
.league-default-display strong { color: var(--chalk); }
.league-default-hint { font-size: 11px; color: var(--chalk-muted); opacity: 0.75; margin-left: 4px; }

/* Expanded panel */
.league-advanced { padding-top: 4px; }

/* League avg (home/away goals) — one compact box instead of two full-width
   cards, so it stays a short control rather than stretching the section.
   Labels sit above the box (mirroring the Country/League pattern) and the
   box itself is held to the same 40px height as the adjacent selects, for
   uniformity across the row. */
.league-avg-col {
  display: flex;
  flex-direction: column;
  gap: 6px;
  flex: 1 1 180px;
  max-width: 260px;
  min-width: 150px;
}
.league-avg-labels {
  display: flex;
  align-items: center;
}
.league-avg-box {
  display: flex;
  height: 40px;
  background: var(--bg-deep);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}
.league-avg-half {
  flex: 1 1 50%;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background 0.15s ease;
}
.league-avg-half.side-away {
  border-left: 1px solid rgba(255, 255, 255, 0.28);
}
html.light .league-avg-half.side-away { border-left-color: rgba(16, 21, 31, 0.22); }
.league-avg-half:focus-within { background: rgba(255, 255, 255, 0.03); }
html.light .league-avg-half:focus-within { background: rgba(16, 21, 31, 0.03); }
.league-avg-label {
  flex: 1 1 50%;
  display: flex;
  align-items: center;
  gap: 5px;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--chalk-muted);
}
.league-avg-label i { font-style: normal; opacity: 0.7; margin-left: 2px; }
.league-avg-dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; }
.side-home .league-avg-dot { background: var(--home); box-shadow: 0 0 6px var(--home); }
.side-away .league-avg-dot { background: var(--away); box-shadow: 0 0 6px var(--away); }
.side-home .league-avg-label { color: var(--home); }
.side-away .league-avg-label { color: var(--away); }
.league-avg-box input {
  width: 100%;
  background: transparent;
  border: none;
  color: var(--chalk);
  font-family: var(--font-mono);
  font-weight: 800;
  font-size: 15px;
  padding: 0;
  text-align: center;
}
.league-avg-box .side-home input { color: var(--home); }
.league-avg-box .side-away input { color: var(--away); }
.league-avg-box input:focus { outline: none; }

/* Quick shortcut beside the box: flip on to remember these averages as this
   league's default (same action as the Manage Leagues "Save" button below —
   this just surfaces it right where the numbers are being typed). */
.league-save-toggle-wrap {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}
.league-save-toggle-wrap.disabled { opacity: 0.4; }
.league-save-toggle-label {
  font-size: 9.5px;
  font-weight: 700;
  line-height: 1.25;
  color: var(--chalk-muted);
  text-transform: uppercase;
  letter-spacing: 0.3px;
}

/* 6th column: plain checkbox (deliberately not the pill toggle-switch used
   elsewhere) — flags this specific match as being played at a neutral venue,
   which blends leagueHome/leagueAway into one shared baseline for both
   sides in runModel() rather than touching either team's own GF/GA input. */
.league-neutral-wrap {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}
.league-neutral-check {
  display: flex;
  align-items: center;
  cursor: pointer;
}
.league-neutral-check input[type="checkbox"] {
  width: 18px;
  height: 18px;
  accent-color: var(--amber);
  cursor: pointer;
}
.league-neutral-label {
  font-size: 9.5px;
  font-weight: 700;
  line-height: 1.25;
  color: var(--chalk-muted);
  text-transform: uppercase;
  letter-spacing: 0.3px;
}
.league-select-row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin: 0 0 12px;
}
.league-select-row .setting-input { flex: 1 1 120px; min-width: 108px; }
.league-select-row .league-avg-col { flex: 1 1 180px; }
.league-select-row .league-save-toggle-wrap { flex-shrink: 0; }
.league-select-row .league-neutral-wrap { flex-shrink: 0; }
.league-select-row select {
  background: var(--bg-deep);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--chalk);
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 13px;
  padding: 10px 10px;
  height: 40px;
  width: 100%;
}
.league-select-row select:disabled { opacity: 0.5; }
.league-select-row select:focus { outline: none; border-color: var(--amber-dim); }
.btn.small { padding: 8px 14px; font-size: 12px; }

/* ---------- shared setting inputs (league avg, O/U line) ---------- */
.setting-input {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--chalk-muted);
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.setting-input span i { font-style: normal; opacity: 0.7; }
.setting-input .stepper {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--bg-deep);
}
.setting-input .stepper:focus-within { border-color: var(--amber); box-shadow: 0 0 0 3px var(--amber-dim); }
.setting-input .step-btn {
  width: 38px;
  height: 38px;
  font-size: 20px;
  background: var(--surface);
  border: none;
  border-radius: 0;
}
.setting-input .step-btn:active { background: var(--amber); color: var(--on-accent); }
.setting-input input {
  width: 72px;
  background: transparent;
  border: none;
  border-left: 1px solid var(--line);
  border-right: 1px solid var(--line);
  color: var(--chalk);
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: 15px;
  padding: 8px 4px;
  text-align: center;
}
.setting-input input:focus { outline: none; }

/* ---------- compute bar ---------- */
.compute-bar {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: 18px;
  margin: 0 0 10px;
  flex-wrap: wrap;
}
.compute-bar .btn.primary { padding: 13px 34px; font-size: 15px; }

.clear-fields-row { display: flex; justify-content: center; margin: -4px 0 16px; }

/* ---------- most likely score hero card ---------- */
.ps-hero {
  background: var(--surface-raised);
  border: 1px solid rgba(29, 177, 255, 0.25);
  border-radius: var(--radius);
  padding: 24px 18px;
  text-align: center;
  margin-bottom: 16px;
  box-shadow: var(--shadow-card);
}
.ps-hero-top {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin-bottom: 14px;
}
.ps-eyebrow {
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--amber);
  opacity: 0.8;
}
.ps-teams-row {
  display: flex;
  align-items: stretch; /* crests stay level even if one name wraps to 2 lines */
  justify-content: center;
  gap: 18px;
  margin-bottom: 14px;
}
.ps-team-col {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  align-items: center;
  gap: 6px;
  flex: 1;
  min-width: 0;
}
.ps-emblem { width: 64px; height: 74px; flex-shrink: 0; }
.ps-team {
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  max-width: 100%;
  text-align: center;
  /* (line-height deliberately inherited, as before -- single-line names must
     render exactly as they did.) */
  /* Wrap at spaces, up to 2 lines, ellipsis only past that. It used to be a
     single nowrap line, so any name wider than its (then very narrow) column
     was cut off. overflow-wrap:break-word is only the last resort for one
     unbroken word wider than the whole column. */
  white-space: normal;
  overflow-wrap: break-word;
  overflow: hidden;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
}
.ps-team.home { color: var(--home); }
.ps-team.away { color: var(--away); }
/* SOURCE-ORDER FIX: this base rule used to sit AFTER the @media (max-width:
   480px) block below. Equal specificity means the later rule wins, so the
   block's `.ps-scoreline { font-size: 1.7rem; letter-spacing: .5px }` was
   silently cancelled and every phone rendered the desktop 44.8px scoreline
   (150px wide) -- leaving the two team-name columns only 70-85px each, which
   is what clipped names like "Crystal Palace" / "Wolverhampton" to "CRYSTAL P...".
   Same trap the .ps-team / .ps-hero notes below describe; moved up here so
   the override applies as it was always meant to. */
.ps-scoreline {
  font-family: var(--font-mono);
  font-size: 2.8rem;
  font-weight: 800;
  color: var(--chalk);
  letter-spacing: 3px;
  line-height: 1;
  flex-shrink: 0;
  align-self: center; /* columns can now differ in height (2-line names) */
}
/* The mobile block only helps viewports <= 480px, but at ~700-1100px the
   Model Comparison tab goes side-by-side and each hero card is only ~350-410px
   wide -- the same squeeze, with no override at all. So the cards are size
   containers and shrink their own scoreline/emblems by the CARD's width
   (see the @container rule after the mobile block). Browsers without
   container queries just keep the media-query behaviour. */
.ps-hero { container-type: inline-size; container-name: ps-hero; }
@media (max-width: 480px) {
  .ps-hero-top { flex-wrap: wrap; justify-content: center; gap: 8px; }
  .ps-eyebrow { text-align: center; }
  /* Was gated at max-width:380px, but most phones report a CSS viewport
     width above that (360-412px is typical) — so this whole block,
     including the font-size fix below, silently never fired on a normal
     phone. Widened to 480px to match every other mobile breakpoint in
     this file (see .h2h-card, .ps-hero-top's own sibling rules below,
     etc.) so it actually applies on the devices it was written for.
     NOTE: this block used to sit BEFORE the base .ps-team rule above.
     With equal selector specificity, source order decides ties — so the
     later base rule always won and silently cancelled this override
     (same bug as the Model Comparison hero's emblem/scoreline fix on the
     Pro line — see that fix's changelog note). Moved here, after the
     base rule, so it actually applies. */
  .ps-teams-row { gap: 6px; }
  /* Names wrap at spaces (max 2 lines -- see the base .ps-team rule above)
     rather than truncating on one row; dropping to 11px here buys extra
     room before a long single word would need to break. */
  .ps-team { font-size: 11px; }
  /* .ps-scoreline is flex-shrink:0 by design (never squish the actual
     score digits) and .ps-emblem was a fixed 64px (46px here before this
     fix) — between them they were still claiming most of a narrow
     phone's row width even after the gap/name shrinks above, leaving too
     little for ps-team to show even a short name like "Home Team" before
     its own ellipsis kicked in harder than intended. Shrinking both is
     what actually fixes that — ported from the Pro line's own fix for
     this same card, which hit and solved this exact gap first. */
  .ps-scoreline { font-size: 1.7rem; letter-spacing: 0.5px; }
  .ps-emblem { width: 30px; height: 35px; }
  /* Even after the shrink above, 360-412px phones (the actual bulk of
     the market) were still only leaving ~55-65px per team-name column —
     enough for "HOME TE…" before the ellipsis, not "HOME TEAM". The
     hero's own left/right padding was the last easy width to claw back:
     it doesn't hold any content of its own, unlike the emblem/scoreline
     above which do. Trimming it here (24px 18px -> 16px 8px) hands that
     ~20px straight to the two name columns without touching anything
     that's actually rendering. */
  .ps-hero { padding: 16px 8px; }
}
/* Container-width sizing for the two hero cards lives right here, after the
   mobile block -- see the note on .ps-scoreline above the block. */
@container ps-hero (max-width: 440px) {
  .ps-teams-row { gap: 6px; }
  .ps-team { font-size: 11px; }
  .ps-scoreline { font-size: 1.7rem; letter-spacing: 0.5px; }
  .ps-emblem { width: 30px; height: 35px; }
}
.ps-divider { height: 1px; background: var(--line); margin: 14px 0 10px; }
.ps-caption { font-size: 11px; color: var(--chalk-muted); letter-spacing: 0.5px; }
.xg-pill-row {
  display: flex;
  align-items: stretch;
  justify-content: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 18px;
}
.xg-pill {
  background: rgba(29, 177, 255, 0.07);
  border: 1px solid rgba(29, 177, 255, 0.18);
  border-radius: var(--radius);
  padding: 10px 16px;
  min-width: 90px;
  text-align: center;
}
.xg-pill-label {
  font-family: var(--font-body);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--chalk-muted);
  margin-bottom: 4px;
}
.xg-pill-val { font-size: 17px; font-weight: 800; color: var(--chalk); letter-spacing: 0.5px; }
.xg-pill-val.accent { color: var(--amber); }
.xg-pill-sub { font-size: 10px; font-weight: 600; color: var(--chalk-muted); margin-top: 3px; letter-spacing: 0.3px; }
.xg-pill-sub:empty { display: none; }
.xg-pill.home { background: rgba(29, 177, 255, 0.07); border-color: rgba(29, 177, 255, 0.22); }
.xg-pill.home .xg-pill-val { color: var(--home); }
.xg-pill.draw { background: rgba(245, 200, 66, 0.08); border-color: rgba(245, 200, 66, 0.25); }
.xg-pill.draw .xg-pill-val { color: var(--draw); }
.xg-pill.away { background: rgba(255, 107, 53, 0.08); border-color: rgba(255, 107, 53, 0.25); }
.xg-pill.away .xg-pill-val { color: var(--away); }

/* ---------- results ---------- */

.engine-readout {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  margin-bottom: 22px;
}
@media (max-width: 680px) {
  .engine-readout { grid-template-columns: repeat(2, 1fr); }
}
.readout-item {
  background: var(--surface);
  padding: 14px 10px;
  text-align: center;
}
.readout-item.highlight { background: var(--surface-raised); }
.readout-item .label {
  display: block;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--chalk-muted);
  margin-bottom: 6px;
}
.readout-item .value {
  display: block;
  font-family: var(--font-mono);
  font-size: 18px;
  font-weight: 600;
  color: var(--amber);
}
.readout-item .value.small {
  font-size: 13px;
  font-weight: 500;
  color: var(--chalk-muted);
}

.markets-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
  margin-bottom: 28px;
}
@media (max-width: 680px) {
  .markets-grid { grid-template-columns: 1fr; }
}
.market-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 16px 18px 18px;
  box-shadow: var(--shadow-card);
}
.market-card h2 {
  font-family: var(--font-display);
  font-size: 15px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  margin: 0 0 12px;
  font-weight: 700;
}
.market-card h2 .muted { font-family: var(--font-mono); font-size: 11px; color: var(--chalk-muted); text-transform: none; letter-spacing: 0; }

/* ---------- Collapsible card (EV Finder & De-Vig on the Verdict tab) ----------
   Same visual language as the FAQ/Help accordion below, but for a single
   card's whole body rather than a list of items. Collapsed by default. */
.collapsible-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  cursor: pointer;
  user-select: none;
  margin: 0 0 12px;
}
.collapsible-head h2 { margin: 0; }
.collapsible-chevron {
  font-size: 13px;
  color: var(--amber);
  flex-shrink: 0;
  line-height: 1;
  transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}
.collapsible-card.open .collapsible-chevron { transform: rotate(90deg); }
.collapsible-body {
  max-height: 0;
  overflow: hidden;
  opacity: 0;
  transition: max-height 0.4s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s ease;
}
.collapsible-card.open .collapsible-body { max-height: 3000px; opacity: 1; }
.ev-devig-subhead { margin-top: 18px; }
.ev-devig-subhead h3 {
  font-family: var(--font-display);
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  margin: 0 0 6px;
  font-weight: 700;
}
/* Bookmaker De-Vig is hidden from view (per request) but its DOM stays
   in place — renderDevig() still populates it in the background, since
   Model Comparison's "Market Implied" column and the Model Comparison
   log both depend on that data. */
.ev-devig-hidden { display: none; }

/* ---------- 1X2 outcome tiles (ported from ScoreMatrix) ---------- */
.outcome-tiles {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
}
.o-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: 14px 8px 12px;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: var(--bg-deep);
  position: relative;
  overflow: hidden;
}
.o-tile::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 4px;
}
.o-tile.home::before { background: var(--home); }
.o-tile.draw::before { background: var(--draw); }
.o-tile.away::before { background: var(--away); }
.o-tile.home { border-color: rgba(29, 177, 255, 0.25); }
.o-tile.draw { border-color: rgba(245, 200, 66, 0.25); }
.o-tile.away { border-color: rgba(255, 107, 53, 0.25); }
/* Wraps the card (.o-tile) with its label above and its descriptive tag
   (Favorite/Unlikely/etc.) below, both outside the card itself — so the
   card's own contents stay down to just the % and its fair decimal odds. */
.o-tile-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
}
.o-tile-wrap.home .o-tile-label { color: var(--home); }
.o-tile-wrap.draw .o-tile-label { color: var(--draw); }
.o-tile-wrap.away .o-tile-label { color: var(--away); }
.o-tile-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--chalk-muted);
}
.o-tile-pct {
  font-family: var(--font-mono);
  font-size: 26px;
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.5px;
}
/* Very narrow phones (320px-class screens): three 26px-percentage tiles need
   ~335px of card, wider than the screen leaves, so the Model Comparison tab
   scrolled sideways. Tighter card/tile padding and a 20px percentage make the
   1X2 row fit; 360px+ phones are untouched. */
@media (max-width: 340px) {
  .market-card { padding: 14px 12px 16px; }
  .outcome-tiles { gap: 6px; }
  .o-tile { padding: 12px 4px 10px; }
  .o-tile-pct { font-size: 20px; }
}
.o-tile.home .o-tile-pct { color: var(--home); }
.o-tile.draw .o-tile-pct { color: var(--draw); }
.o-tile.away .o-tile-pct { color: var(--away); }
/* Fair decimal odds implied by the probability directly above (1/p) — same
   number the Verdict tab's fairOdds() shows for a Best Bet, just surfaced
   here per-outcome so the whole 1X2/O-U/BTTS board reads in both formats
   at once instead of only percentages. */
.o-tile-odds {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 700;
  color: var(--chalk-muted);
  letter-spacing: 0.1px;
}
.o-tile-tag {
  font-size: 10.5px;
  font-weight: 600;
  color: var(--chalk-muted);
  letter-spacing: 0.2px;
}

/* ---------- split pills: Over/Under and BTTS, each outcome standalone ----------
   Colored green at >=60% probability, red below 60% — independently per side,
   so e.g. "Over 71% / Under 29%" renders green + red, not paired opposites. */
.split-pill-row {
  display: flex;
  gap: 10px;
}
/* Wraps the card (.split-pill) with its label (Over/Under/Yes/No) above and
   its descriptive tag (Toss-up/Likely/etc.) below, both outside the card —
   mirrors .o-tile-wrap's treatment of the 1X2 tiles, so the card itself
   holds only the % and its fair decimal odds, plus the bar underneath. */
.split-pill-wrap {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 6px;
}
.split-pill-label {
  font-size: 12px;
  color: var(--chalk-muted);
  text-align: center;
}
.split-pill {
  background: var(--bg-deep);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 10px 12px;
}
.split-pill-value-row {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 8px;
  margin-bottom: 8px;
}
.split-pill-value-row b {
  color: var(--chalk);
  font-family: var(--font-mono);
  font-size: 15px;
  font-weight: 700;
}
/* Fair decimal odds, sat right next to the % it corresponds to (see
   .o-tile-odds for the same idea on the 1X2 tiles). */
.split-pill-odds {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 700;
  color: var(--chalk-muted);
}
.split-pill-bar {
  height: 8px;
  border-radius: var(--radius-pill);
  overflow: hidden;
  background: var(--track);
}
.split-pill-bar > span {
  display: block;
  height: 100%;
  width: 0%;
  border-radius: var(--radius-pill);
  transition: width 0.4s ease, background 0.2s ease;
  background: var(--bad);
}
.split-pill-tag {
  text-align: center;
  font-size: 10.5px;
  font-weight: 600;
  color: var(--chalk-muted);
  letter-spacing: 0.2px;
}
.split-pill.good .split-pill-value-row b { color: var(--good); }
.split-pill.good .split-pill-value-row b::before { content: "▲ "; font-size: 0.75em; }
.split-pill.good .split-pill-bar > span { background: var(--good); }
.split-pill.bad .split-pill-value-row b { color: var(--bad); }
.split-pill.bad .split-pill-value-row b::before { content: "▼ "; font-size: 0.75em; }
.split-pill.bad .split-pill-bar > span { background: var(--bad); }

/* ---------- BTTS card footer: fills the leftover space under the two
   pills with two small derived stats instead of empty air. ---------- */
.market-extra {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px dashed var(--line);
  display: flex;
  flex-direction: column;
  gap: 9px;
}
.market-extra-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 10px;
}
.market-extra-label {
  font-size: 11.5px;
  color: var(--chalk-muted);
  letter-spacing: 0.2px;
}
.market-extra-value {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 700;
  color: var(--chalk);
  white-space: nowrap;
}
.market-extra-value.good { color: var(--good); }
.market-extra-value.good::before { content: "▲ "; font-size: 0.8em; }
.market-extra-value.bad { color: var(--bad); }
.market-extra-value.bad::before { content: "▼ "; font-size: 0.8em; }

.top-scores {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.top-scores li {
  display: flex;
  justify-content: space-between;
  font-family: var(--font-mono);
  font-size: 13px;
  padding: 6px 10px;
  background: var(--bg-deep);
  border-radius: var(--radius);
}
.top-scores li b { color: var(--amber); }

/* ---------- header stats strip: computed λ + Best Bet ----------
   Lives inline in the header row now, centered between the logo and the
   action buttons — one flat divided pill, label stacked over value, thin
   vertical hairlines between stats. Mirrors ScoreMatrix's header-center
   strip, including its narrow-screen fallback (a condensed duplicate strip
   docked under the header instead of squeezing into the row). */
.ss-panel {
  display: grid;
  grid-template-columns: 1fr 1.05fr 1.55fr 1.05fr;
  background: linear-gradient(180deg, var(--surface-raised), var(--surface));
  border: 1px solid var(--line);
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.05) inset, 0 6px 18px -10px rgba(0, 0, 0, 0.5);
  flex: 1 1 auto;
  max-width: 690px;
  min-width: 0;
}
.ss-item {
  padding: 7px 12px 8px;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 2px;
  position: relative;
  min-width: 0;
  border-left: 1px solid var(--line);
  transition: background 0.15s ease;
}
.ss-item:first-child { border-left: none; }
.ss-item:hover { background: rgba(255, 255, 255, 0.025); }
html.light .ss-item:hover { background: rgba(16, 21, 31, 0.03); }
.ss-label {
  font-family: var(--font-body);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--chalk-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ss-sym { text-transform: none; }
.ss-value {
  font-family: var(--font-mono);
  font-size: 14px;
  font-weight: 800;
  letter-spacing: 0.2px;
  color: var(--chalk);
}
.ss-value.home { color: var(--home); }
.ss-value.away { color: var(--away); }
/* Combined λ Home/Away item — replaces the old two separate ss-item
   columns with one, so the header strip has room for Top EV (see
   .ss-item.ss-topev below) without crowding four items into five slots. */
.ss-value.lambdas {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 10px;
}
.ss-value.lambdas .home { color: var(--home); }
.ss-value.lambdas .away { color: var(--away); }
.ss-lambda-sep { color: var(--chalk-muted); opacity: 0.6; }
.ss-value.expscore {
  font-family: var(--font-body);
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 6px;
  font-size: 12px;
  min-width: 0;
}
/* PP Exp. Score pill reuses the same colour convention as the Model
   Comparison tab's column header (.mc-col-head-pp) — --home blue — so it
   reads consistently with that tab. The Top EV pill uses --good green,
   matching the positive-EV colour used on the EV Finder table/Verdict tab. */
.exp-score-pill {
  font-family: var(--font-mono);
  font-weight: 800;
  padding: 2px 9px;
  border-radius: var(--radius-pill);
  line-height: 1.3;
}
.exp-score-pill.pp { color: var(--home); background: var(--home-dim); }
.exp-score-pill.ev { color: var(--good); background: rgba(0, 212, 139, 0.14); }
/* Top EV ↔ Best Bet agreement — lit up in updateHeaderTopEV whenever Top
   EV's category matches window._lastBestBet's pick. Green (not the Best
   Bet item's own gold) so the two "this item is notable" treatments in the
   strip stay visually distinct — gold means the top-3 scorelines are
   unanimous, green here means the two independent rankings (probability
   vs. entered odds) happen to agree on the same market. */
.ss-item.ss-topev { position: relative; overflow: hidden; transition: background 0.25s ease, box-shadow 0.25s ease; }
.ss-item.ss-topev.matches-bestbet {
  background: linear-gradient(180deg, rgba(0, 212, 139, 0.14), rgba(0, 212, 139, 0.03));
  box-shadow: inset 0 0 0 1px rgba(0, 212, 139, 0.4);
}
.ss-topev-match {
  font-size: 11px;
  line-height: 1;
  cursor: help;
  filter: grayscale(0) drop-shadow(0 0 3px rgba(0, 212, 139, 0.6));
}
.ss-value.bestbet {
  font-family: var(--font-body);
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 6px;
  font-size: 12px;
  color: var(--draw);
  min-width: 0;
}
#ssBestBetLabel { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; max-width: 150px; }
#ssBestBetLabel-m { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; max-width: 90px; }
.bestbet-pct {
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 700;
  color: var(--chalk-muted);
  flex-shrink: 0;
  padding: 1px 6px;
  border-radius: 20px;
  background: var(--track);
}
.bestbet-pct.good { color: var(--good); background: rgba(0, 212, 139, 0.14); }
.bestbet-pct.good::before { content: "▲ "; font-size: 0.8em; }
.bestbet-pct.bad { color: var(--bad); background: rgba(255, 68, 102, 0.14); }
.bestbet-pct.bad::before { content: "▼ "; font-size: 0.8em; }

/* Best Bet confirmation — a shimmering gold highlight that plays when the
   model's 3rd most likely scoreline independently agrees with the Best Bet
   pick (the "confirmed" class, toggled in updateHeaderStats). Unconfirmed
   state stays visually quiet — no border, no shimmer, no glow. */
.ss-item.ss-bestbet {
  position: relative;
  overflow: hidden;
  transition: background 0.25s ease, box-shadow 0.25s ease;
}
.ss-item.ss-bestbet.confirmed {
  background: linear-gradient(180deg, rgba(245, 200, 66, 0.14), rgba(245, 200, 66, 0.03));
  box-shadow: inset 0 0 0 1px rgba(245, 200, 66, 0.4);
}
.ss-item.ss-bestbet.confirmed::after {
  content: "";
  position: absolute;
  top: 0;
  left: -60%;
  width: 45%;
  height: 100%;
  background: linear-gradient(115deg, transparent, rgba(255, 255, 255, 0.55), transparent);
  animation: bestBetShimmer 2.8s ease-in-out infinite;
  pointer-events: none;
}
@keyframes bestBetShimmer {
  0% { left: -60%; }
  55% { left: 130%; }
  100% { left: 130%; }
}
@media (prefers-reduced-motion: reduce) {
  .ss-item.ss-bestbet.confirmed::after { animation: none; display: none; }
}

/* Strong Agreement banner — fires on the Verdict card only when both
   independent reads (top-3 scorelines and the de-vigged market) back the
   same pick at once. Sits above the verdict card itself (see
   #verdictTripleBadge in renderVerdict) so it's the first thing seen
   when it fires; empty/no markup the rest of the time, so it never
   reserves layout space it isn't using. */
.verdict-triple-agree {
  position: relative;
  overflow: hidden;
  margin-bottom: 10px;
  padding: 9px 14px;
  border-radius: 10px;
  border: 1px solid rgba(245, 200, 66, 0.55);
  background: linear-gradient(135deg, rgba(245, 200, 66, 0.18), rgba(245, 200, 66, 0.05));
  box-shadow: 0 0 0 1px rgba(245, 200, 66, 0.25), 0 1px 2px rgba(0, 0, 0, 0.15);
  font-size: 12.5px;
  font-weight: 700;
  text-align: center;
  color: var(--chalk);
  letter-spacing: 0.1px;
}
.verdict-triple-agree strong { color: #f5c842; }
.verdict-triple-agree::after {
  content: "";
  position: absolute;
  top: 0;
  left: -60%;
  width: 35%;
  height: 100%;
  background: linear-gradient(115deg, transparent, rgba(255, 255, 255, 0.45), transparent);
  animation: bestBetShimmer 3.4s ease-in-out infinite;
  pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
  .verdict-triple-agree::after { animation: none; display: none; }
}
/* v8.1: light mode — the bright #f5c842 gold on a pale gold wash was nearly
   invisible, and the white shimmer washed the text out. Use a deep amber for the
   highlighted pick, a firmer border/fill, and a much fainter shimmer. */
html.light .verdict-triple-agree {
  border-color: rgba(168, 92, 0, 0.6);
  background: linear-gradient(135deg, rgba(245, 200, 66, 0.38), rgba(245, 200, 66, 0.16));
  box-shadow: 0 0 0 1px rgba(168, 92, 0, 0.18), 0 1px 2px rgba(0, 0, 0, 0.10);
}
html.light .verdict-triple-agree strong { color: #8a4b00; }
html.light .verdict-triple-agree::after {
  background: linear-gradient(115deg, transparent, rgba(255, 255, 255, 0.18), transparent);
}

/* Mobile condensed duplicate strip — hidden on wider screens where the
   in-header .ss-panel already fits; shown below the header on narrow ones.
   2-column grid: Lambdas (H/A) / PP Exp. Score share row 1, Best Bet spans
   the full width on row 2, Top EV spans the full width on row 3 — each
   item gets a full half- or full-width column instead of a quarter, since
   a score pill plus a percentage badge doesn't fit comfortably four-across
   on a phone. */
.ss-panel-mobile {
  display: none;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}
.ss-panel-mobile .ss-item { padding: 8px 8px 9px; border-radius: 0; }
.ss-panel-mobile .ss-item.ss-lambdas { border-left: none; }
.ss-panel-mobile .ss-item.ss-ppscore { border-left: 1px solid var(--line); }
.ss-panel-mobile .ss-value.bestbet { font-size: 11px; }
.ss-panel-mobile .ss-value.expscore { font-size: 12px; }
.ss-panel-mobile .exp-score-pill { white-space: nowrap; }
.ss-panel-mobile .ss-item.ss-bestbet,
.ss-panel-mobile .ss-item.ss-topev {
  grid-column: span 2;
  border-top: 1px solid var(--line);
  border-left: none;
}

/* The width-only check above targets portrait phones. A phone rotated to
   landscape is often 740-920px wide — past that cutoff — but still short
   (usually well under 500px tall), so it was falling through to the
   horizontal .ss-panel built for tablet/desktop widths with no room for
   four KPI tiles plus the brand and theme toggle (cramped header reported
   on a landscape phone). A genuine tablet/desktop at a similar width is
   always much taller (e.g. iPad landscape is ~1024x768), so max-height is
   a safe way to catch "phone turned sideways" without also catching those. */
@media (max-width: 720px), (max-height: 500px) and (orientation: landscape) {
  .ss-panel { display: none; }
  .ss-panel-mobile { display: grid; }
  .site-head-row { justify-content: space-between; }
}

/* ---------- Bet Summary: empty state ---------- */
.empty-state { padding: 40px 10px; text-align: center; }
.empty-state .hint { margin: 0; }

/* ---------- Match Verdict ---------- */
.verdict-card {
  background: linear-gradient(135deg, rgba(29, 177, 255, 0.06), rgba(29, 177, 255, 0));
}
.verdict-inner {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 16px 18px;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  border-left: 4px solid var(--amber);
}
.verdict-eyebrow {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  margin-bottom: 5px;
}
.verdict-label { font-size: 19px; font-weight: 800; color: var(--chalk); line-height: 1.2; }
.verdict-sub { font-size: 12px; color: var(--chalk-muted); margin-top: 3px; }
.verdict-pct-wrap { text-align: right; flex-shrink: 0; margin-left: auto; }
.verdict-pct { font-family: var(--font-mono); font-size: 28px; font-weight: 800; line-height: 1; }
.verdict-fair { font-size: 11px; color: var(--chalk-muted); margin-top: 3px; }

/* Red, same family as .verdict-market-disagree above — this is the "⚠"
   divergence warning, so it shouldn't share the blue primary accent. */

/* Form Check's own footnote line (see renderFormCheck) reuses this class —
   small, muted caption text under its verdict line. */
.h2h-footnote {
  font-size: 11px;
  line-height: 1.6;
  color: var(--chalk-muted);
  margin-top: 8px;
  margin-bottom: 0;
}

/* Draw Watch — Draw was this fixture's most likely single result but
   didn't qualify (see buildDrawWatch in best-bet.js), so something else
   won Best Bet or nothing did. A muted, dashed transparency note, not a
   caution about the pick itself. */
.verdict-drawwatch {
  font-size: 12px;
  line-height: 1.6;
  color: var(--chalk-muted);
  background: rgba(148, 163, 184, 0.08);
  border: 1px dashed var(--line);
  border-radius: var(--radius);
  padding: 8px 10px;
  margin-top: 10px;
}

/* Model-vs-market disagreement (v7.2) — red-tinted caution, flag only; it
   never changes the pick or stake. */
.verdict-disagree {
  font-size: 12px;
  line-height: 1.6;
  color: var(--chalk);
  background: rgba(239, 68, 68, 0.10);
  border: 1px solid rgba(239, 68, 68, 0.35);
  border-left: 3px solid #ef4444;
  border-radius: var(--radius);
  padding: 8px 10px;
  margin-top: 10px;
}

/* Level-match caution — faint amber tint so it's easy to spot among
   the other plain verdict notes. Flag only; never changes the pick. */
.verdict-levelmatch {
  font-size: 12px;
  line-height: 1.6;
  color: var(--chalk);
  background: rgba(255, 180, 40, 0.12);
  border: 1px solid rgba(255, 180, 40, 0.38);
  border-left: 3px solid var(--amber-true);
  border-radius: var(--radius);
  padding: 8px 10px;
  margin-top: 10px;
}

/* Market agreement note — informational only, never feeds Best Bet's own
   pick (see renderVerdictMarketNote). Empty/no-note state collapses to
   nothing via :empty so it doesn't leave a gap before odds are entered.
   Base rule sets the shared shape/spacing; the tier-N rules that follow
   layer in strength — see MARKET_AGREE_STRENGTH_BANDS/
   MARKET_DISAGREE_STRENGTH_BANDS in app.js. Tier 1 (Slight) is the
   faintest treatment either way; tier 3 (Strong) is the boldest. */
#verdictMarketNote:empty { display: none; }
.verdict-market-note {
  font-size: 12px;
  line-height: 1.6;
  border-radius: var(--radius);
  padding: 8px 10px;
  margin-top: 10px;
  border: 1px solid transparent;
}
.verdict-market-tier {
  font-weight: 700;
  text-transform: uppercase;
  font-size: 10px;
  letter-spacing: 0.4px;
  opacity: 0.85;
}
.verdict-market-agree {
  color: var(--chalk-muted);
  background: rgba(0, 212, 139, 0.05);
  border-color: rgba(0, 212, 139, 0.22);
}
.verdict-market-agree.tier-2 {
  color: var(--chalk);
  background: rgba(0, 212, 139, 0.09);
  border-color: rgba(0, 212, 139, 0.38);
}
.verdict-market-agree.tier-3 {
  color: var(--chalk);
  background: rgba(0, 212, 139, 0.20);
  border-color: var(--good);
  box-shadow: inset 3px 0 0 var(--good);
  font-weight: 600;
}
.verdict-market-disagree {
  color: var(--chalk-muted);
  background: rgba(255, 68, 102, 0.05);
  border-color: rgba(255, 68, 102, 0.22);
}
.verdict-market-disagree.tier-2 {
  color: var(--chalk);
  background: rgba(255, 68, 102, 0.09);
  border-color: rgba(255, 68, 102, 0.38);
}
.verdict-market-disagree.tier-3 {
  color: var(--chalk);
  background: rgba(255, 68, 102, 0.20);
  border-color: var(--bad);
  box-shadow: inset 3px 0 0 var(--bad);
  font-weight: 600;
}
.verdict-market-empty {
  color: var(--chalk-muted);
  background: rgba(148, 163, 184, 0.06);
  border: 1px dashed var(--line);
}

/* EV line under the market note — the pick's own price/EV at whatever odds
   are entered for it on the EV Finder, so the note answers "worth backing
   at this price" on top of "does the market agree". Sits directly under
   the note it belongs to, so no top margin of its own. */
.verdict-market-ev {
  font-size: 12px;
  line-height: 1.5;
  color: var(--chalk-muted);
  padding: 2px 10px 0;
}
.verdict-market-ev-pos { color: var(--good); font-weight: 700; }
.verdict-market-ev-neg { color: var(--bad); font-weight: 700; }

/* ---------- Best Bet: "Why this pick?" breakdown ---------- */
.bb-details {
  margin-top: 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-raised);
  overflow: hidden;
}
.bb-details summary {
  cursor: pointer;
  list-style: none;
  padding: 10px 12px;
  font-size: 12px;
  font-weight: 700;
  color: var(--chalk-muted);
  display: flex;
  align-items: center;
  gap: 6px;
}
.bb-details summary::-webkit-details-marker { display: none; }
.bb-details summary::before {
  content: "▸";
  display: inline-block;
  transition: transform 0.15s ease;
  color: var(--amber);
}
.bb-details[open] summary::before { transform: rotate(90deg); }
.bb-details summary:hover { color: var(--chalk); }
.bb-table { padding: 0 10px 10px; }
.bb-row {
  display: grid;
  grid-template-columns: 1.3fr 0.75fr 0.75fr 0.8fr 0.75fr 0.9fr;
  gap: 6px;
  align-items: center;
  padding: 6px 2px;
  border-top: 1px solid var(--line);
  font-size: 11px;
  font-family: var(--font-mono);
}
.bb-row-head {
  font-family: var(--font-body);
  font-size: 10px;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--chalk-muted);
  border-top: none;
  font-weight: 700;
}
.bb-row-cat { font-family: var(--font-body); font-weight: 600; color: var(--chalk); }
.bb-row-cell { color: var(--chalk-muted); text-align: right; }
.bb-row-score { color: var(--chalk); font-weight: 700; }
.bb-row-winner { background: rgba(0, 212, 139, 0.07); border-radius: 6px; }
.bb-row-winner .bb-row-cat { color: var(--good); }

.bb-row-ineligible { opacity: 0.55; }
/* v9.9: Min odds column — stays at full strength on dimmed rows, it is the useful number there */
.bb-row-minodds { color: var(--amber-true); font-weight: 700; }
.bb-row-ineligible .bb-row-minodds { opacity: 1; }
.bb-row-have { display: block; font-size: 8.5px; font-weight: 400; color: var(--chalk-muted); }

.bb-legend { font-size: 10px; color: var(--chalk-muted); padding: 6px 10px 10px; line-height: 1.5; }

@media (max-width: 480px) {
  .bb-row { grid-template-columns: 1.15fr 0.72fr 0.72fr 0.8fr 0.72fr 0.85fr; font-size: 9.5px; gap: 3px; }
}

/* ---------- Signal Check ---------- */
.signal-badge {
  display: inline-block;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.6px;
  padding: 3px 10px;
  border-radius: 20px;
  background: var(--surface-raised);
  border: 1px solid var(--line);
}
.signal-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.signal-note { font-size: 12px; color: var(--chalk-muted); line-height: 1.6; margin-top: 8px; }

/* ---------- Match Log ---------- */
.ml-panel-header { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 12px; flex-wrap: wrap; }
.ml-panel-header-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; justify-content: flex-end; }
.ml-filter-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 12px;
}
.ml-filter-label {
  font-size: 11.5px;
  font-weight: 700;
  color: var(--chalk-muted);
  white-space: nowrap;
}
.ml-filter-row select {
  background: var(--bg-deep);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--chalk);
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 12px;
  padding: 7px 8px;
  height: 32px;
}
.ml-filter-row select:focus { outline: none; border-color: var(--amber-dim); }
.ml-filter-count {
  font-size: 11px;
  color: var(--chalk-muted);
  margin-left: auto;
  white-space: nowrap;
}
.ml-stats-bar {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 10px 12px;
  margin-bottom: 12px;
  background: var(--surface-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  flex-wrap: wrap;
}
.ml-stat { display: flex; flex-direction: column; align-items: center; gap: 2px; }
.ml-stat-val { font-family: var(--font-mono); font-size: 16px; font-weight: 800; }
.ml-stat-val.hit-val { color: var(--good); }
.ml-stat-val.miss-val { color: var(--bad); }
.ml-stat-val.rate-val { color: var(--amber); }
.ml-stat-label { font-size: 10px; color: var(--chalk-muted); letter-spacing: 0.5px; text-transform: uppercase; }
.ml-stat-divider { width: 1px; height: 22px; background: var(--line); }
.ml-empty { color: var(--chalk-muted); font-size: 13px; text-align: center; padding: 18px 0; margin: 0; }

/* Parlay bar — appears once at least one Match Log entry is checked via
   .ml-entry-select. Purely a selection/share tool: it doesn't affect
   Best Bet, grading, or anything else in the log. */
.ml-parlay-bar {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 10px 12px;
  margin-bottom: 12px;
  background: linear-gradient(180deg, rgba(245, 200, 66, 0.1), var(--surface-raised) 70%);
  border: 1px solid var(--amber-dim);
  border-radius: var(--radius);
  flex-wrap: wrap;
}
.ml-parlay-count { font-size: 12px; font-weight: 700; color: var(--chalk); white-space: nowrap; }
.ml-parlay-count b { color: var(--amber); font-family: var(--font-mono); }
.ml-parlay-metric { font-size: 11.5px; color: var(--chalk-muted); white-space: nowrap; }
.ml-parlay-metric b { color: var(--chalk); font-family: var(--font-mono); }
.ml-parlay-actions { display: flex; gap: 6px; flex-wrap: wrap; margin-left: auto; }
@media (max-width: 520px) {
  .ml-parlay-bar { gap: 8px; }
  .ml-parlay-actions { margin-left: 0; width: 100%; }
}

.ml-entry-select-wrap { display: flex; align-items: flex-start; padding-top: 2px; }
.ml-entry-select { width: 17px; height: 17px; accent-color: var(--amber); cursor: pointer; flex-shrink: 0; }
.ml-entry.ml-entry-picked {
  border-color: var(--amber-dim);
  box-shadow: 0 0 0 1px var(--amber-dim), 0 1px 2px rgba(0, 0, 0, 0.15);
}
.ml-entry {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 12px;
  margin-bottom: 8px;
  background: var(--bg-deep);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
}
.ml-entry:last-child { margin-bottom: 0; }
.ml-entry-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; }
.ml-entry-main { flex: 1; min-width: 0; }
.ml-entry-fixture { font-size: 13px; font-weight: 700; }
.ml-team-home { color: var(--home); }
.ml-team-away { color: var(--away); }
.ml-vs { color: var(--chalk-muted); font-weight: 600; margin: 0 5px; font-size: 11px; text-transform: uppercase; }
/* Entry header = names, then three tidy rows (badges / league+time / stats)
   instead of one run-on inline line that wrapped mid-list on phones and left
   separators dangling at line ends (see mlBadgesHtml / mlMetaHtml in app.js).
   Rules that fight the older single-class badge rules below (margin-left) are
   written with an extra .ml-entry-main so they win regardless of source order. */
.ml-entry-main .ml-entry-badges { display: flex; flex-wrap: wrap; align-items: center; gap: 5px; margin-top: 6px; }
.ml-entry-main .ml-entry-badges > * { margin-left: 0; }
.ml-entry-meta { font-size: 11px; color: var(--chalk-muted); display: flex; flex-direction: column; gap: 7px; } /* a direct child of .ml-entry now, so its 10px flex gap already spaces it */
/* League left, time right -- no "·" separator to strand at a line end. If
   the league name is long it wraps inside its own space and the time stays put. */
.ml-entry-when { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; }
.ml-when-league { min-width: 0; overflow-wrap: anywhere; }
.ml-when-time { flex-shrink: 0; white-space: nowrap; opacity: 0.85; }
.ml-entry-stats { display: flex; flex-wrap: wrap; gap: 5px; }
/* λ / Form / Mkt as small pills, same surface + border as the score boxes
   below, so a chip wraps as a whole and never mid-figure. */
.ml-entry-stats > .ml-lambda,
.ml-entry-stats > .ml-score-chip {
  display: inline-block;
  padding: 3px 8px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 6px;
}
/* Top EV gets its own full-width row: label + market on the left, % (and the
   Best-Bet match marker) on the right. */
.ml-stat-ev {
  flex: 1 1 100%;
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  padding: 4px 8px;
  background: rgba(34, 197, 94, 0.10);
  border: 1px solid rgba(34, 197, 94, 0.30);
  border-radius: 6px;
}
.ml-stat-ev .ml-topev { flex: 1; min-width: 0; display: flex; align-items: baseline; gap: 6px; }
.ml-stat-ev .ml-topev-market { min-width: 0; overflow-wrap: anywhere; }
.ml-stat-ev .ml-topev-pct { margin-left: auto; white-space: nowrap; }
.ml-stat-ev .ml-topev-match { margin-left: 0; flex-shrink: 0; }
.ml-lambda { color: var(--chalk); font-family: var(--font-mono); font-weight: 600; white-space: nowrap; } /* nowrap: on narrow phones the meta line wraps between chips, never mid-figure */
.ml-lambda-home { color: var(--home); }
.ml-lambda-away { color: var(--away); }
.ml-lambda-sep { color: var(--chalk); opacity: 0.55; }
/* Form Check / Market Expected top-score chips (see mlScoreChip in app.js) —
   same mono figure style as the λ chip, each value in its own colour with a
   muted label; nowrap keeps a chip from splitting across lines on phones. */
.ml-score-chip { font-family: var(--font-mono); font-weight: 600; white-space: nowrap; cursor: help; }
.ml-score-label { color: var(--chalk-muted); font-weight: 600; opacity: 0.85; }
.ml-form-score .ml-score-val { color: var(--form-score); font-weight: 700; }
.ml-mkt-score .ml-score-val { color: var(--mkt-score); font-weight: 700; }
/* Top EV, sat next to λ in the Match Log meta row — the highest positive-EV
   market at log time (see topEvLabel/topEvValue in addToMatchLog), in
   --good green to match the EV Finder table and Verdict tab's own
   positive-EV colour convention. Three-part treatment (muted "Top EV"
   label / bright market name / green pct) mirrors the header strip's own
   Top EV item, so the market name doesn't just blend into the label as
   one run-on phrase. */
.ml-topev { font-family: var(--font-mono); font-weight: 600; cursor: help; }
.ml-topev-label { color: var(--chalk-muted); font-weight: 600; opacity: 0.85; white-space: nowrap; }
.ml-topev-market { color: var(--chalk); font-weight: 700; }
.ml-topev-pct { color: var(--good); }
.ml-topev-match { font-size: 11px; margin-left: 3px; cursor: help; }

/* Confirmed match log entries — flagged when a logged pick's Best Bet was
   independently corroborated by the model's 3rd most likely scoreline.
   Gold border/glow plus the same shimmer sweep as the header Best Bet
   stat, so it's unmistakable against ordinary entries in the log. */
.ml-entry.ml-entry-confirmed {
  position: relative;
  overflow: hidden;
  border-color: rgba(245, 200, 66, 0.55);
  background: linear-gradient(180deg, rgba(245, 200, 66, 0.09), var(--bg-deep) 60%);
  box-shadow: 0 0 0 1px rgba(245, 200, 66, 0.25), 0 1px 2px rgba(0, 0, 0, 0.15);
}
.ml-entry.ml-entry-confirmed::after {
  content: "";
  position: absolute;
  top: 0;
  left: -60%;
  width: 35%;
  height: 100%;
  background: linear-gradient(115deg, transparent, rgba(255, 255, 255, 0.35), transparent);
  animation: bestBetShimmer 3.4s ease-in-out infinite;
  pointer-events: none;
}
.ml-confirmed-badge {
  display: inline-flex;
  align-items: center;
  margin-left: 7px;
  padding: 1px 7px;
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: 0.4px;
  color: #10151f;
  background: linear-gradient(135deg, #f5c842, #ffe08a);
  border-radius: 20px;
  vertical-align: middle;
  gap: 3px;
}
.ml-confirmed-star { width: 1.25em; height: 1.25em; flex-shrink: 0; }
@media (prefers-reduced-motion: reduce) {
  .ml-entry.ml-entry-confirmed::after { animation: none; display: none; }
}
/* Market agreement badge (see marketStatus in addToMatchLog) — sits in the
   fixture row. marketFairProb is stored on the entry but has no dedicated
   display of its own; only this agree/disagree badge is shown. */
.ml-mkt-badge {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  margin-left: 7px;
  padding: 1px 7px;
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: 0.3px;
  border-radius: 20px;
  vertical-align: middle;
  cursor: help;
}
.ml-mkt-badge.ml-mkt-disagree { color: var(--bad); background: rgba(239, 68, 68, 0.12); border: 1px solid rgba(239, 68, 68, 0.35); }
.ml-mkt-badge.ml-mkt-agree { color: var(--good); background: rgba(34, 197, 94, 0.12); border: 1px solid rgba(34, 197, 94, 0.35); }

/* Form Check badge (class name kept from an earlier feature this was
   shared with). Base style is green, for "Form Check agreed with the
   pick" — see the .ml-h2h-disagree variant below for "diverged". */
.ml-h2h-badge {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  margin-left: 7px;
  padding: 1px 7px;
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: 0.3px;
  border-radius: 20px;
  vertical-align: middle;
  cursor: help;
  color: var(--good);
  background: rgba(34, 197, 94, 0.12);
  border: 1px solid rgba(34, 197, 94, 0.35);
}
/* "Diverge" variant — same badge, red rather than green, for a pick where
   Form Check favored a different market than the one that got logged (see
   formCheckAgrees in logMatchEntry). Same red as .ml-mkt-disagree. */
.ml-h2h-badge.ml-h2h-disagree {
  color: var(--bad);
  background: rgba(239, 68, 68, 0.12);
  border: 1px solid rgba(239, 68, 68, 0.35);
}

/* Kickoff-time chip — same sizing as the badges above, but purely
   informational (not an agree/disagree signal), so it gets its own
   neutral mono styling rather than reusing the green/amber/gray states.
   This is what renderMatchLog's sort (see the "ordered" array) actually
   orders the Match Log by, earliest first — see kickoffTime in
   logMatchEntry/#matchKickoffTime on the Inputs tab. */
.ml-kickoff-badge {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  margin-left: 7px;
  padding: 1px 7px;
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.2px;
  border-radius: 20px;
  vertical-align: middle;
  cursor: help;
  color: var(--chalk);
  background: var(--surface-raised);
  border: 1px solid var(--line);
}
/* Second row: Top Score / 2nd Score / 3rd Score / Bet Pick / Save. Five
   columns — Save gets a touch more room since it holds an input+button. */
.ml-entry-grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1.3fr;
  gap: 10px;
}
.ml-col {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 7px 8px;
  min-width: 0;
}
.ml-col-label {
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--chalk-muted);
  margin-bottom: 4px;
  white-space: nowrap;
}
.ml-col-value {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 700;
  color: var(--chalk);
  display: flex;
  align-items: baseline;
  gap: 6px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ml-col-bet { font-family: var(--font-body); }
/* Bet Pick column: the label (e.g. a long team name + "Win") truncates on
   its own with an ellipsis, while the probability badge is pinned at
   flex-shrink:0 so it's never the part that gets clipped when the
   fixture's team names are long. */
.ml-col-bet-label {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ml-col-bet .ml-col-sub { flex-shrink: 0; }
.ml-col-sub { font-size: 10.5px; font-weight: 600; color: var(--amber); }
.ml-col-ht { border-color: rgba(245, 200, 66, 0.35); }
.ml-col-save { display: flex; flex-direction: column; }
.ml-save-row { display: flex; gap: 5px; }
.ml-entry-score {
  width: 100%;
  min-width: 0;
  padding: 6px 6px;
  border-radius: 6px;
  border: 1px solid var(--line);
  background: var(--bg-deep);
  color: var(--chalk);
  font-family: var(--font-mono);
  font-size: 12px;
  text-align: center;
}
.ml-entry-score:focus { outline: none; border-color: var(--amber-dim); }
.ml-entry-save {
  flex-shrink: 0;
  font-family: var(--font-body);
  font-size: 12px;
  font-weight: 700;
  color: var(--on-accent);
  background: var(--amber);
  border: none;
  border-radius: 6px;
  padding: 6px 10px;
  cursor: pointer;
  transition: filter 0.15s ease, transform 0.15s cubic-bezier(0.16, 1, 0.3, 1);
}
.ml-entry-save:hover { filter: brightness(1.15); }
.ml-entry-save:active { transform: scale(0.96); }
.ml-entry-outcome { display: block; font-size: 10.5px; font-weight: 700; white-space: nowrap; margin-top: 5px; }
.ml-entry-outcome.hit { color: var(--good); }
.ml-entry-outcome.miss { color: var(--bad); }
.ml-entry-outcome.pending { color: var(--chalk-muted); }
@media (max-width: 560px) {
  .ml-entry-grid { grid-template-columns: repeat(2, 1fr); }
  .ml-col-save { grid-column: 1 / -1; }
}
.ml-entry-del {
  background: transparent;
  border: none;
  color: var(--chalk-muted);
  cursor: pointer;
  font-size: 15px;
  line-height: 1;
  padding: 4px 6px;
  flex-shrink: 0;
}
.ml-entry-del:hover { color: var(--bad); }

/* Reload Fixture — repopulates the Inputs tab from a logged entry's saved
   fixtureInputs snapshot (see reloadFixtureFromLog / reloadFixtureFromArchive)
   so odds can be added later without retyping team/GF-GA/league data. */
.ml-entry-reload-row { margin: 4px 0 8px; }
/* Uses a genuinely amber accent (--amber-true — see its definition up top;
   the plain --amber token is actually blue) rather than the Pro violet —
   violet inside a Match Log entry now specifically flags the highest-edge
   chip in the Top 3 strip below, so Reload Fixture needed its own color
   to avoid looking like part of that same signal. */
.ml-entry-reload {
  background: transparent;
  border: 1px dashed var(--amber-true-dim);
  color: var(--amber-true);
  cursor: pointer;
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
  padding: 5px 10px;
  border-radius: var(--radius);
}
.ml-entry-reload:hover { background: var(--amber-true-dim); }

/* Top 3 markets (by edge) strip — a snapshot of the "Why this pick?"
   breakdown's leading rows, taken at the moment a fixture was logged, so
   the Match Log keeps the full-picture context and not just the single
   Best Bet pick. */
.ml-top3-markets {
  border-top: 1px dashed var(--line);
  padding-top: 9px;
  margin-top: 1px;
}
.ml-top3-label {
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--chalk-muted);
  margin-bottom: 6px;
}
.ml-top3-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
}
.ml-mkt-chip {
  display: flex;
  align-items: center;
  gap: 6px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 6px 8px;
  min-width: 0;
  flex-wrap: wrap;
}
.ml-mkt-vs { flex: 0 0 100%; display: flex; justify-content: space-between; align-items: baseline; gap: 8px; padding-left: 21px; font-family: var(--font-mono); font-size: 9.5px; line-height: 1.2; }
.ml-mkt-be { color: var(--pro); font-weight: 600; }
.ml-mkt-ce { color: var(--good); font-weight: 600; text-align: right; }
.ml-mkt-ce-neg { color: var(--bad); }
.ml-mkt-chip-top { border-color: rgba(0, 212, 139, 0.35); background: rgba(0, 212, 139, 0.06); }
/* Whichever of the 3 chips has the single highest edge value — independent
   of rank #1, since the strip is ordered by hybrid score, not raw excess
   (see renderTop3MarketsHtml), so the biggest edge doesn't always land on
   the top-pick chip above. Same border+background treatment as
   .ml-mkt-chip-top, just in the Pro violet accent already used for
   excess/Value-Signal elsewhere on the Verdict tab (var(--pro-dim) /
   var(--pro-tint), same tokens .verdict-excesspick uses) so "biggest edge"
   reads as the same concept in both places. */
.ml-mkt-chip-maxedge { border-color: var(--pro-dim); background: var(--pro-tint); }
.ml-mkt-chip-maxedge .ml-mkt-rank { background: var(--pro); color: #fff; }
.ml-mkt-chip-maxedge .ml-mkt-excess { color: var(--pro); font-weight: 700; }
/* Rare case: the top-ranked chip also happens to carry the single highest
   edge. Rather than one color silently winning, layer a violet ring over
   the green fill so both facts (top pick AND biggest edge) stay visible. */
.ml-mkt-chip-top.ml-mkt-chip-maxedge { box-shadow: inset 0 0 0 1px var(--pro); }
.ml-mkt-rank {
  flex-shrink: 0;
  width: 15px;
  height: 15px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 9.5px;
  font-weight: 800;
  color: var(--bg-deep);
  background: var(--chalk-muted);
  border-radius: 50%;
}
.ml-mkt-chip-top .ml-mkt-rank { background: var(--good); }
.ml-mkt-name {
  flex: 1;
  min-width: 0;
  font-size: 11px;
  font-weight: 600;
  color: var(--chalk);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ml-mkt-prob { font-family: var(--font-mono); font-size: 11px; font-weight: 700; color: var(--chalk); flex-shrink: 0; }
.ml-mkt-chip-below .ml-mkt-name, .ml-mkt-chip-below .ml-mkt-prob { opacity: 0.7; }
.ml-mkt-excess { font-family: var(--font-mono); font-size: 9.5px; color: var(--chalk-muted); flex-shrink: 0; }
@media (max-width: 560px) {
  .ml-top3-row { grid-template-columns: 1fr; }
}
.ml-add-row { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 10px; margin-top: 14px; }

/* ---------- Calibration modal ---------- */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 50;
  padding: 20px;
}
.modal-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  max-width: 480px;
  width: 100%;
  max-height: 82vh;
  overflow-y: auto;
  padding: 20px;
}
.modal-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; }
.modal-head h2 { margin: 0; font-size: 15px; }
.modal-card-narrow { max-width: 380px; }
.modal-card-wide { max-width: 900px; }
.install-help-note { font-size: 12.5px; color: var(--chalk-muted); line-height: 1.6; margin: 0 0 14px; }
.install-help-title { font-size: 13px; margin: 0 0 8px; color: var(--chalk); }
.install-help-steps { margin: 0; padding-left: 20px; display: flex; flex-direction: column; gap: 8px; }
.install-help-steps li { font-size: 13px; line-height: 1.55; color: var(--chalk); }
.install-help-steps strong { color: var(--amber); font-weight: 700; }
.calib-group { margin-bottom: 4px; }
.calib-group-title {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--chalk-muted);
  margin-top: 14px;
  margin-bottom: 2px;
}
.calib-group:first-child .calib-group-title { margin-top: 0; }
.calib-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 10px 0;
  border-bottom: 1px solid var(--line);
}
.calib-row:last-child { border-bottom: none; }
.calib-market { font-size: 13px; font-weight: 700; color: var(--chalk); }
.calib-market-n { font-size: 11px; color: var(--chalk-muted); font-weight: 400; margin-left: 4px; }
.calib-scores { display: flex; gap: 16px; text-align: right; }
.calib-scores div { display: flex; flex-direction: column; align-items: flex-end; }
.calib-scores .cs-label { font-size: 10px; color: var(--chalk-muted); text-transform: uppercase; letter-spacing: 0.5px; }
.calib-scores .cs-val { font-family: var(--font-mono); font-size: 14px; font-weight: 800; color: var(--chalk); }
.calib-elo-split {
  flex-basis: 100%;
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 6px 8px;
  margin-top: 2px;
  background: var(--panel-2, rgba(255,255,255,0.03));
  border-radius: 6px;
  font-size: 11px;
}
.calib-elo-split .cs-label { font-size: 10px; color: var(--chalk-muted); text-transform: uppercase; letter-spacing: 0.4px; }
.calib-elo-split .cs-val { font-family: var(--font-mono); font-size: 12px; font-weight: 700; color: var(--chalk); margin-right: auto; }
.calib-elo-split .cs-val:last-child { margin-right: 0; }
.calib-empty { color: var(--chalk-muted); font-size: 13px; text-align: center; padding: 20px 0; }
.calib-note { font-size: 11px; color: var(--chalk-muted); line-height: 1.6; margin-top: 14px; }

/* Reliability curve rows — reuses .split-pill-bar for the fill bars */
.reliab-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 0;
  border-bottom: 1px solid var(--hairline, rgba(255,255,255,0.06));
}
.reliab-row:last-child { border-bottom: none; }
.reliab-range { font-size: 12px; font-weight: 700; color: var(--chalk); width: 72px; flex-shrink: 0; }
.reliab-bars { flex: 1; display: flex; flex-direction: column; gap: 3px; }
.reliab-bar-line { display: flex; align-items: center; gap: 6px; }
.reliab-bar-label { font-size: 9px; color: var(--chalk-muted); text-transform: uppercase; letter-spacing: 0.4px; width: 50px; flex-shrink: 0; }
.reliab-bar-line .split-pill-bar { flex: 1; }
.reliab-bar-val { font-family: var(--font-mono); font-size: 10px; color: var(--chalk-muted); width: 42px; text-align: right; flex-shrink: 0; }
.reliab-diff { font-family: var(--font-mono); font-size: 12px; font-weight: 800; width: 56px; text-align: right; flex-shrink: 0; color: var(--chalk-muted); }
.reliab-diff.good { color: var(--good); }
.reliab-diff.bad { color: var(--bad); }

.modal-head-actions { display: flex; align-items: center; gap: 8px; }
.archive-intro { font-size: 11px; color: var(--chalk-muted); line-height: 1.6; margin: 0 0 14px; }
.archive-day {
  padding: 10px 0;
  border-bottom: 1px solid var(--line);
}
.archive-day:last-child { border-bottom: none; }
.archive-day-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
}
.archive-day-head { display: flex; flex-direction: column; gap: 2px; }
.archive-day-date { font-size: 13px; font-weight: 700; color: var(--chalk); font-family: var(--font-mono); }
.archive-day-count { font-size: 11px; color: var(--chalk-muted); }
.archive-day-actions { display: flex; gap: 8px; flex-shrink: 0; }
.archive-day-entries {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px dashed var(--line);
}
.archive-day-entries .ml-entry:last-child { margin-bottom: 0; }
/* The archive modal has more room to breathe than the inline Match Log
   card, but its score-editing row (5 read-only stat cells + the Save
   input/button cell) was still inheriting the same tight 6-across grid,
   which squeezed every label and value into ~70px on the modal's old
   480px width — hence the overlapping "SCORE (ESTOP SCORE" mess. The
   modal is now wider (see .modal-card-wide) and this row gets its own,
   roomier 3-across layout instead of reusing the cramped default. */
.archive-day-entries .ml-entry-grid {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}
.archive-day-entries .ml-col { padding: 9px 10px; }
.archive-day-entries .ml-col-save { grid-column: span 1; }
@media (max-width: 640px) {
  .archive-day-entries .ml-entry-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .archive-day-entries .ml-col-save { grid-column: 1 / -1; }
}
.archive-day-toggle.expanded { color: var(--amber); border-color: var(--amber-dim); }

/* ---------- Help tab ---------- */
.help-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 10px;
}
.help-lede { color: var(--chalk-muted); font-size: 12px; line-height: 1.7; margin: 0 0 14px; }
.help-steps p { font-size: 13px; color: var(--chalk-muted); line-height: 1.75; margin: 0 0 10px; }
.help-steps p:last-child { margin-bottom: 0; }
.help-step-title { color: var(--chalk); font-weight: 700; }

/* ---------- FAQ / Help accordion ---------- */
.faq-item, .hg-item {
  border-left: 3px solid var(--amber);
  margin-bottom: 10px;
  background: var(--surface-raised);
  border-radius: 0 var(--radius) var(--radius) 0;
  overflow: hidden;
  transition: border-color 0.15s ease;
}
.faq-item:hover, .hg-item:hover { border-left-color: var(--away); }
.faq-q, .hg-q {
  font-size: 13px;
  font-weight: 700;
  color: var(--chalk);
  background: rgba(29, 177, 255, 0.08);
  cursor: pointer;
  padding: 13px 14px 13px 16px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  user-select: none;
  transition: background 0.15s ease, color 0.15s ease;
}
.faq-q:hover, .hg-q:hover { background: rgba(29, 177, 255, 0.15); }
.faq-item.open .faq-q, .hg-item.open .hg-q { background: rgba(29, 177, 255, 0.18); }
.faq-q::after, .hg-q::after {
  content: '▸';
  font-size: 12px;
  color: var(--amber);
  flex-shrink: 0;
  line-height: 1;
  transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}
.faq-item.open .faq-q::after, .hg-item.open .hg-q::after { transform: rotate(90deg); }
.faq-a, .hg-a {
  font-size: 12px;
  color: var(--chalk-muted);
  line-height: 1.75;
  padding: 0 16px;
  background: var(--surface);
  max-height: 0;
  overflow: hidden;
  opacity: 0;
  border-top: 0 solid var(--line);
  transition: max-height 0.4s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s ease, padding 0.35s ease, border-top-width 0.35s ease;
}
.faq-item.open .faq-a, .hg-item.open .hg-a {
  max-height: 1200px;
  opacity: 1;
  padding: 12px 16px 14px;
  border-top-width: 1px;
}
.faq-a strong, .hg-a strong { color: var(--chalk); }
.faq-item.disclaimer { border-left-color: var(--bad); }
.faq-item.disclaimer .faq-q { color: var(--bad); }
.faq-item.contact { border-left-color: var(--good); }
.faq-item.contact .faq-q { color: var(--good); }
.contact-links { display: flex; flex-direction: column; gap: 8px; margin-top: 4px; }
.contact-links a {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  text-decoration: none;
  font-weight: 600;
  font-size: 12px;
}
.contact-links a.mail { color: var(--amber); }
/* WhatsApp's brand green (#25d366) is fine on the dark theme but only ~2:1
   against white, so in light mode it glared and was hard to read. Same hue
   (142deg), darkened to ~5.3:1 on --surface (the FAQ answer background) --
   see the html.light override just below. The icon follows the text colour
   (its inline fill="#25d366" is only a no-CSS fallback). */
:root { --wa-green: #25d366; }
html.light { --wa-green: #0e7c36; }
.contact-links a.whatsapp { color: var(--wa-green); }
.contact-links a.whatsapp svg { fill: currentColor; }
.contact-links a.phone { color: var(--chalk-muted); }

/* ---------- footer ---------- */
.site-foot { margin-top: 50px; border-top: 1px solid var(--line); background: var(--bg-deep); }
.site-foot .wrap { padding: 32px 20px 20px; }
.site-foot p { margin: 0; color: var(--chalk-muted); font-size: 12px; }

.footer-grid {
  display: flex;
  justify-content: center;
}
.footer-col-brand { text-align: center; }
.footer-brand-mark { display: inline-flex; align-items: stretch; gap: 8px; margin-bottom: 6px; }

.footer-brand-word {
  font-family: var(--font-tagline);
  font-weight: 800;
  font-size: 17px;
}
.footer-about-text { max-width: 320px; margin: 0 auto; line-height: 1.6; }

.footer-copyright {
  margin-top: 18px;
  padding-top: 12px;
  border-top: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  font-size: 11px;
  color: var(--chalk-muted);
  opacity: 0.8;
}
.footer-copyright-note { font-size: 10px; opacity: 0.85; }
.footer-version {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  color: var(--chalk-muted);
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  padding: 1px 7px;
  vertical-align: middle;
}

@media (max-width: 640px) {
  .footer-grid { text-align: center; }
}

/* ---------------------------------------------------------
   Markets View — compact odds entry sitting right below the Team
   Form card on the Inputs tab. Deliberately minimal (three short
   rows, no probability/EV math shown here) since its only job is
   to catch the odds once; evOdds is the shared store, so typing
   here is what drives the EV Finder card's ranked results on the
   Verdict tab — see .marketsview-odds-input's listener in app.js
   and handleMarketsViewOddsInput().

   Split into three labeled, colour-coded groups (1X2 / Total Goals /
   BTTS) instead of one undifferentiated stack of grey pills — each
   field carries a small persistent badge (1/X/2, Over/Under, BTTS-Y/
   BTTS-N) tinted to match its market, reusing colours already
   established elsewhere in the app (--home/--draw/--away for match
   result, the same green/red pairing Team Form's GF/GA bars use for
   "more" vs "less") so this reads as the same visual language, not a
   new one. The badge stays visible once odds are typed (unlike the old
   placeholder-only labelling, which vanished the moment you had a real
   price in the field, leaving a bare number with no context on
   re-visit).
--------------------------------------------------------- */
.marketsview-card { padding-top: 14px; padding-bottom: 16px; gap: 14px; }
/* Single row: all 7 odds fields (1/X/2, Over/Under, BTTS-Y/BTTS-N) side
   by side, with a thin vertical rule marking the boundary between the
   three markets. The old per-group captions (Match Winner 1X2 / Goals
   O/U 2.5 / BTTS Y/N) don't fit above a flattened row, so the
   persistent mv-badge labels inside each field now carry the market
   identity on their own.

   Fields are nested in a .mv-group wrapper per market (1X2 / O-U / BTTS).
   On wide screens .mv-group is `display: contents`, so it's invisible to
   layout and the 7 fields sit flush in one flex row exactly as before.
   Below the mobile breakpoint, .mv-group becomes a real grid and
   .marketsview-row stacks — three short, comfortably-sized rows instead
   of squeezing all 7 fields onto one line (see media query below). */
.marketsview-row { display: flex; align-items: stretch; gap: 6px; }
.mv-group { display: contents; }
.marketsview-divider {
  align-self: center;
  width: 1px;
  height: 28px;
  background: var(--line);
  flex: 0 0 auto;
}
@media (max-width: 480px) {
  .marketsview-row { flex-direction: column; align-items: stretch; gap: 10px; }
  .mv-group { display: grid; gap: 6px; }
  .mv-group-1x2 { grid-template-columns: repeat(3, 1fr); }
  .mv-group-ou, .mv-group-btts { grid-template-columns: repeat(2, 1fr); }
  .marketsview-divider { display: none; }
  .marketsview-field { padding: 9px 6px; gap: 5px; }
}
.marketsview-field {
  position: relative;
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  padding: 8px 6px;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: var(--surface);
  transition: border-color 0.15s ease, background 0.15s ease;
  cursor: text;
  touch-action: manipulation;
}
.marketsview-field:focus-within {
  border-color: var(--mv-accent, var(--amber));
  background: var(--surface-raised);
}
/* Badge now sits centered above the input (part of the same centered
   column) instead of pinned to the field's top-left corner — reads as
   a proper label for the slot underneath it rather than a small corner
   tag, and keeps the whole field's contents on one shared centerline.
   Sized by its own content (min-width, not a fixed square) since 1/X/2
   are single characters but Over/Under/BTTS-Y/BTTS-N are full words —
   a fixed square either clipped the longer labels or left the short
   ones swimming in extra padding. */
.mv-badge {
  position: static;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 6px;
  border-radius: var(--radius-pill);
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 700;
  line-height: 1;
  white-space: nowrap;
  color: var(--mv-accent, var(--chalk-muted));
  background: var(--mv-accent-dim, var(--track));
}
/* Over/Under/BTTS-Y/BTTS-N are full words rather than single letters —
   a touch smaller so they sit comfortably inside the pill instead of
   crowding it, while 1/X/2 above keep the larger single-character size. */
.mv-over .mv-badge,
.mv-under .mv-badge,
.mv-btts-yes .mv-badge,
.mv-btts-no .mv-badge {
  font-size: 10px;
  letter-spacing: 0.2px;
}
/* The green/red pills used the same hue for text and tinted background, so
   the words barely stood out. Lift the text toward white (dark theme) or
   deepen it toward black (light theme) so it contrasts with its own pill.
   Literal colours first as a fallback for browsers without color-mix(). */
.mv-over .mv-badge,
.mv-btts-yes .mv-badge { color: #86f2c9; }
.mv-under .mv-badge,
.mv-btts-no .mv-badge { color: #ffa3b4; }
@supports (color: color-mix(in srgb, red, blue)) {
  .mv-over .mv-badge,
  .mv-under .mv-badge,
  .mv-btts-yes .mv-badge,
  .mv-btts-no .mv-badge { color: color-mix(in srgb, var(--mv-accent) 40%, #fff); }
}
html.light .mv-over .mv-badge,
html.light .mv-btts-yes .mv-badge { color: #005a30; }
html.light .mv-under .mv-badge,
html.light .mv-btts-no .mv-badge { color: #96002a; }
@supports (color: color-mix(in srgb, red, blue)) {
  html.light .mv-over .mv-badge,
  html.light .mv-under .mv-badge,
  html.light .mv-btts-yes .mv-badge,
  html.light .mv-btts-no .mv-badge { color: color-mix(in srgb, var(--mv-accent) 60%, #000); }
}
.mv-home { --mv-accent: var(--home); --mv-accent-dim: var(--home-dim); }
.mv-draw { --mv-accent: var(--draw); --mv-accent-dim: var(--draw-dim); }
.mv-away { --mv-accent: var(--away); --mv-accent-dim: var(--away-dim); }
.mv-over,
.mv-btts-yes { --mv-accent: var(--good); --mv-accent-dim: var(--gf-tint); }
.mv-under,
.mv-btts-no { --mv-accent: var(--bad); --mv-accent-dim: var(--ga-tint); }
/* Empty state: a realistic example price (e.g. "1.90") sits muted and
   unobtrusive — the badge alone now carries the market identity, so the
   placeholder's job shrank to "here's roughly what a price looks like"
   rather than also having to spell out the market name. The moment real
   odds are typed, the native placeholder disappears on its own — no JS
   needed — and :not(:placeholder-shown) below swaps in bigger/bolder
   styling so the entered price takes visual prominence over an empty
   slot. */
.marketsview-odds-input {
  width: 100%;
  min-width: 0;
  padding: 2px 0;
  border: none;
  background: transparent;
  color: var(--chalk);
  font-family: var(--font-mono);
  text-align: center;
}
.marketsview-odds-input::placeholder {
  font-size: 13px;
  font-weight: 500;
  color: var(--chalk-muted);
  opacity: 0.55;
}
.marketsview-odds-input:not(:placeholder-shown) {
  font-size: 16px;
  font-weight: 700;
}
.marketsview-odds-input:focus { outline: none; }

/* ---------- EV Finder ---------- */
.ev-intro { margin-top: -4px; margin-bottom: 16px; }
.ev-empty-msg { margin: 0; }
.ev-row-head, .ev-row {
  display: grid;
  grid-template-columns: 1.5fr 0.85fr 0.85fr 0.85fr 0.85fr;
  align-items: center;
  gap: 8px;
}
.ev-row-head > div:not(:first-child),
.ev-row > div:not(:first-child) {
  text-align: center;
}
.ev-row-head {
  padding: 0 10px 6px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.3px;
  text-transform: uppercase;
  color: var(--chalk-muted);
}
.ev-row {
  padding: 8px 10px;
  border-radius: 10px;
  background: var(--surface);
  border: 1px solid var(--line);
  margin-bottom: 6px;
}
.ev-row:last-child { margin-bottom: 0; }
.ev-row-label { font-weight: 600; font-size: 13px; }
.ev-row-prob, .ev-row-implied {
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--chalk-muted);
}
.ev-row-odds {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 700;
  color: var(--chalk);
}
.ev-row-ev {
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 13px;
}
.ev-row.ev-pos { border-color: var(--good); background: rgba(0, 212, 139, 0.08); }
.ev-row-ev.ev-pos { color: var(--good); }
.ev-row-ev.ev-neg { color: var(--bad); }
@media (max-width: 560px) {
  .ev-row-head, .ev-row { grid-template-columns: 1.3fr 0.9fr 0.9fr 0.9fr; }
  .ev-row-implied, .ev-row-head span:nth-child(4) { display: none; }
}

/* ---------------------------------------------------------
   Bookmaker De-Vig — de-vigged fair % per market group, plus the
   reverse-engineered bookies' λ / score picture underneath.
--------------------------------------------------------- */
.devig-group { margin-bottom: 16px; }
.devig-group:last-child { margin-bottom: 0; }
.devig-group-title {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--chalk-muted);
  margin-bottom: 8px;
}
.devig-overround {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.3px;
  text-transform: none;
  color: var(--amber);
}
.devig-hint { margin: 0; }
.devig-row-head, .devig-row {
  display: grid;
  grid-template-columns: 1.4fr 0.8fr 0.9fr 1fr;
  align-items: center;
  gap: 8px;
}
.devig-row-head > div:not(:first-child),
.devig-row > div:not(:first-child) {
  text-align: center;
}
.devig-row-head {
  padding: 0 10px 6px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.3px;
  text-transform: uppercase;
  color: var(--chalk-muted);
}
.devig-row {
  padding: 8px 10px;
  border-radius: 10px;
  background: var(--surface);
  border: 1px solid var(--line);
  margin-bottom: 6px;
  font-family: var(--font-mono);
  font-size: 13px;
}
.devig-row:last-child { margin-bottom: 0; }
.devig-row-label { font-weight: 600; font-family: var(--font-sans, inherit); }
.devig-fair { font-weight: 700; color: var(--good); }
.devig-divider {
  height: 1px;
  background: var(--line);
  margin: 18px 0;
}
.devig-lambda-row {
  display: flex;
  gap: 10px;
  margin-bottom: 16px;
}
.devig-lambda-box {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 10px 8px;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: var(--surface);
  text-align: center;
}
.devig-lambda-label { font-size: 10px; font-weight: 700; letter-spacing: 0.3px; text-transform: uppercase; color: var(--chalk-muted); }
.devig-lambda-val { font-family: var(--font-mono); font-size: 20px; font-weight: 800; color: var(--chalk); }
.devig-scores-title {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--chalk-muted);
  margin-bottom: 8px;
}
.devig-scores-row { display: flex; gap: 8px; margin-bottom: 12px; }
.devig-score-pill {
  flex: 1;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 10px 6px;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: var(--surface);
}
.devig-score-pill.is-top {
  border-color: rgba(245, 200, 66, 0.55);
  background: linear-gradient(180deg, rgba(245, 200, 66, 0.16), rgba(245, 200, 66, 0.03));
  box-shadow: inset 0 0 0 1px rgba(245, 200, 66, 0.35);
}
.devig-score-top-tag {
  position: absolute;
  top: -8px;
  left: 50%;
  transform: translateX(-50%);
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 0.6px;
  color: #1a1200;
  background: #f5c842;
  padding: 1px 6px;
  border-radius: 6px;
}
.devig-score-pill.is-top .devig-score { color: #f5c842; }
.devig-score { font-family: var(--font-mono); font-size: 17px; font-weight: 800; color: var(--chalk); }
.devig-score-pct { font-family: var(--font-mono); font-size: 11.5px; color: var(--chalk-muted); }
@media (max-width: 560px) {
  .devig-row-head, .devig-row { grid-template-columns: 1.2fr 0.8fr 1fr; }
  .devig-row-head > div:nth-child(3), .devig-row > div:nth-child(3) { display: none; }
}

/* ---------------------------------------------------------
   Model Comparison — full dual-column PP vs Market panel. Each column
   is a self-contained copy of the old Markets tab (hero + 1X2 + O/U +
   BTTS + top scores); side by side on wide screens, stacked on mobile.
--------------------------------------------------------- */
.mc-dual-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  align-items: start;
  margin-bottom: 16px;
}
@media (max-width: 760px) {
  /* minmax(0, 1fr), not plain 1fr: a 1fr track's minimum is its content's
     min-content width, so a wide-enough card inside a column could push the
     whole column (and the page) past a narrow phone's edge. */
  .mc-dual-grid { grid-template-columns: minmax(0, 1fr); }
}
.mc-col { min-width: 0; }

/* "Verdict →" — full-width hand-off button under the last Model Comparison card */
.mc-next-bar { margin: 4px 0 8px; }
.mc-next-bar .btn { width: 100%; }
.mc-col-head {
  font-size: 13px;
  font-weight: 800;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  text-align: center;
  padding: 8px 0;
  border-radius: var(--radius-pill);
  margin-bottom: 10px;
}
.mc-col-head-pp { color: var(--home); background: rgba(29, 177, 255, 0.14); }
.mc-col-head-market { color: var(--away); background: rgba(255, 107, 53, 0.14); }
.mc-markets-grid { grid-template-columns: 1fr !important; margin-top: 14px; }

/* The dual-column layout halves the width a hero card normally has, so
   the xg-pill-row (Expected Goals / O-U / Overround)
   can wrap inconsistently between the two sides depending on how long
   each pill's label happens to be ("EXPECTED GOALS" vs "OVERROUND") —
   forcing it onto one row and shrinking pills to fit keeps both columns
   the same height/shape regardless of label length. */
.mc-col .xg-pill-row { flex-wrap: nowrap; gap: 6px; }
.mc-col .xg-pill { min-width: 0; flex: 1 1 0; padding: 8px 4px; }
.mc-col .xg-pill-label { font-size: 9.5px; letter-spacing: 0.3px; }
.mc-col .xg-pill-val { font-size: 13.5px; }
@media (max-width: 480px) {
  .mc-col .xg-pill-label { font-size: 9px; }
  .mc-col .xg-pill-val { font-size: 12px; }
}

/* Mobile launch splash: a branded "icon + tagline" screen shown on the
   first launch and then every third launch after that (see the
   SPLASH_EVERY cadence in the inline <head> script and hideAppSplash()
   below), so it reads as an occasional welcome rather than something in
   the way of every launch. Icon and tagline
   animate in, hold briefly, then the whole thing fades out over a fixed
   ~1.8s regardless of how fast the page actually loads (this is a
   deliberate branded moment now, not a "wait for assets" mask). Desktop
   already renders fast enough off a mouse-driven page load that this
   isn't needed there, so it's mobile-only. */
.app-splash {
  display: none;
}
html.splash-seen .app-splash {
  display: none !important;
}
@media (max-width: 640px) {
  .app-splash {
    display: flex;
    position: fixed;
    inset: 0;
    z-index: 9999;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 18px;
    background: var(--bg-deep);
    opacity: 1;
    transition: opacity 0.4s ease;
  }
  .app-splash.app-splash-hidden {
    opacity: 0;
    pointer-events: none;
  }
  .app-splash-icon {
    width: 96px;
    height: 96px;
    border-radius: 22px;
    box-shadow: var(--shadow-card);
    opacity: 0;
    transform: scale(0.8);
    animation: appSplashIconIn 0.6s cubic-bezier(0.2, 0.8, 0.2, 1) 0.1s forwards;
  }
  .app-splash-tag {
    font-family: var(--font-tagline);
    font-size: 10px;
    font-weight: 700;
    font-style: normal;
    letter-spacing: 1px;
    text-transform: none;
    color: var(--chalk-muted);
    opacity: 0;
    animation: appSplashTagIn 0.5s ease 0.6s forwards;
  }
  @keyframes appSplashIconIn {
    to { opacity: 1; transform: scale(1); }
  }
  @keyframes appSplashTagIn {
    to { opacity: 1; }
  }
  @media (prefers-reduced-motion: reduce) {
    .app-splash { transition: none; }
    .app-splash-icon, .app-splash-tag { animation: none; opacity: 1; transform: none; }
  }
}

/* ---------- Expected Goals card (Model Comparison tab) ----------
   Cards reuse .market-card; the split-bar gauge below is drawn by
   renderExpectedGoals() (fixture-inputs.js) and renderExpectedGoalsMarket()
   (verdict-markets.js). */

.mc-xg-card { margin-top: 12px; }
.mc-xg-hint { margin: -4px 0 12px; }

/* Collapsible Model Comparison cards — tap the heading to fold the card to its title row */
.mc-col .market-card[data-mc-card] > h2 {
  display: flex; align-items: center; gap: 8px;
  cursor: pointer; user-select: none; -webkit-tap-highlight-color: transparent;
}
.mc-col .market-card[data-mc-card] > h2::after {
  content: "▾"; margin-left: auto; color: var(--chalk-muted); font-size: 14px;
  transition: transform 0.15s ease;
}
.mc-col .market-card[data-mc-card] > h2:focus-visible { outline: 2px solid var(--home); outline-offset: 3px; border-radius: 4px; }
.mc-col .market-card.mc-collapsed { padding-bottom: 14px; }
.mc-col .market-card.mc-collapsed > h2 { margin-bottom: 0; }
.mc-col .market-card.mc-collapsed > h2::after { transform: rotate(-90deg); }
.mc-col .market-card.mc-collapsed > *:not(h2) { display: none; }

/* Expected-goals gauge */
.da-xg-row { display: flex; justify-content: space-between; flex-wrap: wrap; gap: 4px 12px; font-size: 12.5px; margin-bottom: 6px; } /* wrap: two long team names + λ overflowed ~280px screens */
.da-xg-label { display: flex; align-items: center; gap: 5px; color: var(--chalk-muted); }
.da-xg-label b { color: var(--chalk); font-family: var(--font-mono); font-size: 15px; }
.da-xg-label.home::before, .da-xg-label.away::before {
  content: ""; width: 8px; height: 8px; border-radius: 50%; display: inline-block;
}
.da-xg-label.home::before { background: var(--home); }
.da-xg-label.away::before { background: var(--away); }
.da-xg-track {
  display: flex;
  height: 14px;
  border-radius: var(--radius-pill);
  overflow: hidden;
  background: var(--bg-deep);
  border: 1px solid var(--line);
}
.da-xg-fill { height: 100%; transition: width 0.3s ease; }
.da-xg-fill.home { background: var(--home); }
.da-xg-fill.away { background: var(--away); }
.da-xg-note { font-size: 11px; color: var(--chalk-muted); margin: 8px 0 0; }
.da-xg-note b { color: var(--chalk); font-family: var(--font-mono); }


/* ---------- No Bet (v9.9): inline Verdict card + No Bet log ---------- */
.nobet-card { margin-bottom: 12px; border-left: 3px solid var(--amber-true); }
.nobet-card h2 { margin: 0 0 6px; }
.nobet-lead { margin: 0 0 8px; font-size: 13px; color: var(--chalk); line-height: 1.45; }
.nobet-closest { margin: 0 0 6px; padding: 8px 10px; border-radius: 8px; font-size: 13px; background: var(--amber-true-dim); color: var(--chalk); }
.nobet-closest-label { font-size: 10px; font-weight: 700; letter-spacing: 0.5px; text-transform: uppercase; color: var(--amber-true); margin-right: 4px; }
.nobet-have { color: var(--chalk-muted); font-size: 12px; }
.nobet-note { margin: 4px 0 6px; }
.nobet-log-status { margin-top: 8px; font-size: 11.5px; color: var(--chalk-muted); }
.nobet-link { background: none; border: 0; padding: 0; margin-left: 4px; font: inherit; font-weight: 700; color: var(--amber); text-decoration: underline; cursor: pointer; }

/* Match Log view switch */
.ml-view-switch { display: flex; gap: 6px; margin: 0 0 12px; padding: 3px; border-radius: 10px; background: var(--surface); border: 1px solid var(--line); }
.ml-view-btn { flex: 1; padding: 8px 6px; border: 0; border-radius: 8px; font: inherit; font-size: 12.5px; font-weight: 700; color: var(--chalk-muted); background: transparent; cursor: pointer; }
.ml-view-btn.active { color: var(--chalk); background: var(--surface-raised); box-shadow: 0 0 0 1px var(--line); }
.ml-view-btn span { font-family: var(--font-mono); font-weight: 400; font-size: 11px; }

.ml-nb-intro { margin: 0 0 10px; }
.ml-entry-nobet { border-left: 3px solid var(--amber-true); }
.ml-nobet-badge { display: inline-flex; align-items: center; padding: 1px 7px; border-radius: 999px; font-family: var(--font-mono); font-size: 9.5px; font-weight: 700; letter-spacing: 0.4px; color: var(--amber-true); background: var(--amber-true-dim); }
.ml-nobet-label { color: var(--amber-true); letter-spacing: 0.4px; }
.ml-nb-date { margin-left: 7px; font-family: var(--font-mono); font-size: 9.5px; color: var(--chalk-muted); }
.ml-nb-needs { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; margin: 6px 0 4px; font-size: 11px; color: var(--chalk-muted); }
.ml-nb-needs-label { font-size: 9.5px; font-weight: 700; letter-spacing: 0.5px; text-transform: uppercase; color: var(--amber-true); }
.ml-nb-need b { color: var(--chalk); font-weight: 600; }
.ml-nb-need { font-family: var(--font-mono); }
.ml-nb-had { opacity: 0.8; }
.ml-nb-more { margin: 10px 0 0; text-align: center; }

/* ---------- Best Bet decision panel ---------- */
.bb-decision {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 6px;
  margin-top: 10px;
}
.bb-dec-cell {
  background: rgba(29, 177, 255, 0.07);
  border: 1px solid rgba(29, 177, 255, 0.18);
  border-radius: var(--radius);
  padding: 8px 6px;
  text-align: center;
  min-width: 0;
}
.bb-dec-k {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--chalk-muted);
}
.bb-dec-v { font-size: 15px; font-weight: 800; margin-top: 3px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bb-dec-v.good { color: var(--good); }
.bb-dec-foot { font-size: 10px; color: var(--chalk-muted); line-height: 1.5; margin-top: 6px; }
.bb-low { color: var(--chalk-muted); font-weight: 500; }
.bb-ladder { grid-template-columns: repeat(3, 1fr); }
.bestbet-pct[data-kind="cautious"]::after { content: " cautious"; font-size: 0.75em; font-weight: 600; opacity: 0.75; }
@media (max-width: 480px) {
  .bb-dec-v { font-size: 13px; }
}

/* Veto Check (v7.3) — Match Log panel testing the model-vs-market veto. */
.veto-card { background: var(--surface-raised); border: 1px solid var(--line); border-left: 3px solid #ef4444; border-radius: var(--radius); padding: 10px 12px; margin-bottom: 12px; font-size: 12px; line-height: 1.6; }
.veto-title { font-weight: 700; margin-bottom: 4px; }
/* v9.9: collapsed to one summary line by default */
.veto-collapsible { padding: 0; }
.veto-summary { list-style: none; cursor: pointer; padding: 8px 12px; display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 8px; }
.veto-summary::-webkit-details-marker { display: none; }
.veto-summary::before { content: "▸"; color: var(--chalk-muted); transition: transform 0.15s ease; }
.veto-collapsible[open] > .veto-summary::before { transform: rotate(90deg); }
.veto-summary .veto-title { margin: 0; }
.veto-summary small { color: var(--chalk-muted); font-weight: 400; }
.veto-collapsible > :not(summary) { margin-left: 12px; margin-right: 12px; }
.veto-collapsible[open] { padding-bottom: 10px; }
.veto-title small { font-weight: 400; color: var(--chalk-muted); }
.veto-stats { color: var(--chalk); }
.veto-verdict { color: var(--chalk-muted); margin-top: 4px; }
.veto-sub { margin-top: 8px; color: var(--chalk-muted); }
.veto-row { display: flex; align-items: center; gap: 8px; margin-top: 6px; }
.veto-row-t { flex: 1; min-width: 0; }
.veto-row-t small { color: var(--chalk-muted); }
.veto-input { width: 64px; padding: 6px 8px; background: var(--surface); color: var(--chalk); border: 1px solid var(--line); border-radius: 6px; text-align: center; }
.veto-input-bad { border-color: #ef4444; }
.veto-hit, .veto-miss { font-weight: 800; font-size: 15px; width: 18px; text-align: center; flex: none; }
.veto-hit { color: #22c55e; }
.veto-miss { color: #ef4444; }
.veto-src { font-size: 11px; color: var(--chalk-muted); white-space: nowrap; }
.veto-del { flex: none; width: 26px; height: 26px; padding: 0; border: 1px solid var(--line); border-radius: 6px; background: transparent; color: var(--chalk-muted); font-size: 12px; line-height: 1; cursor: pointer; }
.veto-del:hover, .veto-del:focus-visible { color: #ef4444; border-color: #ef4444; }

/* v7.7 — Top EV chip: muted headline figure + tappable info popover. */
.ss-topev .bestbet-pct.ev-headline { opacity: 0.8; } /* v8.8: no longer italic — still slightly muted to flag it is the optimistic figure */
.ss-topev-info {
  background: none; border: 0; padding: 0 0 0 4px; margin: 0;
  font-size: 13px; line-height: 1; color: var(--chalk-muted);
  cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.ss-topev-info:hover, .ss-topev-info:focus-visible { color: var(--chalk); }
.topev-pop {
  position: fixed; left: 12px; right: 12px; max-width: 420px; margin: 0 auto; z-index: 9999;
  background: var(--surface-raised, var(--surface)); color: var(--chalk);
  border: 1px solid var(--line); border-left: 3px solid var(--amber-true, #d99a1e);
  border-radius: var(--radius); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.28);
  padding: 10px 12px; font-size: 12px; line-height: 1.55;
}
.topev-pop p { margin: 6px 0 0; }
.topev-pop-title { font-weight: 700; }


/* v9.1 — results are only produced by "Calculate Probabilities". When an input
   changes afterwards, the previous results stay visible but are flagged. */
body.results-stale #tab-modelcomparison::before,
body.results-stale #tab-betsummary::before {
  content: "⚠ Inputs changed since the last calculation — these results are from the previous run. Press Calculate Probabilities to update them.";
  display: block;
  margin: 0 0 10px;
  padding: 8px 10px;
  border-radius: var(--radius);
  font-size: 11px;
  line-height: 1.4;
  color: var(--amber-true);
  background: rgba(255, 176, 32, 0.10);
  border: 1px solid rgba(255, 176, 32, 0.35);
}
body.results-stale .ss-item { opacity: 0.55; }

/* Back-to-back toggle (Team Form card) */
.b2b-check { display: inline-flex; align-items: center; gap: 6px; margin: 2px 0 6px; font-size: 12px; color: var(--muted, inherit); cursor: pointer; }
.b2b-check input { width: 16px; height: 16px; accent-color: var(--home, currentColor); }
.team-card.away .b2b-check input { accent-color: var(--away, currentColor); }

/* Moneyline odds row (Bookmaker Odds card) */
.marketsview-row-ml { margin-top: 10px; padding-top: 10px; border-top: 1px dashed var(--line); }
.mv-group-ml { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; width: 100%; }
.mv-ml-label { font-size: 11.5px; letter-spacing: 0.3px; color: var(--chalk-muted, inherit); flex: 1 1 100%; }
.mv-group-ml .marketsview-field { flex: 1 1 0; min-width: 0; }


/* ================= Ice-rink backdrop (replaces the football pitch) =================
   Same fixed backdrop element and class names as before (.pitch-lines etc. —
   renaming them would touch markup for no visible gain); only the look changes:
   cool ice sheen, red centre line, blue lines, a faceoff circle, and a goal
   crease + goal line at each end. */
:root { --rink-red: rgba(224, 60, 60, 0.30); --rink-blue: rgba(40, 140, 255, 0.34); --rink-ice: rgba(190, 225, 255, 0.05); }
html.light { --rink-red: rgba(200, 40, 40, 0.28); --rink-blue: rgba(0, 105, 214, 0.30); --rink-ice: rgba(0, 105, 214, 0.05); }
.pitch-lines {
  background-image:
    var(--noise-texture),
    radial-gradient(ellipse 900px 700px at 50% 50%, var(--pitch-glow), transparent 70%),
    radial-gradient(ellipse 140% 100% at 50% 50%, transparent 55%, var(--pitch-vignette) 100%),
    linear-gradient(115deg, transparent 0%, var(--rink-ice) 38%, transparent 62%);
  background-repeat: repeat, no-repeat, no-repeat, no-repeat;
}
/* centre red line (dashed, like the real one) */
.pitch-halfway {
  width: 6px;
  background: repeating-linear-gradient(180deg, var(--rink-red) 0 14px, transparent 14px 20px);
}
/* centre faceoff circle + dot (blue) */
.pitch-center-circle { border-color: var(--rink-blue); box-shadow: 0 0 40px 6px var(--pitch-glow); }
.pitch-center-circle::after { background: var(--rink-blue); width: 10px; height: 10px; }
/* the two blue lines */
.pitch-goal-area {
  top: 0; transform: none; height: 100%; width: 8px; border: none; border-radius: 0;
  background: var(--rink-blue);
}
.pitch-goal-area-left { left: 30%; }
.pitch-goal-area-right { right: 30%; }
/* goal lines (thin red, full height, near each end) */
.pitch-six-yard {
  top: 0; transform: none; height: 100%; width: 2px; border: none; border-radius: 0;
  background: var(--rink-red);
}
.pitch-six-yard-left { left: 6%; }
.pitch-six-yard-right { right: 6%; }
/* goal crease: a half-disc on each goal line */
.pitch-post {
  width: 44px; height: min(88px, 18vh);
  border: 2px solid var(--rink-red); background: var(--rink-blue);
  background-color: rgba(40, 140, 255, 0.10);
}
.pitch-post span { display: none; }
.pitch-post-left { left: 6%; border-left: none; border-radius: 0 100px 100px 0; }
.pitch-post-right { right: 6%; border-right: none; border-radius: 100px 0 0 100px; }
