/* ===== CSS Variables ===== */
:root {
  --bg-primary: #0f1923;
  --bg-secondary: #1a2632;
  --bg-tertiary: #243342;
  --bg-card: #1e2d3d;
  --text-primary: #e8edf2;
  --text-secondary: #8899aa;
  --text-muted: #5a6f82;
  --accent: #00c853;
  --accent-hover: #00e676;
  --accent-dim: rgba(0, 200, 83, 0.15);
  --danger: #ff5252;
  --warning: #ffab40;
  --info: #40c4ff;
  --verizon-color: #ee0000;
  --att-color: #00a8e0;
  --tmobile-color: #e20074;
  --sidebar-width: 380px;
  /* Height of the fixed notification bars stacked at the top of the viewport
     (#free-tier-bar, #coverage-bar). They are position:fixed at top:0 with a
     z-index above the whole UI, so anything else anchored near the top is
     simply BURIED under them — measured with the coverage bar up: the info
     panel's own title sat at y=25 under a bar whose bottom edge was y=35.
     app.js's syncTopBarInset() writes the real measured value here whenever a
     bar appears, changes copy (it re-wraps, so its height changes) or goes;
     0px is the truth when no bar is up. */
  --top-bar-height: 0px;
  /* THE SYSTEM BAR AT THE BOTTOM OF THE SCREEN (Android's gesture/home bar, an
     iPhone's home indicator). Measured 48px on a Galaxy S23 in the Capacitor
     app; 0px on desktop and on 3-button-nav devices. EVERY bottom-anchored
     fixed container adds it, and the rule is absolute (Josh, 2026-08-05: "do
     not have any buttons below or covered by that bottom bar ever") — so it is
     a token rather than a repeated env() call, and the boot smoke overrides
     this one property to a test value and then asserts that NOTHING
     interactive is left inside the zone. */
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --mobile-header-height: 56px;
  --radius: 8px;
  --radius-sm: 4px;
  --shadow: 0 4px 24px rgba(0,0,0,0.4);
  --transition: 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}

/* ===== Reset ===== */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; overflow: hidden; }
body {
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  background: var(--bg-primary);
  color: var(--text-primary);
  -webkit-font-smoothing: antialiased;
}

/* ===== Login Screen ===== */
#login-screen {
  position: fixed; inset: 0;
  background: var(--bg-primary);
  display: flex; align-items: center; justify-content: center;
  z-index: 10001;
  transition: opacity 0.4s ease;
}
#login-screen.fade-out { opacity: 0; pointer-events: none; }
.login-card {
  display: flex; flex-direction: column; align-items: center;
  padding: 32px 28px;
  background: var(--bg-secondary);
  border-radius: 16px;
  border: 1px solid var(--border, rgba(255,255,255,0.06));
  width: min(360px, 90vw);
}
.login-input {
  width: 100%; padding: 10px 12px;
  border-radius: var(--radius-sm, 6px);
  border: 1px solid var(--border, rgba(255,255,255,0.1));
  background: var(--bg-tertiary); color: var(--text-primary);
  font-size: 0.88rem; font-family: inherit;
  margin-bottom: 8px; outline: none;
}
.login-input:focus { border-color: var(--accent); }
.login-error {
  font-size: 0.75rem; color: #ff5252;
  margin-bottom: 8px; display: none;
  text-align: center;
}
.login-btn {
  width: 100%; padding: 10px; font-size: 0.88rem;
  border-radius: var(--radius-sm, 6px);
  cursor: pointer; margin-bottom: 6px;
}
/* Social sign-in ("Continue with …") — the #login-social block is injected-into
   by Auth._renderSocialButtons and stays display:none unless a provider is
   enabled in Auth.AUTH_PROVIDERS, so regions with none configured render the
   card exactly as before. Brand-minimal buttons: each provider's canonical
   colours, vendored FontAwesome brand glyphs, no external assets. */
#login-social { width: 100%; }
.login-divider {
  display: flex; align-items: center; gap: 10px;
  width: 100%; margin: 10px 0 12px;
  font-size: 0.68rem; color: var(--text-muted);
  text-transform: uppercase; letter-spacing: 0.06em;
  white-space: nowrap;
}
.login-divider::before, .login-divider::after {
  content: ''; flex: 1; height: 1px; background: rgba(255, 255, 255, 0.12);
}
.social-btn {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  width: 100%; padding: 10px; margin-bottom: 8px;
  border-radius: var(--radius-sm, 6px);
  border: 1px solid transparent;
  font-size: 0.85rem; font-weight: 600; font-family: inherit;
  cursor: pointer; transition: filter 0.15s ease;
}
.social-btn:hover { filter: brightness(1.08); }
.social-btn i { font-size: 1rem; }
.social-btn-google   { background: #fff;     color: #1f1f1f; border-color: #dadce0; }
.social-btn-google i { color: #4285f4; }
.social-btn-facebook { background: #1877f2;  color: #fff; }
.social-btn-apple    { background: #000;     color: #fff; border-color: rgba(255, 255, 255, 0.25); }
/* ===== Loading Screen ===== */
#loading-screen {
  position: fixed; inset: 0;
  background: var(--bg-primary);
  display: flex; align-items: center; justify-content: center;
  z-index: 10000;
  transition: opacity 0.5s ease;
}
#loading-screen.fade-out { opacity: 0; pointer-events: none; }
.loader-content { text-align: center; }
.loader-icon { font-size: 3rem; color: var(--accent); margin-bottom: 1rem; animation: pulse 1.5s infinite; }
.loader-content h2 { font-size: 1.5rem; font-weight: 700; margin-bottom: 0.5rem; }
.loader-content p { color: var(--text-secondary); margin-bottom: 1.5rem; }
.loader-bar { width: 200px; height: 3px; background: var(--bg-tertiary); border-radius: 3px; overflow: hidden; margin: 0 auto; }
.loader-progress { height: 100%; width: 30%; background: var(--accent); border-radius: 3px; animation: loading 1.5s ease-in-out infinite; }
@keyframes loading { 0% { transform: translateX(-100%); } 100% { transform: translateX(400%); } }
@keyframes pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.1); } }

/* ===== Mobile Header ===== */
#mobile-header {
  display: none;
  position: fixed; top: 0; left: 0; right: 0;
  height: var(--mobile-header-height);
  background: var(--bg-secondary);
  border-bottom: 1px solid var(--bg-tertiary);
  align-items: center;
  justify-content: space-between;
  padding: 0 12px;
  z-index: 1001;
}
#mobile-header h1 { font-size: 1.1rem; font-weight: 700; }
#mobile-header button {
  background: none; border: none; color: var(--text-primary);
  font-size: 1.2rem; padding: 8px; cursor: pointer;
}

/* ===== Sidebar ===== */
.sidebar {
  position: fixed; top: var(--top-bar-height); left: 0; bottom: 0;
  width: var(--sidebar-width);
  background: var(--bg-secondary);
  border-right: 1px solid var(--bg-tertiary);
  display: flex; flex-direction: column;
  z-index: 1000;
  transition: transform var(--transition);
  overflow: hidden;
  /* Runs to bottom:0, so without this the footer's own links — the OSM/DOC
     attribution, Privacy, Terms, Contact — sit UNDER the system bar. Measured
     on the phone: 10px, 35px, 35px, 35px of overlap. */
  padding-bottom: var(--safe-bottom);
}
.sidebar.collapsed { transform: translateX(-100%); }

/* ===== Desktop sidebar collapse (ported from motocamp-all) =====
   ONE body-level custom-property override does the whole job: zeroing
   --sidebar-width reflows #map, the map control rails, the basemap/3D pills
   and #info-panel together, because every one of them is already positioned
   off that variable. Desktop only — mobile keeps the .open overlay pattern,
   where the sidebar is already off-canvas by default. */
@media (min-width: 769px) {
  body.sidebar-collapsed { --sidebar-width: 0px; }
  body.sidebar-collapsed .sidebar { transform: translateX(-100%); }
  /* With the sidebar gone #info-panel would land at left:12px — the same
     corner the fixed #sidebar-expand (») button occupies. Clear the 38px
     button plus its gaps. */
  body.sidebar-collapsed #info-panel { left: 62px; }
  /* MapLibre's top-left control container (the 3D compass) lives INSIDE the
     map, which now starts at x=0 — so it would sit underneath #sidebar-expand,
     which is fixed and on a higher stacking layer. Ridgeflow-specific: the
     motocamp original has no top-left map control to collide with. */
  body.sidebar-collapsed .maplibregl-ctrl-top-left { margin-left: 50px; }
}
#sidebar-collapse {
  background: none; border: none; color: var(--text-secondary);
  font-size: 1rem; cursor: pointer; padding: 4px 8px;
}
#sidebar-collapse:hover { color: var(--text-primary); }
#sidebar-expand {
  position: fixed; top: calc(var(--top-bar-height) + 12px); left: 12px; z-index: 1001;
  width: 38px; height: 38px; border-radius: var(--radius-sm);
  background: var(--bg-secondary); border: 1px solid var(--bg-tertiary);
  color: var(--text-primary); font-size: 1rem; cursor: pointer;
  display: none; align-items: center; justify-content: center;
  box-shadow: 0 2px 10px rgba(0,0,0,0.4);
}
body.sidebar-collapsed #sidebar-expand { display: flex; }

.sidebar-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 16px 20px;
  border-bottom: 1px solid var(--bg-tertiary);
  flex-shrink: 0;
}
.brand { display: flex; align-items: center; gap: 10px; }
.brand i { font-size: 1.5rem; color: var(--accent); }
.brand h1 { font-size: 1.25rem; font-weight: 700; }
#sidebar-close {
  background: none; border: none; color: var(--text-secondary);
  font-size: 1.2rem; cursor: pointer; padding: 4px;
  display: none;
}

.sidebar-body {
  flex: 1; overflow-y: auto; overflow-x: hidden;
  padding: 0;
  scrollbar-width: thin;
  scrollbar-color: var(--bg-tertiary) transparent;
}
.sidebar-body::-webkit-scrollbar { width: 6px; }
.sidebar-body::-webkit-scrollbar-track { background: transparent; }
.sidebar-body::-webkit-scrollbar-thumb { background: var(--bg-tertiary); border-radius: 3px; }

.sidebar-footer {
  padding: 12px 20px;
  border-top: 1px solid var(--bg-tertiary);
  flex-shrink: 0;
}
.sidebar-footer p { font-size: 0.7rem; color: var(--text-muted); line-height: 1.5; }

/* ===== Tab Navigation ===== */
.tab-nav {
  display: flex;
  border-bottom: 1px solid var(--bg-tertiary);
  flex-shrink: 0;
}
.tab-btn {
  flex: 1;
  padding: 12px 8px;
  background: none; border: none;
  color: var(--text-secondary);
  font-size: 0.8rem; font-weight: 500;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  transition: all var(--transition);
  display: flex; align-items: center; justify-content: center; gap: 6px;
}
.tab-btn:hover { color: var(--text-primary); background: var(--bg-tertiary); }
.tab-btn.active { color: var(--accent); border-bottom-color: var(--accent); }
.tab-btn i { font-size: 0.9rem; }

.tab-content { display: none; }
.tab-content.active { display: block; }

/* ===== Sidebar Sections ===== */
.sidebar-section {
  padding: 16px 20px;
  border-bottom: 1px solid rgba(255,255,255,0.04);
}
/* In-panel notice (#coverage-notice). Deliberately NOT position:fixed: this
   replaced a top-fixed banner that sat above the whole UI and covered the map's
   own control rail. Inside the panel it can only ever push content down, so it
   cannot bury a button no matter how far the copy wraps. `hidden` does the
   hiding, so there is no display value to keep in sync. */
.panel-notice {
  display: flex; align-items: flex-start; gap: 10px;
  margin: 12px 20px 0;
  padding: 10px 12px;
  background: rgba(79,195,247,0.08);
  border: 1px solid rgba(79,195,247,0.35);
  border-radius: 8px;
  font-size: 0.78rem; line-height: 1.4;
  color: var(--text-primary, #fff);
}
.panel-notice[hidden] { display: none; }
.panel-notice i { color: #4fc3f7; flex-shrink: 0; margin-top: 1px; }
.panel-notice span { flex: 1; min-width: 0; }
.sidebar-section h3 {
  font-size: 0.8rem; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--text-secondary);
  margin-bottom: 12px;
  display: flex; align-items: center; gap: 8px;
}
.sidebar-section h3 i { color: var(--accent); font-size: 0.85rem; }
.sidebar-section h4 {
  font-size: 0.78rem; font-weight: 600;
  color: var(--text-secondary);
  margin: 12px 0 8px;
}
.hint { font-size: 0.78rem; color: var(--text-muted); margin-bottom: 12px; line-height: 1.4; }

/* ===== Search ===== */
.search-box {
  display: flex; align-items: center;
  background: var(--bg-tertiary);
  border-radius: var(--radius);
  padding: 0 12px;
  border: 1px solid transparent;
  transition: border-color var(--transition);
}
.search-box:focus-within { border-color: var(--accent); }
.search-box i { color: var(--text-muted); font-size: 0.85rem; }
.search-box input {
  flex: 1; background: none; border: none; outline: none;
  color: var(--text-primary); padding: 10px 10px;
  font-size: 0.85rem; font-family: inherit;
}
.search-box input::placeholder { color: var(--text-muted); }
.search-box button { background: none; border: none; color: var(--text-muted); cursor: pointer; padding: 4px; }
.search-results {
  margin-top: 8px;
  background: var(--bg-tertiary);
  border-radius: var(--radius);
  max-height: 240px;
  overflow-y: auto;
}
.search-results.hidden { display: none; }
.search-result-item {
  padding: 10px 14px;
  cursor: pointer;
  font-size: 0.82rem;
  border-bottom: 1px solid rgba(255,255,255,0.04);
  transition: background var(--transition);
  display: flex; align-items: center; gap: 8px;
}
.search-result-item:hover { background: rgba(255,255,255,0.05); }
.search-result-item i { color: var(--accent); width: 16px; text-align: center; }
.search-result-item:last-child { border-bottom: none; }

/* ===== Layer Toggles ===== */
.layer-toggle {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 0;
  cursor: pointer;
  font-size: 0.85rem;
}
.layer-toggle input { display: none; }
.toggle-slider {
  width: 36px; height: 20px;
  background: var(--bg-tertiary);
  border-radius: 10px;
  position: relative;
  transition: background var(--transition);
  flex-shrink: 0;
}
.toggle-slider::after {
  content: '';
  position: absolute;
  width: 16px; height: 16px;
  background: var(--text-secondary);
  border-radius: 50%;
  top: 2px; left: 2px;
  transition: all var(--transition);
}
.layer-toggle input:checked + .toggle-slider { background: var(--accent-dim); }
.layer-toggle input:checked + .toggle-slider::after { transform: translateX(16px); background: var(--accent); }
.toggle-label { flex: 1; }

/* Vehicle picker in the route planner. What you're in changes which roads get
   planned and which clearances get flagged, so it sits ABOVE the gravel/highway
   toggles — it's a bigger decision than either of them. */
.route-vehicle {
  padding: 4px 0 10px;
  border-bottom: 1px solid var(--bg-tertiary);
  margin-bottom: 4px;
}
.route-vehicle-head {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  margin-bottom: 7px;
}
.route-vehicle-title {
  font-size: 0.68rem; font-weight: 600;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text-muted, #888);
}
.route-vehicle-reset {
  background: none; border: none; padding: 0; cursor: pointer;
  font-size: 0.66rem; color: var(--accent);
  text-decoration: underline; text-underline-offset: 2px;
}
.route-vehicle-reset[hidden] { display: none; }
.route-vehicle-picker {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 5px;
}
.route-vehicle-btn {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: 7px 3px;
  border: 1px solid var(--bg-tertiary);
  border-radius: 6px;
  background: transparent;
  color: var(--text-secondary);
  font-size: 0.62rem;
  cursor: pointer;
  transition: all var(--transition);
  min-width: 0;
}
.route-vehicle-btn i { font-size: 0.92rem; }
.route-vehicle-btn span { overflow-wrap: anywhere; text-align: center; line-height: 1.2; }
.route-vehicle-btn:hover { border-color: var(--text-muted, #888); color: var(--text-primary); }
.route-vehicle-btn[aria-pressed="true"] {
  border-color: var(--accent);
  background: rgba(0, 200, 83, 0.12);
  color: var(--text-primary);
}
.route-vehicle-btn[aria-pressed="true"] i { color: var(--accent); }
.route-vehicle-tow {
  display: flex; align-items: center; gap: 7px;
  margin-top: 8px;
  font-size: 0.76rem;
  cursor: pointer;
}
.route-vehicle-tow[hidden] { display: none; }
.route-vehicle-note {
  font-size: 0.66rem;
  color: var(--text-muted, #888);
  margin-top: 7px;
  line-height: 1.45;
}
.route-vehicle-note:empty { display: none; }
.route-vehicle-note .warn { color: #ffab40; }

.badge {
  font-size: 0.65rem; font-weight: 600;
  padding: 2px 6px; border-radius: 3px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}
.badge-green { background: rgba(0,200,83,0.15); color: #00c853; }
.badge-blue { background: rgba(64,196,255,0.15); color: #40c4ff; }
.badge-orange { background: rgba(255,171,64,0.15); color: #ffab40; }
.badge-purple { background: rgba(176,128,255,0.15); color: #b080ff; }
.badge-teal { background: rgba(38,198,178,0.15); color: #26c6b2; }
.badge-yellow { background: rgba(255,230,0,0.15); color: #ffe600; }
.badge-red { background: rgba(230,0,0,0.15); color: #ff5252; }

/* ===== Base Map Selector ===== */
.basemap-selector { display: flex; gap: 6px; }
.basemap-btn {
  flex: 1; padding: 8px;
  background: var(--bg-tertiary);
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
  font-size: 0.75rem; font-weight: 500;
  cursor: pointer;
  transition: all var(--transition);
  display: flex; flex-direction: column; align-items: center; gap: 4px;
}
.basemap-btn i { font-size: 1rem; }
.basemap-btn:hover { color: var(--text-primary); background: rgba(255,255,255,0.08); }
.basemap-btn.active { border-color: var(--accent); color: var(--accent); background: var(--accent-dim); }

/* ===== Filter Chips ===== */
.filter-group { display: flex; flex-wrap: wrap; gap: 6px; }
.filter-chip {
  display: flex; align-items: center; gap: 4px;
  padding: 6px 10px;
  background: var(--bg-tertiary);
  border-radius: 20px;
  font-size: 0.75rem;
  cursor: pointer;
  transition: all var(--transition);
  border: 1px solid transparent;
  user-select: none;
}
.filter-chip:hover { background: rgba(255,255,255,0.08); }
.filter-chip input { display: none; }
.filter-chip:has(input:checked) { border-color: var(--accent); background: var(--accent-dim); color: var(--accent); }
.filter-chip i { font-size: 0.7rem; }

/* ===== Route Planning ===== */
.route-inputs { display: flex; flex-direction: column; gap: 4px; }
.route-point {
  display: flex; align-items: center; gap: 10px;
  background: var(--bg-tertiary);
  border-radius: var(--radius-sm);
  padding: 0 12px;
}
.route-point input {
  flex: 1; background: none; border: none; outline: none;
  color: var(--text-primary); padding: 10px 0;
  font-size: 0.85rem; font-family: inherit;
}
.route-point input::placeholder { color: var(--text-muted); }
/* Route search results dropdown */
.route-search-results {
  position: absolute;
  left: 0; right: 0;
  z-index: 9999;
  margin-top: 2px;
  max-height: 200px;
  overflow-y: auto;
  box-shadow: 0 6px 20px rgba(0,0,0,0.4);
  border: 1px solid rgba(255,255,255,0.08);
}
/* On mobile portrait: float results above keyboard */
@media (max-width: 768px) and (orientation: portrait) {
  .route-search-results {
    position: fixed;
    top: 52px;
    left: 8px; right: 8px;
    max-height: 40vh;
  }
}
/* On mobile landscape: keep results anchored below input, cap height */
@media (max-width: 768px) and (orientation: landscape) {
  .route-search-results {
    position: absolute;
    left: 0; right: 0;
    max-height: 30vh;
  }
}
.route-start-icon { color: var(--accent); font-size: 0.6rem; }
.route-locate-btn {
  flex-shrink: 0;
  padding: 6px 8px;
  border: none;
  color: var(--accent);
  background: none;
  font-size: 1rem;
  cursor: pointer;
  opacity: 0.7;
  transition: opacity 0.2s;
}
.route-locate-btn:hover { opacity: 1; }
.route-locate-btn.locating { animation: pulse-locate 1s infinite; }
@keyframes pulse-locate { 0%, 100% { opacity: 0.4; } 50% { opacity: 1; } }
.route-end-icon { color: var(--danger); font-size: 0.85rem; }
.route-waypoint-icon { color: var(--info); font-size: 0.6rem; }

.route-actions { display: flex; gap: 8px; margin-top: 8px; }
.route-dates { margin-top: 4px; }
.date-inputs { display: flex; gap: 8px; }
.date-field { flex: 1; }
.date-field label { display: block; font-size: 0.72rem; color: var(--text-muted); margin-bottom: 4px; }
.date-field input {
  width: 100%; padding: 8px 10px;
  background: var(--bg-tertiary);
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  font-size: 0.82rem; font-family: inherit;
  outline: none;
}
.date-field input:focus { border-color: var(--accent); }

/* ===== Buttons ===== */
.btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 8px 14px;
  background: var(--bg-tertiary);
  border: 1px solid rgba(255,255,255,0.08);
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
  font-size: 0.8rem; font-weight: 500;
  cursor: pointer;
  transition: all var(--transition);
  font-family: inherit;
}
.btn:hover { background: rgba(255,255,255,0.08); color: var(--text-primary); }
.btn-sm { padding: 6px 10px; font-size: 0.75rem; }
.btn-primary { background: var(--accent); color: #000; border-color: var(--accent); font-weight: 600; }
.btn-primary:hover { background: var(--accent-hover); color: #000; }
.btn-danger { border-color: rgba(255,82,82,0.3); color: var(--danger); }
.btn-danger:hover { background: rgba(255,82,82,0.1); }
.btn-block { width: 100%; justify-content: center; margin-top: 12px; }

/* ===== Weather Controls ===== */

/* ===== Map ===== */
#map {
  position: fixed;
  top: 0; bottom: 0;
  left: var(--sidebar-width);
  right: 0;
  z-index: 1;
}

/* ===== Map Controls ===== */
#map-controls {
  position: fixed;
  top: calc(var(--top-bar-height) + 16px); right: 16px;
  display: flex; flex-direction: column; gap: 8px;
  z-index: 500;
}
.map-btn {
  width: auto; height: auto;
  padding: 8px 10px;
  background: var(--bg-secondary);
  border: 1px solid var(--bg-tertiary);
  border-radius: var(--radius);
  color: var(--text-primary);
  font-size: 1rem;
  cursor: pointer;
  display: flex; align-items: center; gap: 6px;
  transition: all var(--transition);
  box-shadow: var(--shadow);
}
.map-btn-label {
  font-size: 0.65rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--text-secondary);
}
.map-btn:hover { background: var(--bg-tertiary); color: var(--accent); }
.map-btn:hover .map-btn-label { color: var(--accent); }
.map-btn.active { background: var(--accent); color: #fff; border-color: var(--accent); }
.map-btn.active .map-btn-label { color: #fff; }

/* ===== 2D/3D Mode Switch (experiment/3d-earth PROTOTYPE) ===== */
/* Deliberately PROMINENT (Josh): a Google-Maps-style on-map segmented pill —
   big tap targets, unmistakable active state. Bottom-left of the map, clear
   of #map-controls (top-right) and attribution (bottom-right). Known
   prototype overlap: the weather timeline, when opened, slides over this
   corner on mobile. */
/* ===== On-map view controls: ONE ROW, TWO SINGLE-CLICK BUTTONS =====
   Josh, 2026-08-05: "make the 2d3d button and toposat button half the size,
   and just a click rather than a toggle... both on the same row at the bottom,
   don't stack them on top of each other... smaller on mobile, they take up too
   much room."

   They were two stacked segmented pills, each ~46px tall with two 76px
   segments — together they owned the whole bottom-left corner of a phone
   screen. Now: one row, one button each, roughly half the footprint, and each
   button labels the state you are IN (the units-button convention) rather than
   the state it would move you to. */
/* EVERY BOTTOM-ANCHORED MAP CONTROL CLEARS THE SYSTEM BAR.
   Measured on a Galaxy S23 in the Capacitor app (2026-08-05):
   env(safe-area-inset-bottom) = 48px, and #map-mode-bar sat with a 14px gap —
   i.e. 34px INSIDE Android's gesture bar, which covered the 2D/3D and Topo/Sat
   buttons (Josh: "the android home bar covers them"). The viewport meta already
   carries viewport-fit=cover, so the inset is reported; nothing was reading it.
   Desktop and 3-button-nav devices report 0px and are unaffected, which is why
   this is added to the offset rather than replacing it. */
#map-mode-bar {
  position: fixed;
  bottom: calc(22px + var(--safe-bottom));
  left: calc(var(--sidebar-width) + 22px);
  z-index: 500;
  display: flex;
  gap: 6px;
}
/* READABLE OVER ANYTHING, IN EITHER STATE (Josh: "those buttons are hard to see
   if they're in one or the other mode — make those buttons visible whatever mode
   they're in"). These sit directly on map content, which swings from near-white
   glacier and topo paper to dark satellite forest, so:
     - the label is --text-primary, never the dimmer --text-secondary it used to
       be. That dimming was the "hard to see" state: the button showing the mode
       you are IN was the quiet one.
     - the background is a near-opaque plate rather than a flat panel colour, so
       bright imagery cannot bleed through and wash the text out,
     - the border is a light hairline instead of --bg-tertiary (#243342, which is
       invisible against a dark map), and the shadow gives an edge on light
       ground. One treatment, both states, no mode reads as disabled. */
.map-mode-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 30px;
  padding: 0 12px;
  border: 1px solid rgba(232, 237, 242, 0.3);
  border-radius: 999px;
  background: rgba(15, 25, 35, 0.93);
  color: var(--text-primary);
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.6px;
  cursor: pointer;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.5);
}
.map-mode-btn i { font-size: 0.82rem; }
.map-mode-btn:hover { background: rgba(36, 51, 66, 0.96); border-color: rgba(232, 237, 242, 0.5); }
/* 3D is a MODE you are in, not a preference — mark it, so a glance at the
   corner answers "why is the map pitched?". The accent goes on the BORDER only:
   tinting the label green traded one legibility problem for another, since
   #00c853 text is thinner against imagery than plain white is. */
#map-mode-bar.is-3d #btn-mode-cycle {
  border-color: var(--accent);
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(0, 200, 83, 0.45);
}
#map-mode-bar.is-3d #btn-mode-cycle i { color: var(--accent); }
#exag-pill {
  position: fixed;
  /* clears the single #map-mode-bar row, plus the system bar under it */
  bottom: calc(62px + var(--safe-bottom));
  left: calc(var(--sidebar-width) + 22px);
  z-index: 500;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  background: var(--bg-secondary);
  border: 1px solid var(--bg-tertiary);
  border-radius: 999px;
  box-shadow: var(--shadow);
  color: var(--text-primary);
}
#exag-pill input[type="range"] { width: 110px; accent-color: var(--accent); }

/* ===== Current-location puck (shown while recording a trip) =====
   A big green dot + heading arrow that marks where you ARE now (the breadcrumb
   line shows where you've been). The arrow points up in the element and the
   maplibre marker is rotation-aligned to the map + rotated to the GPS heading,
   so it points your direction of travel; .no-heading hides it when stationary. */
.loc-puck { width: 30px; height: 30px; position: relative; pointer-events: none; }
.loc-puck .puck-pulse {
  position: absolute; inset: 0; margin: auto; width: 20px; height: 20px;
  border-radius: 50%; background: #00e676; opacity: 0.4;
  animation: puckPulse 2s ease-out infinite;
}
.loc-puck .puck-dot {
  position: absolute; inset: 0; margin: auto; width: 18px; height: 18px;
  border-radius: 50%; background: #00e676; border: 3px solid #fff;
  box-shadow: 0 0 3px rgba(0,0,0,0.5);
}
.loc-puck .puck-arrow {
  position: absolute; top: -3px; left: 50%; transform: translateX(-50%);
  width: 0; height: 0; border-left: 6px solid transparent;
  border-right: 6px solid transparent; border-bottom: 9px solid #00e676;
  filter: drop-shadow(0 -1px 0 #fff);
}
.loc-puck.no-heading .puck-arrow { display: none; }
@keyframes puckPulse {
  0% { transform: scale(1); opacity: 0.45; }
  100% { transform: scale(2.6); opacity: 0; }
}
.mode-switch-btn {
  min-width: 76px;
  min-height: 46px; /* 44px+ tap target — mobile-friendly */
  padding: 0 20px;
  border: none;
  border-radius: 999px;
  background: transparent;
  color: var(--text-secondary);
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: 1.5px;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  transition: all var(--transition);
}
.mode-switch-btn i { font-size: 0.95rem; }
.mode-switch-btn:hover { color: var(--text-primary); background: rgba(255,255,255,0.08); }
.mode-switch-btn.active { background: var(--accent); color: #fff; }

/* One-time dismissible notices (software-GL warning, 3D quality floor) */
.mode-notice {
  position: fixed;
  top: calc(var(--top-bar-height) + 18px); left: 50%;
  transform: translateX(-50%);
  z-index: 2500;
  max-width: min(92vw, 560px);
  display: flex; align-items: center; gap: 10px;
  padding: 12px 16px;
  background: var(--bg-secondary);
  border: 1px solid var(--warning);
  border-radius: var(--radius);
  color: var(--text-primary);
  font-size: 0.85rem;
  box-shadow: var(--shadow);
}
.mode-notice i { color: var(--warning); }
.mode-notice .mode-notice-ok {
  margin-left: 6px;
  padding: 8px 16px;
  min-height: 40px;
  background: var(--accent); color: #fff;
  border: none; border-radius: var(--radius-sm);
  font-weight: 700; cursor: pointer;
}

/* ===== Weather Tile Overlays ===== */
.weather-tile-temperature { filter: saturate(2.5) contrast(1.8) brightness(1.1); }
.weather-tile-precipitation { filter: saturate(2.0) contrast(1.5); }
.weather-tile-clouds { filter: contrast(1.4) brightness(0.95); }
.weather-tile-wind { filter: saturate(1.8) contrast(1.4); }

/* The Weather Timeline bar was removed 2026-07-22 along with its markup.
   It was a fixed full-width bar at bottom:16px spanning the map, which sat
   directly over the 2D/3D switcher — and its play button never drove the
   radar anyway (see js/weather.js). */

/* ===== Info Panel =====
   Vertical side-loading card (ported from motocamp-all). Was a bottom-anchored
   horizontal strip eating 68vh of a map you are trying to read a track off;
   now a column beside the sidebar, over the map. Mobile keeps the bottom-sheet
   geometry — a 380px column on a phone is the whole screen — overridden in the
   768px block, which must reset top/right/width or they leak in from here. */
#info-panel {
  position: fixed;
  /* Height follows CONTENT, capped — not pinned to the viewport bottom as in
     the motocamp original. Two reasons, both ridgeflow-specific: a three-line
     hut card would otherwise render as a 876px mostly-empty column, and the
     lower-left controls (#map-mode-bar 22px + ~30px tall, #exag-pill 62px;
     was a three-pill stack of #mode-3d-switch 26px, #basemap-switch 88px,
     #exag-pill 140px + ~48px tall) lives under this panel's footprint — a
     full-height card buries the map's own basemap and 2D/3D controls. 212px
     clears the tallest of them. */
  top: calc(var(--top-bar-height) + var(--clear-route-inset, 0px) + 12px); bottom: auto;
  max-height: calc(100vh - var(--top-bar-height) - var(--clear-route-inset, 0px) - 212px);
  left: calc(var(--sidebar-width) + 12px);
  width: 380px;
  max-width: calc(100vw - var(--sidebar-width) - 24px);
  background: var(--bg-secondary);
  border: 1px solid var(--bg-tertiary);
  border-radius: var(--radius);
  z-index: 600;
  overflow-y: auto;
  box-shadow: 0 8px 30px rgba(0,0,0,0.45);
  transition: transform var(--transition), opacity var(--transition);
}
#info-panel.hidden {
  transform: translateX(calc(-100% - 420px));
  opacity: 0;
  pointer-events: none;
}
#info-close {
  position: sticky; top: 0; right: 0;
  float: right; margin: 12px 12px 0 0;
  background: var(--bg-tertiary); border: none;
  z-index: 10;
  color: var(--text-secondary); width: 32px; height: 32px;
  border-radius: 50%; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  font-size: 0.9rem;
}
#info-content { padding: 12px 16px 16px; }

/* Info Panel Content */
.info-header { margin-bottom: 8px; }
.info-header h2 { font-size: 1.15rem; font-weight: 700; margin-bottom: 4px; }
.info-header .info-type { font-size: 0.78rem; color: var(--accent); font-weight: 500; text-transform: uppercase; letter-spacing: 0.03em; }
.info-header .info-status { font-size: 0.75rem; padding: 2px 8px; border-radius: 3px; margin-left: 8px; }
.info-header .info-status.open { background: rgba(0,200,83,0.15); color: #00c853; }
.info-header .info-status.closed { background: rgba(255,82,82,0.15); color: #ff5252; }

.info-facilities {
  display: flex; flex-wrap: wrap; gap: 6px;
  margin-bottom: 10px;
}
.facility-badge {
  display: flex; align-items: center; gap: 4px;
  padding: 3px 8px;
  background: var(--bg-tertiary);
  border-radius: var(--radius-sm);
  font-size: 0.72rem;
  color: var(--text-secondary);
}
.facility-badge.available { color: var(--accent); background: var(--accent-dim); }
.facility-badge i { font-size: 0.8rem; }

.info-details { display: grid; grid-template-columns: 1fr 1fr; gap: 6px 12px; margin-bottom: 10px; }
.info-detail { }
.info-detail-label { font-size: 0.7rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.03em; margin-bottom: 2px; }
.info-detail-value { font-size: 0.85rem; color: var(--text-primary); }

.info-weather {
  background: var(--bg-tertiary);
  border-radius: var(--radius);
  padding: 14px;
  margin-bottom: 16px;
}
.info-weather h4 { font-size: 0.78rem; color: var(--text-secondary); margin-bottom: 8px; }
.weather-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(80px, 1fr)); gap: 8px;
}
.weather-item { text-align: center; }
.weather-item .wx-icon { font-size: 1.3rem; margin-bottom: 2px; }
.weather-item .wx-temp { font-size: 1rem; font-weight: 600; }
.weather-item .wx-desc { font-size: 0.68rem; color: var(--text-muted); }
.weather-item .wx-day { font-size: 0.68rem; color: var(--text-secondary); font-weight: 500; }

.cell-bar-container { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
.cell-carrier { font-size: 0.72rem; width: 64px; color: var(--text-secondary); }
.cell-bar { flex: 1; height: 6px; background: var(--bg-tertiary); border-radius: 3px; overflow: hidden; }
.cell-bar-fill { height: 100%; border-radius: 3px; transition: width 0.5s ease; }
.cell-bar-fill.verizon { background: var(--verizon-color); }
.cell-bar-fill.att { background: var(--att-color); }
.cell-bar-fill.tmobile { background: var(--tmobile-color); }
.cell-tech { font-size: 0.64rem; color: var(--text-muted); width: 52px; text-align: right; white-space: nowrap; }

.info-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.info-actions .btn i { font-size: 0.8rem; }

/* ===== Route Summary Styles ===== */
.route-overview {
  display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 8px;
  margin-bottom: 16px;
}
.route-stat {
  text-align: center;
  padding: 10px;
  background: var(--bg-tertiary);
  border-radius: var(--radius-sm);
}
.route-stat-value { font-size: 1.2rem; font-weight: 700; color: var(--accent); }
.route-stat-label { font-size: 0.68rem; color: var(--text-muted); margin-top: 2px; }

.route-segment {
  padding: 12px 0;
  border-bottom: 1px solid rgba(255,255,255,0.04);
}
.route-segment:last-child { border-bottom: none; }
.route-segment-header {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 6px;
}
.route-segment-header h4 { font-size: 0.85rem; font-weight: 600; }
.route-segment-header span { font-size: 0.75rem; color: var(--text-muted); }
.route-segment-weather {
  display: flex; gap: 12px;
  margin-bottom: 6px;
}
.route-segment-weather .wx-mini {
  display: flex; align-items: center; gap: 4px;
  font-size: 0.78rem; color: var(--text-secondary);
}
.route-segment-services { display: flex; flex-wrap: wrap; gap: 4px; }
.route-segment-services .service-tag {
  font-size: 0.68rem;
  padding: 2px 6px;
  background: var(--bg-tertiary);
  border-radius: 3px;
  color: var(--text-muted);
}
.route-segment-services .service-tag.available { color: var(--accent); background: var(--accent-dim); }

/* ===== Elevation Profile ===== */
.elevation-profile {
  margin-bottom: 14px;
  padding-bottom: 12px;
  border-bottom: 1px solid rgba(255,255,255,0.04);
}
.elevation-stats {
  display: flex; gap: 12px;
  margin-bottom: 8px;
  font-size: 0.75rem;
  color: var(--text-secondary);
}
.elevation-stats span {
  display: flex; align-items: center; gap: 4px;
}
.elevation-chart-wrap {
  position: relative;
  background: var(--bg-tertiary);
  border-radius: var(--radius-sm);
  padding: 4px;
  cursor: crosshair;
}
.elevation-chart-wrap canvas {
  display: block;
  width: 100%;
}
.elevation-tooltip {
  position: absolute;
  background: var(--bg-secondary);
  border: 1px solid var(--bg-tertiary);
  border-radius: var(--radius-sm);
  padding: 4px 8px;
  font-size: 0.72rem;
  color: var(--text-primary);
  pointer-events: none;
  white-space: nowrap;
  z-index: 10;
  box-shadow: var(--shadow);
  line-height: 1.3;
}
.elevation-map-tooltip {
  background: var(--bg-secondary) !important;
  border: 1px solid var(--accent) !important;
  color: var(--text-primary) !important;
  font-size: 0.75rem !important;
  font-weight: 600 !important;
  padding: 2px 6px !important;
  border-radius: 4px !important;
  box-shadow: var(--shadow) !important;
}
.elevation-map-tooltip::before {
  border-top-color: var(--accent) !important;
}

/* ===== Weather Overlay Legend ===== */
.weather-legend-bar {
  display: flex; height: 12px;
  border-radius: 6px; overflow: hidden;
  margin-bottom: 4px;
}
.weather-legend-labels { display: flex; justify-content: space-between; font-size: 0.68rem; color: var(--text-muted); }

/* ===== MapLibre GL Overrides =====
   (Leaflet-era cluster-icon CSS removed 2026-07-19: clusters are GL circle
   paint now — colors live in Utils.clusterColors, sizes in map.clusterLayer.) */
.maplibregl-ctrl-attrib { font-size: 0.6rem !important; background: rgba(15,25,35,0.8) !important; color: var(--text-muted) !important; }
.maplibregl-ctrl-attrib a { color: var(--text-secondary) !important; }
/* Attribution lives in the sidebar footer, not on the map — on a phone it sat
   across the 2D/3D pill and the basemap switch. maplibre still owns the node
   (it rewrites it as sources come and go), so this only restyles it for its new
   home: no panel chrome, no rounded corner, wraps like the credits beside it. */
.map-attribution { margin: 6px 0 8px; }
.maplibregl-ctrl-attrib.in-sidebar {
  background: none !important; padding: 0 !important; margin: 0 !important;
  border-radius: 0 !important; font-size: 0.62rem !important; line-height: 1.5;
  color: var(--text-muted) !important; float: none !important;
}
.maplibregl-ctrl-attrib.in-sidebar .maplibregl-ctrl-attrib-button { display: none !important; }
.maplibregl-ctrl-attrib.in-sidebar .maplibregl-ctrl-attrib-inner { display: inline !important; }
.maplibregl-popup-content {
  background: var(--bg-secondary) !important;
  color: var(--text-primary) !important;
  border-radius: var(--radius) !important;
  box-shadow: var(--shadow) !important;
  border: 1px solid var(--bg-tertiary) !important;
  padding: 12px 14px !important;
  font-family: 'Inter', sans-serif !important;
  /* The map container is overflow:hidden, so a tall popup (e.g. a verbose
     council-closure description) gets clipped at the map edge. Cap the box to
     the viewport and scroll inside it so the WHOLE description is always
     reachable instead of cut off. */
  max-height: min(64vh, calc(100dvh - 96px)) !important;
  overflow-y: auto !important;
  overscroll-behavior: contain;
}
/* The popup tip is a CSS border triangle — theme every anchor direction */
.maplibregl-popup-anchor-bottom .maplibregl-popup-tip { border-top-color: var(--bg-secondary) !important; }
.maplibregl-popup-anchor-top .maplibregl-popup-tip { border-bottom-color: var(--bg-secondary) !important; }
.maplibregl-popup-anchor-left .maplibregl-popup-tip { border-right-color: var(--bg-secondary) !important; }
.maplibregl-popup-anchor-right .maplibregl-popup-tip { border-left-color: var(--bg-secondary) !important; }
.maplibregl-popup-close-button { color: var(--text-secondary) !important; font-size: 20px !important; right: 4px !important; top: 2px !important; }

/* Custom marker styles */
.custom-marker {
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  /* Tight shadow: large blur radii multiply paint cost across hundreds of
     markers when a dense area re-renders after a zoom */
  box-shadow: 0 1px 3px rgba(0,0,0,0.5);
  font-size: 14px;
  transition: transform 0.2s ease;
}
.custom-marker:hover { transform: scale(1.2); }

/* ===== Responsive ===== */
@media (max-width: 768px) {
  #mobile-header { display: flex; }
  #sidebar-close { display: block; }

  .sidebar {
    width: 100%;
    transform: translateX(-100%);
    top: 0;
  }
  .sidebar.open { transform: translateX(0); }
  .sidebar-header { padding-top: calc(var(--mobile-header-height) + 8px); }

  #map {
    left: 0;
    top: var(--mobile-header-height);
  }

  /* ===== THE MAP RAIL ON A PHONE =====
     Josh, 2026-08-05: "remove the reset and fullscreen buttons from the main
     map on mobile... the layout needs to be better."

     It was SEVEN labelled buttons stacked from the top-right, each ~40px tall
     with an uppercase caption — a column down the most valuable third of the
     screen, in the hardest place on a phone to reach one-handed. Three changes,
     all standard practice for mobile maps:

       1. FEWER CONTROLS. Reset and Fullscreen are hidden. Fullscreen is close
          to meaningless here — a phone browser is already fullscreen, and in
          the Capacitor app there is no chrome to hide, so it is a button that
          appears to do nothing. Reset is low-frequency and lives in the
          sidebar. That leaves Rec / Rain / km / Locate: four, inside the
          3-5 guidance for a mobile map.
       2. ICON ONLY. The captions go, so each control is a 44px square rather
          than a labelled slab — 44px being the Apple minimum and the reason
          the size does NOT shrink even though the button does. The Rec caption
          is the one exception: while recording it reads "Stop", and hiding
          that would leave a red button with no statement of what it does.
       3. THUMB REACH. The rail moves to the BOTTOM right, above the mode bar,
          because bottom-aligned controls measurably cut interaction time for
          one-handed use and the top-right corner needs a hand-shuffle.
     Desktop is untouched: it has the room and a cursor. */
  #map-controls {
    top: auto;
    bottom: calc(58px + var(--safe-bottom));  /* clears #map-mode-bar (14px + 26px) and the system bar */
    right: 12px;
    flex-direction: column;
    gap: 8px;                           /* >= the 8px anti-mis-tap spacing */
  }
  #map-controls .map-btn {
    width: 44px; height: 44px;          /* Apple 44px / Android 48px minimum */
    padding: 0;
    justify-content: center;
    border-radius: 50%;
  }
  #map-controls .map-btn-label { display: none; }
  /* …except while recording, where the label IS the state. */
  #map-controls .map-btn.recording { width: auto; border-radius: 999px; padding: 0 12px; gap: 6px; }
  #map-controls .map-btn.recording .map-btn-label { display: inline; }

  #btn-reset, #btn-fullscreen { display: none !important; }

  /* Smaller again on a phone: this corner is the most contested space on the
     screen and these two buttons were eating it. */
  #map-mode-bar {
    left: 12px;
    bottom: calc(14px + var(--safe-bottom));
    gap: 5px;
  }
  .map-mode-btn {
    min-height: 26px;
    padding: 0 9px;
    font-size: 0.7rem;
    gap: 4px;
  }
  .map-mode-btn i { font-size: 0.74rem; }

  #exag-pill {
    left: 12px;
    bottom: calc(50px + var(--safe-bottom));   /* clears the single button row + the system bar */
  }


  /* Back to a bottom sheet on phones. top/right/width are RESET explicitly,
     not inherited — the desktop rule above sets all three. */
  #info-panel {
    top: auto; bottom: 0; left: 0; right: 0;
    width: 100%; max-width: 100%;
    max-height: 60vh;
    border: none; border-top: 1px solid var(--bg-tertiary);
    border-radius: var(--radius) var(--radius) 0 0;
    /* The sheet is anchored to bottom:0, so its last row of content — which is
       often a Directions / Follow button — would sit under the system bar.
       Padding rather than an offset: lifting the whole sheet would leave a strip
       of map showing beneath it, which reads as a rendering fault. */
    padding-bottom: var(--safe-bottom);
  }
  #info-panel.hidden { transform: translateY(100%); opacity: 1; }
  /* Collapse is a desktop affordance: on mobile the sidebar is already
     off-canvas behind the hamburger. */
  #sidebar-collapse, #sidebar-expand { display: none !important; }

  .info-details { grid-template-columns: 1fr; }
  .route-overview { grid-template-columns: 1fr 1fr; }

  /* Inputs must be ≥16px to prevent iOS Safari from zooming on focus */
  .route-point input,
  .search-box input,
  .date-field input {
    font-size: 1rem;
  }
}

/* In landscape on mobile: compact the sidebar so content fits above the keyboard */
@media (max-width: 768px) and (orientation: landscape) {
  .sidebar-header { padding-top: calc(var(--mobile-header-height) + 4px); padding-bottom: 6px; }
  .sidebar-section { padding: 10px 16px; }
  .sidebar-section h3 { margin-bottom: 8px; }
  .tab-btn { padding: 8px 4px; }
}

@media (max-width: 480px) {
  .tab-btn { font-size: 0.72rem; padding: 10px 4px; }
  .basemap-selector { flex-direction: column; }
  .weather-grid { grid-template-columns: repeat(3, 1fr); }
}

/* ===== Context Menu ===== */
#context-menu {
  position: fixed;
  background: var(--bg-secondary);
  border: 1px solid var(--bg-tertiary);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  z-index: 2000;
  min-width: 200px;
  padding: 4px 0;
  overflow: hidden;
}
.ctx-item {
  padding: 10px 16px;
  font-size: 0.82rem;
  cursor: pointer;
  display: flex; align-items: center; gap: 10px;
  transition: background 0.15s;
  color: var(--text-primary);
}
.ctx-item:hover { background: rgba(255,255,255,0.06); }
.ctx-item i { color: var(--accent); width: 16px; text-align: center; font-size: 0.85rem; }
.ctx-divider { height: 1px; background: var(--bg-tertiary); margin: 4px 0; }

/* ===== Hidden utility ===== */
.hidden { display: none !important; }

/* Name tag above the active (panel-open) site — pairs with Layers._highlightActive */
.active-site-tag {
  background: rgba(13, 21, 32, 0.95);
  border: 1px solid rgba(0, 200, 83, 0.6);
  color: #fff;
  font-weight: 600;
  font-size: 0.75rem;
  border-radius: 6px;
  padding: 3px 9px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
  white-space: nowrap;
  max-width: 240px;
  overflow: hidden;
  text-overflow: ellipsis;
}
.active-site-tag::before { border-top-color: rgba(0, 200, 83, 0.6); }

/* ===== Trip recording (js/ride-recorder.js) ===== */
.map-btn.recording {
  background: #d32f2f;
  border-color: #d32f2f;
  color: #fff;
}
.map-btn.recording .map-btn-label { color: #fff; }
.map-btn.recording i { animation: rec-pulse 1.6s ease-in-out infinite; }
@keyframes rec-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}

/* Clear route — on-map, top-left of the MAP (right of the sidebar). Styled off
   the basemap pill so the map's own controls read as one family.
   --clear-route-inset is published while the button is visible and consumed by
   #info-panel below: both live in this corner, and without the inset the panel
   would open underneath the button and bury it. */
#btn-clear-route {
  position: fixed;
  top: calc(var(--top-bar-height) + 12px);
  left: calc(var(--sidebar-width) + 12px);
  z-index: 600;
  display: inline-flex; align-items: center; gap: 7px;
  padding: 9px 14px;
  font: inherit; font-size: 0.82rem; font-weight: 650;
  background: var(--bg-secondary);
  border: 1px solid var(--bg-tertiary);
  border-radius: 999px;
  box-shadow: var(--shadow);
  color: var(--danger, #ff5252);
  cursor: pointer;
}
#btn-clear-route:hover { background: var(--bg-tertiary); }
#btn-clear-route:focus-visible { outline: 2px solid var(--danger, #ff5252); outline-offset: 2px; }
#btn-clear-route i { font-size: 0.86em; }
@media (max-width: 768px) {
  /* Phone: the sidebar overlays rather than offsets, so anchor to the viewport. */
  #btn-clear-route { left: 12px; padding: 8px 12px; font-size: 0.78rem; }
}
