/* styles.css — collapsed cascade of styles-v2..v13 (0.51.2). Built
   by concatenation in load order, so the cascade is identical to the
   twelve-link version it replaces. The lone @import (fonts) is hoisted
   to the top per CSS spec. Edit the source layers, not this file, until
   they are retired. */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&family=Inter+Tight:wght@600;700;800;900&family=JetBrains+Mono:wght@400;500;700&display=swap');


/* ===== styles-v2.css ===== */
/* ==========================================================================
   YesAndChains — Design system v2 (0.32.0)
   ==========================================================================
   Premium dark UI layer. Loaded AFTER the legacy <style> block in index.html
   so these rules cascade-win for anything we touch. Legacy classes that we
   don't override stay on their pre-0.32.0 styling — that's intentional, so
   this ship is incremental and reviewable.

   Authoring rules:
     • New tokens prefixed --v2-* (palette, type, spacing, motion).
     • Component classes use the legacy names (.btn, .card, .home-card, etc.)
       so render functions keep working without HTML edits.
     • All font-size declarations wrap calc(Npx + var(--text-delta)).
     • Motion respects prefers-reduced-motion via the existing
       html[data-motion="reduce"] handler.
   ========================================================================== */

/* ------- Font stack ------- */

/* ------- v2 tokens ---------------------------------------------------- */
:root {
  /* Graphite surface scale — richer than the legacy two-tone --bg/--bg2 pair.
     Layered so deeper cards naturally float above shallower ones. */
  --v2-surface-0:  #07120a;   /* page underlay, behind everything */
  --v2-surface-1:  #0c1810;   /* default bg */
  --v2-surface-2:  #131f17;   /* card */
  --v2-surface-3:  #1a2820;   /* card-elevated */
  --v2-surface-4:  #21332a;   /* hover */
  --v2-line-soft:  rgba(255,255,255,.04);
  --v2-line:       rgba(255,255,255,.08);
  --v2-line-strong:rgba(255,255,255,.14);

  /* Primary green tuned slightly cooler so the gold accent reads brighter. */
  --v2-green:        #6fd693;
  --v2-green-bright: #8aebab;
  --v2-green-deep:   #2f7a4a;

  /* Gold accent (metallic feel) — used for premium states, locked decisions,
     and the subscribed-user signal once the gate ships. */
  --v2-gold:        #d4af37;
  --v2-gold-bright: #f4cf57;
  --v2-gold-deep:   #8a6e1d;

  /* Semantic colors with better outdoor contrast. */
  --v2-amber: #ffc857;
  --v2-red:   #ff6b6b;
  --v2-blue:  #5cc8ff;

  /* Text scale (always wrap font-size in calc with --text-delta). */
  --v2-text-100: #f6fbf6;
  --v2-text-80:  #d9e6d9;
  --v2-text-60:  #a3b8a3;   /* muted (outdoor-readable) */
  --v2-text-40:  #6c8472;
  --v2-text-20:  #3a4a3e;

  /* Type — display for headings, sans for body, mono for code-adjacent. */
  --v2-font-display: 'Inter Tight', 'Inter', system-ui, sans-serif;
  --v2-font-sans:    'Inter', system-ui, -apple-system, sans-serif;
  --v2-font-mono:    'JetBrains Mono', ui-monospace, 'SF Mono', monospace;

  /* Spacing scale (4-pt rhythm). */
  --v2-s-1:  2px;
  --v2-s-2:  4px;
  --v2-s-3:  8px;
  --v2-s-4:  12px;
  --v2-s-5:  16px;
  --v2-s-6:  20px;
  --v2-s-7:  24px;
  --v2-s-8:  32px;
  --v2-s-9:  48px;
  --v2-s-10: 64px;

  /* Radii. */
  --v2-r-sm:   6px;
  --v2-r-md:   10px;
  --v2-r-lg:   14px;
  --v2-r-xl:   20px;
  --v2-r-pill: 999px;

  /* Shadows — soft, layered, premium. Tuned for dark mode. */
  --v2-shadow-1: 0 1px 2px rgba(0,0,0,.45);
  --v2-shadow-2: 0 6px 18px -8px rgba(0,0,0,.55), 0 2px 4px rgba(0,0,0,.35);
  --v2-shadow-3: 0 18px 38px -16px rgba(0,0,0,.62), 0 4px 12px rgba(0,0,0,.4);
  --v2-glow-green: 0 0 0 1px rgba(111,214,147,.35), 0 8px 28px -8px rgba(111,214,147,.4);
  --v2-glow-gold:  0 0 0 1px rgba(212,175,55,.45), 0 8px 28px -8px rgba(212,175,55,.45);

  /* Motion. */
  --v2-dur-fast:  120ms;
  --v2-dur-base:  220ms;
  --v2-dur-slow:  380ms;
  --v2-ease-out:  cubic-bezier(.16, 1, .3, 1);
  --v2-ease-spring: cubic-bezier(.34, 1.56, .64, 1);   /* gentle overshoot */
  --v2-ease-in:   cubic-bezier(.55, .055, .675, .19);
}

/* Honor the existing data-theme switches — light theme still works. */
html[data-theme="light"] {
  --v2-surface-0:  #f7f9f5;
  --v2-surface-1:  #ffffff;
  --v2-surface-2:  #f1f4ee;
  --v2-surface-3:  #e7ede2;
  --v2-surface-4:  #dee6d7;
  --v2-line-soft:  rgba(15,30,15,.04);
  --v2-line:       rgba(15,30,15,.08);
  --v2-line-strong:rgba(15,30,15,.16);
  --v2-green:        #2f8a4f;
  --v2-green-bright: #1f6a3a;
  --v2-green-deep:   #134d28;
  --v2-text-100: #0d1410;
  --v2-text-80:  #2d3a30;
  --v2-text-60:  #4f5e54;
  --v2-text-40:  #7a8a7e;
  --v2-text-20:  #c2cbc4;
  --v2-shadow-1: 0 1px 2px rgba(13,20,16,.08);
  --v2-shadow-2: 0 6px 18px -8px rgba(13,20,16,.18), 0 2px 4px rgba(13,20,16,.08);
  --v2-shadow-3: 0 18px 38px -16px rgba(13,20,16,.22);
}

/* ------- Body shell ---------------------------------------------------- */
body {
  font-family: var(--v2-font-sans);
  background:
    radial-gradient(1200px 700px at 20% -10%, rgba(111,214,147,.06), transparent 60%),
    radial-gradient(900px 500px at 110% 110%, rgba(212,175,55,.05), transparent 55%),
    var(--v2-surface-1);
  color: var(--v2-text-100);
  font-feature-settings: 'ss01' on, 'cv11' on;   /* Inter stylistic tweaks */
  letter-spacing: -0.005em;
}

/* Tighter base scrollbar feel (still hidden by legacy rule for webkit). */
* { font-family: var(--v2-font-sans); }

/* Display family on hole numbers, hero text, headings. */
.v2-display, .hole-num, .home-welcome-line, .wiz-step-title, .modal-title {
  font-family: var(--v2-font-display);
  letter-spacing: -0.025em;
  font-feature-settings: 'ss01' on, 'cv11' on, 'tnum' on;
}

/* Mono on code-adjacent UI (versions, IDs, distances when we want technical feel). */
.v2-mono { font-family: var(--v2-font-mono); letter-spacing: 0; }

/* ------- Header -------------------------------------------------------- */
.app-header {
  background: linear-gradient(180deg, var(--v2-surface-2) 0%, var(--v2-surface-1) 100%);
  border-bottom: 1px solid var(--v2-line);
  padding: 12px 16px;
  position: relative;
}
.app-header::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--v2-green), transparent);
  opacity: .35;
  pointer-events: none;
}

.app-brand-yesand {
  font-family: var(--v2-font-display);
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--v2-text-80);
  opacity: 1;
}
.app-brand-dots { color: var(--v2-text-40); opacity: 1; }
.app-brand-logo {
  filter: drop-shadow(0 2px 6px rgba(111,214,147,.18));
  transition: transform var(--v2-dur-base) var(--v2-ease-spring),
              filter var(--v2-dur-base) var(--v2-ease-out);
}
.app-brand:hover .app-brand-logo {
  transform: translateY(-1px) scale(1.04);
  filter: drop-shadow(0 4px 12px rgba(111,214,147,.32));
}

/* Auth pill — refined. */
.auth-pill {
  background: var(--v2-surface-3);
  border: 1px solid var(--v2-line);
  border-radius: var(--v2-r-pill);
  color: var(--v2-text-60);
  font-family: var(--v2-font-sans);
  font-weight: 600;
  letter-spacing: 0.04em;
  transition: background var(--v2-dur-base) var(--v2-ease-out),
              border-color var(--v2-dur-base) var(--v2-ease-out),
              color var(--v2-dur-base) var(--v2-ease-out),
              transform var(--v2-dur-fast) var(--v2-ease-out);
}
.auth-pill:hover { background: var(--v2-surface-4); border-color: var(--v2-line-strong); color: var(--v2-text-100); }
.auth-pill:active { transform: scale(.97); }
.auth-pill.signed-in {
  background: linear-gradient(135deg, rgba(111,214,147,.18), rgba(111,214,147,.06));
  border-color: rgba(111,214,147,.5);
  color: var(--v2-green-bright);
}

/* ------- Buttons ------------------------------------------------------- */
.btn {
  font-family: var(--v2-font-sans);
  font-weight: 600;
  border-radius: var(--v2-r-md);
  padding: 10px 16px;
  font-size: calc(14px + var(--text-delta));
  letter-spacing: -0.005em;
  line-height: 1.25;
  border: 1px solid transparent;
  transition: background var(--v2-dur-base) var(--v2-ease-out),
              border-color var(--v2-dur-base) var(--v2-ease-out),
              color var(--v2-dur-base) var(--v2-ease-out),
              transform var(--v2-dur-fast) var(--v2-ease-spring),
              box-shadow var(--v2-dur-base) var(--v2-ease-out);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 44px;          /* touch target */
}
.btn:active:not(:disabled) { transform: scale(.97); }
.btn:disabled { opacity: .45; cursor: not-allowed; }

.btn-primary {
  background: linear-gradient(180deg, var(--v2-green-bright), var(--v2-green));
  color: #0a1410;
  border-color: var(--v2-green);
  box-shadow: var(--v2-shadow-1), inset 0 1px 0 rgba(255,255,255,.18);
}
.btn-primary:hover:not(:disabled) {
  filter: brightness(1.05);
  box-shadow: var(--v2-glow-green);
}

.btn-secondary {
  background: var(--v2-surface-3);
  color: var(--v2-text-100);
  border-color: var(--v2-line);
}
.btn-secondary:hover:not(:disabled) {
  background: var(--v2-surface-4);
  border-color: var(--v2-line-strong);
}

/* Premium-tier (gold) — used by subscription gate + locked-decision flair. */
.btn-premium {
  background: linear-gradient(180deg, var(--v2-gold-bright), var(--v2-gold));
  color: #1a1305;
  border-color: var(--v2-gold);
  box-shadow: var(--v2-shadow-1), inset 0 1px 0 rgba(255,255,255,.28);
}
.btn-premium:hover:not(:disabled) {
  filter: brightness(1.06);
  box-shadow: var(--v2-glow-gold);
}

/* Ghost — flat, low-emphasis. */
.btn-ghost {
  background: transparent;
  color: var(--v2-text-60);
  border-color: transparent;
}
.btn-ghost:hover:not(:disabled) {
  color: var(--v2-text-100);
  background: var(--v2-line-soft);
}

/* Icon-only buttons. */
.btn-icon { padding: 8px; width: 44px; height: 44px; }

/* Legacy .link-btn polished. */
.link-btn {
  font-family: var(--v2-font-sans);
  color: var(--v2-green);
  background: none;
  border: none;
  cursor: pointer;
  padding: 4px 0;
  font-weight: 600;
  text-decoration: none;
  transition: color var(--v2-dur-fast) var(--v2-ease-out);
}
.link-btn:hover { color: var(--v2-green-bright); }

/* ------- Cards --------------------------------------------------------- */
.card, .home-card, .review-card, .bag-section-header {
  background: var(--v2-surface-2);
  border: 1px solid var(--v2-line);
  border-radius: var(--v2-r-lg);
  box-shadow: var(--v2-shadow-1);
  transition: background var(--v2-dur-base) var(--v2-ease-out),
              border-color var(--v2-dur-base) var(--v2-ease-out),
              transform var(--v2-dur-fast) var(--v2-ease-spring),
              box-shadow var(--v2-dur-base) var(--v2-ease-out);
}
.home-card { padding: 14px 16px; }
.home-card:hover { background: var(--v2-surface-3); border-color: var(--v2-line-strong); transform: translateY(-1px); box-shadow: var(--v2-shadow-2); }
.home-card:active { transform: scale(.985); }

/* Primary CTA card (green tint). */
.home-card.home-card-primary,
button.home-card[style*="--green2"] {
  background: linear-gradient(135deg, rgba(111,214,147,.14), rgba(111,214,147,.04));
  border-color: rgba(111,214,147,.45);
}
.home-card.home-card-primary .home-card-title { color: var(--v2-green-bright); }
.home-card.home-card-primary:hover {
  background: linear-gradient(135deg, rgba(111,214,147,.22), rgba(111,214,147,.06));
  box-shadow: var(--v2-glow-green);
}

.home-card-title {
  font-family: var(--v2-font-display);
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--v2-text-100);
}
.home-card-sub { color: var(--v2-text-60); font-size: calc(12px + var(--text-delta)); }
.home-card-arrow { color: var(--v2-text-40); transition: transform var(--v2-dur-base) var(--v2-ease-spring); }
.home-card:hover .home-card-arrow { transform: translateX(3px); color: var(--v2-green); }

/* ------- Section headers (collapsible) -------------------------------- */
.bag-section-header { padding: 14px 16px; min-height: 52px; gap: 12px; }
.bag-section-header:hover { background: var(--v2-surface-3); border-color: var(--v2-line-strong); }
.bag-section-label { font-family: var(--v2-font-display); font-weight: 700; letter-spacing: -0.01em; color: var(--v2-text-100); }
.bag-section-chevron { color: var(--v2-text-40); transition: transform var(--v2-dur-base) var(--v2-ease-spring); }
.bag-section-header:not(.collapsed) .bag-section-chevron { transform: rotate(0deg); }
.bag-section-header.collapsed .bag-section-chevron { transform: rotate(-90deg); }

.bag-section-empty {
  background: var(--v2-surface-2);
  border: 1px dashed var(--v2-line);
  border-radius: var(--v2-r-md);
  color: var(--v2-text-60);
}

/* ------- Pills + chips ------------------------------------------------ */
.bag-count, .throw-chip, .wind-chip {
  background: var(--v2-surface-3);
  border: 1px solid var(--v2-line);
  color: var(--v2-text-80);
  font-family: var(--v2-font-sans);
  font-weight: 600;
  letter-spacing: -0.005em;
  border-radius: var(--v2-r-pill);
  padding: 4px 10px;
}

/* ------- Inputs -------------------------------------------------------- */
input, select, textarea {
  background: var(--v2-surface-2);
  border: 1px solid var(--v2-line);
  border-radius: var(--v2-r-md);
  color: var(--v2-text-100);
  font-family: var(--v2-font-sans);
  padding: 12px 14px;
  transition: border-color var(--v2-dur-base) var(--v2-ease-out),
              background var(--v2-dur-base) var(--v2-ease-out),
              box-shadow var(--v2-dur-base) var(--v2-ease-out);
}
input:focus, select:focus, textarea:focus {
  border-color: var(--v2-green);
  background: var(--v2-surface-3);
  box-shadow: 0 0 0 3px rgba(111,214,147,.18);
}
input::placeholder, textarea::placeholder { color: var(--v2-text-40); }
.field-label {
  font-family: var(--v2-font-sans);
  font-weight: 600;
  font-size: calc(12px + var(--text-delta));
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--v2-text-60);
  margin-bottom: 6px;
  display: block;
}

/* ------- Modal --------------------------------------------------------- */
.modal-scrim { background: rgba(7,15,11,.62); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); }
.modal {
  background: var(--v2-surface-2);
  border: 1px solid var(--v2-line);
  border-radius: var(--v2-r-xl);
  box-shadow: var(--v2-shadow-3);
  overflow: hidden;
  animation: v2-modal-in var(--v2-dur-slow) var(--v2-ease-spring);
}
@keyframes v2-modal-in {
  from { opacity: 0; transform: translateY(12px) scale(.97); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
.modal-header { padding: 18px 20px 12px; border-bottom: 1px solid var(--v2-line); }
.modal-title {
  font-family: var(--v2-font-display);
  font-weight: 800;
  letter-spacing: -0.02em;
  font-size: calc(20px + var(--text-delta));
}
.modal-body { padding: 16px 20px; }
.modal-actions { padding: 14px 18px; border-top: 1px solid var(--v2-line); display: flex; gap: 10px; justify-content: flex-end; }

/* ------- Wizard header (shared by Add Disc, Add Course, Start Round) -- */
.wiz-header {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 16px;
  background: linear-gradient(180deg, var(--v2-surface-2), var(--v2-surface-1));
  border-bottom: 1px solid var(--v2-line);
}
.wiz-back {
  font-size: calc(20px + var(--text-delta));
  background: var(--v2-surface-3);
  border: 1px solid var(--v2-line);
  border-radius: var(--v2-r-md);
  color: var(--v2-text-100);
  width: 40px; height: 40px;
  cursor: pointer;
  transition: background var(--v2-dur-fast) var(--v2-ease-out), transform var(--v2-dur-fast) var(--v2-ease-out);
}
.wiz-back:hover { background: var(--v2-surface-4); }
.wiz-back:active { transform: scale(.95); }
.wiz-step-label { font-size: calc(11px + var(--text-delta)); text-transform: uppercase; letter-spacing: 0.08em; color: var(--v2-text-60); margin-bottom: 2px; }
.wiz-step-title { font-family: var(--v2-font-display); font-weight: 800; font-size: calc(20px + var(--text-delta)); letter-spacing: -0.02em; color: var(--v2-text-100); }

/* ------- Home — hero welcome line ------------------------------------- */
.home-welcome-line {
  font-family: var(--v2-font-display);
  font-size: calc(28px + var(--text-delta));
  font-weight: 800;
  letter-spacing: -0.025em;
  color: var(--v2-green-bright);
  background: linear-gradient(135deg, var(--v2-green-bright), var(--v2-green));
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  margin: 8px 4px 18px;
  line-height: 1.15;
}

/* ------- Home — section titles inside Start round picker -------------- */
.home-section-title {
  font-family: var(--v2-font-sans);
  font-weight: 700;
  font-size: calc(12px + var(--text-delta));
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--v2-text-60);
  margin: 18px 4px 8px;
}

/* ------- Round view — hole number is the hero ------------------------- */
.hole-num {
  font-family: var(--v2-font-display);
  font-weight: 900;
  font-size: calc(108px + var(--text-delta));
  line-height: 0.95;
  letter-spacing: -0.05em;
  background: linear-gradient(180deg, var(--v2-text-100), var(--v2-text-60));
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  text-shadow: 0 8px 28px rgba(0,0,0,.45);
}
.hole-pin {
  font-family: var(--v2-font-sans);
  font-weight: 600;
  font-size: calc(13px + var(--text-delta));
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--v2-text-60);
  margin-top: 6px;
}
.hole-info-table {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px 16px;
  margin-top: 14px;
  padding: 14px;
  background: var(--v2-surface-2);
  border: 1px solid var(--v2-line);
  border-radius: var(--v2-r-lg);
  box-shadow: var(--v2-shadow-1);
}
.hole-info-label {
  font-family: var(--v2-font-sans);
  font-weight: 600;
  font-size: calc(10px + var(--text-delta));
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--v2-text-60);
  text-align: center;
}
.hole-info-value {
  font-family: var(--v2-font-display);
  font-weight: 800;
  font-size: calc(18px + var(--text-delta));
  color: var(--v2-text-100);
  letter-spacing: -0.015em;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

/* ------- Round view — score widget (spring on change) ----------------- */
.score-num {
  font-family: var(--v2-font-display);
  font-weight: 900;
  font-size: calc(72px + var(--text-delta));
  letter-spacing: -0.04em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  transition: transform var(--v2-dur-base) var(--v2-ease-spring),
              color var(--v2-dur-base) var(--v2-ease-out);
}
.score-pill {
  background: var(--v2-surface-3);
  border: 1px solid var(--v2-line-strong);
  border-radius: var(--v2-r-pill);
  width: 48px; height: 48px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: calc(22px + var(--text-delta));
  font-weight: 800;
  color: var(--v2-text-100);
  cursor: pointer;
  transition: background var(--v2-dur-fast) var(--v2-ease-out),
              transform var(--v2-dur-fast) var(--v2-ease-spring),
              box-shadow var(--v2-dur-fast) var(--v2-ease-out);
  box-shadow: var(--v2-shadow-1);
}
.score-pill:hover:not(:disabled) { background: var(--v2-surface-4); box-shadow: var(--v2-shadow-2); }
.score-pill:active:not(:disabled) { transform: scale(.9); }
.score-pill:disabled { opacity: .35; cursor: not-allowed; }

/* Score-tier colors map onto v2 palette but keep the existing semantics. */
.score-ace      { color: var(--v2-gold-bright); text-shadow: 0 0 24px rgba(244,207,87,.5); }
.score-eagle    { color: #7ed7ff; }
.score-albatross,
.score-condor,
.score-ostrich  { color: #5cc8ff; }
.score-birdie   { color: var(--v2-green-bright); }
.score-par      { color: var(--v2-text-100); }
.score-bogey    { color: var(--v2-amber); }
.score-double   { color: var(--v2-red); }
.score-triple,
.score-quad     { color: #c79ce4; }

/* Penalty pill — softer than the strokes pills. */
.penalty-pill {
  background: var(--v2-surface-3);
  border: 1px solid var(--v2-line);
  border-radius: var(--v2-r-pill);
  width: 28px; height: 28px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: calc(16px + var(--text-delta));
  color: var(--v2-text-80);
  cursor: pointer;
}

/* ------- Live pin distance chip -------------------------------------- */
#livePinDistance {
  background: linear-gradient(135deg, rgba(111,214,147,.14), rgba(111,214,147,.04));
  border-color: rgba(111,214,147,.4);
  color: var(--v2-green-bright);
  font-family: var(--v2-font-display);
  font-weight: 800;
  letter-spacing: -0.01em;
}

/* ------- Caddy recommender card -------------------------------------- */
.caddy-rec {
  background: var(--v2-surface-2);
  border: 1px solid var(--v2-line);
  border-radius: var(--v2-r-lg);
  padding: 14px 16px;
  margin-top: 10px;
  box-shadow: var(--v2-shadow-1);
}
.caddy-rec-title {
  font-family: var(--v2-font-display);
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--v2-text-100);
  font-size: calc(13px + var(--text-delta));
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.caddy-rec-idle {
  background: var(--v2-surface-2);
  border-style: dashed;
}
.caddy-rec-disc {
  font-family: var(--v2-font-display);
  font-weight: 800;
  font-size: calc(22px + var(--text-delta));
  color: var(--v2-green-bright);
  letter-spacing: -0.02em;
  margin: 6px 0 2px;
}
.caddy-rec-line, .caddy-rec-aim {
  font-size: calc(13px + var(--text-delta));
  color: var(--v2-text-80);
}
.caddy-rec-meta-label {
  font-size: calc(10px + var(--text-delta));
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--v2-text-60);
  margin-right: 6px;
}
.caddy-rec-why {
  margin-top: 8px;
  font-size: calc(13px + var(--text-delta));
  color: var(--v2-text-60);
  line-height: 1.5;
  font-style: italic;
}
.caddy-rec-confidence {
  font-family: var(--v2-font-sans);
  font-weight: 700;
  font-size: calc(11px + var(--text-delta));
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.caddy-rec-refresh {
  background: var(--v2-surface-3);
  border: 1px solid var(--v2-line);
  color: var(--v2-text-80);
  width: 32px; height: 32px;
  border-radius: var(--v2-r-pill);
  cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
}
.caddy-rec-refresh:hover { background: var(--v2-surface-4); color: var(--v2-text-100); }

/* ------- Shared scorecard (multi-player) ----------------------------- */
.shared-scorecard {
  background: var(--v2-surface-2);
  border: 1px solid var(--v2-line);
  border-radius: var(--v2-r-lg);
  box-shadow: var(--v2-shadow-1);
}

/* ------- Stroke chain ------------------------------------------------- */
.stroke-chain-chip {
  font-family: var(--v2-font-mono);
  font-weight: 700;
  letter-spacing: 0;
  background: var(--v2-surface-3);
  border-color: var(--v2-line);
}

/* ------- View transitions -------------------------------------------- */
@media (prefers-reduced-motion: no-preference) {
  .main {
    animation: v2-view-in var(--v2-dur-base) var(--v2-ease-out);
  }
}
@keyframes v2-view-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ------- Logo treatment ---------------------------------------------- */
.logo-icon {
  filter: drop-shadow(0 2px 6px rgba(111,214,147,.18));
  transition: transform var(--v2-dur-base) var(--v2-ease-spring);
}
.home-card:hover .logo-icon { transform: scale(1.08); }

/* ------- Install prompt + premium nudge (used by PWA + subscription) - */
.install-banner {
  position: fixed;
  left: 50%; bottom: 16px;
  transform: translateX(-50%);
  z-index: 1100;
  background: linear-gradient(135deg, var(--v2-surface-3), var(--v2-surface-2));
  border: 1px solid var(--v2-line-strong);
  border-radius: var(--v2-r-xl);
  box-shadow: var(--v2-shadow-3);
  padding: 12px 16px;
  display: flex;
  align-items: center;
  gap: 12px;
  max-width: 92vw;
  width: 480px;
  animation: v2-modal-in var(--v2-dur-slow) var(--v2-ease-spring);
}
.install-banner-icon { font-size: calc(22px + var(--text-delta)); }
.install-banner-body { flex: 1; }
.install-banner-title { font-family: var(--v2-font-display); font-weight: 700; color: var(--v2-text-100); font-size: calc(14px + var(--text-delta)); }
.install-banner-sub   { font-size: calc(12px + var(--text-delta)); color: var(--v2-text-60); margin-top: 2px; }
.install-banner-close {
  background: transparent;
  border: none;
  color: var(--v2-text-40);
  font-size: calc(20px + var(--text-delta));
  cursor: pointer;
  padding: 4px 8px;
  border-radius: var(--v2-r-md);
}
.install-banner-close:hover { color: var(--v2-text-100); background: var(--v2-line-soft); }

/* ------- Round history: pending-cloud-sync chip ----------------------- */
.rh-pending-sync {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-family: var(--v2-font-sans);
  font-weight: 700;
  font-size: calc(10px + var(--text-delta));
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--v2-amber);
  background: rgba(255, 200, 87, 0.12);
  border: 1px solid rgba(255, 200, 87, 0.4);
  border-radius: var(--v2-r-pill);
  padding: 1px 7px;
  margin-left: 6px;
  vertical-align: middle;
  white-space: nowrap;
}

/* ------- Premium / subscription chrome -------------------------------- */
.premium-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-family: var(--v2-font-sans);
  font-weight: 800;
  font-size: calc(10px + var(--text-delta));
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--v2-gold-bright);
  background: linear-gradient(135deg, rgba(212,175,55,.16), rgba(212,175,55,.04));
  border: 1px solid rgba(212,175,55,.45);
  border-radius: var(--v2-r-pill);
  padding: 2px 8px;
}

/* ------- Toast --------------------------------------------------------- */
.toast {
  background: var(--v2-surface-3);
  border: 1px solid var(--v2-line-strong);
  border-radius: var(--v2-r-lg);
  box-shadow: var(--v2-shadow-3);
  color: var(--v2-text-100);
  font-weight: 600;
  letter-spacing: -0.005em;
}

/* ------- Spacer reset -------------------------------------------------- */
.spacer { height: 80px; }

/* ===== styles-v3.css ===== */
/* ==========================================================================
   YesAndChains. Design system v3 polish layer (0.37.0).
   ==========================================================================
   Loaded after styles-v2.css; cascade-wins for anything below. Same
   authoring rules as v2:
     - Wrap font-size in calc(Npx + var(--text-delta)).
     - Respect prefers-reduced-motion via html[data-motion="reduce"].
     - Touch targets stay at 40px+ minimum.
     - Reuse v2 tokens; only add --v3-* when v2 doesn't already have it.

   Coverage map (the "50 polish items" delivered in 0.37.0):
   1.  Smoother focus ring with 3-layer depth (outer haze + crisp mid + inner gap)
   2.  Buttons: gentle pressed-in shadow inset on :active for tactile feedback
   3.  Primary button: animated gradient sweep on hover
   4.  Cards: parallax-ish hover (translateY -2 + shadow lift + border glow)
   5.  Disc cards: subtle radial sheen anchored top-left to imply roundness
   6.  Score widget number: smooth color-shift across over/par/under transitions
   7.  Active-bag chip in header: pulsing border ring
   8.  Wind chip: rotate the direction arrow with eased motion when wind shifts
   9.  Sync chip: spinning gradient ring while syncing
   10. Brand-button (header logo): subtle scale on hover, pointer cursor
   11. Round-history row: slide-in animation on first render of each card
   12. Disc-add wizard tabs: sliding underline indicator
   13. Custom scrollbar refinements (thinner, gold thumb on light areas)
   14. Toast animations: gentle bounce instead of linear fade
   15. Modal: backdrop saturation boost + blur on the modal entrance
   16. Empty states: dotted-border "drop zone" feel
   17. Section dividers: hairline gradient instead of flat
   18. Pin chip on round-view: tiny basket SVG with pulse animation
   19. In-progress round banner: subtle slow shimmer along the left edge
   20. Wind speed numbers: tabular-nums everywhere strokes/distance are shown
   21. Stat badges: glassmorphism look (rgba bg + backdrop-filter blur)
   22. Header active-route indicator: rising-dot accent under current nav item
   23. PWA install banner: refined gradient + dismiss button styling
   24. Disabled buttons: 40% opacity + diagonal stripe pattern overlay
   25. Empty-bag illustration: floating disc emoji with gentle bob animation
   26. Search input focus: gold underline appears beneath the field
   27. Course-card hover: subtle parallax on the basket icon
   28. Round-trend chart: smoother dotted gridlines, tighter axis labels
   29. Trend chart range chips: animated press feedback + active glow
   30. Layout-picker chips: outline + check-icon when selected
   31. Per-shot wizard step indicator: progress bar fills smoothly
   32. Round-recap card: gradient border for personal-best rounds
   33. Login pill: idle pulse to draw attention pre-sign-in
   34. Modal entry: spring scale (0.96 to 1.02 to 1.0) instead of linear
   35. Disc-card delete button: red glow on hover only
   36. Hole-card map: gentle ken-burns pan on the satellite image
   37. Strategy chips: per-shape icon coloring
   38. Score recap grid tiles: scale-in stagger animation
   39. Contribute chips: friendly check-mark when selected
   40. Settings rows: row-level hover background
   41. Field labels: tighter letter-spacing in uppercase
   42. Tabular numerics on every score / distance / time display
   43. Premium chip: subtle moving gradient (gold sheen)
   44. Disc-photo upload zone: dashed border + pulse on drag-over
   45. Course-detail header buttons: equal-weight visual rhythm
   46. Pin-position labels: badge styling with letter spacing
   47. Round-history filter chips: animated count badge
   48. Active-tab gradient underline (for any tab UI)
   49. Multi-line text input: subtle bottom shadow when focused
   50. Footer action bar: refined backdrop blur + gradient top edge
   ========================================================================== */

/* ------- v3 tokens (only where v2 didn't cover) ------- */
:root {
  --v3-glow-green:        0 0 14px rgba(111, 214, 147, .35);
  --v3-glow-gold:         0 0 16px rgba(212, 175, 55, .35);
  --v3-glow-red:          0 0 12px rgba(239, 83, 80, .30);
  --v3-ring-inner:        rgba(111, 214, 147, .55);
  --v3-ring-outer:        rgba(111, 214, 147, .15);
  --v3-glass-bg:          rgba(255, 255, 255, .04);
  --v3-glass-border:      rgba(255, 255, 255, .10);
  --v3-spring:            cubic-bezier(.34, 1.56, .64, 1);
  --v3-overshoot:         cubic-bezier(.22, 1.55, .36, 1);
  --v3-stripe:            repeating-linear-gradient(45deg, rgba(255,255,255,.04) 0 6px, transparent 6px 12px);
}

/* ============== 1. Focus rings ============== */
:focus-visible {
  outline: 2px solid var(--v2-green, #6fd693);
  outline-offset: 3px;
  box-shadow: 0 0 0 4px var(--v3-ring-outer);
  border-radius: inherit;
}

/* ============== 2-3. Button refinements ============== */
.btn {
  position: relative;
  isolation: isolate;
}
.btn:active {
  transform: translateY(1px);
  box-shadow: inset 0 1px 0 rgba(0,0,0,.20), 0 1px 2px rgba(0,0,0,.20);
}
.btn-primary {
  background: linear-gradient(180deg, var(--v2-green-bright, #8aebab) 0%, var(--v2-green, #6fd693) 60%, var(--v2-green-deep, #2f7a4a) 100%);
  box-shadow: 0 1px 0 rgba(255,255,255,.18) inset, 0 4px 12px rgba(47,122,74,.30);
}
.btn-primary::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: linear-gradient(120deg, transparent 35%, rgba(255,255,255,.18) 50%, transparent 65%);
  background-size: 200% 100%;
  background-position: 200% 0;
  transition: background-position .6s ease;
  pointer-events: none;
  z-index: 1;
}
.btn-primary:hover::before { background-position: -50% 0; }

/* ============== 4-5. Card hover lift + disc sheen ============== */
.disc-card, .home-card, .rh-card, .bag-section-header {
  transition: transform .18s var(--v3-overshoot), box-shadow .18s ease, border-color .18s ease;
}
.disc-card:hover, .home-card:hover, .rh-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 22px rgba(0,0,0,.30), 0 2px 4px rgba(0,0,0,.20);
  border-color: var(--v2-line-strong, rgba(255,255,255,.16));
}
.disc-card { position: relative; overflow: hidden; }
.disc-card::after {
  content: "";
  position: absolute;
  top: -25%;
  left: -25%;
  width: 70%;
  height: 70%;
  background: radial-gradient(circle, rgba(255,255,255,.06) 0%, transparent 60%);
  pointer-events: none;
  opacity: .55;
}

/* ============== 6. Score widget gradient ============== */
.score-widget, .score-display {
  font-variant-numeric: tabular-nums;
  transition: color .25s ease;
}

/* ============== 7. Active bag chip pulse ============== */
.bag-count {
  position: relative;
}
.bag-count::after {
  content: "";
  position: absolute;
  inset: -2px;
  border-radius: inherit;
  border: 1.5px solid var(--v3-ring-inner);
  opacity: 0;
  animation: yacPulseRing 2.6s ease-in-out infinite;
  pointer-events: none;
}
@keyframes yacPulseRing {
  0%, 100% { opacity: 0; transform: scale(.96); }
  40%      { opacity: .65; transform: scale(1.02); }
  80%      { opacity: 0; transform: scale(1.06); }
}
html[data-motion="reduce"] .bag-count::after { animation: none; }

/* ============== 8. Wind chip arrow eased rotation ============== */
.wind-chip svg, .wind-chip .wind-arrow {
  transition: transform .55s var(--v3-spring);
}

/* ============== 9. Sync chip spinning ring ============== */
.sync-status[data-state="syncing"]::before {
  content: "";
  display: inline-block;
  width: 10px; height: 10px;
  margin-right: 6px;
  border: 1.5px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: yacSpin 1s linear infinite;
  vertical-align: middle;
}
@keyframes yacSpin { to { transform: rotate(360deg); } }
html[data-motion="reduce"] .sync-status[data-state="syncing"]::before { animation: none; }

/* ============== 10. Brand button hover ============== */
.app-brand {
  transition: transform .15s ease, opacity .15s ease;
  border-radius: 6px;
}
.app-brand:hover { transform: scale(1.02); opacity: .94; }
.app-brand:active { transform: scale(.99); }
.app-brand:focus-visible { outline: 2px solid var(--v2-green, #6fd693); outline-offset: 4px; }

/* ============== 11. Round-history row slide-in ============== */
@keyframes yacSlideIn {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
.rh-card { animation: yacSlideIn .35s var(--v3-overshoot) both; }
.rh-card:nth-child(2) { animation-delay: .04s; }
.rh-card:nth-child(3) { animation-delay: .08s; }
.rh-card:nth-child(4) { animation-delay: .12s; }
.rh-card:nth-child(5) { animation-delay: .16s; }
html[data-motion="reduce"] .rh-card { animation: none; }

/* ============== 12. Wizard tab sliding underline ============== */
.wiz-tab { position: relative; }
.wiz-tab.active::after {
  content: "";
  position: absolute;
  left: 12%; right: 12%;
  bottom: -2px;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--v2-green, #6fd693), transparent);
  border-radius: 2px;
  animation: yacUnderlineGrow .25s var(--v3-overshoot) both;
}
@keyframes yacUnderlineGrow { from { transform: scaleX(.2); opacity: 0; } to { transform: scaleX(1); opacity: 1; } }

/* ============== 13. Custom scrollbar refinements ============== */
* { scrollbar-width: thin; scrollbar-color: var(--v2-surface-3) transparent; }
*::-webkit-scrollbar { width: 8px; height: 8px; }
*::-webkit-scrollbar-thumb { background: var(--v2-surface-3); border-radius: 999px; }
*::-webkit-scrollbar-thumb:hover { background: var(--v2-surface-4); }
*::-webkit-scrollbar-track { background: transparent; }

/* ============== 14. Toast bounce-in ============== */
#toast-host > div {
  transition: opacity .22s ease, transform .25s var(--v3-overshoot) !important;
}

/* ============== 15. Modal backdrop ============== */
#modalScrim.show {
  backdrop-filter: blur(10px) saturate(120%);
  -webkit-backdrop-filter: blur(10px) saturate(120%);
}
#modalScrim .modal {
  animation: yacModalIn .28s var(--v3-spring) both;
}
@keyframes yacModalIn {
  from { opacity: 0; transform: translateY(8px) scale(.96); }
  60%  { opacity: 1; transform: translateY(0) scale(1.02); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
html[data-motion="reduce"] #modalScrim .modal { animation: none; }

/* ============== 16. Empty-state drop-zone feel ============== */
.empty, .bag-section-empty {
  border: 1.5px dashed var(--v2-line, rgba(255,255,255,.08));
  border-radius: var(--r-md, 14px);
  background: var(--v2-surface-1, var(--bg2));
  text-align: center;
  padding: 22px 18px;
}
.empty-icon, .empty .icon { font-size: 32px; opacity: .7; margin-bottom: 6px; animation: yacBob 3.4s ease-in-out infinite; display: inline-block; }
@keyframes yacBob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-4px); } }
html[data-motion="reduce"] .empty-icon, html[data-motion="reduce"] .empty .icon { animation: none; }

/* ============== 17. Section divider hairline gradient ============== */
hr, .section-divider {
  border: none;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--v2-line-strong, rgba(255,255,255,.14)) 50%, transparent);
  margin: 16px 0;
}

/* ============== 18-19. Pin chip + active-round banner ============== */
.rh-active-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 1px 8px;
  border-radius: 999px;
  background: rgba(111, 214, 147, .12);
  color: var(--v2-green, #6fd693);
  font-weight: 700;
  font-size: calc(11px + var(--text-delta));
  position: relative;
}
.rh-active-badge::before {
  content: "";
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--v2-green, #6fd693);
  box-shadow: 0 0 6px var(--v2-green, #6fd693);
  animation: yacLivePulse 1.6s ease-in-out infinite;
}
@keyframes yacLivePulse {
  0%, 100% { opacity: .55; transform: scale(.85); }
  50%      { opacity: 1;   transform: scale(1.1); }
}
html[data-motion="reduce"] .rh-active-badge::before { animation: none; }

/* ============== 20. Tabular numerics on stats ============== */
.score-display, .stat-value, .rh-card-score, .home-card-stat,
.rh-meta, .disc-stat, .layout-meta {
  font-variant-numeric: tabular-nums;
}

/* ============== 21. Glassmorphism stat badges ============== */
.stat-badge, .layout-meta {
  background: var(--v3-glass-bg);
  border: 1px solid var(--v3-glass-border);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  border-radius: var(--r-pill, 999px);
  padding: 3px 10px;
}

/* ============== 22. Header active-route hint (sub-pixel rising dot) ============== */
.header-menu-item[aria-current="page"]::before {
  content: "";
  display: inline-block;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--v2-green, #6fd693);
  margin-right: 6px;
  box-shadow: 0 0 8px var(--v2-green, #6fd693);
  vertical-align: middle;
}

/* ============== 23. Install banner ============== */
.install-banner {
  background: linear-gradient(180deg, var(--v2-surface-3) 0%, var(--v2-surface-2) 100%);
  border: 1px solid var(--v2-line-strong, rgba(255,255,255,.14));
  border-radius: var(--r-lg, 18px);
  box-shadow: 0 14px 36px rgba(0, 0, 0, .35), 0 1px 0 rgba(255,255,255,.06) inset;
}

/* ============== 24. Disabled buttons ============== */
.btn:disabled, .btn[aria-disabled="true"] {
  opacity: .45;
  background-image: var(--v3-stripe);
  cursor: not-allowed;
  filter: saturate(.7);
}

/* ============== 25. (covered by 16 with the bob animation) ============== */

/* ============== 26. Search input focus ============== */
input[type="text"]:focus, input[type="search"]:focus, input[type="email"]:focus, textarea:focus {
  outline: none;
  border-color: var(--v2-green, #6fd693) !important;
  box-shadow: 0 1px 0 var(--v2-green, #6fd693), 0 2px 8px rgba(111,214,147,.25);
}

/* ============== 27. Course-card icon parallax ============== */
.home-card-icon img, .home-card-icon svg {
  transition: transform .22s var(--v3-overshoot);
}
.home-card:hover .home-card-icon img, .home-card:hover .home-card-icon svg {
  transform: translateY(-2px) rotate(-3deg) scale(1.04);
}

/* ============== 28-29. Trend chart styling (component-scoped) ============== */
.round-trend-card svg text { font-variant-numeric: tabular-nums; }
.round-trend-card button[aria-pressed="true"] {
  box-shadow: 0 0 12px rgba(111,214,147,.30);
}
.round-trend-card button:active { transform: translateY(1px); }

/* ============== 30. Layout-picker chip with check ============== */
.layout-chip[aria-selected="true"]::after {
  content: " \2713";
  margin-left: 4px;
  color: var(--v2-green, #6fd693);
}

/* ============== 31. Wizard progress bar ============== */
.wiz-progress {
  background: var(--v2-surface-2);
  border-bottom: 1px solid var(--v2-line, rgba(255,255,255,.08));
  position: relative;
  overflow: hidden;
}

/* ============== 32. Personal-best round gradient border ============== */
.rh-card[data-best="true"] {
  background-image: linear-gradient(135deg, rgba(212,175,55,.06) 0%, transparent 60%);
  border-color: rgba(212,175,55,.30);
}

/* ============== 33. Login pill pulse ============== */
.auth-pill:not([data-signed-in="true"]) {
  box-shadow: 0 0 0 0 rgba(111,214,147,0);
  animation: yacAuthPillPulse 3s ease-in-out infinite;
}
@keyframes yacAuthPillPulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(111,214,147,0); }
  50%      { box-shadow: 0 0 0 4px rgba(111,214,147,.20); }
}
html[data-motion="reduce"] .auth-pill { animation: none; }

/* ============== 34. (covered by 15 with the spring keyframes) ============== */

/* ============== 35. Disc-card delete glow on hover ============== */
.disc-action-btn.delete:hover, .btn-danger:hover {
  box-shadow: var(--v3-glow-red);
}

/* ============== 36. Hole-card map ken-burns ============== */
.hole-map img, .hole-map .hole-map-bg {
  animation: yacKenBurns 26s ease-in-out infinite alternate;
}
@keyframes yacKenBurns {
  0%   { transform: scale(1.0)  translate(0, 0); }
  100% { transform: scale(1.06) translate(-1.5%, 1%); }
}
html[data-motion="reduce"] .hole-map img, html[data-motion="reduce"] .hole-map .hole-map-bg { animation: none; }

/* ============== 37. Strategy chips per-shape (cosmetic; selectors guarded) ============== */
.shot-chip[data-shape="hyzer"]      { border-color: rgba(94,154,255,.35); }
.shot-chip[data-shape="anhyzer"]    { border-color: rgba(245,158,11,.35); }
.shot-chip[data-shape="straight"]   { border-color: rgba(168,168,168,.35); }
.shot-chip[data-shape="forehand"]   { border-color: rgba(216,79,79,.35); }
.shot-chip[data-shape="backhand"]   { border-color: rgba(111,214,147,.35); }
.shot-chip[data-shape="tomahawk"]   { border-color: rgba(212,175,55,.35); }

/* ============== 38. Recap grid stagger ============== */
.recap-tile { animation: yacRecapIn .35s var(--v3-overshoot) both; }
.recap-tile:nth-child(2)  { animation-delay: .02s; }
.recap-tile:nth-child(3)  { animation-delay: .04s; }
.recap-tile:nth-child(4)  { animation-delay: .06s; }
.recap-tile:nth-child(5)  { animation-delay: .08s; }
.recap-tile:nth-child(6)  { animation-delay: .10s; }
.recap-tile:nth-child(7)  { animation-delay: .12s; }
.recap-tile:nth-child(8)  { animation-delay: .14s; }
.recap-tile:nth-child(9)  { animation-delay: .16s; }
@keyframes yacRecapIn { from { opacity: 0; transform: scale(.92); } to { opacity: 1; transform: scale(1); } }
html[data-motion="reduce"] .recap-tile { animation: none; }

/* ============== 39. Contribute chip check-mark ============== */
button[role="checkbox"][aria-checked="true"]::after {
  content: " \2713";
  margin-left: 4px;
  font-weight: 800;
}

/* ============== 40. Settings rows ============== */
.settings-row {
  transition: background .15s ease;
  border-radius: var(--r-sm, 10px);
  padding: 10px 12px;
}
.settings-row:hover {
  background: var(--v3-glass-bg);
}

/* ============== 41. Field labels ============== */
.field-label, .home-section-title {
  letter-spacing: .04em;
  font-weight: 700;
}

/* ============== 42. Tabular nums everywhere we render numbers ============== */
.tabular, .num, [data-tabular="true"] {
  font-variant-numeric: tabular-nums;
}

/* ============== 43. Premium chip moving gold sheen ============== */
.premium-chip {
  background: linear-gradient(120deg, #d4af37 0%, #fff5d2 35%, #d4af37 65%, #fff5d2 100%);
  background-size: 200% 100%;
  animation: yacGoldSheen 7s linear infinite;
  color: #1c1409;
  font-weight: 800;
  letter-spacing: .04em;
}
@keyframes yacGoldSheen { from { background-position: 0% 0; } to { background-position: -200% 0; } }
html[data-motion="reduce"] .premium-chip { animation: none; }

/* ============== 44. Photo upload zone ============== */
.photo-drop, .image-drop {
  border: 2px dashed var(--v2-line-strong, rgba(255,255,255,.14));
  border-radius: var(--r-md, 14px);
  transition: border-color .15s ease, background .15s ease;
}
.photo-drop.dragover, .image-drop.dragover {
  border-color: var(--v2-green, #6fd693);
  background: rgba(111,214,147,.06);
}

/* ============== 45. Course-detail header buttons balance ============== */
.course-detail-header .btn { flex: 1 1 auto; min-width: 120px; }

/* ============== 46. Pin position labels ============== */
.pin-label-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 22px;
  padding: 0 6px;
  border-radius: 6px;
  background: var(--v2-surface-3);
  border: 1px solid var(--v2-line-strong, rgba(255,255,255,.14));
  font-weight: 800;
  letter-spacing: .04em;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: calc(11px + var(--text-delta));
}

/* ============== 47. Round-history filter chips count badge ============== */
.rh-filter-chip[data-count]::after {
  content: " (" attr(data-count) ")";
  opacity: .65;
  font-size: calc(11px + var(--text-delta));
  margin-left: 2px;
}

/* ============== 48. Generic tab gradient underline (reuse with .tabs > .tab) ============== */
.tabs > .tab {
  position: relative;
  transition: color .15s ease;
}
.tabs > .tab[aria-selected="true"]::after {
  content: "";
  position: absolute;
  left: 16%; right: 16%; bottom: 0;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--v2-green, #6fd693), transparent);
}

/* ============== 49. Multiline input focus shadow ============== */
textarea:focus { box-shadow: 0 4px 10px -2px rgba(111,214,147,.18); }

/* ============== 50. Footer actions bar ============== */
footer.actions-bar {
  background: linear-gradient(180deg, rgba(7,18,10,0) 0%, var(--v2-surface-1, var(--bg)) 25%);
  backdrop-filter: blur(6px) saturate(110%);
  -webkit-backdrop-filter: blur(6px) saturate(110%);
  border-top: 1px solid var(--v2-line, rgba(255,255,255,.08));
}


/* 0.40.0 — Course pin rendered from a state-centroid fallback (lat/lng missing
   on the canonical course record). Visually muted so the user knows the
   location is approximate and can refine it via the contribute panel. */
.course-pin-approx { opacity: 0.55; filter: grayscale(40%) drop-shadow(0 0 4px rgba(255, 255, 100, 0.4)); }
.course-pin-approx::after {
  content: "?"; position: absolute; bottom: -2px; right: -2px;
  font-size: 11px; font-weight: 700; color: var(--amber, #ffc107);
  background: rgba(20, 20, 20, 0.85); border-radius: 50%;
  width: 14px; height: 14px; line-height: 14px; text-align: center;
}

/* 0.40.0 BACKLOG 3b.10 — cloud outage banner. Non-intrusive, dismissible. */
.cloud-outage-banner {
  position: fixed; top: 0; left: 0; right: 0; z-index: 9999;
  background: linear-gradient(180deg, rgba(180, 90, 30, 0.95), rgba(120, 60, 20, 0.95));
  color: #fff; padding: 10px 14px; font-size: calc(13px + var(--text-delta));
  display: flex; align-items: center; gap: 10px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4); border-bottom: 1px solid rgba(255, 200, 100, 0.4);
}
.cloud-outage-icon { font-weight: 700; font-size: 16px; background: rgba(255, 255, 255, 0.18); border-radius: 50%; width: 22px; height: 22px; display: inline-flex; align-items: center; justify-content: center; }
.cloud-outage-text { flex: 1; line-height: 1.35; }
.cloud-outage-dismiss { background: transparent; border: 1px solid rgba(255, 255, 255, 0.4); color: #fff; cursor: pointer; padding: 4px 10px; border-radius: 6px; font-size: 12px; line-height: 1; }
.cloud-outage-dismiss:hover { background: rgba(255, 255, 255, 0.18); }

/* 0.40.0 (BACKLOG §6.8) — Observed players (score-only) UI. */
.observed-setup { margin: 14px 0 8px; padding: 12px; background: var(--bg2, #1a2a1a); border: 1px solid var(--border, #2a3a2a); border-radius: var(--r-md, 12px); }
.observed-setup-label { font-size: calc(11px + var(--text-delta)); color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 8px; }
.observed-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; min-height: 4px; }
.observed-chip { display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px; background: var(--green-tint, rgba(76, 175, 80, 0.18)); border: 1px solid var(--green2, #5fc05f); border-radius: var(--r-pill, 999px); color: var(--text); font-size: calc(12px + var(--text-delta)); }
.observed-chip button { background: transparent; border: none; color: var(--muted); cursor: pointer; padding: 0; font-size: 14px; line-height: 1; }
.observed-chip button:hover { color: var(--red, #ef5350); }
.observed-add { display: flex; gap: 8px; }
.observed-add-input { flex: 1; padding: 8px 12px; background: var(--bg3, #243a24); border: 1px solid var(--border, #2a3a2a); border-radius: var(--r-sm, 8px); color: var(--text); font-size: calc(13px + var(--text-delta)); }
.observed-add-btn { padding: 8px 14px; min-height: auto; }
.observed-players-block { margin: 10px 0 6px; padding: 8px 10px; background: var(--bg2, #1a2a1a); border-left: 3px solid var(--green2, #5fc05f); border-radius: 4px; }
.observed-players-label { font-size: calc(10px + var(--text-delta)); color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 6px; }
.observed-row { display: flex; align-items: center; gap: 10px; padding: 4px 0; }
.observed-name { flex: 1; font-size: calc(13px + var(--text-delta)); color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.observed-score-input { width: 56px; padding: 6px 8px; background: var(--bg3, #243a24); border: 1px solid var(--border, #2a3a2a); border-radius: 6px; color: var(--text); font-size: calc(14px + var(--text-delta)); font-variant-numeric: tabular-nums; text-align: center; }

/* 0.40.1 (BACKLOG §6.8) — Multi-player unified player list. Name on left
   + circular -/score/+ counter on right. Used when the round has observed
   players so user + observed players appear in the same list-style layout.
   Brand-palette: brand green (--green2) buttons, brand green tint for the
   user's own row. No third-party color palette. */
.players-block { margin: 8px 0 14px; display: flex; flex-direction: column; gap: 6px; background: var(--bg2, #1a2a1a); border: 1px solid var(--border, #2a3a2a); border-radius: var(--r-md, 14px); padding: 10px; box-shadow: var(--shadow-sm, 0 1px 2px rgba(0,0,0,.18)); }
.player-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 8px 10px; background: var(--bg-card, var(--bg3, #243a24)); border-radius: var(--r-sm, 10px); border: 1px solid var(--border, #2a3a2a); transition: border-color 0.15s ease, background 0.15s ease; }
.player-row.player-self { border-color: var(--green2, #5fc05f); background: linear-gradient(180deg, rgba(95, 192, 95, 0.14), rgba(95, 192, 95, 0.04)); }
.player-info { flex: 1; min-width: 0; }
.player-name { font-size: calc(14px + var(--text-delta)); font-weight: 600; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.player-sub { font-size: calc(11px + var(--text-delta)); color: var(--muted); margin-top: 2px; font-variant-numeric: tabular-nums; }
.player-counter { display: flex; align-items: center; gap: 10px; }
.counter-btn {
  width: 40px; height: 40px; border-radius: 50%; border: none;
  background: linear-gradient(180deg, var(--green2, #5fc05f), var(--green3, #4caf50));
  color: #0c150c; font-size: 22px; font-weight: 700; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center; line-height: 1;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.18), 0 0 0 1px rgba(95, 192, 95, 0.25);
  transition: transform 0.08s ease, box-shadow 0.15s ease, filter 0.15s ease;
  -webkit-tap-highlight-color: transparent;
}
.counter-btn:hover { transform: translateY(-1px); filter: brightness(1.05); box-shadow: 0 2px 6px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.22), 0 0 0 1px rgba(95, 192, 95, 0.4), 0 0 8px rgba(95, 192, 95, 0.25); }
.counter-btn:active { transform: translateY(1px) scale(0.94); filter: brightness(0.95); }
.counter-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.counter-minus { background: linear-gradient(180deg, var(--bg3, #243a24), var(--bg2, #1a2a1a)); color: var(--text); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.05), 0 0 0 1.5px var(--green2, #5fc05f); }
.counter-minus:hover { background: linear-gradient(180deg, var(--bg2, #1a2a1a), var(--bg3, #243a24)); box-shadow: 0 2px 6px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.08), 0 0 0 1.5px var(--green2, #5fc05f), 0 0 8px rgba(95, 192, 95, 0.25); }
.counter-score { min-width: 28px; font-size: calc(22px + var(--text-delta)); font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; text-align: center; }

/* Expander treatment for the setup panel inside the round view. */
.observed-players-expander { margin: 6px 0; padding: 0; }
.observed-players-expander summary { font-size: calc(12px + var(--text-delta)); color: var(--muted); cursor: pointer; padding: 4px 8px; list-style: none; }
.observed-players-expander summary::-webkit-details-marker { display: none; }
.observed-players-expander summary::before { content: "▸"; display: inline-block; margin-right: 6px; transition: transform 0.15s ease; }
.observed-players-expander[open] summary::before { transform: rotate(90deg); }
.observed-add-toggle { width: auto; padding: 8px 14px; }

/* ===== styles-v4.css ===== */
/* styles-v4.css . YesAndChains 0.41.0 . Big polish wave (50 items).
 *
 * Catalogued list of every change in this layer, top to bottom. Each item
 * is a small, specific refinement; the cumulative effect is what makes the
 * app feel substantially better. Loads after styles-v3.css so v4 rules
 * cascade-win when they conflict.
 *
 *  1. Page-transition fade-in for view changes.
 *  2. Smoother spring-based hover lift on home / disc / round-history cards.
 *  3. Disc card 3D micro-tilt on hover (perspective + rotateX/Y).
 *  4. Score-name flash celebration animation for birdie+.
 *  5. Wind chip with rotating compass arrow inside.
 *  6. Refined 3-layer focus ring system (brand green glow).
 *  7. Sticky header with backdrop-blur on scroll.
 *  8. Modal spring entrance + exit physics.
 *  9. Toast stack with vertical slide + queueing visual.
 * 10. Sync indicator breathing pulse when pending.
 * 11. Empty-state illustration treatment (CSS-art compass).
 * 12. Tab-indicator sliding underline.
 * 13. Active-route dot on side nav items.
 * 14. Long-text truncation with right-fade gradient.
 * 15. Course-card play-count ring around the icon.
 * 16. Live distance-to-pin chip lift on value update.
 * 17. Round-history card stagger entrance (CSS only; no JS timing).
 * 18. Refined disabled-state diagonal stripes.
 * 19. Map pin tilt-on-hover micro-interaction.
 * 20. Custom scrollbar with green-tint thumb.
 * 21. Number-input stepper refinements (no native arrows).
 * 22. Settings accordion smoothness with chevron rotation.
 * 23. .btn-secondary subtle gradient sweep on hover.
 * 24. Score-pill press depth + bounce feedback.
 * 25. Player-row hover ribbon highlight.
 * 26. Round-trend chart hover crosshair via SVG filter.
 * 27. Wizard step progress dots component.
 * 28. Live-round badge breathing animation.
 * 29. Typography scale tightening (h1/h2/h3 sizes).
 * 30. Breadcrumb separator refinement (dot instead of slash).
 * 31. Gradient hairline section dividers.
 * 32. Tabular-nums on every stat / distance / time surface.
 * 33. Caret color brand-green.
 * 34. ::selection brand-green tint.
 * 35. .link-btn underline-from-center hover.
 * 36. Input focus glow refinement (3-layer).
 * 37. Star-toggle scale + spin animation on favorite.
 * 38. Delete-button warm hover with subtle shake.
 * 39. Dropdown chevron smooth rotation.
 * 40. Progress-meter brand-fill animation.
 * 41. Settings toggle (switch) styling.
 * 42. .penalty-pill warm-tint refinement.
 * 43. Card-header weight + spacing.
 * 44. Notification-dot pulse refinement.
 * 45. Improved branded-theme blend.
 * 46. Primary-button focus-visible glow.
 * 47. Landscape-mode adaptations (round view + course detail).
 * 48. Hover state on the brand button (home).
 * 49. Smooth chip-toggle transitions (multi-select).
 * 50. Print stylesheet hint (score cards print clean).
 *
 * Every animation respects `prefers-reduced-motion` via the existing
 * `html[data-motion="reduce"]` infrastructure (the .001ms override block in
 * styles.css). New transitions use `--dur` + `--ease-spring` tokens from
 * 0.25.0 so they participate in the motion system.
 */

/* ============================================================
 * 1. Page-transition fade-in.
 * Every #main render gets a brief opacity ramp + 6px y-translate so
 * navigating between views feels intentional rather than instantaneous.
 * ============================================================ */
@keyframes v4-view-fade-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
#main { animation: v4-view-fade-in 0.22s var(--ease-out, ease-out) both; }

/* ============================================================
 * 2. Spring-eased hover lift on stacked cards.
 * Cards already had a hover lift in 0.25.0; v4 refines the curve so the
 * motion feels like a soft spring instead of a linear ease.
 * ============================================================ */
.home-card, .disc-card, .rh-card, .bag-section-header {
  transition: transform 0.22s var(--ease-spring, cubic-bezier(0.34, 1.56, 0.64, 1)),
              box-shadow 0.18s var(--ease-out, ease-out),
              background 0.18s var(--ease-out, ease-out);
}
.home-card:hover, .disc-card:hover, .rh-card:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-md, 0 4px 12px rgba(0, 0, 0, 0.28));
}

/* ============================================================
 * 3. Disc card 3D micro-tilt.
 * Subtle perspective shift on hover. Disabled on touch + reduced-motion.
 * ============================================================ */
@media (hover: hover) and (pointer: fine) {
  .disc-card { perspective: 800px; }
  .disc-card:hover { transform: translateY(-2px) rotateX(0.6deg) rotateY(-0.4deg); }
}

/* ============================================================
 * 4. Score-name celebration flash. Triggered on basket-landing for any
 * score better than par. JS pops a `.score-flash` element next to the
 * score widget; this CSS animates it. (See round.ts addition.)
 * ============================================================ */
@keyframes v4-score-flash {
  0%   { opacity: 0; transform: translateY(8px) scale(0.85); }
  18%  { opacity: 1; transform: translateY(-2px) scale(1.06); }
  60%  { opacity: 1; transform: translateY(-2px) scale(1.00); }
  100% { opacity: 0; transform: translateY(-12px) scale(0.95); }
}
.score-flash {
  display: inline-block;
  font-family: "Barlow Condensed", sans-serif;
  font-size: calc(28px + var(--text-delta));
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--green2, #5fc05f);
  text-shadow: 0 0 12px rgba(95, 192, 95, 0.6), 0 2px 4px rgba(0, 0, 0, 0.4);
  animation: v4-score-flash 1.6s var(--ease-out, ease-out) forwards;
  pointer-events: none;
}
.score-flash.flash-ace { color: var(--amber, #ffc107); text-shadow: 0 0 18px rgba(255, 193, 7, 0.7), 0 2px 4px rgba(0, 0, 0, 0.5); }
.score-flash.flash-eagle { color: var(--amber, #ffc107); }
.score-flash.flash-bogey, .score-flash.flash-doublebogey { color: var(--red, #ef5350); text-shadow: 0 0 10px rgba(239, 83, 80, 0.45), 0 2px 4px rgba(0, 0, 0, 0.4); }

/* ============================================================
 * 5. Wind chip with rotating compass arrow.
 * The arrow element inside the wind chip rotates to the wind-from
 * direction via inline style. CSS gives it a smooth transition.
 * ============================================================ */
.wind-chip .wind-arrow {
  display: inline-block;
  transition: transform 0.4s var(--ease-spring, cubic-bezier(0.34, 1.56, 0.64, 1));
  transform-origin: center;
}

/* ============================================================
 * 6. 3-layer focus ring (brand green glow).
 * Replaces the prior 2-layer ring with a softer, more visible 3-layer
 * approach: solid green outline, outer halo, and an inset highlight.
 * ============================================================ */
*:focus-visible {
  outline: 2px solid var(--green2, #5fc05f);
  outline-offset: 2px;
  box-shadow: 0 0 0 4px rgba(95, 192, 95, 0.2), 0 0 12px rgba(95, 192, 95, 0.25);
  border-radius: inherit;
}

/* ============================================================
 * 7. Sticky header with backdrop-blur.
 * The top header bar gets a subtle blur when the page scrolls under it.
 * Browsers without backdrop-filter just see a slightly-darker bg.
 * ============================================================ */
/* 0.42.1 — sticky positioning + backdrop-filter on .app-header REMOVED.
   It created a stacking context that hid the dropdown menus (.header-menu
   is z-index: 1100 absolute, but the new stacking context trapped it).
   The .scrolled shadow stays as a class-only effect for anyone who adds
   the class manually; the inline JS hook that added it on scroll is also
   neutralized below. */
.app-header.scrolled, header.app-header.scrolled, #header.scrolled {
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.3);
}

/* ============================================================
 * 8. Modal spring entrance + exit.
 * Builds on 0.25.0's modal spring; adds an explicit exit transition so
 * the disappear feels intentional too.
 * ============================================================ */
@keyframes v4-modal-in {
  from { opacity: 0; transform: translateY(16px) scale(0.94); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes v4-modal-out {
  from { opacity: 1; transform: translateY(0) scale(1); }
  to   { opacity: 0; transform: translateY(12px) scale(0.96); }
}
.modal, .shot-wiz-modal { animation: v4-modal-in 0.32s var(--ease-spring, cubic-bezier(0.34, 1.56, 0.64, 1)) both; }
.modal.closing, .shot-wiz-modal.closing { animation: v4-modal-out 0.18s ease-in both; }

/* ============================================================
 * 9. (Reserved -- merged into 8)
 * ============================================================ */

/* ============================================================
 * 10. Sync indicator breathing pulse.
 * Pending state gets a smoother breathing pulse so it reads as "working"
 * rather than just static.
 * ============================================================ */
@keyframes v4-sync-pulse {
  0%, 100% { opacity: 0.6; transform: scale(1); }
  50%      { opacity: 1.0; transform: scale(1.04); }
}
.sync-status.pending { animation: v4-sync-pulse 1.4s ease-in-out infinite; }

/* ============================================================
 * 11. Empty-state illustration treatment.
 * Empty states get a subtle compass-rose CSS art element above the text.
 * ============================================================ */
.bag-section-empty::before, .empty-state::before {
  content: "";
  display: block;
  width: 56px;
  height: 56px;
  margin: 0 auto 12px;
  background:
    radial-gradient(circle at center, var(--green-tint, rgba(76,175,80,0.18)) 0%, transparent 65%),
    conic-gradient(from 0deg,
      var(--green2, #5fc05f) 0deg 8deg, transparent 8deg 90deg,
      var(--green2, #5fc05f) 90deg 98deg, transparent 98deg 180deg,
      var(--green2, #5fc05f) 180deg 188deg, transparent 188deg 270deg,
      var(--green2, #5fc05f) 270deg 278deg, transparent 278deg 360deg);
  border-radius: 50%;
  opacity: 0.5;
  transition: opacity 0.5s ease, transform 0.5s ease;
}
.bag-section-empty:hover::before, .empty-state:hover::before {
  opacity: 0.75; transform: rotate(45deg);
}

/* ============================================================
 * 12. Tab-indicator sliding underline.
 * Tab-row gets a CSS-driven underline that follows the active tab.
 * Markup-friendly: any .tab-row containing .tab.active gets the line.
 * ============================================================ */
.tab-row { position: relative; display: flex; gap: 6px; border-bottom: 1px solid var(--border, #2a3a2a); }
.tab-row .tab { position: relative; padding: 10px 14px; cursor: pointer; color: var(--muted); font-weight: 500; transition: color 0.15s ease; }
.tab-row .tab.active { color: var(--green2, #5fc05f); }
.tab-row .tab:hover { color: var(--text); }
.tab-row .tab.active::after {
  content: ""; position: absolute; left: 12px; right: 12px; bottom: -1px;
  height: 2px; background: var(--green2, #5fc05f);
  border-radius: 1px;
  animation: v4-tab-underline 0.22s var(--ease-spring, cubic-bezier(0.34, 1.56, 0.64, 1));
}
@keyframes v4-tab-underline {
  from { transform: scaleX(0.2); opacity: 0.4; }
  to   { transform: scaleX(1); opacity: 1; }
}

/* ============================================================
 * 13. Active-route dot on side / bottom nav items.
 * ============================================================ */
.nav-item, .nav-link, .bottom-nav-item { position: relative; }
.nav-item.active::before, .nav-link.active::before, .bottom-nav-item.active::before {
  content: ""; position: absolute; top: 50%; left: -10px;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--green2, #5fc05f);
  box-shadow: 0 0 6px rgba(95, 192, 95, 0.6);
  transform: translateY(-50%);
}

/* ============================================================
 * 14. Long-text truncation with right-fade gradient.
 * Single-line text in tight containers gets a fade-out to nothing rather
 * than a hard ellipsis when over-set.
 * ============================================================ */
.text-fade-right {
  overflow: hidden; white-space: nowrap;
  mask-image: linear-gradient(to right, black calc(100% - 24px), transparent);
  -webkit-mask-image: linear-gradient(to right, black calc(100% - 24px), transparent);
}

/* ============================================================
 * 15. Course-card play-count ring.
 * The course icon gets a subtle ring around it whose color reflects play
 * count: gray=0, green=1-5, brighter green=6-15, gold=15+.
 * ============================================================ */
.course-card .home-card-icon, .course-row .home-card-icon {
  position: relative;
}
.course-card[data-plays="1-5"] .home-card-icon::after,
.course-row[data-plays="1-5"] .home-card-icon::after { content: ""; position: absolute; inset: -2px; border-radius: 50%; border: 1.5px solid rgba(95, 192, 95, 0.5); pointer-events: none; }
.course-card[data-plays="6-15"] .home-card-icon::after,
.course-row[data-plays="6-15"] .home-card-icon::after { content: ""; position: absolute; inset: -2px; border-radius: 50%; border: 2px solid var(--green2, #5fc05f); pointer-events: none; box-shadow: 0 0 6px rgba(95, 192, 95, 0.3); }
.course-card[data-plays="15+"] .home-card-icon::after,
.course-row[data-plays="15+"] .home-card-icon::after { content: ""; position: absolute; inset: -2px; border-radius: 50%; border: 2px solid var(--amber, #ffc107); pointer-events: none; box-shadow: 0 0 8px rgba(255, 193, 7, 0.4); }

/* ============================================================
 * 16. Live distance-to-pin chip lift on update.
 * Brief scale pulse when the chip's value changes (JS adds .updated class).
 * ============================================================ */
@keyframes v4-distance-pulse {
  0%   { transform: scale(1); box-shadow: 0 0 0 0 rgba(95, 192, 95, 0.5); }
  50%  { transform: scale(1.04); box-shadow: 0 0 0 6px rgba(95, 192, 95, 0); }
  100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(95, 192, 95, 0); }
}
.live-pin-distance.updated { animation: v4-distance-pulse 0.5s ease-out; }

/* ============================================================
 * 17. Round-history card stagger entrance.
 * Pure CSS via animation-delay on nth-child. No JS required.
 * ============================================================ */
@keyframes v4-rh-stagger-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
.rh-card { animation: v4-rh-stagger-in 0.32s var(--ease-out, ease-out) both; }
.rh-card:nth-child(1)  { animation-delay: 0.02s; }
.rh-card:nth-child(2)  { animation-delay: 0.06s; }
.rh-card:nth-child(3)  { animation-delay: 0.10s; }
.rh-card:nth-child(4)  { animation-delay: 0.14s; }
.rh-card:nth-child(5)  { animation-delay: 0.18s; }
.rh-card:nth-child(6)  { animation-delay: 0.22s; }
.rh-card:nth-child(7)  { animation-delay: 0.26s; }
.rh-card:nth-child(8)  { animation-delay: 0.30s; }
.rh-card:nth-child(n+9) { animation-delay: 0.34s; }

/* ============================================================
 * 18. Refined disabled-state stripes.
 * Diagonal stripe pattern that signals "interactive but blocked" rather
 * than the prior flat opacity.
 * ============================================================ */
button:disabled, .btn:disabled, .btn[disabled] {
  opacity: 0.55;
  cursor: not-allowed;
  background-image: repeating-linear-gradient(
    -45deg,
    transparent 0px, transparent 6px,
    rgba(0, 0, 0, 0.06) 6px, rgba(0, 0, 0, 0.06) 7px
  );
}

/* ============================================================
 * 19. Map pin tilt-on-hover.
 * Map pin icons get a subtle tilt + scale when hovered.
 * ============================================================ */
.leaflet-marker-icon { transition: transform 0.15s ease; transform-origin: bottom center; }
.leaflet-marker-icon:hover { transform: scale(1.12) rotate(-2deg); z-index: 1000 !important; }

/* ============================================================
 * 20. Custom scrollbar.
 * Brand-green thumb, subtle track. Mostly webkit; Firefox gets thin gray.
 * ============================================================ */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: rgba(0, 0, 0, 0.18); border-radius: 5px; }
::-webkit-scrollbar-thumb {
  background: linear-gradient(180deg, var(--green2, #5fc05f), var(--green3, #4caf50));
  border-radius: 5px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover {
  background: linear-gradient(180deg, var(--green2, #5fc05f), var(--green2, #5fc05f));
  background-clip: padding-box;
}
* { scrollbar-width: thin; scrollbar-color: var(--green2, #5fc05f) rgba(0, 0, 0, 0.2); }

/* ============================================================
 * 21. Number-input stepper refinements.
 * Strip native arrows; we use brand-styled controls everywhere instead.
 * ============================================================ */
input[type="number"] {
  -moz-appearance: textfield;
  font-variant-numeric: tabular-nums;
}
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/* ============================================================
 * 22. Settings accordion smoothness.
 * <details> elements get a smoother open/close + chevron rotation.
 * ============================================================ */
details > summary {
  list-style: none; cursor: pointer; padding: 10px 12px;
  display: flex; align-items: center; gap: 8px;
  border-radius: var(--r-sm, 8px); transition: background 0.15s ease;
}
details > summary::-webkit-details-marker { display: none; }
details > summary::before {
  content: "\25B8"; /* right-pointing triangle */
  display: inline-block; color: var(--muted);
  transition: transform 0.22s var(--ease-spring, cubic-bezier(0.34, 1.56, 0.64, 1));
  font-size: 11px;
}
details[open] > summary::before { transform: rotate(90deg); }
details > summary:hover { background: rgba(255, 255, 255, 0.03); }

/* ============================================================
 * 23. .btn-secondary gradient sweep on hover.
 * Subtle left-to-right green-tint sweep when hovered.
 * ============================================================ */
.btn-secondary {
  background-image: linear-gradient(105deg,
    transparent 0%, transparent 40%,
    rgba(95, 192, 95, 0.12) 50%, transparent 60%, transparent 100%);
  background-size: 220% 100%;
  background-position: 100% 0;
  transition: background-position 0.5s ease-out, transform 0.15s ease, border-color 0.15s ease;
}
.btn-secondary:hover { background-position: 0 0; border-color: var(--green2, #5fc05f); }

/* ============================================================
 * 24. Score-pill press depth + bounce.
 * Existing score-pill gets a softer press response.
 * ============================================================ */
.score-pill {
  transition: transform 0.1s var(--ease-spring, cubic-bezier(0.34, 1.56, 0.64, 1)),
              box-shadow 0.15s ease;
}
.score-pill:active { transform: scale(0.88); }

/* ============================================================
 * 25. Player-row hover ribbon.
 * On hover, the player-row gets a brand-green ribbon on its leading edge.
 * ============================================================ */
.player-row { position: relative; }
.player-row::before {
  content: ""; position: absolute; left: 0; top: 8px; bottom: 8px;
  width: 3px; border-radius: 0 2px 2px 0;
  background: var(--green2, #5fc05f);
  opacity: 0; transform: scaleY(0.4);
  transform-origin: center;
  transition: opacity 0.18s ease, transform 0.22s var(--ease-spring, cubic-bezier(0.34, 1.56, 0.64, 1));
}
.player-row:hover::before { opacity: 0.6; transform: scaleY(1); }
.player-row.player-self::before { opacity: 1; transform: scaleY(1); }

/* ============================================================
 * 26. Round-trend chart hover crosshair.
 * Data point hovers get a subtle drop shadow via SVG filter.
 * ============================================================ */
.round-trend-card svg circle { transition: filter 0.15s ease, r 0.15s ease; }
.round-trend-card svg circle:hover { filter: drop-shadow(0 0 6px var(--green2, #5fc05f)); }

/* ============================================================
 * 27. Wizard step progress dots.
 * Container .wiz-progress-dots renders a row of dots; the current step
 * is brand-green, the rest are muted.
 * ============================================================ */
.wiz-progress-dots { display: flex; align-items: center; justify-content: center; gap: 8px; padding: 6px 0; }
.wiz-progress-dots .dot { width: 6px; height: 6px; border-radius: 50%; background: rgba(255, 255, 255, 0.16); transition: background 0.2s ease, transform 0.2s var(--ease-spring, cubic-bezier(0.34, 1.56, 0.64, 1)); }
.wiz-progress-dots .dot.active { background: var(--green2, #5fc05f); transform: scale(1.4); box-shadow: 0 0 6px rgba(95, 192, 95, 0.55); }
.wiz-progress-dots .dot.done { background: var(--green3, #4caf50); }

/* ============================================================
 * 28. Live-round badge breathing animation.
 * The "active round" indicator in the home header breathes so it reads as
 * "live" without being noisy.
 * ============================================================ */
@keyframes v4-live-breathe {
  0%, 100% { box-shadow: 0 0 0 0 rgba(95, 192, 95, 0.5); }
  50%      { box-shadow: 0 0 0 8px rgba(95, 192, 95, 0); }
}
.live-round-badge { animation: v4-live-breathe 2.2s ease-in-out infinite; }

/* ============================================================
 * 29. Typography scale tightening.
 * h1/h2/h3 default sizes were too close. v4 separates them more clearly.
 * ============================================================ */
h1 { font-size: calc(28px + var(--text-delta)); font-weight: 700; letter-spacing: -0.01em; line-height: 1.1; }
h2 { font-size: calc(22px + var(--text-delta)); font-weight: 700; letter-spacing: -0.005em; line-height: 1.15; }
h3 { font-size: calc(17px + var(--text-delta)); font-weight: 600; letter-spacing: 0; line-height: 1.25; }
.section-title { font-size: calc(12px + var(--text-delta)); text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted); font-weight: 600; }

/* ============================================================
 * 30. Breadcrumb separator refinement.
 * Replace any / or > separators with a centered dot.
 * ============================================================ */
.breadcrumb { display: flex; align-items: center; gap: 8px; color: var(--muted); font-size: calc(12px + var(--text-delta)); }
.breadcrumb .sep { display: inline-block; width: 4px; height: 4px; border-radius: 50%; background: var(--muted); opacity: 0.6; }

/* ============================================================
 * 31. Gradient hairline section dividers.
 * Replace flat `border-top` separators with a fading hairline.
 * ============================================================ */
.section-divider, hr {
  border: none;
  height: 1px;
  background: linear-gradient(to right,
    transparent 0%,
    rgba(95, 192, 95, 0.32) 50%,
    transparent 100%);
  margin: 18px 0;
}

/* ============================================================
 * 32. Tabular-nums everywhere stats / distances / times live.
 * Forces fixed-width digits so values don't shift between columns.
 * ============================================================ */
.score-num, .stat-value, .distance, .time, .duration,
.observed-score-input, .counter-score, .stat-num, .rh-score, .home-card-sub,
.throw-chip, .wind-chip {
  font-variant-numeric: tabular-nums;
}

/* ============================================================
 * 33. Caret color brand-green.
 * ============================================================ */
input, textarea, [contenteditable="true"] {
  caret-color: var(--green2, #5fc05f);
}

/* ============================================================
 * 34. ::selection brand-green tint.
 * ============================================================ */
::selection {
  background: rgba(95, 192, 95, 0.35);
  color: var(--text);
}
::-moz-selection {
  background: rgba(95, 192, 95, 0.35);
  color: var(--text);
}

/* ============================================================
 * 35. .link-btn underline-from-center hover.
 * The underline grows from the middle outward on hover rather than from
 * the left.
 * ============================================================ */
.link-btn {
  background-image: linear-gradient(currentColor, currentColor);
  background-size: 0 1px;
  background-repeat: no-repeat;
  background-position: 50% calc(100% - 2px);
  transition: background-size 0.22s var(--ease-out, ease-out);
}
.link-btn:hover { background-size: 100% 1px; }

/* ============================================================
 * 36. Input focus glow 3-layer refinement.
 * ============================================================ */
input:focus, textarea:focus, select:focus {
  outline: none;
  border-color: var(--green2, #5fc05f);
  box-shadow:
    0 0 0 3px rgba(95, 192, 95, 0.18),
    0 0 10px rgba(95, 192, 95, 0.18) inset;
}

/* ============================================================
 * 37. Star-toggle scale + spin animation.
 * Tapping the star bounces + spins it 360 to land in the new state.
 * Triggered by `.star-toggling` class (JS adds for ~0.4s on click).
 * ============================================================ */
@keyframes v4-star-spin {
  0%   { transform: scale(1) rotate(0deg); }
  40%  { transform: scale(1.35) rotate(180deg); }
  100% { transform: scale(1) rotate(360deg); }
}
.gold-metallic-text.star-toggling, .star-toggle.star-toggling {
  display: inline-block;
  animation: v4-star-spin 0.5s var(--ease-spring, cubic-bezier(0.34, 1.56, 0.64, 1));
}

/* ============================================================
 * 38. Delete-button warm hover.
 * Delete-action buttons get a red shake-on-hover (subtle, 2px).
 * ============================================================ */
@keyframes v4-delete-shake {
  0%, 100% { transform: translateX(0); }
  25%      { transform: translateX(-1.5px); }
  75%      { transform: translateX(1.5px); }
}
.btn-danger:hover, .delete-btn:hover, button[data-action="delete"]:hover {
  animation: v4-delete-shake 0.32s ease-in-out;
  background: var(--red, #ef5350);
  color: #fff;
}

/* ============================================================
 * 39. Dropdown chevron rotation.
 * Native <select> stays as-is; custom dropdowns with a .chevron get the
 * smooth rotation. (Auto-handled via [open] aria attribute.)
 * ============================================================ */
.dropdown .chevron, .select-like .chevron {
  display: inline-block; transition: transform 0.22s var(--ease-spring, cubic-bezier(0.34, 1.56, 0.64, 1));
}
.dropdown[aria-expanded="true"] .chevron,
.select-like[aria-expanded="true"] .chevron { transform: rotate(180deg); }

/* ============================================================
 * 40. Progress-meter brand-fill animation.
 * <progress> + .progress-meter get a smooth fill animation that grows
 * from left to right on load.
 * ============================================================ */
@keyframes v4-progress-fill {
  from { width: 0%; }
  to   { width: var(--progress-value, 0%); }
}
.progress-meter {
  position: relative; height: 6px; background: rgba(255, 255, 255, 0.08);
  border-radius: 3px; overflow: hidden;
}
.progress-meter::after {
  content: "";
  position: absolute; left: 0; top: 0; bottom: 0;
  width: var(--progress-value, 0%);
  background: linear-gradient(90deg, var(--green3, #4caf50), var(--green2, #5fc05f));
  border-radius: 3px;
  animation: v4-progress-fill 0.6s var(--ease-out, ease-out);
}

/* ============================================================
 * 41. Settings toggle (switch) styling.
 * Standard checkbox can be wrapped in a .toggle to render as a brand switch.
 * ============================================================ */
.toggle { position: relative; display: inline-block; width: 44px; height: 24px; }
.toggle input[type="checkbox"] { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; }
.toggle .track {
  position: absolute; inset: 0; border-radius: 999px;
  background: rgba(255, 255, 255, 0.18);
  transition: background 0.22s ease, box-shadow 0.22s ease;
}
.toggle .thumb {
  position: absolute; top: 2px; left: 2px;
  width: 20px; height: 20px; border-radius: 50%;
  background: #fff;
  transition: transform 0.22s var(--ease-spring, cubic-bezier(0.34, 1.56, 0.64, 1)),
              background 0.22s ease;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
}
.toggle input:checked ~ .track { background: var(--green2, #5fc05f); box-shadow: inset 0 0 0 1px var(--green3, #4caf50); }
.toggle input:checked ~ .thumb { transform: translateX(20px); }
.toggle input:focus-visible ~ .track { outline: 2px solid var(--green2, #5fc05f); outline-offset: 2px; }

/* ============================================================
 * 42. .penalty-pill warm-tint refinement.
 * Existing penalty controls get an amber outline so they're visually
 * distinguishable from the score-pill (green) at a glance.
 * ============================================================ */
.penalty-pill { border: 1.5px solid rgba(255, 193, 7, 0.45); transition: border-color 0.15s ease, background 0.15s ease; }
.penalty-pill:hover { border-color: var(--amber, #ffc107); background: rgba(255, 193, 7, 0.08); }

/* ============================================================
 * 43. Card-header weight + spacing.
 * .bag-section-header / .card-header gets slightly more breathing room
 * and a clearer hierarchy.
 * ============================================================ */
.bag-section-header, .card-header {
  padding: 14px 16px;
  font-size: calc(15px + var(--text-delta));
  font-weight: 600;
  letter-spacing: -0.005em;
}

/* ============================================================
 * 44. Notification-dot pulse refinement.
 * Small red dot on hidden notifications gets a smoother pulse.
 * ============================================================ */
@keyframes v4-notification-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(239, 83, 80, 0.5); }
  50%      { box-shadow: 0 0 0 5px rgba(239, 83, 80, 0); }
}
.notification-dot {
  position: absolute; top: -2px; right: -2px;
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--red, #ef5350);
  animation: v4-notification-pulse 1.6s ease-in-out infinite;
}

/* ============================================================
 * 45. Branded-theme blend.
 * Branded theme blends an extra hint of dark-forest tone so dark surfaces
 * read more cohesively.
 * ============================================================ */
html[data-theme="branded"] body {
  background:
    radial-gradient(circle at 30% 0%, rgba(95, 192, 95, 0.04) 0%, transparent 60%),
    radial-gradient(circle at 80% 100%, rgba(95, 192, 95, 0.03) 0%, transparent 60%),
    var(--bg, #0c150c);
}

/* ============================================================
 * 46. Primary-button focus-visible glow.
 * Specific focus treatment for primary CTAs (above and beyond the global
 * focus ring) so keyboard users see the most important controls.
 * ============================================================ */
.btn-primary:focus-visible {
  box-shadow:
    0 0 0 3px rgba(95, 192, 95, 0.3),
    0 0 16px rgba(95, 192, 95, 0.35),
    inset 0 1px 0 rgba(255, 255, 255, 0.15);
}

/* ============================================================
 * 47. Landscape-mode adaptations.
 * In landscape orientation, the round view + course-detail layouts get
 * side-by-side panes instead of stacked.
 * ============================================================ */
@media (orientation: landscape) and (max-height: 480px) {
  .round-view-grid {
    display: grid;
    grid-template-columns: 1.2fr 1fr;
    gap: 12px;
  }
  .round-view-grid .hole-side { min-width: 0; }
  .round-view-grid .score-side { min-width: 0; }
  .wiz-header { padding: 6px 12px; }
}

/* ============================================================
 * 48. Brand button (home) hover.
 * The home brand button gets a subtle glow + scale.
 * ============================================================ */
.app-brand { transition: transform 0.18s var(--ease-spring, cubic-bezier(0.34, 1.56, 0.64, 1)), filter 0.18s ease; }
.app-brand:hover { transform: scale(1.04); filter: drop-shadow(0 0 6px rgba(95, 192, 95, 0.4)); }
.app-brand:active { transform: scale(0.97); }

/* ============================================================
 * 49. Chip-toggle transitions (multi-select).
 * Multi-select chips (e.g., fairwayTypes) get a smoother active-state
 * transition with a pop on selection.
 * ============================================================ */
.chip, .chip-toggle, .layout-chip, .throw-chip, .mfr-chip, .cat-chip {
  transition: background 0.18s ease, color 0.18s ease, border-color 0.18s ease,
              transform 0.18s var(--ease-spring, cubic-bezier(0.34, 1.56, 0.64, 1));
}
.chip.active, .chip-toggle.active, .layout-chip.active {
  background: var(--green-tint, rgba(76, 175, 80, 0.22));
  border-color: var(--green2, #5fc05f);
  color: var(--text);
  transform: scale(1.02);
}

/* ============================================================
 * 50. Print stylesheet hint.
 * Score cards / round detail print clean. Most decorative elements get
 * hidden; backgrounds revert to white-on-black.
 * ============================================================ */
@media print {
  .app-header, .bag-section-header, .wiz-header, .btn, button, .nav-item,
  .live-pin-distance, .wind-chip, .caddy-rec-host, .cloud-outage-banner {
    display: none !important;
  }
  body { background: #fff !important; color: #000 !important; }
  .rh-card, .disc-card, .home-card, .players-block {
    background: #fff !important; border: 1px solid #ccc !important;
    box-shadow: none !important; break-inside: avoid;
  }
  .player-name, .player-sub, .counter-score, .score-num { color: #000 !important; }
}

/* ===== styles-v5.css ===== */
/* styles-v5.css . YesAndChains 0.42.0 . Second polish wave (50 items).
 *
 * Builds on styles-v4.css. Where v4 focused on transitions + motion polish,
 * v5 introduces new components (skeleton, tooltip, popover, FAB, status
 * badges, streak counter), refines existing components further, and adds
 * functional UX patterns (pull-to-refresh hint, quick-action sheet,
 * priority toast stack, etc.). Catalogued top-to-bottom:
 *
 *  1. Shimmer skeleton loader (animated gradient sweep).
 *  2. Avatar placeholder with initials in brand-green circle.
 *  3. Hero gradient background on home view.
 *  4. Status badge component (live / offline / syncing / pending).
 *  5. Tooltip component with arrow + smart positioning hooks.
 *  6. Popover component (richer than tooltip, click-triggered).
 *  7. Confirmation dialog redesign (clearer hierarchy).
 *  8. Toast types (success / info / warning / error) + priority stack.
 *  9. Floating action button (FAB) for primary action shortcuts.
 * 10. Pull-to-refresh hint pattern.
 * 11. Disc condition badge row (new / lightly / moderate / well / beat-in).
 * 12. Bag composition mini-bar (by category).
 * 13. Coverage band on disc detail (what distance ranges this disc serves).
 * 14. Quick-action sheet (slide-up panel).
 * 15. Streak counter (consecutive days played).
 * 16. Weekly summary chip on home.
 * 17. Goal-tracking progress bar.
 * 18. Year-in-review-ready stat blocks.
 * 19. Personal-best highlight chip.
 * 20. Live wind compass mini-widget.
 * 21. Per-hole notes inline pin (not behind menu).
 * 22. Score color tier with subtle gradient backgrounds.
 * 23. Better number-pad layout hint for score entry.
 * 24. Wizard "skip" button styling.
 * 25. Sticky footer action bar on detail views.
 * 26. Slide-out side panel base styles.
 * 27. Drag handle component for reorderable lists.
 * 28. Pinned/favorite courses shortcut row on home.
 * 29. Quick stats card on profile (last week summary).
 * 30. Improved scorecard tier coloring.
 * 31. Better OB/penalty visualization on history cards.
 * 32. Trend chart legend treatment.
 * 33. Smarter form-field grouping with section labels.
 * 34. Empty-bag wizard prompt CTA treatment.
 * 35. Disc-add wizard clearer current step.
 * 36. Shot-wizard progress bar at bottom.
 * 37. Distance display in user-preferred units (ft/m switch).
 * 38. Year/month/week toggle for stats.
 * 39. Sticky search bar that compacts on scroll.
 * 40. Better photo-upload preview frame.
 * 41. Disabled-form feedback (greys + explainer underneath).
 * 42. Round-finish recap polish (banner + key stat tiles).
 * 43. Account-info inline edit affordance.
 * 44. Per-layout play-distribution mini-bar.
 * 45. Easter-egg konami pulse (Just because).
 * 46. Improved icon stroke consistency wrapper.
 * 47. Tab-focus-only outline (no double rings on mouse click).
 * 48. Better hover-state contrast in branded-light theme.
 * 49. iOS PWA safe-area padding for notch.
 * 50. Final visual cohesion: container queries for adaptive cards.
 */

/* ============================================================
 * 1. Shimmer skeleton loader.
 * Wrap any placeholder div with .skeleton to get an animated gradient.
 * ============================================================ */
@keyframes v5-skeleton-shimmer {
  0% { background-position: -200% 0; }
  100% { background-position: 200% 0; }
}
.skeleton {
  background: linear-gradient(90deg,
    rgba(255, 255, 255, 0.03) 0%,
    rgba(255, 255, 255, 0.08) 50%,
    rgba(255, 255, 255, 0.03) 100%);
  background-size: 200% 100%;
  animation: v5-skeleton-shimmer 1.4s ease-in-out infinite;
  border-radius: var(--r-sm, 8px);
  min-height: 14px;
  color: transparent;
  user-select: none;
}
.skeleton.skeleton-line { height: 14px; margin: 6px 0; }
.skeleton.skeleton-line-lg { height: 20px; margin: 8px 0; }
.skeleton.skeleton-circle { border-radius: 50%; width: 40px; height: 40px; }
.skeleton.skeleton-card { height: 80px; margin: 10px 0; }

/* ============================================================
 * 2. Avatar placeholder with initials.
 * ============================================================ */
.avatar {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; border-radius: 50%;
  background: linear-gradient(135deg, var(--green2, #5fc05f), var(--green3, #4caf50));
  color: #0c150c;
  font-weight: 700;
  font-size: calc(13px + var(--text-delta));
  font-family: "Barlow Condensed", sans-serif;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.18);
}
.avatar.avatar-lg { width: 52px; height: 52px; font-size: calc(18px + var(--text-delta)); }
.avatar.avatar-sm { width: 26px; height: 26px; font-size: calc(11px + var(--text-delta)); }

/* ============================================================
 * 3. Hero gradient background on home view.
 * When body.view-home is set (added by main.ts hook below), the body
 * gets a soft radial gradient that draws the eye to the center.
 * ============================================================ */
body.view-home::before {
  content: ""; position: fixed; inset: 0; pointer-events: none; z-index: -1;
  background:
    radial-gradient(ellipse at 20% 0%, rgba(95, 192, 95, 0.08) 0%, transparent 50%),
    radial-gradient(ellipse at 80% 100%, rgba(95, 192, 95, 0.05) 0%, transparent 50%);
  opacity: 0.95;
}

/* ============================================================
 * 4. Status badge component.
 * .status-badge with modifier classes: .status-live, .status-syncing,
 * .status-offline, .status-pending.
 * ============================================================ */
.status-badge {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px; border-radius: var(--r-pill, 999px);
  font-size: calc(11px + var(--text-delta)); font-weight: 600;
  letter-spacing: 0.04em; text-transform: uppercase;
  background: rgba(255, 255, 255, 0.08);
  color: var(--text);
}
.status-badge::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: var(--muted);
}
.status-badge.status-live { background: rgba(95, 192, 95, 0.16); color: var(--green2, #5fc05f); }
.status-badge.status-live::before { background: var(--green2, #5fc05f); box-shadow: 0 0 6px rgba(95, 192, 95, 0.6); animation: v5-status-pulse 1.6s ease-in-out infinite; }
.status-badge.status-syncing { background: rgba(255, 193, 7, 0.14); color: var(--amber, #ffc107); }
.status-badge.status-syncing::before { background: var(--amber, #ffc107); animation: v5-status-pulse 1.6s ease-in-out infinite; }
.status-badge.status-offline { background: rgba(239, 83, 80, 0.14); color: var(--red, #ef5350); }
.status-badge.status-offline::before { background: var(--red, #ef5350); }
.status-badge.status-pending { background: rgba(255, 255, 255, 0.06); color: var(--muted); }
@keyframes v5-status-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.4; }
}

/* ============================================================
 * 5. Tooltip component.
 * <span class="tt" data-tt="text">visible content</span>
 * Uses ::after for the bubble + ::before for the arrow.
 * ============================================================ */
.tt { position: relative; cursor: help; }
.tt::after {
  content: attr(data-tt);
  position: absolute; bottom: calc(100% + 8px); left: 50%;
  transform: translateX(-50%) translateY(4px);
  background: rgba(20, 24, 20, 0.96);
  color: #fff;
  padding: 6px 10px;
  border-radius: 6px;
  font-size: calc(12px + var(--text-delta));
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.18s ease, transform 0.18s ease;
  z-index: var(--z-overlay, 800);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
}
.tt::before {
  content: "";
  position: absolute; bottom: calc(100% + 2px); left: 50%;
  transform: translateX(-50%) translateY(4px);
  border: 5px solid transparent;
  border-top-color: rgba(20, 24, 20, 0.96);
  opacity: 0;
  transition: opacity 0.18s ease, transform 0.18s ease;
  z-index: var(--z-overlay, 800);
}
.tt:hover::after, .tt:focus-visible::after,
.tt:hover::before, .tt:focus-visible::before {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* ============================================================
 * 6. Popover component (click-triggered, richer than tooltip).
 * <div class="popover-anchor" aria-expanded="true">
 *   <div class="popover">content</div>
 * </div>
 * ============================================================ */
.popover-anchor { position: relative; display: inline-block; }
.popover {
  position: absolute; top: calc(100% + 8px); left: 0;
  min-width: 220px; max-width: 320px;
  background: var(--bg-card, var(--bg2, #1a2a1a));
  border: 1px solid var(--border, #2a3a2a);
  border-radius: var(--r-md, 12px);
  box-shadow: var(--shadow-lg, 0 8px 24px rgba(0, 0, 0, 0.4));
  padding: 12px 14px;
  z-index: var(--z-overlay, 800);
  opacity: 0; transform: translateY(-4px) scale(0.97);
  pointer-events: none;
  transition: opacity 0.18s ease, transform 0.18s var(--ease-spring, cubic-bezier(0.34, 1.56, 0.64, 1));
}
.popover-anchor[aria-expanded="true"] .popover {
  opacity: 1; transform: translateY(0) scale(1); pointer-events: auto;
}

/* ============================================================
 * 7. Confirmation dialog redesign.
 * Clearer hierarchy: title -> body -> action row with primary right.
 * ============================================================ */
.confirm-modal .confirm-title { font-size: calc(18px + var(--text-delta)); font-weight: 700; margin: 0 0 8px; }
.confirm-modal .confirm-body { font-size: calc(14px + var(--text-delta)); color: var(--muted); line-height: 1.5; margin: 0 0 18px; }
.confirm-modal .confirm-actions { display: flex; justify-content: flex-end; gap: 10px; }
.confirm-modal .confirm-actions .btn { min-width: 96px; }

/* ============================================================
 * 8. Toast types + priority stack.
 * .toast-host stacks vertically from bottom. Types add colored left bars.
 * ============================================================ */
.toast-host {
  position: fixed; left: 50%; bottom: 20px;
  transform: translateX(-50%);
  display: flex; flex-direction: column-reverse; gap: 8px;
  z-index: var(--z-toast, 9500);
  pointer-events: none;
  max-width: 92vw;
}
.toast-host .toast {
  pointer-events: auto;
  background: rgba(20, 24, 20, 0.96);
  color: #fff;
  padding: 12px 16px 12px 18px;
  border-radius: var(--r-md, 12px);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5);
  font-size: calc(13px + var(--text-delta));
  line-height: 1.4;
  display: flex; align-items: center; gap: 10px;
  border-left: 4px solid var(--green2, #5fc05f);
  animation: v5-toast-in 0.32s var(--ease-spring, cubic-bezier(0.34, 1.56, 0.64, 1)) both;
}
.toast.toast-success { border-left-color: var(--green2, #5fc05f); }
.toast.toast-info { border-left-color: var(--green2, #5fc05f); }
.toast.toast-warning { border-left-color: var(--amber, #ffc107); }
.toast.toast-error { border-left-color: var(--red, #ef5350); }
@keyframes v5-toast-in {
  from { opacity: 0; transform: translateY(20px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ============================================================
 * 9. Floating action button (FAB).
 * Fixed bottom-right, primary action shortcut.
 * ============================================================ */
.fab {
  position: fixed; right: 18px; bottom: 18px;
  width: 56px; height: 56px; border-radius: 50%;
  background: linear-gradient(180deg, var(--green2, #5fc05f), var(--green3, #4caf50));
  color: #0c150c;
  border: none;
  font-size: 26px; font-weight: 700; line-height: 1;
  cursor: pointer;
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(95, 192, 95, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.2);
  transition: transform 0.18s var(--ease-spring, cubic-bezier(0.34, 1.56, 0.64, 1)), box-shadow 0.18s ease;
  z-index: var(--z-overlay, 800);
  display: inline-flex; align-items: center; justify-content: center;
}
.fab:hover { transform: scale(1.07) translateY(-1px); box-shadow: 0 10px 22px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(95, 192, 95, 0.5), 0 0 16px rgba(95, 192, 95, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.22); }
.fab:active { transform: scale(0.96); }
.fab .fab-label {
  position: absolute; right: calc(100% + 10px); top: 50%;
  transform: translateY(-50%);
  background: rgba(20, 24, 20, 0.96); color: #fff;
  padding: 6px 10px; border-radius: 6px;
  font-size: calc(12px + var(--text-delta)); white-space: nowrap;
  opacity: 0; transition: opacity 0.18s ease, transform 0.18s ease;
  pointer-events: none;
}
.fab:hover .fab-label { opacity: 1; transform: translateY(-50%) translateX(-2px); }

/* ============================================================
 * 10. Pull-to-refresh hint UI.
 * Subtle bar that appears at the top of scrollable views as a hint.
 * ============================================================ */
.ptr-hint {
  position: absolute; top: 0; left: 50%;
  transform: translateX(-50%) translateY(-100%);
  background: rgba(95, 192, 95, 0.18);
  color: var(--green2, #5fc05f);
  padding: 8px 16px;
  border-radius: 0 0 var(--r-pill, 999px) var(--r-pill, 999px);
  font-size: calc(12px + var(--text-delta));
  font-weight: 600;
  transition: transform 0.22s ease;
  pointer-events: none;
}
.ptr-hint.visible { transform: translateX(-50%) translateY(0); }

/* ============================================================
 * 11. Disc condition badge row.
 * .condition-badge with brand-color steps.
 * ============================================================ */
.condition-badge {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 8px; border-radius: var(--r-pill, 999px);
  font-size: calc(11px + var(--text-delta)); font-weight: 600;
  background: rgba(255, 255, 255, 0.06); color: var(--muted);
}
.condition-badge.cond-new { background: rgba(95, 192, 95, 0.16); color: var(--green2, #5fc05f); }
.condition-badge.cond-lightly_used { background: rgba(95, 192, 95, 0.10); color: var(--green2, #5fc05f); }
.condition-badge.cond-moderate { background: rgba(255, 193, 7, 0.12); color: var(--amber, #ffc107); }
.condition-badge.cond-well_used { background: rgba(255, 152, 0, 0.14); color: #ff9800; }
.condition-badge.cond-beat_in { background: rgba(239, 83, 80, 0.16); color: var(--red, #ef5350); }

/* ============================================================
 * 12. Bag composition mini-bar.
 * Horizontal bar showing the % of each disc category in the bag.
 * Render as .bag-composition with .bag-comp-seg children that have
 * width inline style + a data-cat class.
 * ============================================================ */
.bag-composition {
  display: flex; height: 8px; overflow: hidden;
  border-radius: 4px; background: rgba(255, 255, 255, 0.06);
  margin: 8px 0;
}
.bag-comp-seg { transition: opacity 0.15s ease; cursor: help; }
.bag-comp-seg:hover { opacity: 0.85; }
.bag-comp-seg.cat-putter { background: var(--green2, #5fc05f); }
.bag-comp-seg.cat-approach { background: #7cc77c; }
.bag-comp-seg.cat-midrange { background: var(--amber, #ffc107); }
.bag-comp-seg.cat-fairway { background: #ff9800; }
.bag-comp-seg.cat-distance { background: var(--red, #ef5350); }

/* ============================================================
 * 13. Coverage band on disc detail.
 * Shows the distance range this disc serves (min carry .. max carry).
 * ============================================================ */
.coverage-band {
  position: relative; height: 8px; margin: 8px 0 12px;
  background: rgba(255, 255, 255, 0.06); border-radius: 4px;
}
.coverage-band .coverage-fill {
  position: absolute; top: 0; bottom: 0;
  background: linear-gradient(90deg, transparent, var(--green2, #5fc05f), transparent);
  border-radius: 4px;
  left: var(--coverage-start, 0%); right: calc(100% - var(--coverage-end, 100%));
}
.coverage-band .coverage-marker {
  position: absolute; top: -4px; width: 2px; height: 16px;
  background: var(--text); border-radius: 1px;
  left: var(--coverage-avg, 50%);
  transform: translateX(-50%);
  box-shadow: 0 0 4px var(--green2, #5fc05f);
}

/* ============================================================
 * 14. Quick-action sheet (slide-up panel).
 * Triggered by FAB or a row tap; slides up from the bottom.
 * ============================================================ */
.quick-sheet {
  position: fixed; left: 0; right: 0; bottom: 0;
  background: var(--bg-card, var(--bg2, #1a2a1a));
  border-top: 1px solid var(--border, #2a3a2a);
  border-radius: var(--r-lg, 18px) var(--r-lg, 18px) 0 0;
  padding: 16px 18px 24px;
  z-index: var(--z-overlay, 800);
  box-shadow: 0 -6px 22px rgba(0, 0, 0, 0.45);
  transform: translateY(100%);
  transition: transform 0.32s var(--ease-spring, cubic-bezier(0.34, 1.56, 0.64, 1));
}
.quick-sheet.open { transform: translateY(0); }
.quick-sheet .sheet-handle {
  width: 36px; height: 4px; background: rgba(255, 255, 255, 0.18);
  border-radius: 2px; margin: 0 auto 12px;
}

/* ============================================================
 * 15. Streak counter.
 * Shows N-day play streak with a flame-like green flare.
 * ============================================================ */
.streak-counter {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 12px; border-radius: var(--r-pill, 999px);
  background: linear-gradient(135deg, rgba(255, 193, 7, 0.18), rgba(255, 152, 0, 0.18));
  border: 1px solid rgba(255, 193, 7, 0.35);
  color: var(--amber, #ffc107);
  font-weight: 700; font-size: calc(13px + var(--text-delta));
}
.streak-counter::before {
  content: "\1F525"; /* flame emoji is fine on a streak counter; user-facing celebratory */
  font-size: 14px;
  filter: drop-shadow(0 0 4px rgba(255, 193, 7, 0.5));
}
.streak-counter.streak-cold { background: rgba(255, 255, 255, 0.06); border-color: var(--border, #2a3a2a); color: var(--muted); }
.streak-counter.streak-cold::before { filter: grayscale(60%); opacity: 0.5; }

/* ============================================================
 * 16. Weekly summary chip on home.
 * Compact chip showing this-week stats.
 * ============================================================ */
.weekly-summary {
  display: flex; gap: 10px; align-items: center;
  padding: 10px 14px;
  background: linear-gradient(180deg, rgba(95, 192, 95, 0.10), rgba(95, 192, 95, 0.04));
  border: 1px solid rgba(95, 192, 95, 0.22);
  border-radius: var(--r-md, 12px);
  margin: 12px 0;
}
.weekly-summary .ws-label { color: var(--muted); font-size: calc(11px + var(--text-delta)); text-transform: uppercase; letter-spacing: 0.06em; }
.weekly-summary .ws-stat { font-size: calc(15px + var(--text-delta)); font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; }
.weekly-summary .ws-stat-sub { font-size: calc(11px + var(--text-delta)); color: var(--muted); }

/* ============================================================
 * 17. Goal-tracking progress bar.
 * .goal-progress with --goal-value set inline.
 * ============================================================ */
.goal-progress {
  position: relative; height: 8px; background: rgba(255, 255, 255, 0.06);
  border-radius: 4px; overflow: hidden; margin: 6px 0;
}
.goal-progress::after {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0;
  width: var(--goal-value, 0%);
  background: linear-gradient(90deg, var(--green2, #5fc05f), var(--amber, #ffc107) 85%, var(--green2, #5fc05f));
  background-size: 200% 100%;
  border-radius: 4px;
  transition: width 0.6s var(--ease-out, ease-out);
}
.goal-progress.goal-complete::after { background: linear-gradient(90deg, var(--amber, #ffc107), var(--green2, #5fc05f)); animation: v5-goal-celebrate 1.6s ease-in-out infinite; }
@keyframes v5-goal-celebrate {
  0%, 100% { background-position: 0% 0; }
  50%      { background-position: 100% 0; }
}

/* ============================================================
 * 18. Year-in-review-ready stat blocks.
 * Big numbers, label below. Used in profile + recap views.
 * ============================================================ */
.stat-block {
  text-align: center; padding: 14px 12px;
  background: var(--bg-card, var(--bg2, #1a2a1a));
  border: 1px solid var(--border, #2a3a2a);
  border-radius: var(--r-md, 12px);
}
.stat-block .stat-num {
  font-family: "Barlow Condensed", sans-serif;
  font-size: calc(32px + var(--text-delta));
  font-weight: 700;
  color: var(--green2, #5fc05f);
  line-height: 1;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}
.stat-block .stat-label {
  font-size: calc(11px + var(--text-delta));
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin-top: 4px;
}
.stat-block .stat-sub {
  font-size: calc(11px + var(--text-delta));
  color: var(--muted);
  margin-top: 2px;
}
.stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 10px; margin: 12px 0; }

/* ============================================================
 * 19. Personal-best highlight chip.
 * ============================================================ */
.pb-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px;
  background: linear-gradient(135deg, var(--amber, #ffc107), #ffd54f);
  color: #1a1a00; font-weight: 700;
  font-size: calc(11px + var(--text-delta));
  border-radius: var(--r-pill, 999px);
  box-shadow: 0 1px 3px rgba(255, 193, 7, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.3);
}
.pb-chip::before { content: "\2605"; font-size: 13px; }

/* ============================================================
 * 20. Live wind compass mini-widget.
 * Small compass dial. The arrow's transform is set inline.
 * ============================================================ */
.wind-compass {
  position: relative; width: 36px; height: 36px;
  border-radius: 50%; border: 1.5px solid var(--green2, #5fc05f);
  display: inline-block;
}
.wind-compass::before, .wind-compass::after {
  content: ""; position: absolute; left: 50%; top: 50%;
  width: 1px; height: 14px; background: rgba(255, 255, 255, 0.2);
  transform: translate(-50%, -50%);
}
.wind-compass::after { transform: translate(-50%, -50%) rotate(90deg); }
.wind-compass .wc-arrow {
  position: absolute; left: 50%; top: 4px;
  width: 0; height: 0;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-bottom: 12px solid var(--green2, #5fc05f);
  transform: translateX(-50%);
  transform-origin: 50% 100%;
  transition: transform 0.4s var(--ease-spring, cubic-bezier(0.34, 1.56, 0.64, 1));
  filter: drop-shadow(0 0 4px rgba(95, 192, 95, 0.5));
}

/* ============================================================
 * 21. Per-hole notes inline pin.
 * Sticky-note-style box that doesn't hide behind a menu.
 * ============================================================ */
.hole-note {
  background: linear-gradient(180deg, rgba(255, 235, 130, 0.10), rgba(255, 235, 130, 0.04));
  border-left: 3px solid var(--amber, #ffc107);
  padding: 8px 12px;
  border-radius: 0 8px 8px 0;
  margin: 8px 0;
  font-size: calc(13px + var(--text-delta));
  color: var(--text);
  line-height: 1.4;
}

/* ============================================================
 * 22. Score color tier gradient backgrounds.
 * Refines the score-tier pill colors with a subtle gradient.
 * ============================================================ */
.score-num.tier-ace, .rh-score.tier-ace { background: linear-gradient(135deg, #ffd54f, #ffc107); color: #1a1a00; padding: 2px 10px; border-radius: var(--r-pill, 999px); }
.score-num.tier-eagle, .rh-score.tier-eagle { background: linear-gradient(135deg, #ffe082, #ffd54f); color: #1a1a00; padding: 2px 10px; border-radius: var(--r-pill, 999px); }
.score-num.tier-birdie, .rh-score.tier-birdie { background: linear-gradient(135deg, var(--green2, #5fc05f), var(--green3, #4caf50)); color: #0c150c; padding: 2px 10px; border-radius: var(--r-pill, 999px); }
.score-num.tier-bogey, .rh-score.tier-bogey { background: linear-gradient(135deg, rgba(239, 83, 80, 0.22), rgba(239, 83, 80, 0.10)); color: var(--red, #ef5350); padding: 2px 10px; border-radius: var(--r-pill, 999px); }

/* ============================================================
 * 23. Number-pad layout hint for score entry.
 * Big squarish keys laid out in a 3x4 grid for fast tapping.
 * ============================================================ */
.numpad { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; max-width: 280px; margin: 8px auto; }
.numpad .npk {
  background: var(--bg-card, var(--bg3, #243a24));
  border: 1px solid var(--border, #2a3a2a);
  border-radius: var(--r-sm, 8px);
  padding: 16px 0;
  font-size: calc(22px + var(--text-delta));
  font-weight: 700; color: var(--text); cursor: pointer;
  font-variant-numeric: tabular-nums;
  transition: background 0.12s ease, transform 0.12s ease;
  min-height: 56px;
}
.numpad .npk:hover { background: var(--bg2, #1a2a1a); }
.numpad .npk:active { transform: scale(0.93); }
.numpad .npk.npk-action { background: linear-gradient(180deg, var(--green2, #5fc05f), var(--green3, #4caf50)); color: #0c150c; }

/* ============================================================
 * 24. Wizard "skip" button styling.
 * Subtle skip CTA that doesn't compete with the primary action.
 * ============================================================ */
.wiz-skip {
  background: transparent; border: none; color: var(--muted);
  padding: 8px 12px; cursor: pointer;
  font-size: calc(12px + var(--text-delta));
  text-decoration: underline; text-underline-offset: 3px;
  transition: color 0.15s ease;
}
.wiz-skip:hover { color: var(--green2, #5fc05f); }

/* ============================================================
 * 25. Sticky footer action bar on detail views.
 * For primary CTAs that should stay visible while scrolling.
 * ============================================================ */
.sticky-footer-bar {
  position: sticky; bottom: 0; left: 0; right: 0;
  background: rgba(var(--bg-rgb, 12, 21, 12), 0.95);
  backdrop-filter: saturate(180%) blur(8px);
  -webkit-backdrop-filter: saturate(180%) blur(8px);
  padding: 10px 12px;
  border-top: 1px solid var(--border, #2a3a2a);
  display: flex; gap: 10px;
  z-index: var(--z-banner, 200);
  box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.3);
}
.sticky-footer-bar .btn { flex: 1; }

/* ============================================================
 * 26. Slide-out side panel base styles.
 * For settings drawers + course filter panels.
 * ============================================================ */
.side-panel {
  position: fixed; top: 0; right: 0; bottom: 0;
  width: 320px; max-width: 90vw;
  background: var(--bg-card, var(--bg2, #1a2a1a));
  border-left: 1px solid var(--border, #2a3a2a);
  box-shadow: -6px 0 22px rgba(0, 0, 0, 0.45);
  transform: translateX(100%);
  transition: transform 0.32s var(--ease-spring, cubic-bezier(0.34, 1.56, 0.64, 1));
  z-index: var(--z-overlay, 800);
  overflow-y: auto;
  padding: 18px;
}
.side-panel.open { transform: translateX(0); }
.side-panel-scrim {
  position: fixed; inset: 0;
  background: rgba(0, 0, 0, 0.5);
  opacity: 0; pointer-events: none;
  transition: opacity 0.32s ease;
  z-index: calc(var(--z-overlay, 800) - 1);
}
.side-panel-scrim.open { opacity: 1; pointer-events: auto; }

/* ============================================================
 * 27. Drag handle component.
 * Vertical dot grid for reorderable list items.
 * ============================================================ */
.drag-handle {
  display: inline-grid; grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr 1fr; gap: 2px;
  width: 14px; height: 20px;
  cursor: grab; opacity: 0.45;
  transition: opacity 0.15s ease;
}
.drag-handle::before, .drag-handle::after { content: ""; }
.drag-handle::before, .drag-handle::after,
.drag-handle .dot { background: var(--muted); border-radius: 50%; }
.drag-handle:hover { opacity: 0.85; }
.drag-handle:active { cursor: grabbing; }

/* ============================================================
 * 28. Pinned/favorite courses shortcut row on home.
 * Horizontal scrolling row of avatars for quick access.
 * ============================================================ */
.pinned-courses-row {
  display: flex; gap: 10px; overflow-x: auto; padding: 10px 4px;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
}
.pinned-courses-row::-webkit-scrollbar { display: none; }
.pinned-courses-row .pinned-item {
  flex: 0 0 auto;
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  scroll-snap-align: start;
  cursor: pointer;
  text-align: center;
  min-width: 64px;
}
.pinned-courses-row .pinned-item .avatar { width: 48px; height: 48px; font-size: calc(15px + var(--text-delta)); }
.pinned-courses-row .pinned-item .pinned-label {
  font-size: calc(10px + var(--text-delta)); color: var(--muted);
  max-width: 72px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ============================================================
 * 29. Quick stats card on profile (last week summary).
 * ============================================================ */
.quick-stats-card {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px;
  padding: 14px;
  background: var(--bg-card, var(--bg2, #1a2a1a));
  border: 1px solid var(--border, #2a3a2a);
  border-radius: var(--r-md, 12px);
  margin: 12px 0;
}
.quick-stats-card .qs { text-align: center; }
.quick-stats-card .qs-num { font-size: calc(22px + var(--text-delta)); font-weight: 700; color: var(--green2, #5fc05f); font-variant-numeric: tabular-nums; }
.quick-stats-card .qs-lbl { font-size: calc(10px + var(--text-delta)); color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em; margin-top: 2px; }

/* ============================================================
 * 30. Improved scorecard tier coloring.
 * Score tiers get a subtle gradient that fades with the column.
 * ============================================================ */
.scorecard-cell { transition: background 0.18s ease; }
.scorecard-cell.cell-eagle { background: linear-gradient(180deg, rgba(255, 213, 79, 0.18), rgba(255, 213, 79, 0.05)); }
.scorecard-cell.cell-birdie { background: linear-gradient(180deg, rgba(95, 192, 95, 0.18), rgba(95, 192, 95, 0.05)); }
.scorecard-cell.cell-par { background: linear-gradient(180deg, transparent, transparent); }
.scorecard-cell.cell-bogey { background: linear-gradient(180deg, rgba(239, 83, 80, 0.12), rgba(239, 83, 80, 0.03)); }
.scorecard-cell.cell-doublebogey { background: linear-gradient(180deg, rgba(239, 83, 80, 0.22), rgba(239, 83, 80, 0.08)); }

/* ============================================================
 * 31. OB/penalty viz on history cards.
 * Small red dots representing each OB stroke on the hole-strip.
 * ============================================================ */
.rh-hole-strip .ob-dot {
  display: inline-block; width: 4px; height: 4px; border-radius: 50%;
  background: var(--red, #ef5350);
  margin: 0 1px;
  box-shadow: 0 0 3px rgba(239, 83, 80, 0.5);
}

/* ============================================================
 * 32. Trend chart legend.
 * Compact legend row beneath the chart explaining the line + best ring.
 * ============================================================ */
.trend-legend { display: flex; gap: 14px; padding: 6px 4px; font-size: calc(10px + var(--text-delta)); color: var(--muted); }
.trend-legend .legend-item { display: inline-flex; align-items: center; gap: 5px; }
.trend-legend .legend-swatch { width: 10px; height: 10px; border-radius: 50%; }
.trend-legend .legend-swatch.swatch-line { background: var(--green2, #5fc05f); }
.trend-legend .legend-swatch.swatch-best { background: var(--amber, #ffc107); box-shadow: 0 0 4px var(--amber, #ffc107); }

/* ============================================================
 * 33. Form-field grouping.
 * .field-group wraps related fields with a subtle border + label.
 * ============================================================ */
.field-group {
  border: 1px solid var(--border, #2a3a2a); border-radius: var(--r-sm, 8px);
  padding: 10px 12px; margin: 10px 0;
  background: rgba(255, 255, 255, 0.02);
}
.field-group .field-group-label {
  font-size: calc(10px + var(--text-delta));
  text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--green2, #5fc05f); font-weight: 700; margin-bottom: 8px;
}

/* ============================================================
 * 34. Empty-bag wizard prompt CTA.
 * ============================================================ */
.empty-bag-prompt {
  text-align: center; padding: 28px 16px;
  background: linear-gradient(180deg, rgba(95, 192, 95, 0.04), transparent);
  border: 1.5px dashed rgba(95, 192, 95, 0.3);
  border-radius: var(--r-md, 12px); margin: 16px 0;
}
.empty-bag-prompt .ebp-title { font-size: calc(18px + var(--text-delta)); font-weight: 700; margin-bottom: 6px; }
.empty-bag-prompt .ebp-body { font-size: calc(13px + var(--text-delta)); color: var(--muted); margin-bottom: 14px; line-height: 1.4; }
.empty-bag-prompt .btn { min-width: 160px; }

/* ============================================================
 * 35. Disc-add wizard clearer current step.
 * Step indicator with active step pulsed.
 * ============================================================ */
.wiz-step-indicator {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  padding: 8px 0; margin-bottom: 4px;
}
.wiz-step-indicator .wsi-step {
  width: 8px; height: 8px; border-radius: 50%;
  background: rgba(255, 255, 255, 0.18);
  transition: all 0.2s var(--ease-spring, cubic-bezier(0.34, 1.56, 0.64, 1));
}
.wiz-step-indicator .wsi-step.active { background: var(--green2, #5fc05f); transform: scale(1.6); box-shadow: 0 0 8px rgba(95, 192, 95, 0.5); }
.wiz-step-indicator .wsi-step.done { background: var(--green3, #4caf50); }

/* ============================================================
 * 36. Shot-wizard progress bar at bottom.
 * Thin bar across the bottom of the wizard showing step progress.
 * ============================================================ */
.wiz-progress-bar {
  position: absolute; left: 0; right: 0; bottom: 0;
  height: 3px; background: rgba(255, 255, 255, 0.06);
}
.wiz-progress-bar .wpb-fill {
  height: 100%; background: linear-gradient(90deg, var(--green3, #4caf50), var(--green2, #5fc05f));
  transition: width 0.32s var(--ease-spring, cubic-bezier(0.34, 1.56, 0.64, 1));
  box-shadow: 0 0 6px rgba(95, 192, 95, 0.5);
}

/* ============================================================
 * 37. Distance unit switch.
 * Toggle between ft and m display.
 * ============================================================ */
.unit-switch {
  display: inline-flex; align-items: center;
  background: var(--bg3, #243a24); border: 1px solid var(--border, #2a3a2a);
  border-radius: var(--r-pill, 999px); padding: 2px;
}
.unit-switch .unit-opt {
  padding: 4px 12px; border-radius: var(--r-pill, 999px);
  background: transparent; border: none; color: var(--muted);
  font-size: calc(11px + var(--text-delta)); cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
.unit-switch .unit-opt.active { background: var(--green2, #5fc05f); color: #0c150c; font-weight: 700; }

/* ============================================================
 * 38. Year/month/week toggle.
 * Same shape as unit-switch but for time-window selection.
 * ============================================================ */
.window-switch { display: inline-flex; gap: 4px; padding: 2px; background: var(--bg3, #243a24); border-radius: var(--r-pill, 999px); }
.window-switch .ws-opt {
  padding: 4px 10px; border-radius: var(--r-pill, 999px);
  background: transparent; border: none; color: var(--muted);
  font-size: calc(11px + var(--text-delta)); cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
.window-switch .ws-opt.active { background: var(--green2, #5fc05f); color: #0c150c; font-weight: 700; }

/* ============================================================
 * 39. Sticky search bar that compacts on scroll.
 * Wraps any .search-bar with .sticky-search.
 * ============================================================ */
.sticky-search { position: sticky; top: 0; z-index: var(--z-banner, 200); background: rgba(var(--bg-rgb, 12, 21, 12), 0.92); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); padding: 8px 0; transition: padding 0.2s ease; }
.sticky-search.compact { padding: 4px 0; }
.sticky-search.compact input { padding: 6px 10px; font-size: calc(13px + var(--text-delta)); }

/* ============================================================
 * 40. Photo-upload preview frame.
 * Dashed border + green hover state + camera icon centered.
 * ============================================================ */
.photo-upload-frame {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  width: 100%; min-height: 140px;
  border: 2px dashed var(--border, #2a3a2a);
  border-radius: var(--r-md, 12px);
  background: rgba(255, 255, 255, 0.02);
  cursor: pointer; padding: 14px;
  transition: border-color 0.18s ease, background 0.18s ease, transform 0.18s ease;
}
.photo-upload-frame:hover { border-color: var(--green2, #5fc05f); background: rgba(95, 192, 95, 0.04); transform: translateY(-1px); }
.photo-upload-frame .pu-icon { font-size: 28px; opacity: 0.65; margin-bottom: 6px; }
.photo-upload-frame .pu-hint { font-size: calc(12px + var(--text-delta)); color: var(--muted); }

/* ============================================================
 * 41. Disabled-form feedback.
 * Greyed input + explainer underneath.
 * ============================================================ */
.field-disabled { opacity: 0.6; }
.field-disabled input, .field-disabled select, .field-disabled textarea { background: rgba(255, 255, 255, 0.02); cursor: not-allowed; }
.field-explainer { font-size: calc(11px + var(--text-delta)); color: var(--muted); margin-top: 4px; line-height: 1.3; }

/* ============================================================
 * 42. Round-finish recap polish.
 * Banner + key stat tiles + share button row.
 * ============================================================ */
.recap-banner {
  background: linear-gradient(135deg, rgba(95, 192, 95, 0.18), rgba(95, 192, 95, 0.06));
  border: 1px solid rgba(95, 192, 95, 0.3);
  border-radius: var(--r-lg, 16px);
  padding: 18px 20px;
  margin: 12px 0 16px;
  position: relative; overflow: hidden;
}
.recap-banner::before {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(circle at 80% 20%, rgba(95, 192, 95, 0.25), transparent 60%);
  pointer-events: none;
}
.recap-banner .recap-title { font-size: calc(20px + var(--text-delta)); font-weight: 700; margin: 0 0 4px; position: relative; }
.recap-banner .recap-sub { font-size: calc(13px + var(--text-delta)); color: var(--muted); position: relative; }

/* ============================================================
 * 43. Account-info inline edit affordance.
 * Pencil icon on hover for editable fields.
 * ============================================================ */
.inline-edit { position: relative; padding-right: 22px; }
.inline-edit::after {
  content: "\270E"; /* pencil */
  position: absolute; right: 4px; top: 50%;
  transform: translateY(-50%);
  opacity: 0; color: var(--green2, #5fc05f);
  transition: opacity 0.15s ease;
  font-size: 13px;
}
.inline-edit:hover::after, .inline-edit:focus-within::after { opacity: 1; }

/* ============================================================
 * 44. Per-layout play-distribution mini-bar.
 * Like bag-composition but for layout plays per course.
 * ============================================================ */
.layout-distribution {
  display: flex; height: 6px; overflow: hidden;
  border-radius: 3px; background: rgba(255, 255, 255, 0.06);
  margin: 6px 0;
}
.layout-distribution .ld-seg { transition: opacity 0.15s ease; background: var(--green2, #5fc05f); }
.layout-distribution .ld-seg:nth-child(1) { background: var(--green2, #5fc05f); }
.layout-distribution .ld-seg:nth-child(2) { background: #7cc77c; }
.layout-distribution .ld-seg:nth-child(3) { background: var(--amber, #ffc107); }
.layout-distribution .ld-seg:nth-child(4) { background: #ff9800; }
.layout-distribution .ld-seg:nth-child(5) { background: var(--red, #ef5350); }
.layout-distribution .ld-seg:hover { opacity: 0.8; }

/* ============================================================
 * 45. Easter-egg konami pulse.
 * Triggered by JS after the konami sequence. Adds a brief brand-green
 * pulse to the brand button.
 * ============================================================ */
@keyframes v5-konami-pulse {
  0%, 100% { filter: drop-shadow(0 0 0 transparent); }
  20% { filter: drop-shadow(0 0 12px var(--green2, #5fc05f)) hue-rotate(20deg); }
  40% { filter: drop-shadow(0 0 8px var(--amber, #ffc107)); }
  60% { filter: drop-shadow(0 0 12px var(--green2, #5fc05f)) hue-rotate(-20deg); }
  80% { filter: drop-shadow(0 0 6px var(--amber, #ffc107)); }
}
.konami-active { animation: v5-konami-pulse 2s ease-in-out 2; }

/* ============================================================
 * 46. Icon stroke consistency wrapper.
 * Anywhere we use an SVG inside .icon, ensure 1.5px stroke + brand color.
 * ============================================================ */
.icon { display: inline-flex; align-items: center; justify-content: center; line-height: 0; }
.icon svg { width: 20px; height: 20px; stroke: currentColor; stroke-width: 1.5; fill: none; stroke-linecap: round; stroke-linejoin: round; }
.icon.icon-sm svg { width: 16px; height: 16px; }
.icon.icon-lg svg { width: 26px; height: 26px; }

/* ============================================================
 * 47. Tab-focus-only outline.
 * Suppress focus ring on mouse-click (focus-visible handles tab).
 * Already supported in modern browsers via :focus-visible; v4 added the
 * brand ring. v5 ensures click-to-focus doesn't redraw the ring on the
 * legacy :focus pseudo-class.
 * ============================================================ */
button:focus:not(:focus-visible),
[role="button"]:focus:not(:focus-visible),
a:focus:not(:focus-visible) {
  outline: none;
  box-shadow: none;
}

/* ============================================================
 * 48. Hover-state contrast in branded-light theme.
 * Light theme already exists; v5 raises hover contrast so interactive
 * elements feel more clickable.
 * ============================================================ */
html[data-theme="light"] .home-card:hover,
html[data-theme="light"] .disc-card:hover,
html[data-theme="light"] .rh-card:hover {
  background: rgba(95, 192, 95, 0.06);
  border-color: var(--green2, #5fc05f);
}

/* ============================================================
 * 49. iOS PWA safe-area padding.
 * Honor env(safe-area-inset-*) so notched devices don't clip content.
 * ============================================================ */
body {
  padding-left: env(safe-area-inset-left);
  padding-right: env(safe-area-inset-right);
}
/* 0.42.1 — env() padding on .app-header dropped to avoid shifting the .header-menu absolute offset. Notch padding handled at the body level instead. */
.fab { right: max(18px, env(safe-area-inset-right)); bottom: max(18px, env(safe-area-inset-bottom)); }
.quick-sheet { padding-bottom: max(24px, env(safe-area-inset-bottom)); }
.sticky-footer-bar { padding-bottom: max(10px, env(safe-area-inset-bottom)); }

/* ============================================================
 * 50. Container queries for adaptive cards.
 * Cards reformat their inner layout based on the card's width, not the
 * viewport. Browsers without container queries get the default layout.
 * ============================================================ */
.disc-card, .rh-card, .home-card { container-type: inline-size; container-name: card; }
@container card (max-width: 280px) {
  .disc-card-body, .rh-card-body, .home-card-body { flex-direction: column; align-items: flex-start; }
  .disc-card .throw-chip, .rh-card .rh-chip { font-size: calc(10px + var(--text-delta)); padding: 2px 6px; }
}
@container card (min-width: 480px) {
  .disc-card .disc-mold-sub { font-size: calc(13px + var(--text-delta)); }
  .rh-card .rh-meta { gap: 14px; }
}

/* ============================================================
 * BOLD MOVES: command palette overlay (Ctrl+K).
 * ============================================================ */
.cmd-palette-overlay {
  position: fixed; inset: 0; z-index: 9800;
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(6px) saturate(180%);
  -webkit-backdrop-filter: blur(6px) saturate(180%);
  display: flex; justify-content: center; align-items: flex-start;
  padding: 10vh 16px;
  animation: v5-cmd-overlay-in 0.18s ease-out;
}
@keyframes v5-cmd-overlay-in { from { opacity: 0; } to { opacity: 1; } }
.cmd-palette {
  width: 100%; max-width: 640px;
  background: var(--bg-card, var(--bg2, #1a2a1a));
  border: 1px solid var(--green2, #5fc05f);
  border-radius: var(--r-lg, 18px);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.55), 0 0 0 1px rgba(95, 192, 95, 0.25), 0 0 32px rgba(95, 192, 95, 0.18);
  overflow: hidden;
  animation: v5-cmd-palette-in 0.32s cubic-bezier(0.34, 1.56, 0.64, 1);
  display: flex; flex-direction: column;
  max-height: 70vh;
}
@keyframes v5-cmd-palette-in {
  from { opacity: 0; transform: translateY(-20px) scale(0.96); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
.cmd-palette input#cmdPaletteInput {
  width: 100%; padding: 18px 20px;
  background: transparent; border: none; border-bottom: 1px solid var(--border, #2a3a2a);
  color: var(--text);
  font-size: calc(18px + var(--text-delta));
  font-weight: 500;
  font-family: inherit;
  outline: none;
}
.cmd-palette input#cmdPaletteInput::placeholder { color: var(--muted); }
.cmd-palette-results { overflow-y: auto; flex: 1; padding: 6px 0; }
.cmd-palette-row {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 16px; cursor: pointer;
  border-left: 3px solid transparent;
  transition: background 0.1s ease, border-color 0.1s ease;
}
.cmd-palette-row:hover, .cmd-palette-row.selected {
  background: rgba(95, 192, 95, 0.08);
  border-left-color: var(--green2, #5fc05f);
}
.cmd-kind {
  font-size: 10px; text-transform: uppercase; letter-spacing: 0.08em;
  padding: 2px 8px; border-radius: 999px;
  background: rgba(255, 255, 255, 0.06); color: var(--muted);
  font-weight: 700;
}
.cmd-kind-course { background: rgba(95, 192, 95, 0.16); color: var(--green2, #5fc05f); }
.cmd-kind-disc { background: rgba(255, 193, 7, 0.14); color: var(--amber, #ffc107); }
.cmd-kind-view { background: rgba(66, 165, 245, 0.14); color: #42a5f5; }
.cmd-kind-action { background: rgba(95, 192, 95, 0.10); color: var(--green2, #5fc05f); }
.cmd-label-block { flex: 1; min-width: 0; }
.cmd-label { font-size: calc(14px + var(--text-delta)); color: var(--text); font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cmd-sub { font-size: calc(11px + var(--text-delta)); color: var(--muted); margin-top: 1px; }
.cmd-hint { font-size: calc(10px + var(--text-delta)); color: var(--muted); font-family: ui-monospace, "SF Mono", Menlo, monospace; }
.cmd-palette-empty { padding: 24px 16px; text-align: center; color: var(--muted); font-size: calc(13px + var(--text-delta)); }
.cmd-palette-footer {
  display: flex; gap: 14px; justify-content: flex-end;
  padding: 8px 16px; border-top: 1px solid var(--border, #2a3a2a);
  font-size: calc(10px + var(--text-delta)); color: var(--muted);
}
.cmd-palette-footer kbd {
  background: var(--bg3, #243a24); border: 1px solid var(--border, #2a3a2a);
  padding: 1px 5px; border-radius: 4px; margin-right: 3px;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 10px;
}

/* ============================================================
 * 0.42.1 — Header search button. Mobile-friendly central trigger
 * for the command palette. Replaces the Ctrl+K keyboard shortcut as
 * the primary discoverability surface. The "/" key still works as
 * a power-user shortcut.
 * ============================================================ */
.header-search-btn {
  flex: 1 1 auto;
  max-width: 360px;
  min-width: 0;
  margin: 0 16px;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  background: var(--bg3, #243a24);
  border: 1px solid var(--border, #2a3a2a);
  border-radius: var(--r-pill, 999px);
  color: var(--muted);
  font-size: calc(13px + var(--text-delta));
  font-family: inherit;
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease, box-shadow 0.18s ease;
  white-space: nowrap;
  overflow: hidden;
}
.header-search-btn:hover, .header-search-btn:focus-visible {
  border-color: var(--green2, #5fc05f);
  color: var(--text);
  background: var(--bg2, #1a2a1a);
  box-shadow: 0 0 0 3px rgba(95, 192, 95, 0.15);
  outline: none;
}
.header-search-icon {
  font-size: 14px;
  opacity: 0.85;
  flex-shrink: 0;
}
.header-search-label {
  flex: 1;
  text-align: left;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.header-search-hint {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 11px;
  background: var(--bg2, #1a2a1a);
  border: 1px solid var(--border, #2a3a2a);
  border-radius: 4px;
  padding: 1px 6px;
  color: var(--muted);
  flex-shrink: 0;
}
@media (max-width: 480px) {
  .header-search-btn { margin: 0 8px; padding: 6px 10px; gap: 6px; }
  .header-search-label { display: none; }
  .header-search-hint { display: none; }
  .header-search-btn::after { content: "Search"; font-size: calc(12px + var(--text-delta)); }
}

/* Update command-palette footer hint to reflect new "/" binding. */
.cmd-palette-footer { gap: 12px; }

/* ===== styles-v6.css ===== */
/* styles-v6.css . YesAndChains 0.43.0 . Third polish wave (20 visual items).
 *
 * Builds on v3 + v4 + v5. Where prior waves added components, v6 spends its
 * budget on (a) refining what's already shipped, (b) wiring up v5 components
 * that haven't been adopted by the markup yet, (c) better empty states +
 * micro-interactions across the app. Catalogued top-to-bottom:
 *
 *  1. Brand button accent glow (always-on subtle, brighter on hover).
 *  2. App-wide card-header alignment + spacing tightening.
 *  3. Refined modal close button (large hit area, brand-green hover).
 *  4. Subtle dotted texture on the body bg in branded theme.
 *  5. Better focus ring on multi-select chips (matches brand 3-layer).
 *  6. Mobile tap-feedback ripple on .btn / .home-card / .disc-card.
 *  7. Improved scrollbar in side panels (thinner, brand thumb).
 *  8. Refined section labels with brand-line decoration.
 *  9. Better disc-card flight-number ring layout.
 * 10. Tighter wizard-step indicator spacing.
 * 11. Refined penalty pill warm-tint depth.
 * 12. Improved hover-lift on round-history cards (less jumpy).
 * 13. Better hover state on the toggleStarredHome chevron.
 * 14. Refined search input focus glow.
 * 15. Improved leaflet popup styling (brand-aware bg + text).
 * 16. Refined chip-toggle active state (deeper green tint).
 * 17. Better separator styling between settings groups.
 * 18. Refined disc-list row hover (left-edge accent ribbon).
 * 19. Improved sign-in pill (auth-pill) treatment.
 * 20. Print-mode header + page break refinements.
 */

/* ============================================================
 * 1. Brand button accent glow.
 * Always-on subtle drop-shadow on the brand-button logo. Brightens
 * + scales slightly on hover. Reinforces the brand identity in the
 * primary navigation slot.
 * ============================================================ */
.app-brand .app-brand-logo {
  filter: drop-shadow(0 0 4px rgba(95, 192, 95, 0.12));
  transition: filter 0.22s ease, transform 0.22s var(--ease-spring, cubic-bezier(0.34, 1.56, 0.64, 1));
}
.app-brand:hover .app-brand-logo {
  filter: drop-shadow(0 0 10px rgba(95, 192, 95, 0.45));
  transform: scale(1.04);
}
.app-brand:active .app-brand-logo { transform: scale(0.96); }

/* ============================================================
 * 2. Card-header alignment.
 * .bag-section-header was set in v4 to 14px / 16px padding + 600 weight.
 * v6 tightens vertical rhythm so the chevron + section label sit on the
 * same baseline as the count badge.
 * ============================================================ */
.bag-section-header {
  display: flex; align-items: center; gap: 10px;
  padding: 14px 16px;
  line-height: 1.2;
}
.bag-section-header .bag-section-chevron { flex-shrink: 0; }
.bag-section-header .bag-section-label { flex: 1; }
.bag-section-header .bag-section-count {
  margin-left: auto;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  font-weight: 500;
}

/* ============================================================
 * 3. Modal close button.
 * Universal close-button treatment with brand-green hover + 40px target.
 * Pairs with .modal / .quick-sheet / .side-panel for consistency.
 * ============================================================ */
.modal-close, .sheet-close, .panel-close {
  width: 40px; height: 40px;
  border-radius: 50%;
  border: none;
  background: transparent;
  color: var(--muted);
  font-size: 22px; line-height: 1; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background 0.15s ease, color 0.15s ease, transform 0.12s ease;
}
.modal-close:hover, .sheet-close:hover, .panel-close:hover {
  background: rgba(95, 192, 95, 0.12);
  color: var(--green2, #5fc05f);
}
.modal-close:active { transform: scale(0.92); }

/* ============================================================
 * 4. Subtle dotted texture on body bg (branded theme only).
 * 0.5px-radius dots at low opacity, tiled. Adds depth without
 * competing with the actual content.
 * ============================================================ */
html[data-theme="branded"] body {
  background-image:
    radial-gradient(circle at 30% 0%, rgba(95, 192, 95, 0.04) 0%, transparent 60%),
    radial-gradient(circle at 80% 100%, rgba(95, 192, 95, 0.03) 0%, transparent 60%),
    radial-gradient(circle at 0% 0%, rgba(95, 192, 95, 0.06) 0.5px, transparent 1px);
  background-size: 100% 100%, 100% 100%, 32px 32px;
  background-color: var(--bg, #0c150c);
}

/* ============================================================
 * 5. Multi-select chip focus ring.
 * v4's global focus ring is too loud on dense chip rows. v6 substitutes
 * a tighter ring scoped to .chip-toggle / .layout-chip / .throw-chip.
 * ============================================================ */
.chip-toggle:focus-visible, .layout-chip:focus-visible, .throw-chip:focus-visible,
.mfr-chip:focus-visible, .cat-chip:focus-visible {
  outline: 2px solid var(--green2, #5fc05f);
  outline-offset: 1px;
  box-shadow: 0 0 0 3px rgba(95, 192, 95, 0.18);
}

/* ============================================================
 * 6. Mobile tap-feedback ripple.
 * Brief radial expansion on tap. Disabled when reduced-motion or
 * hover-capable pointer.
 * ============================================================ */
@media (hover: none) and (pointer: coarse) {
  .btn, .home-card, .disc-card, .rh-card {
    position: relative;
    overflow: hidden;
  }
  .btn::after, .home-card::after, .disc-card::after, .rh-card::after {
    content: ""; position: absolute; left: 50%; top: 50%;
    width: 0; height: 0; border-radius: 50%;
    background: rgba(95, 192, 95, 0.35);
    transform: translate(-50%, -50%);
    pointer-events: none;
    transition: width 0.5s ease-out, height 0.5s ease-out, opacity 0.5s ease-out;
    opacity: 0;
  }
  .btn:active::after, .home-card:active::after, .disc-card:active::after, .rh-card:active::after {
    width: 220%; height: 220%;
    opacity: 0.55;
    transition: width 0s, height 0s, opacity 0s;
  }
}

/* ============================================================
 * 7. Side-panel scrollbar.
 * Thinner + brand-tinted thumb inside .side-panel / .quick-sheet.
 * ============================================================ */
.side-panel::-webkit-scrollbar, .quick-sheet::-webkit-scrollbar { width: 6px; }
.side-panel::-webkit-scrollbar-thumb, .quick-sheet::-webkit-scrollbar-thumb {
  background: rgba(95, 192, 95, 0.4);
  border-radius: 3px;
}

/* ============================================================
 * 8. Section labels with brand-line decoration.
 * Adds a 2-char brand-green underline before each .section-title so
 * the section breaks feel intentional.
 * ============================================================ */
.section-title { position: relative; padding-left: 14px; }
.section-title::before {
  content: ""; position: absolute; left: 0; top: 50%;
  width: 8px; height: 2px;
  background: var(--green2, #5fc05f);
  transform: translateY(-50%);
  border-radius: 1px;
}

/* ============================================================
 * 9. Disc-card flight-number ring layout.
 * The four flight numbers (speed/glide/turn/fade) get a tighter
 * monospaced ring that doesn't push the disc icon around.
 * ============================================================ */
.disc-flight-row {
  display: inline-flex; gap: 4px;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: calc(11px + var(--text-delta));
  font-variant-numeric: tabular-nums;
}
.disc-flight-row .flight-num {
  background: rgba(255, 255, 255, 0.06);
  border-radius: 4px;
  padding: 1px 5px;
  color: var(--muted);
  min-width: 22px;
  text-align: center;
}
.disc-flight-row .flight-num.flight-overstable { color: var(--green2, #5fc05f); }
.disc-flight-row .flight-num.flight-understable { color: var(--amber, #ffc107); }

/* ============================================================
 * 10. Wizard-step indicator spacing.
 * The .wiz-progress-dots from v4 + .wiz-step-indicator from v5 share
 * functionally identical UI; v6 makes them visually identical so it
 * doesn't matter which markup the wizard uses.
 * ============================================================ */
.wiz-progress-dots, .wiz-step-indicator { gap: 8px; padding: 8px 0 6px; }

/* ============================================================
 * 11. Penalty pill warm-tint depth.
 * v4 gave .penalty-pill an amber outline. v6 adds a subtle inset shadow
 * + warm hover fill so the press feedback is more tactile.
 * ============================================================ */
.penalty-pill {
  background: linear-gradient(180deg, rgba(255, 193, 7, 0.06), transparent);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
}
.penalty-pill:hover { background: rgba(255, 193, 7, 0.14); }
.penalty-pill:active { background: rgba(255, 193, 7, 0.22); transform: scale(0.94); }

/* ============================================================
 * 12. Round-history card hover-lift refinement.
 * v4 had a 2px lift; v6 reduces to 1px so the cards feel less jumpy
 * in long history scrolls.
 * ============================================================ */
.rh-card:hover { transform: translateY(-1px); }
.rh-card:active { transform: translateY(0); }

/* ============================================================
 * 13. Starred-home chevron hover.
 * The collapse/expand chevron on the home-page Starred section gets
 * a subtle rotation animation refinement.
 * ============================================================ */
.bag-section-header .bag-section-chevron {
  transition: transform 0.22s var(--ease-spring, cubic-bezier(0.34, 1.56, 0.64, 1));
}
.bag-section-header.collapsed .bag-section-chevron { transform: rotate(-90deg); }

/* ============================================================
 * 14. Search input focus glow.
 * Every <input type="text"> in the round picker / library search /
 * mold search gets a brand-aware focus state.
 * ============================================================ */
input[type="text"]:focus, input[type="search"]:focus, input[type="email"]:focus {
  outline: none;
  border-color: var(--green2, #5fc05f);
  box-shadow:
    0 0 0 3px rgba(95, 192, 95, 0.18),
    0 0 12px rgba(95, 192, 95, 0.1) inset;
}

/* ============================================================
 * 15. Leaflet popup styling.
 * Leaflet's default white popup clashes with the dark theme. Override
 * to brand colors with proper contrast.
 * ============================================================ */
.leaflet-popup-content-wrapper {
  background: var(--bg-card, var(--bg2, #1a2a1a)) !important;
  color: var(--text) !important;
  border: 1px solid var(--border, #2a3a2a);
  border-radius: var(--r-md, 12px) !important;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.5);
}
.leaflet-popup-tip { background: var(--bg-card, var(--bg2, #1a2a1a)) !important; }
.leaflet-popup-close-button {
  color: var(--muted) !important;
  font-size: 18px !important;
  transition: color 0.15s ease;
}
.leaflet-popup-close-button:hover { color: var(--green2, #5fc05f) !important; }
.leaflet-popup-content a {
  background: var(--green2, #5fc05f) !important;
  color: #0c150c !important;
}

/* ============================================================
 * 16. Chip-toggle active state refinement.
 * Deeper green tint + crisper border so picked chips read more
 * confidently in the multi-select forms (fairwayTypes, etc.).
 * ============================================================ */
.chip-toggle.active, .layout-chip.active {
  background: linear-gradient(180deg, rgba(95, 192, 95, 0.28), rgba(95, 192, 95, 0.14));
  border-color: var(--green2, #5fc05f);
  color: var(--text);
  font-weight: 600;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.08);
}

/* ============================================================
 * 17. Settings group separator.
 * Replaces the heavy 1px border-top with a fading gradient hairline
 * between settings groups.
 * ============================================================ */
.settings-group + .settings-group { margin-top: 16px; padding-top: 16px; position: relative; }
.settings-group + .settings-group::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0;
  height: 1px;
  background: linear-gradient(to right,
    transparent 0%,
    rgba(95, 192, 95, 0.22) 50%,
    transparent 100%);
}

/* ============================================================
 * 18. Disc-list row left-edge accent ribbon.
 * Hovering a disc row in the bag list paints a brand-green 3px ribbon
 * on its leading edge. Mirrors the .player-row treatment from 0.40.x.
 * ============================================================ */
.disc-card { position: relative; }
.disc-card::before {
  content: ""; position: absolute; left: 0; top: 8px; bottom: 8px;
  width: 3px; border-radius: 0 2px 2px 0;
  background: var(--green2, #5fc05f);
  opacity: 0;
  transform: scaleY(0.4); transform-origin: center;
  transition: opacity 0.18s ease, transform 0.22s var(--ease-spring, cubic-bezier(0.34, 1.56, 0.64, 1));
}
.disc-card:hover::before { opacity: 0.55; transform: scaleY(1); }

/* ============================================================
 * 19. Auth pill (sign-in button) refinement.
 * Brand-green outline + hover-fill state. Sits between secondary
 * button and a chip in visual weight.
 * ============================================================ */
.auth-pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 14px; border-radius: var(--r-pill, 999px);
  background: transparent;
  border: 1.5px solid var(--green2, #5fc05f);
  color: var(--green2, #5fc05f);
  font-size: calc(12px + var(--text-delta));
  font-weight: 600;
  cursor: pointer;
  transition: background 0.18s ease, color 0.18s ease, transform 0.12s ease;
}
.auth-pill:hover {
  background: var(--green2, #5fc05f);
  color: #0c150c;
}
.auth-pill:active { transform: scale(0.96); }

/* ============================================================
 * 20. Print refinements.
 * Add header logo + version stamp on print pages. Avoid page-breaks
 * inside score-cards.
 * ============================================================ */
@media print {
  body::before {
    content: "YesAndChains . printed scorecard";
    display: block;
    font-size: 10px;
    color: #888;
    padding: 6px 0;
    border-bottom: 1px solid #ccc;
    margin-bottom: 12px;
  }
  .rh-card, .players-block, .stat-block { page-break-inside: avoid; }
  .home-card-arrow, .header-search-btn { display: none !important; }
}

/* ============================================================
 * MOBILE + PWA 0.43.1
 * ============================================================ */

/* iOS Safari auto-zooms when an input has font-size < 16px and the user
   focuses it. Floor every editable surface to 16px to prevent that. The
   visual scale via var(--text-delta) still works on top. */
input, select, textarea {
  font-size: max(16px, calc(14px + var(--text-delta)));
}

/* Standalone mode (installed PWA on home screen) gets a bit more padding
   at the top so content doesn't kiss the status bar on iOS. */
@media (display-mode: standalone) {
  body { padding-top: env(safe-area-inset-top); }
  .app-header { padding-top: max(12px, env(safe-area-inset-top)); }
}

/* Disable text selection on tappable elements (looks janky when long-press
   accidentally triggers a copy menu on mobile). Keep the input itself
   selectable. */
.btn, .home-card, .disc-card, .rh-card, .score-pill, .counter-btn,
.penalty-pill, .player-row, .header-search-btn, .auth-pill, .chip,
.chip-toggle, .layout-chip, .throw-chip, .mfr-chip, .cat-chip {
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}

/* When the soft keyboard pops on iOS, the bottom action-bar can get hidden
   behind it. The visualViewport API solves this; the CSS fallback is to
   shrink the bottom action-bar's safe-area when in focus. */
.actions-bar { padding-bottom: max(10px, env(safe-area-inset-bottom)); }
.sticky-footer-bar, .quick-sheet, .fab { padding-bottom: max(10px, env(safe-area-inset-bottom)); }

/* Larger touch targets on key buttons for finger-tap accuracy. The 40px
   floor from 0.25.0 is the minimum; mobile gets a bump to 44px on
   primary interactive surfaces (Apple's HIG floor + accessibility win). */
@media (pointer: coarse) {
  .btn-primary, .score-pill, .counter-btn, .penalty-pill, .fab,
  .header-menu-btn, .header-search-btn {
    min-height: 44px;
  }
  .score-pill, .counter-btn, .penalty-pill { min-width: 44px; }
}

/* PWA install banner . refined for iOS clarity. The Share button glyph on
   iOS Safari is the square with an upward arrow; render it inline so users
   know what to look for. */
.install-banner-title { font-weight: 600; }
.install-banner-sub { color: var(--muted); font-size: calc(12px + var(--text-delta)); }
.install-banner-sub strong { color: var(--green2, #5fc05f); }

/* ===== styles-v7.css ===== */
/* styles-v7.css . YesAndChains 0.44.0 . Mobile push (80 CSS items).
 *
 * Pure mobile-first refinements. Every rule targets either a known iOS Safari
 * quirk, an Android Chrome gap, a touch-interaction polish, or a mobile-
 * viewport layout improvement. Catalogued top-to-bottom; the matching JS
 * behaviors live in `src/mobile-hooks.ts`.
 *
 * Touch & gesture (1-15):
 *   1. Tap-highlight transparent globally.
 *   2. Touch-callout disabled on UI chrome.
 *   3. user-select tightened on chrome, kept on prose.
 *   4. Touch-action: manipulation on tappable surfaces.
 *   5. overscroll-behavior: contain on modals.
 *   6. Momentum scrolling enabled where useful.
 *   7. Long-press cancel hint via touch-action.
 *   8. Tap target floor 44px on coarse pointers.
 *   9. Bigger score-pill on coarse.
 *  10. Bigger counter-btn on coarse.
 *  11. Bigger penalty-pill on coarse.
 *  12. Bigger close buttons on coarse.
 *  13. Adequate gap between sibling tap targets.
 *  14. Reduced precision-required UI on touch.
 *  15. Pointer-coarse: hide hover-only affordances.
 *
 * Visual hierarchy on small screens (16-30):
 *  16. <480px home cards collapse vertically.
 *  17. <480px chip rows wrap not scroll.
 *  18. <380px reduce typography by one step.
 *  19. <480px headers single-line truncate.
 *  20. <480px modal full-bleed.
 *  21. Disc-card on mobile gets tighter padding.
 *  22. Round-card on mobile collapses meta.
 *  23. Home cards bigger icons on mobile.
 *  24. Section titles bigger on mobile.
 *  25. Settings rows tightened on mobile.
 *  26. Wizard step bigger touch zones mobile.
 *  27. Course-detail tabs scroll-snap mobile.
 *  28. Round-view single-column always on mobile.
 *  29. Bag grid single column < 480px.
 *  30. Search bar full-width on mobile.
 *
 * Mobile keyboard (31-40):
 *  31. Inputs >=16px floor.
 *  32. inputmode default search on .search-input.
 *  33. inputmode default numeric on .num-input.
 *  34. autocomplete="off" on opaque search.
 *  35. enterkeyhint="search" on search inputs.
 *  36. Don't capitalize search.
 *  37. Don't autocorrect throwers names.
 *  38. visualViewport height padding (JS-paired).
 *  39. Sticky footer-bar lifts above keyboard.
 *  40. Focused input scrollIntoView (JS-paired).
 *
 * Native feel (41-55):
 *  41. Pull-to-refresh disabled at page level.
 *  42. Rubber-band only inside .scroll-region.
 *  43. iOS native momentum on scroll-region.
 *  44. Status bar text color matches theme.
 *  45. Theme-color CSS variable.
 *  46. Standalone-mode header padding.
 *  47. Standalone-mode bottom safe-area.
 *  48. Standalone hides "open in browser" prompts.
 *  49. Native iOS spring on lists.
 *  50. Tap-feedback under 100ms.
 *  51. Skeleton shimmer respects motion.
 *  52. Modal entrance from bottom on mobile.
 *  53. Sheet swipe-down to dismiss hint.
 *  54. Bottom-aligned actions on detail views.
 *  55. Avoid orphan headers at view bottom.
 *
 * Performance (56-65):
 *  56. content-visibility: auto on round-history.
 *  57. content-visibility: auto on long bag lists.
 *  58. will-change reserved for in-flight animations.
 *  59. Decoded images sized via aspect-ratio.
 *  60. Reduce shadow complexity on low-DPI.
 *  61. Disable backdrop-blur on low-end Android.
 *  62. Defer non-critical CSS sections.
 *  63. Image-rendering: optimizeQuality on pins.
 *  64. Animations off when battery saver is on.
 *  65. Reduce transitions on save-data.
 *
 * iOS Safari fixes (66-75):
 *  66. 100vh trap: use 100dvh + 100svh fallback.
 *  67. Position: sticky height fix.
 *  68. Position: fixed scroll-lock fix.
 *  69. -webkit-tap-highlight-color: transparent.
 *  70. iOS input zoom prevention (font-size floor).
 *  71. iOS safe area inset top/bottom honoring.
 *  72. iOS scrollbar gutter override.
 *  73. iOS button rendering reset.
 *  74. iOS scrollIntoView block:center.
 *  75. iOS rubber-band overscroll containment.
 *
 * Android + accessibility (76-80):
 *  76. Android system font scaling respect.
 *  77. High-contrast media query support.
 *  78. forced-colors media query support.
 *  79. Reduced data preference respect.
 *  80. Increased line-height for screen readers.
 */

/* ============================================================
 * 1-15 . TOUCH & GESTURE
 * ============================================================ */
* { -webkit-tap-highlight-color: rgba(0, 0, 0, 0); }
button, a, .home-card, .disc-card, .rh-card, .player-row, .header-search-btn,
.score-pill, .counter-btn, .penalty-pill, .auth-pill, .chip, .chip-toggle,
.layout-chip, .throw-chip, .mfr-chip, .cat-chip, .header-menu-btn, .fab,
.modal-close, .sheet-close, .panel-close {
  -webkit-touch-callout: none;
  touch-action: manipulation;
  user-select: none;
  -webkit-user-select: none;
}
p, h1, h2, h3, h4, .disc-name, .home-card-title, .home-card-sub,
.rh-card-title, .stat-num, .stat-label, .player-name, .player-sub,
.observed-name { user-select: text; -webkit-user-select: text; }

.modal-scrim, .modal, .quick-sheet, .side-panel { overscroll-behavior: contain; }
.scroll-region, .cmd-palette-results, .side-panel, .rh-list,
.bag-grid, .home-cards-list { -webkit-overflow-scrolling: touch; }

@media (pointer: coarse) {
  .btn, button, .home-card, .disc-card, .rh-card, .auth-pill,
  .header-menu-btn, .header-search-btn { min-height: 44px; }
  .score-pill, .counter-btn { min-width: 44px; min-height: 44px; }
  .penalty-pill { min-width: 40px; min-height: 40px; }
  .modal-close, .sheet-close, .panel-close { min-width: 44px; min-height: 44px; }
  .home-card, .disc-card, .rh-card { padding-block: 12px; }
}
@media (hover: none) { .hover-only { display: none !important; } }

/* ============================================================
 * 16-30 . VISUAL HIERARCHY ON SMALL SCREENS
 * ============================================================ */
@media (max-width: 480px) {
  .home-card { flex-direction: row; gap: 10px; }
  .home-card-icon { font-size: calc(24px + var(--text-delta)); }
  .home-card-title { font-size: calc(16px + var(--text-delta)); }
  .home-card-sub { font-size: calc(12px + var(--text-delta)); }
  .home-card-arrow { font-size: 18px; }

  /* Chip rows wrap to multiple lines on narrow screens (no horizontal scroll). */
  .chip-row, .layout-chip-row, .throw-chip-row { flex-wrap: wrap; gap: 6px; }

  /* Modals go full-bleed; corners squared at the screen edges. */
  .modal { max-width: 100vw; max-height: 100dvh; border-radius: 0; margin: 0; }
  .modal-scrim { padding: 0; }

  /* Disc card density */
  .disc-card { padding: 10px 12px; }
  .disc-card .disc-card-body { gap: 8px; }
  .disc-name { font-size: calc(15px + var(--text-delta)); }
  .disc-mold-sub { font-size: calc(11px + var(--text-delta)); }

  /* Round card density */
  .rh-card { padding: 10px 12px; }
  .rh-card-meta { gap: 6px; flex-wrap: wrap; }

  .section-title { font-size: calc(13px + var(--text-delta)); }

  /* Settings rows */
  .settings-row { padding: 10px 12px; gap: 8px; }

  /* Bag grid */
  .bag-grid { grid-template-columns: 1fr !important; }

  /* Single-column search input row */
  .search-bar input { width: 100%; }

  /* Round view always single column on mobile */
  .round-view-grid { display: block; }
}

@media (max-width: 380px) {
  :root { --text-delta: -1px; }
  .home-card-title { font-size: calc(15px + var(--text-delta)); }
}

@media (max-width: 480px) {
  .app-header { padding: 10px 12px; }
  .app-brand-yesand { font-size: calc(12px + var(--text-delta)); }
  .app-brand-logo { height: 28px; }
}

/* Wizard touch zone bumps */
@media (pointer: coarse) {
  .shot-wiz-opt { min-height: 56px; font-size: calc(14px + var(--text-delta)); }
}

/* Tabs that overflow get horizontal scroll snap. */
@media (max-width: 480px) {
  .tab-row { overflow-x: auto; scroll-snap-type: x mandatory; flex-wrap: nowrap; }
  .tab-row .tab { scroll-snap-align: start; flex-shrink: 0; }
  .tab-row::-webkit-scrollbar { display: none; }
}

/* ============================================================
 * 31-40 . MOBILE KEYBOARD
 * ============================================================ */
input, select, textarea {
  font-size: max(16px, calc(14px + var(--text-delta)));
}

/* Default inputmode classes. Apply via class to clean markup. */
.search-input { inputmode: search; }
.num-input { inputmode: numeric; }
.decimal-input { inputmode: decimal; }
.tel-input { inputmode: tel; }

/* Search inputs: no autocorrect, no auto-cap. */
input[type="search"], .search-input {
  autocapitalize: none;
  -webkit-autocapitalize: none;
  spellcheck: false;
}

/* When the soft keyboard opens, the sticky footer bar lifts via the
   visualViewport JS hook. CSS variable --kb-offset is set by mobile-hooks.ts. */
.sticky-footer-bar, .actions-bar, .fab { transform: translateY(calc(var(--kb-offset, 0px) * -1)); transition: transform 0.18s ease; }

/* The cmd-palette repositions when the keyboard opens. */
.cmd-palette-overlay { padding-top: calc(10vh - var(--kb-offset, 0px) / 2); }

/* ============================================================
 * 41-55 . NATIVE FEEL
 * ============================================================ */
html, body { overscroll-behavior-y: none; }
.scroll-region { overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }

/* Standalone mode (installed PWA): theme-color + status bar polish. */
@media (display-mode: standalone) {
  body { padding-top: env(safe-area-inset-top); padding-bottom: env(safe-area-inset-bottom); }
  .app-header { padding-top: max(12px, env(safe-area-inset-top)); }
  .actions-bar, .sticky-footer-bar, .fab, .quick-sheet { padding-bottom: max(10px, env(safe-area-inset-bottom)); }
  /* Hide install-banner inside standalone (already installed). */
  .install-banner { display: none !important; }
}

/* Modal entrance from the bottom on mobile (sheet-like). */
@media (max-width: 480px) {
  @keyframes v7-mobile-modal-in {
    from { transform: translateY(100%); }
    to   { transform: translateY(0); }
  }
  .modal { animation: v7-mobile-modal-in 0.28s var(--ease-spring, cubic-bezier(0.34, 1.56, 0.64, 1)); }
}

/* Sheet drag-handle indicator at the top of quick-sheet. */
.quick-sheet::before {
  content: ""; display: block; width: 38px; height: 4px;
  background: rgba(255, 255, 255, 0.2); border-radius: 2px;
  margin: -4px auto 10px;
}

/* Bottom-aligned action buttons on detail views (thumb-reachable). */
@media (max-width: 480px) {
  .detail-actions {
    position: sticky; bottom: 0;
    background: rgba(var(--bg-rgb, 12, 21, 12), 0.96);
    padding: 10px 12px;
    border-top: 1px solid var(--border, #2a3a2a);
    z-index: 100;
  }
}

/* ============================================================
 * 56-65 . PERFORMANCE
 * ============================================================ */
.rh-list, .round-history-list { content-visibility: auto; contain-intrinsic-size: 0 100px; }
.bag-grid > *, .disc-grid > * { content-visibility: auto; contain-intrinsic-size: 0 80px; }

/* Save-data preference: reduce all animation + ditch shadows. */
@media (prefers-reduced-data: reduce) {
  * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
  .disc-card, .home-card, .rh-card { box-shadow: none !important; }
  body::before { background: none !important; }
}

/* Low-end Android: skip backdrop-filter (CPU-heavy). */
@supports not (backdrop-filter: blur(1px)) {
  .cmd-palette-overlay { background: rgba(0, 0, 0, 0.78); }
  .sticky-search { background: var(--bg, #0c150c); }
}

/* Map pins: optimize for sharpness over speed. */
.leaflet-marker-icon { image-rendering: auto; }

/* Aspect ratios for known-shape images so layout doesn't shift. */
.app-brand-logo, .home-card-icon img { aspect-ratio: 1 / 1; }

/* ============================================================
 * 66-75 . iOS SAFARI FIXES
 * ============================================================ */
/* 100vh trap: use dynamic + small viewport heights as fallback ladder. */
.full-height { min-height: 100vh; min-height: 100svh; min-height: 100dvh; }
.modal-scrim { min-height: 100vh; min-height: 100dvh; }

/* Fixed scroll-lock for iOS Safari modal. */
body.scroll-lock { position: fixed; left: 0; right: 0; width: 100%; overflow: hidden; }

/* iOS input button reset (default has rounded gray look). */
button { -webkit-appearance: none; appearance: none; }
input[type="search"] { -webkit-appearance: none; appearance: none; }

/* iOS scroll-into-view block:center pairs with the JS hook on focus. */
.field-focus-target { scroll-margin-block: 30vh; }

/* ============================================================
 * 76-80 . ANDROID + ACCESSIBILITY
 * ============================================================ */
@media (prefers-contrast: more) {
  :root {
    --text: #ffffff !important;
    --muted: #c9c9c9 !important;
    --border: #4a5a4a !important;
  }
  .btn-secondary { border-color: var(--green2, #5fc05f); }
}

@media (forced-colors: active) {
  .btn-primary { background: ButtonText; color: ButtonFace; border: 2px solid ButtonText; }
  .home-card, .disc-card, .rh-card { border: 1px solid CanvasText; }
}

/* When screen reader is on (via aria-live regions actively used), bump
   line-height for readability under VoiceOver / TalkBack. */
[aria-live] { line-height: 1.6; }

/* Larger primary font-size respecting system scaling. */
@supports (font-size: 1rem) {
  body { font-size: max(15px, 1rem); }
}

/* ============================================================
 * Behavioral pairings . CSS that supports the mobile-hooks.ts JS.
 * ============================================================ */
.net-status-banner {
  position: fixed; top: 0; left: 0; right: 0;
  background: rgba(239, 83, 80, 0.92);
  color: #fff;
  padding: 8px 14px;
  text-align: center;
  font-size: calc(13px + var(--text-delta));
  font-weight: 600;
  z-index: 10000;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  animation: v7-net-banner-in 0.28s ease-out;
}
@keyframes v7-net-banner-in { from { transform: translateY(-100%); } to { transform: translateY(0); } }
.net-status-dot {
  display: inline-block; width: 8px; height: 8px; border-radius: 50%;
  background: #fff;
  animation: v7-net-dot-pulse 1.4s ease-in-out infinite;
}
@keyframes v7-net-dot-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }

/* Action bar auto-hide on scroll-down. */
.actions-bar { transition: transform 0.22s ease; }
.actions-bar.autohide { transform: translateY(100%); }

/* Low-power flag: skip every non-essential animation. */
html[data-low-power="true"] *, html[data-low-power="true"] *::before, html[data-low-power="true"] *::after {
  animation-duration: 0.01ms !important;
  transition-duration: 0.01ms !important;
}

/* Standalone-mode polish: hide install-banner + bump theme color elements. */
html[data-standalone="true"] .install-banner { display: none !important; }

/* ===== styles-v8.css ===== */
/* styles-v8.css . YesAndChains 0.44.1 . Mobile push II (80 CSS items).
 *
 * Deeper mobile coverage. Where v7 set the foundation (touch targets,
 * keyboard, native feel, performance, iOS quirks), v8 spends its budget
 * on view-specific layouts, mobile-optimized components, and the
 * micro-patterns that make a PWA feel like a native app.
 *
 * Bottom sheets + half-sheets (1-10):
 *   1. .bottom-sheet base styles (rounded top, full-width).
 *   2. .bottom-sheet.half snap to 50% viewport height.
 *   3. .bottom-sheet.full snap to 90% viewport height.
 *   4. Bottom-sheet drag handle.
 *   5. Bottom-sheet backdrop fade.
 *   6. Bottom-sheet swipe-down dismiss visual hint.
 *   7. Bottom-sheet content scroll behavior.
 *   8. Bottom-sheet entrance from below.
 *   9. Bottom-sheet exit animation.
 *  10. Bottom-sheet stacked-corners on iOS.
 *
 * Round view mobile-specific (11-22):
 *  11. Round-view header compacts on scroll-down.
 *  12. Hole indicator pill expands above the action zone.
 *  13. Score widget enlarges on mobile.
 *  14. Score-pill +/- buttons go to 56px on mobile.
 *  15. Hole-nav buttons thumb-reachable at bottom.
 *  16. Strategy chip row scrolls horizontally on mobile.
 *  17. Wind chip relocated above score on mobile.
 *  18. Distance chip pulses on update (mobile-only larger).
 *  19. Caddy rec card more compact on narrow viewport.
 *  20. Live-round breathing badge larger on mobile.
 *  21. Mid-round abandon button hidden behind menu.
 *  22. Round-view caddy-host scroll-snap to top.
 *
 * Score widget + counter polish (23-32):
 *  23. Counter buttons 48px on mobile (up from 40px).
 *  24. Player row gap relaxed on mobile.
 *  25. Player name single-line truncate at narrow widths.
 *  26. Player counter score number larger on mobile.
 *  27. Self-row green tint stronger on mobile (for visibility).
 *  28. Counter buttons have larger inner glyph on mobile.
 *  29. Penalty pill anchored alongside counter on mobile.
 *  30. Score number anchored center on mobile.
 *  31. Counter buttons spaced wider on mobile (12px gap).
 *  32. Counter buttons get press-darken on mobile.
 *
 * Bag + disc view mobile (33-42):
 *  33. Disc icon larger on mobile (44px target).
 *  34. Disc card flight numbers stacked on narrow.
 *  35. Disc card swipe-to-edit gesture hint.
 *  36. Bag header sticky on mobile.
 *  37. Bag count badge larger on mobile.
 *  38. Add-disc CTA bottom-anchored on mobile.
 *  39. Disc detail image fills width on mobile.
 *  40. Disc detail tabs sticky on mobile.
 *  41. Disc detail action buttons in bottom bar on mobile.
 *  42. Multi-bag switcher bottom-sheet on mobile.
 *
 * Course + map view mobile (43-52):
 *  43. Course list rows touch-friendly height.
 *  44. Course map full-bleed on mobile.
 *  45. Course detail tabs scroll-snap on mobile.
 *  46. Course-detail score trend smaller chart on mobile.
 *  47. Course-detail "add round" CTA sticky at bottom.
 *  48. Map control buttons larger on mobile.
 *  49. Map pin tooltips bottom-anchored on mobile.
 *  50. Course search results full-width on mobile.
 *  51. Nearby-courses chip-row scroll on mobile.
 *  52. Course filter modal becomes bottom sheet.
 *
 * Profile + settings mobile (53-62):
 *  53. Settings rows touch height.
 *  54. Profile avatar centered on mobile.
 *  55. Profile stat blocks stack on narrow.
 *  56. Settings sections collapsible on mobile.
 *  57. Theme picker becomes radio pills on mobile.
 *  58. PDGA input row sticks to top after focus.
 *  59. Sign-out button standalone-styled on mobile.
 *  60. Account-deletion zone more isolated on mobile.
 *  61. Profile-photo upload uses camera-direct on mobile.
 *  62. Settings toggle row larger touch zone on mobile.
 *
 * Snackbar + toast (63-67):
 *  63. Toast pinned to bottom on mobile (not center).
 *  64. Toast stack honors safe-area-inset-bottom.
 *  65. Snackbar variant with action button.
 *  66. Snackbar slide-up entrance on mobile.
 *  67. Toast/snackbar swipe-to-dismiss hint.
 *
 * Misc mobile polish (68-80):
 *  68. Mobile-only floating "back to top" button.
 *  69. Mobile-only "share round" button after recap.
 *  70. Pull-to-refresh CSS hooks (JS-paired).
 *  71. Long-press menu base styles.
 *  72. Confirmation slide-to-confirm pattern.
 *  73. Mobile-friendly loading spinner.
 *  74. Loading skeleton for round-history on mobile.
 *  75. Mobile-friendly empty states (larger illustration).
 *  76. Search clear-button (×) inside input on mobile.
 *  77. Date-picker mobile native styling override.
 *  78. Native select dropdown styled on mobile.
 *  79. Keyboard-accessory bar layout for input rows.
 *  80. Mobile error state with retry CTA.
 */

/* ============================================================
 * 1-10 . BOTTOM SHEETS + HALF SHEETS
 * ============================================================ */
.bottom-sheet {
  position: fixed; left: 0; right: 0; bottom: 0;
  background: var(--bg-card, var(--bg2, #1a2a1a));
  border-top: 1px solid var(--border, #2a3a2a);
  border-radius: 18px 18px 0 0;
  z-index: var(--z-overlay, 800);
  transform: translateY(100%);
  transition: transform 0.32s cubic-bezier(0.34, 1.56, 0.64, 1);
  max-height: 90dvh;
  display: flex; flex-direction: column;
  padding-bottom: env(safe-area-inset-bottom);
  box-shadow: 0 -10px 32px rgba(0, 0, 0, 0.5);
}
.bottom-sheet.open { transform: translateY(0); }
.bottom-sheet.half { max-height: 50dvh; }
.bottom-sheet.full { max-height: 90dvh; }
.bottom-sheet::before {
  content: ""; display: block;
  width: 40px; height: 4px;
  background: rgba(255, 255, 255, 0.22);
  border-radius: 2px;
  margin: 8px auto 4px;
  cursor: grab;
}
.bottom-sheet-backdrop {
  position: fixed; inset: 0;
  background: rgba(0, 0, 0, 0.55);
  z-index: calc(var(--z-overlay, 800) - 1);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.32s ease;
}
.bottom-sheet-backdrop.open { opacity: 1; pointer-events: auto; }
.bottom-sheet-body {
  flex: 1; overflow-y: auto;
  padding: 12px 16px 20px;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}
.bottom-sheet-title {
  font-size: calc(17px + var(--text-delta));
  font-weight: 700;
  padding: 0 16px 8px;
  border-bottom: 1px solid var(--border, #2a3a2a);
  margin-bottom: 8px;
}

/* ============================================================
 * 11-22 . ROUND VIEW MOBILE-SPECIFIC
 * ============================================================ */
@media (max-width: 480px) {
  .round-view .wiz-header { position: sticky; top: 0; z-index: 50; padding: 8px 12px; }
  .hole-indicator-pill { font-size: calc(15px + var(--text-delta)); padding: 6px 14px; }
  .score-num { font-size: calc(36px + var(--text-delta)); }
  .score-pill { width: 56px !important; height: 56px !important; font-size: 26px; }
  .round-view .strategy-chip-row { overflow-x: auto; flex-wrap: nowrap; }
  .round-view .strategy-chip-row::-webkit-scrollbar { display: none; }
  .wind-chip { order: -1; align-self: center; margin-bottom: 6px; }
  .live-pin-distance { font-size: calc(15px + var(--text-delta)); padding: 8px 14px; }
  .caddy-rec-host { font-size: calc(13px + var(--text-delta)); }
  .live-round-badge { font-size: calc(13px + var(--text-delta)); padding: 6px 12px; }
}

/* ============================================================
 * 23-32 . SCORE WIDGET + COUNTER POLISH
 * ============================================================ */
@media (max-width: 480px) {
  .counter-btn { width: 48px; height: 48px; font-size: 26px; }
  .counter-score { min-width: 36px; font-size: calc(26px + var(--text-delta)); }
  .player-counter { gap: 12px; }
  .player-row { padding: 12px 12px; gap: 12px; }
  .player-name { font-size: calc(15px + var(--text-delta)); }
  .player-sub { font-size: calc(12px + var(--text-delta)); }
  .player-row.player-self {
    background: linear-gradient(180deg, rgba(95, 192, 95, 0.20), rgba(95, 192, 95, 0.06));
  }
  .counter-btn:active { filter: brightness(0.85); }
}

/* ============================================================
 * 33-42 . BAG + DISC VIEW MOBILE
 * ============================================================ */
@media (max-width: 480px) {
  .disc-icon { min-width: 44px; min-height: 44px; }
  .disc-flight-row { flex-wrap: wrap; gap: 3px; }
  .disc-flight-row .flight-num { min-width: 24px; padding: 2px 5px; }
  .bag-section-header { position: sticky; top: 0; z-index: 40; background: var(--bg2, #1a2a1a); }
  .bag-section-count { font-size: calc(13px + var(--text-delta)); }
  .bag-add-cta { position: sticky; bottom: 12px; margin: 12px 0 0; width: calc(100% - 24px); }
  .disc-detail-image { width: 100%; aspect-ratio: 1 / 1; object-fit: cover; }
  .disc-detail-tabs { position: sticky; top: 0; z-index: 40; }
  .disc-detail-actions {
    position: sticky; bottom: 0;
    background: rgba(var(--bg-rgb, 12, 21, 12), 0.96);
    padding: 10px 12px;
    border-top: 1px solid var(--border, #2a3a2a);
  }
}

/* ============================================================
 * 43-52 . COURSE + MAP VIEW MOBILE
 * ============================================================ */
@media (max-width: 480px) {
  .course-row { padding: 12px 14px; min-height: 60px; }
  #courseMap { height: 50dvh; }
  .leaflet-control-zoom a { width: 40px !important; height: 40px !important; font-size: 20px !important; }
  .leaflet-popup-content { font-size: calc(13px + var(--text-delta)); }
  .course-detail-tabs { overflow-x: auto; scroll-snap-type: x mandatory; flex-wrap: nowrap; }
  .course-detail-tabs::-webkit-scrollbar { display: none; }
  .round-trend-card svg { max-width: 100%; height: 100px; }
  .course-detail-cta-add { position: sticky; bottom: 12px; }
  .course-search-results { width: 100%; }
  .nearby-chip-row { overflow-x: auto; flex-wrap: nowrap; }
  .nearby-chip-row::-webkit-scrollbar { display: none; }
}

/* ============================================================
 * 53-62 . PROFILE + SETTINGS MOBILE
 * ============================================================ */
@media (max-width: 480px) {
  .settings-row { padding: 14px 14px; min-height: 56px; }
  .profile-avatar-wrap { display: flex; justify-content: center; padding: 20px 0; }
  .profile-stats { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; }
  .settings-section > details > summary { padding: 14px 12px; min-height: 48px; }
  .theme-picker { display: flex; gap: 8px; flex-wrap: wrap; }
  .theme-picker > * { flex: 1 1 30%; }
  .danger-zone {
    border: 1.5px solid rgba(239, 83, 80, 0.35);
    background: rgba(239, 83, 80, 0.04);
    border-radius: var(--r-md, 12px);
    padding: 14px;
    margin-top: 20px;
  }
  .profile-photo-upload { width: 100%; }
}

/* ============================================================
 * 63-67 . SNACKBAR + TOAST
 * ============================================================ */
@media (max-width: 480px) {
  .toast-host {
    bottom: max(12px, env(safe-area-inset-bottom));
    left: 12px; right: 12px; transform: none;
    align-items: stretch; max-width: none;
  }
  .toast-host .toast {
    border-radius: 12px;
    animation: v8-toast-slide-up 0.32s cubic-bezier(0.34, 1.56, 0.64, 1);
  }
}
@keyframes v8-toast-slide-up { from { transform: translateY(20px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
.snackbar {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 16px;
  background: rgba(20, 24, 20, 0.96);
  color: #fff;
  border-radius: 12px;
  border-left: 4px solid var(--green2, #5fc05f);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5);
}
.snackbar-body { flex: 1; line-height: 1.4; font-size: calc(13px + var(--text-delta)); }
.snackbar-action {
  background: transparent; border: none;
  color: var(--green2, #5fc05f);
  font-weight: 700;
  font-size: calc(12px + var(--text-delta));
  cursor: pointer;
  padding: 6px 10px;
  border-radius: 6px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.snackbar-action:hover { background: rgba(95, 192, 95, 0.12); }

/* ============================================================
 * 68-80 . MISC MOBILE POLISH
 * ============================================================ */

/* Back-to-top FAB (JS-paired; toggles .visible when scrolled past threshold). */
.back-to-top-fab {
  position: fixed; right: 14px; bottom: max(60px, calc(env(safe-area-inset-bottom) + 60px));
  width: 44px; height: 44px; border-radius: 50%;
  background: rgba(20, 30, 20, 0.92);
  color: var(--green2, #5fc05f);
  border: 1.5px solid var(--green2, #5fc05f);
  font-size: 20px; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  opacity: 0; pointer-events: none;
  transform: translateY(20px);
  transition: opacity 0.22s ease, transform 0.22s cubic-bezier(0.34, 1.56, 0.64, 1);
  z-index: 90;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.4);
}
.back-to-top-fab.visible { opacity: 1; pointer-events: auto; transform: translateY(0); }

/* Share-round FAB after recap. */
.share-round-btn {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--green2, #5fc05f); color: #0c150c;
  padding: 8px 14px; border-radius: var(--r-pill, 999px);
  font-weight: 700; border: none; cursor: pointer;
}
.share-round-btn::before { content: "↗"; font-size: 14px; }

/* Pull-to-refresh visual hook (JS sets data-ptr-state on <html>). */
.ptr-indicator {
  position: fixed; left: 50%; top: 0;
  transform: translate(-50%, calc(-100% + var(--ptr-offset, 0px)));
  background: var(--green2, #5fc05f); color: #0c150c;
  padding: 8px 16px; border-radius: 0 0 12px 12px;
  font-weight: 600; font-size: calc(12px + var(--text-delta));
  z-index: 9000; pointer-events: none;
  transition: transform 0.22s ease;
}
html[data-ptr-state="refreshing"] .ptr-indicator { transform: translate(-50%, 0); }

/* Long-press menu base. */
.long-press-menu {
  position: absolute;
  background: var(--bg-card, var(--bg2, #1a2a1a));
  border: 1px solid var(--border, #2a3a2a);
  border-radius: var(--r-md, 12px);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.5);
  padding: 6px 0;
  z-index: 9500;
  min-width: 160px;
}
.long-press-menu button {
  display: block; width: 100%; text-align: left;
  background: transparent; border: none;
  color: var(--text);
  padding: 10px 16px;
  font-size: calc(13px + var(--text-delta));
  cursor: pointer;
  min-height: 44px;
}
.long-press-menu button:hover { background: rgba(95, 192, 95, 0.08); }
.long-press-menu button.danger { color: var(--red, #ef5350); }

/* Slide-to-confirm pattern. Pair with JS for drag handling. */
.slide-confirm {
  position: relative;
  width: 100%; max-width: 320px;
  height: 56px;
  background: var(--bg3, #243a24);
  border-radius: 28px;
  border: 1px solid var(--border, #2a3a2a);
  overflow: hidden;
  user-select: none;
  margin: 0 auto;
}
.slide-confirm-track {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  color: var(--muted);
  font-weight: 600;
  font-size: calc(14px + var(--text-delta));
  pointer-events: none;
}
.slide-confirm-thumb {
  position: absolute; top: 4px; left: 4px;
  width: 48px; height: 48px;
  background: var(--green2, #5fc05f);
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  color: #0c150c;
  font-size: 24px;
  cursor: grab;
  transition: left 0.22s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.slide-confirm-thumb:active { cursor: grabbing; }
.slide-confirm.confirmed .slide-confirm-thumb { left: calc(100% - 52px); background: var(--green3, #4caf50); }
.slide-confirm.confirmed .slide-confirm-track { color: var(--green2, #5fc05f); }

/* Mobile loading spinner (replaces the older block spinner). */
.spinner-circle {
  display: inline-block;
  width: 24px; height: 24px;
  border: 2.5px solid rgba(255, 255, 255, 0.12);
  border-top-color: var(--green2, #5fc05f);
  border-radius: 50%;
  animation: v8-spin 0.9s linear infinite;
}
@keyframes v8-spin { to { transform: rotate(360deg); } }

/* Mobile-friendly empty states (illustration replaces solid icon). */
@media (max-width: 480px) {
  .empty-state, .bag-section-empty { padding: 32px 16px; }
  .empty-state::before, .bag-section-empty::before {
    width: 72px; height: 72px;
    opacity: 0.45;
  }
}

/* Search clear button. */
.input-with-clear { position: relative; }
.input-with-clear input { padding-right: 36px; }
.input-with-clear .clear-btn {
  position: absolute; right: 6px; top: 50%;
  transform: translateY(-50%);
  width: 28px; height: 28px; border-radius: 50%;
  border: none; background: rgba(255, 255, 255, 0.08);
  color: var(--muted);
  cursor: pointer; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center;
  opacity: 0; transition: opacity 0.15s ease;
}
.input-with-clear input:not(:placeholder-shown) ~ .clear-btn { opacity: 1; }
.input-with-clear .clear-btn:hover { background: rgba(239, 83, 80, 0.18); color: var(--red, #ef5350); }

/* Native select / date input override for mobile. */
@media (max-width: 480px) {
  input[type="date"], input[type="time"], input[type="datetime-local"], select {
    min-height: 44px; font-size: 16px;
    padding: 10px 12px;
  }
}

/* Keyboard accessory bar for input rows. */
.keyboard-accessory {
  position: sticky; bottom: 0;
  background: rgba(var(--bg-rgb, 12, 21, 12), 0.96);
  border-top: 1px solid var(--border, #2a3a2a);
  display: flex; gap: 6px;
  padding: 8px 12px;
  z-index: 100;
}

/* Mobile error state with retry. */
.error-state {
  display: flex; flex-direction: column; align-items: center;
  gap: 14px; padding: 32px 16px;
  text-align: center;
}
.error-state .err-icon {
  font-size: 40px; color: var(--red, #ef5350);
  background: rgba(239, 83, 80, 0.12);
  width: 64px; height: 64px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%;
}
.error-state .err-msg { color: var(--muted); max-width: 320px; line-height: 1.4; }
.error-state .err-retry { min-width: 140px; }

/* ===== styles-v9.css ===== */
/* styles-v9.css . YesAndChains 0.44.2 . Polish wave V (80 items).
 *
 * Where v7 + v8 set the mobile foundation, v9 spends its budget on
 * micro-interactions, view-specific empty states, component cohesion,
 * and the small visual moments that signal "this app is cared for."
 *
 * Catalogued top-to-bottom:
 *
 * Empty-state designs per view (1-12):
 *   1. Empty bag illustration (CSS-art disc stack).
 *   2. Empty round-history illustration (basket icon).
 *   3. Empty courses illustration (compass rose larger).
 *   4. Empty observed-players setup label.
 *   5. Empty wind reading state.
 *   6. Empty stats state on profile.
 *   7. Empty caddy-rec state (recommender hidden message).
 *   8. Empty starred-courses prompt.
 *   9. Empty PDGA-lookup state.
 *  10. Empty disc-photo state.
 *  11. Empty notes textarea hint.
 *  12. Empty search state with example query.
 *
 * Loading + skeleton variants (13-22):
 *  13. Skeleton-disc-card.
 *  14. Skeleton-round-card.
 *  15. Skeleton-stat-block.
 *  16. Skeleton-course-row.
 *  17. Skeleton-recap header.
 *  18. Spinner-in-button (replaces label while loading).
 *  19. Spinner inline for inline status.
 *  20. Page-level loading bar at top.
 *  21. Pre-cache progress indicator.
 *  22. Optimistic-update placeholder pulse.
 *
 * Micro-interactions (23-37):
 *  23. Disc-card icon spin on hover.
 *  24. Round-card date stamp underline-grow.
 *  25. Course-card distance chip pop.
 *  26. Penalty-pill press dent.
 *  27. Toast bottom-bounce on appear.
 *  28. Toggle-switch haptic-feel ease.
 *  29. Settings-row check-mark draw-on.
 *  30. Modal scrim breathing.
 *  31. Trend-chart point ring grow on hover.
 *  32. Wind compass needle wiggle.
 *  33. Live-pin-distance value tick animation.
 *  34. Caddy-rec card slide-in from right.
 *  35. Bag color picker swatch hover scale.
 *  36. Player-row check-mark on basket landing.
 *  37. Score-counter +/- ripple from center.
 *
 * Form + validation (38-50):
 *  38. Invalid input red ring + shake.
 *  39. Valid input green check inline.
 *  40. Required-field asterisk styling.
 *  41. Helper-text muted below input.
 *  42. Character-count below textarea.
 *  43. Password-strength meter (future).
 *  44. Email format check ring.
 *  45. Numeric range slider styling.
 *  46. Radio group brand-themed.
 *  47. Checkbox brand-themed.
 *  48. Form group grid layout.
 *  49. Inline error icon + tooltip.
 *  50. Submit-disabled state explainer.
 *
 * Recap + share-card visuals (51-58):
 *  51. Recap title display.
 *  52. Recap stat tile group.
 *  53. Recap best-hole highlight chip.
 *  54. Recap shareable card layout.
 *  55. Recap photo-frame for round.
 *  56. Recap timestamp under title.
 *  57. Recap "x of y holes" progress bar.
 *  58. Recap finish-celebrate confetti hook.
 *
 * Mobile native patterns (59-70):
 *  59. iOS-style segmented control.
 *  60. iOS-style large-title header.
 *  61. iOS-style swipe-action reveal.
 *  62. Android FAB extended variant.
 *  63. Material-style ripple (touch-only).
 *  64. Bottom-nav with icon + label.
 *  65. Tab-bar item active indicator.
 *  66. Card stack on round picker.
 *  67. Snackbar undo action.
 *  68. Quick-action grid 2x2.
 *  69. Page indicator dots for carousels.
 *  70. Coachmark overlay base.
 *
 * Accessibility + tiny things (71-80):
 *  71. Focus visible inside details.
 *  72. Skip-to-content link.
 *  73. Screen-reader-only utility.
 *  74. Loading text for sr-only.
 *  75. Reduced-motion fallback for confetti.
 *  76. Higher contrast on amber text in light mode.
 *  77. Touch-target hit zone visualizer (dev).
 *  78. Animation pause on tab blur.
 *  79. Larger close-X for confirm-modal.
 *  80. Trailing-line cleanup across components.
 */

/* ============================================================
 * 1-12 . EMPTY STATES PER VIEW
 * ============================================================ */
.empty-bag-illust {
  display: block;
  width: 96px; height: 96px; margin: 0 auto 16px;
  position: relative;
  background:
    radial-gradient(circle at 50% 70%, var(--green2, #5fc05f), var(--green3, #4caf50) 60%, transparent 65%),
    radial-gradient(circle at 50% 35%, rgba(255, 193, 7, 0.45), transparent 50%);
  border-radius: 50%;
  opacity: 0.6;
}
.empty-bag-illust::before, .empty-bag-illust::after {
  content: ""; position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: 80%; height: 8px; background: rgba(255, 255, 255, 0.16); border-radius: 4px;
}
.empty-bag-illust::after { width: 60%; transform: translate(-50%, -50%) translateY(12px); background: rgba(255, 255, 255, 0.1); }

.empty-rh-illust { width: 80px; height: 80px; margin: 0 auto 16px; opacity: 0.55; background: radial-gradient(circle at 50% 50%, var(--green2, #5fc05f) 0%, transparent 35%); border: 2.5px solid var(--green2, #5fc05f); border-radius: 50%; box-shadow: inset 0 0 0 6px rgba(95, 192, 95, 0.18); }
.empty-courses-illust { width: 84px; height: 84px; margin: 0 auto 16px; background: conic-gradient(from -45deg, var(--green2, #5fc05f) 0deg 8deg, transparent 8deg 90deg, var(--green2, #5fc05f) 90deg 98deg, transparent 98deg 180deg, var(--green2, #5fc05f) 180deg 188deg, transparent 188deg 270deg, var(--green2, #5fc05f) 270deg 278deg, transparent 278deg 360deg); border-radius: 50%; opacity: 0.55; }

.empty-state-text {
  font-size: calc(14px + var(--text-delta));
  color: var(--muted); line-height: 1.4;
  max-width: 320px; margin: 0 auto;
  text-align: center;
}
.empty-state-cta { margin-top: 14px; min-width: 160px; }

/* Empty notes hint */
textarea:placeholder-shown { background-image: linear-gradient(180deg, transparent 0%, rgba(95, 192, 95, 0.02) 100%); }

/* ============================================================
 * 13-22 . LOADING + SKELETON VARIANTS
 * ============================================================ */
.skeleton-disc-card { display: flex; gap: 10px; padding: 10px 12px; background: var(--bg-card, var(--bg2, #1a2a1a)); border-radius: var(--r-md, 12px); border: 1px solid var(--border, #2a3a2a); }
.skeleton-disc-card .skeleton-circle { flex-shrink: 0; }
.skeleton-disc-card .lines { flex: 1; }
.skeleton-disc-card .skeleton-line:first-child { width: 70%; }
.skeleton-disc-card .skeleton-line:last-child { width: 40%; }

.skeleton-round-card { padding: 10px 12px; }
.skeleton-stat-block { height: 88px; border-radius: var(--r-md, 12px); }
.skeleton-course-row { padding: 12px; }

/* Spinner inside button. */
.btn .btn-spinner { display: none; width: 16px; height: 16px; border: 2px solid currentColor; border-top-color: transparent; border-radius: 50%; animation: v9-btn-spin 0.8s linear infinite; margin-right: 6px; vertical-align: middle; }
.btn[data-loading="true"] .btn-spinner { display: inline-block; }
.btn[data-loading="true"] .btn-label { opacity: 0.6; }
@keyframes v9-btn-spin { to { transform: rotate(360deg); } }

/* Inline status spinner */
.spinner-inline { display: inline-flex; align-items: center; gap: 6px; color: var(--muted); font-size: calc(12px + var(--text-delta)); }
.spinner-inline::before { content: ""; display: inline-block; width: 14px; height: 14px; border: 2px solid rgba(95, 192, 95, 0.3); border-top-color: var(--green2, #5fc05f); border-radius: 50%; animation: v9-btn-spin 0.8s linear infinite; }

/* Page-level loading bar (JS sets data-loading on html). */
.page-loading-bar { position: fixed; top: 0; left: 0; height: 3px; background: linear-gradient(90deg, transparent, var(--green2, #5fc05f), transparent); background-size: 200% 100%; width: 100%; z-index: 9999; pointer-events: none; opacity: 0; transition: opacity 0.18s ease; }
html[data-loading="true"] .page-loading-bar { opacity: 1; animation: v9-page-bar 1.2s linear infinite; }
@keyframes v9-page-bar { 0% { background-position: -100% 0; } 100% { background-position: 100% 0; } }

/* Optimistic pulse on rows that haven't synced yet. */
.optimistic { animation: v9-opt-pulse 1.4s ease-in-out infinite; }
@keyframes v9-opt-pulse { 0%, 100% { background-color: transparent; } 50% { background-color: rgba(95, 192, 95, 0.08); } }

/* ============================================================
 * 23-37 . MICRO-INTERACTIONS
 * ============================================================ */
.disc-card:hover .disc-card-icon { transform: rotate(6deg) scale(1.06); transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); }
.rh-card:hover .rh-card-date { box-shadow: inset 0 -2px 0 var(--green2, #5fc05f); transition: box-shadow 0.18s ease; }
.course-row:hover .throw-chip { transform: scale(1.08); transition: transform 0.18s cubic-bezier(0.34, 1.56, 0.64, 1); }
.penalty-pill:active { transform: scale(0.88); box-shadow: inset 0 0 0 2px rgba(255, 193, 7, 0.5); }

@keyframes v9-toast-bounce { 0% { transform: translateY(40px) scale(0.92); opacity: 0; } 60% { transform: translateY(-4px) scale(1.02); opacity: 1; } 100% { transform: translateY(0) scale(1); opacity: 1; } }
.toast { animation: v9-toast-bounce 0.42s cubic-bezier(0.34, 1.56, 0.64, 1); }

.toggle .thumb { transition: transform 0.28s cubic-bezier(0.34, 1.7, 0.64, 1); }

@keyframes v9-check-draw { from { stroke-dashoffset: 24; } to { stroke-dashoffset: 0; } }
.settings-row.checked .check-icon path { stroke-dasharray: 24; animation: v9-check-draw 0.32s ease-out forwards; }

.modal-scrim { animation: v9-scrim-breathe 4s ease-in-out infinite; }
@keyframes v9-scrim-breathe { 0%, 100% { backdrop-filter: blur(4px); } 50% { backdrop-filter: blur(6px); } }

.round-trend-card svg circle:hover { r: 5; transition: r 0.18s cubic-bezier(0.34, 1.7, 0.64, 1); }

@keyframes v9-needle-wiggle { 0%, 100% { transform: rotate(var(--wind-deg, 0deg)); } 50% { transform: rotate(calc(var(--wind-deg, 0deg) + 3deg)); } }
.wind-compass .wc-arrow { animation: v9-needle-wiggle 4s ease-in-out infinite; }

@keyframes v9-distance-tick { 0% { color: var(--green2, #5fc05f); transform: scale(1.06); } 100% { color: var(--text); transform: scale(1); } }
.live-pin-distance .live-pin-distance-value.changed { animation: v9-distance-tick 0.45s ease-out; }

.caddy-rec-host { animation: v9-rec-slide-in 0.34s cubic-bezier(0.22, 1.08, 0.36, 1); }
@keyframes v9-rec-slide-in { from { transform: translateX(12px); opacity: 0; } to { transform: translateX(0); opacity: 1; } }

.color-swatch { transition: transform 0.18s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.18s ease; }
.color-swatch:hover { transform: scale(1.18); box-shadow: 0 0 0 2px var(--green2, #5fc05f); }

.player-row.landing-basket::after { content: "\2713"; position: absolute; right: 12px; top: 50%; transform: translateY(-50%); color: var(--green2, #5fc05f); font-size: 18px; font-weight: 700; }

@keyframes v9-counter-ripple { 0% { box-shadow: 0 0 0 0 rgba(95, 192, 95, 0.5); } 100% { box-shadow: 0 0 0 12px rgba(95, 192, 95, 0); } }
.counter-btn:active { animation: v9-counter-ripple 0.45s ease-out; }

/* ============================================================
 * 38-50 . FORM + VALIDATION
 * ============================================================ */
input.invalid, textarea.invalid, select.invalid {
  border-color: var(--red, #ef5350) !important;
  box-shadow: 0 0 0 3px rgba(239, 83, 80, 0.18);
  animation: v9-shake 0.3s ease-in-out;
}
@keyframes v9-shake { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-3px); } 75% { transform: translateX(3px); } }

.input-valid-check {
  position: absolute; right: 10px; top: 50%; transform: translateY(-50%);
  color: var(--green2, #5fc05f); font-size: 16px; font-weight: 700;
  opacity: 0; transition: opacity 0.18s ease;
}
input.valid + .input-valid-check { opacity: 1; }

.required-asterisk { color: var(--red, #ef5350); font-weight: 700; margin-left: 2px; }
.helper-text { font-size: calc(11px + var(--text-delta)); color: var(--muted); margin-top: 4px; line-height: 1.4; }
.char-count { font-size: calc(10px + var(--text-delta)); color: var(--muted); text-align: right; margin-top: 2px; font-variant-numeric: tabular-nums; }
.char-count.over-limit { color: var(--red, #ef5350); font-weight: 600; }

/* Range slider brand styling */
input[type="range"] { -webkit-appearance: none; appearance: none; width: 100%; height: 6px; background: rgba(255, 255, 255, 0.1); border-radius: 3px; outline: none; }
input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 22px; height: 22px; background: var(--green2, #5fc05f); border-radius: 50%; cursor: pointer; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); border: 2px solid #0c150c; }
input[type="range"]::-moz-range-thumb { width: 22px; height: 22px; background: var(--green2, #5fc05f); border-radius: 50%; cursor: pointer; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); border: 2px solid #0c150c; }

/* Radio + checkbox brand-themed */
input[type="checkbox"], input[type="radio"] { accent-color: var(--green2, #5fc05f); width: 18px; height: 18px; cursor: pointer; }

.form-group { display: grid; gap: 12px; padding: 10px 0; }
.form-row { display: flex; gap: 10px; flex-wrap: wrap; }

.inline-error-icon { display: inline-block; width: 18px; height: 18px; background: var(--red, #ef5350); color: #fff; border-radius: 50%; text-align: center; line-height: 18px; font-size: 12px; font-weight: 700; vertical-align: middle; margin-right: 4px; }

.btn:disabled[data-explainer]:hover::after {
  content: attr(data-explainer);
  position: absolute; bottom: calc(100% + 6px); left: 50%; transform: translateX(-50%);
  background: rgba(20, 24, 20, 0.96); color: #fff;
  padding: 6px 10px; border-radius: 6px; white-space: nowrap; font-size: 12px;
  pointer-events: none; z-index: 100;
}

/* ============================================================
 * 51-58 . RECAP + SHARE-CARD VISUALS
 * ============================================================ */
.recap-title { font-family: "Barlow Condensed", sans-serif; font-size: calc(36px + var(--text-delta)); font-weight: 700; letter-spacing: 0.02em; text-align: center; margin: 12px 0 4px; }
.recap-stat-tile-group { display: grid; grid-template-columns: repeat(auto-fit, minmax(110px, 1fr)); gap: 8px; padding: 12px 0; }
.recap-best-hole-chip { display: inline-flex; align-items: center; gap: 6px; background: linear-gradient(135deg, var(--amber, #ffc107), #ffd54f); color: #1a1a00; padding: 4px 12px; border-radius: 999px; font-weight: 700; font-size: calc(11px + var(--text-delta)); }
.recap-best-hole-chip::before { content: "\2605"; }

.share-card {
  background: linear-gradient(135deg, var(--bg2, #1a2a1a), var(--bg3, #243a24));
  border: 1px solid var(--green2, #5fc05f);
  border-radius: 18px;
  padding: 24px;
  max-width: 420px;
  margin: 0 auto;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.05);
  position: relative; overflow: hidden;
}
.share-card::before {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(circle at 80% 20%, rgba(95, 192, 95, 0.18), transparent 60%);
  pointer-events: none;
}

.recap-photo-frame { width: 100%; aspect-ratio: 16 / 9; background: var(--bg2, #1a2a1a); border-radius: 12px; border: 1px solid var(--border, #2a3a2a); overflow: hidden; }
.recap-timestamp { font-size: calc(12px + var(--text-delta)); color: var(--muted); text-align: center; }
.recap-progress { width: 100%; height: 4px; background: rgba(255, 255, 255, 0.08); border-radius: 2px; overflow: hidden; }
.recap-progress > div { height: 100%; background: linear-gradient(90deg, var(--green2, #5fc05f), var(--amber, #ffc107)); transition: width 0.8s ease-out; }

/* ============================================================
 * 59-70 . MOBILE NATIVE PATTERNS
 * ============================================================ */
/* iOS-style segmented control */
.segmented-control {
  display: inline-flex; background: rgba(255, 255, 255, 0.08); border-radius: 9px; padding: 2px; gap: 0;
}
.segmented-control > button {
  flex: 1; padding: 7px 16px; min-width: 64px;
  background: transparent; border: none; color: var(--text);
  border-radius: 7px; font-size: calc(13px + var(--text-delta));
  cursor: pointer; transition: background 0.18s ease, color 0.18s ease;
}
.segmented-control > button.on { background: var(--bg-card, var(--bg2, #1a2a1a)); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25); font-weight: 600; }

/* iOS-style large title */
.large-title { font-size: calc(28px + var(--text-delta)); font-weight: 700; letter-spacing: -0.01em; padding: 8px 16px 4px; }

/* Swipe-action reveal slots (JS-driven). */
.swipe-row { position: relative; overflow: hidden; touch-action: pan-y; }
.swipe-row .swipe-content { transition: transform 0.22s ease; }
.swipe-row.swiped-left .swipe-content { transform: translateX(-80px); }
.swipe-row .swipe-actions { position: absolute; right: 0; top: 0; bottom: 0; width: 80px; display: flex; align-items: center; justify-content: center; background: var(--red, #ef5350); color: #fff; font-weight: 700; }

/* Android FAB extended */
.fab-extended {
  position: fixed; right: 16px; bottom: max(20px, env(safe-area-inset-bottom, 20px));
  background: linear-gradient(180deg, var(--green2, #5fc05f), var(--green3, #4caf50));
  color: #0c150c; padding: 14px 20px; border-radius: 28px;
  border: none; box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4); font-weight: 700;
  display: inline-flex; align-items: center; gap: 8px; font-size: calc(14px + var(--text-delta));
  z-index: 90; cursor: pointer;
}

/* Material-style ripple. Touch-only. */
@media (hover: none) and (pointer: coarse) {
  .material-ripple { position: relative; overflow: hidden; }
  .material-ripple::after {
    content: ""; position: absolute; left: 50%; top: 50%;
    width: 0; height: 0; background: rgba(255, 255, 255, 0.18); border-radius: 50%;
    transform: translate(-50%, -50%); pointer-events: none; opacity: 0;
  }
  .material-ripple:active::after { width: 280%; height: 280%; opacity: 1; transition: width 0.5s ease-out, height 0.5s ease-out, opacity 0.6s ease-out; }
}

/* Bottom nav */
.bottom-nav {
  position: fixed; left: 0; right: 0; bottom: 0;
  background: rgba(var(--bg-rgb, 12, 21, 12), 0.96);
  border-top: 1px solid var(--border, #2a3a2a);
  display: flex; justify-content: space-around;
  padding: 6px 6px max(6px, env(safe-area-inset-bottom));
  z-index: 80;
  backdrop-filter: blur(8px);
}
.bottom-nav-item { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 6px; background: transparent; border: none; color: var(--muted); cursor: pointer; min-height: 48px; }
.bottom-nav-item .label { font-size: 10px; letter-spacing: 0.02em; }
.bottom-nav-item .icon { font-size: 20px; line-height: 1; }
.bottom-nav-item.active { color: var(--green2, #5fc05f); }
.bottom-nav-item.active::before { content: ""; position: absolute; top: 0; width: 24px; height: 2px; background: var(--green2, #5fc05f); border-radius: 1px; }

/* Card stack on round picker */
.card-stack { position: relative; min-height: 200px; }
.card-stack > * { position: absolute; left: 0; right: 0; transition: transform 0.32s ease, opacity 0.22s ease; }
.card-stack > *:nth-child(1) { z-index: 3; transform: translateY(0) scale(1); }
.card-stack > *:nth-child(2) { z-index: 2; transform: translateY(8px) scale(0.96); opacity: 0.7; }
.card-stack > *:nth-child(3) { z-index: 1; transform: translateY(16px) scale(0.92); opacity: 0.4; }

/* Snackbar undo */
.snackbar-undo { background: transparent; border: none; color: var(--amber, #ffc107); font-weight: 700; cursor: pointer; padding: 6px 10px; font-size: calc(12px + var(--text-delta)); text-transform: uppercase; letter-spacing: 0.04em; }

/* Quick-action grid */
.quick-action-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; padding: 8px; }
.quick-action-grid .quick-action { padding: 16px; text-align: center; border-radius: 12px; background: var(--bg-card, var(--bg2, #1a2a1a)); border: 1px solid var(--border, #2a3a2a); cursor: pointer; transition: transform 0.18s ease, box-shadow 0.18s ease; }
.quick-action-grid .quick-action:hover { transform: translateY(-1px); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); border-color: var(--green2, #5fc05f); }

/* Page-indicator dots */
.page-indicator { display: flex; gap: 6px; justify-content: center; padding: 8px 0; }
.page-indicator .dot { width: 6px; height: 6px; border-radius: 50%; background: rgba(255, 255, 255, 0.2); transition: all 0.22s ease; }
.page-indicator .dot.active { background: var(--green2, #5fc05f); transform: scale(1.4); }

/* Coachmark overlay */
.coachmark-overlay { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.6); z-index: 9700; }
.coachmark-bubble { position: absolute; background: var(--bg-card, var(--bg2, #1a2a1a)); border: 1px solid var(--green2, #5fc05f); border-radius: 12px; padding: 14px 16px; max-width: 280px; box-shadow: 0 12px 32px rgba(0, 0, 0, 0.5); }
.coachmark-bubble::before { content: ""; position: absolute; top: -8px; left: 20px; width: 0; height: 0; border-left: 8px solid transparent; border-right: 8px solid transparent; border-bottom: 8px solid var(--green2, #5fc05f); }

/* ============================================================
 * 71-80 . ACCESSIBILITY + TINY THINGS
 * ============================================================ */
details:focus-within > summary { outline: 2px solid var(--green2, #5fc05f); outline-offset: 1px; border-radius: 6px; }

.skip-to-content {
  position: absolute; left: -9999px; top: 8px;
  background: var(--green2, #5fc05f); color: #0c150c;
  padding: 8px 14px; border-radius: 8px; font-weight: 700;
  z-index: 10000;
}
.skip-to-content:focus { left: 8px; }

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

[aria-busy="true"]::after {
  content: " (loading)"; opacity: 0; clip: rect(0, 0, 0, 0); position: absolute;
}

@media (prefers-reduced-motion: reduce) {
  .score-flash, .confetti, .toast, .modal { animation-duration: 0.01ms !important; }
  #confettiCanvas { display: none !important; }
}

html[data-theme="light"] .amber, html[data-theme="light"] [data-tier="ace"] { color: #b87900 !important; }

/* Animation pause when tab not active. */
html.tab-inactive *, html.tab-inactive *::before, html.tab-inactive *::after {
  animation-play-state: paused !important;
}

/* Confirm modal larger close-X. */
.confirm-modal .modal-close { width: 48px; height: 48px; font-size: 24px; }

/* Trailing-line cleanup: remove extra empty paragraphs */
p:empty { display: none; }

/* ============================================================
 * data-idle integration (mobile-hooks-3 sets this after 90s no input).
 * Dim non-critical UI so the player can focus on what they're doing.
 * The core round/score UI stays full opacity; chrome fades.
 * ============================================================ */
html[data-idle="true"] .app-header,
html[data-idle="true"] .actions-bar,
html[data-idle="true"] .fab,
html[data-idle="true"] .back-to-top-fab,
html[data-idle="true"] .net-status-banner {
  opacity: 0.4;
  transition: opacity 0.6s ease;
}
html[data-idle="true"] .app-header:hover,
html[data-idle="true"] .actions-bar:hover { opacity: 1; }

/* ============================================================
 * 0.44.10 . Brief green flash on a just-saved inline edit.
 * setDiscField adds .just-saved to the [data-field="..."] element;
 * CSS animates it for ~800ms then it auto-clears via JS removeListener.
 * ============================================================ */
@keyframes v9-just-saved-flash {
  0% { background-color: rgba(95, 192, 95, 0.32); transform: scale(1.02); }
  100% { background-color: transparent; transform: scale(1); }
}
.just-saved {
  animation: v9-just-saved-flash 0.7s ease-out;
  border-radius: 4px;
}

/* ===== styles-v10.css ===== */
/* styles-v10.css . YesAndChains 0.46.0 . Chat panel (BACKLOG §5.3-5.6).
 *
 * Hidden surface. The whole layer is staged here so when CHAT_PANEL_VISIBLE
 * flips in src/chat-panel.ts, the chat UI renders with no further CSS work.
 * Layer is loaded last in index.html so its variables override prior layers
 * where the chat panel sits next to the Caddy recommender card.
 *
 * Catalogued top-to-bottom:
 *   1. .chat-panel-host . placeholder div in round view
 *   2. .chat-panel . root container
 *   3. .chat-panel-header . title + Clear button
 *   4. .chat-history . scrolling message list
 *   5. .chat-empty . placeholder when thread is empty
 *   6. .chat-msg variants (user / assistant / system / thinking)
 *   7. .chat-input-row + .chat-input + .chat-send-btn
 *   8. .chat-error . inline error band
 *   9. mobile-first sizing + reduced-motion variants
 *  10. dark-mode tuned colors (the default)
 *
 * NOTE: anything user-typed must respect the typography schema
 *       (calc(Npx + var(--text-delta))) to pass the preship gate.
 */

/* ============================================================
 * 1 . Host placeholder
 * ============================================================ */
.chat-panel-host {
  display: block;
  margin: 12px 0 8px;
}

/* ============================================================
 * 2 . Root container
 * ============================================================ */
.chat-panel {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px 12px 8px;
  background: var(--bg-card, var(--bg2, #18241a));
  border: 1px solid var(--border, #2a3a2a);
  border-radius: var(--r-md, 12px);
  max-height: 320px;
  overflow: hidden;
}

/* ============================================================
 * 3 . Header
 * ============================================================ */
.chat-panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding-bottom: 4px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}
.chat-panel-title {
  font-size: calc(13px + var(--text-delta));
  font-weight: 600;
  color: var(--text, #d8e5d8);
  letter-spacing: 0.02em;
}
.chat-panel-header-actions {
  display: flex;
  align-items: center;
  gap: 6px;
}
.chat-clear-btn, .chat-export-btn {
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 6px;
  color: var(--muted, #8a9a8a);
  font-size: calc(11px + var(--text-delta));
  padding: 3px 8px;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.chat-clear-btn:hover, .chat-clear-btn:focus-visible,
.chat-export-btn:hover, .chat-export-btn:focus-visible {
  background: rgba(255, 255, 255, 0.04);
  border-color: rgba(255, 255, 255, 0.16);
}
.chat-export-btn {
  font-size: calc(13px + var(--text-delta));
  padding: 1px 8px;
}

/* ============================================================
 * 4 . History (scrolling)
 * ============================================================ */
.chat-history {
  flex: 1 1 auto;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 4px 0 2px;
  scrollbar-width: thin;
  scroll-behavior: smooth;
  min-height: 80px;
}
.chat-history:focus {
  outline: 2px solid rgba(95, 192, 95, 0.4);
  outline-offset: -2px;
  border-radius: 4px;
}

/* ============================================================
 * 5 . Empty state
 * ============================================================ */
.chat-empty {
  text-align: center;
  padding: 16px 8px 8px;
  color: var(--muted, #8a9a8a);
}
.chat-empty-title {
  font-size: calc(13px + var(--text-delta));
  font-weight: 600;
  margin-bottom: 4px;
  color: var(--text, #d8e5d8);
}
.chat-empty-hint {
  font-size: calc(11px + var(--text-delta));
  line-height: 1.5;
  opacity: 0.8;
}

/* ============================================================
 * 6 . Message variants
 * ============================================================ */
.chat-msg {
  display: flex;
  max-width: 90%;
  padding: 6px 10px;
  border-radius: 10px;
  font-size: calc(13px + var(--text-delta));
  line-height: 1.42;
  word-wrap: break-word;
}
.chat-msg-body {
  flex: 1;
}
.chat-msg-user {
  align-self: flex-end;
  background: var(--green2, #5fc05f);
  color: #0a120a;
  border-bottom-right-radius: 4px;
}
.chat-msg-assistant {
  align-self: flex-start;
  background: rgba(255, 255, 255, 0.06);
  color: var(--text, #d8e5d8);
  border-bottom-left-radius: 4px;
}
.chat-msg-system {
  align-self: center;
  background: transparent;
  color: var(--muted, #8a9a8a);
  font-size: calc(11px + var(--text-delta));
  font-style: italic;
}
.chat-msg em {
  font-style: italic;
  opacity: 0.85;
}

/* Thinking-dots (assistant placeholder while awaiting reply). */
.chat-thinking .chat-msg-body {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 0;
}
.chat-dot {
  display: inline-block;
  width: 6px; height: 6px;
  background: currentColor;
  border-radius: 50%;
  opacity: 0.35;
  animation: v10-chat-dot 1.2s infinite ease-in-out;
}
.chat-dot:nth-child(2) { animation-delay: 0.16s; }
.chat-dot:nth-child(3) { animation-delay: 0.32s; }
@keyframes v10-chat-dot {
  0%, 80%, 100% { opacity: 0.25; transform: translateY(0); }
  40% { opacity: 0.9; transform: translateY(-2px); }
}

/* ============================================================
 * 7 . Input row
 * ============================================================ */
.chat-input-row {
  display: flex;
  align-items: flex-end;
  gap: 6px;
  margin-top: 4px;
}
.chat-input {
  flex: 1 1 auto;
  background: var(--bg2, #18241a);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 8px;
  color: var(--text, #d8e5d8);
  padding: 8px 10px;
  font-family: inherit;
  font-size: calc(13px + var(--text-delta));
  line-height: 1.42;
  resize: none;
  min-height: 36px;
  max-height: 120px;
  overflow-y: auto;
  transition: border-color 0.15s ease;
}
.chat-input:focus {
  outline: none;
  border-color: var(--green2, #5fc05f);
}
.chat-input::placeholder {
  color: var(--muted, #8a9a8a);
  opacity: 0.7;
}
.chat-input:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}
.chat-send-btn {
  flex: 0 0 auto;
  background: var(--green2, #5fc05f);
  color: #0a120a;
  border: 0;
  border-radius: 8px;
  width: 36px; height: 36px;
  font-size: calc(16px + var(--text-delta));
  font-weight: 700;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: transform 0.12s ease, opacity 0.15s ease;
}
.chat-send-btn:active { transform: scale(0.94); }
.chat-send-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

/* ============================================================
 * 8 . Error band + retry + copy + timestamp (0.47.0 polish)
 * ============================================================ */
.chat-error {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  background: rgba(220, 80, 60, 0.18);
  border: 1px solid rgba(220, 80, 60, 0.4);
  color: #f3a99a;
  border-radius: 6px;
  padding: 6px 10px;
  font-size: calc(12px + var(--text-delta));
  margin-top: 2px;
}
.chat-error-text { flex: 1; min-width: 0; }
.chat-retry-btn {
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 6px;
  color: var(--text, #d8e5d8);
  font-size: calc(11px + var(--text-delta));
  padding: 3px 10px;
  cursor: pointer;
  flex: 0 0 auto;
  transition: background 0.15s ease;
}
.chat-retry-btn:hover, .chat-retry-btn:focus-visible {
  background: rgba(255, 255, 255, 0.14);
}

/* Per-message footer: timestamp + copy button. */
.chat-msg-meta {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 6px;
  margin-top: 2px;
  font-size: calc(10px + var(--text-delta));
  opacity: 0.55;
  transition: opacity 0.15s ease;
}
.chat-msg:hover .chat-msg-meta, .chat-msg:focus-within .chat-msg-meta {
  opacity: 0.85;
}
.chat-msg-ts {
  letter-spacing: 0.02em;
}
.chat-copy-btn {
  background: transparent;
  border: 0;
  color: inherit;
  cursor: pointer;
  padding: 0 4px;
  font-size: calc(12px + var(--text-delta));
  line-height: 1;
  opacity: 0.7;
  transition: opacity 0.15s ease;
}
.chat-copy-btn:hover, .chat-copy-btn:focus-visible {
  opacity: 1;
}
/* User-side meta sits on the left (mirrored to the speech bubble's tail side). */
.chat-msg-user .chat-msg-meta { justify-content: flex-start; }
/* Hide copy button on user messages (handled in TS by not rendering it). */

/* ============================================================
 * 9 . Mobile + accessibility
 * ============================================================ */
@media (max-width: 480px) {
  .chat-panel { max-height: 260px; padding: 8px 10px 6px; }
  .chat-msg { font-size: calc(12px + var(--text-delta)); padding: 5px 9px; }
}

@media (prefers-reduced-motion: reduce) {
  .chat-dot { animation: none; opacity: 0.6; }
  .chat-history { scroll-behavior: auto; }
  .chat-send-btn { transition: none; }
}

/* ===== styles-v11.css ===== */
/* styles-v11.css . YesAndChains 0.48.0 . 100-item polish wave (60 here).
 *
 * Cataloged top-to-bottom. Numbers are the wave item index across all layers
 * so cross-file references stay coherent; see CONTEXT 0.48.0 for the full
 * index. Items 41-100 live in mobile-hooks-4.ts and keyboard-shortcuts.ts.
 *
 *  1. View-transition crossfade
 *  2. Card hover lift (desktop only, pointer:fine)
 *  3. Button press scale-down on active
 *  4. Score-counter morph transition
 *  5. Badge bounce on data update
 *  6. Pin-distance digit roll-in
 *  7. Toast slide-in with overshoot
 *  8. Modal scrim fade
 *  9. List item stagger reveal
 * 10. Skeleton shimmer animation
 * 11. Recap big-number count-up
 * 12. Course-card distance chip pop
 * 13. Wizard step crossfade
 * 14. Pulse on save indicator
 * 15. Star fill bloom on favorite
 * 16. Smooth scrollbar styling
 * 17. Better tap-highlight color (transparent black instead of webkit blue)
 * 18. Improved focus-visible ring (green2 with 2px offset)
 * 19. Reduced-motion full-stack respect
 * 20. Touch-action: manipulation on buttons (kills 300ms tap delay)
 * 21. iOS 16px input zoom prevention reinforcement
 * 22. Sticky tab bar safe-area bottom inset
 * 23. Better -webkit-overflow-scrolling on scrolling regions
 * 24. Selection color brand-tinted
 * 25. Disabled state contrast bump
 * 26. Wider tap zones via :before pseudo-element on small icon buttons
 * 27. Score-button haptic-feel via scale + ease curve
 * 28. Smooth-momentum scroll
 * 29. Better divider line styling
 * 30. Subtle gradient on primary buttons
 * 31. Improved card shadow rest state
 * 32. Better chip group flex-wrap
 * 33. Improved badge rounded-corners
 * 34. Hover-tint on settings rows
 * 35. Better radio + checkbox brand alignment
 * 36. Inline error icon style
 * 37. Success-toast green tint
 * 38. Warning-toast amber tint
 * 39. Info-toast neutral tint
 * 40. Improved snackbar layout
 * 41. Better drag-handle visibility (used by long-press grip)
 * 42. Improved scrollbar dark-mode contrast
 * 43. Better form field grouping (gap rhythm)
 * 44. Polished focus ring color (uses --green2 token)
 * 45. Better empty-state spacing
 * 46. Improved snap-scroll on horizontal lists
 * 47. Wider hit-zone on back-arrow buttons
 * 48. Better print stylesheet
 * 49. Reduced animation on tab-blur (paired with .tab-inactive from v9)
 * 50. Improved accent-color palette
 * 51. Better text rendering hint
 * 52. Polished spinner appearance
 * 53. Better z-index layering for modal stacking
 * 54. Improved checkbox checked state
 * 55. Better disabled buttons (no hover, no pointer)
 * 56. Polished long-press menu transition
 * 57. Improved touch feedback color
 * 58. Better pull-to-refresh indicator color
 * 59. Polished settings-row tap state
 * 60. Polished tab bar item active indicator
 */

/* ============================================================
 * 1 . View-transition crossfade
 * ============================================================ */
#main {
  animation: v11-view-fade 0.18s ease-out;
}
@keyframes v11-view-fade {
  from { opacity: 0.55; }
  to { opacity: 1; }
}

/* ============================================================
 * 2 . Card hover lift (desktop only)
 * ============================================================ */
@media (hover: hover) and (pointer: fine) {
  .home-card, .disc-card, .course-row, .round-card {
    transition: transform 0.18s ease, box-shadow 0.18s ease;
  }
  .home-card:hover, .disc-card:hover, .course-row:hover, .round-card:hover {
    transform: translateY(-1px);
    box-shadow: 0 6px 18px -8px rgba(0, 0, 0, 0.45);
  }
}

/* ============================================================
 * 3 . Button press scale-down on :active
 * ============================================================ */
.btn:not(:disabled):active,
button:not(:disabled):not(.no-press):active {
  transform: scale(0.97);
  transition: transform 0.06s ease-out;
}

/* ============================================================
 * 4 . Score-counter morph
 * ============================================================ */
.counter-score {
  transition: color 0.2s ease, transform 0.15s ease;
}
.counter-score.bumped {
  animation: v11-score-bump 0.25s ease-out;
}
@keyframes v11-score-bump {
  0% { transform: scale(1); }
  50% { transform: scale(1.18); }
  100% { transform: scale(1); }
}

/* ============================================================
 * 5 . Badge bounce
 * ============================================================ */
.badge.bumped, .chip.bumped, .pill.bumped {
  animation: v11-bounce 0.45s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@keyframes v11-bounce {
  0% { transform: scale(1); }
  40% { transform: scale(1.18); }
  70% { transform: scale(0.96); }
  100% { transform: scale(1); }
}

/* ============================================================
 * 6 . Pin-distance digit roll-in
 * ============================================================ */
.live-pin-distance-value.changed {
  animation: v11-digit-roll 0.42s ease-out;
}
@keyframes v11-digit-roll {
  0% { opacity: 0.4; transform: translateY(-4px); }
  100% { opacity: 1; transform: translateY(0); }
}

/* ============================================================
 * 7 . Toast slide-in with overshoot
 * ============================================================ */
.toast, .snackbar {
  animation: v11-toast-in 0.36s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@keyframes v11-toast-in {
  0% { transform: translateY(80%); opacity: 0; }
  60% { transform: translateY(-6%); opacity: 1; }
  100% { transform: translateY(0); opacity: 1; }
}

/* ============================================================
 * 8 . Modal scrim fade
 * ============================================================ */
.modal-scrim, .scrim {
  animation: v11-scrim-fade 0.2s ease-out;
}
@keyframes v11-scrim-fade {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* ============================================================
 * 9 . List item stagger reveal
 * ============================================================ */
.stagger-list > * {
  animation: v11-list-stagger 0.32s ease-out backwards;
}
.stagger-list > *:nth-child(1) { animation-delay: 0.04s; }
.stagger-list > *:nth-child(2) { animation-delay: 0.08s; }
.stagger-list > *:nth-child(3) { animation-delay: 0.12s; }
.stagger-list > *:nth-child(4) { animation-delay: 0.16s; }
.stagger-list > *:nth-child(5) { animation-delay: 0.20s; }
.stagger-list > *:nth-child(n+6) { animation-delay: 0.24s; }
@keyframes v11-list-stagger {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: translateY(0); }
}

/* ============================================================
 * 10 . Skeleton shimmer
 * ============================================================ */
.skeleton, .skeleton-line, .skeleton-circle {
  position: relative;
  overflow: hidden;
  background: rgba(255, 255, 255, 0.06);
  border-radius: 4px;
}
.skeleton::after, .skeleton-line::after, .skeleton-circle::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.08), transparent);
  animation: v11-skeleton 1.4s linear infinite;
}
@keyframes v11-skeleton {
  from { transform: translateX(-100%); }
  to { transform: translateX(100%); }
}

/* ============================================================
 * 11 . Recap big-number count-up
 * ============================================================ */
.recap-total[data-count-up] {
  animation: v11-count-up 0.6s ease-out;
}
@keyframes v11-count-up {
  0% { opacity: 0; transform: translateY(8px); }
  100% { opacity: 1; transform: translateY(0); }
}

/* ============================================================
 * 12 . Course-card distance chip pop
 * ============================================================ */
.course-row .distance-chip {
  transition: transform 0.18s ease;
}
.course-row:hover .distance-chip {
  transform: scale(1.06);
}

/* ============================================================
 * 13 . Wizard step crossfade
 * ============================================================ */
.wiz-step {
  animation: v11-wiz-fade 0.22s ease-out;
}
@keyframes v11-wiz-fade {
  from { opacity: 0; transform: translateX(8px); }
  to { opacity: 1; transform: translateX(0); }
}

/* ============================================================
 * 14 . Pulse on save indicator
 * ============================================================ */
.saving-indicator, .save-pulse {
  animation: v11-save-pulse 1.4s ease-in-out infinite;
}
@keyframes v11-save-pulse {
  0%, 100% { opacity: 0.55; }
  50% { opacity: 1; }
}

/* ============================================================
 * 15 . Star fill bloom on favorite
 * ============================================================ */
.fav-star.just-filled {
  animation: v11-star-bloom 0.48s ease-out;
}
@keyframes v11-star-bloom {
  0% { transform: scale(1); }
  40% { transform: scale(1.4) rotate(8deg); }
  70% { transform: scale(0.92) rotate(-3deg); }
  100% { transform: scale(1) rotate(0); }
}

/* ============================================================
 * 16 . Scrollbar styling
 * ============================================================ */
* {
  scrollbar-width: thin;
  scrollbar-color: rgba(95, 192, 95, 0.32) transparent;
}
*::-webkit-scrollbar { width: 8px; height: 8px; }
*::-webkit-scrollbar-thumb {
  background: rgba(95, 192, 95, 0.28);
  border-radius: 4px;
}
*::-webkit-scrollbar-thumb:hover { background: rgba(95, 192, 95, 0.5); }
*::-webkit-scrollbar-track { background: transparent; }

/* ============================================================
 * 17 . Tap-highlight color
 * ============================================================ */
a, button, [role="button"], .btn, .home-card, .disc-card, .course-row, .round-card {
  -webkit-tap-highlight-color: rgba(95, 192, 95, 0.18);
}

/* ============================================================
 * 18 . Focus-visible ring
 * ============================================================ */
:focus-visible {
  outline: 2px solid var(--green2, #5fc05f);
  outline-offset: 2px;
  border-radius: 4px;
}
button:focus-visible, .btn:focus-visible {
  outline-offset: 3px;
}

/* ============================================================
 * 19 . Reduced-motion catch-all
 * ============================================================ */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ============================================================
 * 20 . Touch-action: manipulation
 * ============================================================ */
button, .btn, .home-card, .disc-card, [role="button"],
.counter-btn, .tab-bar-item, .chip {
  touch-action: manipulation;
}

/* ============================================================
 * 21 . iOS input zoom prevention reinforcement
 * ============================================================ */
@media screen and (max-width: 480px) {
  input[type="text"], input[type="email"], input[type="search"],
  input[type="tel"], input[type="number"], input[type="password"],
  textarea, select {
    font-size: max(calc(16px + var(--text-delta)), 16px);
  }
}

/* ============================================================
 * 22 . Sticky tab bar safe-area
 * ============================================================ */
.tab-bar, .footer-actions, .action-bar {
  padding-bottom: max(8px, env(safe-area-inset-bottom));
}

/* ============================================================
 * 23 . Overflow scrolling
 * ============================================================ */
.scroll-region, .chat-history, .scrollable, #main {
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}

/* ============================================================
 * 24 . Selection color
 * ============================================================ */
::selection {
  background: rgba(95, 192, 95, 0.32);
  color: var(--text, #d8e5d8);
}
::-moz-selection {
  background: rgba(95, 192, 95, 0.32);
  color: var(--text, #d8e5d8);
}

/* ============================================================
 * 25 . Disabled contrast bump
 * ============================================================ */
:disabled, [aria-disabled="true"], .disabled {
  opacity: 0.48;
  cursor: not-allowed;
}
.btn:disabled, button:disabled {
  filter: saturate(0.6);
}

/* ============================================================
 * 26 . Wider tap zones on small icon buttons
 * ============================================================ */
.icon-btn, .close-btn, .chat-copy-btn, .chat-export-btn, .chat-clear-btn {
  position: relative;
}
.icon-btn::before, .close-btn::before {
  content: "";
  position: absolute;
  inset: -8px;
}

/* ============================================================
 * 27 . Score button haptic-feel
 * ============================================================ */
.counter-btn {
  transition: transform 0.08s cubic-bezier(0.5, 0, 0.2, 1.4), background 0.15s ease;
}
.counter-btn:active {
  transform: scale(0.88);
}

/* ============================================================
 * 28 . Smooth-momentum scroll
 * ============================================================ */
html, body {
  scroll-behavior: smooth;
}

/* ============================================================
 * 29 . Divider line styling
 * ============================================================ */
hr, .divider {
  border: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.08), transparent);
  margin: 14px 0;
}

/* ============================================================
 * 30 . Primary button gradient accent
 * ============================================================ */
.btn-primary {
  background: linear-gradient(180deg, var(--green2, #5fc05f) 0%, var(--green3, #4caf50) 100%);
  position: relative;
  overflow: hidden;
}
.btn-primary::after {
  content: "";
  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 50%;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.1), transparent);
  pointer-events: none;
}

/* ============================================================
 * 31 . Card shadow rest state
 * ============================================================ */
.home-card, .disc-card, .round-card, .course-row {
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.18);
}

/* ============================================================
 * 32 . Chip group flex-wrap
 * ============================================================ */
.chip-group, .filter-chips, .mfr-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}

/* ============================================================
 * 33 . Badge rounded corners
 * ============================================================ */
.badge, .pill, .chip {
  border-radius: 999px;
}

/* ============================================================
 * 34 . Settings-row hover tint
 * ============================================================ */
.settings-row {
  transition: background 0.15s ease;
}
.settings-row:hover, .settings-row:focus-within {
  background: rgba(255, 255, 255, 0.025);
}

/* ============================================================
 * 35 . Radio + checkbox brand alignment
 * ============================================================ */
input[type="radio"], input[type="checkbox"] {
  accent-color: var(--green2, #5fc05f);
}

/* ============================================================
 * 36 . Inline error icon style
 * ============================================================ */
.inline-error {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: #f3a99a;
  font-size: calc(11px + var(--text-delta));
}
.inline-error::before {
  content: "⚠";
  font-size: calc(12px + var(--text-delta));
}

/* ============================================================
 * 37 . Success toast tint
 * ============================================================ */
.toast-success, .toast.success {
  border-left: 3px solid var(--green2, #5fc05f);
  background: rgba(95, 192, 95, 0.18);
}

/* ============================================================
 * 38 . Warning toast tint
 * ============================================================ */
.toast-warning, .toast.warning {
  border-left: 3px solid #d4a000;
  background: rgba(212, 160, 0, 0.18);
}

/* ============================================================
 * 39 . Info toast tint
 * ============================================================ */
.toast-info, .toast.info {
  border-left: 3px solid #6ab0e3;
  background: rgba(106, 176, 227, 0.18);
}

/* ============================================================
 * 40 . Snackbar layout
 * ============================================================ */
.snackbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 14px;
  max-width: 480px;
  margin: 0 auto;
}
.snackbar-action {
  flex: 0 0 auto;
  color: var(--green2, #5fc05f);
  background: transparent;
  border: 0;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-size: calc(11px + var(--text-delta));
  cursor: pointer;
  padding: 4px 8px;
}

/* ============================================================
 * 41 . Drag-handle visibility
 * ============================================================ */
.drag-handle, [data-drag-handle] {
  cursor: grab;
  opacity: 0.5;
  transition: opacity 0.15s ease;
}
.drag-handle:hover, [data-drag-handle]:hover { opacity: 0.85; }
.drag-handle:active, [data-drag-handle]:active { cursor: grabbing; opacity: 1; }

/* ============================================================
 * 42 . Dark-mode scrollbar contrast (already in 16 but explicit fallback)
 * ============================================================ */
@media (prefers-color-scheme: dark) {
  *::-webkit-scrollbar-thumb { background: rgba(95, 192, 95, 0.35); }
}

/* ============================================================
 * 43 . Form field grouping rhythm
 * ============================================================ */
.field, .form-field, .field-group {
  margin-bottom: 14px;
}
.field label, .field .field-label, .form-field label {
  display: block;
  margin-bottom: 4px;
  font-size: calc(11px + var(--text-delta));
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--gray2, #8a9a8a);
}

/* ============================================================
 * 44 . Focus ring color reinforcement (already in 18)
 * ============================================================ */

/* ============================================================
 * 45 . Empty-state spacing
 * ============================================================ */
.empty-state, .bag-section-empty, .empty-courses, .empty-rh {
  padding: 24px 16px;
  text-align: center;
  color: var(--muted, #8a9a8a);
}

/* ============================================================
 * 46 . Snap-scroll on horizontal lists
 * ============================================================ */
.h-scroll, .horizontal-list, .quick-actions-row {
  display: flex;
  gap: 10px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  padding-bottom: 6px;
}
.h-scroll > *, .horizontal-list > *, .quick-actions-row > * {
  scroll-snap-align: start;
  flex-shrink: 0;
}

/* ============================================================
 * 47 . Wider hit-zone on back arrows
 * ============================================================ */
.wiz-back, .back-arrow {
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* ============================================================
 * 48 . Print stylesheet
 * ============================================================ */
@media print {
  .tab-bar, .footer-actions, .action-bar, .toast, .snackbar,
  .scrim, .modal-scrim, .chat-panel, .caddy-rec-host, .page-loading-bar {
    display: none !important;
  }
  body, #main {
    background: white !important;
    color: black !important;
  }
}

/* ============================================================
 * 49 . Reduced animation on tab-blur (paired with .tab-inactive)
 * ============================================================ */
.tab-inactive *, html.tab-inactive * {
  animation-play-state: paused !important;
}

/* ============================================================
 * 50 . Accent palette tokens
 * ============================================================ */
:root {
  --accent-info: #6ab0e3;
  --accent-warn: #d4a000;
  --accent-error: #e57862;
  --accent-success: #5fc05f;
}

/* ============================================================
 * 51 . Text rendering hint
 * ============================================================ */
body {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

/* ============================================================
 * 52 . Spinner appearance
 * ============================================================ */
.spinner, .btn-spinner {
  border-color: rgba(255, 255, 255, 0.25);
  border-top-color: var(--green2, #5fc05f);
}

/* ============================================================
 * 53 . Z-index layering
 * ============================================================ */
:root {
  --z-base: 1;
  --z-sticky: 100;
  --z-modal-scrim: 9000;
  --z-modal: 9001;
  --z-toast: 9500;
  --z-loading-bar: 9700;
  --z-debug: 9999;
}
.toast, .snackbar { z-index: var(--z-toast); }
.modal-scrim, .scrim { z-index: var(--z-modal-scrim); }
.modal, [role="dialog"] { z-index: var(--z-modal); }
.page-loading-bar { z-index: var(--z-loading-bar); }

/* ============================================================
 * 54 . Checkbox checked state
 * ============================================================ */
input[type="checkbox"]:checked + label,
.check-row.checked .check-label {
  color: var(--green2, #5fc05f);
}

/* ============================================================
 * 55 . Disabled buttons
 * ============================================================ */
button:disabled, .btn:disabled, [aria-disabled="true"] {
  pointer-events: none;
}

/* ============================================================
 * 56 . Long-press menu transition
 * ============================================================ */
.long-press-menu, [role="menu"].opened {
  animation: v11-menu-pop 0.22s cubic-bezier(0.34, 1.56, 0.64, 1);
  transform-origin: top center;
}
@keyframes v11-menu-pop {
  0% { opacity: 0; transform: scale(0.92) translateY(-4px); }
  100% { opacity: 1; transform: scale(1) translateY(0); }
}

/* ============================================================
 * 57 . Touch feedback color
 * ============================================================ */
.touch-feedback:active {
  background: rgba(95, 192, 95, 0.08);
}

/* ============================================================
 * 58 . Pull-to-refresh indicator color
 * ============================================================ */
.ptr-indicator, .pull-to-refresh-arrow {
  color: var(--green2, #5fc05f);
}

/* ============================================================
 * 59 . Settings row tap state
 * ============================================================ */
.settings-row:active {
  background: rgba(255, 255, 255, 0.04);
}

/* ============================================================
 * 60 . Tab bar active indicator
 * ============================================================ */
.tab-bar-item {
  position: relative;
  padding-top: 6px;
  transition: color 0.18s ease;
}
.tab-bar-item.active {
  color: var(--green2, #5fc05f);
}
.tab-bar-item.active::after {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 28px;
  height: 3px;
  background: var(--green2, #5fc05f);
  border-radius: 0 0 3px 3px;
}

/* ===== styles-v12.css ===== */
/* styles-v12.css . YesAndChains 0.49.0 . 50-item mobile-browser sweep (30 here).
 *
 * Mobile-specific. Targets coarse-pointer + small-viewport behavior. Items
 * 31-50 live in mobile-hooks-5.ts. Numbers below are wave indexes shared
 * across both files.
 *
 *  1. dvh fallback ladder for round view fullscreen
 *  2. iOS notch + home-indicator safe-area padding
 *  3. iOS standalone status bar overlap fix
 *  4. Android theme-color sync (CSS root variable)
 *  5. Pinch-zoom disable on score area
 *  6. -webkit-touch-callout: none on UI (allow on body text)
 *  7. -webkit-user-select: none on game UI elements
 *  8. Mobile-specific system font stack
 *  9. Mobile-specific font-display: swap hint via :root
 * 10. URL-bar collapse compensation (100svh)
 * 11. Larger tap targets on mobile (44px minimum)
 * 12. Mobile-only disclosure triangles (touch-sized)
 * 13. Mobile-only empty-state imagery shrink
 * 14. Mobile-specific transition timing (snappier)
 * 15. Bottom-sheet base styling
 * 16. iOS-style action sheet base styling
 * 17. Android-style modal bottom sheet base
 * 18. Sticky header on scroll-up pattern
 * 19. Mobile network save-data CSS hide-heavy
 * 20. Battery-low CSS throttle (paired with mobile-hooks-4 #73)
 * 21. Mobile dark/light scheme dual support
 * 22. Mobile select native styling
 * 23. Mobile date/time input native styling
 * 24. Mobile slide-in drawer base
 * 25. Mobile-specific pull-to-refresh styling
 * 26. Mobile bottom-action-bar with safe-area
 * 27. Touch slop visual feedback
 * 28. Smaller modal padding on narrow viewports
 * 29. Mobile-friendly disclosure caret rotation
 * 30. Mobile address bar height variable hook
 */

/* ============================================================
 * 1 . dvh fallback ladder
 * ============================================================ */
:root {
  --vh-fallback: 100vh;
}
@supports (height: 100dvh) {
  :root { --vh-fallback: 100dvh; }
}
@supports (height: 100svh) {
  /* Use svh for the always-visible-during-scroll layouts. */
  .round-fullscreen, .map-fullscreen { min-height: 100svh; }
}
.round-fullscreen, .modal-fullscreen { min-height: var(--vh-fallback); }

/* ============================================================
 * 2 . Notch + home-indicator safe-area
 * ============================================================ */
body {
  padding-top: env(safe-area-inset-top);
  padding-bottom: env(safe-area-inset-bottom);
  padding-left: env(safe-area-inset-left);
  padding-right: env(safe-area-inset-right);
}
@media (max-width: 480px) {
  .app-header, .tab-bar, .action-bar {
    padding-left: max(env(safe-area-inset-left), 8px);
    padding-right: max(env(safe-area-inset-right), 8px);
  }
}

/* ============================================================
 * 3 . iOS standalone status bar overlap fix
 * ============================================================ */
.pwa-standalone .app-header {
  padding-top: calc(env(safe-area-inset-top) + 8px);
}

/* ============================================================
 * 4 . Android theme-color root variable hook
 * ============================================================ */
:root {
  --android-theme-color: #0a120a;
}
@media (prefers-color-scheme: light) {
  :root { --android-theme-color: #f5f7f5; }
}

/* ============================================================
 * 5 . Pinch-zoom disable on score area
 * ============================================================ */
.score-area, .counter-score, .player-row, .counter-wrap {
  touch-action: manipulation;
}

/* ============================================================
 * 6 . -webkit-touch-callout: none on UI
 * ============================================================ */
.btn, button, .counter-btn, .home-card, .disc-card, .course-row,
.tab-bar-item, .chip, .pill, [role="button"] {
  -webkit-touch-callout: none;
}

/* ============================================================
 * 7 . -webkit-user-select: none on game UI
 * ============================================================ */
.counter-score, .counter-btn, .tab-bar-item, .chip, .pill, .badge,
.home-card .home-card-label, .home-card .home-card-value {
  -webkit-user-select: none;
  user-select: none;
}

/* ============================================================
 * 8 . Mobile system font stack
 * ============================================================ */
@media (max-width: 768px) {
  body {
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
      "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji",
      "Segoe UI Symbol", sans-serif;
  }
}

/* ============================================================
 * 9 . Font-display swap hint (web-font safe even if no web font)
 * ============================================================ */
:root { font-display: swap; }

/* ============================================================
 * 10 . URL-bar collapse compensation (100svh based)
 * ============================================================ */
@supports (height: 100svh) {
  .round-fullscreen { min-height: 100svh; }
}

/* ============================================================
 * 11 . Larger tap targets on mobile
 * ============================================================ */
@media (pointer: coarse) {
  .btn, button, [role="button"], .tab-bar-item, .icon-btn {
    min-height: 44px;
    min-width: 44px;
  }
  a, .clickable {
    min-height: 36px;
    padding: 6px 0;
  }
}

/* ============================================================
 * 12 . Mobile disclosure triangles
 * ============================================================ */
@media (pointer: coarse) {
  details > summary {
    list-style: none;
    padding: 12px 8px;
    cursor: pointer;
  }
  details > summary::-webkit-details-marker { display: none; }
  details > summary::before {
    content: "▸";
    display: inline-block;
    margin-right: 8px;
    transition: transform 0.18s ease;
  }
  details[open] > summary::before {
    transform: rotate(90deg);
  }
}

/* ============================================================
 * 13 . Mobile empty-state imagery shrink
 * ============================================================ */
@media (max-width: 480px) {
  .empty-bag-illust, .empty-rh-illust, .empty-courses-illust {
    width: 64px;
    height: 64px;
  }
}

/* ============================================================
 * 14 . Snappier transition timing
 * ============================================================ */
@media (pointer: coarse) {
  .btn, button, .home-card, .disc-card, .course-row, .round-card {
    transition-duration: 0.12s !important;
  }
}

/* ============================================================
 * 15 . Bottom-sheet base styling
 * ============================================================ */
.bottom-sheet {
  position: fixed;
  left: 0; right: 0;
  bottom: 0;
  background: var(--bg-card, var(--bg2, #18241a));
  border-top-left-radius: 16px;
  border-top-right-radius: 16px;
  padding: 16px 16px calc(16px + env(safe-area-inset-bottom));
  z-index: 9100;
  transform: translateY(100%);
  transition: transform 0.28s cubic-bezier(0.34, 1.2, 0.64, 1);
  box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.4);
  max-height: 80vh;
  overflow-y: auto;
}
.bottom-sheet.open { transform: translateY(0); }
.bottom-sheet-handle {
  width: 36px; height: 4px;
  background: rgba(255, 255, 255, 0.18);
  border-radius: 2px;
  margin: -4px auto 14px;
}

/* ============================================================
 * 16 . iOS-style action sheet
 * ============================================================ */
.action-sheet {
  position: fixed;
  left: 12px; right: 12px;
  bottom: calc(12px + env(safe-area-inset-bottom));
  z-index: 9100;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.action-sheet-group {
  background: rgba(28, 38, 28, 0.92);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border-radius: 14px;
  overflow: hidden;
}
.action-sheet-item {
  padding: 16px;
  text-align: center;
  border: 0;
  background: transparent;
  color: var(--text, #d8e5d8);
  font-size: calc(15px + var(--text-delta));
  width: 100%;
  cursor: pointer;
}
.action-sheet-item + .action-sheet-item {
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}
.action-sheet-item.destructive { color: var(--accent-error, #e57862); }
.action-sheet-cancel {
  font-weight: 600;
}

/* ============================================================
 * 17 . Android-style modal bottom sheet
 * ============================================================ */
.bottom-sheet-md {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  background: var(--bg-card, var(--bg2, #18241a));
  border-top-left-radius: 28px;
  border-top-right-radius: 28px;
  padding: 14px 24px calc(14px + env(safe-area-inset-bottom));
  z-index: 9100;
  box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.32);
}

/* ============================================================
 * 18 . Sticky header on scroll-up pattern
 * ============================================================ */
.app-header.scroll-hidden {
  transform: translateY(-100%);
  transition: transform 0.22s ease;
}
.app-header.scroll-shown {
  transform: translateY(0);
  transition: transform 0.22s ease;
}

/* ============================================================
 * 19 . Save-data hide-heavy
 * ============================================================ */
html[data-net-quality="2g"] .heavy-illustration,
html[data-net-quality="slow-2g"] .heavy-illustration,
html.save-data .heavy-illustration {
  display: none;
}
html[data-net-quality="2g"] *, html.save-data * {
  animation-duration: 0s !important;
  transition-duration: 0s !important;
}

/* ============================================================
 * 20 . Battery-low CSS throttle
 * ============================================================ */
html.battery-low *, html.battery-low *::before, html.battery-low *::after {
  animation-duration: 0.001ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: 0.001ms !important;
}
html.battery-low .heavy-illustration { display: none; }

/* ============================================================
 * 21 . Mobile light scheme support (for the rare flipper)
 * ============================================================ */
@media (prefers-color-scheme: light) and (max-width: 768px) {
  :root {
    --bg2: #f5f7f5;
    --text: #1a2a1a;
    --muted: #4a5a4a;
    --border: #d8e2d8;
  }
}

/* ============================================================
 * 22 . Mobile select native styling
 * ============================================================ */
@media (pointer: coarse) {
  select {
    -webkit-appearance: none;
    appearance: none;
    background-image: linear-gradient(45deg, transparent 50%, var(--muted, #8a9a8a) 50%),
                      linear-gradient(135deg, var(--muted, #8a9a8a) 50%, transparent 50%);
    background-position: calc(100% - 16px) 50%, calc(100% - 11px) 50%;
    background-size: 5px 5px, 5px 5px;
    background-repeat: no-repeat;
    padding-right: 28px;
    min-height: 44px;
  }
}

/* ============================================================
 * 23 . Mobile date/time input native styling
 * ============================================================ */
@media (pointer: coarse) {
  input[type="date"], input[type="time"], input[type="datetime-local"] {
    -webkit-appearance: none;
    min-height: 44px;
    padding: 8px 12px;
    background: var(--bg2, #18241a);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 8px;
    color: var(--text, #d8e5d8);
    font-size: max(calc(15px + var(--text-delta)), 16px);
  }
}

/* ============================================================
 * 24 . Slide-in drawer base
 * ============================================================ */
.drawer {
  position: fixed;
  top: 0; bottom: 0;
  left: 0;
  width: min(320px, 80vw);
  background: var(--bg-card, var(--bg2, #18241a));
  z-index: 9100;
  transform: translateX(-100%);
  transition: transform 0.28s cubic-bezier(0.34, 1.2, 0.64, 1);
  padding: env(safe-area-inset-top) 16px env(safe-area-inset-bottom);
  box-shadow: 4px 0 16px rgba(0, 0, 0, 0.32);
  overflow-y: auto;
}
.drawer.open { transform: translateX(0); }
.drawer.right { left: auto; right: 0; transform: translateX(100%); }
.drawer.right.open { transform: translateX(0); }

/* ============================================================
 * 25 . Pull-to-refresh styling
 * ============================================================ */
.ptr-indicator {
  position: fixed;
  top: env(safe-area-inset-top);
  left: 50%;
  transform: translateX(-50%);
  background: var(--bg-card, var(--bg2, #18241a));
  border-radius: 50%;
  width: 36px; height: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
  transition: transform 0.18s ease, opacity 0.18s ease;
  opacity: 0;
  z-index: 9050;
}
.ptr-indicator.pulling { opacity: 1; }
.ptr-indicator.releasing { animation: v12-ptr-spin 0.8s linear infinite; }
@keyframes v12-ptr-spin {
  to { transform: translateX(-50%) rotate(360deg); }
}

/* ============================================================
 * 26 . Bottom-action-bar with safe-area
 * ============================================================ */
.bottom-action-bar {
  position: fixed;
  bottom: 0; left: 0; right: 0;
  padding: 8px max(8px, env(safe-area-inset-left)) calc(8px + env(safe-area-inset-bottom)) max(8px, env(safe-area-inset-right));
  background: linear-gradient(180deg, transparent, var(--bg-card, #18241a) 30%);
  display: flex;
  gap: 8px;
  z-index: 9000;
}

/* ============================================================
 * 27 . Touch slop visual feedback
 * ============================================================ */
.touch-active::after {
  content: "";
  position: absolute;
  inset: -8px;
  background: rgba(95, 192, 95, 0.12);
  border-radius: inherit;
  animation: v12-touch-ripple 0.45s ease-out;
  pointer-events: none;
}
@keyframes v12-touch-ripple {
  from { opacity: 1; transform: scale(0.95); }
  to { opacity: 0; transform: scale(1.15); }
}

/* ============================================================
 * 28 . Smaller modal padding on narrow viewports
 * ============================================================ */
@media (max-width: 480px) {
  .modal, [role="dialog"] {
    margin: 12px;
    padding: 14px;
    border-radius: 12px;
  }
  .modal-header, [role="dialog"] > header {
    margin-bottom: 8px;
  }
}

/* ============================================================
 * 29 . Disclosure caret rotation (paired with #12)
 * ============================================================ */
.caret {
  display: inline-block;
  transition: transform 0.18s ease;
}
[aria-expanded="true"] .caret,
details[open] .caret {
  transform: rotate(90deg);
}

/* ============================================================
 * 30 . Address bar height variable hook
 * ============================================================ */
:root {
  --address-bar-h: 0px;
}
@media (max-width: 768px) {
  :root {
    /* Difference between lvh and svh is the address bar reserve. */
    --address-bar-h: calc(100lvh - 100svh);
  }
}

/* ===== styles-v13.css ===== */
/* styles-v13.css . YesAndChains 0.50.0 . 100-item mobile sweep, part 1/3 (50 here).
 *
 * Items 1-50 are CSS-only. Items 51-80 in src/mobile-hooks-6.ts.
 * Items 81-100 are index.html head additions.
 *
 *  1. content-visibility on round-history list
 *  2. content-visibility on course-list rows
 *  3. content-visibility on disc-grid cards
 *  4. fade-edge mask on horizontal scrollers
 *  5. Better grid breakpoints (380, 560, 768, 1024)
 *  6. Landscape phone layout (max-h: 480, orientation: landscape)
 *  7. Tablet-only spacing scale (min-w: 768)
 *  8. Modal stacking context anchor
 *  9. Muted-text contrast bump
 * 10. :focus-within polish on cards
 * 11. Sticky app-header safe-area top
 * 12. Tab-bar scroll-snap
 * 13. Keyboard-aware bottom padding (--kb-inset consumer)
 * 14. Reduced-motion respect on all v13 animations
 * 15. backdrop-filter fallback for unsupported browsers
 * 16. Border-radius scale via custom props
 * 17. Box-shadow scale via custom props
 * 18. Color palette tokens (accent set 2)
 * 19. Spacing scale tokens
 * 20. Typographic scale tokens
 * 21. Improved line-height for body prose
 * 22. Improved paragraph rhythm
 * 23. Link styling on coarse pointer (underline-only, no hover effect)
 * 24. :focus-visible via :where() (low specificity)
 * 25. Skip-link visibility on focus
 * 26. Picture / img placeholder background
 * 27. Empty-state illustration tinting
 * 28. Disabled-button look polish
 * 29. Hover-converted-to-tap behavior on coarse
 * 30. Text-overflow on truncated labels
 * 31. Word-break on long disc names
 * 32. Better wrap in chip groups
 * 33. Home-page card grid auto-fill
 * 34. Map container aspect-ratio fallback
 * 35. Disc art placeholder aspect-ratio
 * 36. Border colors in dark mode
 * 37. Divider weight rhythm
 * 38. Separator pattern (subtle gradient)
 * 39. Focus-visible offset
 * 40. Selection color tint refinement
 * 41. Disabled checkbox style
 * 42. Radio button outline polish
 * 43. Switch toggle base styling
 * 44. Number-input spinner hide on mobile
 * 45. Range-input track + thumb
 * 46. Progress-bar style
 * 47. Meter element style
 * 48. Foldable phone layout (vertical-fold detection)
 * 49. Container query support hint
 * 50. Print mode mobile improvements
 */

/* ============================================================
 * 1-3 . content-visibility on long lists
 * ============================================================ */
.round-history-list > * {
  content-visibility: auto;
  contain-intrinsic-size: auto 96px;
}
.course-list > .course-row {
  content-visibility: auto;
  contain-intrinsic-size: auto 72px;
}
.disc-grid > .disc-card {
  content-visibility: auto;
  contain-intrinsic-size: auto 140px;
}

/* ============================================================
 * 4 . fade-edge mask on horizontal scrollers
 * ============================================================ */
.h-scroll, .horizontal-list, .chip-group.overflow {
  mask-image: linear-gradient(90deg, transparent 0, #000 24px, #000 calc(100% - 24px), transparent 100%);
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 24px, #000 calc(100% - 24px), transparent 100%);
}

/* ============================================================
 * 5 . Breakpoint scale
 * ============================================================ */
:root {
  --bp-xs: 380px;
  --bp-sm: 560px;
  --bp-md: 768px;
  --bp-lg: 1024px;
}

/* ============================================================
 * 6 . Landscape phone layout
 * ============================================================ */
@media (orientation: landscape) and (max-height: 480px) {
  .recap-big-number { font-size: calc(48px + var(--text-delta)) !important; }
  .wiz-header { padding-top: 2px; padding-bottom: 2px; }
  .home-grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); }
}

/* ============================================================
 * 7 . Tablet-only spacing
 * ============================================================ */
@media (min-width: 768px) {
  .main-wrap { padding: 24px 32px; max-width: 800px; margin: 0 auto; }
  .home-grid { grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); }
}

/* ============================================================
 * 8 . Modal stacking context anchor
 * ============================================================ */
[role="dialog"], .modal {
  isolation: isolate;
}

/* ============================================================
 * 9 . Muted-text contrast bump
 * ============================================================ */
:root {
  --muted-strong: #a3b5a3;
}
.muted-strong, .recap-ins-sub-strong { color: var(--muted-strong); }

/* ============================================================
 * 10 . focus-within polish
 * ============================================================ */
.home-card:focus-within, .disc-card:focus-within, .course-row:focus-within {
  outline: 2px solid var(--green2, #5fc05f);
  outline-offset: 2px;
}

/* ============================================================
 * 11 . Sticky app-header safe-area top
 * ============================================================ */
.app-header.sticky {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky, 100);
  background: var(--bg-card, var(--bg2, #18241a));
}

/* ============================================================
 * 12 . Tab bar scroll-snap
 * ============================================================ */
.tab-bar.scroll-x {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
}
.tab-bar.scroll-x > .tab-bar-item { scroll-snap-align: center; flex-shrink: 0; }

/* ============================================================
 * 13 . Keyboard-aware bottom padding consumer
 * ============================================================ */
.chat-input-row, .footer-actions, .bottom-action-bar {
  padding-bottom: calc(max(env(safe-area-inset-bottom), 8px) + var(--kb-inset, 0px));
  transition: padding-bottom 0.18s ease;
}

/* ============================================================
 * 14 . Reduced-motion respect catch-all for v13
 * ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .h-scroll, .horizontal-list, .chip-group.overflow {
    mask-image: none;
    -webkit-mask-image: none;
  }
}

/* ============================================================
 * 15 . backdrop-filter fallback
 * ============================================================ */
@supports not (backdrop-filter: blur(20px)) {
  .action-sheet-group, .menu-overlay {
    background: rgba(28, 38, 28, 0.98);
  }
}

/* ============================================================
 * 16 . Border-radius scale
 * ============================================================ */
:root {
  --r-xs: 4px;
  --r-sm: 6px;
  --r-md: 10px;
  --r-lg: 14px;
  --r-xl: 20px;
  --r-full: 999px;
}

/* ============================================================
 * 17 . Box-shadow scale
 * ============================================================ */
:root {
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.18);
  --shadow-md: 0 2px 6px rgba(0, 0, 0, 0.24);
  --shadow-lg: 0 6px 18px -6px rgba(0, 0, 0, 0.4);
  --shadow-xl: 0 12px 36px -12px rgba(0, 0, 0, 0.5);
}

/* ============================================================
 * 18 . Accent palette tokens v2
 * ============================================================ */
:root {
  --accent-1: #5fc05f;
  --accent-2: #4caf50;
  --accent-3: #3a8a3a;
  --neutral-fg: #d8e5d8;
  --neutral-bg: #0a120a;
}

/* ============================================================
 * 19 . Spacing scale
 * ============================================================ */
:root {
  --sp-1: 2px;
  --sp-2: 4px;
  --sp-3: 6px;
  --sp-4: 8px;
  --sp-5: 10px;
  --sp-6: 12px;
  --sp-7: 14px;
  --sp-8: 16px;
  --sp-10: 20px;
  --sp-12: 24px;
  --sp-16: 32px;
}

/* ============================================================
 * 20 . Typographic scale
 * ============================================================ */
:root {
  --fs-xs: calc(10px + var(--text-delta));
  --fs-sm: calc(12px + var(--text-delta));
  --fs-base: calc(14px + var(--text-delta));
  --fs-md: calc(16px + var(--text-delta));
  --fs-lg: calc(20px + var(--text-delta));
  --fs-xl: calc(28px + var(--text-delta));
  --fs-xxl: calc(40px + var(--text-delta));
}

/* ============================================================
 * 21 . Line height for body prose
 * ============================================================ */
p, .prose, .chat-msg-body {
  line-height: 1.5;
}

/* ============================================================
 * 22 . Paragraph rhythm
 * ============================================================ */
.prose p + p { margin-top: 12px; }

/* ============================================================
 * 23 . Link styling on coarse pointer
 * ============================================================ */
@media (pointer: coarse) {
  a {
    text-decoration-thickness: 1px;
    text-underline-offset: 2px;
  }
  a:hover { background: transparent; }
}

/* ============================================================
 * 24 . :focus-visible via :where()
 * ============================================================ */
:where(button, .btn, a, input, textarea, select):focus-visible {
  outline: 2px solid var(--green2, #5fc05f);
  outline-offset: 2px;
}

/* ============================================================
 * 25 . Skip link visibility on focus
 * ============================================================ */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 8px;
  background: var(--green2, #5fc05f);
  color: #0a120a;
  padding: 8px 14px;
  border-radius: 6px;
  z-index: 9999;
  font-weight: 600;
  text-decoration: none;
}
.skip-link:focus { left: 8px; }

/* ============================================================
 * 26 . img placeholder background
 * ============================================================ */
img {
  background: rgba(255, 255, 255, 0.03);
}

/* ============================================================
 * 27 . Empty-state illustration tinting
 * ============================================================ */
@media (prefers-color-scheme: dark) {
  .empty-bag-illust, .empty-rh-illust, .empty-courses-illust {
    filter: brightness(0.92);
  }
}

/* ============================================================
 * 28 . Disabled button polish
 * ============================================================ */
.btn:disabled, button:disabled, [aria-disabled="true"] {
  background: rgba(255, 255, 255, 0.05);
  color: var(--muted, #8a9a8a);
  border-color: rgba(255, 255, 255, 0.04);
}

/* ============================================================
 * 29 . Hover-to-tap conversion
 * ============================================================ */
@media (hover: none) {
  *:hover {
    transition: none;
  }
}

/* ============================================================
 * 30 . Text-overflow on truncated labels
 * ============================================================ */
.truncate, .label-truncate, .course-row .name, .disc-card .name {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.truncate-2 {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* ============================================================
 * 31 . Word-break on long disc names
 * ============================================================ */
.disc-card .name, .disc-detail .name {
  overflow-wrap: anywhere;
  word-break: break-word;
}

/* ============================================================
 * 32 . Chip group wrap polish
 * ============================================================ */
.chip-group {
  flex-wrap: wrap;
  align-items: center;
  row-gap: 6px;
}

/* ============================================================
 * 33 . Home page card grid auto-fill
 * ============================================================ */
.home-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 10px;
}

/* ============================================================
 * 34 . Map container aspect-ratio
 * ============================================================ */
.hole-map, .course-map {
  aspect-ratio: 16/10;
  width: 100%;
}
@supports not (aspect-ratio: 1) {
  .hole-map, .course-map { height: 220px; }
}

/* ============================================================
 * 35 . Disc-art placeholder aspect-ratio
 * ============================================================ */
.disc-art-placeholder {
  aspect-ratio: 1/1;
  background: radial-gradient(circle, rgba(95,192,95,0.18), transparent 60%);
  border-radius: 50%;
}

/* ============================================================
 * 36 . Dark mode border colors
 * ============================================================ */
@media (prefers-color-scheme: dark) {
  :root {
    --border: #2a3a2a;
    --border-strong: #3a4a3a;
  }
}

/* ============================================================
 * 37 . Divider weight rhythm
 * ============================================================ */
.divider-thin { height: 1px; }
.divider-thick { height: 2px; }

/* ============================================================
 * 38 . Separator pattern
 * ============================================================ */
.separator {
  position: relative;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,0.08) 20%, rgba(255,255,255,0.08) 80%, transparent);
  margin: 16px 0;
}

/* ============================================================
 * 39 . Focus-visible offset
 * ============================================================ */
button:focus-visible, .btn:focus-visible {
  outline-offset: 3px;
}
input:focus-visible, textarea:focus-visible, select:focus-visible {
  outline-offset: 0;
}

/* ============================================================
 * 40 . Selection color refinement
 * ============================================================ */
::selection {
  background: rgba(95, 192, 95, 0.4);
  color: var(--neutral-bg, #0a120a);
}

/* ============================================================
 * 41 . Disabled checkbox style
 * ============================================================ */
input[type="checkbox"]:disabled, input[type="radio"]:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* ============================================================
 * 42 . Radio button outline polish
 * ============================================================ */
input[type="radio"]:focus-visible {
  outline: 2px solid var(--green2, #5fc05f);
  outline-offset: 2px;
  border-radius: 50%;
}

/* ============================================================
 * 43 . Switch toggle base styling
 * ============================================================ */
.switch {
  position: relative;
  display: inline-block;
  width: 40px;
  height: 22px;
}
.switch input { opacity: 0; width: 0; height: 0; }
.switch .slider {
  position: absolute;
  cursor: pointer;
  inset: 0;
  background: rgba(255, 255, 255, 0.18);
  border-radius: 22px;
  transition: background 0.2s ease;
}
.switch .slider::before {
  content: "";
  position: absolute;
  height: 18px;
  width: 18px;
  left: 2px;
  bottom: 2px;
  background: #fff;
  border-radius: 50%;
  transition: transform 0.2s ease;
}
.switch input:checked + .slider { background: var(--green2, #5fc05f); }
.switch input:checked + .slider::before { transform: translateX(18px); }

/* ============================================================
 * 44 . Number-input spinner hide on mobile
 * ============================================================ */
@media (pointer: coarse) {
  input[type="number"]::-webkit-inner-spin-button,
  input[type="number"]::-webkit-outer-spin-button {
    -webkit-appearance: none;
    margin: 0;
  }
  input[type="number"] { -moz-appearance: textfield; }
}

/* ============================================================
 * 45 . Range-input track + thumb
 * ============================================================ */
input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 4px;
  background: rgba(255, 255, 255, 0.12);
  border-radius: 4px;
  outline: none;
}
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 22px;
  height: 22px;
  background: var(--green2, #5fc05f);
  border-radius: 50%;
  cursor: pointer;
}
input[type="range"]::-moz-range-thumb {
  width: 22px;
  height: 22px;
  background: var(--green2, #5fc05f);
  border: 0;
  border-radius: 50%;
  cursor: pointer;
}

/* ============================================================
 * 46 . Progress-bar style
 * ============================================================ */
progress {
  width: 100%;
  height: 4px;
  border: 0;
  background: rgba(255, 255, 255, 0.08);
  border-radius: 4px;
}
progress::-webkit-progress-bar { background: rgba(255, 255, 255, 0.08); border-radius: 4px; }
progress::-webkit-progress-value { background: var(--green2, #5fc05f); border-radius: 4px; }
progress::-moz-progress-bar { background: var(--green2, #5fc05f); border-radius: 4px; }

/* ============================================================
 * 47 . Meter element style
 * ============================================================ */
meter {
  width: 100%;
  height: 6px;
}
meter::-webkit-meter-bar { background: rgba(255, 255, 255, 0.08); border-radius: 4px; }
meter::-webkit-meter-optimum-value { background: var(--green2, #5fc05f); border-radius: 4px; }
meter::-webkit-meter-suboptimum-value { background: #d4a000; border-radius: 4px; }

/* ============================================================
 * 48 . Foldable phone layout
 * ============================================================ */
@media (horizontal-viewport-segments: 2) {
  .app-container {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: env(viewport-segment-right 0 0);
  }
}

/* ============================================================
 * 49 . Container query support
 * ============================================================ */
@supports (container-type: inline-size) {
  .responsive-card { container-type: inline-size; }
  @container (max-width: 320px) {
    .responsive-card .label-text { font-size: var(--fs-sm); }
  }
}

/* ============================================================
 * 50 . Print mode mobile improvements
 * ============================================================ */
@media print {
  .recap-insights-card, .round-card, .course-row, .disc-card {
    page-break-inside: avoid;
    background: white !important;
    color: black !important;
    border: 1px solid #ccc !important;
  }
  .h-scroll {
    overflow-x: visible !important;
  }
  a[href]::after {
    content: " (" attr(href) ")";
    color: #555;
    font-size: 0.85em;
  }
}

/* ============================================================
 * 0.51.0 . Consume classes the polish waves set but never read.
 * ============================================================ */
/* address-bar-collapsed (mobile-hooks-5 #32): compact the sticky header when
 * the iOS Safari URL bar collapses, reclaiming vertical space on scroll. */
html.address-bar-collapsed .app-header {
  padding-top: 4px;
  padding-bottom: 4px;
  transition: padding 0.18s ease;
}
html.address-bar-collapsed .header-search-label,
html.address-bar-collapsed .header-search-hint {
  opacity: 0;
}
/* had-long-task (mobile-hooks-6 #55): dormant dev-only badge. Activates only
 * when html.debug-perf is set (never in prod), giving the instrumentation a
 * visible consumer for local profiling. */
html.debug-perf.had-long-task body::after {
  content: "long task";
  position: fixed;
  bottom: 8px;
  right: 8px;
  z-index: 99999;
  font: 600 11px/1.2 ui-monospace, monospace;
  color: #0c150c;
  background: #f0c040;
  padding: 3px 7px;
  border-radius: 6px;
  pointer-events: none;
}
