/* ============================================================================
   cockpit — dialogues et contrôles de formulaire
   Tout ce que produit `site/dialog.js` : la sheet qui monte du bas, la
   confirmation centrée, les choix enrichis, l'interrupteur, le pavé de code,
   la table clé/valeur.

   Ces styles vivent à part parce qu'ils servent DANS DEUX MONDES : les écrans
   de gestion, qui chargent la feuille du site, et l'éditeur de cockpit, qui
   n'en charge rien — il est plein écran et n'a ni chrome ni mise en page
   commune. Les laisser dans la feuille du site donnait, dans l'éditeur, des
   dialogues sans aucun style : un rectangle blanc sur le panneau.
   ========================================================================= */

/* ── L'interrupteur ────────────────────────────────────────────────────────
   Un vrai interrupteur, et non une case à cocher recolorée.

   La distinction n'est pas cosmétique : une case dit « je choisis, je
   validerai plus tard », un interrupteur dit « c'est l'état en ce moment ».
   Dans une application de supervision, presque tout est un état — et la case
   native, en plus, se dessine différemment sur chaque système.

   La piste EST l'input : styler l'élément lui-même plutôt qu'un faux élément
   posé à côté conserve gratuitement le clavier, le focus et le clic sur le
   libellé, qu'un `<span>` décoratif obligerait à réinventer. */
/* ── Interrupteurs ────────────────────────────────────────────────────────────
   Jamais de case à cocher. L'interrupteur dit un ÉTAT EN COURS — activé,
   désactivé — là où la case dit un choix qu'on validera plus tard. Dans une
   application de supervision, presque tout est un état.

   La case reste en dessous, cachée : c'est elle qui porte la sémantique, le
   clavier et les technologies d'assistance. On n'en change que l'apparence. */
.switch, .toggle-label {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 8px 0 0;
  font-size: 14px;
  color: var(--texte-fort);
  cursor: pointer;
}
.switch input[type="checkbox"],
.toggle-label input[type="checkbox"] {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
.switch input[type="checkbox"] + span::before,
.toggle {
  content: "";
  flex: 0 0 auto;
  display: inline-block;
  width: 32px;
  height: 18px;
  border: 1px solid var(--bord-fort);
  border-radius: 999px;
  background: var(--fond);
  transition: background .14s ease, border-color .14s ease;
}
/* Le curseur du toggle : un rond qui glisse. */
.switch input[type="checkbox"] + span,
.toggle-label { position: relative; }
.switch input[type="checkbox"] + span {
  display: flex;
  align-items: center;
  gap: 10px;
}
.switch input[type="checkbox"] + span::after,
.toggle::after {
  content: "";
  position: absolute;
  left: 3px;
  top: 50%;
  width: 12px;
  height: 12px;
  margin-top: -6px;
  border-radius: 50%;
  background: var(--texte-faible);
  transition: transform .14s ease, background .14s ease;
}
.toggle { position: relative; }

/* ── UNE PISTE NUE, SANS LIBELLÉ À CÔTÉ ───────────────────────────────────
   Deux écritures cohabitent, et il faut que les deux marchent :

     <label class="switch"><input><span>En service</span></label>
        les formulaires de réglages — le `<span>` porte le texte, et la piste
        se dessine dans son `::before`.

     <label class="switch"><input><span class="toggle"></span></label>
        l'INSPECTEUR — le libellé est déjà dans la colonne de gauche de la
        rangée, donc le `<span>` n'est plus qu'une piste.

   Sans les lignes ci-dessous, la seconde écriture ne dessinait RIEN : une
   doctrine antérieure, qui stylait l'input lui-même comme piste, posait un
   `.switch .toggle { display: none }` — plus spécifique, donc gagnant — pendant
   que celle-ci cachait l'input. Les deux se neutralisaient, et TOUS les
   interrupteurs de l'inspecteur étaient invisibles : « Cadre », « Vis
   apparentes », « Micro-trace » n'avaient plus que leur étiquette. */
.switch input[type="checkbox"] + .toggle::before { content: none; }
.switch input:checked + .toggle {
  border-color: var(--info);
  background: rgba(63, 200, 240, .22);
}
.switch input:checked + .toggle::after {
  transform: translateX(14px);
  background: var(--info);
}
.switch input:focus-visible + .toggle {
  outline: 2px solid var(--info);
  outline-offset: 2px;
}

.switch input:checked + span::before,
.toggle-label input:checked + .toggle {
  border-color: var(--info);
  background: rgba(63, 200, 240, .22);
}
.switch input:checked + span::after,
.toggle-label input:checked + .toggle::after {
  transform: translateX(14px);
  background: var(--info);
}
.switch input:focus-visible + span::before,
.toggle-label input:focus-visible + .toggle {
  outline: 2px solid var(--info);
  outline-offset: 2px;
}
/* ── Dialogues ────────────────────────────────────────────────────────────────
   Deux formes, deux intentions. La SHEET monte du bas et occupe la largeur :
   on y crée et l'on y modifie, en gardant sous les yeux la liste d'où l'on
   vient. La boîte CENTRÉE arrête : elle sert aux suppressions, et son propos
   est qu'on s'arrête pour lire. */
.dlg {
  padding: 0;
  border: 0;
  background: none;
  color: var(--texte-fort);
  font: inherit;
}
.dlg::backdrop { background: rgba(4, 6, 9, .72); }
.dlg__form {
  border: 1px solid var(--bord);
  background: var(--surface);
}
/* Boîte centrée */
.dlg:not(.dlg--sheet) {
  width: min(460px, calc(100vw - 32px));
  margin: auto;
}
.dlg:not(.dlg--sheet) .dlg__form {
  padding: 22px 24px 18px;
  border-radius: var(--radius);
}
/* Sheet : pleine largeur, ancrée en bas */
.dlg--sheet {
  width: 100%;
  max-width: 100%;
  max-height: 92dvh;
  margin: auto auto 0;
}
.dlg--sheet .dlg__form {
  max-height: 92dvh;
  overflow-y: auto;
  padding: 24px max(24px, calc((100vw - 720px) / 2)) 26px;
  border-width: 1px 0 0;
  border-radius: 0;
}
.dlg--sheet[open] { animation: dlg-rise .2s cubic-bezier(.2, .8, .3, 1); }
@keyframes dlg-rise {
  from { transform: translateY(28px); opacity: 0; }
  to   { transform: none; opacity: 1; }
}
.dlg__title {
  margin: 0 0 10px;
  font-family: var(--font-ui);
  font-size: 14px;
  font-weight: 700;
  color: var(--texte-fort);
}
.dlg--danger .dlg__title { color: var(--texte-alerte); }
.dlg__intro { margin: 0 0 16px; font-size: 13px; line-height: 1.55; color: var(--texte-faible); }
.dlg__what { margin: 0 0 10px; font-size: 14px; color: var(--texte-fort); }
/* La liste des conséquences : c'est elle qui fait la différence avec un
   « êtes-vous sûr ? ». On y cherche celle qu'on n'avait pas prévue. */
.dlg__lines {
  margin: 0 0 16px;
  padding: 10px 14px 10px 30px;
  border-left: 2px solid var(--caution);
  background: rgba(255, 176, 32, .06);
  font-size: 13px;
  line-height: 1.6;
  color: var(--texte-faible);
}
.dlg__lines li { margin: 2px 0; }
.dlg__row { margin-bottom: 14px; }

/* ── UN RÉGLAGE QUI NE S'APPLIQUE PAS RESTE LISIBLE ──────────────────────────
   Il s'éteint, il ne disparaît pas. Un formulaire dont les rangées vont et
   viennent à chaque clic saute sous les yeux, et l'on finit par essayer les
   deux partis pour voir ce que chacun cache. Gris, le réglage dit ce que
   l'autre mode demanderait — et l'on choisit en sachant.

   Le libellé pâlit avec le reste : un intitulé resté net au-dessus d'un champ
   éteint se lit comme un champ qu'on a le droit de remplir. */
.dlg__row.is-muet { opacity: .45; }
.dlg__row.is-muet > label,
.dlg__row.is-muet .dlg__hint { color: var(--texte-tenu); }
.dlg__row.is-muet input,
.dlg__row.is-muet select,
.dlg__row.is-muet textarea { cursor: not-allowed; }
.dlg__row > label {
  display: block;
  margin-bottom: 6px;
  font-size: 12px;
  font-weight: 600;
  color: var(--texte-fort);
}
.dlg__row textarea { resize: vertical; min-height: 64px; font: inherit; }
.dlg__row input:not([type="checkbox"]), .dlg__row select, .dlg__row textarea {
  width: 100%;
  padding: 9px 12px;
  border: 1px solid var(--bord);
  border-radius: var(--radius);
  background: var(--creux);
  color: var(--texte-fort);
  font: inherit;
  font-size: 14px;
}
.dlg__row input:focus, .dlg__row select:focus, .dlg__row textarea:focus {
  outline: none;
  border-color: var(--info);
  box-shadow: 0 0 0 3px rgba(63, 200, 240, .12);
}
/* ── LA RANGÉE D'UN INTERRUPTEUR ────────────────────────────────────────────
   `.toggle-label` déclarait `display: flex` et `gap: 10px`, et les deux étaient
   PERDUS : `.dlg__row > label` est plus spécifique (une classe et un type
   contre une classe) et imposait `display: block`. Le texte se collait donc à
   la pilule, sans un pixel d'écart.

   Le défaut se voyait mal parce qu'il se déguisait : interrupteur ÉTEINT, le
   curseur est à gauche et les quinze pixels vides de la piste passent pour une
   marge ; ALLUMÉ, il glisse à droite et le texte semble soudain collé. Trois
   rangées côte à côte paraissaient alors mal alignées entre elles, alors
   qu'elles l'étaient toutes de la même façon — mal.

   On reprend donc la main avec la spécificité qu'il faut, ici et une seule
   fois. */
.dlg__row--toggle > label {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 0;
}

.dlg__hint { margin: 6px 0 0; font-size: 12px; line-height: 1.5; color: var(--texte-tenu); }

/* L'EXPLICATION SE RANGE SOUS CE QU'ELLE EXPLIQUE. Ailleurs, l'indice et le
   libellé partagent le bord gauche de la rangée ; sous un interrupteur, le
   libellé est décalé de la piste et de son écart — l'indice doit l'être aussi,
   sans quoi il a l'air d'expliquer la rangée précédente. */
.dlg__row--toggle > .dlg__hint { padding-left: calc(32px + 10px); }

/* ── UN INTERRUPTEUR QUI COMPLÈTE UNE PAIRE ──────────────────────────────────
   Il n'a pas de ligne de libellé : son libellé est À CÔTÉ de la piste. Seul sur
   sa ligne, c'est très bien. Dans une paire, en face d'un champ qui, lui, porte
   son libellé au-dessus, il flottait une ligne plus haut — les deux commandes
   ne tombaient pas sur le même fil, et la paire se lisait comme deux réglages
   sans rapport.

   On lui rend donc la hauteur d'une ligne de libellé, vide : `12px` de corps
   pour un interligne normal, plus les `6px` d'écart de `.dlg__row > label`. */
.dlg__row--toggle.dlg__row--half::before {
  content: "";
  display: block;
  height: calc(12px * 1.5);
  margin-bottom: 6px;
}
.dlg__error {
  margin: 0 0 14px;
  padding: 8px 12px;
  border-left: 2px solid var(--alerte);
  background: rgba(255, 59, 48, .08);
  font-size: 13px;
  color: var(--texte-alerte);
}
.dlg__actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 18px; }
/* Un peu plus large dans un dialogue : c'est la seule chose qu'il reste à y
   faire, et le bouton porte la décision de toute la fenêtre. */
.dlg__actions .btn { padding: 9px 18px; }
.dlg__cancel { border-color: var(--bord-fort); color: var(--texte-faible); }
.dlg__ok { border-color: var(--info-bord); color: var(--info); }
.dlg--danger .dlg__ok { border-color: var(--alerte-bord); color: var(--texte-alerte); }
.dlg--danger .dlg__ok:hover { border-color: var(--alerte); }
/* Alignées à GAUCHE par défaut : c'est le cas du dialogue de code et de la page
   du compte, où les cases côtoient d'autres champs et doivent partager leur
   marge. L'écran de connexion, lui, les recentre — sa composition entière est
   centrée (voir `.gate__box` dans `shell.css`). */
.pincells {
  display: flex;
  gap: 10px;
  margin: 0 0 20px;
}
/* La case est une BOÎTE qui contient le champ. Un `<input>` est un élément
   remplacé : il ne peut pas porter de pseudo-élément, donc pas de curseur
   dessiné. C'est la boîte qui le porte. */
.pincell {
  position: relative;
  display: block;
  width: 54px;
  height: 62px;
  border: 1px solid var(--bord-fort);
  border-radius: var(--radius);
  background: var(--creux);
  transition: border-color .12s ease, background .12s ease;
}
.pincell input {
  width: 100%;
  height: 100%;
  padding: 0;
  border: 0;
  border-radius: inherit;
  background: none;
  color: var(--texte-fort);
  font-family: var(--font-mono);
  font-size: 30px;
  text-align: center;
  /* Le curseur natif est masqué : on en dessine un, qui clignote franchement et
     ne dépend pas du réglage du système. */
  caret-color: transparent;
}
.pincell input:focus { outline: none; }
.pincell:has(input:focus) {
  border-color: var(--info);
  background: var(--fond);
  box-shadow: 0 0 0 3px rgba(63, 200, 240, .14);
}
/* LE CURSEUR. Une barre qui clignote dans la case active, pour dire qu'on peut
   taper tout de suite — sans elle, quatre cases vides ressemblent à un dessin
   et l'on cherche où cliquer. `steps(1)` donne le battement net d'un curseur de
   terminal ; une transition douce ferait luire, ce qui ne dit pas la même
   chose. Il disparaît dès que la case porte un chiffre : elle n'attend plus. */
.pincell::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 2px;
  height: 26px;
  margin: -13px 0 0 -1px;
  background: var(--info);
  opacity: 0;
  pointer-events: none;
}
.pincell:has(input:focus):not(.is-set)::after {
  animation: pin-caret 1.06s steps(1) infinite;
}
@keyframes pin-caret {
  0%, 55%   { opacity: 1; }
  56%, 100% { opacity: 0; }
}
.pincell.is-set { border-color: var(--bord-fort); }
.pincell:has(input:disabled) { opacity: .55; }
/* Un repère supplémentaire : au repos, la PREMIÈRE case est marquée, de sorte
   qu'on voie où commencer avant même d'avoir cliqué. */
.pincells:not(:focus-within) .pincell:first-child { border-color: var(--bord-vif); }
/* ── Choix restreint ──────────────────────────────────────────────────────────
   Des radios en cartes, jamais une liste déroulante. Le `<select>` cache ses
   options jusqu'au clic : on ne peut ni les comparer, ni dire sous chacune ce
   qu'elle entraîne. Réservé aux listes COURTES et fermées — une liste ouverte
   ou longue garde une déroulante. */
/* ── LES PARTIS SE RANGENT EN COLONNES QUAND ILS SONT NOMBREUX ───────────────
   Une carte par ligne se lit très bien à trois ou quatre choix. À sept — les
   périodes d'un rapport — la liste traverse l'écran de haut en bas : on ne voit
   plus les partis ENSEMBLE, et c'est précisément pour les comparer qu'on les
   montre en entier plutôt que dans un menu déroulant.

   La grille se remplit d'elle-même : deux colonnes quand la place le permet,
   une seule sinon. Le minimum de 260 pixels est la largeur en dessous de
   laquelle la phrase d'explication passe à trois lignes — c'est elle qui décide,
   pas un nombre de colonnes choisi d'avance. */
.choices {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 6px;
}
.choice {
  display: flex;
  align-items: flex-start;
  gap: 11px;
  padding: 11px 13px;
  border: 1px solid var(--bord);
  border-radius: var(--radius);
  background: var(--creux);
  cursor: pointer;
  transition: border-color .12s ease, background .12s ease;
}
.choice:hover { border-color: var(--bord-vif); }
/* ── LE BOUTON RADIO EST DESSINÉ ICI, ET NON PAR LE NAVIGATEUR ───────────────
   `accent-color` ne colore que l'état COCHÉ : le reste — le disque, sa
   bordure, son fond — reste au moteur, qui le dessine d'après son idée du
   thème. Sur macOS, cette idée est un disque BLANC PLEIN, et l'on se
   retrouvait avec huit pastilles blanches éclatantes sur un fond presque noir :
   les choix non retenus criaient plus fort que celui qu'on avait fait.

   On le dessine donc : un anneau discret au repos, l'encre vive et son point
   au centre quand il est choisi. Deux règles, et le contrôle se comporte
   partout pareil — ce qu'aucun réglage de `color-scheme` ne garantit. */
.choice input[type="radio"] {
  flex: 0 0 auto;
  appearance: none;
  -webkit-appearance: none;
  width: 15px;
  height: 15px;
  /* ── LE REMBOURRAGE DE LA MAISON NE S'APPLIQUE PAS ICI ─────────────────
     `.dlg__row input:not([type="checkbox"])` pose neuf pixels de haut et douze
     de côté : c'est ce qu'il faut à un champ de texte, et c'est ce qui a
     transformé le disque en OVALE dès qu'on lui a retiré son apparence native.
     Un contrôle qu'on dessine doit reprendre TOUTES ses mesures, y compris
     celles qu'il n'avait pas demandées. */
  padding: 0;
  margin: 3px 0 0;
  border: 1.5px solid var(--bord-vif);
  border-radius: 50%;
  background: none;
  cursor: pointer;
  transition: border-color .12s ease;
}
.choice input[type="radio"]:hover { border-color: var(--texte-faible); }
.choice input[type="radio"]:checked {
  border-color: var(--info);
  /* Le point central est peint par le fond lui-même : un pseudo-élément ne
     s'attache pas à un `input`, qui n'a pas d'enfants. */
  background: radial-gradient(circle at center,
              var(--info) 0 4px, transparent 4.5px);
}
.choice b {
  display: block;
  font-size: 14px;
  font-weight: 600;
  color: var(--texte-fort);
}
.choice k {
  display: block;
  margin-top: 3px;
  font-size: 12px;
  line-height: 1.45;
  color: var(--texte-tenu);
}
.choice:has(input:checked) {
  border-color: var(--info);
  background: rgba(63, 200, 240, .07);
}
.choice:has(input:focus-visible) { outline: 2px solid var(--info); outline-offset: 2px; }
/* Petits boutons de texte, dans un dialogue : ils proposent, ils ne commandent
   pas — d'où l'apparence d'un lien plutôt que d'un bouton. */
.dlg__tools { display: flex; gap: 14px; margin-top: 8px; }
.linkbtn {
  padding: 0;
  border: 0;
  background: none;
  color: var(--info);
  font: inherit;
  font-size: 12px;
  cursor: pointer;
}
.linkbtn:hover { text-decoration: underline; }
/* Dans un dialogue, les cases sont plus petites et alignées à gauche : elles y
   côtoient d'autres champs, et les garder à la taille de la page de connexion
   les ferait passer pour l'essentiel du formulaire. */
.pincells--sm { justify-content: flex-start; gap: 8px; margin: 0; }
.pincells--sm .pincell { width: 46px; height: 52px; }
.pincells--sm .pincell input { font-size: 24px; }
.pincells--sm .pincell::after { height: 22px; margin-top: -11px; }
/* ── Liste déroulante ─────────────────────────────────────────────────────────
   Le `<select>` reste là, masqué : il porte la valeur, il part avec le
   formulaire, et une page dont le script n'aurait pas tourné resterait
   utilisable. Ce qu'on voit est dessiné par-dessus.

   ── ELLE S'APPELAIT `.pick`, ET C'ÉTAIT LA CAUSE N°1 ───────────────────────

   `shell.css` déclare AUSSI `.pick` et `.pick__list` — pour un tout autre
   composant : le champ « chercher pour ajouter » des groupes. Deux composants,
   un seul nom ; la cascade donne raison au dernier chargé, et `shell.css`
   passant avant, sa règle `display: inline-block` gagnait ici. Une liste
   déroulante dans une rangée de dialogue se réduisait donc à la largeur de son
   libellé — « Semaine » tenait en cent pixels dans une colonne de trois cent
   cinquante, à côté d'un champ texte qui, lui, l'occupait tout entière.

   Le nom est donc à elle seule, et le `display` est écrit : une liste occupe la
   largeur de sa colonne, comme un champ. Le plafond reste, parce qu'un bouton
   de sept cents pixels pour choisir entre cinq mots n'est pas une liste, c'est
   une bannière. */
.deroul { position: relative; display: block; max-width: 360px; }
.deroul > select {
  /* Masqué SANS `display:none` : un champ retiré du rendu ne peut plus recevoir
     le focus ni être signalé par la validation du navigateur. */
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
.deroul__button {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 8px 11px;
  border: 1px solid var(--bord);
  border-radius: var(--radius);
  background: var(--creux);
  color: var(--texte-fort);
  font: inherit;
  font-size: 14px;
  text-align: left;
  cursor: pointer;
}
.deroul__button span { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.deroul__button i { font-size: 11px; color: var(--texte-tenu); transition: transform .14s ease; }
.deroul__button:hover { border-color: var(--bord-vif); }
.deroul__button:focus-visible,
.deroul.is-open .deroul__button {
  outline: none;
  border-color: var(--info);
  box-shadow: 0 0 0 3px rgba(63, 200, 240, .12);
}
.deroul.is-open .deroul__button i { transform: rotate(180deg); }
.deroul__list {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(100% + 4px);
  z-index: 80;
  max-height: 280px;
  overflow-y: auto;
  padding: 4px;
  border: 1px solid var(--bord-fort);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: 0 12px 30px rgba(0, 0, 0, .7);
}
.deroul.is-up .deroul__list { top: auto; bottom: calc(100% + 4px); }
.deroul__item {
  padding: 8px 10px;
  border-radius: 3px;
  font-size: 14px;
  color: var(--texte-faible);
  cursor: pointer;
}
.deroul__item:hover { background: rgba(255, 255, 255, .05); color: var(--texte-fort); }
.deroul__item.is-on {
  background: rgba(63, 200, 240, .1);
  color: var(--info);
}
/* L'entrée courante porte une coche : la couleur seule ne suffit pas à
   distinguer « survolé » de « choisi » quand le pointeur passe dessus. */
.deroul__item.is-on::after {
  content: "\f00c";
  float: right;
  font-family: "Font Awesome 7 Free", "Font Awesome 6 Free";
  font-weight: 900;
  font-size: 11px;
}
.kv { display: block; }
.kv__head, .kv__line {
  display: grid;
  grid-template-columns: minmax(120px, 1fr) minmax(160px, 2fr) 28px;
  gap: 6px;
  align-items: center;
}
.kv__head {
  margin-bottom: 5px;
  font: 700 11px/1 var(--font-ui);
  letter-spacing: .08em; text-transform: uppercase; color: var(--texte-faible);
}
.kv__line + .kv__line { margin-top: 5px; }
.kv__key, .kv__val {
  min-width: 0;
  padding: 6px 8px;
  border: 1px solid var(--bord);
  border-radius: var(--radius);
  background: var(--fond);
  color: var(--texte-fort);
  font: 400 14px/1.2 var(--font-ui);
}
/* La CLÉ est un identifiant, pas une phrase : la police à chasse fixe le dit
   sans avoir à l'expliquer, et rend visible l'espace en trop. */
.kv__key { font-family: var(--font-mono); font-size: 13px; }
.kv__key:focus, .kv__val:focus { outline: none; border-color: var(--info-bord); }
.kv + .linkbtn, .kv ~ .linkbtn { margin-top: 8px; }
.kv__line--read { grid-template-columns: minmax(120px, 1fr) minmax(140px, 1.4fr) 70px; }
.kv__line--read code {
  font: 500 13px/1.6 var(--font-mono);
  color: var(--info);
}
.kv__line--read span { font-size: 13px; color: var(--texte); }
@media (prefers-reduced-motion: reduce) {
  .switch input[type="checkbox"],
  .switch input[type="checkbox"]::before { transition: none; }
}
@media (prefers-reduced-motion: reduce) {
  .switch span::before, .switch span::after, .toggle, .toggle::after { transition: none; }
}
@media (max-width: 380px) {
  .pincell { width: 46px; height: 54px; }
  .pincell input { font-size: 24px; }
}
@media (prefers-reduced-motion: reduce) { .pincell { transition: none; } }
@media (prefers-reduced-motion: reduce) { .choice { transition: none; } }
@media (prefers-reduced-motion: reduce) { .deroul__button i { transition: none; } }


/* ── Le code QR d'un cockpit ────────────────────────────────────────────────
   Fond BLANC et modules noirs, sans négociation : un lecteur cherche un motif
   sombre sur clair, et un code inversé pour s'accorder au panneau ne se lit
   pas. C'est la seule surface blanche de toute l'application, et elle est
   assumée — c'est une étiquette, pas un écran.

   Une taille généreuse : on le lit à cinquante centimètres, appareil en main,
   parfois dans un local mal éclairé. */
.qrbox { display: flex; flex-direction: column; align-items: center; gap: 10px; }
.qrbox__code {
  width: 232px;
  padding: 10px;
  border-radius: var(--radius, 4px);
  background: #fff;
  line-height: 0;
}
.qrbox__code svg { width: 100%; height: auto; display: block; }
.qrbox__url {
  margin: 0;
  max-width: 100%;
  overflow-wrap: anywhere;
  text-align: center;
  font-family: var(--font-ui);
  font-size: 12px;
  letter-spacing: .04em;
  color: var(--texte-faible);
  user-select: all;
}

/* ── Le champ « où se trouve ce site » ────────────────────────────────────────
   Une adresse qu'on cherche, des résultats qu'on désigne, une carte qui
   confirme. La carte vient en DERNIER et n'apparaît qu'une fois le lieu
   choisi : montrer un cadre vide au-dessus d'un champ qu'on n'a pas encore
   rempli occupe la moitié du dialogue pour ne rien dire. */
.dlg__row--geo { grid-template-columns: 1fr; }
.geo { display: grid; gap: 8px; }

.geo__search { display: flex; gap: 8px; }
.geo__q { flex: 1 1 auto; min-width: 0; }

.geo__hits {
  display: grid;
  gap: 2px;
  max-height: 168px;
  margin: 0;
  padding: 4px;
  overflow-y: auto;
  border: 1px solid var(--bord);
  border-radius: var(--radius);
  background: var(--fond);
  list-style: none;
}
.geo__hit {
  display: block;
  width: 100%;
  padding: 7px 9px;
  border: 0;
  border-radius: 4px;
  background: none;
  color: var(--texte-fort);
  font: inherit;
  font-size: 13px;
  text-align: left;
  /* L'ADRESSE COMPLÈTE, SUR PLUSIEURS LIGNES. Tronquée, deux résultats de la
     même rue deviennent indiscernables — et c'est précisément entre ceux-là
     qu'on hésite. */
  line-height: 1.35;
  cursor: pointer;
}
.geo__hit:hover { background: var(--info-creux); color: var(--info); }
.geo__hit:focus-visible { outline: 1px solid var(--info); outline-offset: -1px; }

.geo__state { min-height: 15px; font-size: 13px; color: var(--inactif); }
.geo__state.is-bad { color: var(--texte-alerte); }

.geo__map { display: grid; gap: 6px; }
.geo__map iframe {
  width: 100%;
  height: 190px;
  border: 1px solid var(--bord);
  border-radius: var(--radius);
  /* Le fond sombre du dialogue derrière une carte claire ferait un rectangle
     blanc éblouissant le temps du chargement. */
  background: var(--fond);
}
.geo__coords {
  margin: 0;
  font-size: 13px;
  color: var(--inactif);
}
.geo__coords b { color: var(--texte-fort); font-weight: 500; }
.geo__clear {
  margin-left: 8px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--info);
  font: inherit;
  font-size: 13px;
  text-decoration: underline;
  cursor: pointer;
}

/* ── L'assistant de branchement ───────────────────────────────────────────────
   Une sheet plus large que les autres : elle porte une table d'aperçu, et une
   table serrée dans 460 pixels ne se lit pas — or c'est précisément ce qu'on
   est venu regarder avant d'enregistrer. */
/* ── UNE SHEET LARGE ÉLARGIT SA COLONNE ───────────────────────────────────
   La sheet ordinaire centre une colonne de 720 pixels en POUSSANT le contenu
   avec une marge intérieure — `padding: … max(24px, (100vw - 720px) / 2) …`.
   Poser un `max-width` par-dessus ne l'élargit donc pas : cela rétrécit la
   boîte pendant que la marge, elle, continue de mordre des deux côtés. Il
   restait une colonne d'une centaine de pixels, où chaque mot tenait une
   ligne et où le champ d'adresse tombait à zéro.

   On reprend la même formule avec l'autre nombre. Une seule ligne, et la
   règle reste celle de la sheet. */
.dlg--wide.dlg--sheet .dlg__form {
  padding-left: max(24px, calc((100vw - 980px) / 2));
  padding-right: max(24px, calc((100vw - 980px) / 2));
}

/* ── UN DIALOGUE À ONGLETS GARDE LA COLONNE DE LA SHEET ──────────────────────
   Il a pris un temps toute la largeur de l'écran, pour que les partis en
   cartes tiennent côte à côte. Sur un grand écran, cela faisait des champs de
   deux mètres et un regard qui traverse la pièce pour aller d'un libellé à sa
   valeur. Les réglages les plus larges — la période — ont maintenant leur
   onglet : la colonne ordinaire leur suffit. */

.asst__line { display: flex; gap: 8px; margin: 4px 0 6px; }
.asst__url { flex: 1 1 auto; min-width: 0; }
.asst__line select { flex: 0 0 auto; }

.asst__result { display: grid; gap: 14px; margin-top: 16px; }

.asst__notes {
  display: grid;
  gap: 5px;
  margin: 0;
  padding: 10px 12px 10px 28px;
  border: 1px solid var(--caution-bord);
  border-radius: var(--radius);
  background: var(--caution-fond);
  color: var(--caution);
  font-size: 13px;
  line-height: 1.45;
}

.asst__rootrow, .asst__namerow {
  display: grid;
  grid-template-columns: 120px 1fr;
  align-items: center;
  gap: 10px;
  font-size: 14px;
  color: var(--texte-fort);
}

/* ── LES CHAMPS DEVINÉS ───────────────────────────────────────────────────
   Deux colonnes, et le CHEMIN EST VISIBLE : c'est ce qui distingue une
   proposition d'une décision. On voit d'où chaque valeur sort, donc on peut
   être en désaccord — et corriger là, sans chercher où. */
.asst__fields {
  display: grid;
  gap: 6px;
  padding: 12px;
  border: 1px solid var(--bord);
  border-radius: var(--radius);
  background: var(--fond);
}
.asst__field {
  display: grid;
  grid-template-columns: 200px 1fr;
  align-items: center;
  gap: 10px;
}
.asst__field label { font-size: 14px; color: var(--texte-fort); }
.asst__field label k {
  margin-left: 5px;
  color: var(--caution);
  font-size: 11px;
}
/* CE QUI N'A PAS ÉTÉ RECONNU se signale — discrètement. Un champ facultatif
   non deviné n'est pas une faute ; un champ requis vide le devient à
   l'enregistrement, et l'aperçu vide le dira mieux qu'une bordure. */
.asst__field.is-missing input { border-color: var(--caution-bord); }

.asst__preview { overflow-x: auto; }
.asst__table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
.asst__table th {
  padding: 6px 9px;
  border-bottom: 1px solid var(--bord);
  color: var(--info);
  font-weight: 500;
  font-size: 11px;
  text-align: left;
  white-space: nowrap;
}
.asst__table td {
  padding: 5px 9px;
  border-bottom: 1px solid var(--surface-vive);
  color: var(--texte-fort);
  font-family: var(--font-mono);
  white-space: nowrap;
}
.asst__empty { margin: 0; color: var(--inactif); font-size: 13px; }
.asst__errors {
  display: grid;
  gap: 4px;
  margin: 10px 0 0;
  padding-left: 18px;
  color: var(--texte-alerte);
  font-size: 13px;
}

/* Le titre d'une étape, à l'intérieur de la sheet : plus discret que celui du
   dialogue, qui reste seul à annoncer de quoi il s'agit. */
.asst__h3 { margin: 6px 0 2px; font-size: 12px; opacity: .75; }

/* ── LE CODE QR, DANS LA FEUILLE « POSER SUR UN ÉCRAN » ──────────────────────
   Il n'a plus de dialogue à lui : il répond à la même question que les deux
   autres options — « comment mettre ce panneau sur un autre écran ? » — et
   trois réponses se lisent mieux au même endroit. En RANGÉE, code à gauche et
   explication à droite : un carré de deux cents pixels empilé au-dessus d'un
   paragraphe pousse les vraies options hors de l'écran. */
.qrbox--inline {
  display: flex;
  align-items: center;
  gap: 16px;
  margin: 0 0 18px;
  padding: 14px;
  border: 1px solid var(--bord);
  border-radius: var(--radius);
  background: var(--fond);
}
.qrbox--inline .qrbox__code {
  flex: 0 0 auto;
  width: 108px;
  /* Le code est un SVG noir sur blanc : sans ce fond, les modules sombres
     disparaîtraient dans la feuille et l'appareil ne lirait rien. */
  padding: 6px;
  border-radius: 3px;
  background: #FFF;
}
.qrbox--inline .qrbox__code svg { display: block; width: 100%; height: auto; }
.qrbox--inline b { display: block; margin-bottom: 4px; font-size: 14px; color: var(--texte-fort); }
.qrbox--inline .qrbox__url {
  margin: 0 0 6px;
  color: var(--info);
  font-family: var(--font-mono);
  font-size: 12px;
  overflow-wrap: anywhere;
}
.qrbox--inline .dlg__hint { margin: 0; }

/* ── CE QUI DÉTRUIT SE VOIT ROUGE ────────────────────────────────────────────
   Supprimer une page, vider un cockpit, effacer un compte : ces boutons
   portaient le gris de tous les autres, avec un texte rosé pour seule
   différence. Sur une rangée de trois boutons, la nuance ne se remarquait
   pas — et l'on cliquait le mauvais.

   ILS PRENNENT DONC LA TEINTE DE CE QU'ILS FONT. Un fond rouge SOURD, pas un
   aplat : le rouge franc appartient aux alarmes de l'installation, et un
   bouton posé sur un écran ne doit pas crier aussi fort qu'une chaudière en
   défaut. Il s'affirme au survol — au moment où la main s'en approche, donc
   au moment où cela compte.

   ── POURQUOI ICI ────────────────────────────────────────────────────────────
   Cette feuille est la seule que chargent À LA FOIS le panneau et les écrans
   de gestion. La règle vivait en deux exemplaires — un dans `app.css`, un dans
   `shell.css` — qui avaient divergé : le premier laissait le fond gris du
   bouton ordinaire, le second l'effaçait. Le même bouton n'avait donc pas la
   même allure selon l'écran où on le rencontrait. */
/* LE VOLET DE PROPRIÉTÉS EST NOMMÉ EXPRESSÉMENT. Il redessine TOUS ses boutons
   — `.insp .btn` — pour les aplatir dans une colonne de réglages, et cette
   règle-là est plus spécifique que la nôtre : le bouton de suppression y
   reprenait le fond sombre et le texte cyan de ses voisins, c'est-à-dire
   exactement l'allure dont on veut le distinguer. Le nommer ici coûte une
   ligne et garde UNE seule définition de la teinte ; la recopier là-bas en
   ferait deux, qui divergeraient. */
.btn--danger,
.insp .btn--danger {
  border-color: var(--alerte-bord);
  background: color-mix(in srgb, var(--alerte-fond) 55%, transparent);
  box-shadow: none;
  color: var(--texte-alerte);
}
.btn--danger:hover,
.insp .btn--danger:hover {
  border-color: var(--alerte);
  background: rgba(140, 43, 36, .36);
  color: #FFD9D6;
}
.btn--danger:active { box-shadow: inset 0 2px 4px rgba(0, 0, 0, .45); }
.btn--danger i,
.insp .btn--danger i { color: var(--alerte); }
.btn--danger:hover i,
.insp .btn--danger:hover i { color: #FF8A82; }

/* ALLUMÉ, il est plein : c'est l'acquittement d'alarme du bandeau, le seul
   endroit où ce bouton doit appeler l'œil de l'autre bout de la pièce. */
.btn--danger.is-on {
  border-color: #7A2A22;
  background: linear-gradient(180deg, #8C2B24, #5E1B16);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .14), 0 0 0 1px rgba(255, 59, 48, .4);
  color: #FFEDEB;
}
.btn--danger.is-on i { color: #FFD9D6; }

/* Ce qu'un champ qui se remplit tout seul a à dire — « pressez le bouton du
   pont, puis réessayez ». À côté du bouton, jamais à la place de l'indice :
   l'indice explique le champ, ceci raconte la dernière tentative. */
.dlg__says { font-size: 12px; line-height: 1.5; color: var(--texte-faible); }
.dlg__says.is-bad { color: var(--caution); }

/* ── UN INTERTITRE DANS UN FORMULAIRE ────────────────────────────────────────
   Il sépare des choses de natures différentes — une adresse et une clé d'un
   côté, des AUTORISATIONS de l'autre. Sans lui, une rangée d'interrupteurs se
   lit comme des réglages de plus, et l'on accorde un droit en croyant cocher
   une option.

   Le trait au-dessus fait le travail : c'est lui qui dit « autre chose
   commence ». Pas de trait sur le premier, qui ne sépare rien. */
.dlg__section { margin: 22px 0 12px; padding-top: 16px; border-top: 1px solid var(--filet); }
.dlg__section:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
.dlg__sectitle {
  margin: 0;
  font: 700 11px/1 var(--font-ui, inherit);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--info);
}
.dlg__section .dlg__hint { margin-top: 6px; }

/* ── LE COUP DE MAIN : ATTEINDRE LE SERVICE SANS QUITTER L'APPLICATION ───────
   Demander un « ClientId » sans dire où il s'obtient fait ouvrir un moteur de
   recherche — et l'on revient quand on revient. Trois choses manquent
   toujours : le pas à pas, les liens qui ouvrent les bonnes pages, et
   l'adresse de retour à recopier chez le service.

   La mise en page suit la règle de la maison : des boutons COMPACTS posés sur
   une ligne, un même bord gauche pour tout le bloc, et le texte qui prend
   toute la largeur. */
.dlg__help {
  margin: 18px 0 14px;
  padding: 14px;
  border: 1px solid var(--filet);
  border-left: 2px solid var(--info-bord);
  border-radius: 0 var(--radius) var(--radius) 0;
  background: rgba(0, 180, 216, .04);
}
.dlg__help .dlg__sectitle { margin-bottom: 10px; }
.dlg__steps {
  margin: 0 0 10px;
  padding-left: 18px;
  font-size: 13px;
  line-height: 1.65;
  color: var(--texte-faible);
}
.dlg__steps li { margin-bottom: 3px; }
.dlg__links { display: flex; flex-wrap: wrap; gap: 6px 16px; margin-bottom: 12px; }
.dlg__links .linkbtn { padding: 0; }
.dlg__links .linkbtn i { margin-right: 6px; font-size: 11px; opacity: .7; }
/* L'ADRESSE DE RETOUR SE COPIE, elle ne se retape pas : une URL recopiée à la
   main se recopie faux, et l'erreur ne se voit qu'au retour du service. */
.dlg__copy {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px;
  border: 1px solid var(--bord-fort); border-radius: var(--radius);
  background: var(--fond);
}
.dlg__copy k {
  flex: 0 0 auto;
  color: var(--texte-tenu);
}
.dlg__copy code {
  flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 12px; color: var(--texte-fort);
}
.dlg__copy .linkbtn { flex: 0 0 auto; padding: 0; }

/* ── DES PASTILLES DANS UN DIALOGUE ─────────────────────────────────────────
   Les styles viennent de `shell.css` — `.chips`, `.chip`, `.jeton` — et ne sont
   pas redécrits : trois écrans désignent des groupes, et ils doivent le faire
   de la même façon. Il ne reste ici que ce qui tient au dialogue : la zone n'a
   pas la marge intérieure d'une carte, et la liste de suggestions doit passer
   au-dessus des rangées suivantes. */
.dlg__chips { padding: 0; align-items: center; }
.dlg__row--chips { position: relative; z-index: 2; }
.dlg__chips .chips__none { margin-right: 2px; }

/* AJOUTER UN GROUPE : un champ DISCRET, pas un formulaire de plus. Il vit au
   bout de la rangée de pastilles, de la taille de ce qu'on y tape — et non de
   la largeur d'un dialogue, qui le ferait passer pour le champ principal.

   ── POURQUOI `input.chipadd__field` ET NON `.chipadd__field` ────────────────

   Parce que la rangée habille déjà TOUS ses champs :
   `.dlg__row input:not([type="checkbox"])` pèse (0,2,1), et un simple
   `.chipadd__field` pèse (0,1,0). Le trait discontinu, la pilule et le petit
   corps étaient donc écrits et n'ont jamais paru : on voyait un champ de
   formulaire ordinaire, cadre plein et coins carrés, posé au bout d'une rangée
   de pastilles. Le sélecteur ci-dessous pèse (0,2,1) lui aussi, et il est
   déclaré plus bas — c'est ce qui le fait gagner. */
.chipadd { position: relative; display: inline-block; }
/* ── CE QUI N'A PAS LA BONNE FORME LE DIT, SANS S'EFFACER ────────────────────
   Une adresse refusée reste dans le champ, et le champ s'allume une seconde.
   La vider aurait fait disparaître ce qu'on venait de taper sans dire quoi
   corriger — et l'on aurait retapé la même. */
.dlg__row input.chipadd__field.is-bad {
  border-color: var(--alerte);
  border-style: solid;
  color: var(--texte-alerte);
}
.dlg__row input.chipadd__field {
  width: 170px;
  padding: 5px 12px;
  border: 1px dashed var(--bord-vif);
  border-radius: 999px;
  background: none;
  color: var(--texte-fort);
  font: inherit;
  font-size: 12px;
}
.dlg__row input.chipadd__field::placeholder { color: var(--texte-tenu); }
.dlg__row input.chipadd__field:hover { border-color: var(--info-bord); }
.dlg__row input.chipadd__field:focus {
  outline: none;
  border-style: solid;
  border-color: var(--info-bord);
}
.chipadd__list {
  position: absolute;
  z-index: 30;
  top: calc(100% + 4px); left: 0;
  min-width: 190px; max-height: 210px; overflow-y: auto;
  margin: 0; padding: 4px;
  list-style: none;
  border: 1px solid var(--bord-fort); border-radius: var(--radius);
  background: var(--surface);
  box-shadow: 0 10px 24px rgba(0, 0, 0, .5);
}
.chipadd__list li { margin: 0; }
.chipadd__list button {
  display: flex; align-items: center; gap: 8px;
  width: 100%;
  padding: 6px 10px;
  border: 0; border-radius: 3px;
  background: none;
  color: var(--texte);
  font: inherit; font-size: 13px; text-align: left;
  cursor: pointer;
}
.chipadd__list button:hover { background: var(--surface-vive); color: var(--texte-fort); }
/* Le nombre de membres : une indication, pas une étiquette de plus à lire. */
.chipadd__list button em {
  margin-left: auto;
  font-style: normal; font-size: 11px; color: var(--texte-tenu);
}

/* ── DES ONGLETS DANS UN DIALOGUE ────────────────────────────────────────────
   Un formulaire long ne se PARCOURT pas : on sait ce qu'on vient y régler. Les
   intertitres deviennent les onglets, et le dialogue garde une hauteur qu'on
   embrasse d'un regard — ce qui est la moitié de ce qu'on attend d'un
   dialogue.

   Mêmes formes que les onglets de la maison (`shell.css`) : un liseré sous
   l'onglet ouvert, jamais un fond plein. C'est un repère, pas une commande. */
.dlg__tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 2px;
  margin: 4px 0 18px;
  border-bottom: 1px solid var(--bord);
}
.dlg__tab {
  position: relative;
  padding: 8px 13px;
  border: 0;
  background: none;
  color: var(--texte-faible);
  font: inherit;
  font-size: 13px;
  letter-spacing: .04em;
  cursor: pointer;
}
.dlg__tab:hover { color: var(--texte-fort); }
.dlg__tab.is-on { color: var(--texte-fort); }
.dlg__tab.is-on::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 2px;
  background: var(--info);
}
.dlg__tab:focus-visible { outline: 1px solid var(--info); outline-offset: -2px; }
/* L'icône, aux mêmes mesures que celle des onglets d'un écran (`shell.css`,
   `.tab i`) : c'est la même chose, elle doit se lire pareil. */
.dlg__tab i { margin-right: 7px; font-size: 12px; }

/* ── UNE NOTE ────────────────────────────────────────────────────────────────
   Ce que le formulaire sait déjà, et qu'il rend. Elle prend TOUTE la largeur —
   un texte explicatif n'habite pas la moitié droite d'une grille de champs — et
   se pose sur un creux plutôt que dans un cadre : elle ne se remplit pas. */
.dlg__note {
  margin: 0 0 14px;
  padding: 10px 12px;
  border-radius: var(--radius);
  background: var(--creux);
  border: 1px solid var(--filet);
}
.dlg__note k {
  display: block;
  margin-bottom: 4px;
  font-size: 11px;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--texte-tenu);
}
.dlg__note p { margin: 0; font-size: 12px; line-height: 1.5; color: var(--texte-faible); }
/* Le premier bloc d'un onglet explique ce qu'on y règle : il respire au-dessus
   du premier champ, sans le trait d'un intertitre qui ferait double emploi
   avec l'onglet lui-même. */
.dlg__lead { margin: 0 0 16px; }
.dlg__panel > .dlg__row:first-child { margin-top: 0; }
/* ── DEUX RÉGLAGES QUI SE LISENT PAR PAIRES ──────────────────────────────────
   Une cadence et son boost, un minimum et un maximum. Empilés, ils font dix
   rangées là où cinq suffisent, et l'on perd de vue qu'ils vont ensemble.

   Le PANNEAU porte la mise en colonnes, et non les rangées : une marge posée
   sur « la moitié qui suit une moitié » s'appliquait aussi à la première de la
   paire SUIVANTE, qui débordait alors et retombait à la ligne — une paire sur
   deux se dépliait. La gouttière appartient au contenant. */
.dlg__panel {
  display: flex; flex-wrap: wrap; gap: 0 12px;
  align-content: flex-start;
  /* La hauteur du plus grand panneau, posée après l'ouverture : sans elle, le
     dialogue change de taille à chaque onglet et ses boutons se dérobent sous
     le curseur. */
  min-height: var(--dlg-panel-h, auto);
}
.dlg__panel > * { flex: 1 0 100%; min-width: 0; }
.dlg__panel > .dlg__row--half { flex: 0 1 calc(50% - 6px); }

/* ── DEUX COLONNES QUAND IL Y A LA PLACE ─────────────────────────────────────
   Un dialogue de réglages est large — mille quatre cents pixels sur un écran
   de bureau — et ses champs s'y empilaient en une colonne : un titre de cinq
   mots occupait une ligne entière, et l'on descendait chercher au bas de
   l'écran des réglages qui auraient tenu côte à côte. Le formulaire devenait
   long là où il était surtout étroit.

   Chaque rangée prend donc la moitié, et l'on ne descend plus que pour ce qui
   le mérite. Ce qui suit reste ENTIER, et chacun pour une raison :

   — les tables et les blocs de texte, qui deviendraient des fentes ;
   — les partis en cartes, qui portent une phrase sous chaque option ;
   — les jetons, dont le nombre varie et qui iraient à la ligne de travers ;
   — les intertitres et les notes, qui annoncent ce qui suit — les couper en
     deux ferait un titre de section flottant à côté d'un champ.

   La règle mesure le PANNEAU et non la fenêtre : un dialogue peut être étroit
   sur un grand écran, et c'est la place disponible qui décide. */
.dlg__panel { container: dlgpanel / inline-size; }

@container dlgpanel (min-width: 680px) {
  .dlg__panel > .dlg__row { flex: 0 1 calc(50% - 6px); }
  .dlg__panel > .dlg__row--pleine,
  .dlg__panel > .dlg__lead,
  .dlg__panel > .dlg__note,
  .dlg__panel > .dlg__section,
  .dlg__panel > .dlg__help,
  .dlg__panel > .dlg__error { flex: 1 0 100%; }
}
/* Hors onglets, le formulaire reste un bloc : l'inline-block suffit. */
.dlg__row--half { display: inline-block; width: calc(50% - 7px); vertical-align: top; }

/* ══ LES TRIGGERS D'UN RAPPORT ═══════════════════════════════════════════════
   Une liste de conditions, chacune sur un point. Deux étages par ligne : le
   point en tête — c'est lui qu'on lit pour savoir de quoi il s'agit — et ses
   règles dessous, en petit. Une seule rangée de six champs aurait fait une
   feuille de calcul, où l'on ne distingue plus une condition d'une autre. */
.trigs { display: flex; flex-direction: column; gap: 8px; }

.trig {
  padding: 10px 11px;
  border: 1px solid var(--bord);
  border-radius: var(--radius);
  background: var(--creux);
}
.trig__tete { display: flex; align-items: center; gap: 8px; }
.trig__rang {
  flex: 0 0 auto;
  width: 18px;
  color: var(--texte-tenu);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  text-align: right;
}
/* La clé est en chasse fixe : on la compare caractère par caractère à celle
   d'un courriel ou d'une armoire, et une fonte proportionnelle rend cette
   comparaison pénible. */
.dlg__row input.trig__cle {
  flex: 1 1 auto;
  min-width: 0;
  padding: 6px 9px;
  font-family: var(--font-mono);
  font-size: 12px;
}
.dlg__row input.trig__cle::placeholder { font-family: var(--font-ui); }
.trig__tete .iconbtn { flex: 0 0 auto; width: 26px; height: 26px; border-color: transparent; }
.trig__tete .iconbtn:hover { border-color: var(--info); }
.trig__tete .iconbtn--bad:hover { border-color: var(--alerte); }

/* Les règles se répartissent : quatre de front sur un dialogue large, deux sur
   un étroit, une seule sur un téléphone — sans qu'aucune règle n'ait à prévoir
   les largeurs. */
.trig__regles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(148px, 1fr));
  gap: 8px;
  margin: 8px 0 0 26px;
}
.trig__regles label {
  display: flex;
  flex-direction: column;
  gap: 3px;
  color: var(--texte-tenu);
  font-size: 10.5px;
}
.dlg__row .trig__regles input,
.dlg__row .trig__regles select {
  padding: 5px 8px;
  font-size: 12px;
}
/* Un seuil n'a pas de sens sur un tout ou rien : les deux champs s'éteignent,
   et gardent ce qu'on y avait mis — repasser sur « dépasse » les retrouve. */
.dlg__row .trig__regles input:disabled,
.dlg__row .trig__regles select:disabled { opacity: .4; cursor: not-allowed; }

.trigs__rien { margin: 0; color: var(--texte-tenu); font-size: 12px; }
.trigs__plus {
  align-self: flex-start;
  padding: 6px 12px;
  border: 1px dashed var(--bord-vif);
  border-radius: 999px;
  background: none;
  color: var(--texte-faible);
  font: inherit;
  font-size: 12px;
  cursor: pointer;
}
.trigs__plus i { margin-right: 6px; font-size: 10px; }
.trigs__plus:hover { border-style: solid; border-color: var(--info); color: var(--info); }

/* Un raccourci à jetons — « + Moi » — se distingue d'un jeton posé : pointillé,
   atone, et il s'allume au survol. C'est une proposition, pas un choix. */
.jeton--propose {
  padding: 3px 10px;
  border-style: dashed;
  background: none;
  color: var(--texte-faible);
  cursor: pointer;
  font: inherit;
}
.jeton--propose:hover { border-color: var(--info); color: var(--texte-fort); }
.jeton--propose i { font-size: .85em; }

/* ── LE POINT D'UN TRIGGER : SON NOM, ET LA LOUPE QUI LE CHANGE ─────────────
   Toute la ligne est le bouton : on vise un nom, pas une icône de vingt-six
   pixels. Le repère en gras, la phrase et la clé dessous, en petit. */
.trig__point {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 10px;
  border: 1px solid var(--bord);
  border-radius: var(--radius);
  background: var(--creux);
  color: var(--texte);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.trig__point:hover { border-color: var(--info); }
.trig__point > i { color: var(--texte-tenu); font-size: 12px; }
.trig__point span { display: flex; flex-direction: column; min-width: 0; }
.trig__point b { font-size: 13px; font-weight: 600; color: var(--texte-fort); }
.trig__point k {
  overflow: hidden;
  color: var(--texte-tenu);
  font-size: 11.5px;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.trig__point k:empty { display: none; }
.trig__vide { color: var(--texte-tenu); }
