body {
  padding-bottom: 5rem; /* space for debug overlay */
}
#question {
  margin-top: 2rem;
}
.gps-dot {
  display: inline-block;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  margin: 0 6px;
  vertical-align: middle;
}
#debug-overlay {
  bottom: calc(70px + env(safe-area-inset-bottom)) !important;
}
.status-box {
  width: 100%;
  /* #status is itself a flex item of .top-header (logo | status-box). A
     flex item's automatic minimum width is based on its content's
     min-content size — and with .gps-street-text forced to white-space:
     nowrap for the ellipsis to work, that min-content size is the FULL
     untruncated text width, not the truncated one. Without overriding
     that default, the whole status box refuses to shrink below the
     complete street name and overflows the header instead of clipping
     it — this min-width: 0 is what actually lets the ellipsis take
     effect rather than just being dead CSS. */
  min-width: 0;
}
.status-text-block {
  flex: 1;
  min-width: 0;
  text-align: right;
  line-height: 1.2;
}
.gps-street-text {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 100%;
}
.acc-width {
  display: inline-block;
  min-width: 40px;
  text-align: right;
}
#hunt-card {
  overflow: hidden;
}
/* .app-container's shared padding/rounded-top (from pwa-style.css) is
   needed on other pages, but here we want the score strip to sit
   flush against the header — same width, square top corners, no gap —
   so it reads as one continuous surface rather than a separate card.
   max-width keeps it from stretching too wide/thin-looking on desktop. */
.app-container {
  padding: 0;
  border-radius: 0 0 1rem 1rem;
  overflow: hidden;
  border: none;
  max-width: 480px;
  margin: 0 auto;
}
/* While #hunt-screen has no content (e.g. waiting behind the "Hunt complete!"
   popup, or before it first fills) the card is very short and would clip the
   team photo that overhangs the score strip. Purely CSS, so it applies from
   the very first paint with no timing gap (a JS class caused a flicker). */
.app-container:has(#hunt-screen:empty),
#hunt-card:has(#hunt-screen:empty) {
  overflow: visible;
}
#hunt-screen {
  background: #fffdfb;
  padding: 20px;
  text-align: left;
}
#score-strip {
  position: relative;
  z-index: 1; /* isolates its own stacking context so the overlapping
                 photo/placeholder below always paints above whatever
                 #hunt-screen renders next, regardless of DOM order */
  text-align: center;
  background: #fbeee0;
  padding: 14px 20px 58px; /* extra bottom room so the photo can overlap below */
}
#team-name-display {
  font-size: 25px;
  font-weight: 700;
  color: #1c2b4a;
}
#score-value {
  font-size: 20px;
  color: #a5825a;
}
.team-avatar {
  position: absolute;
  left: 50%;
  bottom: -50px;
  transform: translateX(-50%);
  width: 100px;
  height: 100px;
  border-radius: 50%;
  object-fit: cover;
  border: 3px solid #e07b39;
  box-shadow: 0 3px 10px rgba(28,43,74,0.2);
  display: none;
  z-index: 5;
}
#team-photo-placeholder-wrap {
  position: absolute;
  left: 50%;
  bottom: -70px;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  z-index: 5; /* above #score-strip's own z-index:1 stacking context AND
                 the progress-trigger-btn below, so the placeholder
                 circle always renders whole rather than partly hidden */
}
.team-avatar-placeholder {
  width: 100px;
  height: 100px;
  border-radius: 50%;
  border: 2px dashed #d8b48a;
  background: #fbeee0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #e07b39;
  font-size: 22px;
  text-decoration: none;
  box-shadow: 0 3px 10px rgba(28,43,74,0.15);
}
.team-avatar-placeholder-label {
  font-size: 11px;
  font-weight: 500;
  margin-top: 4px;
  color: #a5825a;
}
/* Fade only — no vertical movement. This used to slide the content up 8px as
   it faded in, and since every phase screen re-renders on returning to the
   page (and when a popup/completion screen appears), everything under the
   score strip visibly jumped upward each time. */
@keyframes huntFadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}
.hunt-fade-in {
  /* 0.6s with a gentle ease at both ends, starting 0.1s late so the screen has
     finished building (map/images starting to load) before the fade begins;
     "both" keeps it invisible during that short delay rather than flashing. */
  animation: huntFadeIn 0.6s ease-in-out 0.1s both;
}
.phase-label {
  font-size: 15px;
  letter-spacing: 1px;
  text-transform: uppercase;
  font-weight: 500;
  display: flex;
  align-items: center;
  gap: 6px;
}
.phase-label--travel { color: #e07b39; }
.phase-label--arrived { color: #1d9e75; }
.phase-divider {
  border: none;
  height: 1px;
  background: linear-gradient(90deg, #e8d9c8, transparent);
  margin: 12px 0 16px;
}
.point-title {
  font-family: 'Playfair Display', serif;
  font-size: 28px;
  font-weight: 700;
  color: #1c2b4a;
  margin: 8px 0 14px;
}
.task-countdown-label {
  display: block;
  text-align: center;
  font-size: 11px;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: #a08a76;
  margin: 20px 0 6px;
}
.task-countdown {
  display: block;
  width: fit-content;
  margin: 0 auto 12px;
  font-size: 18px;
  font-weight: 700;
  color: #1c2b4a;
  background: #fbeee0;
  border-radius: 20px;
  padding: 4px 16px;
  /* Montserrat's digits aren't fixed-width by default, so even though
     the text content is always the same length ("⏱ 0:29" down to
     "⏱ 0:00"), a narrow digit like "1" measures less than a wide one
     like "8" — the pill's own width (driven by its text content, via
     display:inline-block) subtly resized every single second, most
     noticeably during the last-30s "urgent" flash. tabular-nums forces
     every digit to the same advance width; min-width + centering is a
     belt-and-braces fallback for the rare font/browser combo that
     ignores tabular-nums. */
  font-variant-numeric: tabular-nums;
  min-width: 72px;
  text-align: center;
}
.task-countdown--urgent {
  color: #ffffff;
  background: #d92b2b;
  animation: task-countdown-pulse 1s infinite;
}
@keyframes task-countdown-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.6; }
}
.travel-clue-text {
  font-size: 20px;
  line-height: 1.6;
  color: #1c2b4a;
  margin: 20px 0;
}
.travel-map {
  position: fixed;
  bottom: calc(var(--footer-height) + env(safe-area-inset-bottom, 0));
  left: 0;
  right: 0;
  width: 100%;
  height: 150px;
  border-radius: 12px 12px 0 0;
  overflow: hidden;
  box-shadow: 0 -2px 10px rgba(28,43,74,0.18);
  z-index: 900; /* above hunt content, below the bottom nav (1000) */
}
.travel-map-expand-btn {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 901;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: rgba(42,42,42,0.75);
  color: #fff;
  border: none;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 15px;
}
.travel-map-recenter-btn {
  position: absolute;
  top: 8px;
  left: 8px;
  z-index: 901;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: #ffffff;
  color: #e07b39;
  border: none;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  box-shadow: 0 2px 6px rgba(0,0,0,0.3);
}
.map-recenter-large-btn {
  top: 54px;
  right: 10px;
  left: auto;
  z-index: 3001;
}
/* Travel-phase content clearance is now handled by constraining
   #hunt-screen's own max-height in JS (see constrainHuntScreenHeight in
   questions.js), which measures the actual rendered space directly
   rather than a hand-calculated padding number. */
.map-expand-modal {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.7);
  z-index: 3000;
  align-items: center;
  justify-content: center;
  padding: 20px;
}
.map-expand-modal.show {
  display: flex;
}
.map-expand-modal__inner {
  position: relative;
  width: 100%;
  max-width: 480px;
  height: 70vh;
  border-radius: 12px;
  overflow: hidden;
}
.map-expand-close {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 3001;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: rgba(42,42,42,0.75);
  color: #fff;
  border: none;
  font-size: 20px;
  line-height: 1;
}
#travel-map-large {
  width: 100%;
  height: 100%;
}
/* Any image dropped into clue/question/hint/travel text (all rendered
   as raw HTML into #hunt-screen) is auto-constrained to the screen width
   — otherwise a full-size image blows out the narrow phone layout,
   since neither Bootstrap nor style.css size bare <img> tags by default
   (only Bootstrap's img-fluid *class* does, which text authors won't
   remember to add by hand every time). */
#hunt-screen img {
  max-width: 100%;
  height: auto;
}
.task-question-text {
  font-size: 20px;
  font-weight: 500;
  color: #6b6b6b;
  margin: 10px 0 10px;
}
.hero-photo {
  position: relative;
  height: 190px;
  overflow: hidden;
  display: flex;
  align-items: flex-end;
  background-size: cover;
  background-position: center;
  margin: -22px -20px 18px -20px;
  box-shadow: 0 4px 20px rgba(28,43,74,0.15);
}
.hero-photo__overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(0,0,0,0) 40%, rgba(0,0,0,0.75) 100%);
}
.hero-photo__title {
  position: relative;
  padding: 16px 20px;
}
.hero-photo__title .phase-label { color: #5DCAA5; }
.hero-photo__title .point-title { color: #ffffff; margin: 0; }
/* Rule-and-text treatment (replacing the old filled/bordered box):
   a thin colored bar + indented copy, no fill, no border, no corners —
   same system as .clue-fact below. Icon dropped since the colored bar
   plus the "Hint" label already carry it. */
.hint-card {
  display: flex;
  gap: 12px;
  margin-top: 30px;
  padding: 0;
  background: transparent;
  border: none;
  border-radius: 0;
}
.hint-card::before {
  content: '';
  width: 3px;
  flex-shrink: 0;
  background: #e07b39;
  border-radius: 2px;
}
.hint-card__text {
  display: flex;
  font-size: 15px;
  line-height: 1.5;
  color: #1c2b4a;
  padding: 1px 0;
}
/* Label is its own flex item, not inline text ahead of the hint body —
   so a wrapped second line of the hint lines up under the first word
   of the hint itself, not back under "Hint 2:". Fixed width (not just
   flex-shrink: 0) so "Hint:" and "Hint 2:" take up the same space —
   otherwise the body text of each hint starts at a different point
   instead of lining up under each other, one hint to the next. */
.hint-card__label {
  flex-shrink: 0;
  width: 56px;
  margin-right: 6px;
  color: #c05e1f;
  font-weight: 700;
}
.hint-card__body { flex: 1 1 auto; min-width: 0; }
.hint-card strong { color: #c05e1f; font-weight: 700; }
/* Offline pin-reveal notice (see questions.js's renderHintSectionHtml) —
   muted tone + icon distinguish "you paid for this, the real text is
   coming later" from a normal already-revealed hint. */
.hint-card--pin-offline::before { background: #a5825a; }
.hint-card--pin-offline .hint-card__text { color: #6b5c4d; font-size: 15px; }
.hint-card--pin-offline i { color: #a5825a; margin-right: 4px; }
.hint-reveal-btn {
  margin-top: 14px;
  margin-left: auto;
  background: transparent;
  border: 1px solid #d8cfc4;
  color: #1c2b4a;
  border-radius: 8px;
  padding: 10px 14px;
  font-size: 14px;
  display: flex;
  width: fit-content;
  align-items: center;
  gap: 6px;
  transition: box-shadow 0.15s ease, transform 0.1s ease;
}
.hint-reveal-btn:hover {
  box-shadow: 0 2px 8px rgba(28,43,74,0.1);
}
.hint-reveal-btn:active {
  transform: scale(0.98);
}
/* .btn-primary's own color already matches this site's orange (style.css) —
   only adding the hover/press feedback here, not re-declaring the color. */
.mark-complete-btn, #question .btn-primary {
  transition: box-shadow 0.15s ease, transform 0.1s ease;
}
.mark-complete-btn:hover, #question .btn-primary:hover {
  box-shadow: 0 3px 10px rgba(224,123,57,0.35);
}
.mark-complete-btn:active, #question .btn-primary:active {
  transform: scale(0.98);
}
/* Waypoint markers on the travel map — distinct from the orange "you are
   here" dot, since these are optional points of interest, not your
   own live position. */
.waypoint-marker-icon {
  display: block;
  filter: drop-shadow(0 2px 4px rgba(0,0,0,0.3));
}
.waypoint-info-overlay {
  position: absolute;
  left: 12px;
  right: 12px;
  bottom: 12px;
  z-index: 3002;
  max-height: 40%;
  overflow-y: auto;
  margin: 0;
}
.waypoint-info-fixed {
  position: fixed;
  left: 8px;
  right: 8px;
  bottom: calc(var(--footer-height) + env(safe-area-inset-bottom, 0) + 150px);
  z-index: 900;
  border-radius: 0;
  max-height: 35vh;
  overflow-y: auto;
}
.waypoint-info-close {
  float: right;
  background: none;
  border: none;
  font-size: 20px;
  line-height: 1;
  color: #1c2b4a;
  padding: 0 0 0 10px;
}

/* "Did you know?" facts card — distinct navy accent (vs hint-card's
   orange) so facts read as a different kind of content, not another hint. */
.fact-card {
  background: #eef1f7;
  border: 1px solid #dde3ee;
  border-left: 4px solid #1c2b4a;
  border-radius: 10px;
  padding: 14px 16px;
  margin-top: 16px;
  margin-bottom: 16px;
}
.fact-card-text {
  margin: 0 0 4px;
  color: #333;
}
.fact-card-text:last-child {
  margin-bottom: 0;
}
/* Rule-and-text fact, for the task/travel screens (renderFactsHtml) —
   same system as .hint-card: thin navy rule + indented copy, no box.
   .fact-card above stays as it is for the waypoint-info chip, which is
   a real floating panel over the map, not flow content. */
.clue-fact {
  display: flex;
  gap: 12px;
  margin-top: 20px;
}
.clue-fact::before {
  content: '';
  width: 3px;
  flex-shrink: 0;
  background: #1c2b4a;
  border-radius: 2px;
}
.clue-fact__text {
  font-size: 18px;
  color: #5a5a5a;
  line-height: 1.5;
  padding: 1px 0;
}

/* Answer input (question-type task, before answering) — an underline,
   not a boxed input-group, with the submit action built into the line
   itself. */
.clue-answer-row {
  display: flex;
  align-items: center;
  border-bottom: 2px solid #d8cdbf;
  padding-bottom: 10px;
  margin-top: 6px;
}
.clue-answer-input {
  flex: 1 1 auto;
  min-width: 0;
  border: none;
  outline: none;
  padding: 0;
  font-size: 17px;
  font-family: inherit;
  color: #1c2b4a;
  background: transparent;
}
.clue-answer-submit {
  flex: 0 0 auto;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  border: none;
  background: #e07b39;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-left: 10px;
  transition: box-shadow 0.15s ease, transform 0.1s ease;
}
.clue-answer-submit:hover { box-shadow: 0 3px 10px rgba(224,123,57,0.35); }
.clue-answer-submit:active { transform: scale(0.95); }

/* Verdict screen (question-type task, after answering) — one big
   centered moment instead of a small inline alert, since once the fact/
   question/hint are hidden (see answers.js) there's genuinely little
   else on screen; designed for that, not a sparse leftover of the
   input layout. Reused for the timed-out case too (neutral tone). */
.clue-verdict {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 36px 10px 10px;
}
.clue-verdict__icon {
  width: 88px;
  height: 88px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 18px;
  animation: clue-verdict-pop 0.45s cubic-bezier(.25,1.4,.5,1) both;
}
.clue-verdict__icon svg { width: 54px; height: 54px; }
.clue-verdict__icon--correct { background: #e9f5ea; }
.clue-verdict__icon--correct svg { stroke: #2e7d32; }
.clue-verdict__icon--wrong { background: #fbeae7; }
.clue-verdict__icon--wrong svg { stroke: #c0392b; }
.clue-verdict__icon--neutral { background: #f4ede4; }
.clue-verdict__icon--neutral svg { stroke: #a08a76; }
.clue-verdict__icon .clue-verdict__mark {
  stroke-dasharray: 24;
  stroke-dashoffset: 24;
  animation: clue-verdict-draw 0.35s ease-out 0.25s forwards;
}
.clue-verdict__headline {
  font-family: 'Playfair Display', serif;
  font-size: 25px;
  font-weight: 700;
  color: #1c2b4a;
}
.clue-verdict__points {
  font-size: 15.5px;
  font-weight: 600;
  margin-top: 6px;
}
.clue-verdict__points--correct { color: #2e7d32; }
.clue-verdict__echo {
  font-size: 14px;
  color: #8a8a8a;
  margin-top: 14px;
}
.clue-verdict__echo em { color: #5a5a5a; }
@keyframes clue-verdict-pop {
  0% { transform: scale(0.4); opacity: 0; }
  60% { transform: scale(1.08); opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}
@keyframes clue-verdict-draw {
  0% { stroke-dashoffset: 24; }
  100% { stroke-dashoffset: 0; }
}

/* Progress trigger button — sits to the right of the team photo in the
   score strip, opening the journey/leaderboard modal below. */
.progress-trigger-btn {
  position: absolute;
  right: 20px;
  bottom: 12px;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: #ffffff;
  color: #e07b39;
  border: none;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  box-shadow: 0 2px 6px rgba(0,0,0,0.2);
  z-index: 3; /* below the team photo/placeholder (z-index:5) so the two
                 can never overlap-and-hide each other on a narrow screen */
}

/* Journey/leaderboard modal — same full-screen overlay pattern as the
   map's own expand modal, just with tabbed content instead of a map. */
/* Audio recorder overlay — reuses .qr-scan-modal's dark backdrop, but
   overrides the inner card to a light background since there's no video
   feed to justify staying dark here. */
.audio-rec-inner {
  background: #fff;
}
.audio-rec-body {
  padding: 32px 20px;
  text-align: center;
}
.audio-rec-timer {
  font-size: 32px;
  font-weight: 700;
  color: #1c2b4a;
  margin: 8px 0 20px;
  font-variant-numeric: tabular-nums;
}
.audio-rec-record-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  border: none;
  border-radius: 30px;
  padding: 14px 28px;
  font-size: 16px;
  font-weight: 600;
  color: #fff;
  background: #e07b39;
  cursor: pointer;
}
.audio-rec-record-btn.recording {
  background: #c0392b;
}

.pattern-mode-hint {
  text-align: center;
  font-size: 13px;
  color: #8a8a8a;
  margin: -4px 0 6px;
}
.pattern-tap-target {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  padding: 32px 16px;
  border-radius: 14px;
  border: 2px dashed #e07b39;
  background: #fdf3ec;
  color: #c05e1f;
  font-size: 16px;
  font-weight: 600;
  font-family: inherit;
  appearance: none;
  cursor: pointer;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none; /* no "save image/copy" callout on long-press */
  -webkit-tap-highlight-color: transparent; /* no grey flash box on tap */
  touch-action: none; /* prevents scroll/zoom gestures from eating taps */
}
.pattern-tap-target i {
  font-size: 30px;
}
.pattern-tap-target:active {
  background: #fbe6d6;
}
.pattern-tap-progress {
  text-align: center;
  font-size: 20px;
  letter-spacing: 4px;
  color: #e07b39;
  /* Fixed height (not min-height) + no wrap, so the row of dots can
     never grow taller than this and shove the feedback text below it
     down — a reserved placeholder slot, filled or not, rather than a
     box that expands into existence once there's something to show. */
  height: 24px;
  line-height: 24px;
  overflow: hidden;
  white-space: nowrap;
  margin: 6px 0 0;
  /* Rapid taps on the target above were landing as a mobile text
     selection on these dots — the "selected" highlight/pin handles
     the user saw. Dots aren't meant to be selectable text. */
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}

.qr-scan-feedback {
  margin-top: 10px;
  font-size: 15px;
  color: #6b6b6b;
  text-align: center;
}
/* The .qr-scan-modal shell itself (hunt.html's audio-recorder task reuses
   it — see .audio-rec-inner above) now lives in its own shared file,
   css/qr-scan-style.css, since settings.html's QR-scan feature needs the
   exact same shell without the rest of this hunt-page-specific file —
   hunt.html loads that file alongside this one. */

/* Fade + slide animation for the popups that use this shell (journey/
   leaderboard, hunt summary details, bonus tasks) — timed to match the
   Bootstrap modal used for photos on photos.html (backdrop fade, panel
   slides down ~50px into place with an ease-out). They used to flip between
   display:none and display:flex, which can't be animated, so they snapped
   open and shut. Now they stay laid out but invisible and non-interactive
   when closed, so the same class toggle ("show") fades them in AND out.
   visibility is delayed on close so the fade-out is actually seen. */
.progress-modal {
  display: flex;
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.7);
  z-index: 3000;
  align-items: center;
  justify-content: center;
  padding: 20px;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.3s ease-out, visibility 0s linear 0.3s;
}
.progress-modal.show {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity 0.3s ease-out, visibility 0s linear 0s;
}
.progress-modal .progress-modal__inner {
  transform: translate3d(0, -50px, 0);
  transition: transform 0.3s ease-out;
  will-change: transform;
}
.progress-modal.show .progress-modal__inner {
  transform: translate3d(0, 0, 0);
}
@media (prefers-reduced-motion: reduce) {
  .progress-modal,
  .progress-modal.show,
  .progress-modal .progress-modal__inner {
    transition: none;
  }
}
.progress-modal__inner {
  position: relative;
  width: 100%;
  max-width: 480px;
  height: 70vh;
  background: #ffffff;
  border-radius: 12px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  /* Lifts the white panel off the dark backdrop — was only ever in the
     mockup, never actually carried over into this real shared shell. */
  box-shadow: 0 10px 30px rgba(0,0,0,0.35);
}
.progress-modal__close {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 1;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: rgba(42,42,42,0.75);
  color: #fff;
  border: none;
  font-size: 18px;
  line-height: 1;
}
.progress-modal__tabs {
  display: flex;
  flex-shrink: 0;
}
.progress-tab-btn {
  flex: 1;
  padding: 14px;
  border: none;
  background: #f4f4f2;
  font-size: 14px;
  font-weight: 500;
  color: #888;
  border-bottom: 2px solid transparent;
}
.progress-tab-btn.active {
  background: #fdf1e6;
  color: #1c2b4a;
  font-weight: 700;
  border-bottom: 2px solid #e07b39;
}
.progress-modal__content {
  padding: 18px 20px;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  /* Without this, scrolling this inner pane to its end and continuing to
     drag "hands off" the gesture to whatever's behind the modal (iOS
     Safari's scroll-chaining) — scrolling down worked, but the equivalent
     drag to scroll back UP moved the page behind the popup instead, once
     the pane's own scroll had nowhere further to go. This keeps every
     scroll gesture that starts inside the popup contained to the popup,
     both directions. */
  overscroll-behavior: contain;
}

/* Journey view rows */
.journey-row {
  display: flex;
  gap: 10px;
}
.journey-row__connector {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 40px;
  flex-shrink: 0;
}
.journey-row__icon {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-size: 16px;
}
.journey-row__icon--done { background: #1d9e75; }
.journey-row__icon--current {
  background: #e07b39;
  width: 40px;
  height: 40px;
  box-shadow: 0 0 0 4px #fdf1e6;
}
.journey-row__icon--locked { background: #e9ddcf; color: #b5a48c; }
.journey-row__line {
  width: 2px;
  flex: 1;
  background: #e0d5c8;
  margin: 2px 0;
}
.journey-row__label {
  flex: 1;
  text-align: center;
  padding-bottom: 24px;
}
.journey-row__name {
  font-size: 15.5px;
  color: #6b6b6b;
}
.journey-row__name--current { color: #1c2b4a; font-weight: 700; font-size: 17px; }
.journey-row__name--locked { color: #b5a48c; }
.journey-row__status {
  font-size: 12.5px;
  color: #a5a5a5;
}
.journey-row__status--current { color: #e07b39; font-weight: 500; }
.journey-row__time {
  flex-shrink: 0;
  align-self: center;
  min-width: 64px;
  text-align: right;
  font-size: 13px;
  color: #a5a5a5;
}
.journey-row__time--current { color: #e07b39; font-weight: 500; }

/* Leaderboard rows */
.leaderboard-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 8px;
  border-bottom: 1px solid #f0ece5;
  border-radius: 8px;
}
.leaderboard-row--you {
  background: #fdf1e6;
}
.leaderboard-row__left {
  display: flex;
  align-items: center;
  gap: 10px;
}
.leaderboard-row__rank {
  width: 22px;
  font-size: 13px;
  font-weight: 700;
  color: #a5825a;
}
.leaderboard-row__photo {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
}
.leaderboard-row__photo--placeholder {
  background: #e9e2da;
}
.leaderboard-row__name {
  font-size: 14px;
  color: #1c2b4a;
}
.leaderboard-row__name--you { font-weight: 700; }
.leaderboard-row__score {
  font-size: 14px;
  font-weight: 700;
  /* Navy, not the live orange — orange in the redesigned results/journey
     system means "current / in progress", and every plain point VALUE
     elsewhere (Arrival/Task/Total rows, the hunt-complete total) is
     navy bold. A rank number is just a value, not a "you are here"
     state, so it follows that rule instead of introducing its own. */
  color: #1c2b4a;
}

/* Points feedback — brief "+N points" text shown in the gap between the
   team photo and the progress trigger button, for arrival/correct-answer
   feedback. Positioned to roughly match the photo's own vertical center. */

/* Hunt-complete summary — final score/rank plus the points breakdown,
   shown on the route-complete screen once every point is done. One white
   card (score + rank up top, breakdown rows below a divider) rather than
   the two separate cream boxes this used to be — same card language the
   detailed-results/journey/leaderboard popups all use, and per-answer
   right/wrong detail lives only in the popup now, not duplicated here. */
.hunt-summary-card {
  /* #fbf7f3, not #fffdfb — this card sits on #hunt-screen, which is
     ITSELF #fffdfb, so matching that exactly left the card with no
     visible fill at all, just its 1px border doing all the work (and on
     a phone screen that border alone barely read either). #fbf7f3 is
     the same card tone the old (pre-redesign) cards used, so it's a
     known-visible value in this codebase, not a new one. */
  background: #fbf7f3;
  border: 1px solid #ece1d6;
  border-radius: 14px;
  padding: 16px;
  text-align: center;
  margin: 10px 0 0;
}
.hunt-summary-score__value {
  font-size: 28px;
  font-weight: 800;
  color: #e07b39;
}
.prov {
  font-size: 13px;
  font-weight: 600;
  color: #e47a2e;
}
.hunt-summary-score__rank {
  font-size: 13px;
  color: #6b5c4e;
  margin-top: 4px;
}
/* Also used on its own (no score/rank header) at the top of the detailed-
   results popup, where it needs to be its own white card rather than
   relying on .hunt-summary-card's border — overridden back to a plain
   divider when it IS nested inside that card, just below. */
.hunt-summary-breakdown {
  text-align: left;
  background: #fbf7f3;
  border: 1px solid #ece1d6;
  border-radius: 14px;
  padding: 14px 16px;
  margin-bottom: 20px;
}
.hunt-summary-card .hunt-summary-breakdown {
  background: transparent;
  border: none;
  border-radius: 0;
  padding: 10px 0 0;
  margin: 14px 0 0;
  border-top: 1px solid #ece1d6;
}
.hunt-summary-breakdown__row {
  display: flex;
  justify-content: space-between;
  font-size: 13px;
  color: #1c2b4a;
  padding: 2px 0;
}
.hunt-summary-breakdown__row strong { font-weight: 700; }
.hunt-summary-breakdown__row--total {
  border-top: 1px solid #ece1d6;
  margin-top: 6px;
  padding-top: 8px;
  font-weight: 700;
  font-size: 14.5px;
}
.hunt-summary-pending-note {
  font-size: 11.5px;
  color: #e47a2e;
  margin: -1px 0 1px;
}

/* Detailed results modal — same progress-modal shell (see .progress-modal
   above) with its own header instead of tabs, and a taller/wider inner
   panel since a full clue-by-clue breakdown (with photo thumbnails) needs
   more room than the journey/leaderboard popup. */
.details-modal__inner {
  max-width: 560px;
  /* max-height (not a fixed height) so a short result list doesn't force
     the popup to fill most of the screen regardless of content — it only
     grows this tall when the content actually needs it, and the content
     pane below scrolls once it hits the cap. Matches .progress-modal__inner's
     own 70vh above rather than reaching further down the screen. */
  height: auto;
  max-height: 70vh;
}
/* The results popup opens straight away showing "Loading your results..."
   and then fills in after the fetch. With height:auto it opened as a tiny
   box and then jumped to full size, which read as no animation at all, so
   it now opens at a steady, roomy size and only grows if it needs to. */
#detailsModal .details-modal__inner {
  min-height: min(60vh, 520px);
}
.details-modal__header {
  flex-shrink: 0;
  padding: 16px 44px 12px 20px;
  font-weight: 700;
  font-size: 17px;
  color: #1c2b4a;
  border-bottom: 1px solid #f0ece5;
}
/* Each clue is a connector (icon + the line down to the next one) next to
   a plain white card — same layout .journey-row already uses, so the
   "your journey" list and the full detailed breakdown share one visual
   system instead of two different ones. No left-border card trope. */
.details-list {
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.details-row {
  display: flex;
  gap: 10px;
}
.details-row__connector {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 40px;
  flex-shrink: 0;
}
.details-icon {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-size: 15px;
  flex-shrink: 0;
  /* A plain white ring, same idea as .journey-row__icon--current's glow
     but structural rather than a state highlight — it's what separates
     the icon from the connector line running directly behind it, on
     every outcome here, not just one "current" state. */
  box-shadow: 0 0 0 4px #ffffff;
}
/* Arrival-only clue ("none" task type) — deliberately neutral, not a
   tick: arrival is a fact, not something that can be right/wrong/
   skipped, so it never borrows the "correct" green. */
.details-icon--none {
  background: #ffffff;
  border: 2px solid #d8cdbf;
  color: #a08a76;
  font-size: 8px;
}
.details-icon--correct { background: #2e7d32; }
.details-icon--wrong { background: #c0392b; }
.details-icon--pending { background: #e47a2e; }
.details-icon--timedout { background: #a08a76; }
.details-icon--skipped { background: #6b5c4e; }
.details-row__line {
  width: 2px;
  flex: 1;
  background: #e0d5c8;
  margin: 2px 0;
}
.details-card {
  flex: 1 1 auto;
  min-width: 0;
  background: #fbf7f3;
  border: 1px solid #ece1d6;
  border-radius: 14px;
  padding: 12px 14px;
}
.details-card__title {
  font-weight: 700;
  font-size: 14.5px;
  color: #1c2b4a;
}
.details-pt-row {
  display: flex;
  justify-content: space-between;
  font-size: 13px;
  color: #1c2b4a;
  padding: 2px 0;
  margin-top: 4px;
}
.details-pt-row .val { font-weight: 700; }
.details-tag { font-size: 11.5px; font-weight: 700; }
.details-card__question {
  font-size: 13px;
  color: #1c2b4a;
  background: #f6efe7;
  border-radius: 8px;
  padding: 7px 9px;
  margin-top: 8px;
}
.details-card__answer-row {
  font-size: 13px;
  color: #1c2b4a;
  margin-top: 6px;
}
.details-card__answer-row .yours { font-weight: 600; }
.details-card__answer-row .correct { color: #2e7d32; font-weight: 600; }
.details-card__note {
  font-size: 12.5px;
  color: #6b5c4e;
  margin-top: 6px;
}
.details-hints {
  border-top: 1px dashed #e3d5c6;
  margin-top: 10px;
  padding-top: 8px;
}
.details-hints__item {
  display: flex;
  justify-content: space-between;
  font-size: 12.5px;
  color: #6b5c4e;
}
.details-hints__item .penalty { color: #c0392b; }
.details-hints__note {
  font-size: 12.5px;
  color: #a08a76;
  margin-top: 2px;
}
.details-media { margin-top: 10px; }
/* A genuinely small, square preview — not a full-width banner image — so
   it actually reads as a "thumbnail" alongside the rest of the card
   rather than dominating it. Still has a fixed size (not just a cap) so
   it occupies real, visible space even before it finishes loading or if
   it fails to load at all — an <img> with no intrinsic size and only a
   max-height/max-width can collapse to ~0px, which looked exactly like
   no thumbnail was there. */
.details-media__thumb {
  display: block;
  width: 84px;
  height: 84px;
  object-fit: cover;
  border-radius: 8px;
  cursor: pointer;
  background: #efe6db;
}
.details-media audio { width: 100%; }
.details-media__error {
  font-size: 12px;
  color: #c0392b;
  margin-top: 4px;
}
.details-media__status {
  font-size: 12px;
  color: #a08a76;
  margin-top: 4px;
}

/* Full-screen tap-to-close preview for a details-card photo thumbnail —
   deliberately separate from the progress-modal styling above (this one
   has no inner panel/close button chrome, just the image itself). */
.details-lightbox {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.92);
  z-index: 3200;
  align-items: center;
  justify-content: center;
  padding: 24px;
}
.details-lightbox.show { display: flex; }
.details-lightbox img {
  max-width: 100%;
  max-height: 100%;
  border-radius: 8px;
}

/* ----------------------------------------------------------
   BONUS TASKS — location-free tasks doable any time (js/bonus.js,
   questions.js's bonus header). Star button sits directly left of the
   trophy button (right: 20 + 34 + 10); the list reuses the popup shell
   and the details popup's pt-row / pending-note idiom.
---------------------------------------------------------- */
.bonus-trigger-btn {
  right: 64px;
}
.bonus-trigger-badge {
  position: absolute;
  top: -4px;
  right: -4px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  box-sizing: border-box;
  border-radius: 8px;
  background: #1c2b4a;
  color: #ffffff;
  font-size: 10px;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
}
.bonus-intro {
  font-size: 15px;
  color: #8a8a8a;
  line-height: 1.4;
  margin: 0 0 12px;
  text-align: left;
}
.bonus-summary { margin-bottom: 8px; }
.bonus-summary__done {
  font-size: 12px;
  color: #a5825a;
  font-weight: 600;
  margin-bottom: 6px;
}
.bonus-list { text-align: left; }
.bonus-row {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 12px 8px;
  border: none;
  border-bottom: 1px solid #f0ece5;
  background: transparent;
  font-family: inherit;
  text-align: left;
}
.bonus-row:last-child { border-bottom: none; }
.bonus-row__marker {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
}
.bonus-row__marker--done { background: #2e7d32; }
.bonus-row__marker--pending { background: #e47a2e; }
.bonus-row__marker--todo { border: 2px solid #d8cdbf; }
.bonus-row__main { flex: 1; min-width: 0; }
.bonus-row__title { font-size: 14.5px; font-weight: 700; color: #1c2b4a; }
.bonus-row__meta {
  font-size: 10.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #a08a76;
  margin-top: 2px;
}
.bonus-row__pending { color: #e47a2e; }
.bonus-row__hint { font-size: 11.5px; color: #c0392b; margin-top: 2px; }
.bonus-row__pts { font-size: 14px; color: #a5825a; white-space: nowrap; }
.bonus-row__pts--earned { font-weight: 700; color: #1c2b4a; }

/* Bonus task screen header (questions.js renderArrivedPhase, bonus branch):
   back link + what it's worth, then the "★ Bonus task · Type" label. */
.bonus-task-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 22px;
}
.bonus-task-back {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0;
  background: none;
  border: none;
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  color: #a5825a;
}
.bonus-task-header__pts { font-size: 13px; color: #a5825a; }
.phase-label--bonus { color: #e07b39; font-size: 12px; }
.bonus-task-title { font-size: 20px; margin-top: 6px; }
.details-bonus-heading {
  font-size: 12px;
  letter-spacing: 1px;
  text-transform: uppercase;
  font-weight: 600;
  color: #a5825a;
  margin: 24px 0 10px;
}