/* ============================================================================
   THEMING CONTRACT — READ BEFORE EDITING
   ----------------------------------------------------------------------------
   This file is the SINGLE SOURCE of ClubOS design tokens.

   To RE-THEME (change any color, radius, shadow, or font): edit ONLY the
   :root { ... } block below. Never hunt through the component rules.

   Rules every future edit MUST keep:
     • Component rules reference var(--token) ONLY — never hardcode a color
       (hex or rgba), radius, or shadow in a selector body.
     • To introduce a new shade, ADD a named token to :root FIRST, then
       reference it. Do not inline the literal at the call site.
     • The :root block is the only place raw color literals may appear.

   Guard: no raw hex or rgba() may appear outside the :root block. To
   confirm, scan the file for hex/rgba lines outside :root and expect zero
   matches (see this task's verification notes for the exact awk+grep).
============================================================================ */

/* "Quiet Ops" reskin — token + component override layer for the ClubOS web
   app (server-rendered Jinja + htmx + Alpine). Hand-written, served as its
   own file (same pattern as cc-console-extras.css / cc-public-board.css /
   cc-league.css) so the CI-stale-guarded Tailwind app.css never needs a
   rebuild. NOT loaded last: base.html order is app.css, connectivity.css,
   cc-console-extras.css, cc-quiet.css, cc-sidebar.css, cc-player-app.css,
   cc-premium.css. The three files after this one win the cascade for any
   selector they also touch.

   This file writes NO markup and changes NO behavior. It (a) re-declares the
   app's existing :root design tokens to the Quiet Ops values approved in
   ~/Downloads/redesign/final.html + briefs/FINAL_SPEC.md, which alone
   reskins most of the app since components already reference those vars,
   then (b) overrides specific component classes only where a pure token
   swap can't reach — hardcoded hex/rgba literals, hardcoded border-radii,
   background gradients, and the casual/competitive "pale chip" treatment
   that needs a separate value from the "visible border/dot" treatment the
   shared --casual/--competitive tokens also serve (see the --casual-bg /
   --competitive-bg tokens below).

   Reference: FINAL_SPEC.md "BASE: Quiet Ops (04)" + the :root token block in
   final.html. cc-public-board.css and cc-league.css are intentionally left
   alone beyond what the shared tokens already do — they're a separate,
   previously-approved redesign (Bricolage Grotesque / Instrument Sans) and
   are out of scope here. */

/* ============================================================================
   Fonts — IBM Plex Sans (body) + IBM Plex Mono (numeric/tabular) + Bricolage
   Grotesque (display, revived below). Static weight files already downloaded
   to static/fonts/ (mirrors the @font-face style used in cc-public-board.css).
============================================================================ */
@font-face {
  font-family: "IBM Plex Sans";
  src: url("/static/fonts/ibm-plex-sans-latin-400-normal.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Sans";
  src: url("/static/fonts/ibm-plex-sans-latin-500-normal.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Sans";
  src: url("/static/fonts/ibm-plex-sans-latin-600-normal.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Sans";
  src: url("/static/fonts/ibm-plex-sans-latin-700-normal.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("/static/fonts/ibm-plex-mono-latin-400-normal.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("/static/fonts/ibm-plex-mono-latin-600-normal.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
/* Bricolage Grotesque is the revived display face (was orphaned: file
   present, no @font-face). Confirmed a variable font by reading its WOFF2
   table directory (fvar/gvar/HVAR/MVAR/STAT all present, no Brotli decode
   needed since table tags sit uncompressed in the WOFF2 directory). One
   @font-face with a weight range is correct here, not a per-weight static
   split. */
@font-face {
  font-family: "Bricolage Grotesque";
  src: url("/static/fonts/bricolage-grotesque-latin.woff2") format("woff2");
  font-weight: 200 800;
  font-style: normal;
  font-display: swap;
}

/* ============================================================================
   Tokens — re-declares every var input.css's plain :root block defines
   (this IS the live, load-bearing token set — verified in the compiled
   app.css), plus a small set of new tokens the Quiet Ops look needs that
   the app didn't previously have (marked NEW below).
============================================================================ */
:root {
  /* ---- surfaces ---------------------------------------------------------- */
  --bg: #f7f8f5;
  --panel: #ffffff;
  --panel2: #f4f4f5;
  --line: #e4e4e7;
  --line-strong: #d4d4d8; /* NEW: matches final.html --border-strong */
  --backdrop: rgba(23, 23, 23, 0.32); /* NEW: dialog/overlay scrim */
  --white: #ffffff; /* NEW: white text/icon color for contrast */
  --white-soft: rgba(255, 255, 255, 0.45); /* NEW: spinner track on filled controls */
  --surface-warm: #fffdf6; /* NEW: subtle outdoor warmth */
  --surface-accent: #eaf3ff; /* NEW: selected player-nav surface */
  --surface-alt-soft: rgba(23, 23, 23, 0.02); /* NEW: public-board alt row */

  /* ---- ink --------------------------------------------------------------- */
  --ink: #10233f;
  --ink2: #40536c;
  --muted: #596b82;

  /* ---- accent ------------------------------------------------------------ */
  --accent: #165dcc;
  --accent-strong: #124ca8;
  --accent-hover: #0d3e8a; /* NEW: darker accent for primary-button hover */
  --accent-weak: #e8f1ff; /* NEW: pale accent fill (price card, info chips) */
  --accent-weak-strong: #c6dbfb; /* NEW: border for the above */
  --accent-soft: rgba(22, 93, 204, 0.1); /* NEW: soft accent chip bg */
  --accent-tint: rgba(22, 93, 204, 0.08); /* NEW: faint accent lead-row wash */
  --accent-row-soft: rgba(47, 102, 212, 0.04); /* NEW: public-board viewer row */

  /* ---- lanes -------------------------------------------------------------
     The shared --casual/--competitive vars stay a medium, border-safe hue
     because cc-public-board.css's .pb-court::before left-bar and this file's
     .ct--casual/.court--casual thick tile borders read off them directly and
     would go invisible on a very pale value. --casual-bg/--competitive-bg
     (NEW) are the pale Quiet Ops chip fills, used only in the component
     overrides below (pills/chips/roster tint) where final.html clearly wants
     the softer treatment. */
  --casual: #60a5fa;
  --casual-ink: #0b1220;
  --casual-deep: #1d4ed8;
  --casual-bg: #eff6ff; /* NEW */
  --competitive: #fb923c;
  --competitive-ink: #0b1220;
  --competitive-deep: #c2410c;
  --competitive-bg: #fff7ed; /* NEW */
  --competitive-soft: rgba(251, 146, 60, 0.14); /* NEW */

  /* ---- status ------------------------------------------------------------ */
  --live: #dc2626;
  --live-soft: rgba(220, 38, 38, 0.08); /* NEW: live/play soft chip bg */
  --live-ring: rgba(220, 38, 38, 0.5); /* NEW: pulse-ring keyframe color */
  --ok: #15803d;
  --ok-strong: #166534; /* NEW: free-court number ink */
  --ok-deep: #166534; /* NEW: free-court body copy ink */
  --ok-bg: #f0fdf4; /* NEW: free-court tile fill */
  --ok-border-soft: #86efac; /* NEW: free-court dashed border */
  --ok-hover: #27865f; /* NEW: free-court button hover state */
  --ok-shadow: rgba(22, 163, 74, 0.35); /* NEW: free-court button shadow */
  --warn: #d97706; /* NEW: the app only had ok/danger before */
  --warn-soft: rgba(217, 119, 6, 0.1); /* NEW: day-lock warn bg */
  --warn-border: rgba(217, 119, 6, 0.35); /* NEW: day-lock warn border */
  --danger: #dc2626;
  --danger-border: #fecaca; /* NEW: danger button / danger-zone border */
  --danger-bg: #fef2f2; /* NEW: danger-zone fill */
  --danger-soft: rgba(220, 38, 38, 0.1); /* NEW: danger icon-chip bg */
  --danger-tint: rgba(220, 38, 38, 0.06); /* NEW: faint danger hover wash */
  --danger-hover: #c23a3a; /* NEW: darker red for danger button hover states */
  --on-danger: #ffffff; /* NEW: text/icon color on a filled danger background */

  /* ---- winding pill (session status indicator) ----------------------------- */
  --winding-bg: rgba(251, 146, 60, 0.2); /* NEW: winding pill background (pale orange) */
  --winding-ink: #9a4a13; /* NEW: winding pill text (dark orange-brown) */

  --gold: #a16207;
  --gold-bg: #fefce8; /* NEW: champion card background */
  --gold-border: #fde68a; /* NEW: champion card border */
  --gold-tint: rgba(161, 98, 7, 0.08); /* NEW: #1 standings row wash */
  /* silver/bronze aren't specified by the Quiet Ops spec; kept as-is. */
  --silver: #aeb7c4;
  --bronze: #c77b30;

  /* ---- Court Class tier badge gradients (NEW) -----------------------------
     Dedicated tokens so the badge system stays independently themeable, kept
     separate from --warn/--gold even where a hex value happens to coincide. */
  --tier-bronze-a: #d97706; /* NEW */
  --tier-bronze-b: #92400e; /* NEW */
  --tier-silver-a: #94a3b8; /* NEW */
  --tier-silver-b: #475569; /* NEW */
  --tier-gold-a: #fbbf24; /* NEW */
  --tier-gold-b: #b45309; /* NEW */
  --tier-platinum-a: #818cf8; /* NEW */
  --tier-platinum-b: #4338ca; /* NEW */
  --tier-champion-a: #fde047; /* NEW */
  --tier-champion-b: #a16207; /* NEW */

  /* ---- radius ------------------------------------------------------------ */
  --radius: 12px;
  --radius-sm: 8px; /* NEW: small controls (sm buttons, small icon chips) */
  --radius-lg: 16px; /* NEW: popovers/dialogs */

  /* ---- shadow (flat everywhere except popovers/dialogs) ------------------ */
  --shadow-sm: 0 1px 2px rgba(16, 35, 63, 0.05);
  --shadow: 0 8px 24px rgba(16, 35, 63, 0.08);
  --shadow-lg: 0 18px 44px rgba(16, 35, 63, 0.16), 0 2px 6px rgba(16, 35, 63, 0.08);
  --shadow-topbar: 0 1px 0 var(--line), 0 5px 18px rgba(16, 35, 63, 0.03);
  --shadow-bottomnav: 0 -7px 24px rgba(16, 35, 63, 0.07);

  /* ---- featured session hero -------------------------------------------- */
  --hero-mid: #173d6b;
  --hero-ring: rgba(255, 255, 255, 0.18);
  --hero-copy: #dceaff;

  /* ---- third-party brand marks ------------------------------------------- */
  --google-red: #ea4335;
  --google-blue: #4285f4;
  --google-yellow: #fbbc05;
  --google-green: #34a853;

  /* ---- type -------------------------------------------------------------- */
  --font: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    Helvetica, Arial, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas,
    monospace; /* NEW */
  --font-display: "Bricolage Grotesque", "IBM Plex Sans", sans-serif; /* NEW: display face, hero numerals and headline moments only */

  /* ---- Tailwind v4 @theme mirror (input.css lines 6-24) ------------------
     Verified: app.css's compiled output currently contains ZERO --color-*
     custom properties or Tailwind utility classes referencing them (no
     template uses Tailwind utilities today, only the hand-written component
     classes above) — this block is inert right now but kept for
     forward-compatibility per the brief, in case a future template adds a
     Tailwind utility class. */
  --color-bg: var(--bg);
  --color-panel: var(--panel);
  --color-panel2: var(--panel2);
  --color-ink: var(--ink);
  --color-ink2: var(--ink2);
  --color-muted: var(--muted);
  --color-line: var(--line);
  --color-accent: var(--accent);
  --color-accent-strong: var(--accent-strong);
  --color-casual: var(--casual);
  --color-competitive: var(--competitive);
  --color-live: var(--live);
  --color-ok: var(--ok);
  --color-danger: var(--danger);
  --radius-card: var(--radius);
  --font-sans: var(--font);
}

/* Live-status pulse ring — was hardcoded to the old --live rgb(216,69,69);
   re-declared here on the new red (via --live-ring) so the whole @keyframes
   (not just individual declarations) matches. */
@keyframes pulse {
  0% { box-shadow: 0 0 0 0 var(--live-ring); }
  70% { box-shadow: 0 0 0 8px transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}

/* ============================================================================
   Buttons
============================================================================ */
.btn.primary { box-shadow: none; }
.btn.primary:hover { background: var(--accent-hover); }
.btn.danger { border-color: var(--danger-border); }

/* ============================================================================
   Pills / chips / lane color — the soft Quiet Ops chip treatment
   (pale bg + deep-ink text) using the new --casual-bg/--competitive-bg
   tokens, since the shared --casual/--competitive vars stay a medium,
   border-safe hue (see the token block comment above).
============================================================================ */
.style-pill.casual { background: var(--casual-bg); color: var(--casual-deep); }
.style-pill.competitive { background: var(--competitive-bg); color: var(--competitive-deep); }

.qchip { background: var(--panel); border-color: var(--line); }
.qchip.casual .qpos { background: var(--casual-bg); border-color: var(--casual-bg); color: var(--casual-deep); }
.qchip.competitive .qpos { background: var(--competitive-bg); border-color: var(--competitive-bg); color: var(--competitive-deep); }

.seg2 button.on.casual { background: var(--casual-bg); color: var(--casual-deep); }
.seg2 button.on.competitive { background: var(--competitive-bg); color: var(--competitive-deep); }

/* Matches-waiting-for-court lane chips were hardcoded rgba literals, not
   tokens at all — now the same soft pill as everywhere else. */
.deck-style.casual { background: var(--casual-bg); color: var(--casual-deep); }
.deck-style.comp { background: var(--competitive-bg); color: var(--competitive-deep); }
.deck-row { border-radius: var(--radius); }

.pill.live { background: var(--live-soft); }
.pill.up { background: var(--accent-soft); }
.pill.unpaid { color: var(--competitive-deep); }
.cpaid.unpaid { color: var(--competitive-deep); }

.link-danger:hover { background: var(--danger-tint); }
.deck-x:hover { background: var(--danger-tint); }

.warn {
  background: var(--warn-soft);
  border-color: var(--warn-border);
  color: var(--warn);
  border-radius: var(--radius);
}
.danger-zone { background: var(--danger-bg); border-color: var(--danger-border); border-radius: var(--radius); }

.choice .ico.org { background: var(--accent-weak); }
.fee-note { background: var(--accent-weak); border-color: var(--accent-weak-strong); }
.notfound .nf-code { background: var(--accent-weak); color: var(--accent-strong); }
.qrow.lead { background: linear-gradient(90deg, var(--accent-tint), transparent); }

/* ============================================================================
   Top bar / join chip
============================================================================ */
.topbar { border-radius: var(--radius); box-shadow: none; }
.join-chip {
  border: 1px solid var(--line);
  background: var(--panel);
  border-radius: var(--radius);
}

/* ============================================================================
   Hero (fresh-session screen)
============================================================================ */
.hero { border-radius: var(--radius); box-shadow: none; }
.hero-qr { background: var(--casual-bg); }

/* ============================================================================
   Court tiles (admin console board) — full 2px lane-hue border per the
   FINAL_SPEC O5 "JJ iteration" (superseding the earlier left-accent-bar
   draft); free-court treatment flattened to match final.html's
   .court-tile-free (no gradient).
============================================================================ */
.ct { border-radius: var(--radius); }
.ct--casual { border-width: 2px; }
.ct--competitive { border-width: 2px; }
.ct-style.casual { background: var(--casual-deep); }
.ct--open { border: 2px dashed var(--ok-border-soft); background: var(--ok-bg); }
.ct--open .ct-no { color: var(--ok-strong); }
.ct-open-txt { color: var(--ok-deep); }
.fill-btn { border-radius: var(--radius); }

/* ============================================================================
   Waiting-list roster (check-in) — flat lane tint + left border instead of
   the previous diagonal gradient fill.
============================================================================ */
.crow { border-radius: var(--radius); border-left-width: 3px; }
.crow.casual { background: var(--casual-bg); border-color: var(--casual-bg); border-left-color: var(--casual); }
.crow.competitive { background: var(--competitive-bg); border-color: var(--competitive-bg); border-left-color: var(--competitive); }
.crow.pending.casual { background: var(--panel2); border-color: var(--line); border-left-color: var(--casual); }
.crow.pending.competitive { background: var(--panel2); border-color: var(--line); border-left-color: var(--competitive); }

/* ============================================================================
   Admin home (O2) — session/league cards. Uniform row height, one meta
   line, and a fixed-width action column so the join code + buttons line
   up down the list. Scoped to .admin-home (set on the page's outer .wrap
   in admin/home.html) so admin/play.html's player-facing session-card list
   (narrower .wrap--tight, no sc-actions) is untouched.
============================================================================ */
.admin-home .session-card { min-height: 82px; }
/* Mid widths (tablet / narrowed window): the join code + action buttons can't
   fit on the title row inside .wrap--narrow, so lay them out as a tidy second
   row instead of forcing a single line that overflows off the right edge. */
@media (min-width: 641px) and (max-width: 899px) {
  .admin-home .session-card .sc-main { flex-basis: 100%; }
  .admin-home .session-card .sc-codebox { text-align: left; }
  .admin-home .session-card .sc-actions { flex: 1 1 auto; justify-content: flex-start; }
}
/* Wide screens: uniform single-line rows with a fixed-width action column, but
   only once there is genuinely room so nothing is ever clipped. */
@media (min-width: 900px) {
  .admin-home .session-card { flex-wrap: nowrap; }
  .admin-home .session-card .sc-meta { flex-wrap: nowrap; overflow: hidden; }
  .admin-home .session-card .sc-meta > * { white-space: nowrap; }
  .admin-home .session-card .sc-actions {
    flex-wrap: nowrap;
    justify-content: flex-end;
    min-width: 280px;
  }
  .admin-home .session-card .sc-actions > .btn:not(.danger) { min-width: 104px; }
}

/* ============================================================================
   Dialogs / popovers — the only surfaces that keep a shadow (--shadow-lg,
   flattened above for ordinary cards). Backdrop tint updated to the new ink.
============================================================================ */
dialog.modal { border-radius: var(--radius-lg); }
dialog.modal::backdrop { background: var(--backdrop); }
.sa-menu,
.filter-pop { border-radius: var(--radius-lg); }
.checkout-panel,
.auth-card { border-radius: var(--radius-lg); }

/* Score dialog: flatten the team-color background tint (final.html keeps
   team panels plain white/panel; the colored tbadge pill carries team
   identity instead), and pull team-2's hardcoded orange onto the token. */
.team-panel { border-radius: var(--radius); }
.team-panel.t1,
.team-panel.t2 { background: var(--panel); }
.t2 .tbadge { background: var(--competitive-deep); }
.t2 .sstep-btn { background: var(--competitive-deep); }
.sstep-btn { border-radius: var(--radius); }
.sstep-val { border-radius: var(--radius); }

/* ============================================================================
   Standings table
============================================================================ */
.row.top1 { background: linear-gradient(90deg, var(--gold-tint), transparent); }
.row.top1 .rank { box-shadow: none; }

/* ============================================================================
   Segmented tabs
============================================================================ */
.seg { border-radius: var(--radius); }
.seg a.on,
.seg button.on { border: 1px solid var(--line); }

/* ============================================================================
   Price card / play-type choice cards
============================================================================ */
.price-card {
  background: var(--accent-weak);
  border-color: var(--accent-weak-strong);
  border-radius: var(--radius);
}
.price-card .amt { font-family: var(--font-mono); font-size: 22px; font-weight: 600; color: var(--accent); }

.choice { border-radius: var(--radius); box-shadow: none; }
.choice:hover {
  border-color: var(--line-strong);
  background: var(--panel2);
  box-shadow: none;
  transform: none;
}
.choice .ico { border-radius: var(--radius); }

/* ============================================================================
   cc-console-extras.css follow-ups (loaded before this file — these are
   later-cascade overrides, cc-console-extras.css itself is untouched).
============================================================================ */
.btn.icon.on { background: var(--accent-weak); }
.sa-ic.force { background: var(--accent-weak); }
.sa-ic.end { background: var(--danger-soft); }
.cstat--wait { background: var(--accent-soft); }
.cstat--play { background: var(--live-soft); }

/* ============================================================================
   Timer / duration state colors — .t-ok and .t-late already read the
   --ok/--danger tokens; .t-warn was hardcoded to the old orange and is now
   the dedicated --warn amber.
============================================================================ */
.t-warn { color: var(--warn); }

/* ============================================================================
   Misc hardcoded border-radii normalized to the 8px (controls) / 6px (small
   controls) / 12px (popovers) Quiet Ops scale. Anything already on
   var(--radius) in input.css/cc-public-board.css/cc-league.css needed no
   change here — most cards already were.
============================================================================ */
.btn,
.code-entry input,
.field input,
.field select,
.field textarea,
.search,
.door-search,
.numfield input,
.stat-chip,
.oauth-btn,
.role-seg,
.qr-card,
.qr-holder,
.kebab {
  border-radius: var(--radius);
}
.btn.sm,
.qr {
  border-radius: var(--radius-sm);
}

/* ============================================================================
   Mono / tabular-nums numeric elements
============================================================================ */
.qpos,
.ct-elapsed,
.qchip .qw,
.sstep-val,
.stat-chip b,
.rank,
.wl,
.gp,
.pts,
.stepper .box .v,
.numfield input,
.deck-pos,
.step-n,
.join-code,
.jc-code,
.hero-code,
.session-card .sc-code,
.qr-code-big .code,
.code-entry input {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

/* ============================================================================
   Play-type chooser (L1) — "What are you running?"
   Grid of purchasable formats (session / league / …) plus not-yet-built
   formats shown muted with a "Coming soon" tag. De-emphasized price, value-
   first ordering, filled primary CTA.
============================================================================ */
.purchase-heading {
  font-size: 20px;
  font-weight: 700;
  color: var(--ink);
  margin: 0 0 4px;
}

.purchase-search-wrap {
  position: relative;
  max-width: 480px;
  margin-bottom: 24px;
}

.purchase-search-icon {
  position: absolute;
  left: 14px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--muted);
  pointer-events: none;
  display: flex;
}

.purchase-search-wrap .search {
  width: 100%;
  min-height: 46px;
  padding-left: 38px;
}

.choice-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 16px;
  max-width: 980px;
}

.choice-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 22px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  text-align: left;
  text-decoration: none;
  color: inherit;
  cursor: pointer;
  transition: background-color 0.05s ease, border-color 0.05s ease, transform 0.05s ease;
}

.choice-card:hover {
  background: var(--panel2);
  border-color: var(--line-strong);
  transform: translateY(-1px);
}

/* Not-yet-built formats: dashed border, muted, no hover lift, not a link */
.choice-card.choice-card-soon {
  cursor: default;
  opacity: 0.65;
  border-style: dashed;
}

.choice-card.choice-card-soon:hover {
  background: var(--panel);
  border-color: var(--line);
  transform: none;
}

.choice-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.choice-card-title {
  font-size: 16.5px;
  font-weight: 600;
  color: var(--ink);
  margin: 0;
}

/* Optional "Best value" chip on league card */
.choice-tag {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--ok-strong);
  background: var(--ok-bg);
  border: 1px solid var(--ok-border-soft);
  border-radius: 999px;
  padding: 2px 9px;
  white-space: nowrap;
}

/* "Coming soon" chip — same shape, muted instead of green */
.choice-tag.choice-tag-soon {
  color: var(--ink2);
  background: var(--panel2);
  border-color: var(--line);
}

/* Value/description — comes FIRST to emphasize bundle over price */
.choice-card-sub {
  font-size: 13px;
  color: var(--ink2);
  line-height: 1.5;
  margin: 0;
  flex: 1;
}

/* Price section: quiet treatment (small, ink, not accent blue) */
.choice-price {
  display: flex;
  flex-direction: column;
  gap: 1px;
  margin-top: auto;
  padding-top: 6px;
}

.choice-price-lead {
  font-size: 26px;
  font-weight: 700;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  margin: 0;
}

.choice-price-unit {
  font-size: 15px;
  font-weight: 500;
  color: var(--ink2);
  margin: 0;
}

/* Contextual note under price (e.g., "one-time · no subscription") */
.choice-price-note {
  font-size: 12px;
  color: var(--muted);
  margin: 0;
}

/* Filled primary CTA — blue moved here from price for psychological impact */
.choice-cta {
  width: 100%;
  justify-content: center;
  margin-top: 4px;
}

/* ============================================================================
   Locations — all-parks map, custom pin/cluster icons, pagination
============================================================================ */
.cc-map {
  width: 100%;
  height: 260px;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  overflow: hidden;
  margin-bottom: 20px;
  background: var(--panel2);
}
@media (min-width: 720px) {
  .cc-map {
    height: 420px;
  }
}

/* Custom teardrop pin (L.divIcon) — Leaflet's default .leaflet-div-icon adds a
   white box + border meant for plain text/number icons; our pin is a full
   custom SVG, so strip that chrome. */
.leaflet-div-icon.cc-park-pin {
  background: none;
  border: none;
}
.cc-park-pin .cc-pin-body {
  fill: var(--accent);
  stroke: var(--white);
  stroke-width: 1.5;
}
.cc-park-pin .cc-pin-dot {
  fill: var(--white);
}
.cc-park-pin--hover svg {
  transform: scale(1.15);
  transform-origin: 50% 100%;
  transition: transform 0.1s ease;
}

/* Park name on marker hover — restyle Leaflet's default tooltip box to match
   the app's flat "Quiet Ops" look instead of its own default chrome. */
.cc-park-tooltip.leaflet-tooltip {
  background: var(--panel);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 4px 9px;
  font-size: 12.5px;
  font-weight: 600;
  box-shadow: none;
}
.cc-park-tooltip.leaflet-tooltip-top:before {
  border-top-color: var(--line);
}

/* Cluster count bubble (iconCreateFunction) */
.leaflet-div-icon.cc-cluster-icon {
  background: none;
  border: none;
}
.cc-cluster-bubble {
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--accent);
  color: var(--white);
  font-weight: 700;
  font-size: 13px;
  border: 3px solid var(--panel);
  box-shadow: var(--shadow-lg);
}

/* Prev/Next pagination — no existing pattern in this codebase, built from the
   existing .btn/.btn.sm scale */
.cc-pagination {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  margin-top: 16px;
}
.cc-pagination-status {
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

/* Location-icon button on a Locations row: flies the map to that park without
   also triggering the row's own click (purchase popup) — a real nested
   <button>, so the row itself is a role="button" div rather than a <button>
   (buttons can't nest). */
.cc-row-locate {
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--ink2);
  cursor: pointer;
  transition: background 0.1s ease, color 0.1s ease;
}
.cc-row-locate:hover,
.cc-row-locate:focus-visible {
  background: var(--panel2);
  color: var(--accent);
}

/* Live field validation status (court-name checks): text carries the meaning
   (aria-live span), color only reinforces it. Empty spans collapse. */
.field-status:empty {
  display: none;
}
.field-status.ok {
  color: var(--ok);
}
.field-status.bad {
  color: var(--danger);
}

/* ---- global input/target floors (override frozen app.css rules) -------------
   Live here (the universal layer) because guests hit both: .search on the
   not-found page, .checkout-close on the embedded-checkout overlay. */
/* 16px floor stops iOS zoom-on-focus (app.css .search is 13.5px). */
.search {
  font-size: 16px;
}
/* 44px hit target for the embedded-checkout close X (app.css leaves it unsized). */
.checkout-close {
  align-items: center;
  display: inline-flex;
  justify-content: center;
  min-height: 44px;
  min-width: 44px;
}
