/* ============================================================
   Saint Denis — Red Dead Redemption 2 interactive map
   Same HUD tokens as the checklist. Sidebar = quiet instrument
   panel, map = hero. No gradients, hairline borders.
   ============================================================ */

:root {
  --bg:      #111214;
  --panel:   #1A1C20;
  --panel-2: #1F2126;
  --text:    #EDEAE2;
  --muted:   #868D98;
  /* Red Dead Redemption 2 accent — sage chartreuse, matched to styles.css */
  --accent:  #A6BF4B;
  --accent-hi: #C4DA6A;
  --accent-rgb: 166,191,75;
  --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: 330px;
}

*, *::before, *::after { box-sizing: border-box; }
/* The `hidden` attribute must win over any `display` this file sets. The UA's
   `[hidden] { display: none }` is a user-agent rule, so any author rule setting
   `display` on the same element beats it regardless of specificity; that is how
   an undismissable modal shipped on the hub. `.results[hidden]` and
   `.mbar-n[hidden]` below are the narrow patches this replaces. */
[hidden] { display: none !important; }

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%;
}
.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, glyph-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 728 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 728 interactive icons, 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; }

/* Up to 728 of these are on screen at once, so every declaration here is paid
   728 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;
  background: #1A1C20;                              /* chip stays dark — glyph carries the hue */
  border: 1.5px solid var(--cat-line, #2A2D33);     /* subtle tint of the group hue */
  border-radius: 50%;
  color: var(--cat-color, #EDEAE2);
}
.mg-chip i { font-size: 14px; line-height: 1; display: block; color: inherit; }

.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 728 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 all 728 chips 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 zoom 12 the whole city is on screen and all 728 chips are painted at
   once — exactly the band where the drag lag was felt. At that scale a 14px
   icomoon glyph 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. The hue moves from the glyph
   to the fill so categories stay distinguishable.
   `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 amber, 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; }
}

/* ---------------- 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;
  overflow: hidden;              /* clips a screenshot to the rounded corners */
}
.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; }

/* Screenshot. Fixed 16:9 box so the popup does not reflow as the lazy image
   arrives; `contain` rather than `cover` because a minority of shots are not
   16:9 and cropping one could cut out the very thing it is pointing at. */
.pop-shot {
  position: relative;
  aspect-ratio: 16 / 9;          /* fallback; the real ratio is set inline */
  max-height: min(320px, 38vh);  /* portrait shots ate 75% of a 667px-tall phone */
  background: var(--bg);
  border-bottom: 1px solid var(--line);
  overflow: hidden;
}
.pop-shot img {
  display: block;
  width: 100%; height: 100%;
  object-fit: contain;
}
/* The close button sits over the image; this keeps it legible on a light shot. */
.pop-shot::after {
  content: '';
  position: absolute; inset: 0 0 auto 0; height: 40px;
  background: linear-gradient(rgba(17,18,20,.55), rgba(17,18,20,0));
  pointer-events: none;
}
@supports not (aspect-ratio: 16 / 9) {
  .pop-shot { height: 162px; }        /* 288px content width at 16:9 */
}

.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 { font-size: 11px; }

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

  /* iOS Safari zooms the page on focus for any field under 16px */
  .side-search input[type="search"] { font-size: 16px; }

  /* 10.5px text is a ~13px tap target */
  .linkbtn { display: inline-flex; align-items: center; min-height: 44px; padding: 0 8px; }
  /* the 44px .linkbtn would otherwise push these to 64px; 8 groups of that is a lot of drawer */
  .grp-head, .grp.is-collapsed .grp-head { padding-top: 2px; padding-bottom: 2px; }
}

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

/* ---------------- Account sync chip (spec 10.1) ---------------- */

/* The chip is absolutely positioned against the shell. The 860px block above
   already sets this; saying it unconditionally means the chip does not quietly
   fall back to the viewport at desktop widths. */
.map-shell { position: relative; }

/* SITE CHROME, NOT THE GAME: Waypoint's violet, never var(--accent). */
.wp-sync {
  --wp: #8A7CFF;
  --wp-problem: #FF8A75;
  display: none;
}

/* Pinned top-right of the canvas, a SIBLING OF #map like .side-toggle, never
   inside a Leaflet pane.
   CLEAR OF THE ZOOM CONTROL: map.js calls zoomControl.setPosition('topright')
   on all five maps, and that control is two 32px buttons at right:10px /
   top:10px, so it owns x = 10..42. right:52px is that edge plus a 10px gutter. */
.wp-sync[data-state] {
  display: flex; align-items: center;
  position: absolute; top: 12px; right: 52px; z-index: 1000;
  height: 30px; padding: 0 11px;
  background: rgba(26,28,32,.95);
  border: 1px solid var(--line); border-radius: var(--radius);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
}

.wp-sync-face {
  position: relative;
  display: inline-flex; align-items: center; gap: 7px;
  height: 22px; padding: 0;
  background: none; border: 0;
  font-family: var(--sans);
  font-size: 10.5px; font-weight: 600;
  letter-spacing: .13em; text-transform: uppercase;
  color: var(--muted);
  text-decoration: none;
}
/* 44px hit area grown OUTSIDE layout, so the visible box stays 22px inside a
   30px chip: -11px on each side of 22px is 44px. */
.wp-sync-face::after { content: ""; position: absolute; inset: -11px; }

button.wp-sync-face { cursor: pointer; }
button.wp-sync-face:hover, a.wp-sync-face:hover { color: var(--text); }

.wp-sync-dot { flex: none; width: 7px; height: 7px; border-radius: 50%; background: var(--wp); }
.wp-sync[data-state="problem"] .wp-sync-dot { background: var(--wp-problem); }
.wp-sync[data-state="signedout"] .wp-sync-dot {
  background: none; box-shadow: inset 0 0 0 1.5px var(--wp);
}

/* THE ONLY ANIMATED PROPERTY ON THIS PAGE, on one 7px dot. No will-change --
   the marker pane above is the only element in this sheet allowed one, and a
   second compositor layer would be paid on every frame of every gesture. */
@keyframes wp-sync-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .28; } }
.wp-sync[data-state="syncing"] .wp-sync-dot {
  animation: wp-sync-pulse 1.1s ease-in-out infinite;
}

/* Killed during gestures, so nothing animates while the map is moving.
   `leaflet-dragging` really is on <body> (Draggable._onMove in vendor), so a
   descendant selector reaches this. `is-zooming` IS NOT: map.js puts it on
   map.getContainer(), i.e. #map itself, and a container-scoped selector cannot
   reach a sibling -- so the only thing that works is the general sibling
   combinator, which is why the chip is placed AFTER #map in the markup.
   Only the animation stops. Nothing is hidden, moved or re-laid-out. */
body.leaflet-dragging .wp-sync .wp-sync-dot,
#map.is-zooming ~ .wp-sync .wp-sync-dot { animation: none; }

@media (max-width: 860px) {
  /* Below 860px the sidebar is a drawer and the Layers button moves to
     right:12px, ~34px tall from top:12px. The chip steps under it rather than
     colliding with it. */
  body.side-open .wp-sync[data-state] { top: 66px; }
}
