/* GoGolf brand skin, layered on top of the generic design-system.css from
   starter-kit/ui. A deliberately restrained navy / deep green / gold
   palette - the classic professional golf broadcast look (tournament
   leaderboards, clubhouse signage) - in place of a brighter, more
   "consumer dashboard" multi-color scheme. Not affiliated with, and
   doesn't use the name or marks of, any golf tour or association - this
   is a color aesthetic only. */

:root {
  --brand-green-bright: #2f8f52;
  --brand-green-bright-rgb: 47, 143, 82;
  --brand-green: #1f6e3f;
  --brand-green-dark: #123d24;
  --brand-navy: #14315c;
  --brand-navy-rgb: 20, 49, 92;
  --brand-navy-dark: #0b1e3a;
  --brand-gold: #c9a227;
  --brand-gold-rgb: 201, 162, 39;
  --brand-gold-bg: rgba(var(--brand-gold-rgb), 0.14);
  --brand-gold-text: #e0c065;

  /* Retarget the design system's generic blue/purple accents to the brand
     palette - primary actions and active states read as "GoGolf green" and
     prize/award moments get their own gold accent instead of borrowing the
     generic warn color. */
  --accent: var(--brand-green-bright);
  --accent-2: var(--brand-gold);
  --accent-bg: rgba(var(--brand-green-bright-rgb), 0.14);

  /* Same unification as the light theme below - --ok otherwise stays the
     generic teal-emerald from design-system.css, a visibly different
     green from the brand green used everywhere else. */
  --ok: var(--brand-green-bright);
  --ok-bg: rgba(var(--brand-green-bright-rgb), 0.16);
  --ok-text: #7ed9a0;
}

html[data-theme="light"] {
  /* Crisper light theme: a true-white card surface against a distinctly
     cooler-gray page background (previously both landed on very similar
     off-whites, so the whole page read as one flat gray wash instead of
     cards actually separating from the background). Muted text darkened
     for real legibility rather than just decoration - and --ok now
     matches --brand-green-bright exactly instead of a separate teal-
     emerald, so every "green" moment (confirmed badges, checkmarks,
     buttons, active nav, status dots) reads as the same one green. */
  --bg: #eef1f6;
  --card: #ffffff;
  --card-alt: #f1f4f8;
  --border: #dde2ea;
  --border-soft: #e7eaf0;
  --muted: #55606f;

  --brand-green-bright: #1c5c34;
  --brand-green-bright-rgb: 28, 92, 52;
  --brand-green: #16492a;
  --brand-green-dark: #0f371f;
  --brand-navy: #14315c;
  --brand-navy-rgb: 20, 49, 92;
  --brand-navy-dark: #0b1e3a;
  --brand-gold: #93700a;
  --brand-gold-rgb: 147, 112, 10;
  --brand-gold-bg: rgba(var(--brand-gold-rgb), 0.13);
  --brand-gold-text: #6b5407;

  --accent: var(--brand-green-bright);
  --accent-2: var(--brand-gold);
  --accent-bg: rgba(var(--brand-green-bright-rgb), 0.13);

  --ok: var(--brand-green-bright);
  --ok-bg: rgba(var(--brand-green-bright-rgb), 0.13);
  --ok-text: #16492a;
}

.app-nav button.active {
  background: var(--brand-navy); color: #fff; border-color: var(--brand-navy);
}
.app-nav button.active svg { color: #fff; }
html[data-theme="light"] .app-nav button.active { color: #fff; }

/* Plain, unstyled links (design-system.css sets no default) otherwise
   fall back to browser-default blue, which is neither our gray-neutral
   palette nor our green brand color - just an unrelated third color
   showing up at random. Low specificity so any element/class-level color
   already set elsewhere (buttons styled as links, nav items, etc.) wins
   without needing !important. */
a { color: var(--brand-green-bright); }
a:visited { color: var(--brand-green-bright); }

.logo-mark { height: 36px; width: auto; display: block; }

/* Header gets a very faint brand-green wash instead of a flat card color,
   so it reads as "the app's identity bar" rather than just another card. */
.app-header {
  background: linear-gradient(135deg, var(--card) 0%, var(--card) 55%, rgba(var(--brand-navy-rgb), 0.10) 100%);
  border-top: 3px solid var(--brand-navy);
}

/* Icon sizing/alignment for the inline SVGs from _icons.html - sits inside
   headings, nav buttons, badges, and stat labels without needing a class
   on every single call site. */
h1 svg, h2 svg, .app-nav button svg, .stat-label svg, .badge svg {
  width: 15px; height: 15px; flex-shrink: 0; vertical-align: -2px;
}
h1 svg { width: 20px; height: 20px; color: var(--brand-green-bright); }
h2 svg { color: var(--brand-green-bright); }
button svg { width: 14px; height: 14px; margin-right: 6px; vertical-align: -2px; flex-shrink: 0; }
.app-nav button svg { margin-right: 0; }

/* Section-label and stat-label icons default to plain --muted gray (from
   design-system.css), which meant nearly every repeated category icon in
   the app (calendar, pin, flag, trophy, chart, users...) rendered gray
   instead of brand green - the single biggest source of "everything on
   this page is some shade of gray." These appear dozens of times per
   page, so recoloring them does more for making green feel present and
   consistent than almost anything else. */
.section-label svg, .stat-label svg { color: var(--brand-green-bright); }

/* Plain/neutral badges (scoring format, hole counts, etc. - no ok/warn/err/
   gold status) default to muted-gray-on-gray in the base design system,
   which is low-contrast enough to read as barely-there on a light
   background. Darken the text so neutral badges are still clearly
   readable, not just decorative. */
.badge:not(.ok):not(.err):not(.warn):not(.gold) { color: var(--text); }

/* Gold badge variant for prize/award content - distinct from the
   ok/warn/err status badges, since "1st place" isn't a status. */
.badge.gold { background: var(--brand-gold-bg); color: var(--brand-gold-text); border-color: rgba(var(--brand-gold-rgb), 0.35); }
.badge.gold::before { content: ""; display: inline-block; width: 6px; height: 6px; border-radius: 50%; margin-right: 6px; vertical-align: 1px; background: var(--brand-gold); box-shadow: 0 0 6px rgba(var(--brand-gold-rgb), 0.6); }

/* Icon-led stat tiles: label row holds the icon, keeps stat-box markup
   unchanged elsewhere. */
.stat-label { gap: 6px; }

/* Prize/award list rows */
.prize-row { display: flex; align-items: center; gap: 10px; padding: 8px 0; border-bottom: 1px solid var(--border-soft); }
.prize-row:last-child { border-bottom: none; }
.prize-row.report-resolved { opacity: 0.55; }
.prize-row .prize-icon { color: var(--brand-gold); flex-shrink: 0; }

/* Course search combobox (see static/js/course-search.js) */
.course-search { position: relative; }
.course-search-results {
  position: absolute; z-index: 20; top: 100%; left: 0; right: 0; margin-top: 4px;
  background: var(--card); border: 1px solid var(--border); border-radius: 10px;
  box-shadow: 0 18px 40px -20px rgba(0,0,0,0.6); overflow: hidden; display: none;
  max-height: 260px; overflow-y: auto;
}
.course-search-results.open { display: block; }
.course-search-result {
  padding: 10px 12px; cursor: pointer; border-bottom: 1px solid var(--border-soft);
  display: flex; flex-direction: column; gap: 2px;
}
.course-search-result:last-child { border-bottom: none; }
.course-search-result:hover, .course-search-result.active { background: var(--card-alt); }
.course-search-result .name { font-size: 13px; font-weight: 600; }
.course-search-result .address { font-size: 11px; color: var(--muted); }
.course-search-result.add-new { color: var(--brand-green-bright); font-weight: 600; }
.course-search-result .rating { font-size: 11px; color: var(--brand-gold); }
.course-selected-address { font-size: 12px; color: var(--muted); margin-top: 4px; display: flex; align-items: center; gap: 5px; }

/* --- Progressive disclosure: occasional-use forms (add flight, register
   golfer, send notification, record prize, add course, leave a review)
   collapse behind these by default so the page opens showing only the
   stuff worth checking at a glance, not every form at once. Native
   details/summary - no JS, keyboard/screen-reader friendly for free. --- */
details > summary {
  cursor: pointer; list-style: none; font-weight: 600; font-size: 13px;
  display: flex; align-items: center; gap: 6px; color: var(--text);
  padding: 2px 0; user-select: none;
}
details > summary::-webkit-details-marker { display: none; }
details > summary::after {
  content: "▾"; margin-left: auto; color: var(--muted); font-size: 11px;
  transition: transform 0.15s ease;
}
details[open] > summary::after { transform: rotate(180deg); }
details > summary:hover { color: var(--brand-green-bright); }

/* --- Copy-link buttons replace showing the full raw magic-link URL --- */
.copy-link-btn { font-size: 12px; padding: 6px 10px; }

/* Shared text-input look, replacing the long repeated inline style on
   every form field across admin templates. */
.text-input {
  width: 100%; padding: 8px; border-radius: 8px; border: 1px solid var(--border);
  background: var(--card-alt); color: var(--text); font: inherit;
}

/* --- Star ratings on course cards --- */
.course-rating { display: flex; align-items: center; gap: 8px; margin: 8px 0; }
.course-rating .stars { color: var(--brand-gold); font-size: 14px; letter-spacing: 1px; }
.course-links { display: flex; flex-wrap: wrap; gap: 14px; font-size: 12px; }
.course-links a { display: inline-flex; align-items: center; gap: 5px; color: var(--muted); }
.course-links a:hover { color: var(--brand-green-bright); }

/* --- Course detail hero: name/rating/links/specs on the left, the primary
   "operate this course" action (book a tournament here) on the right -
   replaces a single narrow stacked card with a proper header. --- */
.course-hero-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 20px; flex-wrap: wrap; }
.course-hero-description { margin-top: 14px; font-size: 13.5px; line-height: 1.6; max-width: 62ch; }
.course-hero-notes { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--border-soft); }
.course-hero-actions { display: flex; flex-direction: column; align-items: stretch; gap: 8px; }

/* --- Course details panel (revealed via the hero's "View details"
   toggle) - a quick-reference hole-by-hole par grid, since that's the
   one piece of course info actually worth researching ahead of time.
   Everything else (contact, address, rating) is already shown in the
   hero and is fixed at creation time - nothing here is editable. --- */
.course-details-panel-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; flex-wrap: wrap; margin-bottom: 14px; }
.course-details-panel-head h2 { margin: 0; }
.hole-notes-source { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; color: var(--muted); flex-shrink: 0; }
.hole-notes-source:hover { color: var(--brand-green-bright); }

.hole-par-grid { display: grid; grid-template-columns: repeat(9, 1fr); gap: 8px; }
.hole-par-cell {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 8px 4px; border-radius: 8px; background: var(--card-alt); border: 1px solid var(--border-soft);
}
.hole-par-num { font-size: 10px; font-weight: 700; color: var(--muted); text-transform: uppercase; }
.hole-par-value { font-size: 16px; font-weight: 800; color: var(--brand-green-bright); }
@media (max-width: 640px) {
  .hole-par-grid { grid-template-columns: repeat(6, 1fr); }
}

/* Holes with a published narrative note (see hole_notes) get a hover/
   focus tooltip on their grid cell instead of a second always-expanded
   list repeating every hole number - a small dot marks which cells have
   one, the full text only appears on hover so the grid stays compact. */
.hole-par-cell.has-note { position: relative; cursor: help; border-color: rgba(var(--brand-green-bright-rgb), 0.4); }
.hole-par-cell.has-note::before {
  content: ""; position: absolute; top: 4px; right: 4px; width: 5px; height: 5px; border-radius: 50%;
  background: var(--brand-green-bright);
}
.hole-par-cell.has-note::after {
  content: attr(data-note);
  position: absolute; bottom: calc(100% + 8px); left: 50%; transform: translateX(-50%);
  width: 220px; padding: 10px 12px; border-radius: 10px; background: var(--card); border: 1px solid var(--border-soft);
  box-shadow: 0 12px 30px -14px rgba(0,0,0,0.5); font-size: 12px; font-weight: 400; line-height: 1.5; color: var(--text);
  text-align: left; white-space: normal; opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity 0.15s ease; z-index: 30;
}
.hole-par-cell.has-note:hover::after, .hole-par-cell.has-note:focus-visible::after {
  opacity: 1; visibility: visible;
}

/* --- Individual course reviews (rating + golfer + comment), distinct
   from the aggregate star summary in the hero. --- */
.review-list { display: flex; flex-direction: column; gap: 12px; }
.review-row { padding-bottom: 12px; border-bottom: 1px solid var(--border-soft); }
.review-row:last-child { border-bottom: none; padding-bottom: 0; }
.review-row-top { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.review-row-top .stars { color: var(--brand-gold); font-size: 13px; letter-spacing: 1px; }
.review-comment { margin-top: 4px; }

/* A comfortable button trigger instead of the default full-width text row
   with a chevron - a proper-sized "Edit" button, the form appears below
   it once clicked. Also used standalone (not in a flex row) for "Edit
   course" - that one gets its own top margin so it doesn't hug whatever
   badge/text sits above it. */
details.availability-update {
  margin-top: 12px;
}
details.availability-update > summary {
  display: inline-flex; width: auto; font: inherit; font-size: 13px; font-weight: 600;
  padding: 9px 16px; border-radius: 8px; border: 1px solid var(--border);
  background: var(--card-alt); color: var(--text);
}
details.availability-update > summary::after { content: none; }
details.availability-update > summary:hover { border-color: var(--brand-green-bright); color: var(--brand-green-bright); }

/* --- Landing page hero cards --- */
.landing-card { text-decoration: none; color: inherit; text-align: center; padding: 32px 24px; }
.landing-card h2 { justify-content: center; font-size: 18px; }
.landing-card .sub { text-align: center; }
.landing-card-cta {
  display: inline-flex; align-items: center; gap: 4px; margin-top: 16px;
  font-size: 13px; font-weight: 600; color: var(--brand-green-bright);
}
.landing-card:hover { border-color: var(--brand-green-bright); }

/* --- Courses master-detail layout: a scrollable name list on the left,
   full detail for one selected course on the right - replaces a grid of
   N full cards (a lot of scrolling to compare/find one course) with a
   pattern that scales to however many courses the club adds. --- */
/* Shared sidebar+detail layout - a scrollable name list on the left, a
   detail pane on the right, swapped via AJAX on click (see courses.html and
   golfers.html's loadCourse/loadGolfer JS). Not actually course-specific,
   so both pages use these same class names rather than near-duplicate CSS. */
.roster-layout { display: flex; gap: 20px; align-items: flex-start; }
.roster-sidebar {
  width: 260px; flex-shrink: 0; background: var(--card); border: 1px solid var(--border);
  border-radius: 14px; padding: 12px; max-height: 70vh; overflow-y: auto;
  position: sticky; top: 16px;
}
.roster-sidebar-search {
  width: 100%; padding: 8px; margin-bottom: 8px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--card-alt); color: var(--text); font: inherit;
}
.roster-sidebar-item {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 9px 10px; border-radius: 8px; color: var(--text); text-decoration: none;
  font-size: 13px; font-weight: 600;
}
.roster-sidebar-item:hover { background: var(--card-alt); }
.roster-sidebar-item.active { background: var(--accent-bg); color: var(--brand-green-bright); }
.roster-sidebar-item .mini-stars { color: var(--brand-gold); font-size: 11px; flex-shrink: 0; }
.roster-sidebar-item .roster-flag { font-size: 14px; flex-shrink: 0; }
.roster-detail { flex: 1 1 auto; min-width: 0; }

/* Search-as-you-type combobox for the notify form's Golfer field - a plain
   <select> gets unwieldy once a tournament has more than a handful of
   players, same reasoning as the Golfers page sidebar search. */
.notify-combobox { position: relative; }
.notify-combobox-options {
  display: none; position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 20;
  background: var(--card); border: 1px solid var(--border); border-radius: 8px;
  max-height: 220px; overflow-y: auto; box-shadow: 0 8px 24px rgba(0,0,0,0.18);
}
.notify-combobox-option { padding: 8px 10px; font-size: 13px; cursor: pointer; }
.notify-combobox-option:hover { background: var(--card-alt); }

/* Small dismissable popup for form errors that would otherwise navigate to
   a bare JSON error page (raised via HTTPException from an AJAX-submitted
   form) - only one shown at a time, see showErrorToast(). */
.toast-error {
  position: fixed; top: 20px; left: 50%; transform: translateX(-50%); z-index: 999;
  background: var(--err-bg); color: var(--err); border: 1px solid rgba(248,113,113,0.35);
  padding: 10px 16px; border-radius: 10px; font-size: 13px; font-weight: 600;
  box-shadow: 0 8px 24px rgba(0,0,0,0.25); max-width: 360px; text-align: center;
  cursor: pointer; animation: toast-in 0.15s ease-out;
}
@keyframes toast-in { from { opacity: 0; transform: translate(-50%, -8px); } to { opacity: 1; transform: translate(-50%, 0); } }

@media (max-width: 640px) {
  .roster-layout { flex-direction: column; }
  .roster-sidebar { width: 100%; position: static; max-height: 260px; }
}

/* =========================================================================
   Persistent setup-progress widget - shown on every admin page (see
   next_tournament_progress() in templating.py + the header block in
   base.html). A pulsing status dot (red = overdue, amber = in progress,
   green = fully ready) plus a live progress bar for the soonest upcoming
   tournament's setup checklist.
   ========================================================================= */
.progress-widget {
  margin: 0 0 20px; padding: 12px 20px; border-radius: 14px;
  background: var(--card); border: 1px solid var(--border);
}
.progress-widget-link { display: flex; align-items: center; gap: 14px; text-decoration: none; color: var(--text); flex-wrap: wrap; }
.progress-widget-text { font-size: 13px; flex: 1 1 240px; min-width: 0; }
.progress-widget-text strong { font-weight: 700; }
.progress-widget-when { color: var(--muted); }

.status-dot {
  width: 14px; height: 14px; border-radius: 50%; flex-shrink: 0; position: relative;
}
.status-dot::after {
  content: ""; position: absolute; inset: -5px; border-radius: 50%; opacity: 0.55;
  animation: pulse-ring 1.7s ease-out infinite;
}
.status-dot-red { background: var(--err); box-shadow: 0 0 10px rgba(248,113,113,0.6); }
.status-dot-red::after { background: var(--err); }
.status-dot-amber { background: #f5a623; box-shadow: 0 0 10px rgba(245,166,35,0.55); }
.status-dot-amber::after { background: #f5a623; animation-duration: 2.4s; }
.status-dot-green { background: var(--ok); box-shadow: 0 0 10px rgba(52,211,153,0.55); }
.status-dot-green::after { background: var(--ok); animation-duration: 3.2s; }
.status-dot-neutral { background: var(--muted); }
.status-dot-neutral::after { display: none; }
/* Faster, more insistent pulse for "this is happening right now" vs the
   base green's gentle "all set up, nothing urgent" pace - live and merely
   fully-ready both use green, but shouldn't feel identical. */
.status-dot-live::after { animation-duration: 1s; }

.live-tag {
  display: inline-block; background: var(--err); color: #fff; font-size: 10px; font-weight: 800;
  letter-spacing: 0.06em; padding: 2px 7px; border-radius: 5px; margin-right: 8px; vertical-align: 1px;
  animation: live-tag-flash 1.4s ease-in-out infinite;
}
@keyframes live-tag-flash {
  0%, 100% { opacity: 1; box-shadow: 0 0 0 0 rgba(248,113,113,0.6); }
  50% { opacity: 0.75; box-shadow: 0 0 0 4px rgba(248,113,113,0); }
}

/* Compact round rows on the player "/play" results page - a full .card
   per tournament (22px padding, two stacked full-width buttons) was tall
   and made status hard to spot; this is a single dense row with a bold
   color-coded status pill instead, so several rounds fit without
   scrolling and status reads at a glance. */
.player-round-list { display: flex; flex-direction: column; gap: 8px; }
.player-round-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 10px 14px; border-radius: 12px; border: 1px solid var(--border); background: var(--card);
  flex-wrap: wrap; border-left-width: 3px;
}
.player-round-row.live { border-left-color: var(--ok); }
.player-round-row.upcoming { border-left-color: var(--brand-gold); }
.player-round-row.completed { border-left-color: var(--border); opacity: 0.85; }
.player-round-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.player-round-title { font-weight: 700; font-size: 14px; display: flex; align-items: center; gap: 6px; }
.player-round-meta { font-size: 12px; color: var(--muted); }
.player-round-actions { display: flex; align-items: center; gap: 10px; flex-shrink: 0; flex-wrap: wrap; }
/* Compact rows still need real thumb targets - phone only, no laptop, on
   the day - so these are shorter than a full-size button but not below
   ~40px tall. */
.player-round-actions button { font-size: 13px; padding: 10px 14px; min-height: 40px; }
.player-round-status { font-size: 11px; font-weight: 800; letter-spacing: 0.04em; padding: 5px 10px; border-radius: 999px; text-transform: uppercase; }
.player-round-status.live { background: var(--err); color: #fff; animation: live-tag-flash 1.4s ease-in-out infinite; }
.player-round-status.upcoming { background: var(--brand-gold); color: #fff; }
.player-round-status.completed { background: var(--card-alt); color: var(--muted); border: 1px solid var(--border); }

/* Per-player "actually out on the course right now" status on the
   leaderboard - distinct from the generic amber "in progress" badge, which
   didn't distinguish someone mid-round from someone who just hasn't
   started yet. Same red/pulse language as the tournament-level LIVE NOW
   tag, just at badge scale. */
.badge.live { background: var(--err-bg); color: var(--err); border-color: rgba(248,113,113,0.3); }
.badge.live::before {
  content: ""; display: inline-block; width: 6px; height: 6px; border-radius: 50%; margin-right: 6px; vertical-align: 1px;
  background: var(--err); box-shadow: 0 0 6px rgba(248,113,113,0.7);
  animation: live-tag-flash 1.4s ease-in-out infinite;
}
/* Just the small dot from .badge.ok/.badge.err::before (design-system.css)
   pulled out on its own, for the Registrations table's "Live" (day-of
   Telegram check-in) column - a label pill was more than needed there,
   but the plain 14px .status-dot looked out of place; this matches the
   same dot already used everywhere else (badges), just without the text. */
.mini-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; }
.mini-dot.ok { background: var(--ok); box-shadow: 0 0 6px rgba(52,211,153,0.7); animation: live-tag-flash 1.4s ease-in-out infinite; }
.mini-dot.err { background: var(--err); box-shadow: 0 0 6px rgba(248,113,113,0.7); }

/* Registrations table's Flight/Status column - plain one-line text by
   default (no dropdown visible until you actually want to change
   something), same "click to reveal the edit form" pattern as flight
   cards' own "Edit flight" disclosure just above this table. */
.reg-edit-details summary { cursor: pointer; font-size: 13px; display: flex; align-items: center; gap: 8px; list-style: none; }
.reg-edit-details summary::-webkit-details-marker { display: none; }
.reg-edit-details summary svg { color: var(--muted); opacity: 0.7; }

.next-tag {
  display: inline-block; background: var(--brand-gold); color: #fff; font-size: 10px; font-weight: 800;
  letter-spacing: 0.06em; padding: 2px 7px; border-radius: 5px; margin-right: 8px; vertical-align: 1px;
}

/* Home's "Live now"/"Up next" widget cards (home.html) - plain, default
   card background like every other card on Home; the colored LIVE NOW /
   UPCOMING tag pill is the only thing carrying color here, so these
   cards don't compete visually with their own richer content (progress
   pipelines, leader tables, buttons). The live card gets a green border
   to match the flashing LIVE NOW tag - a quiet "this one's active" cue
   even before you read the tag itself. */
.live-card { border-color: var(--ok); }

/* Tournaments list page (tournaments.html) - a separate, bolder
   treatment: same solid-fill + white-text pattern as the "At a glance"
   tiles on Home (.stat-box.tint-green/.tint-gold), full-strength brand
   color rather than a pale wash, so live/upcoming genuinely pop as
   compact overview tiles. Kept as distinct classes (not .live-card/
   .next-card) so this doesn't bleed into Home's widget cards above,
   which have very different content and need the lighter wash instead. */
.tourn-live-card { border-color: var(--ok); background: var(--brand-green-bright); box-shadow: 0 0 0 1px var(--ok), 0 18px 40px -28px rgba(52,211,153,0.35); }
/* Upcoming stays a plain card - the gold UPCOMING tag pill is the only
   thing carrying color, same "tag does the talking" treatment as live
   gets a bold fill but upcoming doesn't need to compete for attention. */
/* --card-alt is nearly the same gray as the page's own --bg, so with
   opacity blending on top the card barely separated from the page at
   all. A solid, more saturated gray (color-mix from --muted, not a
   translucent overlay) actually reads as a distinct "archived" tile. */
.tourn-completed-card { background: color-mix(in srgb, var(--muted) 25%, var(--card)); border-color: var(--border); }

.tourn-live-card h2, .tourn-live-card h2 a, .tourn-live-card .sub { color: #fff; }
.tourn-live-card h2 svg { color: #fff; }
.tourn-live-card .sub strong { color: #fff; }
.tourn-next-tag {
  display: inline-block; background: var(--brand-gold); color: #fff; font-size: 10px; font-weight: 800;
  letter-spacing: 0.06em; padding: 2px 7px; border-radius: 5px; margin-right: 8px; vertical-align: 1px;
}
/* Higher specificity than .badge.format-net/.format-gross/.format-stableford
   (defined later in this file) so the solid white chip actually wins over
   the live card's own translucent rgba badge backgrounds - otherwise a
   same-specificity tie resolves by source order and the badge keeps its
   own faint wash sitting on top of the card's solid green fill. */
.card.tourn-live-card .badge { background: #fff; border-color: rgba(0,0,0,0.08); }
.card.tourn-live-card .badge.confirmed-badge { color: var(--ok); }

/* Stacked (not side-by-side) course/date facts on a tournament card - a
   real course name needs the card's full width to sit on one line
   instead of wrapping awkwardly in a half-width grid column. */
.tournament-card-facts { display: flex; flex-direction: column; gap: 8px; margin-bottom: 16px; }

@keyframes pulse-ring {
  0% { transform: scale(1); opacity: 0.55; }
  75% { transform: scale(2.4); opacity: 0; }
  100% { transform: scale(2.4); opacity: 0; }
}

.progress-widget-bar { width: 140px; height: 8px; border-radius: 6px; background: var(--card-alt); overflow: hidden; flex-shrink: 0; }
.progress-widget-fill { display: block; height: 100%; border-radius: 6px; transition: width 0.5s ease; }
.progress-widget-fill.fill-red { background: var(--err); }
.progress-widget-fill.fill-amber { background: #f5a623; }
.progress-widget-fill.fill-green { background: var(--ok); }

.new-tournament-columns { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; align-items: start; }
@media (max-width: 640px) {
  .new-tournament-columns { grid-template-columns: 1fr; }
}

/* =========================================================================
   Tournament creation calendar - a fully visible month grid (not hidden
   behind a native date-input popup) with large tap targets, so picking or
   re-picking a date never requires leaving this page.
   ========================================================================= */
.tournament-calendar { background: var(--card-alt); border: 1px solid var(--border); border-radius: 14px; padding: 14px; }
.calendar-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
.calendar-label { font-weight: 700; font-size: 14px; }
.calendar-header button {
  width: 32px; height: 32px; border-radius: 9px; font-size: 16px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
}
.calendar-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; }
.calendar-weekday { text-align: center; font-size: 10px; color: var(--muted); font-weight: 700; padding: 2px 0 6px; }
.calendar-day {
  aspect-ratio: 1; min-height: 32px; border-radius: 8px; border: 1px solid transparent;
  background: var(--card); color: var(--text); font-size: 13px; font-weight: 600; cursor: pointer;
}
.calendar-day:hover:not(.past) { border-color: var(--brand-green-bright); }
.calendar-day.today { border-color: var(--brand-gold); color: var(--brand-gold-text); }
.calendar-day.selected { background: var(--brand-green-bright); border-color: var(--brand-green-bright); color: #fff; }
.calendar-day.past { opacity: 0.35; cursor: not-allowed; pointer-events: none; }

/* Collapsed one-line state once a date is picked - the full grid is only
   needed at the moment of choosing, not permanently taking up half the
   form afterward. Click it to reopen the grid and change the date. */
.calendar-summary {
  display: flex; align-items: center; justify-content: space-between; gap: 10px; width: 100%;
  padding: 12px 14px; border-radius: 10px; border: 1px solid var(--border); background: var(--card);
  font: inherit; font-weight: 700; font-size: 14px; color: var(--text); cursor: pointer; text-align: left;
}
.calendar-summary:hover { border-color: var(--brand-green-bright); }
.calendar-summary-change {
  display: inline-flex; align-items: center; gap: 4px; font-size: 12px; font-weight: 600;
  color: var(--brand-green-bright); flex-shrink: 0;
}

/* Availability-confirm step, revealed once both a date and course are
   picked - the actual "call the pro shop" moment made explicit rather
   than hidden inside a generic form field. */
.confirm-availability-step {
  display: none; margin-top: 14px; padding: 16px; border-radius: 12px;
  background: var(--brand-gold-bg); border: 1px solid rgba(var(--brand-gold-rgb), 0.4);
}
.confirm-availability-step.visible { display: block; }
.confirm-availability-step label { display: flex; align-items: center; gap: 10px; font-weight: 600; font-size: 14px; cursor: pointer; }
.confirm-availability-step input[type="checkbox"] { width: 20px; height: 20px; flex-shrink: 0; }

/* Prev/next hole nav on the scorer entry page - three slots (prev button,
   optional "back to review" link, next button), spaced apart so it reads
   left/center/right even when the middle slot is empty. */
.hole-nav { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 10px; margin-bottom: 14px; }
.hole-nav > a > button { font-size: 14px; padding: 11px 16px; min-height: 44px; }
.hole-nav-review-link { display: inline-flex; align-items: center; gap: 5px; font-size: 13px; font-weight: 600; padding: 11px 6px; min-height: 44px; }

/* Golfer-facing pages (scoring entry, status) are used entirely on a phone
   on the day - no laptop, no mouse - so every tappable element here
   targets a real thumb, not a cursor: ~44px minimum height (Apple/Material
   guidance) and generous gaps between adjacent buttons so a mis-tap
   doesn't hit the wrong one. */
.back-link { display: inline-flex; align-items: center; gap: 4px; font-size: 13px; font-weight: 600; margin-bottom: 8px; padding: 6px 0; }
.back-link svg { transform: scaleX(-1); }

/* Row of pills on the scorer entry page - one per golfer/team in the
   flight - jumping straight to their own status page, mirroring the
   "Switch to scorecard" button status.html has going the other way. */
.switch-status-row { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.switch-status-row button { font-size: 13px; padding: 10px 14px; min-height: 40px; }

/* Pace-of-play chip on the scorer entry page - was plain small gray text,
   easy to miss next to everything else in the page intro. A solid colored
   chip (same ok/warn hues used everywhere else for "good"/"needs
   attention") with a bold headline number reads at a glance instead. */
.pace-chip {
  display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 10px;
  padding: 8px 14px; border-radius: 10px; font-size: 13px; border: 1px solid transparent;
}
.pace-chip.ahead { background: var(--ok-bg); color: var(--ok); border-color: rgba(52,211,153,0.35); }
.pace-chip.behind { background: rgba(251,191,36,0.16); color: var(--warn-text); border-color: rgba(251,191,36,0.4); }
.pace-chip strong { font-weight: 800; }
.pace-chip-detail { font-size: 12px; opacity: 0.85; font-weight: 500; }

/* Admin notification banner - the very first thing on the golfer-facing
   scoring/status pages, so a course-closure/weather/schedule message
   can't be missed. Solid gold "announcement" color, deliberately distinct
   from the red pulse used for live-scoring elements elsewhere, so the two
   kinds of "urgent" don't read as the same thing. */
.notice-banner {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  background: var(--brand-gold); color: #fff; padding: 12px 16px; border-radius: 10px;
  margin-bottom: 10px; font-size: 14px;
  animation: notice-flash 2s ease-in-out infinite;
}
.notice-banner strong { flex: 1 1 auto; min-width: 0; }
.notice-time { font-size: 11px; opacity: 0.85; white-space: nowrap; }
@keyframes notice-flash {
  0%, 100% { box-shadow: 0 0 0 0 rgba(var(--brand-gold-rgb), 0.55); }
  50% { box-shadow: 0 0 0 7px rgba(var(--brand-gold-rgb), 0); }
}
.notice-more { margin-bottom: 16px; }
.notice-more summary { font-size: 12px; color: var(--muted); cursor: pointer; }

/* Live ranking chip on the golfer status page - the .live-tag pill already
   reads as "this is updating in real time" everywhere else in the app, so
   reusing it here (rather than inventing a new "live" visual) ties this
   number to the same live-scoring language instead of just being another
   stat tile. Neutral background - the rank itself isn't inherently
   good/bad the way pace ahead/behind is, so no ok/warn color needed. */
.live-rank-chip {
  display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 10px;
  padding: 8px 14px; border-radius: 10px; font-size: 14px;
  background: var(--card-alt); border: 1px solid var(--border);
}
.live-rank-chip strong { font-weight: 800; }

/* Scorecard table (status.html) - hole numbers and stroke counts are both
   just plain digits in a grid, previously styled identically so it was
   hard to tell which row was which at a glance. Muted/small for the hole
   number header, bold/larger for the actual strokes, plus a leading
   row-label column naming each row explicitly. */
.scorecard-table th { font-size: 11px; font-weight: 700; color: var(--muted); text-align: center; padding: 6px 8px; }
.scorecard-table td { font-size: 16px; font-weight: 700; color: var(--text); text-align: center; padding: 8px; }
.scorecard-table .scorecard-row-label { font-size: 11px; font-weight: 600; color: var(--muted); text-align: left; white-space: nowrap; padding-right: 12px; }
.scorecard-table td.scorecard-row-label { font-size: 12px; }

/* =========================================================================
   Scoring format picker (New Tournament page) - single-select cards
   instead of a dropdown, so all the formats are visible and comparable at
   once with a one-line preview each, rather than hidden behind a click.
   Native radios drive the selected state via :has() - no JS needed, same
   "prefer native controls" approach as the <details> disclosures elsewhere.
   ========================================================================= */
.format-picker-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 12px; margin-top: 10px; }
.format-card { display: block; cursor: pointer; }
.format-card input[type="radio"] { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; opacity: 0; }
.format-card-body {
  position: relative; display: flex; flex-direction: column; gap: 5px;
  padding: 16px; border-radius: 12px; border: 1px solid var(--border); background: var(--card-alt);
  transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease, background 0.15s ease;
  height: 100%;
}
.format-card:hover .format-card-body { transform: translateY(-2px); border-color: var(--brand-green-bright); box-shadow: 0 12px 24px -16px rgba(0,0,0,0.4); }
.format-card input:focus-visible ~ .format-card-body { outline: 2px solid var(--brand-green-bright); outline-offset: 2px; }
.format-card:has(input:checked) .format-card-body {
  border-color: var(--brand-green-bright);
  background: color-mix(in srgb, var(--brand-green-bright) 12%, var(--card-alt));
  box-shadow: 0 0 0 2px var(--brand-green-bright), 0 16px 30px -18px rgba(var(--brand-green-bright-rgb), 0.45);
}
.format-card-icon { color: var(--brand-green-bright); }
.format-card-name { font-weight: 700; font-size: 14px; }
.format-card-desc { font-size: 12px; color: var(--muted); line-height: 1.4; }
.format-card-check {
  position: absolute; top: 12px; right: 12px; color: var(--brand-green-bright);
  opacity: 0; transform: scale(0.4); transition: opacity 0.15s ease, transform 0.15s ease;
}
.format-card:has(input:checked) .format-card-check { opacity: 1; transform: scale(1); }

/* Bold, unmissable primary CTA - a plain bordered button undersold "this
   is the one action that finishes the flow", especially now it sits below
   a whole grid of format cards. Solid fill + depth + a hover "shine" sweep
   for a bit of the game-like polish already used elsewhere (format badges,
   live-tag flash). */
button.btn-cta {
  display: block; width: 100%; margin-top: 22px; padding: 16px; font-size: 16px; font-weight: 800;
  border-radius: 12px; border: 1px solid var(--brand-green-bright);
  background: var(--brand-green-bright); color: #fff;
  box-shadow: 0 1px 0 rgba(255,255,255,0.18) inset, 0 16px 32px -18px rgba(var(--brand-green-bright-rgb), 0.6);
  position: relative; overflow: hidden;
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
button.btn-cta:hover:not(:disabled) {
  transform: translateY(-2px); border-color: var(--brand-green-bright); color: #fff;
  box-shadow: 0 1px 0 rgba(255,255,255,0.22) inset, 0 22px 40px -18px rgba(var(--brand-green-bright-rgb), 0.7);
}
button.btn-cta::after {
  content: ""; position: absolute; top: 0; left: -60%; width: 40%; height: 100%;
  background: linear-gradient(120deg, transparent, rgba(255,255,255,0.35), transparent);
  transform: skewX(-20deg); transition: left 0.5s ease;
}
button.btn-cta:hover::after { left: 130%; }

/* =========================================================================
   Confetti burst (see static/js/confetti.js)
   ========================================================================= */
.confetti-layer { position: absolute; width: 0; height: 0; pointer-events: none; z-index: 999; }
.confetti-piece {
  position: absolute; width: 8px; height: 8px; border-radius: 2px;
  animation: confetti-fall 1.4s ease-out forwards;
}
@keyframes confetti-fall {
  0% { transform: translate(0, 0) rotate(0deg); opacity: 1; }
  100% { transform: translate(var(--dx), 160px) rotate(var(--dr)); opacity: 0; }
}

/* =========================================================================
   Richer, more colorful stat tiles for the Home dashboard - flat neutral
   boxes read as "too light"/lifeless; each stat now gets its own accent
   wash so the dashboard reads as lively rather than a spreadsheet.
   ========================================================================= */
/* Solid brand-colour fills (not a translucent rgba wash over the card
   background) so these read as genuinely colourful tiles rather than a
   faint tint - white text throughout for contrast, same approach as the
   solid-colour LIVE NOW / UPCOMING tags elsewhere in the app. Restrained
   to the brand's own colors (green/navy/gold) plus red specifically for
   "this is live/urgent" - not an arbitrary rainbow with no meaning. */
.stat-box.tint-green { background: var(--brand-green-bright); border-color: var(--brand-green-bright); }
.stat-box.tint-gold { background: var(--brand-gold); border-color: var(--brand-gold); }
.stat-box.tint-navy { background: var(--brand-navy); border-color: var(--brand-navy); }
.stat-box.tint-red { background: var(--err); border-color: var(--err); }
.stat-box.tint-green .stat-value, .stat-box.tint-gold .stat-value,
.stat-box.tint-navy .stat-value, .stat-box.tint-red .stat-value { color: #fff; }
.stat-box.tint-green .stat-value-sub, .stat-box.tint-gold .stat-value-sub,
.stat-box.tint-navy .stat-value-sub, .stat-box.tint-red .stat-value-sub { color: rgba(255,255,255,0.8); }

/* Icon inherits white too, on the same solid fill. */
.stat-box.tint-green .stat-label svg, .stat-box.tint-gold .stat-label svg,
.stat-box.tint-navy .stat-label svg, .stat-box.tint-red .stat-label svg { color: rgba(255,255,255,0.85); }
.stat-box.tint-green .stat-label, .stat-box.tint-gold .stat-label,
.stat-box.tint-navy .stat-label, .stat-box.tint-red .stat-label { color: rgba(255,255,255,0.85); opacity: 1; }

/* Deliberately toned down (not another solid brand fill) - "completed"
   is archived/inactive, next to three bright "currently relevant" tiles,
   so it reads as calm rather than competing for the same attention. */
.stat-box-muted { border-left: 3px solid var(--border); }

/* The golfer credited with a course record - there's no golfer profile
   page yet to link to, so this is a strong visual highlight (full-opacity
   white, bold, small pill) rather than a link that would go nowhere. */
.stat-credit {
  display: inline-flex; align-items: center; gap: 4px; margin-top: 4px;
  padding: 2px 8px; border-radius: 999px; font-weight: 700; color: #fff !important;
  background: rgba(255,255,255,0.18);
}

/* =========================================================================
   Flow pipeline - connected-node visual for the tournament setup
   checklist (course -> flights -> golfers -> live scoring), icons joined
   by an animated flowing dashed line instead of a plain checklist row.
   ========================================================================= */
.flow-pipeline { display: flex; align-items: flex-start; overflow-x: auto; padding: 4px 2px; }
/* Sized to fit a half-width dashboard card (~320-380px content) without
   horizontal clipping - the pipeline used to only ever live in full-width
   cards, so 78px nodes had room to breathe; narrower columns need it
   tighter. Still scrolls (overflow-x: auto) if a card is narrower still. */
.flow-node { display: flex; flex-direction: column; align-items: center; gap: 6px; flex-shrink: 0; width: 60px; }
/* Round-progress pipeline nodes are real links (jump to Flights/Leaderboard
   on the tournament page) - undo the global <a> green + underline and add
   a hover cue instead, so it reads as clickable without looking like a
   normal text link. */
.flow-node-link { text-decoration: none; color: inherit; transition: transform 0.15s ease; }
.flow-node-link:hover, .flow-node-link:visited { color: inherit; }
.flow-node-link:hover { transform: translateY(-2px); }
.flow-node-link:hover .flow-icon { border-color: var(--brand-green-bright); }
.flow-node-link:hover .flow-label { color: var(--brand-green-bright); }
.flow-icon {
  position: relative; width: 38px; height: 38px; border-radius: 50%;
  background: var(--card-alt); border: 1px solid var(--border);
  display: flex; align-items: center; justify-content: center; color: var(--muted);
}
.flow-label { font-size: 9px; font-weight: 700; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; text-align: center; }

.flow-status-dot {
  position: absolute; top: -2px; right: -2px; width: 12px; height: 12px; border-radius: 50%;
  border: 2px solid var(--card); background: var(--muted);
}
.flow-status-dot.dot-pending { background: var(--border); }
.flow-status-dot.dot-done { background: var(--ok); box-shadow: 0 0 6px rgba(52,211,153,0.7); }
.flow-status-dot.dot-live {
  background: var(--brand-green-bright); box-shadow: 0 0 8px rgba(var(--brand-green-bright-rgb), 0.8);
  animation: pulse-scale 1.3s ease-in-out infinite;
}
@keyframes pulse-scale {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.3); }
}

.flow-line {
  flex: 1 1 auto; height: 2px; min-width: 14px; margin-top: 19px;
  background-image: linear-gradient(90deg, var(--border) 50%, transparent 50%);
  background-size: 8px 2px; background-repeat: repeat-x;
}
.flow-line.flowing {
  background-image: linear-gradient(90deg, var(--brand-green-bright) 50%, transparent 50%);
  animation: flow-move 0.7s linear infinite;
}
@keyframes flow-move {
  from { background-position: 0 0; }
  to { background-position: -8px 0; }
}

/* "Live · HH:MM:SS" badge above the leaderboard while a tournament is
   actually in progress - the leaderboard really is live (WebSocket +
   Redis pub/sub), this just makes that visible the way it should be. */
.live-badge {
  display: inline-flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 700;
  padding: 5px 12px; border-radius: 999px; background: var(--accent-bg); color: var(--brand-green-bright);
  border: 1px solid rgba(var(--brand-green-bright-rgb), 0.35); margin-bottom: 12px;
}
.live-badge .flow-status-dot { position: static; border: none; width: 8px; height: 8px; }

/* =========================================================================
   Tables - design-system.css only sets width/border-collapse/font-size,
   leaving cells with browser-default (near-zero) padding and left-aligned
   numbers, so rows look cramped and numeric columns don't line up for
   scanning. Add real cell rhythm, a distinct header row, and a `.num`
   utility for right-aligning numeric columns (Thru/Gross/Net/Handicap).
   ========================================================================= */
table thead th {
  text-align: left; font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.05em; color: var(--muted); padding: 8px 12px; white-space: nowrap;
  border-bottom: 2px solid var(--border);
}
table tbody td { padding: 10px 12px; border-bottom: 1px solid var(--border-soft); vertical-align: middle; }
table tbody tr:last-child td { border-bottom: none; }
table tbody tr:hover td { background: var(--card-alt); }
table th.num, table td.num { text-align: right; font-variant-numeric: tabular-nums; }

/* =========================================================================
   Collapsible whole sections (Flights, Registrations, Prize awards) - same
   visual weight as .section-label but doubles as a <summary> toggle, so an
   admin can collapse sections they don't need right now instead of the
   tournament page always showing every list at full length. A small count
   badge keeps the collapsed state informative at a glance.
   ========================================================================= */
details.section-toggle { margin: 32px 0 20px; }
details.section-toggle:first-of-type { margin-top: 0; }
details.section-toggle > summary {
  font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--muted); padding-bottom: 8px; border-bottom: 1px solid var(--border-soft);
  display: flex; align-items: center; gap: 8px; cursor: pointer; list-style: none; user-select: none;
}
details.section-toggle > summary::-webkit-details-marker { display: none; }
details.section-toggle > summary::after {
  content: "▾"; margin-left: auto; color: var(--muted); font-size: 11px; transition: transform 0.15s ease;
}
details.section-toggle[open] > summary::after { transform: rotate(180deg); }
details.section-toggle > summary:hover { color: var(--brand-green-bright); }
details.section-toggle > summary .count-badge {
  font-size: 10px; font-weight: 700; color: var(--muted); background: var(--card-alt);
  border: 1px solid var(--border-soft); border-radius: 999px; padding: 1px 8px;
  text-transform: none; letter-spacing: normal;
}
details.section-toggle > .section-grid { margin-top: 20px; margin-bottom: 0; }

/* =========================================================================
   Home "At a glance" stats - a fixed 2x2 grid sized to sit in one half of
   a two-column row next to the Live Now card, instead of a full-width row
   of four tiles. Reuses the existing .stat-box tint classes.
   ========================================================================= */
.stat-grid-2x2 { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }

/* Layered shadow + hover lift so the tiles read as raised/tactile instead
   of flat bordered boxes - the "plain" look was two solid colors and
   nothing else. */
.stat-box-3d {
  box-shadow: 0 1px 0 rgba(255,255,255,0.05) inset, 0 8px 16px -12px rgba(0,0,0,0.55);
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.stat-box-3d:hover {
  transform: translateY(-3px);
  box-shadow: 0 1px 0 rgba(255,255,255,0.06) inset, 0 14px 24px -14px rgba(0,0,0,0.6);
}
html[data-theme="light"] .stat-box-3d {
  box-shadow: 0 1px 0 rgba(255,255,255,0.6) inset, 0 6px 14px -10px rgba(20,49,92,0.22);
}
html[data-theme="light"] .stat-box-3d:hover {
  box-shadow: 0 1px 0 rgba(255,255,255,0.7) inset, 0 12px 20px -12px rgba(20,49,92,0.28);
}

/* At-a-glance tiles are real links (Courses/Golfers/Tournaments) - undo
   the global <a> green + underline so a linked tile looks identical to a
   plain one, with just the existing hover lift as the clickability cue. */
a.stat-box { display: block; text-decoration: none; color: inherit; cursor: pointer; }
a.stat-box:visited { color: inherit; }

/* =========================================================================
   Smart tip - a rule-based "insight" fed entirely by data already in the
   DB (setup gaps, ratings, booking history) - no external API call, every
   message traces to a concrete DB fact. Pinned as a corner overlay on its
   host card (which must be position:relative - every .card already is)
   instead of taking its own row, so it doesn't interrupt a grid of
   content tiles below it. Click the mascot to expand a bubble with the
   message - same collapsed-avatar-that-expands pattern as tessfox's
   fox-rec mascot.
   ========================================================================= */
/* display:flex + row-reverse (not a nested position:absolute bubble) is
   the load-bearing part here - the trigger sits at the flex-end (visually
   the right) and the bubble grows from 0 as a normal flex sibling to its
   left. A nested absolutely-positioned bubble would take its containing
   block from this overlay's own auto width (~34px, just the trigger),
   which caps shrink-to-fit sizing to near-nothing - this is why tessfox's
   fox-rec uses the same flex-row structure instead. */
.smart-tip-overlay {
  position: absolute; top: 16px; right: 20px; z-index: 6;
  display: flex; flex-direction: row-reverse; align-items: flex-start; gap: 8px;
}
.smart-tip-trigger {
  position: relative; width: 34px; height: 34px; padding: 0; flex-shrink: 0;
  display: block; background: none; border: none; cursor: pointer;
  animation: smart-tip-bob 3s ease-in-out infinite; transition: transform 0.15s ease;
}
.smart-tip-trigger:hover { transform: scale(1.08); }
.smart-tip-overlay.expanded .smart-tip-trigger { animation-play-state: paused; transform: scale(1.08); }
/* Low-poly geometric golf ball mascot - faceted triangles (light-to-dark
   across two Claude-orange tones) fake a 3D sphere without any raster
   art; a few facets glow/pulse via drop-shadow, same "cybernetic" accent
   language as the fox's HUD visor. */
.smart-tip-ball { width: 100%; height: 100%; overflow: visible; display: block; pointer-events: none; }
.smart-tip-ball-glow { filter: drop-shadow(0 0 3px #ffb088); animation: smart-tip-glow-pulse 2.4s ease-in-out infinite; }
@keyframes smart-tip-glow-pulse {
  0%, 100% { opacity: 0.8; }
  50% { opacity: 1; filter: drop-shadow(0 0 5px #ffb088); }
}
@keyframes smart-tip-bob {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-3px); }
}
.smart-tip-icon-badge {
  position: absolute; top: -4px; right: -6px; width: 15px; height: 15px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center; pointer-events: none;
  background: #d97757; color: #fff; font-size: 10px; font-weight: 800; line-height: 1;
  border: 2px solid var(--card); animation: smart-tip-badge-pulse 1.6s ease-in-out infinite;
}
@keyframes smart-tip-badge-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(217,119,87,0.7); }
  50% { box-shadow: 0 0 0 5px rgba(217,119,87,0); }
}
.smart-tip-overlay.expanded .smart-tip-icon-badge { display: none; }

/* Collapsed to just the avatar by default - expands into a bubble
   alongside it on click instead of always taking up space. */
.smart-tip-bubble {
  max-width: 0; opacity: 0; overflow: hidden; white-space: nowrap; pointer-events: none;
  margin-top: 3px; border-radius: 12px; font-size: 12.5px; line-height: 1.5; color: var(--text);
  background: var(--card); border: 1px solid var(--border-soft);
  box-shadow: 0 12px 30px -14px rgba(0,0,0,0.5);
  transition: max-width 0.25s ease, opacity 0.2s ease, padding 0.25s ease;
}
.smart-tip-overlay.expanded .smart-tip-bubble {
  max-width: 300px; opacity: 1; white-space: normal; padding: 12px 14px; pointer-events: auto;
}
.smart-tip-label { font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); margin-bottom: 3px; }
.smart-tip-bubble p { font-size: 13px; margin: 0; line-height: 1.5; }
.smart-tip-cta { display: inline-flex; align-items: center; gap: 2px; margin-top: 6px; font-size: 12px; font-weight: 700; }

.smart-tip-overlay.tone-warn .smart-tip-bubble { border-color: rgba(251,191,36,0.4); }
.smart-tip-overlay.tone-gold .smart-tip-bubble { border-color: rgba(var(--brand-gold-rgb), 0.4); }
.smart-tip-overlay.tone-info .smart-tip-bubble { border-color: rgba(var(--brand-navy-rgb), 0.4); }

/* Inline placement - a normal flex child at the end of an intro-style row
   (.page-intro-row, .course-hero-row) instead of pinned absolute to a
   card corner; the row's own flex layout puts it on the right, so no
   top/right offsets are needed here. The bubble still has to come out of
   normal flow (position:absolute) even in this variant - letting it grow
   as a real flex sibling would widen/wrap the whole intro row while it
   animates open. Uses an explicit width (not max-width) since this
   overlay's own box is only as wide as the trigger icon, and shrink-to-fit
   sizing is bounded by that narrow containing block. */
.smart-tip-overlay.inline { position: relative; top: auto; right: auto; flex-shrink: 0; }
.smart-tip-overlay.inline .smart-tip-bubble {
  position: absolute; top: 100%; right: 0; margin-top: 8px; z-index: 20;
  max-width: none; width: 0;
  transition: width 0.25s ease, opacity 0.2s ease, padding 0.25s ease;
}
.smart-tip-overlay.inline.expanded .smart-tip-bubble { width: 280px; }

/* .card is display:flex/flex-direction:column, so sibling <span class="badge">
   elements placed directly in a card (not wrapped in a row) stack one per
   line instead of sitting side by side - wasteful on cards with several
   badges (tournament list). */
.badge-row { display: flex; flex-wrap: wrap; gap: 6px; margin-top: auto; padding-top: 10px; }

/* Scoring format badges - each format gets its own brand colour + icon
   instead of one flat gray pill, with a touch of depth (inset highlight +
   drop shadow) and a hover lift so they feel tactile, not flat text. */
.badge.format-net, .badge.format-gross, .badge.format-stableford {
  box-shadow: 0 1px 0 rgba(255,255,255,0.12) inset, 0 3px 8px -4px rgba(0,0,0,0.5);
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.badge.format-net:hover, .badge.format-gross:hover, .badge.format-stableford:hover {
  transform: translateY(-1px);
  box-shadow: 0 1px 0 rgba(255,255,255,0.14) inset, 0 6px 12px -5px rgba(0,0,0,0.55);
}
.badge.format-net { background: rgba(var(--brand-navy-rgb), 0.18); color: var(--brand-navy); border-color: rgba(var(--brand-navy-rgb), 0.4); }
html[data-theme="dark"] .badge.format-net { color: #7ea3d6; }
.badge.format-gross { background: rgba(var(--brand-green-bright-rgb), 0.18); color: var(--brand-green-bright); border-color: rgba(var(--brand-green-bright-rgb), 0.4); }
.badge.format-stableford { background: var(--brand-gold-bg); color: var(--brand-gold-text); border-color: rgba(var(--brand-gold-rgb), 0.4); }

/* Prize category badges (Prizes page + tournament "Prize awards" section) -
   category is free text an admin types in, not a fixed enum, so colors are
   assigned by cycling through these 4 tones based on a stable hash of the
   category string (see category_tone() in templating.py) rather than a
   category list to maintain. Same restrained brand hues as everywhere
   else, just distributed so different categories are actually
   distinguishable at a glance instead of one flat gold for all of them. */
.badge.prize-gold { background: var(--brand-gold-bg); color: var(--brand-gold-text); border-color: rgba(var(--brand-gold-rgb), 0.4); }
.badge.prize-green { background: rgba(var(--brand-green-bright-rgb), 0.18); color: var(--brand-green-bright); border-color: rgba(var(--brand-green-bright-rgb), 0.4); }
.badge.prize-navy { background: rgba(var(--brand-navy-rgb), 0.18); color: var(--brand-navy); border-color: rgba(var(--brand-navy-rgb), 0.4); }
html[data-theme="dark"] .badge.prize-navy { color: #7ea3d6; }
.badge.prize-red { background: var(--err-bg); color: var(--err); border-color: rgba(248,113,113,0.35); }

/* Lighter outline (not another solid fill) so it never gets mistaken for
   the bolder format badge next to it, even when both happen to be green
   (stroke gross + confirmed availability, on an upcoming tournament). */
.badge.confirmed-badge { background: transparent; color: var(--ok); border-color: rgba(52,211,153,0.45); }

/* Mini leaderboard preview embedded in the Home "Live now" card - so the
   current leader is visible without navigating into the tournament page. */
table.leader-preview { margin-top: 12px; }
table.leader-preview thead th { padding: 6px 10px; }
table.leader-preview tbody td { padding: 7px 10px; }
