/* ── Self-hosted fonts ────────────────────────────────────────────
   Vendored rather than loaded from Google's CDN: an external stylesheet
   plus font files cannot be fetched on an offline iPad, which is a
   supported way to use this app. Both are VARIABLE fonts, so one file
   per family covers every weight (72 KB total for both, latin).
   Space Grotesk's axis stops at 700 — the CSS asks for 800 in a few
   places and the browser clamps, exactly as it did via the CDN. */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('fonts/inter-var-latin.woff2') format('woff2');
}
@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url('fonts/space-grotesk-var-latin.woff2') format('woff2');
}

/* ============================================================
   SkipPass — Clean Modern Basketball Stats Tracker
   ============================================================ */

/* ── Reset ──────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html {
  font-size: 16px;
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Mobile viewport: dvh accounts for browser chrome (address bar) */
  height: 100vh;
  height: 100dvh;
  /* Allow scrolling but block pinch-zoom — an accidental two-finger pinch
     during fast stat entry leaves the page stuck zoomed-in on iOS */
  touch-action: pan-x pan-y;
}

/* ── Design Tokens — "Cyan Energy" ───────────────────────────────
   Retokenised from design_handoff_cyan_energy. Worth recording how small
   this diff is: the greyscale, navy and status ramps in the handoff are
   byte-identical to what was already here (#F6F8FA canvas, #FFFFFF card,
   #F1F5F9 hairline, #E2E8F0 rule, #0F172A/#1E293B navy, #475569/#94A3B8
   text, #22C55E/#EF4444 status, #8B949E on-navy). Only the accent family
   moves — orange to cyan — which is why step 1 alone changes the whole
   app's character.

   THE ACCENT SPLITS BY ROLE, and the split is load-bearing rather than
   stylistic. Measured against white:

     --accent      #06B6D4   2.43:1   fills, marks, gradient start
     --accent-dark #0891B2   3.68:1   gradient end
     --accent-ink  #0E7490   5.36:1   anything that is TEXT

   The handoff nominates #0891B2 for "accent text on light", which clears
   AA only for large text (3:1) and not for the 11-15px links it is
   specified on. --accent-ink is one step further down the same cyan ramp:
   indistinguishable from #0891B2 at 12px, and it passes AA at 5.36:1. So
   every text use in this file points at --accent-ink, and --accent is
   reserved for fills, borders and marks — the same discipline the team
   palette already follows, and now it covers the brand colour too.

   The old orange was 2.80:1; cyan at #06B6D4 is 2.43:1, so leaving accent
   text on the raw brand colour would have made every accent label in the
   app LESS legible than before the redesign.
   ------------------------------------------------------------------- */
:root {
  --bg:           #F6F8FA;   /* canvas */
  --surface:      #FFFFFF;   /* card */
  --surface-2:    #F1F5F9;   /* hairline / inset fill */
  --border:       #E2E8F0;   /* table header rule */
  --border-2:     #F1F5F9;   /* row separators inside cards */
  --text-1:       #0F172A;   /* navy */
  --text-2:       #475569;
  --text-3:       #94A3B8;
  --text-faint:   #CBD5E1;

  --accent:       #06B6D4;   /* fills, marks, gradient start — never text */
  --accent-dark:  #0891B2;   /* gradient end */
  --accent-light: #22D3EE;   /* accent on navy: 9.88:1 */
  --accent-ink:   #0E7490;   /* accent AS text on light: 5.36:1 */
  /* Deliberately NOT themed. Some chips are white in both schemes because they
     sit on a cyan gradient, and their label must stay dark: in dark mode
     --accent-ink flips to #22D3EE, which on a white pill is 1.81:1. */
  --on-white-ink: #0E7490;
  --accent-soft:  #ECFEFF;   /* handoff calls this accent-tint */
  --accent-tint:  #ECFEFF;   /* handoff's own name, aliased */
  --accent-line:  #A5F3FC;   /* border on a tinted surface */
  --accent-row:   rgba(6,182,212,.08);
  --on-accent:    #FFFFFF;

  --accent-2:     #3B82F6;   /* REB blue, unchanged */
  --accent-2-soft:#EFF6FF;
  --green:        #22C55E;
  --green-soft:   #F0FDF4;
  --green-on-dark:#4ADE80;
  --red:          #EF4444;
  --red-soft:     #FEF2F2;
  --dark:         #0F172A;
  --dark-2:       #1E293B;
  --on-dark:      #F1F5F9;
  --on-dark-2:    #8B949E;

  /* Gradients. Both are full-bleed screen headers. */
  --grad-accent:  linear-gradient(160deg, #06B6D4 0%, #0891B2 70%);
  --grad-dark:    linear-gradient(160deg, #0F172A 0%, #1E293B 80%);

  /* Radii by ROLE, so step 2 does not have to remember which number goes
     where. -lg and -xl are kept as aliases: every existing component
     already uses them and means exactly these two things. */
  --radius-sm:     8px;
  --radius:        12px;
  --radius-row:    16px;    /* list rows */
  --radius-card:   20px;    /* stat & table cards */
  --radius-hero:   24px;    /* hero cards, bottom trays */
  --radius-header: 32px;    /* gradient header bottom corners */
  --radius-pill:   999px;
  --radius-lg:    var(--radius-row);
  --radius-xl:    var(--radius-hero);
  /* Elevation. The handoff specifies a single-layer card shadow; the old
     two-layer one read heavier than a white card floating on #F6F8FA
     should. Tinted navy rather than pure black, so a card on the canvas
     casts a shadow the same hue family as the canvas itself. */
  --shadow-sm:    0 1px 3px rgba(0,0,0,.07);
  --shadow:       0 4px 12px rgba(15,23,42,.2);      /* dark cards */
  --shadow-tray:  0 8px 24px rgba(15,23,42,.1);      /* floating bottom tray */
  --shadow-accent:0 8px 24px rgba(6,182,212,.25);    /* cyan scoreboard card */

  --font-body:    'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
  --font-display: 'Space Grotesk', var(--font-body);

  /* Type scale from the handoff. Declared here so step 2 stops hardcoding
     sizes per component; nothing is forced to adopt them at once. */
  --fs-hero:      52px;   /* live score pair */
  --fs-hero-sm:   48px;   /* share page score */
  --fs-stat:      28px;   /* header stat trio */
  --fs-wordmark:  26px;   /* 44px on the sign-in splash */
  --fs-title:     16px;   /* screen title in a header bar */
  --fs-section:   15px;   /* section titles */
  --fs-body:      14px;
  --fs-meta:      12px;
  --fs-micro:     10px;   /* uppercase labels, letter-spacing 1-2px */
  --fs-micro-sm:  9px;
  --ls-wordmark:  -1.5px;
  --ls-micro:     1px;

  --tap-color:    transparent;
}

/* ── Base ───────────────────────────────────────────────────── */
body {
  font-family: var(--font-body);
  background: var(--bg);
  color: var(--text-1);
  min-height: 100vh;
  min-height: 100dvh;
  max-width: 480px;
  margin: 0 auto;
  position: relative;
  -webkit-font-smoothing: antialiased;
  padding-bottom: env(safe-area-inset-bottom, 0px);
  /* Prevent overscroll bounce on iOS */
  overscroll-behavior-y: none;
}
button { font-family: var(--font-body); }
input, select, textarea { font-family: var(--font-body); }

/* ── Screens ─────────────────────────────────────────────────── */
.screen {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}
.content {
  padding: 20px;
  flex: 1;
  /* Ensure content doesn't get hidden behind fixed elements */
  padding-bottom: max(20px, env(safe-area-inset-bottom, 20px));
}

/* ── App Header (Home) ────────────────────────────────────────── */
.app-header {
  padding: 20px 20px 4px;
}
.app-logo {
  font-family: var(--font-display);
  font-size: 30px;
  font-weight: 800;
  letter-spacing: -1.5px;
  line-height: 1;
  display: inline-flex;
  align-items: baseline;
}
.logo-skip { color: var(--accent-ink); }
.logo-pass { color: var(--text-1); }

/* ── Screen Header ───────────────────────────────────────────── */
.screen-header {
  display: flex;
  align-items: center;
  padding: 0 20px;
  /* Reserve the iOS status-bar area in standalone (Add to Home Screen) mode.
     Height must include the inset so the 56px content row isn't squished by
     the top padding (box-sizing: border-box). */
  height: calc(56px + env(safe-area-inset-top, 0px));
  padding-top: env(safe-area-inset-top, 0px);
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 0;
  z-index: 10;
  gap: 8px;
}
.screen-title {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 700;
  flex: 1;
  text-align: center;
  letter-spacing: -0.3px;
}
.btn-back {
  font-size: 26px;
  line-height: 1;
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-1);
  width: 36px;
  height: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-sm);
  -webkit-tap-highlight-color: var(--tap-color);
  flex-shrink: 0;
}
.btn-back:active { background: var(--surface-2); }
.hdr-action {
  min-width: 36px;
  height: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.btn-hdr-add {
  font-size: 22px;
  font-weight: 400;
  color: var(--accent-ink);
  background: none;
  border: none;
  cursor: pointer;
  line-height: 1;
  -webkit-tap-highlight-color: var(--tap-color);
}
.btn-hdr-text {
  font-size: 14px;
  font-weight: 600;
  color: var(--accent-ink);
  background: none;
  border: none;
  cursor: pointer;
  -webkit-tap-highlight-color: var(--tap-color);
  white-space: nowrap;
}
.btn-hdr-danger {
  font-size: 14px;
  font-weight: 600;
  color: var(--red);
  background: none;
  border: none;
  cursor: pointer;
  -webkit-tap-highlight-color: var(--tap-color);
}

/* ── Buttons ─────────────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 14px 20px;
  border-radius: var(--radius);
  font-size: 15px;
  font-weight: 600;
  border: none;
  cursor: pointer;
  transition: transform .1s, background .1s, opacity .1s;
  -webkit-tap-highlight-color: var(--tap-color);
  touch-action: manipulation;
  text-decoration: none;
}
.btn:active { transform: scale(0.97); }
.btn-lg {
  padding: 16px 24px;
  font-size: 16px;
  border-radius: var(--radius-lg);
  width: 100%;
}
.btn-sm {
  padding: 10px 16px;
  font-size: 14px;
  border-radius: var(--radius-sm);
}
.btn-full { width: 100%; }

.btn-primary  { background: var(--accent); color: #fff; }
.btn-primary:active { background: #ea6b10; }

.btn-secondary {
  background: var(--surface);
  color: var(--text-1);
  border: 1.5px solid var(--border);
}
.btn-secondary:active { background: var(--surface-2); }

.btn-ghost {
  background: transparent;
  color: var(--text-2);
  border: 1.5px solid var(--border);
}
.btn-ghost:active { background: var(--surface-2); }

.btn-danger        { background: var(--red); color: #fff; }
.btn-danger:active { background: #dc2626; }

.btn-danger-ghost {
  background: transparent;
  color: var(--red);
  border: 1.5px solid var(--red);
}
.btn-danger-ghost:active { background: var(--red-soft); }

/* ── Home Screen ─────────────────────────────────────────────── */
.home-screen { padding-bottom: 40px; }

.active-game-banner {
  margin: 16px 20px 0;
  background: linear-gradient(135deg, var(--dark) 0%, var(--dark-2) 100%);
  border-radius: var(--radius-lg);
  cursor: pointer;
  -webkit-tap-highlight-color: var(--tap-color);
  overflow: hidden;
  box-shadow: var(--shadow);
}
.active-game-banner:active { opacity: 0.9; }
.active-game-inner {
  padding: 16px 18px;
  display: flex;
  align-items: center;
  gap: 14px;
}
.live-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--green);
  box-shadow: 0 0 0 3px rgba(34,197,94,.3);
  animation: livepulse 2s infinite;
  flex-shrink: 0;
}
@keyframes livepulse {
  0%, 100% { box-shadow: 0 0 0 3px rgba(34,197,94,.3); }
  50%       { box-shadow: 0 0 0 7px rgba(34,197,94,.08); }
}
.active-game-info { flex: 1; min-width: 0; }
.live-label {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1.5px;
  color: var(--green);
  display: block;
  margin-bottom: 3px;
}
.active-game-matchup {
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 700;
  color: var(--on-dark);
  display: block;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.active-game-period {
  font-size: 12px;
  color: var(--on-dark-2);
  display: block;
  margin-top: 2px;
}
.banner-chevron { color: var(--on-dark-2); font-size: 22px; font-weight: 300; }

.home-actions {
  padding: 20px 20px 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.btn-plus { font-size: 20px; font-weight: 300; line-height: 1; }

.home-section { padding: 28px 20px 0; }
.section-title {
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 700;
  color: var(--text-1);
  margin-bottom: 12px;
  letter-spacing: -0.2px;
}

/* ── List / Card ─────────────────────────────────────────────── */
.card-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.card-list-boxed {
  background: var(--surface);
  border-radius: var(--radius-lg);
  border: 1.5px solid var(--border);
  overflow: hidden;
}
.list-row {
  display: flex;
  align-items: center;
  padding: 14px 16px;
  border-bottom: 1px solid var(--border-2);
  cursor: pointer;
  -webkit-tap-highlight-color: var(--tap-color);
  transition: background .1s;
  gap: 12px;
}
.list-row:last-child { border-bottom: none; }
.list-row:active { background: var(--surface-2); }
.list-row-content { flex: 1; min-width: 0; }
.list-row-title {
  font-size: 15px;
  font-weight: 600;
  color: var(--text-1);
  display: block;
}
.list-row-sub {
  font-size: 12px;
  color: var(--text-3);
  display: block;
  margin-top: 1px;
}
.list-row-right {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}
.chevron { font-size: 20px; color: var(--border); font-weight: 300; }

.game-card {
  background: var(--surface);
  border-radius: var(--radius);
  padding: 14px 16px;
  display: flex;
  align-items: center;
  cursor: pointer;
  border: 1.5px solid var(--border);
  transition: all .1s;
  -webkit-tap-highlight-color: var(--tap-color);
  gap: 12px;
}
.game-card:active { background: var(--surface-2); transform: scale(.99); }
.game-card-info { flex: 1; min-width: 0; }
.game-card-opponent {
  font-size: 15px;
  font-weight: 600;
  display: block;
}
.game-card-meta {
  font-size: 12px;
  color: var(--text-3);
  display: block;
  margin-top: 2px;
}
.badge-pts {
  font-size: 12px;
  font-weight: 700;
  color: var(--accent-ink);
  background: var(--accent-soft);
  padding: 3px 9px;
  border-radius: 20px;
}
.badge-fmt {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .4px;
  color: var(--text-2);
  background: var(--surface-2);
  padding: 3px 7px;
  border-radius: var(--radius-sm);
}

/* ── Empty States ────────────────────────────────────────────── */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 60px 24px;
  gap: 6px;
}
.empty-icon { font-size: 52px; margin-bottom: 8px; }
.empty-title {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 700;
}
.empty-sub {
  font-size: 14px;
  color: var(--text-3);
  margin-bottom: 12px;
  line-height: 1.5;
}
.empty-hint {
  padding: 20px;
  text-align: center;
  font-size: 14px;
  color: var(--text-3);
}
.empty-hint a {
  color: var(--accent-ink);
  text-decoration: none;
  font-weight: 600;
}

/* ── Forms ───────────────────────────────────────────────────── */
.form-group { margin-bottom: 20px; }
.form-label {
  display: block;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .9px;
  color: var(--text-3);
  text-transform: uppercase;
  margin-bottom: 8px;
}
.form-input {
  width: 100%;
  padding: 13px 16px;
  border: 1.5px solid var(--border);
  border-radius: var(--radius);
  font-size: 16px; /* ≥16px stops iOS Safari from auto-zooming on focus */
  color: var(--text-1);
  background: var(--surface);
  outline: none;
  transition: border-color .15s;
  -webkit-appearance: none;
  appearance: none;
}
.form-input:focus { border-color: var(--accent-ink); }
.form-input::placeholder { color: var(--text-3); }
.form-select {
  background-image: url("data:image/svg+xml,%3Csvg width='12' height='8' viewBox='0 0 12 8' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='%2394A3B8' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 16px center;
  padding-right: 40px;
  cursor: pointer;
}
.form-actions { margin-top: 28px; }

/* Segment control */
.segment-control {
  display: flex;
  background: var(--surface-2);
  border-radius: var(--radius-sm);
  padding: 3px;
  gap: 2px;
}
.seg-btn {
  flex: 1;
  padding: 10px;
  border: none;
  background: transparent;
  border-radius: 6px;
  font-size: 14px;
  font-weight: 600;
  color: var(--text-2);
  cursor: pointer;
  transition: all .2s;
  -webkit-tap-highlight-color: var(--tap-color);
}
.seg-btn.active {
  background: var(--surface);
  color: var(--text-1);
  box-shadow: var(--shadow-sm);
}

/* Section divider with label */
.section-row {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 24px 0 14px;
}
.section-row .section-title { margin-bottom: 0; flex-shrink: 0; }
.section-row-line { flex: 1; height: 1px; background: var(--border); }

/* ── Player Roster Rows ──────────────────────────────────────── */
.player-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  background: var(--surface);
  border-radius: var(--radius);
  margin-bottom: 8px;
  border: 1.5px solid var(--border);
}
.jersey-pill {
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 700;
  color: var(--accent-ink);
  background: var(--accent-soft);
  width: 42px;
  height: 32px;
  border-radius: var(--radius-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.player-row-name {
  flex: 1;
  font-size: 15px;
  font-weight: 500;
}
.btn-remove {
  background: none;
  border: none;
  color: var(--text-3);
  font-size: 16px;
  cursor: pointer;
  padding: 6px 8px;
  border-radius: var(--radius-sm);
  -webkit-tap-highlight-color: var(--tap-color);
  line-height: 1;
}
.btn-remove:active { background: var(--red-soft); color: var(--red); }

/* Editable player fields in roster edit */
.jersey-edit {
  width: 52px;
  height: 34px;
  flex-shrink: 0;
  text-align: center;
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 700;
  color: var(--accent-ink);
  background: var(--accent-soft);
  border: 1.5px solid transparent;
  border-radius: var(--radius-sm);
  -webkit-appearance: none;
  appearance: none;
  outline: none;
}
.jersey-edit:focus { border-color: var(--accent-ink); }
.player-name-edit {
  flex: 1;
  min-width: 0;
  height: 34px;
  font-size: 15px;
  font-weight: 500;
  color: var(--text-1);
  background: transparent;
  border: 1.5px solid transparent;
  border-radius: var(--radius-sm);
  padding: 0 8px;
  outline: none;
}
.player-name-edit:focus { border-color: var(--border); background: var(--surface-2); }

/* Team color picker */
.color-picker {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
.color-swatch {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: 2px solid transparent;
  box-shadow: 0 0 0 1.5px var(--border);
  cursor: pointer;
  padding: 0;
  -webkit-tap-highlight-color: var(--tap-color);
  transition: transform .12s;
}
.color-swatch.active {
  border-color: var(--surface);
  box-shadow: 0 0 0 2.5px var(--text-1);
  transform: scale(1.05);
}
.color-swatch:active { transform: scale(.92); }

/* Roster list color dot */
.roster-color-dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  flex-shrink: 0;
  margin-right: 12px;
}

.add-player-row {
  display: flex;
  gap: 10px;
  align-items: flex-start;
}
.jersey-input-wrap { flex-shrink: 0; width: 72px; }

/* ── Game Screen ─────────────────────────────────────────────── */
.game-screen {
  background: var(--bg);
  /* Lock to viewport height so footer stays pinned at bottom */
  height: 100vh;
  height: 100dvh;
  min-height: 0; /* override .screen min-height so height wins */
  overflow: hidden; /* content scrolls inside its own container */
}

.game-header {
  background: var(--dark);
  padding: 16px 20px 14px;
  padding-top: max(16px, env(safe-area-inset-top, 0px));
  flex-shrink: 0;
}
.game-header-matchup {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin-bottom: 3px;
}
.gh-team {
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 700;
  color: var(--on-dark);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 140px;
}
.gh-vs {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 1px;
  color: var(--on-dark-2);
  flex-shrink: 0;
}
.gh-opp { color: var(--on-dark-2); }
.game-header-date {
  text-align: center;
  font-size: 11px;
  color: var(--on-dark-2);
}

/* Compact header: matchup + score on one row, periods + mode icons below */
.game-header-compact { padding: 10px 14px 10px; padding-top: max(10px, env(safe-area-inset-top, 0px)); }
.game-header-compact .gh-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 8px;
}
.game-header-compact .game-header-matchup {
  justify-content: flex-start;
  margin-bottom: 0;
  min-width: 0;
  gap: 7px;
  flex: 1;
}
.gh-back {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 36px;
  height: 36px;
  margin-left: -8px;
  background: none;
  border: none;
  color: var(--on-dark);
  font-size: 28px;
  line-height: 1;
  padding: 0 6px 3px;
  cursor: pointer;
  -webkit-tap-highlight-color: var(--tap-color);
  touch-action: manipulation;
}
.gh-back:active { opacity: .6; }
.game-header-compact .gh-team { font-size: 15px; max-width: 110px; }
.game-header-compact .game-scoreboard { margin-top: 0; gap: 8px; flex-shrink: 0; }
.game-header-compact .sb-num { font-size: 20px; min-width: 26px; }
.game-header-compact .game-header-date { flex-shrink: 0; }
.gh-controls {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
.gh-periods { display: flex; gap: 4px; }
.gh-period-pill {
  padding: 5px 12px;
  border: none;
  border-radius: 7px;
  background: var(--dark-2);
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 700;
  color: var(--on-dark-2);
  cursor: pointer;
  transition: all .15s;
  -webkit-tap-highlight-color: var(--tap-color);
  touch-action: manipulation;
}
.gh-period-pill.active { background: var(--accent); color: #fff; }
.gh-modes { display: flex; gap: 2px; }
.gh-mode-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 28px;
  border: none;
  border-radius: 7px;
  background: transparent;
  color: var(--on-dark-2);
  cursor: pointer;
  transition: all .15s;
  -webkit-tap-highlight-color: var(--tap-color);
  touch-action: manipulation;
}
.gh-mode-btn.active { background: var(--dark-2); color: var(--accent-light); }  /* on navy: 9.88:1 — the one place raw accent may be text */

/* Period selector */
.period-bar {
  background: var(--surface);
  padding: 10px 16px;
  display: flex;
  align-items: center;
  gap: 12px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.period-bar-label {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1px;
  color: var(--text-3);
  text-transform: uppercase;
  flex-shrink: 0;
}
.period-pills {
  display: flex;
  gap: 6px;
  flex: 1;
}
.period-pill {
  flex: 1;
  padding: 8px 4px;
  border: 1.5px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 700;
  color: var(--text-2);
  cursor: pointer;
  transition: all .15s;
  -webkit-tap-highlight-color: var(--tap-color);
  touch-action: manipulation;
}
.period-pill.active {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent-ink);
}

/* Classic view wrapper — fills remaining game-screen space */
.classic-view-wrap {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0; /* allow flex item to shrink */
  overflow: hidden;
}

/* Stats table */
.stats-col-header {
  display: flex;
  align-items: center;
  padding: 8px 16px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.sc-name {
  flex: 1;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1px;
  color: var(--text-3);
}
.sc-stat {
  width: 42px;
  text-align: center;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1px;
  color: var(--text-3);
  flex-shrink: 0;
}

.player-stat-list {
  flex: 1;
  background: var(--surface);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-y: contain;
}

.player-stat-row {
  display: flex;
  align-items: center;
  padding: 14px 16px;
  border-bottom: 1px solid var(--border-2);
  cursor: pointer;
  -webkit-tap-highlight-color: var(--tap-color);
  transition: background .1s;
}
.player-stat-row:last-child { border-bottom: none; }
.player-stat-row:active { background: var(--accent-soft); }

.player-identity {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}
.j-badge {
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 700;
  color: var(--accent-ink);
  background: var(--accent-soft);
  padding: 4px 6px;
  border-radius: 6px;
  min-width: 34px;
  text-align: center;
  flex-shrink: 0;
}
.player-stat-name {
  font-size: 15px;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sv {
  width: 42px;
  text-align: center;
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 600;
  color: var(--border);
  flex-shrink: 0;
}
.sv.on { color: var(--text-1); }

/* Game footer */
.game-footer {
  display: flex;
  gap: 10px;
  padding: 12px 16px;
  background: var(--surface);
  border-top: 1px solid var(--border);
  /* Flex child of .game-screen — stays pinned at bottom */
  flex-shrink: 0;
  padding-bottom: max(12px, env(safe-area-inset-bottom));
  z-index: 5;
}
.game-footer .btn { flex: 1; }

/* ── Bottom Sheet ────────────────────────────────────────────── */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(15,23,42,0);
  z-index: 100;
  transition: background .3s;
}
.modal-overlay.active { background: rgba(15,23,42,.55); }
.modal-overlay.hidden { display: none; }

.bottom-sheet {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  max-width: 480px;
  margin: 0 auto;
  background: var(--surface);
  border-radius: var(--radius-xl) var(--radius-xl) 0 0;
  z-index: 101;
  transform: translateY(100%);
  transition: transform .3s cubic-bezier(.32,.72,0,1);
  padding-bottom: max(20px, env(safe-area-inset-bottom));
  max-height: 88vh;
  max-height: 88dvh;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}
.bottom-sheet.active  { transform: translateY(0); }
.bottom-sheet.hidden  { display: none; }

.sheet-grip {
  width: 36px;
  height: 4px;
  background: var(--border);
  border-radius: 2px;
  margin: 12px auto 6px;
}
.sheet-player-header {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 20px 14px;
  border-bottom: 1px solid var(--border-2);
}
.sheet-j {
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 700;
  color: var(--accent-ink);
  background: var(--accent-soft);
  width: 46px;
  height: 40px;
  border-radius: var(--radius-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.sheet-pinfo { display: flex; flex-direction: column; gap: 2px; }
.sheet-pname {
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 700;
}
.sheet-period-lbl {
  font-size: 12px;
  color: var(--text-3);
}

.sheet-section {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1px;
  color: var(--text-3);
  text-transform: uppercase;
  padding: 16px 20px 8px;
}

.sheet-stat-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  padding: 0 20px 16px;
}
.sheet-stat-grid-2 {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
  padding: 0 20px 20px;
}

.stat-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  padding: 14px 8px;
  border-radius: var(--radius);
  border: none;
  cursor: pointer;
  -webkit-tap-highlight-color: var(--tap-color);
  transition: all .12s;
  touch-action: manipulation;
}
.stat-btn:active { transform: scale(.95); }
.stat-btn-pts { background: var(--accent-soft); }
.stat-btn-3pt { background: var(--accent-2-soft); }
.stat-btn-other { background: var(--surface-2); }

.stat-btn-num {
  font-family: var(--font-display);
  font-size: 28px;
  font-weight: 800;
  line-height: 1;
  color: var(--accent-ink);
}
.stat-btn-3pt .stat-btn-num { color: var(--accent-2); }
.stat-btn-icon { font-size: 22px; line-height: 1; }
.stat-btn-lbl {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .4px;
  color: var(--text-2);
  text-align: center;
  line-height: 1.3;
  text-transform: uppercase;
}

/* Assist picker */
.assist-list {
  padding: 4px 20px 4px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.assist-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 13px 16px;
  background: var(--surface-2);
  border: 1.5px solid var(--border);
  border-radius: var(--radius);
  cursor: pointer;
  -webkit-tap-highlight-color: var(--tap-color);
  transition: all .1s;
}
.assist-row:active { background: var(--accent-soft); border-color: #fdba74; }
.assist-j {
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 700;
  color: var(--accent-ink);
  background: var(--accent-soft);
  padding: 4px 8px;
  border-radius: 6px;
  min-width: 36px;
  text-align: center;
}
.assist-name { font-size: 15px; font-weight: 500; }
.assist-row-none {
  justify-content: center;
  background: var(--surface-2);
  border-style: dashed;
}
.assist-none-label {
  font-size: 14px;
  font-weight: 600;
  color: var(--text-2);
}
.assist-sheet-info {
  padding: 10px 20px 14px;
  border-bottom: 1px solid var(--border-2);
}
.assist-shot-label {
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 700;
  color: var(--text-1);
}

/* ── Confirm Sheet ────────────────────────────────────────────── */
.confirm-body {
  padding: 16px 20px 8px;
}
.confirm-title {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 700;
  margin-bottom: 6px;
}
.confirm-msg {
  font-size: 14px;
  color: var(--text-2);
  line-height: 1.5;
}
.confirm-actions {
  display: flex;
  gap: 10px;
  padding: 16px 20px 0;
}
.confirm-actions .btn { flex: 1; }

/* ── Game Summary ─────────────────────────────────────────────── */
.summary-dark-header {
  background: var(--dark);
  padding: 20px 20px 16px;
  text-align: center;
}
.summary-matchup {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  margin-bottom: 4px;
}
.sum-team {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 700;
  color: var(--on-dark);
  max-width: 140px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sum-vs {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 1px;
  color: var(--on-dark-2);
}
.sum-opp { color: var(--on-dark-2); }
.summary-meta {
  font-size: 12px;
  color: var(--on-dark-2);
}

.stats-card {
  background: var(--surface);
  border-radius: var(--radius-lg);
  border: 1.5px solid var(--border);
  overflow: hidden;
  margin-bottom: 20px;
}
.stats-card-head {
  display: flex;
  align-items: center;
  padding: 10px 16px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
}
.stats-card-row {
  display: flex;
  align-items: center;
  padding: 13px 16px;
  border-bottom: 1px solid var(--border-2);
}
.stats-card-row:last-child { border-bottom: none; }
.stats-card-row.totals-row {
  background: var(--surface-2);
  border-top: 1.5px solid var(--border);
}
.totals-lbl {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1px;
  color: var(--text-2);
}
.sv-total { color: var(--text-1) !important; font-weight: 700 !important; }
.sc-name-wide {
  flex: 1;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1px;
  color: var(--text-3);
}
.sc-stat-wide {
  width: 42px;
  text-align: center;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1px;
  color: var(--text-3);
  flex-shrink: 0;
}

/* Period breakdown */
.period-section { margin-bottom: 12px; }
.period-section-title {
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .3px;
  color: var(--text-2);
  padding: 8px 14px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
}
.period-stat-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border-2);
}
.period-stat-row:last-child { border-bottom: none; }

/* Play-by-play rows */
.pbp-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 14px;
  border-bottom: 1px solid var(--border-2);
}
.pbp-row:last-child { border-bottom: none; }
.pbp-seq {
  font-family: var(--font-display);
  font-size: 11px;
  font-weight: 700;
  color: var(--text-3);
  min-width: 20px;
  text-align: right;
  flex-shrink: 0;
}
.pbp-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
}
.pbp-main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.pbp-actor {
  font-size: 14px;
  font-weight: 600;
  color: var(--text-1);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pbp-action {
  font-size: 12px;
  color: var(--text-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pbp-score {
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 700;
  color: var(--text-2);
  flex-shrink: 0;
}

/* ── Editable play-by-play ─────────────────────────────────────── */
.pbp-hint {
  font-size: 12px;
  color: var(--text-3);
  margin: -2px 2px 10px;
}
.pbp-row-edit {
  cursor: pointer;
  -webkit-tap-highlight-color: var(--tap-color);
  transition: background .12s;
}
.pbp-row-edit:active { background: var(--surface-2); }
.pbp-edit-ic {
  flex-shrink: 0;
  font-size: 13px;
  color: var(--text-3);
  opacity: .5;
  margin-left: 2px;
}

/* Edit-play bottom sheet */
.edit-play { padding: 4px 20px 8px; }
.edit-label {
  display: block;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .3px;
  text-transform: uppercase;
  color: var(--text-3);
  margin: 14px 0 8px;
}
.edit-play .edit-label:first-child { margin-top: 4px; }
.edit-stat-chips {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
}
.edit-stat-chip {
  padding: 10px 6px;
  border: 1.5px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  font-size: 13px;
  font-weight: 600;
  color: var(--text-3);
  cursor: pointer;
  transition: all .15s;
  -webkit-tap-highlight-color: var(--tap-color);
  touch-action: manipulation;
}
.edit-stat-chip.active {
  background: var(--accent-soft);
  border-color: var(--accent-ink);
  color: var(--accent-ink);
}
.edit-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 16px 20px max(16px, env(safe-area-inset-bottom, 16px));
}
.edit-actions-r { display: flex; gap: 10px; }

/* In-game log sheet */
.sheet-log-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 4px 20px 6px;
}
.sheet-log-title {
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 700;
  color: var(--text-1);
}
.game-log-hint {
  font-size: 12px;
  color: var(--text-3);
  padding: 0 20px 8px;
}
.game-log-list {
  max-height: 52vh;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 0 8px max(12px, env(safe-area-inset-bottom, 12px));
}
.game-log-list .pbp-row { padding: 10px 12px; }
.game-log-empty {
  padding: 28px 20px 40px;
  text-align: center;
  font-size: 14px;
  color: var(--text-3);
}
.glog-per {
  font-family: var(--font-display);
  font-size: 10px;
  font-weight: 700;
  color: var(--text-3);
  min-width: 26px;
  text-align: center;
  padding: 2px 0;
  border-radius: 5px;
  background: var(--surface-2);
  flex-shrink: 0;
}
.period-player-name {
  font-size: 14px;
  font-weight: 500;
}
.stat-chips { display: flex; gap: 5px; flex-wrap: wrap; justify-content: flex-end; }
.chip {
  font-size: 11px;
  font-weight: 700;
  padding: 3px 7px;
  border-radius: 6px;
}
.chip-pts { background: var(--accent-soft); color: #ea580c; }
.chip-reb { background: var(--accent-2-soft); color: #2563eb; }
.chip-ast { background: #f0fdf4; color: #16a34a; }
.chip-stl { background: #fdf4ff; color: #9333ea; }
.chip-to  { background: #fef2f2; color: #dc2626; }

/* ── Toast ───────────────────────────────────────────────────── */
.toast {
  position: fixed;
  /* Account for safe-area + footer height on mobile */
  bottom: calc(80px + env(safe-area-inset-bottom, 0px));
  left: 50%;
  transform: translateX(-50%) translateY(12px);
  background: var(--dark);
  color: var(--on-dark);
  font-size: 14px;
  font-weight: 500;
  padding: 10px 20px;
  border-radius: 20px;
  z-index: 200;
  opacity: 0;
  pointer-events: none;
  transition: opacity .25s, transform .25s;
  white-space: nowrap;
  max-width: calc(100vw - 40px);
  text-align: center;
}
.toast.show {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* ── Update-available banner (new deploy detected) ──────────────── */
.update-banner {
  position: fixed;
  left: 0;
  right: 0;
  top: 0;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  padding-top: calc(10px + env(safe-area-inset-top, 0px));
  background: var(--dark);
  color: var(--on-dark);
  z-index: 500;
  transform: translateY(-100%);
  transition: transform .3s ease;
  box-shadow: 0 2px 12px rgba(0, 0, 0, .25);
}
.update-banner.show { transform: translateY(0); }
.update-banner-txt {
  flex: 1;
  font-size: 14px;
  font-weight: 600;
}
.update-banner-btn {
  flex-shrink: 0;
  background: var(--accent);
  color: #fff;
  font-size: 14px;
  font-weight: 700;
  border: none;
  border-radius: 8px;
  padding: 8px 16px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.update-banner-btn:active { filter: brightness(.92); }
.update-banner-x {
  flex-shrink: 0;
  background: transparent;
  border: none;
  color: var(--on-dark);
  opacity: .6;
  font-size: 16px;
  line-height: 1;
  padding: 6px;
  cursor: pointer;
}
@media print { .update-banner { display: none !important; } }

/* ── End Game Score Entry ─────────────────────────────────────── */
.end-game-scores {
  padding: 8px 20px 16px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.end-game-score-row {
  display: flex;
  align-items: center;
  gap: 12px;
}
.end-score-label {
  font-size: 14px;
  font-weight: 600;
  color: var(--text-1);
  min-width: 100px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.end-score-input {
  width: 100px;
  text-align: center;
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: 700;
  padding: 10px 12px;
}

/* ── Final Score Display (Summary) ───────────────────────────── */
.final-score-display {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  margin: 8px 0 2px;
}
.fs-num {
  font-family: var(--font-display);
  font-size: 36px;
  font-weight: 800;
  line-height: 1;
}
.fs-team { color: var(--on-dark); }
.fs-opp  { color: var(--on-dark-2); }
.fs-dash {
  font-size: 20px;
  color: var(--on-dark-2);
  font-weight: 300;
}
.fs-result {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 2px;
  color: var(--green);
  text-align: center;
  margin-bottom: 4px;
}

/* Score badge in game cards */
.badge-score {
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 700;
  color: var(--accent-ink);
  background: var(--accent-soft);
  padding: 3px 10px;
  border-radius: 20px;
  white-space: nowrap;
}

/* ── View Mode Bar ───────────────────────────────────────────── */
.view-mode-bar {
  display: flex;
  gap: 2px;
  padding: 6px 16px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.vm-btn {
  flex: 1;
  padding: 7px 4px;
  border: none;
  background: transparent;
  border-radius: 6px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-3);
  cursor: pointer;
  transition: all .15s;
  -webkit-tap-highlight-color: var(--tap-color);
  touch-action: manipulation;
}
.vm-btn.active {
  background: var(--accent);
  color: #fff;
}
.vm-btn:not(.active):active { background: var(--surface-2); }

/* ── Grid View ───────────────────────────────────────────────── */
.grid-view {
  flex: 1;
  background: var(--surface);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-y: contain;
  min-height: 0; /* allow flex item to shrink below content size */
}
.grid-player-row {
  padding: 10px 14px;
  border-bottom: 1px solid var(--border-2);
}
.grid-player-row:last-child { border-bottom: none; }
.grid-player-id {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
}
.grid-pname {
  font-size: 14px;
  font-weight: 500;
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.grid-pts-total {
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 700;
  color: var(--accent-ink);
  flex-shrink: 0;
}
.grid-btns {
  display: flex;
  flex-wrap: wrap; /* advanced stat sets can exceed one row */
  gap: 6px;
}
.grid-btn {
  flex: 1;
  min-width: 44px;
  padding: 10px 4px;
  border: none;
  border-radius: var(--radius-sm);
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
  -webkit-tap-highlight-color: var(--tap-color);
  touch-action: manipulation;
  transition: transform .1s;
}
.grid-btn:active { transform: scale(.93); }
.grid-btn-ft     { background: var(--accent-soft); color: var(--accent-ink); }
.grid-btn-2p     { background: var(--accent-soft); color: var(--accent-ink); }
.grid-btn-3p     { background: var(--accent-2-soft); color: var(--accent-2); }
.grid-btn-reb    { background: #f0fdf4; color: #16a34a; }
.grid-btn-oreb   { background: #f0fdf4; color: #16a34a; }
.grid-btn-dreb   { background: #f0fdfa; color: #0d9488; }
.grid-btn-stl    { background: #fdf4ff; color: #9333ea; }
.grid-btn-ftmiss { background: #f8fafc; color: #64748b; }
.grid-btn-to     { background: #fef2f2; color: #dc2626; }
.grid-btn-blk    { background: #f0f9ff; color: #0284c7; }

/* ── Quick Tap View ──────────────────────────────────────────── */
.qt-view {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0; /* allow flex item to shrink below content size */
  overflow: hidden; /* child .qt-player-grid scrolls */
}
.qt-stat-picker {
  display: flex;
  flex-wrap: wrap; /* advanced stat sets can exceed one row */
  gap: 6px;
  padding: 10px 14px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 0;
  z-index: 5;
}
.qt-stat-btn {
  flex: 1;
  min-width: 56px;
  padding: 10px 4px;
  border: 1.5px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 700;
  color: var(--text-2);
  cursor: pointer;
  transition: all .15s;
  -webkit-tap-highlight-color: var(--tap-color);
  touch-action: manipulation;
}
.qt-stat-btn.active {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent-ink);
}
.qt-hint {
  padding: 8px 14px;
  font-size: 12px;
  color: var(--text-3);
  text-align: center;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
}
.qt-hint strong { color: var(--text-1); }
.qt-player-grid {
  flex: 1;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
  padding: 12px 14px;
  background: var(--bg);
  align-content: start;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-y: contain;
  min-height: 0;
}
.qt-player-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 14px 8px;
  background: var(--surface);
  border: 1.5px solid var(--border);
  border-radius: var(--radius);
  cursor: pointer;
  -webkit-tap-highlight-color: var(--tap-color);
  touch-action: manipulation;
  transition: all .12s;
}
.qt-player-btn:active { background: var(--accent-soft); border-color: var(--accent-ink); transform: scale(.96); }
.qt-player-btn.qt-flash { background: var(--accent-soft); border-color: var(--accent-ink); }
.qt-pname {
  font-size: 14px;
  font-weight: 600;
  color: var(--text-1);
  text-align: center;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 100%;
}
.qt-mini-stats {
  font-family: var(--font-display);
  font-size: 11px;
  font-weight: 600;
  color: var(--text-3);
  letter-spacing: .3px;
}

/* ── Both-teams scorekeeping ─────────────────────────────────── */

/* New Game toggle row */
.toggle-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 13px 16px;
  border: 1.5px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  cursor: pointer;
  -webkit-tap-highlight-color: var(--tap-color);
}
.toggle-text {
  flex: 1;
  font-size: 15px;
  font-weight: 600;
  color: var(--text-1);
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.toggle-sub { font-size: 12px; font-weight: 400; color: var(--text-3); }
.toggle-check { display: none; }
.toggle-switch {
  flex-shrink: 0;
  width: 46px;
  height: 28px;
  border-radius: 14px;
  background: var(--border);
  position: relative;
  transition: background .2s;
}
.toggle-switch::after {
  content: '';
  position: absolute;
  top: 3px;
  left: 3px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  transition: transform .2s;
}
.toggle-check:checked + .toggle-switch { background: var(--accent); }
.toggle-check:checked + .toggle-switch::after { transform: translateX(18px); }

.form-hint {
  margin-top: 8px;
  font-size: 12px;
  color: var(--text-3);
}

/* Orb team switcher (2-roster games) */
.orb-team-bar {
  flex-shrink: 0;
  display: flex;
  gap: 4px;
  padding: 8px 14px 0;
  background: var(--surface);
}
.ot-btn {
  flex: 1;
  padding: 8px 6px;
  border: 1.5px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 700;
  color: var(--text-2);
  cursor: pointer;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  transition: all .15s;
  -webkit-tap-highlight-color: var(--tap-color);
  touch-action: manipulation;
}
.ot-btn.active {
  background: var(--dark);
  color: var(--on-dark);
  border-color: var(--dark);
}

/* Stat config chips (New Game) */
.stat-config-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
}
.sc-chip {
  padding: 11px 8px;
  border: 1.5px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  font-size: 13px;
  font-weight: 600;
  color: var(--text-3);
  cursor: pointer;
  transition: all .15s;
  -webkit-tap-highlight-color: var(--tap-color);
  touch-action: manipulation;
}
.sc-chip.active {
  background: var(--accent-soft);
  border-color: var(--accent-ink);
  color: var(--accent-ink);
}

/* Live scoreboard in the game header */
.game-scoreboard {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 12px;
  margin-top: 2px;
}
.sb-num {
  font-family: var(--font-display);
  font-size: 24px;
  font-weight: 800;
  color: var(--accent-ink);
  line-height: 1;
  min-width: 34px;
  text-align: center;
}
.sb-num-opp { color: var(--on-dark); }
.sb-dash { color: var(--on-dark-2); font-size: 15px; }

/* Opponent scored strip (above the footer, all views) */
.opp-score-bar {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 16px;
  background: var(--surface);
  border-top: 1px solid var(--border);
}
.opp-bar-label {
  flex: 1;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.opp-bar-btns { display: flex; gap: 6px; }
.opp-btn {
  padding: 8px 16px;
  border: 1.5px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 700;
  color: var(--text-2);
  cursor: pointer;
  -webkit-tap-highlight-color: var(--tap-color);
  touch-action: manipulation;
  will-change: transform;
}
.opp-btn:active { background: var(--accent-soft); border-color: var(--accent-ink); }
.opp-btn-3:active { background: var(--accent-2-soft); border-color: var(--accent-2); }

/* ── Orb View — slide from center hub to a player ────────────── */
.orb-view {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
  background: var(--bg);
}
.orb-hint {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  flex-wrap: wrap;
  padding: 8px 14px;
  font-size: 12px;
  color: var(--text-3);
  text-align: center;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
}
.orb-cancel-btn {
  padding: 4px 12px;
  border: 1.5px solid var(--border);
  border-radius: 20px;
  background: var(--surface);
  font-size: 12px;
  font-weight: 600;
  color: var(--text-2);
  cursor: pointer;
  -webkit-tap-highlight-color: var(--tap-color);
  touch-action: manipulation;
}
.orb-arena {
  flex: 1;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 8px;
}
.orb-stage {
  position: relative;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
}

/* Court backdrop (key / free-throw lane) behind the split orb */
.orb-court {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  pointer-events: none;
  overflow: visible;
}
.orb-court .oc-lane {
  fill: rgba(148, 163, 184, .07);
  stroke: none; /* sides drawn separately so there's no bottom edge */
}
.orb-court line,
.orb-court path { stroke: #cbd5e1; stroke-width: .8; fill: none; }
.orb-court .oc-arc-bot { stroke-dasharray: 3 2.4; }
.orb-court .oc-hash line { stroke-width: 1; }

/* Center hub — the drag origin */
.orb-center {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: var(--dark);
  color: var(--on-dark);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  z-index: 3;
  border: 3px solid var(--accent);
  box-shadow: var(--shadow);
  cursor: grab;
}
.orb-center-big {
  font-family: var(--font-display);
  font-size: 30px;
  font-weight: 800;
  line-height: 1;
}
.orb-center-lbl {
  font-family: var(--font-display);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 1px;
  color: var(--on-dark-2);
}

/* Multi-stat globe: all 5 stats live inside the hub as swipe origins */
.orb-center-multi { border-color: var(--dark-2); }
.orb-hub-stat {
  position: absolute;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 800;
  color: #fff;
  transition: transform .12s, box-shadow .12s;
  pointer-events: none; /* hit-testing is angle-based on the stage */
}
.orb-hub-stat.s-ft,
.orb-hub-stat.s-2p   { background: var(--accent); }
.orb-hub-stat.s-3p   { background: var(--accent-2); }
.orb-hub-stat.s-reb,
.orb-hub-stat.s-oreb { background: var(--green); }
.orb-hub-stat.s-dreb { background: #0D9488; }
.orb-hub-stat.s-stl  { background: #9333ea; }
.orb-hub-stat.s-ftx  { background: #94A3B8; }
.orb-hub-stat.s-to   { background: var(--red); }
.orb-hub-stat.s-blk  { background: #0EA5E9; }
.orb-hub-stat.active {
  transform: scale(1.18);
  box-shadow: 0 0 0 4px rgba(255, 255, 255, .3);
  z-index: 1;
}
/* During a gesture the pressed stat grows to fill the globe; the rest fade.
   Size transitions only while gesturing, so post-record rebuilds don't animate. */
.orb-stage.gesturing .orb-hub-stat {
  transition: transform .12s, box-shadow .12s,
              left .18s ease, top .18s ease, width .18s ease, height .18s ease,
              font-size .18s ease, opacity .15s;
}
.orb-hub-stat.dimmed { opacity: 0; }
.orb-hub-stat.expanded {
  transform: none;
  box-shadow: none;
  font-size: 32px;
  z-index: 2;
}

/* Per-stat hub accent color */
.orb-stage.s-3p     .orb-center { border-color: var(--accent-2); }
.orb-stage.s-reb    .orb-center,
.orb-stage.s-oreb   .orb-center,
.orb-stage.s-assist .orb-center { border-color: var(--green); }
.orb-stage.s-dreb   .orb-center { border-color: #0D9488; }
.orb-stage.s-stl    .orb-center { border-color: #9333ea; }
.orb-stage.s-ftx    .orb-center { border-color: #94A3B8; }
.orb-stage.s-to     .orb-center { border-color: var(--red); }
.orb-stage.s-blk    .orb-center { border-color: #0EA5E9; }

/* Player cards — solid team-color number badge, clean white body */
.orb-node {
  position: absolute;
  border-radius: 12px;
  background: var(--node-bg, var(--surface));
  border: 1px solid var(--node-border, var(--border));
  box-shadow: 0 1px 3px rgba(15, 23, 42, .07);
  display: flex;
  flex-direction: row;
  align-items: stretch;
  overflow: hidden;
  z-index: 2;
  transition: transform .12s, box-shadow .12s, border-color .12s;
  will-change: transform;
}
.orb-card-num {
  flex: 0 0 auto;
  width: var(--numw, 34px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 3px;
  font-family: var(--font-display);
  font-size: var(--nnum, 20px);
  font-weight: 800;
  letter-spacing: -.5px;
  white-space: nowrap;
  background: var(--num-bg, var(--surface-2));
  color: var(--num-fg, var(--text-1));
}
.orb-card-body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: 3px 8px;
}
.orb-card-name {
  font-size: var(--nname, 13px);
  font-weight: 600;
  color: var(--text-1);
  max-width: 100%;
  text-align: center;
  line-height: 1.1;
  letter-spacing: -.2px;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
.orb-card-stats {
  font-family: var(--font-display);
  font-size: var(--nstat, 11px);
  font-weight: 600;
  color: var(--text-3);
  line-height: 1;
  letter-spacing: .2px;
}
/* Narrow cards (e.g. 5-across on phones): drop stats, give the name the room */
.orb-card-tight .orb-card-stats { display: none; }
.orb-card-tight .orb-card-body { padding: 2px 4px; }

/* "No Assist" spoke */
.orb-node.orb-none {
  border-style: dashed;
  background: var(--surface-2);
}
.orb-node.orb-none .orb-node-j { color: var(--text-3); }

/* Hot: spoke currently under the finger */
.orb-node.hot { transform: scale(1.18); z-index: 4; }
.orb-stage.s-ft .orb-node.hot,
.orb-stage.s-2p .orb-node.hot {
  border-color: var(--accent-ink);
  box-shadow: 0 0 0 6px rgba(249, 115, 22, .25);
}
.orb-stage.s-3p .orb-node.hot {
  border-color: var(--accent-2);
  box-shadow: 0 0 0 6px rgba(59, 130, 246, .25);
}
.orb-stage.s-reb .orb-node.hot,
.orb-stage.s-assist .orb-node.hot {
  border-color: var(--green);
  box-shadow: 0 0 0 6px rgba(34, 197, 94, .25);
}
.orb-stage.s-stl .orb-node.hot {
  border-color: #9333ea;
  box-shadow: 0 0 0 6px rgba(147, 51, 234, .25);
}
.orb-stage.s-oreb .orb-node.hot {
  border-color: var(--green);
  box-shadow: 0 0 0 6px rgba(34, 197, 94, .25);
}
.orb-stage.s-dreb .orb-node.hot {
  border-color: #0D9488;
  box-shadow: 0 0 0 6px rgba(13, 148, 136, .25);
}
.orb-stage.s-ftx .orb-node.hot {
  border-color: #94A3B8;
  box-shadow: 0 0 0 6px rgba(148, 163, 184, .3);
}
.orb-stage.s-to .orb-node.hot {
  border-color: var(--red);
  box-shadow: 0 0 0 6px rgba(239, 68, 68, .25);
}
.orb-stage.s-blk .orb-node.hot {
  border-color: #0EA5E9;
  box-shadow: 0 0 0 6px rgba(14, 165, 233, .25);
}

/* Tether line from hub to finger (cosmetic) */
.orb-tether {
  position: absolute;
  height: 3px;
  border-radius: 2px;
  background: rgba(249, 115, 22, .35);
  transform-origin: 0 50%;
  pointer-events: none;
  z-index: 1;
}
.orb-stage.s-3p     .orb-tether { background: rgba(59, 130, 246, .35); }
.orb-stage.s-reb    .orb-tether,
.orb-stage.s-oreb   .orb-tether,
.orb-stage.s-assist .orb-tether { background: rgba(34, 197, 94, .35); }
.orb-stage.s-dreb   .orb-tether { background: rgba(13, 148, 136, .35); }
.orb-stage.s-stl    .orb-tether { background: rgba(147, 51, 234, .35); }
.orb-stage.s-ftx    .orb-tether { background: rgba(148, 163, 184, .4); }
.orb-stage.s-to     .orb-tether { background: rgba(239, 68, 68, .35); }
.orb-stage.s-blk    .orb-tether { background: rgba(14, 165, 233, .35); }

/* Bench: everyone not on court, one line under the orb */
.orb-bench-wrap {
  flex-shrink: 0;
  padding: 2px 10px calc(10px + env(safe-area-inset-bottom, 0px));
  touch-action: none; /* sub drags start here — don't scroll */
}
.orb-bench-wrap.orb-bench-dim { opacity: .35; pointer-events: none; }
.orb-bench-title {
  font-family: var(--font-display);
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--text-3);
  text-align: center;
  margin-bottom: 6px;
}
.orb-bench {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
}
.orb-node.orb-bench-node {
  position: relative; /* bench nodes flow in the row, not absolutely placed */
  width: 52px;
  height: 52px;
  background: var(--node-bg, var(--surface-2));
}
.orb-bench-node .orb-node-j { font-size: 12px; }
.orb-bench-node .orb-node-name { font-size: 8px; }

/* Player-first origin (pressed player before choosing a stat) */
.orb-node.picked {
  transform: scale(1.12);
  z-index: 4;
  box-shadow: 0 0 0 5px rgba(15, 23, 42, .16);
}

/* Substitution drag: source player + candidate swap target */
.orb-node.sub-src {
  transform: scale(1.12);
  z-index: 4;
  border-color: var(--accent-2);
  box-shadow: 0 0 0 5px rgba(59, 130, 246, .25);
}
.orb-side.subbing .orb-node.hot {
  border-color: var(--accent-2) !important;
  box-shadow: 0 0 0 6px rgba(59, 130, 246, .25) !important;
}
.orb-side.subbing .orb-tether { background: rgba(59, 130, 246, .35); }

/* Orb sides: one column on phones, two courts side by side on tablets */
.orb-sides {
  flex: 1;
  display: flex;
  min-height: 0;
}
.orb-side {
  flex: 1;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.orb-side-dim { opacity: .35; pointer-events: none; }

/* Split orb: one shared globe, home on the top arc + away on the bottom.
   Team names label the two halves; benches sit just inside each end. */
.orb-team-label {
  flex-shrink: 0;
  text-align: center;
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 700;
  padding: 3px 10px 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.orb-bench-compact { padding: 4px 10px; }
.orb-bench-compact .orb-bench-node { width: 46px; height: 46px; }
.orb-bench-compact .orb-bench-node .orb-node-j { font-size: 11px; }
.orb-bench-compact .orb-bench-node .orb-node-name { font-size: 8px; }

/* Chained play: scorer locked mid-stroke, finger seeking the assister.
   Defined after the per-stat rules so the chain state wins the cascade. */
.orb-node.scorer { transform: scale(1.18); z-index: 4; }
.orb-stage.s-2p .orb-node.scorer {
  border-color: var(--accent-ink);
  box-shadow: 0 0 0 6px rgba(249, 115, 22, .25);
}
.orb-stage.s-3p .orb-node.scorer {
  border-color: var(--accent-2);
  box-shadow: 0 0 0 6px rgba(59, 130, 246, .25);
}
/* While chaining, assist candidates + tether go assist-green (overrides stat color) */
.orb-stage.s-chain .orb-node.hot {
  border-color: var(--green);
  box-shadow: 0 0 0 6px rgba(34, 197, 94, .25);
}
.orb-stage.s-chain .orb-tether { background: rgba(34, 197, 94, .35); }

/* Commit flash glow (flashBtn reuses .stat-recorded).
   position:absolute must win over .stat-recorded's position:relative,
   or the node would jump out of the ring during the flash. */
.orb-node.stat-recorded {
  --glow-color: rgba(249, 115, 22, .45);
  position: absolute;
}

/* ── Stat Recorded — Smooth Animations ───────────────────────── */

/* Smooth spring pop — GPU-only (transform) */
@keyframes btn-pop {
  0%   { transform: scale(1);    }
  35%  { transform: scale(1.28); }
  65%  { transform: scale(0.92); }
  100% { transform: scale(1);    }
}

/* Glow ring that pulses out using box-shadow animation */
@keyframes glow-pulse {
  0%   { box-shadow: 0 0 0 0 var(--glow-color, rgba(249,115,22,.5)); }
  50%  { box-shadow: 0 0 0 8px var(--glow-color, rgba(249,115,22,.2)); }
  100% { box-shadow: 0 0 0 0 var(--glow-color, rgba(249,115,22,0)); }
}

/* Floating "+N" text that drifts up — GPU-only (transform + opacity) */
@keyframes float-up {
  0%   { opacity: 1; transform: translate(-50%, 0) scale(1.1); }
  50%  { opacity: 1; transform: translate(-50%, -24px) scale(1.2); }
  100% { opacity: 0; transform: translate(-50%, -40px) scale(0.9); }
}

/* Soft row highlight */
@keyframes row-glow {
  0%   { background-color: transparent; }
  20%  { background-color: var(--accent-soft); }
  100% { background-color: transparent; }
}

/* ── Prepare GPU layers for animated elements ────────────────── */
.grid-btn,
.stat-btn,
.qt-player-btn {
  will-change: transform;
  transform: translateZ(0); /* promote to GPU layer */
}

/* ── Base .stat-recorded — applied to any stat button ────────── */
.stat-recorded {
  animation: btn-pop .4s ease-out, glow-pulse .5s ease-out !important;
  transition: none !important; /* disable transition so it doesn't fight the animation */
  z-index: 2;
  position: relative;
}

/* Color-coded glow per stat type — Grid buttons */
.grid-btn-ft.stat-recorded,
.grid-btn-2p.stat-recorded  { --glow-color: rgba(249,115,22,.45); }
.grid-btn-3p.stat-recorded  { --glow-color: rgba(59,130,246,.45); }
.grid-btn-reb.stat-recorded { --glow-color: rgba(34,197,94,.45); }
.grid-btn-stl.stat-recorded { --glow-color: rgba(147,51,234,.45); }

/* Color-coded glow — Classic stat sheet buttons */
.stat-btn-pts.stat-recorded   { --glow-color: rgba(249,115,22,.4); }
.stat-btn-3pt.stat-recorded   { --glow-color: rgba(59,130,246,.4); }
.stat-btn-other.stat-recorded { --glow-color: rgba(249,115,22,.4); }

/* Quick Tap player card flash */
.qt-player-btn.qt-flash {
  animation: btn-pop .4s ease-out, glow-pulse .5s ease-out !important;
  transition: none !important;
  --glow-color: rgba(249,115,22,.4);
  background: var(--accent-soft) !important;
  border-color: var(--accent-ink) !important;
}

/* ── Floating label — drifts up from button ──────────────────── */
.stat-float-label {
  position: absolute;
  top: -2px;
  left: 50%;
  transform: translate(-50%, 0);
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 800;
  pointer-events: none;
  animation: float-up .65s ease-out forwards;
  z-index: 10;
  will-change: transform, opacity;
  color: var(--accent-ink);
  text-shadow: 0 1px 4px rgba(0,0,0,.1);
  white-space: nowrap;
}
.stat-float-label.blue   { color: var(--accent-2); }
.stat-float-label.green  { color: #22c55e; }
.stat-float-label.purple { color: #9333ea; }
.stat-float-label.red    { color: var(--red); }

/* Grid row soft highlight */
.grid-player-row.row-flash {
  animation: row-glow .5s ease-out;
}

/* ── Mobile fixes ────────────────────────────────────────────── */

/* Prevent iOS rubber-band on the game screen */
.game-screen { overscroll-behavior: none; }

/* Make non-game screens scroll properly with mobile chrome */
.home-screen,
.screen:not(.game-screen) {
  min-height: 100vh;
  min-height: 100dvh;
  padding-bottom: env(safe-area-inset-bottom, 0px);
}

/* Ensure sticky headers don't jump under notch */
.screen-header {
  padding-top: env(safe-area-inset-top, 0px);
}

/* Make qt-stat-picker non-sticky within scrollable container (already pinned by flex) */
.qt-stat-picker {
  flex-shrink: 0;
  position: relative;
  top: auto;
  z-index: auto;
}
.qt-hint { flex-shrink: 0; }

/* ── Tablet: wider layout on larger screens ─────────────────── */
@media (min-width: 600px) {
  body { max-width: 600px; }
  .bottom-sheet { max-width: 600px; }

  /* Grid view can fit more comfortably */
  .grid-btns { gap: 8px; }
  .grid-btn { padding: 12px 6px; font-size: 14px; }

  /* Quick Tap: 3 columns on tablet */
  .qt-player-grid { grid-template-columns: repeat(3, 1fr); }
  .qt-player-btn { padding: 16px 10px; }

  /* Larger sheet stat grid */
  .sheet-stat-grid { gap: 10px; }
  .stat-btn { padding: 16px 10px; }
}

@media (min-width: 768px) {
  body { max-width: 700px; }
  .bottom-sheet { max-width: 700px; }

  /* Even wider grid buttons */
  .grid-btn { padding: 12px 8px; font-size: 14px; }

  /* Stats cards can be wider */
  .stats-card { margin-bottom: 24px; }

  /* The live game uses the full tablet width (iPad portrait too) */
  body.game-wide { max-width: 1140px; }

  /* Roomier chrome on tablets */
  .game-header-compact .gh-team { font-size: 18px; max-width: 220px; }
  .gh-period-pill { padding: 8px 16px; font-size: 14px; }
  .gh-mode-btn { width: 40px; height: 34px; }
  .orb-hint { font-size: 14px; padding: 10px 14px; }
  .orb-team-label { font-size: 16px; padding: 6px 10px 4px; }
  .orb-bench-compact .orb-bench-node { width: 60px; height: 60px; }
  .orb-bench-compact .orb-bench-node .orb-node-j { font-size: 14px; }
  .orb-bench-compact .orb-bench-node .orb-node-name { font-size: 9px; }
  .orb-bench { gap: 12px; }
  .game-footer .btn { padding: 16px; font-size: 16px; }
}

/* ── Wide tablets / landscape: even more room, Quick Tap 4 columns ── */
@media (min-width: 1100px) {
  body.game-wide .qt-player-grid { grid-template-columns: repeat(4, 1fr); }
}

/* Landscape tablet (wide + short): the circular orb is height-bound, so
   trim the surrounding chrome to give it more vertical room. */
@media (min-width: 1000px) and (max-height: 920px) {
  .orb-hint { padding: 5px 14px; }
  .orb-team-label { padding: 2px 10px 1px; font-size: 14px; }
  .orb-bench-compact { padding: 3px 10px; }
  .orb-bench-compact .orb-bench-node { width: 50px; height: 50px; }
  .game-header-compact { padding-top: max(6px, env(safe-area-inset-top, 0px)); padding-bottom: 6px; }
}

/* ── Small phone (< 375px): tighten spacing ─────────────────── */
@media (max-width: 374px) {
  .grid-btns { gap: 4px; }
  .grid-btn { padding: 8px 2px; font-size: 12px; }
  .qt-stat-btn { padding: 8px 2px; font-size: 11px; }
  .orb-hub-stat { font-size: 12px; }
  .game-footer { padding: 10px 12px; }
  .game-footer .btn { padding: 12px 8px; font-size: 13px; }
  .gh-period-pill { padding: 5px 9px; font-size: 11px; }
  .gh-mode-btn { width: 28px; }
  .game-header-compact .gh-team { max-width: 84px; font-size: 14px; }
}

/* ── Share options sheet ─────────────────────────────────────── */
.share-options { display: flex; flex-direction: column; gap: 10px; padding: 4px 0 8px; }
.share-opt {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 16px;
  border: 1.5px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  text-align: left;
  cursor: pointer;
  -webkit-tap-highlight-color: var(--tap-color);
}
.share-opt:active { background: var(--surface-2); border-color: var(--accent-ink); }
.share-opt-icon { font-size: 24px; line-height: 1; flex-shrink: 0; }
.share-opt-main { display: flex; flex-direction: column; gap: 2px; }
.share-opt-title { font-size: 15px; font-weight: 600; color: var(--text-1); }
.share-opt-sub { font-size: 12px; color: var(--text-3); }

/* ── Printable summary (hidden on screen, shown when printing) ── */
#bb-print { display: none; }
@media print {
  body > #app,
  body > #modal-overlay,
  body > #bottom-sheet,
  body > #toast { display: none !important; }
  body { max-width: none; }
  #bb-print {
    display: block !important;
    color: #0F172A;
    font-family: var(--font-body);
    padding: 0;
  }
  @page { margin: 14mm; }

  .p-head { border-bottom: 2px solid #0F172A; padding-bottom: 10px; margin-bottom: 16px; }
  .p-brand {
    font-family: var(--font-display); font-weight: 800; letter-spacing: .5px;
    font-size: 13px; color: var(--accent-ink); text-transform: uppercase;
  }
  .p-match { font-family: var(--font-display); font-size: 22px; font-weight: 800; margin: 6px 0; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
  .p-match .p-chip { font-size: 18px; padding: 4px 15px; }
  .p-vs { color: #94A3B8; font-size: 14px; font-weight: 600; }
  .p-score { font-family: var(--font-display); font-size: 18px; font-weight: 800; margin-top: 4px; }
  .p-result { font-size: 12px; color: #64748B; margin-left: 6px; }
  .p-meta { font-size: 12px; color: #64748B; margin-top: 2px; }

  .p-chip {
    display: inline-block; padding: 3px 12px; border-radius: 999px;
    font-family: var(--font-display); font-weight: 700; font-size: 13px;
    line-height: 1.4; -webkit-print-color-adjust: exact; print-color-adjust: exact;
  }
  .p-team { margin: 18px 0 8px; }
  .p-section {
    font-family: var(--font-display); font-size: 15px; font-weight: 700;
    margin: 20px 0 10px; padding-bottom: 4px; border-bottom: 2px solid #0F172A;
  }
  /* A full box score is up to sixteen columns wide. Tabular figures so the
     made-attempt cells line up as a column of pairs rather than drifting, and
     a tighter cell so it still fits portrait A4 — the alternative is landscape,
     which is the wrong default for a sheet a coach pins up. */
  .p-table {
    width: 100%; border-collapse: collapse; font-size: 11px;
    table-layout: fixed; font-variant-numeric: tabular-nums;
  }
  .p-table th, .p-table td {
    padding: 5px 3px; text-align: center; border-bottom: 1px solid #E2E8F0;
  }
  .p-table th { font-size: 9px; letter-spacing: .3px; color: #64748B; text-transform: uppercase; }
  /* The name column takes what the stats leave, and is the only one allowed to
     be wide; everything else is a number a few characters long. */
  .p-table .p-l {
    text-align: left; width: 22%;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  /* The shooting pairs read as one unit, so the percentage beside each is
     visibly its own column rather than a second number in the same cell. */
  .p-table td.p-shot { font-weight: 600; }
  .p-table th.p-pct, .p-table td.p-pct { color: #475569; }
  .p-table .p-tot td { font-weight: 700; border-top: 2px solid #0F172A; border-bottom: none; }

  /* Chronological two-sided timeline (one event per row, per team side) */
  .p-tl-head { display: flex; align-items: center; margin: 8px 0 4px; }
  .p-tl-hl { flex: 1; text-align: left; }
  .p-tl-hr { flex: 1; text-align: right; }
  .p-tl-hc {
    width: 15%; text-align: center; font-size: 9px; font-weight: 700;
    letter-spacing: .5px; text-transform: uppercase; color: #94A3B8;
  }
  .p-tl { width: 100%; border-collapse: collapse; font-size: 12px; }
  .p-tl-period td {
    font-family: var(--font-display); font-size: 10px; font-weight: 700;
    text-transform: uppercase; color: #64748B; text-align: center;
    padding: 10px 0 3px; border-bottom: 1px solid #E2E8F0;
  }
  .p-tl-l, .p-tl-c, .p-tl-r { vertical-align: top; padding: 5px 0; border-bottom: 1px solid #F1F5F9; }
  .p-tl-l { text-align: right; padding-right: 12px; width: 42.5%; }
  .p-tl-r { text-align: left;  padding-left: 12px;  width: 42.5%; }
  .p-tl-c {
    width: 15%; text-align: center; white-space: nowrap;
    font-family: var(--font-display); font-weight: 700; font-size: 11px; color: #334155;
  }
  .p-assist { color: #64748B; }
  .p-pts { font-family: var(--font-display); font-weight: 700; }

  /* Single-team chronological list */
  .p-pbp { font-size: 12px; }
  .p-pbp-period {
    font-family: var(--font-display); font-size: 10px; font-weight: 700;
    text-transform: uppercase; color: #64748B;
    margin: 8px 0 3px; padding-bottom: 2px; border-bottom: 1px solid #E2E8F0;
  }
  .p-pbp-row { display: flex; align-items: baseline; gap: 8px; padding: 3px 0; border-bottom: 1px solid #F1F5F9; }
  .p-seq { color: #94A3B8; min-width: 22px; text-align: right; flex-shrink: 0; }
  .p-pbp-txt { flex: 1; }

  .p-tl-period, .p-pbp-period, .p-team, .p-section { break-after: avoid; page-break-after: avoid; }
  .p-tl tr, .p-pbp-row, .p-table tr { break-inside: avoid; page-break-inside: avoid; }
  .p-foot { margin-top: 20px; font-size: 10px; color: #94A3B8; text-align: center; }
}

/* ── Scrollbar ───────────────────────────────────────────────── */
::-webkit-scrollbar { width: 0; height: 0; }

/* ── Backup & Restore ─────────────────────────────────────────── */
.home-utility {
  padding: 4px 20px 0;
  text-align: center;
}
.link-btn {
  background: none;
  border: none;
  font-family: inherit;
  font-size: 13px;
  font-weight: 500;
  color: var(--text-3);
  padding: 8px 12px;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
  -webkit-tap-highlight-color: var(--tap-color);
}
.link-btn:active { color: var(--accent-ink); }
.backup-summary {
  margin: 0;
  padding: 0 20px 4px;
  font-size: 13px;
  color: var(--text-3);
}
.share-opt-danger .share-opt-title { color: var(--red); }

/* ── Seasons: standings, leaders, season player table ─────────────
   Stat columns vary per game and can exceed a phone's width, so the
   table scrolls inside its own wrapper rather than the page scrolling
   sideways. */
.box-wrap {
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: var(--surface);
}

.stat-table { width: 100%; border-collapse: collapse; font-size: 14px; }
.stat-table thead th {
  padding: 10px 8px;
  font-size: 11px; font-weight: 700; letter-spacing: 0.05em;
  text-transform: uppercase; color: var(--text-3);
  text-align: right; white-space: nowrap;
}
.stat-table th.st-left, .stat-table td.st-left { text-align: left; }
.stat-table tbody td {
  padding: 11px 8px; text-align: right;
  border-top: 1px solid var(--border);
  font-variant-numeric: tabular-nums;
}
.stat-table td.st-left { font-weight: 500; white-space: nowrap; }
.stat-table td.st-strong { font-weight: 700; }

.leader-block { margin-bottom: 18px; }
.leader-label {
  margin: 0 0 6px;
  font-size: 12px; font-weight: 700; letter-spacing: 0.04em;
  text-transform: uppercase; color: var(--text-2);
}
/* .leader-row and friends lived here — the pre-redesign list rows the leader
   boards were built from. The boards render .lead-card now; nothing referenced
   these. .leader-block and .leader-label above are still the board wrapper. */

/* A season spans several teams, so a player's team has to be visible: without
   it, six different children called "Player One" read as duplicated rows. */
.st-player { display: inline-flex; flex-direction: column; gap: 1px; vertical-align: middle; }
.st-player-name { font-weight: 500; }
.st-player-team { font-size: 11px; font-weight: 400; color: var(--text-3); }

/* ── Home: one thing to do now ─────────────────────────────────────
   The primary card. Everything that used to compete with it on this
   screen now lives behind More. */
.next-up {
  margin: 4px 0 8px;
  padding: 18px;
  border-radius: 18px;
  background: var(--surface);
  border: 1px solid var(--border);
  cursor: pointer;
}
.next-up-live { border-color: var(--accent-ink); background: var(--accent-soft); }
.next-up-empty { cursor: default; }
.next-up-tag {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 11px; font-weight: 700; letter-spacing: 0.07em;
  text-transform: uppercase; color: var(--text-3);
}
.next-up-live .next-up-tag { color: var(--accent-ink); }
.next-up-title {
  margin: 8px 0 4px;
  font-family: 'Space Grotesk', sans-serif;
  font-size: 20px; font-weight: 700; line-height: 1.2;
  overflow-wrap: anywhere;
}
.next-up-sub { margin: 0; font-size: 13px; color: var(--text-2); }
.next-up-empty .btn { margin-top: 14px; }

.app-header { display: flex; align-items: center; justify-content: space-between; }

/* Options a beginner never has to open. Native details, so no JS and nothing
   for the CSP to object to. */
.opt-block {
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 0 14px;
  margin-bottom: 16px;
  background: var(--surface);
}
.opt-summary {
  padding: 13px 0;
  font-size: 14px; font-weight: 600; color: var(--text-2);
  cursor: pointer;
}
.opt-block[open] .opt-summary { border-bottom: 1px solid var(--border); margin-bottom: 14px; }
.opt-note { font-weight: 400; color: var(--text-3); font-size: 12px; }
.form-actions .btn + .btn { margin-top: 10px; }

/* The fixture you personally are keeping, so a volunteer can pick their game
   out of a full league schedule at a glance. */
.game-card-mine {
  border-color: var(--accent-ink);
  background: var(--accent-soft);
}

/* ── Season panes ──────────────────────────────────────────────────
   Four tabs, matching the four jobs the screen used to stack. */
.season-meta { margin: 2px 0 12px; font-size: 13px; color: var(--text-2); }

.tab-bar {
  display: flex; gap: 4px;
  padding: 3px;
  background: var(--border-2);
  border-radius: 12px;
  margin-bottom: 16px;
  /* More tabs than fit stay reachable rather than wrapping into two rows. */
  overflow-x: auto;
}
.tab-btn {
  flex: 1 1 auto;
  min-width: fit-content;
  padding: 9px 12px;
  border: 0; border-radius: 9px;
  background: transparent; color: var(--text-2);
  font-family: inherit; font-size: 14px; font-weight: 600;
  white-space: nowrap; cursor: pointer;
}
.tab-btn.active { background: var(--surface); color: var(--text-1); box-shadow: var(--shadow-sm); }

.chip-row {
  display: flex; gap: 6px;
  margin-bottom: 14px;
  /* Scroll rather than wrap: a second row of chips pushed the content down and
     read as clutter. Matches the tab bar above it. */
  overflow-x: auto;
  scrollbar-width: none;
}
.chip-row::-webkit-scrollbar { display: none; }
.chip { flex: 0 0 auto; }
.chip {
  padding: 6px 11px;
  border: 1px solid var(--border); border-radius: 999px;
  background: var(--surface); color: var(--text-2);
  font-family: inherit; font-size: 13px; font-weight: 500;
  cursor: pointer;
}
.chip.active { border-color: var(--accent-ink); background: var(--accent-soft); color: var(--accent-ink); }

.home-section > .link-btn { margin-top: 10px; }

/* ── Team identity colour ──────────────────────────────────────────
   Colour is always a MARK BESIDE a label, never the label's own text
   colour. Two reasons: the brand orange is 2.73:1 on white so it fails
   as text, and identity must never be carried by colour alone — a
   colourblind reader still has the name. See TEAM_COLORS in app.js for
   the validated palette and what the old one got wrong. */
.team-dot {
  display: inline-block;
  width: 10px; height: 10px;
  border-radius: 3px;
  margin-right: 8px;
  vertical-align: baseline;
  flex: 0 0 auto;
}

/* A fixture is between TWO teams, so the edge carries both: home above, away
   below, with a hard stop. Drawn as a background strip rather than a border so
   no pseudo-element or positioning change is needed on a card that already
   works. */
.game-card-accent {
  padding-left: 12px;
  background-image: linear-gradient(to bottom,
    var(--card-accent) 0 50%, var(--card-accent-2, var(--card-accent)) 50% 100%);
  background-size: 4px 100%;
  background-repeat: no-repeat;
  background-position: left center;
}
.next-up-accent {
  padding-left: 18px;
  background-image: linear-gradient(to bottom,
    var(--card-accent) 0 50%, var(--card-accent-2, var(--card-accent)) 50% 100%);
  background-size: 5px 100%;
  background-repeat: no-repeat;
  background-position: left center;
}
.next-up-accent .next-up-tag { color: var(--card-accent, var(--accent)); }

/* Standings: tabular numerals already; give the leader a touch of weight so
   the eye lands on the top of the table rather than needing colour to rank.
   Colour follows the entity, never its rank. */
.stat-table tbody tr:first-child td.st-left { font-weight: 600; }

/* Standings on a phone: the numbers are the point, so they must never be the
   thing that scrolls off. Rank moves into the team cell — the rows are already
   in rank order, so a whole column was spending width on information the
   position already carried — and a long team name truncates rather than
   pushing W/L/PD out of view. Full name stays in the title attribute. */
.st-rank {
  display: inline-block; min-width: 14px;
  margin-right: 6px;
  font-size: 12px; font-weight: 700; color: var(--text-3);
  font-variant-numeric: tabular-nums;
}
td.st-left { max-width: 190px; }
.st-team-name {
  display: inline-block;
  max-width: 150px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  vertical-align: bottom;
}

/* The warning banner, previously inline light-only hexes. */
.notice-warn {
  background: var(--accent-soft);
  border: 1.5px solid var(--accent-line);
  border-radius: 12px;
  padding: 12px 16px; margin-bottom: 20px;
  font-size: 14px; color: var(--accent-ink);
}

/* ══════════════════════════════════════════════════════════════════
   Dark mode
   ──────────────────────────────────────────────────────────────────
   Its own set of steps, not an inversion. Two things were validated
   separately against the dark surface rather than assumed:

   1. Team identity colours. The light palette FAILS on dark, and in
      opposite directions — the orange too light (L 0.705) and the
      indigo too dark (L 0.457, 2.2:1 contrast). The dark band is
      L 0.48–0.67, so exactly two slots move: orange one step darker,
      indigo one step lighter. The other eight are unchanged, which is
      why a team stays recognisably "the green team" in both modes.
      See TEAM_COLORS / TEAM_COLORS_DARK in app.js.

   2. Surfaces. Text and border steps are chosen for contrast on
      #131C2E rather than flipped from the light values.

   Both `prefers-color-scheme` and an explicit [data-theme] are
   honoured, so the OS decides by default and the user can override.
   ══════════════════════════════════════════════════════════════════ */

/* --accent-line and --accent-ink are declared with the rest of the accent family
   in the token block at the top of this file. This block existed only to append
   them late, and would otherwise put the orange pair straight back. */

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg:            #0B1120;
    --surface:       #131C2E;
    --surface-2:     #1B2537;
    --border:        #23304A;
    --border-2:      #1B2537;
    --text-1:        #F1F5F9;
    --text-2:        #A3B0C2;
    --text-3:        #6B7A90;
    --text-faint:    #475569;
    /* Derived, not given: the handoff specifies light mode only. Same cyan
    ramp, inverted, because on a dark surface the LIGHT steps are the
    legible ones. Measured on #131C2E: #22D3EE 9.42:1, #06B6D4 7.01:1 —
    so dark mode can use cyan for text where light mode cannot. */
    --accent-ink:    #22D3EE;
    --accent-soft:   #0A2A33;
    --accent-tint:   #0A2A33;
    --accent-line:   #155E75;
    --accent-row:    rgba(34,211,238,.10);
    --accent-2-soft: #14243D;
    --green-soft:    #0C2A18;
    --red-soft:      #2A1416;
    --shadow-sm:     0 1px 3px rgba(0,0,0,.4);
    --shadow:        0 4px 14px rgba(0,0,0,.5);
    --shadow-tray:   0 8px 24px rgba(0,0,0,.55);
    --shadow-accent: 0 8px 24px rgba(6,182,212,.28);
  }
}

:root[data-theme="dark"] {
  --bg:            #0B1120;
  --surface:       #131C2E;
  --surface-2:     #1B2537;
  --border:        #23304A;
  --border-2:      #1B2537;
  --text-1:        #F1F5F9;
  --text-2:        #A3B0C2;
  --text-3:        #6B7A90;
  --text-faint:    #475569;
  /* Derived, not given: the handoff specifies light mode only. Same cyan
  ramp, inverted, because on a dark surface the LIGHT steps are the
  legible ones. Measured on #131C2E: #22D3EE 9.42:1, #06B6D4 7.01:1 —
  so dark mode can use cyan for text where light mode cannot. */
  --accent-ink:    #22D3EE;
  --accent-soft:   #0A2A33;
  --accent-tint:   #0A2A33;
  --accent-line:   #155E75;
  --accent-row:    rgba(34,211,238,.10);
  --accent-2-soft: #14243D;
  --green-soft:    #0C2A18;
  --red-soft:      #2A1416;
  --shadow-sm:     0 1px 3px rgba(0,0,0,.4);
  --shadow:        0 4px 14px rgba(0,0,0,.5);
  --shadow-tray:   0 8px 24px rgba(0,0,0,.55);
  --shadow-accent: 0 8px 24px rgba(6,182,212,.28);
}

/* Team marks carry both steps; CSS picks, so no re-render is needed when the
   OS scheme changes mid-session. */
.team-dot { background: var(--c-light, var(--card-accent)); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .team-dot { background: var(--c-dark, var(--c-light)); }
  :root:not([data-theme="light"]) .game-card-accent,
  :root:not([data-theme="light"]) .next-up-accent {
    background-image: linear-gradient(to bottom,
      var(--card-accent-dark, var(--card-accent)) 0 50%,
      var(--card-accent-2-dark, var(--card-accent-2, var(--card-accent))) 50% 100%);
  }
}
:root[data-theme="dark"] .team-dot { background: var(--c-dark, var(--c-light)); }
:root[data-theme="dark"] .game-card-accent,
:root[data-theme="dark"] .next-up-accent {
  background-image: linear-gradient(to bottom,
    var(--card-accent-dark, var(--card-accent)) 0 50%,
    var(--card-accent-2-dark, var(--card-accent-2, var(--card-accent))) 50% 100%);
}

/* The dark surface needs a visible edge where the light one relied on shadow. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .box-wrap,
  :root:not([data-theme="light"]) .chip { border-color: var(--border); }
}

/* The one accent link that lived in an inline style in app.js, so the token
   sweep could not see it. It was raw --accent at 600/13px: 2.43:1. As a class it
   follows the same rule as every other accent link — text is --accent-ink.
   (The handoff's Home mock makes this a white pill with accent-dark text; that
   restructuring belongs to step 3, this is just the legibility.) */
.notice-link {
  color: var(--accent-ink);
  font-weight: 600;
  text-decoration: none;
  margin-left: 4px;
}

/* ── Player card ───────────────────────────────────────────────────
   A trading card for one child. The whole point is that it reads as an
   object rather than another table, so it keeps a card's proportions and
   a card's frame: an outer mount, an inner coloured hero, a nameplate,
   and a stat strip.

   The colour discipline is the same as everywhere else in the app, and
   here it does real work. The team colour is the hero wash and the frame
   edge; the name is ink on the card's own surface. So the brand orange —
   which is 2.73:1 on white and can never carry text — is free to be the
   loudest thing on the card without a single word depending on it.

   The giant jersey number is `aria-hidden` and deliberately low contrast:
   it is the card's photograph, standing in for one we do not have. The
   readable version of the same number sits in the nameplate. */
.pcard {
  max-width: 360px;
  margin: 4px auto 20px;
  background: var(--surface);
  border: 1px solid var(--border);
  /* The mount: a little surface visible all the way around the hero, the
     way a card's border sits inside its cut edge. */
  padding: 7px;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  overflow: hidden;
}

.pcard-hero {
  position: relative;
  height: 132px;
  border-radius: var(--radius);
  overflow: hidden;
  background:
    radial-gradient(120% 120% at 15% 0%, rgba(255,255,255,.30), transparent 60%),
    linear-gradient(150deg,
      var(--card-accent, var(--accent)) 0%,
      color-mix(in oklab, var(--card-accent, var(--accent)) 72%, #0F172A) 100%);
}
/* Foil. Two degrees off the diagonal so it reads as a sheen on the stock
   rather than as stripes, and low enough alpha to survive a screenshot
   being re-compressed. */
.pcard-hero::after {
  content: '';
  position: absolute; inset: 0;
  background: repeating-linear-gradient(112deg,
    rgba(255,255,255,.10) 0 1px, transparent 1px 7px);
  pointer-events: none;
}
.pcard-glyph {
  /* Bleeding a few pixels past the bottom edge is the card-stock look; at -22px
     it cut the digits mid-stroke and read as a clipping bug instead. */
  position: absolute; left: 12px; bottom: -8px;
  font-family: var(--font-display);
  font-size: 94px; font-weight: 700; line-height: 1;
  letter-spacing: -4px;
  color: rgba(255,255,255,.28);
  -webkit-text-stroke: 1.5px rgba(255,255,255,.34);
  font-variant-numeric: tabular-nums;
  user-select: none;
}
/* The rating plate. Solid ink rather than a translucent scrim, so its
   contrast is fixed at 14:1 regardless of which of the ten team colours
   is behind it — a scrim over the light end of the palette would not
   have cleared 4.5:1. */
.pcard-rating {
  position: absolute; top: 10px; right: 10px;
  display: flex; flex-direction: column; align-items: center;
  padding: 7px 11px 6px;
  background: var(--dark);
  border-radius: var(--radius-sm);
  box-shadow: 0 2px 8px rgba(0,0,0,.28);
}
.pcard-rating-val {
  font-family: var(--font-display);
  font-size: 24px; font-weight: 700; line-height: 1;
  color: #FFFFFF;
  font-variant-numeric: tabular-nums;
}
.pcard-rating-lbl {
  margin-top: 3px;
  font-size: 9px; font-weight: 700; letter-spacing: .09em;
  color: var(--on-dark-2);
}

.pcard-plate { padding: 12px 8px 10px; }
.pcard-name {
  margin: 0;
  font-family: var(--font-display);
  font-size: 22px; font-weight: 700; line-height: 1.15;
  letter-spacing: -.4px;
  color: var(--text-1);
  overflow-wrap: anywhere;
}
.pcard-sub {
  margin: 5px 0 0;
  display: flex; align-items: center; gap: 6px;
  font-size: 14px; font-weight: 600; color: var(--text-2);
}
.pcard-season { margin: 3px 0 0; font-size: 12px; color: var(--text-3); }
/* A win-loss record must never break across lines — "3-" then an orphan "0" on
   the next line reads as a different number. */
.pcard-rec { white-space: nowrap; }

.pcard-strip {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: 2px;                     /* the surface gap, not a border */
  background: var(--border-2);
  border-radius: var(--radius);
  overflow: hidden;
}
.pcard-cell {
  display: flex; flex-direction: column; align-items: center;
  padding: 10px 2px 9px;
  background: var(--surface-2);
}
.pcard-cell-val {
  font-family: var(--font-display);
  font-size: 20px; font-weight: 700; line-height: 1;
  color: var(--text-1);
  font-variant-numeric: tabular-nums;
}
.pcard-cell-lbl {
  margin-top: 4px;
  font-size: 10px; font-weight: 700; letter-spacing: .07em; color: var(--text-2);
}
.pcard-cell-per { margin-top: 2px; font-size: 10px; color: var(--text-3); }

.pcard-badges {
  display: flex; flex-wrap: wrap; gap: 6px;
  padding: 10px 2px 2px;
}
.pcard-badge {
  display: inline-flex; align-items: baseline; gap: 5px;
  padding: 5px 9px;
  background: var(--accent-soft);
  border: 1px solid var(--accent-line);
  border-radius: 999px;
  font-size: 12px; font-weight: 600; color: var(--accent-ink);
}
.pcard-badge { gap: 4px; }
.pcard-badge-rank { font-family: var(--font-display); font-weight: 700; }
/* "1st/10", not "1st in Points of 10". The rank alone would flatter — 1st of 3
   and 1st of 264 are different achievements — so the field size stays on the
   badge, just small and attached to the rank it qualifies. */
.pcard-badge-of { font-size: 10px; font-weight: 500; opacity: .7; margin-left: -3px; }

.pcard-shots {
  display: flex; flex-wrap: wrap; gap: 4px 16px;
  margin: 10px 2px 0;
  font-size: 13px; color: var(--text-2);
}
.pcard-shots b {
  font-family: var(--font-display); font-weight: 700; color: var(--text-1);
  font-variant-numeric: tabular-nums;
}

/* Win/loss as a letter, never colour alone — the letter is the signal and
   the tint is reinforcement, so it still reads in forced-colors mode and
   for a red/green-confusing reader. */
.pcard-wl {
  display: inline-block; min-width: 15px; margin-right: 5px;
  font-family: var(--font-display); font-size: 11px; font-weight: 700;
  text-align: center; border-radius: 4px; padding: 1px 3px;
}
.pcard-wl-w { color: #14532D; background: #DCFCE7; }
.pcard-wl-l { color: #7F1D1D; background: #FEE2E2; }
.pcard-wl-t { color: var(--text-2); background: var(--surface-2); }

.pcard-log-row { cursor: pointer; }
/* The best game is marked by a bar and a lift in surface, not an accent fill.
   Filling it read fine on white and became a muddy brown stain on the dark
   surface, where --accent-soft is #2A1C0E; and colour-as-fill was the wrong
   choice regardless, since the bar carries the mark without asking the reader
   to interpret a tint. */
.pcard-log-best td { background: var(--surface-2); font-weight: 600; }
.pcard-log-best td:first-child { box-shadow: inset 3px 0 0 var(--accent); }

.st-muted { color: var(--text-3); font-weight: 500; }

/* Tappable player names. A button so it is keyboard-reachable and announced
   as an action, styled back down to text so the tables do not turn blue. */
.st-player-btn {
  display: inline-flex; flex-direction: column; gap: 1px;
  align-items: flex-start; text-align: left;
  background: none; border: 0; padding: 0; margin: 0;
  font: inherit; color: inherit; cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.st-player-btn .st-player-name { text-decoration: underline;
  text-decoration-color: var(--border); text-underline-offset: 2px; }
.st-player-btn:active .st-player-name { text-decoration-color: var(--accent-ink); }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .pcard-wl-w { color: #BBF7D0; background: #14311F; }
  :root:not([data-theme="light"]) .pcard-wl-l { color: #FECACA; background: #37181A; }
  :root:not([data-theme="light"]) .pcard-hero {
    background:
      radial-gradient(120% 120% at 15% 0%, rgba(255,255,255,.22), transparent 60%),
      linear-gradient(150deg,
        var(--card-accent-dark, var(--card-accent, var(--accent))) 0%,
        color-mix(in oklab,
          var(--card-accent-dark, var(--card-accent, var(--accent))) 62%, #04070D) 100%);
  }
}
:root[data-theme="dark"] .pcard-wl-w { color: #BBF7D0; background: #14311F; }
:root[data-theme="dark"] .pcard-wl-l { color: #FECACA; background: #37181A; }
:root[data-theme="dark"] .pcard-hero {
  background:
    radial-gradient(120% 120% at 15% 0%, rgba(255,255,255,.22), transparent 60%),
    linear-gradient(150deg,
      var(--card-accent-dark, var(--card-accent, var(--accent))) 0%,
      color-mix(in oklab,
        var(--card-accent-dark, var(--card-accent, var(--accent))) 62%, #04070D) 100%);
}

/* The card's season table carries eight columns. At the shared 8px cell padding
   that is 358px of table in a 334px wrapper, so it scrolled on a 375px phone to
   hide about twenty pixels — the worst kind of scroll, because nothing looks cut
   off and a reader never thinks to try. Tightening the numeric cells fits it. */
.stat-table-tight thead th,
.stat-table-tight tbody td { padding-left: 5px; padding-right: 5px; }
.stat-table-tight { font-size: 13px; }
/* The game cell takes whatever the numeric columns leave and wraps into it. The
   shared rule is nowrap, which on a long team name would push STL off the right
   edge instead — the numbers are the reason the table exists, so the name is
   what gives way. Full name stays in the title attribute. */
.pcard-log-row td.st-left { white-space: normal; }
.pcard-log-row .st-player { display: flex; }
.pcard-rank-note {
  margin: 8px 2px 0;
  font-size: 11px; line-height: 1.45; color: var(--text-3);
}

/* ── Team page ─────────────────────────────────────────────────────
   Deliberately NOT the trading-card treatment. A player card is one
   object you screenshot and send; a team page is a reference sheet you
   read. Same colour discipline — the team colour is a band and a dot,
   the name is ink — but a flat header rather than a foil hero, so the
   two screens are never mistaken for each other. */
.tcard {
  margin: 4px 0 20px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}
.tcard-band {
  height: 6px;
  background: var(--card-accent, var(--accent));
}
.tcard-head { padding: 14px 16px 12px; }
.tcard-name {
  margin: 0;
  font-family: var(--font-display);
  font-size: 22px; font-weight: 700; line-height: 1.15; letter-spacing: -.4px;
  color: var(--text-1);
  overflow-wrap: anywhere;
}
.tcard-sub {
  margin: 5px 0 0;
  display: flex; align-items: center; gap: 6px;
  font-size: 13px; font-weight: 500; color: var(--text-2);
}

.tcard-strip {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: 2px;                      /* surface gap, not a border */
  background: var(--border-2);
  border-top: 1px solid var(--border-2);
}
.tcard-cell {
  display: flex; flex-direction: column; align-items: center;
  padding: 11px 2px 10px;
  background: var(--surface-2);
}
.tcard-cell-val {
  font-family: var(--font-display);
  font-size: 19px; font-weight: 700; line-height: 1;
  color: var(--text-1); font-variant-numeric: tabular-nums;
}
.tcard-cell-lbl {
  margin-top: 5px;
  font-size: 10px; font-weight: 700; letter-spacing: .07em; color: var(--text-2);
}
.tcard-cell-sub { margin-top: 2px; font-size: 10px; color: var(--text-3); }

.tcard-form {
  display: flex; align-items: center; flex-wrap: wrap; gap: 4px;
  padding: 11px 16px;
  border-top: 1px solid var(--border);
}
.tcard-form-lbl {
  margin-right: 4px;
  font-size: 10px; font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; color: var(--text-3);
}
.tcard-form .pcard-wl { margin-right: 0; min-width: 20px; font-size: 12px; padding: 3px 4px; }
.tcard-form-note { margin-left: 4px; font-size: 10px; color: var(--text-3); }

/* Head to head: one block per rival. The record is the headline and the
   individual results sit under it as chips, because "we are 2-1 against
   them" and "which one did we lose" are two different questions and
   stacking them means neither needs a tap to answer. */
.h2h {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}
.h2h-top {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 11px 12px;
  background: none; border: 0; font: inherit; color: inherit;
  text-align: left; cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.h2h-top:active { background: var(--surface-2); }
.h2h-name {
  flex: 1; min-width: 0;
  font-size: 15px; font-weight: 600; color: var(--text-1);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.h2h-rec {
  font-family: var(--font-display); font-size: 15px; font-weight: 700;
  color: var(--text-1); font-variant-numeric: tabular-nums;
}
.h2h-pd {
  min-width: 34px; text-align: right;
  font-size: 12px; font-weight: 600; color: var(--text-3);
  font-variant-numeric: tabular-nums;
}
.h2h-games {
  display: flex; flex-wrap: wrap; gap: 6px;
  padding: 0 12px 11px;
}
.h2h-game {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 5px 9px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  font: inherit; color: inherit; cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.h2h-game:active { border-color: var(--accent-ink); }
.h2h-game .pcard-wl { margin-right: 0; }
.h2h-score {
  font-family: var(--font-display); font-size: 13px; font-weight: 700;
  font-variant-numeric: tabular-nums; color: var(--text-1);
}
.h2h-when { font-size: 11px; color: var(--text-3); }

.st-row-tap { cursor: pointer; }
.st-row-tap:active td { background: var(--surface-2); }

/* A team name inside a sentence. Underlined rather than coloured, for the
   same reason as .st-player-btn: the tables must not turn blue, and colour
   is never the only signal. */
.link-inline {
  background: none; border: 0; padding: 0; margin: 0;
  font: inherit; color: inherit; cursor: pointer;
  text-decoration: underline; text-decoration-color: var(--border);
  text-underline-offset: 2px;
}
.link-inline:active { text-decoration-color: var(--accent-ink); }
/* The band carries the dark step too, so a team is recognisably the same team in
   both schemes — the rule the team dots and card accents already follow. CSS
   picks, so changing the OS scheme mid-session needs no re-render. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .tcard-band {
    background: var(--card-accent-dark, var(--card-accent, var(--accent)));
  }
}
:root[data-theme="dark"] .tcard-band {
  background: var(--card-accent-dark, var(--card-accent, var(--accent)));
}

/* A name that is also a link, reused wherever a box score or a header shows
   one. Styled back down to text: these sit inside tables and dark headers
   where a blue link would be louder than the numbers it labels, and the
   underline rather than a colour keeps identity off colour alone. */
.name-link {
  background: none; border: 0; padding: 0; margin: 0;
  font: inherit; color: inherit; cursor: pointer;
  text-align: left;
  text-decoration: underline;
  text-decoration-color: var(--border);
  text-underline-offset: 2px;
  -webkit-tap-highlight-color: transparent;
}
.name-link:active { text-decoration-color: var(--accent-ink); }
/* On the summary's dark header the light border token disappears, so the
   underline needs its own value there. */
.name-link-dark { text-decoration-color: rgba(255,255,255,.35); }
.name-link-dark:active { text-decoration-color: var(--accent-ink); }
/* .name-link's `color: inherit` sits later in this file than .sum-team's own
   colour and beat it on source order, so the two names on the summary's dark
   header inherited near-black body ink onto a near-black background and
   disappeared completely — measured colour rgb(15,23,42) on rgb(15,23,42).
   Restored with the specificity to stay restored. */
.summary-matchup .sum-team { color: var(--on-dark); }
.summary-matchup .sum-opp  { color: var(--on-dark-2); }
/* Four 42px stat columns left ~88px for a name on a 375px phone, so "Klaire
   Wong" was cut to "Klaire Wo…". Now that the name is also the tap target for
   her card, a name you cannot read is a link you cannot aim at. 36px still fits
   a three-digit total at the display font's 17px, and buys 24px for the name.
   Scoped to .sc-stat-wide, which only the summary's box score uses — the live
   game grid sets its column width inline and is untouched. */
.sc-stat-wide { width: 36px; }

/* ── First load after signing in ───────────────────────────────────
   A banner at the top of Home rather than the one-line status hint at
   its foot. On a device that has just signed in the screen is empty, and
   the foot hint is the least visible thing on an empty screen — the
   report that prompted this was simply "no indication of loading". */
.load-banner {
  display: flex; align-items: center; gap: 12px;
  margin: 4px 0 12px;
  padding: 13px 14px;
  background: var(--accent-soft);
  border: 1px solid var(--accent-line);
  border-radius: var(--radius);
}
.load-title {
  margin: 0;
  font-size: 14px; font-weight: 600; color: var(--text-1);
}
.load-sub { margin: 2px 0 0; font-size: 12px; color: var(--text-2); }
.load-banner > div { flex: 1; min-width: 0; }

.load-spinner {
  flex: none;
  width: 18px; height: 18px;
  border: 2px solid var(--accent-line);
  border-top-color: var(--accent-ink);
  border-radius: 50%;
  animation: load-spin .8s linear infinite;
}
@keyframes load-spin { to { transform: rotate(360deg); } }
/* Respect a reader who has asked for less motion: the text already says
   what is happening, so the ring can simply sit still. */
@media (prefers-reduced-motion: reduce) {
  .load-spinner { animation: none; border-top-color: var(--accent-line); }
}

.load-banner-done { background: var(--surface); border-color: var(--border); }
.load-tick {
  flex: none;
  display: flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: 50%;
  background: var(--green); color: #fff;
  font-size: 13px; font-weight: 700;
}
.load-dismiss {
  flex: none;
  background: none; border: 0; padding: 6px 2px;
  font: inherit; font-size: 12px; font-weight: 600;
  color: var(--text-3); cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.load-dismiss:active { color: var(--accent-ink); }
.load-banner-fail { background: var(--red-soft); border-color: var(--red); }
.load-warn {
  flex: none;
  display: flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: 50%;
  background: var(--red); color: #fff;
  font-size: 14px; font-weight: 700;
}

/* ══════════════════════════════════════════════════════════════════
   CYAN ENERGY — shared components  (handoff step 2)
   ------------------------------------------------------------------
   The pieces every screen is assembled from. Steps 3-6 restructure
   templates onto these rather than growing more per-screen CSS.

   One deliberate deviation, and it is the only one. The mock puts
   WHITE text on the #06B6D4 pill for every accent button, including
   the primary CTAs at 15-16px. That is 2.43:1 against a 4.5
   requirement, on the largest and most important text on the screen,
   and it contradicts the handoff's own stated goal of high contrast.
   Navy on the same cyan is 7.35:1 and keeps the fill exactly as
   designed, so the pill stays the colour the mock specifies and the
   label becomes readable. .btn-pill-accent-inv is provided for the
   white-on-cyan version where a design reason outweighs that.
   ══════════════════════════════════════════════════════════════════ */

/* ── Gradient screen header ──────────────────────────────────────
   Full-bleed, scrolls with content (not fixed chrome). The 64px top
   padding covers the status bar and notch; env() adds the real inset
   on devices that report one so it is never guessed. */
.gx-head {
  position: relative;
  padding: calc(64px + env(safe-area-inset-top, 0px)) 22px 24px;
  border-radius: 0 0 var(--radius-header) var(--radius-header);
  color: #fff;
  background: var(--grad-accent);
}
.gx-head-navy { background: var(--grad-dark); }
/* Pull the first content block up under the header's rounded corners
   so the curve reads as the header's edge rather than a gap. */
.gx-head + .content,
.gx-head + .gx-body { padding-top: 18px; }

.gx-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px;
  margin-bottom: 16px;
}
.gx-row-tight { margin-bottom: 14px; }

.gx-title {
  font-family: var(--font-display);
  font-size: var(--fs-title); font-weight: 700;
  margin: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* The lockup: mark then wordmark, the mark aligned to cap height rather than
   to the text box, so the two read as one object. */
.gx-lockup { display: inline-flex; align-items: center; gap: 9px; }
.gx-lockup .mark { flex: none; display: block; }
.gx-wordmark {
  font-family: var(--font-display);
  font-size: var(--fs-wordmark); font-weight: 800;
  letter-spacing: var(--ls-wordmark);
}
.gx-wordmark span { opacity: .7; }

/* Header buttons. 36px circle keeps a 44px touch target once the
   header's own padding is counted. */
.gx-btn {
  flex: none;
  display: flex; align-items: center; justify-content: center;
  width: 36px; height: 36px;
  border: 0; border-radius: 50%;
  background: rgba(255,255,255,.2);
  color: #fff; font-size: 15px;
  cursor: pointer;
  -webkit-tap-highlight-color: var(--tap-color);
}
.gx-btn:active { background: rgba(255,255,255,.32); }
.gx-back {
  flex: none;
  background: none; border: 0; padding: 0 8px 0 0;
  color: #fff; font-size: 20px; font-weight: 300; line-height: 1;
  cursor: pointer;
  min-width: 44px; min-height: 44px;      /* target, not glyph */
  display: flex; align-items: center;
  -webkit-tap-highlight-color: var(--tap-color);
}
.gx-link {
  flex: none;
  background: none; border: 0; padding: 8px 0;
  font-family: var(--font-body);
  font-size: var(--fs-meta); font-weight: 600;
  color: var(--accent-light);
  cursor: pointer;
  -webkit-tap-highlight-color: var(--tap-color);
}
/* On a cyan header, accent-light has no contrast against the gradient; white
   does. .gx-game-head is listed explicitly because it is a separate element and
   was missed by the :not() selector alone. */
.gx-head:not(.gx-head-navy) .gx-link,
.gx-game-head .gx-link { color: #fff; }

.gx-pill {
  font-family: var(--font-body);
  font-size: var(--fs-micro); font-weight: 700;
  letter-spacing: 2px;
  background: rgba(255,255,255,.15);
  padding: 4px 10px;
  border-radius: var(--radius-pill);
  white-space: nowrap;
}
.gx-pill-live { display: inline-flex; align-items: center; gap: 6px; }
.gx-live-dot {
  flex: none;
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--green-on-dark);
  animation: gx-pulse 1.6s ease-in-out infinite;
}
@keyframes gx-pulse { 50% { opacity: .35; } }
@media (prefers-reduced-motion: reduce) { .gx-live-dot { animation: none; } }

/* Stat trio: 8-2 / W3 / 2nd */
.gx-trio { display: flex; justify-content: space-around; gap: 8px; }
.gx-trio-cell { text-align: center; min-width: 0; }
.gx-trio-val {
  font-family: var(--font-display);
  font-size: var(--fs-stat); font-weight: 700; line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.gx-trio-val-win  { color: var(--green-on-dark); }
.gx-trio-val-cyan { color: var(--accent-light); }
.gx-trio-lbl {
  margin-top: 2px;
  font-size: var(--fs-micro-sm); font-weight: 600;
  letter-spacing: var(--ls-micro);
  color: var(--on-dark-2);
  text-transform: uppercase;
}
.gx-head:not(.gx-head-navy) .gx-trio-lbl { color: rgba(255,255,255,.8); }

/* Hero score pair. The opponent side sits at 60% so the eye lands on
   your own team without colour doing the work. */
.gx-score { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.gx-score-side { text-align: center; flex: 1; min-width: 0; }
.gx-score-side-opp { opacity: .6; }
.gx-score-num {
  font-family: var(--font-display);
  font-size: var(--fs-hero); font-weight: 700; line-height: 1;
  font-variant-numeric: tabular-nums;
}
.gx-score-num-win { color: var(--accent-light); }
.gx-score-lbl {
  margin-top: 4px;
  font-size: 11px; font-weight: 600; letter-spacing: var(--ls-micro);
  text-transform: uppercase;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.gx-badge-w, .gx-badge-l {
  flex: none;
  font-family: var(--font-display);
  font-size: 13px; font-weight: 700;
  border-radius: var(--radius-pill);
  padding: 6px 12px;
}
.gx-badge-w { color: var(--green-on-dark); background: rgba(74,222,128,.15); }
.gx-badge-l { color: #FCA5A5;            background: rgba(239,68,68,.18); }

/* A card embedded IN the header (the live-game resume row on Home). */
.gx-inset {
  display: flex; align-items: center; gap: 12px;
  width: 100%;
  background: rgba(255,255,255,.15);
  border: 0;
  border-radius: var(--radius-card);
  padding: 14px 16px;
  color: #fff;
  text-align: left;
  font-family: inherit;
  cursor: pointer;
  -webkit-tap-highlight-color: var(--tap-color);
}
.gx-inset:active { background: rgba(255,255,255,.24); }
.gx-inset-body { flex: 1; min-width: 0; }
.gx-inset-title {
  display: block;
  font-family: var(--font-display);
  font-size: var(--fs-section); font-weight: 700;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.gx-inset-meta {
  display: block;
  font-size: var(--fs-meta); font-weight: 500; opacity: .8; margin-top: 1px;
}
/* White pill on the gradient: accent-dark text on white is 3.68:1, and
   at 600/12px that is short of AA, so this one uses --accent-ink. */
.gx-inset-cta {
  flex: none;
  font-size: var(--fs-meta); font-weight: 600;
  background: #fff; color: var(--on-white-ink);
  border-radius: var(--radius-pill);
  padding: 7px 14px;
}

/* ── Screen body ─────────────────────────────────────────────────
   Gutter 20px, sections 18-24px apart. */
.gx-body { padding: 18px 20px 40px; }
.gx-sec { margin-top: 24px; }
.gx-sec:first-child { margin-top: 0; }
.gx-sec-head {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 12px;
  margin-bottom: 10px;
}
.gx-sec-title {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--fs-section); font-weight: 700;
  color: var(--text-1);
}
.gx-sec-link {
  background: none; border: 0; padding: 0;
  font-family: var(--font-body);
  font-size: var(--fs-meta); font-weight: 600;
  color: var(--accent-ink);
  cursor: pointer; white-space: nowrap;
  -webkit-tap-highlight-color: var(--tap-color);
}
.gx-micro {
  font-size: var(--fs-micro); font-weight: 700;
  letter-spacing: var(--ls-micro);
  text-transform: uppercase;
  color: var(--text-3);
  margin: 0 0 8px;
}

/* ── Cards ───────────────────────────────────────────────────────── */
.gx-card {
  background: var(--surface);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-sm);
}
.gx-card-pad  { padding: 13px 16px; }
.gx-card-row  { border-radius: var(--radius-row); }
.gx-card-hero { border-radius: var(--radius-hero); }
.gx-card-navy {
  background: var(--dark); color: #fff;
  box-shadow: var(--shadow);
}
.gx-card-navy .gx-row-title { color: #fff; }
.gx-card-navy .gx-row-meta  { color: var(--on-dark-2); }

/* ── List row ────────────────────────────────────────────────────
   White card, 40px circle avatar, title + meta, value on the right. */
.gx-list { display: flex; flex-direction: column; gap: 8px; }
.gx-row-item {
  display: flex; align-items: center; gap: 12px;
  width: 100%;
  background: var(--surface);
  border: 0;
  border-radius: var(--radius-row);
  padding: 13px 16px;
  box-shadow: var(--shadow-sm);
  font-family: inherit;
  text-align: left;
  cursor: pointer;
  min-height: 44px;
  -webkit-tap-highlight-color: var(--tap-color);
}
.gx-row-item:active { transform: scale(.985); }
@media (prefers-reduced-motion: reduce) { .gx-row-item:active { transform: none; } }
/* display:block on the children, not divs in the markup: these rows are
   <button>s, and a button may only contain phrasing content. Spans are the
   correct element and the stacking has to come from CSS. */
.gx-row-body  { flex: 1; min-width: 0; }
.gx-row-title {
  display: block;
  font-size: var(--fs-body); font-weight: 600; color: var(--text-1);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.gx-row-meta  {
  display: block;
  font-size: var(--fs-meta); font-weight: 400; color: var(--text-3); margin-top: 1px;
}
.gx-row-val {
  flex: none;
  font-family: var(--font-display);
  font-size: var(--fs-section); font-weight: 700;
  color: var(--text-1);
  font-variant-numeric: tabular-nums;
}
.gx-row-val-cyan { color: var(--accent-ink); }
.gx-row-val-mut  { color: var(--text-2); }
/* Space Grotesk draws the guillemet as a plain > — chevrons stay in the body
   font, where the glyph is the one the design draws. */
.gx-chev {
  flex: none;
  font-family: var(--font-body);
  font-size: 20px; font-weight: 300; line-height: 1;
  color: var(--text-3);
}
.gx-chev-ink { color: var(--accent-ink); font-size: var(--fs-meta); font-weight: 600; }

/* Circle avatars: W/L results, stat labels, initials. */
.gx-av {
  flex: none;
  display: flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border-radius: 50%;
  font-family: var(--font-display);
  font-size: 13px; font-weight: 700;
}
.gx-av-sm  { width: 38px; height: 38px; }
.gx-av-lg  { width: 68px; height: 68px; font-size: 24px; }
.gx-av-w   { background: var(--green-soft);  color: #15803D; }
.gx-av-l   { background: var(--red-soft);    color: #B91C1C; }
.gx-av-t   { background: var(--surface-2);   color: var(--text-2); }
.gx-av-pts { background: var(--accent-soft); color: var(--accent-ink); font-family: var(--font-body); font-size: var(--fs-micro); }
.gx-av-reb { background: var(--accent-2-soft); color: #1D4ED8;  font-family: var(--font-body); font-size: var(--fs-micro); }
.gx-av-stl { background: var(--green-soft);  color: #15803D;    font-family: var(--font-body); font-size: var(--fs-micro); }
.gx-av-cyan{ background: var(--accent); color: #fff; }
.gx-av-ring { box-shadow: 0 0 0 3px rgba(255,255,255,.35); }

/* ── Pill buttons ────────────────────────────────────────────────── */
.gx-pill-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  border: 0; border-radius: var(--radius-pill);
  padding: 16px 20px;
  font-family: var(--font-display);
  font-size: 16px; font-weight: 700;
  cursor: pointer;
  min-height: 44px;
  -webkit-tap-highlight-color: var(--tap-color);
}
.gx-pill-btn:active { transform: scale(.98); }
@media (prefers-reduced-motion: reduce) { .gx-pill-btn:active { transform: none; } }
.gx-pill-full { display: flex; width: 100%; }
/* Navy on cyan: 7.35:1. See the deviation note at the top of this block. */
.gx-pill-accent     { background: var(--accent); color: var(--dark); }
.gx-pill-accent-inv { background: var(--accent-ink); color: #fff; }   /* 5.36:1 */
.gx-pill-navy       { background: var(--dark);   color: #fff; }
.gx-pill-white      {
  background: var(--surface); color: var(--text-1);
  box-shadow: var(--shadow-sm);
}
.gx-pill-ghost {
  background: none; color: var(--accent-ink);
  border: 1.5px solid var(--accent-line);
}
.gx-pill-dashed {
  background: none; color: var(--accent-ink);
  border: 1.5px dashed var(--accent-line);
}

/* ── Chips ───────────────────────────────────────────────────────
   Segments and filters are single-select (one active accent pill);
   stat chips are multi-select. Same shape, different semantics, so
   the markup uses role attributes and the CSS does not care. */
.gx-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.gx-chip {
  border: 1.5px solid var(--border);
  background: var(--surface);
  border-radius: var(--radius-pill);
  padding: 9px 16px;
  font-family: var(--font-body);
  font-size: 13px; font-weight: 600;
  color: var(--text-2);
  cursor: pointer;
  min-height: 40px;
  -webkit-tap-highlight-color: var(--tap-color);
}
.gx-chip:active { border-color: var(--accent); }
/* Active state carries a fill AND a weight change, so it never depends
   on colour alone. */
.gx-chip.is-on {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--dark);
  font-weight: 700;
}

/* The toggle needed no work: .toggle-switch was already 46x28 with a 24px knob
   and an accent track, which is exactly what the handoff specifies. A .gx-toggle
   was written here first and then deleted — it duplicated a control that already
   matched, and as a <button aria-checked> it was WORSE than the real checkbox it
   would have replaced. Checked before assuming, second time round. */

/* ── Table card ──────────────────────────────────────────────────
   A grid, not a <table>: the column template is set per screen and
   the header rule / row hairlines come from tokens. */
.gx-table {
  background: var(--surface);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-sm);
  padding: 4px 16px 6px;
  overflow: hidden;
}
.gx-tr {
  display: grid;
  gap: 4px;
  align-items: center;
  padding: 13px 0;
  border-bottom: 1px solid var(--border-2);
}
.gx-tr:last-child { border-bottom: 0; }
/* A box score with many tracked stats is wider than a phone. It scrolls inside
   its own card; the page itself must never scroll sideways. */
.gx-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.gx-table .gx-tr { min-width: max-content; }
.gx-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gx-thead {
  padding: 10px 0;
  border-bottom: 1px solid var(--border);
  font-size: var(--fs-micro); font-weight: 700;
  letter-spacing: var(--ls-micro);
  color: var(--text-3);
  text-transform: uppercase;
}
.gx-num {
  font-family: var(--font-display);
  font-size: var(--fs-section); font-weight: 500;
  text-align: right;
  color: var(--text-1);
  font-variant-numeric: tabular-nums;
}
.gx-thead .gx-num { font-family: var(--font-body); font-weight: 700; font-size: var(--fs-micro); }
.gx-name { font-size: var(--fs-section); font-weight: 500; color: var(--text-1);
           overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gx-jersey { font-family: var(--font-display); font-size: var(--fs-section); font-weight: 700; color: var(--text-3); }
/* The reader's own player: a tint that fades to the right, so the row is
   marked without a hard band across the card. */
.gx-tr-mine {
  background: linear-gradient(90deg, var(--accent-row), transparent);
}
.gx-tr-mine .gx-jersey { color: var(--accent-ink); }
.gx-tr-mine .gx-name,
.gx-tr-mine .gx-num { font-weight: 700; }
.gx-tr-total { border-bottom: 0; }
.gx-tr-total .gx-name, .gx-tr-total .gx-num { font-weight: 700; }

/* ── Stat tiles ──────────────────────────────────────────────────── */
.gx-tiles { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.gx-tile {
  background: var(--surface);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-sm);
  padding: 14px 12px;
  text-align: center;
}
.gx-tile-navy { background: var(--dark); box-shadow: var(--shadow); }
.gx-tile-val {
  font-family: var(--font-display);
  font-size: 24px; font-weight: 700; line-height: 1;
  color: var(--text-1);
  font-variant-numeric: tabular-nums;
}
.gx-tile-navy .gx-tile-val { color: var(--accent-light); }
.gx-tile-lbl {
  margin-top: 5px;
  font-size: var(--fs-micro-sm); font-weight: 700;
  letter-spacing: var(--ls-micro);
  text-transform: uppercase;
  color: var(--text-3);
}
.gx-tile-navy .gx-tile-lbl { color: var(--on-dark-2); }
.gx-tile-val-win { color: var(--green); }

/* ── Trend bars (cyan ramp) ──────────────────────────────────────── */
.gx-trend { display: flex; align-items: flex-end; gap: 6px; height: 84px; }
.gx-trend-col { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 6px; min-width: 0; }
.gx-trend-bar { width: 100%; border-radius: 6px 6px 2px 2px; background: var(--accent); min-height: 4px; }
.gx-trend-bar-1 { background: #A5F3FC; }
.gx-trend-bar-2 { background: #67E8F9; }
.gx-trend-bar-3 { background: #22D3EE; }
.gx-trend-bar-4 { background: #06B6D4; }
.gx-trend-bar-5 { background: #0891B2; }
.gx-trend-lbl { font-size: var(--fs-micro-sm); font-weight: 600; color: var(--text-3); }

/* ── Floating bottom tray ────────────────────────────────────────── */
.gx-tray {
  position: sticky; bottom: 0;
  margin: 12px -20px 0;
  padding: 12px 16px calc(12px + env(safe-area-inset-bottom, 0px));
  background: var(--surface);
  border-radius: var(--radius-hero) var(--radius-hero) 0 0;
  box-shadow: var(--shadow-tray);
  z-index: 5;
}

/* ── Home ────────────────────────────────────────────────────────── */
.gx-quick { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.gx-quick-btn {
  display: flex; flex-direction: column; gap: 4px;
  border: 0; border-radius: var(--radius-card);
  padding: 16px;
  font-family: inherit; text-align: left;
  cursor: pointer; min-height: 44px;
  -webkit-tap-highlight-color: var(--tap-color);
}
.gx-quick-btn:active { transform: scale(.98); }
@media (prefers-reduced-motion: reduce) { .gx-quick-btn:active { transform: none; } }
.gx-quick-navy  { background: var(--dark); color: #fff; box-shadow: var(--shadow); }
.gx-quick-white { background: var(--surface); color: var(--text-1); box-shadow: var(--shadow-sm); }
.gx-quick-ic  { font-family: var(--font-body); font-size: 22px; font-weight: 400; line-height: 1; }
.gx-quick-lbl { font-size: var(--fs-body); font-weight: 600; }

/* The no-game inset is not a button, so it must not look pressable. */
.gx-inset-flat { cursor: default; background: rgba(255,255,255,.12); }

.gx-empty { text-align: center; }
.gx-empty-title {
  margin: 4px 0 0;
  font-family: var(--font-display);
  font-size: 17px; font-weight: 700; color: var(--text-1);
}
.gx-empty-sub { margin: 6px 0 14px; font-size: 13px; color: var(--text-2); line-height: 1.45; }

.gx-sync {
  margin: 20px 0 0; text-align: center;
  font-size: var(--fs-meta); color: var(--text-3);
}
.gx-score-meta {
  margin: 14px 0 0; text-align: center;
  font-size: var(--fs-meta); color: rgba(255,255,255,.65);
}
/* The team names under the hero scores are tap targets to the team page. */
.gx-score-lbl.name-link { display: block; width: 100%; text-align: center; }

/* ── Live game header ────────────────────────────────────────────
   The mock's cyan header, but the score block is 40px rather than the
   52px used on a box score. This screen's vertical space belongs to the
   stat targets a keeper is hitting one-handed at speed; a 52px score
   plus 64px of safe area would push the first row of targets down by
   most of a thumb's reach. The rounded bottom corners are dropped for
   the same reason — the roster list starts immediately underneath.

   The period pills and the four view-mode buttons have no counterpart in
   the mock, which shows one input mode. They are real functionality and
   stay. */
.gx-game-head {
  padding: calc(14px + env(safe-area-inset-top, 0px)) 16px 10px;
  background: var(--grad-accent);
  color: #fff;
}
.gx-game-head .gx-row { margin-bottom: 10px; }
.gx-score-live .gx-score-num { font-size: 40px; }
.gx-score-live .gx-score-lbl { font-size: 11px; opacity: .9; margin-top: 2px; }
.gx-score-dash { font-family: var(--font-display); font-size: 26px; font-weight: 700; opacity: .5; }

.gx-game-controls {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin-top: 10px;
}
.gx-periods, .gx-modes { display: flex; gap: 6px; }
.gx-period {
  min-width: 40px; min-height: 34px;
  border: 0; border-radius: var(--radius-pill);
  background: rgba(255,255,255,.18);
  color: #fff;
  font-family: var(--font-display);
  font-size: 13px; font-weight: 700;
  cursor: pointer;
  -webkit-tap-highlight-color: var(--tap-color);
}
/* Active period: white fill with navy text. On a cyan header a cyan-filled
   chip would be invisible, and white-on-white needs the ink. */
.gx-period.is-on { background: #fff; color: var(--on-white-ink); }
.gx-mode {
  display: flex; align-items: center; justify-content: center;
  width: 34px; height: 34px;
  border: 0; border-radius: var(--radius-sm);
  background: transparent;
  color: rgba(255,255,255,.7);
  cursor: pointer;
  -webkit-tap-highlight-color: var(--tap-color);
}
.gx-mode.is-on { background: rgba(255,255,255,.22); color: #fff; }

/* ── Game setup ──────────────────────────────────────────────────
   The active chip classes are doubled up (is-on + active): the toggle
   handlers in app.js flip `active`, and the segment picker reads it, so
   the legacy class stays the state carrier and `is-on` is what the new
   look hangs off. One state, two names, rather than rewriting four
   handlers for a reskin. */
.gx-chip.active { background: var(--accent); border-color: var(--accent); color: var(--dark); font-weight: 700; }
.segment-control, .stat-config-grid { display: flex; flex-wrap: wrap; gap: 8px; }

/* Uppercase micro-labels, per the mock's setup screen. */
.gx-micro-lbl {
  font-size: var(--fs-micro) !important;
  font-weight: 700 !important;
  letter-spacing: var(--ls-micro);
  text-transform: uppercase;
  color: var(--text-3) !important;
}
.gx-micro-lbl .opt-note { text-transform: none; letter-spacing: 0; font-weight: 500; }

.gx-actions { display: flex; flex-direction: column; gap: 10px; margin-top: 24px; }

/* ══════════════════════════════════════════════════════════════════
   CYAN ENERGY — screens 4-6, applied at the shared class
   ------------------------------------------------------------------
   Every remaining screen already renders .screen-header and .stat-table,
   so those two classes are where the redesign lands rather than nine
   rewritten templates. The handoff's own step 1 rationale — retokenise
   and much of the app improves for free — extends to components.

   The header stops being sticky. It is a gradient panel that scrolls with
   the content, which the handoff states explicitly ("header gradients
   scroll with content — they're part of the screen, not fixed chrome").
   ══════════════════════════════════════════════════════════════════ */
.screen-header {
  height: auto;
  padding: calc(52px + env(safe-area-inset-top, 0px)) 20px 20px;
  background: var(--grad-accent);
  border-bottom: 0;
  border-radius: 0 0 var(--radius-header) var(--radius-header);
  position: static;
  color: #fff;
}
.screen-header-navy { background: var(--grad-dark); }

.screen-header .btn-back,
.screen-header .screen-title,
.screen-header .btn-hdr-text { color: #fff; }
.screen-header .screen-title {
  font-size: var(--fs-title);
  letter-spacing: 0;
}
.screen-header .btn-back { font-size: 20px; font-weight: 300; }
/* On navy the accent-light reads as a link; on cyan only white does. */
.screen-header-navy .btn-hdr-text { color: var(--accent-light); }

/* The first content block sits under the header's curve. */
.screen-header + .content { padding-top: 18px; }

/* A stat trio dropped into any header. */
.screen-header-stack { flex-direction: column; align-items: stretch; gap: 14px; }
.screen-header-stack .screen-hdr-row { display: flex; align-items: center; gap: 8px; }

/* ── Tables become the table card everywhere ─────────────────────── */
.box-wrap {
  background: var(--surface);
  border: 0;
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-sm);
  padding: 2px 16px 4px;
}
.stat-table thead th {
  padding: 10px 5px;
  border-bottom: 1px solid var(--border);
  font-size: var(--fs-micro); font-weight: 700;
  letter-spacing: var(--ls-micro);
  color: var(--text-3);
}
.stat-table tbody td {
  padding: 13px 5px;
  border-top: 0;
  border-bottom: 1px solid var(--border-2);
  font-family: var(--font-display);
  font-size: var(--fs-section); font-weight: 500;
  color: var(--text-1);
}
.stat-table tbody tr:last-child td { border-bottom: 0; }
.stat-table td.st-left { font-family: var(--font-body); }
.stat-table td.st-strong { font-weight: 700; }
/* The reader's own row: the cyan fade the handoff specifies for a
   highlighted table row, rather than a flat band. */
.st-row-mine td { background: linear-gradient(90deg, var(--accent-row), transparent); }

/* Section titles across every screen pick up the display font + size. */
.section-title {
  font-family: var(--font-display);
  font-size: var(--fs-section);
  font-weight: 700;
  color: var(--text-1);
}

/* Season tabs: the chip language, so a segment reads the same here as on
   the setup screen. Active carries a weight change as well as the fill. */
.tab-bar {
  display: flex; gap: 8px; flex-wrap: wrap;
  background: none; padding: 0; border-radius: 0;
  margin: 4px 0 18px;
}
.tab-btn {
  flex: none;
  border: 1.5px solid var(--border);
  background: var(--surface);
  border-radius: var(--radius-pill);
  padding: 9px 16px;
  font-family: var(--font-body);
  font-size: 13px; font-weight: 600;
  color: var(--text-2);
  min-height: 40px;
  box-shadow: none;
}
.tab-btn.active {
  background: var(--accent); border-color: var(--accent);
  color: var(--dark); font-weight: 700;
}
.season-meta { margin: 0 0 14px; font-size: var(--fs-meta); color: var(--text-3); }

/* ── Sign-in ─────────────────────────────────────────────────────
   The handoff's splash, adapted to a sheet — see the note in auth-ui.js
   for why this is not a full-screen takeover. Full-bleed inside the
   sheet's own rounded top, so the gradient reads as the sheet's head. */
.auth-hero {
  margin: -8px -20px 0;
  padding: 26px 22px 24px;
  background: var(--grad-accent);
  border-radius: var(--radius-hero) var(--radius-hero) 0 0;
  color: #fff;
  text-align: center;
}
.auth-wordmark {
  display: flex; align-items: center; gap: 10px;
  margin: 0;
  font-family: var(--font-display);
  font-size: 32px; font-weight: 800;
  letter-spacing: var(--ls-wordmark);
}
.auth-wordmark .mark { flex: none; }
/* The opacity that dims "Pass" has to sit on the TEXT span, not on every child
   of .auth-wordmark — applied to the whole element it would have faded the
   mark's cyan too. */
.auth-wordmark-text span { opacity: .7; }
.auth-tagline {
  margin: 8px 0 0;
  font-size: 13px; font-weight: 500; line-height: 1.5;
  opacity: .9;
}
.auth-skip {
  background: none; border: 0;
  padding: 14px 8px;
  font-family: var(--font-body);
  font-size: 14px; font-weight: 600;
  color: var(--accent-ink);
  cursor: pointer; width: 100%;
  -webkit-tap-highlight-color: var(--tap-color);
}
.auth-skip:active { color: var(--accent); }


/* ── Contrast corrections found by measuring the rendered pages ───────
   Six regressions the redesign introduced, each measured rather than
   guessed. Recorded because five of the six are the same mistake in
   different places: a colour chosen for one surface, reused on another. */

/* C. W/L/stat avatars invert on the dark surface. The tints go dark, so the
      glyph has to go light — #15803D on #0C2A18 measured 2.68:1. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .gx-av-w,
  :root:not([data-theme="light"]) .gx-av-stl { color: #6EE7A0; }
  :root:not([data-theme="light"]) .gx-av-l   { color: #FCA5A5; }
  :root:not([data-theme="light"]) .gx-av-reb { color: #93C5FD; }
}
:root[data-theme="dark"] .gx-av-w,
:root[data-theme="dark"] .gx-av-stl { color: #6EE7A0; }
:root[data-theme="dark"] .gx-av-l   { color: #FCA5A5; }
:root[data-theme="dark"] .gx-av-reb { color: #93C5FD; }

/* D. Header buttons were coloured for a white bar and are now on a gradient.
      --red on #0891B2 measured 1.02:1 — very nearly invisible. On a coloured
      header the only reliable ink is white, so danger is carried by a tinted
      pill instead of by red text. */
.screen-header .btn-hdr-danger {
  color: #fff;
  background: rgba(239,68,68,.28);
  border-radius: var(--radius-pill);
  padding: 6px 12px;
}
.screen-header .btn-hdr-add { color: #fff; }

/* E. The legacy primary button, still used inside sheets. Same fix and same
      reason as .gx-pill-accent: white on #06B6D4 is 2.43:1, navy is 7.35:1. */
.btn-primary { background: var(--accent); color: var(--dark); }
.btn-primary:active { background: var(--accent-dark); color: #fff; }

/* ── Teams ───────────────────────────────────────────────────────── */
.gx-av-letter {
  background: var(--c-light);
  color: #fff;
  font-size: 16px;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .gx-av-letter { background: var(--c-dark, var(--c-light)); }
}
:root[data-theme="dark"] .gx-av-letter { background: var(--c-dark, var(--c-light)); }
.gx-edit-link {
  flex: none;
  font-size: var(--fs-meta); font-weight: 600;
  color: var(--accent-ink);
  white-space: nowrap;
}
.gx-mt { margin-top: 14px; }
/* A filter row that can outgrow the screen scrolls sideways rather than
   wrapping into three lines and pushing the games out of view. */
.gx-chips-scroll {
  flex-wrap: nowrap;
  overflow-x: auto;
  margin: 0 -20px 14px;
  padding: 0 20px 2px;
  scrollbar-width: none;
}
.gx-chips-scroll::-webkit-scrollbar { display: none; }
.gx-chips-scroll .gx-chip { flex: none; }
.gx-mt-sec { margin-top: 22px; }
.gx-trend-note {
  margin: 12px 0 0;
  font-size: var(--fs-meta); line-height: 1.45; color: var(--text-3);
}

/* ── Team detail head ────────────────────────────────────────────── */
.tcard-head { display: grid; grid-template-columns: auto 1fr; gap: 14px; align-items: center; }
.tcard-head .tcard-name { grid-column: 2; }
.tcard-head .tcard-sub  { grid-column: 2; }
.tcard-av { grid-row: 1 / span 2; }

/* ── Roster editor ───────────────────────────────────────────────
   The handoff wants 40px rounded-square jersey badges. These are live
   number INPUTS, not badges — the whole point of this screen is editing
   them — so they take the badge's shape and tint and stay editable.
   Drag handles are not added: reordering is not a behaviour the app has,
   and a handle that does nothing is worse than no handle. */
.player-row {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 0;
}
.jersey-edit {
  flex: none;
  width: 44px; height: 40px;
  border: 1.5px solid var(--accent-line);
  border-radius: var(--radius-sm);
  background: var(--accent-soft);
  color: var(--accent-ink);
  font-family: var(--font-display);
  font-size: 15px; font-weight: 700;
  text-align: center;
  -moz-appearance: textfield;
}
.jersey-edit::-webkit-outer-spin-button,
.jersey-edit::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.player-name-edit {
  flex: 1; min-width: 0;
  height: 40px;
  border: 1.5px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text-1);
  font-family: var(--font-body);
  font-size: var(--fs-body); font-weight: 500;
  padding: 0 12px;
}
.player-name-edit:focus, .jersey-edit:focus {
  outline: none; border-color: var(--accent);
}
.btn-remove {
  flex: none;
  width: 40px; height: 40px;
  border: 0; border-radius: 50%;
  background: var(--surface-2);
  color: var(--text-2);
  font-size: 15px; cursor: pointer;
  -webkit-tap-highlight-color: var(--tap-color);
}
.btn-remove:active { background: var(--red-soft); color: var(--red); }
.gx-add-btn { padding: 10px 18px; font-size: 14px; min-height: 40px; flex: none; }

/* ── Live game: the floating stat tray ───────────────────────────── */
.qt-view { display: flex; flex-direction: column; min-height: 0; }
.qt-tray { margin-top: auto; }
.qt-tray-hint {
  margin: 0 0 10px;
  font-size: var(--fs-meta); color: var(--text-2); text-align: center;
}
.qt-tray-hint strong { color: var(--text-1); font-weight: 700; }
.qt-stat-picker { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; }
.qt-stat-btn {
  flex: 1 1 auto; min-width: 58px; min-height: 48px;
  border: 1.5px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--text-2);
  font-family: var(--font-display);
  font-size: 16px; font-weight: 700;
  cursor: pointer;
  -webkit-tap-highlight-color: var(--tap-color);
}
/* The selected pill is filled AND heavier — selection never rests on colour
   alone, the same rule the chips follow. */
.qt-stat-btn.active {
  background: var(--accent); border-color: var(--accent);
  color: var(--dark);
}
.qt-stat-btn.qt-p1.active { background: var(--accent-light); border-color: var(--accent-light); }
.qt-stat-btn.qt-p3.active { background: var(--dark); border-color: var(--dark); color: #fff; }

/* ══════════════════════════════════════════════════════════════════
   PLAYER CARD — mock 6a "Gradient hero"
   ------------------------------------------------------------------
   Supersedes the 5a frame. The header runs the full three-stop gradient
   and ends on #0E7490, which is the step where white text finally clears
   AA (5.36:1) — so unlike the two-stop cyan headers elsewhere, small
   white text is safe on the LOWER part of this one. The bar sits at the
   top, where it is lightest, so it keeps larger type.
   ══════════════════════════════════════════════════════════════════ */
.pc-hero {
  position: relative;
  overflow: hidden;
  padding: calc(52px + env(safe-area-inset-top, 0px)) 22px 70px;
  color: #fff;
  background: linear-gradient(170deg,
    var(--card-accent, #06B6D4) 0%,
    color-mix(in oklab, var(--card-accent, #06B6D4) 80%, #0F172A) 55%,
    color-mix(in oklab, var(--card-accent, #06B6D4) 55%, #0F172A) 100%);
}
/* The giant initials. aria-hidden and 10% white: it is texture, so it never
   has to clear a contrast bar, and a screen reader is not read "RY". */
.pc-watermark {
  position: absolute; right: -40px; top: 30px;
  font-family: var(--font-display);
  font-size: 220px; font-weight: 800; line-height: 1;
  letter-spacing: -12px;
  color: rgba(255,255,255,.1);
  pointer-events: none; user-select: none;
}
.pc-bar, .pc-main { position: relative; }
.pc-share { color: #A5F3FC; }

.pc-main {
  margin-top: 26px;
  display: flex; justify-content: space-between; align-items: flex-start; gap: 14px;
}
.pc-id { min-width: 0; }
.pc-name {
  margin: 0;
  font-family: var(--font-display);
  font-size: 38px; font-weight: 800; line-height: 1.05;
  letter-spacing: -1.5px;
  overflow-wrap: anywhere;
}
/* A block, not a flex row: as flex the team dot became its own flex item and
   wrapped onto a line by itself as soon as the meta text needed two lines. */
.pc-meta {
  margin: 8px 0 0;
  font-size: 13px; font-weight: 500; opacity: .85;
  line-height: 1.5;
}
.pc-meta .team-dot { margin-right: 7px; vertical-align: baseline; }
/* A sticker, so it gets a sticker's tilt. Kept to 2deg: any more and the
   descenders start to look like a rendering fault rather than a choice. */
.pc-sticker {
  display: inline-block;
  margin-top: 12px;
  background: #fff; color: var(--accent-ink);
  border-radius: var(--radius-pill);
  padding: 6px 14px;
  font-family: var(--font-display);
  font-size: 11px; font-weight: 800;
  transform: rotate(-2deg);
  box-shadow: 0 3px 8px rgba(0,0,0,.15);
}

/* The rating ring. conic-gradient sweep = the percentile. */
.pc-ring {
  flex: none;
  width: 96px; height: 96px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: conic-gradient(#fff 0 var(--pct, 0%), rgba(255,255,255,.25) var(--pct, 0%) 100%);
}
.pc-ring-none { background: rgba(255,255,255,.22); }
.pc-ring-in {
  width: 80px; height: 80px; border-radius: 50%;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  background: color-mix(in oklab, var(--card-accent, #06B6D4) 80%, #0F172A);
}
.pc-ring-val {
  font-family: var(--font-display);
  font-size: 22px; font-weight: 800; line-height: 1;
  font-variant-numeric: tabular-nums;
}
.pc-ring-lbl {
  margin-top: 2px;
  font-size: 7px; font-weight: 700; letter-spacing: 1px; opacity: .8;
}

/* The stat strip overlaps the header seam. */
.pc-strip {
  position: relative;
  display: grid; grid-template-columns: repeat(4, 1fr);
  margin: -44px 20px 0;
  background: var(--surface);
  border-radius: var(--radius-hero);
  padding: 18px 4px;
  box-shadow: 0 12px 32px rgba(6,182,212,.25);
  color: var(--text-1);
}
.pc-cell { text-align: center; border-right: 1px solid var(--border-2); }
.pc-cell:last-child { border-right: 0; }
.pc-cell-val {
  font-family: var(--font-display);
  font-size: 24px; font-weight: 700; line-height: 1;
  font-variant-numeric: tabular-nums;
}
.pc-cell-hi .pc-cell-val { color: var(--accent-ink); }
.pc-cell-lbl {
  margin-top: 1px;
  font-size: var(--fs-micro-sm); font-weight: 700; letter-spacing: 1.5px;
  color: var(--text-2);
}
.pc-cell-per { font-size: 10px; font-weight: 500; color: var(--text-3); }

.pc-badges {
  display: flex; flex-wrap: wrap; gap: 8px;
  padding: 16px 20px 0;
}
.pc-badge {
  background: var(--accent-soft); color: var(--accent-ink);
  border-radius: var(--radius-pill);
  padding: 7px 12px;
  font-size: 11px; font-weight: 700;
}
.pc-badge-of { opacity: .55; }
.pc-rank-note {
  margin: 10px 20px 0;
  font-size: 11px; line-height: 1.45; color: var(--text-3);
}

/* The save CTA. Gradient and glow exactly as specified; the LABEL is navy
   rather than white, for the same measured reason as every other accent pill —
   white on #06B6D4 is 2.43:1, navy is 7.35:1 and 5.28:1 at the far stop, so
   navy passes AA across the whole sweep without touching the fill. */
.pc-save-wrap { padding: 18px 20px 30px; }
/* ── Season join code ────────────────────────────────────────────
   The code is the whole point of the card, so it is the only thing set in the
   display face at size. Wide letter-spacing because this gets read aloud and
   copied off a screen by hand. */
.join-card {
  background: var(--accent-soft);
  border: 1.5px solid var(--accent-line);
  border-radius: var(--radius-card);
  padding: 18px;
}
.join-label {
  margin: 0;
  font-size: var(--fs-micro-sm); font-weight: 700;
  letter-spacing: 1.5px; text-transform: uppercase;
  color: var(--text-2);
}
.join-code {
  margin: 6px 0 10px;
  font-family: var(--font-display);
  font-weight: 800;
  /* Scaled, not fixed. At a flat 30px with 4px tracking the code measured 201px
     inside a 201px box on a 320px screen — fitting by luck, and one font-render
     away from breaking in the middle of a code somebody is reading aloud.
     Tracking is in em so it shrinks with the type rather than fighting it. */
  font-size: clamp(22px, 7vw, 30px);
  letter-spacing: 0.12em;
  /* 5.15:1 on the tint — the same pairing as a .pc-badge. */
  color: var(--accent-ink);
  /* Last-resort fallback if the clamp still is not enough on some device. */
  overflow-wrap: anywhere;
}
.join-hint { margin: 0 0 12px; font-size: 13px; line-height: 1.5; color: var(--text-2); }
.join-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 10px; }
.join-actions .btn { flex: 1 1 auto; min-width: 96px; }
/* Typed, not read: tabular figures and the same tracking as the code above, so
   what someone types looks like what they were given. */
.join-input {
  font-family: var(--font-display);
  font-size: 22px; font-weight: 700;
  letter-spacing: 3px; text-align: center;
  text-transform: uppercase;
}

/* Follow sits above the share CTA, secondary to it: sharing a card is the
   thing people came to this screen to do, and following is a quiet setting.
   Outlined rather than filled so the two never compete. */
.pc-follow {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%; margin-bottom: 10px;
  background: var(--surface);
  border: 1.5px solid var(--border);
  border-radius: var(--radius-pill);
  padding: 14px;
  font-family: inherit;
  font-size: 15px; font-weight: 600;
  color: var(--text-1);
  cursor: pointer; min-height: 44px;
  -webkit-tap-highlight-color: var(--tap-color);
}
.pc-follow:active { transform: scale(.99); }
@media (prefers-reduced-motion: reduce) { .pc-follow:active { transform: none; } }
/* Following is a state, not an action, so it reads as a filled-in chip. The
   tint/ink pairing is the same one first place uses on the leader boards:
   5.15:1 light, 8.35:1 dark. */
.pc-follow-on {
  background: var(--accent-soft);
  border-color: var(--accent-line);
  color: var(--accent-ink);
}

.pc-save {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%; border: 0;
  background: linear-gradient(135deg, #06B6D4, #0891B2);
  color: var(--dark);
  border-radius: var(--radius-pill);
  padding: 16px;
  font-family: var(--font-display);
  font-size: 15px; font-weight: 700;
  box-shadow: 0 8px 20px rgba(6,182,212,.35);
  cursor: pointer; min-height: 44px;
  -webkit-tap-highlight-color: var(--tap-color);
}
.pc-save:active { transform: scale(.98); }
@media (prefers-reduced-motion: reduce) { .pc-save:active { transform: none; } }
.pc-save[disabled] { opacity: .6; cursor: default; }

/* The card body below the full-bleed hero. */
.pc-below { padding-top: 18px; }

/* ══════════════════════════════════════════════════════════════════
   TEAM PAGE — mock 7a "Gradient hero"
   ------------------------------------------------------------------
   Supersedes the 5a team frame. Same hero language as the 6a player
   card, so nearly all of it is .pc-* reused with a tc-* modifier — the
   two screens are meant to read as the same object type, and sharing
   the classes is what makes that true rather than approximately true.

   The one real difference is the tint. .pc-hero already derives its
   gradient from --card-accent, so pointing that at the team's colour is
   the whole mechanism the handoff asks for: the mock's Huskies orange
   #F97316 -> #EA580C -> #C2410C is exactly what the existing
   color-mix chain produces from #F97316, with no per-team CSS.

   App chrome elsewhere stays cyan, which falls out for free: only this
   screen and the player card set --card-accent.
   ══════════════════════════════════════════════════════════════════ */

/* 36px, not the player card's 38 — team names run longer ("Hustlin'
   Huskies", "Golden State Warriors Legends") and the extra 2px is the
   difference between two lines and three. */
.tc-name { font-size: 36px; }

/* A single initial, so it can be larger than the player card's two-letter
   mark. Barely clipped, though: at 240px with right:-30px, 30px of a 145px
   glyph was outside the frame — a fifth of the letter — and an H reduced to
   two bars and a stub reads as abstract blocks rather than as an initial.
   Measured, then pulled back in. */
.tc-watermark { font-size: 215px; right: -8px; top: 10px; }

/* The Edit link on a team-coloured header. A light tint of the team's own
   accent, so it reads as belonging to this team rather than to the app —
   and it is a tint of white, so it works on every one of the ten team
   colours without a per-colour rule. */
.tc-edit { color: rgba(255,255,255,.85); min-width: 34px; }

/* nowrap per the spec: "1st of 5 in Beginner" broken across two lines
   inside a tilted sticker reads as a rendering fault. Uppercase to match the
   mock, which sets the label in caps. */
.tc-sticker { white-space: nowrap; text-transform: uppercase; }

/* The strip's shadow is tinted with the team colour rather than cyan. */
.tc-strip { box-shadow: 0 12px 32px color-mix(in oklab, var(--card-accent, #06B6D4) 40%, transparent); }

/* ── LAST 5 ──────────────────────────────────────────────────────
   26px rounded squares, not the circles used elsewhere: these are a
   sequence to be read left to right, and squares sit in a row without
   the gaps circles leave. */
.tc-form { padding: 16px 20px 0; }
.tc-form-head {
  display: flex; align-items: baseline; gap: 8px;
  margin-bottom: 8px;
}
.tc-form-row { display: flex; flex-wrap: wrap; gap: 6px; }
.tc-form-lbl {
  font-size: var(--fs-micro); font-weight: 700; letter-spacing: 1.5px;
  color: var(--text-3);
}
.tc-sq {
  display: flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border-radius: var(--radius-sm);
  font-family: var(--font-display);
  font-size: 11px; font-weight: 700;
}
/* The letter carries the result and the tint reinforces it, so this still
   reads in forced-colors mode and for a red/green-confusing reader. */
.tc-sq-w { background: var(--green-soft); color: #15803D; }
.tc-sq-l { background: var(--red-soft);   color: #B91C1C; }
.tc-sq-t { background: var(--surface-2);  color: var(--text-2); }
.tc-form-note { font-size: 10px; color: var(--text-faint); }

/* ── Leader row + head-to-head link card ─────────────────────────── */
.tc-leader, .tc-link-card {
  display: flex; align-items: center; gap: 12px;
  width: calc(100% - 40px);
  margin: 16px 20px 0;
  background: var(--surface);
  border: 0; border-radius: var(--radius-card);
  padding: 14px 16px;
  box-shadow: var(--shadow-sm);
  font-family: inherit; text-align: left;
  cursor: pointer; min-height: 44px;
  -webkit-tap-highlight-color: var(--tap-color);
}
.tc-leader:active, .tc-link-card:active { transform: scale(.985); }
@media (prefers-reduced-motion: reduce) {
  .tc-leader:active, .tc-link-card:active { transform: none; }
}
.tc-leader-av {
  flex: none;
  display: flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; border-radius: 50%;
  background: color-mix(in oklab, var(--card-accent, #06B6D4) 12%, #fff);
  color: color-mix(in oklab, var(--card-accent, #06B6D4) 72%, #0F172A);
  font-family: var(--font-display);
  font-size: 14px; font-weight: 700;
}
.tc-leader-body { flex: 1; min-width: 0; }
.tc-leader-name {
  display: block;
  font-size: var(--fs-body); font-weight: 600; color: var(--text-1);
}
.tc-leader-tag {
  margin-left: 8px;
  font-family: var(--font-display);
  font-size: var(--fs-micro); font-weight: 700;
  /* Mixed toward navy so it clears AA on white for every team colour, not
     just the dark half of the palette. */
  color: color-mix(in oklab, var(--card-accent, #06B6D4) 62%, #0F172A);
}
.tc-leader-meta {
  display: block;
  font-size: var(--fs-meta); color: var(--text-3); margin-top: 1px;
}

.tc-link-card { justify-content: space-between; margin-top: 12px; }
.tc-link-title {
  font-family: var(--font-display);
  font-size: 14px; font-weight: 700; color: var(--text-1);
}
.tc-link-more {
  font-size: var(--fs-meta); font-weight: 600;
  color: color-mix(in oklab, var(--card-accent, #06B6D4) 72%, #0F172A);
}

/* The CTA takes the team's gradient and glow. Navy label, for the measured
   reason every other accent pill has one: white on a light team colour
   fails, and navy passes on all ten. */
.tc-save {
  background: linear-gradient(135deg,
    var(--card-accent, #06B6D4),
    color-mix(in oklab, var(--card-accent, #06B6D4) 78%, #0F172A));
  box-shadow: 0 8px 20px color-mix(in oklab, var(--card-accent, #06B6D4) 50%, transparent);
}


/* ── The team tint on elements that default to cyan ───────────────
   .pc-sticker and .pc-cell-hi are shared with the 6a player card, where the
   accent IS cyan, so both hardcode --accent-ink. On a team page they have to
   follow the team instead: the handoff asks for PD and STREAK in
   team-accent-dark, and the sticker likewise. Mixed toward navy by the same
   62% the leader tag uses, which measured 5.86:1 at worst across all ten
   team colours. */
.tc-screen .pc-sticker,
.tc-screen .pc-cell-hi .pc-cell-val {
  color: color-mix(in oklab, var(--card-accent, #06B6D4) 62%, #0F172A);
}

/* The LAST 5 squares invert on the dark surface, exactly as the circle avatars
   do: --green-soft/--red-soft go dark, so the letter has to go light. Missed
   first time round because .tc-sq-* is a new class and the earlier correction
   only covered .gx-av-*. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .tc-sq-w { color: #6EE7A0; }
  :root:not([data-theme="light"]) .tc-sq-l { color: #FCA5A5; }
}
:root[data-theme="dark"] .tc-sq-w { color: #6EE7A0; }
:root[data-theme="dark"] .tc-sq-l { color: #FCA5A5; }

/* ── Leader cards ────────────────────────────────────────────────
   Four full-width row cards per board. The 2x2 these replace was meant
   to save height and cost 211px more of it over five boards, because
   grid-auto-rows:1fr raised every card in a board to match whichever
   name had wrapped in the narrow column.

   The card language is the player card's, minus its gradient: .pc-badge's
   tint for first place, .pc-cell-hi's accent-ink figure, .pc-cell-lbl's
   micro-label under it. The gradient itself does not survive the trip —
   white on #06B6D4 is 2.43:1, which .pc-name gets away with at 38px and a
   15px name would not. */
/* minmax(0, 1fr), not the implicit `auto` track: an auto track is floored at its
   content's min-content width, and at 320px that pushed the cards ~13px past the
   viewport and gave the whole page a horizontal scrollbar. */
.lead-list { display: grid; grid-template-columns: minmax(0, 1fr); gap: 8px; }
.lead-card {
  display: flex; flex-direction: row; align-items: center; gap: 10px;
  min-height: 62px;
  background: var(--surface);
  border: 0; border-radius: var(--radius-row);
  padding: 10px 14px;
  box-shadow: var(--shadow-sm);
  font-family: inherit; text-align: left;
  cursor: pointer;
  -webkit-tap-highlight-color: var(--tap-color);
}
.lead-card:active { transform: scale(.98); }
@media (prefers-reduced-motion: reduce) { .lead-card:active { transform: none; } }
/* First place takes the accent tint whole — the same soft/ink pairing as a
   .pc-badge, which is legible in both themes (5.15:1 light, 8.35:1 dark) where
   a navy card would have been 1.05:1 against the dark page. */
.lead-card-first {
  background: var(--accent-soft);
  box-shadow: var(--shadow-sm), inset 0 0 0 1.5px var(--accent-line);
}
.lead-card-first .lead-val { color: var(--accent-ink); }

.lead-rank {
  display: flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; border-radius: 50%;
  background: var(--surface-2);
  color: var(--text-2);
  font-family: var(--font-display);
  font-size: 12px; font-weight: 700;
  flex: none;
}
.lead-rank-first { background: var(--accent); color: var(--dark); }
.lead-card .team-dot { margin: 0; flex: none; }

/* flex:1 so this column claims the whole row minus the rank, dot and figure,
   rather than sizing to its own max-content: it is what gives the team line the
   full width to ellipsise into. min-width:0 so overflow is allowed to happen
   here and never pushes the figure off the card. */
.lead-id { flex: 1 1 auto; min-width: 0; }
.lead-name {
  display: block;
  font-size: 15px; font-weight: 600; line-height: 1.25;
  color: var(--text-1);
  overflow-wrap: anywhere;
}
.lead-team {
  display: block; margin-top: 1px;
  font-size: 11px; color: var(--text-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* No margin-left:auto: .lead-id growing already pushes this to the right edge,
   and an auto margin would take any spare width before flex-grow saw it. */
.lead-figure {
  display: flex; flex-direction: column; align-items: flex-end;
  flex: none;
  text-align: right;
}
.lead-val {
  font-family: var(--font-display);
  font-size: 22px; font-weight: 700; line-height: 1;
  color: var(--text-1);
  font-variant-numeric: tabular-nums;
}
/* .pc-cell-lbl's treatment, and its --text-2 with it: --text-3 is 2.56:1 on
   white, and this label carries the unit the number is meaningless without. */
.lead-per {
  margin-top: 4px;
  font-size: var(--fs-micro-sm); font-weight: 700;
  letter-spacing: 1.2px; text-transform: uppercase;
  color: var(--text-2);
  white-space: nowrap;
}

/* ── Icons ───────────────────────────────────────────────────────
   The set is inline SVG stroking currentColor, so an icon takes the
   colour of whatever it sits in and needs no dark-mode variant.

   vertical-align matters more than it looks: an inline <svg> sits on the
   text baseline by default, which hangs it below the line in every
   button that pairs an icon with a word ("Undo", "All games"). */
.ic {
  display: inline-block;
  vertical-align: -0.14em;
  flex: none;
}
/* In a flex row the icon is a sibling, not inline text, so the baseline
   nudge would push it off-centre instead. */
.gx-row-item .ic, .share-opt-icon .ic, .gx-btn .ic, .btn-remove .ic,
.load-tick .ic, .tc-leader .ic, .tc-link-card .ic, .gx-chev .ic,
.chevron .ic, .banner-chevron .ic, .stat-btn-icon .ic,
.gx-back .ic, .btn-back .ic, .empty-icon .ic {
  vertical-align: middle;
}
/* Empty-state icons were a 52px emoji; as strokes they need the muted
   colour the rest of the empty state uses, or they read as content. */
.empty-icon { color: var(--text-faint); line-height: 0; }
.empty-icon .ic { stroke-width: 1.4; }
/* The share-sheet rows sized their emoji with font-size; the SVG carries
   its own size, so the row just needs to stop reserving text space. */
.share-opt-icon { display: flex; align-items: center; line-height: 0; }
