/* ============================================================
   GTA V — Los Santos interactive map
   Same HUD tokens as the rest of the site. Sidebar = quiet
   instrument panel, map = hero. No gradients, hairline borders.
   This module is map-only: GTA V has no checklist page, so the
   map itself is the tracker.
   ============================================================ */

:root {
  --bg:      #111214;
  --panel:   #1A1C20;
  --panel-2: #1F2126;
  --text:    #EDEAE2;
  --muted:   #868D98;
  /* GTA V accent — the green of the game's own HUD/logo, cooled toward the
     teal end so it never reads as San Andreas' leaf green in the game switcher */
  --accent:  #3FBF9F;
  --accent-hi: #6cd4ba;
  --accent-rgb: 63,191,159;
  --line:    #2A2D33;

  --water:   #0d1a26;

  --sans: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --display: "Anton", "Arial Narrow", Impact, var(--sans);

  --radius: 6px;
  --side-w: 342px;
}

*, *::before, *::after { box-sizing: border-box; }
html, body { height: 100%; }

body.map-page {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
}

.num { font-family: var(--mono); font-variant-numeric: tabular-nums; }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

a { color: var(--accent); text-underline-offset: 2px; }
a:hover { color: var(--accent-hi); }

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

.skip-link {
  position: absolute; left: 12px; top: -60px; z-index: 1200;
  background: var(--accent); color: #111214; font-weight: 600;
  padding: 10px 14px; border-radius: var(--radius); text-decoration: none;
  transition: top .15s;
}
.skip-link:focus { top: 12px; }

/* ---------------- Shell ---------------- */

.map-shell { display: flex; height: 100%; width: 100%; }

#map {
  flex: 1 1 auto;
  min-width: 0;
  height: 100%;
  background: var(--water);
  outline: none;
}

/* ---------------- Sidebar ---------------- */

.side {
  flex: 0 0 var(--side-w);
  width: var(--side-w);
  height: 100%;
  display: flex;
  flex-direction: column;
  background: var(--panel);
  border-right: 1px solid var(--line);
  z-index: 900;
}

.side-head { padding: 14px 16px 13px; border-bottom: 1px solid var(--line); }

.side-title-row { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; row-gap: 8px; }

.side-title {
  font-family: var(--display); font-weight: 400;
  font-size: 27px; line-height: 1.05;
  letter-spacing: .075em; text-transform: uppercase;
  margin: 0; transform: skewX(-6deg);
  flex: 1 1 auto; min-width: 0;
}

.side-nav { display: flex; align-items: center; gap: 7px; flex: none; flex-wrap: wrap; row-gap: 6px; }
.side-nav a, .side-nav span {
  font-size: 10.5px; letter-spacing: .13em; text-transform: uppercase;
  text-decoration: none; color: var(--muted);
  padding: 4px 7px; border: 1px solid var(--line); border-radius: 4px;
  white-space: nowrap;
}
.side-nav a:hover { color: var(--text); border-color: #3A3E46; }
.side-nav .here { color: #111214; background: var(--accent); border-color: var(--accent); font-weight: 600; }

.side-sub {
  margin: 7px 0 8px;
  font-size: 11.5px; color: var(--muted);
  letter-spacing: .06em; text-transform: uppercase;
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
.side-sub .dot { color: var(--line); }
.side-sub .num { color: var(--text); font-weight: 600; font-size: 12.5px; }

.side-bar { height: 4px; background: var(--line); border-radius: 2px; overflow: hidden; }
.side-bar > span { display: block; height: 100%; width: 0%; background: var(--accent); transition: width .28s ease; }

/* search */
.side-search { padding: 12px 16px; border-bottom: 1px solid var(--line); position: relative; }
.search-field { position: relative; display: flex; align-items: center; }
.search-ico { position: absolute; left: 11px; color: var(--muted); display: flex; pointer-events: none; }

.side-search input[type="search"] {
  width: 100%;
  background: #141518; border: 1px solid var(--line); color: var(--text);
  font-family: var(--sans); font-size: 14px;
  padding: 9px 12px 9px 34px; border-radius: var(--radius);
}
.side-search input[type="search"]::placeholder { color: #6C737D; }
.side-search input[type="search"]:focus { border-color: var(--accent); }

.results {
  margin: 10px -16px -12px;
  border-top: 1px solid var(--line);
  max-height: 46vh; overflow-y: auto;
}
.results[hidden] { display: none; }
.result {
  display: flex; align-items: center; gap: 10px; width: 100%;
  background: none; border: 0; border-bottom: 1px solid var(--line);
  padding: 9px 16px; text-align: left; cursor: pointer;
  color: var(--text); font-family: var(--sans); font-size: 13.5px;
}
.result:hover, .result:focus-visible { background: var(--panel-2); }
.result-meta { display: block; font-size: 11px; color: var(--muted); letter-spacing: .04em; }
.result.found .result-title { color: var(--muted); text-decoration: line-through; text-decoration-thickness: 1px; }
.results-empty { padding: 14px 16px; color: var(--muted); font-size: 13px; }
.results-more { padding: 8px 16px 10px; color: #5F656E; font-size: 11.5px; font-family: var(--mono); }

/* tree */
.side-tree { flex: 1 1 auto; overflow-y: auto; overscroll-behavior: contain; }

.grp { border-bottom: 1px solid var(--line); }
.grp-head {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 16px 8px;
}
.grp-title {
  margin: 0; flex: 1 1 auto; min-width: 0;
  font-size: 10.5px; font-weight: 600; letter-spacing: .16em;
  text-transform: uppercase; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.grp-pip { width: 8px; height: 8px; flex: none; background: var(--cat-color, var(--line)); }

/* group fold — 8 groups / 63 categories need to collapse */
.grp-toggle {
  display: flex; align-items: center; gap: 10px;
  flex: 1 1 auto; min-width: 0;
  background: none; border: 0; padding: 0; margin: 0;
  cursor: pointer; text-align: left; font: inherit; color: inherit;
}
.grp-toggle:hover .grp-title { color: var(--text); }
.grp-chev {
  flex: none; width: 12px; height: 12px;
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--muted);
  transition: transform .15s ease;
}
.grp-toggle[aria-expanded="true"] .grp-chev { transform: rotate(90deg); }
.grp-n {
  flex: none; font-size: 10.5px; color: #5F656E;
  font-variant-numeric: tabular-nums;
}
.grp.is-collapsed .grp-head { padding-bottom: 12px; }
.grp.is-collapsed .grp-actions { opacity: .35; }
.grp-actions { display: flex; align-items: center; gap: 6px; flex: none; }
.linkbtn {
  background: none; border: 0; padding: 0; cursor: pointer;
  color: var(--muted); font-family: var(--sans); font-size: 10.5px;
  letter-spacing: .08em; text-transform: uppercase;
}
.linkbtn:hover { color: var(--accent); }
.sep { color: var(--line); font-size: 10px; }

.grp-cats { padding-bottom: 8px; }

.cat {
  display: flex; align-items: center; gap: 10px; width: 100%;
  background: none; border: 0; border-left: 2px solid transparent;
  padding: 7px 16px 7px 14px;
  cursor: pointer; text-align: left;
  color: var(--text); font-family: var(--sans); font-size: 13.5px;
  transition: background .12s, opacity .12s, border-color .12s;
}
.cat:hover { background: var(--panel-2); }
.cat[aria-pressed="true"] { border-left-color: #3A3E46; }
.cat[aria-pressed="false"] { opacity: .42; }
.cat-ico {
  flex: none; width: 22px; height: 22px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 13px; color: var(--cat-color, #B9BEC7);
  background: #141518; border: 1px solid var(--line); border-radius: 50%;
  overflow: hidden;
}
/* The GTA V icons are a sprite of full-colour pins drawn at 19x22 — a hair
   taller than the 22px well once the border is counted, so they are scaled
   down rather than clipped. A transform, not a second background-size, so the
   generated rules in icons.css stay the only place a cell size lives. */
.cat-ico i { transform: scale(.74); transform-origin: center; }
.cat-title { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cat-count {
  flex: none; font-family: var(--mono); font-size: 11.5px;
  font-variant-numeric: tabular-nums; color: var(--muted); letter-spacing: -.01em;
}
.cat.done .cat-count { color: var(--accent); }
.cat.done .cat-ico { color: var(--accent); border-color: rgba(var(--accent-rgb),.4); }

.side-foot {
  flex: none; padding: 10px 16px 12px;
  border-top: 1px solid var(--line);
  color: #666C75; font-size: 11.5px;
}
.side-foot p { margin: 0 0 3px; }
.side-foot code { font-family: var(--mono); font-size: 10.5px; color: var(--muted); }

/* mobile toggle */
.side-toggle {
  display: none;
  position: absolute; left: 12px; top: 12px; z-index: 1000;
  align-items: center; gap: 8px;
  background: rgba(26,28,32,.95);
  border: 1px solid var(--line); border-radius: var(--radius);
  color: var(--text); font-family: var(--sans);
  font-size: 11.5px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase;
  padding: 9px 12px; cursor: pointer;
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
}
.side-scrim { display: none; }

/* ---------------- Markers ---------------- */

/* Compositor isolation for the marker layer.
   Measured on GTA 3: at z11 all 728 chips fit the viewport, and every drag
   frame cost 110-130ms with *zero* marker JS running — the whole bill was the
   browser re-rasterising 728 bordered, round, icon-bearing chips as the pane
   translated. Promoting the pane itself (ONE element, one extra texture) means
   its children are rasterised once and the drag only moves the finished layer.
   Deliberately just `will-change: transform`: `backface-visibility` /
   `perspective` hints are legacy WebKit workarounds, and each one is another
   property the compositor has to reason about per element. Nothing else in the
   sheet may take will-change — a hint on 2295 chips would defeat the point by
   giving each one its own layer. */
.leaflet-marker-pane { will-change: transform; }

/* Hit-testing during movement.
   Every pointermove over the map otherwise walks every marker in view — up to
   2295 interactive icons on this map — and a
   hit turns into a :hover match -> a transform transition -> a repaint, all
   while the pane is already translating. Neither hover nor a click is
   meaningful mid-gesture, so the pane simply opts out of the pointer for the
   duration. Leaflet puts `leaflet-dragging` on <body> (verified in
   vendor/leaflet.js, Draggable._onMove/finishDrag), hence the loose descendant
   selector; `is-zooming` is set by our own wheel handler on the container. */
.leaflet-dragging .leaflet-marker-pane,
.leaflet-container.is-zooming .leaflet-marker-pane { pointer-events: none; }

/* GTA V puts up to 2295 of these on screen at once — 1.6x San Andreas — so
   every declaration here is paid 2295 times on each paint. No box-shadow — a blurred layer per chip was the
   dominant paint cost while panning; the border carries the depth instead —
   and no transition outside a hover-capable pointer.
   `contain` is deliberately absent. Paint containment would clip the two things
   that overflow the 28x28 icon box, the found-check badge and the hover scale;
   layout containment would fit, but it also makes each marker a stacking
   context, and that is not a change worth making unmeasured. */
.mg-marker { background: none !important; border: 0 !important; }

.mg-chip {
  position: relative;
  width: 28px; height: 28px;
  display: flex; align-items: center; justify-content: center;
  /* Chip stays dark. In the other modules the group hue lands on the icomoon
     glyph; GTA V's icons are a fixed-colour sprite, so here the border and the
     low-zoom dot carry the hue instead (see icons.css). */
  background: #1A1C20;
  border: 1.5px solid var(--cat-line, #2A2D33);     /* subtle tint of the group hue */
  border-radius: 50%;
  color: var(--cat-color, #EDEAE2);
}
/* The sprite cell is 19.03 x 22; inside a 28px chip that leaves a ring of dark
   around it, which is what makes the coloured pin read as an icon rather than
   as a second marker. Scaled a little so the taller pins clear the border. */
.mg-chip i { transform: scale(.86); transform-origin: center; }

.leaflet-marker-icon:focus-visible .mg-chip,
.mg-marker:focus-visible .mg-chip { outline: 2px solid var(--accent); outline-offset: 2px; }

/* found state always wins over the group hue */
.mg-marker.is-found .mg-chip { opacity: .4; color: var(--accent); border-color: rgba(var(--accent-rgb),.45); }

/* Hover-only affordances, and the only transition markers carry. Scoped to real
   pointers so touch devices never hold a transition on 2295 elements, and kept
   after the found-state rule so its opacity override still wins. Nothing here
   can fire from the pane transform used during a zoom gesture — an inherited
   transform does not start a child transition, and none of these properties
   change while the pane moves. */
@media (hover: hover) {
  /* transform + border-color only. `opacity` used to be in this list, which put
     a third animatable property on every chip for the sake of a hover step
     the eye reads as instant anyway — it now snaps. Never `transition: all`:
     that makes every property a candidate and Chrome tracks the lot. */
  .mg-chip { transition: transform .1s ease, border-color .1s ease; }
  .mg-marker:hover .mg-chip { transform: scale(1.14); border-color: var(--cat-color, #4A4F58); z-index: 2; }
  .mg-marker.is-found:hover .mg-chip { opacity: .75; color: var(--accent); border-color: rgba(var(--accent-rgb),.45); }
}

.mg-check {
  position: absolute; right: -3px; bottom: -3px;
  width: 13px; height: 13px; border-radius: 50%;
  background: var(--accent); color: #111214;
  display: none; align-items: center; justify-content: center;
  font-size: 9px; font-weight: 700; line-height: 1;
  border: 1.5px solid #111214;
}
.mg-marker.is-found .mg-check { display: flex; }

.mg-marker.is-active .mg-chip {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(var(--accent-rgb),.2), 0 2px 8px rgba(0,0,0,.6);
  opacity: 1;
}

/* ---- low-zoom dot mode ---------------------------------------------------
   Below DOT_ZOOM (7 here — see the density table in map.js) a single viewport
   still holds 700+ markers, and at z3-z4 it holds essentially all 2295 —
   exactly the band where the drag lag is felt. At that scale a 19px sprite pin
   is unreadable anyway, so the chip collapses to a bare 12px
   dot: no text run to shape and raster, and the painted disc drops from
   28x28 to 12x12, roughly a fifth of the pixels, and the sprite's own image
   layer disappears with it. The group hue moves to the fill, which is the only
   place these fixed-colour icons can carry it at all, so groups stay
   distinguishable at a glance.
   `zoomed-out` is set on the map container by map.js on zoomend / gesture
   settle — never per frame. Nothing here changes geometry that Leaflet
   measures: the icon box stays 28x28 and the dot is centred inside it with a
   plain margin, so iconAnchor, popupAnchor and hit-testing are untouched. */
.leaflet-container.zoomed-out .mg-chip {
  width: 12px; height: 12px;
  margin: 8px;                                   /* (28 - 12) / 2 — stays on the anchor */
  border-width: 1px;
  border-color: #111214;
  background: var(--cat-color, #9AA1AB);
}
.leaflet-container.zoomed-out .mg-chip i { display: none; }
.leaflet-container.zoomed-out .mg-check { display: none; }

/* found: still accent, still dimmed — the one distinction worth keeping here */
.leaflet-container.zoomed-out .mg-marker.is-found .mg-chip {
  background: var(--accent); border-color: #111214; opacity: .4;
}
.leaflet-container.zoomed-out .mg-marker.is-active .mg-chip {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(var(--accent-rgb),.25);
  opacity: 1;
}
@media (hover: hover) {
  .leaflet-container.zoomed-out .mg-marker:hover .mg-chip { transform: scale(1.35); }
  .leaflet-container.zoomed-out .mg-marker.is-found:hover .mg-chip { opacity: .8; }
}

/* ---- markers over satellite imagery --------------------------------------
   The atlas tiles are flat pastel fills, so a dark chip separates from them on
   its own. The satellite pyramid is the opposite: mid-tone, high-frequency
   scrub and tarmac in roughly the same luminance band as the chip body, cut by
   near-white roads and near-black shadows. Two things fail there.

   1. The chip's border is `--cat-line`, a low-alpha tint of the group hue. It
      is a whisper against flat green and invisible against texture, so the
      only per-group cue at chip zoom disappears. On satellite the border takes
      the full `--cat-color` instead.
   2. Both the chip and the 12px dot lose their edge wherever the imagery
      happens to match them. A dark halo ring restores a constant outline over
      any background.

   Deliberately geometry-free: box-shadow paints outside the border box, and
   the border-width and 28x28 icon box are untouched, so iconAnchor, the dot's
   centring margin and hit-testing stay exactly as they are in atlas mode.
   Scoped to `.style-satellite`, set on the map container by map.js, so atlas
   mode renders byte-for-byte as before.

   Every border-colour rule below is gated on :not(.zoomed-out): in dot mode the
   border is the dark #111214 separator that holds the hue-filled disc off the
   terrain, and recolouring it to the hue would erase exactly the contrast this
   block exists to add. The halo is the dot's fix; the border is the chip's. */
.leaflet-container.style-satellite:not(.zoomed-out) .mg-chip {
  border-color: var(--cat-color, #4A4F58);
}
.leaflet-container.style-satellite .mg-chip {
  box-shadow: 0 0 0 2px rgba(10, 11, 13, .55);
}
/* Dots: a 12px hue disc sits in the same luminance band as scrub and tarmac, so
   this is the weaker case of the two. A tight ring, not the chip's 2px — at
   12px a wide halo reads as a bigger dot and the group hues start to crowd. */
.leaflet-container.style-satellite.zoomed-out .mg-chip {
  box-shadow: 0 0 0 1.5px rgba(10, 11, 13, .7);
}
/* found stays dimmed and accent-bordered; it only gains the halo */
.leaflet-container.style-satellite:not(.zoomed-out) .mg-marker.is-found .mg-chip {
  border-color: rgba(var(--accent-rgb), .55);
}
/* active already carries a ring — keep it, and seat it on the dark halo so the
   accent glow reads against bright tarmac as well as against dark water */
.leaflet-container.style-satellite:not(.zoomed-out) .mg-marker.is-active .mg-chip {
  box-shadow: 0 0 0 2px rgba(10, 11, 13, .8), 0 0 0 5px rgba(var(--accent-rgb), .3), 0 2px 8px rgba(0, 0, 0, .6);
}
.leaflet-container.style-satellite.zoomed-out .mg-marker.is-active .mg-chip {
  box-shadow: 0 0 0 1.5px rgba(10, 11, 13, .8), 0 0 0 4px rgba(var(--accent-rgb), .35);
}

/* ---------------- Popup ---------------- */

.leaflet-popup-content-wrapper {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--text);
  box-shadow: 0 10px 30px rgba(0,0,0,.6);
  padding: 0;
}
.leaflet-popup-content { margin: 0; width: 288px !important; line-height: 1.5; }
.leaflet-popup-tip { background: var(--panel); border: 1px solid var(--line); box-shadow: none; }
.leaflet-popup-close-button {
  color: var(--muted) !important;
  width: 26px !important; height: 26px !important;
  font-size: 18px !important; padding: 3px 0 0 !important;
}
.leaflet-popup-close-button:hover { color: var(--accent) !important; background: none !important; }

.pop-head { padding: 13px 34px 11px 15px; border-bottom: 1px solid var(--line); }
.pop-title { margin: 0 0 5px; font-size: 15px; font-weight: 600; line-height: 1.3; }
.pop-tags { display: flex; flex-wrap: wrap; gap: 6px; }
.pop-tag {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 11px; line-height: 1.3; padding: 3px 7px;
  border: 1px solid var(--line); border-radius: 4px;
  background: #17181C; color: var(--muted); white-space: nowrap;
}
.pop-tag i { transform: scale(.6); transform-origin: center; margin: -4px -3px; }

.pop-body {
  padding: 12px 15px;
  font-size: 13px; color: #C7CBD2;
  max-height: 260px; overflow-y: auto;
}
.pop-body > *:first-child { margin-top: 0; }
.pop-body > *:last-child { margin-bottom: 0; }
.pop-body p { margin: 0 0 .6em; }
.pop-body ul { margin: .3em 0 .7em; padding-left: 1.15em; }
.pop-body li { margin: .18em 0; }
.pop-body strong { color: var(--text); font-weight: 600; }
.pop-body em { color: #D6D9DE; font-style: italic; }
.pop-body a { color: var(--accent); }
.pop-body .pop-none { color: #5F656E; font-family: var(--mono); font-size: 12.5px; }

.pop-foot { padding: 0 15px 13px; }
.pop-btn {
  width: 100%;
  font-family: var(--sans); font-size: 12px; font-weight: 600;
  letter-spacing: .08em; text-transform: uppercase;
  color: var(--text); background: #202329;
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: 9px 12px; cursor: pointer;
  transition: background .12s, border-color .12s, color .12s;
}
.pop-btn:hover { background: #282C33; border-color: #3A3E46; }
.pop-btn[aria-pressed="true"] {
  background: var(--accent); border-color: var(--accent); color: #111214;
}
.pop-btn[aria-pressed="true"]:hover { background: var(--accent-hi); border-color: var(--accent-hi); }

/* ---------------- Leaflet chrome ---------------- */

.leaflet-container { background: var(--water); font-family: var(--sans); outline: none; }
.leaflet-container a { color: var(--accent); }

.leaflet-bar { border: 0; box-shadow: none; }
.leaflet-bar a, .leaflet-bar a:hover {
  background: rgba(26,28,32,.95);
  border: 1px solid var(--line);
  color: var(--text);
  width: 32px; height: 32px; line-height: 30px;
}
.leaflet-bar a:first-child { border-radius: var(--radius) var(--radius) 0 0; }
.leaflet-bar a:last-child { border-radius: 0 0 var(--radius) var(--radius); border-top: 0; }
.leaflet-bar a:hover { background: #282C33; color: var(--accent); }
.leaflet-bar a.leaflet-disabled { color: #4A4F58; background: rgba(26,28,32,.7); }

.leaflet-control-attribution {
  background: rgba(17,18,20,.86) !important;
  color: #666C75 !important;
  border: 1px solid var(--line); border-right: 0; border-bottom: 0;
  border-radius: var(--radius) 0 0 0;
  font-size: 10.5px; padding: 3px 8px;
}
.leaflet-control-attribution a { color: var(--muted) !important; }

/* readout */
.map-readout {
  background: rgba(17,18,20,.9);
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: 6px 10px;
  font-family: var(--mono); font-size: 11px;
  color: var(--muted); letter-spacing: .04em;
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
}
.map-readout b { color: var(--text); font-weight: 600; }

/* ---------------- Tile style switch ----------------
   The bottom-left corner holds two controls now, and Leaflet stacks corner
   controls vertically by floating them. A flex row puts the style pill beside
   the zoom readout instead of above it; the 10px gap is Leaflet's own
   `.leaflet-left .leaflet-control` margin, so nothing here re-specifies it. */
.map-shell .leaflet-bottom.leaflet-left { display: flex; align-items: flex-end; }
.map-shell .leaflet-bottom.leaflet-left > .leaflet-control { float: none; clear: none; }

.map-style {
  display: inline-flex; gap: 3px; padding: 3px;
  background: rgba(17,18,20,.9);
  border: 1px solid var(--line); border-radius: var(--radius);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
}
.map-style-btn {
  appearance: none; -webkit-appearance: none;
  border: 0; background: transparent; cursor: pointer;
  font-family: var(--mono); font-size: 10.5px; font-weight: 600;
  letter-spacing: .08em; text-transform: uppercase;
  color: var(--muted);
  padding: 4px 9px; border-radius: 4px; line-height: 1.5;
}
.map-style-btn:hover { color: var(--text); background: var(--panel-2); }
/* after :hover so the filled segment keeps the accent while the pointer is on it */
.map-style-btn[aria-pressed="true"] { background: var(--accent); color: #111214; }
.map-style-btn[aria-pressed="true"]:hover { background: var(--accent-hi); color: #111214; }
.map-style-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ---------------- Responsive ---------------- */

@media (max-width: 860px) {
  .side-toggle { display: inline-flex; }
  .map-shell { position: relative; }

  .side {
    position: absolute; left: 0; top: 0; bottom: 0;
    z-index: 1100;
    box-shadow: 0 0 40px rgba(0,0,0,.6);
    transform: translateX(-101%);
    transition: transform .2s ease;
    max-width: 86vw;
  }
  body.side-open .side { transform: translateX(0); }
  body.side-open .side-scrim {
    display: block; position: absolute; inset: 0; z-index: 1050;
    background: rgba(0,0,0,.5);
  }
  body.side-open .side-toggle { left: auto; right: 12px; }
}

@media (max-width: 420px) {
  .side-title { font-size: 23px; }
  .leaflet-popup-content { width: 240px !important; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}
