@import "@geolibre/ui/globals.css";

/* Supplies the custom-color/border-radius theme that @geolibre/ui's globals.css
   relies on via @apply (background, border, etc.). globals.css is intentionally
   config-agnostic; the consuming app provides the Tailwind config here. */
@config "../tailwind.config.js";

/* App typeface: IBM Plex Sans for UI, IBM Plex Mono for the numeric/coordinate
   readouts (StatusBar, code, feature IDs). One matched superfamily, so the mono
   readouts and the surrounding UI share a voice. Fontsource's own @font-face
   stylesheets are loaded from main.tsx — see the note there for why they cannot
   be @imported here. Self-hosted rather than CDN-loaded: the desktop build must
   render offline, and the Tauri CSP is `default-src 'self'`.

   This block drives both the `font-sans`/`font-mono` utilities and Tailwind's
   preflight default, so no `font-family` on <body> is needed.

   Plex covers latin, latin-ext, cyrillic, greek and vietnamese only. The
   locales it does NOT cover (ar, fa, hi, ja, ka, ko, th, zh) rely on per-glyph
   fallback to the system stack below — which is why that stack must stay a
   full, ordered list rather than a bare `sans-serif`. */
@theme {
  --font-sans:
    "IBM Plex Sans Variable", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
    "Noto Sans", "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
  --font-mono:
    "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
}

/* Persian (fa) is the one locale that needs a second webfont: Plex has no
   Arabic-script coverage, so without this the UI falls back to whatever the
   system happens to ship. Only the *arabic* subset is loaded — Vazirmatn also
   publishes latin and latin-ext, but those duplicate Plex for 56 KB, and the
   service worker precaches every emitted asset, so an unused subset is weight
   every user downloads on SW install rather than a lazy per-glyph fetch.

   Written out by hand rather than imported from main.tsx because fontsource
   ships no subset-scoped entry point: both index.css and wght.css declare all
   three subsets. The Tailwind-inlining hazard described in main.tsx does not
   apply here — it is specific to @importing fontsource's CSS, whose relative
   url(./files/*.woff2) never reaches Vite's asset pipeline. A bare package
   specifier in a url() that Tailwind passes through is rewritten normally.

   unicode-range is copied verbatim from the package's wght.css; keep it in sync
   if @fontsource-variable/vazirmatn is bumped and the subset boundaries move. */
@font-face {
  font-family: "Vazirmatn Variable";
  font-style: normal;
  font-display: swap;
  font-weight: 100 900;
  src: url("@fontsource-variable/vazirmatn/files/vazirmatn-arabic-wght-normal.woff2")
    format("woff2-variations");
  unicode-range:
    U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0897-08E1, U+08E3-08FF, U+200C-200E,
    U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC, U+102E0-102FB,
    U+10E60-10E7E, U+10EC2-10EC4, U+10EFC-10EFF, U+1EE00-1EE03, U+1EE05-1EE1F, U+1EE21-1EE22,
    U+1EE24, U+1EE27, U+1EE29-1EE32, U+1EE34-1EE37, U+1EE39, U+1EE3B, U+1EE42, U+1EE47, U+1EE49,
    U+1EE4B, U+1EE4D-1EE4F, U+1EE51-1EE52, U+1EE54, U+1EE57, U+1EE59, U+1EE5B, U+1EE5D, U+1EE5F,
    U+1EE61-1EE62, U+1EE64, U+1EE67-1EE6A, U+1EE6C-1EE72, U+1EE74-1EE77, U+1EE79-1EE7C, U+1EE7E,
    U+1EE80-1EE89, U+1EE8B-1EE9B, U+1EEA1-1EEA3, U+1EEA5-1EEA9, U+1EEAB-1EEBB, U+1EEF0-1EEF1;
}

/* Vazirmatn covers the Arabic script; Plex stays second so the Latin text that
   remains in a Persian UI (layer names, coordinates, product names) keeps the
   same voice as every other locale instead of dropping to system-ui. */
html:lang(fa) {
  --font-sans:
    "Vazirmatn Variable", "IBM Plex Sans Variable", ui-sans-serif, system-ui, -apple-system,
    "Segoe UI", Roboto, "Noto Sans Arabic", "Noto Sans", "Helvetica Neue", Arial, sans-serif,
    "Apple Color Emoji", "Segoe UI Emoji";
}

/* Map-floating chrome, a.k.a. "instrument glass".

   The distinction this encodes: chrome docked BESIDE the map (top toolbar,
   status bar, side panels) is fully opaque, while panels that hover OVER the
   map are translucent and blurred so the data reads through them. Translucency
   is the signal for "this floats above your map" — which is why it must not
   spread to docked chrome or to dialogs, which sit on a dimmed overlay rather
   than on the map.

   Codified here because the recipe was already in use across 11 components
   with drifted values — bg-background/90 vs /95, and backdrop-blur-sm vs -md vs
   bare backdrop-blur — so tuning the look meant finding every copy. Components
   keep their own radius, border, shadow and padding; this owns only the surface
   itself.

   Must be an `@utility`, i.e. inside Tailwind's utilities layer — NOT an
   unlayered plain class. Unlayered CSS beats every layered declaration for the
   same property, and cascade-layer precedence is resolved *before* specificity,
   so an unlayered `.map-glass { background-color }` also silently beats
   `hover:bg-accent`. That killed the hover fill on MapGrid's pane buttons and
   the CollaborationStatusBadge toggle — verified dead, not theoretical. Inside
   the layer, `.hover\:bg-accent:hover` (0,2,0) outranks `.map-glass` (0,1,0)
   and hover works again.

   The @supports fallback is nested so it stays in the layer too; hoisting it
   out would reintroduce exactly the same bug for browsers without
   backdrop-filter. Without the blur, 85% over live imagery is unreadable.

   The saturate() boost keeps basemap imagery from going muddy under the blur. */
@utility map-glass {
  background-color: hsl(var(--background) / 0.85);
  -webkit-backdrop-filter: blur(12px) saturate(140%);
  backdrop-filter: blur(12px) saturate(140%);

  @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    background-color: hsl(var(--background) / 0.97);
  }
}

/* Elevation-tied shadow scale, replacing Tailwind's stock one. Each step maps to
   a surface in the ladder rather than being picked by eye:

     shadow-xs   form field — input, textarea, select, colour picker
     shadow-sm   resting control / inline card
     shadow-md   popover, dropdown, tooltip
     shadow-lg   panel floating over the map
     shadow-xl   modal dialog

   shadow-xs matters more than its name suggests: it is what @geolibre/ui's form
   primitives use, so leaving it on the stock colour would have left every input,
   textarea, select and colour field in the app on the invisible-in-dark shadow
   this block exists to fix. Bare `shadow` is defined too (one use, slider.tsx).
   shadow-2xl and shadow-inner are unused; add them here if that changes,
   otherwise they silently fall back to Tailwind's 10% black.

   Redefining the tokens fixes all ~65 existing shadow sites without touching a
   single component. The colours come from --elev-penumbra/--elev-umbra
   (packages/ui/src/globals.css), which are theme-aware — Tailwind's built-in
   scale hardcodes 10% black, so dark mode previously had no visible shadows at
   all.

   The colours are written bare here: Tailwind wraps each one in
   var(--tw-shadow-color, …) when it generates the utility, so `shadow-<color>`
   overrides keep working without spelling the wrapper out (writing it manually
   just nests the fallback twice). */
@theme {
  --shadow-xs: 0 1px 1px 0 var(--elev-penumbra);
  --shadow-sm: 0 1px 2px 0 var(--elev-penumbra), 0 1px 3px 0 var(--elev-umbra);
  --shadow: 0 1px 2px 0 var(--elev-penumbra), 0 1px 3px 0 var(--elev-umbra);
  --shadow-md: 0 2px 4px -1px var(--elev-penumbra), 0 4px 8px -2px var(--elev-umbra);
  --shadow-lg: 0 4px 8px -2px var(--elev-penumbra), 0 12px 20px -4px var(--elev-umbra);
  --shadow-xl: 0 8px 16px -4px var(--elev-penumbra), 0 24px 40px -8px var(--elev-umbra);
}

/* One global reduced-motion guard. Previously only two components respected the
   preference while ~53 transition sites ignored it. Motion is reduced to a
   near-instant cross-fade rather than removed outright, so state changes stay
   perceptible (an abrupt swap is its own accessibility problem) — and scroll
   behaviour is pinned to auto so programmatic smooth scrolls stop animating. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  /* Indeterminate progress is exempt. The blanket rule above would give a
     spinner a single 0.01ms iteration and then freeze it mid-rotation, so
     during a long raster/segmentation/conversion job the UI would look hung —
     a worse outcome for the same user than the abrupt transitions this guard
     exists to fix. There are ~70 animate-spin sites and 6 animate-pulse.

     Slowed rather than stopped: the point of the preference is to avoid large
     vestibular-triggering motion, which a small in-place spinner is not, so
     halving the speed keeps the "still working" signal while calming it. */
  .animate-spin {
    animation-duration: 1.5s !important;
    animation-iteration-count: infinite !important;
  }

  .animate-pulse {
    animation-duration: 3s !important;
    animation-iteration-count: infinite !important;
  }
}

html,
body,
#root {
  height: 100%;
  margin: 0;
  overflow: hidden;
}

/* Keep the app chrome out from under mobile system bars and display cutouts.
   With viewport-fit=cover (see index.html) the webview draws edge-to-edge on
   Android/iOS, so without this the top toolbar renders under the status bar —
   where the system intercepts taps, making those menu buttons unclickable. The
   insets are 0 on desktop/web, so this only affects mobile. */
#root {
  box-sizing: border-box;
  padding-top: env(safe-area-inset-top);
  padding-bottom: env(safe-area-inset-bottom);
  padding-left: env(safe-area-inset-left);
  padding-right: env(safe-area-inset-right);
}

/* MapLibre anchors its controls with physical left/right CSS, so when the app
   runs in a right-to-left locale (html[dir="rtl"]) the inherited direction
   would half-mirror the map chrome (control rows, attribution) while the
   corners stay put. Pin only MapLibre's own control container to ltr — NOT the
   whole `.maplibregl-map` subtree, which also hosts app overlays portalled into
   the map container (e.g. StoryMapPresenter); those must stay free to mirror in
   RTL. Control text still shapes correctly via the Unicode bidi algorithm. */
.maplibregl-control-container {
  direction: ltr;
}

.geoagent-control .geoagent-control-toggle {
  align-items: center;
  display: flex;
  justify-content: center;
}

.geoagent-control .geoagent-control-icon {
  align-items: center;
  display: flex;
  height: 100%;
  justify-content: center;
  width: 100%;
}

.geoagent-control .geoagent-control-icon svg {
  transform: translateX(1px);
}

.geoagent-panel input:focus,
.geoagent-panel select:focus,
.geoagent-panel textarea:focus,
.geoagent-panel input:focus-visible,
.geoagent-panel select:focus-visible,
.geoagent-panel textarea:focus-visible {
  border-color: #2f8f85;
  box-shadow: inset 0 0 0 1px #2f8f85;
  outline: none;
}

/* The Earth Engine "Sign in" button is injected between the project grid and
   the status text inside the (un-padded) details element, so inset it to match
   the 10px gutter of the surrounding content and space it from the status. */
.geoagent-panel button.geolibre-ee-sign-in {
  margin: 0 10px 8px;
  min-height: 32px;
  padding: 0 12px;
  border: 1px solid #d7dde5;
  border-radius: 6px;
  background: #fff;
  color: #17202a;
  font-weight: 700;
  cursor: pointer;
}

.geoagent-panel button.geolibre-ee-sign-in:hover {
  border-color: #b0bec5;
  background: #f1f5f9;
}

.geoagent-panel button.geolibre-ee-sign-in:focus-visible {
  border-color: #2f8f85;
  box-shadow: inset 0 0 0 1px #2f8f85;
  outline: none;
}

.geoagent-panel button.geolibre-ee-sign-in:disabled {
  cursor: not-allowed;
  opacity: 0.55;
}

.geo-editor-control .geo-editor-tool-button {
  align-items: center;
  box-sizing: border-box;
  display: flex !important;
  justify-content: center;
  line-height: 0;
  padding: 0;
}

.geo-editor-control .geo-editor-tool-button svg {
  display: block;
  flex: 0 0 auto;
  margin: 0;
}

.geo-editor-control .geo-editor-tool-button[data-mode="text_marker"] svg {
  height: 24px;
  width: 24px;
}

.geo-editor-control .geo-editor-tool-button[data-mode="text_marker"] svg text {
  font-size: 18px;
}

/*
 * Historical Imagery (Esri Wayback) control. The upstream package ships a
 * light-only stylesheet of hardcoded literal colors with no `.dark` /
 * prefers-color-scheme rules, so pin its `color-scheme` per theme and remap the
 * toggle icon and expanded panel onto the app's design tokens under `.dark` so
 * it tracks GeoLibre's in-app light/dark toggle in both directions. index.css is
 * imported after the component stylesheet, so these rules win the cascade.
 */
.geolibre-esri-wayback-control,
.esri-wayback-control-panel {
  color-scheme: light;
}

.dark .geolibre-esri-wayback-control,
.dark .esri-wayback-control-panel {
  color-scheme: dark;
}

.esri-wayback-control-panel .esri-wayback-range {
  accent-color: #2b7bb9;
}

.esri-wayback-control-panel .esri-wayback-input {
  background-color: #fff !important;
  color: #111827 !important;
}

.esri-wayback-control-panel .esri-wayback-input::placeholder {
  color: #6b7280 !important;
}

/* Collapsed toggle button and its icon (the icon glyph inherits currentColor). */
.dark .esri-wayback-control,
.dark .esri-wayback-control-toggle {
  background: hsl(var(--popover));
  color: hsl(var(--popover-foreground));
}

.dark .esri-wayback-control-toggle:hover {
  background-color: hsl(var(--accent));
}

.dark .esri-wayback-control-icon svg {
  stroke: hsl(var(--popover-foreground));
}

/* Expanded panel surface and chrome. */
.dark .esri-wayback-control-panel {
  background: hsl(var(--popover));
  box-shadow: 0 12px 32px rgb(0 0 0 / 0.45);
  color: hsl(var(--popover-foreground));
}

.dark .esri-wayback-control-header {
  border-bottom-color: hsl(var(--border));
  color: hsl(var(--foreground));
}

.dark .esri-wayback-control-close {
  color: hsl(var(--muted-foreground));
}

.dark .esri-wayback-control-close:hover {
  color: hsl(var(--foreground));
}

/* Secondary/muted text throughout the panel. */
.dark .esri-wayback-status,
.dark .esri-wayback-summary-label,
.dark .esri-wayback-summary-detail,
.dark .esri-wayback-release-count,
.dark .esri-wayback-local-changes-status,
.dark .esri-wayback-slider-endpoints,
.dark .esri-wayback-persistent-status,
.dark .esri-wayback-metadata dt {
  color: hsl(var(--muted-foreground));
}

.dark .esri-wayback-status-error {
  color: hsl(var(--destructive));
}

/* Primary/strong text throughout the panel. */
.dark .esri-wayback-summary-value,
.dark .esri-wayback-label,
.dark .esri-wayback-local-changes-label,
.dark .esri-wayback-metadata h3,
.dark .esri-wayback-metadata dd {
  color: hsl(var(--foreground));
}

/* Grouped sub-panels (summary card, slider, persistent-layer box, metadata). */
.dark .esri-wayback-summary {
  background: hsl(var(--muted));
  border-color: hsl(var(--border));
}

.dark .esri-wayback-slider,
.dark .esri-wayback-persistent {
  background: hsl(var(--background));
  border-color: hsl(var(--border));
}

.dark .esri-wayback-metadata {
  border-top-color: hsl(var(--border));
}

/* Slider step buttons. */
.dark .esri-wayback-slider-button {
  background: hsl(var(--background));
  border-color: hsl(var(--border));
  color: hsl(var(--foreground));
}

.dark .esri-wayback-slider-button:hover:not(:disabled) {
  background: hsl(var(--accent));
  border-color: hsl(var(--ring));
}

.dark .esri-wayback-slider-button:disabled {
  color: hsl(var(--muted-foreground));
}

/* Retarget the native range/checkbox accent (a fixed light-blue above) onto the
   theme so the slider control itself tracks dark mode, not just its container. */
.dark .esri-wayback-range,
.dark .esri-wayback-local-changes-checkbox {
  accent-color: hsl(var(--primary));
}

/* Persistent-layer name input (higher specificity + !important beats the
   forced-light rule above). */
.dark .esri-wayback-control-panel .esri-wayback-input {
  background-color: hsl(var(--background)) !important;
  border-color: hsl(var(--border));
  color: hsl(var(--foreground)) !important;
}

.dark .esri-wayback-control-panel .esri-wayback-input::placeholder {
  color: hsl(var(--muted-foreground)) !important;
}

.dark .esri-wayback-input:focus {
  border-color: hsl(var(--ring));
  box-shadow: 0 0 0 3px hsl(var(--ring) / 0.3);
}

/* "Add layer" primary button. */
.dark .esri-wayback-add-layer-button {
  background: hsl(var(--primary));
  color: hsl(var(--primary-foreground));
}

.dark .esri-wayback-add-layer-button:hover:not(:disabled) {
  background: hsl(var(--primary) / 0.9);
}

.dark .esri-wayback-add-layer-button:disabled {
  background: hsl(var(--muted));
  color: hsl(var(--muted-foreground));
}

.geolibre-components-control .maplibregl-ctrl-group,
.geolibre-components-control .maplibregl-ctrl {
  align-items: center;
  display: flex;
  justify-content: center;
}

.geolibre-components-control .maplibre-gl-control-grid-content button {
  align-items: center;
  box-sizing: border-box;
  display: flex !important;
  justify-content: center;
  line-height: 0;
  padding: 0;
}

.geolibre-components-control .maplibre-gl-control-grid-content button > svg,
.geolibre-components-control .maplibre-gl-control-grid-content .maplibregl-ctrl-icon {
  display: block;
  flex: 0 0 auto;
  margin: 0 auto;
}

.geolibre-components-control
  .maplibre-gl-control-grid-content
  button
  > span:not(.maplibregl-ctrl-icon) {
  align-items: center;
  display: flex;
  height: 100%;
  justify-content: center;
  margin: 0;
  width: 100%;
}

.geolibre-components-control,
.geolibre-components-control .maplibre-gl-control-grid {
  overflow: visible;
}

.geolibre-components-control {
  padding: 10px !important;
}

.geolibre-components-control.maplibre-gl-control-grid--collapsed {
  height: 29px;
  padding: 0 !important;
  width: 29px;
}

.geolibre-components-control.maplibre-gl-control-grid--collapsed .maplibre-gl-control-grid-header,
.geolibre-components-control.maplibre-gl-control-grid--collapsed .maplibre-gl-control-grid-wrench {
  height: 29px !important;
  width: 29px !important;
}

.geolibre-components-control.maplibre-gl-control-grid--collapsed
  .maplibre-gl-control-grid-wrench
  svg {
  height: 16px;
  width: 16px;
}

.geolibre-components-control .maplibre-gl-control-grid-content > * {
  margin: 4px !important;
}

.geolibre-components-control .maplibre-gl-control-grid-floating-panel {
  box-sizing: border-box;
  max-width: min(340px, calc(100vw - 32px));
}

.geolibre-components-control .maplibre-gl-control-grid-floating-panel > .maplibregl-ctrl {
  margin-left: 0 !important;
  margin-right: 0 !important;
}

.geolibre-components-control
  .maplibre-gl-control-grid-floating-panel
  .maplibre-gl-search-input-wrapper {
  gap: 6px !important;
  padding-left: 6px !important;
  padding-right: 6px !important;
  width: 100% !important;
}

.geolibre-components-control .maplibre-gl-control-grid-floating-panel > .maplibre-gl-search {
  display: block !important;
  justify-content: normal !important;
}

.maplibregl-ctrl-top-left .geolibre-components-control .maplibre-gl-control-grid-floating-panel,
.maplibregl-ctrl-bottom-left .geolibre-components-control .maplibre-gl-control-grid-floating-panel {
  left: 0 !important;
  max-width: 100% !important;
  right: auto !important;
  width: 100% !important;
}

.maplibregl-ctrl-top-right .geolibre-components-control .maplibre-gl-control-grid-floating-panel,
.maplibregl-ctrl-bottom-right
  .geolibre-components-control
  .maplibre-gl-control-grid-floating-panel {
  left: auto !important;
  right: 0 !important;
}

.geolibre-components-control .maplibre-gl-control-grid-relocated {
  box-sizing: border-box;
  max-width: min(340px, calc(100vw - 32px)) !important;
}

.geolibre-flatgeobuf-control {
  background-color: hsl(var(--popover)) !important;
  color: hsl(var(--popover-foreground)) !important;
  overflow: visible;
}

.geolibre-flatgeobuf-control .maplibre-gl-add-vector-button {
  display: none !important;
}

.geolibre-pmtiles-control {
  background-color: hsl(var(--popover)) !important;
  color: hsl(var(--popover-foreground)) !important;
  overflow: visible;
}

.geolibre-pmtiles-control .maplibre-gl-pmtiles-layer-button {
  display: none !important;
}

/* SpinGlobeControl (maplibre-gl-components) renders an inline-styled, light-only
   panel positioned flush against its toolbar button. Re-theme it to the app
   popover so it reads in dark mode, and add a small gap so the panel does not
   touch the control icon. */
.spin-globe-panel {
  right: calc(100% + 8px) !important;
  background: hsl(var(--popover)) !important;
  border: 1px solid hsl(var(--border)) !important;
  box-shadow: 0 4px 12px rgb(0 0 0 / 0.25) !important;
  color: hsl(var(--popover-foreground)) !important;
}

/* The control hardcodes color:#000 inline on the title, close button, speed
   label, and units, so recolor every descendant to the popover foreground. */
.spin-globe-panel * {
  color: hsl(var(--popover-foreground)) !important;
}

/* The Start/Stop toggle is the panel's only direct-child button (the close "×"
   is nested in the header), so this leaves the close button transparent. */
.spin-globe-panel > button {
  background: hsl(var(--secondary)) !important;
  border-color: hsl(var(--border)) !important;
}

.spin-globe-panel > button:hover {
  background: hsl(var(--accent)) !important;
}

/* The control's toolbar button stays white like the other map controls in both
   themes, but its icon uses stroke="currentColor"; without a fixed color it
   inherits the dark-mode text color and goes white-on-white over the white
   button. Pin it to the same dark color the other control icons use (see
   .maplibregl-ctrl-layer-control below). */
.maplibre-gl-spin-globe-control button {
  color: #1f2a37;
}

/* The graticule control button: flex-center its inline SVG icon (MapLibre's
   default `.maplibregl-ctrl-group button { display: block }` would otherwise
   left-align it), and pin the stroke="currentColor" icon to a fixed dark color
   so it stays legible on the always-white control button in both themes (same
   approach as the spin-globe control above). The two-class selector out-ranks
   MapLibre's single-class rule regardless of stylesheet order. */
.geolibre-graticule-ctrl .geolibre-graticule-button {
  align-items: center;
  color: #1f2a37;
  display: flex;
  justify-content: center;
}

.geolibre-duckdb-control {
  background-color: transparent !important;
  box-shadow: none !important;
  color: hsl(var(--popover-foreground)) !important;
  height: 0 !important;
  margin: 0 !important;
  pointer-events: none;
}

.geolibre-duckdb-control .duckdb-control-toggle {
  pointer-events: none;
  visibility: hidden;
}

.duckdb-control-panel:has(+ .geolibre-duckdb-control),
.duckdb-control-panel {
  box-sizing: border-box;
  max-height: min(620px, calc(100% - 20px));
  max-width: min(365px, calc(100vw - 32px));
}

.duckdb-control-panel {
  background-color: hsl(var(--popover)) !important;
  border: 1px solid hsl(var(--border));
  color: hsl(var(--popover-foreground)) !important;
  left: 10px !important;
  top: 10px !important;
}

.duckdb-control-header {
  background-color: hsl(var(--card)) !important;
  border-bottom-color: hsl(var(--border)) !important;
  color: hsl(var(--foreground)) !important;
}

.duckdb-control-title,
.duckdb-control-label,
.duckdb-control-section-title,
.duckdb-control-summary-row strong,
.duckdb-control-properties dd {
  color: hsl(var(--foreground)) !important;
}

.duckdb-control-summary-row span,
.duckdb-control-properties dt,
.duckdb-control-placeholder {
  color: hsl(var(--muted-foreground)) !important;
}

.duckdb-control-section,
.duckdb-control-properties th,
.duckdb-control-properties td {
  border-color: hsl(var(--border)) !important;
}

.duckdb-control-input,
.duckdb-control-file,
.duckdb-control-textarea {
  background-color: hsl(var(--background)) !important;
  border-color: hsl(var(--input)) !important;
  color: hsl(var(--foreground)) !important;
}

.duckdb-control-input:focus,
.duckdb-control-file:focus,
.duckdb-control-textarea:focus {
  border-color: hsl(var(--ring)) !important;
  box-shadow: 0 0 0 1px hsl(var(--ring));
}

.duckdb-control-button {
  background-color: hsl(var(--primary)) !important;
  color: hsl(var(--primary-foreground)) !important;
}

.duckdb-control-button:hover {
  background-color: hsl(var(--primary) / 0.9) !important;
}

.duckdb-control-secondary-button {
  background-color: hsl(var(--secondary)) !important;
  color: hsl(var(--secondary-foreground)) !important;
}

.duckdb-control-secondary-button:hover {
  background-color: hsl(var(--accent)) !important;
  color: hsl(var(--accent-foreground)) !important;
}

.duckdb-control-status {
  background-color: hsl(var(--accent)) !important;
  color: hsl(var(--accent-foreground)) !important;
}

.duckdb-control-error {
  background-color: hsl(var(--destructive) / 0.12) !important;
  color: hsl(var(--destructive)) !important;
}

.duckdb-control-close {
  color: hsl(var(--muted-foreground)) !important;
}

.duckdb-control-close:hover {
  color: hsl(var(--foreground)) !important;
}

.geolibre-pmtiles-control .maplibre-gl-pmtiles-layer-panel {
  background-color: hsl(var(--popover)) !important;
  border: 1px solid hsl(var(--border));
  color: hsl(var(--popover-foreground)) !important;
  max-width: min(340px, calc(100vw - 32px));
}

.geolibre-pmtiles-control .maplibre-gl-pmtiles-layer-header {
  background-color: hsl(var(--card)) !important;
  border-bottom-color: hsl(var(--border)) !important;
  color: hsl(var(--foreground)) !important;
}

.geolibre-pmtiles-control .maplibre-gl-pmtiles-layer-title,
.geolibre-pmtiles-control .maplibre-gl-pmtiles-layer-form-group > label {
  color: hsl(var(--foreground)) !important;
}

.geolibre-pmtiles-control .maplibre-gl-pmtiles-layer-close {
  color: hsl(var(--foreground)) !important;
}

.geolibre-pmtiles-control .maplibre-gl-pmtiles-layer-close:hover {
  background-color: hsl(var(--accent)) !important;
  color: hsl(var(--accent-foreground)) !important;
}

.geolibre-pmtiles-control .maplibre-gl-pmtiles-layer-list {
  background-color: hsl(var(--card)) !important;
  border-color: hsl(var(--border)) !important;
  color: hsl(var(--foreground)) !important;
}

.geolibre-pmtiles-control .maplibre-gl-pmtiles-layer-list-item {
  border-bottom-color: hsl(var(--border)) !important;
  color: hsl(var(--foreground)) !important;
}

.geolibre-pmtiles-control .maplibre-gl-pmtiles-layer-list-label,
.geolibre-pmtiles-control .maplibre-gl-pmtiles-layer-list-header {
  color: hsl(var(--foreground)) !important;
}

.geolibre-pmtiles-control .maplibre-gl-pmtiles-layer-badge {
  background-color: hsl(var(--secondary)) !important;
  color: hsl(var(--secondary-foreground)) !important;
}

.geolibre-pmtiles-control .maplibre-gl-pmtiles-layer-form-group > div[style*="background"] {
  background-color: hsl(var(--background)) !important;
  border-color: hsl(var(--border)) !important;
  color: hsl(var(--foreground)) !important;
}

.geolibre-pmtiles-control .maplibre-gl-pmtiles-layer-form-group > div[style*="background"] label,
.geolibre-pmtiles-control .maplibre-gl-pmtiles-layer-form-group > div span {
  color: hsl(var(--foreground)) !important;
}

.geolibre-pmtiles-control .maplibre-gl-pmtiles-layer-form-group > span {
  color: hsl(var(--muted-foreground)) !important;
}

.geolibre-pmtiles-control input[type="checkbox"] {
  accent-color: hsl(var(--primary));
}

.geolibre-pmtiles-control .maplibre-gl-pmtiles-layer-input {
  background-color: hsl(var(--background)) !important;
  border: 1px solid hsl(var(--input)) !important;
  color: hsl(var(--foreground)) !important;
}

.geolibre-pmtiles-control .maplibre-gl-pmtiles-layer-input::placeholder {
  color: hsl(var(--muted-foreground)) !important;
}

.geolibre-pmtiles-control .maplibre-gl-pmtiles-layer-input:focus {
  border-color: hsl(var(--ring)) !important;
  box-shadow: 0 0 0 1px hsl(var(--ring)) !important;
  outline: none;
}

.geolibre-pmtiles-control .maplibre-gl-pmtiles-layer-btn {
  background-color: hsl(var(--card)) !important;
  border: 1px solid hsl(var(--border)) !important;
  color: hsl(var(--foreground)) !important;
}

.geolibre-pmtiles-control .maplibre-gl-pmtiles-layer-btn:hover:not(:disabled) {
  background-color: hsl(var(--accent)) !important;
  color: hsl(var(--accent-foreground)) !important;
}

.geolibre-pmtiles-control .maplibre-gl-pmtiles-layer-btn:disabled {
  color: hsl(var(--muted-foreground)) !important;
  opacity: 0.65;
}

.geolibre-pmtiles-control .maplibre-gl-pmtiles-layer-btn--primary {
  background-color: hsl(var(--primary)) !important;
  border-color: hsl(var(--primary)) !important;
  color: hsl(var(--primary-foreground)) !important;
}

.geolibre-pmtiles-control .maplibre-gl-pmtiles-layer-status--error {
  color: hsl(var(--destructive)) !important;
}

.geolibre-zarr-control {
  background-color: hsl(var(--popover)) !important;
  color: hsl(var(--popover-foreground)) !important;
  overflow: visible;
}

.geolibre-zarr-control .maplibre-gl-zarr-layer-button {
  display: none !important;
}

.geolibre-zarr-control .maplibre-gl-zarr-layer-panel {
  background-color: hsl(var(--popover)) !important;
  border: 1px solid hsl(var(--border));
  box-shadow: 0 12px 32px rgb(0 0 0 / 0.28);
  color: hsl(var(--popover-foreground)) !important;
  max-width: min(340px, calc(100vw - 32px));
}

.geolibre-zarr-control .maplibre-gl-zarr-layer-header {
  background-color: hsl(var(--card)) !important;
  border-bottom-color: hsl(var(--border)) !important;
  color: hsl(var(--foreground)) !important;
}

.geolibre-zarr-control .maplibre-gl-zarr-layer-title,
.geolibre-zarr-control .maplibre-gl-zarr-layer-form-group > label,
.geolibre-zarr-control .maplibre-gl-zarr-layer-checkbox-label,
.geolibre-zarr-control .maplibre-gl-zarr-layer-slider-value,
.geolibre-zarr-control .maplibre-gl-zarr-layer-list-header,
.geolibre-zarr-control .maplibre-gl-zarr-layer-list-label {
  color: hsl(var(--foreground)) !important;
}

.geolibre-zarr-control .maplibre-gl-zarr-layer-close,
.geolibre-zarr-control .maplibre-gl-zarr-layer-list-remove {
  color: hsl(var(--muted-foreground)) !important;
}

.geolibre-zarr-control .maplibre-gl-zarr-layer-close:hover,
.geolibre-zarr-control .maplibre-gl-zarr-layer-list-remove:hover {
  background-color: hsl(var(--accent)) !important;
  color: hsl(var(--accent-foreground)) !important;
}

.geolibre-zarr-control .maplibre-gl-zarr-layer-list {
  background-color: hsl(var(--card)) !important;
  border-color: hsl(var(--border)) !important;
  color: hsl(var(--foreground)) !important;
}

.geolibre-zarr-control .maplibre-gl-zarr-layer-list-item {
  border-bottom-color: hsl(var(--border)) !important;
  color: hsl(var(--foreground)) !important;
}

.geolibre-zarr-control .maplibre-gl-zarr-layer-input,
.geolibre-zarr-control .maplibre-gl-zarr-layer-select {
  background-color: hsl(var(--background)) !important;
  border: 1px solid hsl(var(--input)) !important;
  color: hsl(var(--foreground)) !important;
}

.geolibre-zarr-control .maplibre-gl-zarr-layer-select {
  appearance: none;
  background-image:
    linear-gradient(45deg, transparent 50%, hsl(var(--foreground)) 50%),
    linear-gradient(135deg, hsl(var(--foreground)) 50%, transparent 50%);
  background-position:
    calc(100% - 14px) 50%,
    calc(100% - 9px) 50%;
  background-repeat: no-repeat;
  background-size: 5px 5px;
  color-scheme: light dark;
  padding-right: 2rem !important;
}

.geolibre-zarr-control .maplibre-gl-zarr-layer-input::placeholder {
  color: hsl(var(--muted-foreground)) !important;
}

.geolibre-zarr-control .maplibre-gl-zarr-layer-input[type="number"] {
  min-height: 2rem;
  padding-right: 0.5rem !important;
}

.geolibre-zarr-control .maplibre-gl-zarr-layer-input[type="number"]::-webkit-inner-spin-button,
.geolibre-zarr-control .maplibre-gl-zarr-layer-input[type="number"]::-webkit-outer-spin-button {
  cursor: pointer;
  opacity: 1;
  transform: scale(1.3);
  transform-origin: center;
}

.geolibre-zarr-control .maplibre-gl-zarr-layer-input:focus,
.geolibre-zarr-control .maplibre-gl-zarr-layer-select:focus {
  border-color: hsl(var(--ring)) !important;
  box-shadow: 0 0 0 1px hsl(var(--ring)) !important;
  outline: none;
}

.geolibre-zarr-control .maplibre-gl-zarr-layer-select option {
  background-color: hsl(var(--popover));
  color: hsl(var(--popover-foreground));
}

.geolibre-zarr-control .maplibre-gl-zarr-layer-btn {
  background-color: hsl(var(--card)) !important;
  border: 1px solid hsl(var(--border)) !important;
  color: hsl(var(--foreground)) !important;
}

.geolibre-zarr-control .maplibre-gl-zarr-layer-btn:hover:not(:disabled) {
  background-color: hsl(var(--accent)) !important;
  color: hsl(var(--accent-foreground)) !important;
}

.geolibre-zarr-control .maplibre-gl-zarr-layer-btn:disabled {
  color: hsl(var(--muted-foreground)) !important;
  opacity: 0.65;
}

.geolibre-zarr-control .maplibre-gl-zarr-layer-btn--primary {
  background-color: hsl(var(--primary)) !important;
  border-color: hsl(var(--primary)) !important;
  color: hsl(var(--primary-foreground)) !important;
}

.geolibre-zarr-control .maplibre-gl-zarr-layer-status--error {
  color: hsl(var(--destructive)) !important;
}

.geolibre-zarr-control .maplibre-gl-zarr-layer-checkbox,
.geolibre-zarr-control .maplibre-gl-zarr-layer-slider {
  accent-color: hsl(var(--primary));
}

.geolibre-search-control {
  background-color: #fff !important;
  box-shadow: 0 12px 32px rgb(0 0 0 / 0.28);
  color: #333 !important;
  max-width: min(320px, calc(100vw - 32px));
  overflow: visible;
  position: relative;
  z-index: 3;
}

.geolibre-search-control .maplibre-gl-search-input-wrapper {
  background-color: #fff !important;
  border-bottom: 1px solid #d9d9d9 !important;
  box-sizing: border-box;
  width: 100% !important;
}

.geolibre-search-control .maplibre-gl-search-input {
  background-color: #fff !important;
  caret-color: #111;
  color: #111 !important;
}

.geolibre-search-control .maplibre-gl-search-input::placeholder {
  color: #333 !important;
  opacity: 1;
}

.geolibre-search-control .maplibre-gl-search-input:focus {
  outline: none;
}

.geolibre-search-control .maplibre-gl-search-toggle {
  background: #fff !important;
  border-radius: 4px;
  color: #333 !important;
  height: 29px !important;
  opacity: 1;
  width: 29px !important;
}

.geolibre-search-control .maplibre-gl-search-toggle svg {
  height: 16px;
  width: 16px;
}

.geolibre-search-control .maplibre-gl-search-toggle:hover {
  background: #f2f2f2 !important;
  color: #000 !important;
  opacity: 1;
}

.geolibre-search-control .maplibre-gl-search-icon,
.geolibre-search-control .maplibre-gl-search-clear,
.geolibre-search-control .maplibre-gl-search-collapse {
  color: #333 !important;
  opacity: 1;
}

.geolibre-search-control .maplibre-gl-search-clear:hover,
.geolibre-search-control .maplibre-gl-search-collapse:hover {
  color: #000 !important;
  opacity: 1;
}

.geolibre-search-control .maplibre-gl-search-results {
  background-color: #fff !important;
  border: 1px solid #d9d9d9;
  border-top: 0;
  color: #111 !important;
  max-width: min(320px, calc(100vw - 32px));
}

.geolibre-search-control .maplibre-gl-search-result {
  border-bottom-color: #e5e5e5 !important;
  color: #111 !important;
}

.geolibre-search-control .maplibre-gl-search-result:hover {
  background-color: #f2f2f2 !important;
  color: #000 !important;
}

.geolibre-search-control .maplibre-gl-search-result:hover * {
  color: #000 !important;
}

.geolibre-search-control .maplibre-gl-search-result-detail {
  color: #555 !important;
  opacity: 1;
}

.geolibre-stac-search-control {
  background-color: hsl(var(--popover)) !important;
  color: hsl(var(--popover-foreground)) !important;
  overflow: visible;
  position: relative;
  z-index: 3;
}

.maplibregl-control-container {
  inset: 0;
  pointer-events: none;
  position: absolute;
  z-index: 2;
}

/*
 * The overlaid deck.gl canvas (COG rasters via CogLayerControl, ArcGIS I3S, the
 * Tauri raster fallback) is map content and must sit UNDER the map-control
 * panels, not over them. It lives inside `.maplibregl-control-container` (pinned
 * to z-index 7 below), which already lifts it above the map canvas, so it only
 * needs a low z-index within that container. #1131 raised this to 5, which put
 * the raster above the STAC / Vantor plugin panels (z-index 3) and painted over
 * them (opengeos/GeoLibre#1240). Back to 1: the raster still renders above the
 * basemap, and control panels render above the raster.
 */
#deckgl-overlay {
  z-index: 1;
}

/*
 * The Effects plugin (the default starfield) raises the map canvas to
 * `z-index: 4` and bumps `.maplibregl-control-container` to 5 so normal map
 * controls keep painting above the canvas. The Time Slider dock relocates
 * itself out of the control container into its own reserve-space layout
 * wrapper, so it keeps the upstream library's `z-index: 2` and its
 * upward-floating "Add data" popover is drawn under the z-4 canvas (the panel
 * ends up "behind the map"). Lift the dock above the effects canvas so the
 * popover renders on top. Harmless when effects are off and the canvas sits at
 * its default auto z-index. See GeoLibre issue #570.
 */
.maplibregl-time-slider-dock,
.maplibregl-time-slider-dock.ts-docked {
  z-index: 6;
}

/*
 * The Layer Swipe comparison map paints its clipped half at `z-index: 5`
 * (raised in maplibre-gl-swipe 0.9.1 so it sits above the Effects plugin's z-4
 * map canvas). That ties with the control container, which the Effects plugin
 * also pins to `z-index: 5` inline, so the comparison map ends up covering the
 * top-right controls. Lift the controls above the comparison map. The
 * `!important` is needed to beat the Effects plugin's inline z-index.
 */
.maplibregl-control-container {
  z-index: 7 !important;
}

/*
 * Annotation tools control. Built as a plain `.maplibregl-ctrl-group`, so it
 * inherits MapLibre's default control chrome; these rules map it onto the app's
 * design tokens (so it tracks the in-app `.dark` toggle) and style the tool
 * buttons, the active-tool highlight, and the inline color/width inputs.
 */
.geolibre-annotations-control {
  background-color: hsl(var(--background)) !important;
  border: 1px solid hsl(var(--border)) !important;
  border-radius: 4px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* `display: flex !important` overrides MapLibre's `.maplibregl-ctrl button`
 * (which is `display: block`), so the icon centers in the 29px cell instead of
 * sitting at the top-left. */
.geolibre-annotations-control button {
  align-items: center;
  background: transparent;
  border: none;
  color: hsl(var(--foreground));
  cursor: pointer;
  display: flex !important;
  height: 29px;
  justify-content: center;
  padding: 0;
  width: 29px;
}

.geolibre-annotations-control button > svg {
  display: block;
  flex: 0 0 auto;
  margin: 0 auto;
}

.geolibre-annotations-control button:not(.is-active):hover {
  background-color: hsl(var(--accent));
  color: hsl(var(--accent-foreground));
}

.geolibre-annotations-control button.is-active {
  background-color: hsl(var(--primary));
  color: hsl(var(--primary-foreground));
}

/* Separators between the icon buttons, tinted for the active theme. */
.geolibre-annotations-control button + button,
.geolibre-annotations-control .geolibre-annotations-width,
.geolibre-annotations-control .geolibre-annotations-color {
  border-top: 1px solid hsl(var(--border));
}

.geolibre-annotations-control .geolibre-annotations-color {
  /* `border: none` removes the browser's <input> chrome but, at equal
   * specificity, also cancels the separator rule above, so re-apply the
   * top divider explicitly. */
  border: none;
  border-top: 1px solid hsl(var(--border));
  cursor: pointer;
  height: 24px;
  margin: 2px auto;
  padding: 0;
  width: 24px;
}

.geolibre-annotation-text-input {
  background-color: hsl(var(--background));
  border: 1px solid hsl(var(--primary));
  border-radius: 4px;
  color: hsl(var(--foreground));
  font-size: 13px;
  outline: none;
  padding: 2px 6px;
  transform: translate(-2px, -2px);
}

/*
 * The Measure, Bookmark and View State controls theme themselves purely via
 * `@media (prefers-color-scheme)`, so they follow the OS preference instead of
 * GeoLibre's in-app light/dark toggle (the `.dark` class on <html>). When the
 * two disagree — e.g. the app is in light mode on an OS set to dark — the panel
 * background is forced light by our backgroundColor option while the icons,
 * borders and secondary text stay dark-themed (light gray on white), which
 * reads as poor contrast. Remap each control's theme variables onto the app's
 * design tokens, which already switch with the `.dark` class, so the controls
 * track the in-app theme in both directions regardless of the OS setting.
 * index.css is imported after the component stylesheet, so these same-specificity
 * rules win the cascade over the component's media-query defaults.
 */
.geolibre-measure-control {
  --ms-panel-bg: hsl(var(--popover));
  --ms-text: hsl(var(--popover-foreground));
  --ms-strong-text: hsl(var(--foreground));
  --ms-muted: hsl(var(--muted-foreground));
  --ms-subtle: hsl(var(--muted-foreground));
  --ms-border: hsl(var(--border));
  --ms-input-bg: hsl(var(--background));
  --ms-input-text: hsl(var(--foreground));
  --ms-hover-bg: hsl(var(--accent));
  --ms-subtle-bg: hsl(var(--muted));
  --ms-button-bg: hsl(var(--background));
  --ms-button-text: hsl(var(--foreground));
  --ms-chip-bg: hsl(var(--muted));
  --ms-chip-text: hsl(var(--muted-foreground));
  --ms-secondary-border: hsl(var(--border));
}

.geolibre-bookmark-control {
  --bm-panel-bg: hsl(var(--popover));
  --bm-text: hsl(var(--popover-foreground));
  --bm-muted: hsl(var(--muted-foreground));
  --bm-subtle: hsl(var(--muted-foreground));
  --bm-border: hsl(var(--border));
  --bm-input-bg: hsl(var(--background));
  --bm-input-text: hsl(var(--foreground));
  --bm-placeholder: hsl(var(--muted-foreground));
  --bm-hover-bg: hsl(var(--accent));
  --bm-chip-hover-bg: hsl(var(--accent));
  --bm-button-bg: hsl(var(--background));
  --bm-button-text: hsl(var(--foreground));
  --bm-item-active-bg: hsl(var(--accent));
  --bm-secondary-text: hsl(var(--muted-foreground));
  --bm-secondary-border: hsl(var(--border));
}

.geolibre-view-state-control {
  --vs-surface-bg: hsl(var(--popover));
  --vs-panel-bg: hsl(var(--popover));
  --vs-text: hsl(var(--popover-foreground));
  --vs-heading: hsl(var(--foreground));
  --vs-label: hsl(var(--muted-foreground));
  --vs-muted: hsl(var(--muted-foreground));
  --vs-border: hsl(var(--border));
  --vs-row-hover: hsl(var(--accent));
  --vs-code-bg: hsl(var(--muted));
  --vs-chip-bg: hsl(var(--muted));
  --vs-chip-hover-bg: hsl(var(--accent));
}

/* Make the minimap toggle and collapse buttons follow the in-app theme. The
   upstream control defaults to prefers-color-scheme, which can disagree with
   GeoLibre's class-based theme (e.g. the collapse icon staying dark in dark
   mode). */
.geolibre-minimap-control {
  --mm-button-bg: hsl(var(--popover));
  --mm-button-hover-bg: hsl(var(--accent));
  --mm-button-text: hsl(var(--popover-foreground));
  --mm-button-ring: hsl(var(--border));
}

.geolibre-stac-search-control .maplibre-gl-stac-search-button {
  display: none !important;
}

.geolibre-stac-search-control .maplibre-gl-stac-search-panel {
  background-color: hsl(var(--popover)) !important;
  border: 1px solid hsl(var(--border));
  box-shadow: 0 12px 32px rgb(0 0 0 / 0.28);
  color: hsl(var(--popover-foreground)) !important;
  max-width: min(365px, calc(100vw - 32px));
}

.geolibre-stac-search-control .maplibre-gl-stac-search-header {
  background-color: hsl(var(--card)) !important;
  border-bottom-color: hsl(var(--border)) !important;
  color: hsl(var(--foreground)) !important;
}

.geolibre-stac-search-control .maplibre-gl-stac-search-title,
.geolibre-stac-search-control .maplibre-gl-stac-search-form-group > label,
.geolibre-stac-search-control .maplibre-gl-stac-search-hint,
.geolibre-stac-search-control .maplibre-gl-stac-search-list-header,
.geolibre-stac-search-control .maplibre-gl-stac-search-list-label,
.geolibre-stac-search-control .maplibre-gl-stac-search-rgb-label {
  color: hsl(var(--foreground)) !important;
}

.geolibre-stac-search-control .maplibre-gl-stac-search-close,
.geolibre-stac-search-control .maplibre-gl-stac-search-list-remove {
  color: hsl(var(--muted-foreground)) !important;
}

.geolibre-stac-search-control .maplibre-gl-stac-search-close:hover,
.geolibre-stac-search-control .maplibre-gl-stac-search-list-remove:hover {
  background-color: hsl(var(--accent)) !important;
  color: hsl(var(--accent-foreground)) !important;
}

.geolibre-stac-search-control .maplibre-gl-stac-search-input,
.geolibre-stac-search-control .maplibre-gl-stac-search-select {
  background-color: hsl(var(--background)) !important;
  border: 1px solid hsl(var(--input)) !important;
  color: hsl(var(--foreground)) !important;
}

.geolibre-stac-search-control .maplibre-gl-stac-search-input::placeholder {
  color: hsl(var(--muted-foreground)) !important;
}

.geolibre-stac-search-control .maplibre-gl-stac-search-input:focus,
.geolibre-stac-search-control .maplibre-gl-stac-search-select:focus {
  border-color: hsl(var(--ring)) !important;
  box-shadow: 0 0 0 1px hsl(var(--ring)) !important;
  outline: none;
}

.geolibre-stac-search-control .maplibre-gl-stac-search-select option {
  background-color: hsl(var(--popover));
  color: hsl(var(--popover-foreground));
}

.geolibre-stac-search-control .maplibre-gl-stac-search-btn,
.geolibre-stac-search-control .maplibre-gl-stac-search-btn-clear,
.geolibre-stac-search-control .maplibre-gl-stac-search-btn-clear-footprints {
  background-color: hsl(var(--card)) !important;
  border: 1px solid hsl(var(--border)) !important;
  color: hsl(var(--foreground)) !important;
}

.geolibre-stac-search-control .maplibre-gl-stac-search-btn:hover:not(:disabled),
.geolibre-stac-search-control .maplibre-gl-stac-search-btn-clear:hover,
.geolibre-stac-search-control .maplibre-gl-stac-search-btn-clear-footprints:hover {
  background-color: hsl(var(--accent)) !important;
  color: hsl(var(--accent-foreground)) !important;
}

.geolibre-stac-search-control .maplibre-gl-stac-search-btn:disabled {
  color: hsl(var(--muted-foreground)) !important;
  opacity: 0.65;
}

.geolibre-stac-search-control .maplibre-gl-stac-search-btn--primary,
.geolibre-stac-search-control .maplibre-gl-stac-search-btn--toggle.active {
  background-color: hsl(var(--primary)) !important;
  border-color: hsl(var(--primary)) !important;
  color: hsl(var(--primary-foreground)) !important;
}

.geolibre-stac-search-control .maplibre-gl-stac-search-list {
  background-color: hsl(var(--card)) !important;
  border-color: hsl(var(--border)) !important;
  color: hsl(var(--foreground)) !important;
}

.geolibre-stac-search-control .maplibre-gl-stac-search-list-item {
  background-color: hsl(var(--background)) !important;
  border-bottom-color: hsl(var(--border)) !important;
  color: hsl(var(--foreground)) !important;
}

.geolibre-stac-search-control .maplibre-gl-stac-search-list-item:hover {
  background-color: hsl(var(--accent)) !important;
  color: hsl(var(--accent-foreground)) !important;
}

.geolibre-stac-search-control
  .maplibre-gl-stac-search-list-item:hover
  .maplibre-gl-stac-search-list-label {
  color: hsl(var(--accent-foreground)) !important;
}

.geolibre-stac-search-control
  .maplibre-gl-stac-search-list-item:hover
  .maplibre-gl-stac-search-list-remove {
  color: hsl(var(--accent-foreground)) !important;
}

.geolibre-stac-search-control .maplibre-gl-stac-search-status--error {
  color: hsl(var(--destructive)) !important;
}

.geolibre-flatgeobuf-control .maplibre-gl-add-vector-panel {
  background-color: hsl(var(--popover)) !important;
  border: 1px solid hsl(var(--border));
  box-shadow: 0 12px 32px rgb(0 0 0 / 0.28);
  color: hsl(var(--popover-foreground)) !important;
}

.geolibre-flatgeobuf-control .maplibre-gl-add-vector-header {
  border-bottom-color: hsl(var(--border)) !important;
}

/* The FlatGeobuf form has the most fields of any Add Data panel; tighten its
   vertical rhythm so it fits the panel (the Add Layer button stays visible)
   instead of overflowing into a scrollbar on common window heights. */
.geolibre-flatgeobuf-control .maplibre-gl-add-vector-form-group {
  margin-bottom: 6px;
}

.geolibre-flatgeobuf-control .maplibre-gl-add-vector-form-group > label {
  margin-bottom: 2px;
}

.geolibre-flatgeobuf-control .maplibre-gl-add-vector-input-mode,
.geolibre-flatgeobuf-control .maplibre-gl-sample-dropdown {
  margin-bottom: 6px;
}

.geolibre-flatgeobuf-control .maplibre-gl-add-vector-buttons {
  margin-top: 8px;
}

.geolibre-flatgeobuf-control .maplibre-gl-add-vector-title,
.geolibre-flatgeobuf-control .maplibre-gl-add-vector-form-group label,
.geolibre-flatgeobuf-control .maplibre-gl-add-vector-checkbox-label,
.geolibre-flatgeobuf-control .maplibre-gl-add-vector-slider-value,
.geolibre-flatgeobuf-control .maplibre-gl-add-vector-list-header,
.geolibre-flatgeobuf-control .maplibre-gl-add-vector-list-label {
  color: hsl(var(--popover-foreground)) !important;
}

.geolibre-flatgeobuf-control .maplibre-gl-add-vector-close,
.geolibre-flatgeobuf-control .maplibre-gl-add-vector-list-remove {
  color: hsl(var(--muted-foreground)) !important;
}

.geolibre-flatgeobuf-control .maplibre-gl-add-vector-close:hover,
.geolibre-flatgeobuf-control .maplibre-gl-add-vector-list-remove:hover {
  color: hsl(var(--foreground)) !important;
}

.geolibre-flatgeobuf-control .maplibre-gl-add-vector-input,
.geolibre-flatgeobuf-control .maplibre-gl-add-vector-select,
.geolibre-flatgeobuf-control .maplibre-gl-add-vector-textarea,
.geolibre-flatgeobuf-control .maplibre-gl-add-vector-minzoom-input {
  background-color: hsl(var(--background)) !important;
  border: 1px solid hsl(var(--input)) !important;
  color: hsl(var(--foreground)) !important;
}

.geolibre-flatgeobuf-control .maplibre-gl-add-vector-input::placeholder,
.geolibre-flatgeobuf-control .maplibre-gl-add-vector-textarea::placeholder {
  color: hsl(var(--muted-foreground)) !important;
}

.geolibre-flatgeobuf-control .maplibre-gl-add-vector-input:focus,
.geolibre-flatgeobuf-control .maplibre-gl-add-vector-select:focus,
.geolibre-flatgeobuf-control .maplibre-gl-add-vector-textarea:focus,
.geolibre-flatgeobuf-control .maplibre-gl-add-vector-minzoom-input:focus {
  border-color: hsl(var(--ring)) !important;
  box-shadow: 0 0 0 1px hsl(var(--ring));
  outline: none;
}

.geolibre-flatgeobuf-control .maplibre-gl-add-vector-select option {
  background-color: hsl(var(--popover));
  color: hsl(var(--popover-foreground));
}

.geolibre-flatgeobuf-control .maplibre-gl-add-vector-format-hint {
  color: hsl(var(--muted-foreground)) !important;
}

.geolibre-flatgeobuf-control .maplibre-gl-add-vector-mode-btn {
  background-color: hsl(var(--secondary)) !important;
  border-color: hsl(var(--border)) !important;
  color: hsl(var(--secondary-foreground)) !important;
}

.geolibre-flatgeobuf-control .maplibre-gl-add-vector-mode-btn--active,
.geolibre-flatgeobuf-control .maplibre-gl-add-vector-btn--primary {
  background-color: hsl(var(--primary)) !important;
  border-color: hsl(var(--primary)) !important;
  color: hsl(var(--primary-foreground)) !important;
}

.geolibre-flatgeobuf-control .maplibre-gl-add-vector-slider {
  accent-color: hsl(var(--primary));
}

.maplibregl-ctrl-top-left .geolibre-components-control .maplibre-gl-control-grid-relocated,
.maplibregl-ctrl-bottom-left .geolibre-components-control .maplibre-gl-control-grid-relocated {
  max-width: 100% !important;
  width: 100% !important;
}

.maplibregl-ctrl-top-left .geolibre-components-control .left[class*="panel"],
.maplibregl-ctrl-top-left .geolibre-components-control .right[class*="panel"],
.maplibregl-ctrl-bottom-left .geolibre-components-control .left[class*="panel"],
.maplibregl-ctrl-bottom-left .geolibre-components-control .right[class*="panel"] {
  left: 0 !important;
  right: auto !important;
}

.maplibregl-ctrl-top-right .geolibre-components-control .left[class*="panel"],
.maplibregl-ctrl-top-right .geolibre-components-control .right[class*="panel"],
.maplibregl-ctrl-bottom-right .geolibre-components-control .left[class*="panel"],
.maplibregl-ctrl-bottom-right .geolibre-components-control .right[class*="panel"] {
  left: auto !important;
  right: 0 !important;
}

.geolibre-components-control input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
.geolibre-components-control select,
.geolibre-components-control textarea {
  background-color: #fff !important;
  border: 1px solid #d1d5db;
  border-radius: 4px;
  box-sizing: border-box;
  color: #111827 !important;
  color-scheme: light;
}

.geolibre-components-control input::placeholder,
.geolibre-components-control textarea::placeholder {
  color: #6b7280 !important;
}

.geolibre-components-control select option {
  background-color: #fff;
  color: #111827;
}

.geolibre-colorbar-control,
.geolibre-legend-control,
.geolibre-html-control {
  --maplibre-gl-gui-border-color: hsl(var(--border));
  --maplibre-gl-gui-focus-color: hsl(var(--ring));
  --maplibre-gl-gui-hover-background: hsl(var(--secondary));
  --maplibre-gl-gui-input-background: hsl(var(--background));
  --maplibre-gl-gui-input-color: hsl(var(--foreground));
  --maplibre-gl-gui-muted-color: hsl(var(--muted-foreground));
  --maplibre-gl-gui-placeholder-color: hsl(var(--muted-foreground));
  color: hsl(var(--popover-foreground)) !important;
}

.dark .geolibre-colorbar-control,
.dark .geolibre-legend-control,
.dark .geolibre-html-control,
.dark .geolibre-colorbar-control .colorbar-gui-input,
.dark .geolibre-colorbar-control .colorbar-gui-select,
.dark .geolibre-colorbar-control .colorbar-gui-textarea,
.dark .geolibre-legend-control .legend-gui-input,
.dark .geolibre-legend-control .legend-gui-select,
.dark .geolibre-legend-control .legend-gui-textarea,
.dark .geolibre-html-control .html-gui-input,
.dark .geolibre-html-control .html-gui-select,
.dark .geolibre-html-control .html-gui-textarea {
  color-scheme: dark;
}

/* The graticule settings panel is plain DOM (the plugin contract), so its native
   select/number inputs would otherwise render with the browser's default light
   chrome -- a white dropdown with invisible text on the dark panel. `color-scheme`
   alone is unreliable across webviews, so set the background/text/border
   explicitly from the design tokens (which switch with `.dark`), and theme the
   `<option>` popup too. `color-scheme` still covers the native spinner/color/
   checkbox chrome. */
.geolibre-graticule-panel select,
.geolibre-graticule-panel input[type="number"] {
  background: hsl(var(--background));
  border: 1px solid hsl(var(--border));
  border-radius: 4px;
  color: hsl(var(--foreground));
  padding: 2px 4px;
}

.geolibre-graticule-panel select option {
  background: hsl(var(--background));
  color: hsl(var(--foreground));
}

.dark .geolibre-graticule-panel select,
.dark .geolibre-graticule-panel input {
  color-scheme: dark;
}

/* The timelapse floating panel is plain DOM like the graticule panel above, so
   theme its native speed select (and dropdown popup) from the design tokens. */
.geolibre-timelapse-panel select {
  background: hsl(var(--background));
  border: 1px solid hsl(var(--border));
  border-radius: 4px;
  color: hsl(var(--foreground));
  padding: 2px 4px;
}

.geolibre-timelapse-panel select option {
  background: hsl(var(--background));
  color: hsl(var(--foreground));
}

.dark .geolibre-timelapse-panel select,
.dark .geolibre-timelapse-panel input {
  color-scheme: dark;
}

.geolibre-colorbar-control .colorbar-gui-input,
.geolibre-colorbar-control .colorbar-gui-select,
.geolibre-colorbar-control .colorbar-gui-textarea,
.geolibre-legend-control .legend-gui-input,
.geolibre-legend-control .legend-gui-select,
.geolibre-legend-control .legend-gui-textarea,
.geolibre-html-control .html-gui-input,
.geolibre-html-control .html-gui-select,
.geolibre-html-control .html-gui-textarea {
  background: var(--maplibre-gl-gui-input-background) !important;
  border-color: var(--maplibre-gl-gui-border-color) !important;
  color: var(--maplibre-gl-gui-input-color) !important;
}

.geolibre-colorbar-control .colorbar-gui-input::placeholder,
.geolibre-colorbar-control .colorbar-gui-textarea::placeholder,
.geolibre-legend-control .legend-gui-input::placeholder,
.geolibre-legend-control .legend-gui-textarea::placeholder,
.geolibre-html-control .html-gui-input::placeholder,
.geolibre-html-control .html-gui-textarea::placeholder {
  color: var(--maplibre-gl-gui-placeholder-color) !important;
}

.geolibre-colorbar-control .colorbar-gui-select option,
.geolibre-legend-control .legend-gui-select option,
.geolibre-html-control .html-gui-select option {
  background: hsl(var(--background));
  color: hsl(var(--foreground));
}

.geolibre-components-control input[type="radio"] {
  appearance: none;
  background-color: #fff;
  border: 2px solid #6b7280;
  border-radius: 50%;
  color-scheme: light;
  display: inline-grid;
  flex: 0 0 auto;
  height: 14px;
  margin: 0;
  opacity: 1;
  place-content: center;
  width: 14px;
}

.geolibre-components-control input[type="radio"]::before {
  background-color: #0f766e;
  border-radius: 50%;
  content: "";
  height: 6px;
  transform: scale(0);
  width: 6px;
}

.geolibre-components-control input[type="radio"]:checked {
  border-color: #0f766e;
}

.geolibre-components-control input[type="radio"]:checked::before {
  transform: scale(1);
}

.geolibre-components-control input[type="radio"]:focus-visible {
  box-shadow: 0 0 0 2px rgba(15, 118, 110, 0.2);
  outline: none;
}

.geolibre-components-control .maplibre-gl-control-grid-header input[type="number"] {
  color-scheme: light;
  font-size: 12px;
  height: 22px;
  line-height: 22px;
  padding: 1px 0 1px 4px !important;
  width: 44px !important;
}

.geolibre-components-control
  .maplibre-gl-control-grid-header
  input[type="number"]::-webkit-inner-spin-button,
.geolibre-components-control
  .maplibre-gl-control-grid-header
  input[type="number"]::-webkit-outer-spin-button {
  height: 20px;
  margin: 0;
  opacity: 1;
  width: 18px;
}

.geolibre-components-control .maplibre-gl-splat-panel input[type="number"] {
  font-size: 12px !important;
  height: 32px;
  line-height: 32px;
  padding-bottom: 4px !important;
  padding-right: 4px !important;
  padding-top: 4px !important;
}

.geolibre-components-control
  .maplibre-gl-splat-panel
  input[type="number"]::-webkit-inner-spin-button,
.geolibre-components-control
  .maplibre-gl-splat-panel
  input[type="number"]::-webkit-outer-spin-button {
  height: 28px;
  margin: 0;
  opacity: 1;
  width: 18px;
}

.geolibre-components-control .maplibre-gl-splat-panel > button {
  align-items: center !important;
  display: flex !important;
  justify-content: center !important;
  line-height: 1 !important;
  min-height: 30px;
}

/*
 * Enlarge the native number-input spinner arrows inside dialogs (e.g. the
 * Raster/Conversion tool dialogs). The default WebKit stepper is tiny and only
 * visible on hover; make it always visible and comfortably clickable. Scoped to
 * [role="dialog"] so the carefully sized map-control inputs above are untouched.
 */
[role="dialog"] input[type="number"]::-webkit-inner-spin-button,
[role="dialog"] input[type="number"]::-webkit-outer-spin-button {
  opacity: 1;
  height: 1.9rem;
  width: 1.15rem;
  margin-left: 0.35rem;
  cursor: pointer;
}

.geolibre-splatting-control .maplibre-gl-splat-panel {
  background: hsl(var(--popover)) !important;
  border: 1px solid hsl(var(--border));
  border-radius: 6px;
  box-shadow:
    0 10px 15px -3px rgb(0 0 0 / 0.18),
    0 4px 6px -4px rgb(0 0 0 / 0.18);
  color: hsl(var(--popover-foreground)) !important;
}

.geolibre-splatting-control .maplibre-gl-splat-panel input {
  background: hsl(var(--background)) !important;
  border-color: hsl(var(--input)) !important;
  color: hsl(var(--foreground)) !important;
}

.geolibre-splatting-control .maplibre-gl-splat-panel input::placeholder {
  color: hsl(var(--muted-foreground)) !important;
}

.geolibre-splatting-control .maplibre-gl-splat-panel label,
.geolibre-splatting-control .maplibre-gl-splat-panel > div > span,
.geolibre-splatting-control .maplibre-gl-splat-panel > div > div:first-child {
  color: hsl(var(--popover-foreground)) !important;
}

.geolibre-splatting-control .maplibre-gl-splat-panel > div:first-child {
  border-bottom-color: hsl(var(--border)) !important;
}

.geolibre-splatting-control .maplibre-gl-splat-panel > div:first-child button {
  color: hsl(var(--muted-foreground)) !important;
}

.geolibre-splatting-control .maplibre-gl-splat-panel > div:first-child button:hover {
  color: hsl(var(--foreground)) !important;
}

.geolibre-splatting-control .maplibre-gl-splat-panel > button {
  background: hsl(var(--primary)) !important;
  color: hsl(var(--primary-foreground)) !important;
}

.geolibre-splatting-control .maplibre-gl-splat-panel div[style*="background: #f8f8f8"],
.geolibre-splatting-control .maplibre-gl-splat-panel div[style*="background: rgb(248, 248, 248)"] {
  background: hsl(var(--secondary)) !important;
  border: 1px solid hsl(var(--border));
}

.geolibre-splatting-control .maplibre-gl-splat-panel div[style*="background: #f8f8f8"] span,
.geolibre-splatting-control
  .maplibre-gl-splat-panel
  div[style*="background: rgb(248, 248, 248)"]
  span {
  color: hsl(var(--secondary-foreground)) !important;
}

.geolibre-splatting-control .maplibre-gl-splat-panel > button {
  align-items: center !important;
  display: flex !important;
  justify-content: center !important;
  line-height: 1 !important;
  min-height: 30px;
}

.geolibre-3d-tiles-control {
  background: hsl(var(--popover)) !important;
  color: hsl(var(--popover-foreground)) !important;
}

.geolibre-3d-tiles-control .three-d-tiles-control-toggle {
  color: hsl(var(--popover-foreground)) !important;
}

.geolibre-3d-tiles-control .three-d-tiles-control-toggle:hover {
  background-color: hsl(var(--accent)) !important;
}

.geolibre-3d-tiles-panel {
  --geolibre-3d-tiles-status-success: #0f9f6e;
  background: hsl(var(--popover)) !important;
  border: 1px solid hsl(var(--border)) !important;
  box-shadow:
    0 10px 15px -3px rgb(0 0 0 / 0.18),
    0 4px 6px -4px rgb(0 0 0 / 0.18) !important;
  color: hsl(var(--popover-foreground)) !important;
  /* Follow the in-app theme, not the OS: `light dark` let native controls
     (e.g. the number-input spinner) render dark when the OS is dark even though
     the app is light. */
  color-scheme: light;
}

.dark .geolibre-3d-tiles-panel {
  color-scheme: dark;
}

.geolibre-3d-tiles-panel .three-d-tiles-control-header {
  border-bottom-color: hsl(var(--border)) !important;
  color: hsl(var(--popover-foreground)) !important;
}

.geolibre-3d-tiles-panel .three-d-tiles-control-close,
.geolibre-3d-tiles-panel .three-d-tiles-empty,
.geolibre-3d-tiles-panel .three-d-tiles-list-status,
.geolibre-3d-tiles-panel .three-d-tiles-list-url,
.geolibre-3d-tiles-panel .three-d-tiles-status {
  color: hsl(var(--muted-foreground)) !important;
}

.geolibre-3d-tiles-panel .three-d-tiles-control-close:hover {
  color: hsl(var(--popover-foreground)) !important;
}

.geolibre-3d-tiles-panel .three-d-tiles-field,
.geolibre-3d-tiles-panel .three-d-tiles-checkbox,
.geolibre-3d-tiles-panel .three-d-tiles-list-title {
  color: hsl(var(--popover-foreground)) !important;
}

.geolibre-3d-tiles-panel .three-d-tiles-input {
  background: hsl(var(--background)) !important;
  border-color: hsl(var(--input)) !important;
  color: hsl(var(--foreground)) !important;
}

.geolibre-3d-tiles-panel .three-d-tiles-input[type="number"] {
  min-height: 36px;
  padding-right: 4px;
}

.geolibre-3d-tiles-panel .three-d-tiles-input[type="number"]::-webkit-inner-spin-button,
.geolibre-3d-tiles-panel .three-d-tiles-input[type="number"]::-webkit-outer-spin-button {
  min-height: 30px;
  opacity: 1;
  width: 22px;
}

.geolibre-3d-tiles-panel .three-d-tiles-input:focus {
  border-color: hsl(var(--ring)) !important;
  box-shadow: 0 0 0 2px hsl(var(--ring) / 0.16) !important;
}

.geolibre-3d-tiles-panel .geolibre-google-tiles-key-toggle {
  align-self: flex-start;
  margin-top: 6px;
}

.geolibre-3d-tiles-panel .three-d-tiles-checkbox input,
.geolibre-3d-tiles-panel .three-d-tiles-list-actions input[type="checkbox"],
.geolibre-3d-tiles-panel .three-d-tiles-opacity {
  accent-color: hsl(var(--primary));
}

.geolibre-3d-tiles-panel .three-d-tiles-button,
.geolibre-3d-tiles-panel .three-d-tiles-small-button {
  background: hsl(var(--secondary)) !important;
  border-color: hsl(var(--border)) !important;
  color: hsl(var(--secondary-foreground)) !important;
}

.geolibre-3d-tiles-panel .three-d-tiles-button:hover:not(:disabled),
.geolibre-3d-tiles-panel .three-d-tiles-small-button:hover:not(:disabled) {
  background: hsl(var(--accent)) !important;
  border-color: hsl(var(--border)) !important;
  color: hsl(var(--accent-foreground)) !important;
}

.geolibre-3d-tiles-panel .three-d-tiles-button:disabled,
.geolibre-3d-tiles-panel .three-d-tiles-small-button:disabled {
  background: hsl(var(--muted)) !important;
  border-color: hsl(var(--border)) !important;
  color: hsl(var(--muted-foreground)) !important;
  opacity: 0.75;
}

.geolibre-3d-tiles-panel .three-d-tiles-opacity {
  width: 58px;
}

.geolibre-3d-tiles-panel .three-d-tiles-list-actions {
  color: hsl(var(--popover-foreground)) !important;
}

.geolibre-3d-tiles-panel .three-d-tiles-status,
.geolibre-3d-tiles-panel .three-d-tiles-list-item {
  border-color: hsl(var(--border)) !important;
}

.geolibre-3d-tiles-panel .three-d-tiles-list-item.active {
  background: hsl(var(--accent)) !important;
  border-color: hsl(var(--ring)) !important;
}

.geolibre-3d-tiles-panel .three-d-tiles-status[data-status="loaded"],
.geolibre-3d-tiles-panel .three-d-tiles-list-status[data-status="loaded"] {
  color: var(--geolibre-3d-tiles-status-success) !important;
}

.geolibre-3d-tiles-panel .three-d-tiles-status[data-status="error"],
.geolibre-3d-tiles-panel .three-d-tiles-list-status[data-status="error"] {
  color: hsl(var(--destructive)) !important;
}

.geolibre-components-control
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):focus,
.geolibre-components-control select:focus,
.geolibre-components-control textarea:focus {
  border-color: #2f8f85;
  box-shadow: 0 0 0 2px rgba(47, 143, 133, 0.16);
  outline: none;
}

.maplibregl-ctrl button.maplibregl-ctrl-globe-enabled .maplibregl-ctrl-icon {
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='22' height='22' fill='none' stroke='%2333b5e5' viewBox='0 0 22 22'%3E%3Ccircle cx='11' cy='11' r='8.5'/%3E%3Cpath d='M17.5 11c0 4.819-3.02 8.5-6.5 8.5S4.5 15.819 4.5 11 7.52 2.5 11 2.5s6.5 3.681 6.5 8.5Z'/%3E%3Cpath d='M13.5 11c0 2.447-.331 4.64-.853 6.206-.262.785-.562 1.384-.872 1.777-.314.399-.58.517-.775.517s-.461-.118-.775-.517c-.31-.393-.61-.992-.872-1.777C8.831 15.64 8.5 13.446 8.5 11s.331-4.64.853-6.206c.262-.785.562-1.384.872-1.777.314-.399.58-.517.775-.517s.461.118.775.517c.31.393.61.992.872 1.777.522 1.565.853 3.76.853 6.206Z'/%3E%3Cpath d='M11 7.5c-1.909 0-3.622-.166-4.845-.428-.616-.132-1.08-.283-1.379-.434a1.3 1.3 0 0 1-.224-.138q.07-.058.224-.138c.299-.151.763-.302 1.379-.434C7.378 5.666 9.091 5.5 11 5.5s3.622.166 4.845.428c.616.132 1.08.283 1.379.434.105.053.177.1.224.138q-.07.058-.224.138c-.299.151-.763.302-1.379.434-1.223.262-2.936.428-4.845.428ZM4.486 6.436ZM11 16.5c-1.909 0-3.622-.166-4.845-.428-.616-.132-1.08-.283-1.379-.434a1.3 1.3 0 0 1-.224-.138 1.3 1.3 0 0 1 .224-.138c.299-.151.763-.302 1.379-.434C7.378 14.666 9.091 14.5 11 14.5s3.622.166 4.845.428c.616.132 1.08.283 1.379.434.105.053.177.1.224.138a1.3 1.3 0 0 1-.224.138c-.299.151-.763.302-1.379.434-1.223.262-2.936.428-4.845.428Zm-6.514-1.064ZM11 12.5c-2.46 0-4.672-.222-6.255-.574-.796-.177-1.406-.38-1.805-.59a1.5 1.5 0 0 1-.39-.272.3.3 0 0 1-.047-.064.3.3 0 0 1 .048-.064c.066-.073.189-.167.389-.272.399-.21 1.009-.413 1.805-.59C6.328 9.722 8.54 9.5 11 9.5s4.672.222 6.256.574c.795.177 1.405.38 1.804.59.2.105.323.2.39.272a.3.3 0 0 1 .047.064.3.3 0 0 1-.048.064 1.4 1.4 0 0 1-.389.272c-.399.21-1.009.413-1.804.59-1.584.352-3.796.574-6.256.574Zm-8.501-1.51v.002zm0 .018v.002zm17.002.002v-.002zm0-.018v-.002z'/%3E%3C/svg%3E");
}

/* Compass control (issue #508). Sits directly below the Fullscreen button. The
   needle tracks the live bearing and its north half turns red the moment the
   map is rotated or tilted, so a skewed view is unmistakable; while north-up
   and flat the button is disabled (nothing to reset) but stays high-contrast,
   since that is its resting appearance. GeoLibre keeps map controls light
   (white) in both themes, so the needle uses dark fills that stay legible in
   light and dark mode alike. The button selector carries two classes so it
   outranks maplibre's equally-specific `.maplibregl-ctrl-group button { display:
   block }` (which loads later and would otherwise left-align the needle). */
.geolibre-reset-bearing-ctrl .geolibre-reset-bearing-button {
  align-items: center;
  display: flex;
  justify-content: center;
}

.geolibre-reset-bearing-needle {
  height: 24px;
  transform-origin: 50% 50%;
  width: 24px;
}

.geolibre-reset-bearing-needle-label {
  fill: #1e293b;
  font-family:
    ui-sans-serif,
    system-ui,
    -apple-system,
    "Segoe UI",
    Roboto,
    sans-serif;
  font-size: 8px;
  font-weight: 700;
  /* The label is a real SVG text node: stop it from being text-selected on a
     click-drag and from firing the native text context menu on right-click. */
  pointer-events: none;
  transition: fill 150ms ease;
  user-select: none;
}

.geolibre-reset-bearing-needle-north {
  fill: #1e293b;
  transition: fill 150ms ease;
}

/* Light, slim south tail so the upward north needle stays the single dominant
   pointer (issue #537) — the two halves must not read as equal triangles. */
.geolibre-reset-bearing-needle-south {
  fill: #cbd5e1;
}

.geolibre-reset-bearing-button--active .geolibre-reset-bearing-needle-north,
.geolibre-reset-bearing-button--active .geolibre-reset-bearing-needle-label {
  fill: hsl(var(--destructive));
}

.geolibre-reset-bearing-ctrl .geolibre-reset-bearing-button:disabled {
  cursor: default;
}

/* Maptoolkit logo control (Controls → Logos → Maptoolkit logo). The branding
   companion to Maptoolkit basemaps; mirrors MapLibre's own logo control. The
   wordmark is an inline SVG with its own brand colours, so it needs no theming —
   only sizing/placement. Maptoolkit's attribution terms require a minimum height
   of 24px, so the mark is pinned there. The container reuses `maplibregl-ctrl`
   for corner margins, so drop the control-group chrome to leave just the logo. */
.geolibre-maptoolkit-logo-ctrl {
  background: none;
  box-shadow: none;
}

.geolibre-maptoolkit-logo {
  display: block;
  opacity: 0.85;
  transition: opacity 150ms ease;
}

.geolibre-maptoolkit-logo:hover {
  opacity: 1;
}

.geolibre-maptoolkit-logo svg {
  display: block;
  height: 24px;
  width: auto;
}

/* maplibre-gl-layer-control toggle button icon color.
   The library (>=0.15.1) sizes the icon itself but leaves its color to the host
   theme (the SVG uses stroke="currentColor"). GeoLibre keeps map controls light
   in both light and dark mode, so pin the icon to a fixed dark color matching
   the other controls — otherwise it inherits the dark-mode text color and goes
   white-on-white over the white control background. */
.maplibregl-ctrl-layer-control .layer-control-icon {
  color: #1f2a37;
}

.geolibre-identify-popup .maplibregl-popup-content {
  background: hsl(var(--popover));
  border: 1px solid hsl(var(--border));
  box-shadow:
    0 10px 15px -3px rgb(0 0 0 / 0.18),
    0 4px 6px -4px rgb(0 0 0 / 0.18);
  color: hsl(var(--popover-foreground));
  max-height: calc(100vh - 96px);
  overflow: visible;
}

.geolibre-identify-popup-root {
  max-height: min(640px, calc(100vh - 128px));
  overflow: hidden;
}

.geolibre-identify-popup-rows {
  flex: 1 1 auto;
  min-height: 0;
  max-height: min(560px, calc(100vh - 184px));
  overflow-y: scroll;
  scrollbar-gutter: stable;
  scrollbar-width: thin;
}

.geolibre-kml-description table {
  width: 100%;
  border-collapse: collapse;
}

.geolibre-kml-description td,
.geolibre-kml-description th {
  border-top: 1px solid hsl(var(--border));
  padding: 0.25rem 0.375rem;
  text-align: start;
  vertical-align: top;
}

.geolibre-kml-description tr:nth-child(even) {
  background: hsl(var(--muted) / 0.55);
}

.geolibre-kml-description a {
  color: hsl(var(--primary));
  text-decoration: underline;
}

.geolibre-identify-popup .maplibregl-popup-close-button {
  color: hsl(var(--muted-foreground));
}

.geolibre-identify-popup .maplibregl-popup-close-button:hover {
  background: hsl(var(--accent));
  color: hsl(var(--accent-foreground));
}

.geolibre-identify-popup.maplibregl-popup-anchor-top .maplibregl-popup-tip,
.geolibre-identify-popup.maplibregl-popup-anchor-top-left .maplibregl-popup-tip,
.geolibre-identify-popup.maplibregl-popup-anchor-top-right .maplibregl-popup-tip {
  border-bottom-color: hsl(var(--popover));
}

.geolibre-identify-popup.maplibregl-popup-anchor-bottom .maplibregl-popup-tip,
.geolibre-identify-popup.maplibregl-popup-anchor-bottom-left .maplibregl-popup-tip,
.geolibre-identify-popup.maplibregl-popup-anchor-bottom-right .maplibregl-popup-tip {
  border-top-color: hsl(var(--popover));
}

@media (max-width: 767px) {
  .geolibre-components-control .maplibre-gl-control-grid-floating-panel,
  .geolibre-components-control .maplibre-gl-control-grid-relocated,
  .geolibre-pmtiles-control .maplibre-gl-pmtiles-layer-panel,
  .geolibre-zarr-control .maplibre-gl-zarr-layer-panel,
  .maplibregl-map .pc-control-panel,
  .maplibregl-map .layer-control-panel,
  .duckdb-control-panel {
    box-sizing: border-box;
    /* 96px clears the mobile top toolbar plus the panel's own top offset */
    max-height: calc(100vh - 96px) !important;
    max-height: calc(100dvh - 96px) !important;
    max-width: calc(100vw - 20px) !important;
    overflow-y: auto;
  }

  .duckdb-control-panel {
    left: 10px !important;
    right: auto !important;
    width: calc(100vw - 20px) !important;
  }

  .geolibre-identify-popup .maplibregl-popup-content {
    max-width: calc(100vw - 24px);
  }
}

@media (max-width: 639px) {
  /* On narrow screens the Layout submenu can be wider than the space Radix
     has between the trigger and the viewport edge. Shift it left by the
     shortfall (Radix reports it via the available-width variable) plus an
     8px edge buffer so the submenu stays fully visible. */
  .geolibre-layout-submenu {
    margin-left: max(0px, calc(100% - var(--radix-dropdown-menu-content-available-width) + 8px));
  }
}

.geolibre-identify-popup.maplibregl-popup-anchor-left .maplibregl-popup-tip {
  border-right-color: hsl(var(--popover));
}

.geolibre-identify-popup.maplibregl-popup-anchor-right .maplibregl-popup-tip {
  border-left-color: hsl(var(--popover));
}

/* The draggable photo-placement pin's hint popup (manual placement of a
   non-geotagged photo). Themed to match the app's popover surface. */
.geolibre-placement-popup-root .maplibregl-popup-content {
  background: hsl(var(--popover));
  border: 1px solid hsl(var(--border));
  border-radius: 0.5rem;
  box-shadow:
    0 10px 15px -3px rgb(0 0 0 / 0.18),
    0 4px 6px -4px rgb(0 0 0 / 0.18);
  color: hsl(var(--popover-foreground));
  padding: 0.625rem 0.75rem;
}

.geolibre-placement-popup-root.maplibregl-popup-anchor-top .maplibregl-popup-tip,
.geolibre-placement-popup-root.maplibregl-popup-anchor-top-left .maplibregl-popup-tip,
.geolibre-placement-popup-root.maplibregl-popup-anchor-top-right .maplibregl-popup-tip {
  border-bottom-color: hsl(var(--popover));
}

.geolibre-placement-popup-root.maplibregl-popup-anchor-bottom .maplibregl-popup-tip,
.geolibre-placement-popup-root.maplibregl-popup-anchor-bottom-left .maplibregl-popup-tip,
.geolibre-placement-popup-root.maplibregl-popup-anchor-bottom-right .maplibregl-popup-tip {
  border-top-color: hsl(var(--popover));
}

.geolibre-placement-popup-root.maplibregl-popup-anchor-left .maplibregl-popup-tip {
  border-right-color: hsl(var(--popover));
}

.geolibre-placement-popup-root.maplibregl-popup-anchor-right .maplibregl-popup-tip {
  border-left-color: hsl(var(--popover));
}

.geolibre-placement-popup {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  max-width: 13rem;
}

.geolibre-placement-popup-hint {
  margin: 0;
  font-size: 0.8125rem;
  line-height: 1.25rem;
  color: hsl(var(--popover-foreground));
}

.geolibre-placement-popup-done {
  align-self: flex-end;
  border-radius: 0.375rem;
  background: hsl(var(--primary));
  color: hsl(var(--primary-foreground));
  padding: 0.25rem 0.75rem;
  font-size: 0.8125rem;
  font-weight: 500;
  cursor: pointer;
}

.geolibre-placement-popup-done:hover {
  background: hsl(var(--primary) / 0.9);
}

/* Geotagged-photo popup: a resizable box whose photo scales to fill it, so the
   user can drag the corner to see more detail. */
.geolibre-photo-popup-root .maplibregl-popup-content {
  background: hsl(var(--popover));
  border: 1px solid hsl(var(--border));
  border-radius: 0.5rem;
  box-shadow:
    0 10px 15px -3px rgb(0 0 0 / 0.18),
    0 4px 6px -4px rgb(0 0 0 / 0.18);
  color: hsl(var(--popover-foreground));
  padding: 0.5rem;
}

.geolibre-photo-popup-root .maplibregl-popup-close-button {
  color: hsl(var(--muted-foreground));
  padding-right: 0.25rem;
}

.geolibre-photo-popup-root .maplibregl-popup-close-button:hover {
  background: transparent;
  color: hsl(var(--popover-foreground));
}

.geolibre-photo-popup-root.maplibregl-popup-anchor-top .maplibregl-popup-tip,
.geolibre-photo-popup-root.maplibregl-popup-anchor-top-left .maplibregl-popup-tip,
.geolibre-photo-popup-root.maplibregl-popup-anchor-top-right .maplibregl-popup-tip {
  border-bottom-color: hsl(var(--popover));
}

.geolibre-photo-popup-root.maplibregl-popup-anchor-bottom .maplibregl-popup-tip,
.geolibre-photo-popup-root.maplibregl-popup-anchor-bottom-left .maplibregl-popup-tip,
.geolibre-photo-popup-root.maplibregl-popup-anchor-bottom-right .maplibregl-popup-tip {
  border-top-color: hsl(var(--popover));
}

.geolibre-photo-popup-root.maplibregl-popup-anchor-left .maplibregl-popup-tip {
  border-right-color: hsl(var(--popover));
}

.geolibre-photo-popup-root.maplibregl-popup-anchor-right .maplibregl-popup-tip {
  border-left-color: hsl(var(--popover));
}

.geolibre-photo-popup {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
  /* The initial box; the user can drag it larger (or smaller) from here. */
  width: 260px;
  height: 220px;
  min-width: 160px;
  min-height: 140px;
  max-width: min(85vw, 900px);
  max-height: 85vh;
  resize: both;
  overflow: hidden;
}

.geolibre-photo-popup-img {
  flex: 1 1 auto;
  /* Without min-height: 0 a flex child refuses to shrink below its image's
     intrinsic height, which would break vertical resizing. */
  min-height: 0;
  width: 100%;
  object-fit: contain;
  border-radius: 0.375rem;
  background: hsl(var(--muted));
  cursor: zoom-in;
}

/* Fullscreen lightbox opened by double-clicking the photo popup's image. */
.geolibre-photo-fullscreen {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgb(0 0 0 / 0.92);
}

.geolibre-photo-fullscreen-img {
  max-width: 100vw;
  max-height: 100vh;
  object-fit: contain;
  /* Honor the source's EXIF orientation when showing the original bytes so a
     portrait photo isn't displayed sideways. */
  image-orientation: from-image;
  transform-origin: center center;
  cursor: zoom-in;
  /* Wheel/double-click zoom animates; panning drags update transform live. */
  transition: transform 0.12s ease-out;
  touch-action: none;
  will-change: transform;
}

/* Once magnified past the fit, the cursor invites panning. */
.geolibre-photo-fullscreen-img.is-zoomed {
  cursor: grab;
  /* Panning should track the pointer with no lag, so drop the zoom transition. */
  transition: none;
}

.geolibre-photo-fullscreen-img.is-zoomed:active {
  cursor: grabbing;
}

/* Badge reporting the current zoom as a percentage of native resolution plus
   the source pixel dimensions. */
.geolibre-photo-fullscreen-badge {
  position: fixed;
  bottom: 0.75rem;
  left: 50%;
  transform: translateX(-50%);
  padding: 0.25rem 0.625rem;
  border-radius: 9999px;
  background: rgb(0 0 0 / 0.6);
  color: #fff;
  font-size: 0.75rem;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  pointer-events: none;
  user-select: none;
}

.geolibre-photo-fullscreen-badge:empty {
  display: none;
}

.geolibre-photo-fullscreen-close {
  position: fixed;
  top: 0.75rem;
  right: 1rem;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 9999px;
  background: rgb(255 255 255 / 0.12);
  color: #fff;
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
}

.geolibre-photo-fullscreen-close:hover {
  background: rgb(255 255 255 / 0.24);
}

.geolibre-photo-popup-placeholder {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 0.375rem;
  background: hsl(var(--muted));
  color: hsl(var(--muted-foreground));
  font-size: 0.8125rem;
}

.geolibre-photo-popup-caption {
  flex: 0 0 auto;
  overflow: hidden;
  font-size: 0.75rem;
  line-height: 1rem;
  white-space: nowrap;
  text-overflow: ellipsis;
  color: hsl(var(--popover-foreground));
}

.swipe-control-panel .swipe-control-select {
  height: 28px;
  line-height: 28px;
  min-height: 0;
  padding-bottom: 0;
  padding-top: 0;
}

/* No panel max-height override here on purpose. Up to
   maplibre-gl-planetary-computer 0.3.0 the library pinned an inline
   max-height of 500px that overflowed short windows, so GeoLibre clamped the
   panel to the map height with !important. Since 0.4.0 the panel is
   resizable and content-fit: it sets max-height itself from the live map rect
   (mapRect.height - offset - margin) whenever it repositions, and drops the
   cap to "none" while a resize handle is being dragged. Re-adding a static
   !important cap here would pin the panel to that height and break both --
   see the 0.4.0 bump in PR #1344. */

.dark .pc-control-toggle {
  background: hsl(var(--popover));
  color: hsl(var(--popover-foreground));
}

.dark .pc-control-toggle:hover {
  background: hsl(var(--muted));
}

.dark .pc-control-icon svg {
  fill: none;
  stroke: hsl(var(--popover-foreground));
}

.dark .pc-control-panel {
  background: hsl(var(--popover));
  border: 1px solid hsl(var(--border));
  box-shadow: 0 12px 32px rgb(0 0 0 / 0.45);
  color: hsl(var(--popover-foreground));
}

.dark .pc-control-header,
.dark .pc-control-nav {
  background: hsl(var(--muted));
  border-color: hsl(var(--border));
}

.dark .pc-control-title,
.dark .pc-collection-title,
.dark .pc-result-title,
.dark .pc-details-title,
.dark .pc-section-title,
.dark .pc-meta-item .pc-value,
.dark .pc-stats-grid > div > strong,
.dark .pc-point-values > div > strong,
.dark .pc-stats-title,
.dark .pc-legend-title,
.dark .pc-tilejson-card > div > strong,
.dark .pc-layer-name,
.dark .pc-inspector-title,
.dark .pc-opacity-value,
.dark .pc-cloud-value,
.dark .pc-advanced-render summary,
.dark .pc-checkbox-group label,
.dark .pc-asset-name {
  color: hsl(var(--popover-foreground));
}

.dark .pc-control-close,
.dark .pc-nav-btn,
.dark .pc-loading,
.dark .pc-collection-description,
.dark .pc-label,
.dark .pc-bbox-text,
.dark .pc-date-separator,
.dark .pc-results-count,
.dark .pc-results-empty,
.dark .pc-result-date,
.dark .pc-result-cloud,
.dark .pc-asset-type,
.dark .pc-stats-grid > div > span,
.dark .pc-point-values > div > span,
.dark .pc-legend-labels,
.dark .pc-tilejson-card > div > span,
.dark .pc-layers-empty,
.dark .pc-inspector-hint,
.dark .pc-inspector-coords,
.dark .pc-opacity-label,
.dark .pc-rescale-separator {
  color: hsl(var(--muted-foreground));
}

.dark .pc-control-close:hover,
.dark .pc-btn-icon:hover {
  background: hsl(var(--accent));
  color: hsl(var(--accent-foreground));
}

.dark .pc-search-box,
.dark .pc-selected-collection,
.dark .pc-bbox-display,
.dark .pc-details-meta,
.dark .pc-asset-item,
.dark .pc-tool-loading,
.dark .pc-custom-viz,
.dark .pc-point-json,
.dark .pc-result-thumbnail {
  background: hsl(var(--muted));
}

.dark .pc-collection-item,
.dark .pc-result-item,
.dark .pc-stats-card,
.dark .pc-legend-card,
.dark .pc-tilejson-card,
.dark .pc-layer-item,
.dark .pc-inspector-panel,
.dark .pc-custom-viz {
  border-color: hsl(var(--border));
}

.dark .pc-collection-item:hover,
.dark .pc-result-item:hover {
  background: hsl(var(--accent));
  border-color: hsl(var(--ring));
}

.dark .pc-result-selected,
.dark .pc-result-selected:hover {
  background: hsl(var(--accent));
  border-color: #f59e0b;
}

.dark .pc-tag,
.dark .pc-btn-active,
.dark .pc-layer-controls-active {
  background: rgb(14 116 144 / 0.22);
  color: #67e8f9;
}

.dark .pc-search-input,
.dark .pc-input {
  background: hsl(var(--background));
  border-color: hsl(var(--border));
  color: hsl(var(--foreground));
}

.dark .pc-search-input::placeholder,
.dark .pc-input::placeholder {
  color: hsl(var(--muted-foreground));
}

.dark .pc-search-input:focus,
.dark .pc-input:focus {
  border-color: hsl(var(--ring));
  box-shadow: inset 0 0 0 1px hsl(var(--ring));
}

.dark .pc-btn,
.dark .pc-nav-btn {
  background: hsl(var(--background));
  border-color: hsl(var(--border));
  color: hsl(var(--foreground));
}

.dark .pc-btn:hover,
.dark .pc-nav-btn:hover {
  background: hsl(var(--accent));
}

.dark .pc-btn:disabled:hover {
  background: hsl(var(--background));
}

.dark .pc-btn-primary,
.dark .pc-nav-btn.active,
.dark .pc-search-btn-loading,
.dark .pc-search-btn-loading:disabled,
.dark .pc-search-btn-loading:disabled:hover,
.dark .pc-inspect-active,
.dark .pc-inspect-active:hover {
  background: #0891b2;
  border-color: #0891b2;
  color: #ecfeff;
}

.dark .pc-btn-back {
  color: #67e8f9;
}

.dark .pc-error,
.dark .pc-tool-error {
  background: rgb(127 29 29 / 0.35);
  color: #fecaca;
}

.dark .pc-tool-success {
  background: rgb(20 83 45 / 0.35);
  color: #bbf7d0;
}

.dark .pc-spinner {
  border-color: hsl(var(--border));
  border-top-color: #67e8f9;
}

.dark .pc-control-content::-webkit-scrollbar-track {
  background: hsl(var(--muted));
}

.dark .pc-control-content::-webkit-scrollbar-thumb {
  background: hsl(var(--border));
}

/* Basemaps plugin (maplibre-gl-basemap-control) — the package ships a
   hard-coded light theme with `color-scheme: light`, so map its own classes
   onto the app design tokens when the app is in dark mode. Scoped to the
   package's own root/child classes, mirroring the STAC `.pc-control-*` block
   above. Never edit the package's stylesheet in node_modules. */
.dark .basemap-control {
  background: hsl(var(--popover));
  color: hsl(var(--popover-foreground));
  color-scheme: dark;
  box-shadow: 0 0 0 2px rgb(0 0 0 / 0.4);
}

.dark .basemap-control-toggle {
  color: hsl(var(--popover-foreground));
}

.dark .basemap-control-toggle:hover {
  background-color: hsl(var(--muted));
}

.dark .basemap-control-icon svg {
  stroke: hsl(var(--popover-foreground));
}

.dark .basemap-control-panel {
  background: hsl(var(--popover));
  color: hsl(var(--popover-foreground));
  box-shadow:
    0 8px 28px rgb(0 0 0 / 0.55),
    0 0 0 1px hsl(var(--border));
}

.dark .basemap-control-header {
  border-bottom-color: hsl(var(--border));
}

.dark .basemap-control-title,
.dark .basemap-control-result-name,
.dark .basemap-control-settings-heading,
.dark .basemap-control-multiple-toggle {
  color: hsl(var(--popover-foreground));
}

.dark .basemap-control-settings-toggle,
.dark .basemap-control-close,
.dark .basemap-control-status,
.dark .basemap-control-empty,
.dark .basemap-control-result-meta,
.dark .basemap-control-result-attribution,
.dark .basemap-control-settings-intro,
.dark .basemap-control-provider-group-label {
  color: hsl(var(--muted-foreground));
}

.dark .basemap-control-settings-toggle:hover,
.dark .basemap-control-close:hover {
  color: hsl(var(--popover-foreground));
  background: hsl(var(--accent));
}

.dark .basemap-control-settings-toggle.is-active {
  color: hsl(var(--accent-foreground));
  background: hsl(var(--accent));
}

.dark .basemap-control-status.is-error {
  color: hsl(var(--destructive));
}

.dark .basemap-control-input,
.dark .basemap-control-select,
.dark .basemap-control-settings-back {
  background: hsl(var(--background));
  border-color: hsl(var(--border));
  color: hsl(var(--foreground));
  color-scheme: dark;
}

.dark .basemap-control-input::placeholder {
  color: hsl(var(--muted-foreground));
}

.dark .basemap-control-select option {
  background: hsl(var(--popover));
  color: hsl(var(--popover-foreground));
}

.dark .basemap-control-input:focus,
.dark .basemap-control-select:focus {
  border-color: hsl(var(--ring));
  box-shadow: 0 0 0 3px hsl(var(--ring) / 0.3);
}

.dark .basemap-control-multiple-checkbox {
  accent-color: hsl(var(--ring));
}

.dark .basemap-control-result {
  background: hsl(var(--muted));
  border-color: hsl(var(--border));
  color: hsl(var(--popover-foreground));
}

.dark .basemap-control-result:hover {
  border-color: hsl(var(--ring));
  background: hsl(var(--accent));
}

.dark .basemap-control-result.is-active {
  border-color: hsl(var(--ring));
  background: hsl(var(--accent));
}

.dark .basemap-control-result-type {
  background: hsl(var(--accent));
  color: hsl(var(--accent-foreground));
}

.dark .basemap-control-settings-back:hover {
  border-color: hsl(var(--ring));
  background: hsl(var(--accent));
}

.dark .basemap-control-status-link {
  color: hsl(var(--popover-foreground));
}

.dark .basemap-control-results::-webkit-scrollbar-thumb {
  background: hsl(var(--border));
}

.dark .basemap-control-resize-handle::after {
  border-color: hsl(var(--border));
}

.dark .basemap-control-resize-handle:hover::after {
  border-color: hsl(var(--muted-foreground));
}

.geolibre-earth-engine-control .plugin-control-toggle {
  align-items: center;
  display: flex;
  justify-content: center;
}

.geolibre-earth-engine-control .plugin-control-icon {
  align-items: center;
  display: flex;
  height: 100%;
  justify-content: center;
  width: 100%;
}

/* The repeated class outranks the upstream stylesheet's scoped variable
   blocks (.plugin-control-panel.earth-engine-panel and its dark variants)
   so the app-token remap below keeps winning after the 0.4.2 selector
   scoping. */
.geolibre-earth-engine-panel.geolibre-earth-engine-panel.geolibre-earth-engine-panel {
  --ee-panel-bg: hsl(var(--popover));
  --ee-panel-elevated: hsl(var(--card));
  --ee-panel-muted: hsl(var(--muted));
  --ee-panel-text: hsl(var(--popover-foreground));
  --ee-panel-subtle: hsl(var(--muted-foreground));
  --ee-panel-placeholder: hsl(var(--muted-foreground));
  --ee-panel-border: hsl(var(--border));
  --ee-panel-border-strong: hsl(var(--input));
  --ee-input-bg: hsl(var(--background));
  --ee-input-text: hsl(var(--foreground));
  --ee-item-bg: hsl(var(--card));
  --ee-active-bg: hsl(var(--accent));
  --ee-active-border: hsl(var(--ring));
  --ee-button-primary: hsl(var(--primary));
  --ee-button-muted: hsl(var(--muted-foreground));
  --ee-button-danger: hsl(var(--destructive));
  --ee-shadow: 0 16px 40px hsl(var(--foreground) / 0.16);
  --geolibre-ee-panel-left: 10px;

  color-scheme: light;
  left: var(--geolibre-ee-panel-left) !important;
  max-width: calc(100% - var(--geolibre-ee-panel-left) * 2);
}

.dark .geolibre-earth-engine-panel.geolibre-earth-engine-panel.geolibre-earth-engine-panel {
  --ee-shadow: 0 16px 40px hsl(0 0% 0% / 0.4);

  color-scheme: dark;
}

.geolibre-earth-engine-panel .plugin-control-input:focus,
.geolibre-earth-engine-panel .plugin-control-input:focus-visible {
  border-color: hsl(var(--ring));
  box-shadow: inset 0 0 0 1px hsl(var(--ring));
  outline: none;
}

/* maplibre-gl-raster themes its panel from prefers-color-scheme (the OS
   setting), while GeoLibre themes from the .dark class on <html>. All of
   the panel's colors flow through --mlr-* custom properties, so remapping
   them onto the app theme tokens keeps the panel in sync with the in-app
   light/dark toggle. The doubled selectors outrank the upstream
   prefers-color-scheme block regardless of stylesheet order. */
.mlr-control.geolibre-raster-control,
.mlr-control-panel.geolibre-raster-panel {
  --mlr-bg: hsl(var(--popover));
  --mlr-surface-muted: hsl(var(--muted));
  --mlr-surface-soft: hsl(var(--card));
  --mlr-text: hsl(var(--popover-foreground));
  --mlr-text-strong: hsl(var(--foreground));
  --mlr-text-soft: hsl(var(--popover-foreground) / 0.8);
  --mlr-text-muted: hsl(var(--muted-foreground));
  --mlr-text-faint: hsl(var(--muted-foreground) / 0.75);
  --mlr-border: hsl(var(--border));
  --mlr-border-soft: hsl(var(--border) / 0.8);
  --mlr-border-faint: hsl(var(--border) / 0.6);
  --mlr-border-strong: hsl(var(--input));
  --mlr-accent: hsl(var(--primary));
  --mlr-accent-strong: hsl(var(--primary) / 0.85);
  --mlr-accent-soft: hsl(var(--primary) / 0.12);
  --mlr-hover: hsl(var(--foreground) / 0.06);
  --mlr-error: hsl(var(--destructive));
  --mlr-disabled-bg: hsl(var(--muted));
  --mlr-disabled-text: hsl(var(--muted-foreground) / 0.5);
  --mlr-scrollbar: hsl(var(--border));
  --mlr-scrollbar-hover: hsl(var(--input));
  --mlr-shadow: hsl(var(--foreground) / 0.12);
  --mlr-histogram-neutral: hsl(var(--foreground));

  color-scheme: light;
}

.dark .mlr-control.geolibre-raster-control,
.dark .mlr-control-panel.geolibre-raster-panel {
  --mlr-shadow: hsl(0 0% 0% / 0.4);

  color-scheme: dark;
}

/* maplibre-gl-vector themes its panel from prefers-color-scheme (the OS
   setting), while GeoLibre themes from the .dark class on <html>. All of
   the panel's colors flow through --vc-* custom properties, so remapping
   them onto the app theme tokens keeps the panel in sync with the in-app
   light/dark toggle, following the raster panel pattern above. The doubled
   selectors outrank the upstream prefers-color-scheme block regardless of
   stylesheet order. The attribute picker popup is themed through the same
   variables; it mounts in MapLibre's popup container without a hook for a
   custom class, so it is keyed off html:not(.dark)/.dark instead. The
   multi-layer picker modal mounts straight into the map container (so it
   stays visible while the panel is hidden), which has no custom-class hook
   either, so it is keyed the same way. */
.vector-control.geolibre-vector-control,
.vector-control-panel.geolibre-vector-panel,
html:not(.dark) .vector-control-popup,
html:not(.dark) .vector-control-layer-picker,
.dark .vector-control-popup,
.dark .vector-control-layer-picker {
  --vc-bg: hsl(var(--popover));
  --vc-text: hsl(var(--popover-foreground));
  --vc-text-strong: hsl(var(--foreground));
  --vc-text-soft: hsl(var(--popover-foreground) / 0.8);
  --vc-muted: hsl(var(--muted-foreground));
  --vc-border: hsl(var(--border));
  --vc-border-soft: hsl(var(--border) / 0.8);
  --vc-item-bg: hsl(var(--card));
  --vc-hover: hsl(var(--foreground) / 0.06);
  --vc-accent: hsl(var(--primary));
  --vc-accent-hover: hsl(var(--primary) / 0.85);
  --vc-accent-soft: hsl(var(--primary) / 0.12);
  --vc-accent-text: hsl(var(--primary-foreground));
  --vc-error: hsl(var(--destructive));
  --vc-input-bg: hsl(var(--popover));
  --vc-input-border: hsl(var(--input));
  --vc-scrollbar: hsl(var(--border));
  --vc-scrollbar-hover: hsl(var(--input));
  --vc-shadow: 0 0 0 2px hsl(var(--foreground) / 0.12);

  color-scheme: light;
}

.dark .vector-control.geolibre-vector-control,
.dark .vector-control-panel.geolibre-vector-panel,
.dark .vector-control-popup,
.dark .vector-control-layer-picker {
  --vc-shadow: 0 0 0 2px hsl(0 0% 0% / 0.4);

  color-scheme: dark;
}

/* The panel content scrolls vertically (overflow-y: auto), which forces
   overflow-x to clip and cuts off the Load button's offset focus ring on
   the right edge. Give the scroll area a little horizontal breathing room
   so the ring is not clipped. */
.vector-control-panel.geolibre-vector-panel .vector-control-content {
  padding-inline: 5px;
}

/* The upstream stylesheet themes the MapLibre popup chrome around the
   picker popup from prefers-color-scheme; re-key it to the app theme. The
   html prefixes also outrank the upstream :has() rules when the OS scheme
   and the app theme disagree. */
html:not(.dark) .maplibregl-popup:has(.vector-control-popup) .maplibregl-popup-content {
  background: hsl(var(--popover));
  box-shadow: 0 1px 6px hsl(var(--foreground) / 0.25);
}

html.dark .maplibregl-popup:has(.vector-control-popup) .maplibregl-popup-content {
  background: hsl(var(--popover));
  box-shadow: 0 1px 6px hsl(0 0% 0% / 0.5);
}

html:not(.dark) .maplibregl-popup:has(.vector-control-popup) .maplibregl-popup-close-button,
html.dark .maplibregl-popup:has(.vector-control-popup) .maplibregl-popup-close-button {
  color: hsl(var(--muted-foreground));
}

html:not(.dark) .maplibregl-popup-anchor-top:has(.vector-control-popup) .maplibregl-popup-tip,
html:not(.dark) .maplibregl-popup-anchor-top-left:has(.vector-control-popup) .maplibregl-popup-tip,
html:not(.dark) .maplibregl-popup-anchor-top-right:has(.vector-control-popup) .maplibregl-popup-tip,
html.dark .maplibregl-popup-anchor-top:has(.vector-control-popup) .maplibregl-popup-tip,
html.dark .maplibregl-popup-anchor-top-left:has(.vector-control-popup) .maplibregl-popup-tip,
html.dark .maplibregl-popup-anchor-top-right:has(.vector-control-popup) .maplibregl-popup-tip {
  border-bottom-color: hsl(var(--popover));
}

html:not(.dark) .maplibregl-popup-anchor-bottom:has(.vector-control-popup) .maplibregl-popup-tip,
html:not(.dark)
  .maplibregl-popup-anchor-bottom-left:has(.vector-control-popup)
  .maplibregl-popup-tip,
html:not(.dark)
  .maplibregl-popup-anchor-bottom-right:has(.vector-control-popup)
  .maplibregl-popup-tip,
html.dark .maplibregl-popup-anchor-bottom:has(.vector-control-popup) .maplibregl-popup-tip,
html.dark .maplibregl-popup-anchor-bottom-left:has(.vector-control-popup) .maplibregl-popup-tip,
html.dark .maplibregl-popup-anchor-bottom-right:has(.vector-control-popup) .maplibregl-popup-tip {
  border-top-color: hsl(var(--popover));
}

html:not(.dark) .maplibregl-popup-anchor-left:has(.vector-control-popup) .maplibregl-popup-tip,
html.dark .maplibregl-popup-anchor-left:has(.vector-control-popup) .maplibregl-popup-tip {
  border-right-color: hsl(var(--popover));
}

html:not(.dark) .maplibregl-popup-anchor-right:has(.vector-control-popup) .maplibregl-popup-tip,
html.dark .maplibregl-popup-anchor-right:has(.vector-control-popup) .maplibregl-popup-tip {
  border-left-color: hsl(var(--popover));
}

/* The Web Services controls (FEMA NFHL, NASA Earthdata, US EPA EnviroAtlas,
   USGS National Map) theme themselves from prefers-color-scheme (the OS
   setting), while GeoLibre themes from the .dark class on <html>. Each
   package's colors flow through its own custom properties, so remapping
   them onto the app theme tokens keeps the panels in sync with the in-app
   light/dark toggle, following the raster/vector panel pattern above. The
   panels mount in the map container without the configured control class,
   so the selectors key off the package classes; the repeated classes
   outrank the upstream prefers-color-scheme and .dark-ancestor blocks
   regardless of stylesheet order.

   FEMA and NASA share the generic .plugin-control/.plugin-control-panel
   template classes (as does Earth Engine), and their stylesheets style
   those classes unscoped, so whichever sheet loads last paints every
   panel in the family with its own variables (NASA's
   `background: var(--ne-bg, #fff)` repaints the FEMA panel white, for
   example). Defining both token families on all family elements makes
   the cascade winner irrelevant: every variable resolves to the same
   app token. */
.plugin-control.plugin-control.plugin-control.plugin-control.plugin-control,
.plugin-control-panel.plugin-control-panel.plugin-control-panel.plugin-control-panel.plugin-control-panel,
.fema-wms-popup.fema-wms-popup.fema-wms-popup.fema-wms-popup.fema-wms-popup {
  --fw-bg: hsl(var(--popover));
  --fw-fg: hsl(var(--popover-foreground));
  --fw-muted: hsl(var(--muted-foreground));
  --fw-border: hsl(var(--border));
  --fw-accent: hsl(var(--primary));
  --fw-accent-hover: hsl(var(--primary) / 0.85);
  --fw-accent-contrast: hsl(var(--primary-foreground));
  --fw-input-bg: hsl(var(--popover));
  --fw-input-border: hsl(var(--input));
  --fw-row-hover: hsl(var(--foreground) / 0.06);
  --fw-shadow: 0 0 0 2px hsl(var(--foreground) / 0.12);
  --fw-scroll-thumb: hsl(var(--border));
  --fw-scroll-thumb-hover: hsl(var(--input));
  --fw-error: hsl(var(--destructive));
  --fw-legend-bg: hsl(var(--card));
  --ne-bg: hsl(var(--popover));
  --ne-fg: hsl(var(--popover-foreground));
  --ne-fg-muted: hsl(var(--muted-foreground));
  --ne-border: hsl(var(--border));
  --ne-input-border: hsl(var(--input));
  --ne-input-bg: hsl(var(--popover));
  --ne-accent: hsl(var(--primary));
  --ne-accent-hover: hsl(var(--primary) / 0.85);
  --ne-accent-fg: hsl(var(--primary-foreground));
  --ne-danger: hsl(var(--destructive));
  --ne-danger-hover: hsl(var(--destructive) / 0.85);
  --ne-hover: hsl(var(--foreground) / 0.06);
  --ne-row-bg: hsl(var(--card));
  --ne-badge-bg: hsl(var(--muted));
  --ne-badge-fg: hsl(var(--muted-foreground));
  --ne-scrollbar: hsl(var(--border));
  --ne-scrollbar-hover: hsl(var(--input));
  --ne-shadow: hsl(var(--foreground) / 0.12);

  color-scheme: light;
}

.dark .plugin-control.plugin-control.plugin-control.plugin-control.plugin-control,
.dark
  .plugin-control-panel.plugin-control-panel.plugin-control-panel.plugin-control-panel.plugin-control-panel,
.dark .fema-wms-popup.fema-wms-popup.fema-wms-popup.fema-wms-popup.fema-wms-popup {
  --fw-shadow: 0 0 0 2px hsl(0 0% 0% / 0.45);
  --ne-shadow: hsl(0 0% 0% / 0.4);

  color-scheme: dark;
}

.enviroatlas-control.enviroatlas-control.enviroatlas-control,
.enviroatlas-panel.enviroatlas-panel.enviroatlas-panel {
  --ea-bg: hsl(var(--popover));
  --ea-fg: hsl(var(--popover-foreground));
  --ea-muted: hsl(var(--muted-foreground));
  --ea-border: hsl(var(--border));
  --ea-accent: hsl(var(--primary));
  --ea-accent-fg: hsl(var(--primary-foreground));
  --ea-hover: hsl(var(--foreground) / 0.06);
  --ea-input-bg: hsl(var(--popover));
  --ea-scrollbar: hsl(var(--border));
  --ea-scrollbar-hover: hsl(var(--input));
  --ea-shadow: hsl(var(--foreground) / 0.12);
  --ea-error: hsl(var(--destructive));
  --ea-notice-bg: hsl(var(--muted));

  color-scheme: light;
}

.dark .enviroatlas-control.enviroatlas-control.enviroatlas-control,
.dark .enviroatlas-panel.enviroatlas-panel.enviroatlas-panel {
  --ea-shadow: hsl(0 0% 0% / 0.45);

  color-scheme: dark;
}

.national-map.national-map.national-map,
.national-map-panel.national-map-panel.national-map-panel {
  --nm-bg: hsl(var(--popover));
  --nm-fg: hsl(var(--popover-foreground));
  --nm-fg-strong: hsl(var(--foreground));
  --nm-muted: hsl(var(--muted-foreground));
  --nm-border: hsl(var(--border));
  --nm-input-border: hsl(var(--input));
  --nm-accent: hsl(var(--primary));
  --nm-accent-hover: hsl(var(--primary) / 0.85);
  --nm-accent-ring: hsl(var(--primary) / 0.15);
  --nm-row-hover: hsl(var(--foreground) / 0.06);
  --nm-btn-hover: hsl(var(--foreground) / 0.06);
  --nm-shadow: 0 0 0 2px hsl(var(--foreground) / 0.12);
  --nm-scroll-thumb: hsl(var(--border));
  --nm-scroll-thumb-hover: hsl(var(--input));
  --nm-disabled: hsl(var(--muted));
  --nm-disabled-fg: hsl(var(--muted-foreground));

  color-scheme: light;
}

.dark .national-map.national-map.national-map,
.dark .national-map-panel.national-map-panel.national-map-panel {
  --nm-shadow: 0 0 0 2px hsl(0 0% 0% / 0.5);

  color-scheme: dark;
}

/* maplibre-gl-overture-maps themes its control, panel, and inspect popup
   from prefers-color-scheme (the OS theme): in `auto` mode it stamps a hard
   `ovt-theme-light`/`ovt-theme-dark` class on the elements from the system
   preference, so a light OS keeps the panel light even when the app is in
   dark mode. Remapping the upstream `--ovt-*` tokens to the app theme tokens
   keys the control to the app's light/dark toggle instead. The repeated
   classes outrank the upstream `.overture-control.ovt-theme-*` and
   prefers-color-scheme blocks regardless of stylesheet order. */
.overture-control.overture-control.overture-control,
.overture-control-panel.overture-control-panel.overture-control-panel,
.overture-popup-content.overture-popup-content.overture-popup-content {
  --ovt-bg: hsl(var(--popover));
  --ovt-fg: hsl(var(--popover-foreground));
  --ovt-text: hsl(var(--popover-foreground));
  --ovt-muted: hsl(var(--muted-foreground));
  --ovt-border: hsl(var(--border));
  --ovt-input-border: hsl(var(--input));
  --ovt-input-bg: hsl(var(--popover));
  --ovt-hover: hsl(var(--foreground) / 0.06);
  --ovt-accent: hsl(var(--primary));
  --ovt-scrollbar: hsl(var(--border));
  --ovt-scrollbar-hover: hsl(var(--input));
  --ovt-error-bg: hsl(var(--destructive) / 0.15);
  --ovt-error-fg: hsl(var(--destructive));

  color-scheme: light;
}

.dark .overture-control.overture-control.overture-control,
.dark .overture-control-panel.overture-control-panel.overture-control-panel,
.dark .overture-popup-content.overture-popup-content.overture-popup-content {
  color-scheme: dark;
}

/* Map-only fullscreen (opengeos/GeoLibre#611).
 *
 * The map Fullscreen control maximizes the map canvas (requestFullscreen on the
 * map container). Chromium pulls that element into the browser top layer, so the
 * workspace chrome is hidden automatically. WebKit (the Tauri desktop webview)
 * does not, leaving the toolbar and side panels painted around and on top of the
 * map. DesktopShell mirrors the fullscreen state onto the shell as
 * `data-map-fullscreen`; collapse everything except the map so the canvas owns
 * the whole window on every engine.
 *
 * The shell is `flex flex-col`: its direct children are the toolbar, the
 * workspace row (Layers + map + Style), the attribute table, and the status bar.
 * Hide all of them except the row, then within the row hide everything except
 * the `<main>` map landmark, which flexes to fill. */
[data-map-fullscreen] > *:not([data-workspace-row]) {
  display: none !important;
}

[data-map-fullscreen] [data-workspace-row] > *:not(main) {
  display: none !important;
}

/* Sample-data dropdowns in the Add Data panels (3D Tiles, LiDAR, DuckDB,
   FlatGeobuf, PMTiles, Zarr, Splatting). The upstream packages style these classes with
   their own light / prefers-color-scheme colors, which do not match
   GeoLibre's class-based theming (the app forces color-scheme: light), so map
   them onto the app's design tokens here so the dropdown follows the panel. */
:is(
  .duckdb-sample-trigger,
  .three-d-tiles-sample-trigger,
  .maplibre-gl-sample-trigger,
  .splat-sample-trigger,
  .lidar-sample-trigger
) {
  background-color: hsl(var(--background)) !important;
  border-color: hsl(var(--input)) !important;
  color: hsl(var(--muted-foreground)) !important;
}

:is(
  .duckdb-sample-trigger,
  .three-d-tiles-sample-trigger,
  .maplibre-gl-sample-trigger,
  .splat-sample-trigger,
  .lidar-sample-trigger
):is(:hover, .open, :focus-visible, :active) {
  border-color: hsl(var(--ring)) !important;
}

:is(
  .duckdb-sample-menu,
  .three-d-tiles-sample-menu,
  .maplibre-gl-sample-menu,
  .splat-sample-menu,
  .lidar-sample-menu
) {
  background-color: hsl(var(--popover)) !important;
  border-color: hsl(var(--border)) !important;
}

:is(
  .duckdb-sample-option,
  .three-d-tiles-sample-option,
  .maplibre-gl-sample-option,
  .splat-sample-option,
  .lidar-sample-option
) {
  color: hsl(var(--popover-foreground)) !important;
}

:is(
  .duckdb-sample-option,
  .three-d-tiles-sample-option,
  .maplibre-gl-sample-option,
  .splat-sample-option,
  .lidar-sample-option
):is(:hover, :focus-visible, :active) {
  background-color: hsl(var(--accent)) !important;
  color: hsl(var(--accent-foreground)) !important;
}

/*
 * GeoEditor control (maplibre-gl-geo-editor). The component stylesheet
 * hardcodes light-theme colors (#fff surfaces, #333 text, #e5e5e5 borders)
 * with no theme hooks, so the toolbar, dialogs, and attribute panel stay
 * light when the app is in dark mode. Remap every neutral surface, text, and
 * border color onto the app's design tokens (which switch with the `.dark`
 * class on <html>) so the control tracks the in-app theme. The blue
 * active-tool/primary color (#3388ff) is left as upstream ships it — it is
 * legible on both themes. index.css is imported after the component
 * stylesheet, so these same-specificity rules win the cascade.
 */
.geo-editor-toolbar {
  background: hsl(var(--background));
  box-shadow: 0 0 0 2px hsl(var(--border));
}

.geo-editor-tool-group:not(:last-child) {
  border-bottom-color: hsl(var(--border));
}

.geo-editor-toolbar--horizontal .geo-editor-tool-group:not(:last-child) {
  border-right-color: hsl(var(--border));
}

.geo-editor-tool-group-label {
  color: hsl(var(--muted-foreground));
}

/* Inside the ctrl-group, MapLibre's `.maplibregl-ctrl button` (higher
   specificity than the component's `.geo-editor-tool-button`) already forces
   a transparent button background, so only the icon color needs remapping.
   MapLibre's hover tint (rgba(0,0,0,.05)) is invisible on a dark toolbar, so
   out-specificity it with a token-based highlight. */
.geo-editor-tool-button {
  color: hsl(var(--foreground));
}

.geo-editor-control button.geo-editor-tool-button:not(:disabled):hover {
  background-color: hsl(var(--accent));
  color: hsl(var(--accent-foreground));
}

/* Dialogs (save/open/clear confirmations). */
.geo-editor-dialog {
  background: hsl(var(--popover));
  color: hsl(var(--popover-foreground));
}

.geo-editor-dialog-header,
.geo-editor-dialog-footer {
  border-color: hsl(var(--border));
}

.geo-editor-dialog-title,
.geo-editor-label {
  color: hsl(var(--foreground));
}

.geo-editor-dialog-close {
  color: hsl(var(--muted-foreground));
}

.geo-editor-dialog-close:hover {
  background: hsl(var(--accent));
  color: hsl(var(--accent-foreground));
}

/* Text inputs, selects, and textareas default to the UA's light chrome. */
.geo-editor-input,
.geo-editor-rotate-popup-input,
.geo-editor-rotate-popup-select,
.geo-editor-attribute-input,
.geo-editor-attribute-select,
.geo-editor-attribute-textarea {
  background: hsl(var(--background));
  border-color: hsl(var(--border));
  color: hsl(var(--foreground));
}

.geo-editor-attribute-input:disabled,
.geo-editor-attribute-select:disabled,
.geo-editor-attribute-textarea:disabled {
  background-color: hsl(var(--muted));
  color: hsl(var(--muted-foreground));
}

.geo-editor-slider {
  background: hsl(var(--muted));
}

.geo-editor-btn--secondary,
.geo-editor-rotate-popup-cancel {
  background: hsl(var(--secondary));
  border-color: hsl(var(--border));
  color: hsl(var(--secondary-foreground));
}

.geo-editor-btn--secondary:hover,
.geo-editor-rotate-popup-cancel:hover {
  background: hsl(var(--accent));
  color: hsl(var(--accent-foreground));
}

.geo-editor-stats {
  background: hsl(var(--muted));
}

.geo-editor-stat-value {
  color: hsl(var(--foreground));
}

.geo-editor-stat-label {
  color: hsl(var(--muted-foreground));
}

/* Feature-properties and numeric-rotation popups rendered on the map. Their
   content sits in MapLibre's always-white `.maplibregl-popup-content`, so the
   popup surface (and its anchor tip) must be themed along with the text —
   otherwise the token-mapped text goes light-on-white in dark mode. Mirrors
   the `.geolibre-identify-popup` treatment above. */
.geo-editor-properties-popup .maplibregl-popup-content,
.geo-editor-rotate-popup .maplibregl-popup-content {
  background: hsl(var(--popover));
  border: 1px solid hsl(var(--border));
  color: hsl(var(--popover-foreground));
}

.geo-editor-properties-popup .maplibregl-popup-close-button,
.geo-editor-rotate-popup .maplibregl-popup-close-button {
  color: hsl(var(--muted-foreground));
}

:is(.geo-editor-properties-popup, .geo-editor-rotate-popup):is(
    .maplibregl-popup-anchor-top,
    .maplibregl-popup-anchor-top-left,
    .maplibregl-popup-anchor-top-right
  )
  .maplibregl-popup-tip {
  border-bottom-color: hsl(var(--popover));
}

:is(.geo-editor-properties-popup, .geo-editor-rotate-popup):is(
    .maplibregl-popup-anchor-bottom,
    .maplibregl-popup-anchor-bottom-left,
    .maplibregl-popup-anchor-bottom-right
  )
  .maplibregl-popup-tip {
  border-top-color: hsl(var(--popover));
}

:is(.geo-editor-properties-popup, .geo-editor-rotate-popup).maplibregl-popup-anchor-left
  .maplibregl-popup-tip {
  border-right-color: hsl(var(--popover));
}

:is(.geo-editor-properties-popup, .geo-editor-rotate-popup).maplibregl-popup-anchor-right
  .maplibregl-popup-tip {
  border-left-color: hsl(var(--popover));
}

.geo-editor-popup-table td {
  border-bottom-color: hsl(var(--border));
}

.geo-editor-popup-key,
.geo-editor-rotate-popup-title {
  color: hsl(var(--foreground));
}

.geo-editor-popup-value,
.geo-editor-popup-empty,
.geo-editor-rotate-popup-row span {
  color: hsl(var(--muted-foreground));
}

/* Attribute editing panel. */
.geo-editor-attribute-panel {
  background: hsl(var(--popover));
  color: hsl(var(--popover-foreground));
}

.geo-editor-attribute-panel-header,
.geo-editor-attribute-panel-footer {
  background: hsl(var(--muted));
  border-color: hsl(var(--border));
}

.geo-editor-attribute-panel-title,
.geo-editor-attribute-label,
.geo-editor-attribute-checkbox-label {
  color: hsl(var(--foreground));
}

.geo-editor-attribute-panel-close {
  color: hsl(var(--muted-foreground));
}

.geo-editor-attribute-panel-close:hover {
  background: hsl(var(--accent));
  color: hsl(var(--accent-foreground));
}

.geo-editor-attribute-readonly {
  background-color: hsl(var(--muted));
  border-color: hsl(var(--border));
  color: hsl(var(--muted-foreground));
}

.geo-editor-attribute-readonly-null,
.geo-editor-attribute-empty {
  color: hsl(var(--muted-foreground));
}

.geo-editor-attribute-extra-section {
  border-top-color: hsl(var(--border));
}

.geo-editor-attribute-extra-section-title {
  color: hsl(var(--muted-foreground));
}

/* Native widgets (date pickers, selects, checkboxes) follow the app theme,
   not the OS, inside GeoEditor surfaces. */
.geo-editor-control,
.geo-editor-dialog,
.geo-editor-attribute-panel,
.geo-editor-rotate-popup-form {
  color-scheme: light;
}

.dark .geo-editor-control,
.dark .geo-editor-dialog,
.dark .geo-editor-attribute-panel,
.dark .geo-editor-rotate-popup-form {
  color-scheme: dark;
}

/* The pastel info/warning/error/success fills would glare on dark surfaces;
   swap them for translucent tints of the same hues. */
.dark .geo-editor-message--info,
.dark .geo-editor-attribute-geometry-badge {
  background: rgba(51, 136, 255, 0.15);
  border-color: rgba(51, 136, 255, 0.4);
  color: #9cc7ff;
}

.dark .geo-editor-message--warning {
  background: rgba(255, 193, 7, 0.12);
  border-color: rgba(255, 193, 7, 0.35);
  color: #ffd75e;
}

.dark .geo-editor-message--error {
  background: rgba(220, 53, 69, 0.15);
  border-color: rgba(220, 53, 69, 0.4);
  color: #f1919c;
}

.dark .geo-editor-message--success {
  background: rgba(40, 167, 69, 0.15);
  border-color: rgba(40, 167, 69, 0.4);
  color: #7fd493;
}

/* ---------------------------------------------------------------------------
 * Elevation Profile plugin (packages/plugins/.../elevation-profile).
 *
 * Ported in-house from the external plugin, whose styles shipped in their own
 * bundle; built-in plugins do not import CSS, so the control's styles live here
 * instead. The tokens resolve to GeoLibre's design tokens (--background,
 * --foreground, ...) which already switch with the `.dark` class, so the panel
 * background/text/borders follow the in-app toggle automatically. The `.dark`
 * block below mirrors the plugin's `prefers-color-scheme: dark` values for the
 * few decorative tokens that are not derived from a switching design token
 * (shadow, accent-text, area fill, hover tint), so those track the in-app
 * toggle rather than the OS preference (see the note near line 909).
 * ------------------------------------------------------------------------- */
.elevation-profile,
.elevation-profile-panel {
  --ep-bg: hsl(var(--background, 0 0% 100%));
  --ep-shadow: 0 0 0 2px rgba(0, 0, 0, 0.1);
  --ep-text: hsl(var(--foreground, 222 47% 11%));
  --ep-muted: hsl(var(--muted-foreground, 220 9% 46%));
  --ep-border: hsl(var(--border, 220 13% 91%));
  --ep-hover-bg: hsl(var(--foreground, 222 47% 11%) / 0.06);
  --ep-surface: hsl(var(--secondary, 220 14% 96%));
  --ep-accent: #f97316;
  --ep-accent-text: #fff;
  --ep-area: rgba(249, 115, 22, 0.18);
}

.dark .elevation-profile,
.dark .elevation-profile-panel {
  --ep-shadow: 0 0 0 2px rgba(0, 0, 0, 0.4);
  --ep-hover-bg: hsl(var(--foreground, 210 20% 92%) / 0.1);
  --ep-accent-text: #1f2937;
  --ep-area: rgba(249, 115, 22, 0.22);
}

/* Container / toggle button */
.maplibregl-ctrl-group.elevation-profile {
  background: var(--ep-bg);
  border-radius: 4px;
  box-shadow: var(--ep-shadow);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}

/* Scoped under the container class so these win over GeoLibre's own
   `.maplibregl-ctrl-group button` rules (which otherwise offset the icon). */
.elevation-profile .elevation-profile-toggle {
  box-sizing: border-box;
  width: 29px;
  height: 29px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: none;
  padding: 0;
  margin: 0;
  cursor: pointer;
  color: var(--ep-text);
}

.elevation-profile .elevation-profile-toggle:hover {
  background: var(--ep-hover-bg);
}

.elevation-profile .elevation-profile-toggle svg {
  display: block;
  width: 20px;
  height: 20px;
}

/* Floating panel. Resizable in every dock: it is always positioned by its
   top-left corner (see _updatePanelPosition), so the bottom-right resize handle
   grows it down and to the right consistently. */
.elevation-profile-panel {
  position: absolute;
  display: none;
  flex-direction: column;
  box-sizing: border-box;
  background: var(--ep-bg);
  color: var(--ep-text);
  border-radius: 6px;
  box-shadow: var(--ep-shadow);
  padding: 10px;
  z-index: 1000;
  font-size: 12px;
  line-height: 1.4;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  overflow: auto;
  resize: both;
  min-width: 260px;
  min-height: 170px;
  max-width: 90vw;
  max-height: 85vh;
}

.elevation-profile-panel.expanded {
  display: flex;
}

/* Right-docked panels: render the resize grip in the bottom-left corner (so it
   grows toward the map interior) by flipping the panel to RTL, then restore the
   content's natural left-to-right flow on its children. */
.elevation-profile-panel--anchor-right {
  direction: rtl;
}

.elevation-profile-panel--anchor-right > * {
  direction: ltr;
}

.elevation-profile-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding-bottom: 8px;
  margin-bottom: 8px;
  border-bottom: 1px solid var(--ep-border);
}

.elevation-profile-title {
  font-size: 13px;
  font-weight: 600;
}

.elevation-profile-close {
  width: 20px;
  height: 20px;
  border: none;
  background: transparent;
  color: var(--ep-muted);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  padding: 0;
}

.elevation-profile-close:hover {
  color: var(--ep-text);
}

/* Actions */
.elevation-profile-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.elevation-profile-button {
  flex: 0 0 auto;
  padding: 6px 12px;
  font-size: 12px;
  font-weight: 500;
  color: var(--ep-text);
  background: var(--ep-surface);
  border: 1px solid var(--ep-border);
  border-radius: 4px;
  cursor: pointer;
  transition:
    background-color 0.15s,
    border-color 0.15s;
}

.elevation-profile-button:hover:not(:disabled) {
  border-color: var(--ep-accent);
}

.elevation-profile-button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.elevation-profile-primary,
.elevation-profile-button.is-active {
  color: var(--ep-accent-text);
  background: var(--ep-accent);
  border-color: var(--ep-accent);
}

.elevation-profile-unit {
  margin-left: auto;
}

/* Status line */
.elevation-profile-status {
  margin-top: 8px;
  font-size: 11px;
  color: var(--ep-muted);
  overflow-wrap: break-word;
}

.elevation-profile-status:empty {
  display: none;
}

/* Stats grid */
.elevation-profile-stats {
  display: none;
  grid-template-columns: repeat(5, 1fr);
  gap: 4px;
  margin-top: 10px;
}

.elevation-profile-stats.has-data {
  display: grid;
}

.elevation-profile-stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 4px 2px;
  background: var(--ep-surface);
  border-radius: 4px;
}

.elevation-profile-stat-value {
  font-size: 12px;
  font-weight: 600;
  color: var(--ep-text);
}

.elevation-profile-stat-label {
  font-size: 9px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--ep-muted);
}

/* Chart. Flex-grows so a taller panel produces a taller chart. Its display is
   toggled from JS (hidden when there is no profile) rather than via :empty, so
   the host keeps a measurable width while the chart is being (re)drawn. */
.elevation-profile-chart {
  margin-top: 10px;
  flex: 1 1 auto;
  min-height: 130px;
}

.elevation-profile-svg {
  display: block;
  width: 100%;
  height: 100%;
  cursor: crosshair;
  background: var(--ep-surface);
  border-radius: 4px;
}

.elevation-profile-area {
  fill: var(--ep-area);
  stroke: none;
}

.elevation-profile-line {
  fill: none;
  stroke: var(--ep-accent);
  stroke-width: 1.75;
  vector-effect: non-scaling-stroke;
}

.elevation-profile-axis {
  fill: var(--ep-muted);
  font-size: 9px;
}

.elevation-profile-hover-line {
  stroke: var(--ep-muted);
  stroke-width: 1;
  stroke-dasharray: 3 2;
  vector-effect: non-scaling-stroke;
}

.elevation-profile-hover-dot {
  fill: var(--ep-accent);
  stroke: #fff;
  stroke-width: 1.5;
}

/* Hover readout */
.elevation-profile-readout {
  margin-top: 6px;
  text-align: center;
  font-size: 11px;
  font-weight: 500;
  color: var(--ep-text);
  min-height: 14px;
}

.elevation-profile-readout:empty {
  visibility: hidden;
}

/* Export row (shown only when a profile exists; toggled to flex from JS) */
.elevation-profile-export {
  display: none;
  align-items: center;
  gap: 6px;
  margin-top: 8px;
}

.elevation-profile-export-label {
  font-size: 11px;
  color: var(--ep-muted);
}

.elevation-profile-button-sm {
  padding: 4px 10px;
  font-size: 11px;
}

/* ---------------------------------------------------------------------------
 * Vertical sidebar labels: CJK scripts (zh, ja, ko) read upright in
 * writing-mode: vertical-rl, so the 180deg rotation used for Latin scripts
 * would make them upside-down.  The :lang() pseudo-class handles regional
 * variants (zh-TW, zh-CN, etc.) natively.  The rule matches the same `md:`
 * breakpoint that Tailwind generates md:rotate-180 at.
 *
 * Upright CJK glyphs also stack tightly, so the small `tracking-wide`
 * letter-spacing meant for rotated Latin text leaves them touching (e.g.
 * 图层 reads as one block).  In vertical-rl, letter-spacing runs down the
 * inline axis, so a larger value opens up the gap between stacked glyphs.
 * ------------------------------------------------------------------------- */
@media (min-width: 768px) {
  :lang(zh) .md\:rotate-180,
  :lang(ja) .md\:rotate-180,
  :lang(ko) .md\:rotate-180 {
    rotate: 0deg;
    letter-spacing: 0.15em;
  }
}

/* ---------------------------------------------------------------------------
 * On-map Legend panel (MapLegendPanel): maplibre-gl-components.css forces
 * black text on EVERY form field inside a MapLibre control
 * (`.maplibregl-ctrl input … { color: #000 !important }`), which makes the
 * panel's edit-mode inputs unreadable in dark theme. The panel is
 * theme-aware, so re-assert the theme colors with higher specificity.
 * ------------------------------------------------------------------------- */
.geolibre-legend-panel.maplibregl-ctrl input,
.geolibre-legend-panel.maplibregl-ctrl select,
.geolibre-legend-panel.maplibregl-ctrl textarea {
  color: hsl(var(--foreground)) !important;
}

.geolibre-legend-panel.maplibregl-ctrl input::placeholder,
.geolibre-legend-panel.maplibregl-ctrl textarea::placeholder {
  color: hsl(var(--muted-foreground)) !important;
}
