/* =========================================================================
   birdie/alert — v1 stylesheet
   Single hand-crafted file. No build step. CSS custom properties for theming.
   ========================================================================= */

:root {
  /* Palette — warm-near-black background with chromatic accents quoting
     actual golf course visuals. All ratios computed against --bg.
     Every text/background pair clears WCAG AA, most clear AAA. */
  --bg: #0F1311;
  --bg-elev: #171C1A;
  --bg-input: #1F2624;
  --border: #2A332F;
  --border-strong: #3D4A45;

  --fg: #E8EDE9;             /* 14.8 : 1 — AAA */
  --fg-muted: #A1ADA6;       /* 7.4 : 1  — AAA */
  --fg-dim: #6E7A74;         /* 4.6 : 1  — AA  */

  --accent: #63A985;         /* fairway green — primary brand (muted, per booked-round handoff) */
  --accent-ink: #0A1A0F;     /* text on accent button */
  --sand: #D4B884;           /* secondary accent */
  --flag: #FF6B5B;           /* destructive only */
  --sky: #7BB8E8;            /* informational */

  /* Type stacks — system fonts only, no Google Fonts load */
  --font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
               "Helvetica Neue", Arial, sans-serif;
  --font-mono: ui-monospace, "SF Mono", "Cascadia Code", "JetBrains Mono",
               Menlo, Consolas, "Liberation Mono", monospace;

  /* Type scale — 1.25 modular ramp on 16px base */
  --text-xs: 0.75rem;        /* 12 */
  --text-sm: 0.875rem;       /* 14 */
  --text-base: 1rem;         /* 16 */
  --text-md: 1.25rem;        /* 20 */
  --text-lg: 1.5625rem;      /* 25 */
  --text-xl: 1.9375rem;      /* 31 */

  /* Spacing — base 4px */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-8: 48px;
  --space-10: 64px;

  /* Radii */
  --radius-sm: 4px;
  --radius-md: 8px;
  --radius-lg: 12px;
  --radius-xl: 14px;         /* booked-round cards / panels */
  --radius-pill: 999px;      /* chips, dots, status pills */

  /* Sidebar */
  --sidebar-width: 228px;

  /* Containers */
  --container-narrow: 28rem;
  --container-medium: 36rem;
  --container-wide: 48rem;

  /* Topographic background — tints derived from --accent and --sand so the
     architect-plan SVG tracks the rest of the palette automatically. */
  --topo-line:        color-mix(in oklab, var(--accent) 32%, transparent);
  --topo-line-faint:  color-mix(in oklab, var(--accent) 16%, transparent);
  --topo-line-mute:   color-mix(in oklab, var(--accent) 9%,  transparent);
  --topo-green:       color-mix(in oklab, var(--accent) 55%, transparent);
  --topo-bunker:      color-mix(in oklab, var(--sand)   18%, transparent);
  --topo-bunker-line: color-mix(in oklab, var(--sand)   32%, transparent);
}

/* =========================================================================
   Topographic background
   Fixed bottom-right architect-plan SVG drawn in --accent + --sand tones.
   Page chrome sits above via explicit z-index on .app-shell / .d-side /
   .container / .site-footer. Inline SVG only — no external requests.
   ========================================================================= */

.topo-bg {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
}

.topo-bg > svg {
  position: absolute;
  bottom: -40px;
  right: -80px;
  width: 88vw;
  height: auto;
  opacity: 0.85;
}

.topo-line        { fill: none; stroke: var(--topo-line);       stroke-width: 1.1; }
.topo-line--faint { fill: none; stroke: var(--topo-line-faint); stroke-width: 1; }
.topo-line--mute  { fill: none; stroke: var(--topo-line-mute);  stroke-width: 1; }
.topo-green       { fill: none; stroke: var(--topo-green);      stroke-width: 1.4; }
.topo-bunker      { fill: var(--topo-bunker); stroke: var(--topo-bunker-line); stroke-width: 1; }
.topo-pin         { fill: none; stroke: var(--accent); stroke-width: 1.2; }
.topo-flag        { fill: var(--accent); }
.topo-hole        { fill: var(--accent); }
.topo-callout     { fill: var(--fg-dim); font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.06em; }
.topo-tick        { stroke: var(--topo-line-faint); stroke-width: 1; }

@media (max-width: 720px) {
  .topo-bg > svg {
    width: 120vw;
    right: -30vw;
    bottom: -10vw;
    opacity: 0.7;
  }
}

/* =========================================================================
   Reset / base
   ========================================================================= */

*, *::before, *::after { box-sizing: border-box; }

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: 1.5;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

a {
  color: var(--sky);
  text-decoration: none;
  border-bottom: 1px solid transparent;
}
a:hover { border-bottom-color: var(--sky); }

h1, h2, h3, h4 { margin: 0; line-height: 1.2; font-weight: 600; }
p { margin: 0 0 var(--space-4); }
p:last-child { margin-bottom: 0; }

button { font: inherit; }

dl, dd { margin: 0; }
ul { padding-left: 0; list-style: none; margin: 0; }

code, .mono {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

.dim { color: var(--fg-dim); }
.warn { color: var(--flag); }
.success { color: var(--accent); }

.lede {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  margin: 0 0 var(--space-3);
  font-weight: 600;
}
.lede__label {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fg-muted);
  white-space: nowrap;
}
.lede__rule {
  flex: 1;
  height: 1px;
  background: var(--border);
}

/* Focus rings — visible only via keyboard navigation */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}
:focus:not(:focus-visible) { outline: none; }

/* Reduced motion */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition: none !important;
    animation: none !important;
  }
}

/* Navigation progress bar — a thin accent bar pinned to the top of the
   viewport, shown the instant an internal link or full-page form is followed.
   The dashboard render is fast, but the dark theme paints a black canvas while
   the server responds (worse on a cold host), which reads as a frozen page.
   The bar lives on the *outgoing* page, so it appears immediately and is gone
   once the next page paints — pure feedback, no navigation behaviour change. */
.nav-progress {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 3px;
  transform: scaleX(0);
  transform-origin: 0 50%;
  background: var(--accent);
  box-shadow: 0 0 8px color-mix(in oklab, var(--accent) 60%, transparent);
  opacity: 0;
  z-index: 100;
  pointer-events: none;
}
.nav-progress.is-active {
  opacity: 1;
  /* Crawl toward "almost done" but never reach the end — the page swap ends it. */
  animation: nav-progress-fill 8s cubic-bezier(0.1, 0.7, 0.2, 1) forwards;
}
@keyframes nav-progress-fill {
  0%   { transform: scaleX(0); }
  40%  { transform: scaleX(0.6); }
  100% { transform: scaleX(0.95); }
}
/* Reduced motion kills the crawl (via the global rule above), so show a static
   bar instead of an invisible scaleX(0) one. */
@media (prefers-reduced-motion: reduce) {
  .nav-progress.is-active { transform: scaleX(0.85); }
}

/* =========================================================================
   Layout
   ========================================================================= */

/* App shell — fixed sidebar on desktop, off-canvas drawer on mobile.
   Rendered only when show_nav is true; /r/* token pages skip the sidebar and
   the centered .container fills .main-col on its own. */
.app-shell {
  position: relative;
  z-index: 1;
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: stretch;
  min-height: 100vh;
}
.main-col {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

/* Sidebar */
.d-side {
  flex: 0 0 var(--sidebar-width);
  width: var(--sidebar-width);
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  padding: var(--space-5) var(--space-4);
  background: color-mix(in oklab, var(--bg) 92%, #000);
  border-right: 1px solid var(--border);
}
.d-side__brand { display: inline-flex; align-items: center; gap: var(--space-2); }
.d-side__flag { width: 19px; height: 19px; flex: 0 0 19px; }
/* Flagstick wordmark glyph — pole tracks text, flag + base track the accent. */
.flagstick__pole { stroke: var(--fg); }
.flagstick__flag,
.flagstick__base { fill: var(--accent); }

.d-nav { display: flex; flex-direction: column; gap: 3px; }
.d-nav__item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: 10px var(--space-3);
  border-radius: 9px;
  color: var(--fg-muted);
  font-size: var(--text-sm);
  border-bottom: none;
}
.d-nav__item svg { width: 18px; height: 18px; flex: 0 0 18px; }
.d-nav__item:hover {
  color: var(--fg);
  background: color-mix(in oklab, var(--fg) 6%, transparent);
  border-bottom: none;
}
.d-nav__item.on {
  color: var(--accent);
  background: color-mix(in oklab, var(--accent) 13%, transparent);
}
.d-nav__item.on:hover { color: var(--accent); }
/* Not-yet-built destinations — visible but inert. */
.d-nav__item--stub { color: var(--fg-dim); cursor: default; }
.d-nav__item--stub:hover { color: var(--fg-dim); background: none; }

.d-side__foot {
  margin-top: auto;
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 11px;
  border-radius: 11px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
}
.d-side__user { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.d-side__user b { font-size: 13.5px; }
.d-side__logout { margin: 0; }
.d-side__logout-btn {
  background: none; border: none; padding: 0; cursor: pointer;
  font-family: var(--font-mono); font-size: 10.5px; color: var(--fg-dim);
}
.d-side__logout-btn:hover { color: var(--accent); }

/* Avatar — shared by the sidebar chip, standings, scorecard, and entry rows.
   Caller sets size + background via inline style (sample-data colors). */
.av {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  font-family: var(--font-mono);
  font-weight: 600;
  color: #0b1410;
  flex: 0 0 auto;
}

/* Mobile top bar + hamburger — hidden on desktop, revealed < 1024px. */
.app-topbar { display: none; }
.app-topbar__toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  font-size: var(--text-md);
  color: var(--fg-muted);
  background: none;
  border: none;
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.app-topbar__toggle:hover { color: var(--fg); }

/* Scrim behind the open drawer — hidden until the shell is .is-open (mobile). */
.sidebar-scrim { display: none; }

.site-footer {
  position: relative;
  z-index: 2;
  padding: var(--space-5) var(--space-4);
  margin-top: auto;
  border-top: 1px solid var(--border);
  font-size: var(--text-xs);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.container {
  position: relative;
  z-index: 1;
  flex: 1;
  width: 100%;
  min-width: 0;           /* let wide children (scorecard) scroll, not stretch the page */
  margin-inline: auto;
  padding: var(--space-6) var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}
.container--narrow { max-width: var(--container-narrow); }
.container--medium { max-width: var(--container-medium); }
.container--wide   { max-width: var(--container-wide); }
.container--full   { max-width: none; }

@media (min-width: 50rem) {
  .container { padding-inline: var(--space-6); }
}

/* Mobile (< 1024px) — the sidebar becomes an off-canvas drawer behind a slim
   top bar with the wordmark and a ☰ toggle. JS toggles .is-open on .app-shell;
   the global reduced-motion rule above neutralises the slide transition. */
@media (max-width: 1023px) {
  .app-topbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-4);
    background: var(--bg);
    border-bottom: 1px solid var(--border);
    position: sticky;
    top: 0;
    z-index: 4;
  }

  .d-side {
    position: fixed;
    top: 0;
    left: 0;
    height: 100dvh;
    z-index: 6;
    transform: translateX(-100%);
    transition: transform 0.2s ease;
  }
  .app-shell.is-open .d-side { transform: translateX(0); }

  .sidebar-scrim {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 5;
    background: rgba(0, 0, 0, 0.5);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s ease;
  }
  .app-shell.is-open .sidebar-scrim { opacity: 1; pointer-events: auto; }
}

/* =========================================================================
   Wordmark
   ========================================================================= */

.wordmark {
  font-family: var(--font-mono);
  font-size: var(--text-md);
  font-weight: 500;
  color: var(--fg);
  border-bottom: none;
  letter-spacing: -0.01em;
}
.wordmark:hover { border-bottom: none; }
.wordmark__slash { color: var(--accent); }

/* =========================================================================
   Match card
   ========================================================================= */

.card {
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-5);
  transition: border-color 120ms ease;
}
.card:hover { border-color: var(--border-strong); }

/* Wrap a card in <a class="card-link"> to make the whole card clickable
   without inheriting the default link color/underline. The inner .card:hover
   still fires on hover, so the border lift comes for free. */
.card-link {
  display: block;
  color: inherit;
  border-bottom: none;
}
/* The block display above overrides the `hidden` attribute's display:none, so
   restore it for filtered-out cards (client-side reminders filter). */
.card-link[hidden] { display: none; }
.card-link:hover { border-bottom: none; }

.card__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
  padding-bottom: var(--space-4);
  border-bottom: 1px solid var(--border);
}

.card__title {
  font-family: var(--font-mono);
  font-size: calc(var(--text-md) * 1.15);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: var(--fg);
}

/* Dark container around the data grid. The grid's divider lines only appear
   between cells, so the box's padding insets them from the border on all sides
   — they read as floating dividers, not edge-to-edge table gridlines. */
.card-grid-box {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-2);
}

.card-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1px;
  background: var(--border);          /* divider lines show through the gaps */
}

.card-grid > div {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-width: 0;
  padding: var(--space-3);
  background: var(--bg);               /* matches the box so only dividers show */
}

.card-grid dt {
  font-family: var(--font-sans);
  font-size: calc(var(--text-sm) * 1.15);
  color: var(--fg-muted);
  text-transform: lowercase;
}

.card-grid dd {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  font-family: var(--font-mono);
  font-size: calc(var(--text-base) * 1.15);
  color: var(--fg);
  font-variant-numeric: tabular-nums;
}

.card-grid dd small {
  font-size: var(--text-xs);
  color: var(--fg-dim);
  text-transform: lowercase;
  letter-spacing: 0.02em;
}

@media (min-width: 24rem) {
  .card-grid { grid-template-columns: 1fr 1fr; }
}

@media (min-width: 40rem) {
  .card-grid { grid-template-columns: repeat(4, 1fr); }
}

/* =========================================================================
   Status pill
   ========================================================================= */

.pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 2px var(--space-2);
  border-radius: 999px;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  border: 1px solid var(--border-strong);
  background: transparent;
  color: var(--fg-muted);
  white-space: nowrap;
}

.pill__dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
}

.pill--new,
.pill--booked,
.pill--full,
.pill--active   { color: var(--accent); border-color: var(--accent); }
.pill--notified { color: var(--sky);    border-color: var(--sky); }
.pill--filling  { color: var(--sand);   border-color: var(--sand); }
.pill--cancelled,
.pill--declined,
.pill--owner_declined { color: var(--flag); border-color: var(--flag); }
.pill--expired,
.pill--timed_out,
.pill--reminder_sent,
.pill--partial_booked { color: var(--fg-dim); border-color: var(--fg-dim); }

/* =========================================================================
   Buttons
   ========================================================================= */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: 44px;
  padding: var(--space-2) var(--space-5);
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  font-weight: 600;
  cursor: pointer;
  transition: background-color 120ms ease, border-color 120ms ease, color 120ms ease;
  text-decoration: none;
  user-select: none;
}

.btn--block { width: 100%; }

.btn--primary {
  background: var(--accent);
  color: var(--accent-ink);
  border-color: var(--accent);
}
.btn--primary:hover { filter: brightness(0.92); }

.btn--ghost {
  background: transparent;
  color: var(--fg);
  border-color: var(--border-strong);
}
.btn--ghost:hover { border-color: var(--fg-muted); }

.btn--solid {
  background: var(--bg-elev);
  color: var(--fg);
  border-color: var(--border-strong);
}
.btn--solid:hover { background: var(--bg-input); border-color: var(--fg-muted); }

.btn--flag {
  color: var(--flag);
  border-color: var(--flag);
}
.btn--flag:hover {
  background: rgba(255, 107, 91, 0.08);
  border-color: var(--flag);
}

.check { color: inherit; font-family: var(--font-mono); }

/* =========================================================================
   Action sections
   ========================================================================= */

.actions {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-5);
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}
.actions p { color: var(--fg); }
.actions .dim { color: var(--fg-dim); }
.actions__secondary { margin-top: calc(-1 * var(--space-2)); }

.btn:disabled { opacity: 0.45; cursor: not-allowed; }

/* =========================================================================
   Friend-picker modal (booked page + My Rounds cards)
   ========================================================================= */

/* Open/close is pure CSS: the hidden checkbox toggle reveals the modal. */
.picker__modal {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 50;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
}
.picker__toggle:checked ~ .picker__modal { display: flex; }

.picker__backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
  cursor: pointer;
}

.picker__panel {
  position: relative;
  width: 100%;
  max-width: var(--container-narrow);
  max-height: 85vh;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-5);
  background: var(--bg-elev);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
}

.picker__title { margin: 0; font-size: var(--text-md); }

.picker__all {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding-bottom: var(--space-3);
  border-bottom: 1px solid var(--border);
  color: var(--fg-muted);
  cursor: pointer;
}

.picker__spots {
  margin: 0;
  padding: 0 0 var(--space-3);
  border: 0;
  border-bottom: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.picker__spots legend {
  padding: 0;
  margin-bottom: var(--space-2);
  color: var(--fg-muted);
}
.picker__spot {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 44px;
  padding: var(--space-2);
  border-radius: var(--radius-md);
  color: var(--fg);
  cursor: pointer;
}
.picker__spot:hover { background: var(--bg-input); }

.picker__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.picker__friend {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 44px;
  padding: var(--space-2);
  border-radius: var(--radius-md);
  cursor: pointer;
}
.picker__friend:hover { background: var(--bg-input); }

.picker__av {
  width: 32px;
  height: 32px;
  font-size: var(--text-sm);
}

.picker__name { flex: 1 1 auto; color: var(--fg); }
.picker__last4 { color: var(--fg-dim); font-size: var(--text-sm); }
.picker__empty { color: var(--fg-muted); }

/* Already-invited friends: shown but locked, with an "Invited" badge. */
.picker__friend--invited { opacity: 0.65; cursor: default; }
.picker__friend--invited:hover { background: transparent; }
.picker__tag {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--accent);
  border: 1px solid var(--accent);
  border-radius: var(--radius-sm);
  padding: 2px var(--space-2);
}

.picker__actions {
  display: flex;
  gap: var(--space-3);
  margin-top: var(--space-2);
}
.picker__actions .btn { flex: 1 1 0; }

.picker input[type="checkbox"] {
  accent-color: var(--accent);
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
}

/* =========================================================================
   Claimed-friends list (friend invite page)
   ========================================================================= */

.claimed-list {
  padding: var(--space-4) var(--space-5);
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}
.claimed-list ul { display: flex; flex-direction: column; gap: var(--space-2); }
.claimed-list li {
  font-size: var(--text-sm);
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
}

/* =========================================================================
   Countdown bar — live ticker until the friend-blast SMS goes out
   ========================================================================= */

.countdown {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}

.countdown__text {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  color: var(--fg-muted);
}

.countdown__time {
  color: var(--accent);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.countdown__bar {
  display: block;
  height: 4px;
  background: var(--border);
  border-radius: 2px;
  overflow: hidden;
}

.countdown__bar-fill {
  display: block;
  height: 100%;
  width: 100%;
  background: var(--accent);
  border-radius: 2px;
  transition: width 1s linear;
}

.countdown--done .countdown__time   { color: var(--fg-dim); }
.countdown--done .countdown__bar-fill { background: var(--fg-dim); }

/* =========================================================================
   Lede — header variant with a trailing action button
   ========================================================================= */

.lede > .btn {
  margin-left: auto;
  flex-shrink: 0;
}

/* =========================================================================
   Card list — vertical stack of filter cards
   ========================================================================= */

.card-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.card__actions {
  display: flex;
  gap: var(--space-3);
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--border);
}

/* =========================================================================
   Buttons — small + link variants
   ========================================================================= */

.btn--sm {
  min-height: 36px;
  padding: var(--space-1) var(--space-3);
  font-size: var(--text-sm);
}

/* =========================================================================
   Empty state
   ========================================================================= */

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-6) var(--space-5);
  background: var(--bg-elev);
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-md);
}

.empty-state__title {
  font-family: var(--font-mono);
  font-size: var(--text-md);
  color: var(--fg);
  margin: 0;
}

.empty-state__hint {
  color: var(--fg-muted);
  margin: 0;
}

/* =========================================================================
   Forms — labelled text inputs, error states, fine-print, banners
   ========================================================================= */

.form {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

/* Card-style form wrapper. Opt-in via `.form--card` — the filter pages use
   it. The invite opt-in form uses `.form--invite-card` (a light fairway-tint
   panel) instead. */
.form--card {
  gap: var(--space-5);
  padding: var(--space-5);
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}

/* Invite opt-in — solid panel filled with the page background color and set
   off only by a slightly-lighter border, so the form reads as a contained
   block without changing the dark palette. */
.form--invite-card {
  gap: var(--space-5);
  padding: var(--space-5);
  background: var(--bg);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
}

.form-field {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 0;
}

.form-field--row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-4);
}

.form-field--row > div {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 0;
}

.form-field__label {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--fg-muted);
}

.form-field__hint {
  font-size: var(--text-xs);
  color: var(--fg-dim);
  line-height: 1.5;
}

.form-field__hint.empty-hint {
  color: var(--fg-muted);
  font-style: italic;
}

.form-field__error {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.04em;
  color: var(--flag);
}

.form__actions {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding-top: var(--space-3);
  border-top: 1px solid var(--border);
}

.form__fine-print {
  margin: 0;
  font-size: var(--text-xs);
  line-height: 1.5;
  color: var(--fg-dim);
}

/* =========================================================================
   Inputs — text, number, time, search
   ========================================================================= */

.input {
  width: 100%;
  min-height: 44px;
  padding: var(--space-2) var(--space-3);
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  color: var(--fg);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: 1.4;
  transition: border-color 120ms ease;
  -webkit-appearance: none;
  appearance: none;
}

.input::placeholder { color: var(--fg-dim); }
.input:hover { border-color: var(--border-strong); }
.input:focus,
.input:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-color: var(--accent);
}
.input--mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.input--error { border-color: var(--flag); }

/* Readonly textarea (the copyable invite message) — keep it from resizing
   horizontally and match the input chrome. */
textarea.input { resize: vertical; line-height: 1.5; }

/* OTP entry — big, spaced, centered digits. */
.input--otp {
  font-size: var(--text-lg);
  letter-spacing: 0.4em;
  text-align: center;
  padding-inline: var(--space-3);
}

/* Roster — friends who've joined the operator's group. */
.roster {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.roster__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}
.roster__name { color: var(--fg); }
.roster__meta { color: var(--fg-dim); font-size: var(--text-sm); }

/* Live client-side feedback — red border only after the user has typed
   something AND moved focus away. Empty + placeholder showing → no nag.
   Mid-typing (still focused) → no nag. Invalid value after blur → red. */
.input:not(:focus):not(:placeholder-shown):invalid {
  border-color: var(--flag);
}

/* Search input variant — strip native chrome so it matches the rest. */
.input[type="search"]::-webkit-search-cancel-button {
  -webkit-appearance: none;
  appearance: none;
}

/* Time + number controls render small native pickers — keep them legible
   in dark mode and tabular for alignment. */
input[type="time"].input,
input[type="number"].input {
  color-scheme: dark;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

/* =========================================================================
   Banners — page-level inline notices
   ========================================================================= */

.banner {
  padding: var(--space-3) var(--space-4);
  border: 1px solid;
  border-radius: var(--radius-md);
  font-size: var(--text-sm);
  line-height: 1.5;
}
.banner--error {
  color: var(--flag);
  border-color: var(--flag);
  background: rgba(255, 107, 91, 0.06);
}
.banner--info {
  color: var(--sky);
  border-color: var(--sky);
  background: rgba(123, 184, 232, 0.06);
}
.banner__list {
  margin: 0;
  padding-inline-start: var(--space-5);
}

/* Live availability badge on the owner page — updated by fetch() after load. */
.live-status {
  font-size: var(--text-sm);
  font-weight: 500;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
}
.live-status--checking { color: var(--fg-muted); }
.live-status--open {
  color: var(--accent);
  border-color: var(--accent);
  background: rgba(91, 214, 138, 0.06);
}
.live-status--taken {
  color: var(--flag);
  border-color: var(--flag);
  background: rgba(255, 107, 91, 0.06);
}
.live-status--unknown { color: var(--fg-dim); }

/* Availability pill on match cards (dashboard) — refreshed live by JS. */
.card__pills {
  display: inline-flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  justify-content: flex-end;
}
.availability-pill--open {
  color: var(--accent);
  border-color: var(--accent);
}
.availability-pill--taken {
  color: var(--flag);
  border-color: var(--flag);
}
.availability-pill--unknown,
.availability-pill--checking {
  color: var(--fg-dim);
  border-color: var(--border-strong);
}
/* Applied by the dashboard script while a live scrape is in flight — the pill
   keeps showing its stored value but pulses so the operator sees it's being
   re-checked. Motion gated on user preference, matching the .scan__live dot. */
@media (prefers-reduced-motion: no-preference) {
  .availability-pill--checking { animation: availability-pulse 1.2s ease-in-out infinite; }
}
@keyframes availability-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.45; }
}

/* Infinite-scroll sentinel — a zero-height keyset-cursor marker the
   IntersectionObserver watches. Collapsed and silent until the lazy-load script
   adds .is-loading (while /dashboard/matches is in flight), which reveals a
   centered spinner + label so the list doesn't read as frozen on a slow fetch. */
.dashboard-sentinel {
  height: 0;
  overflow: hidden;
}
.dashboard-sentinel__spinner,
.dashboard-sentinel__label { display: none; }
.dashboard-sentinel.is-loading {
  height: auto;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-4) 0;
  color: var(--fg-muted);
  font-size: var(--text-sm);
}
.dashboard-sentinel.is-loading .dashboard-sentinel__spinner,
.dashboard-sentinel.is-loading .dashboard-sentinel__label { display: inline-flex; }
.dashboard-sentinel__spinner {
  width: 16px;
  height: 16px;
  border: 2px solid var(--border-strong);
  border-top-color: var(--accent);
  border-radius: 50%;
}
/* Spin only when motion is allowed; reduced-motion keeps a static ring + the
   label, matching the .availability-pill--checking / .nav-progress gating. */
@media (prefers-reduced-motion: no-preference) {
  .dashboard-sentinel.is-loading .dashboard-sentinel__spinner {
    animation: dashboard-sentinel-spin 0.8s linear infinite;
  }
}
@keyframes dashboard-sentinel-spin {
  to { transform: rotate(360deg); }
}

/* =========================================================================
   Consent block — structured SMS opt-in disclosure with required checkbox
   ========================================================================= */

.consent {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-4);
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}

.consent__lead {
  margin: 0;
  font-size: var(--text-sm);
  line-height: 1.5;
  color: var(--fg);
}

.consent__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  font-size: var(--text-xs);
  line-height: 1.5;
  color: var(--fg-muted);
}
.consent__list li {
  position: relative;
  padding-left: var(--space-3);
}
.consent__list li::before {
  content: "·";
  position: absolute;
  left: 0;
  color: var(--accent);
  font-weight: 700;
}

.consent__opt-out {
  margin: 0;
  font-size: var(--text-xs);
  line-height: 1.5;
  color: var(--fg-muted);
}
.consent__opt-out strong { color: var(--fg); }
.consent a {
  color: var(--fg-muted);
  border-bottom-color: var(--border-strong);
}
.consent a:hover {
  color: var(--fg);
  border-bottom-color: var(--fg-muted);
}

.consent__checkbox {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-3);
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  font-size: var(--text-sm);
  line-height: 1.4;
  color: var(--fg);
  cursor: pointer;
  transition: border-color 120ms ease;
}
.consent__checkbox:hover { border-color: var(--border-strong); }
.consent__checkbox:has(:checked) { border-color: var(--accent); }
.consent__checkbox input[type="checkbox"] {
  width: 20px;
  height: 20px;
  margin: 0;
  flex-shrink: 0;
  accent-color: var(--accent);
  cursor: pointer;
}

/* =========================================================================
   Checkbox grids — used for days-of-week and courses pickers
   ========================================================================= */

.checkbox-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-2);
}

@media (min-width: 24rem) {
  .checkbox-grid { grid-template-columns: 1fr 1fr; }
}

.checkbox-grid--days {
  /* Wrap-friendly: as many ~64px columns as fit, then wrap. Always stays
     inside the form card without horizontal overflow. */
  grid-template-columns: repeat(auto-fit, minmax(64px, 1fr));
}

.checkbox-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 44px;
  padding: var(--space-2) var(--space-3);
  background: var(--bg-input);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  cursor: pointer;
  user-select: none;
  font-size: var(--text-sm);
  color: var(--fg);
  transition: border-color 120ms ease, background-color 120ms ease;
}

.checkbox-item:hover { border-color: var(--fg-muted); }

.checkbox-item > input[type="checkbox"] {
  margin: 0;
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  accent-color: var(--accent);
  cursor: pointer;
}

.checkbox-item:has(input[type="checkbox"]:checked) {
  border-color: var(--accent);
  background: color-mix(in oklab, var(--accent) 8%, var(--bg-input));
}

.checkbox-item:has(input[type="checkbox"]:focus-visible) {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.checkbox-item--standalone {
  align-items: flex-start;
  padding: var(--space-3) var(--space-4);
}

.checkbox-item--standalone > input[type="checkbox"] {
  margin-top: 2px;
}

.checkbox-item--standalone small {
  display: block;
  font-size: var(--text-xs);
  margin-top: 2px;
}

/* =========================================================================
   Disabled-until-valid submit — uses :has() so no JS required.
   The button looks muted and is unclickable until every required field
   (name + phone) is filled. The consent checkbox is optional, so an
   unchecked box never counts as :invalid and never blocks the button.
   Browsers without :has() (very old) just fall back to native HTML5 form
   validation on submit.
   ========================================================================= */

.form:has(:invalid) .btn--primary {
  opacity: 0.4;
  cursor: not-allowed;
  pointer-events: none;
  filter: none;
}

/* =========================================================================
   Alt-CTA — secondary path for new users who want their own account
   ========================================================================= */

.alt-cta {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.alt-cta p {
  font-size: var(--text-sm);
  color: var(--fg-muted);
  margin: 0;
}
.alt-cta .btn { text-decoration: none; }

/* =========================================================================
   Booked round — shared
   Header (.brhead), live-scoring chip (.scan), avatars, and a reusable
   mono data label. Used by both the scorecard and the score-entry page.
   Lifted from the booked-round handoff; hardcoded hex mapped to tokens.
   ========================================================================= */

/* The scorecard sections (course details, standings, entry bar, grid) are
   wrapped in #scorecard for HTMX swaps, so they no longer get the page
   container's gap — restore even spacing between them here. */
#scorecard {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}

.brhead {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
}
.brhead h1 {
  margin: 0;
  font-size: var(--text-lg);
  font-weight: 600;
  letter-spacing: -0.01em;
}
.brhead__meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 9px;
  margin-top: 6px;
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--fg-muted);
}
.brhead__meta .dot {
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: var(--fg-dim);
  flex: 0 0 3px;
}

/* Live status chip with the pinging dot. */
.scan {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 6px 13px;
  border-radius: var(--radius-pill);
  background: color-mix(in oklab, var(--accent) 12%, transparent);
  border: 1px solid color-mix(in oklab, var(--accent) 32%, transparent);
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.03em;
  color: var(--accent);
  white-space: nowrap;
}
.scan__live { position: relative; width: 7px; height: 7px; flex: 0 0 7px; }
.scan__live::before,
.scan__live::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: var(--accent);
}
/* Ping only when the user hasn't asked to reduce motion. */
@media (prefers-reduced-motion: no-preference) {
  .scan__live::after { animation: ping 1.8s cubic-bezier(0, 0, 0.2, 1) infinite; }
}
@keyframes ping {
  0%        { transform: scale(1);   opacity: 0.7; }
  80%, 100% { transform: scale(2.6); opacity: 0; }
}

/* Reusable mono uppercase micro-label (Par / Hdcp / Plays / "156y to pin"). */
.data-label {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fg-dim);
}

/* To-par colours, shared across standings, scorecard, and entry rows. */
.par-pos { color: var(--accent); }
.par-neg { color: var(--flag); }
.par-e   { color: var(--fg-dim); }

/* =========================================================================
   Booked round — Screen 1: scorecard & standings
   ========================================================================= */

/* Group standings strip */
.standings { display: flex; align-items: stretch; gap: 10px; }
.std {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 13px 15px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--bg-elev);
}
.std--lead {
  border-color: color-mix(in oklab, var(--accent) 45%, transparent);
  background: color-mix(in oklab, var(--accent) 8%, var(--bg-elev));
}
.std__name { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.std__name b { font-size: 14.5px; font-weight: 600; }
.std__name span {
  font-family: var(--font-mono);
  font-size: 10.5px;
  color: var(--fg-dim);
  letter-spacing: 0.04em;
}
.std__par { font-family: var(--font-mono); font-size: 24px; font-weight: 600; }

/* Scorecard card */
.sc-wrap {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  min-width: 0;           /* contain the scrolling grid below */
}
.sc-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: 13px 16px;
  background: var(--bg-elev);
  border-bottom: 1px solid var(--border);
}
.sc-top__label {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fg-dim);
}
.sc-top__label svg { width: 14px; height: 14px; }
.sc-legend {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  font-family: var(--font-mono);
  font-size: 10.5px;
  color: var(--fg-dim);
  letter-spacing: 0.04em;
}
.sc-legend i { display: inline-flex; align-items: center; gap: 6px; font-style: normal; }
.sc-legend__mark { width: 15px; height: 15px; display: inline-block; flex: 0 0 15px; }
.sc-legend__mark--bird { border: 1.5px solid var(--accent); border-radius: 50%; }
.sc-legend__mark--bog  { border: 1.5px solid var(--flag); }

/* The grid itself — a CSS grid, not a table. 1px gaps over a --border
   background render as hairline dividers. */
.sc-scroll { overflow-x: auto; }
.sc {
  display: grid;
  grid-template-columns: 160px repeat(9, 1fr) 42px repeat(9, 1fr) 42px 52px;
  gap: 1px;
  background: var(--border);
  min-width: 720px;            /* below this, .sc-scroll scrolls horizontally */
}
.sc > div {
  background: var(--bg-elev);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 10px 0;
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--fg);
}
.sc .hd { font-size: 10.5px; color: var(--fg-dim); letter-spacing: 0.06em; }
.sc .rowlbl {
  justify-content: flex-start;
  padding-left: 14px;
  gap: 9px;
  font-family: var(--font-sans);
  font-size: 13.5px;
  color: var(--fg);
  font-weight: 600;
}
.sc .rowlbl .av { width: 26px; height: 26px; font-size: 10px; }
.sc .you {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  color: var(--accent);
  letter-spacing: 0.06em;
}
.sc .par-row { background: var(--bg-input); color: var(--fg-muted); font-size: 12px; }
.sc .par-row.rowlbl,
.sc .sum { color: var(--fg-muted); }
.sc .sum { background: var(--bg-input); font-weight: 600; }
.sc .col-now { background: color-mix(in oklab, var(--accent) 13%, var(--bg-elev)); }
.sc .col-now.hd { color: var(--accent); }
.sc .tot { background: var(--bg-input); font-weight: 600; font-size: 14px; }

/* Per-hole result mark vs par. */
.mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 25px;
  height: 25px;
  line-height: 1;
}
.mark--bird { border: 1.6px solid var(--accent); border-radius: 50%; color: var(--accent); }
.mark--bog  { border: 1.6px solid var(--flag); color: var(--flag); }
.mark--dbl  {
  border: 1.6px solid var(--flag);
  color: var(--flag);
  outline: 1.6px solid var(--flag);
  outline-offset: 2px;
}
.cell-empty { color: var(--fg-dim); }

/* Keep the row-label column visible while the grid scrolls on mobile. */
@media (max-width: 1023px) {
  .sc .rowlbl { position: sticky; left: 0; z-index: 1; }
}

/* Quick-entry bar */
.entry-bar {
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 15px 18px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  background: var(--bg-elev);
}
.entry-bar__now {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding-right: 18px;
  border-right: 1px solid var(--border);
}
.entry-bar__h { font-family: var(--font-mono); font-size: 30px; font-weight: 600; line-height: 1; }
.entry-bar__d { display: flex; flex-direction: column; gap: 2px; }
.entry-bar__d b { font-size: 13.5px; }
.entry-bar__qp { display: flex; align-items: center; gap: var(--space-2); flex: 1; flex-wrap: wrap; }
.entry-bar__who { font-family: var(--font-mono); font-size: 12px; color: var(--fg-muted); margin-right: 4px; }
.entry-bar__save {
  height: 44px;
  padding: 0 22px;
  border-radius: var(--radius-md);
  background: var(--accent);
  color: var(--accent-ink);
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  letter-spacing: 0.03em;
  border: none;
  cursor: pointer;
  border-bottom: none;
}
.entry-bar__save:hover { border-bottom: none; }
.entry-bar__save svg { width: 16px; height: 16px; }

/* Standings cards double as buttons: tap one to enter that player's score. */
.std {
  appearance: none;
  width: 100%;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
  transition: border-color 120ms ease, box-shadow 120ms ease;
}
.std:hover { border-color: var(--border-strong); }
.std--active {
  border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
}

/* Inline score-entry form (reuses the .entry-bar box). The outer .entry-form
   holds the hole nav + the save form side by side. */
.entry-form { flex-wrap: wrap; gap: var(--space-3) 18px; }
.entry-form__entry {
  display: flex;
  align-items: center;
  gap: 18px;
  flex: 1;
  min-width: 0;
  flex-wrap: wrap;
}
.entry-form__nav { display: flex; align-items: center; gap: var(--space-2); }
.entry-nav-btn {
  width: 38px;
  height: 40px;
  border-radius: 9px;
  border: 1px solid var(--border-strong);
  background: var(--bg-input);
  color: var(--fg);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
}
.entry-nav-btn:disabled { opacity: 0.4; cursor: default; }
.entry-form__hole {
  appearance: none;
  height: 40px;
  padding: 0 30px 0 12px;
  border-radius: 9px;
  border: 1px solid var(--border-strong);
  background: var(--bg-input)
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%236E7A74' stroke-width='1.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")
    no-repeat right 11px center;
  color: var(--fg);
  font-family: var(--font-mono);
  font-size: 13px;
  cursor: pointer;
}
.entry-form__body {
  display: flex;
  align-items: center;
  gap: 14px;
  flex: 1;
  min-width: 0;
  flex-wrap: wrap;
}
.entry-form__who { display: flex; align-items: center; gap: var(--space-2); white-space: nowrap; }
.entry-form__who b { font-size: 14px; }
.entry-form__pad { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.entry-form__manual {
  width: 58px;
  height: 40px;
  border-radius: 9px;
  border: 1px solid var(--border-strong);
  background: var(--bg-input);
  color: var(--fg);
  font-family: var(--font-mono);
  font-size: 15px;
  text-align: center;
}
.entry-form__save {
  height: 44px;
  padding: 0 22px;
  margin-left: auto;
  border-radius: var(--radius-md);
  background: var(--accent);
  color: var(--accent-ink);
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.03em;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  border: none;
  border-bottom: none;
  cursor: pointer;
}
.entry-form__save svg { width: 16px; height: 16px; }

/* Square score button, shared by the entry bar and the record-score steppers. */
.qbtn {
  width: 40px;
  height: 40px;
  border-radius: 9px;
  border: 1px solid var(--border-strong);
  background: var(--bg-input);
  color: var(--fg);
  font-family: var(--font-mono);
  font-size: 16px;
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.qbtn.on { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }

/* =========================================================================
   Booked round — Screen 2: record score (single hole)
   ========================================================================= */

.rec {
  display: grid;
  grid-template-columns: 380px 1fr;
  gap: var(--space-5);
  flex: 1;
  min-height: 0;
}

/* Left — hole detail panel with the decorative pin sheet behind it. */
.rec-hole {
  position: relative;
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  overflow: hidden;
  background: var(--bg-elev);
  display: flex;
  flex-direction: column;
}
.rec-hole__topo { position: absolute; inset: 0; z-index: 0; width: 100%; height: 100%; }
.rec-hole__in {
  position: relative;
  z-index: 1;
  padding: 22px;
  display: flex;
  flex-direction: column;
  height: 100%;
}
.rec-hole__no { display: flex; align-items: baseline; gap: var(--space-3); }
.rec-hole__no > b {
  font-family: var(--font-mono);
  font-size: 72px;
  font-weight: 600;
  line-height: 0.85;
  letter-spacing: -0.02em;
}
.rec-hole__p { display: flex; flex-direction: column; font-family: var(--font-mono); }
.rec-hole__p .data-label { margin-bottom: 2px; }
.rec-hole__p b { font-size: 17px; }
.rec-hole__dist { margin-top: auto; }
.rec-hole__big-row { margin-top: 6px; }
.rec-hole__big {
  font-family: var(--font-mono);
  font-size: 56px;
  font-weight: 600;
  line-height: 0.85;
  color: var(--accent);
}
.rec-hole__u { font-family: var(--font-mono); font-size: 14px; color: var(--fg-muted); margin-left: var(--space-2); }
.rec-hole__cfb {
  display: flex;
  gap: var(--space-5);
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--fg-dim);
}
.rec-hole__cfb b { display: block; color: var(--fg); font-size: 16px; margin-top: 3px; }

/* Pin-sheet topo colours — token-driven; the numeric opacities live on the SVG. */
.pin-slope { fill: none; stroke: var(--accent); }
.pin-slope--fill { fill: var(--accent); }
.pin-pole { stroke: var(--fg); }
.pin-flag { fill: var(--flag); }
.pin-hole { fill: var(--accent); }

/* Right — entry panel */
.rec-entry {
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  background: var(--bg-elev);
  padding: 18px 20px;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.rec-entry__hd { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); }
.rec-entry__hd b { font-size: 16px; font-weight: 600; }

/* Accent pill on the entry header. */
.rec-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 9px;
  border-radius: var(--radius-pill);
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent);
  border: 1px solid color-mix(in oklab, var(--accent) 55%, transparent);
  white-space: nowrap;
}
.rec-pill__dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: 0 0 6px; }

/* Player entry row */
.pl {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: 13px 14px;
  border: 1px solid var(--border);
  border-radius: 11px;
  background: var(--bg);
}
.pl--active { border-color: var(--accent); background: color-mix(in oklab, var(--accent) 7%, var(--bg)); }
.pl__who { display: flex; align-items: center; gap: 11px; width: 168px; flex: 0 0 168px; }
.pl__nm { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.pl__nm b { font-size: 14.5px; font-weight: 600; }
.pl__nm span { font-family: var(--font-mono); font-size: 10.5px; color: var(--fg-dim); }
.pl__pad { display: flex; align-items: center; gap: 7px; flex: 1; flex-wrap: nowrap; justify-content: center; }
.pl__num { margin-left: auto; display: flex; align-items: center; gap: var(--space-3); }
.pl__v { font-family: var(--font-mono); font-size: 30px; font-weight: 600; min-width: 30px; text-align: center; }
.pl__vpar { font-family: var(--font-mono); font-size: 11px; width: 34px; text-align: center; }

.step {
  width: 38px;
  height: 38px;
  border-radius: 9px;
  border: 1px solid var(--border-strong);
  background: var(--bg-input);
  color: var(--fg);
  font-family: var(--font-mono);
  font-size: 18px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

/* Entry footer + back/next buttons */
.rec-entry__foot {
  margin-top: auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding-top: 6px;
}
.rec-entry__cap { font-family: var(--font-mono); font-size: 12px; color: var(--fg-dim); }
.rec-entry__btns { display: flex; gap: 10px; }
.btn-ghost,
.btn-main {
  height: 44px;
  border-radius: var(--radius-md);
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  letter-spacing: 0.03em;
  cursor: pointer;
  border-bottom: none;
}
.btn-ghost:hover,
.btn-main:hover { border-bottom: none; }
.btn-ghost {
  padding: 0 18px;
  border: 1px solid var(--border-strong);
  color: var(--fg-muted);
  background: transparent;
}
.btn-ghost:hover { color: var(--fg); }
.btn-main {
  padding: 0 22px;
  border: none;
  background: var(--accent);
  color: var(--accent-ink);
}
.btn-ghost svg,
.btn-main svg { width: 16px; height: 16px; }

/* Stack the two-panel layout on narrow screens. */
@media (max-width: 800px) {
  .rec { grid-template-columns: 1fr; }
  .pl { flex-wrap: wrap; }
  .pl__who { width: auto; flex: 1 1 100%; }
  .pl__pad { flex-wrap: wrap; }

  /* Header chip drops below the title; standings stack one-per-row so the
     page never scrolls horizontally (the scorecard scrolls inside its card). */
  .brhead { flex-wrap: wrap; }
  .standings { flex-direction: column; }

  /* Score-entry form stacks: hole nav, then player + pad, then a full-width
     Save — so it stays thumb-friendly without horizontal scrolling. */
  .entry-form { flex-direction: column; align-items: stretch; }
  .entry-form__entry { flex-direction: column; align-items: stretch; }
  .entry-form__nav { width: 100%; }
  .entry-form__hole { flex: 1; }
  .entry-form__save { width: 100%; margin-left: 0; justify-content: center; }
}

/* =========================================================================
   Rail layout — main content + a fixed-width detail rail.
   Used by the dashboard and the filters page (with _next_round.html).
   ========================================================================= */

.rail-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: var(--space-5);
  align-items: start;
  width: 100%;
  max-width: 72rem;
  margin-inline: auto;
}
.rail-layout__main {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}
.rail-layout__aside { min-width: 0; }

/* Stack the rail on narrower screens. "Your next round" jumps to the top
   (above the dashboard title, filters, and recent matches) via grid order. */
@media (max-width: 60rem) {
  .rail-layout { grid-template-columns: 1fr; }
  .rail-layout__aside { order: -1; }
  /* Nothing booked → hide the whole rail when stacked (no empty-state card). */
  .rail-layout__aside--empty { display: none; }
}

/* "Your next round" rail */
.next-round { display: flex; flex-direction: column; gap: var(--space-3); }
.next-round__label { display: inline-flex; align-items: center; gap: var(--space-2); }
.next-round__label svg { width: 14px; height: 14px; }

.next-round__card {
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  background: var(--bg-elev);
  overflow: hidden;
}
.next-round__empty { padding: var(--space-4); }
.next-round__empty p { margin: 0; font-size: var(--text-sm); }
.next-round__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-4);
}
.next-round__course { font-size: 15px; font-weight: 600; display: block; }
.next-round__tees { font-size: 12px; color: var(--fg-muted); margin-top: 4px; }

/* Inset date / tee-time / format / forecast grid */
.next-round__box {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-4);
  margin: 0 var(--space-4);
  padding: var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg);
}
.next-round__box b {
  display: block;
  margin-top: 3px;
  font-family: var(--font-mono);
  font-size: 14px;
}

/* Group confirmation list */
.next-round__group {
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.next-round__member { display: flex; align-items: center; gap: var(--space-2); font-size: 13.5px; }
.next-round__member .av { width: 26px; height: 26px; font-size: 10px; }
.next-round__you { font-family: var(--font-mono); font-size: 10px; color: var(--fg-dim); }
.next-round__status {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.04em;
}
.next-round__status--host { color: var(--fg-dim); }
.next-round__status--in { color: var(--accent); }
/* Per-member remove (×). On the /rounds card the whole article is a stretched
   scorecard link (::after at z-index 1), so lift only this control above it —
   members still tap through to the scorecard, the × stays clickable. */
.next-round__remove-form { position: relative; z-index: 2; display: inline-flex; margin-left: var(--space-1); }
.next-round__remove {
  border: none;
  background: none;
  color: var(--fg-dim);
  cursor: pointer;
  font-size: 18px;
  line-height: 1;
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm);
}
.next-round__remove:hover,
.next-round__remove:focus-visible { color: var(--flag); }
/* "Back to round" link above the scorecard — returns to the round page. */
.round-back { margin-bottom: var(--space-4); font-size: var(--text-sm); }
.next-round__plus {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: 1px dashed var(--border-strong);
  color: var(--fg-dim);
  font-family: var(--font-mono);
  flex: 0 0 26px;
}
.next-round__open { color: var(--fg-dim); font-size: 13px; }
.next-round__invite {
  margin-left: auto;
  padding: 5px 12px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--fg-muted);
  border-bottom: 1px solid var(--border-strong);
}
.next-round__invite:hover { color: var(--accent); border-color: var(--accent); }

/* Footer: booking ref + price */
.next-round__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-4);
  border-top: 1px solid var(--border);
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--fg-muted);
}
.next-round__booked { display: inline-flex; align-items: center; gap: 6px; color: var(--fg-dim); }
.next-round__booked-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
  flex: 0 0 6px;
}
.next-round__foot b { color: var(--fg); }

.next-round__actions {
  display: flex;
  gap: var(--space-2);
  padding: 0 var(--space-4) var(--space-4);
}
.next-round__actions .btn-main,
.next-round__actions .btn-ghost {
  flex: 1;
  height: 40px;
  justify-content: center;
  padding-inline: var(--space-3);
  white-space: nowrap;
}

/* =========================================================================
   My rounds index (/rounds) — a list of booked rounds, each a tappable card
   reusing the .next-round__card styling. See rounds_index.html.
   ========================================================================= */

.rounds-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  margin-top: var(--space-4);
}

/* The whole card opens its scorecard: the primary "View scorecard" link is
   stretched over the card via ::after. The Directions button sits above that
   overlay (z-index) so it stays independently clickable. */
.round-card { position: relative; transition: border-color 120ms ease; }
.round-card:hover { border-color: var(--border-strong); }
.round-card__primary::after { content: ""; position: absolute; inset: 0; z-index: 1; }
.round-card__primary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.round-card__directions { position: relative; z-index: 2; }
/* Bigger course name on the index cards. */
.round-card .next-round__course { font-size: var(--text-md); }

/* Data grid reuses the dashboard card grid (.card-grid); inset so it lines up
   with the card's head/group sections (which pad by --space-4). */
.round-card__grid { margin: 0 var(--space-4); }
/* Blast countdown, shown during the pre-blast BOOKED window. */
.round-card__countdown { margin: 0 var(--space-4) var(--space-4); }

/* Manage row (Invite / Cancel) — above the stretched scorecard overlay so the
   controls stay clickable. The picker trigger and cancel form each take half. */
.round-card__manage { position: relative; z-index: 2; padding-top: 0; }
.round-card__manage > .picker,
.round-card__manage > .round-card__cancel-form { flex: 1; }
.round-card__manage .round-card__manage-btn {
  width: 100%;
  height: 40px;
  justify-content: center;
}
.round-card__cancel { color: var(--flag); border-color: var(--flag); }
/* The shared .btn-ghost:hover drops the bottom border — keep the full outline
   on the card's buttons (Directions, Invite, Cancel) so nothing flickers. */
.next-round__actions .btn-ghost:hover { border-bottom: 1px solid var(--border-strong); }
.next-round__actions .round-card__cancel:hover {
  color: var(--flag);
  background: rgba(255, 107, 91, 0.08);
  border-color: var(--flag);
}

/* Muted countdown pill for already-played rounds. */
.rec-pill--past { color: var(--fg-dim); border-color: var(--border-strong); }

/* "Played" separator between upcoming and past rounds. */
.rounds-divider {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: var(--space-6) 0 var(--space-2);
}
.rounds-divider::before,
.rounds-divider::after { content: ""; flex: 1; height: 1px; background: var(--border); }
.rounds-divider span {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fg-dim);
}

/* =========================================================================
   Reminders filter bar (dashboard) — secondary, client-side filter chips.
   Visual only for now; no wiring.
   ========================================================================= */

.filter-bar { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.filter-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  height: 40px;
  padding: 0 var(--space-3);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  background: var(--bg-input);
  color: var(--fg-muted);
  font-family: var(--font-sans);
  font-size: 13px;
  cursor: pointer;
  border-bottom: 1px solid var(--border-strong);
}
.filter-chip:hover { color: var(--fg); }
.filter-chip svg { width: 14px; height: 14px; flex: 0 0 14px; }
/* Search takes its own full-width row; the From/To/Time/Players chips wrap onto
   the line(s) below it and stretch to fill the same width as the search bar. */
.filter-chip--search { flex: 1 0 100%; min-width: 160px; color: var(--fg-dim); justify-content: flex-start; cursor: text; }
/* min-width: 0 lets the chips shrink below their content so a filled value
   never forces one chip onto its own line (where flex-grow would balloon it to
   full width). */
.filter-bar .filter-chip--select { flex: 1 1 140px; min-width: 0; }
.filter-chip--active { border-color: var(--accent); color: var(--accent); }
.filter-chip--active:hover { color: var(--accent); }

/* One-shot feedback flash on the chip the user just changed. The filters are
   instant/client-side, so this is pure acknowledgement. Motion-gated — under
   reduced-motion the existing .filter-chip--active state change is cue enough. */
@media (prefers-reduced-motion: no-preference) {
  .filter-chip--pulse { animation: filter-chip-pulse 0.45s ease-out; }
}
@keyframes filter-chip-pulse {
  0%   { border-color: var(--accent); box-shadow: 0 0 0 0 color-mix(in oklab, var(--accent) 55%, transparent); }
  100% { box-shadow: 0 0 0 6px color-mix(in oklab, var(--accent) 0%, transparent); }
}

/* Real form controls living inside a chip — strip their native chrome so the
   chip is the visible box. */
.filter-chip input,
.filter-chip select {
  border: none;
  background: transparent;
  color: inherit;
  font: inherit;
  outline: none;
  min-width: 0;
}
/* iOS Safari auto-zooms any focused control under 16px. On touch devices, bump
   the real inputs/selects to 16px so tapping a filter chip never zooms the page.
   Desktop keeps the compact 13px look. Also grow the chip to a 44px tap target. */
@media (pointer: coarse) {
  .filter-chip { height: 44px; }
  .filter-chip input,
  .filter-chip select {
    font-size: 16px;
  }
}
.filter-chip--search input { flex: 1; width: 100%; color: var(--fg); }
.filter-chip--search input::placeholder { color: var(--fg-dim); }
.filter-chip--select { cursor: pointer; }
.filter-chip--select select { appearance: none; -webkit-appearance: none; cursor: pointer; flex: 1 1 auto; }
.filter-chip__chevron { width: 14px; height: 14px; flex: 0 0 14px; pointer-events: none; }
/* From/To label sitting ahead of the select inside a chip. */
.filter-chip__lbl { color: var(--fg-dim); flex: 0 0 auto; }

/* =========================================================================
   Friends — the operator's golf group roster (avatar + phone + SMS status).
   ========================================================================= */

.friend-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.friend {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}
.friend__av { width: 38px; height: 38px; font-size: 13px; }
.friend__id { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.friend__name { font-size: 14.5px; font-weight: 600; display: flex; align-items: center; gap: var(--space-2); }
.friend__you {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  color: var(--accent);
  letter-spacing: 0.06em;
}
.friend__phone { font-size: 12px; color: var(--fg-dim); }
