/* =========================================================
   TOKENS
   ========================================================= */
:root {
  --bg-void:        #0A0C0F;
  --bg-panel:       #14171C;
  --bg-panel-raised:#1B1F25;
  --bg-input:       #101317;
  --border:         #262B32;
  --border-soft:    #1D2128;

  --text-primary:   #E8EAED;
  --text-muted:     #8B939D;
  --text-faint:     #565D66;

  --accent:         #5EEAD4;   /* sarcelle "ligne de niveau" */
  --accent-dim:      rgba(94, 234, 212, 0.12);
  --accent-strong:  #2DD4BF;
  --warn:           #F2A65A;
  --warn-dim:       rgba(242, 166, 90, 0.12);
  --danger:         #EF5350;

  --font-display: 'Space Grotesk', sans-serif;
  --font-body:    'Inter', sans-serif;
  --font-mono:    'JetBrains Mono', monospace;

  --radius-s: 6px;
  --radius-m: 10px;
  --sidebar-w: 360px;
}

* { box-sizing: border-box; }

html, body {
  margin: 0; padding: 0;
  height: 100%;
  background: var(--bg-void);
  color: var(--text-primary);
  font-family: var(--font-body);
  overflow: hidden;
}

#app {
  display: flex;
  height: 100vh;
  width: 100vw;
}

/* =========================================================
   VIEWPORT
   ========================================================= */
#viewport {
  position: relative;
  flex: 1;
  background:
    radial-gradient(ellipse at 30% 20%, rgba(94,234,212,0.05), transparent 60%),
    var(--bg-void);
  overflow: hidden;
}

#scene-canvas {
  display: block;
  width: 100%;
  height: 100%;
}

#hud-stack {
  position: absolute;
  top: 20px; left: 20px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
  /* Largeur dictée par le CONTENU, pas fixée : certaines valeurs sont
     nettement plus longues que d'autres (« IGN haute précision · ~13 m »)
     et se retrouvaient tronquées à largeur fixe. Bornée pour ne pas
     envahir le viewport. */
  width: max-content;
  min-width: 200px;
  max-width: min(380px, 42vw);
  /* Au-dessus du canvas, sous le sélecteur de source (40) qu'il ouvre. */
  z-index: 10;
}
#hud-stack > * { width: 100%; }
#hud-topo {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 12px 16px;
  background: rgba(20, 23, 28, 0.6);
  backdrop-filter: blur(10px);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-m);
  /* Le bandeau laisse passer les clics vers la vue 3D : il recouvre un
     coin du viewport et ne doit pas gêner la manipulation du modèle. */
  pointer-events: none;
}
.hud-line { display: flex; gap: 10px; align-items: baseline; }

/* ...sauf les lignes explicitement interactives, qui doivent les
   recevoir. Sans cette exception, aucun clic ne les atteignait, quel que
   soit le code JavaScript branché dessus. */
.hud-line-action { pointer-events: auto; }
.hud-label {
  font-family: var(--font-display);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
  width: 60px;
  flex-shrink: 0;
}
.hud-value {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--accent);
  white-space: nowrap;
}
.hud-line { flex-wrap: nowrap; }

/* --- Panneau des pièces imprimables (sous le HUD, colonne gauche) --- */
.pieces-panel {
  width: 100%;
  background: rgba(20, 23, 28, 0.7);
  backdrop-filter: blur(10px);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-m);
  overflow: hidden;
}
.pieces-header {
  padding: 9px 12px;
  border-bottom: 1px solid var(--border-soft);
  font-family: var(--font-display);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.pieces-list {
  list-style: none;
  margin: 0; padding: 6px;
  display: flex; flex-direction: column; gap: 2px;
}
.pieces-list li {
  display: flex; gap: 8px; align-items: flex-start;
  padding: 6px 6px;
  border-radius: 6px;
  font-size: 11px;
  line-height: 1.4;
  color: var(--text-muted);
  pointer-events: auto;
}
.pieces-list li.piece-hidden { opacity: 0.4; }
.pieces-list .piece-dot {
  width: 6px; height: 6px;
  margin-top: 5px;
  border-radius: 50%;
  background: var(--accent);
  flex-shrink: 0;
}
.pieces-list li.piece-hidden .piece-dot { background: var(--text-faint); }
.pieces-list .piece-body { flex: 1; }
.pieces-list .piece-name {
  color: var(--text-primary);
  font-family: var(--font-display);
  font-weight: 500;
  display: block;
}
.pieces-list .piece-desc { color: var(--text-faint); }
.piece-eye {
  width: 22px; height: 22px;
  flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: transparent;
  border: none;
  color: var(--text-faint);
  font-size: 13px;
  cursor: pointer;
  border-radius: 5px;
}
.piece-eye:hover { color: var(--accent); background: var(--accent-dim); }

#viewport-toolbar {
  position: absolute;
  bottom: 20px; left: 20px;
  display: flex;
  gap: 6px;
}
.icon-btn {
  width: 36px; height: 36px;
  display: flex; align-items: center; justify-content: center;
  background: rgba(20, 23, 28, 0.7);
  backdrop-filter: blur(10px);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-s);
  color: var(--text-muted);
  cursor: pointer;
  transition: all 0.15s ease;
}
.icon-btn:hover { color: var(--accent); border-color: var(--accent); }
.icon-btn.active { color: var(--bg-void); background: var(--accent); }

/* --- Loader centré : visible mais SANS flou plein écran (juste sa
     propre carte, opaque, au milieu de l'écran) --- */
#loading-center {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  padding: 22px 26px;
  /* Taille FIXE : la largeur suivait le texte, qui gagne un pourcentage
     en cours de route — la boîte changeait donc de dimension en pleine
     progression, donnant l'impression de deux fenêtres successives. */
  width: 280px;
  box-sizing: border-box;
  background: rgba(14, 17, 21, 0.94);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-m);
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.4);
  transition: opacity 0.2s ease, transform 0.2s ease;
  z-index: 6;
}
#loading-center.hidden { opacity: 0; transform: translate(-50%, -50%) scale(0.96); pointer-events: none; }

/* Variante BASSE, pour les couches d'occupation du sol.
   Ces chargements se font pendant que le modèle est déjà visible : une
   boîte au centre masquerait précisément ce que l'utilisateur regarde.
   Placée en bas, elle informe sans cacher. */
#loading-center.at-bottom {
  top: auto; bottom: 26px;
  transform: translate(-50%, 0);
}
#loading-center.at-bottom.hidden { transform: translate(-50%, 8px) scale(0.96); }
.loading-icon-wrap {
  width: 40px; height: 40px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  background: var(--accent-dim);
  color: var(--accent);
  font-size: 18px;
}
.loading-icon-wrap i.anim-spin { animation: loader-spin 1.1s linear infinite; }
.loading-icon-wrap i.anim-pulse { animation: loader-pulse 1.1s ease-in-out infinite; }
@keyframes loader-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
@keyframes loader-pulse { 0%, 100% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.18); opacity: 0.7; } }
.loading-text {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.02em;
  color: var(--text-muted);
  text-align: center;
  line-height: 1.35;
  /* Deux lignes possibles sans changer la hauteur de la boîte. */
  min-height: 32px;
  display: flex; align-items: center; justify-content: center;
}
.loading-pct {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--accent);
  min-height: 14px;
}
.loading-track {
  width: 100%;
  height: 3px;
  background: var(--border);
  border-radius: 2px;
  overflow: hidden;
}
.loading-fill {
  height: 100%;
  width: 30%;
  background: var(--accent);
  border-radius: 2px;
  transition: width 0.2s ease;
}

/* =========================================================
   SIDEBAR
   ========================================================= */
#sidebar {
  width: var(--sidebar-w);
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  background: var(--bg-panel);
  border-left: 1px solid var(--border);
  height: 100vh;
}

.sidebar-header {
  position: relative;
  padding: 18px 20px;
  border-bottom: 1px solid var(--border);
  overflow: hidden;
}
.brand {
  display: flex; align-items: center; gap: 10px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 16px;
  letter-spacing: 0.02em;
  z-index: 1; position: relative;
}
.brand i { color: var(--accent); font-size: 18px; }

.contour-motif {
  position: absolute;
  top: -30%; right: -10%;
  width: 160px; height: 160px;
  background-image:
    repeating-radial-gradient(circle at 60% 50%,
      transparent 0, transparent 8px,
      rgba(94,234,212,0.07) 9px, rgba(94,234,212,0.07) 10px);
  border-radius: 50%;
}

.sidebar-scroll {
  flex: 1;
  overflow-y: auto;
  padding: 4px 0 20px;
}
.sidebar-scroll::-webkit-scrollbar { width: 6px; }
.sidebar-scroll::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }

.panel { padding: 18px 20px; }
.panel-title {
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin: 0 0 14px;
}
.panel-title-row {
  display: flex; align-items: center; justify-content: space-between;
  margin: 0 0 6px;
}
.panel-title-row .panel-title { margin: 0; }

.divider { height: 1px; background: var(--border); margin: 0 20px; }

/* --- Tabs --- */
.tabs {
  display: flex;
  gap: 4px;
  background: var(--bg-input);
  padding: 4px;
  border-radius: var(--radius-m);
  margin-bottom: 16px;
}
.tab {
  flex: 1;
  display: flex; align-items: center; justify-content: center; gap: 6px;
  padding: 8px 0;
  background: transparent;
  border: none;
  border-radius: var(--radius-s);
  color: var(--text-muted);
  font-family: var(--font-body);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.15s ease;
}
.tab:hover { color: var(--text-primary); }
.tab.active { background: var(--bg-panel-raised); color: var(--accent); }

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

/* --- Fields --- */
.field-label {
  display: block;
  font-family: var(--font-display);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.03em;
  color: var(--text-muted);
  margin: 14px 0 6px;
}
.field-label:first-child { margin-top: 0; }
.field-label.small { font-size: 10px; margin: 10px 0 4px; }
.field-label .unit { color: var(--text-faint); font-weight: 400; text-transform: none; }

.field-row { display: flex; gap: 10px; }
.field-col { flex: 1; }

/* Règle de base : AUCUN habillage.
   C'était l'inverse — fond plein, bordure, 9 px de rembourrage sur tout
   champ texte ou nombre du document. Chaque valeur du panneau devenait
   une boîte, et la colonne se lisait comme une pile de cadres plutôt que
   comme une liste de réglages. Les classes plus précises ne rattrapaient
   qu'une partie, d'où des champs au style incohérent selon leur âge.
   L'habillage est désormais l'exception, demandée explicitement. */
input[type="text"], input[type="number"] {
  width: 100%;
  padding: 3px 5px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-s);
  color: var(--text-primary);
  font-family: var(--font-body);
  font-size: 13px;
  outline: none;
  transition: background 0.15s ease, border-color 0.15s ease;
}
/* AUCUN retour au survol.
   Un cadre qui s'allume sous le curseur annonce « ceci est modifiable »
   — une information que tu connais déjà, et qui fait clignoter la
   colonne dès qu'on la traverse à la souris. Le champ ne se distingue
   donc qu'une fois la saisie commencée, quand le repère sert vraiment. */
input:focus { background: var(--bg-input); border-color: var(--accent); }

/* L'EXCEPTION : le champ de recherche. C'est une invite à écrire, pas la
   valeur d'un réglage — sans cadre, rien n'indiquerait où taper. */
#input-address {
  padding: 9px 12px;
  background: var(--bg-input);
  border: 1px solid var(--border);
}
.mono-input { font-family: var(--font-mono); font-size: 12px; }

/* --- Ligne Dimension / lien / Zoom --- */
.link-row { align-items: flex-end; gap: 10px; }
.link-toggle {
  width: 28px; height: 28px;
  flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: var(--radius-s);
  color: var(--text-faint);
  font-size: 14px;
  cursor: pointer;
  margin-bottom: 1px;
  transition: all 0.15s ease;
}
.link-toggle:hover { border-color: var(--accent); color: var(--accent); }
.link-toggle.active { background: var(--accent-dim); border-color: var(--accent); color: var(--accent); }
.derived-readout {
  margin-top: 10px;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-faint);
}
.derived-readout .unit { font-family: var(--font-display); text-transform: none; margin: 0 4px 0 2px; }
.derived-readout #ratio-readout { color: var(--text-muted); }

/* --- Cadran rotatif infini (zoom) --- */
.dial {
  position: relative;
  width: 32px; height: 32px;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--bg-input);
  border: 1px solid var(--border);
  cursor: grab;
  touch-action: none;
  transition: border-color 0.15s ease;
}
.dial:hover, .dial:focus-visible { border-color: var(--accent); outline: none; }
.dial:active { cursor: grabbing; }
.dial::after {
  content: '';
  position: absolute; inset: 0;
  margin: auto;
  width: 4px; height: 4px;
  border-radius: 50%;
  background: var(--border);
}
.dial-notch {
  position: absolute;
  top: 3px; left: 50%;
  width: 2px; height: 9px;
  margin-left: -1px;
  background: var(--accent);
  border-radius: 1px;
  transform-origin: 1px 13px;
  pointer-events: none;
}

/* Indice visuel : ces champs sont ajustables à la molette quand ils ont le focus */
#input-dimension, #input-ratio, #input-exaggeration, #input-smoothing,
#input-trace-width, #input-floor, #frame-height, #frame-thickness,
#fillet-inner-top, #fillet-outer-top, #fillet-outer-bottom, #fillet-outer-vertical {
  cursor: ns-resize;
}

.input-with-btn { display: flex; gap: 8px; }
.input-with-btn input { flex: 1; }

.slider {
  width: 100%;
  -webkit-appearance: none;
  height: 3px;
  background: var(--border);
  border-radius: 2px;
  margin: 8px 0 4px;
}
.slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 14px; height: 14px;
  border-radius: 50%;
  background: var(--accent);
  cursor: pointer;
  box-shadow: 0 0 0 3px var(--accent-dim);
}

.hint {
  display: flex; gap: 6px; align-items: flex-start;
  font-size: 11px;
  line-height: 1.5;
  color: var(--text-faint);
  margin: 10px 0 0;
}
.hint i { margin-top: 2px; }

/* --- Dropzone --- */
.dropzone {
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  padding: 24px 12px;
  border: 1.5px dashed var(--border);
  border-radius: var(--radius-m);
  color: var(--text-faint);
  font-size: 12px;
  text-align: center;
  cursor: pointer;
  transition: all 0.15s ease;
}
.dropzone:hover, .dropzone.dragover { border-color: var(--accent); color: var(--accent); background: var(--accent-dim); }
.dropzone i { font-size: 22px; }

/* --- Shape buttons --- */
.shape-group { display: flex; gap: 8px; margin-bottom: 4px; }
.shape-btn {
  width: 40px; height: 40px;
  display: flex; align-items: center; justify-content: center;
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: var(--radius-s);
  color: var(--text-muted);
  cursor: pointer;
  font-size: 15px;
  transition: all 0.15s ease;
}
.shape-btn:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
.shape-btn.active { background: var(--accent-dim); border-color: var(--accent); color: var(--accent); }
.shape-btn:disabled { opacity: 0.3; cursor: not-allowed; }

/* --- Switch --- */
.switch { position: relative; width: 38px; height: 22px; display: inline-block; }
.switch input { opacity: 0; width: 0; height: 0; }
.switch-track {
  position: absolute; inset: 0;
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: 20px;
  cursor: pointer;
  transition: 0.2s;
}
.switch-track::before {
  content: '';
  position: absolute;
  width: 14px; height: 14px;
  left: 3px; top: 3px;
  background: var(--text-faint);
  border-radius: 50%;
  transition: 0.2s;
}
.switch input:checked + .switch-track { background: var(--accent-dim); border-color: var(--accent); }
.switch input:checked + .switch-track::before { transform: translateX(16px); background: var(--accent); }

.collapsible { overflow: hidden; transition: max-height 0.25s ease, opacity 0.2s ease; }
.collapsible.collapsed { max-height: 0 !important; opacity: 0; }

/* --- Buttons --- */
.btn-primary, .btn-secondary {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  padding: 10px 16px;
  border-radius: var(--radius-s);
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.01em;
  cursor: pointer;
  border: 1px solid transparent;
  transition: all 0.15s ease;
}
.btn-primary { background: var(--accent); color: #06201C; }
.btn-primary:hover:not(:disabled) { background: var(--accent-strong); }
.btn-primary:disabled { background: var(--bg-panel-raised); color: var(--text-faint); cursor: not-allowed; }
.btn-secondary { background: var(--bg-panel-raised); color: var(--text-primary); border-color: var(--border); }
.btn-secondary:hover { border-color: var(--accent); color: var(--accent); }
.btn-icon { padding: 9px 14px; }
.full-width { width: 100%; margin-top: 12px; }

/* --- Alert --- */
.alert-warning {
  display: flex; gap: 8px; align-items: flex-start;
  padding: 10px 12px;
  margin-top: 12px;
  background: var(--warn-dim);
  border: 1px solid var(--warn);
  border-radius: var(--radius-s);
  color: var(--warn);
  font-size: 11px;
  line-height: 1.5;
}
.alert-warning.hidden { display: none; }

/* --- Footer / export --- */
.sidebar-footer {
  padding: 16px 20px;
  border-top: 1px solid var(--border);
  background: var(--bg-panel);
}
.export-status {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-faint);
  min-height: 14px;
  margin-bottom: 8px;
}

.hidden { display: none !important; }

@media (max-width: 900px) {
  #app { flex-direction: column; }
  #sidebar { width: 100%; height: 50vh; border-left: none; border-top: 1px solid var(--border); }
  #viewport { height: 50vh; }
}

/* =========================================================
   ACCORDÉON (sections repliables nommées)
   ========================================================= */
.acc { border-bottom: 1px solid var(--border); }
.acc-head {
  display: flex; align-items: center; gap: 9px;
  padding: 13px 18px;
  cursor: pointer;
  user-select: none;
  transition: background 0.15s ease;
}
.acc-head:hover { background: rgba(255, 255, 255, 0.02); }
.acc-caret {
  font-size: 11px;
  color: var(--text-faint);
  transition: transform 0.2s ease;
}
.acc.collapsed .acc-caret { transform: rotate(-90deg); }
.acc-icon { font-size: 14px; color: var(--accent); }
.acc-title {
  flex: 1;
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.03em;
  color: var(--text-primary);
}
.acc-switch { flex-shrink: 0; }
.acc-body {
  padding: 0 18px 18px;
  overflow: hidden;
}
.acc.collapsed .acc-body { display: none; }

/* =========================================================
   RECHERCHE AVEC SUGGESTIONS
   ========================================================= */
.search-wrap { position: relative; }
.search-wrap input { padding-right: 34px; }
.search-icon {
  position: absolute;
  right: 11px; top: 50%;
  transform: translateY(-50%);
  color: var(--text-faint);
  font-size: 13px;
  pointer-events: none;
}
.search-icon.spinning { animation: loader-spin 0.9s linear infinite; }
.search-results {
  list-style: none;
  margin: 6px 0 0; padding: 4px;
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: var(--radius-s);
  display: flex; flex-direction: column; gap: 2px;
}
.search-results.hidden { display: none; }
.search-results li {
  padding: 8px 10px;
  border-radius: 5px;
  font-size: 12px;
  line-height: 1.35;
  color: var(--text-muted);
  cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease;
}
.search-results li:hover { background: var(--accent-dim); color: var(--accent); }
.search-results li.empty { color: var(--text-faint); cursor: default; }
.search-results li.empty:hover { background: transparent; color: var(--text-faint); }
.sr-name { display: block; color: var(--text-primary); font-weight: 500; }
.search-results li:hover .sr-name { color: var(--accent); }
.sr-detail { display: block; font-size: 11px; color: var(--text-faint); }

/* =========================================================
   GESTIONNAIRE DE TRACES
   ========================================================= */
.traces-list {
  list-style: none;
  margin: 10px 0 0; padding: 0;
  display: flex; flex-direction: column; gap: 4px;
}
.traces-list:empty { display: none; }
.traces-list li {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 9px;
  background: var(--bg-input);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-s);
  font-size: 12px;
}
.trace-swatch {
  width: 8px; height: 8px;
  border-radius: 2px;
  flex-shrink: 0;
}
.trace-name {
  flex: 1;
  color: var(--text-primary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  cursor: text;
}
.trace-name-input {
  flex: 1;
  padding: 2px 5px !important;
  font-size: 12px !important;
}
.trace-pts { color: var(--text-faint); font-family: var(--font-mono); font-size: 10px; }
.trace-del {
  width: 20px; height: 20px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: transparent; border: none;
  color: var(--text-faint); font-size: 11px;
  cursor: pointer; border-radius: 4px;
}
.trace-del:hover { color: var(--danger); background: rgba(239, 83, 80, 0.12); }

/* =========================================================
   CONTRÔLES (libellé + valeur + slider ou molette)
   ========================================================= */
.ctrl { margin-top: 16px; }
.ctrl:first-child { margin-top: 0; }
.ctrl-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px;
  margin-bottom: 7px;
}
.ctrl-head .field-label { margin: 0; display: flex; align-items: center; gap: 6px; }
.ctrl-value { display: flex; align-items: center; gap: 7px; flex-shrink: 0; }
.mono-input.tight {
  field-sizing: content;
  width: auto;
  min-width: 2ch;
  max-width: 9ch;
  padding: 3px 4px;
  text-align: right;
}
.mono-readout {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-primary);
  min-width: 58px;
  text-align: right;
}
.ctrl .slider { margin: 0; }
.ctrl .hint { margin-top: 8px; }
.link-toggle {
  width: 22px; height: 22px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: 5px;
  color: var(--text-faint);
  font-size: 12px;
  cursor: pointer;
  transition: all 0.15s ease;
}
.link-toggle:hover { border-color: var(--accent); color: var(--accent); }
.link-toggle.active { background: var(--accent-dim); border-color: var(--accent); color: var(--accent); }

/* Les molettes sont un peu plus petites dans les contrôles compacts */
.ctrl-value .dial { width: 28px; height: 28px; }
.ctrl-value .dial-notch { top: 3px; height: 8px; transform-origin: 1px 11px; }

.hidden { display: none !important; }

.divider-soft { height: 1px; background: var(--border-soft); margin: 16px 0 4px; }

/* =========================================================
   CADRE : coupe, sous-sections, sélecteur de position
   ========================================================= */
.profile-preview {
  background: var(--bg-input);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-s);
  margin-bottom: 16px;
  overflow: hidden;
}
.profile-preview svg { display: block; width: 100%; height: auto; }

.sub-head {
  display: flex; align-items: center; justify-content: space-between;
  margin: 4px 0 8px;
}
.sub-title {
  font-family: var(--font-display);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.sub-body { overflow: hidden; }
.sub-body.collapsed { display: none; }

.seg-group {
  display: flex; gap: 3px;
  background: var(--bg-input);
  padding: 3px;
  border-radius: var(--radius-s);
  margin-bottom: 12px;
}
.seg {
  flex: 1;
  padding: 6px 0;
  background: transparent;
  border: none;
  border-radius: 4px;
  color: var(--text-muted);
  font-family: var(--font-body);
  font-size: 12px;
  cursor: pointer;
  transition: all 0.15s ease;
}
.seg:hover { color: var(--text-primary); }
.seg.active { background: var(--accent-dim); color: var(--accent); }

.text-area {
  width: 100%;
  padding: 8px 10px;
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: var(--radius-s);
  color: var(--text-primary);
  font-family: var(--font-display);
  font-size: 12px;
  resize: vertical;
  outline: none;
  margin-bottom: 12px;
}
.text-area:focus { border-color: var(--accent); }

.position-picker {
  background: var(--bg-input);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-s);
  padding: 10px;
  display: flex; justify-content: center;
}
.position-picker svg { display: block; width: 150px; height: 150px; cursor: pointer; }
.pp-zone { fill: transparent; stroke: none; cursor: pointer; }
.pp-zone:hover { fill: rgba(94, 234, 212, 0.18); }
.pp-zone.active { fill: rgba(94, 234, 212, 0.35); }
.pp-outline { fill: none; stroke: var(--border); stroke-width: 1.5; }
.pp-label { fill: var(--text-faint); font-size: 9px; font-family: monospace; text-anchor: middle; }


/* --- Recentrage (déplacement du cadrage) --- */
.pan-row { display: flex; gap: 10px; }
.pan-cell {
  flex: 1;
  display: flex; align-items: center; gap: 6px;
  padding: 6px 8px;
  background: var(--bg-input);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-s);
}
.pan-label {
  font-family: var(--font-display);
  font-size: 9px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-faint);
  flex: 1;
}
.pan-cell .mono-readout { min-width: 42px; font-size: 11px; }
.btn-icon-toggle {
  width: 26px; height: 26px;
  display: flex; align-items: center; justify-content: center;
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: var(--radius-s);
  color: var(--text-muted);
  font-size: 13px;
  cursor: pointer;
  transition: all 0.15s ease;
}
.btn-icon-toggle:hover { border-color: var(--accent); color: var(--accent); }
.btn-icon-toggle.active { background: var(--accent-dim); border-color: var(--accent); color: var(--accent); }

/* =========================================================
   LIGNES DE MODULE (accès aux fenêtres de paramétrage)
   ========================================================= */
.module-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.module-list li {
  display: flex; align-items: center; gap: 9px;
  padding: 9px 10px;
  background: var(--bg-input);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-s);
}
.mod-icon { color: var(--accent); font-size: 13px; }
.mod-name {
  flex: 1;
  font-family: var(--font-display);
  font-size: 12px;
  color: var(--text-primary);
}
.mod-open {
  width: 24px; height: 24px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 5px;
  color: var(--text-muted);
  font-size: 11px;
  cursor: pointer;
  transition: all 0.15s ease;
}
.mod-open:hover { border-color: var(--accent); color: var(--accent); background: var(--accent-dim); }
.switch.mini { width: 30px; height: 17px; flex-shrink: 0; }
.switch.mini .switch-track::before { width: 11px; height: 11px; }
.switch.mini input:checked + .switch-track::before { transform: translateX(13px); }

/* =========================================================
   FENÊTRES FLOTTANTES GÉNÉRIQUES
   Visualisation + paramètres réunis. Réduites, elles se rangent dans le
   dock en bas à droite — jamais dans le panneau latéral.
   ========================================================= */
.float-win {
  position: fixed;
  max-width: calc(100vw - var(--sidebar-w) - 40px);
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-m);
  box-shadow: 0 18px 56px rgba(0, 0, 0, 0.55);
  display: flex; flex-direction: column;
  max-height: calc(100vh - 120px);
}
.float-win.hidden { display: none; }
.fw-head {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 10px 10px 13px;
  border-bottom: 1px solid var(--border-soft);
  cursor: grab;
  user-select: none;
  touch-action: none;
}
.fw-head:active { cursor: grabbing; }
.fw-head > i { color: var(--accent); font-size: 13px; }
.fw-title {
  flex: 1;
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--text-primary);
  white-space: nowrap;
}
.fw-btn {
  width: 22px; height: 22px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: transparent; border: none;
  color: var(--text-faint); font-size: 11px;
  cursor: pointer; border-radius: 4px;
}
.fw-btn:hover { color: var(--accent); background: var(--accent-dim); }
.fw-body {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  padding: 14px;
  overflow: hidden;
}
/* Colonne de gauche : l'aperçu. Largeur FIXE et généreuse — elle ne
   suit pas la taille du contenu, sinon la zone grandirait à mesure qu'on
   agrandit la pièce, sans jamais laisser voir de marge autour. */
.fw-col-view {
  flex: 0 0 340px;
  width: 340px;
  position: sticky;
  top: 0;
}
/* Colonne de droite : les réglages, seule zone qui défile. */
.fw-col-ctrl {
  flex: 1 1 auto;
  min-width: 240px;
  /* Hauteur alignée sur celle de l'aperçu au minimum, pour que les deux
     colonnes forment un bloc cohérent même avec peu de réglages. */
  min-height: 330px;
  max-height: calc(100vh - 200px);
  overflow-y: auto;
  padding-right: 6px;
}
.fw-col-ctrl::-webkit-scrollbar { width: 6px; }
.fw-col-ctrl::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
.fw-col-view .fw-view { margin-bottom: 0; }
.fw-col-ctrl .ctrl:first-child { margin-top: 0; }
.fw-body::-webkit-scrollbar { width: 6px; }
.fw-body::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }

/* Zone de visualisation : dimensions FIXES, plus grandes que le contenu
   attendu. Le dessin garde son échelle réelle (px/mm constants) et flotte
   au centre avec de la marge autour : on voit ainsi la pièce grandir DANS
   son cadre, au lieu de voir le cadre grandir avec elle. */
.fw-view {
  background: var(--bg-input);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-s);
  padding: 14px;
  margin-bottom: 0;
  width: 100%;
  height: 330px;
  box-sizing: border-box;
  display: flex; align-items: center; justify-content: center;
  overflow: auto;
}
.fw-view svg { flex: 0 0 auto; }
.fw-view svg { display: block; }
.fw-empty { color: var(--text-faint); font-size: 11px; padding: 22px 10px; text-align: center; }

/* Dock des fenêtres réduites */
.win-dock {
  position: fixed;
  /* À GAUCHE du panneau latéral : posé par-dessus, le dock masquait les
     réglages et donnait l'impression d'un empilement accidentel. */
  right: calc(var(--sidebar-w) + 18px);
  bottom: 18px;
  z-index: 55;
  display: flex; flex-direction: column; gap: 6px; align-items: flex-end;
}
.win-dock-btn {
  display: flex; align-items: center; gap: 7px;
  padding: 8px 12px;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-s);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4);
  color: var(--text-muted);
  font-family: var(--font-display);
  font-size: 11px;
  cursor: pointer;
  transition: all 0.15s ease;
}
.win-dock-btn:hover { color: var(--accent); border-color: var(--accent); }
.win-dock-btn i { color: var(--accent); font-size: 12px; }

/* Bouton « revenir à la valeur par défaut ».
   Toujours en dernier dans la ligne, donc aligné sur une même colonne
   d'un contrôle à l'autre. Quand la valeur est celle d'origine, il est
   masqué mais CONSERVE sa place : sans cela, les valeurs se décaleraient
   dès qu'un paramètre est modifié. */
.reset-btn {
  width: 20px; height: 20px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  margin-left: 2px;
  background: transparent;
  border: none;
  border-radius: 4px;
  color: var(--text-faint);
  font-size: 10px;
  cursor: pointer;
  transition: color 0.15s ease, background 0.15s ease, opacity 0.15s ease;
}
.reset-btn:hover { color: var(--warn); background: var(--warn-dim); }
/* À sa valeur par défaut, le bouton ne réserve PLUS sa place.
   `visibility: hidden` laissait un creux de 22 px entre la valeur et le
   bord : les chiffres des lignes sans bouton flottaient, décalés de ceux
   des lignes qui en ont un. `display: none` les aligne tous sur la même
   colonne. Le bouton réapparaît dès que la valeur s'écarte du défaut, et
   la ligne se décale alors — c'est le prix de l'alignement, et c'est le
   bon échange : on lit une colonne de chiffres, pas une colonne de
   boutons. */
.reset-btn.is-default {
  display: none;
}

/* =========================================================
   MOLETTE HORIZONTALE (défilement infini)
   Même agencement qu'un slider — libellé et valeur au-dessus, contrôle
   sur toute la largeur en dessous — pour que les deux types de réglage
   se lisent de la même façon. La différence tient au comportement : le
   slider a des butées, la molette n'en a pas.
   ========================================================= */
.wheel-h {
  position: relative;
  width: 100%;
  height: 22px;
  border-radius: var(--radius-s);
  background: var(--bg-input);
  border: 1px solid var(--border);
  cursor: ew-resize;
  touch-action: none;
  overflow: hidden;
  transition: border-color 0.15s ease;
}
.wheel-h:hover, .wheel-h:focus-visible { border-color: var(--accent); outline: none; }
.wheel-h:active { cursor: grabbing; }

/* Crans verticaux : leur défilement confirme le geste, sans jamais
   suggérer un début ni une fin de course. */
.wheel-h-track {
  position: absolute; inset: 0;
  background-image: repeating-linear-gradient(
    to right,
    var(--border) 0px, var(--border) 1px,
    transparent 1px, transparent 9px
  );
  background-size: 18px 100%;
}
/* Estompage des bords : évoque un ruban qui continue au-delà du cadre. */
.wheel-h::before {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(to right,
    var(--bg-panel) 0%, transparent 18%, transparent 82%, var(--bg-panel) 100%);
  pointer-events: none;
  z-index: 1;
}
/* Repère central : la position de lecture. */
.wheel-h::after {
  content: '';
  position: absolute;
  top: 3px; bottom: 3px; left: 50%;
  width: 1px;
  margin-left: -0.5px;
  background: var(--accent);
  z-index: 2;
  pointer-events: none;
}

/* Sélecteur de police : chaque option est rendue avec sa propre police,
   pour choisir sur l'aspect plutôt que sur un nom. */
.font-grid {
  display: grid;
  /* S'adapte à la largeur de la colonne de réglages, qui est plus
     étroite que la fenêtre entière depuis la mise en deux colonnes. */
  grid-template-columns: repeat(auto-fill, minmax(74px, 1fr));
  gap: 5px;
}
.font-opt {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 7px 4px 5px;
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: var(--radius-s);
  color: var(--text-primary);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  transition: all 0.15s ease;
}
.font-opt:hover { border-color: var(--accent); }
.font-opt.active { border-color: var(--accent); background: var(--accent-dim); color: var(--accent); }
.font-name {
  font-family: var(--font-body);
  font-size: 9px;
  color: var(--text-faint);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  max-width: 100%;
}
.font-opt.active .font-name { color: var(--accent); }

/* Champ de valeur associé à une molette ou un curseur.
   Présenté comme du simple texte : la saisie doit rester possible sans
   alourdir l'interface d'un cadre par ligne. L'indication n'apparaît
   qu'au survol et au focus, là où elle est utile. */
.val-input {
  /* Largeur AJUSTÉE au contenu, et non fixée.
     Une largeur en dur oblige à choisir entre tronquer « 300000 » et
     réserver la place de six chiffres à « 5 ». Trop étroite, la valeur
     passait à la ligne alors que la place existait à côté du libellé —
     « Dimension réelle » se retrouvait sur deux lignes. `field-sizing`
     laisse le champ suivre son contenu là où il est reconnu ; ailleurs,
     la largeur reste bornée par min/max et le champ ne déborde jamais. */
  field-sizing: content;
  width: auto;
  min-width: 2ch;
  max-width: 9ch;
  padding: 3px 5px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 4px;
  color: var(--text-primary);
  font-family: var(--font-mono);
  font-size: 12px;
  text-align: right;
  outline: none;
  /* Curseur inchangé : une barre de saisie au survol trahirait la
     nature du champ autant qu'un cadre. */
  cursor: default;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.val-input.wide { max-width: 11ch; }
/* Seul le focus révèle le champ : c'est le moment où le repère sert. */
.val-input:focus {
  background: var(--bg-input);
  border-color: var(--accent);
  color: var(--accent);
}
.val-input.is-readonly { cursor: default; }

/* Les champs de COORDONNÉES suivaient encore le style habillé : fond
   plein et bordure permanente, alors qu'ils sont exactement du même
   ordre que les autres valeurs. Ils rejoignent le style commun. */
.mono-input {
  field-sizing: content;
  width: auto;
  min-width: 4ch;
  max-width: 12ch;
  padding: 3px 5px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 4px;
  color: var(--text-primary);
  text-align: right;
  outline: none;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.mono-input:focus { background: var(--bg-input); border-color: var(--accent); color: var(--accent); }

/* Le champ de recherche, lui, GARDE son cadre : c'est une invite à
   écrire, pas la valeur d'un réglage. Sans cadre, rien n'indiquerait où
   taper le nom d'un lieu. */

/* =========================================================
   VOILE PLEIN ÉCRAN (étapes longues : assemblage, compression…)
   ========================================================= */
.full-overlay {
  position: fixed; inset: 0;
  z-index: 200;
  background: rgba(10, 13, 18, 0.82);
  backdrop-filter: blur(6px);
  display: flex; align-items: center; justify-content: center;
  opacity: 1;
  transition: opacity 0.28s ease;
}
.full-overlay.hidden { opacity: 0; pointer-events: none; }
.fo-inner {
  display: flex; flex-direction: column; align-items: center; gap: 22px;
  transform: translateY(0);
  transition: transform 0.28s ease;
}
.full-overlay.hidden .fo-inner { transform: translateY(10px); }

/* Anneaux concentriques qui pulsent en décalé : évoque une progression
   continue sans promettre un pourcentage qu'on ne connaît pas toujours. */
.fo-rings { position: relative; width: 118px; height: 118px; }
.fo-ring {
  position: absolute; inset: 0;
  border: 1.5px solid var(--accent);
  border-radius: 50%;
  opacity: 0;
  animation: fo-pulse 2.4s cubic-bezier(0.22, 0.61, 0.36, 1) infinite;
}
.fo-ring:nth-child(2) { animation-delay: 0.8s; }
.fo-ring:nth-child(3) { animation-delay: 1.6s; }
@keyframes fo-pulse {
  0%   { transform: scale(0.42); opacity: 0; }
  22%  { opacity: 0.75; }
  100% { transform: scale(1); opacity: 0; }
}
.fo-icon {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 32px;
  color: var(--accent);
  animation: fo-breathe 2.2s ease-in-out infinite;
}
@keyframes fo-breathe {
  0%, 100% { transform: scale(1); opacity: 0.9; }
  50%      { transform: scale(1.09); opacity: 1; }
}
.fo-label {
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 500;
  letter-spacing: 0.03em;
  color: var(--text-primary);
  text-align: center;
  min-height: 20px;
}
.fo-track {
  width: 240px; height: 3px;
  background: var(--border);
  border-radius: 2px;
  overflow: hidden;
}
.fo-fill {
  height: 100%; width: 0%;
  background: linear-gradient(90deg, var(--accent), #8ef7e3);
  border-radius: 2px;
  transition: width 0.3s ease;
}
/* Sans progression connue, la barre balaie au lieu de rester figée. */
.fo-fill.indeterminate {
  width: 38% !important;
  animation: fo-sweep 1.4s ease-in-out infinite;
}
@keyframes fo-sweep {
  0%   { transform: translateX(-110%); }
  100% { transform: translateX(320%); }
}

/* =========================================================
   RENDU PHOTO
   ========================================================= */
.photo-preview {
  background: var(--bg-input);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-s);
  overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  min-height: 260px;
  margin-bottom: 14px;
}
.photo-preview img { display: block; max-width: 100%; height: auto; }
.photo-preview .fw-empty { padding: 40px 10px; }
.opt-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
  gap: 5px;
  margin-bottom: 14px;
}
.opt-chip {
  padding: 8px 6px;
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: var(--radius-s);
  color: var(--text-muted);
  font-family: var(--font-body);
  font-size: 11px;
  cursor: pointer;
  transition: all 0.15s ease;
  display: flex; align-items: center; gap: 6px;
}
.opt-chip:hover { border-color: var(--accent); color: var(--text-primary); }
.opt-chip.active { border-color: var(--accent); background: var(--accent-dim); color: var(--accent); }
.opt-swatch {
  width: 13px; height: 13px; border-radius: 3px; flex-shrink: 0;
  border: 1px solid rgba(255,255,255,0.18);
}

/* Fenêtre en plein écran : l'aperçu prend toute la place disponible. */
.float-win.maximized {
  left: 12px !important;
  top: 12px !important;
  width: calc(100vw - 24px) !important;
  max-width: none;
  height: calc(100vh - 24px);
  max-height: none;
}
.float-win.maximized .fw-body { height: calc(100% - 44px); }
.float-win.maximized .fw-col-view {
  flex: 1 1 auto;
  width: auto;
  display: flex; align-items: center; justify-content: center;
  height: 100%;
}
.float-win.maximized .fw-col-ctrl {
  flex: 0 0 320px;
  max-height: 100%;
}
.float-win.maximized .photo-preview {
  width: 100%; height: 100%;
  min-height: 0;
  margin-bottom: 0;
}
.float-win.maximized .photo-preview canvas { max-width: 100%; max-height: 100%; }
.photo-preview canvas { display: block; border-radius: 3px; }

/* Note remplaçant l'aperçu dans la fenêtre de rendu : celui-ci s'affiche
   désormais dans la vue principale. */
.photo-note {
  display: flex; flex-direction: column; align-items: center; gap: 12px;
  padding: 26px 18px;
  background: var(--bg-input);
  border: 1px dashed var(--border);
  border-radius: var(--radius-s);
  color: var(--text-muted);
  text-align: center;
}
.photo-note i { font-size: 30px; color: var(--accent); }
.photo-note p { margin: 0; font-size: 12px; line-height: 1.5; }
#btn-photo.active {
  border-color: var(--accent);
  background: var(--accent-dim);
  color: var(--accent);
}

/* Ligne d'option : libellé à gauche, interrupteur à droite. */
.opt-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px;
  margin-bottom: 4px;
}
.opt-label { font-family: var(--font-body); font-size: 12px; color: var(--text-primary); }

/* Sélecteur de source, ouvert au double-clic sur le HUD. */
.src-picker {
  position: absolute;
  top: 20px; left: 20px;
  z-index: 40;
  width: 300px;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-m);
  box-shadow: 0 18px 44px rgba(0,0,0,0.5);
  overflow: hidden;
}
.src-head {
  padding: 10px 12px;
  border-bottom: 1px solid var(--border-soft);
  font-family: var(--font-display);
  font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text-faint);
  display: flex; align-items: center; justify-content: space-between;
}
.src-head button {
  background: none; border: none; color: var(--text-faint);
  cursor: pointer; font-size: 12px; padding: 2px 4px;
}
.src-head button:hover { color: var(--text-primary); }
.src-item {
  display: block; width: 100%;
  padding: 10px 12px;
  background: none; border: none; border-bottom: 1px solid var(--border-soft);
  text-align: left; cursor: pointer;
  transition: background 0.15s ease;
}
.src-item:last-child { border-bottom: none; }
.src-item:hover:not(.disabled) { background: var(--bg-input); }
.src-item.active { background: var(--accent-dim); }
.src-item.disabled { opacity: 0.42; cursor: not-allowed; }
.src-name {
  display: flex; align-items: center; gap: 7px;
  font-family: var(--font-body); font-size: 12.5px; color: var(--text-primary);
  margin-bottom: 2px;
}
.src-item.active .src-name { color: var(--accent); }
.src-badge {
  margin-left: auto;
  font-family: var(--font-mono); font-size: 9.5px;
  padding: 1px 6px; border-radius: 999px;
  background: var(--bg-input); color: var(--text-faint);
}
.src-badge.ok { background: var(--accent-dim); color: var(--accent); }
.src-detail { font-family: var(--font-body); font-size: 10.5px; color: var(--text-faint); line-height: 1.35; }
#hud-source { cursor: pointer; }
#hud-source:hover { text-decoration: underline dotted; }


/* Ligne « Altitude » du bandeau : cliquable pour changer de source. */
.hud-line-action {
  cursor: pointer;
  border-radius: 4px;
  padding-right: 4px;
  transition: background 0.15s ease;
}
.hud-line-action:hover { background: rgba(255,255,255,0.06); }
.hud-caret {
  font-size: 9px;
  color: var(--text-faint);
  margin-left: 4px;
}
.hud-line-action:hover .hud-caret { color: var(--accent); }
.src-note {
  margin: 0;
  padding: 9px 12px;
  border-bottom: 1px solid var(--border-soft);
  font-family: var(--font-body);
  font-size: 10.5px;
  line-height: 1.4;
  color: var(--text-faint);
}
/* Source d'altitude choisie manuellement : le signaler, pour qu'on ne
   prenne pas un forçage oublié pour le comportement automatique. */
.hud-line-action.is-forced .hud-value { color: var(--accent); }

/* =========================================================
   FENÊTRE « QUALITÉ DES DONNÉES »
   Chaque tuile à sa place réelle dans la grille : la disposition
   des tuiles fautives en dit autant que leurs valeurs.
   ========================================================= */
.diag-loading {
  padding: 28px 16px;
  text-align: center;
  font-family: var(--font-body);
  font-size: 12px;
  color: var(--text-muted);
}
.diag-head {
  margin: 0 0 10px;
  font-family: var(--font-body);
  font-size: 11px;
  color: var(--text-faint);
  line-height: 1.6;
}
.diag-legend { display: inline-flex; align-items: center; gap: 6px; margin-top: 4px; }
.diag-legend i {
  display: inline-block; width: 11px; height: 11px;
  border-radius: 2px; margin-left: 8px;
}
.diag-grid {
  display: grid;
  gap: 2px;
  margin-bottom: 12px;
}
.diag-cell {
  aspect-ratio: 1;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: 1px;
  border-radius: 3px;
  font-family: var(--font-mono);
  color: rgba(255,255,255,0.9);
  cursor: help;
  transition: transform 0.12s ease;
}
/* Le numéro domine : c'est lui qui relie la case à l'étiquette posée
   sur le modèle 3D. */
.diag-cell b { font-size: 12px; font-weight: 700; line-height: 1; }
.diag-cell span { font-size: 8.5px; opacity: 0.75; line-height: 1; }
.diag-cell:hover { transform: scale(1.12); }
.diag-cell.err { background: var(--bg-input); color: var(--text-faint); }
.diag-summary {
  padding: 11px 13px;
  background: var(--bg-input);
  border-radius: var(--radius-s);
  font-family: var(--font-body);
  font-size: 11.5px;
  line-height: 1.6;
  color: var(--text-primary);
}
.diag-hint {
  display: block;
  margin-top: 7px;
  padding-top: 7px;
  border-top: 1px solid var(--border-soft);
  color: var(--text-muted);
  font-size: 10.5px;
}

/* Case de tuile cliquable : elle ouvre la comparaison des couches. */
.diag-cell.clickable { cursor: pointer; }
.diag-cell.clickable:hover { outline: 2px solid rgba(255,255,255,0.65); outline-offset: -2px; }

/* Comparaison des couches IGN sur une tuile. */
.diag-layers {
  margin-top: 12px;
  padding: 11px 13px;
  background: var(--bg-input);
  border-radius: var(--radius-s);
  font-family: var(--font-body);
  font-size: 11px;
}
.diag-layers-head {
  font-family: var(--font-display);
  font-size: 10.5px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: 8px;
}
.diag-layers table { width: 100%; border-collapse: collapse; }
.diag-layers td {
  padding: 3px 4px;
  border-bottom: 1px solid var(--border-soft);
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-primary);
}
.diag-layers td:first-child { font-family: var(--font-body); }
.diag-layers tr.off td { color: var(--text-faint); }
.diag-layers tr.best td { color: var(--accent); font-weight: 600; }
.diag-verdict {
  margin: 9px 0 0;
  padding-top: 8px;
  border-top: 1px solid var(--border-soft);
  font-size: 10.5px;
  line-height: 1.55;
  color: var(--text-muted);
}
.diag-verdict.good { color: var(--accent); }
.diag-zoom-wait {
  padding: 8px 0;
  font-family: var(--font-body);
  font-size: 10.5px;
  color: var(--text-faint);
}
.diag-compare-link {
  margin: 0 0 8px;
  font-family: var(--font-body);
  font-size: 10.5px;
}
.diag-compare-link a { color: var(--accent); text-decoration: none; }
.diag-compare-link a:hover { text-decoration: underline; }
/* Réessayer une source régionale restée sans réponse. */
.src-retry {
  display: block; width: 100%;
  padding: 9px 12px;
  background: var(--bg-input);
  border: none;
  border-top: 1px solid var(--border-soft);
  color: var(--accent);
  font-family: var(--font-body);
  font-size: 11px;
  text-align: center;
  cursor: pointer;
}
.src-retry:hover { background: var(--accent-dim); }

/* =========================================================
   BANDEAU — blocs de provenance et de trace
   ========================================================= */
.hud-panel {
  background: rgba(20, 23, 28, 0.6);
  backdrop-filter: blur(10px);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-m);
  padding: 10px 14px;
  pointer-events: none;
}
.hud-panel.hud-line-action { pointer-events: auto; }
.hud-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  font-family: var(--font-display);
  font-size: 9px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: 7px;
}

/* Provenance : une ligne par source, barre proportionnelle à sa part. */
.hud-source-list { list-style: none; margin: 0; padding: 0; }
.hud-source-item {
  position: relative;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 3px 0;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-primary);
}
/* La barre passe DERRIÈRE le texte : elle donne la proportion d'un coup
   d'œil sans occuper de place propre. */
.hud-source-item .src-dot {
  position: absolute;
  left: 0; top: 2px; bottom: 2px;
  background: var(--accent-dim);
  border-radius: 2px;
  z-index: 0;
}
.hud-source-item .src-label { position: relative; z-index: 1; padding-left: 2px; }
.hud-source-item .src-pct {
  position: relative; z-index: 1;
  margin-left: auto;
  color: var(--text-muted);
  font-size: 10px;
}
.hud-source-note {
  margin-top: 4px;
  font-family: var(--font-body);
  font-size: 10px;
  color: var(--accent);
}
.hud-panel.is-forced { border-color: var(--accent); }

/* Caractéristiques de la trace. */
.hud-stats { display: flex; flex-direction: column; gap: 3px; }
.hud-stat {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 14px;
}
.hud-stat .stat-key {
  font-family: var(--font-body);
  font-size: 10.5px;
  color: var(--text-faint);
}
.hud-stat .stat-val {
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--text-primary);
}

/* =========================================================
   OCCUPATION DU SOL
   ========================================================= */
.lc-row {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 9px 0;
}
.lc-row + .lc-row { border-top: 1px solid var(--border-soft); }
.lc-text { flex: 1; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.lc-name {
  font-family: var(--font-body);
  font-size: 12.5px;
  color: var(--text-primary);
  display: flex; align-items: center; gap: 7px;
}
.lc-icon { font-size: 13px; color: var(--text-muted); }
/* L'eau est la seule couche colorée : c'est elle qu'on doit repérer
   d'un coup d'œil, le reste partageant le matériau du relief. */
.lc-icon.lc-blue { color: #4a9fd8; }
.lc-detail {
  font-family: var(--font-body);
  font-size: 10.5px;
  color: var(--text-faint);
  line-height: 1.35;
}
.lc-state {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-faint);
  white-space: nowrap;
}


/* =============================================================
   ALLÈGEMENT DU PANNEAU
   ============================================================= */

/* Champs saisissables sans habillage : déjà assuré par .val-input, qui
   est le style commun du projet. Ne restait ici qu'à supprimer les
   flèches de pas des champs numériques et à resserrer les espacements.

   J'avais d'abord écrit un second jeu de règles visant `.mono-input` et
   `input[type="number"]` — c'est-à-dire un style parallèle pour le même
   besoin, et c'est ce qui donnait à la rotation une apparence différente
   des autres réglages. Les contrôles utilisent tous `.val-input`. */
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
input[type="number"] { -moz-appearance: textfield; }

.ctrl-head { margin-bottom: 5px; gap: 6px; }
.ctrl-value { gap: 5px; margin-left: auto; justify-content: flex-end; }
/* Le dernier élément de la ligne colle au bord, sans marge résiduelle. */
.ctrl-value > *:last-child { margin-right: 0; }
.reset-btn { margin-left: 0; }
.mono-readout { min-width: 0; }

/* Valeur COLLÉE À DROITE quand rien ne la suit.
   Sans bouton de réinitialisation, la valeur flottait au milieu ; elle
   s'aligne maintenant sur celles qui en ont un, ce qui donne une colonne
   de chiffres lisible d'un coup d'œil. */
.ctrl-head { justify-content: space-between; }
.ctrl-value { margin-left: auto; }

/* Explications au SURVOL plutôt qu'en permanence.
   Chaque phrase d'aide occupait deux à trois lignes sous son réglage.
   Utiles la première fois, elles allongeaient ensuite la colonne sans
   rien apprendre. */
.hint { display: none; }
/* Plus aucune exception : la source d'altitude a désormais sa propre
   ligne résumée (.src-line) et sa bulle. */
.info-dot {
  width: 14px; height: 14px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%;
  font-size: 9px;
  color: var(--text-muted);
  border: 1px solid var(--border-soft);
  cursor: help;
  flex-shrink: 0;
}
.info-dot:hover { color: var(--accent); border-color: var(--accent); }

/* Réglage VERROUILLÉ par une configuration importée. */
.ctrl.locked { opacity: 0.62; }
/* Blocage VISUEL de tout le bloc, molettes comprises — la liste
   précédente en oubliait, et une liste finit toujours par en oublier.
   Le refus réel, lui, est dans le code (voir verrouille()). */
.ctrl.locked > *:not(.ctrl-head),
.ctrl.locked .ctrl-value,
.ctrl.locked .wheel-h { pointer-events: none; }
.lock-badge { font-size: 10px; color: var(--accent); }

/* Fenêtre de reprise de configuration. */
/* Les fenêtres flottantes partagent la même mise en scène.
   Le banc d'essai n'était pas dans cette liste : sans position ni voile,
   son panneau retombait dans le flux du document, donc collé en haut à
   gauche. Les nommer ensemble évite que la prochaine soit oubliée. */
#config-modal {
  position: fixed; inset: 0; z-index: 40;
  display: flex; align-items: center; justify-content: center;
  background: rgba(0, 0, 0, 0.55);
}
#config-modal.hidden { display: none; }
.config-panel {
  width: 420px; max-width: 92vw;
  padding: 22px 24px;
  background: rgba(16, 19, 24, 0.98);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-m);
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.55);
}
.config-panel h3 { margin: 0 0 6px; font-size: 15px; }
.config-sub { margin: 0 0 14px; font-size: 11.5px; color: var(--text-muted); line-height: 1.5; }
.config-group {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 9px 0;
  border-top: 1px solid var(--border-soft);
}
.config-group label { font-size: 12.5px; cursor: pointer; }
.config-group .cg-detail { display: block; font-size: 10.5px; color: var(--text-muted); margin-top: 2px; }
.config-actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 16px; }

/* Verrou taille réelle / échelle. Discret tant qu'il n'est pas posé. */
.lock-btn {
  width: 20px; height: 20px;
  display: inline-flex; align-items: center; justify-content: center;
  background: none; border: none; padding: 0;
  color: var(--text-muted); opacity: 0.35;
  font-size: 11px; cursor: pointer;
  transition: opacity 0.12s ease, color 0.12s ease;
}
.lock-btn:hover { opacity: 0.9; }
.lock-btn.on { opacity: 1; color: var(--accent); }

/* =============================================================
   INFOBULLE MAISON
   =============================================================
   L'attribut `title` du navigateur ne se contrôle pas : apparence
   imposée par le système, délai d'environ une seconde avant affichage,
   largeur non maîtrisée, et disparition au bout de quelques secondes.
   Sur un panneau sombre, ces petites boîtes claires jurent, et le délai
   les rend inutilisables pour survoler plusieurs réglages de suite.

   Celle-ci apparaît immédiatement, suit le thème et se place elle-même
   du côté où il reste de la place. */
#tip {
  position: fixed;
  z-index: 300;
  max-width: 260px;
  padding: 9px 11px;
  background: rgba(18, 22, 28, 0.98);
  border: 1px solid var(--border-soft);
  border-left: 2px solid var(--accent);
  border-radius: var(--radius-s);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
  color: var(--text-secondary);
  font-size: 11.5px;
  line-height: 1.5;
  pointer-events: none;
  opacity: 1;
  transition: opacity 0.12s ease;
}
#tip.hidden { opacity: 0; pointer-events: none; }

/* Ligne de source d'altitude : un résumé, pas un paragraphe. */
.src-line {
  display: flex; align-items: center; gap: 6px;
  margin-top: 8px;
  font-size: 11px;
}
.src-line-label { color: var(--text-muted); }
.src-line-value {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-secondary);
  text-align: right;
}
/* Couverture incomplète : visible sans avoir à survoler. */
.src-line-value.is-partial { color: var(--warn); }

/* =============================================================
   ONGLET DÉVELOPPEUR
   =============================================================
   Signalé sans être caché : ce qu'il contient fonctionne, mais n'est pas
   arrêté. Le distinguer visuellement évite qu'un réglage d'essai soit
   pris pour un réglage de production — et évite surtout d'avoir à
   l'expliquer. */
.acc.is-dev .acc-title { color: var(--text-secondary); }
.dev-tag {
  margin-left: auto;
  padding: 1px 6px;
  border: 1px solid var(--border-soft);
  border-radius: 999px;
  font-size: 9px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.dev-note {
  margin-bottom: 12px;
  padding: 7px 9px;
  border-left: 2px solid var(--warn);
  background: rgba(255, 255, 255, 0.02);
  font-size: 10.5px;
  line-height: 1.5;
  color: var(--text-muted);
}
.dev-sub {
  margin: 4px 0 10px;
  font-size: 11px;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* =============================================================
   SÉLECTEUR DE PRODUIT
   =============================================================
   Deux boutons pleine largeur en tête de barre latérale. Il ne règle
   pas un paramètre : il change ce qu'on fabrique, donc la nature du
   reste du panneau. */
.product-switch {
  display: flex;
  gap: 6px;
  padding: 12px 14px 10px;
  border-bottom: 1px solid var(--border-soft);
}
.product-btn {
  flex: 1;
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 10px 6px;
  background: transparent;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-s);
  color: var(--text-muted);
  font-size: 11px;
  cursor: pointer;
  transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}
.product-btn i { font-size: 16px; }
.product-btn:hover { color: var(--text-secondary); border-color: var(--border); }
.product-btn.active {
  color: var(--accent);
  border-color: var(--accent);
  background: rgba(94, 234, 212, 0.06);
}
/* Sections sans objet pour le produit courant. */
.acc.off-product { display: none; }

/* Téléchargement d'une pièce seule, depuis le panneau. Discret comme
   l'œil qui le jouxte : ce sont deux actions de même rang. */
.piece-dl {
  width: 22px; height: 22px;
  display: flex; align-items: center; justify-content: center;
  background: none; border: none; padding: 0;
  color: var(--text-faint);
  font-size: 11px; cursor: pointer;
  transition: color 0.15s ease;
}
.piece-dl:hover { color: var(--accent); }

/* Note d'introduction dans une fenêtre flottante. */
.fw-note {
  margin: 0 0 14px;
  font-size: 11px;
  line-height: 1.55;
  color: var(--text-muted);
}
/* Les fenêtres sans aperçu n'ont pas besoin de la colonne de gauche. */
.float-win .fw-col-view:empty { display: none; }
