:root {
  --bg: #0b1020;
  --fg: #f2f5ff;
  --fg-secondary: #c8d0e7;
  --muted: #9aa3c7;
  --accent: #e94f37;
  --accent-2: #4fc3f7;
  --card: rgba(15, 22, 48, 0.88);
  --border: rgba(255, 255, 255, 0.1);
}

* { box-sizing: border-box; }

a, button, [role="button"] { touch-action: manipulation; }

.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;
}

:focus-visible {
  outline: 2px solid var(--accent-2);
  outline-offset: 2px;
}

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  background: var(--bg);
  color: var(--fg);
  min-height: 100vh;
}

header {
  padding: 1rem 1.25rem;
  border-bottom: 1px solid var(--border);
  display: flex;
  justify-content: space-between;
  align-items: center;
}

header h1 { margin: 0; font-size: 1.3rem; }

main {
  padding: 1.25rem max(1.25rem, env(safe-area-inset-right, 1.25rem)) 1.25rem max(1.25rem, env(safe-area-inset-left, 1.25rem));
  max-width: 520px;
  margin: 0 auto;
}

/* Desktop main widths.
 *
 * Both `main` (default, 520px mobile) and `.page-main` (720px mobile)
 * stay at their mobile widths up to ≤899px so the existing phone /
 * small-tablet layouts are untouched. At ≥900px both relax to a
 * single comfortable desktop width so grid-heavy surfaces (hunts
 * browse, pricing cards, profile, leaderboard, collection, state)
 * can breathe instead of stacking inside a 520-720px column on a
 * full-width laptop. Custom main classes — .album-main, .board-main,
 * .admin-*-main, .tracker page — keep their own bespoke widths, and
 * inline `style="max-width:NNNpx"` on narrow forms (login,
 * reset-password) still wins via specificity. */
@media (min-width: 900px) {
  main { max-width: 1080px; }
  .page-main { max-width: 1080px; }
}

.tabs {
  display: flex;
  gap: 0.5rem;
  margin-bottom: 1rem;
}
.tab {
  background: transparent;
  color: var(--muted);
  border: 1px solid var(--border);
  padding: 0.5rem 1rem;
  border-radius: 6px;
  cursor: pointer;
}
.tab.active {
  color: var(--fg);
  border-color: var(--accent);
}
.tab-panel { display: none; flex-direction: column; gap: 0.75rem; }
.tab-panel.active { display: flex; }

label {
  display: flex;
  flex-direction: column;
  font-size: 0.9rem;
  color: var(--muted);
  gap: 0.25rem;
}
input {
  padding: 0.6rem 0.75rem;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.04);
  color: var(--fg);
  font-size: 1rem;
}
input:not([type="checkbox"]):not([type="radio"]) {
  min-height: 2.75rem;
}

button, .btn {
  padding: 0.7rem 1rem;
  border-radius: 6px;
  border: none;
  background: var(--accent);
  color: white;
  font-weight: 600;
  font-size: 1rem;
  cursor: pointer;
  text-decoration: none;
  display: inline-block;
  min-height: 2.75rem;
}
/* `button { display: inline-block }` above OVERRIDES the UA
   `[hidden] { display: none }` rule, so `<button hidden>` would still
   render as an empty pill. This bit us on hunt-detail.html where the
   legacy `#buy-hunt-btn` / `#buy-bundle-btn` (kept in the DOM for
   post-purchase polling stability) showed up as two unlabeled orange
   + outlined swatches below the Start hunt button. The `!important`
   matches the pattern used elsewhere in this file (search for
   `[hidden] { display: none !important; }`). */
button[hidden], .btn[hidden] { display: none !important; }
button:disabled { opacity: 0.5; cursor: not-allowed; }

.error { color: #ff7070; min-height: 1.2em; margin: 0; font-size: 0.9rem; }

.hunt-cover {
  width: 100%;
  height: 140px;
  object-fit: cover;
  border-radius: 7px 7px 0 0;
  margin: -1rem -1rem 0.75rem;
  width: calc(100% + 2rem);
  display: block;
}
.start-over-link {
  background: none;
  border: none;
  color: var(--muted);
  font-size: 0.8rem;
  cursor: pointer;
  padding: 0;
  text-decoration: underline;
  text-decoration-style: dotted;
}
.start-over-link:hover,
.start-over-link:focus-visible { color: var(--fg); }

/* Skip-to-content: off-screen until focused, so keyboard users can
   bypass the nav bar (especially the inline desktop bar at ≥900px). */
.skip-to-content {
  position: absolute;
  left: -9999px;
  top: auto;
  z-index: 1001;
  padding: 0.5rem 1rem;
  background: var(--accent);
  color: var(--bg);
  font-weight: 600;
  font-size: 0.9rem;
  text-decoration: none;
  border-radius: 0 0 6px 6px;
  white-space: nowrap;
}
.skip-to-content:focus-visible {
  left: 1rem;
  top: env(safe-area-inset-top, 0);
}
@supports not selector(:focus-visible) {
  .skip-to-content:focus {
    left: 1rem;
    top: env(safe-area-inset-top, 0);
  }
}
main:focus:not(:focus-visible) { outline: none; }

/* ---------- Site nav ---------- */
.site-nav {
  background: rgba(10, 15, 35, 0.95);
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 0;
  z-index: 100;
  backdrop-filter: blur(8px);
  /* When saved as a standalone PWA on iOS, the status bar (time, signal,
     battery) overlaps position:sticky content at top:0. Pad the nav so
     the hamburger menu and brand text sit below the notch / status bar. */
  padding-top: env(safe-area-inset-top, 0);
}
.site-nav-inner {
  max-width: 1100px;
  margin: 0 auto;
  padding: 0.6rem 1rem;
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
}
.site-nav-brand {
  font-weight: 700;
  color: var(--fg);
  text-decoration: none;
  font-size: 1.05rem;
  letter-spacing: -0.01em;
}
/* Hamburger toggle in the top bar */
.site-nav-toggle {
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 6px;
  width: 44px;
  height: 44px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.site-nav-toggle:hover { border-color: var(--accent-2); }
.site-nav-toggle:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 2px; }
.site-nav-bars,
.site-nav-bars::before,
.site-nav-bars::after {
  display: block;
  width: 18px;
  height: 2px;
  background: var(--fg);
  border-radius: 2px;
  content: "";
  position: relative;
}
.site-nav-bars::before { position: absolute; top: -6px; left: 0; }
.site-nav-bars::after  { position: absolute; top:  6px; left: 0; }

/* Drawer — off-canvas panel + scrim. Sits above every sticky/fixed
   element on the page so the open drawer never looks like it's
   layering under the top nav or leaking page content through. */
.site-drawer {
  position: fixed;
  inset: 0;
  z-index: 1000;
}
.site-drawer[hidden] { display: none; }
.site-drawer-scrim {
  position: absolute;
  inset: 0;
  /* Fully opaque by design. The structural body.drawer-open rule below
     is the backstop that hides page content even if this alpha is ever
     lowered, so leaking content through a translucent scrim is no
     longer a regression risk — but a fully opaque scrim is still the
     intended visual: the drawer is a navigation modal, not a frosted
     overlay. Don't lower this without a deliberate UX decision. */
  background: rgba(0, 0, 0, 1);
  opacity: 0;
  transition: opacity 200ms ease;
}
/* Stop the body from scrolling while the drawer is open. Toggled by JS.
   Belt-and-suspenders: hide every top-level body child except the nav
   (which contains the drawer itself) and the toast container, so any
   fixed-position UI rendered by page scripts (camera overlays,
   completed-hunt modals, etc.) can't leak through. This is structural
   rather than per-element so a new page can't regress the overlay by
   forgetting to wrap content in <main>. */
body.drawer-open { overflow: hidden; }
body.drawer-open > *:not(#site-nav):not(.toast-container) {
  visibility: hidden;
}
body.camera-open { overflow: hidden; }
/* Scoped to admin pages only: hide admin chrome until /api/auth/me
   resolves so admin-only content never flashes for a non-admin. NOT
   applied site-wide — gating all of <main> caused a ~20s blank home
   screen on cold starts (see tests/test_hunt_page_rendering.py
   ::test_auth_pending_gate_is_absent). Public pages render immediately. */
body.admin.auth-pending > main,
body.admin.auth-pending > #page-header,
body.admin.auth-pending > header { visibility: hidden; }
.site-drawer.open .site-drawer-scrim { opacity: 1; }
.site-drawer-panel {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: min(280px, 80vw);
  background: #0a0f23;
  border-right: 1px solid var(--border);
  padding: max(1rem, env(safe-area-inset-top, 1rem)) 1.1rem max(1rem, env(safe-area-inset-bottom, 1rem));
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  transform: translateX(-100%);
  transition: transform 200ms ease;
  /* Explicit z-index ensures the panel stacks above the fully-opaque
     scrim in the .site-drawer stacking context. */
  z-index: 1;
}
.site-drawer.open .site-drawer-panel { transform: translateX(0); }
.site-drawer-close {
  align-self: flex-end;
  background: transparent;
  border: none;
  color: var(--muted);
  font-size: 1.5rem;
  line-height: 1;
  padding: 0.5rem 0.6rem;
  cursor: pointer;
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.site-drawer-close:hover { color: var(--fg); }
.site-drawer-close:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 2px; }
/* Primary affordances: Home + Leaderboard. Two accent-tinted card
   buttons at the top of the drawer, identical visual weight, so the
   app's two main destinations are reachable in one tap. Icons sit in
   a small circular badge so the glyph reads cleanly at all sizes. */
.site-drawer-primary {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  margin-top: 0.25rem;
  margin-bottom: 0.4rem;
}
.site-drawer-primary-link {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.8rem 0.9rem;
  border-radius: 12px;
  background: rgba(79,195,247,0.10);
  border: 1px solid rgba(79,195,247,0.35);
  color: var(--fg);
  text-decoration: none;
  font-size: 1.05rem;
  font-weight: 600;
  letter-spacing: -0.005em;
  min-height: 52px;
  transition: background 150ms ease, border-color 150ms ease, transform 100ms ease;
}
.site-drawer-primary-link:hover,
.site-drawer-primary-link:focus-visible {
  background: rgba(79,195,247,0.18);
  border-color: var(--accent-2);
}
.site-drawer-primary-link:active { transform: scale(0.99); }
.site-drawer-primary-link.active {
  background: rgba(79,195,247,0.24);
  border-color: var(--accent-2);
}
.site-drawer-primary-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: rgba(79,195,247,0.18);
  font-size: 1.15rem;
  line-height: 1;
  flex-shrink: 0;
  overflow: hidden;
}
/* The candidate SVGs ship with their own navy rounded-rect background;
   clipping to the parent's 50% radius hides the SVG corners so the
   icon reads as a clean circular badge. */
.site-drawer-primary-icon img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
}
.site-drawer-primary-label { line-height: 1.1; }

/* Secondary submenu: My Account / Request a Custom Hunt / Contact Us.
   Smaller text, softer color, set apart from the primary buttons with
   a "More" label so the visual hierarchy is unambiguous. */
.site-drawer-submenu {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  margin-top: 0.6rem;
  padding-top: 0.6rem;
  border-top: 1px solid var(--border);
}
.site-drawer-submenu-label {
  color: var(--muted);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 0 0.7rem 0.25rem;
}
.site-drawer-sublinks {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}
.site-drawer-sublink {
  color: var(--muted);
  text-decoration: none;
  font-size: 0.85rem;
  padding: 0.55rem 0.7rem;
  border-radius: 6px;
  display: flex;
  align-items: center;
  min-height: 44px;
}
.site-drawer-sublink:hover,
.site-drawer-sublink:focus-visible { color: var(--fg); background: rgba(255,255,255,0.05); }
.site-drawer-sublink.active { color: var(--fg); background: rgba(79,195,247,0.12); }

.site-drawer-auth {
  margin-top: auto;
  padding-top: 0.75rem;
  border-top: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  font-size: 0.85rem;
}
.site-drawer-user { color: var(--muted); }
.site-drawer-user strong { color: var(--accent-2); font-weight: 600; }

@media (max-width: 520px) {
  .site-nav-inner { padding: 0.5rem 0.75rem; gap: 0.5rem; }
  .site-nav-brand { font-size: 0.95rem; }
}

/* Desktop: drawer → inline horizontal nav (audit 2026-05-10).
 *
 * The drawer is intentionally mobile-first chrome — a fullscreen
 * off-canvas panel makes sense on a phone but eats the entire desktop
 * viewport. At ≥900px we hide the hamburger and use `display: contents`
 * on the drawer + panel boxes so their children (the primary links,
 * the "More" submenu, the auth row) flow as siblings of `.site-nav-inner`
 * inside `#site-nav`. Switching `.site-nav` itself to `display: flex`
 * lays those siblings out as one horizontal bar. The `[hidden]` UA
 * rule is overridden with `!important` because the JS leaves the
 * drawer hidden by default — at desktop we always want it visible. */
@media (min-width: 900px) {
  .site-nav {
    display: flex;
    align-items: center;
    max-width: 1100px;
    margin: 0 auto;
    padding-left: 0;
    padding-right: 0;
  }
  .site-nav-inner {
    max-width: none;
    margin: 0;
    padding: 0.6rem 1rem;
    gap: 0.75rem;
    flex: 0 0 auto;
    flex-wrap: nowrap;
  }
  .site-nav-toggle { display: none; }

  /* Reparent the drawer's children into the nav bar via display:contents. */
  .site-drawer,
  .site-drawer[hidden] {
    display: contents !important;
    position: static;
    inset: auto;
    z-index: auto;
  }
  .site-drawer-scrim,
  .site-drawer-close,
  .site-drawer-submenu-label {
    display: none;
  }
  .site-drawer-panel {
    display: contents;
  }
  /* The three submenu rows (primary, sub, auth) lay out side-by-side. */
  .site-drawer-primary,
  .site-drawer-sublinks {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 0.15rem;
    margin: 0;
    padding: 0;
    border-top: 0;
  }
  .site-drawer-submenu {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 0.15rem;
    margin: 0;
    padding: 0;
    border-top: 0;
  }
  .site-drawer-primary-link {
    background: transparent;
    border: 1px solid transparent;
    min-height: 40px;
    padding: 0.4rem 0.75rem;
    font-size: 0.92rem;
    font-weight: 500;
    border-radius: 6px;
  }
  .site-drawer-primary-link:hover,
  .site-drawer-primary-link:focus-visible {
    background: rgba(79,195,247,0.10);
    border-color: rgba(79,195,247,0.25);
  }
  .site-drawer-primary-link.active {
    background: rgba(79,195,247,0.18);
    border-color: rgba(79,195,247,0.45);
  }
  .site-drawer-primary-icon {
    /* The phone-sized icon badges look heavy in an inline horizontal
       bar; the labels alone carry the meaning on desktop. */
    display: none;
  }
  .site-drawer-sublink {
    color: var(--muted);
    padding: 0.4rem 0.7rem;
    font-size: 0.86rem;
    min-height: 36px;
    background: transparent;
  }
  .site-drawer-sublink:hover,
  .site-drawer-sublink:focus-visible { color: var(--fg); background: rgba(255,255,255,0.05); }
  .site-drawer-auth {
    margin: 0 0 0 auto;
    padding: 0 1rem 0 0;
    border-top: 0;
    flex-direction: row;
    gap: 0.5rem;
    font-size: 0.85rem;
    align-items: center;
  }
  /* Belt-and-suspenders: if `body.drawer-open` ever fires on desktop
     (it shouldn't, because the hamburger is hidden), don't blank the
     page — the inline nav is part of the layout, not a modal. */
  body.drawer-open { overflow: visible; }
  body.drawer-open > *:not(#site-nav):not(.toast-container) { visibility: visible; }
}

/* ---------- State/Hunts index pages ---------- */
.state-section {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 1rem 1.15rem;
  margin-bottom: 1rem;
}
.state-section h2 {
  margin: 0 0 0.5rem;
  font-size: 1.05rem;
}
.state-section h2 a {
  color: var(--accent-2);
  text-decoration: none;
}
.state-section h2 a:hover,
.state-section h2 a:focus-visible { text-decoration: underline; }
.state-hero {
  padding: 1rem 1rem 1.1rem;
  margin-bottom: 1rem;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.055), rgba(255, 255, 255, 0.025));
}
.state-back-link {
  color: var(--accent-2);
  text-decoration: none;
  font-size: 0.88rem;
  font-weight: 700;
}
.state-hero h1 {
  margin: 0.45rem 0 0.25rem;
  font-size: clamp(1.55rem, 4vw, 2.15rem);
  line-height: 1.1;
}
.state-meta {
  margin: 0;
  font-size: 0.92rem;
}
.state-hunt-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}
.state-hunt-list li a {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.75rem;
  padding: 0.55rem 0.75rem;
  border-radius: 6px;
  color: var(--fg);
  text-decoration: none;
  background: rgba(255,255,255,0.03);
  border: 1px solid var(--border);
}
.state-hunt-list li a:hover,
.state-hunt-list li a:focus-visible { border-color: var(--accent-2); }
.state-hunt-list .hunt-city {
  color: var(--muted);
  font-size: 0.8rem;
}
@media (max-width: 520px) {
  .state-hunt-list li a {
    align-items: flex-start;
    padding: 0.85rem 0.9rem;
  }
}

/* ---------- Hunt detail page ---------- */
.hunt-detail-hero {
  position: relative;
  border-radius: 10px;
  overflow: hidden;
  margin-bottom: 1rem;
}
.hunt-detail-cover {
  width: 100%;
  /* aspect-ratio reserves the box at the same shape the rendered image
     fills (`max-height: 220px` clips an ultra-tall result), so the
     layout settles before the WebP lands and there's no CLS as the
     hero pops in. The 1200×220 ratio matches the img width/height
     attributes set in hunt-detail.html. */
  aspect-ratio: 1200 / 220;
  max-height: 220px;
  object-fit: cover;
  display: block;
}
/* Shimmering placeholder shown until #hunt-cover fires `load`. Sits
   inside the same `.hunt-detail-hero` box and uses the same
   aspect-ratio so there's no layout shift when the real image lands
   (UAT e2e #8). hunt-detail.js removes the element once the img
   loads (or errors). Borrowed colour stops keep it consistent with
   the .ar-progress-fill shimmer pattern already in the codebase. */
.hunt-detail-cover-skeleton {
  width: 100%;
  aspect-ratio: 1200 / 220;
  max-height: 220px;
  background: linear-gradient(
    90deg,
    rgba(255, 255, 255, 0.04) 0%,
    rgba(255, 255, 255, 0.1) 50%,
    rgba(255, 255, 255, 0.04) 100%
  );
  background-size: 200% 100%;
  animation: hunt-detail-cover-shimmer 1.4s ease-in-out infinite;
}
@keyframes hunt-detail-cover-shimmer {
  0%   { background-position: 100% 0; }
  100% { background-position: -100% 0; }
}
.hunt-detail-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 1rem;
  color: var(--muted);
  font-size: 0.88rem;
  margin: 0.35rem 0 0.75rem;
}
.hunt-detail-description {
  white-space: pre-wrap;
  line-height: 1.55;
  margin-bottom: 1rem;
}
#hunt-detail-map {
  height: 320px;
  border-radius: 10px;
  border: 1px solid var(--border);
  overflow: hidden;
  margin-bottom: 1rem;
}
.hunt-detail-actions {
  display: flex;
  gap: 0.75rem;
  flex-wrap: wrap;
  margin-top: 1rem;
}
.hunt-detail-actions .btn-secondary { background: transparent; }

/* ---------- Hunt page ---------- */
.hunt-body { overflow: hidden; }

/* Camera is now scoped inside .camera-overlay (opt-in AR pop-out).
   The bare <video id="camera"> at body-root is gone; these rules
   apply to the overlay-embedded video. */
.camera-overlay .camera-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  background: #000;
}
.camera-fallback {
  /* Shown inside .camera-overlay when getUserMedia fails. Sits beneath
     the AR elements so the close button and compass remain interactive. */
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, #0b1020 0%, #1a2548 100%);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--muted);
  padding: 1.5rem;
  text-align: center;
  z-index: 1;
}
.camera-fallback[hidden] { display: none !important; }

#overlay {
  position: fixed;
  inset: 0;
  z-index: 1;
  display: flex;
  flex-direction: column;
  /* Only apply top safe-area padding here. The bottom safe-area is moved
     onto `.clue-card` (which is now the scroll container) so its last
     scrollable item (DNF button, issue-panel submit) can actually reach
     the visible bottom edge above the iOS home indicator. */
  padding: env(safe-area-inset-top, 0) 0 0 0;
  pointer-events: none;
}

.hunt-header {
  background: rgba(0,0,0,0.5);
  color: white;
  padding: 0.75rem 1rem;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  pointer-events: auto;
}
.hunt-header .back {
  color: white;
  text-decoration: none;
  font-size: 0.95rem;
  font-weight: 600;
  padding: 0.35rem 0.65rem;
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.12);
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  line-height: 1;
  white-space: nowrap;
}
.hunt-header .back:hover,
.hunt-header .back:focus-visible { background: rgba(255, 255, 255, 0.22); }
.hunt-header .back span { font-size: 1.1rem; }
#hunt-title {
  margin: 0;
  font: inherit;
  font-weight: 700;
  line-height: 1.15;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Safety-reminder top-card on the hunt page — dismissible nudge to
   look up from the phone. See setupSafetyReminder() in hunt.js for the
   per-device sticky dismissal. */
.safety-reminder {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  margin: 0 0 0.85rem;
  padding: 0.6rem 0.75rem;
  background: rgba(255, 212, 121, 0.08);
  border: 1px solid rgba(255, 212, 121, 0.35);
  border-radius: 8px;
  font-size: 0.85rem;
  line-height: 1.35;
  color: #ffe7b3;
}
.safety-reminder[hidden] { display: none !important; }
.safety-reminder-icon {
  flex: 0 0 auto;
  font-size: 1.1rem;
  line-height: 1;
  color: #ffd479;
}
.safety-reminder-body { flex: 1 1 auto; }
.safety-reminder-body strong { display: block; color: #fff; margin-bottom: 0.15rem; }
.safety-reminder-dismiss {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  min-height: 44px;
  background: transparent;
  border: 0;
  color: rgba(255, 231, 179, 0.7);
  font-size: 1.25rem;
  line-height: 1;
  padding: 0;
  cursor: pointer;
}
.safety-reminder-dismiss:hover,
.safety-reminder-dismiss:focus-visible { color: #fff; }

.clue-card {
  position: relative;
  margin-top: auto;
  background: linear-gradient(180deg,
    rgba(15, 22, 48, 0.94) 0%,
    rgba(11, 16, 32, 0.96) 100%);
  border-top: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 20px 20px 0 0;
  box-shadow:
    0 -18px 48px -16px rgba(0, 0, 0, 0.6),
    inset 0 1px 0 rgba(255, 255, 255, 0.06);
  /* Bottom padding includes env(safe-area-inset-bottom) so the last
     scrollable element (DNF button, issue-panel submit) stays above the
     iOS home indicator. */
  padding: 1.35rem 1.25rem calc(1.25rem + env(safe-area-inset-bottom, 0));
  pointer-events: auto;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  /* Card is its own scroll region: caps height so growing content
     (multiple hints, expanded issue panel) can scroll within rather
     than push other chrome off-screen. Fallback vh for iOS <15.4;
     dvh for modern (dynamic-chrome-aware) browsers. */
  max-height: 70vh;
  max-height: min(70dvh, calc(100dvh - 120px));
  overflow-y: auto;
  overscroll-behavior: contain;
  touch-action: pan-y;
  -webkit-overflow-scrolling: touch;
}
.clue-card::before {
  content: "";
  position: absolute;
  top: 0.55rem;
  left: 50%;
  width: 2.75rem;
  height: 0.22rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.22);
  transform: translateX(-50%);
}
.clue-card h2 { margin: 0.25rem 0 0.5rem; }

/* Hero clue text — the single most important piece of information on
   the page. Generous line-height + slightly up-weighted for readability
   in daylight on a phone. */
.clue-hero {
  margin: 0.65rem 0 0.8rem;
  font-size: 1.12rem;
  line-height: 1.5;
  color: var(--fg);
  letter-spacing: 0.005em;
  text-wrap: pretty;
}
.stop-label {
  color: var(--accent-2);
  font-size: 0.8rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.75rem;
}
.stop-label .difficulty {
  letter-spacing: 0.05em;
  color: #f5b700;
  font-size: 0.95rem;
}
.difficulty-pair {
  display: inline-flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 0.45rem;
  align-items: flex-start;
}
.difficulty-terrain {
  color: #a3e635;
  font-size: 0.75rem;
}
/* Labeled difficulty chip — stacks a small "Puzzle" / "Terrain" caption
   above the star/dot symbols so a first-time player can tell what the
   indicators mean at a glance (prior UI showed only the symbols + an
   invisible aria-label). */
.difficulty-chip {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-end;
  line-height: 1;
  gap: 0.15rem;
  min-width: 3.25rem;
  padding: 0.25rem 0.38rem;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.045);
}
.difficulty-chip-label {
  font-size: 0.58rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 600;
}
/* Quiet text-link footer for secondary actions (Start over · Issue).
   Replaces a second full-width button-row that competed visually with
   the primary CTA row above it. */
.secondary-links {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 0.25rem;
  margin-top: 0.85rem;
  font-size: 0.82rem;
}
.secondary-links .linkish {
  background: transparent;
  border: 0;
  color: var(--muted);
  padding: 0.25rem 0.4rem;
  cursor: pointer;
  font-size: inherit;
  font-family: inherit;
  text-decoration: underline;
  text-decoration-color: rgba(255, 255, 255, 0.18);
  text-underline-offset: 3px;
}
.secondary-links .linkish:hover,
.secondary-links .linkish:focus-visible {
  color: var(--fg);
  text-decoration-color: var(--muted);
}
.secondary-links .sep {
  color: rgba(255, 255, 255, 0.25);
  user-select: none;
}

/* ---------- GPS quality banner ---------- */
.gps-quality {
  margin: 0.4rem 0 0.6rem;
  padding: 0.45rem 0.65rem;
  border-radius: 6px;
  font-size: 0.82rem;
  line-height: 1.3;
  text-align: center;
}
.gps-quality--weak {
  background: rgba(245, 183, 0, 0.12);
  border: 1px solid rgba(245, 183, 0, 0.45);
  color: #f5b700;
}
.gps-quality--bad {
  background: rgba(255, 112, 112, 0.12);
  border: 1px solid rgba(255, 112, 112, 0.5);
  color: #ff9a9a;
}

/* ---------- Album (post-hunt keepsake) ---------- */
.album-main {
  max-width: 900px;
  margin: 0 auto;
  padding: 1.5rem max(1.25rem, env(safe-area-inset-right, 1.25rem)) calc(3rem + env(safe-area-inset-bottom, 0)) max(1.25rem, env(safe-area-inset-left, 1.25rem));
}
.album-hero {
  position: relative;
  padding: 1rem 1rem 1.1rem;
  margin-bottom: 1.25rem;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.055), rgba(255, 255, 255, 0.025));
}
.album-hero h1 {
  margin: 0 0 0.25rem;
  font-size: 2rem;
  letter-spacing: -0.01em;
}
.album-subtitle {
  color: var(--muted);
  margin: 0 0 1rem;
}
.album-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 0.75rem;
  margin: 0.5rem 0 1rem;
  padding: 0;
}
.album-stats dt {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
}
.album-stats dd {
  margin: 0.15rem 0 0;
  font-weight: 700;
  font-size: 1.15rem;
  color: var(--accent-2);
}
.album-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 0.25rem;
}
.album-actions .btn-secondary {
  padding: 0.7rem 1rem;
  border-radius: 8px;
  text-decoration: none;
}
.album-share-btn {
  min-width: 9.5rem;
}
.album-share-btn:disabled {
  opacity: 0.75;
  cursor: progress;
}
.album-share-status {
  min-height: 1.2rem;
  color: var(--accent-2);
  font-size: 0.88rem;
  font-weight: 600;
}
#album-map {
  height: 320px;
  border-radius: 10px;
  border: 1px solid var(--border);
  overflow: hidden;
  margin: 0.5rem 0 1.5rem;
}
#album-photos {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 1rem;
}
.album-photo {
  margin: 0;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
}
.album-photo img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  display: block;
}
.album-photo figcaption {
  padding: 0.7rem 0.85rem;
}
.album-photo strong { display: block; margin-bottom: 0.25rem; }
.album-photo p {
  margin: 0;
  font-size: 0.85rem;
  color: var(--muted);
  line-height: 1.45;
}

/* ---------- Projected board ----------
 * TV/projector first, phone-tolerant. Type and photo-tile sizes use
 * clamp() so a 55" TV at 10 feet gets ~3x the scale of a laptop at
 * arm's length without a separate breakpoint matrix. Max values are
 * tuned for a 1920×1080 projector; min values keep the page usable
 * on a host's phone while they pull up the URL.
 */
.board-body {
  margin: 0;
  background: radial-gradient(circle at top, #14203e 0%, #070b1c 80%);
  color: var(--fg);
  min-height: 100vh;
  overflow-x: hidden;
}
.board-main {
  max-width: 1600px;
  margin: 0 auto;
  padding: clamp(1rem, 2.5vw, 2.5rem) clamp(1rem, 3vw, 3rem);
}
.board-header {
  display: flex;
  align-items: baseline;
  gap: 1.25rem;
  margin-bottom: clamp(1rem, 2vw, 2rem);
  flex-wrap: wrap;
}
.board-header h1 {
  margin: 0;
  font-size: clamp(2rem, 6vw, 5.5rem);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.05;
}
.board-subtitle {
  color: var(--muted);
  font-size: clamp(0.95rem, 1.4vw, 1.4rem);
  text-transform: uppercase;
  letter-spacing: 0.12em;
}
.board-grid {
  display: grid;
  grid-template-columns: 0.9fr 1.1fr;
  gap: clamp(1rem, 2.5vw, 2.5rem);
}
@media (max-width: 900px) {
  .board-grid { grid-template-columns: 1fr; }
}
.board-leaderboard-wrap h2,
.board-photos-wrap h2 {
  font-size: clamp(0.9rem, 1.2vw, 1.4rem);
  text-transform: uppercase;
  letter-spacing: 0.15em;
  color: var(--muted);
  margin: 0 0 0.8rem;
}
.board-leaderboard {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: clamp(0.5rem, 0.9vw, 1rem);
}
.board-lb-row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: clamp(0.6rem, 1.2vw, 1.5rem);
  padding: clamp(0.65rem, 1.1vw, 1.25rem) clamp(0.9rem, 1.4vw, 1.6rem);
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--border);
  border-radius: 12px;
  font-size: clamp(1.2rem, 2.2vw, 2.8rem);
  font-weight: 600;
}
.board-lb-row:nth-child(1) {
  background: linear-gradient(90deg, rgba(245, 183, 0, 0.22), rgba(245, 183, 0, 0.05));
  border-color: rgba(245, 183, 0, 0.55);
}
.board-lb-rank {
  font-size: clamp(1rem, 1.8vw, 2.2rem);
  color: var(--muted);
  min-width: 2ch;
}
.board-lb-row:nth-child(1) .board-lb-rank { color: #f5b700; }
.board-lb-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.board-lb-score {
  font-variant-numeric: tabular-nums;
  color: var(--accent-2);
}
.board-photos {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(clamp(140px, 14vw, 260px), 1fr));
  gap: clamp(0.5rem, 0.9vw, 1rem);
}
.board-photo-tile {
  margin: 0;
  background: rgba(255,255,255,0.03);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
.board-photo-tile img {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  display: block;
}
.board-photo-tile figcaption {
  padding: 0.5rem 0.7rem;
  font-size: 0.78rem;
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}
.board-photo-tile strong { color: var(--fg); }
.board-photo-tile span { color: var(--muted); }
.board-footer {
  margin-top: 1.5rem;
  text-align: right;
  color: var(--muted);
  font-size: 0.85rem;
  letter-spacing: 0.06em;
}
.board-empty {
  color: var(--muted);
  padding: 1rem;
}

/* ---------- Stop issue / DNF panel ---------- */
.stop-issue-panel {
  margin-top: 0.5rem;
  padding: 0.75rem;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--border);
  border-radius: 8px;
}
.stop-issue-label {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--muted);
  margin-bottom: 0.4rem;
}
.stop-issue-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
}
.stop-issue-buttons button {
  flex: 1 1 auto;
  min-width: max-content;
}
.stop-issue-buttons button.active {
  border-color: var(--accent-2);
  color: var(--fg);
  background: rgba(79, 195, 247, 0.12);
}

/* ---------- Reveal bottom sheet ---------- */
/* The reveal slides up from the bottom so the camera stays visible above it. */
.reveal-modal {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  pointer-events: auto;
  z-index: 5;
}
.reveal-inner {
  background: rgba(11, 16, 40, 0.97);
  border-top: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 16px 16px 0 0;
  padding: 0.75rem 1.25rem env(safe-area-inset-bottom, 1.25rem);
  max-height: 72vh;
  overflow-y: auto;
  box-shadow: 0 -24px 60px -20px rgba(0, 0, 0, 0.78);
  animation: slideUp 0.32s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
@keyframes slideUp {
  from { transform: translateY(100%); opacity: 0.6; }
  to   { transform: translateY(0);    opacity: 1;   }
}
.bottom-sheet-handle {
  width: 36px;
  height: 4px;
  background: rgba(255,255,255,0.18);
  border-radius: 2px;
  margin: 0 auto 0.85rem;
}
/* Frozen discovery animation inside the reveal card. Sized generously
   so kids can savor the payoff without the camera-overlay detour.
   Position relative so the absolute-positioned fallback emoji inside
   anchors to this box. */
.reveal-discovery {
  position: relative;
  width: 280px;
  height: 280px;
  max-width: 60vw;
  max-height: 60vw;
  margin: 0 auto 0.5rem;
  pointer-events: none;
}
.reveal-discovery[hidden] { display: none !important; }
.reveal-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.25rem 0.45rem;
  border: 1px solid rgba(163, 230, 53, 0.22);
  border-radius: 999px;
  background: rgba(163, 230, 53, 0.08);
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: #a3e635;
  margin-bottom: 0.45rem;
}
.reveal-inner h2 {
  margin: 0 0 0.65rem;
  color: var(--fg);
  font-size: 1.3rem;
  line-height: 1.2;
}
#reveal-text {
  margin: 0.25rem 0 0.95rem;
  color: rgba(245, 247, 255, 0.82);
  font-size: 0.96rem;
  line-height: 1.52;
}
.reveal-image {
  display: block;
  max-width: 100%;
  max-height: 200px;
  width: auto;
  height: auto;
  margin: 0 auto 0.75rem;
  border-radius: 8px;
}

/* ---------- Next clue preview (in reveal sheet) ---------- */
.next-clue-preview {
  margin-top: 1rem;
  padding: 0.85rem;
  background: rgba(79, 195, 247, 0.08);
  border: 1px solid rgba(79, 195, 247, 0.24);
  border-radius: 12px;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
}
.next-clue-label {
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--accent-2);
  margin-bottom: 0.35rem;
}
.next-clue-text {
  margin: 0;
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--fg);
}
.reveal-next-btn {
  width: 100%;
  min-height: 48px;
  margin-top: 1rem;
  border-radius: 12px;
}
.reveal-back-link {
  display: block;
  margin-top: 0.75rem;
  text-align: center;
  font-size: 0.85rem;
}

/* ---------- Completion modal (full-screen, hunt is done) ---------- */
.completed-modal {
  position: absolute;
  inset: 0;
  background: rgba(0,0,0,0.88);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.25rem;
  pointer-events: auto;
  z-index: 150;
}
/* The `display: flex` above has the same specificity as the UA `[hidden]`
   rule, so setting `hidden=true` alone doesn't hide the modal — it stays
   painted over the clue card on every /hunt.html load. Force display:none
   when the attribute is present. Mirrors the fix for .intro-screen below. */
.completed-modal[hidden] { display: none !important; }
.completed-inner {
  background: rgba(11, 16, 40, 0.98);
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 18px;
  padding: 1.5rem;
  max-width: 400px;
  width: 100%;
  text-align: center;
  box-shadow: 0 24px 70px rgba(0, 0, 0, 0.62);
  animation: popIn 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
  max-height: calc(100vh - 2.5rem);
  max-height: calc(100dvh - 2.5rem);
  overflow-y: auto;
  overscroll-behavior: contain;
}
@keyframes popIn {
  from { opacity: 0; transform: scale(0.9); }
  to   { opacity: 1; transform: scale(1); }
}
.completed-inner h2 { margin-top: 0; color: var(--accent-2); }

/* ---------- AR compass overlay ---------- */
.ar-compass {
  position: absolute;
  top: 20%;
  left: 50%;
  transform: translateX(-50%);
  width: 160px;
  height: 160px;
  display: flex;
  flex-direction: column;
  align-items: center;
  pointer-events: none;
  filter: drop-shadow(0 6px 18px rgba(0, 0, 0, 0.5));
}
/* `.ar-compass { display: flex }` has equal specificity to the UA
   `[hidden] { display: none }`. Without this override the compass overlay
   is painted on every /hunt.html load before renderClue() runs.
   Same pattern as .completed-modal / .intro-screen. */
.ar-compass[hidden] { display: none !important; }
/* Suppresses the compass during close-range mode (<= 75 ft) without
   touching the `hidden` attribute, which the user pref + iOS
   permission flow owns. Toggled by hunt.js updateDistance(). */
.ar-compass.compass-close-range { display: none !important; }
.ar-arrow {
  width: 100%;
  height: 100%;
  transition: transform 120ms linear;
  transform-origin: 50% 50%;
  filter: drop-shadow(0 8px 18px rgba(0, 0, 0, 0.55));
}
.ar-compass .ar-ring {
  fill: rgba(0, 0, 0, 0.46);
  stroke: rgba(255, 255, 255, 0.68);
  stroke-width: 2;
}
.ar-compass .ar-distance {
  margin-top: 0.35rem;
  min-width: 5.2rem;
  padding: 0.38rem 0.65rem;
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.62);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  font-weight: 700;
  font-size: 1.05rem;
  color: #fff;
  text-align: center;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.95);
}
.ar-compass.within-range .ar-ring {
  fill: rgba(40, 200, 100, 0.35);
  stroke: rgba(120, 255, 160, 0.9);
  animation: ar-pulse 1.1s ease-in-out infinite;
}
.ar-compass.within-range .ar-arrow {
  transform: rotate(0deg) scale(0.9) !important;
}
@keyframes ar-pulse {
  0%, 100% { stroke-width: 2; transform: scale(1); }
  50% { stroke-width: 5; transform: scale(1.08); }
}

/* Close-range proximity ring — replaces the compass arrow at <= 75 ft
   (see hunt.js:updateDistance). Three concentric rings shrink on a
   2.4s loop at staggered phases so there's always one visible. Color
   is driven by the existing proximity-* tier classes (warm/hot/etc)
   via the --ring-color CSS var. Medium speed per the feature request. */
.ar-proximity-ring {
  position: absolute;
  top: 20%;
  left: 50%;
  transform: translateX(-50%);
  width: 200px;
  height: 200px;
  z-index: 3;
  pointer-events: none;
  --ring-color: rgba(245, 183, 0, 0.85);
}
.ar-proximity-ring[hidden] { display: none !important; }
.ar-proximity-ring .proximity-ring {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 4px solid var(--ring-color);
  box-shadow: 0 0 20px var(--ring-color);
  animation: proximity-ring-shrink 2.4s cubic-bezier(0.4, 0, 0.2, 1) infinite;
  opacity: 0;
}
.ar-proximity-ring .proximity-ring--1 { animation-delay: 0s; }
.ar-proximity-ring .proximity-ring--2 { animation-delay: 0.8s; }
.ar-proximity-ring .proximity-ring--3 { animation-delay: 1.6s; }
.proximity-ring-dist {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 800;
  font-size: 1.4rem;
  color: #fff;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.95);
  pointer-events: none;
}
.proximity-ring-dist strong {
  min-width: 4.6rem;
  padding: 0.42rem 0.72rem;
  border: 1px solid rgba(255, 255, 255, 0.24);
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.62);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  text-align: center;
}
@keyframes proximity-ring-shrink {
  0%   { transform: scale(1.0);  opacity: 0.95; }
  70%  { opacity: 0.6; }
  100% { transform: scale(0.18); opacity: 0; }
}
/* Heat color tiers — piggyback on the existing proximity-* classes
   so ProximityAudio's tier output maps directly to ring color. */
.ar-proximity-ring.proximity-approaching { --ring-color: rgba(79, 195, 247, 0.8); }
.ar-proximity-ring.proximity-near        { --ring-color: rgba(160, 230, 120, 0.9); }
.ar-proximity-ring.proximity-warm        { --ring-color: rgba(255, 152, 0, 0.95); }
.ar-proximity-ring.proximity-hot         { --ring-color: rgba(233, 79, 55, 1); }

/* On-device debug panel — only shown when ?debug=1 is in the URL.
   Tiny text; sits in the top-left safe area of the camera overlay. */
.ar-debug-panel {
  position: absolute;
  top: calc(env(safe-area-inset-top, 0px) + 72px);
  left: 8px;
  max-width: 60vw;
  padding: 0.35rem 0.5rem;
  background: rgba(0, 0, 0, 0.65);
  color: #a3e635;
  font: 500 10px/1.35 ui-monospace, SFMono-Regular, Menlo, monospace;
  border-radius: 6px;
  z-index: 7;
  pointer-events: none;
  white-space: pre-wrap;
}
.ar-debug-panel[hidden] { display: none !important; }

/* ---------- Hint popup modal ---------- */
/* Tap Hint 1 / Hint 2 to open a simple popup with the hint text. Close
   and reopen at will — no penalty on reopen (first-reveal is cached
   client-side). The buttons stay visible regardless of state so the
   player can use them as a reminder. */
.hint-modal {
  position: fixed;
  inset: 0;
  z-index: 85;                 /* above map-reveal (80), below completion */
  background: rgba(0, 0, 0, 0.6);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  pointer-events: auto;
}
#waiver-modal {
  /* Hunt detail pages have Leaflet panes with high internal z-indexes. */
  z-index: 1000;
}
#waiver-modal .hint-modal-inner {
  background: #0f1630;
}
#waiver-modal .hint-modal-body {
  color: var(--fg-secondary);
  font-size: 0.95rem;
  line-height: 1.45;
  white-space: normal;
}
#waiver-modal .hint-modal-body p {
  margin: 0 0 0.75rem;
}
#waiver-modal .hint-modal-body ul {
  margin: 0 0 0.85rem;
  padding-left: 1.1rem;
}
.hint-modal[hidden] { display: none !important; }
.hint-modal-inner {
  position: relative;
  background: var(--card);
  width: 100%;
  max-width: 420px;
  max-height: calc(100dvh - 2rem);
  overflow-y: auto;
  overscroll-behavior: contain;
  border-radius: 14px;
  border: 1px solid rgba(245, 183, 0, 0.4);
  padding: 1.25rem 1.25rem 1.1rem;
  box-shadow: 0 24px 60px -20px rgba(0, 0, 0, 0.7);
  animation: hint-modal-pop 180ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
@supports not (height: 100dvh) {
  .hint-modal-inner { max-height: calc(100vh - 2rem); }
}
@keyframes hint-modal-pop {
  from { transform: scale(0.96); opacity: 0; }
  to   { transform: scale(1);    opacity: 1; }
}
.hint-modal-title {
  margin: 0 0 0.5rem;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: #f5b700;
  font-weight: 700;
}
.hint-modal-body {
  margin: 0;
  color: #f7dc7a;
  font-size: 1rem;
  line-height: 1.45;
  white-space: pre-wrap;
}
.hint-modal-close {
  position: absolute;
  top: 0.4rem;
  right: 0.55rem;
  background: transparent;
  border: none;
  color: var(--fg);
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  padding: 0.5rem 0.6rem;
  border-radius: 6px;
  opacity: 0.75;
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.hint-modal-close:hover { opacity: 1; background: rgba(255, 255, 255, 0.06); }
.hint-modal-close:focus-visible {
  outline: 2px solid #f5b700;
  outline-offset: -2px;
  opacity: 1;
}

.button-row {
  display: flex;
  gap: 0.5rem;
  align-items: stretch;
}
.button-row > * { flex: 1; }
#waiver-modal .button-row {
  position: sticky;
  bottom: -1.1rem;
  margin: 0.85rem -1.25rem -1.1rem;
  padding: 0.7rem 1.25rem 1.1rem;
  background: linear-gradient(
    to top,
    var(--card) 0%,
    var(--card) 78%,
    rgba(13, 20, 43, 0)
  );
}
.btn-secondary {
  background: transparent;
  color: var(--accent-2);
  border: 1px solid var(--accent-2);
  padding: 0.65rem 0.9rem;
  border-radius: 8px;
  font-weight: 600;
  cursor: pointer;
}
.btn-secondary:hover,
.btn-secondary:focus-visible { background: rgba(255, 255, 255, 0.05); }

/* ---------- Hunt header progress bar ---------- */
.hunt-header-center {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.hunt-progress-bar {
  height: 4px;
  background: rgba(255,255,255,0.15);
  border-radius: 2px;
  overflow: hidden;
  width: 100%;
}
.hunt-progress-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--accent-2), #a3e635);
  border-radius: 2px;
  transition: width 0.6s ease;
}

/* ---------- Mini-map overlay ---------- */
.mini-map-wrap {
  position: absolute;
  top: 70px;
  right: 12px;
  width: 120px;
  height: 120px;
  border-radius: 50%;
  overflow: hidden;
  border: 2px solid rgba(255,255,255,0.35);
  box-shadow: 0 4px 16px rgba(0,0,0,0.6);
  pointer-events: none;
  z-index: 2;
}
#mini-map {
  width: 100%;
  height: 100%;
}
/* Leaflet tile layer gets pointer-events for panning — disabled in map init */
.mini-map-wrap .leaflet-container {
  background: #1a2548;
}
@media (max-width: 720px) {
  .leaflet-control-zoom a {
    width: 44px !important;
    height: 44px !important;
    line-height: 44px !important;
    font-size: 1.35rem !important;
  }
}
.map-player-dot {
  width: 12px;
  height: 12px;
  background: #4fc3f7;
  border: 2px solid #fff;
  border-radius: 50%;
  box-shadow: 0 0 6px rgba(79,195,247,0.8);
}
.map-target-pin {
  width: 16px;
  height: 16px;
  background: var(--accent);
  border: 2px solid #fff;
  border-radius: 50%;
  box-shadow: 0 0 8px rgba(233,79,55,0.9);
}

/* ---------- Asset discovery section ---------- */
.asset-discovery-section {
  margin: 0.85rem 0 0.75rem;
  padding: 0.75rem;
  background: rgba(156,39,176,0.08);
  border: 1px solid rgba(156,39,176,0.25);
  border-radius: 8px;
}
/* First-encounter glow-up: warmer gradient + animated golden border so
   the kid SEES this is special. Animation runs once, then sits — per
   CLAUDE.md "rewards should linger, not flash". */
.asset-discovery-section.is-new-discovery {
  background: linear-gradient(135deg, rgba(255,193,7,0.18) 0%, rgba(156,39,176,0.18) 100%);
  border-color: #ffb300;
  box-shadow: 0 0 12px rgba(255,193,7,0.35);
  animation: asset-new-glow 2.5s ease-out 1;
}
@keyframes asset-new-glow {
  0%   { box-shadow: 0 0 0 rgba(255,193,7,0); transform: scale(0.96); }
  30%  { box-shadow: 0 0 24px rgba(255,193,7,0.7); transform: scale(1.02); }
  100% { box-shadow: 0 0 12px rgba(255,193,7,0.35); transform: scale(1); }
}
.asset-discovery-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.4rem;
}
.asset-discovery-label {
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: #9c27b0;
  display: flex;
  align-items: center;
  gap: 0.4rem;
  flex: 1;
  min-width: 0;
}
.is-new-discovery .asset-discovery-label {
  color: #ffb300;
}
.asset-new-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.25rem 0.6rem;
  background: linear-gradient(90deg, #ffb300, #ff7043);
  color: #1a0f00;
  font-size: 0.7rem;
  font-weight: 800;
  letter-spacing: 0.1em;
  border-radius: 999px;
  text-transform: uppercase;
  box-shadow: 0 2px 8px rgba(255,179,0,0.4);
  animation: asset-new-pulse 1.4s ease-in-out infinite;
}
.asset-new-badge-spark {
  display: inline-block;
  font-size: 0.85rem;
  animation: asset-new-spark 1.4s ease-in-out infinite alternate;
}
@keyframes asset-new-pulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.08); }
}
@keyframes asset-new-spark {
  0%   { transform: rotate(-12deg) scale(1); }
  100% { transform: rotate(12deg) scale(1.15); }
}
.asset-encounters-badge {
  display: inline-flex;
  align-items: center;
  padding: 0.2rem 0.55rem;
  background: rgba(255,255,255,0.08);
  color: var(--fg-secondary);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  border-radius: 999px;
  border: 1px solid var(--border);
}
.asset-discovery-card {
  text-align: left;
  display: flex;
  gap: 0.85rem;
  align-items: flex-start;
}
.asset-discovery-text {
  flex: 1;
  min-width: 0;
}
.asset-card-live-preview {
  flex-shrink: 0;
  width: 96px;
  height: 96px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(255,255,255,0.04);
  border-radius: 10px;
  overflow: hidden;
}
.asset-card-live-fallback {
  font-size: 2.6rem;
  line-height: 1;
}
/* On legendary first-time finds, the preview gets a soft golden halo so
   the eye lands on the creature before the text. Subtle — not a pop-up. */
.is-new-discovery .asset-card-live-preview {
  background: radial-gradient(circle at center, rgba(255,193,7,0.22) 0%, rgba(255,193,7,0) 70%);
  box-shadow: 0 0 0 1px rgba(255,193,7,0.35);
}
@media (max-width: 380px) {
  .asset-discovery-card {
    flex-direction: column;
    align-items: center;
    text-align: center;
  }
  .asset-discovery-text { width: 100%; }
}
.asset-name {
  margin: 0 0 0.35rem;
  font-size: 1.1rem;
  font-weight: 700;
  color: var(--fg);
}
.asset-description {
  margin: 0 0 0.5rem;
  font-size: 0.9rem;
  color: var(--fg-secondary);
  line-height: 1.4;
}
.asset-attributes {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.4rem;
  font-size: 0.8rem;
}
.asset-attribute {
  padding: 0.35rem 0.5rem;
  background: rgba(156,39,176,0.12);
  border-radius: 4px;
  color: var(--fg-secondary);
}
.asset-attribute-label {
  font-weight: 600;
  color: #9c27b0;
  text-transform: capitalize;
}

/* ---------- Photo challenge section ---------- */
.photo-challenge-section {
  margin: 0.85rem 0 0.75rem;
  padding: 0.85rem;
  display: grid;
  gap: 0.65rem;
  background: rgba(79, 195, 247, 0.08);
  border: 1px solid rgba(79, 195, 247, 0.26);
  border-radius: 12px;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
  text-align: left;
}
.photo-challenge-label {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--accent-2);
}
.photo-challenge-label img {
  padding: 0.2rem;
  border-radius: 7px;
  background: rgba(79, 195, 247, 0.12);
}
.photo-challenge-prompt {
  margin: 0;
  font-size: 0.9rem;
  color: var(--fg);
  line-height: 1.4;
}
.photo-preview-wrap {
  padding: 0.45rem;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 10px;
  background: rgba(0, 0, 0, 0.16);
}
.photo-preview {
  width: 100%;
  max-height: 160px;
  object-fit: cover;
  border-radius: 8px;
  border: 1px solid var(--border);
  display: block;
  margin-bottom: 0.35rem;
}
.photo-status {
  font-size: 0.8rem;
  color: var(--muted);
}
.photo-status-ok { color: #a3e635; }
.photo-status-error { color: #ff7070; }
.photo-challenge-button {
  width: 100%;
  min-height: 44px;
  border-radius: 10px;
}

/* ---------- Confetti canvas ---------- */
.confetti-canvas {
  position: fixed;
  inset: 0;
  /* Inside #overlay stacking context. Above .camera-overlay (60),
     .map-reveal-modal (80), .hint-modal (85) so confetti rains over
     the AR view + reveal sheet — but below .completed-modal (150)
     so the trophy still wins on hunt completion. */
  z-index: 140;
  pointer-events: none;
}

/* ---------- Completion summary stats ---------- */
.summary-stats {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.55rem;
  margin: 1rem 0 1.25rem;
  text-align: left;
  font-size: 0.95rem;
}
.summary-stat {
  padding: 0.7rem 0.75rem;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.045);
}
.summary-stats dt {
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-size: 0.75rem;
}
.summary-stats dd {
  margin: 0.25rem 0 0;
  color: #f5f7ff;
  font-weight: 700;
  font-size: 1.05rem;
}
@media (min-width: 420px) {
  .summary-stats {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}
.completed-actions {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.65rem;
}
@media (min-width: 420px) {
  .completed-actions {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
.completed-home-link,
.completed-album-link {
  min-height: 44px;
  padding: 0.7rem 0.9rem;
  border-radius: 10px;
  text-align: center;
  text-decoration: none;
}
.completed-reset-row {
  margin-top: 0.75rem;
  text-align: center;
}
.completed-reset-btn {
  font-size: 0.85rem;
}

/* ---------- Standalone pages (leaderboard) ---------- */
.page-body { padding-bottom: 3rem; }
.page-header {
  padding: max(1rem, env(safe-area-inset-top, 1rem)) 1.25rem 1rem;
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  gap: 1rem;
}
.page-header h1 { margin: 0; font-size: 1.25rem; }
.page-header .back {
  color: var(--accent-2);
  text-decoration: none;
  font-weight: 600;
}
/* Right-aligned nav cluster + user-id span rendered by renderPageHeader().
   Inline margin-left is set per-element by the helper (auto on the first,
   then .75rem) so the cluster pushes to the right edge and the items
   stack tightly. Color/size live here so future tweaks don't require
   touching the JS. */
.page-header-link {
  font-size: 0.85rem;
  color: var(--accent, #4a9eff);
  text-decoration: none;
}
.page-header-user {
  font-size: 0.85rem;
}
.page-main {
  padding: 1.25rem max(1.25rem, env(safe-area-inset-right, 1.25rem)) 1.25rem max(1.25rem, env(safe-area-inset-left, 1.25rem));
  max-width: 720px;
  margin: 0 auto;
}

/* Desktop override for `.page-main`. The companion override for the bare
 * `<main>` element lives near the top of this file and works because the
 * unscoped `main { max-width: 520px; }` rule is defined above it. The
 * `.page-main` rule, however, is defined here — long after that first
 * media query block — so when both selectors had equal specificity the
 * source-order tiebreak silently re-clamped `.page-main` back to 720px
 * on desktop, killing the wider layout for hunts, profile, hunt-detail,
 * toc, and collection. (Audit re-run on 2026-05-11 caught the
 * regression.) Re-issue the desktop max-width here so the rule sits
 * after the base `.page-main` declaration and actually wins. */
@media (min-width: 900px) {
  .page-main { max-width: 1080px; }
}

.muted { color: var(--muted); }

/* Shared empty-state block: a small brand illustration over a one-line
   message. Used wherever a list is intentionally empty (no nearby
   hunts, no profile activity, no collected Curiositters yet). The
   illustrations sit at 280×180 in their SVG viewBox but render small
   in flow; flex-column centers them above the text. The art stays
   muted opacity so it reads as decorative rather than competing with
   the headline copy. */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
  padding: 1.25rem 1rem 1.75rem;
  text-align: center;
}
/* `.empty-state { display: flex }` above wins the cascade over the UA
   stylesheet's `[hidden] { display: none }`, so the SVG + text would
   render alongside real content any time the page started with the
   `hidden` HTML attribute or JS set `.hidden = true`. Pin a matching
   author-specificity rule so the `hidden` attribute actually hides
   (UAT e2e #1 on /toc.html and /state.html). */
.empty-state[hidden] {
  display: none;
}

/* Desktop → phone handoff overlay (UAT e2e #10). Painted by
   desktop-handoff.js on fine-pointer devices when the player lands on
   a phone-only surface (/hunt.html). Full-bleed scrim + centered card
   that the player either uses to email themselves a link or dismisses
   with the "Continue on desktop anyway" button. */
.desktop-handoff-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.82);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 9999;
  padding: 1.5rem;
}
.desktop-handoff-card {
  background: var(--surface, #11162a);
  color: var(--fg, #e8edf6);
  border: 1px solid var(--border, #2a3050);
  border-radius: 12px;
  padding: 1.75rem 1.75rem 1.5rem;
  max-width: 28rem;
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  box-shadow: 0 14px 40px rgba(0, 0, 0, 0.45);
}
.desktop-handoff-card h2 {
  margin: 0;
  font-size: 1.15rem;
}
.desktop-handoff-card p {
  margin: 0;
  color: var(--muted, #9aa3b8);
  line-height: 1.45;
  font-size: 0.95rem;
}
.desktop-handoff-email-row {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  margin-top: 0.25rem;
}
.desktop-handoff-email-row label {
  font-size: 0.8rem;
  color: var(--muted, #9aa3b8);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.desktop-handoff-email-row input {
  padding: 0.55rem 0.75rem;
  border-radius: 8px;
  border: 1px solid var(--border, #2a3050);
  background: rgba(0, 0, 0, 0.25);
  color: var(--fg, #e8edf6);
  font: inherit;
}
.desktop-handoff-send-btn {
  margin-top: 0.25rem;
  align-self: stretch;
}
.desktop-handoff-status {
  min-height: 1.2em;
  font-size: 0.88rem;
}
.desktop-handoff-signin a {
  color: var(--accent-2, #4fc3f7);
  text-decoration: none;
  font-weight: 600;
}
.desktop-handoff-dismiss {
  margin-top: 0.5rem;
  background: none;
  border: none;
  color: var(--muted, #9aa3b8);
  cursor: pointer;
  font: inherit;
  font-size: 0.85rem;
  text-decoration: underline;
  align-self: flex-start;
  padding: 0;
}
.desktop-handoff-dismiss:hover,
.desktop-handoff-dismiss:focus-visible {
  color: var(--fg, #e8edf6);
}
.empty-state-art {
  width: min(220px, 70%);
  height: auto;
  opacity: 0.92;
  pointer-events: none;
}
.empty-state-title {
  margin: 0.15rem 0 0;
  color: var(--fg);
  font-size: clamp(1.35rem, 7vw, 2rem);
  line-height: 1.12;
  text-wrap: balance;
}
.empty-state-text {
  color: var(--muted);
  margin: 0;
  font-size: 0.95rem;
  line-height: 1.45;
  max-width: 28rem;
}
.empty-state--nearby {
  grid-column: 1 / -1;
  align-items: center;
  padding: 1rem;
  border: 1px solid rgba(79, 195, 247, 0.22);
  border-radius: 12px;
  background:
    linear-gradient(135deg, rgba(79, 195, 247, 0.08), rgba(233, 79, 55, 0.05)),
    rgba(15, 22, 48, 0.72);
}
.empty-state--nearby .empty-state-art {
  width: min(180px, 58vw);
}
.empty-state-body {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.55rem;
}
.empty-state-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem;
}
.empty-state-button {
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  padding: 0.5rem 0.85rem;
  border: 1px solid rgba(79, 195, 247, 0.35);
  border-radius: 999px;
  background: rgba(79, 195, 247, 0.12);
  color: var(--fg);
  font-size: 0.85rem;
  font-weight: 700;
  text-decoration: none;
}
.empty-state-cta {
  display: inline-flex;
  align-items: center;
  min-height: 2.35rem;
  margin: 0;
  color: var(--accent);
  font-size: 0.9rem;
  font-weight: 700;
}
@media (min-width: 640px) {
  .empty-state--nearby {
    flex-direction: row;
    justify-content: center;
    text-align: left;
  }
  .empty-state--nearby .empty-state-art {
    width: 150px;
  }
  .empty-state-body {
    align-items: flex-start;
  }
  .empty-state-actions {
    justify-content: flex-start;
  }
}

.leaderboard {
  width: 100%;
  border-collapse: collapse;
  margin-top: 1rem;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
}
.leaderboard th,
.leaderboard td {
  padding: 0.6rem 0.85rem;
  text-align: left;
  border-bottom: 1px solid var(--border);
}
.leaderboard th {
  background: rgba(255, 255, 255, 0.04);
  color: var(--muted);
  text-transform: uppercase;
  font-size: 0.75rem;
  letter-spacing: 0.06em;
}
.leaderboard tr:last-child td { border-bottom: none; }
.leaderboard tr:nth-child(1) td:first-child { color: #f5b700; font-weight: 700; }

.table-scroll-wrap {
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--card);
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
  margin-top: 1rem;
}
.table-scroll-wrap > .leaderboard {
  border: none;
  border-radius: 0;
  overflow: visible;
  margin-top: 0;
  background: transparent;
}

/* ---------- Profile page ---------- */
.profile-card {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 1.25rem;
  margin-bottom: 1.25rem;
}
.avatar {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: var(--accent);
  color: white;
  font-size: 1.5rem;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.profile-info { flex: 1; min-width: 0; }
.profile-info h2 { margin: 0 0 0.2rem; font-size: 1.2rem; }
.profile-info p { margin: 0.15rem 0; font-size: 0.88rem; }
.profile-logout-btn { flex-shrink: 0; align-self: center; }

.stats-strip {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0.75rem;
  margin-bottom: 1.5rem;
}
.stat-box {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 0.85rem 0.5rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.25rem;
}
.stat-value {
  font-size: 1.15rem;
  font-weight: 700;
  color: var(--accent-2);
}
.stat-label {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
}

.profile-history-table .completed-hunt-city {
  font-size: 0.8rem;
}

.profile-history-table .completed-score-cell {
  color: var(--accent-2);
  font-weight: 600;
}

@media (max-width: 640px) {
  .profile-history-table {
    border-collapse: separate;
    border-spacing: 0 0.65rem;
  }

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

  .profile-history-table tbody,
  .profile-history-table tr,
  .profile-history-table td {
    display: block;
    width: 100%;
  }

  .profile-history-table tr {
    background: rgba(255, 255, 255, 0.035);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 0.55rem 0.65rem;
  }

  .profile-history-table td {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.32rem 0;
    border: 0;
    text-align: right;
  }

  .profile-history-table td:first-child {
    display: block;
    padding-bottom: 0.5rem;
    text-align: left;
  }

  .profile-history-table td:not(:first-child)::before {
    content: attr(data-label);
    color: var(--muted);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    text-align: left;
  }
}

/* ---------- Achievements strip ---------- */
.achievements-section {
  margin-bottom: 1.75rem;
}
.achievements-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 0.65rem;
}
.achievements-header .section-heading { margin: 0; }
.achievements-count {
  font-size: 0.78rem;
  font-weight: 700;
  color: #ffb300;
}
.achievements-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 0.55rem;
}
.achievement-badge {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  padding: 0.65rem 0.7rem;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  transition: border-color 0.15s ease, transform 0.15s ease;
}
.achievement-badge.is-earned {
  border-color: rgba(255,193,7,0.55);
  background: linear-gradient(180deg, var(--card) 0%, rgba(255,193,7,0.06) 100%);
}
.achievement-badge.is-earned:hover { transform: translateY(-1px); }
.achievement-badge.is-locked {
  filter: grayscale(0.6);
  opacity: 0.65;
}
.achievement-icon {
  font-size: 1.7rem;
  line-height: 1;
  flex-shrink: 0;
  filter: drop-shadow(0 1px 4px rgba(0,0,0,0.2));
}
.achievement-body {
  flex: 1;
  min-width: 0;
}
.achievement-title {
  font-size: 0.82rem;
  font-weight: 700;
  color: var(--fg);
}
.is-earned .achievement-title { color: #ffb300; }
.achievement-desc {
  font-size: 0.7rem;
  color: var(--muted);
  line-height: 1.3;
  margin-top: 0.1rem;
}
.achievement-progress {
  margin-top: 0.4rem;
  height: 4px;
  background: rgba(255,255,255,0.06);
  border-radius: 999px;
  overflow: hidden;
}
.achievement-progress-fill {
  height: 100%;
  background: linear-gradient(90deg, #9c27b0, #ffb300);
  transition: width 0.4s ease;
}

/* ---------- Collection section ---------- */
.collection-section {
  margin-bottom: 2rem;
}
.collection-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 0.75rem;
}
.collection-header .section-heading {
  margin: 0;
}
.uniqueness-badge {
  background: linear-gradient(135deg, rgba(156,39,176,0.2) 0%, rgba(233,79,55,0.1) 100%);
  border: 1px solid rgba(156,39,176,0.3);
  border-radius: 8px;
  padding: 0.5rem 0.75rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.1rem;
}
.uniqueness-score {
  font-size: 1.3rem;
  font-weight: 700;
  color: #9c27b0;
}
.uniqueness-label {
  font-size: 0.65rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
}
.collection-description {
  margin: 0 0 1rem;
  font-size: 0.9rem;
  color: var(--fg-secondary);
}
.collection-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
  gap: 0.75rem;
}
.asset-card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.75rem;
  text-align: center;
  cursor: pointer;
  transition: all 0.2s ease;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.35rem;
}
.asset-card:hover {
  border-color: #9c27b0;
  background: rgba(156,39,176,0.08);
  transform: translateY(-2px);
}
.asset-card-preview {
  width: 64px;
  height: 64px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.asset-card-preview-fallback {
  font-size: 2.25rem;
  line-height: 1;
}
.asset-card-name {
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--fg);
}
.asset-card-rarity {
  font-size: 0.65rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 700;
}
/* Tier accents — mirror the rarity_tier values returned by /api/assets/* */
.asset-card-common { border-color: rgba(150,150,150,0.35); }
.asset-card-common .asset-card-rarity { color: var(--muted); }
.asset-card-uncommon { border-color: rgba(76,175,80,0.45); }
.asset-card-uncommon .asset-card-rarity { color: #4caf50; }
.asset-card-rare { border-color: rgba(33,150,243,0.5); }
.asset-card-rare .asset-card-rarity { color: #2196f3; }
.asset-card-legendary {
  border-color: rgba(255,193,7,0.6);
  background: linear-gradient(180deg, var(--card) 0%, rgba(255,193,7,0.06) 100%);
}
.asset-card-legendary .asset-card-rarity { color: #ffb300; }

/* ---------- Share-collection button row ---------- */
.collection-share-row {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
  margin-bottom: 0.85rem;
}
.share-collection-feedback {
  font-size: 0.82rem;
  color: var(--accent-2);
  font-weight: 500;
  min-width: 0;
  word-break: break-all;
}
.share-collection-feedback a {
  color: var(--accent-2);
  text-decoration: underline;
}

/* ---------- Shared collection viewer (/c/{token}) ---------- */
.shared-uniqueness {
  display: flex;
  flex-direction: column;
  align-items: center;
  background: linear-gradient(135deg, rgba(156,39,176,0.2) 0%, rgba(255,179,0,0.12) 100%);
  border: 1px solid rgba(156,39,176,0.3);
  border-radius: 8px;
  padding: 0.4rem 0.8rem;
  margin-top: 0.5rem;
  align-self: center;
}
.shared-cta {
  margin: 2.5rem auto 1rem;
  text-align: center;
  padding: 1.25rem 1rem;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 12px;
  max-width: 460px;
}
.shared-cta p {
  margin: 0 0 0.65rem;
  font-weight: 600;
  color: var(--fg);
}

/* ---------- Catalog page ---------- */
.catalog-summary {
  margin-bottom: 1rem;
}
.catalog-progress-row {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 0.85rem 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.catalog-progress-label {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
}
.catalog-progress-count {
  font-size: 1.4rem;
  font-weight: 700;
  color: #9c27b0;
}
.catalog-progress-tag {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--muted);
}
.catalog-progress-bar {
  width: 100%;
  height: 8px;
  background: rgba(156,39,176,0.12);
  border-radius: 999px;
  overflow: hidden;
}
.catalog-progress-fill {
  height: 100%;
  width: 0%;
  /* Wide gradient + slow background-position scroll keeps the bar
     feeling alive. The `width` transition still drives the discovery
     count growth — independent axes, no fight. */
  background: linear-gradient(90deg, #9c27b0, #ffb300, #9c27b0);
  background-size: 200% 100%;
  transition: width 0.4s ease;
  animation: progress-shimmer 4s linear infinite;
}
@keyframes progress-shimmer {
  0%   { background-position: 0% 50%; }
  100% { background-position: 200% 50%; }
}
.catalog-anon-note {
  margin: 0.6rem 0 0;
  text-align: center;
  font-size: 0.88rem;
}

/* Intro "definition" card — frames Curiositter as a dictionary entry
   so first-time visitors learn the word AND the loop in one glance.
   Subtle purple-tinted gradient + a drifting sparkle in the corner
   carry the whimsy without crowding the prose. */
.bestiary-intro {
  position: relative;
  background: linear-gradient(135deg, var(--card) 0%, rgba(156, 39, 176, 0.08) 100%);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 1rem 1.1rem 0.9rem;
  margin-bottom: 1rem;
  overflow: hidden;
}
.bestiary-intro-glyph {
  position: absolute;
  top: 0.5rem;
  right: 0.7rem;
  font-size: 1.4rem;
  line-height: 1;
  pointer-events: none;
  animation: sparkle-drift 6s ease-in-out infinite;
  filter: drop-shadow(0 0 6px rgba(255, 213, 79, 0.45));
}
.bestiary-intro-term {
  margin: 0;
  font-size: 1.35rem;
  font-weight: 800;
  color: #ce93d8;
  letter-spacing: 0.01em;
  text-shadow: 0 0 18px rgba(206, 147, 216, 0.35);
}
.bestiary-intro-pos {
  font-size: 0.7rem;
  font-weight: 600;
  font-style: italic;
  color: var(--muted);
  letter-spacing: 0.06em;
  text-transform: lowercase;
  margin-left: 0.3rem;
  text-shadow: none;
}
.bestiary-intro-pron {
  margin: 0.05rem 0 0.55rem;
  font-size: 0.78rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  color: var(--muted);
  letter-spacing: 0.02em;
}
.bestiary-intro-def {
  margin: 0 0 0.6rem;
  font-size: 0.94rem;
  line-height: 1.5;
  color: var(--fg);
}
.bestiary-intro-hint {
  margin: 0;
  font-size: 0.82rem;
  line-height: 1.45;
  color: var(--fg-secondary);
  display: flex;
  gap: 0.35rem;
  align-items: baseline;
}
.bestiary-intro-hint span {
  flex: 0 0 auto;
}

@keyframes sparkle-drift {
  0%, 100% { transform: translateY(0) rotate(0deg); opacity: 0.85; }
  50%      { transform: translateY(-3px) rotate(8deg); opacity: 1; }
}

/* Centered, rounded "rail" framing the rarity filters so they read as
   one deliberate control rather than a free-floating row of pills. */
.catalog-controls {
  display: flex;
  justify-content: center;
  margin-bottom: 1rem;
}
/* Same specificity as `[hidden] { display: none }`, so the rule above
   wins and the chip rail leaks out before JS unhides it. Pin the
   `hidden` attribute back. Matches the pattern used by .ar-compass,
   .completed-modal, .reveal-discovery, etc. */
.catalog-controls[hidden] { display: none !important; }
.catalog-filters {
  display: inline-flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.35rem;
  padding: 0.35rem 0.55rem;
  background: rgba(156, 39, 176, 0.06);
  border: 1px solid rgba(156, 39, 176, 0.28);
  border-radius: 999px;
  box-shadow: 0 0 16px rgba(156, 39, 176, 0.12);
  max-width: 100%;
}
.catalog-chip {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 999px;
  min-height: 44px;
  padding: 0.35rem 0.45rem 0.35rem 0.75rem;
  font-size: 0.82rem;
  font-weight: 600;
  cursor: pointer;
  color: var(--fg);
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  transition: background-color 0.18s ease, border-color 0.18s ease,
              color 0.18s ease, transform 0.18s ease,
              box-shadow 0.18s ease;
}
.catalog-chip:hover { border-color: rgba(255,255,255,0.35); }
.catalog-chip.is-active {
  background: rgba(156,39,176,0.18);
  border-color: rgba(156,39,176,0.6);
  color: #ce93d8;
  transform: scale(1.04);
  box-shadow: 0 0 12px rgba(156, 39, 176, 0.4);
}
.catalog-chip-count {
  min-width: 1.45rem;
  padding: 0.12rem 0.38rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.08);
  color: var(--fg-secondary);
  font-size: 0.72rem;
  font-weight: 800;
  line-height: 1.2;
  text-align: center;
}
.catalog-chip.is-active .catalog-chip-count {
  background: rgba(255, 255, 255, 0.16);
  color: var(--fg);
}
/* Rarity-tinted accents on the per-tier chips so the filter palette
   matches the card border palette below. The active state for each
   chip uses the same color family so it reads as "I'm filtering to
   THIS rarity." Each tier gets a soft glow in its own color. */
.catalog-chip-common.is-active {
  background: rgba(150,150,150,0.18);
  border-color: rgba(200,200,200,0.6);
  color: #e0e0e0;
  box-shadow: 0 0 12px rgba(200, 200, 200, 0.3);
}
.catalog-chip-uncommon.is-active {
  background: rgba(76,175,80,0.18);
  border-color: rgba(76,175,80,0.6);
  color: #81c784;
  box-shadow: 0 0 12px rgba(76, 175, 80, 0.4);
}
.catalog-chip-rare.is-active {
  background: rgba(33,150,243,0.18);
  border-color: rgba(33,150,243,0.6);
  color: #64b5f6;
  box-shadow: 0 0 12px rgba(33, 150, 243, 0.4);
}
.catalog-chip-legendary.is-active {
  background: rgba(255,193,7,0.22);
  border-color: rgba(255,193,7,0.6);
  color: #ffb300;
  box-shadow: 0 0 14px rgba(255, 193, 7, 0.5);
}

.catalog-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 0.85rem;
}

/* Honor the OS-level "reduce motion" preference — kids on managed
   school devices, anyone with vestibular sensitivity. Layout, color,
   and the active-chip scale stay (those are essential affordances);
   only the ambient keyframe animations freeze. */
@media (prefers-reduced-motion: reduce) {
  .bestiary-intro-glyph,
  .catalog-progress-fill,
  .catalog-entry.is-locked .catalog-entry-preview,
  .catalog-entry-locked-mark {
    animation: none !important;
  }
}

.catalog-entry {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 0.9rem 0.7rem;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.45rem;
  transition: transform 0.15s ease, border-color 0.15s ease;
}
.catalog-entry.is-collected:hover {
  transform: translateY(-2px);
  border-color: #9c27b0;
}
.catalog-entry.is-locked {
  /* Muted slate card to match the toned-down silhouette disc above
     (audit 2026-05-10). The pre-existing #f7f8fb→#e9ecf3 was a
     near-white card on a dark page — locked items dominated the
     bestiary grid and out-shouted the collected rows. */
  background: linear-gradient(180deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0.02) 100%);
  border-color: rgba(255,255,255,0.10);
}
.catalog-entry.is-locked:hover {
  transform: translateY(-2px);
  border-color: rgba(255,255,255,0.30);
}
.catalog-entry-preview {
  position: relative;
  width: 72px;
  height: 72px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.catalog-entry-preview-fallback {
  font-size: 2.4rem;
  line-height: 1;
}
/* Locked preview: white "moon" disc with the discovery animation
   flattened to a black silhouette so kids can see the shape of what
   they're chasing without spoiling color/lore. The gentle float
   keyframe drifts each disc by ±2px on Y + 0.5° rotation; the
   :nth-child delays below stagger them so the grid breathes
   asynchronously rather than as one block. */
.catalog-entry.is-locked .catalog-entry-preview {
  /* Muted silver-slate "moon" rather than a pure-white disc — the
     audit (2026-05-10) flagged the pre-existing #ffffff→#ecedf3
     gradient as too bright against the dark theme, with the locked
     row visually shouting over the collected one. The black
     silhouette still pops cleanly against this lower-brightness
     palette. */
  background: radial-gradient(circle at 50% 42%, #cfd4df 0%, #9aa1b4 78%);
  border-radius: 50%;
  box-shadow: inset 0 -3px 8px rgba(0,0,0,0.10), 0 1px 2px rgba(0,0,0,0.05);
  animation: silhouette-float 4s ease-in-out infinite;
}
@keyframes silhouette-float {
  0%, 100% { transform: translateY(0) rotate(0deg); }
  50%      { transform: translateY(-2px) rotate(0.5deg); }
}
/* Stagger so a row of locked cards doesn't bob in unison — every
   sixth card resets, so within any visible row each position has its
   own phase. */
.catalog-entry.is-locked:nth-child(6n+1) .catalog-entry-preview { animation-delay: 0s; }
.catalog-entry.is-locked:nth-child(6n+2) .catalog-entry-preview { animation-delay: -0.7s; }
.catalog-entry.is-locked:nth-child(6n+3) .catalog-entry-preview { animation-delay: -1.4s; }
.catalog-entry.is-locked:nth-child(6n+4) .catalog-entry-preview { animation-delay: -2.1s; }
.catalog-entry.is-locked:nth-child(6n+5) .catalog-entry-preview { animation-delay: -2.8s; }
.catalog-entry.is-locked:nth-child(6n)   .catalog-entry-preview { animation-delay: -3.5s; }
.catalog-entry.is-locked .catalog-entry-preview svg {
  filter: brightness(0) saturate(100%);
  opacity: 0.85;
}
.catalog-entry.is-locked .catalog-entry-preview-fallback {
  color: #1a1d24;
  font-weight: 800;
}
/* Purple "?" badge floats over the silhouette to telegraph "unknown
   trophy." Sits above the SVG in z-order; disappears once collected
   because the badge element is only rendered for locked cards.
   z-index is required because Lottie appends its SVG as a later
   sibling — without it the silhouette paints on top of the mark and
   the "?" only shows through the SVG's transparent pixels. */
.catalog-entry-locked-mark {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.9rem;
  font-weight: 900;
  color: #9c27b0;
  /* Drop shadow matched to the toned-down disc's top tint instead of
     pure #fff so the "?" still reads as raised but doesn't punch a
     bright spot through the muted silhouette card. */
  text-shadow: 0 1px 0 #cfd4df, 0 0 6px rgba(156, 39, 176, 0.45);
  pointer-events: none;
  animation: mark-bobble 2.5s ease-in-out infinite;
}
@keyframes mark-bobble {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-1.5px); }
}
.catalog-entry-name {
  margin: 0;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--fg);
}
.catalog-entry.is-locked .catalog-entry-name {
  color: #1a1d24;
}
.catalog-entry-meta {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  align-items: center;
}
.catalog-entry-rarity {
  font-size: 0.65rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.catalog-entry.is-locked .catalog-entry-rarity {
  color: #555a66;
}
.catalog-entry-encounters {
  font-size: 0.7rem;
  color: var(--muted);
}
.catalog-entry-desc {
  margin: 0.25rem 0 0;
  font-size: 0.78rem;
  color: var(--fg-secondary);
  line-height: 1.35;
}
/* Tier color accents reuse the .asset-card-* palette so the catalog
   entries match the profile collection cards. */
.catalog-entry-common { border-color: rgba(150,150,150,0.35); }
.catalog-entry-common .catalog-entry-rarity { color: var(--muted); }
.catalog-entry-uncommon { border-color: rgba(76,175,80,0.45); }
.catalog-entry-uncommon .catalog-entry-rarity { color: #4caf50; }
.catalog-entry-rare { border-color: rgba(33,150,243,0.5); }
.catalog-entry-rare .catalog-entry-rarity { color: #2196f3; }
.catalog-entry-legendary {
  border-color: rgba(255,193,7,0.6);
  background: linear-gradient(180deg, var(--card) 0%, rgba(255,193,7,0.06) 100%);
}
.catalog-entry-legendary .catalog-entry-rarity { color: #ffb300; }

/* ---------- Asset detail modal (shared by profile + catalog) ---------- */
.asset-modal {
  position: fixed;
  inset: 0;
  z-index: 9000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  animation: asset-modal-in 0.2s ease-out;
}
/* The `display: flex` above has the same specificity as the UA `[hidden]`
   rule, so without this override the modal stays visible even after
   closeAssetModal() sets the hidden attribute — the X / backdrop / Esc
   look broken when in fact only the paint is wrong. */
.asset-modal[hidden] { display: none !important; }
@keyframes asset-modal-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.asset-modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(10, 15, 35, 0.78);
  backdrop-filter: blur(4px);
}
.asset-modal-card {
  position: relative;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 14px;
  max-width: 460px;
  width: 100%;
  padding: 1.4rem 1.2rem 1.2rem;
  text-align: center;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  max-height: 90vh;
  overflow-y: auto;
  box-shadow: 0 12px 48px rgba(0, 0, 0, 0.5);
  animation: asset-modal-card-in 0.25s cubic-bezier(0.2, 0.9, 0.4, 1.2);
}
@keyframes asset-modal-card-in {
  from { transform: translateY(12px) scale(0.96); opacity: 0; }
  to   { transform: translateY(0) scale(1); opacity: 1; }
}
.asset-modal-close {
  position: absolute;
  top: 0.5rem;
  right: 0.7rem;
  min-width: 2.75rem;
  min-height: 2.75rem;
  background: transparent;
  border: none;
  color: var(--muted);
  font-size: 1.6rem;
  line-height: 1;
  cursor: pointer;
  padding: 0;
  border-radius: 6px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.asset-modal-close:hover,
.asset-modal-close:focus-visible { color: var(--fg); background: rgba(255,255,255,0.05); }
.asset-modal-preview {
  position: relative;
  width: 160px;
  height: 160px;
  margin: 0.25rem auto 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(255,255,255,0.04);
  border-radius: 14px;
  overflow: hidden;
}
.asset-modal-fallback { font-size: 4rem; line-height: 1; }
/* Purple "?" badge over the locked silhouette in the detail modal —
   matches the catalog card overlay so the visual language stays
   consistent. Only rendered for locked entries; vanishes once owned.
   z-index keeps it above the Lottie SVG (Lottie is appended after the
   mark, so without this the silhouette would paint over the "?"). */
.asset-modal-locked-mark {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 4.2rem;
  font-weight: 900;
  color: #9c27b0;
  text-shadow: 0 2px 0 #fff, 0 0 14px rgba(156, 39, 176, 0.55);
  pointer-events: none;
}
.asset-modal-tier {
  display: inline-block;
  align-self: center;
  font-size: 0.7rem;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 0.25rem 0.7rem;
  border-radius: 999px;
  background: rgba(255,255,255,0.08);
}
.asset-modal-name {
  margin: 0;
  font-size: 1.4rem;
  font-weight: 700;
  color: var(--fg);
}
.asset-modal-desc {
  margin: 0;
  font-size: 0.95rem;
  color: var(--fg-secondary);
  line-height: 1.45;
  padding: 0 0.4rem;
}
.asset-modal-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  justify-content: center;
  margin: -0.2rem 0 0.1rem;
}
.asset-modal-badges:empty { display: none; }
.asset-modal-badge {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  padding: 0.2rem 0.55rem;
  border-radius: 999px;
  background: rgba(255,255,255,0.06);
  border: 1px solid rgba(255,255,255,0.14);
  color: var(--fg);
  text-transform: capitalize;
}
.asset-modal-badge-rarity {
  background: rgba(156,39,176,0.18);
  border-color: rgba(156,39,176,0.35);
  color: #ce93d8;
  text-transform: none;
}
.asset-modal-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  justify-content: center;
}
.asset-modal-meta-pill {
  font-size: 0.75rem;
  font-weight: 600;
  padding: 0.2rem 0.6rem;
  border-radius: 999px;
  background: rgba(156,39,176,0.15);
  border: 1px solid rgba(156,39,176,0.3);
  color: #ce93d8;
}
.asset-modal-attributes {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.4rem;
  margin-top: 0.4rem;
}
.asset-modal-attribute {
  display: flex;
  flex-direction: column;
  align-items: center;
  background: rgba(255,255,255,0.04);
  border-radius: 8px;
  padding: 0.5rem 0.4rem;
}
.asset-modal-attribute-label {
  font-size: 0.65rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
  font-weight: 700;
}
.asset-modal-attribute-value {
  font-size: 0.85rem;
  color: var(--fg);
  font-weight: 500;
  margin-top: 0.15rem;
  text-transform: capitalize;
}
/* Tier accents on the modal mirror the card palette. */
.asset-modal-common .asset-modal-tier { background: rgba(150,150,150,0.18); color: var(--muted); }
.asset-modal-uncommon .asset-modal-tier { background: rgba(76,175,80,0.18); color: #81c784; }
.asset-modal-rare .asset-modal-tier { background: rgba(33,150,243,0.18); color: #64b5f6; }
.asset-modal-legendary .asset-modal-tier { background: rgba(255,193,7,0.22); color: #ffb300; }
.asset-modal-legendary .asset-modal-card {
  border-color: rgba(255,193,7,0.5);
  box-shadow: 0 0 32px rgba(255,193,7,0.2), 0 12px 48px rgba(0,0,0,0.5);
}
.asset-modal.is-locked .asset-modal-preview {
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #ecedf3 78%);
  border-radius: 50%;
  box-shadow: inset 0 -4px 12px rgba(0,0,0,0.06);
}
.asset-modal.is-locked .asset-modal-preview svg {
  filter: brightness(0) saturate(100%);
  opacity: 0.85;
}
.asset-modal.is-locked .asset-modal-fallback { color: #1a1d24; font-weight: 800; }
body.asset-modal-open { overflow: hidden; }
body.reveal-open { overflow: hidden; }

/* Make collection cards feel tappable on hover */
.asset-card { cursor: pointer; }
.catalog-entry.is-collected { cursor: pointer; }
.catalog-entry.is-locked { cursor: pointer; }

.section-heading {
  margin: 0 0 0.75rem;
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--muted);
}

.hunt-rows { list-style: none; padding: 0; margin: 0 0 1.5rem; display: flex; flex-direction: column; gap: 0.6rem; }
.hunt-row {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 0.9rem 1rem;
  display: flex;
  align-items: center;
  gap: 1rem;
}
.hunt-row-info {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  font-size: 0.9rem;
  min-width: 0;
}
.btn-sm {
  padding: 0.45rem 0.85rem;
  font-size: 0.85rem;
  white-space: nowrap;
}

@media (max-width: 480px) {
  .stats-strip { grid-template-columns: repeat(2, 1fr); }
  .profile-card { flex-direction: column; text-align: center; }
  .profile-logout-btn { align-self: stretch; }

  #section-completed .table-scroll-wrap {
    overflow-x: visible;
  }
  #section-completed .leaderboard {
    border: 0;
    background: transparent;
  }
  #section-completed .leaderboard thead {
    display: none;
  }
  #section-completed .leaderboard tbody {
    display: flex;
    flex-direction: column;
    gap: 0.65rem;
  }
  #section-completed .leaderboard tr {
    display: block;
    padding: 0.8rem;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--card);
  }
  #section-completed .leaderboard td {
    display: flex;
    justify-content: space-between;
    gap: 0.85rem;
    padding: 0.25rem 0;
    border-bottom: 0;
    text-align: right;
  }
  #section-completed .leaderboard td:first-child {
    display: block;
    padding-bottom: 0.55rem;
    text-align: left;
  }
  #section-completed .leaderboard td:not(:first-child)::before {
    color: var(--muted);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
  }
  #section-completed .leaderboard td:nth-child(2)::before { content: "Score"; }
  #section-completed .leaderboard td:nth-child(3)::before { content: "Time"; }
  #section-completed .leaderboard td:nth-child(4)::before { content: "Hints"; }
  #section-completed .leaderboard td:nth-child(5)::before { content: "Completed"; }
}

/* ---------- Admin UI ---------- */
.admin-layout {
  max-width: 1100px;
  display: grid;
  grid-template-columns: 260px 1fr;
  gap: 1.5rem;
  align-items: start;
}
/* stack on narrow screens */
@media (max-width: 720px) {
  .admin-layout { grid-template-columns: 1fr; }
}

.admin-sidebar {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
}
.sidebar-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--border);
  background: rgba(255,255,255,0.03);
}
.sidebar-header h3 { margin: 0; font-size: 0.9rem; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }

.admin-hunt-list { list-style: none; padding: 0; margin: 0; }
.admin-hunt-item {
  padding: 0.7rem 1rem;
  cursor: pointer;
  border-bottom: 1px solid var(--border);
  transition: background 120ms;
}
.admin-hunt-item:last-child { border-bottom: none; }
.admin-hunt-item:hover { background: rgba(255,255,255,0.04); }
.admin-hunt-item.active { background: rgba(79,195,247,0.1); border-left: 3px solid var(--accent-2); }
.hunt-item-title { display: block; font-weight: 600; font-size: 0.9rem; }
.hunt-item-meta { display: block; font-size: 0.78rem; color: var(--muted); margin-top: 0.1rem; }

/* Ship 12: red dot on the admin hunt sidebar when a hunt has ≥1
   unresolved player-filed StopReport. Inline with the title so the
   admin sees it without expanding the hunt. */
.hunt-item-reports-badge {
  display: inline-block;
  margin-left: 0.5rem;
  padding: 0 0.4rem;
  min-width: 1.2rem;
  height: 1.2rem;
  line-height: 1.2rem;
  text-align: center;
  background: var(--accent-warn, #d44);
  color: #fff;
  font-size: 0.7rem;
  font-weight: 600;
  border-radius: 999px;
  vertical-align: 1px;
}

.admin-detail {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 1.25rem;
  min-height: 200px;
}

/* Admin forms */
.admin-form {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}
.admin-form h3, .admin-form h4 { margin: 0 0 0.25rem; }
.admin-form textarea {
  padding: 0.6rem 0.75rem;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: rgba(255,255,255,0.04);
  color: var(--fg);
  font-size: 0.95rem;
  font-family: inherit;
  resize: vertical;
}
.form-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-top: 0.25rem; }

.btn-primary { background: var(--accent); color: white; border: none; padding: .55rem 1rem; border-radius: 6px; font-weight: 600; cursor: pointer; font-size: .9rem; }
.btn-ghost { background: transparent; color: var(--muted); border: 1px solid var(--border); padding: .5rem 0.9rem; border-radius: 6px; cursor: pointer; font-size: .9rem; }
.btn-ghost:hover,
.btn-ghost:focus-visible { background: rgba(255,255,255,0.05); }
.btn-danger { background: transparent; color: #ff7070; border: 1px solid #ff7070; padding: .5rem 0.9rem; border-radius: 6px; cursor: pointer; font-size: .9rem; }
.btn-danger:hover,
.btn-danger:focus-visible { background: rgba(255,80,80,0.1); }
.btn-xs { padding: .5rem .75rem; font-size: .8rem; border-radius: 5px; min-height: 2.75rem; }

/* Stops section */
.stops-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin: 1.5rem 0 0.75rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--border);
}
.stops-header h3 { margin: 0; font-size: 0.9rem; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }

/* Author dashboard for player-filed stop-issue reports. Same shape as
 * .stops-header so it nests under the stops list as a sibling section,
 * not visually a child of any one stop. */
.reports-section { margin-top: 1.5rem; padding-top: 1.25rem; border-top: 1px solid var(--border); }
.reports-header { display: flex; justify-content: space-between; align-items: center; margin: 0 0 0.75rem; }
.reports-header h3 { margin: 0; font-size: 0.9rem; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }
.reports-total-badge {
  display: inline-block;
  margin-left: 0.5rem;
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 600;
  background: rgba(220, 53, 69, 0.18);
  color: #ff6b6b;
  border: 1px solid rgba(220, 53, 69, 0.4);
  text-transform: none;
  letter-spacing: 0;
}
.reports-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 0.5rem; }
.reports-item {
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.6rem 0.85rem;
  font-size: 0.85rem;
}
.reports-item-head { display: flex; justify-content: space-between; align-items: baseline; gap: 0.5rem; flex-wrap: wrap; }
.reports-item-stop { font-weight: 600; }
.reports-item-reason {
  font-size: 0.72rem;
  font-weight: 600;
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  background: rgba(245, 183, 0, 0.18);
  color: #f5b700;
  border: 1px solid rgba(245, 183, 0, 0.4);
}
.reports-item-note { margin: 0.4rem 0; color: var(--fg); white-space: pre-wrap; }
.reports-item-foot { display: flex; justify-content: space-between; align-items: center; gap: 0.5rem; margin-top: 0.4rem; font-size: 0.78rem; flex-wrap: wrap; }

#stops-map {
  height: 260px;
  border-radius: 8px;
  margin-bottom: 1rem;
  border: 1px solid var(--border);
  overflow: hidden;
}

.stops-list { list-style: none; padding: 0; margin: 0 0 1rem; display: flex; flex-direction: column; gap: .5rem; }
.stop-item {
  display: flex;
  align-items: flex-start;
  gap: .75rem;
  background: rgba(255,255,255,0.03);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: .7rem .85rem;
}
.stop-item-num {
  width: 24px; height: 24px; flex-shrink: 0;
  background: var(--accent-2);
  color: #0b1020;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: .75rem; font-weight: 700;
}
.stop-item-body { flex: 1; font-size: .88rem; min-width: 0; }
.stop-item-body .muted { font-size: .78rem; display: block; margin: .15rem 0; }
.stop-clue-preview { margin: .25rem 0 0; color: var(--muted); font-size: .82rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.stop-item-actions { display: flex; gap: .35rem; align-items: flex-start; }

.stop-form {
  margin-top: 1rem;
  padding: 1rem;
  background: rgba(255,255,255,0.03);
  border: 1px solid var(--border);
  border-radius: 8px;
}
.stop-form-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: .6rem;
  margin-bottom: .6rem;
}
@media (max-width: 560px) { .stop-form-grid { grid-template-columns: 1fr; } }

/* ══════════════════════════════════════════════════════════════════════
   HUNT CARD GRID  (hunts index page)
   ══════════════════════════════════════════════════════════════════════ */
.hunt-card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr));
  gap: 0.85rem;
  margin-top: 0.75rem;
}
.hunt-card {
  display: flex;
  flex-direction: column;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: visible;
  text-decoration: none;
  color: var(--fg);
  min-height: 100%;
  transition: border-color 150ms, box-shadow 150ms, transform 150ms;
}
.hunt-card:hover,
.hunt-card:focus-visible {
  border-color: rgba(79, 195, 247, 0.5);
  box-shadow: 0 10px 26px rgba(0, 0, 0, 0.22);
  transform: translateY(-2px);
}
.hunt-card-img-wrap {
  position: relative;
  aspect-ratio: 16 / 9;
  min-height: 138px;
  max-height: 164px;
  background: #121830;
  border-radius: 12px 12px 0 0;
  overflow: hidden;
  flex-shrink: 0;
}
.hunt-card-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.hunt-card-img-overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, transparent 40%, rgba(8, 13, 35, 0.75) 100%);
}
.hunt-card-badge {
  position: absolute;
  top: 8px;
  right: 8px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 8px;
  border-radius: 999px;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.hunt-card-badge--done {
  background: rgba(16, 40, 16, 0.88);
  color: #a3e635;
  border: 1px solid rgba(163, 230, 53, 0.35);
}
.hunt-card-badge--progress {
  background: rgba(10, 30, 55, 0.88);
  color: var(--accent-2);
  border: 1px solid rgba(79, 195, 247, 0.35);
}
/* Pinned top-left so it can coexist with the top-right --done /
   --progress status pill on the same card. */
.hunt-card-badge--owned {
  top: 8px;
  left: 8px;
  right: auto;
  background: rgba(40, 24, 8, 0.88);
  color: #f5c46b;
  border: 1px solid rgba(245, 196, 107, 0.4);
}
.hunt-card-body {
  padding: 0.8rem 0.9rem 0.9rem;
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}
.hunt-card-title {
  margin: 0;
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.2;
  color: var(--fg);
}
.hunt-card-meta {
  display: flex;
  align-items: center;
  gap: 0.28rem 0.5rem;
  color: var(--muted);
  font-size: 0.8rem;
  flex-wrap: wrap;
  line-height: 1.35;
}

/* Ship 13: amber chip rendered inline with the hunt-card meta line
   when a hunt has concerning unresolved player reports (≥3 total or
   any safety / private-property / unsafe-road class). Only renders
   when `hunt.report_health === "concerning"` so the badge stays
   meaningful. */
.hunt-card-reports-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.05rem 0.45rem;
  border-radius: 0.6rem;
  background: rgba(255, 176, 64, 0.18);
  color: #ffb040;
  font-weight: 600;
  font-size: 0.72rem;
  border: 1px solid rgba(255, 176, 64, 0.35);
}

/* Hunt-level difficulty badge — Easy / Medium / Hard. Rendered on
   browse cards, the hunt-detail meta strip, and admin tables. Colors
   are muted so the badge sits alongside other chips without shouting.
   See docs/HUNT_DESIGN.md § Hunt-level difficulty. */
.hunt-difficulty-badge {
  display: inline-block;
  padding: 0.1rem 0.55rem;
  border-radius: 0.6rem;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  border: 1px solid transparent;
  line-height: 1.4;
}
.hunt-difficulty-badge--easy {
  background: rgba(56, 161, 105, 0.20);
  color: #9ae6b4;
  border-color: rgba(56, 161, 105, 0.40);
}
.hunt-difficulty-badge--medium {
  background: rgba(214, 158, 46, 0.22);
  color: #faf089;
  border-color: rgba(214, 158, 46, 0.42);
}
.hunt-difficulty-badge--hard {
  background: rgba(245, 101, 101, 0.22);
  color: #fc8181;
  border-color: rgba(245, 101, 101, 0.42);
}

.hunt-difficulty-badge[data-difficulty-help] {
  position: relative;
  cursor: help;
  text-decoration: none;
  transition: transform 120ms ease, border-color 120ms ease, box-shadow 120ms ease;
}
.hunt-difficulty-badge[data-difficulty-help]:hover,
.hunt-difficulty-badge[data-difficulty-help]:focus-visible {
  transform: translateY(-1px);
  border-color: currentColor;
  box-shadow: 0 0 0 3px rgba(79, 195, 247, 0.16);
  outline: none;
}
.hunt-difficulty-badge[data-tooltip]:hover::after,
.hunt-difficulty-badge[data-tooltip]:focus-visible::after {
  content: attr(data-tooltip);
  position: absolute;
  left: 50%;
  bottom: calc(100% + 0.55rem);
  z-index: 30;
  width: min(260px, 70vw);
  transform: translateX(-50%);
  padding: 0.55rem 0.65rem;
  border-radius: 0.6rem;
  background: rgba(6, 10, 24, 0.96);
  border: 1px solid rgba(255, 255, 255, 0.16);
  color: var(--fg);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: normal;
  line-height: 1.35;
  text-transform: none;
  white-space: normal;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.35);
}
.hunt-difficulty-badge[data-tooltip]:hover::before,
.hunt-difficulty-badge[data-tooltip]:focus-visible::before {
  content: "";
  position: absolute;
  left: 50%;
  bottom: calc(100% + 0.25rem);
  z-index: 31;
  transform: translateX(-50%) rotate(45deg);
  width: 0.55rem;
  height: 0.55rem;
  background: rgba(6, 10, 24, 0.96);
  border-right: 1px solid rgba(255, 255, 255, 0.16);
  border-bottom: 1px solid rgba(255, 255, 255, 0.16);
}

/* Difficulty-gated compass hint shown under the Open Camera button on
   medium/hard hunts when the player is out of range. Hidden via the
   `hidden` attribute when in range or on easy hunts. */
.compass-locked-hint {
  display: block;
  width: 100%;
  margin: 0.15rem 0 0.3rem;
  font-size: 0.78rem;
  color: var(--muted);
  opacity: 0.85;
  text-align: center;
}
.hunt-card-desc {
  margin: 0;
  font-size: 0.85rem;
  color: var(--muted);
  line-height: 1.38;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.hunt-card-progress {
  height: 3px;
  background: rgba(255, 255, 255, 0.1);
  border-radius: 2px;
  overflow: hidden;
  margin-top: auto;
}
.hunt-card-progress-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--accent-2), #a3e635);
  border-radius: 2px;
}

/* ══════════════════════════════════════════════════════════════════════
   AMBIENT SCENE  (hunt page — city-themed animated backdrop)
   The Lottie scene paints into #ambient-bg; per-city sky gradient is
   set inline by renderAmbientScene() in hunt.js. The .scene-stage is
   anchored to the top so the clue card (which sits flex-bottom in
   #overlay) stays unobstructed.
   ══════════════════════════════════════════════════════════════════════ */
.ambient-bg {
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  transition: background 0.6s ease;
}
.scene-stage {
  position: absolute;
  /* Offset below the .hunt-header strip + safe-area inset so the glyphs
     don't clip into the "Back · Clue N of M" bar on phones with a
     status-bar / dynamic island. Tuned to sit just under the header
     edge — the header itself has a semi-transparent dark backdrop, so
     the highest glyph reads as "peeking" rather than clipping when it
     brushes the bottom of the bar. Expressed in `rem` so the offset
     scales alongside the header (which is `rem`-padded) when the user
     increases default font size. */
  top: calc(env(safe-area-inset-top, 0px) + 2rem);
  left: 0;
  right: 0;
  height: 42vh;
  pointer-events: none;
}
/* Bottom fade — scene melts into the dark page background so the
   clue card's edge isn't a hard line. */
.scene-stage::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 30%;
  background: linear-gradient(180deg, transparent 0%, var(--bg) 100%);
}
.scene-glyph {
  position: absolute;
  width: clamp(56px, 14vw, 96px);
  height: clamp(56px, 14vw, 96px);
  filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.15));
  will-change: transform;
}
.scene-glyph svg {
  width: 100%;
  height: 100%;
}

/* Six fixed positions across the upper viewport. Three motion
   keyframes (bob, drift, spin-soft) staggered by delay so the scene
   doesn't pulse in unison. */
.scene-glyph-0 { top: 12%; left:  6%; animation: scene-bob   4.2s ease-in-out infinite; }
.scene-glyph-1 { top: 30%; left: 22%; animation: scene-drift 7.0s ease-in-out infinite; animation-delay: -0.6s; }
.scene-glyph-2 { top: 16%; left: 42%; animation: scene-bob   5.1s ease-in-out infinite; animation-delay: -1.2s; }
.scene-glyph-3 { top:  6%; left: 62%; animation: scene-drift 6.4s ease-in-out infinite; animation-delay: -2.0s; }
.scene-glyph-4 { top: 34%; left: 72%; animation: scene-bob   4.7s ease-in-out infinite; animation-delay: -0.3s; }
.scene-glyph-5 { top: 18%; left: 86%; animation: scene-spin  9.0s ease-in-out infinite; animation-delay: -1.8s; }

@keyframes scene-bob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-12px); }
}
@keyframes scene-drift {
  0%, 100% { transform: translate(0, 0) rotate(-2deg); }
  50%      { transform: translate(8px, -10px) rotate(3deg); }
}
@keyframes scene-spin {
  0%, 100% { transform: rotate(-6deg); }
  50%      { transform: rotate(6deg); }
}

/* Honor OS-level reduce-motion: freeze the wrapper transforms.
   Lottie itself keeps looping internally (the per-glyph idle is
   gentle and not the source of vestibular trouble). */
@media (prefers-reduced-motion: reduce) {
  .scene-glyph { animation: none !important; }
}

/* ══════════════════════════════════════════════════════════════════════
   HUNT INTRO SCREEN
   ══════════════════════════════════════════════════════════════════════ */
.intro-screen {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: flex;
  align-items: flex-end;
}
/* The `display: flex` above has the same specificity as the UA `[hidden]`
   rule, so setting `hidden=true` alone doesn't guarantee the screen hides.
   Force display:none whenever the attribute is present. */
.intro-screen[hidden] { display: none !important; }
.intro-inner {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  overflow: hidden;
}
.intro-cover-wrap {
  position: relative;
  flex: 1;
  min-height: 0;
}
.intro-cover {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.intro-cover-overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    180deg,
    rgba(0, 0, 0, 0.1) 0%,
    rgba(8, 13, 35, 0.5) 60%,
    rgba(8, 13, 35, 0.95) 100%
  );
}
.intro-body {
  position: relative;
  z-index: 1;
  background: rgba(8, 13, 35, 0.97);
  padding: 1.25rem 1.5rem env(safe-area-inset-bottom, 1.5rem);
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.intro-eyebrow {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--accent-2);
}
.intro-title {
  margin: 0;
  font-size: 1.5rem;
  font-weight: 800;
  line-height: 1.15;
  color: var(--fg);
}
.intro-desc {
  margin: 0;
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--muted);
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.intro-stats {
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
  margin: 0.15rem 0;
}
.intro-stat {
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.intro-stat-label {
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--muted);
}
.intro-stat-value {
  font-size: 0.95rem;
  font-weight: 700;
  color: var(--fg);
}
.intro-begin-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  width: 100%;
  padding: 0.9rem 1rem;
  margin-top: 0.35rem;
  background: var(--accent);
  color: white;
  border: none;
  border-radius: 12px;
  font-size: 1.05rem;
  font-weight: 700;
  cursor: pointer;
  letter-spacing: 0.01em;
}
.intro-begin-btn:hover,
.intro-begin-btn:focus-visible { background: #d94430; }
.intro-begin-btn--starting {
  animation: intro-begin-pulse 900ms ease-in-out infinite;
  cursor: progress;
}
.intro-begin-btn--starting img { display: none; }
@keyframes intro-begin-pulse {
  0%, 100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(245, 84, 53, 0.5); }
  50%      { transform: scale(1.02); box-shadow: 0 0 0 12px rgba(245, 84, 53, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .intro-begin-btn--starting { animation: none; }
}
.intro-error {
  margin: 0 0 0.25rem;
  padding: 0.55rem 0.75rem;
  border-radius: 10px;
  background: rgba(220, 53, 41, 0.12);
  border: 1px solid rgba(220, 53, 41, 0.35);
  color: #ffb4ab;
  font-size: 0.9rem;
  line-height: 1.3;
}

/* ══════════════════════════════════════════════════════════════════════
   AR ICON OVERLAYS  (lock / unlock / sparkle)
   ══════════════════════════════════════════════════════════════════════ */
.ar-icons {
  position: absolute;
  top: 30%;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  pointer-events: none;
  z-index: 3;
}
.ar-icon-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
}
/* Ensure the `hidden` attribute actually hides #ar-lock / #ar-unlock.
   Without this override, both icons are painted on page load — so a
   player who is 5 km away still sees the green "YOU'RE HERE!" unlock
   label stacked over the compass. Same specificity fix as .ar-compass. */
.ar-icon-wrap[hidden] { display: none !important; }
.ar-icon-img {
  width: 64px;
  height: 64px;
  filter: drop-shadow(0 4px 14px rgba(0, 0, 0, 0.65));
}
.ar-icon-label {
  font-size: 0.8rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: rgba(255, 255, 255, 0.8);
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.8);
}

/* Lock — de-emphasized, pinned bottom-right of the camera overlay so it
   doesn't compete with the compass arrow, Lottie discovery, or arrive
   CTA in the middle of the frame. Small, low-opacity, red drop-shadow
   to signal "not yet arrived" without dominating the view.

   `position: absolute` resolves against the nearest positioned ancestor
   (.camera-overlay, which is `position: fixed`). #ar-lock is a direct
   child of .camera-overlay — NOT nested inside #ar-icons — because
   #ar-icons has a `transform` that would create a new containing block
   for any `position: fixed` descendants and hijack the offsets. */
.ar-lock {
  position: absolute;
  bottom: calc(1rem + env(safe-area-inset-bottom, 0));
  right: calc(1rem + env(safe-area-inset-right, 0));
  top: auto;
  left: auto;
  transform: none;
  flex-direction: row;
  align-items: center;
  gap: 0.35rem;
  opacity: 0.55;
  z-index: 5;
  pointer-events: none;
}
.ar-lock .ar-icon-img {
  width: 24px;
  height: 24px;
  filter: drop-shadow(0 2px 6px rgba(233, 79, 55, 0.55));
}
.ar-lock .ar-icon-label {
  font-size: 0.65rem;
  letter-spacing: 0.08em;
}

/* Unlock — green, pulses in */
.ar-unlock .ar-icon-img {
  filter: drop-shadow(0 4px 18px rgba(80, 220, 130, 0.7));
}
.ar-unlock-label {
  color: #a3e635;
  font-size: 0.95rem;
}
@keyframes ar-icon-pop {
  0%   { opacity: 0; transform: scale(0.5); }
  60%  { opacity: 1; transform: scale(1.15); }
  100% { opacity: 1; transform: scale(1); }
}
.ar-icon-pulse {
  animation: ar-icon-pop 0.45s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}

/* Sparkle ring overlay */
.ar-sparkle-ring {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 200px;
  height: 200px;
  pointer-events: none;
}
.ar-sparkle-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.ar-sparkle-outer {
  animation: sparkle-spin 1.2s linear forwards;
  opacity: 0;
}
.ar-sparkle-inner {
  animation: sparkle-pop 0.6s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
  opacity: 0;
}
@keyframes sparkle-spin {
  0%   { opacity: 0; transform: rotate(-30deg) scale(0.6); }
  15%  { opacity: 1; }
  80%  { opacity: 1; transform: rotate(20deg) scale(1.05); }
  100% { opacity: 0; transform: rotate(30deg) scale(1.1); }
}
@keyframes sparkle-pop {
  0%   { opacity: 0; transform: scale(0.4); }
  40%  { opacity: 1; transform: scale(1.2); }
  70%  { transform: scale(0.9); }
  85%  { opacity: 1; transform: scale(1); }
  100% { opacity: 0; transform: scale(1); }
}

/* Individual star particles — offset staggered */
.ar-sparkle-star {
  width: 32px;
  height: 32px;
  inset: unset;
  animation: star-fly 0.9s ease-out forwards;
  opacity: 0;
}
.ar-sparkle-star1 { top: 10%;  left: 20%;  animation-delay: 0.05s; }
.ar-sparkle-star2 { top: 15%;  right: 18%; animation-delay: 0.12s; }
.ar-sparkle-star3 { bottom: 12%; left: 50%; margin-left: -16px; animation-delay: 0.18s; }
@keyframes star-fly {
  0%   { opacity: 0; transform: scale(0) rotate(0deg); }
  25%  { opacity: 1; }
  100% { opacity: 0; transform: scale(1.4) rotate(45deg) translateY(-20px); }
}

/* ══════════════════════════════════════════════════════════════════════
   REVEAL SHEET ENHANCEMENTS
   ══════════════════════════════════════════════════════════════════════ */
.reveal-photo-wrap {
  margin-bottom: 0.75rem;
}
/* .reveal-image already styled above — just inherits from that rule */

.next-clue-deco {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-bottom: 0.35rem;
}
.next-clue-deco-icon {
  opacity: 0.6;
  flex-shrink: 0;
}
.photo-challenge-label {
  display: flex;
  align-items: center;
  gap: 0.35rem;
}

/* ══════════════════════════════════════════════════════════════════════
   COMPLETION SCREEN ENHANCEMENTS
   ══════════════════════════════════════════════════════════════════════ */
.completed-trophy {
  position: relative;
  width: 96px;
  height: 96px;
  margin: 0 auto 0.75rem;
}
.completed-trophy-icon {
  position: relative;
  z-index: 1;
  width: 56px;
  height: 56px;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  filter: drop-shadow(0 4px 12px rgba(245, 183, 0, 0.6));
  animation: trophy-drop 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}
@keyframes trophy-drop {
  0%   { opacity: 0; transform: translate(-50%, -60%) scale(0.6); }
  100% { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}
.completed-trophy-ring {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  animation: ring-spin 2.5s linear infinite;
  opacity: 0.7;
}
@keyframes ring-spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* Photo collage */
.photo-collage {
  margin: 0.75rem 0;
  text-align: left;
}
.photo-collage-label {
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  margin-bottom: 0.45rem;
}
.photo-collage-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 4px;
}
.collage-photo {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: 4px;
  border: 1px solid var(--border);
  display: block;
}

/* Medal row */
.medal-row {
  display: flex;
  justify-content: center;
  gap: 1.5rem;
  flex-wrap: wrap;
  margin: 0.5rem 0 1rem;
}
.medal-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.3rem;
}
.medal-item img {
  filter: drop-shadow(0 2px 6px rgba(245, 183, 0, 0.4));
  animation: medal-pop 0.45s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}
@keyframes medal-pop {
  0%   { opacity: 0; transform: scale(0.5) rotate(-15deg); }
  100% { opacity: 1; transform: scale(1) rotate(0deg); }
}
.medal-item span {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--muted);
}

/* ---------- PWA install banner ---------- */
.pwa-install-banner {
  position: fixed;
  left: max(0.75rem, env(safe-area-inset-left, 0.75rem));
  right: max(0.75rem, env(safe-area-inset-right, 0.75rem));
  bottom: calc(0.75rem + env(safe-area-inset-bottom, 0));
  max-width: 480px;
  margin: 0 auto;
  background: rgba(10, 15, 35, 0.98);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 0.85rem 0.9rem;
  display: flex;
  align-items: center;
  gap: 0.8rem;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.35);
  z-index: 150;
}
.pwa-install-banner[hidden] { display: none; }
.pwa-install-icon { width: 40px; height: 40px; border-radius: 8px; flex-shrink: 0; }
.pwa-install-text { flex: 1; font-size: 0.85rem; line-height: 1.35; }
.pwa-install-text strong { color: var(--fg); display: block; margin-bottom: 0.15rem; }
.pwa-install-text p { color: var(--muted); margin: 0; font-size: 0.8rem; }
.pwa-install-actions { display: flex; align-items: center; gap: 0.35rem; flex-shrink: 0; }
#pwa-install-btn { padding: 0.45rem 0.85rem; border-radius: 6px; font-size: 0.85rem; }
.pwa-install-dismiss {
  background: transparent;
  border: none;
  color: var(--muted);
  font-size: 1.3rem;
  line-height: 1;
  padding: 0.2rem 0.5rem;
  cursor: pointer;
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 6px;
}
.pwa-install-dismiss:focus-visible {
  outline: 2px solid var(--accent-2);
  outline-offset: 2px;
}

/* ---------- Camera gate (first-tap permission inside the camera overlay) ----
   Injected by camera-gate.js via renderCameraGate() into #camera-gate-mount
   the first time the player taps "Open Camera & Compass" without a cached
   grant. The module controls which child elements show for each state
   (checking / prompt / denied / unavailable / granted) via
   .camera-gate[data-state="..."]. On "granted" camera.js hides the mount
   and acquires the live stream. */
.camera-gate {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 0.7rem;
  padding: 1.1rem 1rem 0.9rem;
  background: rgba(15, 20, 40, 0.88);
  border: 1px solid rgba(245, 183, 0, 0.3);
  border-radius: 14px;
  margin: 0.5rem 0;
}
.camera-gate[data-state="checking"] { border-color: rgba(79, 195, 247, 0.42); }
.camera-gate[data-state="denied"] { border-color: rgba(255, 112, 112, 0.48); }
.camera-gate[data-state="unavailable"] { border-color: rgba(154, 163, 199, 0.42); }
.camera-gate[data-state="granted"] {
  /* Successful path — module sets body/heading empty; suppress padding so
     the granted "✓" line reads as a quiet confirmation, not a panel. */
  background: transparent;
  border-color: transparent;
  padding: 0.25rem 0;
}
.camera-gate-icon {
  width: 3rem;
  height: 3rem;
  display: grid;
  place-items: center;
  border: 1px solid rgba(245, 183, 0, 0.34);
  border-radius: 14px;
  background: rgba(245, 183, 0, 0.1);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08);
}
.camera-gate[data-state="checking"] .camera-gate-icon {
  border-color: rgba(79, 195, 247, 0.42);
  background: rgba(79, 195, 247, 0.12);
  animation: signal-wait-pulse 1.3s ease-in-out infinite;
}
.camera-gate[data-state="denied"] .camera-gate-icon {
  border-color: rgba(255, 112, 112, 0.45);
  background: rgba(255, 112, 112, 0.12);
}
.camera-gate-icon-img {
  width: 1.35rem;
  height: 1.35rem;
  opacity: 0.92;
  filter: invert(1);
}
.camera-gate-heading {
  font-weight: 700;
  font-size: 1.05rem;
  color: var(--fg);
}
.camera-gate-body {
  color: var(--muted);
  font-size: 0.9rem;
  margin: 0;
  line-height: 1.4;
}
.camera-gate-action {
  min-width: 170px;
  min-height: 44px;
  border-radius: 10px;
}
.camera-gate-ready {
  color: var(--accent-2, #5ec8ff);
  font-size: 0.85rem;
  font-weight: 600;
}

/* Camera-overlay gate: sits inside #camera-overlay (above the black
   video background) when permission hasn't been granted yet. Centered
   over the overlay, frosted card on dark background. */
.camera-overlay-gate {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(420px, calc(100% - 2rem));
  z-index: 5;
}
/* renderCameraGate() adds the `camera-gate` class to the mount element
   itself, so target the mount with a compound selector (not descendant)
   to get the frosted-overlay look on top of the base .camera-gate rule. */
.camera-overlay-gate.camera-gate {
  background: rgba(15, 20, 40, 0.92);
  border: 1px solid rgba(245, 183, 0, 0.5);
  border-radius: 14px;
  padding: 1.4rem 1.25rem 1.25rem;
  margin: 0;
  box-shadow: 0 14px 32px rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  color: #f5f7ff;
}
.camera-overlay-gate .camera-gate-heading { color: #f5f7ff; }
.camera-overlay-gate .camera-gate-body { color: rgba(245, 247, 255, 0.78); }

@media (prefers-reduced-motion: reduce) {
  .camera-gate[data-state="checking"] .camera-gate-icon { animation: none; }
}

/* Small-screen tightening for the hunt page. The AR compass, mini-map, and
   AR icon overlays are all absolutely positioned with percentage-from-top
   offsets tuned for tall viewports. On short iPhones (SE, older Pros in
   landscape-mode-close-to-portrait) they pile into the narrow band above
   the capped clue card. These breakpoints compress that band so the
   compass + mini-map stay visible without overlapping the clue card top. */
@media (max-height: 720px) {
  .ar-compass { top: 14%; }
  #ar-icons { top: 22%; }
  #mini-map-wrap {
    width: 90px;
    height: 90px;
    top: 60px;
    right: 10px;
  }
}
@media (max-width: 400px) {
  /* Very narrow: stack the CLUE label above the difficulty chip pair so
     neither crushes the other. */
  .stop-label {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.3rem;
  }
  .difficulty-pair { align-self: flex-end; }
}
.pwa-install-dismiss:hover,
.pwa-install-dismiss:focus-visible { color: var(--fg); }

/* ══════════════════════════════════════════════════════════════════════
   HINT PAGE REDESIGN — v1 (applies to all hunts, HR is the beta test)

   - Hero clue card is the page (see .clue-card + .clue-hero above).
   - Camera + AR moved into an opt-in .camera-overlay pop-out.
   - Map reveal is now an in-app .map-reveal-modal (Leaflet), replacing
     the old external Google Maps hyperlink.
   - Hint + map actions rendered as .pill buttons instead of a cramped
     tri-column button row.
   - Arrive CTA lives below the help tiers. It only pins to the bottom
     once check-in is actionable, so the disabled distance readout cannot
     cover hint/map controls while the player is still walking.
   ══════════════════════════════════════════════════════════════════════ */

/* ---------- Signal chip (replaces .accuracy-row) ---------- */
.signal-row {
  display: flex;
  justify-content: center;
  margin: 0.35rem 0 0.6rem;
}
.signal-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.28rem 0.7rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.08);
  color: var(--muted);
  font-size: 0.78rem;
  letter-spacing: 0.02em;
}
.signal-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #9aa3c7;
  box-shadow: 0 0 0 0 rgba(154, 163, 199, 0.45);
}
.signal-chip--ok   .signal-dot { background: #a3e635; box-shadow: 0 0 0 3px rgba(163, 230, 53, 0.18); }
.signal-chip--weak .signal-dot { background: #f5b700; box-shadow: 0 0 0 3px rgba(245, 183, 0, 0.2); }
.signal-chip--bad  .signal-dot { background: #ff7070; box-shadow: 0 0 0 3px rgba(255, 112, 112, 0.22); }
.signal-chip--searching .signal-dot {
  background: var(--muted);
  animation: signal-wait-pulse 1.4s ease-in-out infinite;
}
@keyframes signal-wait-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(154, 163, 199, 0.28); }
  50%      { box-shadow: 0 0 0 5px rgba(154, 163, 199, 0); }
}

/* ---------- Help tiers (tiered hint progression) ---------- */
.help-tiers {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0.45rem;
  margin: 0.65rem 0 0.85rem;
  padding: 0.65rem;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 14px;
  background: rgba(255, 255, 255, 0.035);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
}
.help-tiers-header {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted);
  font-weight: 600;
  margin-bottom: 0.05rem;
}
.help-tiers-header::after {
  content: "";
  flex: 1 1 auto;
  height: 1px;
  background: rgba(255, 255, 255, 0.1);
}
.pill[disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}

.pill {
  width: 100%;
  min-height: 46px;
  padding: 0.5rem 0.6rem;
  border-radius: 12px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: rgba(255, 255, 255, 0.04);
  color: var(--fg);
  font-size: 0.88rem;
  font-weight: 600;
  display: grid;
  grid-template-columns: 1.85rem minmax(0, 1fr) auto;
  align-items: center;
  gap: 0.55rem;
  cursor: pointer;
  transition: background 120ms ease, transform 80ms ease, border-color 120ms ease, box-shadow 120ms ease;
  white-space: normal;
  text-align: left;
}
.pill:hover { background: rgba(255, 255, 255, 0.08); }
.pill:active { transform: scale(0.97); }
.pill:focus-visible {
  outline: 2px solid rgba(137, 180, 250, 0.9);
  outline-offset: 2px;
}
.pill-icon {
  width: 1.85rem;
  height: 1.85rem;
  border-radius: 9px;
  display: grid;
  place-items: center;
  background: rgba(255, 255, 255, 0.08);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08);
}
.pill img { opacity: 0.92; }
.pill-label {
  min-width: 0;
  line-height: 1.2;
  overflow-wrap: anywhere;
}
.pill[hidden] { display: none !important; }

/* Help tiers ramp green → red as the spoiler level rises:
     Hint 1 (green) → Hint 2 (yellow) → Hint 3 (orange) →
     Camera & Compass (warm orange) → Show on map (red).
   Each row keeps the icon, action, and penalty in fixed columns so the
   player can scan the escalation without rereading long button copy. */

.pill-hint--1 {
  background: linear-gradient(135deg, rgba(76, 175, 80, 0.18), rgba(76, 175, 80, 0.04));
  border-color: rgba(76, 175, 80, 0.5);
  color: #c6f0c9;
}
.pill-hint--1:hover,
.pill-hint--1:focus-visible { background: linear-gradient(135deg, rgba(76, 175, 80, 0.3), rgba(76, 175, 80, 0.08)); }

.pill-hint--2 {
  background: linear-gradient(135deg, rgba(245, 183, 0, 0.18), rgba(245, 183, 0, 0.04));
  border-color: rgba(245, 183, 0, 0.5);
  color: #ffe9a1;
}
.pill-hint--2:hover,
.pill-hint--2:focus-visible { background: linear-gradient(135deg, rgba(245, 183, 0, 0.3), rgba(245, 183, 0, 0.08)); }

.pill-hint--3 {
  background: linear-gradient(135deg, rgba(255, 138, 0, 0.22), rgba(255, 138, 0, 0.05));
  border-color: rgba(255, 138, 0, 0.65);
  color: #ffd28a;
}
.pill-hint--3:hover,
.pill-hint--3:focus-visible { background: linear-gradient(135deg, rgba(255, 138, 0, 0.34), rgba(255, 138, 0, 0.1)); }

.pill-camera {
  background: linear-gradient(135deg, rgba(255, 107, 53, 0.2), rgba(255, 107, 53, 0.04));
  border-color: rgba(255, 107, 53, 0.55);
  color: #ffd0b8;
}
.pill-camera:hover,
.pill-camera:focus-visible { background: linear-gradient(135deg, rgba(255, 107, 53, 0.32), rgba(255, 107, 53, 0.08)); }

/* Inline "+2 min" cost suffix on each hint pill so the score penalty
   is visible without tapping. Muted so the primary label stays loudest. */
.pill-hint-cost {
  justify-self: end;
  font-size: 0.72rem;
  font-weight: 600;
  line-height: 1;
  padding: 0.28rem 0.42rem;
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.18);
  color: rgba(255, 255, 255, 0.78);
  white-space: nowrap;
}

.pill-map {
  background: linear-gradient(135deg, rgba(233, 79, 55, 0.22), rgba(233, 79, 55, 0.05));
  border-color: rgba(233, 79, 55, 0.6);
  color: #ffd4cb;
}
.pill-map:hover,
.pill-map:focus-visible { background: linear-gradient(135deg, rgba(233, 79, 55, 0.36), rgba(233, 79, 55, 0.1)); }

/* Paywall lock badge on a help-tier pill (camera / map) during the free
   preview. The pill stays clickable so a tap surfaces the unlock card. */
.pill--locked {
  opacity: 0.72;
  filter: grayscale(0.4);
}
.pill--locked .pill-label::after {
  content: "";
  display: inline-block;
  width: 13px;
  height: 13px;
  margin-left: 6px;
  vertical-align: -2px;
  background: url("/static/img/ar/icons/lock.svg") center / contain no-repeat;
  opacity: 0.9;
}

@media (min-width: 520px) {
  .help-tiers {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .help-tiers-header,
  .compass-locked-hint,
  .pill-hint--3,
  .pill-camera,
  .pill-map {
    grid-column: 1 / -1;
  }
}

/* ---------- Free-preview teaser (unpaid player on a free stop) ---------- */
.preview-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  margin: 0.5rem 0 0.25rem;
}
.preview-nav-label {
  font-size: 0.8rem;
  color: var(--muted);
  letter-spacing: 0.02em;
}
.preview-nav-btn {
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.18);
  background: rgba(255, 255, 255, 0.05);
  color: #fff;
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
}
.preview-nav-btn:hover,
.preview-nav-btn:focus-visible { border-color: var(--accent-2); }
.preview-nav-btn:disabled { opacity: 0.3; cursor: default; }

.preview-upsell {
  margin: 0.85rem 0 0.25rem;
  padding: 1rem 1.1rem;
  border: 1px solid rgba(233, 79, 55, 0.5);
  border-radius: 14px;
  background: linear-gradient(135deg, rgba(233, 79, 55, 0.16), rgba(233, 79, 55, 0.04));
}
.preview-upsell-title {
  font-weight: 700;
  font-size: 1.02rem;
  margin-bottom: 0.3rem;
}
.preview-upsell-sub {
  margin: 0 0 0.6rem;
  font-size: 0.9rem;
  color: var(--muted);
}
.preview-upsell-cta {
  display: inline-block;
  width: auto;
  text-decoration: none;
  margin-top: 0.4rem;
}
.preview-upsell--flash {
  animation: preview-upsell-pulse 0.9s ease;
}
@keyframes preview-upsell-pulse {
  0% { box-shadow: 0 0 0 0 rgba(233, 79, 55, 0.55); }
  100% { box-shadow: 0 0 0 12px rgba(233, 79, 55, 0); }
}

/* Shared "what you unlock" list — paywall surfaces + the preview card. */
.unlock-benefits {
  list-style: none;
  margin: 0;
  padding: 0;
}
.unlock-benefits li {
  position: relative;
  padding: 0.18rem 0 0.18rem 1.4rem;
  font-size: 0.9rem;
  line-height: 1.4;
}
.unlock-benefits li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.5rem;
  width: 0.85rem;
  height: 0.85rem;
  background: url("/static/img/ar/icons/unlock.svg") center / contain no-repeat;
  opacity: 0.85;
}
.unlock-benefits strong { color: #fff; }

/* ---------- Arrive bar (check-in CTA inside .clue-card) ---------- */
.arrive-bar {
  margin: 0.75rem -1.25rem -0.25rem;     /* bleed into card padding */
  padding: 0.65rem 1.25rem 0.35rem;
  background: linear-gradient(180deg,
    rgba(15, 22, 48, 0) 0%,
    rgba(11, 16, 32, 0.92) 40%,
    rgba(11, 16, 32, 0.98) 100%);
  z-index: 2;
}
.arrive-bar--sticky {
  position: sticky;
  bottom: 0;
}
.arrive-btn {
  width: 100%;
  min-height: 52px;
  padding: 0.85rem 1rem;
  border-radius: 14px;
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: 0.01em;
  background: linear-gradient(135deg, var(--accent) 0%, #ff8a5c 100%);
  color: white;
  border: 1px solid rgba(255, 255, 255, 0.16);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  position: relative;
  overflow: hidden;
  box-shadow: 0 8px 24px -8px rgba(233, 79, 55, 0.65);
  transition: transform 80ms ease, box-shadow 160ms ease, filter 160ms ease, background 160ms ease, border-color 160ms ease;
}
.arrive-btn::before {
  content: "";
  flex: 0 0 auto;
  width: 0.58rem;
  height: 0.58rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.65);
  box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.12);
}
.arrive-btn:hover:not(:disabled),
.arrive-btn:focus-visible:not(:disabled) { filter: brightness(1.06); }
.arrive-btn:active:not(:disabled) { transform: scale(0.99); }
.arrive-btn:disabled {
  opacity: 1;
  box-shadow: none;
  cursor: not-allowed;
}
.arrive-btn--waiting:disabled {
  background: rgba(255, 255, 255, 0.065);
  border-color: rgba(255, 255, 255, 0.13);
  color: rgba(255, 255, 255, 0.62);
}
.arrive-btn--waiting::before {
  background: #9aa3c7;
  animation: signal-wait-pulse 1.4s ease-in-out infinite;
}
.arrive-btn--near:disabled {
  background: linear-gradient(135deg, rgba(245, 183, 0, 0.16), rgba(245, 183, 0, 0.04));
  border-color: rgba(245, 183, 0, 0.32);
  color: #ffe9a1;
}
.arrive-btn--near::before {
  background: #f5b700;
  box-shadow: 0 0 0 3px rgba(245, 183, 0, 0.18);
}
.arrive-btn--ready {
  background: linear-gradient(135deg, #21a870 0%, var(--accent) 100%);
  border-color: rgba(163, 230, 53, 0.48);
  box-shadow: 0 10px 28px -10px rgba(33, 168, 112, 0.72);
}
.arrive-btn--ready::before {
  background: #a3e635;
  box-shadow: 0 0 0 4px rgba(163, 230, 53, 0.2);
}
.arrive-btn--checking {
  background: linear-gradient(135deg, rgba(79, 195, 247, 0.22), rgba(79, 195, 247, 0.08));
  border-color: rgba(79, 195, 247, 0.38);
  color: #d9f3ff;
}
.arrive-btn--checking::before {
  background: #4fc3f7;
  animation: signal-wait-pulse 1.1s ease-in-out infinite;
}
.arrive-btn--gps-error:disabled {
  background: linear-gradient(135deg, rgba(255, 112, 112, 0.18), rgba(255, 112, 112, 0.05));
  border-color: rgba(255, 112, 112, 0.34);
  color: #ffd0d0;
}
.arrive-btn--gps-error::before {
  background: #ff7070;
  box-shadow: 0 0 0 3px rgba(255, 112, 112, 0.2);
}

/* ---------- Camera pop-out overlay ---------- */
.camera-overlay {
  position: fixed;
  inset: 0;
  z-index: 60;                 /* above #overlay (z:1) and below reveal modals (z:~80) */
  background: #000;
  pointer-events: auto;
}
.camera-overlay::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    linear-gradient(180deg,
      rgba(0, 0, 0, 0.52) 0%,
      rgba(0, 0, 0, 0.18) 16%,
      rgba(0, 0, 0, 0) 38%,
      rgba(0, 0, 0, 0) 64%,
      rgba(0, 0, 0, 0.48) 100%);
}
/* Same specificity fix as .completed-modal / .ar-compass: an element
   with an explicit display rule ties UA [hidden] and wins the cascade. */
.camera-overlay[hidden] { display: none !important; }

.camera-close {
  position: absolute;
  top: calc(0.75rem + env(safe-area-inset-top, 0));
  right: 0.75rem;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.35);
  background: rgba(0, 0, 0, 0.55);
  color: white;
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.32);
  backdrop-filter: blur(6px);
}
.camera-close:hover { background: rgba(0, 0, 0, 0.8); }

/* Sound toggle button inside the camera overlay — mutes/unmutes the
   proximity beeping. Mirrors the camera-close style but on the left. */
.sound-toggle {
  position: absolute;
  top: calc(0.75rem + env(safe-area-inset-top, 0));
  left: 0.75rem;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.35);
  background: rgba(0, 0, 0, 0.55);
  color: white;
  font-size: 1.3rem;
  line-height: 1;
  cursor: pointer;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: center;
  backdrop-filter: blur(6px);
}
.sound-toggle:hover { background: rgba(0, 0, 0, 0.8); }

/* Compass show/hide toggle inside the camera overlay. Shares the
   pill/blur style of #sound-toggle but sits next to it on the left
   so the compass arrow (mid-screen) is within thumb reach. */
.compass-toggle {
  position: absolute;
  top: calc(0.75rem + env(safe-area-inset-top, 0));
  left: calc(0.75rem + 44px + 0.5rem);
  width: 44px;
  height: 44px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.35);
  background: rgba(0, 0, 0, 0.55);
  color: white;
  cursor: pointer;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: center;
  backdrop-filter: blur(6px);
  transition: background 0.15s ease, border-color 0.15s ease;
}
.compass-toggle:hover { background: rgba(0, 0, 0, 0.8); }
.compass-toggle img {
  opacity: 0.65;
  transition: opacity 0.15s ease;
}
.compass-toggle--on img { opacity: 1; }

.camera-close,
.sound-toggle,
.compass-toggle {
  background: rgba(6, 10, 24, 0.68);
  border-color: rgba(255, 255, 255, 0.32);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.32);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  transition: background 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease, transform 80ms ease;
}
.camera-close:hover,
.sound-toggle:hover,
.compass-toggle:hover {
  background: rgba(6, 10, 24, 0.86);
  border-color: rgba(255, 255, 255, 0.46);
}
.camera-close:active,
.sound-toggle:active,
.compass-toggle:active {
  transform: scale(0.96);
}
.camera-close:focus-visible,
.sound-toggle:focus-visible,
.compass-toggle:focus-visible {
  outline: 2px solid rgba(245, 183, 0, 0.95);
  outline-offset: 3px;
}
.sound-toggle[aria-pressed="true"] {
  background: rgba(255, 112, 112, 0.34);
  border-color: rgba(255, 112, 112, 0.76);
  box-shadow: 0 8px 24px rgba(255, 112, 112, 0.2);
}
.compass-toggle--on {
  background: rgba(245, 183, 0, 0.44);
  border-color: rgba(245, 183, 0, 0.95);
  box-shadow: 0 8px 24px rgba(245, 183, 0, 0.24);
}

/* Proximity color escalation on the AR compass ring. The ring pulses
   with increasingly urgent colors as the player approaches the stop. */
.proximity-approaching .ar-ring { stroke: rgba(79, 195, 247, 0.5); }
.proximity-near .ar-ring { stroke: rgba(245, 183, 0, 0.6); }
.proximity-warm .ar-ring { stroke: rgba(255, 152, 0, 0.8); }
.proximity-hot .ar-ring { stroke: rgba(233, 79, 55, 1); stroke-width: 3; }

/* Proximity message: shown alongside the close-range ring (<= 100 ft).
   Sits below the rings so it doesn't crowd the distance readout in the
   center. Pulses gently to draw the eye without competing with the
   ring animation. */
.ar-search-msg {
  position: absolute;
  left: 50%;
  top: 100%;
  transform: translateX(-50%);
  margin-top: 0.5rem;
  width: max-content;
  max-width: 80vw;
  padding: 0.45rem 0.7rem;
  border: 1px solid rgba(245, 183, 0, 0.38);
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.62);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  color: #f5b700;
  font-size: 0.9rem;
  font-weight: 600;
  text-align: center;
  letter-spacing: 0.02em;
  line-height: 1.3;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.95);
  animation: search-pulse 1.5s ease-in-out infinite;
  pointer-events: none;
}
@keyframes search-pulse {
  0%, 100% { opacity: 0.75; }
  50% { opacity: 1; }
}
.ar-search-msg[hidden] { display: none !important; }

/* Lottie discovery animation — themed icon that appears when the player
   gets within 50 ft and stays pinned (frozen) after arrival. Anchored
   to the same top edge as .ar-proximity-ring (top: 20%): the ring is
   200×200, while this .lottie-discovery container is intentionally
   larger at 240×240 so the Lottie / emoji sits directly over the
   heat-ring as one visual group — the payoff lands where the eye is
   already tracking the solved circle. */
.lottie-discovery {
  position: absolute;
  left: 50%;
  top: 20%;
  /* CSS-default position is centered (kept for reduce-motion / no-
     compass fallback). When real-AR anchoring is active, JS adds
     `.ar-anchored` and writes the three custom properties below;
     they shift + scale the container around its CSS anchor without
     needing JS to also recompute the centering offset. */
  --ar-anchor-x: 0vw;
  --ar-anchor-y: 0%;
  --ar-anchor-scale: 1;
  transform: translateX(-50%);
  width: 240px;
  height: 240px;
  max-width: 60vw;
  max-height: 40vh;
  z-index: 4;
  pointer-events: none;
  will-change: transform;
  transition: transform 80ms linear;
  /* Fallback emoji renders via `.discovery-fallback`. When Lottie
     injects an <svg> inside, JS adds `.lottie-loaded` which hides the
     emoji — otherwise the emoji stays visible so a kid always sees a
     bunny. */
}
.lottie-discovery.ar-anchored {
  top: var(--ar-anchor-y);
  transform: translate(calc(-50% + var(--ar-anchor-x)), 0) scale(var(--ar-anchor-scale));
  /* Smaller transition window so anchored panning feels responsive. */
  transition: transform 50ms linear, top 120ms linear;
}
.lottie-discovery[hidden] { display: none !important; }

/* Stage-2 reveal asset (the bunny / fox / gem). World-anchored to the
   same bearing as the chest so they pan together. Sits slightly above
   and to the right of the chest at default; the JS-driven anchor
   transform applies to both. Pop-in scale animation when first shown
   gives a satisfying "hops out of the box" beat. */
.lottie-reveal-asset {
  position: absolute;
  left: calc(50% + 60px);
  top: 12%;
  --ar-anchor-x: 0vw;
  --ar-anchor-y: 0%;
  --ar-anchor-scale: 1;
  transform: translateX(-50%);
  width: 180px;
  height: 180px;
  max-width: 45vw;
  max-height: 35vh;
  z-index: 5;
  pointer-events: none;
  will-change: transform;
  transition: transform 80ms linear;
}
.lottie-reveal-asset.ar-anchored {
  /* Offset 6vw right of the chest so the bunny sits next to it, not
     on top of it. The chest's --ar-anchor-x is shared so they pan in
     lockstep; the reveal asset adds the lateral offset on top. */
  top: calc(var(--ar-anchor-y) - 8%);
  transform: translate(calc(-50% + var(--ar-anchor-x) + 6vw), 0)
             scale(calc(var(--ar-anchor-scale) * 0.85));
  transition: transform 50ms linear, top 120ms linear;
}
.lottie-reveal-asset[hidden] { display: none !important; }
/* One-shot pop when first appearing — kids need a clear "look at me"
   beat for the bunny so it doesn't blend into the chest. */
.lottie-reveal-asset.reveal-asset-popin {
  animation: reveal-asset-popin 600ms cubic-bezier(0.34, 1.56, 0.64, 1) both;
}
@keyframes reveal-asset-popin {
  0%   { opacity: 0; transform: translate(calc(-50% + var(--ar-anchor-x) + 6vw), 30px) scale(0.2); }
  60%  { opacity: 1; transform: translate(calc(-50% + var(--ar-anchor-x) + 6vw), -8px) scale(1.1); }
  100% { opacity: 1; transform: translate(calc(-50% + var(--ar-anchor-x) + 6vw), 0) scale(calc(var(--ar-anchor-scale) * 0.85)); }
}

/* Off-screen anchor arrow: three small blue chevrons that pop in
   when the world-locked chest leaves the camera FOV, then fade out.
   JS adds `.left` / `.right` (which way to pan) plus `.pop` (start
   the one-shot animation) and clears them on auto-hide. */
.ar-anchor-arrow {
  position: absolute;
  top: 45%;
  display: flex;
  gap: 0.15rem;
  z-index: 6;
  pointer-events: none;
}
.ar-anchor-arrow.left  { left: 1rem;  }
.ar-anchor-arrow.right { right: 1rem; }
.ar-anchor-arrow[hidden] { display: none !important; }

.ar-anchor-arrow-glyph {
  display: inline-block;
  font-size: 1.6rem;
  font-weight: 700;
  line-height: 1;
  color: var(--accent-2);
  text-shadow:
    0 0 6px rgba(0, 0, 0, 0.85),
    0 1px 2px rgba(0, 0, 0, 0.6);
  opacity: 0;
  --ar-arrow-rot: 0deg;
}
.ar-anchor-arrow.left .ar-anchor-arrow-glyph { --ar-arrow-rot: 180deg; }

.ar-anchor-arrow.pop .ar-anchor-arrow-glyph {
  animation: anchor-arrow-pop 1.1s ease-out forwards;
}
.ar-anchor-arrow.pop .ar-anchor-arrow-glyph:nth-child(1) { animation-delay: 0s;    }
.ar-anchor-arrow.pop .ar-anchor-arrow-glyph:nth-child(2) { animation-delay: 0.08s; }
.ar-anchor-arrow.pop .ar-anchor-arrow-glyph:nth-child(3) { animation-delay: 0.16s; }

@keyframes anchor-arrow-pop {
  0%   { opacity: 0; transform: rotate(var(--ar-arrow-rot)) scale(0.6);  }
  20%  { opacity: 1; transform: rotate(var(--ar-arrow-rot)) scale(1.15); }
  40%  { opacity: 1; transform: rotate(var(--ar-arrow-rot)) scale(1);    }
  70%  { opacity: 1; transform: rotate(var(--ar-arrow-rot)) scale(1);    }
  100% { opacity: 0; transform: rotate(var(--ar-arrow-rot)) scale(1);    }
}
/* Lottie injects its SVG into .lottie-host so the fallback emoji
   (a sibling) is never clobbered by the renderer. */
.lottie-discovery .lottie-host,
.reveal-discovery .lottie-host {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
}

/* Shared static emoji fallback inside #lottie-discovery and
   #reveal-discovery. Absolute-centered so it sits behind any Lottie
   SVG that loads. Wiggle animation so it feels alive. */
.discovery-fallback {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: clamp(80px, 42vw, 240px);
  line-height: 1;
  pointer-events: none;
  filter: drop-shadow(0 6px 18px rgba(0, 0, 0, 0.5));
  animation: discovery-wiggle 1.6s ease-in-out infinite;
}
.lottie-discovery.lottie-loaded .discovery-fallback,
.lottie-reveal-asset.lottie-loaded .discovery-fallback,
.reveal-discovery.lottie-loaded .discovery-fallback {
  display: none;
}
@keyframes discovery-wiggle {
  0%, 100% { transform: translateY(0) rotate(-4deg); }
  50%      { transform: translateY(-6px) rotate(4deg); }
}

/* Compass permission prompt inside the camera overlay. Shown when device
   orientation hasn't been granted yet. The button inside provides the fresh
   user gesture iOS needs for DeviceOrientationEvent.requestPermission(). */
.camera-compass-prompt {
  position: absolute;
  left: 50%;
  bottom: calc(1.5rem + env(safe-area-inset-bottom, 0));
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.65rem;
  text-align: center;
  padding: 1.25rem;
  border: 1px solid rgba(245, 183, 0, 0.46);
  border-radius: 14px;
  background: rgba(15, 20, 40, 0.92);
  color: #fff;
  z-index: 5;
  width: min(320px, calc(100% - 2rem));
  box-shadow: 0 14px 32px rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}
.camera-compass-icon {
  width: 3rem;
  height: 3rem;
  display: grid;
  place-items: center;
  border: 1px solid rgba(245, 183, 0, 0.38);
  border-radius: 14px;
  background: rgba(245, 183, 0, 0.1);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08);
}
.camera-compass-icon img {
  width: 1.35rem;
  height: 1.35rem;
  opacity: 0.94;
}
.camera-compass-title {
  margin: 0;
  font-weight: 700;
  font-size: 1.05rem;
  color: #f5f7ff;
}
.camera-compass-body {
  margin: 0;
  color: rgba(245, 247, 255, 0.72);
  font-size: 0.82rem;
  line-height: 1.35;
}
.camera-compass-enable-btn {
  min-width: 180px;
  min-height: 44px;
  border-radius: 10px;
}
.camera-compass-prompt[hidden] { display: none !important; }

.camera-hint {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  transition: opacity 0.5s ease;
  padding: 0.5rem 0.9rem;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.72);
  color: #fff;
  font-size: 0.82rem;
  letter-spacing: 0.02em;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  z-index: 4;
}
/* Same specificity fix as .ar-compass[hidden]: an explicit display rule
   beats the UA [hidden] stylesheet, so we must override it explicitly. */
.camera-hint[hidden] { display: none !important; }

/* AR compass + icons were historically siblings of .clue-card (absolute
   positioning relative to #overlay). They now live inside .camera-overlay
   — same positioned-ancestor contract, so their `top: 20%` / `top: 30%`
   offsets still compose correctly. Bump z-index so they paint above the
   video but below the close button. */
.camera-overlay .ar-compass { z-index: 3; }
.camera-overlay .ar-icons { z-index: 2; }

/* ---------- Map reveal modal (in-app Leaflet bottom sheet) ---------- */
.map-reveal-modal {
  position: fixed;
  inset: 0;
  z-index: 80;                 /* above camera overlay, below completion */
  background: rgba(0, 0, 0, 0.6);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  pointer-events: auto;
}
.map-reveal-modal[hidden] { display: none !important; }
.map-reveal-inner {
  background: rgba(11, 16, 40, 0.98);
  width: 100%;
  max-width: 520px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-bottom: 0;
  border-radius: 20px 20px 0 0;
  padding: 0.75rem 1.25rem calc(1.25rem + env(safe-area-inset-bottom, 0));
  box-shadow: 0 -24px 60px -20px rgba(0, 0, 0, 0.7);
  animation: map-reveal-slide-up 280ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
@keyframes map-reveal-slide-up {
  from { transform: translateY(30%); opacity: 0.4; }
  to   { transform: translateY(0);   opacity: 1; }
}
.map-reveal-inner h2 {
  margin: 0.25rem 0 0.65rem;
  font-size: 1.15rem;
  color: var(--fg);
}
.map-reveal-map {
  width: 100%;
  height: min(260px, 42vh);
  min-height: 220px;
  border-radius: 12px;
  border: 1px solid rgba(255, 255, 255, 0.16);
  overflow: hidden;
  background: #0a0f23;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06);
}
.map-reveal-actions {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 0.75rem;
  margin-top: 0.85rem;
}
.map-reveal-external-link,
.map-reveal-close-btn {
  min-height: 44px;
  border-radius: 10px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.map-reveal-external-link {
  min-width: 0;
}
.map-reveal-close-btn {
  min-width: 7rem;
}
@media (max-width: 420px) {
  .map-reveal-actions {
    grid-template-columns: 1fr;
  }
  .map-reveal-external-link,
  .map-reveal-close-btn {
    width: 100%;
  }
}
.map-target-pin--lg {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: radial-gradient(circle, #ff8a5c 0%, var(--accent) 70%);
  border: 3px solid #fff;
  box-shadow: 0 0 0 3px rgba(233, 79, 55, 0.35), 0 4px 10px rgba(0, 0, 0, 0.45);
}

/* ══════════════════════════════════════════════════════════════════════
   SHARED 401 / SESSION-EXPIRED FLOW (PR F)
   ══════════════════════════════════════════════════════════════════════ */

/* Toast — fixed bottom-right notification used by common.js showToast().
   Auto-dismissed after ~3s. Stacks if multiple fire. */
.toast-container {
  position: fixed;
  bottom: calc(1rem + env(safe-area-inset-bottom, 0));
  right: 1rem;
  z-index: 200;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  pointer-events: none;
  max-width: calc(100vw - 2rem);
}
.toast {
  background: rgba(15, 22, 48, 0.95);
  color: var(--fg);
  border: 1px solid rgba(79, 195, 247, 0.35);
  border-radius: 10px;
  padding: 0.7rem 1rem;
  font-size: 0.9rem;
  line-height: 1.35;
  box-shadow: 0 10px 28px -10px rgba(0, 0, 0, 0.65);
  backdrop-filter: blur(6px);
  pointer-events: auto;
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 200ms ease, transform 200ms ease;
}
.toast--visible {
  opacity: 1;
  transform: translateY(0);
}
.toast--error {
  border-color: rgba(233, 79, 55, 0.55);
  color: #ffd4cb;
}

/* Banner inside #auth-panel, shown by app.js when the user arrived via
   a ?return= session-expired redirect. Tells them why they're on the
   login form and what they'll get back to. */
.return-banner {
  background: rgba(245, 183, 0, 0.12);
  border: 1px solid rgba(245, 183, 0, 0.45);
  color: #f5b700;
  padding: 0.6rem 0.85rem;
  border-radius: 8px;
  font-size: 0.88rem;
  margin-bottom: 1rem;
  line-height: 1.35;
}

/* ---------- Landing page (public marketing home) ----------
   The hero itself uses the shared .page-hero pattern (see further down) so
   the homepage matches Account / Custom Request / Pricing. Only the
   landing-page-specific sections (.landing-cta, .landing-how, etc.) live in
   this block. */
.landing-cta {
  display: inline-block;
  padding: 0.75rem 1.5rem;
  font-size: 1rem;
  font-weight: 600;
  border-radius: 8px;
  text-align: center;
  text-decoration: none;
  width: auto;
}

/* How it works: 3-step row */
.landing-how { margin: 2rem 0; }
.landing-how h2 { margin: 0 0 1rem; font-size: 1.2rem; }
.landing-steps {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
.landing-step {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 1rem;
}
.landing-step-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  font-weight: 700;
  font-size: 0.85rem;
  margin-bottom: 0.5rem;
}
.landing-step h3 { margin: 0 0 0.3rem; font-size: 1rem; }
.landing-step p { margin: 0; color: var(--muted); font-size: 0.9rem; line-height: 1.4; }

/* Active hunts / state chips */
.landing-locations { margin: 2rem 0; }
.landing-locations h2 { margin: 0 0 0.5rem; font-size: 1.2rem; }
.landing-locations h3 { margin: 1.25rem 0 0.6rem; font-size: 1rem; }

.landing-state-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin: 0.75rem 0;
}
.landing-state-chip {
  background: rgba(79, 195, 247, 0.1);
  border: 1px solid rgba(79, 195, 247, 0.35);
  color: var(--accent-2);
  padding: 0.4rem 0.85rem;
  border-radius: 999px;
  font-size: 0.85rem;
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
}
.landing-state-chip:hover,
.landing-state-chip:focus-visible {
  background: rgba(79, 195, 247, 0.2);
  color: #fff;
}
@media (min-width: 600px) {
  .landing-steps { flex-direction: row; }
  .landing-step { flex: 1; }
  .landing-steps-4 { flex-wrap: wrap; }
  .landing-steps-4 .landing-step { flex: 1 1 calc(50% - 0.5rem); }
}

/* Step icon — replaces the numbered circle for the 4-step explainer.
   Just an emoji in a soft square so it stays visual without needing
   extra image assets. */
.landing-step-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 8px;
  background: rgba(79, 195, 247, 0.12);
  font-size: 1.25rem;
  margin-bottom: 0.5rem;
}

/* Intro paragraph under the hero. */
.landing-intro {
  margin: 1.5rem 0;
}
.landing-intro p {
  margin: 0;
  color: var(--muted);
  font-size: 1rem;
  line-height: 1.55;
}

/* Section lead — the muted intro paragraph that sits under each h2. */
.landing-section-lead {
  margin: 0.25rem 0 1rem;
  font-size: 0.92rem;
  line-height: 1.45;
}

/* ---------- "What's the AR part?" explainer ---------- */
.landing-ar { margin: 2.5rem 0; }
.landing-ar h2 { margin: 0 0 0.25rem; font-size: 1.2rem; }
.landing-ar .landing-section-lead { margin: 0 0 1rem; }
.landing-ar-grid {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
.landing-ar-figure {
  position: relative;
  width: 100%;
  max-width: 380px;
  margin: 0 auto;
  aspect-ratio: 16 / 9;
  border-radius: 12px;
  overflow: hidden;
  background: #000;
  border: 1px solid var(--border);
}
.landing-ar-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.landing-ar-scrim {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse at center 65%, rgba(10, 15, 35, 0.55) 0%, rgba(10, 15, 35, 0.15) 55%, rgba(10, 15, 35, 0) 80%),
    linear-gradient(180deg, rgba(10, 15, 35, 0.05) 0%, rgba(10, 15, 35, 0.45) 100%);
  pointer-events: none;
}
.landing-ar-arrow {
  position: absolute;
  left: 50%;
  top: 26%;
  width: 14%;
  max-width: 64px;
  transform: translateX(-50%);
  filter: drop-shadow(0 0 8px rgba(255, 200, 80, 0.85)) drop-shadow(0 2px 4px rgba(0, 0, 0, 0.4));
  pointer-events: none;
}
.landing-ar-compass {
  position: absolute;
  left: 50%;
  top: 55%;
  width: 24%;
  max-width: 110px;
  transform: translate(-50%, -50%);
  filter: drop-shadow(0 0 12px rgba(79, 195, 247, 0.55)) drop-shadow(0 4px 8px rgba(0, 0, 0, 0.5));
  opacity: 0.95;
  pointer-events: none;
}
.landing-ar-distance {
  position: absolute;
  left: 50%;
  bottom: 10%;
  transform: translateX(-50%);
  text-align: center;
  color: #fff;
  background: rgba(10, 15, 35, 0.55);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  border: 1px solid rgba(255, 255, 255, 0.25);
  border-radius: 999px;
  padding: 0.35rem 0.85rem;
  font-size: 0.85rem;
  line-height: 1.1;
  pointer-events: none;
}
.landing-ar-distance strong {
  display: block;
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: 0.02em;
}
.landing-ar-distance span {
  display: block;
  font-size: 0.7rem;
  color: rgba(255, 255, 255, 0.75);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin-top: 0.1rem;
}
.landing-ar-badge {
  position: absolute;
  top: 0.6rem;
  left: 0.6rem;
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: #fff;
  background: rgba(220, 50, 50, 0.85);
  border-radius: 4px;
  padding: 0.18rem 0.5rem;
}
.landing-ar-badge::before {
  content: "● ";
  color: #fff;
}
.landing-ar-copy p { margin: 0 0 0.75rem; font-size: 0.95rem; line-height: 1.5; }
.landing-ar-copy p:last-child { margin-bottom: 0; }
@media (min-width: 720px) {
  .landing-ar-grid {
    flex-direction: row;
    align-items: stretch;
    gap: 1.5rem;
  }
  .landing-ar-figure { flex: 1 1 55%; max-width: none; margin: 0; }
  .landing-ar-copy { flex: 1 1 45%; align-self: center; }
}

/* ---------- Hunt format cards ---------- */
.landing-formats { margin: 2.5rem 0; }
.landing-formats h2 { margin: 0 0 0.25rem; font-size: 1.2rem; }
.landing-format-cards {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
.landing-format-card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
.landing-format-img {
  width: 100%;
  height: 160px;
  object-fit: cover;
  display: block;
}
.landing-format-body {
  padding: 1rem;
}
.landing-format-tag {
  display: inline-block;
  background: rgba(233, 79, 55, 0.15);
  color: var(--accent);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  padding: 0.2rem 0.55rem;
  border-radius: 999px;
  margin-bottom: 0.5rem;
}
.landing-format-card h3 {
  margin: 0 0 0.4rem;
  font-size: 1.05rem;
}
.landing-format-card p {
  margin: 0;
  color: var(--muted);
  font-size: 0.9rem;
  line-height: 1.45;
}

@media (min-width: 720px) {
  .landing-format-cards { flex-direction: row; }
  .landing-format-card { flex: 1; }
}

/* ---------- Hint progression list ---------- */
.landing-hints { margin: 2.5rem 0; }
.landing-hints h2 { margin: 0 0 0.25rem; font-size: 1.2rem; }
.landing-hint-list {
  list-style: none;
  padding: 0;
  margin: 1rem 0 0;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
}
.landing-hint-row {
  display: grid;
  grid-template-columns: minmax(80px, auto) auto 1fr;
  gap: 0.65rem;
  align-items: baseline;
  padding: 0.7rem 0.9rem;
  border-bottom: 1px solid var(--border);
  font-size: 0.9rem;
  line-height: 1.4;
}
.landing-hint-row:last-child { border-bottom: none; }
.landing-hint-tier {
  font-weight: 600;
  color: var(--accent-2);
  white-space: nowrap;
}
.landing-hint-cost {
  font-size: 0.78rem;
  color: var(--muted);
  background: rgba(255, 255, 255, 0.04);
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  white-space: nowrap;
  justify-self: start;
}
.landing-hint-text { color: var(--fg); }

/* ---------- City image grid ----------
   Populated with up to 8 top-market cities by populateCityGrid() in
   app.js. Mobile defaults to 2 columns at a 16:11 aspect (~130px tall);
   the old 1-column layout would have stacked 8 cards vertically and
   blown out the section's scroll height. Tablet/desktop widen to a
   16:10 aspect, 4 cols from 900px up (see media queries below). */
.landing-city-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.6rem;
  margin: 1rem 0 0.75rem;
}
.landing-city-card {
  position: relative;
  display: block;
  border-radius: 12px;
  overflow: hidden;
  aspect-ratio: 16 / 11;
  min-height: 130px;
  text-decoration: none;
}
.landing-city-card img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 200ms ease;
}
.landing-city-card:hover img { transform: scale(1.04); }
.landing-city-label {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  padding: 0.65rem 0.85rem;
  background: linear-gradient(180deg, transparent, rgba(10, 15, 35, 0.85));
  color: #fff;
  font-weight: 600;
  font-size: 1.05rem;
}

/* ---------- Hunts market spotlight ----------
   Surfaced at the bottom of /hunts.html as a compact chip rail so
   it doesn't compete with the main search + state browse flow.
   Sizing is roughly half the original 94px/16:8 cards so the
   section reads as a secondary "explore by city" affordance. */
.market-spotlight { margin: 1.5rem 0 1.75rem; }
.market-spotlight-header {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-bottom: 0.8rem;
}
.market-spotlight-header h2 {
  margin: 0 0 0.25rem;
  font-size: 1.05rem;
}
.market-spotlight-header p { margin: 0; font-size: 0.85rem; }
.market-card-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.5rem;
}
.market-card {
  position: relative;
  display: block;
  min-height: 48px;
  aspect-ratio: 16 / 5;
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
  background: var(--card);
  text-decoration: none;
  box-shadow: 0 6px 14px rgba(0, 0, 0, 0.14);
}
.market-card img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 200ms ease;
}
.market-card:hover img { transform: scale(1.04); }
.market-card-label {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  flex-direction: column;
  gap: 0;
  padding: 0.6rem 0.5rem 0.3rem;
  background: linear-gradient(180deg, transparent, rgba(10, 15, 35, 0.92));
  color: #fff;
}
.market-card-label strong {
  font-size: 0.78rem;
  line-height: 1.1;
}
.market-card-label span {
  color: rgba(255, 255, 255, 0.82);
  font-size: 0.62rem;
}

@media (min-width: 700px) {
  .market-spotlight-header {
    align-items: flex-end;
    flex-direction: row;
    justify-content: space-between;
  }
  .market-card-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .market-card { min-height: 44px; }
}

@media (min-width: 520px) {
  .landing-city-grid { gap: 0.9rem; }
  .landing-city-card { aspect-ratio: 16 / 10; min-height: 160px; }
}

@media (min-width: 900px) {
  .landing-city-grid { grid-template-columns: repeat(4, 1fr); }
  .landing-city-card { min-height: 170px; }
}

/* ---------- Closing photo band ----------
   Photographic bookend above the final CTA. Uses the same treasure-map
   flat-lay that's served as the og:image/twitter:image so social shares
   match the on-page art. */
.landing-closing-band {
  margin: 2rem 0 1.5rem;
  border-radius: 14px;
  overflow: hidden;
  border: 1px solid var(--border);
}
.landing-closing-band img {
  display: block;
  width: 100%;
  height: auto;
  max-height: 320px;
  object-fit: cover;
}

/* ---------- Final CTA block ---------- */
.landing-final-cta {
  margin: 2.5rem 0 1rem;
  padding: 1.5rem 1.25rem;
  background: linear-gradient(135deg, rgba(79, 195, 247, 0.12), rgba(233, 79, 55, 0.10));
  border: 1px solid var(--border);
  border-radius: 12px;
  text-align: center;
}
.landing-final-cta h2 { margin: 0 0 0.5rem; font-size: 1.3rem; }
.landing-final-cta p { margin: 0 0 1rem; color: var(--muted); font-size: 0.95rem; }
.landing-final-cta .landing-cta { width: auto; padding: 0.75rem 1.75rem; }

/* ---------- Notify-me / mailing-list capture ---------- */
.landing-notify {
  margin: 1.5rem 0 1rem;
  padding: 1.5rem 1.25rem;
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid var(--border);
  border-radius: 12px;
  text-align: center;
}
.landing-notify h2 { margin: 0 0 0.5rem; font-size: 1.2rem; }
.landing-notify p { margin: 0 0 0.85rem; color: var(--muted); font-size: 0.93rem; }
.landing-notify .notify-form {
  display: flex;
  gap: 0.5rem;
  justify-content: center;
  flex-wrap: wrap;
  margin: 0 auto 0.5rem;
  max-width: 32rem;
}
.landing-notify .notify-form input[type="email"] {
  flex: 1 1 16rem;
  min-width: 0;
  padding: 0.6rem 0.85rem;
  background: var(--card-bg, rgba(255, 255, 255, 0.04));
  color: inherit;
  border: 1px solid var(--border);
  border-radius: 8px;
  font: inherit;
}
.landing-notify .notify-form input[type="email"]:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.landing-notify .notify-form .btn { padding: 0.6rem 1.25rem; }
.landing-notify .notify-status {
  margin: 0.25rem 0 0.5rem;
  font-size: 0.92rem;
  min-height: 1.2em;
}
.landing-notify .notify-fineprint {
  font-size: 0.8rem;
  opacity: 0.85;
  margin-top: 0.5rem;
}

/* ---------- Auth panel heading (when shown below marketing content) ---------- */
.auth-panel-heading {
  margin: 2.5rem 0 0.25rem;
  font-size: 1.2rem;
}
.auth-panel-lead {
  margin: 0 0 1rem;
  font-size: 0.92rem;
  line-height: 1.45;
}

/* ---------- Hunts filter bar + matchmaker controls ---------- */
.hunts-filter-bar { margin-bottom: 1rem; }
.hunt-matchmaker {
  margin: 0.85rem 0 1rem;
  padding: 0.9rem;
  border: 1px solid rgba(79, 195, 247, 0.24);
  border-radius: 16px;
  background:
    radial-gradient(circle at top left, rgba(79, 195, 247, 0.14), transparent 34%),
    rgba(15, 22, 48, 0.68);
}
.hunt-matchmaker-heading-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 0.75rem;
}
.hunt-matchmaker h2 {
  margin: 0 0 0.15rem;
  font-size: 1rem;
}
.hunt-matchmaker p { margin: 0; }
.hunt-filter-grid {
  display: grid;
  grid-template-columns: minmax(190px, 1.5fr) repeat(3, minmax(150px, 1fr));
  gap: 0.65rem;
}
.hunt-search-label { min-width: 0; }
.hunt-search-input,
.hunt-filter-select {
  width: 100%;
  min-height: 2.75rem;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: rgba(7, 12, 28, 0.78);
  color: var(--fg);
  font: inherit;
}
.hunt-search-input::placeholder { color: rgba(200, 208, 231, 0.62); }
.hunt-filter-select {
  appearance: none;
  background-image:
    linear-gradient(45deg, transparent 50%, var(--muted) 50%),
    linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position:
    calc(100% - 1rem) 1.05rem,
    calc(100% - 0.72rem) 1.05rem;
  background-size: 0.32rem 0.32rem, 0.32rem 0.32rem;
  background-repeat: no-repeat;
  padding-right: 2rem;
}
.hunt-filter-reset,
.link-button {
  background: transparent;
  border: 0;
  color: var(--accent-2);
  padding: 0;
  font-size: 0.85rem;
  font-weight: 700;
  text-decoration: underline;
  text-decoration-style: dotted;
}
.hunt-filter-reset { white-space: nowrap; }
.hunt-filter-summary {
  min-height: 1.1rem;
  margin-top: 0.6rem !important;
  color: var(--accent-2);
  font-size: 0.82rem;
}
@media (max-width: 820px) {
  .hunt-filter-grid { grid-template-columns: 1fr 1fr; }
  .hunt-search-label { grid-column: 1 / -1; }
}
@media (max-width: 560px) {
  .hunt-matchmaker { padding: 0.8rem; }
  .hunt-matchmaker-heading-row { flex-direction: column; }
  .hunt-filter-grid { grid-template-columns: 1fr; }
}
.state-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin-bottom: 0.75rem;
}
.state-chip {
  background: transparent;
  color: var(--muted);
  border: 1px solid var(--border);
  padding: 0.35rem 0.85rem;
  border-radius: 999px;
  font-size: 0.82rem;
  font-weight: 500;
  cursor: pointer;
  white-space: nowrap;
}
.state-chip.active {
  color: var(--fg);
  border-color: var(--accent-2);
  background: rgba(79, 195, 247, 0.1);
}
.state-chip:hover,
.state-chip:focus-visible { border-color: var(--accent-2); color: var(--fg); }
/* Home-state chip — pinned at the head of the short list per
   docs/BROWSE_AND_DISCOVERY.md. Subtle accent so the user can find it. */
.state-chip--home {
  border-color: var(--accent-2);
  background: rgba(79, 195, 247, 0.06);
}
.state-chip--more {
  font-style: italic;
  color: var(--muted);
}

/* ---------- Browse-page location chip + first-visit nudge ----------
   See docs/BROWSE_AND_DISCOVERY.md. Kid-safe defaults: silent, no
   modal, fail open. */
.location-bar {
  margin: 0 0 1rem;
}
.location-chip-host {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}
.location-chip {
  background: var(--card);
  color: var(--fg);
  border: 1px solid var(--accent-2);
  padding: 0.4rem 0.9rem;
  border-radius: 999px;
  font-size: 0.85rem;
  font-weight: 500;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
}
.location-chip:hover,
.location-chip:focus-visible {
  background: rgba(79, 195, 247, 0.12);
}
.location-chip--secondary {
  border-color: var(--border);
  color: var(--muted);
  background: transparent;
}
.location-chip--set {
  background: rgba(79, 195, 247, 0.1);
}
.location-zip-form {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  flex-wrap: wrap;
}
.location-zip-input {
  width: 5rem;
  padding: 0.4rem 0.6rem;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--fg);
  font-size: 0.9rem;
  font-variant-numeric: tabular-nums;
}
.location-zip-error {
  color: var(--accent-warn, #ffb86b);
  font-size: 0.8rem;
}
.location-nudge[hidden] { display: none !important; }
.location-nudge {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-top: 0.6rem;
  padding: 0.5rem 0.75rem;
  background: rgba(79, 195, 247, 0.06);
  border: 1px dashed var(--accent-2);
  border-radius: 10px;
  color: var(--muted);
  font-size: 0.85rem;
}
.location-nudge[hidden] {
  display: none;
}
.location-nudge-dismiss {
  flex: 0 0 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  min-height: 44px;
  background: transparent;
  border: 0;
  color: var(--muted);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  padding: 0;
}
.location-nudge-dismiss:hover,
.location-nudge-dismiss:focus-visible { color: var(--fg); }

/* ---------- "Your area" pill on a state-section header ---------- */
.state-section-home-pill {
  display: inline-block;
  margin-left: 0.6rem;
  padding: 0.1rem 0.55rem;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--accent-2);
  background: rgba(79, 195, 247, 0.1);
  border: 1px solid var(--accent-2);
  border-radius: 999px;
  vertical-align: middle;
}

/* ---------- City-tinted placeholder for hunts without a cover_image.
   The inline `style` from cityGradientStyle() seeds the hue; a
   region-neutral image (compass / map / parchment) sits behind the
   gradient at reduced opacity so every card carries a visual without
   risking a wrong-region stock photo. See docs/BROWSE_AND_DISCOVERY.md. */
.hunt-card-img-themed {
  position: relative;
  aspect-ratio: 16 / 9;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.hunt-card-themed-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.55;
  mix-blend-mode: luminosity;
}
.hunt-card-themed-icon {
  width: 38%;
  max-width: 96px;
  opacity: 0.18;
  filter: brightness(2);
  position: absolute;
  inset: auto auto 8% 10%;
  z-index: 1;
}
.hunt-card-themed-title {
  position: relative;
  z-index: 1;
  color: rgba(255, 255, 255, 0.96);
  font-weight: 600;
  font-size: 1.05rem;
  text-align: center;
  padding: 0 1rem;
  line-height: 1.25;
  text-shadow: 0 2px 6px rgba(0, 0, 0, 0.6);
}

/* ---------- Setup page (location-only onboarding) ----------
   Hero + single rich location card + "why we need this" strip.
   Camera permission is requested lazily on the hunt page when the
   player taps the camera pill (see camera.js). */
.setup-page {
  max-width: 640px;
  margin: 0 auto;
  padding-bottom: 2rem;
}
.setup-hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  margin: 1.5rem 0 1.75rem;
  gap: 0.65rem;
}
.setup-hero-mark {
  position: relative;
  width: 76px;
  height: 76px;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 0.25rem;
}
.setup-hero-pin {
  position: relative;
  z-index: 2;
  font-size: 2.4rem;
  line-height: 1;
  filter: drop-shadow(0 4px 10px rgba(79, 195, 247, 0.35));
}
.setup-hero-ring {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(79, 195, 247, 0.28) 0%, rgba(79, 195, 247, 0) 70%);
  animation: setup-hero-pulse 2.6s ease-in-out infinite;
}
@keyframes setup-hero-pulse {
  0%, 100% { transform: scale(1); opacity: 0.85; }
  50%      { transform: scale(1.18); opacity: 1; }
}
.setup-hero-title {
  margin: 0;
  font-size: 1.7rem;
  line-height: 1.15;
  letter-spacing: -0.01em;
}
.setup-hero-sub {
  margin: 0;
  max-width: 30rem;
  color: var(--muted);
  font-size: 0.98rem;
  line-height: 1.5;
}
.setup-card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  margin-bottom: 1.25rem;
}
.setup-card--solo {
  padding: 1.4rem 1.4rem 1.3rem;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
}
.setup-card-head {
  display: flex;
  align-items: center;
  gap: 0.85rem;
}
.setup-card-head > div {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}
.setup-card--solo .setup-card-icon {
  font-size: 2rem;
  width: 3rem;
  height: 3rem;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(79, 195, 247, 0.1);
  border: 1px solid rgba(79, 195, 247, 0.35);
  border-radius: 12px;
}
.setup-why {
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 1rem 1.15rem;
  margin: 0 0 1.5rem;
}
.setup-why-title {
  margin: 0 0 0.6rem;
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}
.setup-why-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 0.6rem;
}
.setup-why-list li {
  display: flex;
  gap: 0.7rem;
  align-items: flex-start;
  font-size: 0.92rem;
  line-height: 1.45;
  color: var(--fg);
}
.setup-why-list strong { color: var(--fg); }
.setup-why-icon {
  font-size: 1.15rem;
  line-height: 1.2;
  flex-shrink: 0;
}
.setup-card[data-state="granted"],
.setup-card[data-state="set"] {
  border-color: rgba(80, 200, 120, 0.5);
  background: linear-gradient(180deg, rgba(80, 200, 120, 0.06), var(--card));
}
.setup-card[data-state="denied"],
.setup-card[data-state="unavailable"] {
  border-color: rgba(255, 184, 107, 0.45);
}
.setup-card-icon {
  font-size: 1.6rem;
  line-height: 1;
}
.setup-card-title {
  margin: 0;
  font-size: 1.1rem;
  font-weight: 600;
}
.setup-card-status {
  display: inline-block;
  padding: 0.15rem 0.55rem;
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  width: fit-content;
}
.setup-card-status--ok {
  color: #50c878;
  background: rgba(80, 200, 120, 0.12);
  border: 1px solid rgba(80, 200, 120, 0.4);
}
.setup-card-status--pending {
  color: var(--accent-2);
  background: rgba(79, 195, 247, 0.1);
  border: 1px solid var(--accent-2);
}
.setup-card-status--blocked {
  color: var(--accent-warn, #ffb86b);
  background: rgba(255, 184, 107, 0.1);
  border: 1px solid rgba(255, 184, 107, 0.45);
}
.setup-card-status--neutral {
  color: var(--muted);
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--border);
}
.setup-card-status--cta {
  cursor: pointer;
  padding: 0.45rem 0.95rem;
  font-size: 0.8rem;
  user-select: none;
  transition: background 120ms ease, transform 120ms ease;
}
.setup-card-status--cta:hover {
  background: rgba(79, 195, 247, 0.18);
}
.setup-card-status--cta:active {
  transform: scale(0.97);
}
.setup-card-status--cta:focus-visible {
  outline: 2px solid var(--accent-2);
  outline-offset: 2px;
}
.setup-card-body {
  margin: 0;
  color: var(--muted);
  font-size: 0.9rem;
  line-height: 1.4;
}
.setup-card-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 0.4rem;
}
.setup-card-btn {
  font-size: 0.9rem;
}
.setup-card-btn-skip {
  background: transparent;
  border: 0;
  color: var(--muted);
  text-decoration: underline;
  cursor: pointer;
  padding: 0.3rem 0.5rem;
  font-size: 0.85rem;
}
.setup-card-btn-skip:hover { color: var(--fg); }
.setup-zip-form {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  flex-wrap: wrap;
}
.setup-zip-input {
  width: 5rem;
  padding: 0.4rem 0.6rem;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--fg);
  font-size: 0.9rem;
  font-variant-numeric: tabular-nums;
}
.setup-zip-error {
  color: var(--accent-warn, #ffb86b);
  font-size: 0.8rem;
}
.setup-footer {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  align-items: center;
  margin-top: 1rem;
  text-align: center;
}
.setup-footer .btn {
  min-width: 12rem;
}
.setup-footer-hint {
  margin: 0;
  font-size: 0.85rem;
}

/* ---------- Stops table of contents (hunt-detail.html) ---------- */
.stops-toc { margin: 1.5rem 0; }
.stops-toc-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}
.stops-toc-item {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
}
.stops-toc-item--completed { border-left: 3px solid #a3e635; }
.stops-toc-item--open { border-left: 3px solid var(--accent-2); }
.stops-toc-item--locked {
  border-left: 3px solid rgba(255, 255, 255, 0.22);
  background: rgba(255, 255, 255, 0.025);
}

/* One layout for every card variant (open <a>, completed <summary>,
   locked <a> or <div>): num circle on the left, title + clue stacked
   in a flexible content column on the right, optional status/trailing
   chip on the far right. Keeping every variant on the same flex row
   means each card is one tap target the full height of the row. */
.stops-toc-item summary,
.stops-toc-link,
.stops-toc-locked {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.55rem 0.7rem;
  font-size: 0.95rem;
  min-height: 44px;
  cursor: pointer;
  text-decoration: none;
  color: var(--fg);
}
.stops-toc-link:hover,
.stops-toc-item summary:hover,
.stops-toc-locked:hover,
.stops-toc-link:focus-visible,
.stops-toc-item summary:focus-visible { background: rgba(255,255,255,0.04); }
.stops-toc-item summary { list-style: none; }
.stops-toc-item summary::-webkit-details-marker { display: none; }
/* hunt-detail.js still renders its locked variants as a <button> /
   <div> with this class (no .stops-toc-link wrapper); the legacy reset
   keeps them looking like the rest of the row. */
.stops-toc-locked {
  background: none;
  border: none;
  width: 100%;
  text-align: left;
  font: inherit;
}
/* Inert locked variant for purchased-but-finale-gated players — no
   hover since there's nothing to click. */
.stops-toc-link.stops-toc-locked { cursor: default; }
.stops-toc-link.stops-toc-locked:hover { background: transparent; }

.stops-toc-content {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}
.stops-toc-heading {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.4rem;
}
.stops-toc-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: rgba(255,255,255,0.08);
  font-size: 0.8rem;
  font-weight: 600;
  flex-shrink: 0;
  align-self: flex-start;
  margin-top: 0.1rem;
}
.stops-toc-item--completed .stops-toc-num { background: rgba(163,230,53,0.15); color: #a3e635; }
.stops-toc-item--open .stops-toc-num { background: rgba(79,195,247,0.15); color: var(--accent-2); }
.stops-toc-item--locked .stops-toc-num {
  background: rgba(255, 255, 255, 0.08);
  color: var(--fg-secondary);
}
.stops-toc-icon { font-size: 0.85rem; flex-shrink: 0; }
.stops-toc-status,
.stops-toc-arrow {
  font-size: 0.9rem;
  flex-shrink: 0;
  color: var(--muted);
  align-self: center;
}
.stops-toc-title { font-weight: 500; line-height: 1.3; }
/* Legacy single-row layout (hunt-detail.js) renders the title as a
   direct child of the flex row and needs flex:1 so it pushes trailing
   chips to the far right. Inside .stops-toc-content (toc.js) the title
   is stacked vertically and doesn't need it. */
.stops-toc-link > .stops-toc-title,
.stops-toc-item summary > .stops-toc-title,
.stops-toc-locked > .stops-toc-title { flex: 1; }
.stops-toc-reveal {
  padding: 0 0.85rem 0.75rem 3.5rem;
  color: var(--muted);
  font-size: 0.9rem;
  line-height: 1.4;
}
.stops-toc-clue {
  margin: 0;
  /* hunt-detail.js's TOC renders the clue as a sibling of the row,
     so it needs left padding to align under the title past the num
     gutter. toc.js nests the clue inside .stops-toc-content where the
     padding override below pulls it back to the content column edge. */
  padding: 0.15rem 0 0.05rem 2.5rem;
  color: var(--muted);
  font-size: 0.85rem;
  line-height: 1.35;
  font-style: italic;
}
.stops-toc-content .stops-toc-clue { padding: 0; }

/* Inline paywall card — sits inside the stops-toc list at the boundary
   where the player's access ends. The boxed treatment + accent border
   make the breakpoint obvious without interrupting the stops rhythm. */
.stops-toc-paywall {
  background: rgba(79, 195, 247, 0.06);
  border: 1px solid var(--accent-2);
  border-radius: 12px;
  padding: 1rem;
  margin: 0.75rem 0;
}
@keyframes paywall-flash {
  0%, 100% { background: rgba(79, 195, 247, 0.06); }
  30% { background: rgba(79, 195, 247, 0.22); }
}
.stops-toc-paywall--flash {
  animation: paywall-flash 0.7s ease;
}
.stops-toc-paywall-heading {
  margin: 0 0 0.25rem;
  font-size: 1rem;
  color: var(--accent-2);
}
.stops-toc-paywall-sub {
  margin: 0 0 0.85rem;
  font-size: 0.88rem;
  color: var(--muted);
  line-height: 1.4;
}
.stops-toc-paywall-ctas {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.stops-toc-paywall .anytown-tiers {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.5rem;
  margin-bottom: 0.75rem;
}
.stops-toc-paywall .anytown-sub-banner {
  margin-top: 0.5rem;
}

/* "Free" pill rendered next to the first N stops on non-owners' TOC,
   making the free-vs-paid split visible without reading the paywall
   card. Lime green keeps it consistent with the tier-1 group color. */
.stop-free-badge {
  display: inline-block;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 0.1rem 0.45rem;
  border-radius: 999px;
  margin-left: 0.4rem;
  color: #1f2937;
  background: var(--tier-color-g1);
  white-space: nowrap;
}

/* Locked stops on a paywall hunt show "Buy to unlock" + a brighter
   left border so they read as actionable, not as dim placeholders. */
.stops-toc-locked-cta {
  font-size: 0.78rem;
  color: var(--accent-2);
  font-weight: 600;
  padding: 0.18rem 0.52rem;
  border: 1px solid rgba(79, 195, 247, 0.35);
  border-radius: 999px;
  background: rgba(79, 195, 247, 0.08);
  white-space: nowrap;
  flex-shrink: 0;
  align-self: center;
}
.stops-toc-item.stops-toc-item--paywall {
  opacity: 1;
  border-left-color: var(--accent-2);
}
.stops-toc-locked--cta:hover,
.stops-toc-locked--cta:focus-visible {
  background: rgba(79, 195, 247, 0.06);
}

/* Quiet pill button beneath the stops list — only rendered after
   purchase on canonical 13-stop hunts. Tapping opens the unlock-modal
   that explains how the tier-2/tier-3 stops gate. */
.unlock-info-btn {
  display: block;
  margin: 1rem auto 0;
  padding: 0.55rem 1.1rem;
  font-size: 0.9rem;
  background: transparent;
  color: var(--accent-2);
  border: 1px solid var(--accent-2);
  border-radius: 999px;
  cursor: pointer;
}
.unlock-info-btn:hover { background: rgba(79, 195, 247, 0.08); }
.unlock-info-btn:focus-visible {
  outline: 2px solid var(--accent-2);
  outline-offset: 2px;
}

/* Modal overlay — shape mirrors .hint-modal so the two feel like one
   pattern. Higher z-index than the AR compass overlay (60) but below
   the completion modal (150) so a finale celebration still wins. */
.unlock-modal {
  position: fixed;
  inset: 0;
  z-index: 90;
  background: rgba(0, 0, 0, 0.6);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
}
.unlock-modal[hidden] { display: none !important; }
.unlock-modal-inner {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 1.25rem 1.25rem 1.5rem;
  max-width: 420px;
  width: 100%;
  max-height: calc(100dvh - 2rem);
  overflow-y: auto;
  position: relative;
  animation: hint-modal-pop 180ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
.unlock-modal-title {
  margin: 0 0 0.6rem;
  font-size: 1.05rem;
  color: var(--fg);
}
.unlock-modal-list {
  margin: 0;
  padding-left: 1.1rem;
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--muted);
}
.unlock-modal-list li + li { margin-top: 0.35rem; }
.unlock-modal-close {
  position: absolute;
  top: 0.4rem;
  right: 0.5rem;
  background: transparent;
  border: none;
  font-size: 1.5rem;
  line-height: 1;
  color: var(--muted);
  cursor: pointer;
  padding: 0.5rem 0.6rem;
  border-radius: 6px;
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.unlock-modal-close:hover { color: var(--fg); background: rgba(255, 255, 255, 0.06); }
.unlock-modal-close:focus-visible {
  outline: 2px solid var(--accent-2);
  outline-offset: 2px;
}

/* Inline paywall offer cards — Buy hunt, All Access, Bundle. Same shape
   so the three options read as parallel choices; differentiated by
   tinted background + heading color so the eye can still tell them
   apart. Whole card is a click target (role=button); the inner CTA
   button stops propagation so we don't double-fire checkout. */
.paywall-option-card {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  padding: 0.85rem 1rem;
  border-radius: 0.5rem;
  background: rgba(20, 25, 50, 0.55);
  border: 1px solid var(--border);
  cursor: pointer;
  transition: background-color 0.15s ease, transform 0.05s ease;
}
.paywall-option-card:hover {
  background: rgba(255, 255, 255, 0.05);
}
.paywall-option-card:active {
  transform: scale(0.995);
}
/* The inner <button> owns the tab stop; light up the whole card when
   keyboard focus lands inside so the focused area still reads as a
   single offer, not just a button. */
.paywall-option-card:focus-within {
  outline: 2px solid var(--accent-2);
  outline-offset: 2px;
}
.paywall-option-heading {
  margin: 0;
  font-size: 1rem;
  color: var(--fg);
}
.paywall-option-price {
  font-size: 1.05rem;
  font-weight: 700;
}
.paywall-option-sub {
  font-size: 0.88rem;
  color: var(--muted);
  line-height: 1.4;
}
.paywall-option-cta {
  width: 100%;
  margin-top: 0.35rem;
}

/* Variant: Buy this hunt — warm red to match the primary checkout CTA. */
.paywall-option-card--hunt {
  background: rgba(229, 62, 62, 0.10);
  border-color: rgba(229, 62, 62, 0.45);
}
.paywall-option-card--hunt:hover {
  background: rgba(229, 62, 62, 0.16);
}
.paywall-option-card--hunt .paywall-option-heading {
  color: #f87171;
}

/* Variant: All Access — gold gradient (subscription tier). */
.paywall-option-card--all-access {
  background: linear-gradient(135deg, rgba(194, 124, 10, 0.22), rgba(246, 173, 85, 0.16));
  border-color: rgba(246, 173, 85, 0.45);
}
.paywall-option-card--all-access:hover {
  background: linear-gradient(135deg, rgba(194, 124, 10, 0.30), rgba(246, 173, 85, 0.24));
}
.paywall-option-card--all-access .paywall-option-heading {
  color: #f6ad55;
}

/* Variant: Bundle — accent-blue tint, paired with the existing
   .paywall-bundle-* classes that style the inner hunt-titles list. */
.paywall-option-card--bundle {
  background: rgba(79, 195, 247, 0.10);
  border-color: var(--accent-2);
}
.paywall-option-card--bundle:hover {
  background: rgba(79, 195, 247, 0.16);
}
.paywall-bundle-heading {
  color: var(--accent-2);
}
.paywall-bundle-savings {
  display: inline-block;
  margin-left: 0.35rem;
  padding: 0.1rem 0.45rem;
  border-radius: 999px;
  background: rgba(72, 187, 120, 0.22);
  border: 1px solid rgba(72, 187, 120, 0.5);
  color: #9ae6b4;
  font-size: 0.78rem;
  font-weight: 600;
  vertical-align: middle;
}
.paywall-bundle-hunts {
  margin: 0.15rem 0 0.25rem;
  padding-left: 1.1rem;
  font-size: 0.88rem;
  color: var(--muted);
  line-height: 1.4;
}
.paywall-bundle-hunts li {
  margin: 0.1rem 0;
}
.paywall-bundle-more {
  list-style: none;
  margin-left: -1.1rem;
  font-style: italic;
  opacity: 0.85;
}
/* Quiet "see all pricing options" link below the three offer cards. */
.paywall-pricing-link {
  display: block;
  text-align: center;
  margin-top: 0.85rem;
  font-size: 0.85rem;
  color: var(--accent-2);
  text-decoration: none;
}
.paywall-pricing-link:hover {
  text-decoration: underline;
}
.paywall-pricing-link:focus-visible {
  outline: 2px solid var(--accent-2);
  outline-offset: 2px;
  border-radius: 4px;
}

/* Site-wide footer injected by common.js renderSiteFooter(). Follows
   main's responsive max-width so the border-top lines up with the
   content column at every breakpoint. */
.site-footer {
  margin: 3rem auto 1rem;
  padding: 1.5rem 1.25rem 0;
  max-width: 520px;
  border-top: 1px solid var(--border);
  text-align: center;
  font-size: 0.85rem;
  color: var(--muted);
}
@media (min-width: 900px) {
  .site-footer { max-width: 1080px; }
}
body.admin .site-footer { max-width: 1280px; }
.site-footer-links {
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem;
  justify-content: center;
  margin-bottom: 0.6rem;
}
.site-footer-links a {
  color: var(--muted);
  text-decoration: none;
}
.site-footer-links a:hover,
.site-footer-links a:focus {
  color: var(--fg);
  text-decoration: underline;
}
.site-footer-contact {
  margin-bottom: 0.6rem;
  font-size: 0.8rem;
}
.site-footer-contact a {
  color: var(--accent);
  text-decoration: none;
}
.site-footer-contact a:hover,
.site-footer-contact a:focus {
  text-decoration: underline;
}
.site-footer-copy {
  font-size: 0.8rem;
  opacity: 0.7;
}

/* ══════════════════════════════════════════════════════════════════════
   CUSTOM QUOTE FORM  (contact page)
   ══════════════════════════════════════════════════════════════════════ */
.quote-form {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 1.1rem;
  margin: 1rem 0 1.5rem;
}
.quote-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.75rem;
}
@media (max-width: 520px) {
  .quote-row { grid-template-columns: 1fr; }
}
.quote-form label { gap: 0.35rem; }
.quote-form textarea {
  padding: 0.6rem 0.75rem;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.04);
  color: var(--fg);
  font-family: inherit;
  font-size: 1rem;
  resize: vertical;
}
.quote-form input[type="range"] {
  padding: 0;
  background: transparent;
  border: none;
}
.quote-range-value {
  color: var(--fg);
  font-size: 0.9rem;
  font-variant-numeric: tabular-nums;
}
.quote-required { color: var(--accent); }
.quote-optional { color: var(--muted); font-weight: normal; font-size: 0.8rem; }

.quote-packages {
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.6rem 0.9rem 0.8rem;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}
.quote-packages legend {
  color: var(--muted);
  font-size: 0.85rem;
  padding: 0 0.35rem;
}
.quote-pkg {
  display: grid;
  grid-template-columns: auto 1fr auto auto;
  align-items: center;
  gap: 0.6rem;
  padding: 0.55rem 0.6rem;
  border: 1px solid var(--border);
  border-radius: 6px;
  cursor: pointer;
  color: var(--fg);
  font-size: 0.95rem;
}
.quote-pkg:hover { border-color: rgba(79, 195, 247, 0.5); }
.quote-pkg input[type="radio"] { margin: 0; }
.quote-pkg:has(input[type="radio"]:checked) {
  border-color: var(--accent-2);
  background: rgba(79, 195, 247, 0.08);
}
.quote-pkg-title { font-weight: 600; }
.quote-pkg-meta { color: var(--muted); font-size: 0.85rem; }
.quote-pkg-price { font-variant-numeric: tabular-nums; color: var(--fg); font-weight: 600; }

.quote-extras {
  flex-direction: row !important;
  align-items: flex-start;
  gap: 0.6rem !important;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--border);
  border-radius: 6px;
  cursor: pointer;
  color: var(--fg);
  font-size: 0.92rem;
}
.quote-extras input[type="checkbox"] { margin-top: 0.2rem; }
.quote-extras-price {
  color: var(--muted);
  margin-left: 0.4rem;
  font-variant-numeric: tabular-nums;
}

.quote-total {
  font-size: 1rem;
  color: var(--muted);
  padding-top: 0.4rem;
  border-top: 1px solid var(--border);
}
.quote-total strong {
  color: var(--fg);
  font-size: 1.15rem;
  font-variant-numeric: tabular-nums;
  margin-left: 0.35rem;
}

.quote-success {
  margin: 0;
  color: #a3e635;
  font-size: 0.95rem;
}

.quote-map-block {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.quote-map-panel {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 0.6rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.02);
}
.quote-map-help {
  margin: 0;
  color: var(--muted);
  font-size: 0.85rem;
}
.quote-map {
  height: 320px;
  width: 100%;
  border-radius: 6px;
  overflow: hidden;
  background: #121830;
}
.quote-map-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem;
  flex-wrap: wrap;
}
.quote-map-stats {
  font-size: 0.85rem;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.quote-map-error { margin: 0; min-height: 1.1em; }

/* ══════════════════════════════════════════════════════════════════════
   ADMIN · QUOTES PAGE
   ══════════════════════════════════════════════════════════════════════ */
.admin-quotes-main {
  max-width: 960px;
  margin: 0 auto;
  padding: 1.25rem;
}
.quote-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-bottom: 1rem;
}
.quote-filter {
  background: transparent;
  color: var(--muted);
  border: 1px solid var(--border);
  padding: 0.4rem 0.9rem;
  border-radius: 999px;
  font-size: 0.85rem;
  font-weight: 500;
  cursor: pointer;
}
.quote-filter.active {
  color: var(--fg);
  border-color: var(--accent-2);
  background: rgba(79, 195, 247, 0.1);
}
.quote-filter-count {
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.quote-filter.active .quote-filter-count { color: var(--fg); }

.quote-filter-group {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.75rem;
}
.quote-filter-group .quote-filters { margin-bottom: 0; }
.quote-filter-label {
  color: var(--muted);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 600;
  flex-shrink: 0;
}
.quote-card-lifecycle {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 0.15rem 0.55rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.08);
  color: var(--muted);
  flex-shrink: 0;
}
.quote-card-lifecycle[data-lifecycle="requested"] {
  background: rgba(79, 195, 247, 0.15); color: #a5dcff;
}
.quote-card-lifecycle[data-lifecycle="awaiting_feedback"] {
  background: rgba(255, 215, 0, 0.15); color: #ffe486;
}
.quote-card-lifecycle[data-lifecycle="paid"] {
  background: rgba(163, 230, 53, 0.18); color: #c6f086;
}
.quote-card-lifecycle[data-lifecycle="in_progress"] {
  background: rgba(186, 104, 200, 0.18); color: #e1b6f0;
}
.quote-card-lifecycle[data-lifecycle="shipped"] {
  background: rgba(79, 195, 247, 0.22); color: #c8e9ff;
}
.quote-card-lifecycle[data-lifecycle="live"] {
  background: rgba(76, 175, 80, 0.22); color: #b8efb6;
}
.quote-card-lifecycle[data-lifecycle="deprecated"] {
  background: rgba(255, 255, 255, 0.05); color: var(--muted);
}

.quote-empty {
  color: var(--muted);
  padding: 2rem 0;
  text-align: center;
  font-style: italic;
}

.quote-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
}
.quote-card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
}
.quote-card-summary {
  width: 100%;
  display: block;
  text-align: left;
  background: transparent;
  color: var(--fg);
  border: none;
  padding: 0.85rem 1rem;
  cursor: pointer;
  font: inherit;
}
.quote-card-summary:hover { background: rgba(255, 255, 255, 0.03); }
.quote-card-summary.open { background: rgba(79, 195, 247, 0.06); }
.quote-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 0.25rem;
}
.quote-card-email {
  font-weight: 600;
  font-size: 0.95rem;
  word-break: break-all;
}
.quote-card-status {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 0.15rem 0.55rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.08);
  color: var(--muted);
  flex-shrink: 0;
}
.quote-card-status[data-status="new"] {
  background: rgba(233, 79, 55, 0.15); color: #ffb4a8;
}
.quote-card-status[data-status="contacted"] {
  background: rgba(79, 195, 247, 0.15); color: #a5dcff;
}
.quote-card-status[data-status="quoted"] {
  background: rgba(255, 215, 0, 0.15); color: #ffe486;
}
.quote-card-status[data-status="won"] {
  background: rgba(163, 230, 53, 0.15); color: #c6f086;
}
.quote-card-status[data-status="lost"],
.quote-card-status[data-status="archived"] {
  background: rgba(255, 255, 255, 0.05); color: var(--muted);
}
.quote-card-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  color: var(--muted);
  font-size: 0.82rem;
}
.quote-card-body {
  padding: 0 1rem 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
  border-top: 1px solid var(--border);
  padding-top: 0.85rem;
  margin-top: 0;
}
.quote-details {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 0.5rem 1rem;
  margin: 0;
  font-size: 0.88rem;
}
.quote-details > div { display: flex; flex-direction: column; gap: 0.1rem; }
.quote-details dt {
  color: var(--muted);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.quote-details dd { margin: 0; color: var(--fg); }
.quote-details-notes { gap: 0.35rem; }
.quote-notes-readonly {
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.6rem 0.75rem;
  color: var(--fg);
  font-size: 0.9rem;
  white-space: pre-wrap;
  min-height: 2.4em;
}
.quote-card-body select,
.quote-card-body textarea {
  padding: 0.55rem 0.7rem;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.04);
  color: var(--fg);
  font-family: inherit;
  font-size: 0.95rem;
}
.quote-card-body textarea { resize: vertical; }
.quote-save-status {
  font-size: 0.85rem;
  color: #a3e635;
  align-self: center;
}
.quote-save-status.error { color: #ff7070; }

.quote-details-geofence {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 0.6rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: rgba(79, 195, 247, 0.04);
}
.quote-geofence-stats {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.6rem;
  flex-wrap: wrap;
  font-size: 0.85rem;
  color: var(--fg);
  font-variant-numeric: tabular-nums;
}
.quote-geofence-label {
  color: var(--muted);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.quote-admin-map {
  height: 220px;
  width: 100%;
  border-radius: 6px;
  overflow: hidden;
  background: #121830;
}

/* ── AI draft panel ── */
.quote-ai-panel {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  padding: 0.7rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: rgba(163, 230, 53, 0.04);
}
.quote-ai-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.6rem;
}
.quote-ai-label {
  color: var(--muted);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.quote-ai-rating {
  font-size: 0.78rem;
  font-variant-numeric: tabular-nums;
  padding: 0.12rem 0.55rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.08);
  color: var(--fg);
}
.quote-ai-rating[data-tier="good"] { background: rgba(163, 230, 53, 0.2); color: #c6f086; }
.quote-ai-rating[data-tier="marginal"] { background: rgba(255, 215, 0, 0.2); color: #ffe486; }
.quote-ai-rating[data-tier="poor"] { background: rgba(233, 79, 55, 0.2); color: #ffb4a8; }

.quote-ai-empty,
.quote-ai-drafting {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.quote-ai-empty p,
.quote-ai-drafting p { margin: 0; }

.quote-ai-draft {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
}
.quote-ai-rubric summary,
.quote-ai-yaml summary {
  cursor: pointer;
  color: var(--muted);
  font-size: 0.85rem;
  padding: 0.25rem 0;
}
.quote-ai-rubric dl {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.25rem 0.75rem;
  margin: 0.35rem 0;
  font-size: 0.88rem;
}
.quote-ai-rubric dt {
  color: var(--muted);
  text-transform: capitalize;
}
.quote-ai-rubric dd {
  margin: 0;
  font-variant-numeric: tabular-nums;
}
.quote-ai-yaml pre {
  max-height: 320px;
  overflow: auto;
  background: rgba(0, 0, 0, 0.25);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.65rem;
  font-size: 0.8rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  white-space: pre-wrap;
  color: var(--fg);
}
.quote-ai-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}
.quote-ai-override {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.82rem;
  color: var(--muted);
  cursor: pointer;
}
.quote-ai-reject-panel {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  padding: 0.55rem;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: rgba(255, 112, 112, 0.04);
}
.quote-ai-reject-panel textarea {
  padding: 0.5rem 0.65rem;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.04);
  color: var(--fg);
  font-family: inherit;
  font-size: 0.9rem;
  resize: vertical;
}
.quote-ai-linked {
  margin: 0;
  font-size: 0.85rem;
  color: #a3e635;
}
.quote-ai-error { margin: 0; min-height: 1.1em; }

/* =============================================================================
   PAYMENTS — hunt-card price chip, hunt-detail buy CTAs, /purchases page
   ============================================================================= */

/* Anytown hunt-detail purchase UI: a subscription banner above three
   side-by-side tier cards. Mirrors the existing .btn family so visual
   weight matches the standard-hunt price chip. */
.anytown-sub-banner {
  padding: 0.75rem 1rem;
  border-radius: 0.5rem;
  background: linear-gradient(135deg, rgba(194, 124, 10, 0.25), rgba(246, 173, 85, 0.18));
  border: 1px solid rgba(246, 173, 85, 0.45);
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
}
.anytown-tiers {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 0.75rem;
}
.anytown-tier {
  padding: 0.75rem;
  border-radius: 0.5rem;
  background: rgba(20, 25, 50, 0.7);
  border: 1px solid rgba(255, 255, 255, 0.08);
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}
.anytown-tier h4 { margin: 0; font-size: 1rem; }
.anytown-tier .price { font-size: 1.1rem; font-weight: 700; }
.anytown-tier .range { font-size: 0.85rem; opacity: 0.8; }
.anytown-tier--owned {
  opacity: 0.6;
  background: rgba(49, 130, 206, 0.25);
}

/* Per-stop lock badges on the TOC / stops overview. The ?? icon sits
   inline so a kid can tell which stops are still to unlock at a glance. */
.stop-lock-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.1rem 0.45rem;
  margin-left: 0.4rem;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 600;
  background: rgba(194, 124, 10, 0.35);
  color: #f6ad55;
  border: 1px solid rgba(246, 173, 85, 0.4);
}

/* Local Legend badge on stops-toc rows (Strava-style — most visits in
 * the rolling 90 day window). Inline with the stop title; gold to read
 * as "trophy" without competing with the green "completed" border or
 * the blue accent. Same shape and weight as .stop-lock-badge — both
 * are inline metadata pills, distinguished only by color (gold here,
 * orange there). */
.toc-legend-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.2rem;
  padding: 0.08rem 0.45rem;
  margin-left: 0.4rem;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 600;
  background: rgba(245, 183, 0, 0.18);
  color: #f5b700;
  border: 1px solid rgba(245, 183, 0, 0.45);
  white-space: nowrap;
}

/* Subscription card on /profile.html — shows status + "Manage" CTA
   that opens Stripe's hosted Customer Portal. */
.subscription-card {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1rem;
  border-radius: 0.75rem;
  background: rgba(20, 25, 50, 0.7);
  border: 1px solid rgba(255, 255, 255, 0.08);
  flex-wrap: wrap;
}
.subscription-status {
  display: inline-block;
  margin-left: 0.5rem;
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  font-size: 0.78rem;
  font-weight: 600;
  background: rgba(160, 160, 160, 0.25);
}
.subscription-status--active {
  background: rgba(56, 161, 105, 0.3);
  color: #9ae6b4;
}
.subscription-status--warn {
  background: rgba(214, 158, 46, 0.3);
  color: #faf089;
}
.subscription-status--off {
  background: rgba(120, 120, 120, 0.25);
  color: #cbd5e0;
}

/* Inline badges used in the admin Anytown overlay list. Three subtle
   variants so source/state distinctions read at a glance. */
.badge {
  display: inline-block;
  padding: 0.05rem 0.4rem;
  margin-left: 0.3rem;
  border-radius: 999px;
  font-size: 0.68rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  background: rgba(160, 160, 160, 0.25);
  color: #cbd5e0;
}
.badge--info { background: rgba(49, 130, 206, 0.3); color: #90cdf4; }
.badge--accent { background: rgba(56, 161, 105, 0.3); color: #9ae6b4; }
.badge--warn { background: rgba(214, 158, 46, 0.3); color: #faf089; }

.archetype-list {
  list-style: disc;
  padding-left: 1.25rem;
  margin: 0;
}

/* Buy CTA buttons on hunt-detail piggy-back on the existing .btn /
   .btn-secondary styles — no new selectors needed. The post-purchase
   "Finalizing…" status uses .muted; only need a subtle progress hint. */
#post-paid-status::after {
  content: "";
  display: inline-block;
  width: 0.6em;
  margin-left: 0.4em;
  animation: post-paid-dots 1.2s steps(4, end) infinite;
}
@keyframes post-paid-dots {
  0%   { content: ""; }
  25%  { content: "."; }
  50%  { content: ".."; }
  75%  { content: "..."; }
  100% { content: ""; }
}

/* Owned hunts + receipts list on /profile.html (My Account). */
.owned-hunts {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}
.owned-hunts li {
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 8px;
  padding: 0.5rem 0.85rem;
}
.owned-hunts a { color: inherit; text-decoration: none; }
.owned-hunts a:hover { text-decoration: underline; }

.purchases-table {
  width: 100%;
  border-collapse: collapse;
  margin-top: 0.75rem;
}
.purchases-table th,
.purchases-table td {
  text-align: left;
  padding: 0.5rem 0.7rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  font-size: 0.9rem;
}
.purchases-table th {
  color: #9aa3c7;
  font-weight: 600;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.purchases-table code {
  font-size: 0.82rem;
  background: rgba(255, 255, 255, 0.06);
  padding: 0.05rem 0.35rem;
  border-radius: 4px;
}

/* =============================================================================
   ADMIN CONSOLE — asset index + asset preview pages
   ============================================================================= */
.asset-index-page,
.asset-preview-page {
  max-width: 1080px;
  margin: 0 auto;
  padding: 1.5rem 1rem 4rem;
}

.asset-index-header,
.asset-preview-header {
  flex-direction: column;
  align-items: flex-start;
  gap: 0.25rem;
  justify-content: flex-start;
}

.asset-index-header h1,
.asset-preview-header h1 {
  margin: 0 0 0.5rem;
  font-size: 1.6rem;
}

.asset-index-header p,
.asset-preview-header p {
  margin: 0;
}

.asset-index-controls {
  display: flex;
  gap: 0.75rem;
  align-items: center;
  flex-wrap: wrap;
  margin: 1rem 0 0.75rem;
}

.asset-index-search {
  flex: 1 1 320px;
  min-width: 220px;
  padding: 0.55rem 0.75rem;
  font-size: 1rem;
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.04);
  color: inherit;
}

.asset-index-search:focus {
  outline: 2px solid var(--accent, #4a9eff);
  outline-offset: 2px;
}

.asset-index-tree {
  margin-top: 0.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.asset-index-state {
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.02);
  overflow: hidden;
}

.asset-index-state[open] {
  background: rgba(255, 255, 255, 0.04);
}

.asset-index-state-summary {
  cursor: pointer;
  padding: 0.7rem 0.9rem;
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  font-weight: 600;
  list-style: none;
}

.asset-index-state-summary::-webkit-details-marker { display: none; }

.asset-index-state-summary::before {
  content: "▶";
  font-size: 0.7em;
  color: var(--accent, #4a9eff);
  transition: transform 0.15s ease;
  display: inline-block;
}

.asset-index-state[open] > .asset-index-state-summary::before {
  transform: rotate(90deg);
}

.state-summary-code {
  font-size: 1.05rem;
  letter-spacing: 0.05em;
}

.state-summary-count {
  font-size: 0.85rem;
}

.asset-index-state-body {
  padding: 0.25rem 0.9rem 0.9rem;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.asset-index-hunt {
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 8px;
  background: rgba(0, 0, 0, 0.18);
}

.asset-index-hunt-summary {
  cursor: pointer;
  padding: 0.55rem 0.75rem;
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  flex-wrap: wrap;
  list-style: none;
}

.asset-index-hunt-summary::-webkit-details-marker { display: none; }

.asset-index-hunt-summary::before {
  content: "▸";
  color: var(--accent, #4a9eff);
  margin-right: 0.15rem;
  display: inline-block;
  transition: transform 0.15s ease;
}

.asset-index-hunt[open] > .asset-index-hunt-summary::before {
  transform: rotate(90deg);
}

.hunt-summary-title {
  font-weight: 600;
}

.hunt-summary-slug {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 0.85rem;
}

.hunt-summary-count {
  font-size: 0.85rem;
}

.asset-index-hunt-body {
  padding: 0 0.75rem 0.75rem;
}

.stop-card {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  padding: 0.7rem 0.8rem;
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 0.5rem;
  background: rgba(255, 255, 255, 0.02);
}

.stop-card + .stop-card {
  margin-top: 0.5rem;
}

.stop-card-head {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  flex-wrap: wrap;
}

.stop-order {
  font-variant-numeric: tabular-nums;
  color: var(--muted, #a8b0c0);
  font-size: 0.85rem;
}

.stop-card-title {
  font-weight: 600;
  font-size: 0.95rem;
  overflow-wrap: anywhere;
}

.stop-card-assets {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: 0.6rem;
}

.asset-panel {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding: 0.55rem 0.65rem;
  border: 1px solid rgba(255, 255, 255, 0.06);
  border-radius: 0.4rem;
  background: var(--card);
  min-width: 0;
}

.asset-panel-label {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 600;
}

.asset-panel-empty {
  background: rgba(255, 255, 255, 0.02);
  border-style: dashed;
}

.asset-panel-missing {
  font-size: 0.85rem;
  font-style: italic;
}

.asset-slug-link {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 0.85rem;
  color: var(--accent, #4a9eff);
  text-decoration: none;
  overflow-wrap: anywhere;
  word-break: break-word;
}

.asset-slug-link:hover,
.asset-slug-link:focus {
  text-decoration: underline;
}

.asset-slug-empty {
  color: rgba(255, 255, 255, 0.3);
}

.asset-desc {
  font-size: 0.78rem;
  color: var(--muted, #a8b0c0);
  line-height: 1.35;
  overflow-wrap: anywhere;
}

.asset-index-empty {
  margin: 0.4rem 0;
  font-size: 0.9rem;
}

/* Asset group card (slug-first view) */
.asset-group-card {
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.03);
  padding: 1rem 1.1rem 0.9rem;
}

.asset-group-head {
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  margin-bottom: 0.35rem;
}

.asset-group-head .asset-slug-link {
  font-size: 1rem;
  font-weight: 600;
}

.asset-use-count {
  font-size: 0.82rem;
}

.asset-group-card .asset-desc {
  margin: 0 0 0.75rem;
  font-size: 0.82rem;
  color: var(--muted, #a8b0c0);
  line-height: 1.4;
}

.asset-usage-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.875rem;
}

.asset-usage-table th {
  text-align: left;
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted, #a8b0c0);
  padding: 0.3rem 0.5rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  font-weight: 600;
}

.asset-usage-table td {
  padding: 0.35rem 0.5rem;
  vertical-align: top;
}

.asset-usage-table tbody tr + tr td {
  border-top: 1px solid rgba(255, 255, 255, 0.05);
}

/* Asset preview page */
.asset-preview-header .back {
  display: inline-block;
  margin-bottom: 0.4rem;
  color: var(--accent, #4a9eff);
  text-decoration: none;
  font-size: 0.9rem;
}

.asset-preview-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 1rem;
  margin: 1rem 0;
}

.asset-preview-card {
  border-radius: 12px;
  padding: 1rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  border: 1px solid rgba(255, 255, 255, 0.1);
}

.asset-preview-card-light {
  background: #f4f1ec;
  color: #222;
}

.asset-preview-card-dark {
  background: #0d1424;
  color: #eee;
}

.asset-preview-label {
  font-size: 0.75rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  opacity: 0.7;
}

.asset-preview-host {
  width: 280px;
  height: 280px;
  max-width: 80vw;
  display: flex;
  align-items: center;
  justify-content: center;
}

.asset-preview-host > svg {
  max-width: 100%;
  max-height: 100%;
}

.asset-preview-meta {
  margin-top: 1.5rem;
}

.asset-preview-meta h2 {
  font-size: 1.05rem;
  margin: 0 0 0.5rem;
}

.asset-preview-meta-list {
  margin: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 0.4rem 1rem;
}

.asset-preview-meta-list .meta-row {
  display: flex;
  gap: 0.5rem;
  align-items: baseline;
  border-bottom: 1px dashed rgba(255, 255, 255, 0.08);
  padding-bottom: 0.25rem;
}

.asset-preview-meta-list dt {
  color: var(--muted, #a8b0c0);
  font-size: 0.8rem;
  min-width: 6rem;
}

.asset-preview-meta-list dd {
  margin: 0;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 0.85rem;
}

/* =============================================================================
   REDUCED MOTION — respects OS-level "reduce motion" preference (WCAG 2.1)
   ============================================================================= */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01s !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01s !important;
    scroll-behavior: auto !important;
  }
}

/* ─── Admin asset index — pool catalog view (20260502a) ──────────────── */

.asset-tier-section {
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.02);
  overflow: hidden;
  margin-bottom: 0.5rem;
}
.asset-tier-section[open] { background: rgba(255, 255, 255, 0.04); }
.asset-tier-summary {
  cursor: pointer;
  padding: 0.7rem 0.9rem;
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  list-style: none;
}
.asset-tier-summary::-webkit-details-marker { display: none; }
.asset-tier-summary::before {
  content: "▶";
  font-size: 0.7em;
  color: var(--accent, #4a9eff);
  transition: transform 0.15s ease;
  display: inline-block;
}
.asset-tier-section[open] > .asset-tier-summary::before { transform: rotate(90deg); }
.asset-tier-label { font-weight: 700; font-size: 1rem; }
.asset-tier-count { font-size: 0.82rem; color: var(--muted); }
.asset-tier-legendary .asset-tier-label { color: #ffb300; }
.asset-tier-rare      .asset-tier-label { color: #2196f3; }
.asset-tier-uncommon  .asset-tier-label { color: #4caf50; }
.asset-tier-common    .asset-tier-label { color: var(--muted); }

.asset-pool-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 0.75rem;
  padding: 0.25rem 0.9rem 0.9rem;
}

.asset-type-badge {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 0.15rem 0.4rem;
  border-radius: 4px;
  font-weight: 600;
}
.asset-type-animal   { background: rgba(76, 175, 80, 0.15); color: #81c784; }
.asset-type-mythical { background: rgba(255, 193, 7, 0.15); color: #ffb300; }

.asset-style-badge {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 0.15rem 0.4rem;
  border-radius: 4px;
  font-weight: 600;
}
.asset-style-kawaii       { background: rgba(255, 182, 193, 0.18); color: #f7a8b8; }
.asset-style-chibi-fierce { background: rgba(244, 81, 30, 0.18);  color: #ff8a65; }
.asset-style-heraldic     { background: rgba(255, 215, 0, 0.18);  color: #ffd54f; }
.asset-style-mythic-grand { background: rgba(186, 104, 200, 0.18); color: #ce93d8; }
.asset-style-cosmic       { background: rgba(100, 181, 246, 0.18); color: #90caf9; }
.asset-style-cryptid      { background: rgba(141, 110, 99, 0.18); color: #bcaaa4; }

.asset-backup-emoji {
  font-size: 1em;
  margin-right: 0.15rem;
  filter: saturate(1.05);
}

.asset-filter-pills { display: flex; gap: 0.4rem; }
.asset-filter-pill {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 0.35rem 0.85rem;
  font-size: 0.85rem;
  font-weight: 500;
  cursor: pointer;
  color: var(--fg);
  transition: all 0.15s ease;
}
.asset-filter-pill:hover { border-color: #9c27b0; }
.asset-filter-pill.active {
  background: rgba(156, 39, 176, 0.15);
  border-color: #9c27b0;
  color: #ce93d8;
  font-weight: 600;
}

.scene-assets-section {
  margin-top: 2.5rem;
  border-top: 1px solid var(--border, rgba(255, 255, 255, 0.1));
  padding-top: 1.25rem;
}
.scene-assets-section h2 {
  font-size: 0.85rem;
  font-weight: 700;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.07em;
  margin: 0 0 0.75rem;
}
.scene-assets-row {
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  padding: 0.35rem 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}
.scene-assets-row:last-child { border-bottom: none; }

/* ── Curiositters landing section ──────────────────────────────────────────── */
.landing-curiositters { margin: 2.5rem 0; }

.landing-curiositters-chest {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

.landing-chest-slot {
  width: 140px;
  height: 140px;
  margin: 0 auto 0.75rem;
  flex-shrink: 0;
}

.landing-curiositter-reel {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
  margin-top: 0.5rem;
}

.landing-curiositter-slot {
  width: 160px;
  height: 160px;
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #ecedf3 78%);
  border-radius: 50%;
  box-shadow: inset 0 -3px 8px rgba(0,0,0,.06), 0 1px 3px rgba(0,0,0,.08);
  overflow: hidden;
  position: relative;
}

.landing-curiositter-fallback {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 2.5rem;
  pointer-events: none;
}

.landing-curiositter-dots {
  display: flex;
  gap: 0.4rem;
}

.landing-curiositter-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--color-muted, #bbb);
  transition: background 0.3s;
}

.landing-curiositter-dot.is-active {
  background: var(--color-accent, #7c3aed);
}

@media (min-width: 720px) {
  .landing-curiositters-chest { text-align: left; align-items: flex-start; }
}

/* ── Admin Hunts Console ─────────────────────────────────────────────── */
.admin-hunts-main { padding: 1rem 1.25rem 3rem; max-width: 1200px; margin: 0 auto; }
.admin-hunts-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  align-items: end;
  justify-content: space-between;
  padding: 0.75rem 0 1rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  margin-bottom: 1rem;
}
.admin-hunts-filters { display: flex; flex-wrap: wrap; gap: 0.75rem; }
.admin-hunts-filters label { display: flex; flex-direction: column; font-size: 0.8rem; gap: 0.25rem; }
.admin-hunts-filters select,
.admin-hunts-filters input[type="search"] {
  min-width: 9rem;
  min-height: 2.75rem;
  padding: 0.4rem 0.55rem;
  border-radius: 6px;
  border: 1px solid rgba(255, 255, 255, 0.18);
  background: rgba(255, 255, 255, 0.04);
  color: inherit;
  font-size: 0.9rem;
}
.admin-hunts-toggles { display: flex; flex-wrap: wrap; gap: 0.75rem; align-items: center; font-size: 0.85rem; }
.admin-hunts-toggles label { display: inline-flex; gap: 0.35rem; align-items: center; }

.admin-hunts-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9rem;
}
.admin-hunts-table th,
.admin-hunts-table td {
  text-align: left;
  padding: 0.55rem 0.6rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  vertical-align: top;
}
.admin-hunts-table th {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-muted, #999);
  font-weight: 600;
}
.admin-hunts-table tbody tr { cursor: pointer; }
.admin-hunts-table tbody tr:hover { background: rgba(255, 255, 255, 0.04); }
.admin-hunts-table a { color: #4fc3f7; text-decoration: none; font-weight: 600; }
.admin-hunts-table a:hover { text-decoration: underline; }
.admin-hunts-table code { font-size: 0.8rem; color: #a0a0a0; }

.hunt-tag-chip,
.hunt-flag {
  display: inline-block;
  padding: 0.1rem 0.45rem;
  border-radius: 999px;
  font-size: 0.7rem;
  margin-right: 0.25rem;
  font-weight: 600;
  white-space: nowrap;
}
.hunt-tag-chip { background: rgba(124, 58, 237, 0.18); color: #c4b5fd; }
.hunt-flag { letter-spacing: 0.04em; }
.flag-test { background: rgba(255, 159, 67, 0.2); color: #ffb86c; }
.flag-hidden { background: rgba(150, 150, 150, 0.2); color: #cfcfcf; }
.flag-featured { background: rgba(255, 213, 0, 0.18); color: #ffe066; }
.flag-anytown { background: rgba(79, 195, 247, 0.18); color: #4fc3f7; }
.flag-free { background: rgba(72, 187, 120, 0.2); color: #6ee7a3; }

@media (max-width: 600px) {
  .admin-hunts-main { padding: 0.75rem 0.75rem 2rem; }
  .admin-hunts-filters { width: 100%; }
  .admin-hunts-filters label { flex: 1 1 calc(50% - 0.4rem); min-width: 0; }
  .admin-hunts-filters select,
  .admin-hunts-filters input[type="search"] { min-width: 0; width: 100%; }
  .admin-hunts-toggles { width: 100%; }
  /* Hide Slug (col 2) and Tags (col 6) at narrow widths. Title still
     links through to /admin-hunt.html?slug=…, so the slug column isn't
     load-bearing for navigation. */
  .admin-hunts-table th:nth-child(2),
  .admin-hunts-table td:nth-child(2),
  .admin-hunts-table th:nth-child(6),
  .admin-hunts-table td:nth-child(6) { display: none; }
  .admin-hunts-table { font-size: 0.82rem; }
  .admin-hunts-table th,
  .admin-hunts-table td { padding: 0.45rem 0.4rem; }
}

/* ── Admin Hunt detail page ──────────────────────────────────────────── */
.admin-hunt-detail-main { padding: 1rem 1.25rem 3rem; max-width: 760px; margin: 0 auto; }
.admin-hunt-form { display: flex; flex-direction: column; gap: 1.25rem; }
.admin-section {
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 8px;
  padding: 0.75rem 1rem 1rem;
  background: rgba(255, 255, 255, 0.02);
}
.admin-section legend {
  padding: 0 0.4rem;
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-muted, #aaa);
}
.admin-section label {
  display: block;
  margin-top: 0.6rem;
  font-size: 0.85rem;
}
.admin-section input[type="text"],
.admin-section input[type="number"],
.admin-section input[type="search"],
.admin-section input:not([type]),
.admin-section textarea,
.admin-section select {
  width: 100%;
  padding: 0.45rem 0.6rem;
  border-radius: 6px;
  border: 1px solid rgba(255, 255, 255, 0.18);
  background: rgba(255, 255, 255, 0.04);
  color: inherit;
  font: inherit;
  margin-top: 0.2rem;
}
.admin-section input[readonly] { opacity: 0.65; cursor: not-allowed; }
.admin-section .checkbox-label {
  display: flex;
  align-items: flex-start;
  gap: 0.55rem;
  margin-top: 0.5rem;
}
.admin-section .checkbox-label input[type="checkbox"] {
  margin-top: 0.2rem;
}

.admin-section.read-only { background: rgba(255, 255, 255, 0.01); }
.readonly-grid {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 0.25rem 0.75rem;
  font-size: 0.85rem;
  margin: 0.5rem 0 0.75rem;
}
.readonly-grid dt { color: var(--color-muted, #999); }
.readonly-grid dd { margin: 0; }

.tag-input-wrap {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem;
  padding: 0.45rem 0.55rem;
  border-radius: 6px;
  border: 1px solid rgba(255, 255, 255, 0.18);
  background: rgba(255, 255, 255, 0.04);
  margin-top: 0.4rem;
}
.tag-chips { display: flex; flex-wrap: wrap; gap: 0.3rem; }
.tag-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.15rem 0.5rem;
  border-radius: 999px;
  background: rgba(124, 58, 237, 0.25);
  color: #ddd6fe;
  font-size: 0.78rem;
  font-weight: 600;
}
.tag-chip-x {
  background: none;
  border: none;
  color: inherit;
  cursor: pointer;
  font-size: 1rem;
  padding: 0;
  line-height: 1;
}
#tag-input {
  flex: 1;
  min-width: 8rem;
  border: none;
  background: transparent;
  color: inherit;
  font: inherit;
  outline: none;
  padding: 0.15rem 0;
}

/* =========================================================================
   Admin Console — desktop-first
   =========================================================================

   The user-facing AR scavenger-hunt pages are mobile-first (max content
   width 520–720px, touch tap targets, narrow column). Admin pages are
   operations tooling — they're consumed on a laptop, not in the field —
   so they get a wider content column, multi-column grids, and a denser
   layout.

   The contract is opt-in via the `body.admin` marker class on every
   admin HTML page. User pages MUST NOT set this class. See
   "Admin vs. user pages" in CLAUDE.md for the full list of admin pages.

   All overrides are gated behind @media (min-width: 1024px) so that
   admins triaging from a phone still get the existing mobile fallback
   behavior — they just don't get the wide-screen treatment.
   ========================================================================= */

/* Admin Console dashboard grid — mobile fallback (single column).
   `body.admin .admin-console-grid` is the entry point at /admin-console.html;
   each card is a big tap target that links to one admin tool. */
.admin-console-intro {
  margin: 0 0 1.25rem;
  font-size: 0.92rem;
}
.admin-console-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.75rem;
}
.admin-console-card {
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-rows: auto auto;
  grid-template-areas:
    "icon title"
    "icon desc";
  column-gap: 0.9rem;
  row-gap: 0.2rem;
  padding: 1.1rem 1.25rem;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  color: var(--fg);
  text-decoration: none;
  transition: border-color 120ms, transform 120ms, background 120ms;
}
.admin-console-card:hover {
  border-color: var(--accent-2);
  background: rgba(79, 195, 247, 0.06);
  transform: translateY(-1px);
}
.admin-console-card-icon {
  grid-area: icon;
  font-size: 2rem;
  line-height: 1;
  align-self: center;
}
.admin-console-card-title {
  grid-area: title;
  font-weight: 700;
  font-size: 1.05rem;
  color: var(--fg);
}
.admin-console-card-desc {
  grid-area: desc;
  color: var(--muted);
  font-size: 0.86rem;
  line-height: 1.4;
}

.admin-vendors-main {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
.vendor-summary-grid,
.social-summary-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.75rem;
}
.vendor-summary-item,
.social-summary-item {
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--card);
  padding: 0.85rem 1rem;
}
.vendor-summary-item span,
.social-summary-item span {
  display: block;
  color: var(--muted);
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.vendor-summary-item strong,
.social-summary-item strong {
  display: block;
  margin-top: 0.3rem;
  font-size: 1.65rem;
}
.social-summary-item--ok {
  border-color: rgba(123, 211, 137, 0.35);
  background: rgba(123, 211, 137, 0.08);
}
.social-summary-item--warn {
  border-color: rgba(240, 196, 87, 0.38);
  background: rgba(240, 196, 87, 0.09);
}
.social-summary-item--bad {
  border-color: rgba(255, 112, 112, 0.38);
  background: rgba(255, 112, 112, 0.08);
}
.vendor-toolbar,
.social-toolbar {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.75rem;
  align-items: flex-end;
}
.vendor-toolbar h2,
.social-toolbar h2 {
  margin: 0 0 0.25rem;
  font-size: 1.25rem;
}
.vendor-toolbar p,
.social-toolbar p {
  margin: 0;
}
.admin-social-main {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
.social-toolbar-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}
.social-section-header {
  display: flex;
  justify-content: space-between;
  gap: 0.75rem;
  align-items: flex-start;
  margin-bottom: 0.75rem;
}
.social-section-header h3 {
  margin: 0 0 0.25rem;
  font-size: 1.05rem;
}
.social-section-header p {
  margin: 0;
}
.social-oauth-grid {
  display: grid;
  gap: 0.55rem;
}
.social-oauth-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.35rem;
  padding: 0.75rem;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.03);
}
.social-oauth-row > span {
  color: var(--muted);
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.social-oauth-row strong {
  min-width: 0;
  overflow-wrap: anywhere;
  font-size: 0.92rem;
}
.social-oauth-action {
  width: fit-content;
  min-height: 2.35rem;
}
.social-readiness-section,
.social-workspace-section,
.social-account-list,
.social-post-list {
  display: grid;
  gap: 1rem;
}
.social-readiness-note {
  border-radius: 8px;
  padding: 0.8rem 1rem;
  font-size: 0.9rem;
  line-height: 1.45;
}
.social-readiness-note ul,
.social-account-blockers ul {
  margin: 0.45rem 0 0;
  padding-left: 1.2rem;
}
.social-readiness-note--ok {
  border: 1px solid rgba(123, 211, 137, 0.35);
  background: rgba(123, 211, 137, 0.08);
}
.social-readiness-note--blocked,
.social-account-blockers {
  border: 1px solid rgba(255, 112, 112, 0.34);
  background: rgba(255, 112, 112, 0.08);
}
.social-account-card {
  display: grid;
  gap: 0.85rem;
}
.social-account-header {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.75rem;
  align-items: flex-start;
}
.social-account-header h3 {
  margin: 0 0 0.25rem;
  font-size: 1.05rem;
}
.social-account-header p {
  margin: 0;
}
.social-chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem;
  align-items: center;
}
.social-chip {
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 999px;
  padding: 0.28rem 0.6rem;
  min-height: 1.9rem;
  display: inline-flex;
  align-items: center;
  color: var(--fg);
  background: rgba(255, 255, 255, 0.045);
  font-size: 0.82rem;
  text-decoration: none;
}
.social-chip--ok {
  border-color: rgba(123, 211, 137, 0.35);
  background: rgba(123, 211, 137, 0.11);
}
.social-chip--warn {
  border-color: rgba(240, 196, 87, 0.4);
  background: rgba(240, 196, 87, 0.12);
}
.social-chip--bad {
  border-color: rgba(255, 112, 112, 0.38);
  background: rgba(255, 112, 112, 0.1);
}
.social-account-meta {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.6rem;
  margin: 0;
}
.social-account-meta div {
  min-width: 0;
}
.social-account-meta dt,
.social-capabilities > span,
.social-validation > span {
  color: var(--muted);
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.social-account-meta dd {
  margin: 0.25rem 0 0;
  overflow-wrap: anywhere;
}
.social-account-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 0.75rem;
}
.social-capabilities {
  display: grid;
  gap: 0.45rem;
}
.social-validation,
.social-account-blockers {
  border-radius: 8px;
  padding: 0.75rem;
}
.social-validation {
  border: 1px solid rgba(255, 255, 255, 0.1);
  background: rgba(255, 255, 255, 0.03);
}
.social-validation--ok {
  border-color: rgba(123, 211, 137, 0.35);
}
.social-validation--warn {
  border-color: rgba(240, 196, 87, 0.4);
}
.social-validation--bad {
  border-color: rgba(255, 112, 112, 0.38);
}
.social-validation strong {
  display: block;
  margin-top: 0.25rem;
}
.social-validation p {
  margin: 0.35rem 0 0;
  color: var(--muted);
  font-size: 0.88rem;
  overflow-wrap: anywhere;
}
.social-validation-checks {
  display: grid;
  gap: 0.45rem;
  margin: 0.65rem 0 0;
  padding: 0;
  list-style: none;
}
.social-validation-checks li {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem;
  align-items: center;
  min-width: 0;
}
.social-validation-checks li > strong {
  display: inline;
  margin: 0;
}
.social-validation-checks li > span:not(.social-chip) {
  color: var(--muted);
  font-size: 0.84rem;
  overflow-wrap: anywhere;
}
.social-composer {
  display: grid;
  gap: 0.85rem;
}
.social-composer-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.75rem;
}
.social-composer textarea[name="caption"] {
  min-height: 7rem;
}
.social-field-label {
  display: block;
  color: var(--muted);
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-bottom: 0.45rem;
}
.social-target-grid {
  display: grid;
  gap: 0.55rem;
}
.social-target-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 0.55rem 0.7rem;
  align-items: center;
  margin: 0;
  padding: 0.7rem;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.03);
}
.social-target-row input[type="checkbox"] {
  margin: 0;
}
.social-target-row span {
  min-width: 0;
}
.social-target-row strong,
.social-target-row small {
  display: block;
}
.social-target-row small,
.social-target-empty {
  color: var(--muted);
}
.social-target-row select {
  grid-column: 2;
  width: 100%;
}
.social-target-row--disabled {
  opacity: 0.55;
}
.social-composer-actions,
.social-post-actions {
  align-items: center;
}
.social-post-card {
  display: grid;
  gap: 0.85rem;
}
.social-post-header {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.75rem;
  align-items: flex-start;
}
.social-post-header h3 {
  margin: 0 0 0.25rem;
  font-size: 1.05rem;
}
.social-post-header p,
.social-post-caption {
  margin: 0;
}
.social-post-caption {
  line-height: 1.45;
}
.social-post-meta {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.6rem;
  margin: 0;
}
.social-post-meta dt {
  color: var(--muted);
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.social-post-meta dd {
  margin: 0.25rem 0 0;
  overflow-wrap: anywhere;
}
.social-post-targets {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem;
}
.social-plan,
.social-preflight {
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.03);
  padding: 0.65rem 0.75rem;
}
.social-plan summary,
.social-preflight summary {
  cursor: pointer;
  font-weight: 700;
}
.social-plan pre {
  margin: 0.6rem 0 0;
  max-height: 20rem;
  overflow: auto;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  font-size: 0.78rem;
}
.social-preflight-checks {
  display: grid;
  gap: 0.45rem;
  margin: 0.65rem 0 0;
  padding: 0;
  list-style: none;
}
.social-preflight-checks li {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem;
  align-items: center;
  min-width: 0;
}
.social-preflight-checks strong {
  min-width: 8.5rem;
}
.social-preflight-checks span:not(.social-chip) {
  color: var(--muted);
  font-size: 0.84rem;
  overflow-wrap: anywhere;
}
.vendor-list {
  display: grid;
  gap: 1rem;
}
.vendor-card {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
  border-radius: 8px;
}
.vendor-card-header {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.75rem;
  align-items: flex-start;
}
.vendor-card-header h3 {
  margin: 0 0 0.25rem;
  font-size: 1.05rem;
}
.vendor-card-header p {
  margin: 0;
}
.vendor-badge-row,
.vendor-link-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem;
  align-items: center;
}
.vendor-badge,
.vendor-link-row > * {
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 999px;
  padding: 0.28rem 0.6rem;
  min-height: 1.9rem;
  display: inline-flex;
  align-items: center;
  color: var(--fg);
  background: rgba(255, 255, 255, 0.045);
  font-size: 0.82rem;
  text-decoration: none;
}
.vendor-badge-status {
  border-color: rgba(123, 211, 137, 0.35);
  background: rgba(123, 211, 137, 0.11);
}
.vendor-badge-sync {
  border-color: rgba(240, 166, 87, 0.42);
  background: rgba(240, 166, 87, 0.12);
}
.vendor-form-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.75rem;
}
.vendor-card label {
  margin-top: 0;
}
.vendor-card textarea {
  min-height: 4.5rem;
}
.vendor-sync-message {
  border-left: 3px solid var(--accent-2);
  padding: 0.55rem 0.75rem;
  background: rgba(79, 195, 247, 0.06);
  color: var(--muted);
  font-size: 0.88rem;
  line-height: 1.4;
}
.vendor-actions {
  align-items: center;
}
.vendor-sync-meta {
  color: var(--muted);
  font-size: 0.86rem;
}

@media (min-width: 1024px) {
  /* Wider page column on every admin page. Overrides the mobile-first
     .page-main { max-width: 720px } default at the top of this file. */
  body.admin .page-main {
    max-width: 1280px;
    padding: 1.5rem 2rem;
  }

  /* Hunt-editor / Anytown two-pane layout: wider sidebar + right panel,
     and let the main column reach its 1280px ceiling instead of stopping
     at the legacy 1100px. */
  body.admin .admin-layout {
    max-width: none;
    grid-template-columns: 320px 1fr;
    gap: 2rem;
  }

  /* Forms inside admin pages still cap at 720px so inputs don't stretch
     across the full 1280px page — long inputs are unreadable. */
  body.admin .admin-form {
    max-width: 720px;
  }

  /* Per-page main containers that previously set their own max-width
     should inherit from .page-main instead. */
  body.admin .admin-quotes-main,
  body.admin .admin-hunts-main,
  body.admin .admin-hunt-detail-main,
  body.admin .marketing-container {
    max-width: none;
  }

  /* Admin-console card grid expands to three columns. The 1280px page
     column at this breakpoint divides cleanly into three cards with
     comfortable gaps. */
  body.admin .admin-console-grid {
    grid-template-columns: repeat(3, 1fr);
    gap: 1.5rem;
  }
  body.admin .admin-console-card {
    /* Stacked layout (icon on top, then title, then desc) reads more
       naturally in a 3-column grid where each card is taller than wide. */
    grid-template-columns: 1fr;
    grid-template-rows: auto auto auto;
    grid-template-areas:
      "icon"
      "title"
      "desc";
    padding: 1.5rem 1.4rem;
    min-height: 180px;
    row-gap: 0.5rem;
  }
  body.admin .admin-console-card-icon {
    font-size: 2.4rem;
  }
  body.admin .admin-console-card-title {
    font-size: 1.1rem;
  }

  body.admin .vendor-summary-grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
  body.admin .social-summary-grid {
    grid-template-columns: repeat(6, minmax(0, 1fr));
  }
  body.admin .social-oauth-row {
    grid-template-columns: minmax(180px, 0.7fr) minmax(0, 2fr) auto auto;
    align-items: center;
  }
  body.admin .social-account-meta {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
  body.admin .social-composer-grid {
    grid-template-columns: 1fr 1fr;
  }
  body.admin .social-target-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
  body.admin .social-post-meta {
    grid-template-columns: 2fr 0.5fr 1fr;
  }
  body.admin .vendor-form-grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  /* Tracker page shipped with an inline `style="max-width:960px"` on its
     <main>; the inline style wins by specificity. The Tracker is denser
     than other admin pages but should still get a roomier column on a
     laptop — bump it via `body.admin` so the inline 960px is overridden. */
  body.admin main.page-main[style*="max-width:960px"] {
    max-width: 1280px !important;
  }

  /* Marketing-plan page has its own .marketing-container with an inline
     2rem auto margin; the rule above already lifts max-width, this one
     just normalizes the side padding so it lines up with .page-main. */
  body.admin .marketing-container {
    margin: 1.5rem auto;
    padding: 0 2rem;
  }
}

/* ---------- Shared "elegant page" aesthetic ----------
   Originally inlined into pricing.html. Promoted here so custom-hunts
   and profile (and any future page) can adopt the same hero + card
   pattern without duplicating CSS. */
.page-hero {
  text-align: center;
  padding: 2rem 0 1rem;
}
.page-hero h1,
.page-hero h2 {
  margin: 0 0 0.5rem;
}
.page-hero p {
  color: var(--muted);
  max-width: 560px;
  margin: 0 auto 1.5rem;
}
.page-hero-art {
  display: block;
  width: min(360px, 80vw);
  height: auto;
  margin: 0 auto 0.5rem;
  pointer-events: none;
}

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 1rem;
  margin: 1.25rem 0;
}
.card-grid--single {
  grid-template-columns: 1fr;
  max-width: 640px;
  margin-inline: auto;
}

.section-card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 1.25rem 1.1rem;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}
.section-card[hidden] { display: none !important; }
.section-card--featured {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent);
}
.section-card-label {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0;
}
.section-card-label--featured { color: var(--accent); }
.section-card-title {
  font-size: 1.2rem;
  font-weight: 700;
  color: var(--fg);
  margin: 0;
}

.curiositter-accent-img {
  display: block;
  width: 100%;
  height: auto;
  max-width: 820px;
  aspect-ratio: 820 / 312;
  object-fit: cover;
  border: 1px solid rgba(79, 195, 247, 0.18);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.035);
  box-shadow: 0 14px 28px rgba(0, 0, 0, 0.18);
}
.section-card .curiositter-accent-img {
  margin: 0.1rem 0 0.25rem;
}
.curiositter-accent-img--standalone {
  margin: 1rem auto 1.35rem;
}
.curiositter-accent-img--social-preview {
  aspect-ratio: 820 / 450;
}

/* Collapsible FAQ rows when stacked inside a .section-card (about page). */
.section-card details {
  border-top: 1px solid var(--border);
  padding: 0.6rem 0;
}
.section-card details:first-of-type { border-top: 0; padding-top: 0; }
.section-card details summary {
  cursor: pointer;
  padding: 0.25rem 0;
  list-style: revert;
}
.section-card details[open] summary { margin-bottom: 0.4rem; }
.section-card details p { margin: 0.4rem 0 0.2rem; }

/* Difficulty explainer on the home page. */
.landing-difficulty {
  margin: 2.5rem 0;
  scroll-margin-top: 5rem;
}
.landing-difficulty h2 {
  margin: 0 0 0.25rem;
  font-size: 1.2rem;
}
.difficulty-level-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.85rem;
}
.difficulty-level-card {
  display: block;
  background: linear-gradient(180deg, rgba(255,255,255,0.055), rgba(255,255,255,0.025)), var(--card);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 1rem;
  color: var(--fg);
  text-decoration: none;
}
.difficulty-level-card:hover,
.difficulty-level-card:focus-visible {
  border-color: rgba(79, 195, 247, 0.45);
  box-shadow: 0 12px 28px rgba(0, 0, 0, 0.22);
  outline: none;
}
.difficulty-level-card h3 {
  margin: 0.65rem 0 0.3rem;
  font-size: 1rem;
}
.difficulty-level-card p {
  margin: 0;
  color: var(--muted);
  font-size: 0.9rem;
  line-height: 1.45;
}
@media (min-width: 760px) {
  .difficulty-level-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* SVG asset repository inventory */
.svg-assets-page {
  max-width: 1180px;
  margin: 0 auto;
  padding: 1.5rem 1rem 4rem;
}

.svg-assets-summary {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin: 1rem 0 0;
}

.svg-assets-summary span {
  padding: 0.45rem 0.65rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.04);
  color: var(--muted);
  font-size: 0.85rem;
}

.svg-assets-summary strong {
  color: var(--fg);
}

.svg-assets-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
  gap: 1rem;
  margin-top: 1rem;
}

.svg-asset-card {
  display: grid;
  grid-template-rows: 12rem 1fr;
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--card);
}

.svg-asset-unused {
  border-style: dashed;
  opacity: 0.84;
}

.svg-asset-preview {
  display: grid;
  place-items: center;
  min-height: 12rem;
  padding: 1rem;
  background:
    linear-gradient(45deg, rgba(255, 255, 255, 0.04) 25%, transparent 25%),
    linear-gradient(-45deg, rgba(255, 255, 255, 0.04) 25%, transparent 25%),
    linear-gradient(45deg, transparent 75%, rgba(255, 255, 255, 0.04) 75%),
    linear-gradient(-45deg, transparent 75%, rgba(255, 255, 255, 0.04) 75%);
  background-color: rgba(255, 255, 255, 0.02);
  background-position: 0 0, 0 0.5rem, 0.5rem -0.5rem, -0.5rem 0;
  background-size: 1rem 1rem;
}

.svg-asset-preview img {
  max-width: 100%;
  max-height: 10rem;
  object-fit: contain;
}

.svg-assets-no-preview {
  color: var(--muted);
  font-size: 0.85rem;
}

.svg-asset-body {
  padding: 0.85rem 0.95rem 1rem;
}

.svg-asset-card-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.75rem;
}

.svg-asset-card h2 {
  margin: 0;
  font-size: 1rem;
  overflow-wrap: anywhere;
}

.svg-asset-usage-pill {
  flex: 0 0 auto;
  border: 1px solid rgba(79, 195, 247, 0.3);
  border-radius: 999px;
  padding: 0.18rem 0.45rem;
  color: var(--accent-2);
  font-size: 0.72rem;
  white-space: nowrap;
}

.svg-asset-unused .svg-asset-usage-pill {
  border-color: rgba(255, 255, 255, 0.16);
  color: var(--muted);
}

.svg-asset-path {
  margin: 0.45rem 0;
  color: var(--muted);
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 0.78rem;
  overflow-wrap: anywhere;
}

.svg-asset-card h3 {
  margin: 0.7rem 0 0.3rem;
  color: var(--muted);
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.svg-asset-refs {
  margin: 0;
  padding-left: 1.1rem;
  color: var(--muted);
  font-size: 0.84rem;
}

.svg-asset-refs li + li {
  margin-top: 0.2rem;
}

.svg-asset-refs a {
  color: var(--accent, #4a9eff);
  text-decoration: none;
}

.svg-asset-refs a:hover,
.svg-asset-refs a:focus {
  text-decoration: underline;
}

.svg-asset-unused-note {
  margin: 0;
  color: var(--muted);
  font-size: 0.84rem;
}
