/* Match Loop — app shell styles
   Original design system. Mobile-first. Dark navy + lime accent.
*/

:root {
  --bg: #0a1020;
  --bg-elev: #121a2e;
  --surface: #1a2440;
  --surface-2: #222e4f;
  --border: #2a3760;
  --border-soft: #1f2a4a;
  --text: #eef2fb;
  --text-dim: #aab4ce;
  --text-mute: #7585a3;
  --accent: #1668F0;
  --accent-2: #0CCB88;
  --accent-ink: #ffffff;
  --danger: #ff7a8c;
  --warn: #ffcc66;
  --ok: #2FD165;
  --info: #3B86F7;

  /* matchloop brand palette — exact values pulled from matchloop.app CSS.
     blue→sky→teal→green→lime loop, violet on the cool end. */
  --blue: #1668F0;
  --sky: #089DED;
  --teal: #0CCB88;
  --green: #2FD165;
  --lime: #C6EE1D;
  --violet: #6246EC;
  --ink: #0E1726;
  --slate: #5B6577;
  --mist: #F4F7FB;
  --line: #E6ECF4;
  /* Signature blue→green gradient for primary actions + brand moments. */
  --brand-grad: linear-gradient(100deg, #1668F0 0%, #0CCB88 60%, #2FD165 100%);
  /* Full landing "loop" gradient for hero/brand accents. */
  --brand-loop: linear-gradient(100deg, #6246EC, #1668F0 28%, #089DED 48%, #0CCB88 70%, #2FD165 84%, #C6EE1D);
  --brand-soft: linear-gradient(135deg, rgba(22,104,240,0.12), rgba(12,203,136,0.12) 60%, rgba(198,238,29,0.12));

  --radius-sm: 8px;
  --radius: 14px;
  --radius-lg: 20px;
  --radius-xl: 28px;

  --shadow-card: 0 1px 0 rgba(255,255,255,0.03) inset, 0 8px 24px rgba(0,0,0,0.25);
  --shadow-pop: 0 12px 40px rgba(0,0,0,0.5);
  --shadow-soft: 0 10px 30px rgba(0,0,0,0.35);

  --pad: 16px;
  --gap: 12px;

  --font-sans: 'Outfit', 'Manrope', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-display: 'Sora', 'Outfit', ui-sans-serif, system-ui, -apple-system, sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;
}

/* Brand display font (Sora) for prominent headings. */
.topbar .title,
.hero .name,
.section h2,
.brand-name { font-family: var(--font-display); }

[data-density="compact"] {
  --pad: 12px;
  --gap: 8px;
  --radius: 12px;
  --radius-lg: 16px;
}

/* Light is the default brand look — bright, airy, blue→green.
   Palette pulled from matchloop.app (mist bg, white cards, ink text,
   slate muted, line borders, blue accent, brand green for "ok"). */
[data-theme="light"] {
  --bg: #F4F7FB;          /* mist */
  --bg-elev: #ffffff;
  --surface: #ffffff;
  --surface-2: #EFF3F9;
  --border: #E6ECF4;      /* line */
  --border-soft: #EEF2F8;
  --text: #0E1726;        /* ink */
  --text-dim: #5B6577;    /* slate */
  --text-mute: #97A1B2;
  --accent: #1668F0;      /* blue */
  --accent-2: #0CCB88;    /* teal */
  --accent-ink: #ffffff;
  --ok: #17B267;          /* brand green, deepened for text legibility on white */
  --warn: #E8912A;
  --danger: #E5544B;
  --info: #1668F0;
  /* Layered, brand-tinted depth so cards lift off the mist instead of
     reading as flat white rectangles. */
  --shadow-card: 0 1px 2px rgba(14,23,38,0.05), 0 10px 28px rgba(22,40,80,0.09);
  --shadow-soft: 0 2px 6px rgba(14,23,38,0.06), 0 18px 40px rgba(22,40,80,0.14);
}

* { box-sizing: border-box; }
html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 15px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  min-height: 100%;
}
body {
  background:
    radial-gradient(1200px 600px at 80% -10%, rgba(22,104,240,0.10), transparent 60%),
    radial-gradient(800px 600px at -10% 100%, rgba(12,203,136,0.08), transparent 60%),
    var(--bg);
  min-height: 100vh;
}
/* Light (default) — soft blue→green wash for the airy brand feel. */
[data-theme="light"] body {
  background:
    radial-gradient(900px 520px at 82% -12%, rgba(22,104,240,0.10), transparent 60%),
    radial-gradient(760px 520px at -12% 108%, rgba(12,203,136,0.10), transparent 60%),
    var(--bg);
}

button { font-family: inherit; cursor: pointer; }
input, textarea, select { font-family: inherit; color: inherit; }

/* layout: mobile-first single column up to 720 then desktop framed
   The "app" sits in a phone-shaped column on desktop so it stays mobile-first,
   while taking the full viewport on actual phones. */

.app-root {
  width: 100%;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: stretch;
}

.app-frame {
  width: 100%;
  max-width: 100%;
  min-height: 100vh;
  background: var(--bg);
  display: flex;
  flex-direction: column;
  position: relative;
  overflow: hidden;
}

/* [bottomnav-fix] On mobile, give the frame a DEFINITE viewport height so the
   inner .scroll (flex:1, overflow-y:auto) scrolls internally and the sibling
   .bottomnav stays pinned to the bottom of the viewport on every screen.
   With the base min-height:100vh (a floor, not a fixed height), tall content
   grew the frame past the viewport, the page scrolled, and the nav dropped
   below the fold. 100dvh tracks the real visible viewport on iOS; min-height:0
   removes the 100vh floor so content can never push the frame taller. Desktop
   (>=880px) keeps its own phone-frame sizing; safe-area padding is untouched. */
@media (max-width: 879px) {
  /* [navbar-dvh · Ashli 2026-07-18] iOS Safari toolbar fix. body/.app-root used
     min-height:100vh — and `vh` on iOS is the LARGEST (toolbar-collapsed) viewport —
     so the root was taller than the .app-frame (100dvh, the CURRENT visible viewport).
     That extra strip sat BELOW the frame, and the sticky bottom nav (pinned to the
     frame's dvh bottom) appeared to "ride up" above an empty strip after a scroll/pull.
     Aligning the whole chain to dvh means nothing exceeds the visible viewport, so the
     nav stays flush to the real bottom as the toolbar collapses/expands. */
  html { min-height: 100dvh; }
  body { min-height: 100dvh; }
  .app-root { min-height: 100dvh; }
  .app-frame {
    height: 100dvh;
    min-height: 0;
  }
  /* [guest-scroll] The PUBLIC guest response page (real opponents, mobile Safari)
     has NO pinned .bottomnav — its "Send response" button is inline at the end of
     the form. So it must NOT inherit the captain app's fixed 100dvh + overflow:hidden
     frame, which CLIPS the form's bottom (Send button unreachable) — worse under
     Safari's collapsing URL bar. Let the guest page flow as a normal scrolling
     document sized by dvh (not the 100vh trap) with safe-area padding, so the whole
     form incl. Send stays visible + tappable. */
  .app-frame.guest-flow {
    height: auto;
    min-height: 100dvh;
    overflow: visible;
    padding-bottom: calc(28px + env(safe-area-inset-bottom));
  }
}

/* on desktop, show a phone-shaped column for the captain & player roles */
@media (min-width: 880px) {
  .app-root {
    padding: 32px 16px 80px;
    background:
      radial-gradient(900px 600px at 85% -5%, rgba(22,104,240,0.14), transparent 60%),
      radial-gradient(800px 600px at 0% 105%, rgba(12,203,136,0.14), transparent 60%),
      linear-gradient(180deg, #EAF1FB 0%, #EAF7F1 100%);
  }
  .app-root .app-frame[data-role="captain"],
  .app-root .app-frame[data-role="player"] {
    max-width: 440px;
    border-radius: 28px;
    border: 1px solid var(--border-soft);
    box-shadow: 0 30px 80px rgba(22,40,80,0.18), 0 0 0 1px rgba(255,255,255,0.6) inset;
    margin: 0 auto;
    min-height: 880px;
    max-height: calc(100vh - 64px);
  }
}

/* Role switcher (devtool, persistent above app) */
.role-switcher {
  position: fixed;
  /* [safe-area] Clear the notch on notched iOS (dev "View as" control). */
  top: calc(12px + env(safe-area-inset-top));
  left: 50%;
  transform: translateX(-50%);
  background: rgba(20, 28, 56, 0.85);
  backdrop-filter: blur(12px);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 4px;
  display: flex;
  gap: 2px;
  z-index: 40;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.02em;
}
.role-switcher button {
  background: transparent;
  border: 0;
  color: var(--text-dim);
  padding: 6px 12px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.02em;
}
.role-switcher button.active {
  background: var(--accent);
  color: var(--accent-ink);
}

/* Top bar */
.topbar {
  display: flex;
  align-items: center;
  gap: 12px;
  /* [safe-area] Pad the top header below the notch/status bar on notched iOS.
     env() resolves to 0 on desktop/non-notched, so layout there is unchanged. */
  padding: calc(18px + env(safe-area-inset-top)) var(--pad) 14px;
  border-bottom: 1px solid var(--border-soft);
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--bg);
}
.topbar .back {
  width: 36px;
  height: 36px;
  display: grid;
  place-items: center;
  border-radius: 12px;
  background: var(--surface);
  border: 1px solid var(--border-soft);
  color: var(--text);
}
.topbar .title {
  font-weight: 700;
  font-size: 17px;
  letter-spacing: -0.01em;
  flex: 1;
}
.topbar .sub {
  font-size: 12px;
  color: var(--text-mute);
  font-weight: 500;
  margin-top: 2px;
}
.topbar .action {
  background: transparent;
  border: 0;
  color: var(--accent);
  font-weight: 700;
  font-size: 14px;
  padding: 8px 4px;
}

/* Scrolling content area */
.scroll {
  flex: 1;
  overflow-y: auto;
  /* [item-4b · Ashli 2026-07-18] Was 120px — a legacy fixed reserve from a
     position:fixed footer era. `.bottomnav` is now a STICKY FLEX SIBLING (in-flow,
     below the scroll), so it never overlaps scroll content and no large reserve is
     needed. The 120px was pure dead scrollable space below the last content (the
     "dead space below Cancel"). MEASURED: the dvh nav chain is correct (html/body/
     app-root/frame all = innerHeight, not over-reserving) — this padding was the
     source. Trimmed to a small buffer; the footer's own safe-area padding remains. */
  padding-bottom: 24px;
  -webkit-overflow-scrolling: touch;
}

/* [polish-1] Makeup "View as opponent" preview sheet overlay. On phones it must
   pin to the VIEWPORT (fixed) — it renders inside a tall scroll body, so the old
   `absolute` anchored to the scrolled document and dropped the bottom-sheet
   off-screen (clipped mid-content). On desktop (≥880px) the app is a centered
   phone-frame, where the original frame-scoped `absolute` is correct and unchanged. */
.mk-sheet-overlay { position: fixed; }
@media (min-width: 880px) { .mk-sheet-overlay { position: absolute; } }

/* Bottom nav (captain/player) */
.bottomnav {
  position: sticky;
  bottom: 0;
  background: linear-gradient(180deg, color-mix(in oklab, var(--bg) 0%, transparent) 0%, var(--bg) 30%);
  padding: 16px var(--pad) calc(16px + env(safe-area-inset-bottom));
  display: flex;
  gap: 8px;
  z-index: 5;
}
.bottomnav .nav-item {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  background: transparent;
  border: 0;
  color: var(--text-mute);
  font-size: 11px;
  font-weight: 600;
  padding: 8px 0;
}
.bottomnav .nav-item.active { color: var(--accent); }

/* Buttons */
.btn {
  border: 0;
  background: var(--brand-grad);
  color: #ffffff;
  font-weight: 700;
  font-size: 15px;
  padding: 14px 20px;
  border-radius: 999px;
  letter-spacing: -0.005em;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  transition: transform 0.06s ease, opacity 0.15s ease, filter 0.15s ease;
}
.btn:hover { filter: brightness(1.06) saturate(1.04); }
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: 0.45; cursor: not-allowed; }
.btn.block { width: 100%; }
.btn.secondary {
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
}
.btn.secondary:hover { background: var(--surface-2); }
.btn.ghost {
  background: transparent;
  color: var(--text-dim);
}
.btn.ghost:hover { color: var(--text); }
.btn.danger {
  background: transparent;
  color: var(--danger);
  border: 1px solid color-mix(in oklab, var(--danger) 30%, transparent);
}
.btn.sm { font-size: 13px; padding: 8px 14px; }

/* Cards */
.card {
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
  padding: var(--pad);
  box-shadow: var(--shadow-card);
}
.card.tight { padding: 12px; }
.card.flat { box-shadow: none; }

.section {
  padding: 20px var(--pad);
}
.section .label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-mute);
  margin-bottom: 10px;
}
.section h2 {
  margin: 0 0 14px;
  font-size: 20px;
  font-weight: 700;
  letter-spacing: -0.015em;
}
.stack { display: flex; flex-direction: column; gap: var(--gap); }
.row { display: flex; gap: var(--gap); align-items: center; }
.row.between { justify-content: space-between; }

/* Pills / badges */
.pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--surface-2);
  border: 1px solid var(--border-soft);
  color: var(--text-dim);
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  white-space: nowrap;
}
.pill .dot { width: 6px; height: 6px; border-radius: 999px; background: currentColor; }
.pill.accent { background: color-mix(in oklab, var(--accent) 18%, transparent); color: var(--accent); border-color: color-mix(in oklab, var(--accent) 30%, transparent); }
.pill.warn { color: var(--warn); border-color: color-mix(in oklab, var(--warn) 35%, transparent); background: color-mix(in oklab, var(--warn) 14%, transparent); }
.pill.ok { color: var(--ok); border-color: color-mix(in oklab, var(--ok) 35%, transparent); background: color-mix(in oklab, var(--ok) 12%, transparent); }
.pill.danger { color: var(--danger); border-color: color-mix(in oklab, var(--danger) 35%, transparent); background: color-mix(in oklab, var(--danger) 12%, transparent); }
.pill.muted { background: transparent; }

/* Match card */
.match-card {
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  text-align: left;
  width: 100%;
  color: var(--text);
  transition: border-color 0.15s ease, transform 0.06s ease;
}
.match-card:hover { border-color: var(--border); }
.match-card:active { transform: scale(0.998); }
.match-card .title { font-weight: 700; font-size: 16px; letter-spacing: -0.01em; }
.match-card .meta { color: var(--text-dim); font-size: 13px; }
.match-card .head { display: flex; justify-content: space-between; align-items: flex-start; gap: 8px; }

/* Date option chips */
.date-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 10px;
}
.date-opt {
  text-align: left;
  background: var(--surface);
  border: 1.5px solid var(--border-soft);
  border-radius: var(--radius);
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  color: var(--text);
  transition: border-color 0.15s, background 0.15s;
  position: relative;
}
.date-opt:hover { border-color: var(--border); }
.date-opt.selected {
  border-color: var(--accent);
  background: color-mix(in oklab, var(--accent) 8%, var(--surface));
}
.date-opt.selected::after {
  content: '';
  position: absolute;
  top: 8px;
  right: 8px;
  width: 18px;
  height: 18px;
  border-radius: 999px;
  background: var(--accent);
  background-image: linear-gradient(135deg, transparent 35%, var(--accent-ink) 35% 45%, transparent 45%, transparent 55%, var(--accent-ink) 55% 65%, transparent 65%);
}
.date-opt .dow { font-size: 11px; color: var(--text-mute); text-transform: uppercase; letter-spacing: 0.08em; font-weight: 700; }
.date-opt .day { font-size: 22px; font-weight: 800; letter-spacing: -0.02em; line-height: 1; }
.date-opt .time { font-size: 13px; color: var(--text-dim); font-weight: 600; }
.date-opt .courts { font-size: 11px; color: var(--text-mute); margin-top: 2px; font-family: var(--font-mono); }

/* Inputs */
.field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.field > label {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--text-mute);
  text-transform: uppercase;
}
.input, .textarea, .select {
  background: var(--surface);
  border: 1px solid var(--border-soft);
  color: var(--text);
  border-radius: var(--radius);
  padding: 12px 14px;
  /* 16px min so iOS/WKWebView never auto-zooms the page on input focus. */
  font-size: 16px;
  font-family: inherit;
  outline: none;
  transition: border-color 0.15s;
  width: 100%;
}
.input:focus, .textarea:focus, .select:focus {
  border-color: var(--accent);
}
.textarea { min-height: 80px; resize: vertical; }

/* iOS/WKWebView blows up native <input type="date">: with the default
   -webkit-appearance and width:100% the control's value box (and the inline
   picker anchored to it) inflates to near full-screen on device, while Safari
   renders it normally. Reset the appearance and constrain the inner
   value/edit pseudo-elements so the field matches other .input fields. */
input[type="date"] {
  -webkit-appearance: none;
  appearance: none;
  min-height: 0;
}
input[type="date"]::-webkit-date-and-time-value {
  margin: 0;
  text-align: left;
}
input[type="date"]::-webkit-datetime-edit {
  padding: 0;
}

/* Scrolling time picker — hide native scrollbar on webkit so the wheel
   reads cleanly. Firefox + IE handled inline via scrollbar-width/msOverflowStyle. */
.time-wheel-scroller::-webkit-scrollbar { display: none; }

/* Loading spinner */
.spinner {
  display: inline-block;
  width: 14px; height: 14px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 999px;
  animation: spin 0.7s linear infinite;
  vertical-align: -2px;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* Player roster row */
.player-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 0;
  border-bottom: 1px solid var(--border-soft);
}
.player-row:last-child { border-bottom: 0; }
.avatar {
  width: 36px; height: 36px;
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--text-dim);
  display: grid;
  place-items: center;
  font-weight: 700;
  font-size: 13px;
  letter-spacing: 0.02em;
  flex-shrink: 0;
}
.player-row .name { font-weight: 600; flex: 1; font-size: 14px; }
.player-row .status { font-size: 11px; color: var(--text-mute); }

/* Tally bar */
.tally {
  display: flex;
  height: 8px;
  border-radius: 999px;
  overflow: hidden;
  background: var(--surface-2);
  border: 1px solid var(--border-soft);
}
.tally span { display: block; height: 100%; }
.tally .seg-yes { background: var(--accent); }
.tally .seg-mb { background: var(--warn); }
.tally .seg-no { background: var(--danger); }

/* Stat grid (used in rules details) */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 12px;
}
.stat {
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  padding: 14px 16px;
}
.stat .v { font-size: 24px; font-weight: 800; letter-spacing: -0.02em; }
.stat .k { font-size: 11px; color: var(--text-mute); text-transform: uppercase; letter-spacing: 0.08em; font-weight: 700; margin-top: 4px; }

/* Toast */
.toast {
  position: fixed;
  left: 50%;
  /* [safe-area] Keep the toast clear of the home indicator on notched iOS. */
  bottom: calc(32px + env(safe-area-inset-bottom));
  transform: translateX(-50%);
  background: var(--accent);
  color: var(--accent-ink);
  font-weight: 700;
  padding: 12px 20px;
  border-radius: 999px;
  z-index: 60;
  box-shadow: 0 12px 30px rgba(0,0,0,0.35);
  display: flex;
  align-items: center;
  gap: 8px;
  animation: toastIn 0.3s cubic-bezier(0.2, 0.9, 0.3, 1.2);
}
@keyframes toastIn {
  from { opacity: 0; transform: translate(-50%, 20px); }
  to { opacity: 1; transform: translate(-50%, 0); }
}

/* Logo */
.logo-mark {
  width: 32px; height: 32px;
  border-radius: 50%;
  background: var(--accent);
  display: grid;
  place-items: center;
  position: relative;
  overflow: hidden;
  flex-shrink: 0;
}
.logo-mark::before, .logo-mark::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 1.5px solid var(--accent-ink);
  border-color: var(--accent-ink) transparent transparent var(--accent-ink);
  transform: rotate(-25deg);
  opacity: 0.85;
}
.logo-mark::after {
  transform: rotate(155deg);
}
.brand-row { display: flex; align-items: center; gap: 10px; }
.brand-row .brand-dark { display: inline-flex; align-items: center; gap: 10px; }
.brand-name { font-weight: 800; letter-spacing: -0.02em; font-size: 17px; }
.brand-name b { color: var(--accent); font-weight: 800; }

/* Lock the logo to its native colors. The PNG has the metallic infinity +
   navy ground + lime tennis ball + lime wordmark accent baked in — we want
   the browser to render those pixels exactly, with no filter/invert/blend
   side effects from ancestor styles, and with a high-quality downscale so
   the navy strokes don't dissolve into the highlights at small sizes. */
.brand-mark {
  filter: none !important;
  -webkit-filter: none !important;
  mix-blend-mode: normal !important;
  opacity: 1 !important;
  display: block;
  /* Use the browser's smooth high-quality downscaler. The old
     -webkit-optimize-contrast value sharpened/crunched the gradient PNG and
     made it read cheap; "auto" matches how matchloop.app renders the same
     logo.png (height:40px, width:auto) — crisp at any size below source. */
  image-rendering: auto;
  forced-color-adjust: none;
  print-color-adjust: exact;
  -webkit-print-color-adjust: exact;
}

/* Swap brand mark by theme — light mode uses the raster logo (with "match loop" wordmark baked in),
   dark mode uses the SVG + neon wordmark for contrast. */
[data-theme="light"] .brand-row .brand-dark { display: none !important; }
[data-theme="light"] .brand-row .brand-light { display: inline-block !important; }

/* Hero header (captain dash) */
.hero {
  padding: 24px var(--pad) 20px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.hero .greeting {
  font-size: 13px;
  color: var(--text-mute);
  font-weight: 600;
  letter-spacing: 0.01em;
}
.hero .name {
  font-size: 26px;
  font-weight: 800;
  letter-spacing: -0.02em;
}

/* Alert/banner */
.banner {
  background: linear-gradient(180deg, color-mix(in oklab, var(--accent) 18%, transparent), color-mix(in oklab, var(--accent) 6%, transparent));
  border: 1px solid color-mix(in oklab, var(--accent) 35%, transparent);
  border-radius: var(--radius-lg);
  padding: 14px 16px;
  display: flex;
  gap: 12px;
  align-items: flex-start;
}
.banner.warn {
  background: linear-gradient(180deg, color-mix(in oklab, var(--warn) 18%, transparent), color-mix(in oklab, var(--warn) 6%, transparent));
  border-color: color-mix(in oklab, var(--warn) 35%, transparent);
}
.banner .icon-wrap {
  width: 36px; height: 36px;
  border-radius: 10px;
  background: var(--accent);
  color: var(--accent-ink);
  display: grid; place-items: center;
  flex-shrink: 0;
}
.banner.warn .icon-wrap { background: var(--warn); color: #2a1a00; }
.banner .ttl { font-weight: 700; font-size: 14px; margin-bottom: 2px; }
.banner .body { font-size: 13px; color: var(--text-dim); line-height: 1.45; }

/* slot row in confirm view */
.slot-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 0;
  border-bottom: 1px solid var(--border-soft);
}
.slot-row:last-child { border-bottom: 0; }
.slot-row .when { flex: 1; }
.slot-row .when b { display: block; font-size: 14px; font-weight: 700; }
.slot-row .when span { font-size: 12px; color: var(--text-mute); }
.slot-row .count {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-dim);
}

/* response squares
   -----------------------------------------------------------------
   The poll grid lives inside a `.resp-grid-scroll` wrapper so that
   when there are 4+ proposed makeup dates the date columns scroll
   horizontally instead of overflowing off-screen. Each row sets its
   own `--date-cols` inline so the header + all player rows share the
   exact same column template and stay aligned while scrolling.

   The player name column is sticky-left so it stays readable while
   the captain scrolls dates on mobile.
   ----------------------------------------------------------------- */
.resp-grid-scroll {
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
  /* keep a hint of the next date visible so users notice the scroll */
  scroll-padding-right: 24px;
  /* [polish-v2 · scroll affordance] Overflow-AWARE right-edge fade (pure CSS, no JS):
     a soft "there's more →" gradient that shows ONLY while the grid can scroll right
     and hides itself at the end / when everything fits. Two layers at the right edge —
     a SHADOW pinned to the viewport (scroll-attached, always drawn) and a SURFACE COVER
     pinned to the CONTENT's right edge (local-attached) that slides over the shadow once
     you reach the end. Paired with the partial next-column peek (fixed date columns), the
     scroll is self-explanatory to players AND captains. */
  background:
    linear-gradient(to left, var(--surface) 42%, transparent) right center / 30px 100% no-repeat,
    linear-gradient(to left, color-mix(in oklab, var(--text) 13%, transparent), transparent) right center / 20px 100% no-repeat;
  background-attachment: local, scroll;
}
.resp-grid-scroll::-webkit-scrollbar { height: 6px; }
.resp-grid-scroll::-webkit-scrollbar-thumb {
  background: var(--border-soft);
  border-radius: 999px;
}
.resp-grid-scroll::-webkit-scrollbar-track { background: transparent; }

.resp-grid {
  display: grid;
  /* [polish-v2 · Ashli ballot 2026-07-17] FULL NAMES, never truncated, at any date
     count. The name column floor is `--name-col` (set per-grid = the longest first
     name + orig badge; see ResponseGrid). minmax(var(--name-col), 1fr): the name never
     shrinks below its content (no "Cat…"/"He…") AND grows to fill leftover when dates
     are few — and because every row uses the SAME `--name-col`, the columns stay
     aligned (a per-row max-content would misalign). The DATE columns are now a FIXED
     48px (pill + "Sat/9/Both" header): they never compress — extra dates overflow and
     the `.resp-grid-scroll` wrapper scrolls horizontally (name column sticky-left). */
  grid-template-columns:
    [name] minmax(var(--name-col, 120px), 1fr)
    [dates] repeat(var(--date-cols, 3), 48px);
  gap: 6px 8px;
  align-items: center;
  width: 100%;
}
.resp-grid .name-cell {
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--surface);
  /* fade-out to hint at scrollable content beneath */
  padding-right: 8px;
  min-width: 0;
}
/* On player rows the sticky name cell needs to cover the row border
   peek-through cleanly. The card bg is --surface so this matches. */
.resp-grid .name-cell .name {
  /* [polish-v2] Full names — no ellipsis truncation. One line (the column is sized to
     fit the longest name via --name-col, so nothing needs to be clipped). */
  white-space: nowrap;
}
.resp-grid .name { font-size: 13px; font-weight: 600; }
.resp-grid .cell {
  width: 28px; height: 28px;
  /* Fixed-size pill centered in its (now fluid) column so rows stay aligned. */
  justify-self: center;
  border-radius: 8px;
  display: grid; place-items: center;
  font-size: 11px;
  font-weight: 700;
  border: 1px solid var(--border-soft);
  background: var(--surface-2);
  color: var(--text-mute);
}
/* [makeup-partial] On very narrow phones with several proposed dates, shrink
   the cells/gap a touch so the fluid columns still hold a centered pill without
   forcing a horizontal scroll — keeping the phone render matched to desktop. */
@media (max-width: 380px) {
  .resp-grid { column-gap: 5px; }
  .resp-grid .cell { width: 24px; height: 24px; font-size: 10px; }
}
.resp-grid .cell.yes { background: color-mix(in oklab, var(--accent) 25%, var(--surface)); color: var(--accent); border-color: color-mix(in oklab, var(--accent) 40%, transparent); }
.resp-grid .cell.no { background: color-mix(in oklab, var(--danger) 18%, var(--surface)); color: var(--danger); border-color: color-mix(in oklab, var(--danger) 30%, transparent); }
.resp-grid .cell.mb { background: color-mix(in oklab, var(--warn) 18%, var(--surface)); color: var(--warn); border-color: color-mix(in oklab, var(--warn) 30%, transparent); }
/* Button form of cell (captain-tappable in poll grid) — match div styling */
button.cell {
  font: inherit; font-size: 11px; font-weight: 700;
  padding: 0; margin: 0; line-height: 1;
  transition: transform 80ms ease, box-shadow 120ms ease;
}
button.cell:hover { transform: translateY(-1px); box-shadow: 0 2px 6px color-mix(in oklab, var(--text) 12%, transparent); }
button.cell:active { transform: translateY(0); }
button.cell:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Hide scrollbar on mobile */
.scroll::-webkit-scrollbar { display: none; }
.scroll { scrollbar-width: none; }

/* utilities */
.muted { color: var(--text-mute); }
.dim { color: var(--text-dim); }
.mono { font-family: var(--font-mono); }
.tnum { font-variant-numeric: tabular-nums; }
.hr { height: 1px; background: var(--border-soft); border: 0; margin: 8px 0; }

/* Skeleton tennis-ball icon (svg currentColor) */
.skel-icon { width: 1em; height: 1em; flex-shrink: 0; }

/* =====================================================================
   DEMO-MODE BAR — persistent across all screens in the prototype build.
   Lets reviewers jump between Sign Up / Captain / Player / Opponent
   Captain without losing context or having to refresh. Production build
   strips both this CSS block and the React component that renders it.
   ===================================================================== */
.demo-bar {
  position: sticky;
  top: 0;
  z-index: 60;
  /* [safe-area] Clear the notch on notched iOS (demo-mode banner). */
  padding-top: env(safe-area-inset-top);
  background: color-mix(in oklab, var(--info) 14%, var(--bg) 86%);
  border-bottom: 1px solid color-mix(in oklab, var(--info) 28%, transparent);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.demo-bar-inner {
  max-width: 1180px;
  margin: 0 auto;
  padding: 7px 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  flex-wrap: wrap;
}
.demo-bar-tag {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: color-mix(in oklab, var(--info) 75%, var(--text) 25%);
  white-space: nowrap;
}
.demo-bar-dot {
  width: 7px;
  height: 7px;
  border-radius: 999px;
  background: var(--info);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--info) 25%, transparent);
  animation: demo-pulse 2.4s ease-in-out infinite;
}
@keyframes demo-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.45; }
}
.demo-pill {
  display: inline-flex;
  align-items: stretch;
  gap: 2px;
  padding: 3px;
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: 999px;
  box-shadow: 0 1px 0 rgba(255,255,255,0.02) inset;
  max-width: 100%;
  overflow-x: auto;
  scrollbar-width: none;
}
.demo-pill::-webkit-scrollbar { display: none; }
.demo-opt {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: transparent;
  border: 0;
  color: var(--text-mute);
  padding: 7px 12px;
  border-radius: 999px;
  cursor: pointer;
  font: inherit;
  font-size: 12px;
  font-weight: 700;
  white-space: nowrap;
  transition: color 0.15s, background 0.15s, transform 0.06s;
}
.demo-opt:hover:not(.active) { color: var(--text); background: var(--surface-2); }
.demo-opt:active { transform: scale(0.97); }
.demo-opt.active {
  background: var(--accent);
  color: var(--accent-ink);
  box-shadow: 0 1px 6px color-mix(in oklab, var(--accent) 30%, transparent);
}
.demo-opt .demo-opt-label { display: inline-block; }
@media (max-width: 540px) {
  .demo-bar-inner { padding: 6px 8px; gap: 8px; }
  .demo-bar-tag { font-size: 9px; letter-spacing: 0.1em; }
  .demo-opt { padding: 6px 10px; font-size: 11px; }
}

/* =====================================================================
   View-as toggle (Captain / Player demo switcher)
   Sits above the app frame as a thin centered pill. Subtle on purpose —
   it's a dev/demo affordance, not part of the product chrome.
   ===================================================================== */
.viewas-bar {
  display: flex;
  justify-content: center;
  padding: 10px var(--pad) 8px;
  background: var(--bg);
}
@media (min-width: 880px) {
  .viewas-bar {
    padding: 0 0 12px;
    background: transparent;
  }
}
.viewas-pill {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 3px;
  background: color-mix(in oklab, var(--surface) 90%, var(--bg));
  border: 1px solid var(--border-soft);
  border-radius: 999px;
  box-shadow: 0 1px 0 rgba(255,255,255,0.02) inset;
}
.viewas-opt {
  background: transparent;
  border: 0;
  color: var(--text-mute);
  padding: 6px 16px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.02em;
  border-radius: 999px;
  cursor: pointer;
  transition: background 0.15s, color 0.15s, transform 0.06s;
  min-width: 80px;
}
.viewas-opt:hover:not(.active) { color: var(--text); }
.viewas-opt:active { transform: scale(0.98); }
.viewas-opt.active {
  background: var(--accent);
  color: var(--accent-ink);
  box-shadow: 0 1px 6px color-mix(in oklab, var(--accent) 30%, transparent);
}
.viewas-reset {
  width: 24px;
  height: 24px;
  margin-left: 4px;
  border-radius: 999px;
  background: var(--surface-2);
  border: 0;
  color: var(--text-mute);
  display: grid;
  place-items: center;
  cursor: pointer;
  transition: color 0.15s, background 0.15s;
}
.viewas-reset:hover { color: var(--text); background: var(--surface); }

.matchday-panel {
  background:
    linear-gradient(180deg, color-mix(in oklab, var(--accent) 18%, var(--surface)) 0%, var(--surface) 80%);
  border: 1px solid color-mix(in oklab, var(--accent) 45%, var(--border-soft));
  border-radius: var(--radius-lg);
  padding: 16px;
  margin: 16px var(--pad) 0;
  position: relative;
  overflow: hidden;
}
.matchday-panel::before {
  content: '';
  position: absolute;
  inset: 0;
  background:
    radial-gradient(400px 200px at 90% -20%, color-mix(in oklab, var(--accent) 35%, transparent), transparent 60%);
  pointer-events: none;
}
.matchday-header {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  position: relative;
}
.matchday-pulse {
  width: 12px;
  height: 12px;
  border-radius: 999px;
  background: var(--accent);
  margin-top: 6px;
  box-shadow: 0 0 0 0 color-mix(in oklab, var(--accent) 60%, transparent);
  animation: mdpulse 2s ease-out infinite;
  flex-shrink: 0;
}
@keyframes mdpulse {
  0% { box-shadow: 0 0 0 0 color-mix(in oklab, var(--accent) 70%, transparent); }
  70% { box-shadow: 0 0 0 14px color-mix(in oklab, var(--accent) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in oklab, var(--accent) 0%, transparent); }
}
.matchday-eyebrow {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent);
}
.matchday-title {
  font-weight: 800;
  font-size: 19px;
  letter-spacing: -0.015em;
  margin-top: 2px;
  color: var(--text);
}
.matchday-meta {
  color: var(--text-dim);
  font-size: 12px;
  margin-top: 2px;
}

/* arrival progress */
.matchday-progress {
  margin-top: 14px;
  position: relative;
}
.matchday-progress-track {
  height: 6px;
  border-radius: 999px;
  background: var(--surface-2);
  border: 1px solid var(--border-soft);
  overflow: hidden;
  position: relative;
  display: flex;
}
.matchday-progress-fill {
  height: 100%;
  background: var(--accent);
  transition: width 0.4s ease;
}
.matchday-progress-eta {
  height: 100%;
  background: var(--warn);
  opacity: 0.7;
  transition: width 0.4s ease;
}
.matchday-progress-row {
  display: flex;
  gap: 8px;
  margin-top: 6px;
  font-size: 11px;
  font-weight: 700;
  color: var(--text);
}
.matchday-progress-row b { color: var(--text); }
.matchday-progress-row .warn { color: var(--warn); }
.matchday-progress-row .danger { color: var(--danger); }
.matchday-progress-row .muted { color: var(--text-mute); }

/* arrival roster strip */
.matchday-roster {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  margin-top: 12px;
  cursor: pointer;
}
.matchday-roster-more {
  display: inline-flex;
  align-items: center;
  padding: 4px 10px;
  border-radius: 999px;
  background: var(--surface-2);
  font-size: 11px;
  font-weight: 700;
  color: var(--text-dim);
}
.matchday-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 8px 3px 3px;
  border-radius: 999px;
  background: var(--surface-2);
  border: 1px solid var(--border-soft);
  font-size: 11px;
  font-weight: 700;
  color: var(--text-dim);
  position: relative;
}
.matchday-chip .matchday-chip-name { white-space: nowrap; }
.matchday-chip .matchday-chip-mark {
  width: 14px;
  height: 14px;
  display: grid;
  place-items: center;
  border-radius: 999px;
}
.matchday-chip.arr-arrived {
  background: color-mix(in oklab, var(--accent) 18%, var(--surface));
  border-color: color-mix(in oklab, var(--accent) 35%, transparent);
  color: var(--accent);
}
.matchday-chip.arr-arrived .matchday-chip-mark { background: var(--accent); color: var(--accent-ink); }
.matchday-chip.arr-eta {
  background: color-mix(in oklab, var(--warn) 16%, var(--surface));
  border-color: color-mix(in oklab, var(--warn) 35%, transparent);
  color: var(--warn);
}
.matchday-chip.arr-eta .matchday-chip-mark { background: var(--warn); color: #2a1a00; }
.matchday-chip.arr-no-show {
  background: color-mix(in oklab, var(--danger) 14%, var(--surface));
  border-color: color-mix(in oklab, var(--danger) 35%, transparent);
  color: var(--danger);
}
.matchday-chip.arr-no-show .matchday-chip-mark { background: var(--danger); color: white; }

/* matchday quick actions */
.matchday-actions {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
  margin-top: 14px;
  position: relative;
}
.matchday-action {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px;
  border-radius: var(--radius);
  background: var(--surface);
  border: 1px solid var(--border-soft);
  color: var(--text);
  font-weight: 700;
  font-size: 13px;
  text-align: left;
  transition: border-color 0.15s ease, transform 0.06s ease, background 0.15s ease;
}
.matchday-action:hover:not(:disabled):not(.is-disabled) {
  border-color: color-mix(in oklab, var(--accent) 50%, var(--border-soft));
  background: color-mix(in oklab, var(--accent) 6%, var(--surface));
}
.matchday-action:active:not(:disabled):not(.is-disabled) { transform: scale(0.98); }
.matchday-action:disabled,
.matchday-action.is-disabled { opacity: 0.4; cursor: not-allowed; }
.matchday-action.primary {
  background: var(--accent);
  color: var(--accent-ink);
  border-color: var(--accent);
}
.matchday-action.primary:hover:not(:disabled) {
  background: var(--accent-2);
}
.matchday-action-icon {
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: 8px;
  background: color-mix(in oklab, var(--accent) 18%, var(--surface-2));
  color: var(--accent);
  flex-shrink: 0;
}
.matchday-action.primary .matchday-action-icon {
  background: color-mix(in oklab, var(--accent-ink) 20%, transparent);
  color: var(--accent-ink);
}
.matchday-action-label { line-height: 1.2; }

/* =====================================================================
   Sheets (Day-of Mode + Scorecard sub-flows)
   ===================================================================== */
.md-sheet {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: stretch;
  justify-content: stretch;
}
.md-sheet-bg {
  position: absolute;
  inset: 0;
  background: rgba(5, 8, 16, 0.6);
  backdrop-filter: blur(4px);
}
.md-sheet-card {
  position: relative;
  flex: 1;
  background: var(--bg);
  display: flex;
  flex-direction: column;
  max-height: 100vh;
  animation: sheetIn 0.25s ease;
}
@media (min-width: 880px) {
  .md-sheet { align-items: center; justify-content: center; }
  .md-sheet-card {
    flex: 0 0 auto;
    width: 440px;
    max-height: 85vh;
    border-radius: 28px;
    overflow: hidden;
    border: 1px solid var(--border);
    box-shadow: 0 30px 80px rgba(0,0,0,0.5);
  }
}
@keyframes sheetIn {
  from { transform: translateY(20px); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}
.md-sheet-head {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 18px var(--pad) 14px;
  border-bottom: 1px solid var(--border-soft);
}
.md-sheet-close {
  width: 36px; height: 36px;
  border-radius: 12px;
  background: var(--surface);
  border: 1px solid var(--border-soft);
  color: var(--text);
  display: grid;
  place-items: center;
  flex-shrink: 0;
}
.md-sheet-body {
  flex: 1;
  overflow-y: auto;
  padding-bottom: 32px;
}

/* Check-in row (used in CheckInSheet + EmergencySubSheet) */
.checkin-row {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  background: transparent;
  border: 0;
  text-align: left;
  padding: 12px;
  color: var(--text);
  cursor: pointer;
}
.checkin-row .checkin-row-body { flex: 1; min-width: 0; }
.checkin-row-name { font-weight: 700; font-size: 14px; }
.checkin-row-meta { font-size: 11px; color: var(--text-mute); margin-top: 2px; }

/* =====================================================================
   Scorecard
   ===================================================================== */
.scorecard-tally {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: 12px;
  align-items: center;
  padding: 18px 12px;
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
}
.scorecard-side {
  text-align: center;
  padding: 6px 4px;
  border-radius: var(--radius);
  border: 1.5px solid transparent;
}
.scorecard-side.win {
  background: color-mix(in oklab, var(--accent) 10%, transparent);
  border-color: color-mix(in oklab, var(--accent) 50%, transparent);
}
.scorecard-side-team {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-mute);
  margin-bottom: 4px;
}
.scorecard-side.win .scorecard-side-team { color: var(--accent); }
.scorecard-side-score {
  font-size: 48px;
  font-weight: 800;
  letter-spacing: -0.04em;
  line-height: 1;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.scorecard-vs {
  font-size: 24px;
  font-weight: 800;
  color: var(--text-mute);
}
.scorecard-line {
  padding: 14px 14px;
}
.scorecard-played-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px 4px 4px;
  border-radius: 999px;
  background: var(--surface-2);
  border: 1px solid var(--border-soft);
  color: var(--text);
  font-size: 12px;
  font-weight: 600;
}
.scorecard-played-chip:hover { border-color: var(--border); background: var(--surface); }
.scorecard-played-chip:disabled { cursor: default; opacity: 0.9; }
.scorecard-view-line {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 0;
  border-bottom: 1px solid var(--border-soft);
}
.scorecard-view-line:last-child { border-bottom: 0; }
.scorecard-view-meta { flex: 1; min-width: 0; }
.scorecard-view-slot {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-mute);
}
.scorecard-view-played { font-size: 13px; color: var(--text); margin-top: 2px; }
.scorecard-view-result {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* =====================================================================
   Onboarding
   ===================================================================== */
.onboard-card {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 18px;
  border-radius: var(--radius-lg);
  background: var(--surface);
  border: 1px solid var(--border-soft);
  color: var(--text);
  text-align: left;
  cursor: pointer;
  transition: border-color 0.15s, background 0.15s;
}
.onboard-card:hover {
  border-color: color-mix(in oklab, var(--accent) 50%, var(--border));
  background: var(--bg-elev);
}
.onboard-card-icon {
  width: 44px;
  height: 44px;
  border-radius: 12px;
  display: grid;
  place-items: center;
  flex-shrink: 0;
}
.onboard-color {
  width: 32px;
  height: 32px;
  border-radius: 999px;
  border: 0;
  cursor: pointer;
  transition: transform 0.1s ease, box-shadow 0.15s ease;
}
.onboard-color:hover { transform: scale(1.08); }

/* =====================================================================
   USTA Import Flow
   ===================================================================== */
.usta-step-dots {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px var(--pad) 4px;
}
.usta-step-dot {
  width: 22px;
  height: 4px;
  border-radius: 999px;
  background: var(--surface-2);
  transition: background 0.2s ease, width 0.2s ease;
}
.usta-step-dot.active {
  background: var(--accent);
  width: 32px;
}
.usta-step-dot.done {
  background: color-mix(in oklab, var(--accent) 50%, var(--border));
}

.usta-hero {
  display: flex;
  gap: 14px;
  align-items: flex-start;
  padding: 16px;
  border-radius: var(--radius-lg);
  background: linear-gradient(135deg,
    color-mix(in oklab, var(--accent) 10%, var(--surface)),
    var(--surface));
  border: 1px solid color-mix(in oklab, var(--accent) 20%, var(--border-soft));
}
.usta-hero-badge {
  width: 44px;
  height: 44px;
  border-radius: 12px;
  display: grid;
  place-items: center;
  background: var(--accent);
  color: var(--accent-ink);
  flex-shrink: 0;
}

.usta-demo-banner {
  margin: 0 var(--pad);
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  border-radius: var(--radius);
  background: color-mix(in oklab, var(--info) 12%, var(--surface));
  border: 1px solid color-mix(in oklab, var(--info) 28%, transparent);
  color: var(--info);
  font-size: 12px;
  font-weight: 600;
  line-height: 1.45;
}

.usta-demo-note {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  border: 1px dashed var(--border);
  font-size: 11px;
  color: var(--text-dim);
  line-height: 1.5;
}
.usta-demo-note b { color: var(--text); }
.usta-demo-dot {
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: var(--info);
  margin-top: 6px;
  flex-shrink: 0;
  box-shadow: 0 0 0 4px color-mix(in oklab, var(--info) 20%, transparent);
}

.usta-error {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  background: color-mix(in oklab, var(--danger) 12%, var(--surface));
  border: 1px solid color-mix(in oklab, var(--danger) 30%, transparent);
  color: var(--danger);
  font-size: 12px;
  font-weight: 600;
}

.usta-loader {
  display: inline-grid;
  place-items: center;
  width: 64px;
  height: 64px;
  margin: 0 auto;
  border-radius: 50%;
  background: color-mix(in oklab, var(--accent) 12%, var(--surface));
  border: 1px solid color-mix(in oklab, var(--accent) 25%, var(--border));
}

.usta-section-head {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 14px 2px 8px;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-mute);
}
.usta-section-icon {
  display: inline-flex;
  width: 14px;
  height: 14px;
  align-items: center;
  justify-content: center;
  color: var(--text-dim);
}
.usta-section-icon svg { width: 12px; height: 12px; }

.usta-avatar {
  width: 32px;
  height: 32px;
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--text-dim);
  display: grid;
  place-items: center;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.02em;
  flex-shrink: 0;
  border: 1px solid var(--border-soft);
}
.usta-avatar.lg {
  width: 40px;
  height: 40px;
  font-size: 13px;
}

.usta-preview-player {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 10px;
  border-radius: var(--radius-sm);
}
.usta-preview-player + .usta-preview-player {
  border-top: 1px solid var(--border-soft);
}

.usta-preview-match {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px;
  border-radius: var(--radius-sm);
}
.usta-preview-match + .usta-preview-match {
  border-top: 1px solid var(--border-soft);
}
.usta-week {
  display: inline-grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: 8px;
  background: var(--surface-2);
  color: var(--text-dim);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.02em;
  flex-shrink: 0;
}

/* Editable roster row used in the confirm step */
.roster-edit-row {
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  padding: 12px;
}
.roster-edit-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}
@media (max-width: 380px) {
  .roster-edit-grid { grid-template-columns: 1fr; }
}
.field.tight { gap: 4px; }
.field.tight > label {
  font-size: 10px;
  letter-spacing: 0.06em;
}
.input.sm {
  padding: 8px 10px;
  /* keep ≥16px on iOS to avoid focus auto-zoom (small padding keeps it compact). */
  font-size: 16px;
}

/* Invite step rows */
.invite-toggle-all {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 6px 10px 6px 6px;
  border-bottom: 1px solid var(--border-soft);
  margin-bottom: 4px;
}
.invite-row {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 10px;
  background: transparent;
  border: 0;
  cursor: pointer;
  text-align: left;
  border-radius: var(--radius-sm);
  transition: background 0.12s ease;
}
.invite-row + .invite-row {
  border-top: 1px solid var(--border-soft);
}
.invite-row:hover:not(:disabled) { background: var(--surface-2); }
.invite-row:disabled { cursor: not-allowed; opacity: 0.6; }
.invite-row.on { background: color-mix(in oklab, var(--accent) 8%, transparent); }

.invite-check {
  width: 20px;
  height: 20px;
  border-radius: 6px;
  border: 1.5px solid var(--border);
  background: var(--surface);
  display: grid;
  place-items: center;
  color: var(--accent-ink);
  flex-shrink: 0;
  transition: background 0.12s ease, border-color 0.12s ease;
}
.invite-check.on {
  background: var(--accent);
  border-color: var(--accent);
}

.invite-channel-toggle {
  display: inline-flex;
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: 999px;
  padding: 2px;
  gap: 2px;
}
.invite-channel-btn {
  border: 0;
  background: transparent;
  color: var(--text-mute);
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.06em;
  padding: 4px 10px;
  border-radius: 999px;
  cursor: pointer;
}
.invite-channel-btn:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}
.invite-channel-btn.on {
  background: var(--accent);
  color: var(--accent-ink);
}

/* Invite manager — code pill + share buttons */
.invite-code-pill {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  padding: 14px 16px;
  border-radius: var(--radius);
  background: linear-gradient(135deg,
    color-mix(in oklab, var(--accent) 12%, var(--surface-2)),
    var(--surface-2));
  border: 1.5px dashed color-mix(in oklab, var(--accent) 35%, var(--border));
  color: var(--text);
  cursor: pointer;
  transition: border-color 0.15s, background 0.15s;
}
.invite-code-pill:hover {
  border-color: var(--accent);
  border-style: solid;
}
.invite-code {
  font-family: var(--font-mono);
  font-size: 18px;
  font-weight: 800;
  letter-spacing: 0.04em;
  color: var(--accent);
}
.invite-code-action {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-mute);
}

/* Captain crown badge (co-captains + primary captain) */
.captain-crown {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border-radius: 999px;
  background: color-mix(in oklab, var(--accent) 22%, var(--surface));
  color: var(--accent);
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* =====================================================================
   Billing — pricing cards & upgrade banner
   ===================================================================== */
.pricing-card {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
  padding: 22px 20px 20px;
  box-shadow: var(--shadow-card);
  transition: border-color 0.15s, transform 0.15s;
}
.pricing-card[data-selected="true"] {
  border-color: color-mix(in oklab, var(--accent) 45%, transparent);
  background: linear-gradient(
    180deg,
    color-mix(in oklab, var(--accent) 6%, var(--surface)) 0%,
    var(--surface) 100%
  );
  box-shadow:
    0 0 0 1px color-mix(in oklab, var(--accent) 22%, transparent),
    0 12px 28px color-mix(in oklab, var(--accent) 12%, transparent);
}
.pricing-card__ribbon {
  position: absolute;
  top: -10px; left: 16px;
  padding: 4px 10px;
  border-radius: 999px;
  background: var(--accent);
  color: var(--accent-ink);
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  box-shadow: 0 4px 12px color-mix(in oklab, var(--accent) 35%, transparent);
}
.pricing-card__head { margin-bottom: 14px; }
.pricing-card__title {
  font-size: 18px;
  font-weight: 800;
  letter-spacing: -0.01em;
}
.pricing-card__tagline {
  font-size: 13px;
  color: var(--text-dim);
  margin-top: 4px;
}
.pricing-card__price {
  display: flex;
  align-items: baseline;
  gap: 6px;
  margin-bottom: 14px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--border-soft);
}
.pricing-card__amount {
  font-size: 34px;
  font-weight: 800;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.pricing-card__cadence {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-mute);
  letter-spacing: 0.02em;
}
.pricing-card__bullets {
  list-style: none;
  margin: 0 0 16px;
  padding: 0;
  display: grid;
  gap: 8px;
}
.pricing-card__bullets li {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  color: var(--text-dim);
}
.pricing-card__bullets li svg {
  flex-shrink: 0;
}
.pricing-card__hint {
  margin-top: 10px;
  font-size: 11px;
  color: var(--text-mute);
  text-align: center;
}

/* Upgrade banner — slot atop the captain dashboard */
.upgrade-banner {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 14px 16px;
  border-radius: var(--radius);
  background: linear-gradient(
    180deg,
    color-mix(in oklab, var(--accent) 10%, var(--surface)) 0%,
    color-mix(in oklab, var(--accent) 4%, var(--surface)) 100%
  );
  border: 1px solid color-mix(in oklab, var(--accent) 35%, transparent);
  color: var(--text);
  cursor: pointer;
  text-align: left;
  transition: transform 0.08s, border-color 0.15s;
  box-shadow:
    0 0 0 1px color-mix(in oklab, var(--accent) 12%, transparent),
    0 4px 14px color-mix(in oklab, var(--accent) 8%, transparent);
}
.upgrade-banner:hover {
  border-color: color-mix(in oklab, var(--accent) 55%, transparent);
}
.upgrade-banner:active {
  transform: translateY(1px);
}
.upgrade-banner__icon {
  width: 36px;
  height: 36px;
  border-radius: 10px;
  background: var(--accent);
  color: var(--accent-ink);
  display: grid;
  place-items: center;
  flex-shrink: 0;
}
.upgrade-banner__icon svg { width: 16px; height: 16px; }
.upgrade-banner__body {
  flex: 1;
  min-width: 0;
}
.upgrade-banner__title {
  font-weight: 700;
  font-size: 14px;
}
.upgrade-banner__sub {
  font-size: 11px;
  color: var(--text-mute);
  margin-top: 2px;
  text-wrap: pretty;
}
.upgrade-banner__chev {
  color: var(--accent);
  flex-shrink: 0;
}

/* =====================================================================
   Match Format Picker — used in Create Team (manual + USTA confirm)
   and in Captain → More → Lineup.
   ===================================================================== */
.mf-picker {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.mf-summary {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 12px 14px;
  border-radius: 12px;
  background: color-mix(in oklab, var(--accent) 8%, var(--surface));
  border: 1px solid color-mix(in oklab, var(--accent) 25%, var(--border-soft));
}
.mf-summary-main {
  display: flex;
  align-items: baseline;
  gap: 6px;
  font-size: 16px;
  color: var(--text);
  letter-spacing: -0.01em;
}
.mf-summary-main b {
  font-size: 22px;
  font-weight: 800;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}
.mf-summary-main .mf-plus {
  color: var(--text-mute);
  font-weight: 600;
}
.mf-summary-meta {
  font-size: 11px;
  color: var(--text-mute);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-top: 2px;
}

.mf-presets {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
  gap: 6px;
}
.mf-preset {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 9px 10px;
  border-radius: 10px;
  background: var(--surface);
  border: 1px solid var(--border-soft);
  color: var(--text);
  cursor: pointer;
  text-align: left;
  transition: border-color 0.12s ease, background 0.12s ease;
  font: inherit;
}
.mf-preset:hover {
  border-color: var(--border);
}
.mf-preset.on {
  background: color-mix(in oklab, var(--accent) 14%, var(--surface));
  border-color: var(--accent);
}
.mf-preset-label {
  font-weight: 700;
  font-size: 13px;
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
}
.mf-preset.on .mf-preset-label {
  color: var(--accent);
}
.mf-preset-sub {
  font-size: 10px;
  color: var(--text-mute);
  font-weight: 500;
}

.mf-steppers {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}
.mf-stepper {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 10px 12px;
  border-radius: 10px;
  background: var(--surface);
  border: 1px solid var(--border-soft);
}
.mf-stepper-label {
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-dim);
}
.mf-stepper-controls {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.mf-step-btn {
  width: 30px;
  height: 30px;
  border-radius: 8px;
  border: 1px solid var(--border-soft);
  background: var(--bg);
  color: var(--text);
  font-size: 18px;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  display: grid;
  place-items: center;
  transition: background 0.12s ease, border-color 0.12s ease;
}
.mf-step-btn:hover:not(:disabled) {
  border-color: var(--accent);
  color: var(--accent);
}
.mf-step-btn:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}
.mf-step-value {
  font-size: 18px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--text);
  min-width: 18px;
  text-align: center;
}

/* Compact variant for in-row editing (e.g. inside settings cards) */
.mf-picker[data-compact="1"] {
  gap: 10px;
}
.mf-picker[data-compact="1"] .mf-summary {
  padding: 10px 12px;
}
.mf-picker[data-compact="1"] .mf-summary-main {
  font-size: 14px;
}
.mf-picker[data-compact="1"] .mf-summary-main b {
  font-size: 18px;
}

/* ===== Create-team league picker (STEP 1) ===== */
.league-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 10px;
}
@media (min-width: 560px) {
  .league-grid { grid-template-columns: 1fr 1fr; }
}
.league-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  padding: 22px 20px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 16px;
  cursor: pointer;
  text-align: left;
  color: var(--text);
  transition: border-color 0.12s, transform 0.06s, background 0.12s;
}
.league-card:hover { border-color: var(--accent); background: var(--surface-2); }
.league-card:active { transform: scale(0.99); }
.league-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.league-card-name { font-weight: 800; font-size: 18px; letter-spacing: -0.01em; }
.league-card-sub { font-size: 12px; color: var(--text-dim); line-height: 1.5; }

/* ===== USTA photo import ===== */
.usta-example-btn {
  display: block;
  width: 100%;
  max-width: 280px;
  margin: 0 auto;
  padding: 0;
  border: 1px solid var(--border-soft);
  border-radius: 14px;
  overflow: hidden;
  background: var(--surface-2);
  cursor: zoom-in;
}
.usta-example-img { display: block; width: 100%; height: auto; }
.usta-example-fallback { display: none; }
.usta-example-btn.missing {
  cursor: default;
  display: grid;
  place-items: center;
  min-height: 150px;
  padding: 20px;
  border-style: dashed;
}
.usta-example-btn.missing .usta-example-img { display: none; }
.usta-example-btn.missing .usta-example-fallback {
  display: block;
  font-size: 12px;
  color: var(--text-mute);
  text-align: center;
}
.usta-drop {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 32px 20px;
  border: 1.5px dashed var(--border-soft);
  border-radius: 16px;
  background: var(--surface-2);
  color: var(--text);
  cursor: pointer;
  transition: border-color 0.12s;
}
.usta-drop:hover { border-color: var(--accent); }
.usta-thumb-wrap {
  border: 1px solid var(--border-soft);
  border-radius: 14px;
  overflow: hidden;
  background: var(--surface-2);
}
.usta-thumb {
  display: block;
  width: 100%;
  height: auto;
  max-height: 340px;
  object-fit: contain;
}
.usta-repick {
  display: block;
  width: 100%;
  margin-top: 8px;
  padding: 8px;
  text-align: center;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-dim);
  background: transparent;
  border: 0;
  cursor: pointer;
}
.usta-fail-badge {
  display: inline-grid;
  place-items: center;
  width: 48px;
  height: 48px;
  border-radius: 999px;
  background: color-mix(in oklab, var(--danger) 18%, var(--surface));
  color: var(--danger);
}
.usta-edit-card { padding: 12px; }
.usta-edit-grid2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}
.usta-roster-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px;
}
.usta-roster-row .input { flex: 1; min-width: 0; }
.usta-share-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
}
.usta-share-url {
  font-size: 10px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.usta-lightbox {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: rgba(0, 0, 0, 0.82);
  display: grid;
  place-items: center;
  padding: 24px;
  cursor: zoom-out;
}
.usta-lightbox-img {
  max-width: 100%;
  max-height: 90vh;
  border-radius: 10px;
  cursor: default;
}
.usta-lightbox-close {
  position: fixed;
  /* [safe-area] Keep the lightbox close button clear of the notch on iOS. */
  top: calc(16px + env(safe-area-inset-top));
  right: 18px;
  width: 36px;
  height: 36px;
  border-radius: 999px;
  border: 0;
  background: rgba(255, 255, 255, 0.15);
  color: #fff;
  font-size: 16px;
  cursor: pointer;
}

/* ===================================================================
   BRAND POLISH — carry the matchloop blue→green identity across every
   screen: depth on cards, gradient accents on section headers + the
   sticky top bar, a tinted dashboard hero, and a gradient-text helper.
   All token-driven, so the (untouched) rain/makeup flow inherits it too.
   =================================================================== */

/* Subtle brand-tinted canvas so the app never reads as flat dead white. */
[data-theme="light"] .app-frame {
  background:
    radial-gradient(720px 420px at 100% 0%, rgba(22,104,240,0.06), transparent 60%),
    radial-gradient(680px 460px at 0% 100%, rgba(12,203,136,0.06), transparent 62%),
    linear-gradient(180deg, #F7FAFF 0%, var(--bg) 42%, #F2FBF6 100%);
}

/* Cards lift with depth + a brand-tinted hover. */
.card { transition: box-shadow 0.18s ease, transform 0.08s ease, border-color 0.18s ease; }
button.card:hover, a.card:hover {
  transform: translateY(-1px);
  box-shadow: var(--shadow-soft);
  border-color: color-mix(in oklab, var(--accent) 22%, var(--border-soft));
}

/* Section headers get a small brand gradient bar so every screen's
   structure reads as designed, not as anonymous grey labels. */
.section .label { position: relative; padding-left: 13px; }
.section .label::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.16em;
  width: 4px;
  height: 0.82em;
  border-radius: 2px;
  background: var(--brand-grad);
}

/* Gradient hairline under the sticky top bar — brand presence on every
   screen without shouting. */
[data-theme="light"] .topbar { border-bottom-color: transparent; }
[data-theme="light"] .topbar::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 2px;
  background: var(--brand-loop);
  opacity: 0.85;
}

/* Dashboard greeting band — a soft brand wash so the top of Home is
   colorful and welcoming instead of empty white. */
[data-theme="light"] .hero {
  background: linear-gradient(135deg, rgba(22,104,240,0.12), rgba(12,203,136,0.10) 62%, rgba(198,238,29,0.12));
  border-radius: 0 0 24px 24px;
  box-shadow: 0 8px 24px rgba(22,40,80,0.05);
}

/* Gradient-text helper for brand moments (e.g. the greeting name). */
.brand-text {
  background: var(--brand-grad);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
}

/* Reusable gradient top-strip for showcase cards (next-match hero). */
.brand-strip {
  height: 4px;
  border-radius: 999px;
  background: var(--brand-loop);
}

