/* Force the [hidden] attribute to win against inline display:flex /
   display:grid declarations. Several panels / banners / toasts ship
   with inline `display: flex` and toggle visibility via `el.hidden =
   true`, which silently fails because inline `display` beats the UA's
   `[hidden] { display: none }`. !important here means setting `hidden`
   actually hides the element regardless of its inline display value. */
[hidden] { display: none !important; }

/* The MapLibre-provided GeolocateControl is added to the map (so
   .trigger() works + the accuracy circle layer registers) but its
   default top-right button is hidden — we expose location via the
   custom #locate-me button in the right-rail instead, so it sits
   alongside zoom / layer / share for visual consistency. */
.maplibregl-ctrl-top-right .maplibregl-ctrl-geolocate,
.maplibregl-ctrl-top-right .maplibregl-ctrl-group:has(.maplibregl-ctrl-geolocate) {
  display: none !important;
}

/* In dark mode the white rail buttons sit on the dark map base with
   no visual grouping — they read as floating dots. Wrap them in a
   subtle translucent gray pill so the column reads as a single
   control surface. Light mode keeps the existing free-standing look. */
html[data-theme="dark"] #right-rail {
  background: rgba(36, 28, 18, 0.55);
  backdrop-filter: var(--blur-glass);
  -webkit-backdrop-filter: var(--blur-glass);
  padding: 8px 6px;
  border-radius: 26px;
  border: 1px solid rgba(255, 255, 255, 0.08);
  box-shadow: var(--shadow-2);
}

/* ─── Haive desktop map — design overrides ─────────────────────────────
 * Extracted from the inline <style> block previously emitted via JS in
 * app/views/app/map/index.html.erb. Tokens come from the layout
 * (:root + [data-theme=…]); rules here only reference var(--…).
 *
 * Browser caches this file separately from the HTML so cold-load
 * payload drops by ~20 KB and a return visit hits the disk cache.
 * ─────────────────────────────────────────────────────────────────── */

/* Side panel + opposite-rail positioning. When data-panel-side is
   "right" the panel jumps to the right edge and the right-rail
   (zoom + layer + filter buttons) moves to the left edge. */
#map-area[data-panel-side='left']  #side-panel { left: 10px;  right: auto; }
#map-area[data-panel-side='left']  #right-rail { right: 16px; left: auto; }
#map-area[data-panel-side='right'] #side-panel { right: 10px; left: auto; }
#map-area[data-panel-side='right'] #right-rail { left: 16px;  right: auto; }
/* Resize handle docks on the panel's inner edge (toward the map). */
#map-area[data-panel-side='left']  #side-panel-resize { right: 0; }
#map-area[data-panel-side='right'] #side-panel-resize { left:  0; }
#side-panel-resize:hover { background: var(--brand-yellow); opacity: 0.4; }
/* Mirror the side-panel header when the panel is on the right. */
#map-area[data-panel-side='right'] #side-panel-header { flex-direction: row-reverse; }
/* Open / closed state — slide the panel off-screen on close. */
#map-area[data-panel-open='true']  #side-panel { transform: translateX(0); pointer-events: auto; }
#map-area[data-panel-open='false'][data-panel-side='left']  #side-panel { transform: translateX(calc(-100% - 20px)); pointer-events: none; }
#map-area[data-panel-open='false'][data-panel-side='right'] #side-panel { transform: translateX(calc(100% + 20px));  pointer-events: none; }
/* Tab visibility driven by data-tab-visible. */
#map-area #side-panel-tab { display: none; }
#map-area[data-tab-visible='true'] #side-panel-tab { display: flex; }
#map-area[data-panel-side='left']  #side-panel-tab { left: 0;  border-radius: 0 12px 12px 0; flex-direction: column; }
#map-area[data-panel-side='right'] #side-panel-tab { right: 0; border-radius: 12px 0 0 12px; flex-direction: column; }
/* Profile / buzz detail panels share the same edge as the around-you
   panel. The [hidden] !important is load-bearing — inline display:flex
   would otherwise beat the UA [hidden]{display:none}. */
#map-area[data-panel-side='left']  #profile-detail { left: 10px;  right: auto; }
#map-area[data-panel-side='right'] #profile-detail { right: 10px; left: auto; }
#profile-detail[hidden] { display: none !important; }
#map-area[data-panel-side='left']  #buzz-detail { left: 10px;  right: auto; }
#map-area[data-panel-side='right'] #buzz-detail { right: 10px; left: auto; }
#buzz-detail[hidden] { display: none !important; }
/* Top-to-bottom label inside the side-panel-tab. */
#side-panel-tab-label { transform: rotate(0deg); }
/* While bootstrapping (data-panel-init=true), kill transitions so
   the panel snaps to its persisted state without animating from the
   default-open position. JS removes the attribute after first paint. */
#map-area[data-panel-init='true'] #side-panel,
#map-area[data-panel-init='true'] #side-panel-tab { transition: none !important; }

/* ─── Design system overrides ─────────────────────────────────────────
   Glass surfaces, dark-mode-aware colours, spring motion, marker
   hover / active states, skeleton shimmer, polish. */

#side-panel, #profile-detail, #buzz-detail, #ai-results,
#layer-menu, #marker-filter-menu, #ai-history-menu, #address-suggestions {
  background: var(--color-surface) !important;
  backdrop-filter: var(--blur-glass);
  -webkit-backdrop-filter: var(--blur-glass);
  color: var(--color-text) !important;
  border: 1px solid var(--color-border-soft);
}
/* #address-bar is just a flex wrapper around the picker pill now;
   the visible chrome lives on #address-pill inside. Keep the wrapper
   transparent so its parent row doesn't pick up a glass card border. */
#address-bar { background: transparent !important; border: 0 !important; backdrop-filter: none; -webkit-backdrop-filter: none; }
#side-panel, #profile-detail, #buzz-detail {
  transition: transform var(--dur-panel) var(--ease-spring), opacity var(--dur-base) var(--ease-spring);
}
/* Layer menu / filter menu / history menu items respect the theme. */
#layer-menu button, #marker-filter-menu .marker-filter-row, #ai-history-menu button {
  color: var(--color-text);
  background: transparent !important;
}
#layer-menu button:hover, #marker-filter-menu .marker-filter-row:hover, #ai-history-menu button:hover {
  background: var(--color-border-soft) !important;
}
/* Right-rail buttons + zoom + theme toggle pick up theme colours. */
#right-rail button, #side-panel-tab, #side-panel-flip, #side-panel-close,
#profile-detail-back, #buzz-detail-back, #anchor-toggle {
  background: var(--color-surface) !important;
  color: var(--color-text) !important;
  backdrop-filter: var(--blur-glass);
  border: 1px solid var(--color-border-soft);
  transition: transform var(--dur-quick) var(--ease-spring), background var(--dur-quick) var(--ease-soft);
}
#right-rail button:hover, #side-panel-flip:hover, #side-panel-close:hover,
#profile-detail-back:hover, #buzz-detail-back:hover {
  transform: scale(1.06);
}
#right-rail button:active { transform: scale(0.96); }
#map-area { background: var(--color-bg); }
#ai-input, #address-input, #ai-input::placeholder, #address-input::placeholder {
  color: var(--color-text);
}
#ai-input::placeholder, #address-input::placeholder { color: var(--color-text-muted); }
/* Side-panel rows. */
#side-panel-list button, #ai-results-list button {
  transition: transform var(--dur-quick) var(--ease-spring),
              box-shadow var(--dur-quick) var(--ease-soft);
}
#side-panel-list button:hover, #ai-results-list button:hover {
  transform: translateY(-1px);
  box-shadow: var(--shadow-2);
}

/* MapLibre marker hover / active. The marker root keeps MapLibre's
   `transform: translate(x, y)`; hover + active scale targets the inner
   .haive-marker-inner instead, so we don't fight MapLibre's positioning. */
.maplibregl-marker .haive-marker-inner {
  transition: transform var(--dur-quick) var(--ease-spring);
  transform-origin: center;
  will-change: transform;
  position: relative;
}
/* Markers live on the map plane — their z-index stays in single digits
   so a hovered / active / spidered marker can never poke over the
   floating UI (side panel z:8, top-block z:9, header z:10, …). It only
   needs to clear the radius-circle overlay (z:4). */
.maplibregl-marker:hover { z-index: 5 !important; }
.maplibregl-marker:hover .haive-marker-inner { transform: scale(1.12); }
.maplibregl-marker.haive-marker-spidered { z-index: 6 !important; }
.maplibregl-marker.haive-marker-active { z-index: 7 !important; }
.maplibregl-marker.haive-marker-active .haive-marker-inner { transform: scale(1.18); }
.maplibregl-marker.haive-marker-active .haive-marker-inner > div:first-child {
  box-shadow: 0 0 0 3px var(--brand-yellow), 0 4px 14px rgba(0,0,0,0.35);
}
@keyframes haive-marker-pulse {
  0% { transform: scale(0.8); opacity: 0.6; }
  80%, 100% { transform: scale(1.9); opacity: 0; }
}
@keyframes haive-marker-arrive {
  0% { transform: scale(0.6); opacity: 0; box-shadow: 0 0 0 8px rgba(246,179,0,0.55); }
  70% { transform: scale(1.1); opacity: 1; box-shadow: 0 0 0 0 rgba(246,179,0,0); }
  100% { transform: scale(1); opacity: 1; box-shadow: 0 0 0 0 rgba(246,179,0,0); }
}
.haive-marker-arrive .haive-marker-inner > div {
  animation: haive-marker-arrive 700ms var(--ease-spring) both;
}

/* ── Density-dot mode ────────────────────────────────────────────────
   Between the cluster scale and the full-marker scale (≈ z14–16) every
   individual marker collapses to a small solid-colored dot: each marker
   carries TWO children — the dot element (first child, `display:none`
   by default) and the full marker (second child, the hexagon / bee).
   In dot mode we flip the dot on and hide the full one, mirroring the
   density-dot tier the iOS + Android maps use (separate dot views), so a
   busy neighbourhood reads as a manageable sprinkle of dots instead of a
   wall of 30px markers. `!important` because the per-state appearance is
   inline on the elements. */
.maplibregl-marker.haive-marker-dot .haive-marker-inner > div:first-child {
  display: block !important;
  width: 11px !important;
  height: 11px !important;
  border-radius: 50% !important;
  border-width: 1.5px !important;
  box-shadow: 0 1px 3px rgba(0,0,0,0.3) !important;
}
.maplibregl-marker.haive-marker-dot .haive-marker-inner > div:first-child > * { display: none !important; }
.maplibregl-marker.haive-marker-dot .haive-marker-inner > *:not(:first-child) { display: none !important; }
.maplibregl-marker.haive-marker-dot:hover .haive-marker-inner { transform: scale(1.6); }
/* No pulse ring / arrive bloom on a dot — it'd dwarf the dot itself. */
.maplibregl-marker.haive-marker-dot.haive-marker-active .haive-marker-inner::before { display: none !important; }
.maplibregl-marker.haive-marker-dot .haive-marker-inner > div:first-child {
  animation: none !important;
}
.maplibregl-marker.haive-marker-active .haive-marker-inner::before {
  content: '';
  position: absolute;
  inset: -4px;
  border-radius: 50%;
  background: var(--brand-yellow);
  animation: haive-marker-pulse 1.6s var(--ease-soft) infinite;
  z-index: -1;
  pointer-events: none;
}

/* Skeleton shimmer used while AI is thinking and while lazy
   about-fetches are in flight. */
@keyframes haive-shimmer {
  0% { background-position: -200% 0; }
  100% { background-position: 200% 0; }
}
.haive-skeleton {
  background: linear-gradient(90deg,
    var(--color-border-soft) 0%, var(--color-border) 50%, var(--color-border-soft) 100%);
  background-size: 200% 100%;
  animation: haive-shimmer 1.4s var(--ease-soft) infinite;
  border-radius: var(--r-sm);
}
/* AI results panel slide-up entrance. */
@keyframes haive-rise {
  from { transform: translateY(8px); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}
#ai-results:not([hidden]) { animation: haive-rise var(--dur-base) var(--ease-spring); }
#profile-detail:not([hidden]), #buzz-detail:not([hidden]) {
  animation: haive-rise var(--dur-panel) var(--ease-spring);
}
/* Snackbar — replaces #toast styling with bottom-left + brand pill. */
#toast {
  background: var(--color-surface) !important;
  color: var(--color-text) !important;
  border: 1px solid var(--color-border-soft);
  backdrop-filter: var(--blur-glass);
}

/* Side panel header / tabs / chrome buttons pick up tokens. */
#side-panel-header { border-bottom-color: var(--color-border-soft) !important; }
#side-panel-tabs { border-bottom-color: var(--color-border-soft) !important; }
#side-panel-count { color: var(--color-text-muted) !important; }
#side-panel-flip, #side-panel-close { background: var(--color-border-soft) !important; color: var(--color-text) !important; }
#profile-detail header, #buzz-detail header { border-bottom-color: var(--color-border-soft) !important; }
#profile-detail header { color: var(--color-text); }
#profile-detail-title, #buzz-detail-title { color: var(--color-text); }
#profile-detail-back, #buzz-detail-back { background: var(--color-border-soft) !important; color: var(--color-text) !important; }
.side-panel-tab, .profile-detail-tab {
  color: var(--color-text-soft) !important;
  transition: color var(--dur-quick) var(--ease-soft);
}
.side-panel-tab[aria-selected='true'], .profile-detail-tab[aria-selected='true'] {
  color: var(--color-text) !important;
}
/* Active-tab underline (replaces the cream-tint bg). Uses ::after so
   we don't reflow the button's box. */
.side-panel-tab, .profile-detail-tab {
  position: relative;
  background: transparent !important;
}
.side-panel-tab::after, .profile-detail-tab::after {
  content: '';
  position: absolute;
  left: 12px;
  right: 12px;
  bottom: 0;
  height: 2px;
  background: var(--brand-yellow);
  border-radius: 2px;
  transform: scaleX(0);
  transform-origin: 50% 50%;
  transition: transform var(--dur-base) var(--ease-spring);
}
.side-panel-tab[aria-selected='true']::after,
.profile-detail-tab[aria-selected='true']::after {
  transform: scaleX(1);
}
.side-panel-tab-count, #profile-detail-buzz-count { color: var(--color-text-muted) !important; }

/* AI bar / address bar / inputs / placeholder all theme-aware. */
#ai-input, #address-input { color: var(--color-text); }
#ai-input::placeholder, #address-input::placeholder { color: var(--color-text-muted); }
#ai-input:disabled { opacity: 0.55; }
#ai-search-icon { color: var(--brand-yellow); }
#ai-clear, #ai-history-toggle { color: var(--color-text-soft) !important; }
#address-bar, #address-suggestions { color: var(--color-text); }
#ai-results-answer {
  color: var(--color-text);
  word-wrap: break-word;
  overflow-wrap: break-word;
}
#ai-results-tabs { border-bottom-color: var(--color-border-soft) !important; }

/* Right-rail buttons + theme toggle text colour follows tokens. */
#right-rail button { color: var(--color-text) !important; }
#right-rail button:disabled { opacity: 0.5; cursor: not-allowed; }

/* Marker-filter & layer-menu items follow tokens. */
#marker-filter-menu .marker-filter-row { color: var(--color-text); }
#layer-menu button { border-bottom: 1px solid var(--color-border-soft) !important; }
#radius-label { color: var(--color-text-soft) !important; }

/* :focus-visible — visible outline for keyboard users. */
button:focus-visible, a:focus-visible, input:focus-visible, [role='tab']:focus-visible,
.side-panel-tab:focus-visible, .profile-detail-tab:focus-visible {
  outline: 2px solid var(--brand-yellow) !important;
  outline-offset: 2px;
  border-radius: var(--r-sm);
}
/* AI question + address inputs sit inside their own bordered pills, so
   the global yellow focus ring doubles up with the pill chrome. Drop
   the ring on these two inputs specifically. */
#ai-input:focus, #ai-input:focus-visible,
#address-input:focus, #address-input:focus-visible {
  outline: none !important;
  box-shadow: none !important;
}

/* Mobile responsive — clamp panel widths + drop min-width below 480 px
   so floating chrome doesn't overshoot the viewport. */
@media (max-width: 480px) {
  #side-panel { width: min(380px, 92vw) !important; }
  #profile-detail, #buzz-detail { width: min(360px, 92vw) !important; }
  #top-block { width: 92vw !important; min-width: 0 !important; }
  #address-search-row { width: 92vw !important; min-width: 0 !important; bottom: 90px !important; }
  #ai-results { max-height: 50vh !important; }
  header { padding-left: 12px !important; padding-right: 12px !important; }
  #side-panel-flip { display: none !important; }
  #right-rail button { width: 36px !important; height: 36px !important; }
}
@media (max-width: 360px) {
  #side-panel { width: 96vw !important; }
  #profile-detail, #buzz-detail { width: 96vw !important; }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* Map-loading ribbon at the top of the side panel — wired by JS when
   at least one in-flight fetch is running. */
#side-panel-loading-ribbon {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--brand-yellow), transparent);
  background-size: 200% 100%;
  animation: haive-shimmer 1.2s linear infinite;
  z-index: 2;
  pointer-events: none;
}
/* Make the side-panel header + tabs sticky so they don't scroll away
   when the user scrolls deep into the list. */
#side-panel-header {
  position: sticky;
  top: 0;
  background: var(--color-surface);
  backdrop-filter: var(--blur-glass);
  z-index: 3;
}
#side-panel-tabs {
  position: sticky;
  top: 49px;
  background: var(--color-surface);
  backdrop-filter: var(--blur-glass);
  z-index: 2;
}
/* Stronger blur on the AI search bar — focal element gets more depth. */
#top-block > div:first-child {
  backdrop-filter: blur(40px) saturate(180%);
  -webkit-backdrop-filter: blur(40px) saturate(180%);
  background: var(--color-surface) !important;
  color: var(--color-text);
}
/* Dropdown enter animation — opacity + 4 px rise. */
@keyframes haive-dropdown {
  from { opacity: 0; transform: translateY(-4px); }
  to { opacity: 1; transform: translateY(0); }
}
#layer-menu:not([hidden]),
#marker-filter-menu:not([hidden]),
#ai-history-menu:not([hidden]),
#address-suggestions:not([hidden]) {
  animation: haive-dropdown var(--dur-quick) var(--ease-spring);
}
/* Skip link — invisible until focused, then jumps over the header to
   the side panel for keyboard / screen-reader users. */
.skip-link {
  position: absolute;
  top: -40px;
  left: 8px;
  z-index: 100;
  padding: 8px 14px;
  background: var(--brand-yellow);
  color: var(--brand-brown);
  border-radius: var(--r-sm);
  font-weight: 700;
  text-decoration: none;
  transition: top var(--dur-quick) var(--ease-spring);
}
.skip-link:focus { top: 8px; }
