/* Ticket Window — see docs/DESIGN.md. */

@font-face {
  font-family: 'Oswald';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("fonts/oswald-700.cedd65736210.woff2") format('woff2');
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/inter-400.cef6d3a6737e.woff2") format('woff2');
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("fonts/inter-600.ca03b7ee20d3.woff2") format('woff2');
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("fonts/inter-700.64d12f9f7d82.woff2") format('woff2');
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/jetbrains-mono-400.3fb54ef45e30.woff2") format('woff2');
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("fonts/jetbrains-mono-600.dba84cb55691.woff2") format('woff2');
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("fonts/jetbrains-mono-700.b9c90042b2e0.woff2") format('woff2');
}

:root {
  --ground: #E7EBEA;
  --surface: #FFFFFF;
  --surface-2: #DCE2DF;
  --ink: #1A2422;
  --ink-mute: #57635F;
  --accent: #1D3557;
  --accent-2: #E8A33D;
  --accent-text: #ffffff;
  --win: #00966B;
  --loss: #D2551A;
  --line: #CBD3CE;
  --marker: #C23B2E;
  --marker-dried: #8B7355;

  --f-display: 'Oswald', ui-rounded, -apple-system, "Segoe UI", system-ui, sans-serif;
  --f-body: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  --f-mono: 'JetBrains Mono', ui-monospace, "SF Mono", Menlo, monospace;

  /* Tells the browser this page supports both themes, so natively-rendered
     form controls (checkbox tick, select's dropdown popup, scrollbars) that
     have no author background/color of their own follow the OS/manual theme
     too, instead of always rendering with light-mode UA styling. */
  color-scheme: light dark;
}

@media (prefers-color-scheme: dark) {
  :root {
    --ground: #14181A;
    --surface: #1D2224;
    --surface-2: #262C2E;
    --ink: #ECEFEC;
    --ink-mute: #92A19B;
    --accent: #6E93C9;
    --accent-2: #E0A857;
    --accent-text: #000000;
    --win: #2FBF8F;
    --loss: #E37142;
    --line: #303838;
    --marker: #E2574A;
    --marker-dried: #9C8564;
    color-scheme: dark;
  }
}
:root[data-theme="dark"] {
  --ground: #14181A;
  --surface: #1D2224;
  --surface-2: #262C2E;
  --ink: #ECEFEC;
  --ink-mute: #92A19B;
  --accent: #6E93C9;
  --accent-2: #E0A857;
  --accent-text: #000000;
  --win: #2FBF8F;
  --loss: #E37142;
  --line: #303838;
  --marker: #E2574A;
  --marker-dried: #9C8564;
  color-scheme: dark;
}
:root[data-theme="light"] {
  --ground: #E7EBEA;
  --surface: #FFFFFF;
  --surface-2: #DCE2DF;
  --ink: #1A2422;
  --ink-mute: #57635F;
  --accent: #1D3557;
  --accent-2: #E8A33D;
  --accent-text: #ffffff;
  --win: #00966B;
  --loss: #D2551A;
  --line: #CBD3CE;
  --marker: #C23B2E;
  --marker-dried: #8B7355;
  color-scheme: light;
}

* { box-sizing: border-box; }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--f-body);
  -webkit-font-smoothing: antialiased;
}

a { color: var(--accent); }

.page {
  max-width: 480px;
  margin: 0 auto;
  padding: 0 16px 48px;
}

.site-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 18px 16px 14px;
  max-width: 480px;
  margin: 0 auto;
}
.site-header .brand {
  font-family: var(--f-display);
  font-weight: 700;
  font-size: 19px;
  text-decoration: none;
  color: var(--ink);
}
.site-header .account { font-size: 13px; color: var(--ink-mute); }
.site-header .account a { margin-left: 10px; }
.site-header .logout-form { display: inline; margin-left: 10px; }
.icon-link {
  display: inline-flex;
  align-items: center;
  position: relative;
  vertical-align: middle;
  color: var(--ink-mute);
}
.icon-link:hover { color: var(--accent); }
.notification-badge {
  position: absolute;
  top: -6px;
  right: -8px;
  display: inline-block;
  min-width: 15px;
  padding: 0 4px;
  border-radius: 999px;
  background: var(--accent-2);
  color: #000000;
  font-size: 11px;
  font-weight: 700;
  text-align: center;
  line-height: 15px;
}
.site-header .logout-button {
  background: none; border: 0; padding: 0; margin: 0;
  font: inherit; cursor: pointer;
}

.league-indicator {
  margin-right: 10px;
  color: var(--ink-mute);
}
.league-switcher {
  display: inline-block;
  margin-right: 10px;
  position: relative;
}
.league-switcher summary {
  cursor: pointer;
  list-style: none;
  color: var(--ink-mute);
}
.league-switcher summary::-webkit-details-marker { display: none; }
.league-switcher summary::after {
  content: "▾";
  display: inline-block;
  margin-left: 4px;
  font-size: 10px;
  transition: transform .15s ease;
}
.league-switcher[open] summary::after { transform: rotate(180deg); }
.league-switcher ul {
  list-style: none;
  margin: 4px 0 0;
  padding: 6px;
  position: absolute;
  right: 0;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: 0 4px 12px rgba(27, 35, 30, .1);
  min-width: 140px;
  z-index: 10;
}
.league-switcher li form { margin: 0; }
.league-switcher li button {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: 0;
  padding: 6px 8px;
  font: inherit;
  color: var(--ink);
  cursor: pointer;
  border-radius: 6px;
}
.league-switcher li button:hover {
  background: var(--surface-2);
}

.messages { list-style: none; margin: 0 0 16px; padding: 0; }
.messages li {
  background: var(--surface);
  border: 1.5px solid var(--win);
  color: var(--win);
  border-radius: 12px;
  padding: 10px 14px;
  font-size: 13.5px;
  font-weight: 600;
  margin-bottom: 8px;
}
.messages li.error { border-color: var(--loss); color: var(--loss); }

@media (prefers-reduced-motion: no-preference) {
  .messages li { animation: message-in .35s ease-out; }
  @keyframes message-in {
    from { opacity: 0; transform: translateY(-6px); }
    to { opacity: 1; transform: translateY(0); }
  }
}

.form-errors {
  background: var(--surface);
  border: 1.5px solid var(--loss);
  color: var(--loss);
  border-radius: 12px;
  padding: 12px 14px;
  font-size: 13.5px;
  margin-bottom: 16px;
}
.form-errors p { margin: 0 0 4px; }
.form-errors p:last-child { margin-bottom: 0; }

.screen-head { padding: 4px 0 16px; }
.week-label {
  font-family: var(--f-mono);
  font-size: 11px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 4px;
}
.screen-head h1 { font-family: var(--f-display); font-size: 26px; font-weight: 700; margin: 0 0 14px; }
.leagues-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.leagues-head h1 { margin-bottom: 0; }
.leagues-head-action {
  font-family: var(--f-display); font-weight: 700; font-size: 14px;
  text-decoration: none; white-space: nowrap; margin-bottom: 14px;
}
.league-head { display: flex; align-items: center; gap: 10px; }
.settings-gear {
  text-decoration: none;
  font-size: 20px;
  line-height: 1;
  color: var(--ink-mute);
  margin-bottom: 14px;
}
.settings-gear:hover { color: var(--accent); }

/* Was 11px/muted/uppercase -- the same visual weight as body text.
   Now sized and weighted to read as a real section break; the forced
   uppercase transform is dropped in favor of each heading's own natural
   case (see docs/superpowers/specs/2026-07-21-season-dashboard-design.md). */
.section-label {
  font-family: var(--f-mono); font-size: 15px; font-weight: 700; letter-spacing: .04em;
  color: var(--ink); margin: 32px 0 12px;
}
.section-label:first-child { margin-top: 8px; }

/* A matrix's section label shares a line with its orientation toggle. */
.matrix-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin: 32px 0 10px; }
.matrix-head .section-label { margin: 0; }
.matrix-orient { display: inline-flex; border: 1.5px solid var(--line); border-radius: 999px; padding: 2px; flex-shrink: 0; }
.stats-mode-toggle { margin-top: 4px; }
/* The browser's built-in `[hidden] { display: none }` rule loses to ANY
   author-stylesheet rule that sets `display` on the same element (author
   origin always beats user-agent origin, regardless of selector
   specificity) -- .stat-line's own `display: flex` was silently winning,
   so a toggled-off SU/ATS row never actually hid, just kept its flex
   layout with the `hidden` attribute sitting there doing nothing. This
   forces the point home for every stats-toggle target regardless of what
   display value its own class sets. */
[data-stat-value][hidden] { display: none !important; }
.matrix-orient-btn {
  font-family: var(--f-body); font-size: 11px; font-weight: 700; color: var(--ink-mute);
  background: none; border: 0; border-radius: 999px; padding: 4px 10px; cursor: pointer;
}
.matrix-orient-btn.is-active { background: var(--accent); color: var(--accent-text); }
.matrix-dash { color: var(--ink-mute); }

.section-subhead {
  display: flex; align-items: center; gap: 8px;
  font-weight: 700; font-size: 12.5px; color: var(--ink-mute);
  margin: 18px 0 8px;
}
.section-subhead:first-child { margin-top: 0; }
.trophy-tag {
  font-family: var(--f-mono); font-size: 9px; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--accent); border: 1.5px solid var(--accent);
  border-radius: 999px; padding: 2px 7px;
}
.trophy-list { list-style: none; margin: 0 0 8px; padding: 0; display: flex; flex-direction: column; gap: 7px; }
.trophy-list li { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; font-size: 13px; }
.trophy-rank { font-family: var(--f-mono); color: var(--ink-mute); width: 1.4em; flex-shrink: 0; }
.trophy-who { flex: 1; font-weight: 700; }
.trophy-count { font-family: var(--f-mono); color: var(--ink-mute); font-variant-numeric: tabular-nums; }
.trophy-cat { color: var(--ink-mute); }
.notification-unread { border-left: 3px solid var(--accent-2); padding-left: 8px; }
.trophy-note { font-size: 11px; color: var(--ink-mute); }
.trophy-link { font-size: 13px; font-weight: 600; text-decoration: none; }
.trophy-link::after { content: " \2192"; }

.mode-banner {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding-bottom: 12px; margin-bottom: 4px; border-bottom: 2px dashed var(--line);
}
.mode-chip {
  font-family: var(--f-body); font-weight: 700; font-size: 11.5px;
  padding: 5px 10px; border-radius: 999px;
  background: var(--surface-2); color: var(--ink-mute);
}
.mode-chip.is-on { background: var(--accent); color: var(--accent-text); }
.mode-progress {
  font-family: var(--f-mono); font-size: 11px; color: var(--ink-mute);
  margin-left: auto; font-variant-numeric: tabular-nums;
}


.confidence-chip {
  display: flex; align-items: center; justify-content: space-between;
  margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--line);
}
.confidence-chip > span:first-child { font-size: 11.5px; font-weight: 600; color: var(--ink-mute); }

.confidence-stepper { display: flex; align-items: center; gap: 10px; }
.stepper-btn {
  width: 26px; height: 26px; flex: 0 0 auto;
  font-family: var(--f-display); font-size: 14px; line-height: 1;
  border: 2px solid var(--line); border-radius: 8px;
  background: var(--surface); color: var(--ink); cursor: pointer;
}
.stepper-btn:hover { border-color: var(--accent); color: var(--accent); }
.stepper-btn:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 2px; }

.confidence-input {
  width: 34px; text-align: center;
  font-family: var(--f-display); font-weight: 700; font-size: 16px;
  border: 2px solid var(--line); border-radius: 8px; padding: 4px 2px;
  background: var(--surface); color: var(--ink);
  /* stepper buttons drive the value; hide the browser's own spin controls */
  -moz-appearance: textfield;
  appearance: textfield;
}
.confidence-input::-webkit-outer-spin-button,
.confidence-input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.back { display: inline-block; margin: 4px 0 14px; font-weight: 600; font-size: 13px; color: var(--ink-mute); text-decoration: none; }

/* Game detail hero -- a literal event-ticket metaphor. See
   docs/superpowers/specs/2026-07-21-game-detail-ticket-redesign-design.md.
   Sharp corners (no border-radius) with a hand-jittered clip-path outline
   instead of a perfect rectangle, so it reads as a physically imperfect
   printed card rather than a clean UI panel. */
/* Separates one game's whole card (ticket + insights) from the next in
   week_picks.html's list -- without it, an insights panel's muted text
   ran right into the next game's eyebrow row with nothing to mark where
   one game ends and the next begins. The dashed rule matches the
   ticket-tear perforation look used elsewhere in this design. Applied
   unconditionally (including after the last game) rather than trying to
   detect "last card" -- the form's own .submit-row follows the loop as a
   sibling, so a :last-child rule wouldn't actually match the last
   .ticket-card-wrap anyway, and the extra breathing room before the
   Save button reads fine regardless. */
.ticket-card-wrap { margin-bottom: 28px; padding-bottom: 22px; border-bottom: 2px dashed var(--line); }

.detail-hero { position: relative; display: flex; margin-bottom: 14px; }

.detail-hero.is-intact {
  background: var(--surface);
  box-shadow: 0 3px 10px rgba(0,0,0,.10);
  transform: rotate(-0.35deg);
  clip-path: polygon(
    0% 0.6%, 12% 0%, 27% 0.8%, 41% 0.2%, 58% 0.7%, 73% 0%, 89% 0.5%, 100% 0%,
    99.4% 14%, 100% 29%, 99.5% 47%, 100% 64%, 99.3% 81%, 100% 100%,
    86% 99.5%, 71% 100%, 55% 99.4%, 39% 100%, 22% 99.5%, 8% 100%, 0% 99.6%,
    0.6% 83%, 0% 66%, 0.5% 48%, 0% 31%, 0.7% 15%
  );
}
/* Left edge of the printed border sits a touch inset from the true
   edge (3px) -- top/right/bottom stay flush. Border itself widened
   from 1.5px to 3px so it survives the jittered edge's small dips
   instead of breaking at them (a 1.5px stroke was thinner than some of
   the dips at real mobile widths). */
.detail-hero.is-intact::before {
  content: '';
  position: absolute; inset: 0 0 0 3px;
  border: 3px solid var(--ink);
  opacity: .35;
  pointer-events: none;
}
.is-intact .detail-hero-stub { border-left: 2px dashed var(--line); }

/* Once a game locks, the stub visually tears off: two independent
   pieces (own background/shadow/rotation each) with a real gap between
   them, and jagged clip-path notches on the two edges that used to meet
   at the perforation. Gap narrowed from 14px to 5px -- it was pure dead
   space eating into the main ticket's usable width. */
.detail-hero.is-torn { gap: 5px; }
.is-torn .detail-hero-main {
  position: relative;
  background: var(--surface);
  box-shadow: 0 3px 10px rgba(0,0,0,.10);
  transform: rotate(-0.5deg);
  clip-path: polygon(
    0% 1.5%, 12% 0%, 27% 1.3%, 41% 0.3%, 58% 1.2%, 73% 0%, 89% 0.8%, 100% 0%,
    98.5% 9%, 100% 18%, 98.3% 27%, 100% 37%, 98.5% 47%, 100% 58%, 98.3% 68%,
    100% 78%, 98.5% 88%, 100% 100%,
    86% 99.3%, 71% 100%, 55% 99.2%, 39% 100%, 22% 99.3%, 8% 100%, 0% 99.4%,
    1.5% 83%, 0% 66%, 1.3% 48%, 0% 31%, 1.2% 15%
  );
}
/* Printed border on the torn pieces too -- only on the three sides
   that are the ticket's real outer edge. The fourth side (right, for
   the main piece; left, for the stub) is where it physically tore
   away from the other piece, so it stays a raw, unbordered edge. */
.is-torn .detail-hero-main::before {
  content: ''; position: absolute; inset: 0 0 0 3px;
  border-top: 3px solid var(--ink); border-left: 3px solid var(--ink); border-bottom: 3px solid var(--ink);
  opacity: .35; pointer-events: none;
}
.is-torn .detail-hero-stub {
  position: relative;
  background: var(--surface);
  box-shadow: 0 3px 10px rgba(0,0,0,.10);
  transform: rotate(0.8deg);
  clip-path: polygon(
    1.5% 0.7%, 30% 0%, 60% 0.6%, 100% 0%,
    99.4% 20%, 100% 40%, 99.3% 60%, 100% 80%, 99.4% 100%,
    65% 99.5%, 35% 100%, 3% 99.6%,
    1.5% 90%, 3% 88%, 1.5% 78%, 3% 68%, 1.5% 58%, 3% 47%, 1.5% 37%, 3% 27%, 1.5% 18%, 3% 9%
  );
}
.is-torn .detail-hero-stub::before {
  content: ''; position: absolute; inset: 0;
  border-top: 3px solid var(--ink); border-right: 3px solid var(--ink); border-bottom: 3px solid var(--ink);
  opacity: .35; pointer-events: none;
}

.detail-hero-main { flex: 1; min-width: 0; padding: 14px 14px 12px; font-family: var(--f-mono); }
.ticket-eyebrow { font-size: 10.5px; letter-spacing: .18em; color: var(--ink-mute); display: flex; justify-content: space-between; }

/* Font sizes here (and in .ticket-details/.ticket-odds-row below)
   restored to their pre-mobile-mockup values -- the mockup used a
   390px frame that turned out narrower than the real ticket actually
   renders at, so the aggressive shrinking wasn't needed. The
   overflow/ellipsis safety net stays regardless. */
/* Venue sits between the eyebrow and the matchup -- above the team
   names, not down with the odds -- since it reads more like part of
   "when/where" alongside the date/time than like a betting detail. */
.ticket-venue { margin-top: 6px; font-size: 10.5px; letter-spacing: .08em; color: var(--ink-mute); text-transform: uppercase; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Accented so the label reads at a glance rather than blending into the
   muted venue line -- the point of it is noticing the game is abroad. */
.venue-international { color: var(--accent); font-weight: 700; }

.ticket-matchup { margin-top: 14px; font-size: 15px; font-weight: 600; letter-spacing: .01em; line-height: 1.55; text-transform: uppercase; }
.ticket-matchup div { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ticket-matchup .at { color: var(--ink-mute); font-weight: 400; padding: 1px 0; }
.ticket-matchup .fav { position: relative; }
.ticket-matchup .fav::after { content: "\2605"; font-size: 9px; margin-left: 6px; color: var(--accent-2); vertical-align: middle; }

/* Only ever wraps the odds row now (venue moved above the matchup) --
   omitted from the template entirely when there's no odds line, so
   this dashed divider never renders over an empty gap.

   The actual bug in the last two attempts: comparing the raw numbers,
   the gap *above* the odds text (this block's old margin-top:14px +
   padding-top:12px = 26px) was simply larger than the gap *below* it
   (.detail-hero-main's padding-bottom:12px) -- an asymmetry baked
   directly into the authored values, nothing to do with flex/leftover-
   space behavior (which is genuinely unpredictable here, since main's
   own content is often taller than the stub's, leaving no leftover
   space at all for flex-grow/auto-margin tricks to redistribute).
   padding-top here now matches .detail-hero-main's padding-bottom
   exactly (12px each), so the odds row sits with equal, fixed gaps to
   the dashed line above and the card's bottom edge below, regardless
   of stretch behavior. */
.ticket-details {
  margin-top: 10px; padding-top: 12px; border-top: 2px dashed var(--line);
  font-size: 11px; color: var(--ink-mute);
}
.ticket-details b { color: var(--ink); font-weight: 700; }

/* Odds condensed to one left-justified line, grouped by team (spread +
   ML) with O/U between. min-width:0 isn't needed here since this is a
   flex row (not an earlier grid version, which was the actual source
   of overflow: 1fr grid tracks default to min-width:auto and refuse to
   shrink below their text's intrinsic width). */
/* Evenly spaced across 3 columns (was left-justified flex, a holdover
   from the narrow 390px mockup -- the real ticket has plenty of width
   for this to sit centered/evenly spaced instead). minmax(min-content,
   1fr), not plain 1fr, so a long spread/moneyline combination can't
   compress a column below what its own text needs. */
/* No margin-top here -- .ticket-details' own padding-top already
   provides the (symmetric, matched to padding-bottom below) gap from
   the dashed line. This row's margin-top:8px was a leftover from when
   the venue line used to sit directly above it in the same wrapper
   (before venue moved up next to the matchup); with venue gone, it was
   just adding an extra, unaccounted-for 8px above the text that broke
   the intended symmetry. */
/* Three columns, two rows: labels on the first, values on the second, so a
   team's number sits directly under its own abbreviation.

       CHI        O/U       CAR
     -2.5/-135    44.5    +2.5/+114

   Previously each team was one blob ("CHI -2.5/-135") and wrapped on its
   own, which put the numbers at different heights. minmax(0, ...) rather
   than a min-content floor -- a floor means the grid can't shrink below its
   text, so a narrow ticket overflowed the card and ran through the
   perforation into the stub instead of adapting. */
.ticket-odds-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, auto) minmax(0, 1fr);
  row-gap: 3px; column-gap: 8px;
  font-size: 11px; letter-spacing: .08em;
}
.ticket-odds-label { text-align: center; color: var(--ink-mute); }
/* Every number contrasts, not just the over/under -- they're all the
   figures you're actually reading. */
.ticket-odds-value { text-align: center; color: var(--ink); font-weight: 600; overflow-wrap: anywhere; }

/* Narrowed from the original 148px, then widened back up a bit to
   128px -- reclaims width for the main ticket area (long team names)
   while still leaving enough room for the stub's own content. */
.detail-hero-stub {
  width: 128px; flex-shrink: 0; padding: 12px 8px;
  display: flex; flex-direction: column; align-items: stretch; justify-content: center; gap: 4px;
}
.stub-label {
  font-family: var(--f-body); font-size: 8.5px; font-weight: 600; color: var(--ink-mute);
  text-transform: uppercase; letter-spacing: .06em; text-align: center; margin-bottom: 5px;
}
.stub-final-label { color: var(--ink-mute); font-style: italic; }
/* minmax(min-content, 1fr), not plain 1fr -- guarantees neither outer
   track shrinks below its content's natural size, while still sharing
   any leftover space 1fr-style so the badge stays centered. (Turned
   out not to be the cause of the punch-circle rendering as a sliver --
   that was .punch-circle needing display:inline-block, see below --
   but this is still a more robust pattern than a bare 1fr on its own.) */
.stub-team-row { display: grid; grid-template-columns: minmax(min-content, 1fr) auto minmax(min-content, 1fr); align-items: center; }
/* No spread this game -- collapses to two centered columns (badge,
   circle) instead of three with a dead empty spread cell. */
.stub-team-row.no-spread { display: flex; justify-content: center; align-items: center; gap: 8px; }
.stub-spread { font-family: var(--f-mono); font-size: 9px; color: var(--ink-mute); justify-self: center; }
/* Fixed width (not min-width) so every badge is the same size
   regardless of a 2- vs 3-letter abbreviation ("NE" vs "SEA") --
   min-width let 3-letter abbreviations render wider than 2-letter
   ones. */
.stub-team-row .team-badge {
  width: 2.6em; padding: 3px 2px; font-size: 10px; border-radius: 5px; justify-self: center;
}

/* "@" shares the exact same 3-column grid as the team rows above/below
   it, placed explicitly in the middle column -- so it lines up with
   the badge specifically, not with the center of the whole stub's
   width (which drifts depending on how wide the spread text is on
   either side, which is what centering it standalone actually did). */
.stub-at-row { display: grid; grid-template-columns: minmax(min-content, 1fr) auto minmax(min-content, 1fr); align-items: center; margin: 1px 0; }
.stub-at { grid-column: 2; justify-self: center; font-family: var(--f-display); font-weight: 700; font-size: 12px; color: var(--ink-mute); }

/* The circle is the real pick control now (wraps a radio input) --
   padding+negative margin gives a comfortably large tap target without
   visually growing the circle itself. */
.punch-circle-label { justify-self: center; cursor: pointer; padding: 6px; margin: -6px; position: relative; }
.punch-circle-label input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.punch-circle-label.is-disabled { cursor: default; }

/* A plain dashed-outline circle by default (both teams); the picked
   team's circle additionally gets a hand-drawn "X" (see .marker-x
   below) -- deliberately not a punched-hole cutout (that relied on
   var(--ground) contrasting with var(--surface), which doesn't hold up
   in every theme). Back to its original 20px -- that was always the
   right size once it actually rendered at its declared size.

   display: inline-block is the actual fix for a "circle renders as a
   thin sliver" bug this used to have: it's a <span>, which defaults to
   display:inline, and width/height are silently ignored on inline
   elements -- the circle was never rendering at its declared size at
   all, it was collapsing to its inline content's natural size
   (near-zero, since its only child is the absolutely-positioned,
   out-of-flow marker-x SVG) with just the two side borders rendering
   close together. */
.punch-circle {
  display: inline-block;
  width: 20px; height: 20px; border-radius: 50%;
  border: 2px dashed var(--ink-mute);
  position: relative; flex-shrink: 0; justify-self: center;
}
.punch-circle-label input:focus-visible + .punch-circle { outline: 2px solid var(--accent-2); outline-offset: 2px; }

/* Mark visibility and the "drawn in" animation are both driven entirely
   by JS-added classes (is-picked / is-drawing -- see ticket-pick.js),
   not by :checked. An earlier version gated opacity on :checked (which
   flips instantly, natively) while the animation's undrawn starting
   point only got applied a tick later once the change-event JS ran --
   for one paint, the mark showed fully drawn before JS reset it and
   animated it back in, reading as a flash of "leftover" ink. Routing
   visibility through the same JS-owned classes eliminates that race.
   A server-rendered existing pick gets `is-picked` directly in the
   template (no `is-drawing`), so there's no animation on page load. */
/* Explicitly sized and centred rather than `inset: -3px`. The SVG has a
   viewBox but no width/height attributes, which makes it a replaced element
   with no intrinsic size -- and for those, an over-constrained inset does
   NOT stretch the box. The browser keeps the intrinsic size and honours
   top/left while dropping right/bottom, so the X rendered ~3px up and left
   of the circle. 26px = the 20px circle plus the 3px overhang each side
   that the old inset was reaching for. */
.marker-x {
  position: absolute;
  top: 50%; left: 50%;
  width: 26px; height: 26px;
  transform: translate(-50%, -50%) rotate(-8deg);
  opacity: 0;
}
.punch-circle.is-picked .marker-x { opacity: 1; }
/* stroke-dasharray is 1 2 (dash, gap), not just 1 -- with a bare `1`
   (dash=1, gap=1, since a single value repeats), the "hidden" resting
   state below (dashoffset:1) lands exactly ON the dash/gap boundary at
   the path's start point. Combined with stroke-linecap:round, that
   boundary is precision-sensitive enough that a stray dot could render
   right at the tip of each stroke even though it's meant to be fully
   hidden -- seen as a brief flash of "the start of stroke 1 and the
   end of stroke 2" the instant the animation begins. Widening the gap
   and resting at dashoffset:2 (solidly mid-gap, not at its edge) gives
   real margin against that. */
.marker-x path { stroke: var(--marker); stroke-width: 3; stroke-linecap: round; fill: none; stroke-dasharray: 1 2; stroke-dashoffset: 0; }
.punch-circle.is-drawing .marker-x path { stroke-dashoffset: 2; animation: draw-stroke .32s ease-out forwards; }
.punch-circle.is-drawing .marker-x path:last-child { animation-delay: .22s; }
@keyframes draw-stroke { to { stroke-dashoffset: 0; } }
@media (prefers-reduced-motion: reduce) {
  .punch-circle.is-drawing .marker-x path { animation: none; stroke-dashoffset: 0; }
}
/* Locked: the circle isn't a real tap target anymore (see is-disabled
   above) -- dried ink IS the disabled look, no separate greyed-out
   treatment. */
.is-torn .marker-x path { stroke: var(--marker-dried); opacity: .8; }

.stat-line-group { margin-bottom: 16px; display: flex; flex-direction: column; gap: 11px; }
.stat-line { display: flex; justify-content: space-between; font-size: 13.5px; }
.stat-label { color: var(--ink-mute); }
.stat-value { font-family: var(--f-mono); font-weight: 600; font-variant-numeric: tabular-nums; }

.pick-block { background: var(--surface); border-radius: 16px; padding: 16px; margin-bottom: 14px; }
.pick-block-label { font-weight: 700; font-size: 12px; color: var(--ink-mute); margin: 0 0 10px; }
.pick-block > input[type="text"],
.pick-block > input[type="email"],
.pick-block > select,
.pick-block > textarea {
  width: 100%; font: inherit; font-size: 14px; padding: 9px 10px;
  border: 1.5px solid var(--line); border-radius: 8px; background: var(--surface); color: var(--ink);
}

.standings-list { list-style: none; margin: 0; padding: 4px 0 24px; display: flex; flex-direction: column; gap: 10px; }
.standings-row {
  display: flex; align-items: center; gap: 12px;
  background: var(--surface); border-radius: 14px; padding: 12px 14px;
  box-shadow: 0 1px 0 var(--line);
}
.standings-row.rank-1 { position: relative; overflow: hidden; box-shadow: 0 0 0 2px var(--accent-2); }
.standings-row .rank { font-family: var(--f-display); font-weight: 700; font-size: 16px; color: var(--ink-mute); width: 18px; }
.standings-row.rank-1 .rank { color: var(--accent-2); }
.standings-row .who { flex: 1; min-width: 0; font-weight: 700; font-size: 14.5px; }
.standings-row .record-cell { text-align: right; }
.standings-row .pct { display: block; font-family: var(--f-mono); font-weight: 700; font-size: 14px; font-variant-numeric: tabular-nums; }
.standings-row .wl { font-size: 10.5px; color: var(--ink-mute); font-variant-numeric: tabular-nums; }

.pick-matrix-wrap {
  overflow-x: auto;
  margin: 0 0 20px;
}
.pick-matrix {
  border-collapse: collapse;
  font-size: 12px;
  font-family: var(--f-mono);
  font-variant-numeric: tabular-nums;
}
.pick-matrix th, .pick-matrix td {
  padding: 6px 8px;
  text-align: center;
  white-space: nowrap;
}
.pick-matrix thead th {
  color: var(--ink-mute);
  font-weight: 700;
  font-family: var(--f-body);
  border-bottom: 1.5px solid var(--line);
}
.pick-matrix thead th a {
  color: inherit;
  text-decoration: none;
}
.pick-matrix tbody th {
  text-align: left;
  font-family: var(--f-body);
  font-weight: 700;
  color: var(--ink);
}
.pick-matrix tbody tr:nth-child(even) {
  background: var(--surface-2);
}
/* Freeze the row-label column (the header corner and every row's username
   cell are both this row's first <th>) so it stays visible while the rest
   of a wide matrix scrolls horizontally under it. Needs its own background
   (matching the row-stripe it sits on) since sticky positioning doesn't
   otherwise stop scrolled cells from showing through underneath it. */
.pick-matrix th:first-child {
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--surface);
  box-shadow: 1px 0 0 var(--line);
}
.pick-matrix tbody tr:nth-child(even) th:first-child {
  background: var(--surface-2);
}
.matrix-pick {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 2px 8px;
  border-radius: 4px;
  border: 2px solid;
  font-family: var(--f-body);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .02em;
}
.matrix-pick-tie {
  background: var(--surface-2);
  border-color: var(--line);
  color: var(--ink-mute);
}

/* Confetti -- see docs/DESIGN.md's Motion section (pattern 2). The one
   ambient/looping animation in the system, reserved for the #1 standings
   spot. Unlike the diamond glint below, this pattern has no static-but-
   visible fallback: the rank-1 row's existing 2px accent-2 outline (above)
   is already the complete reduced-motion experience, so outside the query
   these squares stay invisible (opacity: 0) rather than sitting frozen
   mid-fall.

   Position, size, color, fall distance, rotation, and delay are randomized
   per piece at render time (see picks/confetti.py) and set as inline
   styles/custom properties on each <span> -- not fixed CSS classes -- so
   every celebratory burst actually looks different, rather than the same
   hand-picked arrangement every time. --rot/--fall feed the one shared
   keyframe below so each piece can have its own arc without a separate
   @keyframes per piece. */
.confetti {
  position: absolute;
  border-radius: 1px;
  opacity: 0;
  pointer-events: none;
}

@media (prefers-reduced-motion: no-preference) {
  .confetti { animation: confetti-fall 3.6s ease-in infinite; }
}

@keyframes confetti-fall {
  0%   { transform: translateY(-4px) rotate(0deg); opacity: 0; }
  12%  { opacity: 1; }
  65%  { opacity: 1; }
  100% { transform: translateY(var(--fall, 24px)) rotate(var(--rot, 50deg)); opacity: 0; }
}

.submit-row { padding-top: 4px; }
/* For a row holding more than one button-in-its-own-form (e.g. Accept/
   Decline) -- .button's width:100% otherwise makes each one fill the
   whole row on its own line, stacking them directly on top of each
   other instead of sitting side by side. */
.submit-row-multi { display: flex; gap: 10px; padding-top: 4px; }
.submit-row-multi form { flex: 1; }
.button {
  display: inline-block;
  font-family: var(--f-display); font-weight: 700; font-size: 15px;
  background: var(--accent); color: var(--accent-text); border: 0;
  padding: 13px 20px; border-radius: 12px; cursor: pointer; width: 100%;
  text-align: center; text-decoration: none;
  box-sizing: border-box;
}
.button:hover { filter: brightness(1.05); }
.button.is-submitting {
  opacity: .6;
  pointer-events: none;
  cursor: not-allowed;
}

/* Destructive/leave-type actions -- var(--loss) is already the app's
   established "negative" semantic color (see docs/DESIGN.md), reused
   here rather than introducing a new red. Outlined, not filled, so it
   doesn't read as loud/urgent as the primary accent button next to it. */
.button-danger {
  background: transparent; color: var(--loss); border: 2px solid var(--loss);
  padding: 11px 20px;
}
.button-danger:hover { background: var(--loss); color: var(--accent-text); filter: none; }

.member-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.member-row-actions { display: flex; align-items: center; gap: 10px; }
.member-row-action { background: none; border: 0; padding: 0; font-size: 12px; color: var(--ink-mute); text-decoration: underline; cursor: pointer; }
.member-row-action:hover { color: var(--accent); }
.member-row-action-remove:hover { color: var(--loss); }

.season-list { list-style: none; margin: 0; padding: 0; }
.season-block { margin-bottom: 24px; }
.season-block h2 { font-family: var(--f-display); font-size: 18px; margin: 0 0 8px; }
.season-block h2 a { color: inherit; text-decoration: none; }

.login-form { background: var(--surface); border-radius: 16px; padding: 20px; margin-top: 16px; }
.login-form p { margin: 0 0 12px; }
.login-form label { display: block; font-size: 12.5px; font-weight: 600; color: var(--ink-mute); margin-bottom: 4px; }
.login-form input[type="text"],
.login-form input[type="email"],
.login-form input[type="password"] {
  width: 100%; padding: 10px 12px; border-radius: 10px; border: 2px solid var(--line);
  font-size: 15px; background: var(--ground); color: var(--ink);
}

.auth-links { margin-top: 14px; font-size: 13px; color: var(--ink-mute); }

/* Confirm stamp -- see docs/DESIGN.md's Components section. Fixed to the
   viewport (not a specific card) so the same element/JS works from any
   page: a rubber-stamp-style confirmation that lands when a pick is
   submitted, reinforcing the "physical ticket" metaphor the rest of the
   design system leans on, rather than a generic toast. */
.confirm-stamp {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) rotate(-8deg);
  opacity: 0;
  pointer-events: none;
  font-family: var(--f-display);
  font-weight: 700;
  font-size: 26px;
  letter-spacing: .1em;
  color: var(--win);
  border: 4px solid var(--win);
  border-radius: 12px;
  padding: 12px 26px;
  background: var(--surface);
  text-transform: uppercase;
  box-shadow: 0 16px 40px -12px rgba(30, 40, 25, .45);
  z-index: 50;
  transition: opacity .2s ease;
}
.confirm-stamp.is-visible { opacity: 1; }

@media (prefers-reduced-motion: no-preference) {
  .confirm-stamp.is-visible { animation: stamp-in .4s cubic-bezier(.34, 1.56, .64, 1); }
  @keyframes stamp-in {
    0% { transform: translate(-50%, -50%) scale(2.4) rotate(-14deg); opacity: 0; }
    100% { transform: translate(-50%, -50%) scale(1) rotate(-8deg); opacity: 1; }
  }
}

/* Trophy case -- see docs/DESIGN.md's Components section and the
   Trophy Chip mockup linked there. Tier is set via a class
   (.tier-bronze etc.) rather than an inline style, matching how the rest
   of this stylesheet avoids inline styles in templates. */
.trophy-subhead {
  font-family: var(--f-display);
  font-weight: 700;
  font-size: 15px;
  margin: 24px 0 10px;
}

.trophy-grid {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.trophy-chip {
  position: relative;
  background: var(--surface);
  border-radius: 14px;
  padding: 14px 16px;
  box-shadow: 0 1px 2px rgba(27, 35, 30, .06), 0 4px 14px rgba(27, 35, 30, .05);
  border: 2.5px solid var(--tier-color, var(--line));
  cursor: pointer;
}
.trophy-chip.is-unearned {
  cursor: default;
  opacity: .4;
  border-color: var(--line);
}

.trophy-chip.tier-bronze   { --tier-color: #9C7A54; }
.trophy-chip.tier-silver   { --tier-color: #9CA3AA; }
.trophy-chip.tier-gold     { --tier-color: #D4A62A; }
.trophy-chip.tier-platinum { --tier-color: #5D6FA3; }
.trophy-chip.tier-diamond  { --tier-color: #2FA8E0; overflow: visible; }

.trophy-chip summary {
  list-style: none;
}
.trophy-chip summary::-webkit-details-marker { display: none; }

.trophy-summary-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
}

.trophy-summary-text {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.trophy-name {
  font-family: var(--f-display);
  font-weight: 700;
  font-size: 15px;
}
.trophy-count {
  font-family: var(--f-mono);
  font-variant-numeric: tabular-nums;
  font-size: 13px;
  color: var(--ink-mute);
}
.trophy-description {
  font-size: 13px;
  color: var(--ink-mute);
  margin: 0;
}
.trophy-chip.is-unearned .trophy-description {
  margin-top: 6px;
}

.trophy-holes {
  display: flex;
  gap: 7px;
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1.5px dashed var(--line);
  align-items: center;
}
.trophy-holes .hole {
  width: 13px;
  height: 13px;
  border-radius: 50%;
  border: 1.5px solid var(--line);
  background: var(--ground);
}
.trophy-holes .hole.filled {
  border-color: var(--tier-color);
  background: var(--tier-color);
  box-shadow: inset 0 0 0 2px var(--surface);
}
.trophy-holes .tier-word {
  margin-left: auto;
  font-family: var(--f-display);
  font-weight: 700;
  font-size: 11px;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--tier-color);
}

.trophy-award-list {
  list-style: none;
  margin: 12px 0 0;
  padding: 12px 0 0;
  border-top: 1.5px dashed var(--line);
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.trophy-award-list li {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  font-size: 13px;
}
.trophy-award-list .when { color: var(--ink); }
.trophy-award-list .when a,
.trophy-award-list .note a {
  color: inherit;
  text-decoration: none;
}
.trophy-award-list .note {
  font-family: var(--f-mono);
  font-variant-numeric: tabular-nums;
  color: var(--ink-mute);
  font-size: 12px;
}

.season-links {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.season-links li {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  font-size: 13.5px;
}

.standings-link { font-size: 13px; font-weight: 600; text-decoration: none; }
.standings-link::after { content: " \2192"; }

.empty-season {
  background: var(--surface); border-radius: 14px; padding: 16px; margin: 10px 0 4px;
  font-size: 13.5px; color: var(--ink-mute);
}
.empty-season p { margin: 0 0 8px; }
.empty-season p:last-child { margin-bottom: 0; }

/* Past-seasons dropdown -- same <details> disclosure pattern as the
   header's league-switcher, just with plain <a> links instead of
   POST-switch buttons, since viewing a season isn't a state change. */
.season-dropdown { margin: 4px 0 8px; position: relative; }
.season-dropdown summary {
  cursor: pointer; list-style: none; display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--f-body); font-weight: 600; font-size: 13.5px; color: var(--ink);
  padding: 8px 12px; border: 1.5px solid var(--line); border-radius: 10px;
}
.season-dropdown summary::-webkit-details-marker { display: none; }
.season-dropdown summary::after { content: "\25BE"; font-size: 10px; color: var(--ink-mute); }
.season-dropdown[open] summary::after { transform: rotate(180deg); }
.season-dropdown ul {
  list-style: none; margin: 4px 0 0; padding: 6px;
  position: absolute; left: 0; background: var(--surface); border: 1px solid var(--line);
  border-radius: 10px; box-shadow: 0 4px 12px rgba(27,35,30,.12); min-width: 200px; z-index: 5;
}
.season-dropdown li a { display: block; padding: 7px 10px; border-radius: 7px; color: var(--ink); text-decoration: none; font-size: 13.5px; }
.season-dropdown li a:hover { background: var(--surface-2); }

.field-row { margin-bottom: 12px; }
.field-row label { display: block; font-size: 12.5px; font-weight: 600; color: var(--ink-mute); margin-bottom: 4px; }
.field-row input, .field-row select {
  width: 100%; font: inherit; font-size: 14px; padding: 9px 10px;
  border: 1.5px solid var(--line); border-radius: 8px; background: var(--surface); color: var(--ink);
}
.field-row-check { display: flex; align-items: center; gap: 8px; margin-bottom: 12px; }
.field-row-check label { font-size: 13.5px; font-weight: 600; margin: 0; }
.pick-block-help { font-size: 12.5px; color: var(--ink-mute); margin: -4px 0 12px; }


/* ---------------------------------------------------------------------
   Phones.

   Everything above is tuned at the .page max-width of 480px, which the
   layout never adapted away from -- there were no width-based breakpoints
   at all, so a 390px iPhone got the 480px design squeezed into 358px of
   content and a 320px SE into 288px. Nothing overflowed; it just got
   progressively tighter in the places that could least afford it.

   430px covers every current iPhone and most Androids. Kept to the few
   things that are measurably worst rather than a wholesale re-layout.
   --------------------------------------------------------------------- */
@media (max-width: 430px) {
  /* 8px back for content, on both the page and the header that has to
     line up with it. */
  .page { padding-left: 12px; padding-right: 12px; }
  .site-header { padding-left: 12px; padding-right: 12px; }

  /* The pick stub is a fixed 128px, so its share of the row grows as the
     screen shrinks -- 28.6% at the design width but 44.4% on an SE, taking
     it straight out of the team names next to it. */
  .detail-hero-stub { width: 108px; padding-left: 6px; padding-right: 6px; }

  /* Was nowrap + ellipsis, which truncates from the right -- and the
     "(International)" label lives on the right, so exactly the thing worth
     seeing is what got cut. Wrapping to a second line costs nothing here. */
  .ticket-venue { white-space: normal; overflow: visible; text-overflow: clip; }

  /* A long league name would otherwise push the notification and profile
     icons toward the edge. Truncate the name instead -- it's the least
     important thing in that row, and it's on screen elsewhere. */
  .league-switcher summary,
  .league-indicator {
    display: inline-block;
    max-width: 38vw;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: middle;
  }

  /* Big enough to read at 480px, unnecessarily large once the column is
     100px narrower. */
  .screen-head h1 { font-size: 23px; }
}

/* Diamond glint -- see docs/DESIGN.md's Motion section (pattern 3). A
   sharp, brief flash catching a facet, not an ambient twinkle -- gated
   behind prefers-reduced-motion, with a static-but-visible default. */
.glint {
  position: absolute;
  width: 30px;
  height: 30px;
  opacity: .6;
  pointer-events: none;
  transform: rotate(var(--rot, 0deg));
  filter: drop-shadow(0 0 5px var(--tier-diamond, #2FA8E0));
}
.glint::before,
.glint::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  background: linear-gradient(90deg, transparent, #2FA8E0 30%, #FFFFFF 50%, #2FA8E0 70%, transparent);
}
.glint::before { width: 30px; height: 3.5px; transform: translate(-50%, -50%); }
.glint::after  { width: 3.5px; height: 30px; transform: translate(-50%, -50%); }

.glint.g1 { top: -12px; right: 26px; --rot: 6deg; }
.glint.g2 { top: 4px; right: -12px; width: 22px; height: 22px; --rot: -12deg; }
.glint.g2::before { width: 22px; }
.glint.g2::after  { height: 22px; }
.glint.g3 { bottom: -11px; right: 58px; width: 20px; height: 20px; --rot: 20deg; }
.glint.g3::before { width: 20px; }
.glint.g3::after  { height: 20px; }
.glint.g4 { top: 32%; left: -12px; --rot: -8deg; }

@media (prefers-reduced-motion: no-preference) {
  .glint { animation: glint-flash 4.8s ease-in-out infinite; }
  .glint.g1 { animation-delay: 0s; }
  .glint.g2 { animation-delay: 1.2s; }
  .glint.g3 { animation-delay: 2.4s; }
  .glint.g4 { animation-delay: 3.6s; }
}

@keyframes glint-flash {
  0%   { opacity: .15; transform: rotate(var(--rot, 0deg)) scale(.5); }
  18%  { opacity: 1;   transform: rotate(var(--rot, 0deg)) scale(1.15); }
  30%  { opacity: 1;   transform: rotate(var(--rot, 0deg)) scale(1.05); }
  45%  { opacity: .2;  transform: rotate(var(--rot, 0deg)) scale(.6); }
  100% { opacity: .15; transform: rotate(var(--rot, 0deg)) scale(.5); }
}

.theme-toggle {
  background: none;
  border: 1.5px solid var(--line);
  border-radius: 999px;
  padding: 4px 10px;
  font: inherit;
  font-family: var(--f-body);
  font-size: 11.5px;
  font-weight: 600;
  color: var(--ink-mute);
  cursor: pointer;
  margin-left: 10px;
}
.theme-toggle:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.team-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 3px 10px;
  border-radius: 6px;
  border: 2px solid;
  font-family: var(--f-display);
  min-width: 4.2em;
}

.line-lock-note {
  font-family: var(--f-body);
  font-size: 12px;
  color: var(--ink-mute);
  margin: 0 0 10px;
}

/* Deliberately no box/background/divider here -- bordering this like a
   card made it read as another pickable game rather than commentary on
   the one above it, and a rule between the ticket and its own stats
   turned out to be one divider too many next to the between-games
   divider on .ticket-card-wrap. Just spacing. */
.insights-panel {
  padding: 10px 0 0;
  margin: 10px 0 0;
}
.insights-heading {
  display: flex; align-items: center; gap: 8px;
  font-family: var(--f-mono); font-size: 11px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-mute); margin: 0 0 8px;
}
.insights-heading:not(:first-child) { margin-top: 12px; }
.insight-line {
  font-size: 13px; margin: 0 0 6px; display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
}
.insight-line:last-child { margin-bottom: 0; }
.insight-line-muted { color: var(--ink-mute); font-size: 12px; }
