/* ============================================================================
   OPENLAND — APPLICATION SHELL
   ----------------------------------------------------------------------------
   Layout law, in priority order:
   1. The map is never fully covered. It is the primary instrument.
   2. Every primary action sits in the bottom 40% of the viewport, reachable
      by a right or left thumb without shifting grip.
   3. Nothing that matters is smaller than 48px of touch target.
   4. Color is never the only carrier of meaning — shape, label, or position
      always doubles it, because the night theme collapses every hue to red.
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  overscroll-behavior: none;
}

body {
  font-family: var(--font-ui);
  font-size: var(--t-body);
  line-height: var(--lh-body);
  color: var(--ink);
  background: var(--ground-0);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  -webkit-tap-highlight-color: transparent;

  /* iOS: a long press anywhere on chrome otherwise raises the copy/share
     callout and starts a text selection. On a map you hold, drag and pinch
     constantly, that fires by accident all day. Selection is granted back
     below to the text worth copying — coordinates, addresses, spot names. */
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}

/* The exceptions: anything someone has a real reason to copy out of the app. */
.detail, .detail *, .card__name, .coach__body, input, textarea {
  -webkit-touch-callout: default;
  -webkit-user-select: text;
  user-select: text;
}

/* Kills the 350ms wait Safari holds every tap for in case it becomes a
   double-tap zoom, and stops a pinch anywhere on the chrome from scaling the
   document. Panning still works, so the sheet scrolls and the list scrolls;
   only the zoom gesture is withheld.

   Deliberately not applied to #map: MapLibre sets its own touch-action and
   owns every gesture inside the canvas, which is the one place a pinch should
   do something. */
.app, .sheet, .sheet__body, .topbar, .maprail, .modal, .coach__card,
button, .chip, .purpose__opt, .iconbtn, .card, a[href] {
  touch-action: pan-x pan-y;
}
button, .chip, .purpose__opt, .iconbtn, .card, a[href] {
  touch-action: manipulation;
}

h1, h2, h3, h4 { margin: 0; font-weight: 600; line-height: var(--lh-snug); }
p { margin: 0; }
button, input, select, textarea { font: inherit; color: inherit; }

:focus-visible {
  outline: 3px solid var(--signal);
  outline-offset: 2px;
  border-radius: var(--r-xs);
}

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

/* Skip link — keyboard users land here first. */
.skip {
  position: fixed; top: -100px; left: var(--s-4);
  z-index: var(--z-toast);
  background: var(--signal); color: var(--signal-ink);
  padding: var(--s-3) var(--s-5); border-radius: var(--r-md);
  font-weight: 700; text-decoration: none;
  transition: top var(--d-fast) var(--ease-out);
}
.skip:focus { top: calc(var(--safe-t) + var(--s-3)); }

/* --- Typographic primitives ---------------------------------------------- */

/* The wordmark, and only the wordmark. */
.display {
  font-family: var(--font-brand);
  font-weight: 700;
  line-height: var(--lh-tight);
  letter-spacing: 0.005em;
}
.label {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--t-meta);
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--ink-3);
}
.micro {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--t-micro);
  letter-spacing: var(--track-micro);
  text-transform: uppercase;
  color: var(--ink-3);
}
.data {
  font-family: var(--font-data); font-feature-settings: var(--num-tabular);
  font-size: var(--t-data);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}

/* ============================================================================
   SHELL
   ========================================================================== */

.app {
  position: fixed;
  inset: 0;
  display: block;
  isolation: isolate;
}

#map {
  position: absolute;
  inset: 0;
  z-index: var(--z-map);
  background: var(--ground-0);
}

/* Map canvas gets a subtle vignette so floating chrome always has contrast
   to sit against, whatever the terrain underneath is doing. */
.map-vignette {
  position: absolute; inset: 0;
  z-index: calc(var(--z-map) + 1);
  pointer-events: none;
  background:
    linear-gradient(to bottom, rgba(0,0,0,.34) 0%, transparent 16%),
    linear-gradient(to top, rgba(0,0,0,.30) 0%, transparent 22%);
}
[data-theme='day'] .map-vignette {
  background:
    linear-gradient(to bottom, rgba(255,253,246,.55) 0%, transparent 15%),
    linear-gradient(to top, rgba(255,253,246,.45) 0%, transparent 20%);
}

/* ============================================================================
   TOP: search capsule + status
   A capsule, not a bar — the map stays visible to the edges of the screen.
   ========================================================================== */

.topbar {
  position: absolute;
  top: calc(var(--safe-t) + var(--s-3));
  left: calc(var(--safe-l) + var(--s-3));
  right: calc(var(--safe-r) + var(--s-3));
  z-index: var(--z-map-ui);
  display: flex;
  gap: var(--s-2);
  align-items: flex-start;
  pointer-events: none;
}
.topbar > * { pointer-events: auto; }

.search {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: var(--s-2);
  height: var(--tap);
  padding: 0 var(--s-2) 0 var(--s-4);
  background: var(--sheet-glass);
  backdrop-filter: blur(14px) saturate(1.3);
  -webkit-backdrop-filter: blur(14px) saturate(1.3);
  border: var(--hair) solid var(--line);
  border-radius: var(--r-full);
  box-shadow: var(--shadow-2);
}
.search__icon { flex: none; color: var(--ink-3); display: grid; place-items: center; }
.search input {
  flex: 1; min-width: 0;
  border: 0; background: none; outline: none;
  font-size: var(--t-body);
  color: var(--ink);
}
.search input::placeholder { color: var(--ink-3); }

.iconbtn {
  flex: none;
  width: var(--tap); height: var(--tap);
  display: grid; place-items: center;
  border: var(--hair) solid var(--line);
  border-radius: var(--r-full);
  background: var(--sheet-glass);
  backdrop-filter: blur(14px) saturate(1.3);
  -webkit-backdrop-filter: blur(14px) saturate(1.3);
  color: var(--ink);
  box-shadow: var(--shadow-2);
  cursor: pointer;
  transition: transform var(--d-fast) var(--ease-out),
              background var(--d-fast) var(--ease-out);
}
.iconbtn:active { transform: scale(0.93); background: var(--ground-4); }
.iconbtn[aria-pressed='true'] {
  background: var(--signal); border-color: var(--signal); color: var(--signal-ink);
}
.iconbtn--bare { border: 0; background: none; box-shadow: none; backdrop-filter: none; }
.iconbtn--sm { width: var(--tap-sm); height: var(--tap-sm); }

/* Badge on an icon button (e.g. active filter count) */
.iconbtn { position: relative; }
.iconbtn__count {
  position: absolute; top: 2px; right: 2px;
  min-width: 20px; height: 20px; padding: 0 5px;
  display: grid; place-items: center;
  border-radius: var(--r-full);
  background: var(--signal); color: var(--signal-ink);
  font-family: var(--font-data); font-feature-settings: var(--num-tabular); font-size: 11px; font-weight: 700;
  border: 2px solid var(--ground-2);
}

/* ============================================================================
   MAP CONTROLS — right rail, thumb-height, above the sheet peek
   ========================================================================== */

.maprail {
  position: absolute;
  right: calc(var(--safe-r) + var(--s-3));
  bottom: calc(var(--sheet-peek, 194px) + var(--s-3));
  z-index: var(--z-map-ui);
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  transition: bottom var(--d-base) var(--ease-out);
}
.maprail .iconbtn { box-shadow: var(--shadow-2); }

/* Compass only appears when the map is rotated or pitched. */
.maprail__compass { display: none; }
.maprail__compass[data-visible='true'] { display: grid; }
.maprail__compass svg { transition: transform var(--d-fast) linear; }

/* Locate button states: idle / seeking / locked */
.locate[data-state='seeking'] { color: var(--signal); }
.locate[data-state='seeking'] svg { animation: pulse 1.1s var(--ease-in-out) infinite; }
.locate[data-state='locked'] { color: var(--signal); border-color: var(--signal); }
@keyframes pulse { 50% { opacity: .35; transform: scale(.9); } }

/* Scale bar — bottom-left, out of thumb territory */
.scalebar {
  position: absolute;
  left: calc(var(--safe-l) + var(--s-3));
  bottom: calc(var(--sheet-peek, 194px) + var(--s-3));
  z-index: var(--z-map-ui);
  display: flex; flex-direction: column; gap: 3px;
  pointer-events: none;
  transition: bottom var(--d-base) var(--ease-out);
}
.scalebar__bar {
  height: 6px;
  border: var(--hair) solid var(--ink-2);
  border-top: 0;
  min-width: 40px;
}
.scalebar__txt {
  font-family: var(--font-data); font-feature-settings: var(--num-tabular); font-size: var(--t-micro);
  color: var(--ink-2);
  text-shadow: 0 1px 3px var(--ground-0);
}

/* Attribution — legally required for OSM/ODbL. Small, always present. */
.attrib {
  position: absolute;
  right: calc(var(--safe-r) + var(--s-2));
  /* Above the sheet, not tucked under its lip. The old -16px put this
     entirely behind a sheet that paints at a higher z-index, so the OSM
     credit was visible only as a smear at the rounded corner — and ODbL
     attribution is a license condition, not decoration. */
  bottom: calc(var(--sheet-peek, 194px) + var(--s-1));
  z-index: var(--z-map-ui);
  font-size: 10px;
  color: var(--ink-3);
  background: var(--scrim);
  padding: 2px 6px;
  border-radius: var(--r-xs);
  transition: bottom var(--d-base) var(--ease-out);
}
.attrib a { color: inherit; }

/* ============================================================================
   BOTTOM SHEET — three detents
   peek : the Tonight strip and a result count. Map fully usable.
   half : a browsable list.
   full : reading a spot, or a settings surface.
   ========================================================================== */

.sheet {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  z-index: var(--z-sheet);
  height: var(--sheet-h, 194px);
  display: flex;
  flex-direction: column;
  background: var(--sheet-glass);
  backdrop-filter: blur(20px) saturate(1.35);
  -webkit-backdrop-filter: blur(20px) saturate(1.35);
  border-top: var(--hair) solid var(--line-strong);
  border-radius: var(--r-xl) var(--r-xl) 0 0;
  box-shadow: var(--shadow-3);
  transition: height var(--d-slow) var(--ease-out);
  will-change: height;
  max-width: 720px;
  margin: 0 auto;
}
.sheet[data-dragging='true'] { transition: none; }

.sheet__grip {
  flex: none;
  height: 26px;
  display: grid; place-items: center;
  cursor: grab;
  touch-action: none;
}
.sheet__grip::after {
  content: '';
  width: 42px; height: 4px;
  border-radius: var(--r-full);
  background: var(--line-strong);
}
.sheet__grip:active { cursor: grabbing; }

.sheet__body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding-bottom: calc(var(--safe-b) + var(--s-6));
}
/* At peek the sheet's own height already reserves the home-indicator inset,
   and nothing scrolls, so repeating that reserve as padding here would just
   push the chip row back under the indicator it was meant to clear. */
.sheet[data-detent='peek'] .sheet__body { overflow: hidden; padding-bottom: 0; }

/* ============================================================================
   TONIGHT STRIP — the app's center of gravity.
   Sunset countdown on the left, what you can still reach on the right.
   ========================================================================== */

.tonight {
  display: grid;
  /* minmax(0,1fr) rather than 1fr: a bare 1fr refuses to shrink below its
     content, so a long sunset line would push its own column off screen. */
  grid-template-columns: 46px minmax(0, 1fr);
  gap: var(--s-3);
  align-items: center;
  padding: 0 var(--gutter) var(--gap-tight);
  width: 100%;
  text-align: left;
}
.tonight__dial { width: 46px; height: 46px; flex: none; }
.tonight__main { min-width: 0; overflow: hidden; }
/* Deliberately not the loudest thing in the sheet. It is a count you glance at
   to know the list is worth opening — not a headline. The purpose control above
   already says what is being counted, so shouting the number a second time in
   display size only crowded out the light remaining, which is the line that
   actually changes what you do next. */
.tonight__head {
  display: block;
  font-family: var(--font-display);
  font-size: var(--t-body);
  font-weight: 700;
  letter-spacing: .01em;
  line-height: 1.2;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tonight__sub {
  display: block;
  font-size: var(--t-meta);
  color: var(--ink-2);
  line-height: 1.3;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The dial: an arc of remaining daylight. Reads at a glance at 60mph. */
.dial__track { stroke: var(--line); }
.dial__arc   { stroke: var(--signal); transition: stroke-dashoffset var(--d-slow) var(--ease-out); }
.dial__num   { font-family: var(--font-data); font-feature-settings: var(--num-tabular); font-weight: 700; fill: var(--ink); }
.dial__unit  { font-family: var(--font-display); fill: var(--ink-3); letter-spacing: .08em; }
.dial--night .dial__arc { stroke: var(--violet); }

/* ============================================================================
   BACK TO THE MAP
   ----------------------------------------------------------------------------
   The sheet can be dragged down, but a drag is invisible: nothing on screen
   says the map is still under there, and a keyboard or switch user has no
   grip to pull. This is the same exit rendered as a control — one target, one
   place, present the whole time the map is covered.
   ========================================================================== */

.mapback {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  bottom: calc(var(--sheet-h, 194px) + var(--s-2));
  z-index: 45;
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  min-height: var(--tap-sm);
  padding: 0 var(--s-4);
  border: var(--hair) solid var(--line-strong);
  border-radius: var(--r-full);
  background: var(--ground-1);
  color: var(--ink);
  font-family: inherit;
  font-size: var(--t-meta);
  font-weight: 700;
  white-space: nowrap;
  cursor: pointer;
  box-shadow: var(--shadow-2);
  transition: bottom var(--d-base) var(--ease-out), opacity var(--d-fast) var(--ease-out);
}
.mapback:active { transform: translateX(-50%) scale(.96); }
.mapback[hidden] { display: none; }

/* Dragging publishes --sheet-h every frame; following it there would fight
   the finger, so the button just rides along without its own animation. */
.sheet[data-dragging='true'] ~ .mapback { transition: none; }

/* ============================================================================
   PURPOSE — the one control that never moves
   ----------------------------------------------------------------------------
   Three fixed columns, no scrolling, no overflow. It sits above the chips so
   the eye reads "what am I looking at" before "how do I narrow it", and it is
   the same three words in the same three places on every load.

   Deliberately not a chip: chips scroll and can be off-screen, and a control
   that decides what the whole screen means must never be the one you have to
   go looking for.
   ========================================================================== */

.purpose {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 2px;
  margin: 0 var(--gutter) var(--gap-tight);
  padding: 3px;
  background: var(--ground-2);
  border: var(--hair) solid var(--line);
  border-radius: var(--r-full);
}

.purpose__opt {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  min-height: var(--tap-sm);
  padding: 0 var(--s-2);
  border: 0;
  border-radius: var(--r-full);
  background: transparent;
  color: var(--ink-3);
  font-family: inherit;
  font-size: var(--t-meta);
  font-weight: 700;
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--d-fast) var(--ease-out),
              color var(--d-fast) var(--ease-out);
}
.purpose__opt:active { transform: scale(.97); }

/* The selected state carries a filled background AND a weight change, so it
   survives the night theme collapsing every hue toward red. */
.purpose__opt[aria-checked='true'] {
  background: var(--signal);
  color: var(--signal-ink);
}

/* Under 340px the labels are what give, not the tap targets. */
@media (max-width: 340px) {
  .purpose__opt span { display: none; }
  .purpose__opt { gap: 0; }
}

/* ============================================================================
   FILTER CHIPS — horizontally scrolling, snap, never wrap
   ========================================================================== */

.chips {
  display: flex;
  gap: var(--s-2);
  overflow-x: auto;
  scrollbar-width: none;
  scroll-snap-type: x proximity;
  padding: 0 var(--gutter) var(--gap-tight);
  margin: 0;
  list-style: none;
}
.chips::-webkit-scrollbar { display: none; }
.chips > li { scroll-snap-align: start; flex: none; }

.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  height: var(--tap-sm);
  padding: 0 var(--s-4);
  border: var(--hair) solid var(--line-strong);
  border-radius: var(--r-full);
  background: var(--ground-3);
  color: var(--ink-2);
  font-size: var(--t-meta);
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--d-fast) var(--ease-out),
              color var(--d-fast) var(--ease-out),
              border-color var(--d-fast) var(--ease-out),
              transform var(--d-fast) var(--ease-out);
}
.chip:active { transform: scale(.95); }
.chip[aria-pressed='true'] {
  background: var(--signal);
  border-color: var(--signal);
  color: var(--signal-ink);
}
.chip__ico { display: grid; place-items: center; }
.chip--ghost { background: transparent; border-style: dashed; }

/* ============================================================================
   RESULT LIST
   ========================================================================== */

.listhead {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--gap-tight) var(--gutter) var(--gap-tight);
}
.listhead__sort {
  border: 0; background: none; cursor: pointer;
  color: var(--signal); font-family: inherit;
  font-size: var(--t-meta); font-weight: 700;
  display: inline-flex; align-items: center; gap: 5px;
  min-height: var(--tap-sm);
  /* Negative inset so the text starts on the gutter while the tap target
     still extends past it. */
  padding: 0 var(--s-2);
  margin-left: calc(var(--s-2) * -1);
}
.listhead__by { color: var(--ink-3); font-weight: 500; }

.spotlist { list-style: none; margin: 0; padding: 0 var(--gutter); }
.spotlist > li + li { margin-top: var(--gap-tight); }

.card {
  position: relative;
  display: grid;
  grid-template-columns: 38px minmax(0, 1fr) auto;
  gap: var(--gap-block);
  align-items: start;
  width: 100%;
  /* Horizontal air is what makes the column of names read as aligned;
     vertical air just costs rows on a phone, where two visible results is
     not a list. Generous across, measured down. */
  padding: var(--s-3) var(--gap-block);
  border: var(--hair) solid var(--line);
  border-radius: var(--r-lg);
  background: var(--ground-3);
  text-align: left;
  cursor: pointer;
  transition: transform var(--d-fast) var(--ease-out),
              border-color var(--d-fast) var(--ease-out);
}
.card:active { transform: scale(.985); }
.card[aria-current='true'] { border-color: var(--signal); }
.card--stale { opacity: .72; }

.card__mark {
  width: 38px; height: 38px;
  display: grid; place-items: center;
  border-radius: var(--r-md);
  background: var(--ground-1);
  border: var(--hair) solid var(--line);
  color: var(--ink-2);
}
.card__body { min-width: 0; }
.card__name {
  font-family: var(--font-display);
  font-size: var(--t-title);
  font-weight: 700;
  line-height: 1.15;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Row gap slightly larger than column gap: when this wraps, the two lines
   need to read as separate rows rather than as one dense block. */
.card__facts {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--gap-tight) var(--s-3);
  margin-top: 6px;
  font-size: var(--t-meta);
  color: var(--ink-2);
}
.card__side {
  display: flex; flex-direction: column; align-items: flex-end;
  justify-content: space-between; gap: var(--s-1);
}
.card__dist {
  font-family: var(--font-data); font-feature-settings: var(--num-tabular); font-size: var(--t-data); font-weight: 700;
  color: var(--ink); white-space: nowrap;
}
.card__dist small {
  font-family: var(--font-display); font-size: var(--t-micro);
  color: var(--ink-3); letter-spacing: var(--track-micro);
  display: block; text-align: right; text-transform: uppercase;
}

/* ============================================================================
   BADGES, PILLS, SIGNALS
   Each carries a glyph or a letter as well as a color — the night theme
   removes hue as a channel, so color alone can never be the message.
   ========================================================================== */

.pill {
  display: inline-flex; align-items: center; gap: 5px;
  height: 24px; padding: 0 9px;
  border-radius: var(--r-sm);
  background: var(--ground-1);
  border: var(--hair) solid var(--line);
  font-size: var(--t-micro);
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--ink-2);
  white-space: nowrap;
}
.pill--free  { color: var(--go);   border-color: var(--go);   background: var(--go-wash); }
.pill--fee   { color: var(--ink-2); }

/* An absence is not news. "Cost unknown" was rendering at the same weight as
   "Free" — a bordered, uppercase box that outshouted the name of the place
   above it, for the least actionable fact on the card. It still has to be
   readable, because "we do not know" is a real answer someone must be able to
   see; it just stops competing for the eye. */
.pill--unknown {
  background: transparent;
  border-color: transparent;
  padding-left: 0;
  color: var(--ink-3);
  text-transform: none;
  letter-spacing: 0;
  font-family: var(--font-ui);
  font-size: var(--t-meta);
  font-weight: 500;
}
.pill--warn  { color: var(--warn); border-color: var(--warn); background: var(--warn-wash); }
.pill--stop  { color: var(--stop); border-color: var(--stop); background: var(--stop-wash); }
.pill--water { color: var(--water);border-color: var(--water);background: var(--water-wash); }
.pill--signal{ color: var(--signal);border-color: var(--signal);background: var(--signal-wash); }

/* Freshness: a four-step ladder, always with words next to it. */
.fresh { display: inline-flex; align-items: center; gap: 6px; font-size: var(--t-meta); }
.fresh__dot {
  width: 9px; height: 9px; border-radius: var(--r-full);
  flex: none; box-shadow: 0 0 0 2px var(--ground-3);
}
.fresh--current .fresh__dot { background: var(--go); }
.fresh--recent  .fresh__dot { background: var(--amber); }
.fresh--aging   .fresh__dot { background: var(--warn); }
.fresh--stale   .fresh__dot {
  background: transparent;
  border: 2px solid var(--ink-3);
}
.fresh--current { color: var(--go); }
.fresh--recent  { color: var(--ink-2); }
.fresh--aging   { color: var(--warn); }
.fresh--stale   { color: var(--ink-3); }

/* Road difficulty: five bars. Shape carries the value, color reinforces. */
.road { display: inline-flex; align-items: center; gap: 6px; }
.road__bars { display: inline-flex; gap: 2px; align-items: flex-end; height: 14px; }
.road__bar {
  width: 4px; border-radius: 1px;
  background: var(--line-strong);
}
.road__bar:nth-child(1) { height: 5px; }
.road__bar:nth-child(2) { height: 7px; }
.road__bar:nth-child(3) { height: 9px; }
.road__bar:nth-child(4) { height: 11.5px; }
.road__bar:nth-child(5) { height: 14px; }
.road[data-level='1'] .road__bar.on { background: var(--road-1); }
.road[data-level='2'] .road__bar.on { background: var(--road-2); }
.road[data-level='3'] .road__bar.on { background: var(--road-3); }
.road[data-level='4'] .road__bar.on { background: var(--road-4); }
.road[data-level='5'] .road__bar.on { background: var(--road-5); }
.road__txt { font-size: var(--t-meta); color: var(--ink-2); }

/* Rig-fit verdict */
.fit { display: inline-flex; align-items: center; gap: 6px; font-size: var(--t-meta); font-weight: 600; }
.fit--ok    { color: var(--go); }
.fit--tight { color: var(--warn); }
.fit--no    { color: var(--stop); }

/* ============================================================================
   SPOT DETAIL
   Ordered by the question a tired driver actually asks, in order:
   can I sleep here — can I get there — what will it be like — what's nearby —
   who says so.
   ========================================================================== */

.detail { padding: 0 var(--s-4); }

.detail__top { padding-bottom: var(--s-3); }
.detail__kind { display: flex; align-items: center; gap: var(--s-2); margin-bottom: var(--s-1); }
.detail__name {
  font-family: var(--font-display);
  font-size: var(--t-display);
  font-weight: 700;
  line-height: var(--lh-tight);
  color: var(--ink);
}
.detail__where {
  margin-top: var(--s-1);
  font-size: var(--t-meta);
  color: var(--ink-2);
}

/* The verdict block — the single most important thing on the screen. */
.verdict {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--hair);
  margin: var(--s-3) 0;
  border: var(--hair) solid var(--line);
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--line);
}
.verdict__cell {
  background: var(--ground-3);
  padding: var(--s-3) var(--s-2);
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  text-align: center;
  min-height: 82px;
  justify-content: center;
}
.verdict__val {
  font-family: var(--font-data); font-feature-settings: var(--num-tabular);
  font-size: var(--t-data-lg);
  font-weight: 700;
  line-height: 1;
  color: var(--ink);
}
.verdict__val--go   { color: var(--go); }
.verdict__val--warn { color: var(--warn); }
.verdict__val--stop { color: var(--stop); }
.verdict__lab {
  font-family: var(--font-display);
  font-size: var(--t-micro);
  font-weight: 600;
  letter-spacing: var(--track-micro);
  text-transform: uppercase;
  color: var(--ink-3);
}

/* Section */
.sect { padding: var(--s-5) 0; border-top: var(--hair) solid var(--line); }
.sect__head {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-3); margin-bottom: var(--s-3);
}
.sect__title {
  font-family: var(--font-display);
  font-size: var(--t-heading);
  font-weight: 700;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--ink-2);
}

/* Fact rows */
.facts { display: grid; gap: var(--s-1); }
.fact {
  display: grid;
  grid-template-columns: 22px 1fr auto;
  gap: var(--s-3);
  align-items: center;
  padding: var(--s-2) 0;
  min-height: var(--tap-sm);
}
.fact + .fact { border-top: var(--hair) solid var(--line); }
.fact__ico { color: var(--ink-3); display: grid; place-items: center; }
.fact__lab { font-size: var(--t-body); color: var(--ink-2); }
.fact__val {
  font-family: var(--font-data); font-feature-settings: var(--num-tabular); font-size: var(--t-data);
  color: var(--ink); text-align: right; font-weight: 700;
}
.fact__val--muted { color: var(--ink-3); font-weight: 400; }

/* Amenity grid — glyph + word, wrapping */
.amen { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.amen__item {
  display: inline-flex; align-items: center; gap: 6px;
  padding: var(--s-2) var(--s-3);
  border: var(--hair) solid var(--line);
  border-radius: var(--r-md);
  background: var(--ground-1);
  font-size: var(--t-meta);
  color: var(--ink-2);
}
.amen__item[data-has='yes'] { color: var(--ink); border-color: var(--line-strong); }
.amen__item[data-has='no']  { color: var(--ink-3); opacity: .55; text-decoration: line-through; }
.amen__item[data-has='unknown'] { border-style: dashed; }

/* Essentials strip — nearest water / dump / propane / fuel / shower */
.strip {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(84px, 1fr);
  gap: var(--s-2);
  overflow-x: auto;
  scrollbar-width: none;
  padding-bottom: var(--s-1);
}
.strip::-webkit-scrollbar { display: none; }
.strip__item {
  display: flex; flex-direction: column; align-items: center; gap: 5px;
  padding: var(--s-3) var(--s-2);
  border: var(--hair) solid var(--line);
  border-radius: var(--r-md);
  background: var(--ground-1);
  text-align: center;
  cursor: pointer;
  min-height: 92px;
  justify-content: center;
}
.strip__ico { color: var(--water); }
.strip__dist {
  font-family: var(--font-data); font-feature-settings: var(--num-tabular); font-size: var(--t-data); font-weight: 700; color: var(--ink);
}
.strip__lab {
  font-family: var(--font-display); font-size: var(--t-micro); font-weight: 600;
  letter-spacing: var(--track-micro); text-transform: uppercase; color: var(--ink-3);
}
.strip__item[data-far='true'] .strip__dist { color: var(--warn); }
.strip__item[data-none='true'] { opacity: .5; }

/* What's around here — trails, summits, water, oddities */
.nearby { display: grid; gap: var(--hair); }
.nearby__row {
  display: grid;
  grid-template-columns: 26px minmax(0, 1fr) auto;
  gap: var(--s-3);
  align-items: center;
  width: 100%;
  min-height: var(--tap);
  padding: var(--s-2) 0;
  border: 0;
  border-top: var(--hair) solid var(--line);
  background: none;
  text-align: left;
  cursor: pointer;
}
.nearby__row:first-child { border-top: 0; }
.nearby__row:active { background: var(--ground-1); }
.nearby__ico { color: var(--ink-3); display: grid; place-items: center; }
.nearby__txt { min-width: 0; }
.nearby__name {
  display: block;
  font-size: var(--t-body);
  color: var(--ink);
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
}
.nearby__meta {
  display: block;
  font-size: var(--t-meta);
  color: var(--ink-3);
}
.nearby__dist {
  font-family: var(--font-data); font-feature-settings: var(--num-tabular);
  font-size: var(--t-data);
  font-weight: 700;
  color: var(--ink-2);
  white-space: nowrap;
}

/* Legality callout — the thing that keeps a knock on the window from happening */
.legal {
  display: grid; grid-template-columns: 24px 1fr; gap: var(--s-3);
  padding: var(--s-3);
  border-radius: var(--r-md);
  border: var(--hair) solid var(--line-strong);
  background: var(--ground-1);
  font-size: var(--t-meta);
  line-height: 1.45;
  color: var(--ink-2);
}
.legal--ok   { border-color: var(--go);   background: var(--go-wash); }
.legal--warn { border-color: var(--warn); background: var(--warn-wash); }
.legal--stop { border-color: var(--stop); background: var(--stop-wash); }
.legal strong { color: var(--ink); font-weight: 700; }
.legal__ico { color: currentColor; }

/* Provenance — where every field came from. Trust is a feature. */
.prov { display: grid; gap: var(--s-2); }
.prov__row {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-3); padding: var(--s-2) 0;
  font-size: var(--t-meta);
  border-bottom: var(--hair) solid var(--line);
}
.prov__src { color: var(--ink-2); display: flex; align-items: center; gap: 7px; }
.prov__lic { font-family: var(--font-data); font-feature-settings: var(--num-tabular); font-size: var(--t-micro); color: var(--ink-3); }
.prov__link { color: var(--signal); text-decoration: none; font-weight: 700; }

/* Weather row */
.wx { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: var(--s-2); }
.wx__slot {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: var(--s-2);
  border-radius: var(--r-sm);
  background: var(--ground-1);
}
.wx__t { font-family: var(--font-data); font-feature-settings: var(--num-tabular); font-weight: 700; color: var(--ink); }
.wx__h { font-family: var(--font-display); font-size: var(--t-micro);
         letter-spacing: var(--track-micro); color: var(--ink-3); text-transform: uppercase; }

/* ============================================================================
   BUTTONS
   ========================================================================== */

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--s-2);
  min-height: var(--tap);
  padding: 0 var(--s-5);
  border-radius: var(--r-md);
  border: var(--hair) solid transparent;
  background: var(--ground-4);
  color: var(--ink);
  font-weight: 700;
  font-size: var(--t-body);
  cursor: pointer;
  text-decoration: none;
  transition: transform var(--d-fast) var(--ease-out),
              background var(--d-fast) var(--ease-out);
}
.btn:active { transform: scale(.97); }
.btn--primary { background: var(--signal); color: var(--signal-ink); }
.btn--ghost   { background: transparent; border-color: var(--line-strong); color: var(--ink); }
.btn--danger  { background: transparent; border-color: var(--stop); color: var(--stop); }
.btn--block   { width: 100%; }
.btn:disabled { opacity: .45; cursor: not-allowed; }

.actions {
  position: sticky; bottom: 0;
  display: grid; grid-template-columns: 1fr auto auto; gap: var(--s-2);
  padding: var(--s-3) var(--s-4) calc(var(--safe-b) + var(--s-3));
  margin: 0 calc(var(--s-4) * -1);
  background: linear-gradient(to top, var(--ground-2) 62%, transparent);
}

/* ============================================================================
   MODAL SURFACES (filters, rig profile, layers, offline, settings)
   ========================================================================== */

.modal {
  position: fixed; inset: 0;
  z-index: var(--z-modal);
  display: grid;
  align-items: end;
  justify-items: center;
  background: var(--scrim);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  animation: fade var(--d-base) var(--ease-out);
}
.modal[hidden] { display: none; }
@keyframes fade { from { opacity: 0; } }

.modal__panel {
  width: 100%;
  max-width: 720px;
  max-height: 92vh;
  display: flex;
  flex-direction: column;
  background: var(--ground-2);
  border: var(--hair) solid var(--line-strong);
  border-bottom: 0;
  border-radius: var(--r-xl) var(--r-xl) 0 0;
  box-shadow: var(--shadow-3);
  animation: rise var(--d-slow) var(--ease-out);
}
@keyframes rise { from { transform: translateY(3%); opacity: .6; } }

.modal__head {
  flex: none;
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-3);
  padding: var(--s-4) var(--s-4) var(--s-3);
  border-bottom: var(--hair) solid var(--line);
}
.modal__title {
  font-family: var(--font-display);
  font-size: var(--t-title); font-weight: 700;
  letter-spacing: .01em;
}
.modal__body {
  flex: 1; min-height: 0; overflow-y: auto;
  padding: var(--s-4);
  overscroll-behavior: contain;
}
.modal__foot {
  flex: none;
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-2);
  padding: var(--s-3) var(--s-4) calc(var(--safe-b) + var(--s-4));
  border-top: var(--hair) solid var(--line);
}

/* Form controls */
.field { display: grid; gap: var(--s-2); margin-bottom: var(--s-5); }
.field__lab {
  font-family: var(--font-display); font-size: var(--t-meta); font-weight: 700;
  letter-spacing: var(--track-label); text-transform: uppercase; color: var(--ink-2);
}
.field__hint { font-size: var(--t-meta); color: var(--ink-3); line-height: 1.4; }

.input, .select {
  min-height: var(--tap);
  padding: 0 var(--s-3);
  border: var(--hair) solid var(--line-strong);
  border-radius: var(--r-md);
  background: var(--ground-1);
  color: var(--ink);
  font-size: var(--t-body);
  width: 100%;
}
.input--data { font-family: var(--font-data); font-feature-settings: var(--num-tabular); }

/* Segmented control */
.seg {
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
  gap: var(--hair);
  padding: var(--hair);
  background: var(--line);
  border-radius: var(--r-md);
  overflow: hidden;
}
.seg__opt {
  min-height: var(--tap-sm);
  border: 0; cursor: pointer;
  background: var(--ground-1);
  color: var(--ink-2);
  font-size: var(--t-meta); font-weight: 700;
  display: grid; place-items: center; gap: 2px;
  padding: var(--s-2) var(--s-1);
}
.seg__opt[aria-pressed='true'] { background: var(--signal); color: var(--signal-ink); }

/* Toggle rows */
.toggle {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--gap-block);
  min-height: var(--tap);
  padding: var(--s-3) 0;
  width: 100%;
  border: 0; background: none; cursor: pointer; text-align: left;
}
.toggle + .toggle { border-top: var(--hair) solid var(--line); }
/* Name over hint, not name-then-hint. This was a bare inline span, so the two
   ran together with no separator at all — "Your rigVan · 20 ft". */
.toggle__txt {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.toggle__name {
  font-size: var(--t-body); color: var(--ink); font-weight: 600;
  line-height: var(--lh-snug);
}
.toggle__hint {
  font-size: var(--t-meta); color: var(--ink-3); line-height: 1.35;
  text-wrap: pretty;
}
.toggle__sw {
  flex: none; width: 50px; height: 30px;
  border-radius: var(--r-full);
  background: var(--ground-4);
  border: var(--hair) solid var(--line-strong);
  position: relative;
  transition: background var(--d-fast) var(--ease-out);
}
.toggle__sw::after {
  content: ''; position: absolute; top: 3px; left: 3px;
  width: 22px; height: 22px; border-radius: var(--r-full);
  background: var(--ink-2);
  transition: transform var(--d-base) var(--ease-spring), background var(--d-fast);
}
.toggle[aria-pressed='true'] .toggle__sw { background: var(--signal); border-color: var(--signal); }
.toggle[aria-pressed='true'] .toggle__sw::after { transform: translateX(20px); background: var(--signal-ink); }

/* Range with a live data read-out */
.range { display: grid; grid-template-columns: 1fr 78px; gap: var(--s-3); align-items: center; }
.range input[type='range'] { width: 100%; accent-color: var(--signal); height: var(--tap-sm); }
.range__out {
  font-family: var(--font-data); font-feature-settings: var(--num-tabular); font-size: var(--t-data); font-weight: 700;
  text-align: right; color: var(--ink);
}

/* ============================================================================
   LAYER LEGEND
   ========================================================================== */

.legend { display: grid; gap: var(--s-2); }
.legend__row { display: flex; align-items: center; gap: var(--s-3); font-size: var(--t-meta); }
.legend__sw {
  width: 22px; height: 14px; border-radius: 3px; flex: none;
  border: var(--hair) solid rgba(255,255,255,.28);
}
.legend__name { color: var(--ink-2); }
.legend__note { color: var(--ink-3); margin-left: auto; font-size: var(--t-micro); }

/* ============================================================================
   OFFLINE MANAGER
   ========================================================================== */

.region {
  display: grid; grid-template-columns: 1fr auto; gap: var(--s-3);
  align-items: center;
  padding: var(--s-3) 0;
}
.region + .region { border-top: var(--hair) solid var(--line); }
.region__name { font-weight: 600; }
.region__meta { font-family: var(--font-data); font-feature-settings: var(--num-tabular); font-size: var(--t-micro); color: var(--ink-3); }
.progress {
  height: 4px; border-radius: var(--r-full); background: var(--ground-4); overflow: hidden;
  margin-top: 6px;
}
.progress__fill { height: 100%; background: var(--signal); transition: width var(--d-base) linear; }

/* ============================================================================
   TOAST + STATUS
   ========================================================================== */

.toasts {
  position: fixed;
  left: 50%; transform: translateX(-50%);
  bottom: calc(var(--sheet-h, 194px) + var(--s-4));
  z-index: var(--z-toast);
  display: grid; gap: var(--s-2);
  width: min(560px, calc(100% - var(--s-8)));
  pointer-events: none;
  transition: bottom var(--d-base) var(--ease-out);
}
.toast {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-md);
  background: var(--ground-4);
  border: var(--hair) solid var(--line-strong);
  box-shadow: var(--shadow-2);
  font-size: var(--t-meta);
  pointer-events: auto;
  animation: toastin var(--d-base) var(--ease-out);
}
@keyframes toastin { from { transform: translateY(8px); opacity: 0; } }
.toast--warn { border-color: var(--warn); }
.toast--stop { border-color: var(--stop); }
.toast__act { margin-left: auto; color: var(--signal); font-weight: 700; background: none; border: 0; cursor: pointer; }

/* Offline banner */
.offline-flag {
  display: none;
  align-items: center; gap: var(--s-2);
  padding: var(--s-2) var(--s-4);
  background: var(--warn-wash);
  border-bottom: var(--hair) solid var(--warn);
  color: var(--warn);
  font-size: var(--t-meta); font-weight: 700;
}
body[data-online='false'] .offline-flag { display: flex; }

/* ============================================================================
   EMPTY / LOADING STATES
   ========================================================================== */

.empty {
  display: grid; place-items: center; gap: var(--s-3);
  padding: var(--s-10) var(--s-5);
  text-align: center;
}
.empty__ico { color: var(--ink-3); }
.empty__head { font-family: var(--font-display); font-size: var(--t-title); font-weight: 700; }
.empty__txt { font-size: var(--t-meta); color: var(--ink-3); max-width: 34ch; line-height: 1.5; }

.skel {
  border-radius: var(--r-lg);
  background: linear-gradient(100deg, var(--ground-3) 30%, var(--ground-4) 50%, var(--ground-3) 70%);
  background-size: 300% 100%;
  animation: shimmer 1.4s linear infinite;
  height: 86px;
}
@keyframes shimmer { to { background-position: -300% 0; } }

/* ============================================================================
   MAP MARKERS (DOM overlays for the selected spot + user position)
   ========================================================================== */

.me {
  width: 22px; height: 22px; border-radius: var(--r-full);
  background: var(--signal);
  border: 3px solid var(--ground-2);
  box-shadow: 0 0 0 1px var(--signal), 0 2px 8px rgba(0,0,0,.5);
}
.me__halo {
  position: absolute; inset: -13px;
  border-radius: var(--r-full);
  background: var(--signal-wash);
  animation: halo 2.6s var(--ease-in-out) infinite;
}
@keyframes halo { 50% { transform: scale(1.5); opacity: .25; } }

/* Heading cone, shown when the device reports a bearing */
.me__cone {
  position: absolute; left: 50%; top: 50%;
  width: 0; height: 0;
  border-left: 13px solid transparent;
  border-right: 13px solid transparent;
  border-bottom: 26px solid var(--signal-wash);
  transform-origin: 50% 100%;
  transform: translate(-50%, -100%) rotate(var(--heading, 0deg));
}

/* ============================================================================
   RESPONSIVE — tablet / desktop becomes a side panel, map stays dominant
   ========================================================================== */

@media (min-width: 860px) {
  /* No touch, no swipe: a horizontally scrolling row in a fixed panel simply
     hides whatever does not fit. There is vertical room here, so wrap. */
  .chips {
    flex-wrap: wrap;
    overflow-x: visible;
    row-gap: var(--gap-tight);
    padding-bottom: var(--gap-tight);
  }

  .sheet {
    top: calc(var(--safe-t) + 76px);
    bottom: var(--s-4);
    left: var(--s-4);
    right: auto;
    width: 420px;
    height: auto !important;
    max-width: none;
    margin: 0;
    border-radius: var(--r-xl);
    border: var(--hair) solid var(--line-strong);
  }
  .sheet__grip { display: none; }
  .sheet[data-detent='peek'] .sheet__body { overflow-y: auto; }
  .topbar { left: calc(var(--safe-l) + var(--s-4)); width: 420px; right: auto; }
  .maprail { bottom: calc(var(--safe-b) + var(--s-4)); }
  .scalebar { left: calc(468px + var(--s-4)); bottom: calc(var(--safe-b) + var(--s-4)); }
  .attrib  { bottom: calc(var(--safe-b) + var(--s-2)); }
  .toasts  { bottom: var(--s-5); left: calc(50% + 220px); }
  .modal { align-items: center; }
  .modal__panel { border-radius: var(--r-xl); border-bottom: var(--hair) solid var(--line-strong); max-height: 84vh; }
  .modal__foot { padding-bottom: var(--s-4); }
}

@media (min-width: 1280px) {
  .sheet { width: 470px; }
  .topbar { width: 470px; }
  .scalebar { left: calc(518px + var(--s-4)); }
}

/* Landscape phone: the sheet must never eat the map. */
@media (max-height: 520px) and (orientation: landscape) and (max-width: 859px) {
  .sheet { left: auto; right: 0; width: min(52%, 400px); top: 0; border-radius: var(--r-xl) 0 0 0; height: 100% !important; }
  .sheet__grip { display: none; }
  .topbar { right: auto; width: min(46%, 360px); }
  .maprail { bottom: calc(var(--safe-b) + var(--s-3)); right: calc(min(52%, 400px) + var(--s-3)); }
  .scalebar { bottom: calc(var(--safe-b) + var(--s-3)); }
}

/* Printing a spot page — a real use case at a trailhead kiosk. */
@media print {
  .topbar, .maprail, .sheet__grip, .actions, .scalebar, .toasts { display: none !important; }
  #map { position: relative; height: 40vh; }
  .sheet { position: relative; height: auto !important; box-shadow: none; }
}

/* ============================================================================
   FIRST-RUN COACH
   ----------------------------------------------------------------------------
   No backdrop and no scrim: the map behind stays visible and usable, which is
   the whole point — you are being shown a control in its own context, not read
   a slideshow about one. Only the ring and the caption are ours.
   ========================================================================== */

.coach {
  position: fixed;
  inset: 0;
  z-index: 60;
  pointer-events: none;    /* everything except our own two children */
}

.coach__ring {
  position: fixed;
  border: 2px solid var(--signal);
  border-radius: var(--r-lg);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--signal) 28%, transparent);
  transition: top var(--d-base) var(--ease-out), left var(--d-base) var(--ease-out),
              width var(--d-base) var(--ease-out), height var(--d-base) var(--ease-out);
}

.coach__card {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  width: min(340px, calc(100vw - 24px));
  pointer-events: auto;
  padding: var(--s-4);
  border: var(--hair) solid var(--line-strong);
  border-radius: var(--r-lg);
  background: var(--ground-2);
  box-shadow: var(--shadow-3);
  transition: top var(--d-base) var(--ease-out);
}
.coach__card:focus { outline: none; }
.coach__card:focus-visible { outline: 2px solid var(--signal); outline-offset: 2px; }

.coach__title {
  margin: 0 0 var(--s-2);
  font-family: var(--font-display);
  font-size: var(--t-title);
  font-weight: 700;
  color: var(--ink);
}
.coach__body {
  margin: 0;
  font-size: var(--t-body);
  line-height: 1.5;
  color: var(--ink-2);
}
.coach__foot {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  margin-top: var(--s-4);
}
.coach__count {
  flex: 1;
  font-family: var(--font-data); font-feature-settings: var(--num-tabular);
  font-size: var(--t-micro);
  color: var(--ink-3);
  letter-spacing: var(--track-micro);
  text-transform: uppercase;
}
.coach__skip {
  border: 0; background: none; cursor: pointer;
  min-height: var(--tap-sm); padding: 0 var(--s-2);
  font-family: inherit; font-size: var(--t-meta); font-weight: 600;
  color: var(--ink-3);
}
.coach__skip[hidden] { display: none; }
.coach__next { min-height: var(--tap-sm); padding: 0 var(--s-5); }

/* A ring that pulses is an animation on top of a map someone may be driving
   beside. Respect the setting and simply stop moving. */
@media (prefers-reduced-motion: reduce) {
  .coach__ring, .coach__card { transition: none; }
}

/* ============================================================================
   NOTICE — an aside that is neither an error nor a toast
   ========================================================================== */

.notice {
  margin-bottom: var(--s-4);
  padding: var(--s-4);
  border: var(--hair) solid var(--line-strong);
  border-radius: var(--r-lg);
  background: var(--ground-2);
}
.notice__head {
  display: flex; align-items: center; gap: var(--s-2);
  color: var(--ink);
}

.steps {
  margin: 0;
  padding-left: 1.25em;
  display: grid;
  gap: var(--s-2);
  font-size: var(--t-meta);
  line-height: 1.45;
  color: var(--ink-2);
}
.steps > li::marker { color: var(--signal); font-weight: 700; }

/* ============================================================================
   GROUND VIEWS
   ----------------------------------------------------------------------------
   A horizontal strip rather than a grid: these are supporting evidence for the
   road grade above, not a gallery, and a grid would give them more of the
   screen than their reliability deserves.
   ========================================================================== */

.views {
  display: flex;
  gap: var(--s-2);
  overflow-x: auto;
  scrollbar-width: none;
  scroll-snap-type: x proximity;
  padding-bottom: var(--s-1);
}
.views::-webkit-scrollbar { display: none; }

.view {
  position: relative;
  flex: none;
  width: 172px;
  scroll-snap-align: start;
  border: var(--hair) solid var(--line-strong);
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--ground-1);
  text-decoration: none;
  color: inherit;
}
.view__img {
  display: block;
  width: 100%;
  height: 116px;
  object-fit: cover;
  background: var(--ground-2);
}
.view__meta {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-2);
  padding: 6px var(--s-2) 7px;
}
.view__when {
  font-family: var(--font-data); font-feature-settings: var(--num-tabular);
  font-size: var(--t-meta);
  font-weight: 700;
  color: var(--ink);
}
.view__src {
  font-size: var(--t-micro);
  color: var(--ink-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The flag is a word, not a tint — the night theme collapses every hue toward
   red, so a color-coded "this one is old" would vanish exactly when someone is
   deciding whether to commit to a road in the dark. */
.view__flag {
  position: absolute;
  top: var(--s-2);
  left: var(--s-2);
  padding: 2px 7px;
  border-radius: var(--r-full);
  background: var(--warn);
  color: var(--signal-ink);
  font-size: var(--t-micro);
  font-weight: 700;
  letter-spacing: var(--track-micro);
  text-transform: uppercase;
}
.view--stale .view__img { opacity: .82; }

/* ============================================================================
   FIELD ACTIONS — Select all / Clear beside a group label
   ========================================================================== */

.field__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-3);
}
.field__acts { display: inline-flex; gap: var(--s-1); flex: none; }

.linkbtn {
  border: 0;
  background: none;
  cursor: pointer;
  font-family: inherit;
  font-size: var(--t-meta);
  font-weight: 700;
  color: var(--signal);
  /* Full tap height without the visual weight of a button: the label it sits
     beside is small, and two chunky buttons there would outrank the chips
     they act on. */
  min-height: var(--tap-sm);
  padding: 0 var(--s-2);
}
.linkbtn:active { opacity: .7; }

/* ============================================================================
   NEAREST MATCH — what an empty list should say instead of "nothing here"
   ========================================================================== */

.nearest__seek {
  margin: 0 0 var(--gap-block);
  font-size: var(--t-meta);
  color: var(--ink-3);
}
.nearest__line {
  margin: 0 0 var(--gap-block);
  font-size: var(--t-body);
  line-height: var(--lh-body);
  color: var(--ink-2);
  text-wrap: balance;
}
.nearest__line strong { color: var(--ink); font-weight: 700; }
.nearest__from { color: var(--ink-3); }

/* ============================================================================
   SUMMARY BUBBLES — the answer before the reading
   ========================================================================== */

.bubbles {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: var(--gap-block);
}

.bubble {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 28px;
  padding: 0 10px;
  border-radius: var(--r-full);
  background: var(--ground-3);
  border: var(--hair) solid var(--line-strong);
  color: var(--ink-2);
  font-size: var(--t-meta);
  font-weight: 600;
  white-space: nowrap;
}

/* Tone is carried by the border and the text, never by fill alone: the night
   theme collapses every hue toward red, and these sit at the top of the
   screen where a misread is most expensive. Each one also has an icon and a
   word, so the color is the third signal rather than the only one. */
/* An absence is a fact worth stating and never worth shouting. */
.bubble--dim {
  background: transparent;
  border-style: dashed;
  border-color: var(--line-strong);
  color: var(--ink-3);
  font-weight: 500;
}
.bubble--go   { color: var(--go);   border-color: var(--go); }
.bubble--warn { color: var(--warn); border-color: var(--warn); }
.bubble--stop { color: var(--stop); border-color: var(--stop); }
