/* =============================================================================
   LISTINGS MAP — the national inventory figure
   -----------------------------------------------------------------------------
   A drop-in module: `<%= render "marketing/listings_map" %>` and nothing else.
   Used on /buyers, / and /brokers; written so a fourth page costs one line.

   Loaded by the marketing layout on EVERY page rather than per-page, because a
   one-line module cannot also require its caller to remember a stylesheet. It
   is small, and it is the price of the interface. The module's SCRIPT is loaded
   by the partial instead, so a page without the map pays no JavaScript.

   No colour literal appears in this file. Every --dmap-* role resolves through
   the band's own --da-sec-* tokens (pages.css), which is what lets the same
   markup sit on bone or on ink and recolour its own furniture with no modifier.
   The PIN colour is the exception in spirit though not in kind: it is pinned to
   the brand green on both bands, because the pins sit on Google's own light
   basemap and not on the band at all.

   ── HOW IT IS BUILT ────────────────────────────────────────────────────────
   A real Google basemap in .dmap__map, with every listing drawn into ONE
   <canvas> (.dmap__pins) laid over it. Not a marker per listing: that is what
   the /explore map does and it is why zooming it is not smooth. See
   marketing/listings_map.js for the arithmetic.

   .dmap__svg is the FALLBACK, hidden unless maps.googleapis.com fails to
   arrive, in which case the same listings are drawn onto a committed SVG
   outline of the United States. A still picture rather than an empty box.
   ============================================================================= */

.dmap {
  /* The pin. Deep teal with white type, which is the shade the /explore map
     already uses for the same pill, and it is FIXED on both bands rather than
     following --da-sec-accent: the pins are drawn on Google's light basemap, so
     the ink band's brighter accent would be the wrong contrast against it. The
     canvas reads this property, so the palette still lives in one place. */
  --dmap-pin:       var(--da-deep-teal);
  /* The hairline around a pill. Labels are allowed to overlap, and without an
     edge two of them merge into one green blob that reads as a rendering fault.
     Near-white rather than the band's ink: the pills sit on Google's light
     basemap, not on the band. */
  --dmap-pin-edge:  color-mix(in srgb, var(--white) 88%, var(--da-deep-teal));
  /* The focused listing's pin: darker rather than bigger, so it separates from
     its neighbours without moving the eye or reflowing the collision test. */
  --dmap-pin-focus: var(--da-charcoal);
  /* The approximate-area circle drawn around a focused listing. */
  --dmap-halo-fill: color-mix(in srgb, var(--da-deep-teal) 13%, transparent);
  --dmap-halo-line: color-mix(in srgb, var(--da-deep-teal) 62%, transparent);

  --dmap-border:    color-mix(in srgb, var(--da-sec-ink) 16%, transparent);
  --dmap-ground:    color-mix(in srgb, var(--da-sec-ink) 4%, transparent);
  --dmap-card-bg:   var(--da-sec-bg);
  --dmap-card-line: color-mix(in srgb, var(--da-sec-ink) 18%, transparent);
  --dmap-ctl-bg:    var(--da-sec-bg);
  /* Fallback-only: the SVG land fill and its state hairlines. Stronger than
     the 8% the first version used, which was invisible on the ink band: with no
     basemap under it, this outline IS the picture and has to carry it. */
  --dmap-land:      color-mix(in srgb, var(--da-sec-ink) 13%, transparent);
  --dmap-land-line: color-mix(in srgb, var(--da-sec-ink) 26%, transparent);

  margin: var(--sp-12) auto 0;
}

/* ── Size ──────────────────────────────────────────────────────────────────
   70% of the band's width, centred. Full bleed made the stage 1349x759 at a
   1440 viewport, where the map dominated the page instead of supporting the
   argument above it.

   Only above 1000px, and that floor is not cosmetic. The script switches to
   compact pill metrics and drops country-level pills below a 520px STAGE
   (COMPACT_PX in marketing/listings_map.js), so shrinking a tablet's map by a
   further 30% would silently turn its price labels off. At a 1000px viewport
   the wrap is ~924px and 70% of it is ~647px, which stays clear of that. Below
   the break there is no width to spare anyway. */
@media (min-width: 1000px) {
  .dmap { max-width: 70%; }
}

/* ── The stage ─────────────────────────────────────────────────────────────
   A hairline box on ALL FOUR SIDES with an even radius. Not a coloured edge
   accent: this codebase bans those, and a map needs a frame, not a stripe. */
.dmap__stage {
  position: relative;
  overflow: hidden;
  border: 1px solid var(--dmap-border);
  border-radius: var(--radius-card);
  background: var(--dmap-ground);
  /* The outline's own view rect (see marketing_map:build). Held as a ratio so
     the box cannot letterbox the country. */
  /* 16:9. The contiguous 48 are roughly 2:1 in Mercator at these latitudes, so
     a taller frame spends its extra height on Canada and the Gulf of Mexico.
     16:9 is the closest familiar ratio that still leaves the northern pills
     room above their listings. */
  aspect-ratio: 16 / 9;
}
/* Google's own gestureHandling: "cooperative" decides what touch and wheel do
   (a plain wheel scrolls the page, ctrl+wheel zooms, one finger scrolls and two
   pan), so there is deliberately no touch-action here to override it. */
/* The pointer cursor over a listing, which is the affordance that says a pin
   can be clicked.
   !important, and reaching into Google's own subtree, because neither is
   avoidable: Maps sets `cursor` as an INLINE style on its draggable div (the
   grab hand), and an inline style beats any selector that is not important. A
   rule on .dmap__stage alone changes nothing, because the pointer is never over
   the stage itself, it is over Google's div. */
.dmap__stage.is-pointing,
.dmap__stage.is-pointing .dmap__map,
.dmap__stage.is-pointing .dmap__map * { cursor: pointer !important; }

/* Google mounts into this. It fills the stage, and the canvas sits on top. */
.dmap__map {
  position: absolute;
  inset: 0;
  z-index: 1;
}
/* Google's default light basemap has a white-ish ground; keep the frame's own
   ground behind it so the box is never briefly transparent while tiles load. */
.dmap__map:empty { background: var(--dmap-ground); }

/* Every pin on the map. pointer-events: none so Google keeps its drag and
   pinch; the module listens on the stage and hit-tests in JS. */
.dmap__pins {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
}

/* ── The fallback picture ──────────────────────────────────────────────────
   Hidden until the script finds no Maps API. Same box, same canvas of pins,
   just no basemap and no zoom. */
.dmap__svg {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: block;
  width: 100%;
  height: 100%;
}
.dmap__land path {
  fill: var(--dmap-land);
  stroke: var(--dmap-land-line);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}
/* A still picture must not advertise gestures it does not have, and its zoom
   buttons do nothing. */
.dmap.is-static .dmap__hint,
.dmap.is-static .dmap__ctl { display: none; }

/* ── The hover card ────────────────────────────────────────────────────────
   Positioned by the script in stage coordinates; it flips side and edge so it
   can never leave the frame. */
.dmap__card {
  position: absolute;
  z-index: 4;
  min-width: 148px;
  max-width: 232px;
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--dmap-card-line);
  border-radius: var(--radius-tile);
  background: var(--dmap-card-bg);
  box-shadow: 0 8px 24px color-mix(in srgb, var(--da-charcoal) 14%, transparent);
  pointer-events: none;
  /* Opacity only. A card that slides toward the cursor lags behind it. */
  opacity: 0;
  transition: opacity var(--dur-hover-out) var(--ease-out);
}
.dmap__card.is-on { opacity: 1; }
.dmap__card-value {
  display: block;
  font-family: var(--font-brand);
  font-size: var(--da-lede);
  font-weight: var(--fw-bold);
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: var(--da-sec-ink);
}
.dmap__card-type {
  display: block;
  margin-top: var(--sp-1);
  font-family: var(--font-brand);
  font-size: var(--da-eyebrow);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tk-eyebrow);
  text-transform: uppercase;
  color: var(--da-sec-accent);
}
.dmap__card-place {
  display: block;
  margin-top: var(--sp-2);
  font-family: var(--font-brand);
  font-size: var(--e-meta);
  line-height: 1.35;
  color: var(--da-sec-muted);
}

/* ── The focus panel ───────────────────────────────────────────────────────
   Rises at the bottom of the frame when a listing is focused, carrying the
   same information /explore's dock does, in the same words: what it is, that
   its location is approximate and by how much, its figure, and the way through
   to the real listing.

   Its colours come from the band like the rest of the module's furniture,
   rather than being pinned white the way /explore's card is. /explore has its
   own light chrome; here the panel floats over a grey basemap inside an ink
   band, and charcoal-on-light is the contrast that belongs. */
.dmap__panel {
  position: absolute;
  z-index: 6;
  left: 50%;
  bottom: var(--sp-4);
  transform: translate(-50%, 8px);
  width: min(420px, calc(100% - var(--sp-8)));
  padding: var(--sp-4) var(--sp-5);
  border: 1px solid var(--dmap-card-line);
  border-radius: var(--radius-card);
  background: var(--dmap-card-bg);
  box-shadow: 0 12px 34px color-mix(in srgb, var(--da-charcoal) 26%, transparent);
  opacity: 0;
  pointer-events: none;
  transition:
    opacity var(--dur-card) var(--ease-out),
    transform var(--dur-card) var(--ease-out);
}
.dmap__panel.is-on {
  opacity: 1;
  transform: translate(-50%, 0);
  pointer-events: auto;
}
.dmap__panel-head { display: flex; align-items: flex-start; gap: var(--sp-3); }
.dmap__panel-title {
  flex: 1 1 auto;
  font-family: var(--font-brand);
  font-size: var(--da-h3);
  font-weight: var(--fw-bold);
  line-height: 1.15;
  letter-spacing: -0.02em;
  color: var(--da-sec-ink);
}
.dmap__panel-close {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border: 1px solid var(--dmap-card-line);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--da-sec-muted);
  cursor: pointer;
  transition: border-color var(--dur-hover-out) var(--ease-out), color var(--dur-hover-out) var(--ease-out);
}
.dmap__panel-close:hover { border-color: var(--da-sec-accent); color: var(--da-sec-ink); }
.dmap__panel-close:focus-visible { outline: none; box-shadow: var(--nav-focus-ring); }
.dmap__panel-close .ico { width: 13px; height: 13px; }
.dmap__panel-where {
  margin: var(--sp-2) 0 0;
  font-family: var(--font-brand);
  font-size: var(--e-meta);
  line-height: 1.4;
  color: var(--da-sec-muted);
}
.dmap__panel-figures {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  margin-top: var(--sp-3);
}
.dmap__panel-price {
  font-family: var(--font-brand);
  font-size: var(--da-h3);
  font-weight: var(--fw-bold);
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--da-sec-ink);
}
.dmap__panel-price-label,
.dmap__panel-stats {
  font-family: var(--font-brand);
  font-size: var(--e-meta);
  color: var(--da-sec-muted);
}
.dmap__panel-stats { margin-left: auto; }
.dmap__panel-cta { margin-top: var(--sp-4); }

/* ── Reset view ────────────────────────────────────────────────────────────
   Top centre, and shown only while the camera is off its home framing, which
   is the only time it has anything to do. */
.dmap__reset {
  position: absolute;
  z-index: 5;
  top: var(--sp-4);
  left: 50%;
  transform: translateX(-50%);
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-4);
  border: 1px solid var(--dmap-card-line);
  border-radius: var(--radius-pill);
  background: var(--dmap-card-bg);
  box-shadow: 0 4px 16px color-mix(in srgb, var(--da-charcoal) 18%, transparent);
  font-family: var(--font-brand);
  font-size: var(--e-meta);
  font-weight: var(--fw-semibold);
  color: var(--da-sec-ink);
  cursor: pointer;
}
.dmap__reset:hover { border-color: var(--da-sec-accent); }
.dmap__reset:focus-visible { outline: none; box-shadow: var(--nav-focus-ring); }
.dmap__reset kbd {
  font-family: var(--font-brand);
  font-size: var(--da-eyebrow);
  font-weight: var(--fw-medium);
  color: var(--da-sec-muted);
}

/* ── The pin key ───────────────────────────────────────────────────────────
   On the map, top left, the way /explore's is. A FILLED pill against an
   OUTLINED one, because that is what the two pins look like: an earlier
   version of /explore's used two blank white pills and read as a pair of
   toggle switches. */
.dmap__key {
  position: absolute;
  z-index: 5;
  top: var(--sp-4);
  left: var(--sp-4);
  display: grid;
  gap: 5px;
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--dmap-card-line);
  border-radius: var(--radius-tile);
  background: var(--dmap-card-bg);
  box-shadow: 0 4px 16px color-mix(in srgb, var(--da-charcoal) 14%, transparent);
  font-family: var(--font-brand);
  font-size: var(--e-meta);
  color: var(--da-sec-ink);
}
.dmap__key-title {
  font-size: var(--da-eyebrow);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tk-eyebrow);
  text-transform: uppercase;
  color: var(--da-sec-muted);
}
.dmap__key-row { display: flex; align-items: center; gap: var(--sp-2); }
.dmap__key-swatch {
  flex: 0 0 auto;
  width: 26px;
  height: 14px;
  border-radius: var(--radius-pill);
  border: 1.5px solid var(--dmap-pin);
}
.dmap__key-swatch--asking { background: var(--dmap-pin); }
/* The near-white the canvas actually fills an outlined pill with, NOT the
   panel's background: on the ink band those are charcoal and near-white, and a
   key that shows the wrong one of the two is worse than no key. */
.dmap__key-swatch--revenue { background: var(--dmap-pin-edge); }
.dmap__key-swatch--dot {
  width: 14px;
  height: 14px;
  background: var(--dmap-pin);
  border-color: transparent;
}
/* "What am I seeing?" carries the geomask explanation, which is the single
   most important thing this map has to be able to say about itself. Opens
   DOWNWARD, because the key sits at the top of the frame. */
.dmap__key-help {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  color: var(--da-sec-muted);
  cursor: help;
}
.dmap__key-help .ico { width: 13px; height: 13px; flex: 0 0 auto; }
.dmap__key-pop {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  width: 258px;
  padding: var(--sp-3);
  border: 1px solid var(--dmap-card-line);
  border-radius: var(--radius-tile);
  background: var(--dmap-card-bg);
  box-shadow: 0 10px 28px color-mix(in srgb, var(--da-charcoal) 26%, transparent);
  font-size: var(--e-meta);
  line-height: 1.45;
  color: var(--da-sec-body);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur-hover-out) var(--ease-out), visibility var(--dur-hover-out);
}
.dmap__key-help:hover .dmap__key-pop,
.dmap__key-help:focus-visible .dmap__key-pop { opacity: 1; visibility: visible; }
.dmap__key-pop strong { font-weight: var(--fw-semibold); color: var(--da-sec-ink); }

/* The key, the reset control and the panel are chrome, not the picture: a
   still fallback has no focus interaction and no two kinds of pin to key. */
.dmap.is-static .dmap__key,
.dmap.is-static .dmap__reset,
.dmap.is-static .dmap__panel { display: none; }

/* ── Controls ──────────────────────────────────────────────────────────────── */
.dmap__ctl {
  position: absolute;
  z-index: 5;
  right: var(--sp-4);
  bottom: var(--sp-4);
  display: flex;
  flex-direction: column;
  gap: 1px;
  border: 1px solid var(--dmap-border);
  border-radius: var(--radius-input);
  overflow: hidden;
  background: var(--dmap-border);
}
.dmap__btn {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border: 0;
  padding: 0;
  background: var(--dmap-ctl-bg);
  color: var(--da-sec-ink);
  cursor: pointer;
  transition: background var(--dur-hover-out) var(--ease-out);
}
.dmap__btn:hover { background: color-mix(in srgb, var(--da-sec-accent) 12%, var(--da-sec-bg)); }
.dmap__btn:focus-visible { outline: none; box-shadow: var(--nav-focus-ring); }
.dmap__btn[disabled] { opacity: 0.4; cursor: default; }
.dmap__btn .ico { --ico: 16px; width: 16px; height: 16px; }
.dmap__btn--reset { font-family: var(--font-brand); font-size: var(--da-eyebrow); font-weight: var(--fw-semibold); }

/* ── Caption + legend ─────────────────────────────────────────────────────── */
.dmap__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-3) var(--sp-8);
  margin-top: var(--sp-5);
}
.dmap__count {
  font-family: var(--font-brand);
  font-size: var(--da-body);
  font-weight: var(--fw-semibold);
  color: var(--da-sec-ink);
}
.dmap__count b { font-weight: var(--fw-bold); color: var(--da-sec-accent); }
.dmap__hint {
  font-family: var(--font-brand);
  font-size: var(--e-meta);
  color: var(--da-sec-muted);
}
/* Two hints, because the gestures are not the same. A phone has no ctrl key and
   no hover, and telling a thumb to "hold ctrl while scrolling" is worse than
   saying nothing. Keyed on `hover: none` as well as width so a touch laptop
   gets the honest one. */
.dmap__hint--touch { display: none; }
@media (hover: none), (max-width: 599px) {
  .dmap__hint--wide { display: none; }
  .dmap__hint--touch { display: inline; }
}
/* No `margin-left: auto`. Pushing the legend to the far right looks right only
   while the whole footer fits one line; once the stage narrowed to 70% it
   wrapped, and a right-aligned fragment alone on the second line reads as a
   mistake. Flowing inline after the hint means it wraps left-aligned with
   everything else at every width. */
.dmap__legend {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  font-family: var(--font-brand);
  font-size: var(--da-eyebrow);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tk-eyebrow);
  text-transform: uppercase;
  color: var(--da-sec-muted);
}
.dmap__legend span { display: inline-flex; align-items: center; gap: var(--sp-2); }
.dmap__legend i {
  width: 8px;
  height: 8px;
  border-radius: var(--radius-pill);
  background: var(--dmap-pin);
}

/* The accessible equivalent of the picture: the per-state tally, server
   rendered, so a screen reader and a crawler both get the claim the map makes.
   Not display:none — that would take it out of the accessibility tree too. */
.dmap__sr {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ── Empty and failed states ───────────────────────────────────────────────
   The section renders its heading before the feed lands, so the stage needs
   something to say while it is empty. A failed fetch keeps the note visible;
   the module never shows a blank frame. */
.dmap__note {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: grid;
  place-items: center;
  padding: var(--sp-6);
  text-align: center;
  font-family: var(--font-brand);
  font-size: var(--da-body);
  color: var(--da-sec-muted);
  transition: opacity var(--dur-card) var(--ease-out);
}
.dmap.is-ready .dmap__note { opacity: 0; pointer-events: none; }

/* The optional thesis line between the title and the blurb: the sentence the
   map is evidence FOR. It takes the band's accent (amber on ink at 5.16:1, deep
   teal on bone at 4.9:1), which is why it is a role token and not a literal. */
.dmap__claim {
  margin: var(--sp-5) 0 0;
  max-width: 40em;
  font-family: var(--font-brand);
  font-size: var(--da-lede);
  font-weight: var(--fw-semibold);
  line-height: 1.45;
  color: var(--da-sec-accent);
}
.da-sec--ink .dmap__claim { color: var(--da-amber); }

.dmap__cta { margin: var(--sp-8) 0 0; }

/* ── Motion ────────────────────────────────────────────────────────────────
   Gated on .da-motion exactly like every other marketing reveal, so it is armed
   before first paint and disarmed if the script never reports in.

   A single fade, not the staged bloom an SVG could have had: the pins are
   canvas pixels, which CSS cannot animate individually, and animating the
   canvas ELEMENT would fade the basemap with it. The basemap has its own tile
   fade anyway, so a second one on top reads as slow rather than considered.

   .da-motion--quiet (the visitor has Reduce Motion on) shortens it to a plain
   linear fade. There is no travel or scale here to remove. */
.da-motion .dmap__map,
.da-motion .dmap__pins,
.da-motion .dmap__svg { opacity: 0; }
.dmap.is-shown .dmap__map,
.dmap.is-shown .dmap__pins,
.dmap.is-shown .dmap__svg {
  opacity: 1;
  transition: opacity var(--dur-reveal) var(--ease-reveal);
}
.dmap.is-shown .dmap__pins { transition-delay: 160ms; }
.da-motion--quiet .dmap.is-shown .dmap__map,
.da-motion--quiet .dmap.is-shown .dmap__pins,
.da-motion--quiet .dmap.is-shown .dmap__svg {
  transition: opacity 360ms linear;
}

/* ── Responsive ────────────────────────────────────────────────────────────
   The country is a 1.7:1 shape, so the stage keeps its ratio and only the
   furniture moves. Below the tablet break the legend drops under the count and
   the pills are suppressed by the script (they need room to be readable). */
@media (max-width: 899px) {
  .dmap { margin-top: var(--sp-10); }
  .dmap__card { max-width: 190px; }
}
@media (max-width: 599px) {
  /* 16:9 is barely 190px tall on a phone, too short to read a country in. But a
     PORTRAIT frame is worse: the lower 48 are a 2:1 shape, so fitting them
     across a 300px width draws them 150px tall and every pixel of height past
     that is Canada and the Gulf of Mexico. 5:4 is the compromise, and it wastes
     about 90px against the 224 a 4:5 frame did. */
  .dmap__stage { aspect-ratio: 5 / 4; }
  .dmap__ctl { right: var(--sp-3); bottom: var(--sp-3); }
  .dmap__btn { width: 32px; height: 32px; }
  .dmap__foot { gap: var(--sp-2) var(--sp-5); }
  /* Touch has no hover, so the card only ever appears on a tap; keep it small
     enough not to cover the market being tapped. */
  .dmap__card { max-width: 168px; padding: var(--sp-2) var(--sp-3); }
}
