/* map.css -- the REAL map band: tiles, markers, puck, recenter, state overlay.
   Themed entirely with CSS variables defined in base.css (light + dark safe).
   Tier colors fall back to sane defaults so the map never renders colorless
   even if a token is missing. */

.map-band {
  position: relative;
  width: 100%;
  /* Fill the map slot the app shell gives us; base.css owns the outer frame. */
  height: var(--map-band-height, 42vh);
  min-height: 220px;
  background: var(--map-band-bg, #e9eef2);
  overflow: hidden;
  border-bottom: 1px solid var(--border, rgba(0, 0, 0, 0.08));
  isolation: isolate;            /* keep marker z-indexes contained */
}

/* The Leaflet canvas fills the band. */
.map-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  background: var(--map-band-bg, #e9eef2);
}

/* Leaflet's own controls / attribution, themed to fit. The bar paints the real
   surface rather than a translucent white: over dark tiles a see-through white
   left the dark-mode label at 1.54:1, and legal attribution has to stay
   readable in both themes. */
.map-band .leaflet-control-attribution {
  font-size: 10px;
  line-height: 1.4;
  padding: 1px 6px;
  background: var(--surface, #ffffff);
  color: var(--text-dim, #5b6470);
  border-top-right-radius: 6px;
}
.map-band .leaflet-control-attribution a {
  color: var(--brand, #2f6df0);
}

/* ---------------- User location puck ---------------- */
.map-user-icon { background: transparent; border: none; }
.map-user-puck {
  position: relative;
  display: block;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--user-puck, #2f6df0);
  border: 3px solid #fff;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25), 0 2px 6px rgba(0, 0, 0, 0.35);
}
.map-user-pulse {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  background: var(--user-puck, #2f6df0);
  opacity: 0.35;
  animation: map-pulse 2s ease-out infinite;
}
@keyframes map-pulse {
  0%   { transform: translate(-50%, -50%) scale(1);   opacity: 0.35; }
  70%  { transform: translate(-50%, -50%) scale(3.4); opacity: 0; }
  100% { transform: translate(-50%, -50%) scale(3.4); opacity: 0; }
}
.map-accuracy-ring {
  color: var(--user-puck, #2f6df0);
  fill: var(--user-puck, #2f6df0);
  stroke: var(--user-puck, #2f6df0);
}

/* ---------------- Station pins ---------------- */
.map-pin { background: transparent; border: none; }
.map-pin-body {
  position: relative;
  display: block;
  width: 30px;
  height: 42px;
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.35));
  transition: transform 0.12s ease;
  transform-origin: 50% 100%;
}
.map-pin-shape {
  fill: var(--pin-color, var(--tier-unrated, #636e7d));
  stroke: rgba(0, 0, 0, 0.25);
  stroke-width: 1;
}
.map-pin-dot {
  fill: #fff;
  opacity: 0.95;
}
.map-pin-glyph {
  position: absolute;
  left: 0;
  top: 0;
  width: 30px;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  font: 700 13px/1 system-ui, sans-serif;
  /* The glyph sits on .map-pin-dot, which is white in BOTH themes, so it must
     NOT follow --pin-color: the dark tier tokens are tuned to sit on a dark
     surface and the dark unrated gray lands at 3.59:1 on white. The light tier
     values are the ones tuned against white, so the glyph takes a literal in
     both themes. Measured against the backdrop that actually renders, not
     against pure white: only unrated pins draw a glyph, and their dot is 85%
     opaque (below), so the real backdrop is white composited over the unrated
     fill -- #e8e9ec light, #ecedef dark. #606a79 clears both at 4.51:1 and
     4.67:1 (5.48:1 on pure white). */
  color: #606a79;
  pointer-events: none;
}

/* Unrated pins read as hollow/neutral -- cold-start honesty. */
.map-pin.is-unrated .map-pin-shape {
  fill: var(--tier-unrated, #636e7d);
  stroke-dasharray: 2 2;
}
.map-pin.is-unrated .map-pin-dot { opacity: 0.85; }

/* Selected / previewed pin lifts and grows. */
.map-pin.is-selected .map-pin-body {
  transform: scale(1.22) translateY(-2px);
}
.map-pin.is-selected .map-pin-shape {
  stroke: #fff;
  stroke-width: 2;
}

/* Best-overall rated stop -- the crown + a soft glow ring. */
.map-pin-crown {
  position: absolute;
  left: 50%;
  top: -12px;
  transform: translateX(-50%);
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.4));
  z-index: 2;
}
.map-pin.is-best .map-pin-body {
  filter: drop-shadow(0 0 0 2px rgba(244, 194, 13, 0.9))
          drop-shadow(0 2px 4px rgba(0, 0, 0, 0.4));
}

/* Trip route line. map.js hands Leaflet a literal brand hex as the stroke
   presentation attribute; this CSS beats that attribute, so the line follows the
   theme token instead of staying light-mode blue on a dark map. */
.map-route-line {
  stroke: var(--brand, #2f6df0);
}

/* ---------------- Recenter control (thumb zone) ---------------- */
.map-recenter {
  position: absolute;
  right: 12px;
  bottom: 14px;
  z-index: 600;                 /* above Leaflet panes (markers ~600) */
  width: 46px;
  height: 46px;
  border-radius: 50%;
  border: 1px solid var(--border, rgba(0, 0, 0, 0.12));
  background: var(--surface, #fff);
  color: var(--accent, #2f6df0);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.22);
  -webkit-tap-highlight-color: transparent;
  transition: transform 0.08s ease, background 0.15s ease;
}
/* --surface-hover is not a base.css token, so its literal was the value that
   actually shipped -- a light grey that washed out on a dark map. */
.map-recenter:hover { background: var(--surface-2, #f0f2f5); }
.map-recenter:active { transform: scale(0.94); }
.map-recenter:disabled {
  opacity: 0.45;
  cursor: default;
  color: var(--text-muted, #9aa0a6);
}

/* ---------------- State overlay (locating / denied / error / empty) ----- */
.map-overlay {
  position: absolute;
  inset: 0;
  z-index: 500;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  pointer-events: none;          /* let the real map stay draggable */
  background: var(--map-overlay-scrim, rgba(233, 238, 242, 0.55));
  backdrop-filter: blur(1px);
}
.map-overlay[hidden] { display: none; }
.map-overlay-card {
  pointer-events: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  max-width: 280px;
  text-align: center;
  padding: 16px 18px;
  border-radius: 14px;
  background: var(--surface, #fff);
  color: var(--text, #1c1f23);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
  border: 1px solid var(--border, rgba(0, 0, 0, 0.08));
}
.map-overlay-icon { color: var(--accent, #2f6df0); line-height: 0; }
.map-overlay[data-kind="denied"] .map-overlay-icon,
.map-overlay[data-kind="error"] .map-overlay-icon {
  color: var(--tier-poor, #c63127);
}
.map-overlay-text {
  font: 500 14px/1.4 system-ui, sans-serif;
  color: var(--text, #1c1f23);
}

.map-spin { animation: map-rotate 0.9s linear infinite; }
@keyframes map-rotate { to { transform: rotate(360deg); } }

/* Hard-unavailable band (Leaflet failed to load). */
.map-band--unavailable { display: flex; align-items: center; justify-content: center; }
.map-band--unavailable .map-overlay { background: transparent; backdrop-filter: none; }

/* ---------------- Dark theme niceties ---------------- */
@media (prefers-color-scheme: dark) {
  .map-band {
    --map-band-bg: #1b1f24;
    --map-overlay-scrim: rgba(20, 23, 27, 0.55);
  }
  /* Mute raw OSM tiles slightly so bright tiles do not fight a dark UI. */
  .map-band .leaflet-tile-container img {
    filter: brightness(0.9) contrast(1.02);
  }
}

/* Respect reduced-motion users -- kill the pulse + spin animations. */
@media (prefers-reduced-motion: reduce) {
  .map-user-pulse { animation: none; opacity: 0; }
  .map-spin { animation: none; }
  .map-pin-body { transition: none; }
}
