/* Shared browse-map stylesheet — the redesigned map view from
   design_handoff/marketplace-browse-navigation-redesign 2 (Browse
   Listings.dc.html + MAP_HANDOFF.md).

   Loaded by BOTH surface families:
     · buyer explore/browse (explore layout + buying/browse head) — alongside
       marketing/pages/explore.css
     · broker browse (/brokering/practices?view=map) — alongside the Tailwind
       bundle. Load AFTER the bundle so these rules win ties against the old
       broker .map-value-pill styles.

   Colors are EXACT design hexes, never brand tokens — marketing explore.css
   redefines --color-brand-green to near-black for its buttons, which turned
   the pills black when this file used the token. Keep every selector map-scoped (.explore-map-*,
   .map-value-pill*, .explore-focus-marker*) — this file must not restyle
   page chrome on either surface. */

/* ════════════════════════════════════════════════════════════════
   MAP VIEW (?view=map) — Browse Listings redesign
   Source of truth: design_handoff/marketplace-browse-navigation-
   redesign 2/project/Browse Listings.dc.html + MAP_HANDOFF.md.
   Pill class names match what the shared explore-map Stimulus
   controller renders. brokering.css is not
   loaded on the explore layout, so everything is self-contained.
   ════════════════════════════════════════════════════════════════ */
@keyframes exDockRise {
  from { opacity: 0; transform: translate(-50%, 14px); }
  to   { opacity: 1; transform: translate(-50%, 0); }
}
@keyframes exTipIn {
  from { opacity: 0; transform: translate(-50%, calc(-100% + 4px)); }
  to   { opacity: 1; transform: translate(-50%, -100%); }
}
@keyframes exFadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* ── Layout: 320px sidebar + map, 620px panel (page scrolls on overflow) ── */
.explore-map-layout {
  display: flex;
  gap: 12px;
  height: 620px;
  margin-bottom: 24px;
}

/* ── Sidebar ─────────────────────────────────────────────────────── */
.explore-map-sidebar {
  flex: 0 0 320px;
  min-height: 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: #fff;
  border: 1px solid #e6eae8;
  border-radius: 14px;
  padding: 0;
}

/* Sticky "Selected" bar — tops the list while a listing is focused */
.explore-map-selected-bar {
  flex: none;
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 9px 12px;
  border-bottom: 1px solid rgba(20, 55, 42, .12);
  background: #e8f6ee;
  animation: exFadeIn .2s ease both;
}
.explore-map-selected-bar.hidden { display: none; }
.explore-map-selected-bar__icon {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 7px;
  background: #205e3a;
  color: #fff;
}
.explore-map-selected-bar__text { min-width: 0; flex: 1; display: flex; flex-direction: column; }
.explore-map-selected-bar__eyebrow {
  font-size: var(--text-2xs);
  font-weight: var(--fw-bold);
  letter-spacing: .05em;
  text-transform: uppercase;
  color: #2f7b5a;
}
.explore-map-selected-bar__label {
  font-size: var(--text-sm);
  font-weight: var(--fw-bold);
  color: #0c3e26;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.explore-map-selected-bar__clear {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 7px;
  border: 1px solid rgba(32, 94, 58, .28);
  background: #fff;
  color: #1b4d3a;
  cursor: pointer;
}

/* List header — "N in view · Follows the map" */
.explore-map-sidebar__header {
  flex: none;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 13px;
  border-bottom: 1px solid rgba(20, 55, 42, .1);
}
.explore-map-sidebar__count { font-size: var(--text-sm); font-weight: var(--fw-bold); color: #12241c; }
.explore-map-sidebar__hint { margin-left: auto; font-size: var(--text-xs); color: #9aa4a0; }
.explore-map-sidebar__hint.hidden { display: none; }

/* Sort pinned to the header's right edge -- the top-right of the LISTING COLUMN,
   which is where broker's sits. Its trigger styling comes from browse_v5.css via the
   shared .browse-toolbar__sort class. */
.explore-map-sidebar__sort { margin-left: auto; }

/* The scroller, mirroring broker's .brokering-browse-split__scroll: it holds the
   rows AND the pager, so the pager scrolls away with the cards instead of hanging
   over them. */
.explore-map-sidebar__scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}

.explore-map-sidebar__rows {
  padding: 9px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.explore-map-sidebar__more {
  padding: 8px;
  text-align: center;
  font-size: var(--text-xs);
  color: #8a938e;
}
.explore-map-sidebar__more.hidden { display: none; }

/* Numbered pager for the results list. Same row as broker's .explore-map-pager
   below, down to the padding: no band and no hairline, because it now sits inside
   the scroll area rather than forming the column's footer. Themes across all three
   modes for free, having no colour of its own. */
.explore-map-sidebar__pager {
  flex: none;
  display: flex;
  align-items: center;
  /* Label left, pages right -- the design's pager row, and the same shape as the
     grid's shared partial. It used to centre a bare row of buttons with no label,
     which is what made the split view's footer look nothing like the design. */
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  padding: 14px 2px 2px;
}
.explore-map-sidebar__pager.hidden { display: none; }

/* Broker's map sidebar uses .explore-map-pager as its container and had NO rule at
   all -- its pager was a bare left-aligned flow with the label wedged against the
   buttons. Both containers get the design's row; only the buyer sidebar keeps the
   hairline and white band, which separate it from its own scroll area. */
.explore-map-pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  padding: 14px 2px 2px;
}

.explore-map-pager.hidden { display: none; }

.explore-map-pager__label {
  font-size: var(--text-base, 0.8125rem);
  color: var(--base-text-tertiary, #767676);
}

.explore-map-pager__pages {
  display: flex;
  align-items: center;
  gap: 6px;
}
/* The map sidebar's pager is rendered by the Stimulus controller rather than the
   shared partial (it pages within the viewport), so it matches .browse-pager__btn
   by hand: 30px circles, the current page filled dark. It used to be bordered
   9px rects in a different green, which is what made the map sidebar look like a
   different product from the grid below it. */
.explore-map-pager__page {
  min-width: 30px;
  height: 30px;
  padding: 0 6px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: 999px;
  background: var(--browse-surface, #F7F7F7);
  color: var(--base-text-secondary, #484848);
  font-size: var(--text-base, 0.8125rem);
  font-weight: var(--fw-medium, 500);
  cursor: pointer;
  transition: background-color 120ms linear;
}

.explore-map-pager__page:hover { background: var(--base-bg-hover, #EFEFEF); }

.explore-map-pager__page.is-current {
  background: #222222;
  color: #fff;
  font-weight: var(--fw-semibold, 600);
  cursor: default;
}

.explore-map-pager__gap {
  min-width: 20px;
  text-align: center;
  color: var(--base-text-tertiary, #A8A8A8);
  font-size: var(--text-base, 0.8125rem);
}

.explore-map-sidebar__empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 40px 16px;
  text-align: center;
  font-size: var(--text-base);
  color: var(--base-text-tertiary, #737373);
}

/* ── Sidebar row ─────────────────────────────────────────────────── */
.explore-map-listing-row {
  position: relative;
  flex: none;
  border: 1px solid #e6eae8;
  background: #fff;
  border-radius: 11px;
  padding: 11px 12px;
  cursor: pointer;
  box-shadow: 0 1px 2px rgba(16, 40, 28, .04);
  transition: background .15s, border-color .15s, box-shadow .15s;
}
.explore-map-listing-row.hidden { display: none; }
.explore-map-listing-row.is-highlighted {
  background: #f2faf5;
  border-color: #bfe0cd;
}
.explore-map-listing-row.is-selected {
  background: #e8f6ee;
  border-color: #205e3a;
  box-shadow: 0 0 0 2px rgba(32, 94, 58, .25);
}
.explore-map-listing-row__rail {
  display: none;
  position: absolute;
  left: 0;
  top: 11px;
  bottom: 11px;
  width: 3px;
  border-radius: 0 3px 3px 0;
  background: #205e3a;
}
.explore-map-listing-row.is-selected .explore-map-listing-row__rail { display: block; }

.explore-map-listing-row__top { display: flex; align-items: flex-start; gap: 8px; }
.explore-map-listing-row__main { flex: 1; min-width: 0; }

.explore-map-listing-row__badges {
  display: flex;
  gap: 5px;
  flex-wrap: wrap;
  margin-bottom: 6px;
}
.explore-map-listing-row__badges .explore-badge {
  height: 18px;
  padding: 0 7px;
  font-size: var(--text-2xs);
}

.explore-map-listing-row__title-row { display: flex; align-items: center; gap: 5px; color: #12241c; }
.explore-map-listing-row__pin { flex: none; display: inline-flex; color: #2f7b5a; }
.explore-map-listing-row__title {
  font-size: var(--text-base);
  font-weight: var(--fw-bold);
  letter-spacing: -.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.explore-map-listing-row__sub {
  font-size: var(--text-xs);
  color: var(--base-text-tertiary, #737373);
  margin: 2px 0 0 18px;
}

.explore-map-listing-row__save {
  flex: none;
  width: 27px;
  height: 27px;
  border-radius: 8px;
  border: 1px solid #e6eae8;
  background: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  color: #9aa4a0;
}
.explore-map-listing-row__save:hover { box-shadow: 0 2px 8px rgba(0, 0, 0, .12); }
.explore-map-listing-row__save .explore-card__save-icon { width: 14px; height: 14px; }
.explore-map-listing-row__save[data-saved="true"] { color: #dc2626; }
.explore-map-listing-row__save[data-saved="true"] .explore-card__save-icon svg,
.explore-map-listing-row__save[data-saved="true"] svg { fill: #dc2626; stroke: #dc2626; }

.explore-map-listing-row__footer {
  margin-top: 9px;
  padding-top: 8px;
  border-top: 1px solid rgba(20, 55, 42, .08);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.explore-map-listing-row__price { display: flex; align-items: baseline; gap: 5px; margin: 0; }
.explore-map-listing-row__amount {
  font-size: var(--text-lg);
  font-weight: var(--fw-bold);
  letter-spacing: -.02em;
  color: #0c3e26;
}
.explore-map-listing-row__stat-label {
  font-size: var(--text-2xs);
  font-weight: var(--fw-semibold);
  color: rgba(12, 62, 38, .6);
}
.explore-map-listing-row__stats { display: flex; gap: 10px; }
.explore-map-listing-row__stat { display: flex; flex-direction: column; }
.explore-map-listing-row__stat .explore-map-listing-row__stat-label {
  font-size: var(--text-2xs);
  font-weight: var(--fw-bold);
  color: #9aa4a0;
  text-transform: uppercase;
  letter-spacing: .04em;
}
.explore-map-listing-row__stat strong { font-size: var(--text-xs); font-weight: var(--fw-bold); color: #171717; }

/* ── Map panel + chrome ──────────────────────────────────────────── */
.explore-map-panel {
  flex: 1;
  min-width: 0;
  position: relative;
  overflow: hidden;
  border: 1px solid #e6eae8;
  border-radius: 14px;
  background: #f5f1e8;
  padding: 0;

  /* ── The pin encoding, defined ONCE ──────────────────────────────────────
     The map has two kinds of price pin, and the legend has a swatch for each. They
     have to look identical or the legend lies, and until now they only matched by
     coincidence: pill and swatch each hardcoded `var(--browse-accent)` separately, so
     either one could be changed without the other. These tokens are the single
     definition both read; the panel is their home because it is the common ancestor
     of the pills and the legend on all four surfaces that render this map.

     The pairing is the v5 accent: asking price FILLED, annual revenue OUTLINED.
     🚨 Tried near-black (#181818 filled / #FFFFFF outlined, which is what the design
     prototype shows) and REVERTED on review, 2026-09-01: on our map, with our tile
     style and our card set, it did not look good. Do not re-apply it from the
     prototype without asking. The accent is what ships.
     Literal fallbacks on purpose: `--browse-accent` and `--browse-ink-soft` are
     pinned on the Browse roots, but this panel renders on four surfaces and a bare
     var() would drop the whole declaration wherever one is not in scope. */
  --map-pin-asking-bg: var(--browse-accent, #0EA184);
  --map-pin-asking-ink: #FFFFFF;
  --map-pin-asking-border: var(--browse-accent, #0EA184);
  --map-pin-revenue-bg: #FFFFFF;
  --map-pin-revenue-ink: var(--browse-ink-soft, #0A6E5C);
  /* The white pill needs an edge or it disappears against light map tiles, and the
     accent is what makes it read as the filled pin's sibling. The ⓘ copy calls this
     variant "outlined", which is exactly what it is. */
  --map-pin-revenue-border: var(--browse-accent, #0EA184);
}

.explore-map-canvas {
  position: absolute;
  inset: 0;
  z-index: 1;
}

/* Hovering a deck.gl listing dot: the dots aren't real map features, so the
   map keeps its grab cursor — force a pointer while one is hovered. */
.explore-map-canvas.is-dot-hover,
.explore-map-canvas.is-dot-hover .gm-style div,
.explore-map-canvas.is-dot-hover canvas {
  cursor: pointer !important;
}

/* Legend — top-left. STACKED, one row per marker: the map draws three of them and a
   single-line pill could only name two without running half the width of the panel.
   (The design's one-liner assumes every listing has an asking price. Ours do not.) */
.explore-map-legend {
  position: absolute;
  top: 12px;
  left: 12px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  padding: 9px 11px;
  border-radius: 12px;
  background: rgba(255, 255, 255, .95);
  border: 1px solid rgba(20, 55, 42, .12);
  box-shadow: 0 2px 8px rgba(16, 40, 28, .1);
  z-index: 30;
  font-size: var(--text-xs);
  color: #3f4a45;
  max-width: 190px;
}

.explore-map-legend__title {
  margin-bottom: 1px;
  font-size: var(--text-2xs);
  font-weight: var(--fw-bold);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: #8a938e;
}

/* Each swatch IS its pin: filled accent for asking price, outlined for annual
   revenue. Same 22x15 as the map's pill, so the key is checkable against the map. */
/* The swatches ARE the pins, so they read the same tokens the pills do (declared on
   .explore-map-panel). Never restate a colour here: a swatch that carries its own
   value is a legend that can go out of date without anybody noticing. */
.explore-map-legend__swatch {
  flex: none;
  width: 22px;
  height: 15px;
  border-radius: 99px;
  border: 1.5px solid transparent;
}
.explore-map-legend__swatch.is-asking {
  background: var(--map-pin-asking-bg, #0EA184);
  border-color: var(--map-pin-asking-border, #0EA184);
}
.explore-map-legend__swatch.is-revenue {
  background: var(--map-pin-revenue-bg, #FFFFFF);
  border-color: var(--map-pin-revenue-border, #0EA184);
}
.explore-map-legend__row {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: var(--text-xs);
  color: #6f7a74;
}
/* The dot IS the map's unpriced dot, at the same grey (#9A9A9A). No pill swatches:
   a 22x15 white rounded rect next to a label is a switch, not a key. */
.explore-map-legend__dot {
  flex: none;
  width: 7px;
  height: 7px;
  border-radius: 99px;
  background: #9a9a9a;
}

/* The swatch IS the ring: a circle at the ring's own stroke and fill, so the
   key is checkable against the map the way the pin swatches are. */
.explore-map-legend__ring {
  flex: none;
  width: 14px;
  height: 14px;
  border-radius: 99px;
  border: 1.5px solid #16a34a;
  background: rgba(22, 163, 74, .12);
}
/* A filled dot by default. `.is-ring` makes it a hollow circle at that preference's
   own stroke and fill, matching .explore-map-legend__ring: only a regional selection
   actually draws rings, so only then should the swatch claim to key one. */
.explore-map-legend__pref.is-national .explore-map-legend__pref-dot {
  background: #6f7a74;
}/* 🚨 The ORIGINAL popover, restored and still in use. Public explore and buyer browse
   are out of scope on this branch, so they keep the explainer they have always had;
   only the broker map (the surface that passes `coverage`) takes the rebuilt one
   below. See the split in explore/_map_panel.html.erb. Delete this block the day
   those two surfaces move over. */
.explore-map-legend__popover {
  display: none;
  position: absolute;
  top: 20px;
  left: -10px;
  width: 184px;
  background: #12241c;
  color: #fff;
  border-radius: 8px;
  padding: 8px 10px;
  font-size: var(--text-xs);
  line-height: 1.45;
  font-weight: var(--fw-medium);
  letter-spacing: normal;
  text-transform: none;
  box-shadow: 0 8px 24px rgba(16, 40, 28, .28);
  z-index: 60;
}
.explore-map-legend__popover strong { color: #fff; }
.explore-map-legend__info-icon:hover .explore-map-legend__popover,
.explore-map-legend__info-icon:focus-visible .explore-map-legend__popover { display: block; }

/* The legend's "What am I seeing?" panel.
   The shared `tooltip` controller wears this through its `classes` value, exactly as
   .ws-stage-pop does on the workspace board, so floating-ui keeps placement, flipping,
   clamping and the arrow and only the surface is ours.

   🚨 It is a LIGHT card, not the base .tooltip. That base is the dark grey pill for a
   one-line label gloss; this is a four-row key, and next to the Leads board's own
   explainer a black rectangle reads as a different product. Surface, radius and shadow
   are the same trio .ws-stage-pop uses.

   🚨 NOT named `.explore-map-tip`: that is taken, by the dark green card the map draws
   over a marker (further down this file). A panel carrying both would pick up that
   card's surface and type.

   Opacity and visibility are toggled rather than `display`, because display cannot
   transition and the base .tooltip's none/block flip makes the panel snap. */
.tooltip.explore-map-pop {
  width: 268px;
  max-width: calc(100vw - 32px);
  padding: 14px 16px 15px;
  background: var(--base-bg-low, #fff);
  color: var(--base-text, #222);
  border-radius: 16px;
  box-shadow: var(--ws-shadow-menu, 0 12px 40px rgba(0, 0, 0, .16));
  font-size: var(--text-xs);
  line-height: 1.45;
  text-align: left;
  white-space: normal;

  display: block;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transform: translateY(-4px);
  transition:
    opacity 140ms ease-out,
    transform 140ms ease-out,
    visibility 0s linear 140ms;
}
.tooltip.explore-map-pop.open {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transform: none;
  transition:
    opacity 140ms ease-out,
    transform 140ms ease-out,
    visibility 0s;
}
@media (prefers-reduced-motion: reduce) {
  .tooltip.explore-map-pop,
  .tooltip.explore-map-pop.open { transform: none; transition-duration: 1ms; }
}

/* .tooltip's own .arrow is an 8px square rotated 45deg behind the card, so it only
   needs this card's surface instead of the dark pill's. */
.tooltip.explore-map-pop .arrow { background-color: var(--base-bg-low, #fff); }

.explore-map-pop__title {
  margin: 0 0 9px;
  font-weight: var(--fw-semibold);
  color: var(--base-text, #222);
}
/* The swatch column is fixed so the four labels start on one edge; a 22px pill and a
   7px dot in the same flex row would otherwise stagger them. */
.explore-map-pop__row {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  margin-bottom: 7px;
  color: var(--base-text-secondary, #6f7a74);
}
.explore-map-pop__row > i {
  flex: none;
  width: 22px;
  margin-top: 2px;
}
.explore-map-pop__foot {
  margin: 10px 0 0;
  padding-top: 9px;
  border-top: 1px solid var(--base-border-tertiary, rgba(20, 55, 42, .12));
  color: var(--base-text-tertiary, #8a938e);
}

.explore-map-legend__info-row {
  color: #8a938e;
  font-size: var(--text-xs);
  cursor: help;
}
.explore-map-legend__info-row:focus-visible {
  outline: 2px solid var(--base-border-focus, #0EA184);
  outline-offset: 2px;
  border-radius: 4px;
}
.explore-map-legend__info-icon {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 15px;
  height: 15px;
  color: #8a938e;
  cursor: help;
  flex: none;
}

/* Custom zoom +/− — top-right. Sat at 54px while the Pins/Clusters toggle held
   the 12px slot above it; the toggle went with clustering, so this takes it. */
.explore-map-zoom {
  position: absolute;
  top: 12px;
  right: 12px;
  display: flex;
  flex-direction: column;
  border-radius: 10px;
  overflow: hidden;
  background: rgba(255, 255, 255, .96);
  border: 1px solid rgba(20, 55, 42, .12);
  box-shadow: 0 2px 8px rgba(16, 40, 28, .1);
  z-index: 30;
}
.explore-map-zoom button {
  width: 34px;
  height: 32px;
  border: none;
  background: transparent;
  color: #12402a;
  cursor: pointer;
  font-size: var(--text-lg);
  font-weight: var(--fw-bold);
  line-height: 1;
}
.explore-map-zoom button:first-child { border-bottom: 1px solid rgba(20, 55, 42, .1); }
.explore-map-zoom button:last-child { font-size: var(--text-xl); }

/* Reset view pill — top-center while drilled in / focused */
/* Reset view — top-center. A WHITE pill in the design, matching the legend and the
   count badge; it used to be a dark green slab, which read as the only shouted
   control on a deliberately quiet canvas. */
.explore-map-reset {
  position: absolute;
  top: 14px;
  left: 50%;
  transform: translateX(-50%);
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 14px;
  border-radius: 999px;
  background: #FFFFFF;
  color: #222222;
  border: none;
  box-shadow: 0 6px 20px rgb(0 0 0 / 0.10), 0 1px 3px rgb(0 0 0 / 0.04);
  font-size: var(--text-xs);
  font-weight: var(--fw-semibold);
  cursor: pointer;
  z-index: 35;
  animation: exFadeIn .2s ease both;
}
.explore-map-reset.hidden { display: none; }
.explore-map-reset__kbd { color: #B4B4B4; font-weight: var(--fw-semibold); }

/* Count badge — bottom-left. WHITE with grey text in the design, not the dark
   green slab this was; same pill geometry and shadow as the legend. */
.explore-map-count-badge {
  position: absolute;
  bottom: 16px;
  left: 16px;
  margin: 0;
  padding: 7px 13px;
  border-radius: 999px;
  background: #FFFFFF;
  color: #5E5E5E;
  font-size: var(--text-xs);
  font-weight: var(--fw-semibold);
  box-shadow: 0 6px 20px rgb(0 0 0 / 0.10), 0 1px 3px rgb(0 0 0 / 0.04);
  z-index: 30;
}

/* Viewport refetch indicator — top-center pill while the map loads a new area's
   markers (viewport loading only). Sits above the reset pill during the brief
   moment both could show. */
/* Loading indicator — an Airbnb-style pill of three bouncing dots, top-center of
   the map, shown while a viewport refetch or a results page is in flight. Sits on
   the always-light map canvas (same in every theme), so no dark override needed. */
.explore-map-loading {
  position: absolute;
  top: 12px;
  left: 50%;
  transform: translateX(-50%);
  display: inline-flex;
  align-items: center;
  height: 30px;
  padding: 0 16px;
  border-radius: 99px;
  background: #fff;
  box-shadow: 0 4px 14px rgba(12, 62, 38, .22);
  z-index: 45;
  animation: exFadeIn .15s ease both;
}
.explore-map-loading.hidden { display: none; }
.explore-map-loading__dots { display: inline-flex; align-items: center; gap: 5px; }
.explore-map-loading__dots span {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #0c3e26;
  animation: exDotBounce 1s ease-in-out infinite;
}
.explore-map-loading__dots span:nth-child(2) { animation-delay: .16s; }
.explore-map-loading__dots span:nth-child(3) { animation-delay: .32s; }
@keyframes exDotBounce {
  0%, 80%, 100% { transform: translateY(0); opacity: .35; }
  40% { transform: translateY(-5px); opacity: 1; }
}

/* While a page/viewport load is in flight the results list dims — paired with the
   loading pill it reads as "updating" without a jarring content swap. */
.explore-map-sidebar__rows.is-loading {
  opacity: .5;
  transition: opacity .18s ease;
}


/* Sidebar row skeletons — shown until the first viewport fetch fills the list.
   Theme-agnostic neutral tint so it reads on the light and dark sidebar alike. */
.explore-map-row-skeleton {
  height: 92px;
  margin: 0 0 10px;
  border-radius: 12px;
  background: rgba(127, 127, 127, .12);
}

/* ── Zoom scrubber — bottom-center hot-dots (Region → Street) ────── */
.explore-map-zoombar {
  position: absolute;
  bottom: 12px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 6px 12px;
  border-radius: 99px;
  background: rgba(255, 255, 255, .95);
  border: 1px solid rgba(20, 55, 42, .12);
  box-shadow: 0 2px 8px rgba(16, 40, 28, .1);
  z-index: 30;
}
.explore-map-zoombar__title {
  font-size: var(--text-2xs);
  font-weight: var(--fw-bold);
  letter-spacing: .05em;
  text-transform: uppercase;
  color: #8a938e;
}
.explore-map-zoombar__dots { display: flex; align-items: center; gap: 5px; }
.explore-map-zoombar__dot {
  width: 10px;
  height: 10px;
  border-radius: 99px;
  border: none;
  cursor: pointer;
  padding: 0;
  background: #d3ddd7;
  transition: background .15s, width .15s;
}
.explore-map-zoombar__dot.is-passed { background: #8bbfa2; }
.explore-map-zoombar__dot.is-active { width: 20px; background: #205e3a; }
.explore-map-zoombar__label {
  font-size: var(--text-xs);
  font-weight: var(--fw-bold);
  color: #12402a;
  min-width: 64px;
}
@media (max-width: 640px) {
  .explore-map-zoombar__title,
  .explore-map-zoombar__label { display: none; }
}

/* ── Price pills ─────────────────────────────────────────────────── */
.map-value-pill {
  position: absolute;
  transform: translate(-50%, -100%);
  transform-origin: bottom center;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  border: none;
  background: transparent;
  padding: 0;
  cursor: pointer;
  z-index: 600;
  transition: opacity .2s, transform .16s cubic-bezier(.34, 1.56, .64, 1);
}
.map-value-pill-label {
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  gap: 3px;
  height: 24px;
  padding: 0 9px;
  border-radius: 99px;
  font-size: var(--text-xs);
  font-weight: var(--fw-bold);
  letter-spacing: -.01em;
  white-space: nowrap;
  box-shadow: 0 2px 6px rgba(16, 40, 28, .2);
  transition: box-shadow .13s, background .13s, color .13s;
}
/* Asking price is a FILLED pin, annual revenue an OUTLINED one, both in the v5
   accent rather than the forest green this shipped with. Values come from the
   --map-pin-* tokens on `.explore-map-panel`, which the LEGEND swatches read too, so
   the key cannot drift from the map it describes. The near-black encoding the design
   prototype uses was tried here and reverted: see the note beside the tokens.
   🚨 Both the background AND the border are stated on BOTH variants, always: the base
   `.map-value-pill-label` in the broker and buyer Tailwind bundles carries
   `border: 1.5px solid var(--color-brand-green)` from the pre-v5 map, that token
   resolves differently per bundle, and the marketing bundle does not define it at all
   (so the declaration is dropped and /explore gets no border). Leaving any of the
   three properties unset is how one pin ended up with three looks. */
.map-value-pill--asking_price .map-value-pill-label {
  background: var(--map-pin-asking-bg, #0EA184);
  color: var(--map-pin-asking-ink, #FFFFFF);
  border: 1.5px solid var(--map-pin-asking-border, #0EA184);
}
.map-value-pill--annual_revenue .map-value-pill-label {
  background: var(--map-pin-revenue-bg, #FFFFFF);
  color: var(--map-pin-revenue-ink, #0A6E5C);
  border: 1.5px solid var(--map-pin-revenue-border, #0EA184);
}

/* Hover / peek / focus goes DEEPER than the accent, because the resting asking-price
   pin is already the accent: a hover that repainted it the same colour would be
   invisible on exactly the pins most people hover.
   Literal fallback on purpose: `--browse-ink-soft` is pinned on the Browse roots, but
   the map panel renders on four surfaces and a bare var() would drop the whole
   declaration wherever it is not in scope. */
.map-value-pill:hover .map-value-pill-label,
.map-value-pill.is-peeked .map-value-pill-label,
.map-value-pill.is-focused .map-value-pill-label {
  background: var(--browse-ink-soft, #0A6E5C);
  color: #ffffff;
  border-color: var(--browse-ink-soft, #0A6E5C);
}

/* The design's pin has no pointer: the pill sits centred on its coordinate. */
.map-value-pill-tail { display: none; }
.map-value-pill-saved {
  width: 6px;
  height: 6px;
  border-radius: 99px;
  background: #dc2626;
}
/* Diamond caret — carries the pill's own fill (and border for the revenue
   variant) so it reads as part of the pill, not a detached triangle. */
.map-value-pill-tail {
  width: 8px;
  height: 8px;
  margin-top: -5px;
  border: 0; /* neutralize the legacy triangle-tail rules in the broker Tailwind bundle */
  border-radius: 1px;
  box-shadow: none;
  background: transparent;
  transform: rotate(45deg);
}
/* Hidden today (`.map-value-pill-tail { display: none }` above), so these are inert,
   but pointed at the pin tokens anyway, because the whole point of the caret is to
   carry the pill's own fill. Left on the forest green it shipped with, re-enabling it
   would silently contradict the pill. */
.map-value-pill--asking_price .map-value-pill-tail {
  background: var(--map-pin-asking-bg, #0EA184);
}
.map-value-pill--annual_revenue .map-value-pill-tail {
  background: var(--map-pin-revenue-bg, #FFFFFF);
  border-right: 1.5px solid var(--map-pin-revenue-border, #0EA184);
  border-bottom: 1.5px solid var(--map-pin-revenue-border, #0EA184);
}
/* Peek/hover pops the pin — a clear "zoom + recolor" cue when a sidebar row (or
   the pin itself) is hovered, the Airbnb behavior. !important because the SHARED
   base .map-value-pill lives in the Tailwind @layer components bundle (broker), and
   a layered base out-cascades an unlayered override here — same reason the dark
   overrides in tailwind/components/buying.css use !important. */
.map-value-pill:hover,
.map-value-pill:focus-visible,
.map-value-pill.is-peeked {
  z-index: 680;
  outline: none;
  transform: translate(-50%, -100%) scale(1.2) !important;
}
.map-value-pill:hover .map-value-pill-label,
.map-value-pill:focus-visible .map-value-pill-label,
.map-value-pill.is-peeked .map-value-pill-label {
  background: var(--browse-ink-soft, #0A6E5C) !important;
  color: #fff !important;
  border-color: var(--browse-ink-soft, #0A6E5C) !important;
  box-shadow: 0 6px 16px rgba(10, 110, 92, .34), 0 0 0 3px rgba(14, 161, 132, .18) !important;
}
.map-value-pill:hover .map-value-pill-tail,
.map-value-pill:focus-visible .map-value-pill-tail,
.map-value-pill.is-peeked .map-value-pill-tail {
  background: var(--browse-ink-soft, #0A6E5C) !important;
  border-color: var(--browse-ink-soft, #0A6E5C) !important;
}
.map-value-pill.is-dimmed { opacity: .28; }
.map-value-pill.is-dimmed:hover,
.map-value-pill.is-dimmed.is-peeked { opacity: 1; }

/* Peek pill — the price pin popped in when a sidebar card whose listing has no pin
   of its own is hovered (dot → pin, Airbnb-style). The pop is an ANIMATION, which
   beats the layered Tailwind base .map-value-pill transform WITHOUT needing
   !important; it ends slightly enlarged so the hovered listing stands out. */
.map-value-pill--peek {
  z-index: 690;
  animation: exPillPop .22s cubic-bezier(.34, 1.56, .64, 1) both;
  /* Non-interactive so hovering a MAP dot doesn't hand hover to the pill (which
     would fire the dot's mouseout and flicker); clicks fall through to the dot. */
  pointer-events: none;
}
/* Unpriced listing (no asking price or revenue) popped as a neutral "Value TBD"
   pin, so a Value-TBD card still becomes a pin on hover like any other. */
.map-value-pill--unpriced .map-value-pill-label {
  background: #fff;
  color: #4b5563;
  border: 1.5px solid #cbd5cf;
}
.map-value-pill--unpriced .map-value-pill-tail {
  background: #fff;
  border-right: 1.5px solid #cbd5cf;
  border-bottom: 1.5px solid #cbd5cf;
}
.map-value-pill--peek .map-value-pill-label {
  box-shadow: 0 6px 16px rgba(12, 62, 38, .4), 0 0 0 3px rgba(12, 62, 38, .18) !important;
}
@keyframes exPillPop {
  from { transform: translate(-50%, -100%) scale(.3); opacity: 0; }
  to   { transform: translate(-50%, -100%) scale(1.12); opacity: 1; }
}

/* ── Tooltip (peek) — anchored above its marker ──────────────────── */
.explore-map-tip {
  position: absolute;
  transform: translate(-50%, -100%);
  z-index: 1200;
  pointer-events: none;
  background: #12241c;
  color: #fff;
  border-radius: 10px;
  padding: 9px 12px;
  box-shadow: 0 8px 24px rgba(16, 40, 28, .28);
  animation: exTipIn .12s ease both;
  min-width: 150px;
}
.explore-map-tip__title { font-size: var(--text-sm); font-weight: var(--fw-bold); letter-spacing: -.01em; }
.explore-map-tip__kind {
  font-size: var(--text-2xs);
  font-weight: var(--fw-semibold);
  color: #a9c6b6;
  margin-left: 3px;
}
.explore-map-tip__sub { font-size: var(--text-xs); color: #a9c6b6; margin-top: 2px; }
.explore-map-tip__stats { font-size: var(--text-xs); color: #cfe3d7; margin-top: 6px; font-weight: var(--fw-semibold); }
.explore-map-tip__extra { font-size: var(--text-xs); color: #a9c6b6; margin-top: 5px; }
.explore-map-tip__hint { font-size: var(--text-2xs); color: #6f9884; margin-top: 5px; }

/* ── Focused listing marker: price pin + dashed ring + caption ───── */
.explore-focus-marker {
  position: absolute;
  width: 0;
  height: 0;
  z-index: 900;
  pointer-events: none;
}
.explore-focus-marker__ring {
  position: absolute;
  left: 0;
  top: 0;
  transform: translate(-50%, -50%);
  border-radius: 50%; /* 99px caps out on large rings and reads as a rounded square */
  border: 1.5px dashed rgba(32, 94, 58, .6);
  background: rgba(32, 94, 58, .13);
}
.explore-focus-marker__pin {
  position: absolute;
  left: 0;
  top: 0;
  transform: translate(-50%, -100%);
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  border: none;
  background: transparent;
  padding: 0;
  cursor: pointer;
  pointer-events: auto;
}
.explore-focus-marker__pin-label {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: 30px;
  padding: 0 11px;
  border-radius: 99px;
  background: var(--browse-accent, #0EA184);
  color: #fff;
  border: 2px solid #fff;
  font-size: var(--text-base);
  font-weight: var(--fw-bold);
  letter-spacing: -.01em;
  box-shadow: 0 6px 16px rgba(14, 161, 132, .34);
  white-space: nowrap;
}
.explore-focus-marker__pin-label { position: relative; z-index: 1; }
.explore-focus-marker__pin-tail {
  width: 10px;
  height: 10px;
  margin-top: -6px;
  border-radius: 1px;
  background: var(--browse-accent, #0EA184);
  transform: rotate(45deg);
}
.explore-focus-marker__caption {
  position: absolute;
  left: 0;
  top: 12px;
  transform: translateX(-50%);
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 9px;
  border-radius: 99px;
  background: rgba(255, 255, 255, .96);
  border: 1px solid rgba(32, 94, 58, .3);
  box-shadow: 0 2px 8px rgba(16, 40, 28, .14);
  font-size: var(--text-xs);
  font-weight: var(--fw-bold);
  color: #1b4d3a;
  white-space: nowrap;
}

/* ── Docked focus card — rises bottom-center on focus ────────────── */
.explore-map-dock {
  position: absolute;
  bottom: 54px;
  left: 50%;
  transform: translateX(-50%);
  width: min(370px, calc(100% - 32px));
  background: #fff;
  border: 1px solid rgba(20, 55, 42, .14);
  border-radius: 12px;
  box-shadow: 0 14px 40px rgba(16, 40, 28, .22);
  z-index: 36;
  padding: 10px 12px 11px;
  animation: exDockRise .28s cubic-bezier(.33, 1, .68, 1) both;
}
.explore-map-dock.hidden { display: none; }
.explore-map-dock__head { display: flex; align-items: flex-start; gap: 8px; }
.explore-map-dock__main { flex: 1; min-width: 0; }
.explore-map-dock__badges { display: flex; gap: 5px; flex-wrap: wrap; margin-bottom: 4px; }
.explore-map-dock__badges .explore-badge { height: 17px; padding: 0 6px; font-size: var(--text-2xs); }
.explore-map-dock__badges .explore-badge.hidden { display: none; }
/* Collapse the badges row when nothing is showing — since the practice-type badge
   was removed (it just repeated the dock title), the only badge left is the match
   chip, which is hidden for non-matching listings. Without this, the empty flex row
   leaves a stray margin above the title. */
.explore-map-dock__badges:not(:has(.explore-badge:not(.hidden))) { display: none; }
/* The design's focus card: a near-black title over a grey location line, a price in
   near-black with a grey caption, and a teal primary beside a neutral Save. Ours read
   as an all-green panel -- green title, green price, dark forest button -- which made
   it look like a different component from the cards beside it. */
.explore-map-dock__title-row {
  display: flex;
  align-items: center;
  gap: 6px;
  color: var(--base-text, #222222);
}
.explore-map-dock__title {
  font-size: var(--text-lg, 0.9375rem);
  font-weight: var(--fw-bold);
  letter-spacing: -.01em;
}
.explore-map-dock__city {
  font-size: var(--text-xs);
  line-height: 1.35;
  color: var(--base-text-tertiary, #737373);
  /* No 19px indent now that the pin glyph is gone. */
  margin: 2px 0 0;
}
.explore-map-dock__close {
  flex: none;
  width: 22px;
  height: 22px;
  border-radius: 7px;
  border: 1px solid #e6eae8;
  background: #fff;
  color: var(--base-text-tertiary, #737373);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.explore-map-dock__price-row {
  display: flex;
  align-items: baseline;
  gap: 5px;
  margin-top: 6px;
}
.explore-map-dock__price {
  font-size: var(--text-xl, 1.125rem);
  font-weight: var(--fw-bold);
  letter-spacing: -.02em;
  color: var(--base-text, #222222);
}
.explore-map-dock__price-label {
  font-size: var(--text-xs);
  color: var(--base-text-tertiary, #8C8C8C);
  font-weight: var(--fw-medium);
}
.explore-map-dock__stats {
  margin-left: auto;
  font-size: var(--text-xs);
  color: var(--base-text-tertiary, #737373);
}
.explore-map-dock__actions { display: flex; gap: 8px; margin-top: 12px; align-items: center; }

/* Content-width and teal, like the design's, not a full-bleed forest-green bar. */
.explore-map-dock__cta {
  flex: none;
  height: 38px;
  padding: 0 18px;
  border-radius: 999px;
  border: none;
  background: var(--browse-accent, #0EA184);
  color: #fff;
  font-size: var(--text-base, 0.8125rem);
  font-weight: var(--fw-semibold);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.explore-map-dock__cta:hover { background: var(--browse-accent-deep, #0C7C66); }
/* The design pairs the primary with a neutral "Save" pill rather than a bordered
   icon square. */
.explore-map-dock__save {
  flex: none;
  width: 38px;
  height: 38px;
  border-radius: 999px;
  border: 0;
  background: var(--browse-surface, #F7F7F7);
  color: #9aa4a0;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.explore-map-dock__save .explore-card__save-icon { width: 14px; height: 14px; }
.explore-map-dock__save[data-saved="true"] { color: #dc2626; }
.explore-map-dock__save[data-saved="true"] svg { fill: #dc2626; stroke: #dc2626; }

/* ── Responsive ───────────────────────────────────────────────────
   The broker map (/brokering/practices?view=map) shares this panel chrome
   but NOT the buyer/explore `.explore-map-layout` wrapper (it uses its own
   `.brokering-listings-map-layout`). These bare rules keep the broker map's
   ≤900px behavior unchanged (its responsive pass is separate). The
   buyer/explore surfaces are governed by the `.explore-map-layout`-scoped
   four-tier system further below, which overrides these within that wrapper
   (higher specificity) and never reaches the broker map. */
@media (max-width: 900px) {
  .explore-map-panel {
    order: 1;
    height: 420px;
    flex: none;
  }
  .explore-map-legend { max-width: 160px; }
  .explore-map-dock { bottom: 12px; }
}

/* ── Dock badges — self-contained so the broker page (which doesn't load
   marketing/pages/explore.css) renders them identically ─────────── */
.explore-map-dock .explore-badge {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  height: 20px;
  padding: 0 8px;
  border-radius: 99px;
  background: #eef1ef;
  border: 1px solid transparent;
  color: #404040;
  font-size: var(--text-2xs);
  font-weight: var(--fw-bold);
  text-transform: uppercase;
  letter-spacing: .03em;
  white-space: nowrap;
}
.explore-map-dock .explore-badge--match {
  background: rgba(4, 120, 87, .1);
  color: #065f46;
}
.explore-map-dock .explore-badge--match.is-full-match {
  background: #dcefe4;
  border-color: #bfe3cf;
  color: #166a41;
}

/* ════════════════════════════════════════════════════════════════
   BUYER / EXPLORE RESPONSIVE MAP: four tiers (Browse redesign)
   Source of truth: browse-redesign-proposal (map + list, phone/tablet).
   Everything here is scoped under `.explore-map-layout`, which only the
   buyer/explore surfaces (explore, buying/browse, buying/matches) render.
   The broker map uses `.brokering-listings-map-layout`, so these rules can
   never touch it. Grid view stays a one-tap toggle at every width.

     phone   (max 767px):   full-bleed map + draggable bottom sheet
     tablet  (768-1023px):  stacked, map on top, 2-up list below
     split   (1024-1279px): list rail beside a flexible, taller map
     desktop (min 1280px):  unchanged (base rules: 320px sidebar + 620px map)
   ════════════════════════════════════════════════════════════════ */

/* The drag handle is phone-sheet chrome only (kept out of flow elsewhere). */
.explore-map-sheet-handle { display: none; }

/* The Selected-bar "View" CTA replaces the on-map dock on phones; on wider
   screens the dock owns the commit action, so it stays hidden. */
.explore-map-selected-bar__view { display: none; }

/* Native app renders edge-to-edge (viewport-fit=cover in the explore layout), so
   page content would otherwise slide under the status bar / native nav bar. Pad the
   top by the safe-area inset to keep the search + result bars clear of it. env() is 0
   on the web, so this is native-only and the broker map (no .is-native) is untouched. */
body.explore-page.is-native main {
  padding-top: env(safe-area-inset-top, 0px);
}

/* ── Phone (≤767): full-bleed map, listings on a draggable sheet ─── */
@media (max-width: 767px) {
  .explore-map-layout {
    position: relative;
    display: block;
    height: 72dvh;
    min-height: 460px;
    gap: 0;
    margin-bottom: 16px;
  }
  .explore-map-layout .explore-map-panel {
    position: absolute;
    inset: 0;
    height: auto;
    flex: none;
    order: 0;
  }

  /* Trim map chrome on phone: the bottom-anchored zoombar + count badge would
     sit behind the sheet (the sheet header carries the in-view count), and the
     +/- zoom buttons overlap the raised sheet, so drop them and rely on pinch
     to zoom. Scoped so the broker map keeps all of its chrome. */
  .explore-map-layout .explore-map-zoombar,
  .explore-map-layout .explore-map-count-badge,
  .explore-map-layout .explore-map-zoom { display: none; }
  /* The on-map focus dock is replaced by the sheet's Selected bar + View. */
  .explore-map-layout .explore-map-dock { display: none; }

  /* Sidebar becomes the sheet: overlays the map, slides between detents.
     JS (browse-sheet) sets --sheet-y in px once connected; the 82% fallback
     is the peek detent before then. */
  .explore-map-layout .explore-map-sidebar {
    position: absolute;
    left: 0;
    right: 0;
    /* Lift the sheet above the native bottom tab bar / home indicator. env() is
       non-zero only under viewport-fit=cover (native app); it resolves to 0 on
       the web, so the sheet stays flush there. */
    bottom: env(safe-area-inset-bottom, 0px);
    z-index: 20;
    order: 0;
    flex: none;
    height: 100%;
    max-height: none;
    border-radius: 18px 18px 0 0;
    box-shadow: 0 -12px 30px -14px rgba(12, 62, 38, .3);
    transform: translateY(var(--sheet-y, 82%));
    transition: transform .3s cubic-bezier(.33, 1, .68, 1);
    touch-action: none;
    will-change: transform;
  }
  .explore-map-layout .explore-map-sidebar.is-dragging { transition: none; }

  /* Drag handle: grip bar centered in a comfortably tall (≥48dp with the
     header below it) grabbable strip. */
  .explore-map-sheet-handle {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 30px;
    padding: 0;
    border: 0;
    background: transparent;
    cursor: grab;
    flex: none;
    touch-action: none;
  }
  .explore-map-sheet-handle:active { cursor: grabbing; }
  .explore-map-sheet-handle__grip {
    width: 38px;
    height: 5px;
    border-radius: 99px;
    background: #d3ddd8;
  }

  /* Rows scroll only once the sheet is fully raised. The sheet drags to full,
     then its content scrolls, never both at once. */
  .explore-map-layout .explore-map-sidebar__scroll {
    overflow-y: hidden;
    touch-action: none;
  }
  .explore-map-layout .explore-map-sidebar.is-full .explore-map-sidebar__scroll {
    overflow-y: auto;
    touch-action: pan-y;
  }

  /* Selected-bar commit CTA (phone) */
  .explore-map-selected-bar__view {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    flex: none;
    height: 28px;
    padding: 0 10px;
    border: 0;
    border-radius: 8px;
    background: #205e3a;
    color: #fff;
    font-size: var(--text-sm);
    font-weight: var(--fw-bold);
    cursor: pointer;
  }
  .explore-map-selected-bar__view:hover { background: #0c3e26; }

  /* Declutter: the legend covers a third of a phone's width, so shrink it. */
  .explore-map-layout .explore-map-legend {
    max-width: 150px;
    padding: 8px 10px;
  }

  /* When the sheet is fully raised the map is mostly covered, so fade its legend
     out (it returns at peek/half). */
  .explore-map-layout .explore-map-legend { transition: opacity .2s ease; }
  .explore-map-layout.is-sheet-full .explore-map-legend { opacity: 0; pointer-events: none; }

  /* No "Esc" hint on phone (there's no hardware keyboard). */
  .explore-map-layout .explore-map-reset__kbd { display: none; }

  /* Legibility: on phone the map view is dropped into the native app, whose
     other screens (Account, sign-in) use a 15-18px scale. Bring the sheet's
     text up to match so Browse doesn't read as a cramped web page: listing
     titles 15px (like the account rows), roomier sub/header, and the smallest
     meta labels (badges/stats) nudged off their 9-9.5px lows. */
  .explore-map-layout .explore-map-sidebar__count { font-size: var(--text-md); }
  .explore-map-layout .explore-map-sidebar__hint { font-size: var(--text-sm); }
  .explore-map-layout .explore-map-listing-row__badges .explore-badge { height: 20px; font-size: var(--text-xs); }
  .explore-map-layout .explore-map-listing-row__title { font-size: var(--text-lg); }
  .explore-map-layout .explore-map-listing-row__sub { font-size: var(--text-base); }
  .explore-map-layout .explore-map-listing-row__amount { font-size: var(--text-xl); }
  .explore-map-layout .explore-map-listing-row__stat strong { font-size: var(--text-base); }
  .explore-map-layout .explore-map-listing-row__stat .explore-map-listing-row__stat-label { font-size: var(--text-2xs); }
}

/* ── Portrait tablet (768-1023): stacked, map on top, 2-up list below ── */
@media (min-width: 768px) and (max-width: 1023px) {
  .explore-map-layout {
    display: flex;
    flex-direction: column;
    height: auto;
    gap: 12px;
  }
  .explore-map-layout .explore-map-panel {
    order: 1;
    flex: none;
    height: 46vh;
    min-height: 340px;
  }
  .explore-map-layout .explore-map-sidebar {
    order: 2;
    flex: none;
    height: 46vh;
    min-height: 320px;
    max-height: none;
  }
  .explore-map-layout .explore-map-sidebar__rows {
    display: grid;
    grid-template-columns: 1fr 1fr;
    align-content: start;
  }
  .explore-map-layout .explore-map-sidebar__more { grid-column: 1 / -1; }
}

/* ── Split (1024-1279): list rail beside a flexible, taller map ──── */
@media (min-width: 1024px) and (max-width: 1279px) {
  .explore-map-layout {
    height: clamp(560px, calc(100vh - 168px), 860px);
  }
  .explore-map-layout .explore-map-sidebar {
    flex: 0 0 40%;
    max-width: 440px;
  }
}

/* ════════════════════════════════════════════════════════════════
   DARK MODE — buyer Browse map overlay chrome
   Scoped to `.dark .buying-shell` so it only reaches the authenticated
   buyer map (which renders inside .buying-shell). The public/marketing
   explore map lives under body.explore-page (NOT .buying-shell) and is
   deliberately left untouched. Base rules above are all light-only
   (white/beige fills), so without these the floating chrome renders as
   bright white cards on the dark map.

   PRICE DATA-VIZ IS INTENTIONALLY NOT TOUCHED HERE: the legend
   dot (.explore-map-legend__dot), the zoombar green dots
   (.is-passed / .is-active), and every
   --asking_price / price-bucket color keep their exact light hexes so
   the color→price encoding is preserved in dark mode.
   ════════════════════════════════════════════════════════════════ */

/* Floating overlay surfaces → most-elevated dark surface + neutral
   border (they float above the map). Existing box-shadows are kept. */
/* `.brokering-shell` is included because the broker Browse map renders this same
   floating chrome and had NO dark treatment at all, so its legend and zoom
   rendered as bright white cards on the dark map. */
.dark :is(.buying-shell, .brokering-shell) .explore-map-panel,
.dark :is(.buying-shell, .brokering-shell) .explore-map-legend,
.dark :is(.buying-shell, .brokering-shell) .explore-map-zoom,
.dark :is(.buying-shell, .brokering-shell) .explore-map-zoombar {
  background: var(--base-bg-highest);
  border-color: var(--base-border-secondary);
}/* Primary text: zoombar title and the legend rows. */
.dark .buying-shell .explore-map-zoombar__title,
.dark :is(.buying-shell, .brokering-shell) .explore-map-legend__row {
  color: var(--base-text);
}

/* Muted text: the zoombar level label. */
.dark .buying-shell .explore-map-zoombar__label {
  color: var(--base-text-secondary);
}

/* Most-muted text: the "ⓘ" info row + its icon. */
.dark :is(.buying-shell, .brokering-shell) .explore-map-legend__info-row,
.dark :is(.buying-shell, .brokering-shell) .explore-map-legend__info-icon {
  color: var(--base-text-tertiary);
}

/* Zoom buttons: idle sits transparent on the dark surface with a readable
   label; the zoom divider follows the neutral border. */
.dark :is(.buying-shell, .brokering-shell) .explore-map-zoom button {
  background: transparent;
  color: var(--base-text);
}
.dark :is(.buying-shell, .brokering-shell) .explore-map-zoom button:first-child {
  border-bottom-color: var(--base-border-secondary);
}
/* Value pills are price data-viz and keep their light-mode look in dark. The
   asking-price variant is a green fill; the annual-revenue variant is a white
   surface with dark-green ink + green outline. That white pill matches the
   legend's white swatch and encodes a data value ("no asking price"), not
   chrome, so it MUST stay white in dark too — it is deliberately NOT darkened
   here (the dark-green ink stays readable on white in both modes). */

/* Idle zoom-progress dot (light gray chrome); the passed/active green dots are
   data-viz, so :not() leaves them alone. */
.dark .buying-shell .explore-map-zoombar__dot:not(.is-passed):not(.is-active) {
  background: var(--base-text-tertiary);
}

/* Selected-listing dock (the on-map popup card). White surface + dark-green
   title/price ink that vanish on dark. Elevate the surface and flip the ink;
   the green "View full details" CTA and the .explore-badge chips are left as-is
   (CTA is a primary button; badges flip via the .dark .buying-shell .explore-badge rules). */
.dark .buying-shell .explore-map-dock {
  background: var(--base-bg-highest);
  border-color: var(--base-border-secondary);
}
.dark .buying-shell .explore-map-dock__title-row,
.dark .buying-shell .explore-map-dock__title { color: var(--base-text); }
.dark .buying-shell .explore-map-dock__price { color: var(--text-primary); }
.dark .buying-shell .explore-map-dock__price-label { color: var(--base-text-secondary); }
.dark .buying-shell .explore-map-dock__close {
  background: transparent;
  border-color: var(--base-border-secondary);
}
/* Heart/save button ships a white fill + light border; flip to the dock's
   outline-button treatment (matches __close). The [data-saved] red ink is left
   alone — it reads on the dark surface and the light rule still wins for it. */
.dark .buying-shell .explore-map-dock__save {
  background: transparent;
  border-color: var(--base-border-secondary);
}

/* ── Browse map-detail slideover (buyer) ──────────────────────────────
   The buyer-browse detail slideover reuses the shared slideover chrome
   (.slideover-panel/-header/-footer + .brokering-slideover-stack/-section),
   but this page also loads marketing/pages/explore.css AFTER the Tailwind
   build, and that sheet redeclares those classes as hardcoded #fff / #F1F7F5
   with NO dark override — so the whole slideover renders white in dark. Its
   plain-class rules (0,1,0) can't be beaten by load order here, so restore the
   dark surfaces with shell-scoped rules (0,3,0) that also load last. Values
   mirror the canonical broker slideover's L3 hierarchy (dark-mode-system.md
   §"Slideover surface hierarchy"): panel chrome (panel + header + footer) is
   the elevated floating surface --base-bg-highest; the scroll stack drops to
   --background; section cards are darker wells at --base-bg-low. So the buyer
   slideover reads identically to broker. Buyer-scoped, so the public explore
   page (no .buying-shell) stays light and marketing stays out of scope. */
.dark .buying-shell .slideover-panel,
.dark .buying-shell .slideover-header,
.dark .buying-shell .slideover-footer { background: var(--base-bg-highest); }
/* transparent since 2026-09-11: the stack inherits its host now rather than dropping a step
   below it, matching the broker/seller drawers. The rule is KEPT rather than deleted, and it
   is kept in THIS sheet, for the reason the comment above gives -- marketing/pages/explore.css
   redeclares .brokering-slideover-stack unlayered and leaks onto browse pages, so something
   shell-scoped has to out-rank it here. */
.dark .buying-shell .brokering-slideover-stack { background: transparent; }
.dark .buying-shell .brokering-slideover-section { background: var(--base-bg-low); }

/* 🚨 THE BUYER'S CARD RECIPE, and it has to live here rather than in the app bundle
   (2026-09-11). The bundle's `.brokering-slideover-section` is borderless + 16px +
   --brk-shadow-card, but marketing/pages/explore.css redeclares that class UNLAYERED and
   loads after the bundle on /buying/browse, so its hairline-and-flat version wins there --
   and, because Turbo never unloads a stylesheet, on every page visited afterwards too. This
   sheet loads after BOTH and is shell-scoped (0,2,0 unlayered), so it settles it.

   The marketing copy is deliberately left flat: that sheet also serves the PUBLIC explore
   page, which loads no Tailwind bundle and therefore has no --brk-shadow-card, where
   borderless + an unresolvable shadow would be an invisible rectangle. Buyer resolves the
   token because buyer-v2.css declares it on `html:not(.dark) body.buying-body .buying-shell`
   -- which is also why this rule is NOT under `.dark`: in dark the token is undefined by
   design and the hairline below carries the elevation. */
.buying-shell .brokering-slideover-section {
  border: 0;
  border-radius: 16px;
  box-shadow: var(--brk-shadow-card);
}

.dark .buying-shell .brokering-slideover-section {
  border: 1px solid var(--base-border-tertiary);
}

/* ── Explore badges — consolidated onto the design-system status tokens ────────
   The .explore-badge--* family (base colors in marketing/pages/explore.css) hardcoded
   a light hex per variant and needed a hand-written .dark patch per variant in buying.css
   — bug-prone: a forgotten `color` left the dock's --type badge dark-on-dark. Drive every
   variant from the shared --status-* tokens instead (the same tokens the canonical .pill
   consumes): one rule per status, flips for light + dark automatically, zero dark patches.
   The --status-* light values already match the old marketing hex and the dark values match
   the old .dark patch rgba()s, so this is a near-zero visual change that deletes the drift.
   Scoped to .buying-shell: the public explore page is light-only, lacks the dashboard
   --status-* tokens, and ships its own marketing `.pill`, so it keeps the marketing colors
   untouched. Dock selectors (.explore-map-dock .explore-badge--*) are re-stated at higher
   specificity to beat the dock's own neutral/match base rules earlier in this file. */
.buying-shell .explore-badge { border: 1px solid transparent; }

.buying-shell .explore-badge--type,
.buying-shell .explore-badge--locked,
.buying-shell .explore-badge--inquiry.is-neutral,
.buying-shell .explore-inquiry-status.is-neutral,
.buying-shell .explore-map-dock .explore-badge--type {
  background: var(--status-neutral-bg);
  color: var(--status-neutral-text);
}
.buying-shell .explore-badge--anon,
.buying-shell .explore-badge--new,
.buying-shell .explore-badge--verified,
.buying-shell .explore-badge--match,
.buying-shell .explore-badge--match-item,
.buying-shell .explore-badge--inquiry.is-success,
.buying-shell .explore-inquiry-status.is-success,
.buying-shell .explore-map-dock .explore-badge--match {
  background: var(--status-success-bg);
  color: var(--status-success-text);
}
.buying-shell .explore-badge--granted,
.buying-shell .explore-badge--specialty,
.buying-shell .explore-badge--budget,
.buying-shell .explore-badge--inquiry.is-info,
.buying-shell .explore-inquiry-status.is-info {
  background: var(--status-info-bg);
  color: var(--status-info-text);
}
.buying-shell .explore-badge--inquiry.is-purple,
.buying-shell .explore-inquiry-status.is-purple {
  background: var(--status-purple-bg);
  color: var(--status-purple-text);
}
.buying-shell .explore-badge--location {
  background: var(--status-warning-bg);
  color: var(--status-warning-text);
}

/* ---------------------------------------------------------------------------
   Broker Browse v5 split: the map panel fills a rounded frame in a CSS grid,
   not the buyer's flex .explore-map-layout.

   Both of this file's own sizing modes are wrong in that context. The default
   `.explore-map-panel { flex: 1 }` needs a flex parent, and the <=900px block
   above switches it to `flex: none; height: 420px`, which collapsed the panel
   to its content width (~2px — the canvas and every piece of chrome inside are
   absolutely positioned, so there is no intrinsic width) and forced a height
   that overflowed the frame and got clipped.

   Pinning it with absolute inset sizing is immune to both. `height: auto` is
   required because an absolutely positioned box resolves its height from an
   explicit `height` in preference to `bottom`, so the 420px above would
   otherwise still win. This lives here rather than in brokering.css because
   this stylesheet is unlayered and loads last, so it outranks the Tailwind
   bundle's @layer no matter how specific the selector there is.
   --------------------------------------------------------------------------- */
.brokering-browse-split__map .explore-map-panel {
  position: absolute;
  inset: 0;
  height: auto;
  min-height: 0;
  border: 0;
  border-radius: 0;
}

/* ══════════════════════════════════════════════════════════════════════════
   Coverage card v4, Direction B ("mode at rest, list in a flyout"), from the
   Claude Design handoff (Sep 2026) plus its INTERACTIONS pass.

   It REPLACED the .explore-map-legend__section / __pref* / __more / __actions /
   __subtle rules and every .explore-map-coverage__* rule; .explore-map-legend__link
   went with them, dead once the Change chip moved into the flyout footer.

   🚨 .explore-map-legend, __swatch, __dot, __ring and __popover are all still here
   and still used: public explore and buyer browse take _map_panel's else branch and
   render the ORIGINAL legend. Do not tidy them away.

   🚨 Every var() carries a literal fallback, which is this file's standing rule and
   is load-bearing rather than defensive: /explore loads the marketing bundle and NOT
   themes/light.css, so --ws-shadow-menu is undefined there, and --browse-accent is
   scoped to .browse-v5 rather than :root on every surface.

   🚨 THE CARD NEVER RESIZES. Mode and the summary are both at rest, and the only
   disclosure is a flyout that opens BESIDE the card. Nothing here animates a width or
   a height, which is what the earlier expand-in-place direction had to do and what
   made its open and close read as jerky. The flyout is a `safe-dropdown` menu and
   appears the way every other menu in this app appears.

   The three rules that govern every state below, so they are not re-litigated per
   element:
     · hover arrives at 0ms and leaves over 120ms linear;
     · press is 80ms linear and there is NO scale-down;
     · hover on the resting card is a border or colour step, never a new fill, because
       the card sits over a map and any one fill value disappears against some
       background. INSIDE the opaque flyout a fill is safe, so press uses one.
   ══════════════════════════════════════════════════════════════════════════ */
/* The card. v2 surface trio: --base-bg-low, 16px radius. It is map chrome, so it wears
   the lighter chrome shadow and the design's .97 fill, which lets the map read faintly
   through it rather than punching a solid hole in the canvas. 215px: 25px wider than
   the direction that hid mode, which is what the segmented row costs. */
.explore-map-cov {
  position: absolute;
  top: 12px;
  left: 12px;
  z-index: 30;
  width: 215px;
  padding: 7px 9px 6px;
  border-radius: 16px;
  background: color-mix(in srgb, var(--base-bg-low, #fff) 97%, transparent);
  border: 1px solid rgba(20, 55, 42, .10);
  box-shadow: 0 2px 8px rgba(16, 40, 28, .10);
  color: #3F4A45;
}

/* 🚨 An author `display` beats the UA's [hidden] rule, and the controller hides half
   the flyout by attribute (the footer's two shapes, Select all). Said once, here,
   rather than per element. */
.explore-map-cov [hidden] { display: none; }

/* ── Row 1: mode, at rest ──────────────────────────────────────────────────
   A SEGMENTED pair, geometry lifted from `.browse-v5 .segmented` so the map's mode
   switch and the toolbar's scope switch are visibly the same control. Full width
   because there are exactly two modes and no third will be added: Nationwide is a
   scope, not a place. */
.explore-map-cov__modes {
  display: flex;
  gap: 2px;
  padding: 2px;
  border-radius: 999px;
  background: var(--status-neutral-bg, #F4F4F4);
  box-shadow: inset 0 1px 2px rgb(0 0 0 / .05);
}
.explore-map-cov__mode {
  flex: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 22px;
  border-radius: 999px;
  font: var(--type-ws-chip) var(--font-sans);
  color: var(--base-text-tertiary, #767676);
  text-decoration: none;
  white-space: nowrap;
  transition: color 120ms linear;
}
.explore-map-cov__mode.is-on {
  background: var(--base-bg-low, #fff);
  box-shadow: 0 1px 2px rgb(0 0 0 / .06);
  font: var(--type-ws-chip-on) var(--font-sans);
  color: var(--base-text, #171717);
}

/* ── Row 2: the summary, and the flyout trigger ────────────────────────── */
.explore-map-cov__summary {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 8px 2px 7px;
  border: 0;
  background: none;
  text-align: left;
  font-family: inherit;
  cursor: pointer;
}
.explore-map-cov__summary:focus-visible {
  outline: 2px solid var(--base-border-focus, #0EA184);
  outline-offset: 2px;
  border-radius: 8px;
}
.explore-map-cov__label {
  font: var(--type-ws-action) var(--font-sans);   /* 12px / 600 */
  color: var(--base-text, #171717);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.explore-map-cov__label.is-muted { color: #6F7A74; }
.explore-map-cov__glyph { flex: none; color: #6F7A74; }
/* Points AT the flyout. It does NOT rotate: nothing opens in place here, and a caret
   that turned would promise a card that expands downward. */
.explore-map-cov__chevron { flex: none; margin-left: auto; color: #8A938E; }

/* The dot stack. HOLLOW on purpose: a filled coverage dot at MAP_COLORS Green
   (#16a34a) or Cyan (#0e7490) sits two rows above a filled mint price swatch, and the
   two colour systems must not be confusable. The hollow ring repeats the shape it
   keys, at the ring's own stroke and a lighter fill than the map's 0.06 (which is
   invisible at 11px). The white ring is what keeps the overlap readable. */
.explore-map-cov__dots { flex: none; display: flex; align-items: center; }
.explore-map-cov__dots .explore-map-cov__dot + .explore-map-cov__dot { margin-left: -4px; }
.explore-map-cov__dots-rest {
  margin-left: 3px;
  font: var(--type-ws-eyebrow) var(--font-sans);  /* 11px / 600 */
  color: #8A938E;
}
.explore-map-cov__dot {
  flex: none;
  width: 11px;
  height: 11px;
  border-radius: 999px;
  border: 1.5px solid var(--pref-color);
  background: color-mix(in srgb, var(--pref-color) 14%, transparent);
  box-shadow: 0 0 0 2px var(--base-bg-low, #fff);
}

/* `none` state only: the single route out, in the legend, because there is no flyout. */
.explore-map-cov__setup {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  margin-left: auto;
  font: var(--type-ws-eyebrow) var(--font-sans);
  color: var(--browse-accent, #0EA184);
  text-decoration: none;
}
.explore-map-cov__setup:hover { text-decoration: underline; }

/* ── Row 3: the pin key. Labelled: a bare swatch pair reads as a toggle. ─ */
.explore-map-cov__key {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 4px 10px;
  padding: 7px 2px 2px;
  border-top: 1px solid rgba(20, 55, 42, .08);
}
/* Full-width flex item, which is what forces the break after it without a wrapper.
   Type matches .explore-map-legend__title exactly, down to the .08em: it is the same
   overline on the same map, and the other two surfaces still render that one. */
.explore-map-cov__key-title,
.explore-map-cov__flytitle {
  margin: 0;
  font-size: var(--text-2xs);
  font-weight: var(--fw-bold);
  line-height: 1.25;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: #8A938E;
}
.explore-map-cov__key-title { flex: 0 0 100%; }
.explore-map-cov__key-row {
  display: flex;
  align-items: center;
  gap: 6px;
  font: var(--type-caption) var(--font-sans);      /* 11px / 400 */
  color: #6F7A74;
}
.explore-map-cov__info {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  margin: -3px -4px -3px auto;
  padding: 0;
  border: 0;
  background: none;
  color: #8A938E;
  cursor: help;
}
.explore-map-cov__info:hover { color: #6F7A74; }
.explore-map-cov__info:focus-visible {
  outline: 2px solid var(--base-border-focus, #0EA184);
  outline-offset: 2px;
  border-radius: 6px;
}

/* ── The flyout ────────────────────────────────────────────────────────────
   safe-dropdown positions it (fixed, beside the card, top edges level) because BOTH
   .explore-map-panel and .brokering-browse-split__map clip with overflow: hidden. It
   is a menu, so it is opaque and wears the menu shadow, unlike the card. */
/* 🚨 The width is set on the LIST, not here, and that is not an accident. safe-dropdown
   measures the menu at `width: auto` with `max-width: none` to find its natural size,
   then pins the result inline, so a width OR a max-width authored on the menu is
   overridden either way. The one thing the measurement respects is its own content, so
   the fixed width goes on the widest child and the menu shrink-wraps to it. */
.explore-map-cov__flyout {
  padding: 12px 10px 10px;
  border-radius: 16px;
  background: var(--base-bg-low, #fff);
  box-shadow: var(--ws-shadow-menu, 0 12px 40px rgba(0, 0, 0, .16));
  color: #3F4A45;
}
.explore-map-cov__flyhead {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 8px;
  padding: 0 4px;
}
.explore-map-cov__flyhead .explore-map-cov__all { margin-left: auto; }

/* Scrolls rather than growing: a broker may hold twelve preferences and this sits over
   the map. The footer is outside the scroller, so the commit is reachable without
   scrolling to the end of the list. */
.explore-map-cov__list {
  /* 264px of menu less its 10px of horizontal padding on each side. See the flyout's
     note above for why the number lives here. */
  width: 244px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-height: 240px;
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* 🚨 A MENU row, not a form row: the tick and the colour dot lead, the name takes the
   space, and the radius sits at the right edge. That reading is right here because
   this is a menu. It is also the layout that weakens past about a dozen rows, where
   the ZIP column starts to look like a data table; the list scrolls before then. */
.explore-map-cov__item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px;
  border-radius: 10px;
  border: 1px solid transparent;
  text-decoration: none;
  color: #3F4A45;
}
/* Hover is a border step, not a fill. */
.explore-map-cov__item:hover { border-color: var(--base-border-secondary, rgba(20, 55, 42, .18)); }
.explore-map-cov__item:focus-visible {
  outline: 2px solid var(--base-border-focus, #0EA184);
  outline-offset: 1px;
}
/* 🚨 The tick is always in the DOM and hidden by COLOUR, not by markup: the controller
   flips .is-on locally while staging and must not have to build an SVG to do it. */
.explore-map-cov__check {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 15px;
  height: 15px;
  border-radius: 4px;
  border: 1.5px solid rgba(20, 55, 42, .22);
  background: var(--base-bg-low, #fff);
  color: transparent;
}
/* Selected is a TINT, never a grey. */
.explore-map-cov__item.is-on .explore-map-cov__check {
  background: var(--browse-accent, #0EA184);
  border-color: var(--browse-accent, #0EA184);
  color: #fff;
}
/* In a row the dot sits on an opaque menu, so it needs no white ring to separate it. */
.explore-map-cov__item .explore-map-cov__dot { box-shadow: none; }
.explore-map-cov__name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font: var(--type-ws-chip-on) var(--font-sans);   /* 12.5px / 600 */
  color: #3F4A45;
}
/* 🚨 Type only, shared by BOTH callers: the flyout's rows and the single-preference
   summary line. The row-specific clamp lives on the row selector below, because the solo
   line is a full-width line of its own and 92px would truncate the one thing it exists
   to say. */
.explore-map-cov__zone {
  font: var(--type-caption) var(--font-sans);
  color: #8A938E;
}
/* Capped so the NAME wins the row. The radius is secondary data and truncating it
   costs nothing (the full wording is on its title); truncating the preference name
   costs the one thing the row is for. */
.explore-map-cov__item .explore-map-cov__zone {
  flex: none;
  max-width: 92px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── One regional preference, no flyout: name over area ────────────────────
   The flyout is the detail surface, and it only exists when there is a multi-select to
   disclose. With one preference there is none, so the ZIP and radius have nowhere else
   on the map to go. A column, so the summary row stays ONE flex item and the row's own
   align-items: center cannot pull the two lines apart. */
.explore-map-cov__solo {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}
.explore-map-cov__soloname {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}
/* 19px = the dot's 11px plus the row's 8px gap, so the area aligns to the NAME rather
   than to the dot. The flyout rows use 18px against a 15px check box; same intent at
   this row's metrics, not a second value picked by eye. */
.explore-map-cov__solo .explore-map-cov__zone {
  padding-left: 19px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The footer's two shapes: a quiet route to settings when nothing is pending, Cancel
   plus the named commit when something is. Fixed min-height so staging does not grow
   the flyout by a few pixels the first time something is ticked. */
.explore-map-cov__foot {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 39px;
  margin-top: 8px;
  padding-top: 9px;
  border-top: 1px solid rgba(20, 55, 42, .10);
}
.explore-map-cov__all {
  font: var(--type-ws-eyebrow) var(--font-sans);
  color: var(--browse-accent, #0EA184);
  text-decoration: none;
  white-space: nowrap;
}
.explore-map-cov__all:hover { text-decoration: underline; }
/* 🚨 PLAIN TEXT. No pill, no border, no shadow, no underline, in ANY state, hover
   included. It is the quietest thing in the flyout and the only control in it that does
   not change what the map shows, so it must not compete with the commit button beside
   it or with the ticks above it.

   It is deliberately NOT .explore-pref-bar__edit. That one is a white pill with a
   shadow, which works on the tinted preference bar it lives on and reads as a raised
   button in a white menu, which is exactly what this must not be.

   margin-left: auto puts it on the footer's right. */
.explore-map-cov__subtle {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 0;
  border: 0;
  background: none;
  box-shadow: none;
  font: var(--type-ws-eyebrow) var(--font-sans);
  color: var(--browse-accent, #0EA184);
  text-decoration: none;
  white-space: nowrap;
}
/* A colour step only. Anything with an edge to it is what was wrong before. */
.explore-map-cov__subtle:hover {
  color: var(--browse-accent-deep, #0C7C66);
  border: 0;
  box-shadow: none;
  text-decoration: none;
}
.explore-map-cov__subtle:active { color: #0A6E5C; }
.explore-map-cov__subtle:focus-visible {
  outline: 2px solid var(--base-border-focus, #0EA184);
  outline-offset: 2px;
  border-radius: 6px;
}
.explore-map-cov__foot > .explore-map-cov__subtle[hidden] { display: none; }

/* The commit. Names the outcome ("Show 2 preferences"), never says "Apply", and is
   ABSENT rather than disabled when there is nothing pending. One mint filled action,
   and only while the flyout is open: the rest of the Browse view has none, so the
   one-primary-per-view rule holds. */
.explore-map-cov__apply {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  height: 30px;
  padding: 0 14px;
  border: 0;
  border-radius: 999px;
  background: var(--browse-accent, #0EA184);
  color: #fff;
  font: var(--type-ws-action) var(--font-sans);   /* 12px / 600 */
  cursor: pointer;
  transition: background-color 120ms linear;
}
.explore-map-cov__apply:hover { background: var(--browse-accent-deep, #0C7C66); }
/* Press is a colour step within 80ms. NO scale-down: press feedback is confirmation of
   input, not a flourish. */
.explore-map-cov__apply:active {
  background: #0A6E5C;
  transition: background-color 80ms linear;
}
.explore-map-cov__apply:focus-visible {
  outline: 2px solid var(--base-border-focus, #0EA184);
  outline-offset: 2px;
}

/* The exit, not the choice. Quiet in every state, and never accented. */
.explore-map-cov__cancel {
  padding: 0;
  border: 0;
  background: none;
  font: var(--type-ws-eyebrow) var(--font-sans);
  font-weight: var(--fw-medium, 500);
  color: #8A938E;
  cursor: pointer;
}
.explore-map-cov__cancel:hover { color: #6F7A74; text-decoration: underline; }
.explore-map-cov__cancel:active { color: #3F4A45; }
.explore-map-cov__cancel:focus-visible {
  outline: 2px solid var(--base-border-focus, #0EA184);
  outline-offset: 2px;
  border-radius: 6px;
}

/* ── Interaction states, stated in one place ───────────────────────────── */

/* Press. One value, every pressable thing in the card and the flyout. */
.explore-map-cov__summary:active,
.explore-map-cov__item:active,
.explore-map-cov__mode:active {
  background: var(--browse-surface, #F7F7F7);
  transition: background-color 80ms linear;
}
.explore-map-cov__summary:active { border-radius: 8px; }

/* Hover leaves gently, arrives instantly. */
.explore-map-cov__item,
.explore-map-cov__mode,
.explore-map-cov__chevron,
.explore-map-cov__info,
.explore-map-cov__subtle {
  transition: border-color 120ms linear, color 120ms linear, background-color 120ms linear;
}

/* 🚨 The ACTIVE mode segment has no hover, no press and no pointer cursor, because it
   is rendered as a <span> rather than a link: pressing the mode you are already in is
   a no-op. Stated defensively in case the markup regresses to a link. */
.explore-map-cov__mode.is-on,
.explore-map-cov__mode.is-on:hover,
.explore-map-cov__mode.is-on:active {
  background: var(--base-bg-low, #fff);
  box-shadow: 0 1px 2px rgb(0 0 0 / .06);
  font: var(--type-ws-chip-on) var(--font-sans);
  color: var(--base-text, #171717);
  cursor: default;
}

/* 🚨 An INACTIVE segment's hover is a text step only. Never a pill: the white pill is
   what marks the active mode, and giving hover one makes both segments look selected.
   This is the most commonly mis-built state on this control. */
.explore-map-cov__mode:not(.is-on):hover {
  background: transparent;
  box-shadow: none;
  color: var(--base-text, #222);
}

/* 🚨 A selected row's tick keeps its exact resting mint on hover. Darkening it reads as
   pressed, on a control that has not been pressed. The colour dot never changes either:
   it is data, and data does not respond to a pointer. */
.explore-map-cov__item.is-on:hover .explore-map-cov__check {
  background: var(--browse-accent, #0EA184);
  border-color: var(--browse-accent, #0EA184);
}
.explore-map-cov__item:hover .explore-map-cov__dot,
.explore-map-cov__dots:hover .explore-map-cov__dot { filter: none; opacity: 1; }
/* The row is the target. A second hover treatment on the box makes one control look
   like two. */
.explore-map-cov__check:hover { border-color: rgba(20, 55, 42, .22); }

/* The pin key is a KEY, not a filter. A hover there implies the pins can be switched
   by type, which they cannot. */
.explore-map-cov__key-row:hover .explore-map-legend__swatch { filter: none; }

/* ⓘ stays accented while its popover is pinned open. */
.explore-map-cov__info[aria-expanded="true"],
.explore-map-cov__info:active { color: var(--browse-accent, #0EA184); }

/* Links: underline on hover, one step darker on press, colour never changes on hover. */
.explore-map-cov__all:active,
.explore-map-cov__setup:active { color: var(--browse-accent-deep, #0C7C66); }

/* The chevron is the only thing that responds to hovering the summary row. */
.explore-map-cov__summary:hover .explore-map-cov__chevron { color: #6F7A74; }
.explore-map-cov__summary[aria-expanded="true"] .explore-map-cov__chevron {
  color: var(--browse-accent, #0EA184);
}

/* Scroller: the workspace tokens, not a new treatment. */
.explore-map-cov__list { scrollbar-width: thin; scrollbar-color: var(--ws-scroll-thumb, rgba(34,34,34,.12)) transparent; }
.explore-map-cov__list::-webkit-scrollbar { width: 10px; }
.explore-map-cov__list::-webkit-scrollbar-track { background: transparent; }
.explore-map-cov__list::-webkit-scrollbar-thumb {
  border: 3px solid var(--base-bg-low, #fff);
  border-radius: 8px;
  background: var(--ws-scroll-thumb, rgba(34, 34, 34, .12));
}
.explore-map-cov__list::-webkit-scrollbar-thumb:hover { background: var(--ws-scroll-thumb-hover, rgba(34, 34, 34, .24)); }

/* ── ≤900px ────────────────────────────────────────────────────────────────
   The card narrows; the flyout does not become a sheet. safe-dropdown already clamps
   a fixed menu back on screen, and at 264px it fits every width down to 320. */
@media (max-width: 900px) {
  .explore-map-cov { width: 178px; }
  /* 44px minimum target on touch. */
  .explore-map-cov__item { min-height: 44px; }
  .explore-map-cov__check { width: 18px; height: 18px; border-radius: 5px; }
  .explore-map-cov__mode { height: 26px; }
}

/* Phone: the resting card keeps mode and the summary but drops the labelled key, which
   the ⓘ then carries on its own. Coverage is unreachable while the results sheet is
   full, which is correct: it describes a map nobody can see. */
@media (max-width: 767px) {
  .explore-map-cov {
    width: 168px;
    padding: 6px 8px;
    transition: opacity .2s ease;
  }
  .explore-map-cov__summary { padding: 7px 2px 3px; }
  .explore-map-cov__key { padding: 4px 2px 0; }
  .explore-map-cov__key-title,
  .explore-map-cov__key-row { display: none; }
  .explore-map-layout.is-sheet-full .explore-map-cov { opacity: 0; pointer-events: none; }
}
