@charset "UTF-8";
/**
 * LAAC Map Plugin - Main Stylesheet
 * 
 * This file imports all layer-specific stylesheets:
 * 1. _foundation.scss - CSS Variables & Design Tokens
 * 2. _layout.scss - Page Structure & Layout
 * 3. _components.scss - UI Components & Interactive Elements
 * 4. _states.scss - Loading & Error States
 * 5. _integration.scss - Third-party Library Overrides
 * 6. _utilities.scss - Utility Classes & Accessibility
 */
/* Import all layer files using modern @use syntax */
/**
 * Shared breakpoints for the Map plugin
 * Note: Aligns naming with site conventions while preserving current behavior.
 */
/**
 * LAAC Map Plugin - Foundation Layer
 * CSS Custom Properties (Variables) & Design Tokens
 */
/*
█████████████████████████████████
 * 1. FOUNDATION LAYER
█████████████████████████████████
*/
:root {
  /*
  █████████████████████████████████
   * 1.1 COLOR SYSTEM
   *    Foundation colors that everything else derives from
  █████████████████████████████████
  */
  /* Primary Brand Color - Change this to update the entire theme */
  --map-primary-hue: 302; /* Purple - change this for different themes */
  --map-primary-chroma: 0.15; /* Saturation level */
  --map-primary-lightness: 0.55; /* Base lightness */
  /* Neutral Base - Pure white for backgrounds */
  --map-neutral-white: oklch(1 0 0);
  --map-neutral-black: oklch(0 0 0);
  /*
  █████████████████████████████████
   * 1.2 PRIMARY COLORS
   *    All derived from the base primary color
  █████████████████████████████████
  */
  --map-primary-color: oklch(
    var(--map-primary-lightness) var(--map-primary-chroma)
      var(--map-primary-hue)
  );
  --map-primary-hover: oklch(
    calc(var(--map-primary-lightness) - 0.1) var(--map-primary-chroma)
      var(--map-primary-hue)
  );
  --map-primary-light: oklch(
    calc(var(--map-primary-lightness) + 0.15)
      calc(var(--map-primary-chroma) * 0.5) var(--map-primary-hue)
  );
  --map-primary-dark: oklch(
    calc(var(--map-primary-lightness) - 0.2) var(--map-primary-chroma)
      var(--map-primary-hue)
  );
  /* Text on --map-primary-color fills; dark theme flips it (primary is lighter there) */
  --map-text-on-primary: var(--map-neutral-white);
  /* Secondary - Lighter version of primary */
  --map-secondary-color: oklch(
    0.7 calc(var(--map-primary-chroma) * 0.7) var(--map-primary-hue)
  );
  /* "You are here" dot. Deliberately NOT derived from --map-primary-hue: the
     place markers own the purple, and the visitor's own position has to read
     as a different kind of thing at a glance. Blue (hue 250) is the
     conventional choice and stays ~50 degrees clear of the 302 primary. */
  --map-user-location-color: oklch(0.55 0.18 250);
  /*
  █████████████████████████████████
   * 1.3 BACKGROUND COLORS
   *    All derived from neutral white
  █████████████████████████████████
  */
  --map-background-white: var(--map-neutral-white);
  --map-background-light: oklch(0.98 0.005 0); /* Very light gray */
  --map-background-medium: oklch(0.95 0.01 0); /* Light gray */
  --map-background-dark: oklch(0.1 0.005 0); /* Dark gray for dark mode */
  /*
  █████████████████████████████████
   * 1.4 TEXT COLORS
   *    Optimized for WCAG AA contrast (4.5:1)
  █████████████████████████████████
  */
  --map-text-primary: oklch(0.25 0.01 0); /* Very dark gray */
  --map-text-secondary: oklch(0.45 0.01 0); /* Medium gray */
  --map-text-muted: oklch(0.6 0.01 0); /* Light gray */
  --map-text-inverse: var(
    --map-neutral-white
  ); /* White text for dark backgrounds */
  /*
  █████████████████████████████████
   * 1.5 BORDER COLORS
   *    Derived from background with subtle chroma
  █████████████████████████████████
  */
  --map-border-color: oklch(0.88 0.01 0); /* Light border */
  --map-border-light: oklch(0.92 0.005 0); /* Very light border */
  --map-border-dark: oklch(0.75 0.01 0); /* Medium border */
  --map-border-primary: oklch(
    var(--map-primary-lightness) calc(var(--map-primary-chroma) * 0.3)
      var(--map-primary-hue)
  );
  /*
  █████████████████████████████████
   * 1.6 SEMANTIC COLORS
   *    Using complementary and triadic relationships
  █████████████████████████████████
  */
  /* Error - Complementary to primary (180° offset) */
  --map-error-hue: calc(var(--map-primary-hue) + 180);
  --map-error-color: oklch(
    var(--map-primary-lightness) var(--map-primary-chroma) var(--map-error-hue)
  );
  --map-error-bg: oklch(
    0.97 calc(var(--map-primary-chroma) * 0.1) var(--map-error-hue)
  );
  --map-error-border: oklch(
    0.9 calc(var(--map-primary-chroma) * 0.2) var(--map-error-hue)
  );
  /* Success - Triadic relationship (+120°) */
  --map-success-hue: calc(var(--map-primary-hue) + 120);
  --map-success-color: oklch(
    var(--map-primary-lightness) var(--map-primary-chroma)
      var(--map-success-hue)
  );
  --map-success-bg: oklch(
    0.97 calc(var(--map-primary-chroma) * 0.1) var(--map-success-hue)
  );
  --map-success-border: oklch(
    0.9 calc(var(--map-primary-chroma) * 0.2) var(--map-success-hue)
  );
  /* Warning - Triadic relationship (+60°) */
  --map-warning-hue: calc(var(--map-primary-hue) + 60);
  --map-warning-color: oklch(
    var(--map-primary-lightness) var(--map-primary-chroma)
      var(--map-warning-hue)
  );
  --map-warning-bg: oklch(
    0.97 calc(var(--map-primary-chroma) * 0.1) var(--map-warning-hue)
  );
  --map-warning-border: oklch(
    0.9 calc(var(--map-primary-chroma) * 0.2) var(--map-warning-hue)
  );
  /*
  █████████████████████████████████
   * 1.7 ACCESSIBILITY COLORS
   *    High contrast for focus and interactive elements
  █████████████████████████████████
  */
  --map-focus-color: oklch(
    var(--map-primary-lightness) calc(var(--map-primary-chroma) * 1.3)
      var(--map-primary-hue)
  );
  --map-focus-ring: oklch(
    var(--map-primary-lightness) var(--map-primary-chroma)
      var(--map-primary-hue) / 0.3
  );
  --map-focus-bg: oklch(
    calc(var(--map-primary-lightness) + 0.3)
      calc(var(--map-primary-chroma) * 0.1) var(--map-primary-hue)
  );
  /* Spacing (aliases site --space-*; fallbacks when map.css loads without main.css) */
  --map-spacing-xs: var(--space-2xs, 0.25rem);
  --map-spacing-sm: var(--space-xs, 0.5rem);
  --map-spacing-md: var(--space-md, 1rem);
  --map-spacing-lg: var(--space-lg, 1.25rem);
  --map-spacing-xl: var(--space-2xl, 2rem);
  /* Nav bar height: pill (1rem font + 1rem padding) + nav padding top+bottom */
  --map-nav-height: 3rem;
  /* Border radius */
  --map-border-radius-sm: 4px;
  --map-border-radius-md: 8px;
  --map-border-radius-lg: 12px;
  --map-border-radius-xl: 20px;
  --map-border-radius-full: 9999px;
  /* Typography (aliases site --text-*; fallbacks when map.css loads without main.css) */
  --map-font-size-xs: var(--text-xs, 0.7rem);
  --map-font-size-sm: var(--text-md, 0.9rem);
  --map-font-size-base: var(--text-base, 1rem);
  --map-font-size-lg: var(--text-lg, 1.1rem);
  --map-font-size-xl: var(--text-xl, 1.2rem);
  --map-font-size-xxl: var(--text-3xl, 1.5rem);
  /* Shadows */
  --map-shadow-sm: 0 2px 5px rgba(0, 0, 0, 0.2);
  --map-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.15);
  --map-shadow-lg: 0 2px 8px rgba(0, 102, 204, 0.1);
  /* Transitions */
  --map-transition-fast: 0.2s;
  --map-transition-medium: 0.3s;
  --map-transition-enter: 0.25s ease-out; /* decelerate in */
  --map-transition-exit: 0.18s ease-in; /* accelerate out */
  /* Z-index */
  --map-z-controls: 1000;
  --map-z-popup: 1001;
  --map-z-overlay: 1002;
  /* Map specific */
  --map-marker-size: 25px;
  --map-marker-height: 41px;
  --map-progress-height: 20px;
  --map-control-size: 40px;
  --map-sidebar-width: 400px;
  --map-min-height: 500px;
  --map-mobile-height: 300px;
  --map-mobile-sidebar-height: 200px;
  /* Popup */
  --map-popup-max-width: 280px;
}

/*
█████████████████████████████████
 * 2. DARK THEME (plugin-owned; no dependency on global site CSS)
█████████████████████████████████
*/
@media (prefers-color-scheme: dark) {
  :root:not([data-theme=light]) {
    --map-background-white: oklch(0.22 0.02 280);
    --map-background-light: oklch(0.26 0.02 280);
    --map-background-medium: oklch(0.3 0.02 280);
    --map-background-dark: oklch(0.15 0.02 280);
    --map-text-primary: oklch(0.92 0.01 80);
    --map-text-secondary: oklch(0.7 0.01 80);
    --map-text-muted: oklch(0.55 0.01 80);
    --map-text-inverse: oklch(0.22 0.01 30);
    --map-border-color: oklch(0.35 0.02 280);
    --map-border-light: oklch(0.3 0.02 280);
    --map-border-dark: oklch(0.45 0.02 280);
    --map-primary-lightness: 0.65;
    --map-text-on-primary: var(--map-text-inverse); /* white is 3.43:1 on the 0.65-lightness primary */
    --map-user-location-color: oklch(0.68 0.16 250); /* lifted so the dot holds on a dark basemap */
    --map-focus-bg: oklch(0.32 0.04 300);
    --map-error-bg: oklch(0.28 0.06 25);
    --map-success-bg: oklch(0.28 0.06 145);
    --map-warning-bg: oklch(0.3 0.06 75);
    --map-shadow-sm: 0 2px 5px rgba(0, 0, 0, 0.4);
    --map-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.35);
    --map-shadow-lg: 0 2px 8px rgba(0, 0, 0, 0.3);
  }
}
[data-theme=dark] {
  --map-background-white: oklch(0.22 0.02 280);
  --map-background-light: oklch(0.26 0.02 280);
  --map-background-medium: oklch(0.3 0.02 280);
  --map-background-dark: oklch(0.15 0.02 280);
  --map-text-primary: oklch(0.92 0.01 80);
  --map-text-secondary: oklch(0.7 0.01 80);
  --map-text-muted: oklch(0.55 0.01 80);
  --map-text-inverse: oklch(0.22 0.01 30);
  --map-border-color: oklch(0.35 0.02 280);
  --map-border-light: oklch(0.3 0.02 280);
  --map-border-dark: oklch(0.45 0.02 280);
  --map-primary-lightness: 0.65;
  --map-text-on-primary: var(--map-text-inverse); /* white is 3.43:1 on the 0.65-lightness primary */
  --map-user-location-color: oklch(0.68 0.16 250); /* lifted so the dot holds on a dark basemap */
  --map-focus-bg: oklch(0.32 0.04 300);
  --map-error-bg: oklch(0.28 0.06 25);
  --map-success-bg: oklch(0.28 0.06 145);
  --map-warning-bg: oklch(0.3 0.06 75);
  --map-shadow-sm: 0 2px 5px rgba(0, 0, 0, 0.4);
  --map-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.35);
  --map-shadow-lg: 0 2px 8px rgba(0, 0, 0, 0.3);
}

[data-theme=light] {
  /* Force light when host sets data-theme="light" (overrides system dark) */
  --map-background-white: oklch(1 0 0);
  --map-background-light: oklch(0.98 0.005 0);
  --map-background-medium: oklch(0.95 0.01 0);
  --map-background-dark: oklch(0.1 0.005 0);
  --map-text-primary: oklch(0.25 0.01 0);
  --map-text-secondary: oklch(0.45 0.01 0);
  --map-text-muted: oklch(0.6 0.01 0);
  --map-text-inverse: oklch(1 0 0);
  --map-border-color: oklch(0.88 0.01 0);
  --map-border-light: oklch(0.92 0.005 0);
  --map-border-dark: oklch(0.75 0.01 0);
  --map-primary-lightness: 0.55;
  --map-focus-bg: oklch(0.85 0.04 300);
  --map-error-bg: oklch(0.97 0.02 25);
  --map-success-bg: oklch(0.97 0.02 145);
  --map-warning-bg: oklch(0.97 0.02 75);
  --map-shadow-sm: 0 2px 5px rgba(0, 0, 0, 0.2);
  --map-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.15);
  --map-shadow-lg: 0 2px 8px rgba(0, 102, 204, 0.1);
}

/**
 * LAAC Map Plugin - Main Stylesheet
 * 
 * This file imports all layer-specific stylesheets:
 * 1. _foundation.scss - CSS Variables & Design Tokens
 * 2. _layout.scss - Page Structure & Layout
 * 3. _components.scss - UI Components & Interactive Elements
 * 4. _states.scss - Loading & Error States
 * 5. _integration.scss - Third-party Library Overrides
 * 6. _utilities.scss - Utility Classes & Accessibility
 */
/* Import all layer files using modern @use syntax */
/**
 * LAAC Map Plugin - Layout Layer
 * Page Structure & Layout Styles
 */
/*
█████████████████████████████████
 * 1. FOUNDATION
 *  Full screen app layout  
█████████████████████████████████
*/
/* Reset body and html for full viewport app */
html:has(body.map) html,
html:has(body.map) body {
  height: 100%;
  margin: 0;
  padding: 0;
  overflow: hidden; /* Prevent any scroll on body */
}
html:has(body.map) main {
  margin-top: 0;
  max-width: 100vw;
  height: 100svh;
  overflow: hidden; /* Prevent main from scrolling */
}

/*
█████████████████████████████████
 * 2. LAYOUT LAYER
█████████████████████████████████
*/
.map-page {
  background: var(--map-background-light);
  height: 100%; /* Inherit from body.map main */
}

.map-container {
  width: 100%;
  max-width: 100%;
  height: 100%; /* Inherit from .map-page */
  display: flex;
  flex-direction: column;
}

.map-nav {
  position: absolute;
  inset: 0 0 auto;
  z-index: var(--map-z-overlay);
  pointer-events: none;
}
.map-nav > * {
  pointer-events: auto;
}

.map-intro {
  background: var(--map-background-white);
  padding: var(--map-spacing-xl) 0;
  border-bottom: 1px solid var(--map-border-color);
  flex-shrink: 0; /* Prevent intro from shrinking */
}
.map-intro .container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 var(--map-spacing-lg);
}

/*
█████████████████████████████████
 * 2.2 MAP VIEW
 *    Map container and viewport
█████████████████████████████████
*/
/* Map view — direct child of .map-container, fills remaining space after intro */
.map-view {
  flex: 1;
  min-height: 0; /* Allow flex container to shrink below natural height */
  background: var(--map-background-white);
  position: relative;
  display: flex;
  flex-direction: column;
}

/*
█████████████████████████████████
 * 2.3 SIDEBAR
 *    Sidebar layout and navigation
█████████████████████████████████
*/
/* Sidebar: absolute overlay on map — never pushes map content */
/* overflow: hidden clips .place-detail while it's in its hidden (translateX(100%)) state */
.map-sidebar {
  position: absolute;
  right: 0;
  left: auto;
  top: 0;
  z-index: var(--map-z-controls);
  width: var(--map-sidebar-width);
  height: 100%;
  overflow: hidden;
  /* No background — header and body carry their own; map shows through the rest */
  display: flex;
  flex-direction: column;
  pointer-events: none; /* Let clicks pass through the transparent container */
  /* Desktop: slide out from the right edge; the nav magnifier discloses it */
  transform: translateX(100%);
  transition: transform var(--map-transition-medium) ease;
}
.map-sidebar > * {
  pointer-events: auto;
}

.map-container[data-search-open=true] .map-sidebar {
  transform: translateX(0);
}

.map-sidebar-body {
  flex: 1;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  background: var(--map-background-light);
  border-right: 1px solid var(--map-border-color);
  box-shadow: 2px 0 8px rgba(0, 0, 0, 0.08);
  max-height: 100svh;
}

/* Mobile: bottom sheet sidebar; detail panel expands to full height */
@media (max-width: 48em) {
  .map-sidebar {
    left: 0;
    right: auto;
    top: auto;
    bottom: 0;
    width: 100%;
    height: auto;
    max-height: 50svh;
    pointer-events: auto;
    /* Mobile uses the bottom-bar + body display toggle, not the desktop slide */
    transform: none;
    transition: none;
  }
  /* Mobile: collapse hides the body (bottom bar stays); desktop slides instead */
  .map-container[data-search-open=false] .map-sidebar-body {
    display: none;
  }
  .map-container[data-search-open=false] .map-sidebar {
    max-height: none;
  }
  /* Both sheets open the same way: full screen, bar on top, content below.
     The old split (places 50svh, filters 90svh) meant two tabs in one bar
     produced two different sheets — the incoherence this replaces. Keeping a
     sliver of map behind a half-height sheet bought nothing: the map is a tap
     away on the ✕, and the list needs the rows. */
  .map-container[data-search-open=true] .map-sidebar {
    top: 0;
    height: 100svh;
    max-height: 100svh;
  }
  .map-container[data-search-open=true] .map-sidebar-body {
    flex: 1;
    min-height: 0;
    max-height: none;
    border-right: none;
    border-top: none;
    border-bottom: 1px solid var(--map-border-color);
    box-shadow: none;
  }
  /* Detail is the one sheet that stays partial, and for a reason the others
     don't have: it describes a specific marker, so that marker has to stay on
     screen (place-detail.js pans it into --map-detail-top). Declared last so
     it wins over the full-height rule above when both attributes are set. */
  .map-container[data-detail-open=true] .map-sidebar {
    top: var(--map-detail-top, 40svh);
    bottom: 0;
    max-height: none;
    height: auto;
  }
}
/**
 * LAAC Map Plugin - Main Stylesheet
 * 
 * This file imports all layer-specific stylesheets:
 * 1. _foundation.scss - CSS Variables & Design Tokens
 * 2. _layout.scss - Page Structure & Layout
 * 3. _components.scss - UI Components & Interactive Elements
 * 4. _states.scss - Loading & Error States
 * 5. _integration.scss - Third-party Library Overrides
 * 6. _utilities.scss - Utility Classes & Accessibility
 */
/* Import all layer files using modern @use syntax */
/**
 * LAAC Map Plugin - Components Layer
 * UI Components & Interactive Elements
 */
/* Typography — grouped to avoid repetition across component rules */
.sidebar-header h2,
.sidebar-empty,
.venue-card-title,
.venue-card-address,
.place-detail__name,
.place-detail__address,
.place-detail__category-label,
.place-detail__options li,
.map-popup--name,
.map-popup__title {
  text-wrap: balance;
}

.sidebar-count,
.progress-label {
  font-variant-numeric: tabular-nums lining-nums; /* matches .nums-tabular */
}

/*
█████████████████████████████████
 * 3. COMPONENT LAYER
█████████████████████████████████
*/
/*
█████████████████████████████████
 * 3.1 MAP CONTAINER
 *    Core map wrapper and controls
█████████████████████████████████
*/
.map-wrapper {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden; /* Prevent any overflow from breaking viewport */
  -webkit-font-smoothing: antialiased;
}

.map-viewport {
  height: 100%;
  width: 100%;
  position: relative; /* establish positioning context for overlays */
  overflow: hidden; /* Prevent any overflow from breaking viewport */
}

.map-control-button {
  width: var(--map-control-size);
  height: var(--map-control-size);
  background: var(--map-background-white);
  border: 1px solid var(--map-border-color);
  border-radius: var(--map-border-radius-sm);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--map-font-size-lg);
  font-weight: bold;
  color: var(--map-text-primary);
  transition: background-color var(--map-transition-fast);
}
.map-control-button:hover {
  background: var(--map-background-light);
}
.map-control-button:focus {
  outline: 2px solid var(--map-primary-color);
  outline-offset: 2px;
}

/* Geolocation button — lives inside the renderer's own control group, so the
   vendor chrome (44px box, white fill, border, radius, hover) already applies
   and keeps it pixel-identical to the zoom buttons beside it. Only the emoji
   glyph needs sizing here.

   Deliberately NOT restyled: `.maplibregl-ctrl-group button` and
   `.leaflet-bar a` are both (0,1,1) and load after this sheet, so any
   single-class attempt to set size/background/border here is dead code —
   and out-specifying it would make this button diverge from the zoom
   controls it sits with, which is the opposite of what we want. */
.map-geolocation-button {
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  text-align: center;
  -webkit-user-select: none;
  user-select: none;
}

/*
█████████████████████████████████
 * 3.2 SIDEBAR COMPONENTS
 *    Sidebar content and venue cards
█████████████████████████████████
*/
/* Sidebar header */
.sidebar-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--map-spacing-md);
  border-bottom: 1px solid var(--map-border-color);
  flex-shrink: 0;
}
.sidebar-header h2 {
  margin: 0;
  font-size: var(--map-font-size-xl);
  color: var(--map-text-primary);
  font-weight: 600;
}
.sidebar-header p {
  margin: var(--map-spacing-xs) 0 0 0;
  color: var(--map-text-secondary);
  font-size: var(--map-font-size-sm);
}

.sidebar-count {
  font-size: var(--map-font-size-xs);
  color: var(--map-text-secondary);
}

/* Sidebar content */
.sidebar-content {
  flex: 1;
  overflow-y: auto;
  padding: var(--map-spacing-md);
}

/* Venue list — real <ul>/<li> for list semantics; strip default styling */
.venue-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Venue cards */
.venue-card {
  background: var(--map-background-white);
  border: 1px solid var(--map-border-color);
  border-radius: var(--map-border-radius-md);
  padding: var(--map-spacing-md);
  margin-bottom: var(--map-spacing-md);
  transition: all var(--map-transition-fast);
}
.venue-card:hover {
  border-color: var(--map-primary-color);
  box-shadow: var(--map-shadow-sm);
}
.venue-card:last-child {
  margin-bottom: 0;
}
.venue-card.is-selected {
  border-color: var(--map-focus-color);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--map-focus-color) 35%, transparent);
}

/* When the venue card is rendered inside a map popup, keep the popup's blurred/transparent background */
.venue-card.is-in-popup {
  background: transparent;
  border-color: transparent;
}

.venue-card-header {
  margin-bottom: var(--map-spacing-sm);
}

.venue-card-title {
  margin: 0;
  font-size: var(--map-font-size-lg);
  font-weight: 600;
  color: var(--map-text-primary);
  line-height: 1.2;
  transition: color var(--map-transition-fast);
}

.venue-card--interactive {
  cursor: pointer;
}
.venue-card--interactive:focus-visible {
  outline: 2px solid var(--map-focus-color);
  outline-offset: 2px;
}
.venue-card--interactive:hover .venue-card-title {
  color: var(--map-primary-color);
}

.venue-card-neighborhood {
  display: inline-block;
  font-size: var(--map-font-size-xs);
  color: var(--map-text-secondary);
  padding: 2px var(--map-spacing-xs);
  border-radius: var(--map-border-radius-sm);
  white-space: nowrap;
  margin-bottom: var(--map-spacing-xs);
}

.venue-card-content {
  margin-bottom: var(--map-spacing-sm);
}

.venue-card-address {
  font-size: var(--map-font-size-sm);
  color: var(--map-text-secondary);
  margin: 0 0 var(--map-spacing-xs) 0;
  line-height: 1.35;
}

.venue-card-progress {
  margin-top: var(--map-spacing-sm);
}

footer.venue-card-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--map-spacing-xs) var(--map-spacing-sm);
  align-items: baseline;
  margin-top: var(--map-spacing-sm);
  padding-top: var(--map-spacing-sm);
  border-top: 1px solid var(--map-border-light);
}
footer.venue-card-actions div.meta {
  display: flex;
  gap: var(--map-spacing-xs);
  margin-inline: var(--map-spacing-sm);
}

/* Address disclosure — summary sits on the action row; address reveals below */
.venue-card-disclosure {
  flex: 1 1 auto;
  min-width: 0;
}

/* Summary inherits .venue-card-link; only the marker + caret differ */
.venue-card-disclosure-summary {
  list-style: none;
  cursor: pointer;
}
.venue-card-disclosure-summary::-webkit-details-marker {
  display: none;
}

.venue-card-disclosure-icon {
  margin-right: 0.3em;
}

.venue-card-disclosure .venue-card-address {
  margin-top: var(--map-spacing-xs);
  margin-bottom: 0;
}

/* Shared style for the card's action row: Address (disclosure) + Website.
   Same colour, size, light weight, baseline, and no underline. */
.venue-card-link {
  color: var(--map-primary-color);
  text-decoration: none;
  font-size: var(--map-font-size-sm);
  font-weight: 400;
}
.venue-card-link:hover {
  text-decoration: none;
  opacity: 0.75;
}
.venue-card-link:focus-visible {
  outline: 2px solid var(--map-focus-color);
  outline-offset: 2px;
}

/* Normalize focus outlines across common interactive elements */
:where(.map-control-button,
.venue-card--interactive,
.select-input,
.range-input):focus {
  outline: 2px solid var(--map-focus-color);
  outline-offset: 2px;
}

/*
█████████████████████████████████
 * 3.3 PLACE DETAIL PANEL
 *    Slides in over the sidebar content on marker click
█████████████████████████████████
*/
.place-detail {
  position: absolute;
  inset: 0; /* top/right/bottom/left: 0 — fills entire .map-sidebar */
  background: var(--color-page, var(--map-background-light));
  z-index: 10;
  display: none;
  flex-direction: column;
  transform: translateX(100%);
  transition: transform var(--map-transition-exit);
  pointer-events: none;
}

.map-container[data-detail-open=true] .place-detail {
  display: flex;
  transform: translateX(0);
  transition: transform var(--map-transition-enter);
  pointer-events: auto;
}

.place-detail__inner {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
}

/* Close sits inside the purple header (top-right): a white circle with the
   header's own hue for the ✕, so it reads clearly against the purple fill. */
.place-detail__close {
  position: absolute;
  top: var(--map-spacing-md);
  right: var(--map-spacing-md);
  z-index: 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border: none;
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  color: var(--map-primary-color);
  background: var(--map-neutral-white);
  border-radius: var(--map-border-radius-full);
  box-shadow: var(--map-shadow-sm);
  transition: color var(--map-transition-fast), background-color var(--map-transition-fast), box-shadow var(--map-transition-fast);
}
.place-detail__close:hover {
  box-shadow: var(--map-shadow-md);
}
.place-detail__close:focus-visible {
  outline: 2px solid var(--map-neutral-white);
  outline-offset: 2px;
}

.place-detail__body {
  flex: 1;
  overflow-y: auto;
  padding: 0;
  display: flex;
  flex-direction: column;
}

.place-detail__contact {
  background: var(--map-primary-color);
  padding: var(--map-spacing-md);
  flex-shrink: 0;
  border-bottom-left-radius: var(--map-border-radius-xl);
  border-bottom-right-radius: var(--map-border-radius-xl);
}

.place-detail__name {
  font-size: var(--map-font-size-xxl);
  font-weight: 700;
  /* room for the close button pinned to the top-right of the purple header */
  margin: 0 2.25rem var(--map-spacing-sm) 0;
  line-height: 1.2;
  color: var(--map-text-inverse);
}

.place-detail__neighborhood {
  display: inline-block;
  margin-bottom: var(--map-spacing-sm);
  /* Override .venue-card-neighborhood tokens for the reversed card */
  background: rgba(255, 255, 255, 0.2);
  color: var(--map-text-inverse);
}

.place-detail__address {
  font-size: var(--map-font-size-sm);
  color: var(--map-text-inverse);
  opacity: 0.85;
  margin: var(--map-spacing-xs) 0;
  line-height: 1.4;
}

.place-detail__website {
  display: inline-block;
  margin-top: var(--map-spacing-xs);
  font-size: var(--map-font-size-sm);
  color: var(--map-text-inverse);
  text-decoration: none;
}
.place-detail__website:hover {
  text-decoration: underline;
}

/* Survey CTA lives at the end of the body (after any facet data), not
   pinned to the header. Lead-in text reads directly into the pill below it
   ("No accessibility data yet. Please take the [Accessibility Survey]"). */
.place-detail__survey-section {
  padding: var(--map-spacing-md);
  flex-shrink: 0;
}

.place-detail__survey-intro {
  margin: 0 0 var(--map-spacing-sm) 0;
  font-size: var(--map-font-size-sm);
  line-height: 1.4;
  color: var(--map-text-primary);
}

.place-detail__survey-button {
  display: inline-block;
  background: var(--color-success, var(--green, #1a7f37));
  color: var(--color-on-accent, var(--map-neutral-white));
  padding: 0.65rem 1.5rem;
  border-radius: var(--map-border-radius-full);
  font-size: var(--map-font-size-base);
  font-weight: 700;
  text-decoration: none;
  transition: background-color var(--map-transition-fast), transform var(--map-transition-fast);
}
.place-detail__survey-button:hover {
  transform: translateY(-1px);
}
.place-detail__survey-button:focus-visible {
  outline: 2px solid var(--map-primary-color);
  outline-offset: 2px;
}

.place-detail__facets {
  padding: var(--map-spacing-md);
  flex: 1;
}

.place-detail__category {
  margin-bottom: var(--map-spacing-lg);
}
.place-detail__category:last-child {
  margin-bottom: 0;
}

.place-detail__category-label {
  display: flex;
  align-items: baseline;
  gap: var(--map-spacing-xs);
  font-size: var(--map-font-size-base);
  font-weight: normal;
  color: var(--map-text-primary);
  margin: 0 0 var(--map-spacing-xs) 0;
}

.place-detail__category-icon {
  font-size: 0.9em;
  line-height: 1.3;
  flex-shrink: 0;
}

.place-detail__group-label {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--map-spacing-xs);
  font-size: calc(var(--map-font-size-sm) * 0.75);
  font-weight: 600;
  color: var(--map-text-primary);
  margin: var(--map-spacing-xs) 0 4px 0;
}

.place-detail__group-disclosure {
  margin: var(--map-spacing-xs) 0 0 0;
}

.place-detail__group-summary {
  display: flex;
  align-items: center;
  gap: 0.75em;
  font-size: var(--map-font-size-sm);
  font-weight: 600;
  color: var(--map-text-primary);
  margin: 0;
  padding: 0;
  cursor: pointer;
  list-style: none;
  -webkit-user-select: none;
  user-select: none;
}
.place-detail__group-summary::-webkit-details-marker {
  display: none;
}
.place-detail__group-summary {
  /* Caret indicator */
}
.place-detail__group-summary::before {
  content: "▶";
  font-size: 0.75em;
  line-height: 1.4;
  color: var(--map-text-secondary);
  transition: transform 200ms ease;
  width: 0.8em;
  flex-shrink: 0;
  text-align: center;
}
.place-detail__group-summary:hover {
  color: var(--map-primary-color);
}
.place-detail__group-summary:focus-visible {
  outline: 2px solid var(--map-focus-color);
  outline-offset: 2px;
}

/* Fixed name column so the status pills line up across disclosure rows.
   Scoped to the summary — the verdict-less "Other" group reuses
   .place-detail__group-name inside .place-detail__group-label. */
.place-detail__group-summary .place-detail__group-name {
  flex: 0 0 120px;
}

details[open] > .place-detail__group-summary::before {
  content: "▾";
}

.place-detail__group-options {
  list-style: none;
  margin: var(--map-spacing-xs) 0 0 0;
  padding: 0;
}

.place-detail__group-option {
  display: flex;
  align-items: flex-start;
  gap: 0.5em;
  font-size: var(--map-font-size-sm);
  color: var(--map-text-secondary);
  margin-bottom: 4px;
  line-height: 1.4;
  padding: 2px 0;
}
.place-detail__group-option:last-child {
  margin-bottom: 0;
}

.place-detail__group-option-icon {
  flex-shrink: 0;
  font-size: 0.9em;
  line-height: 1.5;
  width: 1em;
}

.place-detail__group-option--matched .place-detail__group-option-icon {
  color: var(--map-success, #1a7f37);
}

.place-detail__group-option--unmatched .place-detail__group-option-icon {
  color: var(--map-text-tertiary, #9ca3af);
}

.place-detail__group-option--unmatched .place-detail__group-option-label {
  color: var(--map-text-tertiary, #9ca3af);
}

.place-detail__status {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  font-weight: 600;
  font-size: var(--map-font-size-xs);
  flex-shrink: 0;
  padding: 2px 6px;
  border-radius: var(--map-border-radius-sm);
  white-space: nowrap;
}

.place-detail__status-icon {
  font-size: 0.9em;
}

.place-detail__status--yes {
  color: var(--map-success, #1a7f37);
  background-color: color-mix(in srgb, var(--map-success, #1a7f37) 12%, transparent);
}

.place-detail__status--no {
  color: var(--map-text-secondary, #6b7280);
  background-color: color-mix(in srgb, var(--map-text-secondary, #6b7280) 12%, transparent);
}

.place-detail__options {
  list-style: disc;
  padding-left: 1.5em;
  margin: var(--map-spacing-xs) 0 0 0;
}
.place-detail__options li {
  font-size: var(--map-font-size-sm);
  color: var(--map-text-secondary);
  margin-bottom: 4px;
  line-height: 1.4;
}
.place-detail__options + .place-detail__group-label {
  margin-top: var(--map-spacing-sm);
}

.place-detail__comments {
  margin-top: var(--map-spacing-lg);
  padding: var(--map-spacing-md);
  border-top: 1px solid var(--map-border-color);
}

.place-detail__comments-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--map-spacing-sm);
  font-size: var(--map-font-size-sm);
  font-weight: 600;
  color: var(--map-text-primary);
  cursor: pointer;
  list-style: none;
}
.place-detail__comments-summary::-webkit-details-marker {
  display: none;
}
.place-detail__comments-summary::after {
  flex-shrink: 0;
  font-size: 1.1em;
  line-height: 1;
  color: var(--map-text-secondary);
  content: "…";
}

.place-detail__comments-details[open] .place-detail__comments-summary::after {
  content: "▾";
}

.place-detail__comments-body {
  margin-top: var(--map-spacing-md);
}

.place-detail__comments-group {
  margin-bottom: var(--map-spacing-lg);
}
.place-detail__comments-group:last-child {
  margin-bottom: 0;
}

.place-detail__comments-group-title {
  font-size: var(--map-font-size-sm);
  font-weight: 600;
  color: var(--map-text-secondary);
  margin: 0 0 var(--map-spacing-sm);
}

.place-detail__comments-entry {
  margin-bottom: var(--map-spacing-md);
}
.place-detail__comments-entry:last-child {
  margin-bottom: 0;
}

.place-detail__comments-label {
  font-size: var(--map-font-size-sm);
  font-weight: 600;
  color: var(--map-text-primary);
  margin: 0 0 var(--map-spacing-xs);
}

.place-detail__comments-text {
  font-size: var(--map-font-size-sm);
  color: var(--map-text-secondary);
  margin: 0;
  line-height: 1.45;
  white-space: pre-wrap;
}

.place-detail__loading {
  padding: var(--map-spacing-lg);
  text-align: center;
  color: var(--map-text-muted);
}

/* Simplified name-only popup */
.map-popup--name {
  padding: var(--map-spacing-xs) var(--map-spacing-sm);
}
.map-popup--name .map-popup__title {
  font-size: var(--map-font-size-base);
  font-weight: 600;
  color: var(--map-primary-color);
}

/* Progress indicators */
.progress-container {
  margin-top: var(--map-spacing-sm);
}

.progress-label {
  font-size: var(--map-font-size-xs);
  color: var(--map-text-secondary);
  margin-bottom: var(--map-spacing-xs);
  display: flex;
  justify-content: space-between;
}

.progress-bar {
  width: 100%;
  height: var(--map-progress-height);
  background: var(--map-background-light);
  border-radius: var(--map-border-radius-full);
  overflow: hidden;
}

.progress-fill {
  height: 100%;
  background: var(--map-primary-color);
  border-radius: var(--map-border-radius-full);
  transition: width var(--map-transition-medium);
}

/* 3.4 MAP NAV — site wayfinding + filter summary (count, chips) */
.map-nav {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: var(--map-spacing-sm);
  padding: var(--map-spacing-sm) var(--map-spacing-md);
  flex-shrink: 0;
}

.map-nav-main {
  display: flex;
  flex-direction: row;
  align-items: flex-start; /* keep pills/toggle aligned to the first chip row when chips wrap */
  gap: var(--map-spacing-sm);
  width: 100%;
  /* When the full-height search is open, reserve its width so the nav content
     (chips) stays clear of it and the toggle is pushed to the search's edge */
  transition: padding-right var(--map-transition-medium) ease;
  /* The reserved padding region must not intercept clicks meant for the search
     header beneath it — only real nav controls stay interactive */
  pointer-events: none;
}
.map-nav-main > * {
  pointer-events: auto;
}

@media (min-width: 48.0625em) {
  .map-container[data-search-open=true] .map-nav-main {
    padding-right: var(--map-sidebar-width);
  }
}
.map-nav-row {
  display: flex;
  align-items: flex-start;
  gap: var(--map-spacing-sm);
  flex: 1;
  min-width: 0;
  transition: opacity var(--map-transition-fast, 0.15s) ease;
}

.map-nav-brand-pills {
  display: flex;
  gap: 0.4rem;
  flex-wrap: nowrap;
}

/* Default/hover text swap inside the guide pill */
.map-brand-pill-hover {
  display: none;
}

/* Hover interactions — hover-capable devices only */
@media (hover: hover) {
  .map-brand-pill--guide:hover .map-brand-pill-default,
  .map-brand-pill--guide:focus-visible .map-brand-pill-default {
    display: none;
  }
  .map-brand-pill--guide:hover .map-brand-pill-hover,
  .map-brand-pill--guide:focus-visible .map-brand-pill-hover {
    display: inline;
  }
  /* When guide pill is hovered/focused: fade out siblings and map UI */
  .map-nav-brand-pills:has(.map-brand-pill--guide:hover,
  .map-brand-pill--guide:focus-visible) .map-brand-pill:not(.map-brand-pill--guide) {
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--map-transition-fast, 0.15s) ease;
  }
  .map-container:has(.map-brand-pill--guide:hover,
  .map-brand-pill--guide:focus-visible) .map-nav-row {
    opacity: 0;
    pointer-events: none;
  }
  .map-container:has(.map-brand-pill--guide:hover,
  .map-brand-pill--guide:focus-visible) .map-sidebar,
  .map-container:has(.map-brand-pill--guide:hover,
  .map-brand-pill--guide:focus-visible) .facets-list,
  .map-container:has(.map-brand-pill--guide:hover,
  .map-brand-pill--guide:focus-visible) .section-container {
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--map-transition-fast, 0.15s) ease;
  }
}
.map-brand-pill {
  font-family: var(--font-ks);
  font-size: var(--map-font-size-base);
  background-color: var(--lightpurple);
  color: black !important;
  padding: 0.5rem 0.75rem;
  border-radius: 0.25rem;
  line-height: 1;
  text-decoration: none;
  border: 1px solid transparent;
  filter: url(#remove-black);
  transition: all var(--map-transition-fast, 0.15s) ease;
  display: inline-flex;
  align-items: center;
  gap: 0.3em;
}
.map-brand-pill:hover {
  background-color: var(--map-background-white, white);
  color: var(--lightpurple) !important;
  border-color: var(--lightpurple);
  filter: none;
}

.map-brand-pill-arrow {
  display: inline-block;
  overflow: hidden;
  max-width: 0;
  opacity: 0;
  transition: max-width 0.25s ease, opacity 0.2s ease;
}

.map-brand-pill:hover .map-brand-pill-arrow {
  max-width: 1.5em;
  opacity: 1;
}

/* 3.x MAP CHIPS - filter chips floated on map, outside sidebar */
.map-chips {
  display: flex;
  align-items: center;
  pointer-events: none;
  /* Bound the chips region so it shrinks and scrolls instead of overflowing
     across the toggle / search when there are many active filters */
  min-width: 0;
  flex: 1 1 auto;
}
.map-chips > * {
  pointer-events: auto;
}

.map-container[data-detail-open=true] .map-chips,
.map-container[data-detail-open=true] .map-nav-with {
  display: none !important;
}

.map-container[data-has-filters=true] .map-nav-with {
  display: inline-flex;
}

.map-container:has(.map-nav-with:hover) .filter-chip {
  border-color: var(--map-primary-color);
  background: var(--map-primary-light);
  color: var(--map-background-white);
}

.map-wrapper .maplibregl-ctrl-bottom-left,
.map-wrapper .leaflet-bottom.leaflet-left {
  margin: var(--map-spacing-sm) var(--map-spacing-md);
}

.map-nav-status {
  display: inline-flex;
  align-items: center;
  margin: 0;
  padding: 0.5rem 0.75rem;
  border-radius: var(--map-border-radius-md);
  background: var(--map-primary-color);
  color: var(--map-neutral-white);
  border: 1px solid var(--map-border-color);
  font-size: var(--map-font-size-base);
  font-weight: 600;
  line-height: 1; /* match the guide brand pill so both pills are the same height */
  flex-shrink: 0;
}

/* Count inside nav label */
.map-nav-label {
  display: inline-flex;
  align-items: center;
  gap: 0.3em;
}

.map-nav-label .count-label-text {
  font-family: var(--font-ks);
}

.map-nav-label .count-number {
  font-weight: 400;
  opacity: 0.8;
  line-height: 1;
}

/* "with" connector — visible only when filters are active */
.map-nav-with {
  display: none;
  padding: 0.25rem 0.25rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-family: var(--font-ks);
  color: var(--map-primary-color);
  font-size: var(--map-font-size-xs);
  line-height: 1.2;
  white-space: nowrap;
  cursor: default;
}

/*
█████████████████████████████████
 * 3.5 SEARCH — toggle, tabs, collapse state
 *    Controlled via data-search-open / data-search-tab on .map-container
█████████████████████████████████
*/
.search-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--map-spacing-xs);
  padding: 0.4rem 0.5rem;
  border: 1px solid var(--map-primary-color);
  border-radius: var(--map-border-radius-sm);
  background: var(--map-background-white);
  color: var(--map-primary-color);
  cursor: pointer;
  font-size: var(--map-font-size-xs);
  flex-shrink: 0;
  transition: background-color var(--map-transition-fast), border-color var(--map-transition-fast), color var(--map-transition-fast);
}
.search-toggle:focus-visible {
  outline: 2px solid var(--map-focus-color);
  outline-offset: 2px;
}
.search-toggle {
  /* Active (panel open) — inverse of the default outline: filled instead of outlined */
}
.search-toggle[aria-expanded=true] {
  background: var(--map-primary-color);
  border-color: var(--map-primary-color);
  color: var(--map-text-on-primary);
}

.search-toggle-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1rem;
  height: 1rem;
  position: relative;
  flex-shrink: 0;
}

.search-toggle-icon--open span {
  position: absolute;
  width: 100%;
  height: 2px;
  background: currentColor;
  border-radius: 1px;
}
.search-toggle-icon--open span:first-child {
  transform: rotate(45deg);
}
.search-toggle-icon--open span:last-child {
  transform: rotate(-45deg);
}

.search-toggle-icon--closed {
  flex-direction: column;
  justify-content: center;
  gap: 3px;
}
.search-toggle-icon--closed span {
  display: block;
  width: 100%;
  height: 2px;
  background: currentColor;
  border-radius: 1px;
}

.map-container[data-search-open=true] .search-toggle-icon--closed,
.map-container[data-search-open=true] .search-toggle-icon--search,
.map-container[data-search-open=false] .search-toggle-icon--open {
  display: none;
}

/* Magnifying-glass icon for the nav toggle (search closed, X when open) */
.search-toggle-icon--search svg {
  display: block;
}

/* Desktop nav magnifier — sits at the right of the nav, inline with the purple
   brand pills. Carries a persistent "Search" label (no hover-expand). */
.search-toggle--nav {
  margin-inline-start: auto;
  gap: var(--map-spacing-xs);
}

/* Always-visible label (overrides the collapsing hover-expand label) */
.search-toggle-label.search-toggle-label--static {
  max-width: none;
  overflow: visible;
}

/* Mobile keeps the bottom-bar hamburger toggle; hide the nav magnifier there */
@media (max-width: 48em) {
  .search-toggle--nav {
    display: none;
  }
}
/* Search collapsed — hide desktop tabs; body hidden in _layout.scss */
.map-container[data-search-open=false] .search-tabs {
  display: none;
}
.map-container[data-search-open=false] .map-sidebar-header {
  border-bottom: none;
}

/* Desktop only: transparent header when search collapsed over map */
@media (min-width: 48.0625em) {
  .map-container[data-search-open=false] .map-sidebar-header {
    background: transparent;
  }
}
.search-toggle-label {
  max-width: 0;
  overflow: hidden;
  white-space: nowrap;
  transition: max-width var(--map-transition-fast) ease;
}

.search-toggle:hover .search-toggle-label,
.search-toggle:focus-visible .search-toggle-label {
  max-width: 8rem;
}

/*
█████████████████████████████████
 * 3.6 FILTER CHIPS
 *    Inline chips in map nav
█████████████████████████████████
*/
.filter-chips {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  min-width: 0;
  max-width: 100%;
}
.filter-chips[hidden] {
  display: none;
}

.filter-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 0.25rem 0.5rem;
  background: var(--map-background-white);
  border: 1px solid var(--map-primary-color);
  border-radius: var(--map-border-radius-full);
  font-size: var(--map-font-size-xs);
  color: var(--map-primary-color);
  cursor: pointer;
  white-space: nowrap;
  box-shadow: var(--map-shadow-sm);
  transition: all var(--map-transition-fast);
  line-height: 1.2;
}
.filter-chip:hover {
  border-color: var(--map-primary-color);
  background: var(--map-primary-light);
  color: var(--map-background-white);
}
.filter-chip:focus-visible {
  outline: 2px solid var(--map-focus-color);
  outline-offset: 2px;
}

.filter-chip-label {
  /* max-width: 120px; */
  overflow: hidden;
  text-overflow: ellipsis;
}

.filter-chip-remove {
  font-size: 0.85em;
  opacity: 0.6;
  line-height: 1;
}

.filter-chip:hover .filter-chip-remove {
  opacity: 1;
}

.filter-chip--clear {
  background: var(--map-primary-color);
  color: var(--map-background-white);
  border-color: transparent;
  font-weight: 600;
}
.filter-chip--clear:hover {
  background: var(--map-primary-hover);
}

.map-sidebar-header {
  display: flex;
  align-items: center;
  gap: var(--map-spacing-sm);
  padding: var(--map-spacing-sm) var(--map-spacing-md);
  border-bottom: 1px solid var(--map-border-color);
  background: var(--map-background-light);
  flex-shrink: 0;
}

.search-tabs {
  display: flex;
  gap: var(--map-spacing-xs);
  flex: 1;
  min-width: 0;
}

.search-tab {
  padding: 0.4rem 0.75rem;
  border: 1px solid transparent;
  border-radius: var(--map-border-radius-sm);
  background: transparent;
  color: var(--map-text-secondary);
  cursor: pointer;
  font-size: var(--map-font-size-sm);
  white-space: nowrap;
  /* Selecting a tab makes it semibold, and semibold is wider — "Filters"
     gains ~6px, which moved the whole tab group and made the two open sheets
     sit differently from each other. Reserve the bold width up front with a
     zero-height copy of the label, so the box is the same whether or not this
     tab is the active one. data-label is set alongside the visible text in
     map-sidebar-header.php.

     ::before, not ::after — the Filters tab's active-filter dot already owns
     ::after further down, at a higher specificity, and silently won this
     element's `content` (the phantom rendered as an empty string, so only the
     Filters tab kept resizing). One pseudo-element each. */
}
.search-tab::before {
  content: attr(data-label);
  display: block;
  height: 0;
  overflow: hidden;
  visibility: hidden;
  font-weight: 600;
  pointer-events: none;
}
.search-tab {
  /* The phantom above is a block box, which wraps the label's text in an
     anonymous block — and `text-overflow` is not inherited, so an anonymous
     box always falls back to `clip`. Putting it on .search-tab clips long
     translations mid-glyph instead of ellipsising them. The real element below
     is what carries the shrink path; .search-tab only sets the width. */
}
.search-tab .search-tab-label {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
}
.search-tab {
  /* Active tab — purple text + purple border, no fill (mobile + desktop) */
}
.search-tab[aria-selected=true] {
  background: transparent;
  color: var(--map-primary-color);
  font-weight: 600;
  border-color: var(--map-primary-color);
}
.search-tab[aria-selected=true]:hover, .search-tab[aria-selected=true]:focus-visible {
  background: var(--map-background-light);
  color: var(--map-primary-color);
}
.search-tab:hover:not([aria-selected=true]) {
  color: var(--map-primary-color);
  background: var(--map-background-light);
}
.search-tab:focus-visible {
  outline: 2px solid var(--map-focus-color);
  outline-offset: 2px;
}

/* 3.6.1 BOTTOM-BAR NAV EXTRAS (mobile only)
   Back-to-guide link + live count live in the bottom bar on mobile; on desktop
   the top .map-nav carries them, so they stay hidden here. The sr-only status
   is display:none rather than merely clipped, so desktop doesn't announce the
   count twice from two live regions. */
.map-bottombar-back,
.map-bottombar-count,
.map-bottombar-count-status {
  display: none;
}

/* Home — shares the bar's leading slot with the ✕ (only ever one at a time),
   so the two must agree on their box to the pixel or the count and tabs shift
   when a sheet opens. Same square, different surface: the ✕ is a raised white
   disc, home is unfilled. Keep the geometry here and in .map-sheet-close in
   step. */
.map-bottombar-back {
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  /* 44px, not the 1.75rem this used to be. The global touch-target rule in
     _wcag.scss only reaches `button`, so as a bare <a> this control sized
     itself and landed at 42px — under WCAG 2.5.5, and 2px off the ✕ that
     replaces it, which shifted the whole row on open. Both now take the token
     the rule uses, so they are compliant and identical by construction. */
  width: var(--min-touch-target);
  height: var(--min-touch-target);
  border-radius: var(--map-border-radius-full);
  /* No fill, unlike the ✕ that shares this slot and the count next to it. Two
     filled circles side by side read as one grouped control; the bare emoji
     keeps home legible as its own thing. The 44px box is still the target. */
  background: transparent;
  box-shadow: none;
  text-decoration: none;
}
.map-bottombar-back:hover {
  background: var(--map-background-medium);
}
.map-bottombar-back:focus-visible {
  outline: 2px solid var(--map-focus-color);
  outline-offset: 2px;
}

/* Emoji glyph, so it renders in its own colours on the filled circle rather
   than inheriting `color`. Sized under the circle so it never crowds the edge;
   the explicit family keeps a text-styled variant from being substituted. */
.map-bottombar-back-icon {
  display: block;
  font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif;
  font-size: 0.9rem;
  line-height: 1;
}

/* Compact count chip — number only (full label is read out via sr-only text).
   It is a button: it discloses .map-count-summary, which says in words what the
   number counts. On mobile the top nav (count + chips) is hidden, so without
   this the bare "13" has no explanation anywhere. */
.map-bottombar-count {
  align-items: center;
  flex: 0 0 auto;
  margin: 0;
  padding: 0.25rem 0.55rem;
  border: none;
  border-radius: var(--map-border-radius-full);
  background: var(--map-primary-color);
  color: var(--map-neutral-white);
  font-family: var(--font-ks);
  font-size: var(--map-font-size-sm);
  font-weight: 600;
  line-height: 1.4;
  cursor: pointer;
}
.map-bottombar-count:focus-visible {
  outline: 2px solid var(--map-focus-color);
  outline-offset: 2px;
}
.map-bottombar-count[aria-expanded=true] {
  box-shadow: 0 0 0 2px var(--map-background-light), 0 0 0 4px var(--map-primary-color);
}

/* Sheet close — the single exit from an open Places/Filters sheet, in the same
   visual language as .place-detail__close so every sheet closes the same way.
   Hidden while the sheet is shut: the tabs are the only way in. Shares the
   bar's leading slot with .map-bottombar-back — same box, different fill. */
.map-sheet-close {
  display: none;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  /* Matches .map-bottombar-back exactly — see the note there. */
  width: var(--min-touch-target);
  height: var(--min-touch-target);
  padding: 0;
  border: none;
  border-radius: var(--map-border-radius-full);
  background: var(--map-background-white);
  color: var(--map-primary-color);
  box-shadow: var(--map-shadow-sm);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
  transition: box-shadow var(--map-transition-fast);
}
.map-sheet-close:hover {
  box-shadow: var(--map-shadow-md);
}
.map-sheet-close:focus-visible {
  outline: 2px solid var(--map-focus-color);
  outline-offset: 2px;
}

/* Plain-language reading of the count. Sits above the bar (DOM order inside
   .map-sidebar), so it reads as an annotation on the number that opened it. */
.map-count-summary {
  position: relative;
  display: none;
  flex: 0 1 auto;
  /* Six facet groups with several values each outgrow the space above the bar,
     and the sidebar clips overflow — without a cap the panel's own ✕ and Clear
     button are the first things to disappear, with no way to scroll to them. */
  max-height: 60svh;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--map-spacing-md) 2.75rem var(--map-spacing-md) var(--map-spacing-md);
  background: var(--map-background-white);
  border-top: 1px solid var(--map-border-color);
  box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.08);
  font-size: var(--map-font-size-sm);
  color: var(--map-text-primary);
}
.map-count-summary[hidden] {
  display: none;
}

.map-count-summary__heading {
  margin: 0 0 var(--map-spacing-xs);
  font-family: var(--font-ks);
  font-size: var(--map-font-size-lg);
  font-weight: 700;
  line-height: 1.2;
}

.map-count-summary__lead {
  margin: 0 0 var(--map-spacing-sm);
  color: var(--map-text-secondary);
}

.map-count-summary__groups {
  margin: 0 0 var(--map-spacing-sm);
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--map-spacing-xs);
}

.map-count-summary__group {
  display: flex;
  flex-direction: column;
  padding-inline-start: var(--map-spacing-sm);
  border-inline-start: 3px solid var(--map-primary-color);
}

.map-count-summary__group-name {
  font-weight: 600;
}

.map-count-summary__group-values {
  color: var(--map-text-secondary);
}

.map-count-summary__rule {
  margin: 0;
  color: var(--map-text-muted);
  font-size: var(--map-font-size-xs);
  line-height: 1.4;
}

.map-count-summary__clear {
  margin-top: var(--map-spacing-sm);
  padding: 0.4rem 0.75rem;
  border: 1px solid var(--map-primary-color);
  border-radius: var(--map-border-radius-sm);
  background: transparent;
  color: var(--map-primary-color);
  font-size: var(--map-font-size-xs);
  cursor: pointer;
}
.map-count-summary__clear:focus-visible {
  outline: 2px solid var(--map-focus-color);
  outline-offset: 2px;
}

.map-count-summary__close {
  position: sticky;
  float: right;
  top: 0;
  margin-inline-end: calc(var(--map-spacing-sm) - 2.75rem);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  padding: 0;
  border: none;
  border-radius: var(--map-border-radius-full);
  background: var(--map-background-light);
  color: var(--map-text-secondary);
  font-size: 0.9rem;
  line-height: 1;
  cursor: pointer;
}
.map-count-summary__close:hover {
  color: var(--map-primary-color);
}
.map-count-summary__close:focus-visible {
  outline: 2px solid var(--map-focus-color);
  outline-offset: 2px;
}

/*
█████████████████████████████████
 * 3.7 SEARCH PANELS
 *    Places list and Filter facets (exclusive panels)
█████████████████████████████████
*/
.search-panel--filters,
.search-panel--places {
  flex: 1;
  min-height: 0;
  overflow: hidden;
  flex-direction: column;
}

.search-panel[hidden] {
  display: none !important;
}

.search-panel--filters:not([hidden]),
.search-panel--places:not([hidden]) {
  display: flex;
}

.search-panel--filters {
  border-bottom: none;
}

.search-panel--places .sidebar-content {
  flex: 1;
  min-height: 0;
}

/* Inline list search — a fixed header above the scrolling list */
.places-search {
  flex: 0 0 auto;
  padding: var(--map-spacing-md) var(--map-spacing-md) 0;
}
.places-search[hidden] {
  display: none;
}

.places-search-input {
  width: 100%;
  padding: var(--map-spacing-sm);
  font-family: inherit;
  font-size: var(--map-font-size-sm);
  color: var(--map-text-primary);
  background: var(--map-background-white);
  border: 1px solid var(--map-border-color);
  border-radius: var(--map-border-radius-md);
}
.places-search-input::placeholder {
  color: var(--map-text-muted);
}
.places-search-input:focus-visible {
  outline: 2px solid var(--map-focus-color);
  outline-offset: 1px;
  border-color: var(--map-focus-color);
}

/* Empty while the field is — collapses so it costs no space at rest */
.places-search-status {
  margin: 0;
  font-size: var(--map-font-size-xs);
  color: var(--map-text-secondary);
}
.places-search-status:not(:empty) {
  margin-block-start: var(--map-spacing-xs);
}

.venue-card[hidden] {
  display: none;
}

/* The shared .filters-inline forces height:100vh (sized for a full-height
   desktop sidebar). Inside the search panel it must instead fill the panel so
   the facet list scrolls and the sticky "Clear All Filters" stays anchored —
   critical now that the mobile Filters sheet is shorter than the viewport. */
.search-panel--filters .sidebar-filters {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}

.search-panel--filters .filters-inline {
  flex: 1;
  min-height: 0;
  height: auto;
  max-height: 100%;
}

/* Mobile: fold the top nav into a single integrated bottom bar */
@media (max-width: 48em) {
  /* Top nav is folded into the bottom bar on mobile — hide it to free the map top */
  .map-nav {
    display: none;
  }
  /* Bottom bar now carries the back link + count */
  .map-bottombar-back,
  .map-bottombar-count {
    display: inline-flex;
  }
  /* Stays visually hidden via .sr-only; this only re-enters the a11y tree */
  .map-bottombar-count-status {
    display: block;
  }
  /* Count summary is a mobile answer to a mobile problem (no chips line).
     It always sits against the bar that opened it, which means opposite sides
     in the two states: collapsed the bar is at the bottom of the screen so the
     summary rises above it (natural DOM order); open the bar is the sheet's
     title bar so the summary drops below it (the order swap). count-summary.js
     moves focus into the panel on open, so the reordering can't strand a
     keyboard user behind it. */
  .map-count-summary:not([hidden]) {
    display: block;
  }
  .map-container[data-search-open=true] .map-sidebar-header {
    order: 1;
  }
  .map-container[data-search-open=true] .map-count-summary {
    order: 2;
    border-top: none;
    border-bottom: 1px solid var(--map-border-color);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  }
  .map-container[data-search-open=true] .map-sidebar-body {
    order: 3;
  }
  /* The ✕ appears only once there is a sheet to close */
  .map-container[data-search-open=true] .map-sheet-close {
    display: inline-flex;
  }
  /* Toggle is icon-only on mobile */
  .search-toggle-label {
    display: none;
  }
  /* Collapsed, the header IS the bottom bar: back | count | (gap) | tabs.
     Open, the same row becomes the full-screen sheet's title bar and gains the
     ✕ — same controls, same order, so the bar never reshuffles under the thumb. */
  .map-sidebar-header {
    padding: 0.4rem 0.5rem;
    gap: 0.4rem;
    border-bottom: none;
    border-top: 1px solid var(--map-border-color);
    box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.08);
  }
  .map-container[data-search-open=true] .map-sidebar-header {
    border-top: none;
    border-bottom: 1px solid var(--map-border-color);
    box-shadow: none;
  }
  /* Push the tabs to the right; home and the count stay left. The two read as
     separate controls rather than a pair because home carries no fill — see
     .map-bottombar-back. The tabs keep a shrink path for long translations
     (.search-tab-label ellipsises), but the leading slot holds exactly one
     control in both states, so a row that fits closed fits open. */
  .search-tabs {
    flex: 0 1 auto;
    min-width: 0;
    margin-inline-start: auto;
  }
  .search-tab {
    padding: 0.4rem 0.5rem;
    min-width: 0;
    overflow: hidden;
  }
  /* The leading slot swaps its occupant and nothing else moves. Closed the bar
     is map chrome, so it carries home; open it is the sheet's title bar, so the
     ✕ takes the same square. Both are 1.75rem circles, so the count and the
     tabs land on the identical pixels either way — the row never reshuffles
     under the thumb. (An earlier arrangement put the ✕ at the far end and hid
     home, which shifted the tabs on every open.) */
  .map-container[data-search-open=true] .map-bottombar-back {
    display: none;
  }
  /* Narrow phones (≤360px): at the standard spacing the four controls stop
     fitting and the tab labels start ellipsising — "Filt…" / "All Spa…", which
     is not acceptable, because the labels *are* the navigation. Buy the ~13px
     back from padding rather than from the words. The 44px touch targets and
     the flexible gap before the count are both left alone. */
}
@media (max-width: 48em) and (max-width: 22.5em) {
  .map-sidebar-header {
    padding-inline: 0.3rem;
    gap: 0.25rem;
  }
  .search-tabs {
    gap: 0.15rem;
  }
  .search-tab {
    padding-inline: 0.2rem;
  }
}
@media (max-width: 48em) {
  /* Borderless toggle on mobile in both open/closed states */
  .search-toggle {
    border: none;
    background: transparent;
    padding: 0.35rem 0.45rem;
    box-shadow: none;
  }
  .search-toggle:hover, .search-toggle:focus-visible {
    border: none;
    outline: none;
    background: var(--map-background-white);
  }
  .search-toggle {
    /* Stay borderless — the desktop filled "active" state doesn't apply here */
  }
  .search-toggle[aria-expanded=true] {
    border: none;
    background: transparent;
    color: var(--map-primary-color);
  }
  /* Active-filter indicator dot on the Filters tab — full management in overlay.
     Keep this on ::after: .search-tab::before is spoken for by the width
     reservation that stops the tabs resizing when selection moves. */
  .map-container[data-has-filters=true] .search-tab[data-target=filters] {
    position: relative;
  }
  .map-container[data-has-filters=true] .search-tab[data-target=filters]::after {
    content: "";
    position: absolute;
    top: 0.1rem;
    right: 0.1rem;
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 50%;
    background: var(--map-primary-color);
    box-shadow: 0 0 0 2px var(--map-background-light);
  }
  /* Collapsed bottom bar */
  .map-container[data-search-open=false] .map-sidebar {
    height: auto;
    max-height: none;
    overflow: hidden;
  }
  .map-container[data-search-open=false] {
    /* Re-show tabs in the bottom bar (a global collapsed rule hides them) */
  }
  .map-container[data-search-open=false] .search-tabs {
    display: flex;
  }
  .map-container[data-search-open=false] {
    /* Collapsed: tabs visible but none reads as active */
  }
  .map-container[data-search-open=false] .search-tab[aria-selected=true] {
    background: transparent;
    color: var(--map-text-secondary);
    font-weight: 400;
    border-color: transparent;
  }
  /* Zoom control lifts above the bottom bar so both + and − stay visible */
  .map-wrapper .maplibregl-ctrl-bottom-left,
  .map-wrapper .leaflet-bottom.leaflet-left {
    margin-bottom: calc(var(--map-bottombar-height, 3.25rem) + var(--map-spacing-sm));
  }
}
.sidebar-empty {
  padding: var(--map-spacing-lg);
  text-align: center;
  color: var(--map-text-muted);
  font-size: var(--map-font-size-sm);
}

/*
█████████████████████████████████
 * 3.7 MAP HTML MARKERS
 * Individual place markers and cluster markers rendered as maplibregl.Marker
 * HTML elements for full CSS/SVG control.
 *
 * Individual (.map-place-marker): white square, rounded corners.
 *   .has-data variant adds a purple outline ring — indicates the place has
 *   at least one matched accessibility facet (facets object non-empty).
 *   No ring = no matched facets. See makePlaceMarkerEl() in map.js.
 *
 * Cluster (.map-cluster): SVG with count label + arc ring.
 *   Arc ratio = hasDataCount / point_count — fraction of places in the
 *   cluster with accessibility data. Full ring = all have data, empty = none.
 *   See makeClusterMarkerEl() in map.js for arc math and design rationale.
█████████████████████████████████
*/
.map-place-marker {
  /* The element is a 28px invisible hit target: role=button pulls in the
     global 44px touch-target mins (_wcag.scss), overridden here but kept
     ≥24px (WCAG 2.5.8). The visible square stays 20px (drawn by ::before)
     so it remains clearly smaller than the 34px cluster core / 54px ring. */
  width: 28px;
  height: 28px;
  min-width: 0;
  min-height: 0;
  padding: 0;
  cursor: pointer;
  transition: transform 120ms ease;
}
.map-place-marker::before {
  content: "";
  position: absolute;
  inset: 4px; /* 28px box − 4px each side = 20px visual square */
  background: var(--map-background-white);
  border-radius: 4px;
  /* ring (spread=0, blur=0, 1.5px) + drop shadow — no separate border needed */
  box-shadow: 0 0 0 1.5px var(--map-border-primary), var(--map-shadow-md);
}
.map-place-marker:hover {
  transform: scale(1.15);
}
.map-place-marker {
  /* Partial data (1–49% of categories matched): light purple fill */
}
.map-place-marker.has-data--partial::before {
  background: var(--map-primary-light);
  box-shadow: 0 0 0 1.5px var(--map-primary-color), var(--map-shadow-md);
}
.map-place-marker {
  /* Full data (≥50% of categories matched): solid purple fill */
}
.map-place-marker.has-data--full::before {
  background: var(--map-primary-color);
  box-shadow: 0 0 0 1.5px var(--map-primary-dark), var(--map-shadow-md);
}
.map-place-marker.is-selected {
  transform: scale(1.2);
  z-index: 2;
}
.map-place-marker.is-selected::before {
  box-shadow: 0 0 0 3px var(--map-focus-color), 0 0 0 5px color-mix(in srgb, var(--map-focus-color) 35%, transparent), var(--map-shadow-md);
}

/* Place name label — sits below the marker square, only visible when zoomed in */
.map-place-label {
  position: absolute;
  /* +1px from the 28px hit box = +5px from the 20px visual square */
  top: calc(100% + 1px);
  left: 50%;
  transform: translateX(-50%);
  white-space: nowrap;
  font-size: 11px;
  font-weight: 600;
  color: var(--map-text-primary);
  /* Legibility over any map tile colour */
  text-shadow: 0 0 3px white, 0 0 6px white, 0 1px 4px white;
  pointer-events: none;
  line-height: 1.2;
  opacity: 0;
  transition: opacity 200ms ease;
}

.is-zoomed-in .map-place-label {
  opacity: 1;
}

.map-cluster {
  cursor: pointer;
  transition: transform 120ms ease;
}
.map-cluster svg {
  display: block;
}
.map-cluster:hover {
  transform: scale(1.1);
}

/*
█████████████████████████████████
 * 3.8 GEOLOCATION NOTICE DIALOG
 *    Privacy notice before location access
█████████████████████████████████
*/
.geolocation-notice {
  position: fixed;
  inset: 50% auto auto 50%;
  transform: translate(-50%, -50%);
  padding: 0;
  border: none;
  border-radius: 8px;
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.15);
  width: min(440px, 100vw - 2rem);
  height: auto;
  z-index: 1000;
  background: var(--color-page, white);
  color: var(--color-text);
  margin: 0;
}
.geolocation-notice::backdrop {
  background: color-mix(in oklch, var(--color-text) 45%, transparent);
}

.geolocation-notice-content {
  padding: var(--space-lg, 24px);
  border-radius: 8px;
}
.geolocation-notice-content h2 {
  margin: 0 0 var(--space-md, 16px) 0;
  font-size: 18px;
  font-weight: 600;
  color: var(--color-text);
}
.geolocation-notice-content p {
  margin: 0 0 var(--space-lg, 24px) 0;
  font-size: 14px;
  color: var(--color-text-muted);
  line-height: 1.5;
}

.geolocation-notice-actions {
  display: flex;
  gap: var(--space-md, 16px);
  justify-content: flex-end;
  /* No `border` shorthand here — it would out-specify the per-variant borders
     below (0,2,0 vs 0,1,0) and flatten Cancel's outline. Each variant owns its
     own border; both keep 1px so the two buttons stay the same box size. */
}
.geolocation-notice-actions button {
  padding: 0.5rem 1.25rem;
  border-radius: 4px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: all 150ms ease;
}
.geolocation-notice-actions button:focus-visible {
  outline: 2px solid var(--color-focus-ring);
  outline-offset: 2px;
}

.geolocation-notice-cancel {
  background: var(--color-bg-muted);
  color: var(--color-text);
  border: 1px solid var(--color-border);
}
.geolocation-notice-cancel:hover {
  background: color-mix(in oklch, var(--color-text) 10%, var(--color-page));
}

.geolocation-notice-confirm {
  background: var(--purple);
  color: var(--color-text-inverse);
  border: 1px solid transparent;
}
.geolocation-notice-confirm:hover {
  background: color-mix(in oklch, var(--purple) 85%, var(--color-text));
}

/*
█████████████████████████████████
 * 3.9 USER LOCATION MARKER
 *    "You are here" dot dropped after a successful locate
█████████████████████████████████
*/
/* Shared by both engines: MapLibre centres the element itself (anchor:
   'center'), Leaflet positions this same class as the divIcon root with a
   [11,11] anchor on a 22px box — so the element must be exactly 22px square
   and draw itself from the centre out. */
.map-user-location {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  /* Non-interactive: it marks a position, it isn't a control. Without this the
     dot would swallow clicks meant for a place marker underneath it. */
  pointer-events: none;
  /* Round, coloured and ringed — three axes of difference from the white/purple
     rounded squares used for places, so it never reads as another venue. */
  background: var(--map-user-location-color);
  box-shadow: 0 0 0 3px var(--map-background-white), var(--map-shadow-md);
  /* Halo pulsing outward, so the dot is findable on a crowded map without
     needing colour alone to carry it. */
}
.map-user-location::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: var(--map-user-location-color);
  opacity: 0.35;
  animation: map-user-location-pulse 2.4s ease-out infinite;
}

@keyframes map-user-location-pulse {
  0% {
    transform: scale(1);
    opacity: 0.35;
  }
  70% {
    transform: scale(2.6);
    opacity: 0;
  }
  100% {
    transform: scale(2.6);
    opacity: 0;
  }
}
/* The halo is decoration; the dot itself still marks the position. */
@media (prefers-reduced-motion: reduce) {
  .map-user-location::after {
    animation: none;
    opacity: 0;
  }
}
[data-reduced-motion=reduce] .map-user-location::after {
  animation: none;
  opacity: 0;
}

/**
 * LAAC Map Plugin - States Layer
 * Loading & Error States
 */
/*
█████████████████████████████████
 * 4. STATE LAYER
█████████████████████████████████
*/
/*
█████████████████████████████████
 * 4.1 LOADING STATES
 *    User feedback during operations
█████████████████████████████████
*/
.map-loading {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  background: rgba(255, 255, 255, 0.9);
  /* Overlay and fade support */
  position: absolute;
  inset: 0;
  z-index: var(--map-z-overlay);
  pointer-events: none;
  opacity: 1;
  transition: opacity 5s;
}

/* Pure-CSS fade hook: when the wrapper is ready, fade out the loader */
[data-map-ready=true] .map-loading {
  opacity: 0;
}

.loading-spinner {
  width: var(--map-control-size);
  height: var(--map-control-size);
  border: 4px solid var(--map-background-light);
  border-top: 4px solid var(--map-primary-color);
  border-radius: var(--map-border-radius-full);
  animation: spin 1s linear infinite;
}

@keyframes spin {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}
/*
█████████████████████████████████
 * 4.2 ERROR STATES
 *    Error handling and user feedback
█████████████████████████████████
*/
.map-error {
  display: none;
  align-items: center;
  justify-content: center;
  height: 100%;
  background: var(--map-error-bg);
  border: 1px solid var(--map-error-border);
  color: var(--map-error-color);
  text-align: center;
  padding: var(--map-spacing-xl);
  /* Overlay */
  position: absolute;
  inset: 0;
  z-index: var(--map-z-overlay);
}

/**
 * █████████████████████████████████
 *
 * 🎨 LAAC Map Plugin — Integration Layer (SCSS)
 *
 * █████████████████████████████████
 *
 * Third‑party library overrides and integration glue.
 *
 * Features:
 * - Leaflet UI refinements (attribution, popup, markers)
 * - Defensive overrides against external resets
 * - Data‑driven marker styling hooks
 *
 * Components:
 * - Map Attribution (Leaflet, MapLibre)
 * - Popups (base + frosted‑glass backdrop)
 * - Leaflet Marker Icons + Shadows
 * - ARIA Visibility for Markers
 * - Data‑driven Marker (`.map-marker`)
 * - Popup Content Structure (Leaflet + MapLibre)
 *
 * Dependencies:
 * - Leaflet CSS structure and classnames
 * - MapLibre CSS structure and classnames
 * - Map design tokens (CSS variables)
 */
/*  ==================================================
      ⚙️ Integration Layer
    ==================================================  */
/*  ==================================================
      🌐 Leaflet customization
      Third‑party library overrides
    ==================================================  */
/**
 * 🎛️ Component — Map Attribution Controls
 *
 * Provides compact, accessible attribution UIs for Leaflet and MapLibre.
 *
 * Features:
 * - Chip‑like MapLibre attribution with toggle disclosure
 * - Minimal Leaflet attribution sizing
 *
 * Dependencies:
 * - .maplibregl-ctrl-attrib DOM structure
 * - div.leaflet-control-attribution
 */
/* Attribution */
div.leaflet-control-attribution {
  font-size: 0.25rem;
}

/* MapLibre attribution (bottom-right) — match example look */
.maplibregl-ctrl-bottom-right .maplibregl-ctrl-attrib {
  margin: var(--map-spacing-xs);
  padding: 2px 6px;
  background: rgba(255, 255, 255, 0.85);
  border-radius: var(--map-border-radius-sm);
  box-shadow: var(--map-shadow-sm);
  font-size: 11px;
  line-height: 1.2;
  color: var(--map-text-primary);
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* Hide inner content by default; MapLibre adds [open] when expanded */
.maplibregl-ctrl-bottom-right .maplibregl-ctrl-attrib .maplibregl-ctrl-attrib-inner {
  display: none;
}

.maplibregl-ctrl-bottom-right .maplibregl-ctrl-attrib[open] .maplibregl-ctrl-attrib-inner {
  display: block;
}

/* Use built-in summary trigger; style it like an "i" */
.maplibregl-ctrl-bottom-right .maplibregl-ctrl-attrib summary.maplibregl-ctrl-attrib-button {
  list-style: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  border-radius: var(--map-border-radius-full);
  background: var(--map-background-light);
  color: var(--map-text-primary);
  font-weight: 700;
  font-size: 12px;
  cursor: pointer;
}

.maplibregl-ctrl-bottom-right .maplibregl-ctrl-attrib summary.maplibregl-ctrl-attrib-button::-webkit-details-marker {
  display: none;
}

.maplibregl-ctrl-bottom-right .maplibregl-ctrl-attrib summary.maplibregl-ctrl-attrib-button::before {
  content: "i";
}

.maplibregl-ctrl-bottom-right .maplibregl-ctrl-attrib a {
  color: inherit;
  text-decoration: none;
}

.maplibregl-ctrl-bottom-right .maplibregl-ctrl-attrib a:hover {
  text-decoration: underline;
}

.maplibregl-ctrl-bottom-right .maplibregl-ctrl-attrib a:focus-visible {
  outline: 2px solid var(--map-focus-color);
  outline-offset: 2px;
  border-radius: 2px;
}

/**
 * 💬 Component — Popups (Base)
 *
 * Shared base padding, radius, shadow, and typography for Leaflet and
 * MapLibre popups.
 *
 * Dependencies:
 * - .leaflet-popup-content-wrapper
 * - .maplibregl-popup-content
 */
/* Popup */
.leaflet-popup-content-wrapper,
.maplibregl-popup-content {
  padding: var(--map-spacing-sm) var(--map-spacing-md) !important;
  border-radius: var(--map-border-radius-md) !important;
  box-shadow: var(--map-shadow-md) !important;
  color: var(--map-text-primary);
  max-width: var(--map-popup-max-width); /* read by JS for MapLibre */
}

/**
 * ✨ Component — Popup Backdrop Blur
 *
 * Frosted‑glass effect for popup container and tip.
 */
/* Popup backdrop blur */
.leaflet-popup-content-wrapper,
.leaflet-popup-tip,
.maplibregl-popup-content {
  background: rgba(255, 255, 255, 0.137254902) !important;
  -webkit-backdrop-filter: blur(20px) !important;
  backdrop-filter: blur(20px) !important;
}

/*
 * MapLibre popup tip — backdrop-filter workaround
 *
 * The default tip uses `width: 0; height: 0; border: 10px solid transparent`
 * (CSS border triangle trick). backdrop-filter only applies to an element's
 * box, so it has no visible area on a 0×0 element. We override to real
 * dimensions + clip-path so the frosted-glass effect actually renders.
 */
.maplibregl-popup-tip {
  border: none !important;
}

/* Shared frosted-glass for all tip directions */
.maplibregl-popup-anchor-bottom .maplibregl-popup-tip,
.maplibregl-popup-anchor-bottom-left .maplibregl-popup-tip,
.maplibregl-popup-anchor-bottom-right .maplibregl-popup-tip,
.maplibregl-popup-anchor-top .maplibregl-popup-tip,
.maplibregl-popup-anchor-top-left .maplibregl-popup-tip,
.maplibregl-popup-anchor-top-right .maplibregl-popup-tip,
.maplibregl-popup-anchor-left .maplibregl-popup-tip,
.maplibregl-popup-anchor-right .maplibregl-popup-tip {
  background: rgba(255, 255, 255, 0.6) !important;
  -webkit-backdrop-filter: blur(20px) !important;
  backdrop-filter: blur(20px) !important;
}

/* anchor-bottom / bottom-left / bottom-right — tip points ▼ */
.maplibregl-popup-anchor-bottom .maplibregl-popup-tip,
.maplibregl-popup-anchor-bottom-left .maplibregl-popup-tip,
.maplibregl-popup-anchor-bottom-right .maplibregl-popup-tip {
  width: 20px !important;
  height: 10px !important;
  clip-path: polygon(0 0, 100% 0, 50% 100%) !important;
  margin-top: -1px !important;
}

/* anchor-top / top-left / top-right — tip points ▲ */
.maplibregl-popup-anchor-top .maplibregl-popup-tip,
.maplibregl-popup-anchor-top-left .maplibregl-popup-tip,
.maplibregl-popup-anchor-top-right .maplibregl-popup-tip {
  width: 20px !important;
  height: 10px !important;
  clip-path: polygon(50% 0, 100% 100%, 0 100%) !important;
  margin-bottom: -1px !important;
}

/* anchor-left — tip points ◄ */
.maplibregl-popup-anchor-left .maplibregl-popup-tip {
  width: 10px !important;
  height: 20px !important;
  clip-path: polygon(0 50%, 100% 0, 100% 100%) !important;
  margin-right: -1px !important;
}

/* anchor-right — tip points ► */
.maplibregl-popup-anchor-right .maplibregl-popup-tip {
  width: 10px !important;
  height: 20px !important;
  clip-path: polygon(100% 50%, 0 0, 0 100%) !important;
  margin-left: -1px !important;
}

.leaflet-popup-content,
.maplibregl-popup .maplibregl-popup-content .map-popup {
  margin: 0;
}

/* Marker icons — ensure proper display */
/**
 * 📍 Component — Leaflet Default Marker Icons
 *
 * Ensures image‑based markers render at tokenized sizes and positions; also
 * guards against global resets on <img> elements.
 *
 * The :not() excludes the "you are here" dot, which is a divIcon rather than
 * one of Leaflet's image pins: every declaration here is !important, so
 * without the exclusion the dot would be forced to the 25×41 pin box, offset
 * by the pin's anchor margins, and painted over with marker-icon.png.
 *
 * Dependencies:
 * - .leaflet-container .leaflet-marker-icon
 * - .leaflet-marker-shadow
 */
.leaflet-container .leaflet-marker-icon:not(.map-user-location) {
  width: var(--map-marker-size) !important;
  height: var(--map-marker-height) !important;
  margin-left: calc(-1 * var(--map-marker-size) / 2) !important;
  margin-top: calc(-1 * var(--map-marker-height)) !important;
  background-image: url("./vendor/images/marker-icon.png") !important;
  background-size: var(--map-marker-size) var(--map-marker-height) !important;
  background-repeat: no-repeat !important;
}
.leaflet-container .leaflet-marker-shadow {
  width: var(--map-marker-height) !important;
  height: var(--map-marker-height) !important;
  margin-left: calc(-1 * var(--map-marker-height) / 2) !important;
  margin-top: calc(-1 * var(--map-marker-height)) !important;
  background-image: url("./vendor/images/marker-shadow.png") !important;
  background-size: var(--map-marker-height) var(--map-marker-height) !important;
  background-repeat: no-repeat !important;
}
.leaflet-container {
  /* Defensive overrides */
}
.leaflet-container img.leaflet-marker-icon {
  width: var(--map-marker-size) !important;
  height: var(--map-marker-height) !important;
  max-width: var(--map-marker-size) !important;
  max-height: var(--map-marker-height) !important;
  min-width: var(--map-marker-size) !important;
  min-height: var(--map-marker-height) !important;
}

/**
 * ✅ Component — ARIA Visibility Overrides (Markers)
 *
 * Keeps markers visible even if libraries toggle aria-hidden.
 */
/* ARIA visibility overrides */
.leaflet-marker-icon[aria-hidden=true],
.leaflet-marker-shadow[aria-hidden=true] {
  display: block !important;
  visibility: visible !important;
  opacity: 1 !important;
}

/*  ==================================================
      📍 Map marker styles
      Used by helpers.php for dynamic marker generation
    ==================================================  */
/**
 * 🧩 Component — Data‑Driven Map Marker
 *
 * Tokenized, color/size/border driven via CSS custom properties bound from
 * data attributes on `.map-marker` elements.
 */
.map-marker {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--map-background-white);
  font-weight: bold;
  font-size: var(--map-font-size-xs);
  border-radius: var(--map-border-radius-full);
  border: 2px solid var(--map-background-white);
}

/* Dynamic marker sizing and colors via data attributes */
.map-marker[data-size] {
  width: var(--marker-size);
  height: var(--marker-size);
}

.map-marker[data-color] {
  background-color: var(--marker-color);
}

.map-marker[data-border] {
  border-color: var(--marker-border);
}

/*  ==================================================
      💬 MapLibre popup (shared styles)
      Structure:
        .maplibregl-popup
          .maplibregl-popup-content
            .map-popup
              header.popup-header > h3.popup-title + .popup-neighborhood
              .popup-content
                .popup-address
                .popup-actions > a.popup-link
    ==================================================  */
/**
 * 🧱 Component — Popup Content Structure
 *
 * Normalizes inner header, address, and actions; applies focus/hover
 * affordances. Applies to both MapLibre and Leaflet popups.
 */
.maplibregl-popup,
.leaflet-popup-pane .leaflet-popup {
  z-index: var(--map-z-popup);
  /* Close button */
}
.maplibregl-popup .maplibregl-popup-close-button,
.maplibregl-popup .leaflet-popup-close-button,
.leaflet-popup-pane .leaflet-popup .maplibregl-popup-close-button,
.leaflet-popup-pane .leaflet-popup .leaflet-popup-close-button {
  position: absolute;
  top: var(--map-spacing-xs);
  right: var(--map-spacing-xs);
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  border-radius: var(--map-border-radius-full);
  color: var(--map-text-primary);
  font-size: var(--map-font-size-lg);
  line-height: 1;
  cursor: pointer;
  transition: background-color var(--map-transition-fast);
}
.maplibregl-popup .maplibregl-popup-close-button:hover,
.maplibregl-popup .leaflet-popup-close-button:hover,
.leaflet-popup-pane .leaflet-popup .maplibregl-popup-close-button:hover,
.leaflet-popup-pane .leaflet-popup .leaflet-popup-close-button:hover {
  background: var(--map-background-light);
}
.maplibregl-popup .maplibregl-popup-close-button:focus-visible,
.maplibregl-popup .leaflet-popup-close-button:focus-visible,
.leaflet-popup-pane .leaflet-popup .maplibregl-popup-close-button:focus-visible,
.leaflet-popup-pane .leaflet-popup .leaflet-popup-close-button:focus-visible {
  outline: 2px solid var(--map-focus-color);
  outline-offset: 2px;
}
.maplibregl-popup,
.leaflet-popup-pane .leaflet-popup {
  /* Inner content structure */
}
.maplibregl-popup .map-popup,
.leaflet-popup-pane .leaflet-popup .map-popup {
  display: block;
  min-width: 200px;
}
.maplibregl-popup .map-popup .popup-header,
.leaflet-popup-pane .leaflet-popup .map-popup .popup-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--map-spacing-sm);
  margin-bottom: var(--map-spacing-xs);
}
.maplibregl-popup .map-popup .popup-title,
.leaflet-popup-pane .leaflet-popup .map-popup .popup-title {
  margin: 0;
  font-size: var(--map-font-size-lg);
  color: var(--map-text-primary);
  font-weight: 600;
  text-wrap: balance;
}
.maplibregl-popup .map-popup .popup-neighborhood,
.leaflet-popup-pane .leaflet-popup .map-popup .popup-neighborhood {
  font-size: var(--map-font-size-xs);
  color: var(--map-text-secondary);
  background: var(--map-background-light);
  padding: 2px var(--map-spacing-xs);
  border-radius: var(--map-border-radius-sm);
  white-space: nowrap;
}
.maplibregl-popup .map-popup .popup-content,
.leaflet-popup-pane .leaflet-popup .map-popup .popup-content {
  display: grid;
  gap: var(--map-spacing-sm);
}
.maplibregl-popup .map-popup .popup-address,
.leaflet-popup-pane .leaflet-popup .map-popup .popup-address {
  font-size: var(--map-font-size-sm);
  color: var(--map-text-secondary);
}
.maplibregl-popup .map-popup .popup-address strong,
.leaflet-popup-pane .leaflet-popup .map-popup .popup-address strong {
  color: var(--map-text-primary);
}
.maplibregl-popup .map-popup .popup-address p,
.leaflet-popup-pane .leaflet-popup .map-popup .popup-address p {
  margin: 0;
  line-height: 1.4;
}
.maplibregl-popup .map-popup .popup-actions,
.leaflet-popup-pane .leaflet-popup .map-popup .popup-actions {
  display: flex;
  align-items: center;
  gap: var(--map-spacing-sm);
  padding-top: var(--map-spacing-sm);
  border-top: 1px solid var(--map-border-light);
}
.maplibregl-popup .map-popup .popup-link,
.leaflet-popup-pane .leaflet-popup .map-popup .popup-link {
  color: var(--map-primary-color);
  text-decoration: none;
  font-size: var(--map-font-size-sm);
}
.maplibregl-popup .map-popup .popup-link:hover,
.leaflet-popup-pane .leaflet-popup .map-popup .popup-link:hover {
  text-decoration: underline;
}
.maplibregl-popup .map-popup .popup-link:focus-visible,
.leaflet-popup-pane .leaflet-popup .map-popup .popup-link:focus-visible {
  outline: 2px solid var(--map-focus-color);
  outline-offset: 2px;
  border-radius: var(--map-border-radius-sm);
}

/**
 * LAAC Map Plugin - Main Stylesheet
 * 
 * This file imports all layer-specific stylesheets:
 * 1. _foundation.scss - CSS Variables & Design Tokens
 * 2. _layout.scss - Page Structure & Layout
 * 3. _components.scss - UI Components & Interactive Elements
 * 4. _states.scss - Loading & Error States
 * 5. _integration.scss - Third-party Library Overrides
 * 6. _utilities.scss - Utility Classes & Accessibility
 */
/* Import all layer files using modern @use syntax */
/**
 * LAAC Map Plugin - Utilities Layer
 * Utility Classes & Accessibility Styles
 */
/*
█████████████████████████████████
 * 6. UTILITIES LAYER
█████████████████████████████████
*/
/*
█████████████████████████████████
 * 6.1 ACCESSIBILITY & RESPONSIVE
 *    Global accessibility and mobile styles
█████████████████████████████████
*/
/* Screen reader only content */
.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;
}

/* Utility classes */
.hidden {
  display: none !important;
}

/* Focus management */
.map-wrapper:focus-within {
  outline: 2px solid var(--map-focus-color);
  outline-offset: 2px;
}

/* High contrast mode support */
@media (prefers-contrast: high) {
  :root {
    --map-border-color: oklch(0.2 0.01 0);
    --map-text-secondary: oklch(0.3 0.01 0);
    --map-background-light: oklch(0.95 0.005 0);
  }
}
/* Reduced motion: OS preference or site settings (html[data-reduced-motion]) */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-property: none !important;
    transition-duration: 0.01ms !important;
  }
  /* Loader fade: opacity-only at normal timing (see map-loader-quirks) */
  [data-allow-opacity-transition] {
    transition-property: opacity !important;
    transition-duration: var(--map-transition-fast, 0.25s) !important;
  }
}
html[data-reduced-motion=reduce] *,
html[data-reduced-motion=reduce] *::before,
html[data-reduced-motion=reduce] *::after {
  animation-duration: 0.01ms !important;
  animation-iteration-count: 1 !important;
  transition-property: none !important;
  transition-duration: 0.01ms !important;
}
html[data-reduced-motion=reduce] {
  /* Loader fade: opacity-only at normal timing (see map-loader-quirks) */
}
html[data-reduced-motion=reduce] [data-allow-opacity-transition] {
  transition-property: opacity !important;
  transition-duration: var(--map-transition-fast, 0.25s) !important;
}

/* Overlay root: out of flex layout; trigger visually hidden (Filter tab opens overlay) */
.map-container > .facet-container {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
  pointer-events: none;
}
.map-container > .facet-container .facet-overlay:not([hidden]) {
  pointer-events: auto;
}
.map-container > .facet-container .facet-trigger {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Mobile filter overlay — compact modal (mirrors facets.scss) */
@media (max-width: 48em) {
  .facet-overlay {
    padding: 0.35rem;
    align-items: stretch;
  }
  .facet-overlay .overlay-modal {
    width: 100%;
    max-height: 92svh;
    border-radius: var(--map-border-radius-sm);
  }
  .facet-overlay .overlay-header {
    padding: 0.5rem 0.65rem;
  }
  .facet-overlay .overlay-content {
    padding: 0.5rem 0.65rem 0.65rem;
  }
  .facet-overlay .section-container summary {
    display: flex;
    flex-wrap: nowrap;
    align-items: flex-start;
    gap: 0.35rem;
    padding: 0.5rem 0.6rem;
    font-size: var(--map-font-size-base);
  }
  .facet-overlay .section-container summary .facet-summary-text {
    flex: 1 1 auto;
    min-width: 0;
    line-height: 1.3;
  }
  .facet-overlay .section-container summary .facet-summary-emoji {
    flex-shrink: 0;
    align-self: baseline;
  }
  .facet-overlay .section-container summary::after {
    flex-shrink: 0;
    align-self: center;
    margin-left: 0.15rem;
  }
  /* Compact gutter; the shared calc in facets.scss picks this up. */
  .facet-overlay .section-container .facet-wrapper {
    --facet-gutter: 0.6rem;
  }
  .facet-overlay .section-container .facet-summary-control {
    margin-top: 0.5rem;
  }
  .facet-overlay .section-container .facet-wrapper:has(.facet-summary-control) > details > summary {
    padding-left: 0.35rem;
  }
  .facet-overlay .section-container .section-content {
    padding: 0.25rem 0.6rem 0.5rem;
  }
  .facet-overlay .filter-actions {
    flex-direction: column;
  }
}
/* Print styles */
@media print {
  .facet-container,
  .map-sidebar {
    display: none !important;
  }
  .map-view {
    height: auto !important;
    min-height: auto !important;
  }
}

/*# sourceMappingURL=map.css.map */
