/* ============================================================
   HydroBassin Tunisie — UI v2
   Design system : Manrope, dark/light, bleu-cyan premium
   ============================================================ */

/* ------------------------------------------------------------------ Variables */

/* ============================================================
   VERROU PUBLIC
   ------------------------------------------------------------
   Posé par le script en tête d'`index.html` sur `/login`,
   `/register` et `/pending` — les trois chemins servis avec la
   coquille de l'application parce qu'elle porte la modale.

   `visibility` et non `display` : on ne veut RIEN afficher, mais
   sans démonter la mise en page, que la modale suppose présente.
   La règle porte sur `body` et se rétablit sur la modale seule,
   ce qui la rend indifférente à l'ajout d'un futur panneau —
   celui-ci naîtra caché, plutôt qu'oublié dans une liste.

   Ce masquage n'est PAS la sécurité : elle est côté serveur, où
   `/app` exige une session et où toute route métier répond 401.
   Il empêche seulement qu'une coquille inerte soit prise pour un
   accès.
   ============================================================ */
.hb-verrou-public body { visibility: hidden; }
.hb-verrou-public #auth-modal-backdrop,
.hb-verrou-public #auth-modal-backdrop * { visibility: visible; }
/* Fond OPAQUE : le voile translucide laisserait deviner l'interface
   par transparence, ce qui reviendrait à la montrer à demi. */
.hb-verrou-public #auth-modal-backdrop {
  background: var(--bg-deep-2);
}


:root {
  /* Palette sombre (défaut) — navy profond, accents cyan/bleu */
  --bg-deep:        #0c1c2e;
  --bg-deep-2:      #07111e;
  --bg-deep-3:      #050d17;

  --panel-bg:       rgba(12, 26, 44, 0.92);
  --panel-border:   rgba(86, 158, 214, 0.16);
  --panel-border-m: rgba(86, 158, 214, 0.26);

  --sidebar-bg:     rgba(8, 18, 30, 0.82);
  --sidebar-border: rgba(86, 158, 214, 0.17);

  --cyan:  #33c7e6;
  --blue:  #2f7af0;
  --blue2: #2161d8;
  --teal:  #16a9c6;
  --green: #37d896;
  --amber: #fbbf24;
  --red:   #f87171;

  --text:       #d6e8f5;
  --text-2:     #e2eef8;
  --text-muted: #8cafc8;
  --text-dim:   #6d8ea6;

  --card-bg:    rgba(14, 30, 50, 0.60);
  --card-bg-2:  rgba(14, 30, 50, 0.40);
  --input-bg:   rgba(8, 18, 30, 0.78);

  --radius:     12px;
  --radius-sm:  9px;

  /* Couleurs des couches cartographiques — synchronisées avec constants.js */
  --map-stream:      #22d3ee;
  --map-watershed:   #3b82f6;
  --map-outlet:      #f87171;
  --map-outlet-test: #9aa8b8;
  --map-admin:       #7e92a6;
}

[data-theme="light"] {
  --bg-deep:        #eff3f8;
  --bg-deep-2:      #e5ecf3;
  --bg-deep-3:      #dae3ed;

  --panel-bg:       rgba(255, 255, 255, 0.97);
  --panel-border:   rgba(34, 62, 98, 0.11);
  --panel-border-m: rgba(34, 62, 98, 0.19);

  --sidebar-bg:     rgba(255, 255, 255, 0.97);
  --sidebar-border: rgba(34, 62, 98, 0.12);

  --text:       #1a3349;
  --text-2:     #0f2337;
  --text-muted: #4a6278;
  --text-dim:   #7a92a8;

  --card-bg:    rgba(248, 252, 255, 0.95);
  --card-bg-2:  rgba(243, 248, 253, 0.95);
  --input-bg:   rgba(238, 245, 252, 0.97);
}

/* ---- Light mode — overrides pour éléments avec valeurs codées en dur ---- */
[data-theme="light"] body {
  background: radial-gradient(120% 90% at 50% -10%, #eff3f8 0%, #e5ecf3 55%, #dae3ed 100%);
}

[data-theme="light"] .app-header {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(240, 245, 252, 0.96));
}

[data-theme="light"] .chart-wrap {
  background: rgba(234, 243, 252, 0.72);
}
[data-theme="light"] .chart-empty {
  background: rgba(234, 243, 252, 0.88);
  color: #6a8299;
}

[data-theme="light"] .sidebar-legend {
  background: rgba(241, 246, 252, 0.60);
  border-color: rgba(47, 122, 240, 0.14);
}

[data-theme="light"] .leaflet-control-attribution {
  background: rgba(255, 255, 255, 0.92) !important;
  color: #7a92a8 !important;
}
[data-theme="light"] .leaflet-control-attribution a { color: var(--blue) !important; }
/* Zoom Leaflet en thème clair : même conteneur/boutons que .map-tools
   (spécification harmonisée, cf. section « Contrôles de carte »). */
[data-theme="light"] .leaflet-control-zoom.leaflet-bar {
  background: rgba(255, 255, 255, 0.95);
  border-color: rgba(47, 122, 240, 0.20);
  box-shadow: 0 4px 18px rgba(0, 0, 0, 0.12);
}
[data-theme="light"] .leaflet-control-zoom.leaflet-bar a {
  background: none;
  border-color: transparent;
  color: #4a6278;
}
[data-theme="light"] .leaflet-control-zoom.leaflet-bar a:hover {
  background: rgba(47, 122, 240, 0.08);
  border-color: rgba(47, 122, 240, 0.28);
  color: var(--blue);
}

[data-theme="light"] .btn-import {
  background: rgba(241, 246, 252, 0.95);
  border-color: rgba(47, 122, 240, 0.22);
}

/* .btn-icon-sq (bouton thème du header) : le cyan brut tombe sous 3:1 de
   contraste sur fond quasi-blanc. Même substitution cyan→blue déjà utilisée
   pour .fscale-bar et .btn-reset-link en thème clair. */
[data-theme="light"] .btn-icon-sq { color: var(--blue); }


[data-theme="light"] .error-banner {
  background: rgba(220, 38, 38, 0.07);
  border-bottom-color: rgba(220, 38, 38, 0.22);
  color: #991b1b;
}
[data-theme="light"] .error-banner button { color: #991b1b; }

/* ------------------------------------------------------------------ Reset */
*, *::before, *::after { box-sizing: border-box; }

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

body {
  font-family: 'Manrope', system-ui, -apple-system, sans-serif;
  font-size: 13px;
  color: var(--text);
  background: radial-gradient(120% 90% at 50% -10%, var(--bg-deep) 0%, var(--bg-deep-2) 55%, var(--bg-deep-3) 100%);
  -webkit-font-smoothing: antialiased;
  font-feature-settings: 'tnum' 1;
  transition: background 0.3s ease, color 0.3s ease;
}

button, input, select, textarea {
  font-family: inherit;
  font-size: inherit;
}

#app-root {
  display: flex;
  flex-direction: column;
  height: 100vh;
  overflow: hidden;
}

/* ------------------------------------------------------------------ Scrollbar */
.hb-scroll::-webkit-scrollbar { width: 6px; }
.hb-scroll::-webkit-scrollbar-track { background: transparent; }
.hb-scroll::-webkit-scrollbar-thumb {
  background: rgba(90, 150, 200, 0.18);
  border-radius: 6px;
}
.hb-scroll:hover::-webkit-scrollbar-thumb { background: rgba(90, 150, 200, 0.32); }

/* ================================================================ HEADER */
.app-header {
  height: 72px;
  flex: 0 0 72px;
  display: flex;
  align-items: center;
  gap: 20px;
  padding: 0 22px;
  background: linear-gradient(180deg, var(--panel-bg), rgba(8, 17, 28, 0.80));
  border-bottom: 1px solid var(--panel-border);
  position: relative;
  z-index: 20;
  backdrop-filter: blur(14px);
  transition: background 0.3s ease;
}

/* Logo + titre */
.hdr-brand {
  display: flex;
  align-items: center;
  gap: 13px;
  flex-shrink: 0;
  min-width: 0;
}

.logo-mark {
  width: 44px; height: 44px;
  border-radius: 12px;
  background: linear-gradient(150deg, #1f6fd6, #16b6d8);
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
  box-shadow: 0 6px 20px -6px rgba(28, 150, 210, 0.65),
              inset 0 1px 0 rgba(255, 255, 255, 0.22);
}

.hdr-title-group { line-height: 1.15; min-width: 0; }

/* Conteneur flex : le texte du titre et le badge de version sont deux éléments
   distincts, ce qui permet de tronquer le PREMIER sans jamais rogner le
   second (cf. css/responsive.css). Le gap porte à lui seul l'espacement après
   « Tunisie » — pas de marge sur le badge, qui ferait double emploi. */
.title-main {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 20px;
  font-weight: 800;
  letter-spacing: -0.3px;
  color: var(--text-2);
  white-space: nowrap;
}
/* min-width: 0 est INDISPENSABLE : sans lui, la taille minimale automatique
   d'un élément flex vaut son contenu intrinsèque, et un texte en
   `white-space: nowrap` refuserait de se comprimer — l'ellipse ne se
   déclencherait jamais et le débordement irait manger le badge. */
.title-text { min-width: 0; }
.title-cyan { color: var(--cyan); }

/* Badge de version bêta. Premier usage « couleur pleine » de --amber, jusqu'ici
   réservé (cf. DESIGN.md). Compact et secondaire : il annonce un état du
   produit, il ne concurrence pas le titre. */
.beta-badge {
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
  padding: 3px 7px;
  border: 1px solid rgba(251, 191, 36, 0.42);
  border-radius: 999px;
  background: rgba(245, 158, 11, 0.13);
  color: var(--amber);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  line-height: 1;
  white-space: nowrap;
}
/* --amber (#fbbf24) n'est pas redéfini en thème clair et tombe sous le seuil
   de contraste sur un en-tête blanc. Même substitution que cyan -> blue
   appliquée ailleurs pour les mêmes raisons (cf. .btn-icon-sq, .modal-badge). */
[data-theme="light"] .beta-badge {
  color: #b45309;
  border-color: rgba(180, 83, 9, 0.42);
  background: rgba(245, 158, 11, 0.16);
}
.title-sub {
  font-size: 10.5px;
  color: var(--text-muted);
  margin-top: 3px;
  font-weight: 500;
  white-space: nowrap;
}

/* Centre */
.hdr-center {
  flex: 1;
  display: flex;
  justify-content: center;
}

/* La pastille d'en-tête annonçant le moteur de délimitation (.engine-status,
   .status-dot, @keyframes status-blink) a été retirée de l'interface : ses
   règles n'avaient plus d'usage. .hdr-center subsiste, vide, comme unique
   élément d'espacement flexible entre la marque et les actions. */

/* Actions droite */
.hdr-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}

.hdr-sep {
  width: 1px; height: 28px;
  background: var(--panel-border-m);
  margin: 0 3px;
}

/* ================================================================ EXPORT SIG (Lot 4) */
.sig-export { position: relative; }

.sig-export-menu {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  min-width: 190px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 6px;
  background: var(--panel-bg);
  border: 1px solid var(--panel-border-m);
  border-radius: 10px;
  box-shadow: 0 12px 28px -8px rgba(0, 0, 0, 0.35);
  z-index: 30;
}
.sig-export-menu[hidden] { display: none; }

.sig-export-item {
  display: flex;
  align-items: center;
  width: 100%;
  border: none;
  background: none;
  color: var(--text);
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 600;
  text-align: left;
  padding: 8px 10px;
  border-radius: 7px;
  cursor: pointer;
}
.sig-export-item:hover { background: var(--card-bg-2); color: var(--cyan); }
[data-theme="light"] .sig-export-item:hover { color: var(--blue); }

/* Contenu réservé aux lecteurs d'écran (ex. détail de progression d'analyse) :
   jamais affiché visuellement, jamais dans le libellé d'un bouton. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ================================================================ BUTTONS */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  border: none;
  cursor: pointer;
  font-family: inherit;
  font-size: 13px;
  font-weight: 700;
  border-radius: 11px;
  padding: 0 16px;
  height: 42px;
  white-space: nowrap;
  /* Sans effet sur un <button> (jamais souligné) — nécessaire pour que .btn
     appliqué à un <a> (ex. "Nous contacter", lien mailto: natif) rende
     identiquement à un bouton. */
  text-decoration: none;
  color: inherit;
  transition: background 0.18s, border-color 0.18s, opacity 0.18s, transform 0.15s, box-shadow 0.18s;
}
.btn:disabled { opacity: 0.42; cursor: not-allowed; transform: none !important; }
.btn svg { flex-shrink: 0; }
.btn[hidden] { display: none; }
/* [hidden] seul ne suffit pas sur <svg> (spécificité/UA) — sans cette règle
   les deux icônes du bouton thème (lune/soleil) restaient visibles ensemble. */
svg[hidden] { display: none; }

/* Anneau de focus clavier — vocabulaire cyan déjà établi (.coord-input:focus,
   .btn-reset-link:focus-visible). Scopé au header pour ne pas affecter les
   boutons .btn de la sidebar/du panneau résultats qui partagent la classe. */
.app-header .btn:focus-visible {
  outline: none;
  border-color: rgba(51, 199, 230, 0.55);
  box-shadow: 0 0 0 3px rgba(51, 199, 230, 0.10);
}

.btn-blue {
  background: linear-gradient(180deg, var(--blue), var(--blue2));
  color: #fff;
  border: 1px solid rgba(60, 140, 235, 0.55);
  box-shadow: 0 6px 18px -8px rgba(47, 122, 240, 0.85);
}
.btn-blue:hover:not(:disabled) {
  transform: translateY(-1px);
  box-shadow: 0 8px 22px -6px rgba(47, 122, 240, 0.9);
}

.btn-teal {
  background: linear-gradient(180deg, var(--teal), #0d8ba8);
  color: #fff;
  border: 1px solid rgba(30, 180, 205, 0.5);
  box-shadow: 0 6px 18px -8px rgba(22, 169, 198, 0.85);
}
.btn-teal:hover:not(:disabled) {
  transform: translateY(-1px);
  box-shadow: 0 8px 22px -6px rgba(22, 169, 198, 0.9);
}

.btn-ghost {
  background: var(--card-bg-2);
  color: var(--text-2);
  border: 1px solid var(--panel-border-m);
}
.btn-ghost:hover:not(:disabled) {
  background: rgba(86, 158, 214, 0.12);
  border-color: rgba(86, 158, 214, 0.28);
}

.btn-primary {
  background: linear-gradient(180deg, #3d88f5, var(--blue2));
  color: #fff;
  border: 1px solid rgba(60, 140, 235, 0.55);
  box-shadow: 0 8px 22px -8px rgba(47, 122, 240, 0.85), inset 0 1px 0 rgba(255, 255, 255, 0.12);
  height: 48px;
  font-size: 14px;
  font-weight: 800;
  letter-spacing: -0.2px;
}
.btn-primary:hover:not(:disabled) {
  transform: translateY(-1px);
  box-shadow: 0 10px 26px -6px rgba(47, 122, 240, 0.92), inset 0 1px 0 rgba(255, 255, 255, 0.16);
}

.btn-block {
  width: 100%;
  justify-content: center;
}

/* Spinner de traitement du bouton principal d'analyse : remplace l'icône
   flèche à l'identique (même emplacement, mêmes dimensions 15x15) pour ne
   provoquer aucun décalage de largeur/alignement — cf. correctif "Analyse en
   cours" qui déformait le bouton. */
.btn-spinner { animation: btn-spinner-rotate 0.8s linear infinite; transform-origin: 50% 50%; }
@keyframes btn-spinner-rotate { to { transform: rotate(360deg); } }

.btn-icon-sq {
  width: 40px; height: 40px;
  padding: 0;
  border-radius: 11px;
  background: var(--card-bg-2);
  color: var(--cyan);
  border: 1px solid var(--panel-border-m);
  display: flex; align-items: center; justify-content: center;
  transition: border-color 0.2s, box-shadow 0.2s, background 0.2s;
}
.btn-icon-sq:hover {
  border-color: rgba(51, 199, 230, 0.5);
  box-shadow: 0 0 0 3px rgba(51, 199, 230, 0.12);
}

.flex-1 { flex: 1; }

/* ================================================================ ERROR BANNER */
.error-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 20px;
  background: rgba(248, 113, 113, 0.12);
  border-bottom: 1px solid rgba(248, 113, 113, 0.30);
  color: #ffd9d6;
  font-size: 13px;
  font-weight: 500;
  flex-shrink: 0;
}
.error-banner[hidden] { display: none; }
.error-banner button {
  background: none; border: none;
  font-size: 20px; line-height: 1;
  color: #ffd9d6; cursor: pointer; padding: 0 4px;
}

/* ================================================================ LAYOUT BODY */
.app-body {
  display: flex;
  flex: 1;
  min-height: 0;
  gap: 8px;
  padding: 8px;
  overflow: hidden;
}

/* ================================================================ LEFT SIDEBAR */
.sidebar-left {
  display: flex;
  flex-direction: column;
  /* Élargi depuis l'arrivée de l'onglet « Mes analyses » : à 296 px, les noms
     d'analyses et la ligne « Exutoire : 36,16029 · 9,35005 » étaient tronqués.
     Seuil mesuré de non-troncature : 320 px. Cette largeur de base ne vaut
     qu'au-delà de 1800 px, où la carte a de la marge ; en dessous, les paliers
     de la section RESPONSIVE la resserrent progressivement pour que la carte
     reste la zone dominante sur un écran de portable. */
  width: 372px;
  flex-shrink: 0;
  background: var(--sidebar-bg);
  border: 1px solid var(--sidebar-border);
  border-radius: 16px;
  backdrop-filter: blur(14px);
  overflow: hidden;
  transition: background 0.3s ease;
}

/* Tab bar */
.stab-bar {
  display: flex;
  padding: 6px 6px 0;
  gap: 4px;
  border-bottom: 1px solid var(--panel-border);
  flex-shrink: 0;
}

.stab {
  flex: 1;
  /* Trois onglets au lieu de deux depuis l'arrivée de « Mes analyses » : à
     13,5 px et 6 px de marge, ce libellé passait sur deux lignes et déséquilibrait
     la barre, seul de son espèce. Corps et marges resserrés d'un cran pour que
     les trois tiennent sur une ligne à la largeur de sidebar la plus étroite.
     `.stab` n'habille que ces trois boutons : le panneau droit utilise `.rtab`. */
  padding: 12px 4px 11px;
  font-size: 12.5px;
  white-space: nowrap;
  font-weight: 700;
  color: var(--text-dim);
  background: none;
  border: none;
  cursor: pointer;
  position: relative;
  text-align: center;
  border-radius: 9px 9px 0 0;
  transition: color 0.18s;
  font-family: inherit;
}
.stab:hover { color: var(--text); }
.stab.is-active {
  color: var(--text-2);
}
.stab.is-active::after {
  content: '';
  position: absolute;
  left: 16%; right: 16%;
  bottom: -1px;
  height: 2.5px;
  border-radius: 2px;
  background: var(--cyan);
  box-shadow: 0 0 10px var(--cyan);
}

/* Tab panels */
.stab-panel {
  flex: 1;
  overflow-y: auto;
  padding: 16px 14px 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-height: 0;
}
.stab-panel[hidden] { display: none; }

/* Layer list */
.layer-list {
  display: flex;
  flex-direction: column;
  gap: 7px;
}

.layer-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 11px;
  border-radius: 11px;
  border: 1px solid var(--panel-border);
  background: var(--card-bg-2);
  transition: border-color 0.18s, background 0.18s;
}
.layer-item.is-active {
  border-color: rgba(86, 158, 214, 0.22);
  background: rgba(86, 158, 214, 0.07);
}

.layer-avail {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--cyan);
  flex-shrink: 0;
  box-shadow: 0 0 5px rgba(51, 199, 230, 0.6);
}

.layer-icon {
  width: 32px; height: 32px;
  border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}

.layer-info { flex: 1; min-width: 0; }
.layer-name {
  font-size: 12px;
  font-weight: 700;
  color: var(--text-2);
  line-height: 1.2;
}
.layer-desc {
  font-size: 10px;
  color: var(--text-dim);
  line-height: 1.35;
  margin-top: 2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.layer-check {
  width: 16px; height: 16px;
  flex-shrink: 0;
  accent-color: var(--cyan);
  cursor: pointer;
}

/* Import button */
.btn-import {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 13px 14px;
  margin-top: 4px;
  border-radius: 12px;
  border: 1.5px dashed rgba(51, 199, 230, 0.28);
  background: rgba(13, 28, 46, 0.3);
  color: var(--text-muted);
  font-family: inherit;
  cursor: not-allowed;
  opacity: 0.7;
  text-align: left;
}
.import-label { font-size: 12.5px; font-weight: 700; color: var(--text-2); }
.import-desc  { font-size: 10px; color: var(--text-dim); margin-top: 1px; }

/* ================================================================ GUIDE
   Onglet "Guide" (remplace l'ancien onglet "Sources"). Deux vues dans le
   même panneau, jamais de popup/modale : #guide-home (carte "Premiers pas")
   et #guide-steps (contenu détaillé). Piloté par webapp/js/guide.js. */

/* "Premiers pas" est désormais une carte compacte au même modèle que FAQ et
   Besoin d'aide (.guide-mini-card, plus bas) — plus de structure CSS dédiée
   et volumineuse : seule la variante "métadonnée" (5 étapes · environ 2 min)
   est propre à cette carte, cf. .guide-mini-card-meta. */

/* -------- Vue détaillée par étapes -------- */

/* "Retour au Guide" — élément propre au Guide (ne réutilise pas
   .btn-reset-link, partagée avec "Réinitialiser le point" ailleurs dans
   l'app) : alignement à gauche assumé (pas de centrage), zone cliquable
   généreuse, contraste plus soutenu qu'un simple lien discret, sans devenir
   un bouton principal. */
.guide-back-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 10px 7px 8px;
  margin: 0 0 2px -8px;
  background: none;
  border: none;
  border-radius: 8px;
  color: var(--text-muted);
  font-size: 12.5px;
  font-weight: 700;
  font-family: inherit;
  cursor: pointer;
  transition: color 0.15s, background 0.15s;
}
.guide-back-btn:hover { color: var(--text-2); background: rgba(86, 158, 214, 0.10); }
.guide-back-btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(51, 199, 230, 0.20);
}
[data-theme="light"] .guide-back-btn { color: #4a6278; }
[data-theme="light"] .guide-back-btn:hover { color: var(--blue); background: rgba(47, 122, 240, 0.08); }
[data-theme="light"] .guide-back-btn:focus-visible { box-shadow: 0 0 0 3px rgba(47, 122, 240, 0.22); }

.guide-steps-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-top: 10px;
}
.guide-step-count {
  font-size: 11px;
  font-weight: 700;
  color: var(--text-dim);
  white-space: nowrap;
}

/* Indicateur de progression à 5 étapes — même vocabulaire visuel que
   .phase-indicator (pastille numérotée + segment de liaison), décliné pour
   le Guide. Le numéro reste toujours affiché (jamais uniquement une couleur
   qui porterait seule le sens de la progression). */
.guide-progress {
  display: flex;
  align-items: flex-start;
  margin: 10px 0 8px;
  padding: 0;
  list-style: none;
}
.guide-progress-step {
  position: relative;
  flex: 1;
  display: flex;
  justify-content: center;
}
.guide-progress-step:not(:last-child)::after {
  content: '';
  position: absolute;
  top: 8px;
  left: calc(50% + 11px);
  right: calc(-50% + 11px);
  height: 2px;
  background: var(--panel-border-m);
  transition: background 0.3s ease;
}
.guide-progress-step.is-done:not(:last-child)::after { background: var(--green); }

.guide-progress-dot {
  width: 18px; height: 18px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  /* Étape future : contour net + fond transparent (plutôt qu'un simple
     disque teinté peu contrasté) — le numéro reste identifiable sans
     dépendre de la seule couleur. */
  background: transparent;
  border: 1.5px solid var(--panel-border-m);
  font-size: 9px;
  font-weight: 800;
  color: var(--text-muted);
  position: relative;
  z-index: 1;
  transition: background 0.3s ease, border-color 0.3s ease, color 0.3s ease;
}
.guide-progress-step.is-done .guide-progress-dot {
  background: var(--green);
  border-color: var(--green);
  color: #04141f;
}
.guide-progress-step.is-active .guide-progress-dot {
  background: var(--cyan);
  border-color: var(--cyan);
  color: #04141f;
  box-shadow: 0 0 0 3px rgba(51, 199, 230, 0.16);
}
[data-theme="light"] .guide-progress-step.is-active .guide-progress-dot { background: var(--blue); border-color: var(--blue); }
[data-theme="light"] .guide-progress-step.is-done .guide-progress-dot,
[data-theme="light"] .guide-progress-step.is-done:not(:last-child)::after { background: #0e8a5c; border-color: #0e8a5c; }

.guide-step-content {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.guide-step-title {
  font-size: 14.5px;
  font-weight: 800;
  color: var(--text-2);
  margin: 0;
  line-height: 1.3;
}
.guide-step-text {
  font-size: 12.5px;
  color: var(--text-muted);
  line-height: 1.6;
  margin: 0;
}
/* Parcours discret "Exutoire → Délimitation → Analyse → Export" (étape 1) */
.guide-journey {
  font-size: 11px;
  font-weight: 700;
  color: var(--text-dim);
  letter-spacing: 0.1px;
}

/* Encadré conseil / méthode — même habillage que .coming-soon-info */
.guide-tip {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 12px 14px;
  border-radius: 11px;
  border: 1px solid rgba(60, 140, 235, 0.22);
  background: rgba(30, 80, 160, 0.08);
  font-size: 12px;
  color: var(--text-muted);
  line-height: 1.55;
}
.guide-tip svg { color: #6fb6f0; flex-shrink: 0; margin-top: 2px; }

/* Légende à 3 lignes (étape 3 : point rouge / point cyan / ligne pointillée).
   Symboles volontairement autonomes (dimensions propres, jamais la classe
   partagée .legend-swatch) : sa règle "ligne" (22x4, définie plus loin dans
   ce fichier) écrasait sinon le cercle cyan par ordre de cascade à
   spécificité égale — seul le rouge s'en sortait car .swatch-outlet est
   déclarée juste après .legend-swatch. Couleurs reprises telles quelles des
   marqueurs déjà utilisés sur la carte (--map-outlet, --map-stream), même
   diamètre pour les deux cercles. */
.guide-legend { display: flex; flex-direction: column; gap: 8px; }
.guide-legend-row {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 12px;
  color: var(--text-muted);
  line-height: 1.4;
}
.guide-swatch-outlet,
.guide-swatch-used {
  width: 11px; height: 11px;
  border-radius: 50%;
  flex-shrink: 0;
}
.guide-swatch-outlet { background: var(--map-outlet); }
.guide-swatch-used   { background: var(--map-stream); }
.guide-swatch-line {
  width: 26px; height: 0;
  border-top: 2px dashed var(--map-stream);
  flex-shrink: 0;
}

/* Liste d'items icône + titre + description (étape 5) — réutilise le
   gabarit visuel de .layer-item/.layer-icon/.layer-info, sans troncature
   (une description plus longue doit rester lisible en entier). */
.guide-item-list { display: flex; flex-direction: column; gap: 7px; }
.guide-item-desc {
  font-size: 10.5px;
  color: var(--text-dim);
  line-height: 1.4;
  margin-top: 2px;
}
.guide-final-message {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--text-2);
  line-height: 1.5;
  margin: 4px 0 0;
}

/* Boutons principaux du Guide : halo sensiblement réduit par rapport au
   .btn-primary global (ex. "Délimiter le bassin") — un onboarding n'a pas
   besoin de la même intensité lumineuse qu'une action de calcul déclenchée.
   Volontairement scopé à #panel-guide : le composant global .btn-primary
   n'est pas modifié, ni les autres boutons de l'app. */
#panel-guide .btn-primary {
  box-shadow: 0 3px 10px -5px rgba(47, 122, 240, 0.55), inset 0 1px 0 rgba(255, 255, 255, 0.10);
}
#panel-guide .btn-primary:hover:not(:disabled) {
  box-shadow: 0 5px 14px -5px rgba(47, 122, 240, 0.62), inset 0 1px 0 rgba(255, 255, 255, 0.12);
}

/* En-tête sticky de la vue détaillée (retour + titre/compteur + progression)
   — reste visible en haut du panneau pendant le défilement de l'étape.
   Fond opaque (--panel-bg, plus couvrant que --sidebar-bg) pour éviter toute
   superposition visible avec le texte qui défile dessous. */
.guide-steps-header {
  position: sticky;
  top: -16px;
  z-index: 2;
  margin: -16px -14px 0;
  padding: 14px 14px 10px;
  background: var(--panel-bg);
  border-bottom: 1px solid var(--panel-border);
}

.guide-step-content {
  /* Respiration verticale entre la bordure de l'en-tête sticky (progression)
     et le titre de l'étape — jusqu'ici absente (0), le titre touchait
     directement la bordure. */
  padding-top: 18px;
  /* Espace réservé sous le dernier contenu pour qu'il ne soit jamais masqué
     par la navigation sticky en pied de panneau (~73px de haut avec ses
     propres paddings) — marge de sécurité incluse. */
  padding-bottom: 84px;
}

.guide-nav {
  display: flex;
  gap: 8px;
  margin: 4px -14px -14px;
  padding: 10px 14px 14px;
  position: sticky;
  bottom: -14px;
  z-index: 2;
  background: var(--panel-bg);
  border-top: 1px solid var(--panel-border);
}
.guide-nav .btn { flex: 1; justify-content: center; }

/* Élargissement temporaire du panneau pendant la consultation détaillée de
   "Premiers pas" (400-440px demandés) — ne recouvre jamais la sidebar
   droite : .map-area (flex:1, min-width:0) absorbe la différence. */
.sidebar-left { transition: width 0.22s ease; }
.sidebar-left.is-guide-detail { width: 420px; }

/* -------- Cartes compactes de l'accueil (FAQ / Besoin d'aide) --------
   Plus discrètes que .guide-card (Premiers pas) : padding réduit, pas de
   bloc de texte long. */
.guide-mini-card {
  width: 100%;
  margin-top: 10px;
  padding: 12px 14px;
  border-radius: var(--radius);
  border: 1px solid var(--panel-border);
  background: var(--card-bg-2);
}

/* Carte FAQ : la carte entière EST le bouton (icône + texte + chevron). */
button.guide-mini-card {
  display: flex;
  align-items: center;
  gap: 12px;
  color: inherit;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
  transition: border-color 0.18s, background 0.18s;
}
button.guide-mini-card:hover { border-color: rgba(86, 158, 214, 0.32); background: rgba(86, 158, 214, 0.08); }
button.guide-mini-card:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(51, 199, 230, 0.20); }
[data-theme="light"] button.guide-mini-card:hover { border-color: rgba(47, 122, 240, 0.28); background: rgba(47, 122, 240, 0.06); }
[data-theme="light"] button.guide-mini-card:focus-visible { box-shadow: 0 0 0 3px rgba(47, 122, 240, 0.22); }

/* Carte "Besoin d'aide ?" : conteneur non interactif (div) contenant deux
   boutons FRÈRES — le déclencheur (icône+texte+chevron) et "Nous
   contacter" — jamais un bouton imbriqué dans un bouton, donc aucun risque
   de double activation par propagation d'événement. */
.guide-mini-card-help {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.guide-mini-card-trigger {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 2px;
  margin: -2px;
  border-radius: 8px;
  background: none;
  border: none;
  color: inherit;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
  transition: background 0.18s;
}
.guide-mini-card-trigger:hover { background: rgba(86, 158, 214, 0.08); }
.guide-mini-card-trigger:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(51, 199, 230, 0.20); }
[data-theme="light"] .guide-mini-card-trigger:hover { background: rgba(47, 122, 240, 0.06); }
[data-theme="light"] .guide-mini-card-trigger:focus-visible { box-shadow: 0 0 0 3px rgba(47, 122, 240, 0.22); }

.guide-mini-card-icon {
  width: 32px; height: 32px;
  border-radius: 9px;
  display: flex; align-items: center; justify-content: center;
  background: rgba(51, 199, 230, 0.14);
  color: var(--cyan);
  flex-shrink: 0;
}
[data-theme="light"] .guide-mini-card-icon { background: rgba(47, 122, 240, 0.10); color: var(--blue); }

.guide-mini-card-body { flex: 1; min-width: 0; }
.guide-mini-card-title { font-size: 13px; font-weight: 800; color: var(--text-2); }
.guide-mini-card-preview { font-size: 11px; color: var(--text-dim); line-height: 1.45; margin: 2px 0 0; }
/* Métadonnée compacte propre à "Premiers pas" (5 étapes · environ 2 min) —
   justifie que cette carte reste légèrement plus haute que FAQ/Besoin
   d'aide, jamais une troisième ligne de description. */
.guide-mini-card-meta { font-size: 10.5px; font-weight: 700; color: var(--text-dim); margin: 3px 0 0; }
.guide-mini-card-chevron { color: var(--text-dim); flex-shrink: 0; }

/* -------- Vue FAQ (accordéon) -------- */
.guide-faq-item { border-bottom: 1px solid var(--panel-border); }
.guide-faq-item:last-child { border-bottom: none; }
.guide-faq-q-wrap { margin: 0; }
.guide-faq-question {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  padding: 13px 2px;
  background: none;
  border: none;
  color: var(--text-2);
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 700;
  text-align: left;
  line-height: 1.4;
  cursor: pointer;
}
.guide-faq-question:hover { color: var(--cyan); }
[data-theme="light"] .guide-faq-question:hover { color: var(--blue); }
.guide-faq-question:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(51, 199, 230, 0.20);
  border-radius: 6px;
}
.guide-faq-question svg {
  flex-shrink: 0;
  color: var(--text-dim);
  transition: transform 0.2s ease;
}
.guide-faq-question.is-open svg { transform: rotate(180deg); }
.guide-faq-question.is-open { color: var(--cyan); }
[data-theme="light"] .guide-faq-question.is-open { color: var(--blue); }

/* Réponse légèrement en retrait (repère visuel supplémentaire, pas
   uniquement la couleur/rotation du chevron). */
.guide-faq-answer {
  margin-left: 4px;
  padding: 0 2px 14px 12px;
  border-left: 2px solid var(--panel-border-m);
}
.guide-faq-answer p {
  font-size: 12px;
  color: var(--text-muted);
  line-height: 1.6;
  margin: 0;
}

/* -------- Vue "Besoin d'aide ?" -------- */
.guide-help-info-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin: 0;
  padding-left: 18px;
}
.guide-help-info-list li {
  font-size: 12px;
  color: var(--text-muted);
  line-height: 1.4;
}
/* Discret, sous la liste — informe sans demander à l'utilisateur d'identifier
   un mode de données ou de délimitation (ajoutés automatiquement à la copie). */
.guide-help-auto-note {
  font-size: 11px;
  color: var(--text-dim);
  line-height: 1.5;
  margin: 10px 0 0;
}
.guide-help-actions {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 4px;
}
.guide-copy-status {
  font-size: 11.5px;
  font-weight: 700;
  color: var(--green);
  margin: 2px 0 0;
}
.guide-copy-status:empty { display: none; }
[data-theme="light"] .guide-copy-status { color: #0e8a5c; }

/* Indicateur de phase compact (Exutoire → Analyse → Résultats → Exports).
   Piloté par webapp/js/phase-indicator.js via is-active/is-done. */
.phase-indicator {
  display: flex;
  align-items: flex-start;
  margin-bottom: 16px;
}
.phase-step {
  position: relative;
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
}
/* `:last-of-type` et non `:last-child` : `.phase-indicator` se termine par la
   région live `#phase-live` (un `<p>`), donc la dernière étape n'est jamais le
   dernier *enfant* et traçait un connecteur vers le vide, débordant du panneau.
   Compté par type, le dernier `div` est bien la dernière étape. */
.phase-step:not(:last-of-type)::after {
  content: '';
  position: absolute;
  top: 8px;
  left: calc(50% + 11px);
  right: calc(-50% + 11px);
  height: 2px;
  background: var(--panel-border-m);
  transition: background 0.4s ease;
}
/* Étape validée : vert doux (var(--green), déjà utilisé pour le statut moteur
   du header) — volontairement distinct du cyan/bleu de l'étape active, pour
   que "validé" et "en cours" ne se lisent jamais comme le même état. Segment
   de ligne parcouru marqué dans la même teinte. */
.phase-step.is-done:not(:last-of-type)::after { background: var(--green); }

/* Pastille numérotée (1-4) — le numéro est le contenu texte de l'élément,
   jamais un libellé séparé. Taille suffisante pour rester lisible tout en
   restant compacte (une petite pastille de stepper, pas un gros badge). */
.phase-dot {
  width: 18px; height: 18px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--panel-border-m);
  font-size: 9px;
  font-weight: 800;
  color: var(--text-dim);
  position: relative;
  z-index: 1;
  transition: background 0.3s ease, box-shadow 0.3s ease, color 0.3s ease;
}
/* Étape validée : pastille pleine vert doux, numéro conservé (pas remplacé
   par une coche) — l'ordre reste lisible d'un coup d'œil. Pas de halo ni
   d'animation : reste plus discrète que l'étape active, qui elle pulse et
   colore aussi son libellé — le regard doit d'abord aller à l'étape en cours. */
.phase-step.is-done .phase-dot {
  background: var(--green);
  color: #04141f;
}
.phase-step.is-active .phase-dot {
  background: var(--cyan);
  color: #04141f;
  box-shadow: 0 0 0 3px rgba(51, 199, 230, 0.16);
  animation: phase-pulse 2.2s ease-in-out infinite;
}

.phase-label {
  font-size: 9.5px;
  font-weight: 700;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.4px;
  text-align: center;
  transition: color 0.3s ease;
}
/* Libellé de l'étape validée : reste neutre (ni cyan ni vert) — seul le
   point change de couleur. Évite que "validé" rivalise visuellement avec
   "actif", qui lui colore aussi son libellé. */
.phase-step.is-done .phase-label { color: var(--text-muted); }
.phase-step.is-active .phase-label { color: var(--cyan); }

@keyframes phase-pulse {
  0%, 100% { box-shadow: 0 0 0 3px rgba(51, 199, 230, 0.16), 0 0 8px rgba(51, 199, 230, 0.65); }
  50%      { box-shadow: 0 0 0 5px rgba(51, 199, 230, 0.08), 0 0 3px rgba(51, 199, 230, 0.35); }
}

/* Cyan brut sous 3:1 de contraste sur fond quasi-blanc — même substitution
   cyan→blue qu'ailleurs (.fscale-bar, .btn-reset-link) en thème clair. Le
   vert (var(--green)) n'est pas mieux loti (≈1.8:1 sur blanc) : variante plus
   soutenue dédiée à l'étape validée en thème clair. */
[data-theme="light"] .phase-step.is-active .phase-dot { background: var(--blue); }
[data-theme="light"] .phase-step.is-active .phase-label { color: var(--blue); }
[data-theme="light"] .phase-step.is-active .phase-dot {
  box-shadow: 0 0 0 3px rgba(47, 122, 240, 0.16);
  animation: phase-pulse-light 2.2s ease-in-out infinite;
}
[data-theme="light"] .phase-step.is-done:not(:last-of-type)::after,
[data-theme="light"] .phase-step.is-done .phase-dot { background: #0e8a5c; }
@keyframes phase-pulse-light {
  0%, 100% { box-shadow: 0 0 0 3px rgba(47, 122, 240, 0.16), 0 0 8px rgba(47, 122, 240, 0.5); }
  50%      { box-shadow: 0 0 0 5px rgba(47, 122, 240, 0.08), 0 0 3px rgba(47, 122, 240, 0.3); }
}

/* Étape terminée : la coche remplace le numéro — l'état ne repose jamais sur
   la seule couleur. Le numéro reste dans le DOM (span.phase-num), seule sa
   présentation change. */
.phase-step.is-done .phase-num { display: none; }
.phase-step.is-done .phase-dot::after {
  content: '✓';
  font-size: 10px;
  font-weight: 800;
}

/* Étape active en travail (analyse ou export en cours) : anneau tournant
   discret à la place du numéro. Purement décoratif (aria-hidden sur la
   pastille) — l'annonce passe par #phase-live, une phrase par transition. */
.phase-step.is-busy .phase-num { display: none; }
.phase-step.is-busy .phase-dot::after {
  content: '';
  width: 8px; height: 8px;
  border-radius: 50%;
  border: 1.8px solid rgba(4, 20, 31, 0.3);
  border-top-color: #04141f;
  animation: phase-dot-spin 0.8s linear infinite;
}
@keyframes phase-dot-spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  .phase-step.is-active .phase-dot { animation: none; }
  /* Sans animation, l'anneau figé ne dit rien : on garde le numéro. */
  .phase-step.is-busy .phase-num { display: inline; }
  .phase-step.is-busy .phase-dot::after { content: none; }
}

/* Bouton principal désactivé : surface neutre et texte atténué — jamais une
   simple baisse d'opacité du bouton bleu (l'état resterait ambigu). Scopé au
   bouton d'analyse pour ne pas toucher les autres boutons primaires. */
#btn-run-analysis:disabled {
  opacity: 1;
  background: rgba(46, 68, 94, 0.45);
  color: var(--text-dim);
  border-color: rgba(86, 158, 214, 0.16);
  box-shadow: none;
}
[data-theme="light"] #btn-run-analysis:disabled {
  background: rgba(140, 160, 182, 0.22);
  color: #7a92a8;
  border-color: rgba(47, 122, 240, 0.14);
}
#btn-run-analysis:focus-visible {
  outline: none;
  border-color: rgba(51, 199, 230, 0.65);
  box-shadow: 0 0 0 3px rgba(51, 199, 230, 0.18);
}
#btn-run-analysis[hidden] { display: none; }

/* ---------------------------------------------------------------------------
   Contenu contextuel du panneau Délimitation
--------------------------------------------------------------------------- */

/* Coordonnées du point sélectionné, dans la carte d'instruction. */
.delim-outlet-coords {
  margin-top: 6px;
  font-size: 12px;
  font-weight: 700;
  color: var(--cyan);
  font-feature-settings: 'tnum' 1;
}
.delim-outlet-coords[hidden] { display: none; }
[data-theme="light"] .delim-outlet-coords { color: var(--blue); }

/* Carte de résultat compacte « Bassin délimité ». */
.delim-result-card {
  background: var(--card-bg-2);
  border: 1px solid var(--panel-border);
  border-radius: var(--radius);
  padding: 12px;
  display: flex;
  flex-direction: column;
}
.delim-result-card[hidden] { display: none; }
.delim-result-head {
  display: flex;
  align-items: flex-start;
  gap: 9px;
}
.delim-result-check {
  flex-shrink: 0;
  width: 22px; height: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  color: var(--green);
  background: rgba(61, 220, 151, 0.12);
  border: 1px solid rgba(61, 220, 151, 0.35);
}
.delim-result-status {
  margin-top: 1px;
  font-size: 11px;
  font-weight: 700;
  color: var(--green);
}
[data-theme="light"] .delim-result-check,
[data-theme="light"] .delim-result-status { color: #0e8a5c; }
[data-theme="light"] .delim-result-check {
  background: rgba(14, 138, 92, 0.10);
  border-color: rgba(14, 138, 92, 0.35);
}
.delim-result-facts {
  margin: 10px 0 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.delim-result-fact {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 8px;
  font-size: 11.5px;
}
.delim-result-fact dt { color: var(--text-muted); font-weight: 600; }
.delim-result-fact dd {
  margin: 0;
  color: var(--text);
  font-weight: 700;
  font-feature-settings: 'tnum' 1;
  text-align: right;
}
.delim-result-fact[hidden] { display: none; }
.delim-result-edit {
  margin-top: 11px;
  width: 100%;
  height: 36px;
  font-size: 12.5px;
  justify-content: center;
}
.delim-result-edit:focus-visible {
  outline: none;
  border-color: rgba(51, 199, 230, 0.55);
  box-shadow: 0 0 0 3px rgba(51, 199, 230, 0.10);
}
.delim-result-card .btn-reset-link { margin-top: 2px; }
[data-theme="light"] .delim-result-card { background: var(--card-bg); }

/* ---------------------------------------------------------------------------
   Accordéons du panneau Délimitation — « Saisir des coordonnées » et
   « Légende ». Même vocabulaire que les accordéons du panneau droit
   (.morpho-accordion) : vrai bouton, chevron droite/bas, zone tactile 44 px.
--------------------------------------------------------------------------- */
.delim-accordion {
  border: 1px solid var(--panel-border);
  border-radius: var(--radius);
  background: var(--card-bg-2);
  overflow: hidden;
  flex-shrink: 0;
}
/* Les deux accordéons utilitaires restent en bas du panneau, à la place
   qu'occupait la légende. */
#acc-coords { margin-top: auto; }
.delim-accordion-btn {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  min-height: 44px;
  padding: 0 12px;
  border: none;
  background: none;
  color: var(--text);
  font-family: inherit;
  font-size: 12px;
  font-weight: 700;
  text-align: left;
  cursor: pointer;
}
.delim-accordion-btn:hover { background: rgba(51, 199, 230, 0.05); }
.delim-accordion-btn:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: -2px;
  border-radius: var(--radius);
}
.delim-accordion-icon { flex-shrink: 0; color: var(--text-muted); }
.delim-accordion-label { flex: 1; }
.delim-accordion-chevron {
  flex-shrink: 0;
  color: var(--text-muted);
  transition: transform 0.18s ease;
}
.delim-accordion-btn[aria-expanded="true"] .delim-accordion-chevron { transform: rotate(90deg); }
.delim-accordion-body {
  padding: 2px 12px 12px;
  animation: morpho-accordion-open 0.18s ease;
}
.delim-accordion-body[hidden] { display: none; }
[data-theme="light"] .delim-accordion { background: var(--card-bg); }
[data-theme="light"] .delim-accordion-btn:hover { background: rgba(47, 122, 240, 0.05); }
@media (prefers-reduced-motion: reduce) {
  .delim-accordion-body { animation: none; }
  .delim-accordion-chevron { transition: none; }
}

/* La légende garde ses lignes telles quelles, mais son conteneur historique
   perd sa boîte : c'est le corps de l'accordéon qui la porte désormais. */
.delim-accordion .sidebar-legend {
  margin-top: 0;
  padding: 0;
  background: none;
  border: none;
  border-radius: 0;
}

/* ---------------------------------------------------------------------------
   Saisie des coordonnées — CRS, bascule Décimal | DMS, composition DMS, UTM
--------------------------------------------------------------------------- */
.coord-crs-row { display: flex; flex-direction: column; gap: 5px; margin-bottom: 10px; }
.coord-select {
  display: block;
  width: 100%;
  height: 36px;
  padding: 0 9px;
  border-radius: 10px;
  border: 1px solid var(--panel-border-m);
  background: var(--input-bg);
  color: var(--text-2);
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 600;
  outline: none;
  cursor: pointer;
  transition: border-color 0.18s, box-shadow 0.18s;
}
.coord-select:focus-visible {
  border-color: rgba(51, 199, 230, 0.55);
  box-shadow: 0 0 0 3px rgba(51, 199, 230, 0.10);
}

/* Bascule « Décimal | DMS » — discrète, alignée à droite sous les champs.
   Jamais deux gros boutons : deux libellés compacts et un séparateur. */
.coord-format {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 2px;
  margin-top: 5px;
}
.coord-format[hidden] { display: none; }
.coord-format-opt {
  border: none;
  background: none;
  color: var(--text-muted);
  font-family: inherit;
  font-size: 11px;
  font-weight: 700;
  height: 24px;
  padding: 0 7px;
  border-radius: 6px;
  cursor: pointer;
}
.coord-format-opt:hover { color: var(--text); }
.coord-format-opt.is-active {
  color: var(--cyan);
  background: rgba(51, 199, 230, 0.10);
}
.coord-format-opt:focus-visible { outline: 2px solid var(--cyan); outline-offset: 1px; }
.coord-format-sep { color: var(--text-dim); font-size: 11px; }
[data-theme="light"] .coord-format-opt.is-active {
  color: var(--blue);
  background: rgba(47, 122, 240, 0.10);
}

/* Composition DMS compacte : degrés, minutes, secondes, orientation. */
.coord-dms-group { display: flex; flex-direction: column; gap: 9px; }
.coord-dms-group[hidden] { display: none; }
.coord-dms-row .coord-label { margin-bottom: 5px; }
.coord-dms-inputs {
  display: flex;
  align-items: center;
  gap: 3px;
}
.coord-dms-input {
  width: 44px;
  height: 34px;
  padding: 0 6px;
  text-align: right;
  font-feature-settings: 'tnum' 1;
}
.coord-dms-sec { width: 62px; }
.coord-dms-unit {
  color: var(--text-muted);
  font-size: 11px;
  margin-right: 3px;
  flex-shrink: 0;
}
.coord-dms-hemi {
  width: 52px;
  height: 34px;
  margin-left: auto;
  padding: 0 6px;
}

/* Délimitation panel */
.delim-mode-cards { display: flex; flex-direction: column; gap: 8px; }

.delim-mode-card {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 13px 12px;
  border-radius: 12px;
  border: 1px solid var(--panel-border);
  background: var(--card-bg-2);
}
/* `display: flex` l'emporte sur la règle UA de [hidden] — nécessaire quand la
   carte d'instruction cède la place à la carte de résultat (delim-panel.js). */
.delim-mode-card[hidden] { display: none; }
.delim-mode-title {
  font-size: 13px;
  font-weight: 700;
  color: var(--text-2);
}
.delim-mode-desc {
  font-size: 10.5px;
  color: var(--text-dim);
  margin-top: 2px;
}

/* Coord inputs */
.coord-row {
  display: flex;
  gap: 8px;
}
/* `display: flex` l'emporte sur la règle UA de [hidden] — nécessaire pour les
   groupes décimal/UTM masqués selon le CRS (coord-input.js). */
.coord-row[hidden] { display: none; }
.coord-field { flex: 1; }
.coord-label {
  display: block;
  font-size: 10.5px;
  color: var(--text-muted);
  margin-bottom: 5px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.9px;
}
.coord-input {
  display: block;
  width: 100%;
  height: 40px;
  padding: 0 11px;
  border-radius: 10px;
  border: 1px solid var(--panel-border-m);
  background: var(--input-bg);
  color: var(--text-2);
  font-size: 13px;
  font-weight: 600;
  outline: none;
  transition: border-color 0.18s, box-shadow 0.18s;
}
.coord-input:focus {
  border-color: rgba(51, 199, 230, 0.55);
  box-shadow: 0 0 0 3px rgba(51, 199, 230, 0.10);
}
.coord-input::placeholder { color: var(--text-dim); font-weight: 400; }

/* État invalide (validation latitude/longitude) — même vocabulaire que le
   focus cyan ci-dessus, en rouge d'alerte (--red), cohérent avec l'usage
   existant de --red sur error-banner et le marqueur d'exutoire. */
.coord-input.is-invalid {
  border-color: rgba(248, 113, 113, 0.6);
  box-shadow: 0 0 0 3px rgba(248, 113, 113, 0.10);
}
.coord-error-msg {
  font-size: 10.5px;
  color: var(--red);
  line-height: 1.4;
  margin: -2px 0 0;
}
.coord-error-msg[hidden] { display: none; }

/* Static field */
.field-static-row { display: flex; flex-direction: column; gap: 5px; }
.field-static-val {
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 12px;
  border-radius: 10px;
  border: 1px solid var(--panel-border-m);
  background: var(--input-bg);
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text);
}

/* Lien discret "Réinitialiser le point" */
.btn-reset-link {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  width: 100%;
  padding: 5px 8px;
  background: none;
  border: none;
  color: var(--text-dim);
  font-size: 11px;
  font-family: inherit;
  cursor: pointer;
  border-radius: 6px;
  transition: color 0.15s, background 0.15s;
  margin-top: 2px;
}
.btn-reset-link:hover { color: var(--text-muted); background: rgba(86, 158, 214, 0.07); }
.btn-reset-link:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(51, 199, 230, 0.10);
}
.btn-reset-link:disabled { opacity: 0.42; cursor: default; pointer-events: none; }
/* `display: flex` ci-dessus l'emporte sur la règle UA de [hidden] : la
   visibilité pilotée par delim-panel.js a besoin de cette règle explicite. */
.btn-reset-link[hidden] { display: none; }
[data-theme="light"] .btn-reset-link { color: #7a92a8; }
[data-theme="light"] .btn-reset-link:hover { color: #4a6a88; background: rgba(47, 122, 240, 0.06); }

/* ================================================================ CENTER MAP */
.map-area {
  flex: 1;
  min-width: 0;
  position: relative;
  border-radius: 16px;
  overflow: hidden;
  border: 1px solid rgba(86, 158, 214, 0.16);
  background: #0c1f1a;
}

#map {
  width: 100%;
  height: 100%;
  filter: saturate(1.1) contrast(1.03) brightness(0.92);
}

/* ---- Basemap control : panneau horizontal flottant à gauche ---- */
/* ---- Contrôles de carte : colonne unique en haut à droite ----
   Le zoom Leaflet (+/−) et la barre d'outils (contrôle Leaflet custom,
   cf. measure.js) partagent le même coin et EXACTEMENT la même
   spécification visuelle : conteneur, taille de bouton, rayon, survol. */
.leaflet-control-zoom.leaflet-bar,
.map-tools {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 5px;
  background: rgba(9, 20, 33, 0.88);
  border: 1px solid rgba(86, 158, 214, 0.20);
  border-radius: 12px;
  backdrop-filter: blur(12px);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.22);
}

/* Boutons : même gabarit pour les <a> du zoom Leaflet et nos <button>. */
.leaflet-control-zoom.leaflet-bar a,
.map-tool-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 9px;
  background: none;
  color: var(--text-muted);
  cursor: pointer;
}
/* Neutralise le style natif .leaflet-bar (bordures internes, coins carrés). */
.leaflet-control-zoom.leaflet-bar a {
  line-height: 28px;
  font-size: 15px;
  font-weight: 700;
  text-decoration: none;
  text-indent: 0;
}
.leaflet-control-zoom.leaflet-bar a:first-child,
.leaflet-control-zoom.leaflet-bar a:last-child { border-radius: 9px; }

.leaflet-control-zoom.leaflet-bar a:hover,
.map-tool-btn:hover:not(:disabled) {
  background: rgba(51, 199, 230, 0.10);
  border-color: rgba(51, 199, 230, 0.28);
  color: var(--cyan);
}
.map-tool-btn.is-active {
  background: rgba(51, 199, 230, 0.15);
  border-color: rgba(51, 199, 230, 0.40);
  color: var(--cyan);
}
.map-tool-btn:disabled,
.leaflet-control-zoom.leaflet-bar a.leaflet-disabled {
  opacity: 0.38;
  cursor: not-allowed;
  background: none;
  border-color: transparent;
}
.map-tools-sep {
  height: 1px;
  margin: 2px 4px;
  background: rgba(86, 158, 214, 0.20);
}

/* Curseur croix pendant une mesure */
#map.is-measuring { cursor: crosshair; }

/* Readout des mesures : à gauche de la colonne de contrôles */
.map-measure-readout {
  position: absolute;
  top: 12px;
  right: 60px;
  z-index: 8;
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-width: 240px;
  padding: 8px 11px;
  background: rgba(9, 20, 33, 0.88);
  border: 1px solid rgba(86, 158, 214, 0.20);
  border-radius: 10px;
  backdrop-filter: blur(12px);
  font-size: 11px;
  color: var(--text-dim);
  font-feature-settings: 'tnum' 1;
}
.map-measure-readout strong { color: var(--text-2); font-size: 12px; }
.map-measure-readout[hidden] { display: none; }

/* Étiquette permanente des mesures figées */
.measure-tooltip {
  background: rgba(9, 20, 33, 0.92);
  border: 1px solid rgba(251, 191, 36, 0.45);
  border-radius: 8px;
  color: #fbd57c;
  font-family: 'Manrope', system-ui, sans-serif;
  font-size: 11px;
  font-weight: 700;
  font-feature-settings: 'tnum' 1;
  padding: 3px 8px;
  box-shadow: none;
}
.measure-tooltip::before { display: none; }

[data-theme="light"] .map-tools,
[data-theme="light"] .map-measure-readout {
  background: rgba(255, 255, 255, 0.95);
  border-color: rgba(47, 122, 240, 0.20);
  box-shadow: 0 4px 18px rgba(0, 0, 0, 0.12);
}
[data-theme="light"] .map-tool-btn { color: #4a6278; }
[data-theme="light"] .map-tool-btn:hover:not(:disabled),
[data-theme="light"] .map-tool-btn.is-active {
  color: var(--blue);
  background: rgba(47, 122, 240, 0.08);
  border-color: rgba(47, 122, 240, 0.28);
}
[data-theme="light"] .measure-tooltip {
  background: rgba(255, 255, 255, 0.95);
  color: #92600a;
  border-color: rgba(217, 119, 6, 0.45);
}

.basemap-control {
  position: absolute;
  left: 14px;
  bottom: 10px;
  z-index: 8;
  display: flex;
  flex-direction: row;
  gap: 3px;
  padding: 5px;
  background: rgba(9, 20, 33, 0.88);
  border: 1px solid rgba(86, 158, 214, 0.20);
  border-radius: 12px;
  backdrop-filter: blur(12px);
  box-shadow: 0 4px 18px rgba(0, 0, 0, 0.32);
}

/* Vignette individuelle */
.basemap-thumb {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 5px 6px 5px;
  border: 2px solid transparent;
  border-radius: 8px;
  background: transparent;
  font-family: inherit;
  cursor: pointer;
  transition: border-color 0.16s, background 0.16s, box-shadow 0.16s;
}
.basemap-thumb:hover {
  background: rgba(255, 255, 255, 0.05);
  border-color: rgba(86, 158, 214, 0.28);
}
.basemap-thumb.active {
  border-color: var(--cyan);
  background: rgba(51, 199, 230, 0.08);
  box-shadow: 0 0 0 1px rgba(51, 199, 230, 0.18), inset 0 0 0 1px rgba(51, 199, 230, 0.10);
}

/* Miniature — vraie tuile, servie LOCALEMENT.
 *
 * Ces quatre pastilles pointaient directement vers ArcGIS, OpenStreetMap et
 * OpenTopoMap : trois résolutions DNS et trois négociations TLS avant le
 * premier rendu, pour 62 × 36 px chacune. Les images sont désormais générées
 * une fois par scripts/data/build_basemap_thumbnails.py — de VRAIES tuiles des
 * mêmes fonds, à la même emprise (z=8, nord-ouest tunisien), 9,9 Ko au total
 * pour les quatre, servies depuis l'origine de l'application. */
.basemap-swatch {
  width: 62px;
  height: 36px;
  border-radius: 5px;
  display: block;
  flex-shrink: 0;
  border: 1px solid rgba(86, 158, 214, 0.15);
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}
/* Tuile z=8 x=134 y=100 — Siliana / nord-ouest de la Tunisie.
   Les couleurs de repli restent en place : elles évitent une pastille blanche
   le temps que l'image arrive, et couvrent le cas d'un fichier absent. */
.basemap-relief .basemap-swatch {
  background-image: url('assets/basemaps/relief.webp');
  background-color: #484848; /* fallback */
}
.basemap-satellite .basemap-swatch {
  background-image: url('assets/basemaps/satellite.webp');
  background-color: #0b2818; /* fallback */
}
.basemap-plan .basemap-swatch {
  background-image: url('assets/basemaps/plan.webp');
  background-color: #cee3f5; /* fallback */
}
.basemap-dark .basemap-swatch {
  background-image: url('assets/basemaps/dark.webp');
  background-color: #1c1e24; /* fallback — ton du fond Alidade Smooth Dark */
}

/* Libellé */
.basemap-label {
  font-size: 10.5px;
  font-weight: 600;
  color: var(--text-dim);
  line-height: 1;
  letter-spacing: 0.01em;
  white-space: nowrap;
  transition: color 0.16s;
}
.basemap-thumb:hover .basemap-label      { color: var(--text-muted); }
.basemap-thumb.active .basemap-label     { color: var(--cyan); }

/* Mode clair */
[data-theme="light"] .basemap-control {
  background: rgba(255, 255, 255, 0.95);
  border-color: rgba(47, 122, 240, 0.20);
  box-shadow: 0 4px 18px rgba(0, 0, 0, 0.12);
}
[data-theme="light"] .basemap-thumb:hover {
  background: rgba(47, 122, 240, 0.06);
  border-color: rgba(47, 122, 240, 0.28);
}
[data-theme="light"] .basemap-thumb.active {
  border-color: var(--blue);
  background: rgba(47, 122, 240, 0.08);
  box-shadow: 0 0 0 1px rgba(47, 122, 240, 0.18), inset 0 0 0 1px rgba(47, 122, 240, 0.10);
}
[data-theme="light"] .basemap-label           { color: #6a8099; }
[data-theme="light"] .basemap-thumb:hover .basemap-label  { color: var(--text); }
[data-theme="light"] .basemap-thumb.active .basemap-label { color: var(--blue); }
[data-theme="light"] .basemap-plan .basemap-swatch { border-color: rgba(47, 122, 240, 0.22); }

/* ---- Recherche de lieux : panneau flottant en haut à gauche ----
   Coin réservé de longue date (le zoom Leaflet a été recréé topright pour le
   lui laisser, cf. map.js). Même spécification visuelle que le chrome
   flottant de la carte (.map-tools, .basemap-control) : fond, hairline,
   rayon, blur — le composant doit sembler de la même famille. z-index 8,
   comme .basemap-control : au-dessus des tuiles, sous les modales. */
.map-search {
  position: absolute;
  top: 12px;
  left: 14px;
  z-index: 8;
  width: 300px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
/* `display: flex` ci-dessus écrase la règle UA de l'attribut `hidden` (les
   styles auteur priment) : sans cette ligne, le composant serait visible
   même sans clé configurée — même piège déjà traité pour .basemap-control
   dans responsive.css. */
.map-search[hidden] { display: none; }
.place-search-field {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 12px;
  height: 40px;
  background: rgba(7, 27, 46, 0.84);
  border: 1px solid rgba(86, 158, 214, 0.20);
  border-radius: 12px;
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.22);
  transition: border-color 0.18s, box-shadow 0.18s;
}
/* Anneau de focus porté par le CONTENEUR (l'input, sans bordure propre, ne
   peut pas le dessiner) — même vocabulaire cyan que .coord-input:focus. */
.place-search-field:focus-within {
  border-color: rgba(51, 199, 230, 0.55);
  box-shadow: 0 0 0 3px rgba(51, 199, 230, 0.10), 0 4px 14px rgba(0, 0, 0, 0.22);
}
.place-search-icon { color: var(--text-muted); flex-shrink: 0; }
.place-search-input {
  flex: 1;
  min-width: 0;
  border: none;
  outline: none;
  background: none;
  color: var(--text-2);
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
}
.place-search-input::placeholder { color: var(--text-dim); font-weight: 400; }

/* Liste de suggestions et zone d'état : même carte flottante que le champ,
   LÉGÈREMENT plus opaque que lui — du texte dense s'y lit par-dessus la
   carte, là où le champ n'affiche qu'une ligne. */
.place-search-listbox,
.place-search-status {
  margin: 0;
  padding: 5px;
  list-style: none;
  background: rgba(7, 27, 46, 0.90);
  border: 1px solid rgba(86, 158, 214, 0.20);
  border-radius: 12px;
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.30);
  /* Jamais plus haute que la carte : 5 options tiennent largement, mais un
     viewport très bas (paysage téléphone) ne doit pas la faire déborder. */
  max-height: min(280px, 50vh);
  overflow-y: auto;
}

/* Sans backdrop-filter (navigateur ancien, accélération coupée), le voile
   translucide ne floute plus rien : le fond devient quasi opaque pour que le
   texte reste lisible par-dessus n'importe quel fond de carte. */
@supports not ((backdrop-filter: blur(10px)) or (-webkit-backdrop-filter: blur(10px))) {
  .place-search-field { background: rgba(7, 27, 46, 0.97); }
  .place-search-listbox,
  .place-search-status { background: rgba(7, 27, 46, 0.98); }
  [data-theme="light"] .place-search-field { background: rgba(255, 255, 255, 0.97); }
  [data-theme="light"] .place-search-listbox,
  [data-theme="light"] .place-search-status { background: rgba(255, 255, 255, 0.98); }
}
.place-search-option {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 7px 9px;
  border-radius: 8px;
  border: 1px solid transparent;
  cursor: pointer;
}
/* Surbrillance unique (souris ET clavier, cf. surligner()) — même traitement
   que le survol des boutons d'outils de carte. */
.place-search-option.is-active {
  background: rgba(51, 199, 230, 0.10);
  border-color: rgba(51, 199, 230, 0.28);
}
.place-search-option-nom {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--text-2);
}
.place-search-option-detail {
  font-size: 11px;
  font-weight: 500;
  color: var(--text-muted);
}
.place-search-status {
  padding: 9px 12px;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--text-muted);
}

/* Mode clair — même hairline bleue que le reste du chrome flottant
   (.map-tools, .basemap-control), fond translucide, liste légèrement plus
   opaque que le champ (même règle qu'en sombre). */
[data-theme="light"] .place-search-field,
[data-theme="light"] .place-search-listbox,
[data-theme="light"] .place-search-status {
  border-color: rgba(47, 122, 240, 0.20);
  box-shadow: 0 4px 18px rgba(0, 0, 0, 0.12);
}
[data-theme="light"] .place-search-field {
  background: rgba(255, 255, 255, 0.88);
}
[data-theme="light"] .place-search-listbox,
[data-theme="light"] .place-search-status {
  background: rgba(255, 255, 255, 0.94);
}
[data-theme="light"] .place-search-field:focus-within {
  border-color: rgba(47, 122, 240, 0.55);
  box-shadow: 0 0 0 3px rgba(47, 122, 240, 0.12), 0 4px 18px rgba(0, 0, 0, 0.12);
}
[data-theme="light"] .place-search-option.is-active {
  background: rgba(47, 122, 240, 0.08);
  border-color: rgba(47, 122, 240, 0.28);
}

/* Sidebar legend (dans le panneau Délimitation) — poussée en bas du panneau
   flex (même rôle d'ancrage que l'ancienne ligne technique retirée). */
.sidebar-legend {
  margin-top: auto;
  padding: 10px 12px;
  background: rgba(9, 20, 33, 0.45);
  border: 1px solid rgba(86, 158, 214, 0.14);
  border-radius: 10px;
}
.sidebar-legend-title {
  font-size: 10px;
  font-weight: 800;
  color: var(--text-dim);
  margin-bottom: 8px;
  letter-spacing: 0.6px;
  text-transform: uppercase;
}
.legend-row {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 11px;
  color: var(--text-muted);
  margin-bottom: 5px;
}
.legend-row:last-child { margin-bottom: 0; }
.legend-swatch {
  width: 22px; height: 4px;
  border-radius: 2px;
  flex-shrink: 0;
}
.swatch-outlet      { background: var(--map-outlet); height: 10px; width: 10px; border-radius: 50%; }
/* « Exutoire ajusté » — reprend trait pour trait .outlet-used-marker-dot :
   même couleur (--map-stream), même liseré blanc, même proportion réduite
   face au point rouge sélectionné. La pastille de légende et le marqueur de
   la carte ne peuvent donc pas diverger. */
.swatch-outlet-snapped {
  background: var(--map-stream);
  height: 10px; width: 10px;
  border-radius: 50%;
  border: 1.5px solid #fff;
}
/* « Ligne d'ajustement » — reproduit le pointillé cyan de la polyline tracée
   entre les deux marqueurs (cf. showOutletSnapDiagnostic, dashArray '4 5').
   Un `border: dashed` a été écarté : sur 22 px de large, le navigateur ajuste
   lui-même la longueur des tirets et le trait devenait indiscernable du trait
   plein du réseau hydrographique juste en dessous. Le dégradé répété impose
   au contraire le motif exact 4 px pleins / 5 px vides. */
.swatch-snap-line {
  height: 2px;
  background: repeating-linear-gradient(
    to right,
    var(--map-stream) 0 4px,
    transparent 4px 9px
  );
}
.swatch-outlet-test { background: var(--map-outlet-test); height: 8px; width: 8px; border-radius: 50%; border: 1.5px solid #fff; }
.swatch-stream      { background: var(--map-stream); }
/* Halo du contour du bassin.

   Leaflet n'offre aucun équivalent de `line-blur` (propriété MapLibre) :
   l'adoucissement passe donc par un filtre CSS, appliqué à la SEULE pane du
   halo. Une pane personnalisée reçoit son propre renderer SVG, si bien que ce
   filtre ne touche ni la carte, ni les tuiles, ni aucune autre couche — le
   halo est le seul contenu de cette pane.

   Sur mobile, le flou est nettement plus coûteux (rastérisation d'une large
   surface à chaque frame de panoramique) pour un gain à peine perceptible sur
   un petit écran : il y est réduit. Le halo reste parfaitement lisible sans
   flou — c'est un adoucissement, pas la substance de l'effet. */
.leaflet-basinHalo-pane { filter: blur(3px); }
@media (max-width: 768px) {
  .leaflet-basinHalo-pane { filter: blur(2px); }
}

/* La pastille reflète le réglage : `--basin-fill-opacity` est écrite par
   basin-opacity.js depuis l'état unique de map.js. Le trait plein reste
   entièrement opaque au-dessus, comme le contour sur la carte — c'est lui qui
   porte la limite du bassin. */
.swatch-basin {
  background: var(--map-watershed);
  position: relative;
  opacity: calc(0.45 + var(--basin-fill-opacity, 0.30));
}

/* ---------------------------------------------------------------------------
   Réglette d'opacité du bassin, dans la ligne de légende

   Discrète par construction : au repos, seule la piste est visible. La valeur
   n'apparaît qu'au survol, au focus clavier ou pendant le glissement, sous
   forme d'une bulle au-dessus du curseur. Aucun libellé permanent, aucun
   panneau : la légende ne grandit pas.
--------------------------------------------------------------------------- */
.legend-row-basin { position: relative; }

.basin-opacity {
  position: relative;
  display: inline-flex;
  align-items: center;
  margin-left: auto;      /* poussée à droite, la ligne ne s'allonge pas */
  flex-shrink: 0;
}

.basin-opacity-range {
  -webkit-appearance: none;
  appearance: none;
  width: 58px;            /* fourchette demandée : 55 à 60 px en desktop */
  height: 14px;           /* zone TACTILE : plus haute que la piste visible */
  margin: 0;
  background: transparent;
  cursor: pointer;
}
/* Piste fine — le contraste vient de la poignée, pas de l'épaisseur. */
.basin-opacity-range::-webkit-slider-runnable-track {
  height: 3px;
  border-radius: 2px;
  background: var(--panel-border-m);
}
.basin-opacity-range::-moz-range-track {
  height: 3px;
  border-radius: 2px;
  background: var(--panel-border-m);
}
.basin-opacity-range::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 10px; height: 10px;
  margin-top: -3.5px;     /* recentre la poignée sur une piste de 3 px */
  border-radius: 50%;
  background: var(--cyan);
  border: none;
  box-shadow: 0 1px 3px var(--bg-deep-3);
  transition: transform 0.12s ease;
}
.basin-opacity-range::-moz-range-thumb {
  width: 10px; height: 10px;
  border-radius: 50%;
  background: var(--cyan);
  border: none;
  box-shadow: 0 1px 3px var(--bg-deep-3);
  transition: transform 0.12s ease;
}
.basin-opacity-range:hover::-webkit-slider-thumb,
.basin-opacity-range:focus-visible::-webkit-slider-thumb { transform: scale(1.25); }
.basin-opacity-range:hover::-moz-range-thumb,
.basin-opacity-range:focus-visible::-moz-range-thumb { transform: scale(1.25); }
.basin-opacity-range:focus-visible {
  outline: 2px solid rgba(51, 199, 230, 0.55);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}
[data-theme="light"] .basin-opacity-range::-webkit-slider-thumb { background: var(--blue); }
[data-theme="light"] .basin-opacity-range::-moz-range-thumb { background: var(--blue); }

/* Bulle de valeur — au-dessus du curseur, jamais dans le flux : la légende
   garde exactement la même hauteur qu'elle soit visible ou non. */
.basin-opacity-bulle {
  position: absolute;
  bottom: calc(100% + 6px);
  right: 0;
  padding: 3px 7px;
  border-radius: 7px;
  background: var(--panel-bg);
  border: 1px solid var(--panel-border-m);
  color: var(--text-2);
  font-size: 10px;
  font-weight: 700;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.15s ease;
  z-index: 5;
}
.basin-opacity.is-active .basin-opacity-bulle { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .basin-opacity-range::-webkit-slider-thumb,
  .basin-opacity-range::-moz-range-thumb,
  .basin-opacity-bulle { transition: none; }
}
.swatch-admin       { background: var(--map-admin); border-top: 2px dashed var(--map-admin); background: none; }

/* Leaflet overrides */
.leaflet-control-attribution {
  font-size: 9px !important;
  background: rgba(9, 20, 33, 0.75) !important;
  color: var(--text-dim) !important;
  border-radius: 6px 0 0 0 !important;
}
.leaflet-control-attribution a { color: var(--cyan) !important; }
/* (l'ancien restyling !important des boutons zoom vivait ici — remplacé par
   la spécification harmonisée « Contrôles de carte » plus haut, qui couvre
   zoom Leaflet et outils cartographiques d'un seul tenant, deux thèmes.) */

/* Outlet marker */
.outlet-marker-icon { background: transparent; border: none; }
.outlet-marker-dot {
  display: block;
  width: 18px; height: 18px;
  border-radius: 50%;
  background: var(--map-outlet);
  border: 2.5px solid #fff;
  box-shadow: 0 0 0 3px rgba(248, 113, 113, 0.4), 0 3px 8px rgba(0,0,0,0.5);
  animation: outlet-pulse 2.4s ease-in-out infinite;
}
@keyframes outlet-pulse {
  0%, 100% { box-shadow: 0 0 0 3px rgba(248, 113, 113, 0.4), 0 3px 8px rgba(0,0,0,0.5); }
  50%       { box-shadow: 0 0 0 7px rgba(248, 113, 113, 0.15), 0 3px 8px rgba(0,0,0,0.5); }
}

/* Calcul en cours : la pulsation EXISTANTE passe en cyan et s'accélère. Aucun
   élément ajouté sur la carte — la couleur suffit à distinguer « point posé »
   de « délimitation en cours », là où l'utilisateur regarde en attendant son
   bassin. Retirée sur succès, erreur et annulation (cf. setOutletComputing). */
.outlet-marker-icon.is-computing .outlet-marker-dot {
  animation-name: outlet-pulse-computing;
  animation-duration: 1.2s;
}
@keyframes outlet-pulse-computing {
  0%, 100% { box-shadow: 0 0 0 3px rgba(51, 199, 230, 0.45), 0 3px 8px rgba(0,0,0,0.5); }
  50%       { box-shadow: 0 0 0 9px rgba(51, 199, 230, 0.12), 0 3px 8px rgba(0,0,0,0.5); }
}
@media (prefers-reduced-motion: reduce) {
  .outlet-marker-dot,
  .outlet-marker-icon.is-computing .outlet-marker-dot { animation: none; }
}

/* ---------------------------------------------------------------------------
   Bulle cartographique « Délimiter ce bassin »

   Ancrée au marqueur d'exutoire, elle propose l'action liée AU POINT. Elle ne
   reprend volontairement pas le bleu plein de .btn-primary : deux boutons de
   même poids visuel pour la même action se seraient concurrencés. Verre fumé
   bleu nuit, filet cyan — le vocabulaire des panneaux (--panel-bg) et des
   accents (--cyan) déjà en place.

   L'ancre Leaflet est réduite à un point ; la bulle se positionne elle-même en
   absolu (cf. positionOutletBubble), ce qui lui permet de glisser près d'un
   bord SANS emmener sa pointe.
   --------------------------------------------------------------------------- */
.outlet-bubble-anchor {
  background: transparent;
  border: none;
  /* L'ancre n'a aucune surface : sans cela, une boîte transparente
     intercepterait les clics destinés à la carte autour de la bulle. */
  pointer-events: none;
  width: 0 !important;
  height: 0 !important;
}

/* Le PLACEMENT est porté par ce conteneur et n'est JAMAIS transitionné : la
   bulle doit apparaître au nouveau point, pas y glisser à travers la carte.
   Le bouton, lui, ne transforme que son survol d'un pixel. */
.outlet-bubble-shift {
  --bulle-dx: 0px;
  --pointe-dx: 0px;
  --bulle-ecart: 12px;

  position: absolute;
  left: 0;
  top: 0;
  width: max-content;
  transform: translate(calc(-50% + var(--bulle-dx)), calc(-100% - var(--bulle-ecart)));
  pointer-events: none;
}
.outlet-bubble-shift[data-place='bottom'] {
  transform: translate(calc(-50% + var(--bulle-dx)), var(--bulle-ecart));
}

.outlet-bubble {
  /* Fond et filet passent par des variables : la POINTE les réutilise telles
     quelles, si bien qu'aucun écart d'opacité ne peut creuser une ligne de
     séparation entre le corps et sa pointe — au repos comme au survol. */
  --bulle-fond: rgba(7, 27, 46, 0.76);
  --bulle-filet: rgba(54, 197, 220, 0.58);

  pointer-events: auto;

  display: inline-flex;
  align-items: center;
  gap: 7px;
  /* Le texte ne passe jamais à la ligne : une bulle à deux lignes cesserait de
     se lire comme une étiquette posée sur la carte. */
  white-space: nowrap;

  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  line-height: 1.2;
  /* Le texte et l'icône gardent leur pleine opacité : c'est le FOND qui laisse
     passer la carte, jamais le contenu. */
  color: #f2fbff;

  background-color: var(--bulle-fond);
  border: 1px solid var(--bulle-filet);
  border-radius: 11px;
  padding: 8px 10px;
  box-shadow: 0 5px 16px rgba(0, 0, 0, 0.20);
  cursor: pointer;
  /* Ni transform ni dimension : le survol est purement tonal, la bulle ne
     bouge pas d'un pixel sous le curseur. */
  transition:
    background-color 180ms ease,
    border-color 180ms ease,
    box-shadow 180ms ease;
  position: relative;
}

/* Le flou n'est appliqué que là où il est réellement pris en charge. */
@supports (backdrop-filter: blur(10px)) or (-webkit-backdrop-filter: blur(10px)) {
  .outlet-bubble {
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
  }
}
/* Sans flou, la carte transparaîtrait crûment derrière le texte : on rend
   alors le fond plus couvrant plutôt que d'abandonner la lisibilité. */
@supports not ((backdrop-filter: blur(10px)) or (-webkit-backdrop-filter: blur(10px))) {
  .outlet-bubble { --bulle-fond: rgba(7, 27, 46, 0.88); }
  .outlet-bubble:hover:not(:disabled),
  .outlet-bubble:focus-visible { --bulle-fond: rgba(7, 27, 46, 0.93); }
}

.outlet-bubble-icon,
.outlet-bubble-spinner { flex-shrink: 0; }
.outlet-bubble-icon { color: var(--cyan); }
.outlet-bubble-spinner { color: var(--cyan); animation: outlet-bubble-spin 0.9s linear infinite; }
@keyframes outlet-bubble-spin { to { transform: rotate(360deg); } }
.outlet-bubble svg[hidden] { display: none; }

/* Pointe — carré tourné à 45°, reprenant le fond et deux côtés du filet par les
   MÊMES variables que le corps. Son centre reste dans la bulle : la moitié
   haute du losange se confond avec le fond, seule la moitié basse dépasse, donc
   aucun trait ne les sépare. */
.outlet-bubble::after {
  content: '';
  position: absolute;
  left: calc(50% + var(--pointe-dx));
  width: 11px;
  height: 11px;
  background-color: var(--bulle-fond);
  transform: translateX(-50%) rotate(45deg);
  transition: background-color 180ms ease, border-color 180ms ease;
}
.outlet-bubble[data-place='top']::after {
  bottom: -7px;
  border-right: 1px solid var(--bulle-filet);
  border-bottom: 1px solid var(--bulle-filet);
}
/* Près du bord haut de la carte, la bulle bascule SOUS le marqueur (le
   déplacement est porté par `.outlet-bubble-shift`) : seule la pointe se
   retourne ici, pour continuer de désigner le point. */
.outlet-bubble[data-place='bottom']::after {
  top: -7px;
  border-left: 1px solid var(--bulle-filet);
  border-top: 1px solid var(--bulle-filet);
}

/* Survol et focus clavier : le filet se précise, le fond devient un peu plus
   couvrant. Rien d'autre — ni halo, ni agrandissement, ni déplacement. */
.outlet-bubble:hover:not(:disabled),
.outlet-bubble:focus-visible {
  --bulle-fond: rgba(7, 27, 46, 0.84);
  --bulle-filet: rgba(54, 197, 220, 0.85);
}
.outlet-bubble:active:not(:disabled) {
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.18);
}

/* Focus clavier — anneau cyan franc, jamais un simple `outline: none`. Il garde
   sa pleine opacité quelle que soit la transparence du fond. */
.outlet-bubble:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: 2px;
}

.outlet-bubble:disabled { cursor: not-allowed; }
/* Pendant la délimitation la bulle reste lisible — c'est elle qui annonce que
   quelque chose est en cours ; l'estomper la ferait passer pour absente. */
.outlet-bubble[aria-busy='true'] { cursor: progress; }
.outlet-bubble:disabled:not([aria-busy='true']) { opacity: 0.55; }

/* Pointeur grossier (tactile) : la cible doit atteindre 44 x 44 px, seuil en
   deçà duquel un doigt rate le bouton plus souvent qu'il ne l'atteint. */
@media (pointer: coarse) {
  .outlet-bubble {
    min-height: 44px;
    min-width: 44px;
    padding: 10px 12px;
  }
}

/* Écrans réellement étroits : seul le mot « Délimiter » subsiste, pour que la
   bulle ne barre pas la carte. Le libellé accessible, lui, ne change jamais. */
@media (max-width: 380px) {
  .outlet-bubble-label { font-size: 0; }
  .outlet-bubble-label::after { content: 'Délimiter'; font-size: 13px; }
  .outlet-bubble[aria-busy='true'] .outlet-bubble-label::after { content: 'En cours…'; }
}

@media (prefers-reduced-motion: reduce) {
  .outlet-bubble { transition: none; }
  .outlet-bubble:hover:not(:disabled),
  .outlet-bubble:active:not(:disabled) { transform: none; }
  .outlet-bubble-spinner { animation: none; }
}

/* Marqueur "exutoire utilisé" (snapping hydrologique, mode hybride) — cf.
   docs/hybrid_delineation.md. Même famille visuelle que le marqueur rouge,
   couleur --map-stream (cyan) pour le distinguer sans ambiguïté. */
.outlet-used-marker-dot {
  display: block;
  width: 14px; height: 14px;
  border-radius: 50%;
  background: var(--map-stream);
  border: 2px solid #fff;
  box-shadow: 0 0 0 2px rgba(34, 211, 238, 0.4), 0 2px 6px rgba(0,0,0,0.5);
}

/* Exutoire PROPOSÉ, en attente de décision. Même famille que l'exutoire ajusté
   — même cyan, même liseré blanc — mais un halo plus large : c'est ce que
   l'utilisateur doit repérer d'abord, face au point rouge qu'il a choisi. */
.outlet-proposed-marker-dot {
  display: block;
  width: 18px; height: 18px;
  border-radius: 50%;
  background: var(--map-stream);
  border: 2px solid #fff;
  box-shadow: 0 0 0 4px rgba(34, 211, 238, 0.3), 0 2px 8px rgba(0, 0, 0, 0.55);
}

/* Étiquette de distance, posée au milieu de la ligne de liaison. Lisible sans
   survol — sur mobile il n'y a pas de survol du tout. Le fond opaque la
   détache du fond de carte, quel qu'il soit : sans lui, elle deviendrait
   illisible sur une image satellite. */
.outlet-distance-label {
  /* Laisse passer les clics : l'étiquette ne doit pas voler un clic destiné à
     la carte, où l'utilisateur est justement invité à repositionner son point. */
  pointer-events: none;
  white-space: nowrap;
}
.outlet-distance-label span {
  display: inline-block;
  transform: translate(-50%, -50%);
  padding: 3px 8px;
  border-radius: 999px;
  background: rgba(8, 20, 34, 0.88);
  border: 1px solid rgba(34, 211, 238, 0.55);
  color: #e6f7fb;
  font-size: 11px;
  font-weight: 700;
  font-feature-settings: 'tnum' 1;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.45);
}

/* ================================================================ RIGHT SIDEBAR */
.sidebar-right {
  display: flex;
  flex-direction: column;
  width: 340px;
  flex-shrink: 0;
  background: var(--sidebar-bg);
  border: 1px solid var(--sidebar-border);
  border-radius: 16px;
  backdrop-filter: blur(14px);
  overflow: hidden;
  transition: background 0.3s ease;
}

/* Icon tab bar */
.rtab-bar {
  display: flex;
  padding: 10px 10px 0;
  gap: 4px;
  border-bottom: 1px solid var(--panel-border);
  flex-shrink: 0;
}

.rtab {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  padding: 10px 4px 12px;
  font-family: inherit;
  font-size: 11px;
  font-weight: 700;
  color: var(--text-dim);
  background: none;
  border: none;
  cursor: pointer;
  position: relative;
  border-radius: 9px 9px 0 0;
  transition: color 0.18s;
  line-height: 1;
}
.rtab:hover { color: var(--text); }
.rtab.is-active { color: var(--text-2); }
.rtab.is-active::after {
  content: '';
  position: absolute;
  left: 12%; right: 12%;
  bottom: -1px;
  height: 2.5px;
  border-radius: 2px;
  background: var(--cyan);
  box-shadow: 0 0 10px var(--cyan);
}
.rtab svg { flex-shrink: 0; }

/* Result panels */
.result-panel {
  flex: 1;
  overflow-y: auto;
  padding: 16px 16px 16px;
  display: flex;
  flex-direction: column;
  gap: 0;
  min-height: 0;
}
.result-panel[hidden] { display: none; }

/* Empty state — bandeau en haut du panneau morpho */
.panel-empty-banner {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 15px;
  border-radius: 12px;
  border: 1px solid var(--panel-border);
  background: var(--card-bg-2);
  margin-bottom: 14px;
}
.panel-empty-banner[hidden] { display: none; }
.panel-empty-banner svg { opacity: 0.35; flex-shrink: 0; }
.panel-empty-banner .empty-title {
  font-size: 13px;
  font-weight: 700;
  color: var(--text-muted);
  margin: 0 0 3px;
}
.panel-empty-banner .empty-sub {
  font-size: 11px;
  color: var(--text-dim);
  line-height: 1.45;
  margin: 0;
}

/* Encart méthode (discret, non bloquant) — cf. section "Information sur la
   méthode" : réutilise les tokens de couleur existants (thème clair/sombre),
   aucune nouvelle couleur littérale. */
.method-info-note {
  font-size: 11px;
  line-height: 1.5;
  color: var(--text-dim);
  background: var(--card-bg-2);
  border: 1px solid var(--panel-border);
  border-radius: 10px;
  padding: 8px 11px;
  margin: 0 0 14px;
}
.method-info-note[hidden] { display: none; }
.method-info-note .method-warning {
  display: block;
  margin-top: 3px;
  color: var(--text-muted);
}

/* Snapping hydrologique de l'exutoire — variante "warning" (distance entre
   90 et 500 m) : léger accent ambre, même encart discret sinon (cf.
   #outlet-snapping-note, docs/hybrid_delineation.md). */
.method-info-note.is-warning { border-left: 3px solid var(--amber); }
/* État NORMAL de l'ajustement : un filet cyan — c'est une information, pas une
   alerte. L'ambre ci-dessus reste réservé au statut « warning » décidé par le
   backend (seuil métier 90-500 m), jamais à un seuil inventé côté interface. */
.method-info-note.is-adjust { border-left: 3px solid var(--cyan); }
.method-info-note strong { color: var(--text-muted); font-weight: 700; }

/* ---- Panneau Morphologie : révélation progressive ---- */

.empty-hint {
  font-size: 10.5px;
  color: var(--text-dim);
  margin: 6px 0 0;
}

/* Carte de progression (état « analyse en cours ») */
.morpho-progress-card {
  background: var(--card-bg);
  border: 1px solid var(--panel-border);
  border-radius: var(--radius);
  padding: 16px 18px;
  margin: 4px 0;
}
.morpho-progress-card[hidden] { display: none; }
.morpho-progress-head {
  display: flex;
  align-items: center;
  gap: 9px;
  margin-bottom: 10px;
}
.morpho-progress-title {
  font-size: 13px;
  font-weight: 700;
  color: var(--text-2);
  margin: 0;
}
.morpho-progress-spinner {
  width: 14px;
  height: 14px;
  border: 2px solid rgba(51, 199, 230, 0.25);
  border-top-color: var(--cyan);
  border-radius: 50%;
  animation: morpho-spin 0.9s linear infinite;
  flex-shrink: 0;
}
/* Barre INDÉTERMINÉE : le backend ne fournit aucun pourcentage, on n'en
   simule pas — un segment cyan parcourt la piste. */
.morpho-progress-bar {
  height: 3px;
  border-radius: 2px;
  background: rgba(51, 199, 230, 0.14);
  overflow: hidden;
  margin-bottom: 12px;
}
.morpho-progress-bar span {
  display: block;
  height: 100%;
  width: 34%;
  border-radius: 2px;
  background: var(--cyan);
  animation: morpho-indeterminate 1.4s ease-in-out infinite;
}
@keyframes morpho-spin { to { transform: rotate(360deg); } }
@keyframes morpho-indeterminate {
  0%   { transform: translateX(-110%); }
  100% { transform: translateX(400%); }
}
.morpho-progress-phases {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.morpho-progress-phases li {
  position: relative;
  padding-left: 22px;
  font-size: 11.5px;
  color: var(--text-dim);
}
/* Puce d'état : cercle vide (à venir), point cyan (en cours), coche verte
   (terminé) — l'état n'est jamais porté par la seule couleur. */
.morpho-progress-phases li::before {
  content: '○';
  position: absolute;
  left: 2px;
  color: var(--text-dim);
}
.morpho-progress-phases li.is-active {
  color: var(--text);
  font-weight: 600;
}
.morpho-progress-phases li.is-active::before { content: '●'; color: var(--cyan); }
.morpho-progress-phases li.is-done { color: var(--text-muted); }
.morpho-progress-phases li.is-done::before { content: '✓'; color: var(--green); }
.morpho-progress-hint {
  font-size: 10.5px;
  color: var(--text-dim);
  margin: 12px 0 0;
}

/* Carte d'erreur locale */
.morpho-error-card {
  background: var(--card-bg);
  border: 1px solid rgba(248, 113, 113, 0.35);
  border-left: 3px solid var(--red);
  border-radius: var(--radius);
  padding: 14px 16px;
  margin: 4px 0;
}
.morpho-error-card[hidden] { display: none; }
.morpho-error-title {
  font-size: 13px;
  font-weight: 700;
  color: var(--text-2);
  margin: 0 0 6px;
}
.morpho-error-message {
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--text-muted);
  margin: 0;
}
.morpho-error-retry {
  margin-top: 11px;
  min-height: 34px;
  padding: 0 14px;
  border: 1px solid var(--panel-border-m);
  border-radius: 9px;
  background: none;
  color: var(--text);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
}
.morpho-error-retry:hover { border-color: rgba(51, 199, 230, 0.4); color: var(--cyan); }
.morpho-error-retry:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }
.morpho-error-retry[hidden] { display: none; }

/* Décision d'exutoire — VOLONTAIREMENT PAS ROUGE.
   Même gabarit que la carte d'erreur, accent ambre : l'utilisateur n'a pas
   devant lui une panne mais un choix à faire, et le rouge lui ferait chercher
   un problème technique inexistant. Le liseré de 3 px est le même vocabulaire
   que les autres encarts du projet ; seule la teinte change. */
.morpho-decision-card {
  background: var(--card-bg);
  border: 1px solid rgba(251, 191, 36, 0.32);
  border-left: 3px solid var(--amber);
  border-radius: var(--radius);
  padding: 14px 16px;
  margin: 4px 0;
}
.morpho-decision-card[hidden] { display: none; }
/* `--amber` n'est pas redéfini en thème clair et tombe sous le seuil de
   contraste sur fond blanc — même substitution que .beta-badge, pour la même
   raison. */
[data-theme="light"] .morpho-decision-card {
  border-color: rgba(180, 83, 9, 0.3);
  border-left-color: #b45309;
}
.morpho-decision-title {
  font-size: 13px;
  font-weight: 700;
  color: var(--text-2);
  margin: 0 0 6px;
}
.morpho-decision-message {
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--text-muted);
  margin: 0;
}
/* Les deux actions passent à la ligne plutôt que de déborder : le panneau est
   étroit, et « Choisir un autre emplacement » ne tient pas toujours à côté du
   bouton principal. */
.morpho-decision-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 12px;
}
.morpho-decision-actions .btn { min-height: 34px; font-size: 12px; }
.morpho-decision-actions .btn[hidden] { display: none; }

/* Accordéons des résultats */
.morpho-accordion {
  border: 1px solid var(--panel-border);
  border-radius: var(--radius);
  background: var(--card-bg-2);
  margin-top: 10px;
  overflow: hidden;
}
.morpho-accordion-heading { margin: 0; }
.morpho-accordion-btn {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  min-height: 44px;   /* zone tactile confortable */
  padding: 0 12px;
  border: none;
  background: none;
  color: var(--text);
  font-family: inherit;
  font-size: 12px;
  font-weight: 700;
  text-align: left;
  cursor: pointer;
}
.morpho-accordion-btn:hover { background: rgba(51, 199, 230, 0.05); }
.morpho-accordion-btn:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: -2px;
  border-radius: var(--radius);
}
.morpho-accordion-chevron {
  flex-shrink: 0;
  color: var(--text-muted);
  transition: transform 0.18s ease;
}
/* Chevron : droite fermé, bas ouvert. */
.morpho-accordion-btn[aria-expanded="true"] .morpho-accordion-chevron { transform: rotate(90deg); }
.morpho-accordion-body {
  padding: 2px 12px 12px;
  animation: morpho-accordion-open 0.18s ease;
}
.morpho-accordion-body[hidden] { display: none; }
@keyframes morpho-accordion-open {
  from { opacity: 0; transform: translateY(-3px); }
  to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .morpho-progress-bar span { animation: none; width: 100%; opacity: 0.45; }
  .morpho-progress-spinner { animation: none; }
  .morpho-accordion-body { animation: none; }
  .morpho-accordion-chevron { transition: none; }
}

/* Thème clair : mêmes surfaces que les cartes voisines. */
[data-theme="light"] .morpho-progress-card,
[data-theme="light"] .morpho-error-card,
[data-theme="light"] .morpho-accordion {
  background: var(--card-bg);
}
[data-theme="light"] .morpho-accordion-btn:hover { background: rgba(47, 122, 240, 0.05); }

/* Lignes clé/valeur compactes des rubriques Morphologie : libellé à gauche,
   valeur à droite, filet fin entre les lignes — une grandeur par ligne, plus
   dense que les anciennes cartes à tuiles. */
.morpho-kv-list { display: flex; flex-direction: column; }
.morpho-kv {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 6px 2px;
  border-bottom: 1px solid var(--panel-border);
  font-size: 12px;
}
.morpho-kv:last-child { border-bottom: none; }
.morpho-kv-label {
  color: var(--text-muted);
  line-height: 1.35;
  min-width: 0;
}
.morpho-kv-value {
  font-weight: 700;
  color: var(--text-2);
  font-feature-settings: 'tnum' 1;
  white-space: nowrap;
  text-align: right;
  flex-shrink: 0;
}

/* En-tête d'accordéon avec bouton ⛶ frère (jamais un bouton dans un bouton) :
   le bouton d'accordéon garde toute la largeur restante, l'agrandissement se
   cale à droite avec sa propre zone tactile. */
.morpho-accordion-head-row { display: flex; align-items: center; }
.morpho-accordion-head-row .morpho-accordion-btn { flex: 1; min-width: 0; }
.morpho-accordion-expand {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  margin-right: 8px;
  padding: 0;
  border-radius: 8px;
  border: 1px solid var(--panel-border-m);
  background: var(--card-bg-2);
  color: var(--cyan);
  cursor: pointer;
  transition: border-color 0.18s, box-shadow 0.18s, background 0.18s, opacity 0.18s;
}
.morpho-accordion-expand:hover:not(:disabled) {
  border-color: rgba(51, 199, 230, 0.5);
  box-shadow: 0 0 0 3px rgba(51, 199, 230, 0.12);
}
.morpho-accordion-expand:focus-visible {
  outline: none;
  border-color: rgba(51, 199, 230, 0.55);
  box-shadow: 0 0 0 3px rgba(51, 199, 230, 0.10);
}
.morpho-accordion-expand:disabled { opacity: 0.42; cursor: not-allowed; }
/* Même substitution cyan→blue qu'ailleurs en thème clair (.chart-expand-btn). */
[data-theme="light"] .morpho-accordion-expand { color: var(--blue); }
[data-theme="light"] .morpho-accordion-expand:hover:not(:disabled) {
  border-color: rgba(47, 122, 240, 0.5);
  box-shadow: 0 0 0 3px rgba(47, 122, 240, 0.12);
}

/* Note d'un graphique (sous l'en-tête de sa rubrique). */
.chart-note {
  display: flex;
  align-items: baseline;
  gap: 6px;
  margin: 4px 0 8px;
  font-size: 11px;
  color: var(--text-dim);
}
.chart-note .info-tip { margin-left: 0; }

/* Empty state plein-panneau (non utilisé actuellement, conservé pour usage futur) */
.panel-empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  flex: 1;
  text-align: center;
  padding: 40px 20px;
  color: var(--text-dim);
}
.panel-empty-state svg { opacity: 0.35; margin-bottom: 16px; }
.empty-title {
  font-size: 14px;
  font-weight: 700;
  color: var(--text-muted);
  margin: 0 0 8px;
}
.empty-sub {
  font-size: 12px;
  color: var(--text-dim);
  line-height: 1.55;
  max-width: 240px;
  margin: 0;
}

/* Results panel head */
.results-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 14px;
}

.section-title {
  font-size: 14.5px;
  font-weight: 800;
  color: var(--text-2);
  line-height: 1;
}
.panel-desc {
  font-size: 12px;
  color: var(--text-muted);
  line-height: 1.5;
  margin: 6px 0 0;
}

/* Section labels */
.section-label {
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: 0.9px;
  text-transform: uppercase;
  color: var(--text-dim);
  display: flex;
  align-items: center;
  gap: 6px;
}
.mt-section { margin-top: 18px; margin-bottom: 10px; }

.info-tip {
  font-size: 11px;
  color: var(--text-dim);
  cursor: help;
  margin-left: 4px;
}

/* ---- Info-bulle méthodologique (limites d'une source de données) ----------
   Signale une nuance, pas un incident : teinte ambre du badge BÊTA, jamais de
   rouge, de triangle d'alerte ni d'animation. Le panneau est un petit encart
   de la même famille que les modales (surface, filet, arrondi, ombre), câblé
   par webapp/js/info-popover.js. */
.info-pop {
  position: relative;
  display: inline-flex;
  vertical-align: baseline;
}
.info-pop-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 16px;
  min-height: 16px;
  margin-left: 3px;
  vertical-align: middle;
  padding: 0;
  border: none;
  background: none;
  color: var(--amber);
  font-family: inherit;
  font-size: 11px;
  line-height: 1;
  cursor: pointer;
  opacity: 0.8;
  transition: opacity 0.15s ease;
}
.info-pop-btn:hover { opacity: 1; }
.info-pop-btn:focus-visible {
  outline: 2px solid var(--amber);
  outline-offset: 1px;
  border-radius: 50%;
  opacity: 1;
}
/* Zone tactile confortable là où il n'y a pas de souris. Elle est étendue par
   un pseudo-élément plutôt qu'en agrandissant le bouton : la boîte de mise en
   page reste de 16 px, donc la hauteur de la ligne de titre qui accueille
   l'icône ne bouge pas d'un pixel entre bureau et mobile. */
@media (pointer: coarse) {
  .info-pop-btn { font-size: 12.5px; }
  .info-pop-btn::after {
    content: '';
    position: absolute;
    inset: -10px;
  }
}

.info-pop-panel {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  z-index: 60;
  /* Recadrage horizontal mesuré à l'ouverture (info-popover.js) : le panneau
     reste dans le panneau droit, même dans sa colonne de droite. */
  transform: translateX(var(--pop-shift, 0px));
  display: flex;
  flex-direction: column;
  gap: 6px;
  width: max-content;
  max-width: min(320px, calc(100vw - 32px));
  padding: 11px 13px;
  border-radius: 12px;
  border: 1px solid var(--panel-border-m);
  background: var(--panel-bg);
  box-shadow: 0 10px 28px -8px rgba(0, 0, 0, 0.45);
  text-align: left;
  white-space: normal;
  cursor: default;
}
.info-pop-panel[hidden] { display: none; }
/* Ouverture vers le haut quand le bas manque de place (tiroir mobile) —
   posée par info-popover.js après mesure, jamais devinée à l'avance. */
.info-pop-panel.is-above { top: auto; bottom: calc(100% + 8px); }
.info-pop-title {
  font-size: 11px;
  font-weight: 800;
  color: var(--amber);
  letter-spacing: 0.01em;
}
.info-pop-text {
  font-size: 11px;
  font-weight: 500;
  line-height: 1.45;
  color: var(--text-muted);
}
.info-pop-text strong { color: var(--text-2); font-weight: 700; }

/* Thème clair : l'ambre par défaut passe sous le seuil de contraste sur une
   surface blanche — même substitution que pour le badge BÊTA. La surface du
   panneau reste celle des cartes du thème, jamais un blanc pur posé sur un
   fond sombre. */
[data-theme="light"] .info-pop-btn { color: #b45309; }
[data-theme="light"] .info-pop-btn:focus-visible { outline-color: #b45309; }
[data-theme="light"] .info-pop-title { color: #b45309; }
[data-theme="light"] .info-pop-panel {
  background: var(--card-bg);
  box-shadow: 0 10px 28px -10px rgba(15, 42, 68, 0.22);
}

/* Titre de graphique (sous l'eyebrow "Graphiques") — sentence case, moins
   proéminent que .section-label, distingue les deux courbes sans surcharger
   la hiérarchie. */
.chart-title {
  display: flex;
  align-items: center;
  font-size: 12px;
  font-weight: 700;
  color: var(--text-muted);
  margin-bottom: 8px;
}
.mt-chart-title { margin-top: 16px; }

/* Bouton "agrandir" en haut à droite du bloc Courbe hypsométrique */
.chart-expand-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  margin-left: auto;
  padding: 0;
  border-radius: 7px;
  border: 1px solid var(--panel-border-m);
  background: var(--card-bg-2);
  color: var(--cyan);
  cursor: pointer;
  transition: border-color 0.18s, box-shadow 0.18s, background 0.18s, opacity 0.18s;
}
.chart-expand-btn:hover:not(:disabled) {
  border-color: rgba(51, 199, 230, 0.5);
  box-shadow: 0 0 0 3px rgba(51, 199, 230, 0.12);
}
.chart-expand-btn:focus-visible {
  outline: none;
  border-color: rgba(51, 199, 230, 0.55);
  box-shadow: 0 0 0 3px rgba(51, 199, 230, 0.10);
}
.chart-expand-btn:disabled { opacity: 0.42; cursor: not-allowed; }
/* Cyan brut sous 3:1 de contraste sur fond quasi-blanc — même substitution
   cyan→blue qu'ailleurs (.fscale-bar, .btn-icon-sq) en thème clair. */
[data-theme="light"] .chart-expand-btn { color: var(--blue); }
[data-theme="light"] .chart-expand-btn:hover:not(:disabled) {
  border-color: rgba(47, 122, 240, 0.5);
  box-shadow: 0 0 0 3px rgba(47, 122, 240, 0.12);
}
/* Dans .climate-head-actions, l'alignement à droite vient déjà du conteneur
   (justify-content: flex-end) — pas besoin (et pas souhaitable, ça créerait
   un espacement irrégulier) que chaque bouton pousse aussi avec margin-left: auto. */
.climate-head-actions .chart-expand-btn { margin-left: 0; }

/* ================================================================ MODALE COURBE HYPSOMÉTRIQUE */
.modal-backdrop {
  position: fixed;
  inset: 0;
  /* 500 : une modale GLOBALE passe au-dessus de tout l'étage cartographique —
     panes Leaflet (≤ 400), scène 3D #scene3d (450) ET bascule Vue 2D/3D
     (460). À 100, la modale de protection d'exutoire ouverte pendant la
     Vue 3D passait SOUS la scène : boutons interceptés par le canvas,
     modale inutilisable (constaté en test P6, identique vue historique et
     MapLibre). Le contenu modal, enfant du backdrop, suit d'office. */
  z-index: 500;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: rgba(5, 11, 19, 0.72);
  backdrop-filter: blur(6px);
  animation: modal-fade-in 0.18s ease-out;
}
.modal-backdrop[hidden] { display: none; }

.modal {
  width: 100%;
  max-width: 760px;
  max-height: min(88vh, 820px);
  display: flex;
  flex-direction: column;
  background: var(--panel-bg);
  border: 1px solid var(--panel-border-m);
  border-radius: 16px;
  box-shadow: 0 24px 60px -12px rgba(0, 0, 0, 0.55);
  overflow: hidden;
  animation: modal-scale-in 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}
.modal:focus-visible { outline: none; }

@keyframes modal-fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes modal-scale-in {
  from { opacity: 0; transform: scale(0.97) translateY(6px); }
  to   { opacity: 1; transform: scale(1) translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .modal-backdrop, .modal { animation: none; }
}

.modal-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 14px;
  padding: 18px 20px;
  border-bottom: 1px solid var(--panel-border);
  flex-shrink: 0;
}
.modal-title {
  font-size: 16px;
  font-weight: 800;
  color: var(--text-2);
}
.modal-subtitle {
  font-size: 11.5px;
  color: var(--text-dim);
  margin-top: 3px;
}
.modal-header-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
}
.modal-hi-badge {
  display: inline-flex;
  align-items: center;
  padding: 4px 10px;
  border-radius: 999px;
  background: rgba(51, 199, 230, 0.14);
  border: 1px solid rgba(51, 199, 230, 0.30);
  font-size: 11px;
  font-weight: 700;
  color: var(--cyan);
  white-space: nowrap;
}
.modal-hi-badge[hidden] { display: none; }

/* Badge générique d'en-tête de modale (même style que .modal-hi-badge, nom
   neutre pour un usage hors hypsométrie — ex. année du diagramme climatique). */
.modal-badge {
  display: inline-flex;
  align-items: center;
  padding: 4px 10px;
  border-radius: 999px;
  background: rgba(51, 199, 230, 0.14);
  border: 1px solid rgba(51, 199, 230, 0.30);
  font-size: 11px;
  font-weight: 700;
  color: var(--cyan);
  white-space: nowrap;
}
[data-theme="light"] .modal-badge { color: var(--blue); border-color: rgba(47, 122, 240, 0.30); background: rgba(47, 122, 240, 0.10); }

.modal-close {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border-radius: 9px;
  border: 1px solid var(--panel-border-m);
  background: var(--card-bg-2);
  color: var(--text-muted);
  cursor: pointer;
  transition: border-color 0.18s, background 0.18s, color 0.18s;
}
.modal-close:hover {
  color: var(--text-2);
  border-color: rgba(248, 113, 113, 0.4);
  background: rgba(248, 113, 113, 0.08);
}
.modal-close:focus-visible {
  outline: none;
  border-color: rgba(51, 199, 230, 0.55);
  box-shadow: 0 0 0 3px rgba(51, 199, 230, 0.10);
}

.modal-body {
  padding: 20px;
  overflow-y: auto;
  flex: 1;
  min-height: 0;
}

.modal-chart-wrap { height: 320px; margin-bottom: 4px; }

/* Modale de graphique agrandi (profil altimétrique) : occupe réellement
   l'écran (~85 % de la fenêtre, bornée) et le graphique est RECONSTRUIT à
   cette taille par Chart.js (maintainAspectRatio: false) — jamais un simple
   agrandissement CSS du canvas compact. */
.modal-chart-large {
  max-width: min(88vw, 1200px);
  height: min(82vh, 900px);
  max-height: min(82vh, 900px);
}
.modal-chart-large .modal-body {
  display: flex;
  flex-direction: column;
}
.modal-chart-large .modal-chart-wrap {
  flex: 1;
  height: auto;
  min-height: 0;
  margin-bottom: 0;
}

.modal-table-scroll {
  max-height: 220px;
  overflow-y: auto;
  border-radius: 10px;
  border: 1px solid var(--panel-border);
}
/* Seule table restante dans la popup (plus de "Table des données" au-dessus) :
   plus de hauteur disponible, meilleure lisibilité pour les classes d'altitude. */
.modal-table-scroll-tall { max-height: 320px; }
.modal-table-scroll table { width: 100%; }
.modal-table-scroll thead th {
  position: sticky;
  top: 0;
  background: var(--sidebar-bg);
}

/* Repères H5/H50/H95 dans la table des classes : ligne discrètement teintée,
   badge cyan compact dans la colonne "Repère". */
.modal-table-scroll tr.is-marked-row { background: rgba(51, 199, 230, 0.06); }
.modal-hyp-marker-cell {
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--cyan);
  white-space: nowrap;
}

.modal-footer {
  display: flex;
  gap: 10px;
  padding: 14px 20px;
  border-top: 1px solid var(--panel-border);
  flex-shrink: 0;
}
.modal-footer .btn { flex: 1; justify-content: center; }

@media (max-width: 640px) {
  .modal-footer { flex-direction: column; }
}

/* Badges */
.badge-done {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 10px;
  border-radius: 999px;
  background: rgba(55, 216, 150, 0.14);
  border: 1px solid rgba(55, 216, 150, 0.30);
  font-size: 11px;
  font-weight: 700;
  color: #7ee9b8;
}
.badge-done[hidden] { display: none; }
/* Thème clair : le vert pâle (pensé pour fond sombre) manque de contraste sur
   fond clair — texte plus foncé, bordure et fond légèrement plus soutenus,
   même gabarit discret. Le thème sombre n'est pas touché. */
[data-theme="light"] .badge-done {
  color: #0f7a4d;
  border-color: rgba(16, 143, 88, 0.42);
  background: rgba(16, 143, 88, 0.10);
}

.badge-soon-sm {
  display: inline-flex;
  align-items: center;
  padding: 3px 8px;
  border-radius: 999px;
  background: rgba(60, 140, 235, 0.14);
  border: 1px solid rgba(60, 140, 235, 0.28);
  font-size: 10px;
  font-weight: 700;
  color: #6fb6f0;
  white-space: nowrap;
  flex-shrink: 0;
}

.badge-soon-lg {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 14px;
  border-radius: 10px;
  background: rgba(60, 140, 235, 0.14);
  border: 1px solid rgba(60, 140, 235, 0.30);
  font-size: 12.5px;
  font-weight: 700;
  color: #6fb6f0;
}

/* ================================================================ MORPHOLOGIE */

/* 4 résumé cards */
.morpho-summary-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
  margin-bottom: 4px;
}

.morpho-card {
  border-radius: 12px;
  border: 1px solid var(--panel-border);
  background: var(--card-bg-2);
  padding: 13px 10px;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
}
.morpho-card svg { opacity: 0.9; }
.morpho-card-label {
  font-size: 10px;
  color: var(--text-muted);
  font-weight: 600;
}
.morpho-card-value {
  font-size: 15px;
  font-weight: 800;
  color: var(--text-2);
  line-height: 1.1;
}
.kpi-unit {
  font-size: 10px;
  font-weight: 600;
  color: var(--text-dim);
}

/* Indices grid */
.indices-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  margin-bottom: 4px;
}

.index-card {
  border-radius: 11px;
  border: 1px solid var(--panel-border);
  background: var(--card-bg-2);
  padding: 11px 10px;
}
.index-label {
  font-size: 10px;
  color: var(--text-muted);
  line-height: 1.3;
  margin-bottom: 7px;
}
.index-value {
  font-size: 15px;
  font-weight: 800;
  color: var(--text-2);
}
.value-pending { color: var(--text-dim) !important; font-weight: 500 !important; font-size: 12px !important; }

/* Terrain stats row */
.terrain-stats-row {
  display: flex;
  gap: 10px;
  margin-bottom: 10px;
}
.terrain-stat {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 10px 11px;
  border-radius: 10px;
  border: 1px solid var(--panel-border);
  background: var(--card-bg-2);
}
.terrain-stat-label { font-size: 10px; color: var(--text-dim); font-weight: 600; }
.terrain-stat-value { font-size: 13px; font-weight: 800; color: var(--text-2); }

/* Chart wraps */
.chart-wrap {
  position: relative;
  border-radius: 12px;
  border: 1px solid var(--panel-border);
  background: rgba(8, 17, 28, 0.45);
  padding: 10px;
  margin-bottom: 4px;
  overflow: hidden;
}
.chart-wrap canvas { display: block; width: 100% !important; }
.chart-empty {
  position: absolute;
  inset: 0;
  display: none;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 16px;
  font-size: 12px;
  color: var(--text-dim);
  background: rgba(8, 17, 28, 0.45);
  line-height: 1.5;
}
.chart-wrap.is-empty .chart-empty { display: flex; }
.chart-wrap.is-empty canvas { opacity: 0.15; }

/* ================================================================ STATISTIQUES */

/* Thematic layout: chart centré + table pleine largeur */
.landcover-layout {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 8px;
}
.landcover-layout .chart-wrap {
  width: 130px;
  height: 130px;
  align-self: center;
  flex: none;
  margin-bottom: 0;
}
.landcover-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 10.5px;
}
.landcover-table thead tr {
  border-bottom: 1px solid var(--panel-border-m);
}
.landcover-table th {
  padding: 3px 4px;
  color: var(--text-dim);
  font-weight: 600;
  font-size: 9.5px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}
.landcover-table th.lc-th-num { text-align: right; }
.landcover-table tr {
  border-bottom: 1px solid var(--panel-border);
}
.landcover-table td {
  padding: 4px 4px;
  color: var(--text-muted);
  vertical-align: middle;
}
.landcover-table .landcover-pct {
  text-align: right;
  font-weight: 700;
  color: var(--text-2);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* Ligne désignée depuis l'anneau, ou survolée / focalisée au clavier. Un
   simple voile : la mise en évidence ne doit pas concurrencer la lecture des
   chiffres, et le nom comme la valeur restent lisibles sans elle — la couleur
   n'est jamais la seule porteuse d'information. */
.landcover-table tbody tr.is-highlighted,
.landcover-table tbody tr:hover {
  background: rgba(51, 199, 230, 0.10);
}
.landcover-table tbody tr:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: -2px;
}

/* Conteneur des anneaux de répartition. L'encadrement général des graphiques
   (fond soutenu + bordure marquée) dessinait un gros cadre bleu autour d'un
   simple filet de couleur. Le conteneur reste nécessaire — il porte le
   message d'état vide, positionné en absolu — mais s'efface visuellement. */
.chart-wrap--donut {
  background: rgba(255, 255, 255, 0.02);
  border-color: rgba(134, 174, 214, 0.10);
  padding: 6px;
}
[data-theme='light'] .chart-wrap--donut {
  background: rgba(34, 62, 98, 0.02);
  border-color: rgba(34, 62, 98, 0.08);
}
.lc-code {
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  font-size: 10px;
  padding-right: 6px !important;
}
.landcover-swatch {
  display: inline-block;
  width: 9px; height: 9px;
  border-radius: 2px;
  margin-right: 5px;
  vertical-align: middle;
  flex-shrink: 0;
}
.chart-source {
  font-size: 10px;
  color: var(--text-dim);
  margin-top: 4px;
  line-height: 1.4;
}

/* ================================================================ ONGLETS THÉMATIQUES */
/* Grille de pills (3 colonnes, 2 lignes pour 5 onglets) — remplace l'ancienne
   ligne flex unique où 5 boutons flex:1 se compressaient jusqu'à tronquer
   leurs libellés ("Occup...", "Bioclim...", etc.). Chaque libellé est un mot
   court et complet (Climat, Occupation, Pédologie, Géologie, Bioclimat) :
   plus besoin d'ellipse. */
.theme-tabs {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 6px;
}

.ttab {
  padding: 7px 4px;
  font-family: inherit;
  font-size: 11px;
  font-weight: 700;
  color: var(--text-dim);
  background: var(--card-bg-2);
  border: 1px solid var(--panel-border);
  border-radius: 8px;
  cursor: pointer;
  text-align: center;
  white-space: nowrap;
  transition: color 0.15s, background 0.15s, border-color 0.15s;
  line-height: 1.3;
}
.ttab:hover {
  color: var(--text);
  border-color: var(--cyan);
}
.ttab.is-active {
  background: color-mix(in srgb, var(--cyan) 15%, transparent);
  border-color: var(--cyan);
  color: var(--cyan);
}
[data-theme="light"] .ttab.is-active { color: var(--blue); border-color: var(--blue); }

.theme-panel { margin-top: 12px; }
.theme-panel[hidden] { display: none; }
/* Titre clair au-dessus du graphique/tableau (Occupation du sol, Pédologie,
   Géologie, Bioclimatique) — reprend le nom complet, les onglets eux-mêmes
   restant courts pour tenir dans la grille. */
.theme-panel > .section-label { margin-bottom: 8px; }

/* Onglet Climat — en-tête (titre + sélecteur d'année) et grille de
   métadonnées (réutilise les classes rmeta-* du bloc Détails techniques). */
/* Titre/sous-titre en pleine largeur, actions (année + agrandir/PNG/CSV) sur
   leur propre ligne alignée à droite juste en dessous — évite de comprimer
   le titre "Diagramme climatique" contre les boutons dans la sidebar étroite. */
.climate-head {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 10px;
}
.climate-head-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 6px;
}
.climate-title {
  font-size: 13px;
  font-weight: 800;
  color: var(--text-2);
}
.climate-subtitle {
  font-size: 11px;
  color: var(--text-muted);
  margin-top: 2px;
}
.climate-year-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
  font-size: 10.5px;
  font-weight: 700;
  color: var(--text-dim);
}
.climate-year-label[hidden] { display: none; }
/* Même vocabulaire que .coord-input (fond input, hairline, focus cyan). */
.climate-year-select {
  height: 28px;
  padding: 0 6px;
  border-radius: 9px;
  border: 1px solid var(--panel-border-m);
  background: var(--input-bg);
  color: var(--text-2);
  font: inherit;
  font-size: 12px;
  font-weight: 700;
  font-feature-settings: 'tnum' 1;
  cursor: pointer;
}
.climate-year-select:focus {
  outline: none;
  border-color: rgba(51, 199, 230, 0.55);
  box-shadow: 0 0 0 3px rgba(51, 199, 230, 0.10);
}
.climate-meta { margin-top: 12px; }
.climate-meta[hidden] { display: none; }
.climate-note {
  margin: 8px 0 0;
  font-size: 10.5px;
  color: var(--text-dim);
  line-height: 1.5;
}
.climate-note[hidden] { display: none; }

/* ================================================================ RAPPORT */
/* Panneau volontairement court : titre, description, deux actions, historique.
   Les métadonnées vivent repliées dans .tech-details en bas de panneau. */
.report-meta-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px 16px;
}
.report-meta-item { display: flex; flex-direction: column; gap: 3px; }
.rmeta-label  { font-size: 10.5px; color: var(--text-dim); font-weight: 600; }
.rmeta-value  { font-size: 12px;   color: var(--text-2);   font-weight: 700; }

.report-actions { margin-top: 10px; }
/* Indication affichée pendant la génération du rapport. Elle dit ce qui prend
   du temps ET combien : masquer une attente d'une minute derrière un simple
   sablier laisserait croire à un blocage. */
.report-hint {
  font-size: 11px;
  line-height: 1.5;
  margin: 8px 0 0;
  color: var(--text-muted);
}
.report-hint[hidden] { display: none; }

/* Accordéon "Détails techniques" — délibérément discret : pas de carte,
   juste un disclosure natif en fin de panneau. */
.tech-details {
  margin-top: 14px;
  border-top: 1px solid var(--panel-border);
  padding-top: 10px;
}
.tech-details summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  font-weight: 700;
  color: var(--text-dim);
  user-select: none;
}
.tech-details summary::-webkit-details-marker { display: none; }
.tech-details summary::before {
  content: '';
  width: 0;
  height: 0;
  border-left: 4px solid currentColor;
  border-top: 3.5px solid transparent;
  border-bottom: 3.5px solid transparent;
  transition: transform 0.15s ease-out;
}
.tech-details[open] summary::before { transform: rotate(90deg); }
@media (prefers-reduced-motion: reduce) {
  .tech-details summary::before { transition: none; }
}
.tech-details summary:hover { color: var(--text-muted); }
.tech-details .report-meta-grid { margin-top: 10px; }
.tech-details-note {
  margin: 10px 0 0;
  font-size: 10.5px;
  color: var(--text-dim);
  line-height: 1.5;
}

/* ================================================================ AUTH MVP */
/* .btn force display:inline-flex, qui l'emporte sur le [hidden] du navigateur
   — règle explicite nécessaire, même motif que .save-badge[hidden] etc. */
#btn-auth-login[hidden] { display: none; }

/* Bloc utilisateur unique : initiales + nom + chevron, menu déroulant
   (Déconnexion). #auth-user-chip porte la visibilité globale (piloté par
   refreshAuthUI) et sert d'ancre de positionnement pour le menu. */
.auth-user-chip { position: relative; }
.auth-user-chip[hidden] { display: none; }

.user-menu-trigger {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 4px 10px 4px 4px;
  border-radius: 999px;
  border: 1px solid var(--panel-border-m);
  background: var(--card-bg-2);
  color: inherit;
  font-family: inherit;
  cursor: pointer;
  transition: border-color 0.2s, box-shadow 0.2s;
}
.user-menu-trigger:hover {
  border-color: rgba(51, 199, 230, 0.5);
  box-shadow: 0 0 0 3px rgba(51, 199, 230, 0.12);
}

.user-avatar-sm {
  width: 24px; height: 24px;
  border-radius: 50%;
  background: linear-gradient(150deg, var(--blue), var(--cyan));
  display: flex; align-items: center; justify-content: center;
  font-size: 10px;
  font-weight: 800;
  color: #04141f;
  flex-shrink: 0;
}

.auth-user-name {
  font-size: 12px;
  font-weight: 700;
  color: var(--text-2);
  max-width: 140px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.chevron-icon {
  color: var(--text-dim);
  flex-shrink: 0;
  transition: transform 0.2s ease;
}
.user-menu-trigger[aria-expanded="true"] .chevron-icon { transform: rotate(180deg); }

.user-menu-dropdown {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  min-width: 170px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 6px;
  background: var(--panel-bg);
  border: 1px solid var(--panel-border-m);
  border-radius: 10px;
  box-shadow: 0 12px 28px -8px rgba(0, 0, 0, 0.35);
  z-index: 30;
}
.user-menu-dropdown[hidden] { display: none; }

.user-menu-item {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  border: none;
  background: none;
  color: var(--text);
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 600;
  text-align: left;
  padding: 8px 10px;
  border-radius: 7px;
  cursor: pointer;
}
.user-menu-item:hover { background: var(--card-bg-2); color: var(--cyan); }
[data-theme="light"] .user-menu-item:hover { color: var(--blue); }
/* Administration est un LIEN (`<a href="/admin">`) et non un bouton : c'est une
   navigation, elle doit s'ouvrir dans un onglet au clic du milieu comme
   n'importe quel lien. Ces deux règles lui rendent l'apparence des autres
   entrées, que le style de lien par défaut trahirait. */
a.user-menu-item { text-decoration: none; }
a.user-menu-item[hidden] { display: none; }
/* Séparateur : la déconnexion est d'une autre nature que les entrées de
   navigation qui la précèdent, et se trouver dessus par inadvertance coûte
   cher. */
.user-menu-sep {
  height: 1px;
  margin: 4px 2px;
  background: var(--panel-border);
}

/* ------------------------------------------------------------- Mon compte */
/* Liste de définition : chaque ligne est une paire libellé/valeur, ce qu'un
   `<dl>` dit déjà — inutile de le rejouer en ARIA. */
.account-fields { margin: 0; padding: 0; }
.account-fields[hidden] { display: none; }
.account-row {
  display: grid;
  grid-template-columns: minmax(0, 8.5rem) minmax(0, 1fr);
  gap: 12px;
  align-items: baseline;
  padding: 9px 0;
  border-bottom: 1px solid var(--panel-border);
}
.account-row:last-child { border-bottom: none; }
.account-row dt {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-dim);
}
.account-row dd {
  margin: 0;
  font-size: 13.5px;
  color: var(--text-2);
  /* Une adresse longue ne doit pas élargir la modale. */
  overflow-wrap: anywhere;
}
/* Champ facultatif jamais renseigné : un tiret dit « rien ici », là où le vide
   laisserait croire à un défaut d'affichage. */
.account-row dd.is-empty { color: var(--text-dim); font-style: italic; }

.account-status-badge {
  display: inline-block;
  padding: 2px 9px;
  border-radius: 999px;
  border: 1px solid rgba(51, 199, 230, 0.38);
  background: rgba(51, 199, 230, 0.10);
  color: var(--cyan);
  font-size: 11.5px;
  font-weight: 700;
}
[data-theme="light"] .account-status-badge { color: var(--blue); }

.account-state {
  margin: 0 0 4px;
  font-size: 13px;
  color: var(--text-muted);
}
.account-state[hidden] { display: none; }
.account-note {
  margin: 14px 0 0;
  font-size: 12px;
  color: var(--text-dim);
}
.account-note[hidden] { display: none; }
.account-note a { color: var(--cyan); }
[data-theme="light"] .account-note a { color: var(--blue); }

.modal-auth { max-width: 400px; }
.auth-form { display: flex; flex-direction: column; gap: 12px; }
.auth-field { display: flex; flex-direction: column; gap: 5px; }
.auth-field[hidden] { display: none; }
.auth-label {
  font-size: 11px;
  font-weight: 700;
  color: var(--text-muted);
}
.auth-optional { font-weight: 400; color: var(--text-dim); }
.auth-input { width: 100%; }
.auth-error {
  font-size: 11.5px;
  line-height: 1.5;
  margin: 0;
  color: var(--red);
}
.auth-error[hidden] { display: none; }
.auth-success {
  font-size: 11.5px;
  line-height: 1.5;
  margin: 0;
  color: var(--green);
}
.auth-success[hidden] { display: none; }
/* État transitoire : « Vérification de votre adresse e-mail… ». Ton neutre
   assumé — ni vert ni rouge tant que le serveur n'a pas répondu. */
.auth-status {
  font-size: 11.5px;
  line-height: 1.5;
  margin: 0;
  color: var(--text-muted);
}
.auth-status[hidden] { display: none; }
/* Écran « demande enregistrée » (mode pending) — compte rendu sans champ,
   même vocabulaire typographique que le reste de la modale. */
.auth-pending { display: flex; flex-direction: column; gap: 8px; }
.auth-pending[hidden] { display: none; }
.auth-pending-lead {
  font-size: 12.5px;
  font-weight: 700;
  line-height: 1.5;
  margin: 0;
  color: var(--text);
}
.auth-pending-text {
  font-size: 11.5px;
  line-height: 1.5;
  margin: 0;
  color: var(--text-muted);
}
/* Prénom + Nom côte à côte, empilés quand la modale est étroite. */
.auth-field-pair { display: flex; gap: 10px; }
.auth-field-pair[hidden] { display: none; }
.auth-field-pair .auth-field { flex: 1 1 0; min-width: 0; }
@media (max-width: 420px) {
  .auth-field-pair { flex-direction: column; gap: 12px; }
}
/* Lien "Mot de passe oublié ?" — même vocabulaire que .auth-switch-btn,
   aligné à droite sous le champ mot de passe. */
.auth-forgot-link {
  align-self: flex-end;
  background: none;
  border: none;
  padding: 0;
  margin-top: -6px;
  font: inherit;
  font-size: 11px;
  font-weight: 600;
  color: var(--text-muted);
  cursor: pointer;
  text-decoration: underline;
}
.auth-forgot-link:hover { color: var(--cyan); }
.auth-forgot-link[hidden] { display: none; }
.auth-switch {
  font-size: 11.5px;
  color: var(--text-dim);
  margin: 2px 0 0;
  text-align: center;
}
.auth-switch-btn {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  font-weight: 700;
  color: var(--cyan);
  cursor: pointer;
  text-decoration: underline;
}

/* Modale métadonnées (sauvegarde / renommage) */
.meta-textarea {
  resize: vertical;
  min-height: 64px;
  font-family: inherit;
  line-height: 1.5;
}

/* ============================================== RETOUR UTILISATEUR (bêta) */
/* Réutilise .auth-form / .auth-field / .auth-label / .coord-input : seuls les
   éléments qui n'existaient pas encore (segments, étoiles, consentement) sont
   ajoutés ici. */

.fb-fieldset {
  border: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.fb-fieldset > legend { padding: 0; }

.fb-segments { display: flex; gap: 6px; }
/* L'input radio reste dans le flux et focusable — il porte l'état et le
   clavier ; seul son rendu est délégué au <span> frère. Le masquer par
   `display: none` le retirerait du parcours de tabulation. */
.fb-segment { flex: 1; position: relative; cursor: pointer; }
.fb-segment input {
  position: absolute;
  inset: 0;
  opacity: 0;
  margin: 0;
  cursor: pointer;
}
.fb-segment span {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 34px;
  padding: 0 8px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--panel-border-m);
  background: var(--card-bg-2);
  font-size: 11.5px;
  font-weight: 700;
  color: var(--text-muted);
  text-align: center;
  transition: color 0.15s, border-color 0.15s, background 0.15s;
}
.fb-segment input:checked + span {
  color: var(--cyan);
  border-color: rgba(51, 199, 230, 0.55);
  background: rgba(51, 199, 230, 0.12);
}
.fb-segment input:focus-visible + span {
  box-shadow: 0 0 0 3px rgba(51, 199, 230, 0.18);
}
[data-theme="light"] .fb-segment input:checked + span {
  color: var(--blue);
  border-color: rgba(47, 122, 240, 0.55);
  background: rgba(47, 122, 240, 0.10);
}

.fb-stars { display: flex; align-items: center; gap: 2px; }
.fb-star { position: relative; cursor: pointer; line-height: 1; }
.fb-star input {
  position: absolute;
  inset: 0;
  opacity: 0;
  margin: 0;
  cursor: pointer;
}
.fb-star span[aria-hidden] {
  display: block;
  padding: 2px 3px;
  font-size: 20px;
  color: var(--text-dim);
  transition: color 0.15s;
}
/* Les étoiles se remplissent jusqu'à celle qui est cochée : `:has()` évite de
   dupliquer l'état en JavaScript. */
.fb-star input:checked ~ span[aria-hidden],
.fb-stars:has(.fb-star input:checked) .fb-star:has(~ .fb-star input:checked) span[aria-hidden] {
  color: var(--amber);
}
.fb-star input:focus-visible ~ span[aria-hidden] {
  outline: 2px solid rgba(51, 199, 230, 0.55);
  outline-offset: 1px;
}
.fb-star-clear {
  margin-left: 8px;
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  font-size: 11px;
  font-weight: 600;
  color: var(--text-muted);
  cursor: pointer;
  text-decoration: underline;
}
.fb-star-clear:hover { color: var(--cyan); }
.fb-star-clear[hidden] { display: none; }
[data-theme="light"] .fb-star-clear:hover { color: var(--blue); }

.fb-counter {
  margin: 0;
  align-self: flex-end;
  font-size: 10.5px;
  color: var(--text-dim);
}
.fb-counter.is-over { color: var(--red); }

.fb-consent {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  font-size: 11.5px;
  line-height: 1.45;
  color: var(--text-muted);
  cursor: pointer;
}
.fb-consent input { margin: 1px 0 0; flex-shrink: 0; }

.fb-actions { display: flex; gap: 8px; margin-top: 2px; }
.fb-actions .btn { flex: 1; justify-content: center; }

/* ==================================================== MODALE CONTACT (Guide) */
.contact-intro {
  margin: 0 0 10px;
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--text);
}
/* L'adresse est le contenu principal de cette modale : elle est mise en avant
   et reste sélectionnable à la souris, en plus du bouton de copie. */
.contact-email {
  display: block;
  margin-bottom: 14px;
  font-size: 15px;
  font-weight: 700;
  color: var(--cyan);
  word-break: break-all;
}
.contact-email:hover { text-decoration: underline; }
[data-theme="light"] .contact-email { color: var(--blue); }
.contact-actions { display: flex; flex-direction: column; gap: 8px; }

/* Mes analyses sauvegardées (onglet du panneau gauche) */
.saved-analyses { display: flex; flex-direction: column; gap: 10px; }
/* En-tête du panneau : compteur à gauche, rafraîchissement à droite, sur une
   seule ligne — y compris à 324 px, la plus étroite des largeurs de sidebar. */
.saved-analyses-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
/* Compteur : typographie secondaire, casse normale — c'est une indication, pas
   un titre. Le titre, c'est l'onglet actif. */
.saved-analyses-count {
  margin: 0;
  min-width: 0;
  font-size: 11.5px;
  color: var(--text-dim);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Bouton icône : mêmes dimensions et mêmes états que le menu ⋯ des cartes —
   une seule grammaire d'action discrète dans ce panneau. 28 px de cible,
   au-dessus des 26 px du menu car il est seul sur sa ligne. */
.saved-refresh-btn {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border-radius: 6px; /* {rounded.xs} */
  border: 1px solid transparent;
  background: none;
  color: var(--text-dim);
  cursor: pointer;
}
.saved-refresh-btn:hover:not(:disabled) {
  background: var(--card-bg);
  border-color: var(--panel-border);
  color: var(--text-2);
}
.saved-refresh-btn:disabled { opacity: 0.45; cursor: not-allowed; }
.saved-refresh-btn:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }
/* Rotation pendant le chargement : réutilise le keyframe générique des
   boutons, aucun nouveau mécanisme d'animation. */
.saved-refresh-btn.is-loading svg { animation: btn-spinner-rotate 0.8s linear infinite; }
@media (prefers-reduced-motion: reduce) {
  .saved-refresh-btn.is-loading svg { animation: none; }
}
.saved-analyses-state,
.saved-analyses-message {
  font-size: 11px;
  line-height: 1.5;
  margin: 0;
  color: var(--text-dim);
}
.saved-analyses-message.is-ok    { color: var(--green); }
.saved-analyses-message.is-error { color: var(--red); }
.saved-analyses-state[hidden],
.saved-analyses-message[hidden] { display: none; }
.saved-analyses-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
/* Carte compacte : titre + date, 2 blocs métriques, exutoire + action
   principale. Actions secondaires (Renommer/Supprimer) dans un menu ⋯. */
.saved-item {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px 12px;
  border-radius: 11px;
  border: 1px solid var(--panel-border);
  background: var(--card-bg-2);
}
/* Analyse actuellement ouverte : état actif → vocabulaire cyan existant
   (bordure accent + teinte de fond légère), cf. .layer-item.is-active. */
.saved-item.is-current {
  border-color: rgba(51, 199, 230, 0.35);
  background: rgba(51, 199, 230, 0.06);
}

.saved-item-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px;
}
.saved-item-id { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.saved-item-title {
  font-size: 12.5px;
  font-weight: 800;
  color: var(--text-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.saved-item-date {
  font-size: 10.5px;
  color: var(--text-dim);
  font-feature-settings: 'tnum' 1;
}
.saved-item-desc {
  font-size: 10.5px;
  color: var(--text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Menu ⋯ (actions secondaires) */
.saved-menu-wrap { position: relative; flex-shrink: 0; }
.saved-menu-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  padding: 0;
  border-radius: 6px; /* {rounded.xs} */
  border: 1px solid transparent;
  background: none;
  color: var(--text-dim);
  cursor: pointer;
}
.saved-menu-btn:hover,
.saved-menu-btn[aria-expanded="true"] {
  background: var(--card-bg);
  border-color: var(--panel-border);
  color: var(--text-2);
}
.saved-menu {
  position: absolute;
  top: 30px;
  right: 0;
  z-index: 30; /* au-dessus des cartes voisines, sous les modales (100) */
  display: flex;
  flex-direction: column;
  min-width: 136px;
  padding: 4px;
  border-radius: 9px;
  border: 1px solid var(--panel-border-m);
  background: var(--panel-bg);
}
.saved-menu[hidden] { display: none; }
.saved-menu button {
  display: block;
  width: 100%;
  padding: 7px 10px;
  border: none;
  border-radius: 6px;
  background: none;
  text-align: left;
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  color: var(--text);
  cursor: pointer;
}
.saved-menu button:hover { background: var(--card-bg); }
.saved-menu .saved-delete { color: var(--red); }

/* Blocs métriques : même grammaire que les morpho-cards (label 9.5px
   uppercase + valeur bold tabulaire), valeur insécable avec son unité. */
/* Zone centrale d'une carte d'analyse : la forme du bassin à gauche, ses deux
   mesures empilées à droite.

   La colonne de la miniature est FIXE et la seconde élastique : la vignette
   garde la même largeur d'une carte à l'autre — l'œil descend la liste sans
   que les formes sautent — et ce sont les valeurs qui absorbent la largeur
   disponible. `align-items: stretch` (défaut) fait suivre la hauteur de la
   miniature à celle des deux indicateurs : aucune hauteur n'est écrite ici,
   et la carte ne grandit que de la différence entre deux blocs côte à côte et
   deux blocs empilés. */
.saved-item-body {
  display: grid;
  grid-template-columns: 96px minmax(0, 1fr);
  gap: 8px;
}
.saved-item-shape {
  /* Repère du SVG, qui est détaché du flux : c'est la HAUTEUR DES DEUX
     INDICATEURS, à côté, qui fixe celle de cette case — jamais l'inverse. */
  position: relative;
  /* Plancher de lisibilité : sans lui, la case suivrait la hauteur des deux
     indicateurs et un bassin allongé n'y tiendrait plus que sur quelques
     pixels de large. */
  min-height: 70px;
  border-radius: 9px;
  /* Même vocabulaire que les cadres « Surface » et « Périmètre » : c'est un
     indicateur de plus, pas un élément d'une autre famille. */
  border: 1px solid var(--panel-border);
  background: var(--card-bg);
  min-width: 0;
  overflow: hidden;
}
/* La marge autour de la forme vient du `viewBox` calculé côté serveur (9 %
   de l'emprise) : elle reste donc la même quelle que soit la taille rendue,
   et ne dépend pas d'un rembourrage CSS qui varierait avec la largeur du
   panneau. */
/* DÉTACHÉE DU FLUX, volontairement.
   Un SVG dans le flux impose sa taille intrinsèque, c'est-à-dire le rapport
   de son `viewBox` : un bassin deux fois plus haut que large étirait la carte
   à 269 px au lieu de 148. En position absolue il ne participe plus au calcul
   des hauteurs — il se contente de remplir la case, et `preserveAspectRatio`
   l'y ajuste sans le déformer. La hauteur d'une carte ne dépend donc plus de
   la forme du bassin qu'elle montre. */
.basin-outline {
  position: absolute;
  inset: 0;
  /* En POURCENTAGE, et non `auto` : un SVG porteur d'un `viewBox` est un
     élément remplacé, dont la taille `auto` est la taille INTRINSÈQUE — soit
     le rapport du viewBox. Il débordait alors la case, que `overflow: hidden`
     rognait : un bassin deux fois plus haut que large n'était visible que par
     sa tranche centrale. Un pourcentage se résout contre la case, qui a une
     hauteur définie, et le tracé y est ajusté en entier.
     La marge autour de la forme n'est pas ajoutée ici : elle est déjà dans le
     `viewBox` calculé côté serveur (9 % de l'emprise). */
  width: 100%;
  height: 100%;
  display: block;
  /* Purement informative : elle n'intercepte rien. Sans cela la vignette
     avalerait les clics destinés à la carte qui la porte. */
  pointer-events: none;
}
.basin-outline path {
  fill: none;
  stroke: var(--cyan);
  stroke-width: 1.4;
  stroke-linejoin: round;
  stroke-linecap: round;
}
/* Analyse sans géométrie exploitable : le même cadre, une forme générique
   discrète. Pas de message d'erreur — la carte garde toutes ses actions. */
.basin-outline.is-empty path {
  stroke: var(--text-dim);
  stroke-width: 1.1;
  stroke-dasharray: 4 3;
  opacity: 0.55;
}
/* En clair, le cyan du thème sombre pâlirait sur fond blanc : c'est le bleu
   HydroBassin qui porte le contour. `--cyan` et `--blue` sont communs aux deux
   thèmes — seul l'usage change ici, aucune couleur n'est réécrite. */
[data-theme="light"] .basin-outline path {
  stroke: var(--blue);
}

.saved-item-stats {
  display: grid;
  grid-template-rows: 1fr 1fr;
  gap: 6px;
  min-width: 0;
}
/* Empilés le long de la miniature, les deux indicateurs tiennent chacun sur
   UNE ligne : libellé à gauche, valeur à droite. Superposer libellé et valeur
   comme lorsqu'ils étaient côte à côte doublerait la hauteur de la carte pour
   la même information. */
.saved-stat {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  padding: 6px 9px;
  border-radius: 9px;
  border: 1px solid var(--panel-border);
  background: var(--card-bg);
  min-width: 0;
}
.saved-stat-label {
  flex: none;
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: 0.7px;
  text-transform: uppercase;
  color: var(--text-dim);
}
.saved-stat-value {
  font-size: 12.5px;
  font-weight: 800;
  color: var(--text-2);
  font-feature-settings: 'tnum' 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.saved-item-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  flex-wrap: wrap;
}
.saved-item-outlet {
  flex: 1;
  min-width: 0;
  font-size: 10.5px;
  color: var(--text-dim);
  font-feature-settings: 'tnum' 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.saved-open {
  flex-shrink: 0;
  height: 30px;
  padding: 0 12px;
  font-size: 11.5px;
  font-weight: 700;
}

/* Sauvegarde en base (bouton + badge d'état + message de retour) */
.btn-save { margin-top: 8px; }
.save-badge {
  display: inline-flex;
  align-items: center;
  margin-left: auto;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 10px;
  font-weight: 700;
  background: rgba(109, 142, 166, 0.14);
  border: 1px solid rgba(109, 142, 166, 0.30);
  color: var(--text-muted);
}
.save-badge.is-saved {
  background: rgba(55, 216, 150, 0.14);
  border-color: rgba(55, 216, 150, 0.30);
  color: var(--green);
}
.save-badge[hidden] { display: none; }
.save-status {
  font-size: 11px;
  line-height: 1.5;
  margin: 8px 0 0;
  color: var(--text-muted);
}
.save-status.is-ok    { color: var(--green); }
.save-status.is-error { color: var(--red); }
.save-status[hidden]  { display: none; }

/* ================================================================ CARTES */

/* Fiches des quatre cartes thématiques téléchargeables (onglet « Cartes »).
   Reprend le vocabulaire visuel du panneau : fond `--card-bg`, bordure
   `--panel-border`, rayon `--radius`, bouton `.btn.btn-primary` d'origine.
   Seules les couleurs d'ACCENT par thème sont nouvelles, et elles sont
   centralisées ci-dessous. */

/* ---- Accents thématiques -------------------------------------------------
   Une couleur d'identité par thème, déclinée pour les deux modes. Elles ne
   servent QU'À trois endroits : l'icône, son conteneur, et un liseré interne
   de 2 px sur le bord gauche de la fiche. Le bouton, lui, garde la couleur
   d'action unique de HydroBassin — quatre boutons de quatre couleurs
   feraient croire à quatre actions différentes.

   Ces valeurs n'ont RIEN à voir avec les palettes des PNG générés, qui
   viennent des statistiques métier et ne sont pas touchées ici. */
:root {
  --tm-elevation: #8fae7e;   /* vert-olive — relief, altitudes */
  --tm-landcover: #4fc98a;   /* vert       — végétation, occupation du sol */
  --tm-pedology:  #c98a5e;   /* brun terre — sols */
  --tm-geology:   #dfa93f;   /* ocre       — roches, strates */
  --tm-bioclimat: #35b6c4;   /* bleu-vert  — climat */
}
[data-theme="light"] {
  /* Assombries : les teintes du mode sombre passeraient à 2:1 sur fond clair. */
  --tm-elevation: #4a6b3c;
  --tm-landcover: #1c8a56;
  --tm-pedology:  #96562c;
  --tm-geology:   #8d6410;
  --tm-bioclimat: #0e7c8a;
}

.thematic-map-card[data-accent="elevation"] { --tm-accent: var(--tm-elevation); }
.thematic-map-card[data-accent="landcover"] { --tm-accent: var(--tm-landcover); }
.thematic-map-card[data-accent="pedology"]  { --tm-accent: var(--tm-pedology); }
.thematic-map-card[data-accent="geology"]   { --tm-accent: var(--tm-geology); }
.thematic-map-card[data-accent="bioclimat"] { --tm-accent: var(--tm-bioclimat); }

/* ---- Grille --------------------------------------------------------------
   `container-type: inline-size` plutôt qu'une media query : la largeur utile
   du panneau ne se déduit pas de celle de l'écran. Mesuré dans l'application
   réelle : 301 px sur desktop (panneau fixe de 340 px), 346 px en tiroir
   tablette, 325 px en tiroir téléphone. Une règle fondée sur le viewport
   donnerait donc DEUX colonnes sur un écran de 1920 px là où il n'y a place
   que pour une, et une seule sur tablette là où deux tiennent.

   Le seuil de 344 px est la largeur en dessous de laquelle deux fiches ne
   peuvent plus afficher « Générer et télécharger » sans le replier : à
   301 px utiles, deux colonnes donneraient des fiches de 145 px pour un
   libellé qui en réclame 122 à 11 px, marges comprises. */
.thematic-maps { container-type: inline-size; }

.thematic-maps-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 10px;
  margin-top: 12px;
  align-items: stretch;      /* fiches de même hauteur sur une même ligne */
}
@container (min-width: 344px) {
  .thematic-maps-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ---- Fiche ---------------------------------------------------------------
   Compactée d'environ 15 % par rapport à l'étape 5 (163 px -> ~138 px à
   l'état disponible) : marges resserrées, icône de 34 à 28 px, description
   raccourcie et bornée à deux lignes. */
.thematic-map-card {
  container-type: inline-size;
  container-name: tmcard;

  display: flex;
  flex-direction: column;
  gap: 5px;
  padding: 9px 11px;

  background: var(--card-bg);
  /* L'accent TEINTE la bordure entière plutôt que de former un bandeau
     coloré sur un seul côté : ce bandeau latéral est un tic d'interface, et
     il pesait lourd répété quatre fois dans une colonne de 300 px. La couleur
     du thème reste lisible — elle borde la fiche sur tout son pourtour — sans
     ajouter un quatrième aplat vif à l'écran. */
  border: 1px solid color-mix(in srgb, var(--tm-accent) 26%, var(--panel-border));
  border-radius: var(--radius);
  transition: border-color 0.18s ease, background 0.18s ease;
}
/* Mode clair : une ombre portée très légère décolle les fiches du panneau,
   dont le fond est presque aussi clair qu'elles. En mode sombre la bordure
   suffit — une ombre y serait invisible ou sale. */
[data-theme="light"] .thematic-map-card {
  box-shadow: 0 1px 2px rgba(34, 62, 98, 0.07);
}

/* Survol discret, et seulement là où un vrai pointeur existe : sur écran
   tactile `:hover` reste collé après un appui. Aucune information n'en
   dépend (cf. §11 accessibilité). */
@media (hover: hover) and (pointer: fine) {
  .thematic-map-card:hover {
    border-color: color-mix(in srgb, var(--tm-accent) 45%, var(--panel-border-m));
  }
}

.tmc-head {
  display: flex;
  align-items: center;
  gap: 8px;
}
.tmc-icon {
  flex-shrink: 0;
  width: 28px; height: 28px;
  border-radius: var(--radius-sm);
  /* Teinte de l'accent, très diluée : le conteneur signale le thème sans
     colorer la fiche entière. */
  background: color-mix(in srgb, var(--tm-accent) 15%, transparent);
  border: 1px solid color-mix(in srgb, var(--tm-accent) 32%, transparent);
  color: var(--tm-accent);
  display: flex; align-items: center; justify-content: center;
}
/* Les SVG sont ceux de l'étape 5, inchangés : même `viewBox`, mêmes tracés,
   même `stroke-width="1.7"`. Seule leur taille de rendu passe de 18 à 16 px —
   l'épaisseur de trait étant exprimée dans le `viewBox`, elle suit la même
   réduction et la géométrie reste identique. */
.tmc-icon svg { width: 16px; height: 16px; }

/* ---- Statut --------------------------------------------------------------
   Le statut est TEXTUEL avant d'être coloré : « Indisponible », « Disponible »,
   « En cours… », « En attente ». La pastille de couleur ne fait que doubler
   l'information, jamais la porter seule. */
.tmc-status {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  flex-shrink: 0;
  padding: 3px 8px;
  border-radius: 999px;
  border: 1px solid var(--panel-border-m);
  background: var(--card-bg-2);
  color: var(--text-muted);
  font-size: 10px;
  font-weight: 700;
  line-height: 1.3;
  white-space: nowrap;
}
.tmc-status::before {
  content: "";
  width: 6px; height: 6px;
  border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
}
.thematic-map-card[data-state="ready"] .tmc-status      { color: var(--green); }
.thematic-map-card[data-state="generating"] .tmc-status { color: var(--cyan); }
.thematic-map-card[data-state="blocked"] .tmc-status    { color: var(--text-dim); }

.tmc-title {
  margin: 0;
  font-size: 12.5px;
  font-weight: 700;
  color: var(--text-2);
  line-height: 1.2;
}
.tmc-desc {
  margin: 0;
  font-size: 11px;
  line-height: 1.4;
  color: var(--text-muted);
  /* Bornée à deux lignes : au-delà, les fiches d'une même ligne cesseraient
     d'avoir la même hauteur utile. Le texte n'est jamais coupé au milieu d'un
     mot — `overflow-wrap` reste sur les états d'erreur, plus imprévisibles. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.tmc-hint,
.tmc-message {
  margin: 0;
  font-size: 10.5px;
  line-height: 1.4;
  color: var(--text-dim);
  overflow-wrap: anywhere;
}
.tmc-hint[hidden],
.tmc-message[hidden] { display: none; }
/* L'état n'est jamais porté par la seule couleur : le texte lui-même dit ce
   qui se passe (« Carte téléchargée. », message d'erreur explicite). */
.tmc-message.is-success { color: var(--green); }
.tmc-message.is-error { color: var(--red); }

/* ---- Bouton --------------------------------------------------------------
   `margin-top: auto` colle le bouton au bas de la fiche : sur une même ligne
   de grille, les quatre boutons s'alignent quelle que soit la longueur des
   textes au-dessus. */
.tmc-action {
  position: relative;
  margin-top: auto;
  height: 44px;              /* cible tactile minimale, tous formats */
  font-size: 12.5px;
  border-radius: var(--radius-sm);
  /* Halo de `.btn-primary` nettement adouci : il convient à un bouton unique
     et dominant (« Délimiter le bassin »), pas à quatre boutons empilés dans
     un panneau de 300 px, où il empâtait la colonne. La couleur d'action,
     elle, est rigoureusement celle de l'application. */
  box-shadow: 0 3px 10px -7px rgba(47, 122, 240, 0.75),
              inset 0 1px 0 rgba(255, 255, 255, 0.10);
}
.tmc-action:hover:not(:disabled) {
  box-shadow: 0 5px 14px -7px rgba(47, 122, 240, 0.85),
              inset 0 1px 0 rgba(255, 255, 255, 0.14);
}
/* Anneau de focus clavier — même vocabulaire cyan que le reste de
   l'application (`.guide-mini-card:focus-visible`, `.btn-reset-link`…).
   Sans lui, ces quatre boutons héritaient du seul anneau par défaut du
   navigateur, peu lisible sur un dégradé bleu. */
.tmc-action:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(51, 199, 230, 0.38),
              0 3px 10px -7px rgba(47, 122, 240, 0.75);
}
/* Le spinner occupe la place de l'icône de téléchargement, aux mêmes
   dimensions : le bouton ne change pas de largeur en passant en génération —
   même principe que `.btn-spinner` du bouton d'analyse. */
.tmc-spinner {
  display: none;
  width: 15px; height: 15px;
  flex-shrink: 0;
  border-radius: 50%;
  border: 2px solid rgba(51, 199, 230, 0.35);
  border-top-color: var(--cyan);
  animation: btn-spinner-rotate 0.8s linear infinite;
}
.thematic-map-card[data-state="generating"] .tmc-spinner { display: inline-block; }
.thematic-map-card[data-state="generating"] .tmc-action-icon { display: none; }

/* Une AUTRE fiche est en cours de génération : le bouton est grisé le temps
   que celle-ci se termine. L'état est nommé pour rester lisible dans
   l'inspecteur et dans les tests. */
.thematic-map-card[data-state="blocked"] .tmc-action { cursor: not-allowed; }

/* Fiche étroite — c'est la largeur de la FICHE qui décide, pas celle du
   panneau : à deux colonnes une fiche tombe vers 145-170 px, où le libellé
   du bouton ne tient plus sur une ligne avec son icône. On retire l'icône
   (le spinner, lui, reste : c'est l'indicateur de progression) et on autorise
   le repli du libellé plutôt que de le laisser déborder. */
@container tmcard (max-width: 210px) {
  .tmc-action {
    padding: 0 8px;
    font-size: 11.5px;
    white-space: normal;
    line-height: 1.15;
    text-align: center;
  }
  .thematic-map-card .tmc-action-icon { display: none; }
}

/* Mouvement réduit : le spinner cesse de tourner (l'état reste lisible par le
   libellé du bouton, le statut et `aria-busy`), les transitions disparaissent. */
@media (prefers-reduced-motion: reduce) {
  .tmc-spinner { animation: none; }
  .thematic-map-card { transition: none; }
}

/* Les règles `.coming-soon-*` et `.csi-*` ont été retirées avec l'encart
   « module à venir » du panneau Cartes : les quatre cartes thématiques sont
   livrées, plus rien dans la page n'utilisait ces classes. */

/* ================================================================ FOOTER */
.app-footer {
  height: 38px;
  flex: 0 0 38px;
  display: flex;
  align-items: center;
  gap: 22px;
  padding: 0 22px;
  background: var(--panel-bg);
  border-top: 1px solid var(--panel-border);
  font-size: 11px;
  color: var(--text-dim);
  backdrop-filter: blur(10px);
  flex-shrink: 0;
}
.footer-item {
  display: flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
}
.footer-item strong { color: var(--text-muted); font-weight: 600; }
.footer-brand { font-weight: 600; }
.footer-flag { font-size: 13px; margin-left: 4px; }

/* Échelle graphique dans le footer */
.footer-scale-item { gap: 5px; }
.fscale-bar {
  display: inline-block;
  width: 60px;           /* valeur initiale, mise à jour via JS */
  height: 6px;
  border: 1.5px solid var(--cyan);
  border-top: none;      /* forme ⊔ : tirets verticaux + ligne basse */
  min-width: 16px;
  max-width: 120px;
  transition: width 0.18s ease;
  vertical-align: middle;
  flex-shrink: 0;
}
[data-theme="light"] .fscale-bar { border-color: var(--blue); }

/* Position du curseur dans le footer */
#footer-cursor-coords { font-variant-numeric: tabular-nums; display: inline-block; min-width: 190px; }

/* ================================================================ STEPPER (caché, compat workflow.js) */
.step, .step-dot, .step-label,
.stepper { display: none !important; }

/* ================================================================ RESPONSIVE */
/* Largeur du panneau gauche : dégradé progressif plutôt qu'une marche unique.
   La carte est la zone dominante d'HydroBassin — sur un portable (1366-1600 px)
   elle ne doit pas payer l'arrivée de « Mes analyses ». Les trois paliers
   restent tous au-dessus du seuil mesuré de 320 px, en dessous duquel les
   libellés des cartes de sauvegarde commencent à être tronqués.
   Ces blocs ne touchent QUE `.sidebar-left` : le panneau droit garde ses
   propres paliers, inchangés. */
@media (max-width: 1799px) {
  /* Portables 15-16 pouces : 28 px rendus à la carte. */
  .sidebar-left { width: 344px; }
}
@media (max-width: 1499px) {
  /* 1366 px, le cas le plus courant : 324 px laisse 4 px de marge au-dessus du
     seuil et rend 48 px à la carte par rapport à la largeur de base. */
  .sidebar-left { width: 324px; }
}

@media (max-width: 1400px) {
  .title-sub { display: none; }
  .sidebar-right { width: 312px; }
  .morpho-summary-grid { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 1160px) {
  /* Plancher : exactement le seuil de non-troncature mesuré. */
  .sidebar-left  { width: 320px; }
  .sidebar-right { width: 290px; }
  .indices-grid  { grid-template-columns: repeat(2, 1fr); }
}

/* Élargissement du panneau droit sur grand écran (refonte Morphologie) : le
   panneau porte désormais des lignes clé/valeur et deux graphiques — la carte
   garde largement la priorité, mais 340 px était trop étroit dès qu'un écran
   confortable est disponible. Placées APRÈS les règles max-width ci-dessus
   pour l'emporter dans la zone de recouvrement 1280–1400 px (même
   spécificité, cascade). Aucun effet ≤ 1024 px (tiroirs de responsive.css). */
@media (min-width: 1280px) {
  .sidebar-right { width: 400px; }
  .morpho-summary-grid { grid-template-columns: repeat(4, 1fr); }
}
@media (min-width: 1500px) {
  .sidebar-right { width: 450px; }
}
@media (min-width: 1800px) {
  .sidebar-right { width: 480px; }
}

/* Le masquage des deux panneaux sous 960 px (`display: none`) vivait ici. Il
   rendait l'application inutilisable sur smartphone et tablette : les deux
   panneaux portent la totalité du parcours (exutoire, coordonnées, CRS,
   bouton de délimitation, réinitialisation, légende, KPI, graphiques,
   onglets, Guide et FAQ), et rien ne les remplaçait.
   Ils sont désormais transformés en tiroirs par `css/responsive.css`, dont
   toutes les règles sont bornées à `max-width: 1024px`. Le pied de page, lui,
   reste masqué sur petit écran — sa bande dense de 38 px n'a pas d'équivalent
   tactile — mais depuis la feuille responsive, avec le même breakpoint que le
   reste. Ce bloc n'a donc plus de contenu propre.
   Aucun effet à partir de 1025 px, ni avant ni après ce changement. */

/* ===========================================================================
   Aide à la première sélection de l'exutoire + protection du bassin calculé
   (curseur viseur, bulle « Placez l'exutoire », viseur candidat, modale
   « Changer d'exutoire ? », bouton global de sauvegarde)
=========================================================================== */

/* Curseur viseur cyan — hotspot exactement au centre (12 12) pour préserver
   la précision géographique du clic. Purement visuel : aucun traitement
   n'est attaché aux mouvements de la souris. L'outil mesure garde son
   curseur (:not(.is-measuring)). */
#map.is-outlet-picking:not(.is-measuring),
#map.is-outlet-picking:not(.is-measuring) .leaflet-grab,
#map.is-outlet-picking:not(.is-measuring) .leaflet-interactive {
  cursor: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'><g fill='none' stroke='%23071b2e' stroke-width='3.4' stroke-linecap='round' opacity='0.55'><circle cx='12' cy='12' r='7'/><path d='M12 1.5v4.5M12 18v4.5M1.5 12H6M18 12h4.5'/></g><g fill='none' stroke='%2333c7e6' stroke-width='1.8' stroke-linecap='round'><circle cx='12' cy='12' r='7'/><path d='M12 1.5v4.5M12 18v4.5M1.5 12H6M18 12h4.5'/></g><circle cx='12' cy='12' r='1.6' fill='%2333c7e6'/></svg>") 12 12, crosshair;
}

/* Bulle « Placez l'exutoire » — position posée UNE fois près du premier
   survol, jamais suivie par le pointeur. pointer-events:none : elle ne bloque
   ni zoom, ni déplacement, ni clic — seul son « × » est interactif. */
.outlet-coachmark {
  position: absolute;
  left: 0; top: 0;               /* position réelle portée par transform */
  will-change: transform;        /* suivi du curseur par translate3d (rAF) */
  z-index: 9;
  max-width: 240px;
  padding: 10px 30px 11px 12px;
  background: rgba(9, 20, 33, 0.94);
  border: 1px solid rgba(51, 199, 230, 0.38);
  border-radius: 11px;
  box-shadow: 0 10px 28px -10px rgba(0, 0, 0, 0.55);
  pointer-events: none;
  animation: modal-fade-in 0.18s ease;
}
.outlet-coachmark[hidden] { display: none; }
.outlet-coachmark-title {
  font-size: 12.5px;
  font-weight: 800;
  color: var(--text);
  margin-bottom: 3px;
}
.outlet-coachmark-text {
  font-size: 11.5px;
  line-height: 1.45;
  color: var(--text-muted);
}
.outlet-coachmark-close {
  /* Frère de la bulle (jamais son enfant : un ancêtre pointer-events:none le
     rendrait injouable) — positionné sur son coin supérieur droit par le même
     translate3d. */
  position: absolute;
  left: 0; top: 0;
  will-change: transform;
  z-index: 10;
  width: 24px; height: 24px;
  border: none;
  background: none;
  color: var(--text-dim);
  font-size: 15px;
  line-height: 1;
  border-radius: 6px;
  cursor: pointer;
}
.outlet-coachmark-close[hidden] { display: none; }
.outlet-coachmark-close:hover { color: var(--text); background: rgba(86, 158, 214, 0.12); }
.outlet-coachmark-close:focus-visible { outline: 2px solid var(--cyan); outline-offset: 1px; }
/* Flèche sur le bord qui fait face au curseur (la bulle est à droite ou à
   gauche du viseur), à hauteur du point suivi. Aucune flèche au tactile
   (bulle fixe, data-place="fixed"). */
.outlet-coachmark-arrow {
  position: absolute;
  top: var(--coachmark-arrow-y, 50%);
  width: 10px; height: 10px;
  transform: translateY(-50%) rotate(45deg);
  background: inherit;
  border: 1px solid rgba(51, 199, 230, 0.38);
}
.outlet-coachmark[data-place="right"] .outlet-coachmark-arrow {
  left: -6px;
  border-top: none;
  border-right: none;
}
.outlet-coachmark[data-place="left"] .outlet-coachmark-arrow {
  right: -6px;
  border-bottom: none;
  border-left: none;
}
.outlet-coachmark[data-place="fixed"] .outlet-coachmark-arrow { display: none; }
[data-theme="light"] .outlet-coachmark {
  background: rgba(255, 255, 255, 0.96);
  border-color: rgba(47, 122, 240, 0.30);
}
[data-theme="light"] .outlet-coachmark-arrow { border-color: rgba(47, 122, 240, 0.30); }
@media (prefers-reduced-motion: reduce) {
  .outlet-coachmark { animation: none; }
}

/* Viseur de position CANDIDATE — repère discret pendant la confirmation,
   jamais confondu avec le marqueur d'exutoire (croix, pas de disque plein). */
.outlet-candidate-icon { background: none; border: none; }
.outlet-candidate-cross {
  display: block;
  width: 22px; height: 22px;
  border: 1.6px dashed var(--cyan);
  border-radius: 50%;
  position: relative;
  opacity: 0.9;
}
.outlet-candidate-cross::before,
.outlet-candidate-cross::after {
  content: '';
  position: absolute;
  background: var(--cyan);
}
.outlet-candidate-cross::before {
  left: 50%; top: 4px; bottom: 4px;
  width: 1.6px;
  transform: translateX(-50%);
}
.outlet-candidate-cross::after {
  top: 50%; left: 4px; right: 4px;
  height: 1.6px;
  transform: translateY(-50%);
}

/* Modale « Changer d'exutoire ? » — même socle que les autres modales, en
   plus compact. Le bassin reste visible derrière le voile existant. */
.modal-outlet-change { max-width: 470px; }
.outlet-change-head {
  display: flex;
  align-items: center;
  gap: 10px;
}
.outlet-change-warn {
  flex-shrink: 0;
  width: 30px; height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 9px;
  color: #f0b429;
  background: rgba(240, 180, 41, 0.12);
  border: 1px solid rgba(240, 180, 41, 0.32);
}
.outlet-change-message {
  margin: 0;
  padding: 14px 20px 0;
  font-size: 13px;
  line-height: 1.5;
  color: var(--text-2);
}
.outlet-change-note {
  margin: 12px 20px 0;
  padding: 10px 12px;
  border-radius: 10px;
  font-size: 12px;
  line-height: 1.5;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.outlet-change-note[hidden] { display: none; }
.outlet-change-note strong { font-size: 12.5px; }
.outlet-change-note.is-info {
  background: rgba(61, 136, 245, 0.10);
  border: 1px solid rgba(61, 136, 245, 0.30);
  color: var(--text-2);
}
.outlet-change-note.is-success {
  background: rgba(55, 216, 150, 0.10);
  border: 1px solid rgba(55, 216, 150, 0.30);
  color: var(--text-2);
}
.outlet-change-note.is-success strong { color: var(--green); }
[data-theme="light"] .outlet-change-note.is-success strong { color: #0e8a5c; }
.outlet-change-error {
  margin: 10px 20px 0;
  font-size: 12px;
  color: var(--red);
}
.outlet-change-error[hidden] { display: none; }
.outlet-change-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding: 16px 20px 18px;
}
.outlet-change-actions .btn {
  height: 38px;
  font-size: 12.5px;
  flex: 1 1 auto;
  justify-content: center;
}
/* Seconde phrase de la confirmation de suppression : même paragraphe, ton
   plus discret — l'avertissement ne doit pas rivaliser avec le nom de
   l'analyse, qui est l'information que l'utilisateur doit vérifier. */
.delete-analysis-hint {
  display: block;
  margin-top: 6px;
  font-size: 12px;
  color: var(--text-dim);
}

/* Action destructive — rouge, toujours EN DERNIER dans l'ordre de lecture.
   Partagée par « Changer sans sauvegarder » et « Supprimer » (confirmation
   de suppression d'une analyse) : une seule définition du rouge d'action. */
.outlet-change-discard {
  background: rgba(248, 113, 113, 0.12);
  color: var(--red);
  border: 1px solid rgba(248, 113, 113, 0.42);
}
.outlet-change-discard:hover:not(:disabled) {
  background: rgba(248, 113, 113, 0.20);
  border-color: rgba(248, 113, 113, 0.6);
}
.outlet-change-discard:focus-visible { outline: 2px solid var(--red); outline-offset: 2px; }
[data-theme="light"] .outlet-change-discard { color: #c93b3b; }
/* Sur mobile : boutons empilés, la destruction reste en bas. */
@media (max-width: 560px) {
  .outlet-change-actions { flex-direction: column; }
}

/* Bouton global de sauvegarde — état succès discret. */
#btn-save-global.is-saved {
  color: var(--green);
  opacity: 1;
}
[data-theme="light"] #btn-save-global.is-saved { color: #0e8a5c; }

/* Erreur de validation locale d'un champ de nommage — sous le champ, rouge
   discret, reliée par aria-describedby. */
.field-error {
  margin: 5px 0 0;
  font-size: 11px;
  line-height: 1.4;
  color: var(--red);
}
.field-error[hidden] { display: none; }

/* Actions de la modale de métadonnées : Annuler + Sauvegarder côte à côte. */
.meta-actions {
  display: flex;
  gap: 8px;
}
.meta-actions .btn { flex: 1 1 auto; justify-content: center; height: 42px; }

/* Étape de nommage de la modale « Changer d'exutoire ? » — remplace le
   contenu de confirmation, jamais un second dialogue. */
.outlet-change-naming { padding: 4px 20px 0; }
.outlet-change-naming[hidden] { display: none; }
.outlet-change-naming-text {
  margin: 8px 0 12px;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--text-2);
}
.outlet-change-naming .auth-label { display: block; margin-bottom: 5px; }
.outlet-change-naming-actions { padding: 14px 0 18px; }
.outlet-change-message[hidden] { display: none; }
.outlet-change-actions[hidden] { display: none; }

/* ============================================================ VUE 3D (POC)
   Scène Three.js isolée du bassin — frère de #map dans .map-area. Montrée /
   cachée par [hidden] (propriété el.hidden). Bascule « Vue 2D | Vue 3D » en
   haut à droite de la zone centrale, visible dans les deux modes. */
#scene3d {
  position: absolute;
  inset: 0;
  z-index: 450; /* au-dessus des panes Leaflet (max 400), sous la bascule */
  /* Fond de scène : le canvas WebGL est TRANSPARENT, ce dégradé suit le
     thème HydroBassin sans reconstruction de la scène. */
  background: linear-gradient(180deg, #0c1722 0%, #172733 100%);
  border-radius: inherit;
  overflow: hidden;
}
[data-theme="light"] #scene3d {
  background: linear-gradient(180deg, #f3f6f8 0%, #e4ebf0 100%);
}
#scene3d[hidden] { display: none !important; }
.scene3d-canvas, .scene3d-canvas canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

/* --- Bascule de mode --------------------------------------------------- */
.view-mode-switch {
  position: absolute;
  top: 12px;
  right: 60px; /* laisse le contrôle de zoom Leaflet à l'extrême droite */
  z-index: 460;
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 3px;
  background: rgba(20, 26, 33, 0.85);
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 10px;
  backdrop-filter: blur(4px);
}
.view-mode-switch[hidden] { display: none !important; }
.vms-btn {
  border: 0;
  background: transparent;
  color: #c8d2dc;
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  padding: 5px 12px;
  border-radius: 8px;
  cursor: pointer;
}
.vms-btn:hover:not(:disabled) { color: #fff; background: rgba(255, 255, 255, 0.08); }
.vms-btn:focus-visible { outline: 2px solid var(--cyan); outline-offset: 1px; }
.vms-btn.is-active {
  background: rgba(51, 199, 230, 0.18);
  color: var(--cyan);
}
.vms-btn:disabled { opacity: 0.45; cursor: not-allowed; }
[data-theme="light"] .view-mode-switch { background: rgba(255, 255, 255, 0.92); border-color: rgba(30, 45, 60, 0.18); }
[data-theme="light"] .vms-btn { color: #4a6278; }
[data-theme="light"] .vms-btn:hover:not(:disabled) { color: #16324a; background: rgba(30, 45, 60, 0.07); }
[data-theme="light"] .vms-btn.is-active { background: rgba(9, 130, 158, 0.14); color: #087e9b; }

/* --- Bandeau inférieur : grille à deux groupes EN FLUX ------------------ */
/* Le conteneur 3D est un container query : le point de rupture dépend de SA
   largeur réelle (panneaux latéraux ouverts compris), pas de la fenêtre. */
#scene3d { container-type: inline-size; }
.scene3d-bar {
  position: absolute;
  left: 12px;
  right: 12px;
  bottom: 12px;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  column-gap: 16px;
  row-gap: 8px;
  pointer-events: none; /* la barre est transparente aux gestes 3D… */
}
.scene3d-bar > * { pointer-events: auto; } /* …mais pas ses groupes. */
.scene3d-hud {
  justify-self: start;
  display: flex;
  align-items: center;
  flex-wrap: wrap;      /* peut se contracter sans jamais passer SOUS la légende */
  gap: 8px;
  padding: 6px 10px;
  background: rgba(20, 26, 33, 0.82);
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 10px;
  color: #e8edf2;
  font-size: 12px;
  line-height: 1;
  backdrop-filter: blur(4px);
}
.scene3d-hud[hidden] { display: none !important; }
.scene3d-exag { display: flex; align-items: center; gap: 7px; white-space: nowrap; }
.scene3d-exag input[type="range"] { width: 96px; accent-color: #7fb7e6; margin: 0; }
#scene3d-exaggeration-value { min-width: 32px; font-variant-numeric: tabular-nums; font-weight: 600; }
.scene3d-btn {
  border: 1px solid rgba(255, 255, 255, 0.22);
  background: rgba(255, 255, 255, 0.08);
  color: #e8edf2;
  border-radius: 7px;
  padding: 4px 8px;
  font: inherit;
  font-size: 12px;
  line-height: 1;
  cursor: pointer;
  white-space: nowrap;
}
.scene3d-btn:hover { background: rgba(255, 255, 255, 0.16); }
.scene3d-btn-icon { display: inline-flex; align-items: center; padding: 4px 6px; }
/* Infobulle accessible : visible au survol ET au focus clavier. */
.scene3d-info { position: relative; opacity: 0.7; cursor: help; font-size: 13px; }
.scene3d-info:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; border-radius: 4px; }
.scene3d-info::after {
  content: attr(data-tip);
  position: absolute;
  left: 50%;
  bottom: calc(100% + 8px);
  transform: translateX(-50%);
  width: max-content;
  max-width: 280px;
  padding: 7px 10px;
  background: rgba(14, 19, 25, 0.96);
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 8px;
  color: #e8edf2;
  font-size: 11.5px;
  line-height: 1.45;
  white-space: pre-line;
  text-align: left;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.15s;
  pointer-events: none;
  z-index: 10;
}
.scene3d-info:hover::after,
.scene3d-info:focus::after { opacity: 1; visibility: visible; }

/* --- Légende altimétrique (groupe droit du bandeau) --------------------- */
.scene3d-legend {
  justify-self: end;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  background: rgba(20, 26, 33, 0.82);
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 10px;
  color: #e8edf2;
  font-size: 11.5px;
  white-space: nowrap; /* min/max jamais tronqués : la grille replie avant */
  backdrop-filter: blur(4px);
}
.scene3d-legend[hidden] { display: none !important; }

/* --- Thème clair du bandeau : contrôles flottants intégrés au thème -------
   Mêmes conventions que la bascule Vue 2D/3D et les panneaux clairs de
   l'interface (fond blanc translucide + bordure ardoise discrète). La rampe
   hypsométrique et toutes les valeurs restent STRICTEMENT identiques. */
[data-theme="light"] .scene3d-hud,
[data-theme="light"] .scene3d-legend {
  background: rgba(255, 255, 255, 0.88);
  border-color: rgba(30, 45, 60, 0.16);
  color: #16324a;
}
[data-theme="light"] .scene3d-exag input[type="range"] { accent-color: #087e9b; }
[data-theme="light"] .scene3d-btn {
  border-color: rgba(30, 45, 60, 0.24);
  background: rgba(30, 45, 60, 0.05);
  color: #2c4a63;
}
[data-theme="light"] .scene3d-btn:hover { background: rgba(30, 45, 60, 0.12); }
[data-theme="light"] .scene3d-info { color: #4a6278; opacity: 0.85; }
[data-theme="light"] .scene3d-info::after {
  background: rgba(255, 255, 255, 0.97);
  border-color: rgba(30, 45, 60, 0.2);
  color: #16324a;
}
.scene3d-ramp {
  display: inline-block;
  width: 110px;
  height: 10px;
  border-radius: 5px;
  border: 1px solid rgba(255, 255, 255, 0.25);
}
.scene3d-minmax { font-variant-numeric: tabular-nums; white-space: nowrap; }

/* --- Indicateur nord (la flèche suit la caméra) ------------------------- */
.scene3d-north {
  position: absolute;
  top: 56px;
  right: 12px;
  width: 30px;
  height: 30px;
  opacity: 0.9;
}
#scene3d-north-needle { transform-origin: 12px 12px; }

/* Thème clair de la boussole : mêmes conventions que les blocs Exagération /
   Altitude (fond blanc translucide, bordure ardoise). Les remplissages du SVG
   sont des ATTRIBUTS de présentation : ces règles CSS les surchargent sans
   toucher au balisage — la logique, la position et l'orientation de
   l'aiguille restent strictement inchangées. */
[data-theme="light"] .scene3d-north svg > circle {
  fill: rgba(255, 255, 255, 0.88);
  stroke: rgba(30, 45, 60, 0.22);
}
[data-theme="light"] #scene3d-north-needle path:last-child {
  fill: #4a6278; /* queue de l'aiguille : ardoise lisible sur fond clair */
}
[data-theme="light"] .scene3d-north svg text {
  fill: #16324a;
  font-weight: 600;
}

/* --- Attribution MapLibre (chemin expérimental ?maplibre3d=1) ------------ */
/* Pastille alignée sur les thèmes HydroBassin : le défaut MapLibre (fond
   blanc semi-opaque) devient un rectangle blanc agressif en thème sombre.
   Portée limitée à #scene3d : la Vue 2D Leaflet n'est jamais concernée. */
#scene3d .maplibregl-ctrl-attrib {
  background: rgba(14, 19, 25, 0.72);
  color: #b9c6d1;
  border-radius: 6px;
  font-size: 11px;
}
#scene3d .maplibregl-ctrl-attrib a { color: #cfdae4; }
[data-theme="light"] #scene3d .maplibregl-ctrl-attrib {
  background: rgba(255, 255, 255, 0.72);
  color: #4a6278;
}
[data-theme="light"] #scene3d .maplibregl-ctrl-attrib a { color: #16324a; }

/* --- Statut / repli ------------------------------------------------------ */
.scene3d-status {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 24px;
  color: #e8edf2;
  font-size: 14px;
  background: rgba(21, 26, 33, 0.92);
}
.scene3d-status[hidden] { display: none !important; }

/* Deux lignes quand les deux groupes ne tiennent plus côte à côte —
   décision prise sur la largeur RÉELLE du conteneur 3D. */
@container (max-width: 650px) {
  .scene3d-bar {
    grid-template-columns: minmax(0, 1fr);
  }
  .scene3d-hud { justify-self: start; }
  .scene3d-legend { justify-self: start; }
  /* Infobulle ⓘ : centrée, elle débordait du bord droit du conteneur
     (overflow:hidden la rognait dès ~420 px). Sur conteneur étroit, elle
     s'ancre au bord droit de l'icône et s'étend vers la gauche, largeur
     bornée à la largeur réelle du conteneur (unités cqw). */
  .scene3d-info::after {
    left: auto;
    right: -6px;
    transform: none;
    max-width: min(280px, 82cqw);
  }
}
@media (max-width: 720px) {
  .view-mode-switch { right: 12px; top: 56px; }
}

/* Piège connu du dépôt : .map-tool-btn pose un display explicite qui
   l'emporte sur la règle UA [hidden]{display:none}. Conservé pour tout futur
   bouton d'outil masquable. */
.map-tool-btn[hidden] { display: none !important; }
