/* Styles for the map browser. Split out of index.html, which had grown to
   862 lines of markup, styles and behaviour together — most of the
   repository by volume, and where every recent bug had been. */

:root {
  --chrome: rgba(18, 20, 26, .82);
  --chrome-solid: #12141a;
  --line: rgba(255, 255, 255, .12);
  --text: #e7e9ee;
  --muted: #9aa1b0;
  --accent: #ff4d6d;
  /* Sits behind unboxed text laid directly over map tiles. The interface is
     dark throughout, so the light type needs a dark halo to hold its edge
     over pale streets and water alike. */
  --status-halo: rgba(0, 0, 0, .85);

  /* The bottom row of chrome is measured from the filter bar, so everything
     down there lines up on one centre rather than each picking its own offset.
     The bar's height is pinned rather than left to its contents, so these sums
     stay true if the icons or their padding change. */
  --bar-bottom: 34px;   /* clear of the attribution strip Leaflet pins down there */
  --bar-height: 52px;
  --btn-size: 44px;
}
* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
button, input { touch-action: manipulation; }
html, body { height: 100%; margin: 0; overscroll-behavior: none; }
body {
  font: 14px/1.4 system-ui, -apple-system, sans-serif;
  background: var(--chrome-solid);
  color: var(--text);
}

/* The map is the app; everything else floats over it. */
#map { position: fixed; inset: 0; transition: right .25s ease; }
/* With room for both, the list takes space from the map rather than covering
   it — otherwise markers sit hidden underneath and centring aims at the
   midpoint of a map that is partly off-screen. Below the breakpoint the panel
   is full width, so there is no map left to shrink and it overlays instead. */
@media (min-width: 641px) {
  body.list-open #map { right: 380px; }
}

.chrome {
  position: fixed;
  z-index: 500;
  display: flex;
  gap: 8px;
}

/* Top right: search. Above the list panel's own z-index so it stays reachable
   while the panel is open. */
#actions {
  top: calc(12px + env(safe-area-inset-top));
  right: calc(12px + env(safe-area-inset-right));
  z-index: 600;
}

/* Top left, mirroring search across the top of the map. The search field
   expands leftwards from its own button, so the two never meet: the field
   stops well short of this corner even on a narrow screen. */
#btn-list {
  position: fixed;
  z-index: 600;
  top: calc(12px + env(safe-area-inset-top));
  left: calc(12px + env(safe-area-inset-left));
}
/* Nothing to list while the view is summarised, so the control goes away
   rather than opening an empty panel. */
#btn-list.hidden { display: none; }

/* Bottom right, on the filter bar's centre line rather than its baseline.
   Both used to sit at the same distance from the bottom edge, which aligned
   their bottom edges — and since the bar is taller than the button, the button
   read as hanging off the bottom of the row. Half the height difference lifts
   it onto the same centre. */
#btn-locate {
  position: fixed; z-index: 500;
  bottom: calc(var(--bar-bottom) + (var(--bar-height) - var(--btn-size)) / 2
               + env(safe-area-inset-bottom));
  right: calc(12px + env(safe-area-inset-right));
}
/* .icon-btn.on already fills the button with the accent, so the icon has
   to contrast against it rather than match it — tinting it accent too
   made the button a solid block with nothing on it. */
#btn-locate.on { color: #fff; }
#btn-locate.busy svg { animation: spin 1s linear infinite; }
#btn-locate.denied { opacity: .45; }
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { #btn-locate.busy svg { animation: none; } }

/* The blue is conventional for "you", and deliberately unlike any category
   colour so it never reads as a venue. */
.me { }
.me-dot { background: #2f7bff; border: 2px solid #fff; border-radius: 50%;
  width: 16px; height: 16px; box-shadow: 0 0 0 1px rgba(0,0,0,.25); }

button {
  font: inherit;
  color: var(--text);
  background: var(--chrome);
  border: 1px solid var(--line);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
}
button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
button svg { width: 20px; height: 20px; flex: none; }

.icon-btn {
  width: var(--btn-size); height: var(--btn-size);
  border-radius: 12px;
  padding: 0;
  flex: none;
}
.icon-btn:disabled { opacity: .55; cursor: default; }
.icon-btn.on { background: var(--accent); border-color: var(--accent); }

/* Search slides out to the left of its button, inside the same chrome row. */
/* The field grows leftwards out of its own button. Kept in a row with it so
   stacking the list button below does not push the field onto its own line. */
.search-row { display: flex; align-items: center; gap: 8px; }

#actions input {
  /* Matched to the button it grows out of: same height, same radius, same
     translucency, so the pair reads as one control rather than a field that
     happens to sit nearby. */
  height: 44px;
  width: 0; opacity: 0; padding: 0;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--chrome);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  color: var(--text);
  font: inherit; font-size: 15px;
  /* Strips the platform's own field styling, including the inner shadow iOS
     applies and the focus ring Chrome draws in its own blue. */
  -webkit-appearance: none; appearance: none;
  outline: none;
  transition: width .22s ease, opacity .22s ease, padding .22s ease;
}
#actions input::-webkit-search-cancel-button { display: none; }
#actions input::placeholder { color: var(--muted); }
#actions.search-open input {
  width: min(240px, 52vw); opacity: 1; padding: 0 15px;
}
#actions.search-open input:focus { border-color: rgba(255, 77, 109, .55); }

/* The list panel: a vertical strip docked to the right on a laptop, wide
   enough to read a row without crowding the map; on a phone there is no
   room to spare, so it takes the full width instead. */
#list-panel {
  position: fixed; top: 0; bottom: 0; right: 0; width: 380px; max-width: 100%;
  background: var(--chrome-solid); border-left: 1px solid var(--line);
  z-index: 550; display: flex; flex-direction: column;
  transform: translateX(100%); transition: transform .25s ease;
}
#list-panel.open { transform: translateX(0); }
@media (max-width: 640px) { #list-panel { width: 100%; } }

.panel-head {
  padding: calc(68px + env(safe-area-inset-top)) 16px 12px;
  border-bottom: 1px solid var(--line); color: var(--muted); font-size: 12.5px; flex: none;
}
.panel-head b { color: var(--text); font-weight: 600; }
#list { overflow-y: auto; flex: 1; min-height: 0; }
.row { padding: 10px 16px; border-bottom: 1px solid var(--line); cursor: pointer; }
.row:hover { background: rgba(255, 255, 255, .05); }
.row.selected { background: rgba(255, 77, 109, .12); box-shadow: inset 3px 0 0 var(--accent); }
.row .n { font-weight: 600; }
.row .d { color: var(--muted); font-size: 12px; margin-top: 2px; }
.row .detail:empty { display: none; }
.row .detail { margin: 10px -16px -10px; border-top: 1px solid var(--line); }
/* The popup block, reused unchanged apart from the chrome it does not need
   here — no rounded card, no scroll cap, and it is not itself clickable. */
.row .detail .pop { padding: 12px 16px 14px; cursor: default; }
.row .detail .pop h3, .row .detail .pop .kind { display: none; }
.tag { display: inline-block; padding: 1px 6px; border-radius: 4px; background: rgba(255, 255, 255, .08); font-size: 11px; margin-right: 5px; color: var(--text); }
.swatch { display: inline-block; width: 7px; height: 7px; border-radius: 50%; margin-right: 5px; vertical-align: middle; }
.empty { padding: 20px 16px; color: var(--muted); font-size: 13px; }

/* Bottom centre: the three categories. */
#filters {
  bottom: calc(var(--bar-bottom) + env(safe-area-inset-bottom));
  height: var(--bar-height);
  align-items: center;
  left: 50%;
  transform: translateX(-50%);
  background: var(--chrome);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 6px;
  gap: 4px;
}
#filters button {
  background: transparent;
  border: none;
  backdrop-filter: none;
  border-radius: 11px;
  padding: 9px 14px;
  color: var(--muted);
  font-size: 13px;
  font-weight: 500;
}
#filters button.on { background: var(--accent); color: #fff; }
/* Icon-only throughout. A label would need translating; a fork and a beer
   glass would not. The accessible name lives in aria-label instead. */
#filters button span { display: none; }

/* Unobtrusive readout, top left. */
/* The count sits over the map directly above the filter bar, sharing its
   centre line so the two read as one stack.
   
   Deliberately unboxed: it is a single number that changes as the map moves,
   and a panel around it added a second piece of chrome competing with the bar
   below it. Without a background it has to carry its own contrast, hence the
   halo — map tiles run pale through towns and dark over water, so the type
   cannot rely on what is behind it.
   
   Not interactive, so it must never intercept a drag aimed at the map. */
#status {
  position: fixed;
  z-index: 500;
  /* Sits a clear gap above the bar rather than a hardcoded offset that has to
     be re-derived whenever the bar moves. */
  bottom: calc(var(--bar-bottom) + var(--bar-height) + 10px
               + env(safe-area-inset-bottom));
  left: 50%;
  transform: translateX(-50%);
  padding: 0;
  font-size: 13px;
  color: var(--muted);
  max-width: 90vw;
  text-align: center;
  pointer-events: none;
  white-space: nowrap;
  text-shadow: 0 1px 3px var(--status-halo), 0 0 8px var(--status-halo);
}
#status b { color: var(--text); font-weight: 700; font-size: 15px; font-variant-numeric: tabular-nums; }
#status span { color: var(--muted); font-variant-numeric: tabular-nums; }

/* Leaflet's own chrome, kept out of the way of ours. */
.leaflet-control-zoom { display: none; }
.leaflet-control-attribution {
  padding: 2px 6px !important;
  background: var(--chrome) !important;
  color: var(--muted) !important;
  backdrop-filter: blur(12px);
  font-size: 10px !important;
}
.leaflet-control-attribution a { color: var(--muted) !important; }
.leaflet-popup-content-wrapper, .leaflet-popup-tip {
  background: var(--chrome-solid);
  color: var(--text);
  border: 1px solid var(--line);
}
.leaflet-popup-content { margin: 0; font-size: 13px; }
.leaflet-popup-scrolled { overflow-y: auto; border-bottom: none !important; border-top: none !important; }
.leaflet-popup.detail .leaflet-popup-content-wrapper { border-radius: 12px; }
.pop { padding: 14px 16px; cursor: pointer; }
.pop h3 { margin: 0 0 2px; font-size: 15px; line-height: 1.25; }
.pop .kind { margin: 0 0 8px; color: var(--accent); font-size: 11px;
  text-transform: uppercase; letter-spacing: .06em; }
.pop p { margin: 0 0 6px; }
.pop .addr { color: var(--text); }
.pop .hours { color: var(--muted); font-variant-numeric: tabular-nums; }
.pop .links { display: flex; flex-wrap: wrap; gap: 10px; margin: 8px 0 0; }
.pop .links a, .pop dd a { color: var(--accent); }
.pop dl { display: grid; grid-template-columns: auto 1fr; gap: 2px 12px;
  margin: 12px 0 0; padding-top: 10px; border-top: 1px solid var(--line); font-size: 12px; }
.pop dt { color: var(--muted); }
.pop dd { margin: 0; overflow-wrap: anywhere; }
.leaflet-popup-content b { font-size: 14px; }
.leaflet-popup-close-button { color: var(--muted) !important; }

@media (prefers-reduced-motion: reduce) { * { transition: none !important; } }
