/* Reset : chaque page portait ce bloc dans son <style> local, supprime a la
   migration. Il vit desormais ici, une seule fois pour toutes les pages. */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; padding: 0; }

/* Briques visuelles communes aux pages du front D'ONE 31.
   Aucune couleur en dur : tout vient de tokens.css. */

/* --- Barre superieure --- */
.d-bar {
  background: var(--surface);
  border-radius: var(--r-card);
  padding: var(--sp-3) var(--sp-4);
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}
.d-bar__title { font-size: var(--fs-title); font-weight: 800; color: var(--text-strong); }
.d-bar__sub { font-size: var(--fs-sm); color: var(--text-dim); margin-top: 2px; }
.d-bar__right { margin-left: auto; display: flex; align-items: center; gap: var(--sp-2); }

/* --- Rangees de tuiles --- */
.d-row {
  background: var(--surface);
  border-radius: var(--r-card);
  padding: var(--sp-2);
  display: grid;
  gap: var(--sp-2);
}
.d-row--state { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.d-row--action { grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); }

/* --- Tuile d'etat --- */
.d-tile {
  background: var(--surface-2);
  border-radius: var(--r-tile);
  padding: var(--sp-4) var(--sp-2);
  text-align: center;
}
.d-tile svg { stroke: var(--accent); fill: none; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.d-tile__value { font-size: var(--fs-value); font-weight: 800; color: var(--accent); margin-top: var(--sp-2); line-height: 1; }
.d-tile__value.is-ok { color: var(--ok); }
.d-tile__value.is-warn { color: var(--warn); }
.d-tile__value.is-danger { color: var(--danger); }
/* Avant la premiere reponse de l'API : ni succes ni echec, une couleur
   neutre plutot qu'un rouge d'alerte qui flashe a chaque chargement. */
.d-tile__value.is-pending { color: var(--text-dim); }
.d-tile__label {
  font-size: var(--fs-label);
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--text-dim);
  margin-top: var(--sp-2);
  font-weight: 700;
}

/* --- Tuile d'action --- */
.d-act {
  background: var(--surface-2);
  border-radius: var(--r-tile);
  padding: var(--sp-4) var(--sp-1);
  text-align: center;
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--text);
  cursor: pointer;
  border: 0;
  font-family: inherit;
  min-height: 48px;
}
.d-act svg { stroke: var(--accent); fill: none; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.d-act__label { margin-top: var(--sp-2); }
.d-act.is-selected { background: var(--line); box-shadow: inset 0 0 0 2px var(--accent); }
.d-act.is-off { opacity: .4; cursor: not-allowed; }

/* --- Panneau de detail --- */
.d-panel { background: var(--surface); border-radius: var(--r-card); padding: var(--sp-4); }
.d-panel__kicker { font-size: var(--fs-label); letter-spacing: 1.4px; color: var(--accent); text-transform: uppercase; font-weight: 800; }
.d-panel__title { font-size: var(--fs-title); font-weight: 800; color: var(--text-strong); margin: 4px 0 var(--sp-4); }

/* --- Ligne a points de conduite --- */
.d-line { display: flex; align-items: baseline; gap: var(--sp-1); font-size: var(--fs-md); padding: 7px 0; }
.d-line__key { color: var(--text); }
.d-line__dots { flex: 1; border-bottom: 1px dotted var(--line); transform: translateY(-4px); }
.d-line__value { color: var(--text-strong); font-weight: 600; font-family: ui-monospace, Menlo, monospace; font-size: var(--fs-body); }

/* --- Pastille d'etat : jamais la couleur seule, toujours un mot --- */
.d-state {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: var(--fs-label);
  font-weight: 800;
  border-radius: var(--r-badge);
  padding: 4px 9px;
  white-space: nowrap;
}
.d-state::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex-shrink: 0; }
.d-state.is-live {
  color: var(--ok);
  background: var(--surface-2);                              /* repli */
  background: color-mix(in srgb, var(--ok) 14%, var(--surface-2));
}
.d-state.is-blocked {
  color: var(--warn);
  background: var(--surface-2);                               /* repli */
  background: color-mix(in srgb, var(--warn) 14%, var(--surface-2));
}
.d-state.is-offline {
  color: var(--danger);
  background: var(--surface-2);                               /* repli */
  background: color-mix(in srgb, var(--danger) 14%, var(--surface-2));
}
.d-state.is-pending {
  color: var(--text-dim);
  background: var(--surface-2);                                     /* repli */
  background: color-mix(in srgb, var(--text-dim) 14%, var(--surface-2));
}

/* --- Surimpression sur video --- */
.d-overlay {
  position: absolute;
  left: var(--sp-2); right: var(--sp-2); top: var(--sp-2);
  display: flex; align-items: center; gap: var(--sp-2);
  background: var(--bg);                                      /* repli */
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  border-radius: var(--r-tile);
  padding: 8px 11px;
  /* La bande ne doit pas manger les clics de la carte sous elle (Leaflet,
     outils de mesure) : seuls ses propres controles restent cliquables. */
  pointer-events: none;
  /* Leaflet empile ses panneaux jusqu'a 700 et #map ne cree pas de contexte
     d'empilement : sans cela la bande est PEINTE DESSOUS et devient invisible,
     alors qu'elle reste cliquable — les panneaux laissent passer les clics.
     Le piege est de croire au test de collision, qui la dit bien au-dessus.
     Sous 1000, pour laisser devant les controles Leaflet (echelle, zoom). */
  z-index: 800;
}
.d-overlay .d-btn, .d-overlay .d-overlay__chip, .d-overlay .ctrl-take { pointer-events: auto; }
.d-overlay__name { font-size: var(--fs-md); font-weight: 800; color: var(--text-strong); }
.d-overlay--bottom { top: auto; bottom: var(--sp-2); right: auto; }
/* Les outils de mesure mangeaient la moitie de la tuile Carte dans la grille,
   et s'y retrouvaient sur deux lignes. Ils n'apparaissent qu'une fois la carte
   agrandie, ou il y a la place de tracer et de lire le resultat. La bande de
   meta des vignettes video, elle, garde son comportement. */
.d-overlay--outils { display: none; }
body.zoom.mesures-on .d-vtile.full .d-overlay--outils { display: flex; }
/* Droits carto de l'abonnement : le viewer pose carte3d-on, tiers-on et
   mesures-on sur le body d'apres client-info ; sans la classe, l'outil
   n'existe pas pour le client. */
body.d-viewer:not(.carte3d-on) #btn3d { display: none; }
body.d-viewer:not(.tiers-on) #btnDronesTiers,
body.d-viewer:not(.tiers-on) #btnDronesAmis { display: none; }
body.d-viewer:not(.mesures-on) #btn3dMesure,
body.d-viewer:not(.mesures-on) #btn3dProfil { display: none; }
body.d-viewer:not(.carterapide-on) #btnCarteRapide,
body.d-viewer:not(.carterapide-on) #btnThermique,
body.d-viewer:not(.carterapide-on) #selVolCarteRapide { display: none; }
.d-select { background: var(--surface-2); color: var(--text); border: 1px solid var(--line); border-radius: var(--r-badge); padding: 4px 8px; font-size: var(--fs-sm); font-family: inherit; pointer-events: auto; }
.d-select--vol { max-width: 220px; }
/* --- Menus Couches et Outils de la tuile Carte --- */
/* Neuf commandes avec libelle passaient sur trois lignes dans la grille et
   couvraient le tiers de la carte : les fonds (Couches) et les calques
   metier (Outils) se choisissent dans une colonne depliee sous leur bouton.
   Le menu est un frere de la bande, pas un enfant : la tuile rogne ce qui
   la deborde (overflow hidden), et c'est a la tuile que sa hauteur se
   borne, avec defilement si elle est basse. */
.d-couches {
  position: absolute; left: var(--sp-2); top: calc(var(--touch) + var(--sp-2) * 3);
  max-height: calc(100% - var(--touch) - var(--sp-2) * 4); overflow-y: auto;
  display: flex; flex-direction: column; gap: var(--sp-1);
  width: 230px; padding: var(--sp-1); box-sizing: border-box;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-tile);
  pointer-events: auto; z-index: 800;
}
.d-couches[hidden] { display: none; }
.d-couches .d-btn { width: 100%; min-height: 40px; text-align: left; white-space: nowrap; flex-shrink: 0; }
.d-couches .d-btn.active::after, .d-couches .d-btn.is-selected::after { content: " ✓"; float: right; }
.d-couches .d-select { flex-shrink: 0; }
/* Viewer simplifie (second lien du client) : flux video et carte avec la
   position des drones, rien d autre. Les droits sont deja coupes par le
   serveur ; cette regle cache ce qui ne depend d aucun droit. */
body.vue-simple #yoloGlobalBtn,
body.vue-simple .ctrl-take,
body.vue-simple #btnOutils,
body.vue-simple #menuOutils,
body.vue-simple #btnAero,
body.vue-simple #btn3d,
body.vue-simple #orthoToggleBtn,
body.vue-simple .d-overlay--outils { display: none !important; }
body:not(.oaci-on) #btnOaci, body:not(.oaci-on) #opaciteOaciBloc { display: none !important; }
.d-opacite { display: flex; align-items: center; gap: 8px; padding: 4px 10px 8px; font-size: 12px; font-weight: 600; color: var(--text-dim); white-space: nowrap; }
.d-opacite input[type="range"] { flex: 1; min-width: 90px; accent-color: var(--accent); }
.d-opacite output { min-width: 4ch; text-align: right; color: var(--text); font-variant-numeric: tabular-nums; }
/* Nombre d'outils actifs, sur le bouton qui ouvre le menu. */
.d-couches__cpt {
  margin-left: var(--sp-1); padding: 1px 6px;
  background: var(--bg); color: var(--accent);
  border-radius: var(--r-badge); font-size: var(--fs-label);
}
.d-couches__cpt[hidden] { display: none; }
.carte-rapide-canvas { pointer-events: none; }
body.d-viewer:not(.carterapide-on) #btnComparer { display: none; }
/* Panneau de comparaison : a droite du menu Outils, meme gabarit. Sur
   tablette il prend toute la largeur et se replie par son titre. */
.d-comparaison { left: calc(230px + var(--sp-2) * 2); width: 260px; }
.d-comparaison__titre { font-weight: 700; }
.d-comparaison__corps { display: flex; flex-direction: column; gap: var(--sp-1); }
.d-comparaison__corps[hidden] { display: none; }
.d-comparaison__tete { font-size: var(--fs-sm); color: var(--text-strong); font-variant-numeric: tabular-nums; }
.d-comparaison__lbl { font-size: var(--fs-label); color: var(--text); }
.d-comparaison__sens { display: flex; gap: var(--sp-1); }
.d-comparaison__sens .d-btn { flex: 1; width: auto; text-align: center; }
.d-comparaison__etat { font-size: var(--fs-sm); color: var(--text); min-height: 1.2em; font-variant-numeric: tabular-nums; }
@media (max-width: 768px) {
  .d-comparaison { left: var(--sp-2); right: var(--sp-2); width: auto; }
}
/* Boite avant / apres : voile plein ecran, deux vignettes recadrees. */
.d-avantapres { position: fixed; inset: 0; background: var(--voile); z-index: 1200; display: flex; align-items: center; justify-content: center; padding: var(--sp-2); }
.d-avantapres[hidden] { display: none; }
.d-avantapres__boite { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-tile); padding: var(--sp-2); max-width: 100%; }
.d-avantapres__barre { display: flex; justify-content: space-between; align-items: center; gap: var(--sp-2); margin-bottom: var(--sp-1); font-weight: 700; color: var(--text-strong); }
.d-avantapres__deux { display: flex; gap: var(--sp-2); flex-wrap: wrap; justify-content: center; }
.d-avantapres__deux figure { margin: 0; text-align: center; }
.d-avantapres__deux canvas { max-width: 100%; border: 1px solid var(--line); border-radius: var(--r-badge); }
.d-avantapres__deux figcaption { font-size: var(--fs-sm); color: var(--text); margin-top: var(--sp-1); }
.d-chip-drone { font-variant-numeric: tabular-nums; }
/* En plein soleil le translucide devient illisible : fond opaque sur petit ecran. */
@media (max-width: 768px) {
  .d-overlay { background: var(--bg); }
}

/* --- Interrupteur --- */
.d-switch { width: 34px; height: 18px; border-radius: 10px; background: var(--line); position: relative; flex-shrink: 0; display: inline-block; }
.d-switch::after { content: ""; position: absolute; width: 14px; height: 14px; border-radius: 50%; background: var(--text-strong); top: 2px; left: 2px; transition: left .15s; }
.d-switch.is-on { background: var(--accent); }
.d-switch.is-on::after { left: 18px; }
/* Zone tactile de 48px : invisible, centree sur l'interrupteur.
   L'interface est utilisee dehors, avec des gants. */
.d-switch::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 48px;
  height: 48px;
}

/* --- Onglet --- */
.d-tab {
  font-size: var(--fs-sm); font-weight: 700; color: var(--text-dim);
  padding: 8px 14px; border-radius: var(--r-badge);
  background: transparent; border: 0; font-family: inherit; cursor: pointer;
  min-height: 48px;
}
.d-tab.is-active { background: var(--surface-2); color: var(--text-strong); }

/* --- Bouton --- */
.d-btn {
  border-radius: var(--r-badge); padding: var(--sp-2) var(--sp-4);
  font-size: var(--fs-sm); font-weight: 800;
  background: var(--surface-2); color: var(--text);
  border: 0; font-family: inherit; cursor: pointer;
  min-height: 48px;
}
.d-btn.is-primary { background: var(--accent); color: var(--bg); }
.d-btn.is-warn { background: var(--warn); color: var(--bg); }
.d-btn.is-danger { background: var(--danger); color: var(--bg); }
/* Bouton indisponible : slot verrouille pendant une diffusion, ou mode
   desactive le temps d'une bascule camera. */
.d-btn:disabled, .d-btn[aria-disabled="true"] { opacity: .45; cursor: not-allowed; }

/* --- Choix du mode de capture (screenshare) --- */
/* Le bouton Ecran est retire par screenshare.html quand getDisplayMedia est
   absent — c'est la capacite reelle qui decide, pas la largeur d'ecran : une
   tablette Android large en manque aussi, et un PC a fenetre etroite l'a. */
.d-modes { display: flex; gap: var(--sp-2); flex-wrap: wrap; }
.d-modes .d-btn { flex: 1; min-width: 96px; }

/* --- Champ et erreur --- */
.d-field {
  background: var(--surface);                                 /* repli */
  background: color-mix(in srgb, var(--bg) 70%, var(--surface));
  border: 1px solid var(--line);
  border-radius: var(--r-tile);
  padding: 14px 15px;
  font-size: var(--fs-md);
  color: var(--text);
  font-family: inherit;
  width: 100%;
  min-height: 48px;
}
.d-field:focus { outline: 0; border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent); }
.d-error {
  background: var(--surface);                                 /* repli */
  background: color-mix(in srgb, var(--danger) 14%, var(--surface));
  color: var(--danger);
  border-radius: var(--r-tile);
  padding: 11px 13px;
  font-size: var(--fs-body);
  font-weight: 700;
}
/* Pas d'erreur a afficher : pas de pave colore non plus. */
.d-error:empty { background: transparent; padding: 0; min-height: 18px; }

/* --- Ecran d'acces centre : index, login, totp --- */
body.d-auth {
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  margin: 0;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-4);
}
.d-auth__card {
  background: var(--surface);
  border-radius: 18px;
  padding: 34px 30px;
  width: 100%;
  max-width: 380px;
  text-align: center;
}
.d-auth__title { font-size: 21px; font-weight: 800; color: var(--text-strong); }
.d-auth__sub { font-size: var(--fs-body); color: var(--text-dim); margin-top: var(--sp-1); line-height: 1.5; }
.d-auth__card .d-field, .d-auth__card .d-btn { margin-top: var(--sp-3); }
.d-auth__code { display: flex; gap: var(--sp-2); justify-content: center; margin-top: var(--sp-4); }

/* --- Complements ecrans d'acces : logo, marque, messages, code --- */
.d-auth__card .d-logo-placeholder {
  width: 64px; height: 64px;
  background: var(--surface-2);
  border-radius: var(--r-tile);
  display: flex; align-items: center; justify-content: center;
  font-size: 28px;
  margin: 0 auto;
}
.d-auth__card .d-logo-img { max-height: 64px; max-width: 200px; object-fit: contain; }
.d-auth__card .d-brand {
  font-size: var(--fs-label);
  color: var(--text-dim);
  letter-spacing: 2px;
  text-transform: uppercase;
  margin-top: var(--sp-2);
}
.d-auth__card .d-brand b { color: var(--accent); }
.d-auth__card .d-shield { font-size: 48px; margin-bottom: var(--sp-3); }
.d-auth__card .d-hint { margin-top: var(--sp-4); color: var(--text-dim); font-size: var(--fs-sm); }
.d-auth__card .d-auth__code-input { font-size: 2rem; letter-spacing: .4em; text-align: center; }
.d-auth__card .d-msg {
  margin-top: var(--sp-3);
  padding: 11px 13px;
  border-radius: var(--r-tile);
  font-size: var(--fs-body);
  font-weight: 700;
  display: none;
}
.d-auth__card .d-msg.err {
  background: color-mix(in srgb, var(--danger) 14%, var(--surface));
  color: var(--danger);
  display: block;
}
.d-auth__card .d-msg.ok {
  background: color-mix(in srgb, var(--ok) 14%, var(--surface));
  color: var(--ok);
  display: block;
}

/* --- Console client : etat, action, detail --- */
.d-page { background: var(--bg); color: var(--text); margin: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; }
.d-page > main { padding: var(--sp-3); display: flex; flex-direction: column; gap: var(--sp-3); }
.d-panel[hidden] { display: none; }

/* --- Zone de depot : logo client, images orthophoto --- */
.d-dropzone, .logo-upload-mini {
  border: 2px dashed var(--line);
  border-radius: var(--r-tile);
  padding: var(--sp-5) var(--sp-4);
  text-align: center;
  cursor: pointer;
  color: var(--text-dim);
  transition: .15s;
}
/* La zone de depot d'images doit se viser d'un glisser-deposer, pas seulement
   se cliquer : une bande plate rate sa cible. La variante "mini" du logo garde
   sa petite taille, elle n'accueille qu'un fichier. */
.d-dropzone {
  min-height: 150px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
}
.d-dropzone:hover, .d-dropzone.is-drag,
.logo-upload-mini:hover, .logo-upload-mini.is-drag {
  border-color: var(--accent);
  color: var(--text);
  background: var(--surface);                                       /* repli */
  background: color-mix(in srgb, var(--accent) 6%, var(--surface));
}

/* --- Notification toast --- */
.d-toast {
  position: fixed; bottom: var(--sp-4); right: var(--sp-4);
  background: var(--surface);                                       /* repli */
  background: color-mix(in srgb, var(--ok) 16%, var(--surface));
  color: var(--ok);
  border: 1px solid var(--line);                                    /* repli */
  border: 1px solid color-mix(in srgb, var(--ok) 40%, var(--line));
  border-radius: var(--r-tile);
  padding: var(--sp-3) var(--sp-4);
  font-size: var(--fs-body);
  font-weight: 700;
  z-index: 300;
  pointer-events: none;
  opacity: 0;
  transition: opacity .3s;
  max-width: 280px;
}
.d-toast.is-show { opacity: 1; }
.d-toast.is-err {
  background: var(--surface);                                       /* repli */
  background: color-mix(in srgb, var(--danger) 16%, var(--surface));
  color: var(--danger);
  border-color: var(--line);                                        /* repli */
  border-color: color-mix(in srgb, var(--danger) 40%, var(--line));
}

/* --- Viewer : grille de vignettes plein ecran --- */
.d-grid { display: grid; gap: var(--sp-2); height: 100%; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); }
.d-vtile { background: var(--surface-2); border-radius: var(--r-tile); overflow: hidden; position: relative; }
.d-vtile__body { position: relative; width: 100%; height: 100%; min-height: 0; }
.d-vtile__body video, .d-vtile__body iframe { width: 100%; height: 100%; object-fit: cover; display: block; border: 0; background: var(--bg); }
.d-vtile.is-offline .d-vtile__body, .d-vtile.is-blocked .d-vtile__body { background: var(--bg); display: flex; align-items: center; justify-content: center; }
/* Vignette sans image : un pictogramme seul. Discret — c'est un etat courant,
   pas une alarme, et quatre vignettes rouges d'un coup fatiguent l'oeil. */
.d-vtile__dead { color: var(--text-dim); opacity: .55; }
.d-vtile__dead svg { width: 54px; height: 54px; display: block; }
.d-vtile__dead.is-suspendu { color: var(--warn); opacity: .7; }
.d-overlay__meta { display: flex; gap: var(--sp-1); flex-wrap: wrap; }
.d-overlay__chip {
  background: var(--bg);                                      /* repli */
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  border-radius: var(--r-badge);
  padding: 5px 9px;
  font-size: var(--fs-sm);
  font-weight: 700;
}
@media (max-width: 768px) { .d-overlay__chip { background: var(--bg); } }
/* La surimpression du haut peut porter nom + etat + actions : elle passe
   a la ligne plutot que de deborder de la vignette. */
.d-overlay { flex-wrap: wrap; }

/* --- Viewer : ecran live.html (chrome hors vignettes) --- */
body.d-viewer {
  background: var(--bg);
  color: var(--text-strong);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  margin: 0;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.d-viewer header { display: flex; align-items: center; gap: 14px; padding: var(--sp-2) var(--sp-4); border-bottom: 1px solid var(--line); flex-shrink: 0; background: var(--surface); }
.d-viewer .logo-img { height: 36px; max-width: 140px; object-fit: contain; }
.d-viewer .logo-text { font-size: var(--fs-title); font-weight: 700; color: var(--text-strong); }
.d-viewer .d-brand { font-size: var(--fs-label); letter-spacing: 2px; color: var(--text-dim); text-transform: uppercase; }
.d-viewer .d-brand b { color: var(--accent); }
.d-viewer main { flex: 1; min-height: 0; padding: var(--sp-2); }
.d-viewer .yolo-hdr-btn, .d-viewer .yolo-btn { display: none; }
body.yolo-ready.d-viewer .yolo-hdr-btn { display: inline-flex; align-items: center; gap: 5px; }
body.yolo-ready.d-viewer .yolo-btn { display: inline-flex; align-items: center; gap: 3px; }
.d-viewer .clock-body { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; height: 100%; }
.d-viewer .clock-body .time { font-size: 48px; font-weight: 700; color: var(--accent); }
.d-viewer .clock-body .date { font-size: var(--fs-body); color: var(--text-dim); text-transform: capitalize; }
.d-viewer #map { width: 100%; height: 100%; background: var(--surface-2); }
.d-viewer .empty-map { display: flex; align-items: center; justify-content: center; height: 100%; color: var(--text-dim); font-size: var(--fs-body); }
.d-viewer .detect-canvas { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 5; }
body.zoom .d-grid .d-vtile { display: none; }
body.zoom .d-grid .d-vtile.full { display: flex; position: fixed; inset: 0; z-index: 50; border-radius: 0; }
.d-viewer .back { display: none; position: fixed; top: 14px; right: 18px; z-index: 60; }
body.zoom .back { display: block; }
/* Fenetre detachee (?carte=1) : pas de retour possible, un bouton Plein ecran
   a sa place ; le bouton Detacher n a plus de sens dans cette fenetre. */
body.carte-seule .back, body.carte-seule #btnDetacher { display: none !important; }
#btnPleinEcranCarte { position: fixed; top: 14px; right: 18px; z-index: 60; }
/* Bandeau de progression orthophoto */
.d-viewer #ortho-banner { position: fixed; top: 0; left: 0; right: 0; z-index: 80; background: var(--surface); border-bottom: 1px solid var(--line); padding: var(--sp-2) var(--sp-4); display: none; align-items: center; gap: 14px; }
.d-viewer .ob-label { font-size: var(--fs-label); color: var(--accent); font-weight: 700; white-space: nowrap; flex-shrink: 0; }
.d-viewer .ob-bar-bg { flex: 1; background: var(--surface-2); border-radius: 20px; height: 6px; overflow: hidden; }
.d-viewer .ob-bar-fill { background: var(--accent); height: 100%; border-radius: 20px; transition: width .5s; }
.d-viewer .ob-step { font-size: var(--fs-label); color: var(--text-dim); white-space: nowrap; max-width: 280px; overflow: hidden; text-overflow: ellipsis; flex-shrink: 0; }
.d-viewer .ob-pct { font-size: var(--fs-label); color: var(--accent); font-weight: 700; white-space: nowrap; flex-shrink: 0; }
/* Chargeur / alerte de detection IA */
.d-viewer .yolo-loader { position: fixed; top: 0; left: 0; right: 0; z-index: 150; background: var(--surface); border-bottom: 2px solid var(--accent); padding: var(--sp-2) var(--sp-4); align-items: center; gap: 12px; font-size: var(--fs-sm); color: var(--text-dim); display: none; }
.d-viewer .yolo-loader b { color: var(--accent); }
.d-viewer .yolo-alert { position: fixed; bottom: 24px; right: 20px; z-index: 200; min-width: 240px; max-width: 300px; background: var(--surface); border: 2px solid var(--danger); border-radius: var(--r-tile); padding: var(--sp-4) var(--sp-4); display: none; flex-direction: column; gap: 4px; animation: d-yolo-alert .3s ease; }
.d-viewer .yolo-alert .ya-row { display: flex; align-items: center; gap: var(--sp-2); }
.d-viewer .yolo-alert .ya-icon { font-size: 22px; }
.d-viewer .yolo-alert .ya-txt { font-size: var(--fs-body); color: var(--danger); font-weight: 700; }
.d-viewer .yolo-alert .ya-sub { font-size: var(--fs-sm); color: var(--text-dim); }
@keyframes d-yolo-alert { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
/* Barre d'outils de mesure orthophoto, en surimpression basse de la tuile Carte.
   Zone tactile 48px conservee (regle d-btn) : seul le remplissage change. */
.d-viewer .ortho-tool { padding: 5px 11px; font-size: var(--fs-sm); }
.d-viewer .ortho-tool.active { background: var(--accent); color: var(--bg); }
.d-viewer .ortho-tool.clear { color: var(--danger); }
@media (max-width: 640px) {
  .d-viewer header { padding: var(--sp-1) var(--sp-2); gap: var(--sp-2); }
  .d-viewer .d-brand { display: none; }
  .d-viewer .logo-img { height: 28px; }
  .d-viewer .logo-text { font-size: var(--fs-md); }
}
@media (max-width: 640px) and (orientation: portrait) {
  body.d-viewer { height: auto; min-height: 100dvh; overflow-y: auto; }
  .d-viewer main { overflow: visible; padding: var(--sp-1); }
  .d-viewer .d-grid { height: auto !important; grid-template-columns: 1fr !important; }
  .d-viewer .d-vtile { height: 56vw; }
}

/* --- Viewer sur telephone : une source en grand, les autres en bande ---
   Sous 768px un mur 2x2 de videos est illisible en plein soleil : une seule
   source reste affichee, les autres passent en bande de vignettes.
   Seules les tuiles source ([data-path], donc video) sont concernees : la
   tuile Horloge et la tuile Carte n'ont pas de data-path et restent visibles
   (empilees sous la source active) — la carte porte les positions drone,
   elle ne doit jamais disparaitre sur telephone. */
.d-strip { display: none; flex-shrink: 0; }
/* Une seule commande d'agrandissement par gabarit d'ecran, jamais deux qui
   partagent le meme glyphe et le meme texte pour deux mecanismes differents :
   - hors mobile, le geste habituel reste le bouton .expand de chaque
     vignette live (zoom CSS plein cadre) : lui seul permet de choisir QUELLE
     tuile agrandir. La barre plein ecran globale ne le peut pas — elle vise
     toujours la seule tuile focalisee — donc elle reste masquee ici.
   - sous 768px, la tuile focalisee occupe deja toute la largeur : un zoom
     CSS n'y ajoute rien. .expand disparait et seule la barre plein ecran
     (vraie API Fullscreen + verrouillage d'orientation) reste. */
.d-fsbar { display: none; }
@media (max-width: 768px) {
  .d-grid { display: block; }
  .d-grid .d-vtile[data-path] { display: none; }
  .d-grid .d-vtile.is-focused { display: block; }
  .d-viewer .expand { display: none; }
  .d-strip {
    display: flex; gap: var(--sp-1);
    padding: var(--sp-2); overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
  .d-strip__thumb {
    width: 80px; flex-shrink: 0;
    border-radius: var(--r-badge); overflow: hidden;
    background: var(--surface-2);
    border: 2px solid transparent;
    min-height: 48px;
    font-family: inherit;
    cursor: pointer;
  }
  .d-strip__thumb.is-focused { border-color: var(--accent); }
  .d-strip__label { font-size: var(--fs-label); font-weight: 800; padding: 5px 6px; display: flex; align-items: center; gap: 4px; color: var(--text); }
  .d-strip__dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; }
  .d-strip__dot.is-live { background: var(--ok); }
  .d-strip__dot.is-blocked { background: var(--warn); }
  .d-strip__dot.is-offline { background: var(--danger); }
  /* Le point de couleur seul ne suffit pas : l'abreviation du mot d'etat
     l'accompagne toujours sur cette bande tactile etroite. */
  .d-strip__abbr { color: var(--text-dim); flex-shrink: 0; }
  .d-fsbar {
    display: flex;
    flex-shrink: 0;
    gap: var(--sp-2);
    padding: var(--sp-2);
    border-top: 1px solid var(--line);
  }
  .d-fsbar .d-btn { flex: 1; min-height: 48px; }
}

/* En plein ecran, la surimpression s'efface d'elle-meme apres inactivite et
   revient au toucher (armerInactivite/surTouche dans le script). La bande
   du bas (meta GPS/altitude, outils ortho) reste masquee : elle genait la
   vue plein ecran et n'apporte rien qu'un commandant doive lire ici. */
.d-vtile:fullscreen .d-overlay { transition: opacity .4s; }
.d-vtile:fullscreen.is-idle .d-overlay { opacity: 0; }
.d-vtile:fullscreen .d-overlay--bottom { display: none; }

/* --- Tutoriel guide --- */
.d-tut-overlay {
  position: fixed; inset: 0;
  background: var(--bg);                                            /* repli */
  background: color-mix(in srgb, var(--bg) 84%, transparent);
  z-index: 200;
  display: none;
}
.d-tut-card {
  position: fixed; z-index: 203; display: none;
  background: var(--surface);
  border: 1px solid var(--accent);
  border-radius: 14px;
  padding: var(--sp-5) var(--sp-4);
  width: min(400px, 92vw);
  box-shadow: 0 8px 40px var(--accent);                              /* repli */
  box-shadow: 0 8px 40px color-mix(in srgb, var(--accent) 45%, transparent);
  left: 20px; top: 20px;
}
.d-tut-num { font-size: var(--fs-label); color: var(--accent); letter-spacing: 2px; text-transform: uppercase; margin-bottom: var(--sp-3); }
.d-tut-title { font-size: var(--fs-title); font-weight: 800; color: var(--text-strong); margin-bottom: var(--sp-3); line-height: 1.3; }
.d-tut-body { font-size: var(--fs-body); color: var(--text-dim); line-height: 1.65; margin-bottom: var(--sp-5); }
.d-tut-body b { color: var(--text-strong); }
.d-tut-body code { background: var(--surface-2); color: var(--accent); border-radius: 3px; padding: 1px 5px; font-size: var(--fs-sm); }
.d-tut-footer { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); }
.d-tut-dots { display: flex; gap: 5px; flex-shrink: 0; }
.d-tut-nav { display: flex; align-items: center; gap: var(--sp-2); }
.d-tut-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--line); transition: background .2s; }
.d-tut-dot.is-done { background: var(--line);                                     /* repli */
  background: color-mix(in srgb, var(--accent) 45%, var(--line)); }
.d-tut-dot.is-active { background: var(--accent); box-shadow: 0 0 6px var(--accent); }
.d-tut-spotlight { position: relative; z-index: 201; outline: 2px solid var(--accent); outline-offset: 5px; border-radius: var(--r-tile); }
/* En plein soleil, sur mobile : le tuto reste epingle en bas, a portee du pouce. */
@media (max-width: 600px) {
  .d-tut-card { left: 12px; right: 12px; top: auto; bottom: 16px; width: auto; overflow-y: auto; padding: var(--sp-5) var(--sp-4); max-height: calc(100vh - 32px); max-height: calc(100dvh - 32px); }
}

/* --- Console mode Marc : liste des tenants a gauche, detail en onglets a droite --- */
.d-super { background: var(--bg); color: var(--text); font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; }
.d-super main { padding: var(--sp-3); display: flex; flex-direction: column; gap: var(--sp-3); }
.d-super header.d-bar { border-radius: 0; border-bottom: 1px solid var(--line); position: sticky; top: 0; z-index: 10; flex-wrap: wrap; }

.d-super__login { position: fixed; inset: 0; z-index: 100; background: var(--bg); display: flex; align-items: center; justify-content: center; padding: var(--sp-4); }
.d-super__login[hidden] { display: none; }

.d-super__global { display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-2) var(--sp-4); padding: var(--sp-2) var(--sp-3); background: var(--surface); border-bottom: 1px solid var(--line); font-size: var(--fs-sm); color: var(--text-dim); }
.d-super__gstat strong { color: var(--text-strong); font-size: var(--fs-md); font-weight: 800; }
.d-super__label { font-size: var(--fs-label); letter-spacing: 2px; text-transform: uppercase; color: var(--text-dim); font-weight: 700; }

/* Acces rapide : depuis la refonte, seul endroit qui porte les liens viewer et
   dashboard de chaque tenant — il reste donc visible sur telephone. */
/* La barre s'enroule sur plusieurs lignes quand la fenetre retrecit, au lieu de
   defiler horizontalement : un acces rapide qu'il faut faire defiler pour
   trouver un client n'est plus un acces rapide. */
.d-qnav { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1); padding: var(--sp-1) var(--sp-3); background: var(--surface); border-bottom: 1px solid var(--line); }
.d-qnav__title { font-size: var(--fs-label); letter-spacing: 2px; text-transform: uppercase; color: var(--text-dim); white-space: nowrap; margin-right: var(--sp-1); flex-shrink: 0; }
.d-qnav__group { position: relative; display: flex; align-items: center; background: var(--surface-2); border-radius: var(--r-badge); flex-shrink: 0; }
.d-qnav__btn { display: inline-flex; align-items: center; gap: 4px; min-height: 48px; padding: 0 var(--sp-2); border-left: 1px solid var(--line); font-size: var(--fs-sm); font-weight: 700; color: var(--text); text-decoration: none; white-space: nowrap; }
.d-qnav__btn.is-dev { color: var(--text-dim); }
/* Acces rapide replie : le nom est un bouton, les liens n'existent dans le
   DOM que pour le client ouvert (rendu par mode MarcRender.renderQuickNav). */
.d-qnav__toggle { display: inline-flex; align-items: center; gap: 6px; min-height: 48px; padding: 0 var(--sp-2); border: 0; background: transparent; font-family: inherit; font-size: var(--fs-label); font-weight: 800; color: var(--text-dim); cursor: pointer; max-width: 160px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.d-qnav__group.is-open .d-qnav__toggle { color: var(--text-strong); }
/* Menu deroule sous le nom du client ouvert : liens empiles, plus grands que
   la barre, par-dessus la liste des tenants (z-index sous les toasts). */
.d-qnav__menu { position: absolute; top: 100%; left: 0; z-index: 900; margin-top: 4px; display: flex; flex-direction: column; min-width: 220px; padding: var(--sp-1); background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--r-tile); box-shadow: 0 10px 28px color-mix(in srgb, var(--bg) 70%, transparent); }
.d-qnav__menu .d-qnav__btn { border-left: 0; border-radius: var(--r-badge); min-height: 52px; padding: 0 var(--sp-3); font-size: var(--fs-md); gap: 8px; }
.d-qnav__menu .d-qnav__btn:hover { background: var(--surface); color: var(--text-strong); }
.d-qnav__logo { height: 24px; width: 24px; object-fit: contain; border-radius: 4px; background: var(--surface); flex-shrink: 0; }

.d-bulk { display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-2); background: var(--surface); border-radius: var(--r-card); padding: var(--sp-2) var(--sp-3); }
/* Creation d'un client : un bouton, puis un champ et deux boutons sur la meme ligne. */
.d-creation { display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-2); margin: var(--sp-2) 0; }
.d-creation__form { display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-2); }
.d-input { min-height: 38px; padding: 0 var(--sp-2); border-radius: var(--r-badge); border: 1px solid var(--line); background: var(--surface-2); color: var(--text); font-family: inherit; font-size: var(--fs-sm); min-width: 240px; }
.d-input:focus { outline: none; border-color: var(--accent); }
.viewer-url--rc { margin-top: var(--sp-1); }
.d-bulk__count { font-size: var(--fs-sm); color: var(--text-dim); }
.d-bulk__send { margin-left: auto; }
.d-super button:disabled { opacity: .4; cursor: not-allowed; }

.d-master { display: flex; gap: var(--sp-2); align-items: flex-start; }
/* La barre superieure est sticky (top:0, z-index 10, ~72px de haut : deux
   fois --sp-3 de padding plus un bouton de 48px). La liste doit se coller
   SOUS elle, pas a 9px du haut de la fenetre, sinon la premiere ligne
   defile derriere l'en-tete ; z-index explicite plutot que de laisser
   l'ordre du DOM decider. */
/* L'en-tete de cette page est en flex-wrap : sa hauteur change avec la largeur
   de la fenetre. Un decalage fixe ferait donc passer les premieres lignes de la
   liste DERRIERE l'en-tete des qu'il s'enroule sur deux lignes — des clients
   disparaissent sans que rien ne le signale. La hauteur reelle est mesuree au
   chargement et au redimensionnement dans --entete-h ; le repli ne sert que si
   le script n'a pas encore tourne. La liste borne aussi sa hauteur et defile
   elle-meme : un element colle plus haut que l'ecran rend sa partie basse
   inatteignable. */
.d-tenants { width: 236px; flex-shrink: 0; background: var(--surface); border-radius: var(--r-card); padding: var(--sp-2); display: flex; flex-direction: column; gap: var(--sp-1); position: sticky; top: calc(var(--entete-h, 72px) + var(--sp-2)); z-index: 1; max-height: calc(100vh - var(--entete-h, 72px) - var(--sp-4)); overflow-y: auto; }
.d-tenant-row { display: flex; align-items: center; gap: var(--sp-1); }
/* Case d'envoi groupe : coche de 20px, mais 48px de hauteur a viser au doigt. */
.client-sel-chk {
  appearance: none; -webkit-appearance: none;
  width: 32px; height: 48px; margin: 0; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: none; border: 0; cursor: pointer;
}
.client-sel-chk::before {
  content: "";
  width: 20px; height: 20px;
  display: flex; align-items: center; justify-content: center;
  border: 2px solid var(--line); border-radius: 5px;
  background: var(--surface-2);
  font-size: var(--fs-sm); font-weight: 800; line-height: 1;
}
.client-sel-chk:checked::before { content: "✓"; border-color: var(--accent); background: var(--accent); color: var(--bg); }
.client-sel-chk:focus-visible { outline: 2px solid var(--accent); outline-offset: -4px; border-radius: var(--r-badge); }
.d-tenant {
  flex: 1; min-width: 0;
  background: var(--surface-2); border: 0; border-left: 3px solid transparent;
  border-radius: var(--r-tile); padding: 11px 12px;
  display: flex; align-items: center; gap: var(--sp-2);
  font-family: inherit; color: var(--text); cursor: pointer;
  min-height: 48px; text-align: left;
}
.d-tenant.is-selected { border-left-color: var(--accent); background: var(--line); }
.d-tenant__name { font-size: var(--fs-body); font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Dans la liste, la pastille perd son fond (juste le point + le mot abrege) :
   le ratio chiffre a cote ne suffit pas seul, suspendu et hors ligne valent
   tous deux 0/n. */
.d-tenant .d-state { padding: 0; background: none; }
.d-tenant__ratio { margin-left: auto; font-size: var(--fs-sm); font-weight: 800; color: var(--text-dim); font-variant-numeric: tabular-nums; }

.d-detail-slot { flex: 1; min-width: 0; }
.d-detail { background: var(--surface); border-radius: var(--r-card); padding: var(--sp-4); }
.d-detail .d-bar { background: none; border-radius: 0; padding: 0; flex-wrap: wrap; }
.d-detail .d-bar__sub { font-family: ui-monospace, Menlo, monospace; word-break: break-all; }
/* Logo du tenant : c'est lui qu'on reconnait avant de lire le nom. */
.client-logo { width: 44px; height: 44px; flex-shrink: 0; object-fit: contain; padding: 3px; border-radius: var(--r-tile); background: var(--surface-2); }
.logo-placeholder { width: 44px; height: 44px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; border-radius: var(--r-tile); background: var(--surface-2); font-size: var(--fs-title); }
.d-tabs { display: flex; gap: var(--sp-1); margin: var(--sp-3) 0; border-bottom: 1px solid var(--line); padding-bottom: var(--sp-1); flex-wrap: wrap; }
.d-detail__body { margin-top: var(--sp-1); }
.d-empty, .d-pool--indisponible, .d-historique { background: var(--surface-2); border-radius: var(--r-tile); padding: var(--sp-3); color: var(--text-dim); font-size: var(--fs-body); }

/* Onglet Sources : une ligne par flux, puis le pool d'affectation. */
.d-srow { background: var(--surface-2); border-radius: var(--r-tile); padding: 9px 13px; display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; min-height: 48px; font-size: var(--fs-body); font-weight: 600; margin-bottom: var(--sp-1); }
.d-srow__name { color: var(--text-strong); font-weight: 700; }
.d-srow__path { margin-left: auto; font-family: ui-monospace, Menlo, monospace; font-size: var(--fs-sm); color: var(--text-dim); }
.d-srow__actions { display: flex; gap: var(--sp-1); }
.btn-cut, .btn-restore { min-height: 48px; padding: 0 var(--sp-3); border: 0; border-radius: var(--r-badge); font-family: inherit; font-size: var(--fs-sm); font-weight: 800; cursor: pointer; white-space: nowrap; }
.btn-cut { background: var(--danger); color: var(--bg); }
.btn-restore { background: var(--ok); color: var(--bg); }
.d-pool { margin-top: var(--sp-3); }
.src-group-label { font-size: var(--fs-label); letter-spacing: 1px; text-transform: uppercase; color: var(--text-dim); margin: var(--sp-2) 0 var(--sp-1); }
.src-chk-wrap { display: flex; gap: var(--sp-1); flex-wrap: wrap; }
.src-chk-label { display: inline-flex; align-items: center; gap: var(--sp-1); min-height: 48px; padding: 0 var(--sp-2); border-radius: var(--r-badge); background: var(--surface-2); color: var(--text-dim); font-size: var(--fs-sm); font-weight: 700; cursor: pointer; }
.src-chk-label.assigned {
  color: var(--text-strong);
  background: var(--line);                                          /* repli */
  background: color-mix(in srgb, var(--accent) 18%, var(--surface-2));
}
.src-chk-label.shared {
  color: var(--text-strong);
  background: var(--line);                                          /* repli */
  background: color-mix(in srgb, var(--accent-deep) 26%, var(--surface-2));
}
.src-chk-label input { width: 18px; height: 18px; accent-color: var(--accent); cursor: pointer; }

/* Onglet Modules : quota de drones et trois bascules. */
.d-modules, .d-securite { display: flex; flex-direction: column; gap: var(--sp-2); align-items: flex-start; }
.d-modules__quota { display: flex; align-items: center; gap: var(--sp-1); flex-wrap: wrap; }
.d-modules__label { font-size: var(--fs-label); letter-spacing: 1px; text-transform: uppercase; color: var(--text-dim); font-weight: 700; min-width: 104px; }
.drone-btn, .photos-btn { min-width: 48px; min-height: 48px; border: 0; border-radius: var(--r-badge); background: var(--surface-2); color: var(--text); font-family: inherit; font-size: var(--fs-md); font-weight: 800; cursor: pointer; }
.drone-btn.active { background: var(--accent); color: var(--bg); }
.photos-btn:disabled { opacity: .35; cursor: not-allowed; }
.photos-val { min-width: 48px; text-align: center; font-size: var(--fs-md); font-weight: 800; color: var(--text-strong); }
.d-toggle-row { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; min-height: 48px; }
/* L'interrupteur mesure 26px, sa zone tactile 48px : l'input transparent couvre toute la case. */
.toggle { position: relative; display: inline-block; width: 46px; height: 48px; flex-shrink: 0; }
.toggle input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; z-index: 1; }
.slider { position: absolute; left: 0; right: 0; top: 11px; height: 26px; background: var(--line); border-radius: 26px; transition: background .2s; }
.slider::before { content: ""; position: absolute; width: 20px; height: 20px; left: 3px; top: 3px; background: var(--text-strong); border-radius: 50%; transition: transform .2s; }
.toggle input:checked + .slider { background: var(--accent); }
.toggle input:checked + .slider::before { transform: translateX(20px); }
.ortho-lbl { font-size: var(--fs-sm); font-weight: 700; color: var(--text-dim); }
.ortho-lbl.on { color: var(--ok); }

/* Onglet Securite : niveau, verrou, reinitialisation. */
.d-securite__niveaux { display: flex; gap: var(--sp-1); flex-wrap: wrap; }
.sec-lvl-btn { min-height: 48px; padding: 0 var(--sp-3); border: 0; border-radius: var(--r-badge); background: var(--surface-2); color: var(--text); font-family: inherit; font-size: var(--fs-sm); font-weight: 700; cursor: pointer; }
.sec-lvl-btn.active { background: var(--line); box-shadow: inset 0 0 0 2px var(--accent); color: var(--text-strong); }
.d-lock-lbl { font-size: var(--fs-sm); font-weight: 700; color: var(--text-dim); }
.btn-reset-client { min-height: 48px; padding: 0 var(--sp-3); border: 0; border-radius: var(--r-badge); background: var(--warn); color: var(--bg); font-family: inherit; font-size: var(--fs-sm); font-weight: 800; cursor: pointer; }

/* Onglet Diffusion : QR, lien viewer, logo. */
.d-diffusion { display: flex; gap: var(--sp-3); align-items: flex-start; flex-wrap: wrap; }
.qr-mini { background: var(--text-strong); border-radius: var(--r-tile); padding: var(--sp-1); flex-shrink: 0; }
.qr-mini img { display: block; width: 104px; height: 104px; }
.d-diffusion__right { flex: 1; min-width: 200px; display: flex; flex-direction: column; gap: var(--sp-2); }
.d-diffusion input[type="file"] { display: none; }
.viewer-url { font-family: ui-monospace, Menlo, monospace; font-size: var(--fs-sm); color: var(--accent); background: var(--surface-2); border-radius: var(--r-tile); padding: var(--sp-2) var(--sp-3); word-break: break-all; line-height: 1.5; }

/* Onglet E-mail. */
.d-email { display: flex; gap: var(--sp-2); align-items: center; flex-wrap: wrap; }

/* Onglet Compte du mode Marc */
.d-compte { display: flex; flex-direction: column; gap: var(--sp-3); align-items: flex-start; }
.d-compte__etat { font-size: var(--fs-sm); color: var(--text-dim); }
.d-compte__etat.is-actif { color: var(--ok); }
.d-compte__ligne { display: flex; gap: var(--sp-2); align-items: center; flex-wrap: wrap; }
.d-compte .login-input { min-width: 220px; }
.d-compte__mdp { font-size: var(--fs-md); letter-spacing: .12em; padding: var(--sp-1) var(--sp-3); border: 1px dashed var(--accent); border-radius: var(--r-tile); color: var(--text-strong); user-select: all; }
.d-compte__mdp[hidden] { display: none; }
.d-compte__aide { font-size: var(--fs-sm); color: var(--text-dim); }
.email-input, .login-input {
  flex: 1; min-width: 190px; min-height: 48px; padding: 0 var(--sp-3);
  background: var(--surface-2);                                     /* repli */
  background: color-mix(in srgb, var(--bg) 70%, var(--surface));
  border: 1px solid var(--line); border-radius: var(--r-tile);
  color: var(--text); font-family: inherit; font-size: var(--fs-md);
}
.email-input:focus, .login-input:focus { outline: 0; border-color: var(--accent); }
.btn-save-email, .btn-send-email { min-height: 48px; padding: 0 var(--sp-3); border: 0; border-radius: var(--r-badge); font-family: inherit; font-size: var(--fs-sm); font-weight: 800; cursor: pointer; white-space: nowrap; }
.btn-save-email { background: var(--surface-2); color: var(--text); }
.btn-send-email { background: var(--accent); color: var(--bg); }

/* Barre de titre du detail : renommage et regeneration des liens. */
.client-name-display { cursor: pointer; border-radius: var(--r-badge); padding: 2px 6px; }
.client-name-display:hover { background: var(--surface-2); }
.client-name-input { width: 220px; min-height: 48px; padding: 2px 8px; background: var(--surface-2); border: 1px solid var(--accent); border-radius: var(--r-badge); color: var(--text-strong); font-family: inherit; font-size: var(--fs-title); font-weight: 800; }
/* Glyphe visible de ~20px, mais zone tactile de 48px visee au doigt — meme
   pseudo-element invisible et centre que .d-switch. */
.edit-icon { margin-left: var(--sp-1); font-size: var(--fs-md); color: var(--text-dim); cursor: pointer; position: relative; display: inline-block; }
.edit-icon::before {
  content: "";
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: 48px; height: 48px;
}
.btn-regen { min-height: 48px; padding: 0 var(--sp-3); border: 0; border-radius: var(--r-badge); background: var(--surface-2); color: var(--text); font-family: inherit; font-size: var(--fs-sm); font-weight: 800; cursor: pointer; white-space: nowrap; }
/* Compteurs flux/viewers de la barre du detail : de l'information, pas un
   controle — pas de curseur pointeur ni de cible tactile a 48px comme .d-btn. */
.d-chip { border-radius: var(--r-badge); padding: var(--sp-2) var(--sp-4); font-size: var(--fs-sm); font-weight: 800; background: var(--surface-2); color: var(--text); display: inline-flex; align-items: center; }
/* Meme glyphe crayon que .edit-icon, meme defaut : dashboard.html le pose en
   style inline (font-size 11px) sur la table RTMP ; la cible tactile de 48px
   vit ici, partagee, pour ne pas la dupliquer par ligne de tuile. */
.drone-edit-icon { position: relative; display: inline-block; }
.drone-edit-icon::before {
  content: "";
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: 48px; height: 48px;
}

/* --- Historique global des connexions (tous tenants confondus) --- */
.conn-card { padding: 0; }
.conn-head { display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-3) var(--sp-4); min-height: 48px; cursor: pointer; user-select: none; }
.conn-head h3 { flex: 1; font-size: var(--fs-sm); letter-spacing: 2px; text-transform: uppercase; color: var(--text-dim); font-weight: 800; }
.conn-head .chev { color: var(--text-dim); transition: transform .2s; }
.conn-card.is-open .conn-head .chev { transform: rotate(90deg); }
.conn-body { display: none; padding: 0 var(--sp-4) var(--sp-4); }
.conn-card.is-open .conn-body { display: block; }
.conn-filters { display: flex; gap: var(--sp-2); flex-wrap: wrap; align-items: center; margin-bottom: var(--sp-4); }
.conn-filters button { min-height: 48px; padding: 0 var(--sp-3); border: 0; border-radius: var(--r-badge); background: var(--surface-2); color: var(--text); font-family: inherit; font-size: var(--fs-sm); font-weight: 700; cursor: pointer; }
.conn-filters button.active { background: var(--line); box-shadow: inset 0 0 0 2px var(--accent); color: var(--text-strong); }
.conn-filters select { min-height: 48px; padding: 0 var(--sp-2); border: 1px solid var(--line); border-radius: var(--r-badge); background: var(--surface-2); color: var(--text); font-family: inherit; font-size: var(--fs-sm); }
.conn-totals { display: flex; flex-direction: column; gap: var(--sp-1); margin-bottom: var(--sp-4); }
.conn-total-row { display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap; font-size: var(--fs-sm); color: var(--text-dim); }
.conn-total-row .ct-name { min-width: 110px; font-weight: 800; color: var(--text); }
.conn-total-row .ct-dur { color: var(--accent); font-weight: 800; }
.conn-heatmap-wrap { overflow-x: auto; margin-bottom: var(--sp-4); }
.conn-heatmap { display: grid; gap: 2px; font-size: var(--fs-label); }
.conn-hm-label { display: flex; align-items: center; padding-right: var(--sp-2); white-space: nowrap; font-size: var(--fs-sm); color: var(--text-dim); }
.conn-hm-col-head { height: 14px; text-align: center; font-size: var(--fs-label); color: var(--text-dim); }
/* Intensite du bleu = duree cumulee ; le chiffre exact reste dans l'infobulle de la case. */
.conn-hm-cell { width: 14px; height: 14px; border-radius: 2px; background: var(--surface-2); cursor: pointer; }
.conn-hm-cell.is-l1 { background: color-mix(in srgb, var(--accent) 30%, var(--surface-2)); }
.conn-hm-cell.is-l2 { background: color-mix(in srgb, var(--accent) 55%, var(--surface-2)); }
.conn-hm-cell.is-l3 { background: color-mix(in srgb, var(--accent) 78%, var(--surface-2)); }
.conn-hm-cell.is-l4 { background: var(--accent); }
.conn-table-wrap { overflow-x: auto; }
.conn-table { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); }
.conn-table th { padding: var(--sp-1) var(--sp-2); text-align: left; border-bottom: 1px solid var(--line); font-size: var(--fs-label); letter-spacing: 1px; text-transform: uppercase; color: var(--text-dim); }
.conn-table td { padding: var(--sp-2); border-bottom: 1px solid var(--line); color: var(--text); }
.conn-type-badge { padding: 2px 7px; border-radius: var(--r-badge); background: var(--surface-2); font-size: var(--fs-label); font-weight: 800; color: var(--text-dim); }
.conn-type-stream { color: var(--accent); }
.conn-type-live { color: var(--ok); }
.conn-type-dashboard { color: var(--text); }
.conn-empty { padding: var(--sp-4) 0; text-align: center; font-size: var(--fs-sm); color: var(--text-dim); }

/* Sous 900px la liste des tenants passe au-dessus du detail, en bande horizontale. */
@media (max-width: 900px) {
  .d-master { flex-direction: column; }
  .d-tenants { width: 100%; position: static; flex-direction: row; overflow-x: auto; }
  .d-tenant-row { flex-shrink: 0; }
  .d-detail-slot { width: 100%; }
}
@media (max-width: 640px) {
  .d-super main { padding: var(--sp-2); }
  .d-detail { padding: var(--sp-3); }
  .d-bulk__send { margin-left: 0; }
  .conn-table thead { display: none; }
  .conn-table tr { display: block; border: 1px solid var(--line); border-radius: var(--r-tile); margin-bottom: var(--sp-2); padding: var(--sp-1); }
  .conn-table td { display: flex; justify-content: space-between; gap: var(--sp-2); border: 0; padding: 4px var(--sp-1); }
  .conn-table td::before { content: attr(data-label); font-size: var(--fs-label); letter-spacing: 1px; text-transform: uppercase; color: var(--text-dim); }
}

/* ── Incrustation deux caméras (viewer) ─────────────────────────────── */
.pip { position: relative; overflow: hidden; }
/* Descendant (pas enfant direct) : la vidéo principale vit dans .d-vtile__body,
   la vignette clonée dans .incruste — ni l'une ni l'autre n'est un enfant
   direct de .d-vtile.pip. .d-vtile__body et .incruste sont déjà positionnés
   (position: relative / absolute), donc inset: 0 s'y cadre correctement. */
.pip .moitie {
  position: absolute; inset: 0;
  width: 200%; height: 100%;
  object-fit: cover;
}
.pip .moitie--gauche { left: 0; }
.pip .moitie--droite { left: -100%; }
.pip > .incruste {
  position: absolute; right: 8px; bottom: 8px;
  width: 30%; height: 30%;
  border: 2px solid var(--accent);
  border-radius: var(--r-tile);
  overflow: hidden; cursor: pointer;
  min-width: var(--touch); min-height: var(--touch);
}

/* --- Fond de carte --- */
/* Le PLAN IGN n'existe qu'en rendu clair, illisible au milieu du theme
   sombre : on l'inverse cote navigateur. La desaturation reste partielle :
   l'inversion tire les batiments beiges de l'IGN vers un brun chaud, garde
   volontairement — une version neutralisee a 92 % a ete comparee et ecartee. Le filtre est porte par la couche
   de fond seule (option className de Leaflet) — pose sur .leaflet-tile-pane,
   il inverserait aussi l'orthophoto superposee. */
.basemap-dark { filter: invert(1) hue-rotate(180deg) grayscale(.45) brightness(1.5) contrast(.82); }
/* La photo aerienne est deja sombre : on l'attenue seulement, pour que le
   marqueur et la trace du drone gardent leur contraste par-dessus. */
.basemap-photo { filter: brightness(.82) saturate(.85); }
/* La Licence Ouverte impose de citer l'IGN, sans peser sur la carte. */
.leaflet-container .leaflet-control-attribution {
  background: transparent;
  color: var(--text-dim);
  font-size: var(--fs-label);
}
.leaflet-container .leaflet-control-attribution a { color: var(--text-dim); }

/* --- Vue 3D (MapLibre) --- */
/* Surcouche plein ecran : elle vit hors de #grid, que la reconstruction de la
   grille vide a chaque changement de flux. */
.v3d { position: fixed; inset: 0; z-index: 900; background: var(--bg); }
.v3d[hidden] { display: none; }
/* Selecteur double a dessein : la feuille de MapLibre est injectee apres
   celle-ci et pose `position: relative` sur le conteneur via sa propre
   classe. A specificite egale, la derniere chargee gagne — le conteneur
   retombait alors a zero de haut et le canvas ne s'affichait pas. */
.v3d .v3d__carte { position: absolute; inset: 0; }
.v3d__bar {
  position: absolute;
  top: var(--sp-3); right: var(--sp-3);
  display: flex; gap: var(--sp-2); z-index: 1;
}
.v3d__etat {
  position: absolute;
  left: 50%; top: var(--sp-3);
  transform: translateX(-50%);
  background: var(--surface);
  color: var(--text-dim);
  border-radius: var(--r-badge);
  padding: var(--sp-2) var(--sp-4);
  font-size: var(--fs-sm);
  font-weight: 700;
  z-index: 1;
}
/* Le libelle du drone est un marqueur HTML : une couche `symbol` MapLibre
   exigerait une police vectorielle servie par un tiers. */
.v3d__drone {
  background: var(--surface);
  color: var(--text-strong);
  border: 2px solid var(--accent);
  border-radius: var(--r-badge);
  padding: 3px 9px;
  font-size: var(--fs-label);
  font-weight: 800;
  white-space: nowrap;
}

/* --- Profil en long --- */
.profil {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  /* Au-dessus de la vue 3D (900) mais aussi des controles Leaflet : leur
     conteneur .leaflet-bottom porte un z-index de 1000, et l'attribution
     de la carte passait par-dessus le graphe. */
  z-index: 1100;
  background: var(--surface);
  border-top: 1px solid var(--line);
  padding: var(--sp-3) var(--sp-4) var(--sp-4);
}
.profil[hidden] { display: none; }
.profil__tete { display: flex; align-items: center; gap: var(--sp-3); margin-bottom: var(--sp-2); }
.profil__titre { font-size: var(--fs-sm); font-weight: 800; color: var(--text-strong); white-space: nowrap; }
.profil__stats { font-size: var(--fs-body); color: var(--text-dim); flex: 1; }
.profil__tete .d-btn { min-height: 34px; padding: var(--sp-1) var(--sp-3); }
.profil__graphe { width: 100%; }
.profil__graphe svg { display: block; }
.profil__cadre { position: relative; }
/* Graduations de l'echelle verticale, dans le cadre et non sous l'axe :
   posees aux extremites horizontales, on les lisait comme les altitudes de
   depart et d'arrivee. */
.profil__graduation {
  position: absolute; left: 0;
  font-size: var(--fs-label); color: var(--text-dim);
  background: var(--surface); padding: 0 4px; border-radius: 3px;
}
.profil__graduation--haut { top: 0; }
.profil__graduation--bas { bottom: 0; }
.profil__axe {
  display: flex; justify-content: space-between;
  font-size: var(--fs-label); color: var(--text-dim); margin-top: 3px;
}
.profil__axe span:first-child { color: var(--accent); font-weight: 700; }
/* Lecture de la mesure en 3D, sous la barre de boutons. */
.v3d__lecture {
  position: absolute;
  top: calc(var(--sp-3) + 52px); right: var(--sp-3);
  background: var(--surface);
  color: var(--text-strong);
  border-radius: var(--r-badge);
  padding: var(--sp-2) var(--sp-4);
  font-size: var(--fs-sm); font-weight: 700;
  z-index: 1;
}
.v3d__lecture[hidden] { display: none; }

/* --- Recherche de lieu et boussole, dans la vue plein ecran --- */
/* Recherche et cases a cocher dans une seule colonne : en position absolue,
   la liste de resultats recouvrait les cases au lieu de les decaler. */
.v3d__colonne {
  position: absolute;
  top: var(--sp-3); left: var(--sp-3);
  z-index: 2; width: 280px;
  display: flex; flex-direction: column; gap: var(--sp-2);
}
.v3d__recherche { position: relative; }
.v3d__recherche .d-field { min-height: 40px; padding: 9px 12px; }
.v3d__resultats {
  margin-top: 4px;
  max-height: 40vh; overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-tile);
  overflow: hidden;
}
.v3d__resultats[hidden] { display: none; }
.v3d__resultat {
  display: flex; flex-direction: column; gap: 1px;
  width: 100%; text-align: left;
  background: transparent; border: 0; font-family: inherit; cursor: pointer;
  padding: 8px 12px;
  border-bottom: 1px solid var(--line);
}
.v3d__resultat:last-child { border-bottom: 0; }
.v3d__resultat:hover { background: var(--surface-2); }
.v3d__resultat-nom { font-size: var(--fs-sm); font-weight: 700; color: var(--text-strong); }
.v3d__resultat-detail { font-size: var(--fs-label); color: var(--text-dim); }
.v3d__resultat--vide { color: var(--text-dim); font-size: var(--fs-label); cursor: default; }

.v3d__boussole {
  position: absolute;
  left: var(--sp-3);
  /* Au-dessus de l'echelle, et au-dessus du panneau de profil quand il est
     ouvert : il publie sa hauteur dans --h-profil. */
  bottom: calc(54px + var(--h-profil, 0px));
  z-index: 2;
  width: 62px; height: 62px;
  border-radius: 50%;
  background: var(--surface);
  border: 1px solid var(--line);
  cursor: pointer;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 2px;
  font-family: inherit;
}
/* L'aiguille pointe le nord : une fleche dont la moitie haute est accentuee. */
.v3d__aiguille {
  width: 0; height: 0;
  border-left: 6px solid transparent;
  border-right: 6px solid transparent;
  border-bottom: 18px solid var(--accent);
  transform-origin: 50% 70%;
  transition: transform .12s linear;
}
.v3d__cap { font-size: var(--fs-label); font-weight: 800; color: var(--text-dim); }

/* Echelles Leaflet et MapLibre, accordees au theme sombre. */
.leaflet-control-scale-line,
.maplibregl-ctrl-scale {
  background: var(--surface);
  color: var(--text-dim);
  border-color: var(--line);
  font-size: var(--fs-label);
}

/* L'echelle MapLibre s'ecarte elle aussi du panneau de profil. */
.v3d .maplibregl-ctrl-bottom-left { bottom: var(--h-profil, 0px); }
.v3d .maplibregl-ctrl-bottom-right { bottom: var(--h-profil, 0px); }

/* --- Panneau de couches de la vue plein ecran --- */
.v3d__couches {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-tile);
  padding: var(--sp-2) var(--sp-3);
  display: flex; flex-direction: column; gap: 2px;
}
.v3d__couches label {
  display: flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-sm); color: var(--text);
  cursor: pointer; min-height: 30px;
}
.v3d__couches input { accent-color: var(--accent); width: 15px; height: 15px; }

/* --- Panneau meteo : colonne d'heures, a droite --- */
.meteo {
  position: fixed;
  right: var(--sp-3);
  top: calc(var(--sp-3) + 52px);       /* sous la barre de boutons */
  z-index: 1100;
  width: 184px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  padding: var(--sp-3);
}
.meteo[hidden] { display: none; }
.meteo__tete { display: flex; align-items: center; gap: var(--sp-2); margin-bottom: var(--sp-1); }
.meteo__titre { font-size: var(--fs-sm); font-weight: 800; color: var(--text-strong); flex: 1; }
.meteo__tete .d-btn { min-height: 30px; padding: 2px var(--sp-2); }
.meteo__jour { font-size: var(--fs-label); color: var(--text-dim); margin-bottom: var(--sp-2); }

/* Trois heures visibles, les suivantes au defilement. L'accroche verticale
   evite de s'arreter au milieu d'une heure. */
.meteo__colonne {
  max-height: 258px;
  overflow-y: auto;
  scroll-snap-type: y mandatory;
  display: flex; flex-direction: column; gap: var(--sp-2);
  overscroll-behavior: contain;        /* ne pas faire defiler la carte dessous */
}
.meteo__heure {
  scroll-snap-align: start;
  flex: 0 0 auto;
  background: var(--surface-2);
  border-radius: var(--r-tile);
  padding: var(--sp-2) var(--sp-3);
}
.meteo__heure.is-maintenant { box-shadow: inset 0 0 0 2px var(--accent); }
.meteo__quand {
  display: flex; align-items: center; justify-content: space-between;
  font-size: var(--fs-sm); font-weight: 800; color: var(--text-strong); margin-bottom: 4px;
}
/* Direction du vent : la fleche montre vers ou il souffle, le sigle dit d'ou
   il vient — c'est la convention orale des equipes (« vent de sud-ouest »). */
.meteo__boussole { display: flex; align-items: center; gap: 4px; }
.meteo__fleche { width: 14px; height: 14px; color: var(--accent); display: block; }
.meteo__fleche svg { width: 14px; height: 14px; display: block; }
.meteo__secteur { font-size: var(--fs-label); font-weight: 700; color: var(--text-dim); }
.meteo__ligne {
  display: flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-label); color: var(--text-dim);
}
.meteo__ligne b { margin-left: auto; }
.meteo__ico { width: 16px; height: 16px; flex-shrink: 0; }
.meteo__ligne b { color: var(--text); font-weight: 700; }
.meteo__ligne b.is-ok { color: var(--ok); }
.meteo__ligne b.is-warn { color: var(--warn); }
.meteo__ligne b.is-danger { color: var(--danger); }

/* --- Carte en veille : Muret vue du dessus, avec la marque --- */
/* La bande ne doit pas manger les clics : la carte dessous reste utilisable
   pour preparer une intervention avant tout decollage. */
.d-veille {
  position: absolute;
  left: 0; right: 0; bottom: var(--sp-3);
  text-align: center;
  pointer-events: none;
  z-index: 500;
}
/* Le logo est pose sur la carte, a l'adresse du siege. Variante pour fond
   sombre : le blanc du JPEG d'origine est transparent, et le « ONE » noir a
   ete passe en blanc — sinon il disparaissait dans la carte. Le bleu de la
   marque est intact. Une ombre portee decolle le tout du relief. */
.d-siege {
  object-fit: contain;
  filter: drop-shadow(0 1px 3px var(--bg));
}
.d-veille__note {
  font-size: var(--fs-label);
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--text-dim);
  margin-top: var(--sp-1);
  text-shadow: 0 2px 8px var(--bg);
}

/* --- Marqueur du drone : pictogramme oriente selon le cap --- */
.picto-drone { background: none; border: 0; }
.picto-drone__svg { display: block; width: 100%; height: 100%; }
.picto-drone__rot {
  position: relative;
  width: 100%;
  height: 100%;
  transform-origin: 50% 50%;
  transition: transform .4s linear;
}
.picto-drone__alt {
  position: absolute;
  left: 50%;
  top: 100%;
  transform: translateX(-50%);
  transform-origin: 50% 0;
  margin-top: 2px;
  padding: 0 3px;
  border-radius: 3px;
  background: var(--bg);
  color: var(--text);
  font-size: var(--fs-label);
  line-height: 1.4;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  transition: font-size .15s ease-out, transform .4s linear;
}
.picto-drone__alt:empty { display: none; }
.picto-drone:hover .picto-drone__alt { font-size: 16px; color: var(--text-strong); }
@media (prefers-reduced-motion: reduce) {
  .picto-drone__svg, .picto-drone__rot, .picto-drone__alt { transition: none; }
}

/* --- Drones tiers : bandeau d'approche, marqueur et etiquette de la carte --- */
.d-viewer .d-btn.is-selected { background: var(--accent); color: var(--bg); }
.bandeau-alerte {
  background: var(--surface);
  border: 1px solid var(--danger);
  color: var(--text-strong);
  font-size: var(--fs-sm);
  font-weight: 700;
  padding: var(--sp-2) var(--sp-4);
  text-align: center;
}
.drone-tiers__corps {
  display: block;
  width: 14px;
  height: 14px;
  background: var(--danger);
  transform: rotate(45deg);
  margin: 2px;
}
.drone-tiers--ami .drone-tiers__corps { background: var(--accent); }
.etiq-drone { background: var(--surface); color: var(--text); }
.detecteur-fixe__corps {
  display: block;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--accent);
  border: 2px solid var(--text-strong);
  box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.25);
}
.etiq-detecteur { background: var(--surface); color: var(--text); font-size: var(--fs-sm); }
.etiq-detecteur--hors-ligne { color: var(--text-dim); border-style: dashed; }
.d-modules__etat { font-size: var(--fs-sm); color: var(--text-dim); padding: 6px 0 0; }
.d-etat-erreur { color: var(--danger); }

/* --- Mode d'emploi repliable sous un panneau (orthophoto) --- */
.d-help {
  margin-top: var(--sp-4);
  border: 1px solid var(--line);
  border-radius: var(--r-tile);
  background: var(--surface);
  font-size: var(--fs-sm);
  color: var(--text);
  line-height: 1.55;
}
.d-help > summary {
  cursor: pointer;
  padding: var(--sp-3) var(--sp-4);
  font-weight: 700;
  color: var(--text-strong);
  list-style: none;
}
.d-help > summary::-webkit-details-marker { display: none; }
.d-help > summary::before { content: '▸ '; color: var(--accent); }
.d-help[open] > summary::before { content: '▾ '; }
.d-help__body { padding: 0 var(--sp-4) var(--sp-4); }
.d-help__body h4 {
  margin: var(--sp-4) 0 var(--sp-1);
  font-size: var(--fs-body);
  color: var(--accent);
}
.d-help__body h4:first-child { margin-top: 0; }
.d-help__body ol, .d-help__body ul { margin: 0; padding-left: 20px; }
.d-help__body li { margin-bottom: 4px; }
.d-help__body table { border-collapse: collapse; margin-top: var(--sp-1); }
.d-help__body td, .d-help__body th {
  border: 1px solid var(--line);
  padding: 4px var(--sp-2);
  text-align: left;
}
.d-help__body th { color: var(--text-dim); font-weight: 600; }
.d-help__body .is-warn { color: var(--warn); }


/* ── Prise de main (contrôle DRC) ─────────────────────────────────────── */
/* Petit bouton dans la vignette, à côté du statut. Caché sauf si le droit
   est accordé (body.control-on). */
.ctrl-take{display:none}
body.control-on .ctrl-take{
  display:inline-flex;align-items:center;gap:4px;
  font-family:inherit;font-size:var(--fs-sm);font-weight:700;
  padding:4px var(--sp-2);border-radius:var(--r-badge);
  border:1px solid var(--accent);background:transparent;color:var(--accent);
  cursor:pointer;white-space:nowrap
}
body.control-on .ctrl-take:hover{background:var(--accent);color:var(--bg)}

/* Overlay des onglets de contrôle, par-dessus le drone en plein écran. */
.ctrlov{position:fixed;right:var(--sp-4);bottom:var(--sp-4);z-index:1400;
  width:300px;max-width:calc(100vw - 32px);
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r-card);
  box-shadow:0 10px 34px rgba(0,0,0,.5);overflow:hidden;display:none}
.ctrlov.is-open{display:block}
.ctrlov__tabs{display:flex;background:var(--surface-2)}
.ctrlov__tab{flex:1;min-height:46px;border:0;background:transparent;color:var(--text-dim);
  font-family:inherit;font-weight:700;font-size:var(--fs-sm);cursor:pointer}
.ctrlov__tab.is-active{color:var(--text);box-shadow:inset 0 -2px 0 var(--accent)}
.ctrlov__panels{padding:var(--sp-4)}
.ctrlov__panel{display:none;flex-direction:column;gap:var(--sp-3)}
.ctrlov__panel.is-active{display:flex}
.ctrlov .d-btn{width:100%;min-height:46px;justify-content:center}
.ctrlov .d-btn.is-toggle{background:var(--surface-2);color:var(--text)}
.ctrlov .d-btn.is-toggle.on{background:var(--accent);color:var(--bg)}
.ctrl__state{font-size:var(--fs-sm);color:var(--text-dim);text-align:center;
  padding:var(--sp-2) var(--sp-3);border-radius:var(--r-badge);background:var(--bg)}
.ctrl__state.is-ok{color:var(--ok)}
.ctrl__state.is-wait{color:var(--warn)}
.ctrl__msg{min-height:16px;font-size:var(--fs-sm);color:var(--text-dim);text-align:center}
.ctrl__avenir{font-size:var(--fs-sm);color:var(--text-dim);text-align:center;padding:var(--sp-3)}

/* Panneau Caméra de la prise de main : ligne de zoom, croix directionnelle. */
.ctrl__ligne{display:flex;align-items:center;gap:var(--sp-2);flex-wrap:wrap}
.ctrl__ligne .d-btn{width:auto;min-height:38px;flex:1 1 auto;justify-content:center;padding:0 var(--sp-2)}
.ctrl__ligne .d-select{flex:1 1 90px;min-height:38px}
.ctrl__libelle{font-size:var(--fs-sm);color:var(--text-dim);font-weight:700;flex:0 0 auto}
.ctrlov .d-btn.ctrl-zoom.on{background:var(--accent);color:var(--bg)}
/* Manche virtuel de la nacelle : un disque, un bouton qui suit le doigt ;
   la vitesse croit avec l'ecart au centre (voir live.html). */
.ctrl__ligne--manche{justify-content:center;gap:var(--sp-3)}
.ctrl__manche{position:relative;width:140px;height:140px;flex:0 0 auto;border-radius:50%;
  background:radial-gradient(circle,var(--surface-2) 0 30%,transparent 31% 32%,var(--surface-2) 33%);
  border:2px solid var(--line);touch-action:none;user-select:none;cursor:grab}
.ctrl__manche:active{cursor:grabbing;border-color:var(--accent)}
.ctrl__manche-bouton{position:absolute;left:50%;top:50%;width:44px;height:44px;margin:-22px 0 0 -22px;border-radius:50%;
  background:var(--accent);box-shadow:0 2px 8px rgba(0,0,0,.4);pointer-events:none;transition:transform .05s linear}
.ctrl__ligne--manche #ctrl-recentrer{flex:0 0 auto}

/* Ecran bloquant de premiere connexion (dashboard) : par-dessus tout, meme fond que la page de connexion */
.d-mdp-oblig { position: fixed; inset: 0; z-index: 1000; display: flex; align-items: center; justify-content: center; background: var(--bg); padding: var(--sp-4); }
.d-mdp-oblig[hidden] { display: none; }

/* ── Calque Aero ─────────────────────────────────────────────────────── */
/* Le menu Aero porte aussi Drones tiers et Amis : il reste visible avec l un
   ou l autre droit, et ses entrees propres au trafic aerien exigent aero-on. */
body:not(.aero-on):not(.tiers-on) #btnAero, body:not(.aero-on):not(.tiers-on) #menuAero { display: none !important; }
body:not(.aero-on) #menuAero > :not(#btnDronesTiers):not(#btnDronesAmis) { display: none !important; }
.d-aero { display: flex; flex-direction: column; gap: 6px; min-width: 220px; }
.d-aero__ligne, .d-aero__lbl { display: flex; gap: 6px; align-items: center; font-size: 13px; color: var(--text); }
.d-aero__astuce { font-size: 12px; color: var(--text-dim); }
.d-aero__lbl b { margin-left: auto; font-variant-numeric: tabular-nums; }
.d-aero__passages { list-style: none; margin: 0; padding: 0; max-height: 180px; overflow: auto; font-size: 12px; }
.d-aero__passages li { padding: 3px 0; border-top: 1px solid var(--line); }
.d-aero__passages li.is-alerte { color: var(--danger); }
.d-aero__sources { font-size: 12px; color: var(--text-dim); }
.d-aero__sources.is-panne { color: var(--danger); font-weight: 700; }
.d-aero__licence { font-size: 11px; color: var(--text-dim); }
.aero-marque { position: relative; }
.aero-marque__corps { display: block; width: 100%; height: 100%; transform-origin: 50% 50%; }
.aero-svg { width: 100%; height: 100%; fill: var(--trafic); stroke: var(--bg); stroke-width: 1; }
.aero-marque--rouge .aero-svg { fill: var(--danger); filter: drop-shadow(0 0 4px var(--danger)) drop-shadow(0 0 2px var(--danger)); }
.aero-marque--rouge .aero-marque__etiquette { color: var(--danger); font-size: 12px; }
.aero-marque--rouge { z-index: 1000 !important; }
.aero-marque--perime { opacity: .45; }
.aero-marque__etiquette { position: absolute; left: calc(100% + 3px); top: 50%; transform: translateY(-50%); white-space: nowrap; font-weight: 600; font-size: 11px; line-height: 1.2; font-family: inherit;
  color: var(--trafic); text-shadow: 0 0 3px var(--bg), 0 0 3px var(--bg); pointer-events: none; }
.aero-trainee { stroke: var(--trafic); stroke-opacity: .55; stroke-dasharray: 4 4; }
.aero-trainee--rouge { stroke: var(--danger); }
.bandeau-aero { cursor: pointer; }
.d-aero__point { display: flex; flex-direction: column; gap: 6px; padding-top: 6px; border-top: 1px solid var(--line); }
.d-aero__saisie { flex: 1; min-width: 0; background: var(--surface-2); border: 1px solid var(--line); border-radius: 6px; color: var(--text); font: inherit; font-size: 12px; padding: 4px 6px; }
.d-aero__point-info { font-size: 12px; color: var(--text-dim); }
#map.aero-pose, #map.aero-pose .leaflet-interactive { cursor: crosshair; }
.aero-point { font-size: 24px; line-height: 28px; text-align: center; filter: drop-shadow(0 0 2px var(--bg)); }
.aero-point__cercle { stroke: var(--danger); stroke-width: 2; stroke-dasharray: 6 6; fill: var(--danger); fill-opacity: .06; }
.aero-terrain { position: relative; }
.aero-terrain__symbole { display: flex; align-items: center; justify-content: center; width: 22px; height: 22px; border-radius: 50%;
  font-weight: 700; font-size: 12px; line-height: 1; color: var(--bg); background: var(--trafic); border: 2px solid var(--bg); box-sizing: border-box; }
.aero-terrain--rouge .aero-terrain__symbole { background: var(--danger); box-shadow: 0 0 6px var(--danger); }
.aero-terrain__etiquette { position: absolute; left: calc(100% + 3px); top: 50%; transform: translateY(-50%); white-space: nowrap;
  font-weight: 600; font-size: 11px; color: var(--trafic); text-shadow: 0 0 3px var(--bg), 0 0 2px var(--bg); }
.aero-terrain--rouge .aero-terrain__etiquette { color: var(--danger); }
.aero-fiche .leaflet-popup-content { font-size: 12px; line-height: 1.45; }
.aero-fiche__consignes { display: block; margin-top: 4px; color: var(--text-dim); }
.bandeau-aero--panne { background: var(--surface-2) !important; border-color: var(--text-dim) !important; color: var(--text-dim) !important; cursor: default; }

.aero-filtres, .aero-reglages, .aero-lecteur, .aero-exports { display: flex; flex-wrap: wrap; gap: 8px 14px; align-items: center; margin: 8px 0; }
.aero-liste { list-style: none; margin: 0; padding: 0; max-height: 260px; overflow: auto; }
.aero-liste__passage { width: 100%; text-align: left; background: none; border: 0; border-top: 1px solid var(--line); color: var(--text); padding: 6px 2px; cursor: pointer; font: inherit; }
.aero-liste__passage.is-alerte { color: var(--danger); }
.aero-liste__passage:disabled { cursor: default; opacity: .6; }
.aero-carte { height: 360px; border-radius: 8px; margin: 8px 0; }
.aero-lecteur input[type=range] { flex: 1; min-width: 160px; }
.aero-profil { width: 100%; height: 120px; background: var(--surface-2); border-radius: 6px; }
.aero-profil__aeronef { stroke: var(--danger); stroke-width: 2; }
.aero-profil__drone { stroke: var(--accent); stroke-width: 2; }
.aero-profil__curseur { stroke: var(--text-strong); stroke-dasharray: 3 3; }
.aero-profil__txt { fill: var(--text-dim); font-size: 10px; }
.aero-note { font-size: 12px; color: var(--text-dim); }
.aero-erreur { color: var(--danger); font-size: 13px; margin: 8px 0; }
.aero-liste__erreur { color: var(--danger); padding: 6px 2px; }

/* ── Rejeu d'une opération (archives 7 jours) ─────────────────────────── */
.rejeu-hdr-btn { display: none; }
body.enregistrement-on .rejeu-hdr-btn { display: inline-flex; }
.rejeu-bandeau { display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-2) var(--sp-3); background: var(--surface-2); background: color-mix(in srgb, var(--accent) 18%, var(--surface-2)); color: var(--text-strong); border-bottom: 1px solid var(--line); flex-wrap: wrap; }
.rejeu-bandeau[hidden] { display: none; }
.rejeu-bandeau__titre { font-weight: 700; }
.rejeu-bandeau__barre { flex: 1; min-width: 160px; }
.rejeu-bandeau__heure { font-family: ui-monospace, Menlo, monospace; }
.rejeu-bandeau__vitesse { width: auto; }
/* Au-dessus des panneaux Leaflet (jusqu'a 1000) et des bandes .d-overlay (800),
   qui partagent le contexte d'empilement racine. */
.rejeu-liste { position: fixed; inset: 60px 16px auto 16px; max-width: 720px; margin: 0 auto; background: var(--surface); border: 1px solid var(--line); border-radius: 12px; padding: var(--sp-3); z-index: 1150; max-height: 70vh; overflow: auto; }
.rejeu-liste__barre { display: flex; justify-content: space-between; align-items: center; margin-bottom: var(--sp-2); }
.rejeu-op { display: flex; gap: var(--sp-2); align-items: center; flex-wrap: wrap; padding: var(--sp-2) 0; border-top: 1px solid var(--line); }
.rejeu-op__libelle { flex: 1; min-width: 220px; }
.rejeu-op__liens { display: flex; gap: var(--sp-1); flex-wrap: wrap; }
.d-vtile__sansvideo { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; color: var(--text-dim); background: var(--bg); }
/* En rejeu, les tuiles montrent l'archive : prendre la main viserait le drone
   du direct, que l'operateur ne voit plus. */
body.rejeu-on .d-vtile .ctrl-take { display: none; }
