/* Monochrome pixel/arcade theme, matching the sibling ../tennis_Quick app:
   black & white base (sharp corners, thick borders, hard block shadows,
   uppercase mono type) with punchy color reserved for moments that should
   hit hard - tier accents, wins/losses, achievements, wildcards. The color
   pops harder BECAUSE everything else is grayscale. Fixed dark look always
   (no light-mode variant), same commitment tennis_Quick makes. */
:root {
  color-scheme: dark;
  --surface-1:      #000000;
  --page:           #000000;
  --panel-2:        #0d0d0d;
  --text-primary:   #ffffff;
  --text-secondary: #aaaaaa;
  --text-muted:     #888888;
  --gridline:       #333333;
  --baseline:       #555555;
  --border:         #ffffff;
  --border-dim:     #555555;
  --series-1:       #ffffff;
  --series-1-track: #333333;
  --good:           #39ff6a;
  --bad:            #ff3b3b;
  --gold:           #ffd400;
  /* Deep Mode tournament-tier accents - fixed categorical hue order, never
     reused for anything else, so a category is always recognizable by color
     at a glance without needing to read the label. */
  --tier-slam:        #ffd400;
  --tier-masters1000: #a78bfa;
  --tier-atp500:      #3987e5;
  --tier-atp250:      #2dd4bf;
  --tier-challenger:  #fb923c;
  --tier-itf:         #9ca3af;
  --tier-junior:      #f472b6;
  --wildcard:         #ffd400;
  --card-accent:      #a78bfa;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: "Consolas", "Courier New", ui-monospace, monospace;
  background: var(--page);
  color: var(--text-primary);
  line-height: 1.45;
  position: relative;
}

/* subtle scanline overlay for CRT flavor - fixed, non-interactive */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 500;
  background: repeating-linear-gradient(
    to bottom,
    rgba(255, 255, 255, 0.025) 0px,
    rgba(255, 255, 255, 0.025) 1px,
    transparent 1px,
    transparent 3px
  );
}

.app {
  max-width: 760px;
  margin: 0 auto;
  padding: 24px 16px 64px;
  position: relative;
}

h1 {
  font-size: 20px;
  font-weight: 700;
  margin: 0 0 4px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.subtitle {
  color: var(--text-secondary);
  font-size: 13px;
  margin: 0 0 24px;
}

.card {
  background: var(--surface-1);
  border: 2px solid var(--border);
  border-radius: 0;
  padding: 20px;
  margin-bottom: 16px;
  box-shadow: 4px 4px 0 var(--border-dim);
}

.card h2 {
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-secondary);
  margin: 0 0 16px;
  font-weight: 700;
}

label {
  display: block;
  font-size: 11px;
  color: var(--text-secondary);
  margin-bottom: 4px;
  margin-top: 12px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}
label:first-of-type { margin-top: 0; }

input, select {
  width: 100%;
  padding: 9px 10px;
  border-radius: 0;
  border: 2px solid var(--border);
  background: var(--page);
  color: var(--text-primary);
  font-size: 14px;
  font-family: inherit;
}
input:focus, select:focus { outline: none; border-color: var(--gold); }

.btn {
  display: inline-block;
  padding: 12px 18px;
  min-height: 44px;
  border-radius: 0;
  border: 2px solid var(--border);
  background: var(--text-primary);
  color: #000;
  font-size: 14px;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  cursor: pointer;
  font-family: inherit;
  touch-action: manipulation;
  box-shadow: 3px 3px 0 var(--border-dim);
}
.btn:hover { background: var(--gold); border-color: var(--gold); }
.btn:active { transform: translate(2px, 2px); box-shadow: 1px 1px 0 var(--border-dim); }
.btn.secondary {
  background: var(--page);
  color: var(--text-secondary);
  border: 2px solid var(--border);
}
.btn.secondary:hover { color: #000; background: var(--text-primary); }

.btn-row { margin-top: 20px; display: flex; gap: 10px; flex-wrap: wrap; }

/* Confirm & continue is pinned to the bottom of the viewport during season
   planning - that step's list (team slots + one-offs + cards) can run long,
   and scrolling back down to find the confirm button every time you toggle
   a pick was annoying. #step-decision's own bottom padding below reserves
   room so this floating bar never covers the last card in the list. */
#confirm-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 60;
  margin: 0;
  padding: 12px 16px;
  background: var(--surface-1);
  border-top: 2px solid var(--border);
  box-shadow: 0 -4px 0 var(--border-dim);
  justify-content: center;
}
#confirm-bar .btn { max-width: 760px; width: 100%; }
#step-decision { padding-bottom: 76px; }
.btn.small { padding: 6px 12px; min-height: 32px; font-size: 12px; box-shadow: 2px 2px 0 var(--border-dim); }
/* Active-filter state (e.g. the Statistics modal's surface picker) - gold
   like every other "this is the selected one" signal in the app. */
.btn.secondary.selected {
  background: var(--gold);
  color: #000;
  border-color: var(--gold);
}

/* My Careers panel - no login, so "your code" is the entire identity (see
   web/server.py's anonymous profile-cookie design); this bar is the one
   place a player is reminded of it and can carry it to another device. */
.profile-code-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  background: var(--page);
  border: 2px solid var(--border);
  border-radius: 0;
  padding: 10px 14px;
  margin-bottom: 16px;
  font-size: 13px;
}
.profile-code-bar b { font-variant-numeric: tabular-nums; letter-spacing: 0.04em; color: var(--gold); }

.careers-list { display: flex; flex-direction: column; gap: 10px; }
.career-card {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  background: var(--page);
  border: 2px solid var(--border);
  border-radius: 0;
  padding: 14px;
  box-shadow: 3px 3px 0 var(--border-dim);
}
.career-card.retired { opacity: 0.7; box-shadow: none; }
.career-card-info { display: flex; flex-direction: column; gap: 3px; }
.career-card-name { font-weight: 700; font-size: 15px; }
.career-card-meta { font-size: 12px; color: var(--text-secondary); }
.career-card-badge {
  display: inline-block;
  font-size: 10px;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  padding: 2px 7px;
  border-radius: 0;
  margin-left: 6px;
  border: 1px solid var(--good);
  background: color-mix(in srgb, var(--good) 15%, transparent);
  color: var(--good);
}
.career-card-badge.retired-badge {
  border-color: var(--text-muted);
  background: color-mix(in srgb, var(--text-muted) 15%, transparent);
  color: var(--text-muted);
}

.resume-code-row {
  display: flex;
  gap: 8px;
  margin-top: 16px;
  align-items: center;
}
.resume-code-row input { width: auto; flex: 1; }

/* KPI row - pinned to the top of the viewport on scroll so fatigue/rank/etc.
   stay visible while reading the calendar/decisions further down the page. */
.kpi-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
  gap: 12px;
  margin: 0 0 4px;
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--page);
  padding: 10px 0;
}
.kpi {
  background: var(--surface-1);
  border: 2px solid var(--border);
  border-radius: 0;
  padding: 14px 14px;
  box-shadow: 3px 3px 0 var(--border-dim);
}
.kpi .label {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-muted);
  margin-bottom: 6px;
}
.kpi .value {
  font-size: 22px;
  font-weight: 900;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}
.kpi .value.long-value { font-size: 13px; }
.kpi .value.critical { color: var(--bad); }
.kpi .value.warning { color: var(--gold); }
.kpi .delta {
  font-size: 12px;
  color: var(--good);
  margin-top: 2px;
  font-variant-numeric: tabular-nums;
}

/* Tap/click-friendly replacement for native title="" tooltips - a bare
   title attribute never shows on touch devices (no hover state exists
   there at all), so anything meant to be read on a phone needs its own
   popover instead. See showTip/hideTip in app.js - elements keep their
   title attribute too (still gives desktop mouse users the free native
   hover), this class just adds the tap path everyone else needs. */
.tap-tip { cursor: help; }
.tap-tip-bubble {
  position: fixed;
  z-index: 2000;
  max-width: 260px;
  background: var(--surface-1);
  border: 2px solid var(--card-accent);
  box-shadow: 4px 4px 0 rgba(0, 0, 0, 0.7);
  padding: 8px 10px;
  font-size: 12px;
  line-height: 1.4;
  white-space: pre-line;
  color: var(--text-primary);
}

/* Attribute star rows */
.attr-row {
  display: grid;
  grid-template-columns: 76px 1fr 44px;
  align-items: center;
  gap: 10px;
  margin-bottom: 10px;
}
.attr-row .attr-label {
  font-size: 13px;
  color: var(--text-secondary);
}
.star-row {
  display: flex;
  gap: 3px;
}
.star-row svg { width: 20px; height: 20px; flex-shrink: 0; }
.attr-value {
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
  text-align: right;
  /* A fixed-width single-line cell clipped/overlapped the preview badge
     the moment a real delta badge AND a preview badge both showed at
     once (2 seasons in, mid-selection) - most visible on mobile where
     the column is already narrow. Wrapping badges onto their own line
     instead of forcing everything onto one keeps them readable and
     still right-aligned under the number. */
  display: flex;
  align-items: baseline;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: 2px;
}
.attr-row.attr-down .attr-label { color: var(--text-primary); }

/* Surface fit - a diverging bar per surface, same label/indicator/value
   row shape as the attribute stars above (see .attr-row) so it reads as
   part of the same "who is this player" picture, not a bolted-on extra.
   Centered on zero: bars grow right (green) for a surface that suits this
   player, left (red) for one that doesn't - the whole row is scannable at
   a glance for "which surface should I focus on." */
.surface-fit-section {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--gridline);
}
.surface-fit-heading {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-muted);
  margin-bottom: 8px;
}
.surface-row {
  display: grid;
  grid-template-columns: 56px 1fr auto;
  align-items: center;
  gap: 10px;
  margin-bottom: 6px;
}
.surface-label {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-secondary);
}
.surface-bar {
  position: relative;
  height: 10px;
  border: 1px solid var(--border-dim);
  background: var(--page);
}
.surface-bar-mid {
  position: absolute;
  top: -1px;
  bottom: -1px;
  left: 50%;
  width: 1px;
  background: var(--border-dim);
}
.surface-bar-fill {
  position: absolute;
  top: 0;
  bottom: 0;
}
.surface-bar-fill.up { background: var(--good); }
.surface-bar-fill.down { background: var(--bad); }
.surface-value {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  min-width: 40px;
  font-size: 12px;
  font-weight: 900;
  font-variant-numeric: tabular-nums;
  text-align: right;
  color: var(--text-muted);
}
.surface-value.fit-good { color: var(--good); }
.surface-value.fit-bad { color: var(--bad); }

.delta-badge {
  font-size: 11px;
  font-weight: 900;
  margin-left: 4px;
}
.delta-badge.up { color: var(--good); }
.delta-badge.down { color: var(--bad); }
/* Preview of a selected-but-unconfirmed development decision's effect -
   deliberately lighter/dashed-feeling (lower opacity, bordered pill) so it
   never reads as an already-happened change like the plain delta badge above. */
.delta-badge.preview {
  padding: 1px 5px;
  border: 1px dashed currentColor;
  border-radius: 0;
  opacity: 0.75;
}

/* Attribute star-up toast - a small self-dismissing card celebrating a
   visible star-rating increase (not every raw point gain, only ones that
   actually move the displayed stars - see renderAttrs). */
#attr-toast-container {
  position: fixed;
  top: 16px;
  right: 16px;
  z-index: 1000;
  display: flex;
  flex-direction: column;
  gap: 8px;
  pointer-events: none;
}
.attr-toast {
  background: var(--surface-1);
  border: 2px solid var(--good);
  border-radius: 0;
  padding: 8px 14px;
  box-shadow: 4px 4px 0 rgba(0, 0, 0, 0.7);
  opacity: 0;
  transform: translateX(24px);
  transition: opacity 0.3s ease, transform 0.3s ease;
}
.attr-toast.show {
  opacity: 1;
  transform: translateX(0);
}
.attr-toast-row {
  display: flex;
  align-items: center;
  gap: 8px;
}
.attr-toast-row + .attr-toast-row { margin-top: 4px; }
.attr-toast-label {
  font-size: 13px;
  font-weight: 900;
  color: var(--good);
  white-space: nowrap;
  text-transform: uppercase;
}
/* Achievement unlocks reuse the same toast stack/timing as attribute
   star-ups (see showAchievementToast) but in gold, not green - a different
   kind of event (a permanent career milestone vs. a stat going up). */
.attr-toast.achievement { border-color: var(--gold); }
.attr-toast.achievement .attr-toast-label { color: var(--gold); }
.attr-toast .star-row { display: inline-flex; gap: 1px; }
.attr-toast .star-row svg { width: 14px; height: 14px; }

/* Achievements entry-point bar - a slim full-width tappable strip (used
   both in the active game and on the final scorecard) rather than a full
   card, since it's a secondary nav trigger, not primary content. */
.achv-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  background: var(--surface-1);
  border: 2px solid var(--border);
  border-radius: 0;
  padding: 12px 16px;
  margin-bottom: 16px;
  font-size: 14px;
  font-weight: 700;
  color: var(--text-primary);
  cursor: pointer;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  box-shadow: 3px 3px 0 var(--border-dim);
}
.achv-bar:hover { border-color: var(--gold); }
.achv-bar #achv-bar-progress, .achv-bar #achv-bar-progress-sc {
  color: var(--text-secondary);
  font-weight: 900;
  font-variant-numeric: tabular-nums;
}
/* Game-panel instance only (the scorecard's is a short, single-screen view -
   no need to fight for a sticky slot there). Sticky, same as .budget-bar
   below - otherwise this sits in normal flow directly under the sticky
   .kpi-row and gets hidden behind it the moment you scroll even slightly,
   which is exactly what made it read as "not clickable." */
#btn-view-achievements {
  position: sticky;
  top: var(--kpi-row-height, 112px);
  z-index: 15;
}

/* Achievements modal overlay */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.75);
  z-index: 900;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}
.modal-panel {
  background: var(--surface-1);
  border: 2px solid var(--border);
  border-radius: 0;
  padding: 20px;
  max-width: 720px;
  width: 100%;
  max-height: 85vh;
  overflow-y: auto;
  box-shadow: 6px 6px 0 var(--border-dim);
}
.modal-header {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 14px;
}
.modal-header h2 {
  margin: 0;
  font-size: 16px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-secondary);
}
.modal-header #achv-modal-progress {
  flex: 1;
  color: var(--text-secondary);
  font-weight: 900;
  font-variant-numeric: tabular-nums;
}

.achv-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 10px;
}
.achv-item {
  border: 2px solid var(--border-dim);
  border-radius: 0;
  padding: 10px 12px;
}
.achv-item.unlocked {
  border-color: var(--good);
  background: color-mix(in srgb, var(--good) 10%, transparent);
}
.achv-item.locked { opacity: 0.5; }
.achv-item-title {
  display: flex;
  align-items: center;
  gap: 6px;
  font-weight: 700;
  font-size: 13px;
}
.achv-item.unlocked .achv-item-title { color: var(--good); }
.achv-item-desc {
  font-size: 12px;
  color: var(--text-secondary);
  margin-top: 4px;
}
.achv-item-pct {
  font-size: 11px;
  color: var(--text-muted);
  margin-top: 6px;
  font-variant-numeric: tabular-nums;
}

/* Elo line chart - now scorecard-only (see .sc-chart-wrap below); the
   live in-game version and its hover tooltip/crosshair were removed
   (redundant with this same chart already shown at retirement). */
svg.chart { width: 100%; height: 180px; display: block; overflow: visible; }
.chart-line {
  fill: none;
  stroke: var(--series-1);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.chart-dot { fill: var(--gold); }
.chart-grid { stroke: var(--gridline); stroke-width: 1; }
.chart-axis-label { fill: var(--text-muted); font-size: 10px; }

/* Season plan / decision buttons */
.plan-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 10px;
}
.plan-grid-wide {
  grid-template-columns: 1fr;
}

/* Icon shown at the head of every decision/card/team-slot tile (see
   web/static/icons.js) - a small bordered pixel-art square, inline before
   the item's title so the whole row reads as one unit. */
.plan-btn-head {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 2px;
}
.pixel-icon { image-rendering: pixelated; }

/* "Your Team" - persistent leveled slots, always a fixed 3-per-row grid
   (unlike the one-off decisions grid below, which reflows by width) so it
   reads as a stable roster rather than a shopping list. */
.team-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  margin-bottom: 20px;
}
.one-offs-heading { margin-top: 4px; }
.team-slot-card .team-level-line {
  display: block;
  font-size: 11px;
  font-weight: 900;
  letter-spacing: 0.04em;
  color: var(--gold);
  margin-top: 4px;
}
.team-slot-card .team-current-effects {
  display: block;
  font-size: 11px;
  color: var(--good);
  margin-top: 2px;
}
@media (max-width: 640px) {
  .team-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 420px) {
  .team-grid { grid-template-columns: 1fr; }
}
.plan-btn {
  padding: 14px 16px;
  min-height: 44px;
  border-radius: 0;
  border: 2px solid var(--border);
  background: var(--page);
  color: var(--text-primary);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  text-align: left;
  font-family: inherit;
  touch-action: manipulation;
  display: block;
  width: 100%;
  box-shadow: 3px 3px 0 var(--border-dim);
}
.plan-btn:hover { border-color: var(--gold); box-shadow: 3px 3px 0 var(--gold); }
.plan-btn:active { background: var(--series-1-track); }
.plan-btn.selected {
  border-color: var(--series-1);
  background: var(--series-1-track);
  box-shadow: 3px 3px 0 var(--series-1);
}

/* Deep Mode tournament tier accents - a left border stripe in the tier's
   fixed categorical color, so the level is recognizable before reading any
   text (fixed hue-per-tier, never reused for anything else on the page). */
.plan-btn.tier-slam        { border-left: 5px solid var(--tier-slam); }
.plan-btn.tier-masters1000 { border-left: 5px solid var(--tier-masters1000); }
.plan-btn.tier-atp500      { border-left: 5px solid var(--tier-atp500); }
.plan-btn.tier-atp250      { border-left: 5px solid var(--tier-atp250); }
.plan-btn.tier-challenger  { border-left: 5px solid var(--tier-challenger); }
.plan-btn.tier-itf         { border-left: 5px solid var(--tier-itf); }
.plan-btn.tier-tour_finals { border-left: 5px solid var(--tier-slam); }
.plan-btn.tier-junior_slam { border-left: 5px solid var(--tier-junior); }
.plan-btn.tier-youth_finals { border-left: 5px solid var(--tier-junior); }

/* Budget affordability - a right-side accent, deliberately the opposite
   edge from the tier stripe so the two signals (what it is / can I afford
   it) never compete for the same border. */
.plan-btn.afford-yes { border-right: 5px solid var(--good); }
.plan-btn.afford-no {
  border-right: 5px solid var(--bad);
  opacity: 0.5;
  cursor: not-allowed;
}

/* Wildcards are a rare, valuable entry method - a tinted fill plus a
   full-color border (not just the corner chip) so one stands out from the
   surrounding direct-entry/qualifying cards at a glance. */
.plan-btn.wildcard-entry {
  background: color-mix(in srgb, var(--wildcard) 14%, var(--page));
  border-color: var(--wildcard);
}

.tier-chip {
  display: inline-block;
  font-size: 10px;
  font-weight: 900;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  padding: 2px 7px;
  border-radius: 0;
  margin-right: 6px;
  color: #000;
  vertical-align: middle;
  /* Fallback for Standard/Quick titles, which have no Deep-mode "category"
     and so get no tier-X modifier below - without this the chip has no
     background at all and disappears against the dark theme. */
  background: var(--text-muted);
}
.tier-chip.tier-slam        { background: var(--tier-slam); }
.tier-chip.tier-masters1000 { background: var(--tier-masters1000); }
.tier-chip.tier-atp500      { background: var(--tier-atp500); color: #fff; }
.tier-chip.tier-atp250      { background: var(--tier-atp250); }
.tier-chip.tier-challenger  { background: var(--tier-challenger); }
.tier-chip.tier-itf         { background: var(--tier-itf); color: #fff; }
.tier-chip.tier-tour_finals { background: var(--tier-slam); }
.tier-chip.tier-junior_slam { background: var(--tier-junior); color: #fff; }
.tier-chip.tier-youth_finals { background: var(--tier-junior); color: #fff; }

.wildcard-badge {
  display: inline-block;
  font-size: 10px;
  font-weight: 900;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 2px 8px;
  border-radius: 0;
  margin-left: 6px;
  border: 1px solid var(--wildcard);
  background: var(--wildcard);
  color: #000;
  vertical-align: middle;
}
.last-year-badge {
  display: inline-block;
  font-size: 10px;
  font-weight: 900;
  letter-spacing: 0.02em;
  padding: 2px 8px;
  border-radius: 0;
  margin-left: 6px;
  border: 1px solid var(--gold);
  background: color-mix(in srgb, var(--gold) 18%, transparent);
  color: var(--gold);
  vertical-align: middle;
}
.last-year-badge.title-defense {
  border-color: var(--wildcard);
  background: color-mix(in srgb, var(--wildcard) 22%, transparent);
  color: var(--wildcard);
}
.home-badge {
  display: inline-block;
  font-size: 10px;
  font-weight: 900;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 2px 8px;
  border-radius: 0;
  margin-left: 6px;
  border: 1px solid var(--good);
  background: color-mix(in srgb, var(--good) 20%, transparent);
  color: var(--good);
  vertical-align: middle;
}
/* Home-country entries get the same tinted-fill treatment wildcards do
   (see .plan-btn.wildcard-entry above) so "you're playing at home" reads
   as a distinct, positive signal at a glance, not just the small badge. */
.plan-btn.home-entry {
  background: color-mix(in srgb, var(--good) 10%, var(--page));
  border-color: var(--good);
}
.plan-btn .plan-cost {
  display: block;
  font-weight: 400;
  color: var(--text-muted);
  font-size: 11px;
  margin-top: 4px;
}
/* The dollar figure used to be plain text buried inside the same muted,
   11px narrative sentence as the flavor text - easy to miss entirely at a
   glance. Its own bold, higher-contrast, slightly larger span makes "how
   much does this cost" scannable without reading the whole line. */
.plan-btn .plan-cost .cost-amount {
  font-weight: 900;
  font-size: 12px;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}
.plan-btn.afford-no .plan-cost { color: var(--bad); font-weight: 600; }
.plan-btn.afford-no .plan-cost .cost-amount { color: var(--bad); }
.plan-btn.decision-card .plan-cost.negative .cost-amount { color: var(--good); }
.plan-effects {
  display: block;
  font-size: 11px;
  font-weight: 900;
  margin-top: 3px;
  font-variant-numeric: tabular-nums;
}
.plan-effects .up { color: var(--good); }
.plan-effects .down { color: var(--bad); }

/* Per-attribute effect tags (see appendEffectsLine) - independent wrapping
   chips instead of one dot-joined line, so a decision touching 4-5
   attributes at once reads as a tidy tag row instead of a crowded sentence. */
.effect-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-top: 5px;
}
.effect-chip {
  font-size: 10px;
  font-weight: 900;
  padding: 2px 6px;
  border-radius: 0;
  border: 1px solid currentColor;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.effect-chip.up { color: var(--good); background: color-mix(in srgb, var(--good) 15%, transparent); }
.effect-chip.down { color: var(--bad); background: color-mix(in srgb, var(--bad) 15%, transparent); }
.plan-btn .plan-desc {
  display: block;
  font-weight: 400;
  color: var(--text-secondary);
  font-size: 12px;
  margin-top: 5px;
  line-height: 1.4;
}
.plan-btn .plan-range {
  display: inline-block;
  font-weight: 400;
  color: var(--text-muted);
  font-size: 11px;
  margin-top: 6px;
}

/* Budget bar (multi-select decision step) - sticky so it stays visible
   while scrolling through a potentially long list of decision cards. */
.budget-bar {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  background: var(--page);
  border: 2px solid var(--border);
  border-radius: 0;
  padding: 10px 14px;
  margin-bottom: 14px;
  font-size: 13px;
  position: sticky;
  /* Stacks below BOTH sticky elements above it - the .kpi-row and the
     achievements bar (#btn-view-achievements) - not just the KPI row, or
     this and the achievements bar would fight for the same spot once both
     are stuck, the same overlap bug this comment used to describe for just
     the KPI row alone. Both heights are measured live in JS (renderKpis)
     since they grow once delta badges start appearing (2nd season onward)
     - a fixed guess drifts out of sync and lets whatever's above cover
     this bar again after the first update. */
  top: calc(var(--kpi-row-height, 112px) + var(--achv-bar-height, 60px));
  z-index: 10;
  box-shadow: 3px 3px 0 var(--border-dim);
}
.budget-bar > div { display: flex; flex-direction: column; }
.budget-bar .label {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-muted);
}
.budget-bar .value {
  font-weight: 900;
  font-variant-numeric: tabular-nums;
}
.budget-bar .value.over { color: var(--bad); }

.plan-btn.decision-card {
  position: relative;
  padding-left: 42px;
}
.plan-btn.decision-card .check {
  position: absolute;
  left: 14px;
  top: 14px;
  width: 18px;
  height: 18px;
  border-radius: 0;
  border: 2px solid var(--border);
  background: var(--surface-1);
}
.plan-btn.decision-card.selected .check {
  background: var(--gold);
  border-color: var(--gold);
}
.plan-btn.decision-card.selected .check::after {
  content: "";
  display: block;
  width: 5px; height: 9px;
  border: solid #000;
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
  margin: 2px auto;
}
.plan-btn.decision-card.disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
.plan-btn.decision-card .plan-cost.negative { color: var(--good); }

/* Cards - a distinct violet accent from both decisions (gold) and wildcard
   tournament entries (gold), so all three "special" treatments read as
   different concepts at a glance. */
.plan-btn.card-choice {
  border-color: var(--card-accent);
  background: color-mix(in srgb, var(--card-accent) 12%, var(--page));
}
.plan-btn.card-choice .check { border-color: var(--card-accent); }
.plan-btn.card-choice.selected {
  background: color-mix(in srgb, var(--card-accent) 22%, var(--page));
  border-color: var(--card-accent);
}
.plan-btn.card-choice.selected .check {
  background: var(--card-accent);
  border-color: var(--card-accent);
}

/* Deep Mode "Your cards" inventory panel (weekly view) - purchased cards
   waiting to be played, each with its own trigger button. */
#card-inventory-section {
  margin-bottom: 16px;
  padding: 12px 14px;
  border: 2px solid var(--card-accent);
  border-radius: 0;
  background: color-mix(in srgb, var(--card-accent) 10%, var(--page));
}
#card-inventory-section h3 { margin: 0 0 8px; font-size: 13px; text-transform: uppercase; letter-spacing: 0.03em; }
.card-inventory-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 0;
  border-top: 1px solid var(--border-dim);
}
.card-inventory-item:first-of-type { border-top: none; }
.card-inventory-item .label { font-weight: 700; font-size: 13px; }
.card-inventory-item .narrative { display: block; font-size: 11px; color: var(--text-secondary); margin-top: 2px; }
.card-inventory-item .btn { padding: 6px 12px; font-size: 12px; flex-shrink: 0; }
.pending-effects-note {
  font-size: 12px;
  color: var(--card-accent);
  font-weight: 700;
  margin-top: 8px;
}

/* Surface fit - reuses the affordability green/red language (Deep Mode
   tournament cards) so "this favors you" reads consistently across the app.
   Lives only on the retirement scorecard now (see renderScorecardSurfaceFit)
   - final affinity as a one-time retrospective, not a live panel that
   barely changes season to season. */
.sc-surface-fit-wrap { margin-top: 20px; }
.sc-section-label {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-muted);
  margin-bottom: 8px;
  text-align: left;
}
#sc-surface-fit-row { display: flex; gap: 8px; flex-wrap: wrap; }
.surface-fit-chip {
  flex: 1 1 100px;
  padding: 8px 10px;
  border-radius: 0;
  background: var(--page);
  border: 2px solid var(--border-dim);
  text-align: center;
}
.surface-fit-chip .name { display: block; font-size: 11px; color: var(--text-muted); text-transform: uppercase; }
.surface-fit-chip .value { display: block; font-size: 15px; font-weight: 900; font-variant-numeric: tabular-nums; }
.surface-fit-chip.fit-good .value { color: var(--good); }
.surface-fit-chip.fit-bad .value { color: var(--bad); }
.surface-hint { font-weight: 900; }
.surface-hint.fit-good { color: var(--good); }
.surface-hint.fit-bad { color: var(--bad); }

/* Step flow */
.step-indicator {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 18px;
}
.step-dot {
  width: 24px; height: 24px;
  border-radius: 0;
  background: var(--page);
  border: 2px solid var(--border-dim);
  color: var(--text-muted);
  font-size: 12px;
  font-weight: 900;
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.step-dot.active { background: var(--gold); border-color: var(--gold); color: #000; }
.step-dot.done { background: var(--series-1-track); border-color: var(--series-1); color: var(--series-1); }
.step-line { flex: 1; height: 2px; background: var(--gridline); }
.step-hint { color: var(--text-muted); font-size: 12px; margin: -10px 0 14px; }
.field-hint { color: var(--text-muted); font-size: 11px; margin: 6px 0 0; }
.defending-hint { color: var(--gold); }
.debt-hint { color: var(--bad); }
.event-consumes-hint { color: var(--text-muted); font-size: 12px; margin: 10px 0 14px; }
.titles-won-heading { margin-bottom: 10px; color: var(--text-secondary); font-size: 13px; text-transform: uppercase; letter-spacing: 0.03em; }

.tier-filter-row {
  display: flex;
  gap: 16px;
  margin-bottom: 10px;
}
.tier-filter-toggle {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--text-secondary);
  cursor: pointer;
  user-select: none;
  text-transform: uppercase;
  letter-spacing: 0.02em;
}
.tier-filter-toggle input { cursor: pointer; }

/* Titles list */
.title-entry {
  border-top: 1px solid var(--gridline);
  padding: 10px 0;
  font-size: 13px;
  display: flex;
  justify-content: space-between;
  gap: 8px;
  color: var(--text-secondary);
}
.title-entry:first-child { border-top: none; }
.title-entry .title-name { color: var(--text-primary); font-weight: 700; }
.title-entry .title-stats { font-variant-numeric: tabular-nums; text-align: right; }
.empty-note { color: var(--text-muted); font-size: 13px; }

/* Season log */
.log-entry {
  border-top: 1px solid var(--gridline);
}
.log-entry:first-child { border-top: none; }
.log-summary {
  padding: 10px 0;
  font-size: 13px;
  color: var(--text-secondary);
  display: flex;
  justify-content: space-between;
  gap: 8px;
  cursor: pointer;
  user-select: none;
}
.log-summary:hover { color: var(--text-primary); }
.log-entry .log-year { color: var(--text-primary); font-weight: 700; width: 70px; flex-shrink: 0; }
.log-summary .chevron { color: var(--text-muted); margin-left: 6px; flex-shrink: 0; transition: transform 0.15s ease; }
.log-entry.expanded .chevron { transform: rotate(90deg); }
.log-detail {
  display: none;
  padding: 4px 0 12px;
}
.log-entry.expanded .log-detail { display: block; }
.tourney-row {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  font-size: 12px;
  color: var(--text-secondary);
  padding: 4px 8px;
  border-radius: 0;
}
.tourney-row:nth-child(odd) { background: var(--panel-2); }
.tourney-row .tourney-name { color: var(--text-primary); }

.hidden { display: none !important; }

/* Marquee tournament reveal */
@keyframes fadeInUp {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: translateY(0); }
}
.marquee-round {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  font-size: 13px;
  padding: 8px 10px;
  border-radius: 0;
  margin-bottom: 6px;
  background: var(--page);
  border: 1px solid var(--border-dim);
  opacity: 0;
  animation: fadeInUp 0.35s ease forwards;
}
.marquee-round .mr-result { font-weight: 900; }
.marquee-round.win .mr-result { color: var(--good); }
.marquee-round.loss .mr-result { color: var(--bad); }
.season-recap {
  margin-top: 16px;
  padding-top: 16px;
  border-top: 1px solid var(--gridline);
  font-size: 13px;
  color: var(--text-secondary);
  line-height: 1.7;
}
.season-recap b { color: var(--text-primary); }
.narrative-line {
  font-style: italic;
  color: var(--text-primary);
  margin-bottom: 8px;
}

/* Scorecard */
.scorecard {
  text-align: center;
  padding: 28px 16px;
}
.sc-eyebrow {
  color: var(--text-muted);
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-weight: 700;
}
.scorecard .big {
  font-size: 30px;
  font-weight: 900;
  margin: 8px 0 2px;
}
.sc-sub {
  color: var(--text-secondary);
  font-size: 13px;
  margin-bottom: 16px;
}
.sc-chart-wrap { margin: 16px 0; }
.sc-stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
  gap: 10px;
  text-align: left;
  margin-top: 8px;
}
.sc-stat {
  background: var(--page);
  border: 2px solid var(--border-dim);
  border-radius: 0;
  padding: 12px;
}
.sc-stat .label {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-muted);
  margin-bottom: 4px;
}
.sc-stat .value {
  font-size: 18px;
  font-weight: 900;
  font-variant-numeric: tabular-nums;
}
.sc-stat .compare {
  font-size: 10px;
  color: var(--text-muted);
  margin-top: 3px;
}
.sc-stat .compare.up { color: var(--good); }
.sc-stat .compare.down { color: var(--bad); }
.scorecard .tier-reveal {
  margin-top: 20px;
  font-size: 14px;
  color: var(--text-secondary);
}

/* Feedback button + modal - sits in normal document flow at the bottom of
   the page (not fixed - it was covering content while scrolling). */
#feedback-btn {
  display: block;
  margin: 40px auto 24px;
  padding: 10px 16px;
  border-radius: 0;
  border: 2px solid var(--border);
  background: var(--page);
  color: var(--text-primary);
  font-family: inherit;
  font-size: 12px;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  cursor: pointer;
  box-shadow: 3px 3px 0 var(--border-dim);
}
#feedback-btn:hover { border-color: var(--gold); color: var(--gold); }
.feedback-modal-panel { max-width: 420px; text-align: left; }
.feedback-modal-panel textarea {
  width: 100%;
  min-height: 120px;
  padding: 9px 10px;
  border-radius: 0;
  border: 2px solid var(--border);
  background: var(--page);
  color: var(--text-primary);
  font-size: 14px;
  font-family: inherit;
  resize: vertical;
}
.feedback-modal-panel textarea:focus { outline: none; border-color: var(--gold); }
#feedback-status { font-size: 12px; color: var(--text-secondary); margin-top: 10px; min-height: 1.2em; }
#feedback-status.ok { color: var(--good); }
#feedback-status.err { color: var(--bad); }

@media (max-width: 480px) {
  .app { padding: 16px 12px 48px; }
  .card { padding: 16px; }
  .kpi-row { gap: 8px; }
  .kpi { padding: 10px; }
  .kpi .value { font-size: 18px; }

  /* Same 76px/1fr/44px columns as desktop left almost no room for the
     value cell once a real delta badge and a preview badge both need to
     fit next to the number - shrinking the label and stars a little
     gives that cell (which now wraps, see .attr-value) enough width to
     actually look aligned instead of crowded/clipped. */
  .attr-row { grid-template-columns: 58px 1fr 56px; gap: 6px; }
  .star-row svg { width: 16px; height: 16px; }

  /* long strings (tournament name+country+tier, budget bar values) need to
     stack rather than compete for space with a right-aligned sibling */
  .budget-bar { font-size: 12px; }
  .tourney-row, .log-summary, .title-entry {
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
  }
  .tourney-row .tourney-name, .title-entry .title-name { white-space: normal; }
  .tourney-row span:last-child, .title-entry .title-stats { text-align: left; }
  .log-summary .log-year { width: auto; }
  .log-summary .chevron { position: absolute; right: 0; }
  .log-summary { position: relative; padding-right: 20px; }
  #feedback-btn { padding: 8px 12px; font-size: 11px; }
}
