/* ═══════════════════════════════════════════════════════════════════════════
   Simone — Couche composants
   RÈGLE ABSOLUE : aucune couleur, aucun rayon, aucune ombre, aucune police
   en dur dans ce fichier. Tout passe par un token de directions.css.
   Changer de direction ne doit JAMAIS demander de toucher ce fichier.
   ═══════════════════════════════════════════════════════════════════════════ */

/* RÈGLE : tout composant qui impose une géométrie déclare son propre display.
   Sans cela, il dépend de la balise sur laquelle on le pose — posé sur un
   <span>, il reste en ligne et sa hauteur est purement et simplement ignorée.
   Contrôlé par verif/display.mjs. */

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html { -webkit-text-size-adjust: 100%; }

body {
  font-family: var(--font-ui);
  font-size: var(--text-base);
  line-height: 1.5;
  letter-spacing: var(--ui-tracking);
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}

button, input, select, textarea { font: inherit; letter-spacing: inherit; color: inherit; }
button { cursor: pointer; background: none; border: none; }
a { color: inherit; text-decoration: none; }
ul { list-style: none; }

/* L'attribut [hidden] vaut display:none dans la feuille du navigateur, mais
   toute classe qui fixe un display l'emporte sur elle. Sans ce rappel, masquer
   un composant par [hidden] ne fait rien du tout. */
[hidden] { display: none !important; }

:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* ── Typographie ──────────────────────────────────────────────────────────── */
.display-1 { font-family: var(--font-display); font-weight: var(--display-weight);
             font-size: 28px; line-height: 1.15; letter-spacing: var(--display-tracking); }
.display-2 { font-family: var(--font-display); font-weight: var(--display-weight);
             font-size: 20px; line-height: 1.25; letter-spacing: var(--display-tracking); }
.display-3 { font-family: var(--font-display); font-weight: var(--display-weight);
             font-size: 16px; line-height: 1.35; letter-spacing: var(--display-tracking); }
.muted     { color: var(--text-muted); }
.subtle    { color: var(--text-subtle); }
.mono      { font-family: var(--font-mono); font-size: .86em; }
.overline  { font-size: 11px; font-weight: 600; letter-spacing: .09em;
             text-transform: uppercase; color: var(--text-subtle); }

/* ── Transitions de vue entre pages ───────────────────────────────────────
   Le back-office recharge la page à chaque clic : 131 ms, ce n'est pas lent,
   c'est SAUTANT. Le navigateur peut fondre l'ancienne page dans la nouvelle
   au lieu de la remplacer d'un coup.

   La colonne et la barre du haut portent un nom : le navigateur les traite
   alors comme le MÊME élément des deux côtés, et elles restent en place
   pendant que le contenu se remplace. Tout le reste se fond.

   ⚠ Ce qui n'est pas pris en charge est simplement ignoré : Chrome et Safari
   récents l'animent, Firefox recharge comme avant. Aucune dégradation.
   ⚠ Le filet universel « moins d'animations » ne touche PAS les
   pseudo-éléments de transition : on coupe donc explicitement. */
@view-transition { navigation: auto; }
@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
}
::view-transition-old(root), ::view-transition-new(root) { animation-duration: var(--dur); }

.side { view-transition-name: colonne; }
.topbar { view-transition-name: barre-haut; }

/* ── Coque applicative ────────────────────────────────────────────────────── */
.app { display: grid; grid-template-columns: 240px 1fr; min-height: 100vh; }

.side {
  background: var(--nav-bg); color: var(--nav-text);
  /* Aucun gap : le filet du pied doit se poser EXACTEMENT là où les entrées
     disparaissent sous le bord du défilement. Les 24 px d'écart venaient
     d'ici, pas d'une marge. */
  display: flex; flex-direction: column; gap: 0;
  /* ⚠ Pas de rembourrage EN HAUT : il appartient à .side-nav, qui défile.
     Posé ici, il laissait une bande vide au-dessus du contenu coupé dès
     qu'on faisait défiler le menu. */
  padding: 0 var(--space-3) var(--space-5);
  border-right: var(--filet-w) solid var(--border);
  transition: background var(--dur) var(--ease);
  /* Navigation et contenu défilent chacun pour soi : la barre latérale
     garde la hauteur de l'écran, collée en haut, avec son propre défilement
     (qui ne se propage pas à la page). La page, elle, défile pour le
     contenu — les barres collantes et les ancres continuent de marcher. */
  position: sticky; top: 0; align-self: start;
  height: 100vh; height: 100dvh;
  /* Une colonne collante forme sa propre couche : sans z-index, elle passait SOUS les barres collantes du contenu
     (plan et réglages de l'éditeur), et le menu du compte, qui déborde sur elles, était coupé. */
  z-index: 30;
}
/* ⚠ Le défilement appartient au MENU, pas à la colonne : sans cela le pied
   (l'utilisateur) partirait vers le haut dès que la liste des contenus
   dépasse. Il reste désormais posé en bas, toujours à portée. */
.side-nav {
  flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  padding-top: var(--space-5);
  /* Quand l'entrée courante est amenée en vue au chargement, « nearest » la
     colle au bord : ce retrait lui laisse de l'air. */
  scroll-padding: var(--space-6) 0;
  display: flex; flex-direction: column;
  scrollbar-width: thin; scrollbar-color: color-mix(in srgb, var(--nav-text) 25%, transparent) transparent;
}
/* Des filets plutôt que des intitulés : un groupe se reconnaît à sa place,
   pas à son nom. « Contenu », « Structure », « Configuration » disparaissent. */
.side-group + .side-group {
  margin-top: var(--space-4); padding-top: var(--space-4);
  border-top: 1px solid var(--nav-filet);
}
.side-group { display: flex; flex-direction: column; gap: 2px; }
.side-group .overline { padding: 0 var(--space-3); margin-bottom: var(--space-2);
  /* --text-subtle est un jeton de surface CLAIRE : sur le fond de la barre il
     tombait à 3,55:1. Le jeton de la barre donne 6,42:1. */
  color: var(--nav-text); }

.nav-item {
  display: flex; align-items: center; gap: var(--space-3);
  height: var(--control-h); padding: 0 var(--space-3);
  border-radius: var(--radius-md);
  color: var(--nav-text); font-weight: 500;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.nav-item i { font-size: var(--icon-md); opacity: .85; }
.nav-item:hover { background: var(--nav-active-bg); color: var(--nav-text-active); }
.nav-item.est-courant { background: var(--nav-active-bg); color: var(--nav-text-active); font-weight: 600; }
.nav-item.est-courant i { color: var(--nav-icon-active); opacity: 1; }
.nav-item .count { margin-left: auto; font-family: var(--font-num); font-size: 11px; opacity: .6; font-variant-numeric: tabular-nums; }

/* ── Rail de navigation clair ─────────────────────────────────────────────
   La navigation d'une page à sections (Réglages) : même géométrie que
   .nav-item, mais sur fond clair. Les motifs d'écran le composaient en
   redéfinissant les tokens de .nav-item à la main — un vrai manque. */
.rail { display: flex; flex-direction: column; gap: 2px; }
.rail a {
  display: flex; align-items: center; gap: var(--space-3);
  height: var(--control-h); padding: 0 var(--space-3);
  border-radius: var(--radius-md); color: var(--text-muted); font-weight: 500;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.rail a i { font-size: var(--icon-md); }
.rail a:hover { background: var(--surface-2); color: var(--text); }
.rail a.est-courant, .rail a[aria-current="page"] { background: var(--accent-soft); color: var(--accent-soft-text); font-weight: 600; }
.rail a.est-courant i, .rail a[aria-current="page"] i { color: var(--accent); }

.side-foot {
  /* Aucune marge au-dessus : le filet doit se poser EXACTEMENT là où les
     entrées disparaissent sous le bord du défilement. Un écart, et le trait
     semblait flotter au-dessus de rien. */
  flex: none; position: relative;
  padding-top: var(--space-3);
  border-top: 1px solid var(--nav-filet);
}
.side-user {
  display: flex; align-items: center; gap: var(--space-3); width: 100%;
  padding: var(--space-2) var(--space-3); border-radius: var(--radius-md);
  text-align: left; color: inherit; cursor: pointer;
}
.side-user .chevron { margin-left: auto; font-size: var(--icon-sm); opacity: .7;
  transition: transform var(--dur-fast) var(--ease); }
.side-user[aria-expanded="true"] { background: var(--nav-active-bg); }
.side-user[aria-expanded="true"] .chevron { transform: rotate(180deg); }
/* La fenêtre du compte s'ouvre VERS LE HAUT, depuis le pied de la colonne :
   son origine d'animation n'est donc pas celle des menus qui tombent. */
/* ⚠ « .menu.side-menu » et non « .side-menu » : le composant .menu est
   déclaré plus bas dans la feuille, et sa min-width de 190 px l'emportait
   par ordre de source. */
.menu.side-menu {
  display: block;
  position: absolute; bottom: calc(100% + var(--space-2)); left: 0;
  /* Plus large que la colonne : elle déborde sur le contenu, comme toute
     fenêtre contextuelle. À 216 px, le choix d'affichage était à l'étroit. */
  min-width: 276px; z-index: 40; transform-origin: bottom left;
}
.side-menu .menu-item { width: 100%; }
.side-affichage {
  display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  font-size: 13.5px; color: var(--text);
}
.side-affichage .seg { margin-left: auto; }
/* ⚠ .seg button n'a pas de justify-content : ses boutons portent du TEXTE et
   se calent à gauche de leur rembourrage. En leur imposant une largeur pour
   n'y mettre qu'une icône, celle-ci restait collée au bord. */
.side-affichage .seg button {
  justify-content: center; width: 32px; padding: 0; font-size: 15px;
}
/* ── Le mot-symbole, en lettres ───────────────────────────────────────────
   Londrina Solid : un tracé plein, sans ombre. La marque se tient seule,
   sans rien autour. Elle sert partout — la colonne comme les écrans hors
   session — et sa taille vient de l'appel. */
.mot-symbole {
  display: flex; justify-content: center;
  font-family: "Londrina Solid", var(--font-display), cursive;
  font-size: var(--taille, 34px); line-height: 1; letter-spacing: .06em;
  color: currentColor;
}
.mot-symbole span { display: inline-block; position: relative; }
/* La couleur vit sur une SECONDE couche, superposée à la lettre au repos :
   elle peut ainsi se fondre à l'entrée du pointeur comme à la sortie. Portée
   par la lettre elle-même, elle aurait surgi d'un coup.
   (Le mot-symbole est un role="img" avec son aria-label : ce doublon de
   texte n'est pas annoncé.) */
.mot-symbole span::after {
  content: attr(data-l); position: absolute; inset: 0;
  opacity: 0; transition: opacity var(--dur-lent) var(--ease);
}

/* Au survol, une TRAVERSÉE des teintes — pas un clignotement.

   ⚠ POURQUOI CE N'EST PAS UN FLASH, mesuré et non supposé. La clarté
   perceptuelle est figée (le L d'OKLCH vaut .78 à chaque image), mais la
   luminance au sens WCAG, elle, varie : mesurée de 0,389 (teinte 0) à
   0,553 (teinte 180) — soit 0,164 d'écart, au-dessus du seuil de 0,10.
   Ce qui met donc l'animation hors de portée de la règle WCAG 2.3.1, ce
   n'est PAS l'absence de variation : c'est son rythme. La luminance monte
   et redescend une seule fois par cycle de 1,1 s, soit environ 0,9 Hz, là
   où un flash suppose plus de trois oscillations par seconde.
   Ne pas raccourcir la durée sous ~0,7 s sans refaire cette mesure.

   Et rien ne bouge pour qui demande moins d'animations : l'animation
   n'existe pas hors de « no-preference ». */
@media (prefers-reduced-motion: no-preference) {
  .mot-symbole:hover span::after,
  a:focus-visible .mot-symbole span::after {
    opacity: 1;
    animation: xx-teintes 1.1s linear infinite;
  }
}

@keyframes xx-teintes {
  0%   { color: oklch(.78 .19  20); }
  25%  { color: oklch(.78 .19 110); }
  50%  { color: oklch(.78 .19 200); }
  75%  { color: oklch(.78 .19 290); }
  100% { color: oklch(.78 .19 380); }
}

.side-version {
  display: block;
  padding: var(--space-2) var(--space-3) var(--space-1);
  font-family: var(--font-mono); font-size: 11px; color: var(--text-subtle);
}
.side-user:hover { background: var(--nav-active-bg); }
.side-user .who { min-width: 0; }
.side-user .who b { display: block; font-size: 13px; font-weight: 600; color: var(--nav-text-strong); }
.side-user .who span { font-size: 11px; color: var(--nav-text);
  /* Pas d'opacity : elle atténuait le texte à 3,44:1 sans que la couleur
     déclarée bouge — invisible pour un contrôle qui compare des jetons. */ }

/* ── Zone principale ──────────────────────────────────────────────────────── */
.main { display: flex; flex-direction: column; min-width: 0; }
/* Ce qu'il reste à l'écran de la barre du haut (fil d'Ariane), qui part avec
   le défilement : 56 px à l'ouverture, 0 une fois sortie. coque.js le tient à
   jour. Tout panneau collé sous une barre d'écran plein cadre le retire de sa
   hauteur — sans lui, son bas dépassait de l'écran de 56 px tant que la page
   n'avait pas défilé, et ses dernières lignes restaient hors d'atteinte. */
:root { --haut-visible: 56px; }

.topbar {
  height: 56px; flex: none;
  display: flex; align-items: center; gap: var(--space-4);
  padding: 0 var(--pad-section);
  background: var(--surface);
  border-bottom: var(--filet-w) solid var(--border);
}
.crumb { display: flex; align-items: center; gap: var(--space-2); color: var(--text-muted); font-size: 13px; }
.crumb b { color: var(--text); font-weight: 600; }
.crumb i { font-size: var(--icon-sm); color: var(--text-subtle); }
/* Fil d'Ariane du back-office : une liste ordonnée dont chaque étape mène à
   son écran ; la dernière (aria-current) est la page, tronquée si longue. */
.crumb { min-width: 0; }
.crumb ol { display: flex; align-items: center; gap: var(--space-2); min-width: 0; margin: 0; padding: 0; list-style: none; }
.crumb li { display: inline-flex; align-items: center; gap: var(--space-2); flex: 0 1 auto; min-width: 0; white-space: nowrap; }
/* Trop long pour la barre : les étapes parentes cèdent (points de
   suspension) ; la page courante garde sa place, jusqu'à 70 % de la barre.
   Le site, lui, ne cède pas. */
.crumb li:last-child { flex-shrink: 0; max-width: 70%; }
.crumb li.crumb-site { flex: none; }
.crumb li > b, .crumb li:not(.crumb-site) > a { display: block; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.crumb a { display: inline-flex; align-items: center; gap: var(--space-2); color: inherit; text-decoration: none; border-radius: var(--radius-sm); }
/* Souligné au survol : le texte seul, jamais l'icône du site. */
.crumb a:hover { color: var(--text); }
.crumb a:hover > span { text-decoration: underline; text-underline-offset: 3px; }
.crumb a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.content { padding: var(--pad-section); display: flex; flex-direction: column; gap: var(--pad-section); }

.page-head { display: flex; align-items: flex-start; gap: var(--space-4); }
.page-head .grow { flex: 1; min-width: 0; }
.page-head p { color: var(--text-muted); margin-top: var(--space-1); }

/* ── Boutons ──────────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  height: var(--control-h); padding: 0 var(--space-4);
  border-radius: var(--radius-md);
  border: var(--border-w) solid transparent;
  font-size: calc(var(--text-base) - 1px); font-weight: 600; white-space: nowrap;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease),
              color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease),
              transform var(--dur-fast) var(--ease);
}
.btn i { font-size: var(--icon-sm); }
.btn:active { transform: translateY(1px); }

.btn-primary   { background: var(--accent); color: var(--accent-text); box-shadow: var(--shadow-sm); }
.btn-primary:hover { background: var(--accent-hover); }

.btn-secondary { background: var(--surface); color: var(--text); border-color: var(--border-strong); box-shadow: var(--shadow-sm); }
.btn-secondary:hover { background: var(--surface-2); }

.btn-ghost     { background: transparent; color: var(--text-muted); }
.btn-ghost:hover,
.cp-onglets button:hover { background: var(--surface-2); color: var(--text); }

.btn-danger    { background: var(--danger); color: var(--danger-text); }
.btn-danger:hover { filter: brightness(.92); }

.btn-sm { height: var(--control-h-sm); padding: 0 var(--space-3); font-size: 13px; }
.btn-icon { width: var(--control-h); padding: 0; }
.btn-icon.btn-sm { width: var(--control-h-sm); }

/* ── Champs ───────────────────────────────────────────────────────────────── */
.field { display: flex; flex-direction: column; gap: var(--space-2); }
.field > label, .field .pied > label { font-size: 13px; font-weight: 600; }
/* Une aide : dans un champ, dans le tiroir de la composition (sous une liste
   d'éléments, hors d'un .field — elle y prenait le corps du texte courant), et
   sous un message. PAS partout : rendue globale en 0.9.189, la règle avait
   rétréci en gris 12 px des avertissements écrits « help » ailleurs (« gardez
   l'archive en lieu sûr », « vous serez déconnecté », les explications des
   droits d'un membre) — vu au contrôle visuel du 06/10/2026. */
.field .help, .cp-tiroir .help, .msg-detail .help { font-size: 12px; color: var(--text-subtle); }
.field .err  { font-size: 12px; color: var(--danger); display: flex; align-items: center; gap: 5px; }

.input, .select, .textarea {
  width: 100%; height: var(--control-h); padding: 0 var(--space-3);
  background: var(--surface); color: var(--text);
  border: var(--border-w) solid var(--border-strong);
  border-radius: var(--radius-md);
  transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
.textarea { height: auto; min-height: 84px; padding: var(--space-3); resize: vertical; line-height: 1.55; }
/* ── L'œil d'un champ de mot de passe ──────────────────────────────────────
   La boîte est posée par mdp.js autour du champ : sans script, ni boîte ni
   bouton, et le champ reste un champ. */
.champ-mdp { position: relative; display: block; }
.champ-mdp .input { padding-right: calc(var(--control-h) - var(--space-1)); }
.oeil-mdp { position: absolute; top: 0; right: 0; width: var(--control-h); height: var(--control-h);
  display: grid; place-items: center; border: 0; background: none; cursor: pointer;
  color: var(--text-subtle); font-size: var(--icon-md); border-radius: var(--radius-md);
  transition: color var(--dur-fast) var(--ease); }
.oeil-mdp:hover { color: var(--text); }
.oeil-mdp:focus-visible { outline: var(--border-w) solid var(--accent); outline-offset: -2px; color: var(--text); }

/* ── L'écran de connexion ──────────────────────────────────────────────────
   Pas de carte : une carte encadre un bloc AU SEIN d'une page, et celle-ci ne
   contenait qu'elle. Le monogramme, une phrase, les champs, le bouton. */
.connexion { width: 340px; max-width: 100%; display: flex; flex-direction: column; gap: var(--space-4); }
.connexion .monogramme { align-self: center; color: var(--text); }
.connexion h1 { margin: 0 0 var(--space-2); text-align: center; font-size: 17px; line-height: 1.4; font-weight: 600; }

/* ── L'écran de connexion illustré ─────────────────────────────────
   Le paysage à gauche, une bande blanche à droite sur toute la hauteur.
   ⚠ APRÈS « .connexion », ET C'EST LA CONDITION POUR QUE ÇA MARCHE. Les deux
   sélecteurs pointent aussi fort (0,2,0) : c'est l'ordre du fichier qui
   tranche. Placé avant, « .connexion .monogramme { color: var(--text) } »
   l'emportait — et en mode sombre le monogramme ressortait BLANC sur la bande
   blanche, donc invisible. Vu à l'écran, pas deviné.
   ⚠ « 100dvh » ET PAS « 100vh » : sur un téléphone, 100vh compte la barre
   d'adresse comme si elle n'était pas là — la bande dépasserait sous l'écran et
   le bouton « Se connecter » se cacherait derrière elle.
   ⚠ LA BANDE EST BLANCHE EN TOUTE CIRCONSTANCE, mode sombre compris : elle
   jouxte une illustration vive aux couleurs fixées, et un panneau sombre à
   côté d'un coucher de soleil ne tiendrait pas. Elle impose donc aussi son
   encre, sans quoi le texte clair du mode sombre disparaîtrait dessus.
   Les valeurs viennent des PRIMITIVES (--gray-…), qui ne basculent pas avec le
   mode ; les sémantiques (--text, --surface), elles, basculent. */
/* ⚠ LA HAUTEUR SE TIENT PAR LES DEUX BOUTS.
   1. <html> reçoit une hauteur DÉFINIE : sans elle, le « 100 % » du corps n'a
      rien à quoi se mesurer et ne vaut rien. Visé par un ATTRIBUT posé par le
      serveur, et non par « :has() » : un sélecteur dont le soutien varie est
      une inconnue de trop quand on cherche un défaut qu'on ne reproduit pas.
   2. Le fond est BLANC, pas « --bg ». Cet écran est clair en toute
      circonstance ; sa toile devait l'être aussi. Avec « --bg », un visiteur en
      mode sombre avait un écran clair posé sur une toile presque noire : le
      moindre débordement se lisait comme une BANDE NOIRE. Désormais il ne
      pourrait apparaître qu'un liseré blanc, de la couleur de la bande.
   3. Et le corps n'a PLUS de hauteur fixe, seulement un plancher. Piné à
      « height: 100 % », il ne pouvait pas grandir : tout ce qu'une extension
      ou un gestionnaire de mots de passe injecte APRÈS le chargement débordait
      hors de lui, et la zone débordée montrait la toile. Cela explique le
      « un instant plus tard » : le défaut naît quand le script tiers s'exécute,
      pas au rendu.
   ⚠ L'ORDRE DES TROIS min-height COMPTE : la dernière déclaration comprise
   l'emporte. vh d'abord (le repli universel), puis 100 % (le plancher adossé
   à la hauteur de <html>), et dvh EN DERNIER — c'est lui qu'on veut sur un
   téléphone, où 100 vh ignore la barre d'adresse et cacherait le bouton. */
html[data-ecran="illustre"] { height: 100%; background: var(--gray-0); }
.ecran-illustre { min-height: 100vh; min-height: 100%; min-height: 100dvh; margin: 0;
  background: var(--gray-0);
  /* ⚠ LA LIGNE SE DÉCLARE, ELLE AUSSI. Avec les seules colonnes, la ligne est
     IMPLICITE : dimensionnée sur son contenu. Le min-height étirait la boîte à
     la hauteur du cadre, mais la LIGNE restait à la hauteur du formulaire — et
     les deux panneaux avec elle. Mesuré chez Ronan : corps 797, panneaux 642.
     Les 155 px manquants montraient le fond du corps : noir tant qu'il suivait
     le mode, blanc ensuite. Je cherchais un débordement ; c'était un MANQUE.
     « minmax(0, 1fr) » absorbe tout l'espace libre : la ligne fait la hauteur du
     cadre quoi que contiennent les panneaux. Ne pas compter sur l'étirement
     par défaut d'une ligne automatique — il dépend de la hauteur définie du
     conteneur, et un min-height n'en est pas une. */
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(320px, 440px);
  grid-template-rows: minmax(0, 1fr); }
/* ⚠ L'AURORE EST POSÉE DANS LA PAGE, PAS EN « background-image » : un SVG
   appelé comme image est rendu en mode statique et ses animations ne tournent
   pas (mesuré : pixels identiques après cinq secondes). Le panneau se contente
   donc de la cadrer, et le dessin se charge du reste avec son
   « preserveAspectRatio="xMidYMid slice" » — l'équivalent de « cover ». */
.ecran-illustration { position: relative; overflow: hidden; background: var(--gray-950); }
.aurore { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
/* Une photo posée dans les Réglages remplace l'aurore : même cadre, même
   rognage. Pas de « lazy » : c'est la seule image de la page et elle est
   au-dessus de la ligne de flottaison. */
.ecran-photo { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
/* Le crédit de la photo : discret, dans le coin, mais lisible sur n'importe
   quelle image — d'où l'ombre portée plutôt qu'un aplat, qui masquerait un
   morceau de la photo. L'aurore du produit n'en porte pas : c'est son dessin. */
.ecran-credit { position: absolute; z-index: 1; left: var(--space-4); bottom: var(--space-3); margin: 0;
  font-size: 11px; line-height: 1.3; letter-spacing: .02em; color: #fff; opacity: .85;
  text-shadow: 0 1px 3px rgb(0 0 0 / .6); pointer-events: none; max-width: calc(100% - var(--space-8)); }
/* ⚠ UNE OMBRE PORTÉE NE SUFFIT PAS SUR UNE PHOTO CLAIRE : le crédit est blanc,
   et n'importe quelle image peut être posée là — un ciel blanc le ferait
   disparaître. Un voile très doux, confiné au bas de l'image, le tient lisible
   partout ; sur une photo sombre il ne se voit pas. Il n'est posé QUE s'il y a
   un crédit : sans texte, il n'y aurait rien à tenir lisible. */
.ecran-illustration:has(.ecran-credit)::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 96px; pointer-events: none;
  background: linear-gradient(to top, rgb(0 0 0 / .38), rgb(0 0 0 / 0)); }
/* ⚠ LES DEUX PANNEAUX SONT PLACÉS EXPLICITEMENT, pas laissés à l'ordre du
   document : c'est ce qui permet d'échanger les côtés sans toucher au HTML —
   l'ordre de lecture (illustration décorative, puis formulaire) reste le même
   pour un lecteur d'écran, quelle que soit la place choisie. */
.ecran-illustre > .ecran-illustration { grid-column: 1; grid-row: 1; }
.ecran-illustre > .ecran-bande { grid-column: 2; grid-row: 1; }
.ecran-illustre.champs-gauche { grid-template-columns: minmax(320px, 440px) minmax(0, 1fr); }
.ecran-illustre.champs-gauche > .ecran-illustration { grid-column: 2; }
.ecran-illustre.champs-gauche > .ecran-bande { grid-column: 1; }
/* Au centre : l'image prend tout, et les champs flottent par-dessus. La bande
   n'est plus un panneau mais un cadre transparent ; c'est le formulaire qui
   devient une carte, sinon le texte se poserait à même la photo. */
.ecran-illustre.champs-centre { grid-template-columns: minmax(0, 1fr); }
.ecran-illustre.champs-centre > .ecran-illustration,
.ecran-illustre.champs-centre > .ecran-bande { grid-column: 1; }
/* ⚠ LA BANDE DOIT ÊTRE AU-DESSUS DE L'IMAGE. Les deux occupent la même case
   de la grille, et « .ecran-photo » est en position absolue : un élément
   positionné se peint par-dessus un élément qui ne l'est pas, quel que soit
   l'ordre du document. Sans cette ligne, le formulaire était bien là — mesuré,
   carte de 380 × 439, tous les champs à leur place — mais la photo le
   recouvrait entièrement. Le DOM disait juste, l'écran était vide. */
.ecran-illustre.champs-centre > .ecran-bande { background: transparent; padding: var(--space-8) var(--space-6);
  position: relative; z-index: 1; }
.ecran-illustre.champs-centre .connexion {
  background: var(--surface); border-radius: var(--radius-lg);
  padding: var(--space-10) var(--space-8); box-shadow: 0 24px 60px rgb(0 0 0 / .32);
  width: 380px; max-width: 100%; }
/* ⚠ LA BANDE REDONNE LES SÉMANTIQUES CLAIRES, elle ne repeint pas chaque
   composant. Le premier essai forçait la couleur du titre, des libellés, des
   champs… un à un : le message d'erreur, lui, continuait de suivre le mode de
   la page — une boîte rouge sombre posée sur du blanc. En redéclarant ici les
   jetons, tout ce que la bande contient suit, y compris ce qu'on n'avait pas
   prévu d'y mettre. Les valeurs sont celles de :root, reprises à l'identique —
   ce sont des PRIMITIVES, qui ne basculent pas avec le mode. */
.ecran-bande {
  --bg: var(--gray-50); --surface: var(--gray-0); --surface-2: var(--gray-100);
  --surface-sunken: var(--gray-150); --surface-inverse: var(--gray-950);
  --text: var(--gray-950); --text-muted: var(--gray-700);
  --text-subtle: var(--gray-600); --text-inverse: var(--gray-0);
  --select-fleche: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256' fill='%2317171A'%3E%3Cpath d='M213.66,101.66l-80,80a8,8,0,0,1-11.32,0l-80-80A8,8,0,0,1,53.66,90.34L128,164.69l74.34-74.35a8,8,0,0,1,11.32,11.32Z'/%3E%3C/svg%3E");
  --border: var(--gray-200); --border-strong: var(--gray-500);
  --accent: var(--violet-600); --accent-hover: var(--violet-700);
  --accent-text: var(--gray-0); --accent-soft: var(--violet-50); --accent-soft-text: var(--violet-700);
  --ok: var(--green-600); --ok-soft: var(--green-50); --ok-soft-text: var(--green-700);
  --info: var(--blue-600); --info-soft: var(--blue-50); --info-soft-text: var(--blue-700);
  --warn: var(--amber-600); --warn-soft: var(--amber-50); --warn-soft-text: var(--amber-700);
  --danger: var(--red-600); --danger-soft: var(--red-50); --danger-soft-text: var(--red-700);
  --danger-text: var(--gray-0);
  --focus-ring: 0 0 0 3px rgba(91, 84, 232, .28);
  background: var(--surface); color: var(--text);
  display: grid; grid-template-columns: minmax(0, 1fr); place-items: center;
  padding: var(--space-16) var(--space-8); overflow-y: auto; }
/* ⚠ SOUS 48 rem, LE PAYSAGE PASSE EN BANDEAU. Gardé en colonne, il aurait
   laissé au formulaire la moitié d'un écran de téléphone — inutilisable.
   ⚠ « minmax(0, 1fr) » ET PAS « 1fr » POUR LA SECONDE LIGNE. Un « 1fr » nu vaut
   « minmax(auto, 1fr) » : son minimum est le CONTENU, si bien que la ligne
   grossit au lieu d'être bornée, la bande cesse de défiler, et le bouton sort
   de l'écran sans qu'on puisse l'y ramener. Mesuré à 740 × 360 : bande de 439
   pour 252 disponibles, bouton à 500. Avec un minimum à zéro, la ligne tient
   dans le cadre et « overflow-y: auto » reprend son office. */
@media (max-width: 48rem) {
  /* ⚠ « minmax(0, 1fr) auto » : L'IMAGE PREND CE QUE LE FORMULAIRE LUI LAISSE.
     Une part fixe (30vh) condamnait les petits écrans : à 320 × 568 elle prenait
     170 px et poussait le bouton sous la ligne de flottaison. Ici la bande est
     dimensionnée sur son contenu et le bandeau reçoit le reste — généreux sur un
     grand téléphone, mince sur un petit, jamais au détriment de la tâche. Le
     minimum à zéro lui permet de disparaître plutôt que de pousser. */
  .ecran-illustre { grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr) auto; }
  .ecran-bande { padding: var(--space-10) var(--space-6); overflow: visible; }
  /* ⚠ SUR UNE COLONNE, LES TROIS PLACES SE REJOIGNENT : « à droite » et « à
     gauche » n'ont plus de sens quand il n'y a qu'une colonne, et superposer
     la carte à l'image sur un téléphone laisserait trop peu de place aux
     champs. On revient donc partout à l'image en haut, le formulaire dessous. */
  .ecran-illustre.champs-gauche > .ecran-illustration,
  .ecran-illustre.champs-centre > .ecran-illustration { grid-column: 1; grid-row: 1; }
  .ecran-illustre.champs-gauche > .ecran-bande,
  .ecran-illustre.champs-centre > .ecran-bande { grid-column: 1; grid-row: 2; background: var(--surface); }
  .ecran-illustre.champs-centre .connexion { background: none; border-radius: 0; padding: 0; box-shadow: none; width: 340px; }
}
/* ⚠ SUR UN ÉCRAN BAS, LA DÉCORATION CÈDE. En paysage sur un téléphone, le
   bandeau prenait 30 % d'une hauteur déjà minuscule et repoussait le
   formulaire ; l'image est une invitation, pas la tâche. Sous 32 rem de haut
   elle disparaît et la bande prend tout. */
@media (max-height: 32rem) {
  .ecran-illustre { grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr); }
  .ecran-illustration { display: none; }
  /* ⚠ UN SEUL DÉFILEMENT. Le formulaire dépasse forcément une hauteur de 360 :
     c'est la PAGE qui doit défiler, pas la bande dans la page. Deux défilements
     imbriqués se disputent le doigt, et celui du dessus n'a souvent rien à
     faire défiler — le geste paraît alors mort. */
  .ecran-bande { padding: var(--space-6); overflow: visible; place-items: start center; }
}

.input::placeholder, .textarea::placeholder { color: var(--text-subtle); }
.input:hover, .select:hover, .textarea:hover { border-color: var(--text-subtle); }
/* Au focus, UN trait d'1 px : la bordure prend l'accent, rien de plus.
   L'anneau translucide de 3 px qu'on y ajoutait faisait un double filet
   (signalé le 06/10/2026), puis l'épaississement d'un pixel vers l'intérieur
   un trait de 2 px — tous les filets restent à 1 px (Ronan, même jour). Le
   curseur dit le reste. */
.input:focus, .select:focus, .textarea:focus { outline: none; border-color: var(--accent); box-shadow: none; }
.input:disabled { background: var(--surface-2); color: var(--text-subtle); cursor: not-allowed; }
.input.est-errone { border-color: var(--danger); }

/* Le chevron des listes : caret-down du jeu d'icônes (trait d'1 px à 16 px),
   comme au site — plus le triangle (Ronan, 06/10/2026). Centré dans la
   hauteur, son bord visible sur la marge du texte : le dessin occupe 42 → 216
   de ses 256 unités en largeur, 88 → 184 en hauteur, on compense. */
.select {
  appearance: none; padding-right: calc(var(--space-3) + 22px);
  background-image: var(--select-fleche);
  background-position: right calc(var(--space-3) - 2.5px) top calc(50% - .5px);
  background-size: 16px 16px;
  background-repeat: no-repeat;
}

.input-search { position: relative; display: flex; align-items: center; }
.input-search i { position: absolute; left: var(--space-3); color: var(--text-subtle); font-size: var(--icon-sm); pointer-events: none; }
.input-search .input { padding-left: var(--space-8); }

/* ── Interrupteur, case, radio ────────────────────────────────────────────── */
.switch { position: relative; display: inline-block; width: 40px; height: 24px; flex: none; }
.switch input { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; z-index: 1; }
.switch .track {
  position: absolute; inset: 0; background: var(--surface-sunken);
  border: var(--border-w) solid var(--border-strong);
  border-radius: var(--radius-full);
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.switch .track::after {
  content: ""; position: absolute; top: 50%; left: 2px;
  width: 18px; height: 18px; transform: translateY(-50%);
  background: var(--surface); border-radius: var(--radius-full);
  box-shadow: var(--shadow-sm);
  transition: transform var(--dur) var(--ease), background var(--dur) var(--ease);
}
.switch input:checked + .track { background: var(--accent); border-color: var(--accent); }
.switch input:checked + .track::after { transform: translate(16px, -50%); }
.switch input:focus-visible + .track { box-shadow: var(--focus-ring); }

.check, .radio {
  width: 18px; height: 18px; flex: none; appearance: none;
  background: var(--surface);
  border: var(--border-w) solid var(--border-strong);
  border-radius: var(--radius-sm);
  display: grid; place-items: center; cursor: pointer;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.radio { border-radius: var(--radius-full); }
.check:checked, .radio:checked { background: var(--accent); border-color: var(--accent); }
.check:checked::after {
  content: ""; width: 9px; height: 5px;
  border-left: 2px solid var(--accent-text); border-bottom: 2px solid var(--accent-text);
  transform: rotate(-45deg) translate(1px, -1px);
}
.radio:checked::after { content: ""; width: 7px; height: 7px; border-radius: var(--radius-full); background: var(--accent-text); }
/* Cocher se voit : la coche se trace (de la branche courte à la longue), le
   point du bouton radio grossit avec un léger rebond. */
@media (prefers-reduced-motion: no-preference) {
  .check:checked::after { animation: ds-coche var(--dur) var(--ease) both; }
  .radio:checked::after { animation: ds-point var(--dur) cubic-bezier(.34, 1.56, .64, 1) both; }
  @keyframes ds-coche { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
  @keyframes ds-point { from { transform: scale(0); } to { transform: scale(1); } }
}

.opt { display: flex; align-items: center; gap: var(--space-3); font-size: 13px; }
.opt-rangee {
  display: flex; align-items: center; gap: var(--space-4);
  padding: var(--space-3) 0;
}
.opt-rangee .grow { flex: 1; min-width: 0; }
.opt-rangee b { display: block; font-size: 13px; font-weight: 600; }
.opt-rangee span { font-size: 12px; color: var(--text-subtle); }

/* ── Choix d'icône ──────────────────────────────────────────────────────────
   Des boutons radio : une seule icône, choisie au clavier comme à la souris.
   Le radio est posé sur toute la case, invisible, pour garder le focus et
   l'annonce des lecteurs d'écran ; l'état se lit sur le label (:has). */
.choix-icones {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(36px, 1fr)); gap: var(--space-1);
}
.choix-icones label {
  position: relative; display: grid; place-items: center; height: 36px;
  border-radius: var(--radius-sm); border: var(--border-w) solid transparent;
  color: var(--text-muted); cursor: pointer;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.choix-icones label:hover { background: var(--surface-2); color: var(--text); }
.choix-icones input { position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer; }
.choix-icones label:has(input:checked) { background: var(--accent-soft); color: var(--accent-soft-text); border-color: var(--accent); }
.choix-icones label:has(input:focus-visible) { box-shadow: var(--focus-ring); }
.choix-icones i { font-size: var(--icon-md); }

/* ── Pastilles d'état ─────────────────────────────────────────────────────── */
.pill {
  display: inline-flex; align-items: center; gap: 5px;
  height: 22px; padding: 0 var(--space-2);
  border-radius: var(--radius-pill);
  font-size: 11.5px; font-weight: 600; white-space: nowrap;
  background: var(--surface-2); color: var(--text-muted);
}
.pill::before { content: ""; width: 6px; height: 6px; border-radius: var(--radius-full); background: currentColor; }
.pill-ok     { background: var(--ok-soft);     color: var(--ok-soft-text); }
.pill-warn   { background: var(--warn-soft);   color: var(--warn-soft-text); }
.pill-danger { background: var(--danger-soft); color: var(--danger-soft-text); }
.pill-info   { background: var(--info-soft);   color: var(--info-soft-text); }
.pill-accent { background: var(--accent-soft); color: var(--accent-soft-text); }

/* ── Segments et barre d'outils ───────────────────────────────────────────── */
.seg {
  display: inline-flex; padding: 3px; gap: 2px;
  background: var(--surface-2); border-radius: var(--radius-md);
  border: var(--filet-w) solid var(--border);
}
/* Boutons pour un réglage, liens quand chaque segment est une adresse (filtre
   d'une liste) : même apparence, et le lien doit déclarer son display. */
.seg button, .seg a {
  display: inline-flex; align-items: center;
  height: calc(var(--control-h) - 8px); padding: 0 var(--space-3);
  border-radius: calc(var(--radius-md) - 2px);
  font-size: 13px; font-weight: 500; color: var(--text-muted); white-space: nowrap;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.seg button:hover, .seg a:hover { color: var(--text); }
.seg button.est-courant, .seg a.est-courant { background: var(--surface); color: var(--text); font-weight: 600; box-shadow: var(--shadow-sm); }

.toolbar { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }
.toolbar .grow { flex: 1; min-width: 160px; }

/* ── Cartes ───────────────────────────────────────────────────────────────── */
.card {
  background: var(--surface);
  border: var(--filet-w) solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}
.card-head {
  display: flex; align-items: center; gap: var(--space-3);
  padding: var(--pad-card); padding-bottom: var(--space-4);
}
.card-head .grow { flex: 1; min-width: 0; }
.card-body { padding: var(--pad-card); padding-top: 0; display: flex; flex-direction: column; gap: var(--gap-form); }
.card-foot {
  display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-4) var(--pad-card);
  border-top: var(--filet-w) solid var(--border);
  background: var(--surface-2);
  border-radius: 0 0 var(--radius-lg) var(--radius-lg);
}
.card-foot .grow { flex: 1; }

.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: var(--gap-form); }
/* Variantes : les motifs les composaient en style direct (« .grid-2
   détourné », relevé par le banc des motifs). Nommées, elles se replient
   proprement en largeur étroite. */
.grid-2.avec-cote { grid-template-columns: minmax(0, 1fr) var(--cote, 280px); align-items: start; }
.grid-2.avec-rail { grid-template-columns: var(--rail, 220px) minmax(0, 1fr); align-items: start; gap: var(--space-8); }
/* ── Lignes de liste (tableau de bord) ────────────────────────────────────
   Une ligne qui mène quelque part : repère (vignette ou avatar), titre et
   précision, et à droite un état ou un compte. */
.tb-lignes { display: flex; flex-direction: column; padding: 0 var(--space-2) var(--space-2); }
.tb-ligne {
  display: flex; align-items: center; gap: var(--space-3); min-width: 0;
  padding: var(--space-2) var(--space-3); border-radius: var(--radius-md); color: inherit; text-decoration: none;
}
.tb-ligne:hover { background: var(--surface-2); }
.tb-ligne:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.tb-ligne .grow { flex: 1; min-width: 0; }
.tb-ligne .grow b, .tb-ligne .grow > span { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tb-ligne .grow b { font-size: 13.5px; font-weight: 500; }
.tb-ligne .grow > span { font-size: 12px; color: var(--text-subtle); }
.tb-droite { display: flex; align-items: center; gap: var(--space-2); flex: none; }
.tb-fleche { color: var(--text-subtle); flex: none; }
/* ── Liste de contenus : une carte par entrée ────────────────────────────── */
/* Un tableau imposait ses colonnes : un titre long passait à la ligne et les
   rangées se chevauchaient. Une carte par entrée, un titre qui se coupe, et
   la carte entière est cliquable — plus besoin d'en-tête pour dire ce que
   chaque colonne contient. */
.ct-lignes { display: flex; flex-direction: column; gap: var(--space-2); }
.ct-ligne {
  position: relative; display: flex; align-items: center; gap: var(--space-3); min-width: 0;
  padding: var(--space-3); background: var(--surface);
  border: var(--filet-w) solid var(--border); border-radius: var(--radius-lg);
  transition: border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.ct-ligne:hover { background: var(--surface-2); border-color: var(--accent); }
/* Un brouillon se montre moins : il n'est pas encore au monde. Au survol il
   reprend sa pleine encre — on va le lire, autant qu'il soit lisible. */
.ct-ligne.est-brouillon { opacity: .6; }
.ct-ligne.est-brouillon:hover { opacity: 1; }
.ct-ligne:has(.ct-lien:focus-visible) { box-shadow: var(--focus-ring); }
.ct-ligne.est-saisi { opacity: .35; }
/* Le lien s'étend à toute la carte. Ce qui doit rester cliquable par-dessus —
   traductions, étiquette, poignée — se pose au-dessus de lui. */
.ct-lien { display: block; flex: 1; min-width: 0; color: inherit; text-decoration: none; cursor: pointer; }
.ct-lien::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
.ct-ligne > :not(.ct-lien) { position: relative; z-index: 1; }
.ct-lien b { display: block; font-size: 14px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ct-meta { display: flex; align-items: center; gap: var(--space-2); min-width: 0; margin-top: 2px; font-size: 12px; color: var(--text-subtle); }
.ct-meta > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ct-adresse { display: inline-block; flex: none; max-width: 60%; font-family: var(--font-mono); font-size: 11.5px;
  padding: 1px 6px; border-radius: var(--radius-sm); background: var(--surface-sunken); color: var(--text-muted); }
/* La marque de gauche : sur une liste de contenus elle dit le RÉFÉRENCEMENT
   (pas le statut, qui se lit en toutes lettres dans la carte) ; sur la liste
   des types, elle porte l'icône du type — là, elle distingue vraiment. */
.ct-marque { flex: none; display: grid; place-items: center; width: 22px; height: 22px; font-size: 17px; color: var(--text-subtle); }
.ct-marque.est-ok { color: var(--ok); }
.ct-marque.est-manque { color: var(--danger); }
.ct-marque.est-hors { color: var(--text-subtle); }
.ct-droite { flex: none; display: flex; align-items: center; gap: var(--space-1); }
/* Les gestes de fin de ligne. Ils se montrent au survol de la carte et restent
   là dès qu'on les vise ou qu'on les atteint au clavier — sans quoi ils
   seraient inatteignables sans souris. */
/* Une poignée se saisit : le pointeur le dit, et le dit encore pendant qu'on
   la tient. Écrit UNE fois — la règle était recopiée dans chaque écran qui
   range quelque chose, et la liste des contenus, nouvelle, n'en avait aucune. */
.poignee { cursor: grab; }
/* ── Réordonner sans souris ────────────────────────────────────────────────
   Le glisser-déposer HTML5 ne part pas d'un geste tactile : sur tablette, ces
   deux commandes sont le SEUL chemin pour changer un ordre. Elles servent
   aussi au clavier et au lecteur d'écran.
   ⚠ Toujours visibles, jamais révélées au survol — une commande qui n'apparaît
   qu'au survol n'existe pas pour un doigt. Et z-index au-dessus du lien étiré
   qui recouvre une rangée de la liste des contenus. */
.rang-gestes { display: flex; flex: none; gap: 2px; position: relative; z-index: 2; }
/* Les commandes reprennent .outil : survol, appui, focus et désactivé y sont
   déjà écrits une fois. Ne rien recopier ici — le cliquet de doublons.mjs l'a
   refusé, et il avait raison. */
.rang-geste i { font-size: 12px; }
.poignee:active, .est-saisi .poignee { cursor: grabbing; }
.cp-poignee:active { cursor: grabbing; }

.ct-geste { display: flex; opacity: 0; transition: opacity var(--dur-fast) var(--ease); }
.ct-ligne:hover .ct-geste, .ct-geste:focus-within { opacity: 1; }
.ct-jeter { color: var(--danger); }
.ct-jeter:hover { background: var(--danger-soft); color: var(--danger); }
@media (hover: none) { .ct-geste { opacity: 1; } }

.tb-ligne.est-danger .thumb { color: var(--danger); }
.tb-ligne.est-warn .thumb { color: var(--warn); }
.tb-direct { display: block; width: 8px; height: 8px; border-radius: 50%; background: var(--ok); flex: none; box-shadow: 0 0 0 3px var(--ok-soft); }
.tableau { --cote: 360px; }
.tableau-colonne { display: flex; flex-direction: column; gap: var(--gap-form); min-width: 0; }

.grille-cartes {
  display: grid; gap: var(--gap-form);
  grid-template-columns: repeat(auto-fill, minmax(min(var(--carte-min, 240px), 100%), 1fr));
}

/* ── Tableau ──────────────────────────────────────────────────────────────── */
.table-wrap {
  background: var(--surface);
  border: var(--filet-w) solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
}
table { width: 100%; border-collapse: collapse; }
thead th {
  text-align: left; font-size: 11.5px; font-weight: 600; letter-spacing: .05em;
  text-transform: uppercase; color: var(--text-subtle);
  height: var(--th-h); padding: 0 var(--space-4);
  background: var(--surface-2);
  border-bottom: var(--filet-w) solid var(--border);
}
tbody td {
  padding: 0 var(--space-4); height: var(--row-h);
  border-bottom: var(--filet-w) solid var(--border);
  vertical-align: middle;
}
tbody tr:last-child td { border-bottom: none; }
tbody tr { transition: background var(--dur-fast) var(--ease); }
tbody tr:hover { background: var(--surface-2); }
tbody tr.est-choisi { background: var(--accent-soft); }
.cell-title { display: flex; align-items: center; gap: var(--space-3); }
.cell-title .thumb {
  width: 34px; height: 34px; flex: none; border-radius: var(--radius-sm);
  background: var(--surface-sunken); display: grid; place-items: center;
  color: var(--text-subtle); font-size: var(--icon-sm);
}
.cell-title b { font-weight: 600; display: block; }
.cell-title span { font-size: 12px; color: var(--text-subtle); }
.col-fin { text-align: right; }
.num { font-family: var(--font-num); font-variant-numeric: tabular-nums; color: var(--text-muted); font-size: 13px; }

.avatar {
  width: 26px; height: 26px; flex: none; border-radius: var(--radius-full);
  background: var(--accent-soft); color: var(--accent-soft-text);
  display: inline-grid; place-items: center;
  font-size: 10.5px; font-weight: 700; letter-spacing: 0;
}
.cellule-personne { display: flex; align-items: center; gap: var(--space-2); font-size: 13px; color: var(--text-muted); }

/* ── Fenêtre modale ──────────────────────────────────────────────────────
   Le voile n'est pas décoratif : il capte le clic extérieur et retire le fond
   du champ d'attention. Révélé manquant par la couche React — le banc n'avait
   qu'un conteneur de démonstration. */
.modal-veil {
  position: fixed; inset: 0; z-index: 60;
  display: grid; place-items: center; padding: var(--space-6);
  background: color-mix(in srgb, var(--surface-inverse) 55%, transparent);
  animation: xx-surgit var(--dur) var(--ease);
}
.modal-veil > .modal { width: 100%; max-width: 440px; }

.modal-demo { position: relative; border-radius: var(--radius-lg); overflow: hidden;
              background: var(--surface-sunken); padding: var(--space-8);
              border: var(--filet-w) solid var(--border); }
.modal {
  max-width: 440px; margin: 0 auto;
  background: var(--surface);
  border: var(--filet-w) solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}
.modal-head { padding: var(--pad-card); padding-bottom: var(--space-3); display: flex; gap: var(--space-3); align-items: flex-start; }
.modal-head .icon {
  width: 36px; height: 36px; flex: none; border-radius: var(--radius-md);
  display: grid; place-items: center; font-size: var(--icon-md);
  background: var(--danger-soft); color: var(--danger-soft-text);
}
.modal-head .grow { flex: 1; }
.modal-head p { color: var(--text-muted); font-size: 13px; margin-top: var(--space-1); }
.modal-foot { display: flex; justify-content: flex-end; gap: var(--space-3); padding: var(--space-4) var(--pad-card);
              border-top: var(--filet-w) solid var(--border); background: var(--surface-2); }

/* ── Bandeau de contrôle du banc ──────────────────────────────────────────── */
.bench {
  /* left+right bornent le bloc conteneur : avec « left:50% » seul, la largeur
     disponible se mesurait du milieu de l'écran au bord droit — la barre se
     repliait sur trois lignes alors qu'il restait la moitié de la place.
     width:fit-content + margin auto la recentrent sans transform. */
  position: fixed; bottom: var(--space-4); left: var(--space-4); right: var(--space-4);
  width: fit-content; max-width: 100%; margin: 0 auto; z-index: 50;
  display: flex; align-items: center; gap: var(--space-2);
  padding: var(--space-2);
  background: var(--surface); color: var(--text);
  border: var(--border-w) solid var(--border-strong);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
}
.bench { flex-wrap: wrap; justify-content: center; gap: var(--space-1); }
/* Douze entrées dans une barre flottante : on resserre ici plutôt que de
   rapetisser les boutons partout ailleurs. */
.bench .btn-sm { padding: 0 var(--space-2); gap: 6px; }
.bench .seg button { padding: 0 var(--space-2); }
.bench .sep { width: 1px; height: 22px; background: var(--border); }
/* La page en cours se colore : dans une barre de douze entrées, savoir où l'on
   est ne doit pas demander de lire les douze. */
.bench .est-courant {
  background: var(--accent-soft); color: var(--accent-soft-text); font-weight: 600;
}
.bench .est-courant:hover { background: var(--accent-soft); }
.bench .lab { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .07em;
              color: var(--text-subtle); padding: 0 var(--space-1); }

/* ── Bandeau de composants isolés ─────────────────────────────────────────── */
.specimens { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: var(--space-4); }
.spec { display: flex; flex-direction: column; gap: var(--space-3); }
.spec-row { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }
.swatches { display: flex; gap: var(--space-2); flex-wrap: wrap; }
.sw { display: block; width: 44px; height: 44px; border-radius: var(--radius-md); border: var(--filet-w) solid var(--border); }
.nuance-legende { font-size: 10px; color: var(--text-subtle); text-align: center; margin-top: 4px; }
.nuance-bloc { text-align: center; }

/* ═══════════════════════════════════════════════════════════════════════════
   ÉTATS ET COMPOSANTS COMPLÉMENTAIRES
   Toujours la même règle : aucune valeur en dur, uniquement des rôles.
   ═══════════════════════════════════════════════════════════════════════════ */

@keyframes xx-tourne { to { transform: rotate(360deg); } }
@keyframes xx-glisse { to { background-position-x: -200%; } }
@keyframes xx-surgit { from { opacity: 0; transform: translateY(6px); } }

/* ── Entrée d'une surface ────────────────────────────────────────────────
   Une zone qui apparaît arrive de son bord, en glissant et en se révélant :
   panneau de réglages, tiroir, et demain toute surface qu'on montre. Posée
   sur l'élément qu'on AFFICHE (hidden → visible) : l'animation rejoue à
   chaque apparition, jamais quand seul son contenu change. La distance se
   règle par --entree-distance (24px ; 100% pour traverser l'écran). */
@keyframes xx-entre-droite { from { opacity: 0; transform: translateX(var(--entree-distance, 24px)); } }
@keyframes xx-entre-gauche { from { opacity: 0; transform: translateX(calc(-1 * var(--entree-distance, 24px))); } }
@keyframes xx-entre-bas    { from { opacity: 0; transform: translateY(var(--entree-distance, 24px)); } }
.entree-droite { animation: xx-entre-droite var(--dur-lent) var(--ease) both; }
.entree-gauche { animation: xx-entre-gauche var(--dur-lent) var(--ease) both; }
.entree-bas    { animation: xx-entre-bas var(--dur-lent) var(--ease) both; }
@keyframes xx-entre-haut { from { opacity: 0; transform: translateY(calc(-1 * var(--entree-distance, 24px))); } }
.entree-haut   { animation: xx-entre-haut var(--dur-lent) var(--ease) both; }
/* Un fondu court, sans déplacement : un contenu qui en remplace un autre. */
.entree-fondu  { animation: xx-surgit var(--dur) var(--ease) both; }
/* La sortie, symétrique et plus brève : ce qui part ne doit pas retenir
   l'attention. Posée par SIMONE_mouvement.cacher() (ressources/admin/
   mouvement.js), qui ne cache l'élément qu'une fois l'animation finie. */
@keyframes xx-sort-droite { to { opacity: 0; transform: translateX(var(--entree-distance, 24px)); } }
@keyframes xx-sort-gauche { to { opacity: 0; transform: translateX(calc(-1 * var(--entree-distance, 24px))); } }
@keyframes xx-sort-bas    { to { opacity: 0; transform: translateY(var(--entree-distance, 24px)); } }
.entree-droite.est-sortant { animation: xx-sort-droite var(--dur) var(--ease-sortie) both; }
.entree-gauche.est-sortant { animation: xx-sort-gauche var(--dur) var(--ease-sortie) both; }
.entree-bas.est-sortant    { animation: xx-sort-bas var(--dur) var(--ease-sortie) both; }
@keyframes xx-sort-haut { to { opacity: 0; transform: translateY(calc(-1 * var(--entree-distance, 24px))); } }
.entree-haut.est-sortant   { animation: xx-sort-haut var(--dur) var(--ease-sortie) both; }

/* ── Boutons : désactivé et chargement ───────────────────────────────────── */
.btn:disabled, .btn[aria-disabled="true"] {
  background: var(--surface-2); color: var(--text-subtle);
  border-color: var(--border); box-shadow: none;
  cursor: not-allowed; transform: none;
}
.btn.est-occupe { position: relative; color: transparent; pointer-events: none; }
.btn.est-occupe > * { visibility: hidden; }
.btn.est-occupe::after {
  content: ""; position: absolute; width: 15px; height: 15px;
  border: 2px solid currentColor; border-top-color: transparent;
  border-radius: var(--radius-full);
  animation: xx-tourne .7s linear infinite;
  visibility: visible;
}
.btn-primary.est-occupe::after { color: var(--accent-text); }
.btn-secondary.est-occupe::after, .btn-ghost.est-occupe::after { color: var(--text-muted); }
.btn-danger.est-occupe::after { color: var(--danger-text); }

/* ── Lien ────────────────────────────────────────────────────────────────── */
.lien {
  color: var(--accent); text-decoration: underline;
  text-underline-offset: 2px; text-decoration-thickness: 1px;
  text-decoration-color: color-mix(in srgb, var(--accent) 35%, transparent);
  transition: text-decoration-color var(--dur-fast) var(--ease);
}
.lien:hover { text-decoration-color: currentColor; }

/* ── Champ : préfixe, suffixe, compteur ──────────────────────────────────── */
.champ-groupe {
  display: flex; align-items: stretch;
  border: var(--border-w) solid var(--border-strong);
  border-radius: var(--radius-md); background: var(--surface);
  transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
.champ-groupe:focus-within { border-color: var(--accent); box-shadow: none; }
.champ-groupe .input { border: none; box-shadow: none; background: transparent; }
.champ-groupe .input:focus { box-shadow: none; }
.champ-groupe .affixe {
  display: flex; align-items: center; padding: 0 var(--space-3);
  color: var(--text-subtle); font-size: 13px; white-space: nowrap;
  background: var(--surface-2);
}
.champ-groupe .affixe:first-child { border-right: var(--filet-w) solid var(--border);
  border-radius: calc(var(--radius-md) - 1px) 0 0 calc(var(--radius-md) - 1px); }
.champ-groupe .affixe:last-child { border-left: var(--filet-w) solid var(--border);
  border-radius: 0 calc(var(--radius-md) - 1px) calc(var(--radius-md) - 1px) 0; }

.field .pied { display: flex; align-items: center; gap: var(--space-3); }
.field .pied .help { flex: 1; }
/* Un libellé accompagné (lien « Oublié ? », compteur) vit dans .pied : il garde
   son style de libellé et pousse son voisin à droite. */
.field .pied > label { flex: 1; min-width: 0; }
.field .compteur { font-family: var(--font-num); font-size: 12px;
                   color: var(--text-subtle); font-variant-numeric: tabular-nums; }
.field .compteur.est-limite { color: var(--danger); font-weight: 600; }
.input[readonly] { background: var(--surface-2); color: var(--text-muted); }
.input.est-ok { border-color: var(--ok); }

/* ── Case indéterminée ───────────────────────────────────────────────────── */
.check:indeterminate { background: var(--accent); border-color: var(--accent); }
.check:indeterminate::after {
  content: ""; width: 9px; height: 2px; background: var(--accent-text); border: none; transform: none;
}
.check:disabled, .radio:disabled, .switch input:disabled + .track {
  background: var(--surface-2); border-color: var(--border); cursor: not-allowed;
}
/* Coché mais non modifiable (imposé par un autre réglage) : l'état se lit encore. */
.check:checked:disabled, .switch input:checked:disabled + .track {
  background: color-mix(in srgb, var(--accent) 45%, var(--surface-2)); border-color: transparent;
}

/* ── Curseur ─────────────────────────────────────────────────────────────── */
.curseur { width: 100%; appearance: none; background: transparent; height: 20px; }
.curseur::-webkit-slider-runnable-track {
  height: 4px; border-radius: var(--radius-full); background: var(--surface-sunken);
}
.curseur::-webkit-slider-thumb {
  appearance: none; width: 16px; height: 16px; margin-top: -6px;
  border-radius: var(--radius-full); background: var(--accent);
  border: 2px solid var(--surface); box-shadow: var(--shadow-sm);
}
.curseur:focus-visible::-webkit-slider-thumb { box-shadow: var(--focus-ring); }

/* ── Badge numérique et étiquette ────────────────────────────────────────── */
.badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 18px; height: 18px; padding: 0 5px;
  border-radius: var(--radius-full);
  background: var(--accent); color: var(--accent-text);
  font-family: var(--font-num); font-size: 11px; font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.badge-neutre { background: var(--surface-sunken); color: var(--text-muted); }
.badge-point { min-width: 8px; width: 8px; height: 8px; padding: 0; }

.etiquette {
  display: inline-flex; align-items: center; gap: 5px;
  height: 26px; padding: 0 var(--space-1) 0 var(--space-3);
  border-radius: var(--radius-pill);
  background: var(--surface-2); color: var(--text);
  border: var(--filet-w) solid var(--border);
  font-size: 12.5px; font-weight: 500;
}
.etiquette button {
  display: grid; place-items: center; width: 18px; height: 18px;
  border-radius: var(--radius-full); color: var(--text-subtle);
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.etiquette button:hover { background: var(--danger-soft); color: var(--danger-soft-text); }
.etiquette button i { font-size: 12px; }

/* ── Onglets ─────────────────────────────────────────────────────────────── */
.onglets { display: flex; gap: var(--space-5); border-bottom: var(--filet-w) solid var(--border); }
.onglets button {
  position: relative; padding: 0 0 var(--space-3);
  font-size: 14px; font-weight: 500; color: var(--text-muted);
  transition: color var(--dur-fast) var(--ease);
}
.onglets button::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 2px;
  background: var(--accent); border-radius: var(--radius-full);
  transform: scaleX(0); transition: transform var(--dur) var(--ease);
}
.onglets button:hover { color: var(--text); }
.onglets button.est-courant { color: var(--text); font-weight: 600; }
.onglets button.est-courant::after { transform: scaleX(1); }
.onglets .badge { margin-left: 6px; }

/* ── Progression, squelette, rotation ────────────────────────────────────── */
.progression {
  display: block;
  height: 6px; border-radius: var(--radius-full);
  background: var(--surface-sunken); overflow: hidden;
}
.progression > span {
  display: block; height: 100%; background: var(--accent);
  border-radius: var(--radius-full);
  transition: width var(--dur) var(--ease);
}
.progression.est-indetermine > span {
  width: 40%; animation: xx-glisse 1.2s linear infinite;
  background: linear-gradient(90deg, transparent, var(--accent), transparent);
  background-size: 200% 100%;
}
.squelette {
  display: block;
  border-radius: var(--radius-sm);
  background: linear-gradient(90deg, var(--surface-2) 25%, var(--surface-sunken) 37%, var(--surface-2) 63%);
  background-size: 200% 100%;
  animation: xx-glisse 1.4s ease-in-out infinite;
}
.rotation { display: inline-block; animation: xx-tourne .8s linear infinite; }

/* ── Message ─────────────────────────────────────────────────────────────── */
.message {
  display: flex; gap: var(--space-3); padding: var(--space-4);
  border-radius: var(--radius-md); font-size: 13.5px; line-height: 1.55;
  background: var(--surface-2); color: var(--text);
}
.message > i { font-size: var(--icon-md); flex: none; }
.message .grow { flex: 1; min-width: 0; }
.message b { display: block; margin-bottom: 2px; }
.message-info   { background: var(--info-soft);   color: var(--info-soft-text); }
.message-ok     { background: var(--ok-soft);     color: var(--ok-soft-text); }
.message-warn   { background: var(--warn-soft);   color: var(--warn-soft-text); }
.message-danger { background: var(--danger-soft); color: var(--danger-soft-text); }
.message p { color: var(--text); opacity: .85; }

/* ── Notification ────────────────────────────────────────────────────────── */
.notification {
  display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--surface-inverse); color: var(--text-inverse);
  border-radius: var(--radius-md); box-shadow: var(--shadow-lg);
  font-size: 13.5px; animation: xx-surgit var(--dur) var(--ease);
}
.notification i { font-size: var(--icon-md); }
.notification .grow { flex: 1; }
.notification button { color: currentColor; opacity: .7; }
.notification button:hover { opacity: 1; }

/* ── Infobulle ───────────────────────────────────────────────────────────── */
.infobulle { position: relative; display: inline-flex; }
.infobulle::after {
  content: attr(data-bulle); position: absolute; bottom: calc(100% + 8px); left: 50%;
  transform: translateX(-50%); white-space: nowrap;
  padding: 5px var(--space-2); border-radius: var(--radius-sm);
  background: var(--surface-inverse); color: var(--text-inverse);
  font-size: 12px; font-weight: 500; box-shadow: var(--shadow-md);
  opacity: 0; pointer-events: none; transition: opacity var(--dur-fast) var(--ease);
}
.infobulle:hover::after, .infobulle:focus-within::after { opacity: 1; }

/* ── Menu déroulant ──────────────────────────────────────────────────────── */
.menu {
  min-width: 190px; padding: var(--space-1);
  background: var(--surface); border: var(--filet-w) solid var(--border);
  border-radius: var(--radius-md); box-shadow: var(--shadow-lg);
}
.menu-item {
  display: flex; align-items: center; gap: var(--space-3); width: 100%;
  height: var(--control-h-sm); padding: 0 var(--space-3);
  border-radius: var(--radius-sm); font-size: 13.5px; color: var(--text);
  transition: background var(--dur-fast) var(--ease);
}
.menu-item i { font-size: var(--icon-sm); color: var(--text-subtle); }
.menu-item:hover { background: var(--surface-2); }
.menu-item .raccourci { margin-left: auto; font-family: var(--font-mono);
                        font-size: 11px; color: var(--text-subtle); }
.menu-item.est-danger { color: var(--danger); }
.menu-item.est-danger i { color: var(--danger); }
.menu-item.est-danger:hover { background: var(--danger-soft); }
.menu-sep { display: block; height: 1px; margin: var(--space-1) 0; background: var(--border); }
.menu-titre { padding: var(--space-2) var(--space-3) var(--space-1); font-size: 11px;
              font-weight: 600; text-transform: uppercase; letter-spacing: .08em;
              color: var(--text-subtle); }

/* ── Panneau latéral ─────────────────────────────────────────────────────── */
.panneau {
  width: 340px; display: flex; flex-direction: column;
  background: var(--surface); border-left: var(--filet-w) solid var(--border);
  box-shadow: var(--shadow-lg);
}
.panneau-head { display: flex; align-items: center; gap: var(--space-3);
                padding: var(--space-4) var(--pad-card);
                border-bottom: var(--filet-w) solid var(--border); }
.panneau-head .grow { flex: 1; min-width: 0; }
.panneau-corps { padding: var(--pad-card); display: flex; flex-direction: column; gap: var(--gap-form); }

/* ── Tableau : tri, sélection groupée ────────────────────────────────────── */
thead th.tri { cursor: pointer; user-select: none; }
thead th.tri span { display: inline-flex; align-items: center; gap: 4px; }
thead th.tri i { font-size: 12px; opacity: .35; transition: opacity var(--dur-fast) var(--ease); }
thead th.tri:hover i { opacity: .7; }
thead th.tri.est-actif { color: var(--text); }
thead th.tri.est-actif i { opacity: 1; color: var(--accent); }

.barre-selection {
  display: flex; align-items: center; gap: var(--space-3);
  height: var(--th-h); padding: 0 var(--space-4);
  background: var(--accent-soft); color: var(--accent-soft-text);
  border-bottom: var(--filet-w) solid var(--border);
  font-size: 13px; font-weight: 600;
}
.barre-selection .grow { flex: 1; }

/* Sous sélection, la barre prend la place de l'en-tête sans rien déplacer.
   On masque le thead en visibility, jamais en display : il continue de fixer
   les largeurs de colonnes. */
.table-wrap { position: relative; }
.table-wrap.avec-selection thead th { visibility: hidden; }
.table-wrap.avec-selection .barre-selection {
  position: absolute; top: 0; left: 0; right: 0; z-index: 1;
}

/* ── Pagination ──────────────────────────────────────────────────────────── */
.pagination { display: flex; align-items: center; gap: var(--space-1); }
.pagination button {
  min-width: var(--control-h-sm); height: var(--control-h-sm); padding: 0 var(--space-2);
  border-radius: var(--radius-sm); font-family: var(--font-num); font-size: 13px;
  color: var(--text-muted); font-variant-numeric: tabular-nums;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.pagination button:hover:not(:disabled) { background: var(--surface-2); color: var(--text); }
.pagination button.est-courant { background: var(--accent); color: var(--accent-text); font-weight: 600; }
.pagination button:disabled { opacity: .35; cursor: not-allowed; }
.pagination .ecart { color: var(--text-subtle); padding: 0 var(--space-1); }

/* ── Avatars groupés ─────────────────────────────────────────────────────── */
.avatars { display: inline-flex; }
.avatars .avatar { border: 2px solid var(--surface); }
.avatars .avatar + .avatar { margin-left: -9px; }
.avatars .avatar:last-child { background: var(--surface-sunken); color: var(--text-muted); }

/* ── Accordéon ───────────────────────────────────────────────────────────── */
.accordeon { border: var(--filet-w) solid var(--border); border-radius: var(--radius-lg);
             overflow: hidden; background: var(--surface); }
.accordeon-item + .accordeon-item { border-top: var(--filet-w) solid var(--border); }
.accordeon-tete {
  display: flex; align-items: center; gap: var(--space-3); width: 100%;
  padding: var(--space-4) var(--pad-card); font-size: 14px; font-weight: 600; text-align: left;
  transition: background var(--dur-fast) var(--ease);
}
.accordeon-tete:hover { background: var(--surface-2); }
.accordeon-tete .grow { flex: 1; }
.accordeon-tete i { font-size: var(--icon-sm); color: var(--text-subtle);
                    transition: transform var(--dur) var(--ease); }
.accordeon-item.est-ouvert .accordeon-tete i { transform: rotate(180deg); }
.accordeon-corps { padding: 0 var(--pad-card) var(--space-5);
                   font-size: 13.5px; color: var(--text-muted); line-height: 1.6; }

/* ── Zone de dépôt ───────────────────────────────────────────────────────── */
.depot {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--space-2); padding: var(--space-10) var(--space-6); text-align: center;
  border: 2px dashed var(--border-strong); border-radius: var(--radius-lg);
  background: var(--surface-2); color: var(--text-muted);
  transition: border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.depot i { font-size: 30px; color: var(--text-subtle); }
.depot b { color: var(--text); font-size: 14px; }
.depot.est-survole { border-color: var(--accent); background: var(--accent-soft); }
/* Un fichier est choisi : le trait cesse d'être en pointillés — il n'y a
   plus rien à y déposer, il y a quelque chose dedans. */
.depot.est-choisi { border-style: solid; border-color: var(--accent); }
.depot.est-choisi i { color: var(--accent); }
.depot:focus-visible { border-color: var(--accent); }

/* Les archives déposées par FTP (Réglages → Sauvegarde) : une ligne par archive —
   le nom et ce qu'on en sait à gauche, les gestes à droite, qui passent dessous
   quand la carte est étroite. Pas un tableau : quatre colonnes ne tiennent pas
   dans une carte de réglages (le nom se coupait au tiret, le bouton sortait). */
.depot-liste { list-style: none; margin: 0; padding: 0; border: var(--filet-w) solid var(--border); border-radius: var(--radius-md); }
.depot-rang { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-4); padding: var(--space-3) var(--space-4); }
.depot-rang + .depot-rang { border-top: var(--filet-w) solid var(--border); }
.depot-corps { flex: 1 1 15rem; min-width: 0; display: flex; flex-direction: column; gap: var(--space-1); }
.depot-nom { overflow-wrap: anywhere; font-size: 13px; }
.depot-meta { font-size: 12px; color: var(--text-subtle); }
.depot-meta.est-erreur { color: var(--danger); }
.depot-gestes { display: flex; align-items: center; gap: var(--space-2); }
.depot-gestes form { margin: 0; }

/* ── La double authentification ─────────────────────────────────────────────
   Le champ du code : gros, à chasse fixe, chiffres bien espacés — on le lit sur
   un téléphone posé à côté, et on le recopie en trente secondes. */
.code-champ { font-family: var(--font-mono); font-size: 20px; letter-spacing: .22em; text-align: center; }
.code-champ::placeholder { letter-spacing: .22em; opacity: .45; }
/* L'inscription : deux étapes numérotées. Le QR code est TOUJOURS foncé sur
   blanc (le dessin se fait dans le navigateur, avec son fond et sa marge) :
   un QR clair sur sombre ne se lit pas, et le mode sombre ne doit pas s'y
   inviter. */
.facteur-etapes { margin: 0; padding-left: var(--space-5); display: flex; flex-direction: column; gap: var(--space-5); }
.facteur-etapes > li { padding-left: var(--space-1); }
.facteur-qr { display: block; width: 200px; max-width: 100%; aspect-ratio: 1; margin: var(--space-3) auto var(--space-2);
  background: #fff; border: var(--filet-w) solid var(--border); border-radius: var(--radius-md); overflow: hidden; }
.facteur-qr svg { display: block; width: 100%; height: 100%; }
.facteur-qr:empty { display: none; }
.facteur-ouvrir { display: block; font-size: 13px; text-align: center; margin-bottom: var(--space-1); }
/* « 482 913 » : de quoi ressemble ce qu'on cherche. */
.facteur-exemple { display: inline-block; padding: 0 var(--space-2); border-radius: var(--radius-sm, 4px); background: var(--surface-2);
  font-family: var(--font-mono); letter-spacing: .12em; white-space: nowrap; }
/* Ce que fait l'application après le scan — l'étape qui manquait. */
.facteur-aide-appli { display: flex; gap: var(--space-3); margin-top: var(--space-3); padding: var(--space-3); font-size: 13px; line-height: 1.5;
  background: var(--surface-2); border-radius: var(--radius-md); }
.facteur-aide-appli > i { flex: none; font-size: 20px; color: var(--accent); margin-top: 1px; }
.facteur-cle { margin-top: var(--space-2); }
.facteur-cle summary { cursor: pointer; font-size: 13px; color: var(--accent); }
.facteur-cle-corps { display: flex; flex-direction: column; gap: var(--space-2); margin-top: var(--space-2); }
.facteur-cle-corps > * { margin: 0; }
/* La clé se coupe ENTRE ses groupes de quatre, jamais au milieu d'un. */
.facteur-cle-valeur { min-height: 0; resize: none; line-height: 1.6; letter-spacing: .04em; word-break: normal; overflow-wrap: normal; }
/* Les codes de secours : deux colonnes, à chasse fixe, faciles à recopier. */
.secours-liste { list-style: none; margin: 0; padding: var(--space-3); display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-2) var(--space-4);
  background: var(--surface-2); border-radius: var(--radius-md); }
.secours-liste code { font-size: 15px; letter-spacing: .06em; }

/* ── Illustration ────────────────────────────────────────────────────────
   Toujours du SVG bâti sur les tokens, jamais une image matricielle : un PNG
   ne sait pas changer de mode. La hauteur pilote, la largeur suit. */
.illustration { display: block; color: var(--text-subtle); }
.illustration svg { display: block; height: var(--h, 120px); width: auto; }
.illustration .accent { color: var(--accent); }

/* ── État vide ───────────────────────────────────────────────────────────── */
.vide { display: flex; flex-direction: column; align-items: center; gap: var(--space-3);
        padding: var(--space-16) var(--space-6); text-align: center; }
.vide > i { font-size: 34px; color: var(--text-subtle); }
.vide p { color: var(--text-muted); max-width: 42ch; }
.vide .btn { margin-top: var(--space-2); }

/* ── Mot-symbole posé dans une interface ─────────────────────────────────
   Le tracé est en currentColor et sans dimension propre : c'est la hauteur qui
   pilote, la largeur suit. Règle promue depuis la page Marque au moment où un
   deuxième écran en a eu besoin. */
.logo { display: inline-block; line-height: 0; color: inherit; }
.logo svg { display: block; height: var(--h, 20px); width: auto; }

/* ── Séparateur ──────────────────────────────────────────────────────────── */
.separateur { display: block; height: 1px; background: var(--border); border: none; }
.separateur-titre { display: flex; align-items: center; gap: var(--space-3);
                    color: var(--text-subtle); font-size: 11px; font-weight: 600;
                    text-transform: uppercase; letter-spacing: .08em; }
.separateur-titre::before, .separateur-titre::after {
  content: ""; flex: 1; height: 1px; background: var(--border);
}

/* ═══════════════════════════════════════════════════════════════════════════
   ÉDITEUR DE TEXTE RICHE
   Il produit de la STRUCTURE, pas du style. Aucun choix de police, de corps
   ni de couleur : ces décisions appartiennent au thème, pas au contenu.
   ═══════════════════════════════════════════════════════════════════════════ */

.editeur {
  border: var(--filet-w) solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  /* clip et non hidden : hidden fait de l'éditeur un conteneur de défilement,
     et la barre « sticky » ne collerait plus qu'à lui — c'est-à-dire jamais. */
  overflow: clip;
}

/* ── Barre d'outils fixe ─────────────────────────────────────────────────── */
.editeur-barre {
  position: sticky; top: 0; z-index: 3;
  display: flex; align-items: center; gap: var(--space-1); flex-wrap: wrap;
  padding: var(--space-2) var(--space-3);
  background: var(--surface);
  border-bottom: var(--filet-w) solid var(--border);
}
.barre-groupe { display: flex; align-items: center; gap: 2px; }
.barre-groupe + .barre-groupe::before {
  content: ""; width: 1px; height: 18px; margin: 0 var(--space-2);
  background: var(--border);
}
.outil {
  display: grid; place-items: center;
  width: var(--control-h-sm); height: var(--control-h-sm);
  border-radius: var(--radius-sm); color: var(--text-muted);
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.outil i { font-size: var(--icon-sm); }
.outil:hover { background: var(--surface-2); color: var(--text); }
.outil.est-actif { background: var(--accent-soft); color: var(--accent-soft-text); }
.outil:disabled { color: var(--text-subtle); opacity: .45; cursor: not-allowed; background: none; }
.outil-large { width: auto; padding: 0 var(--space-3); gap: var(--space-2);
               grid-auto-flow: column; font-size: 13px; font-weight: 500; }

/* ── Corps rédactionnel ──────────────────────────────────────────────────── */
.editeur-corps { padding: var(--space-8) var(--space-10) var(--space-16); }
.prose { max-width: 62ch; margin: 0 auto; outline: none; }
/* Pas d'anneau de focus sur un corps de texte : le curseur dit déjà où l'on est,
   et l'anneau encadrerait toute la page rédigée. */
.prose:focus-visible { box-shadow: none; }
.prose:empty::before,
.prose > p:only-child:empty::before {
  content: attr(data-vide); color: var(--text-subtle); pointer-events: none;
}
.prose > * + * { margin-top: var(--space-4); }
.prose h2 { font-family: var(--font-display); font-size: 22px; font-weight: var(--display-weight);
            letter-spacing: var(--display-tracking); line-height: 1.25; margin-top: var(--space-8); }
.prose h3 { font-family: var(--font-display); font-size: 17px; font-weight: 600;
            letter-spacing: var(--display-tracking); line-height: 1.35; margin-top: var(--space-6); }
.prose p { line-height: 1.7; }
.prose ul, .prose ol { padding-left: var(--space-6); line-height: 1.7; }
.prose ul { list-style: disc; }
.prose ol { list-style: decimal; }
.prose li + li { margin-top: var(--space-2); }
.prose blockquote {
  border-left: 3px solid var(--accent); padding-left: var(--space-5);
  color: var(--text-muted); font-size: 16px;
}
.prose a { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }
.prose code { font-family: var(--font-mono); font-size: .88em;
              background: var(--surface-2); padding: 2px 5px; border-radius: var(--radius-sm); }
.prose pre { background: var(--surface-inverse); color: var(--text-inverse);
             padding: var(--space-4); border-radius: var(--radius-md); overflow-x: auto; }
.prose pre code { background: none; padding: 0; color: inherit; }
.prose hr { border: none; height: 1px; background: var(--border); margin: var(--space-8) 0; }
.prose figure { margin-top: var(--space-6); }
.prose figure img { width: 100%; border-radius: var(--radius-md); display: block; }
.prose figcaption { margin-top: var(--space-2); font-size: 13px; color: var(--text-subtle); text-align: center; }
.prose mark { background: var(--warn-soft); color: var(--warn-soft-text);
              padding: 1px 3px; border-radius: 3px; }
.prose ::selection { background: var(--accent-soft); }

/* ── Poignée de bloc ─────────────────────────────────────────────────────── */
.bloc-rang { position: relative; }
.bloc-outils {
  position: absolute; top: 2px; right: calc(100% + var(--space-3));
  display: flex; gap: 2px; opacity: 0;
  transition: opacity var(--dur-fast) var(--ease);
}
.bloc-rang:hover .bloc-outils, .bloc-rang:focus-within .bloc-outils { opacity: 1; }
.bloc-outils button {
  display: grid; place-items: center; width: 24px; height: 24px;
  border-radius: var(--radius-sm); color: var(--text-subtle);
}
.bloc-outils button:hover { background: var(--surface-2); color: var(--text); }
.bloc-outils i { font-size: var(--icon-sm); }

/* ── Barre flottante de sélection ────────────────────────────────────────── */
.barre-flottante {
  position: fixed; z-index: 40;
  display: flex; align-items: center; gap: 2px; padding: var(--space-1);
  background: var(--surface-inverse); border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  opacity: 0; pointer-events: none;
  transform: translate(-50%, -4px);
  transition: opacity var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.barre-flottante.est-visible { opacity: 1; pointer-events: auto; transform: translate(-50%, -8px); }
.barre-flottante .outil { color: var(--text-inverse); opacity: .75; }
.barre-flottante .outil:hover { background: color-mix(in srgb, var(--text-inverse) 16%, transparent); opacity: 1; }
.barre-flottante .outil.est-actif { background: var(--accent); color: var(--accent-text); opacity: 1; }
.barre-flottante .barre-groupe + .barre-groupe::before {
  background: color-mix(in srgb, var(--text-inverse) 25%, transparent);
}

/* ── Sélecteur de blocs ──────────────────────────────────────────────────── */
.menu-blocs {
  position: absolute; z-index: 30; width: 260px; max-height: 320px; overflow-y: auto;
  padding: var(--space-1);
  background: var(--surface); border: var(--filet-w) solid var(--border);
  border-radius: var(--radius-md); box-shadow: var(--shadow-lg);
}
.bloc-choix {
  display: flex; align-items: center; gap: var(--space-3); width: 100%;
  padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm); text-align: left;
  transition: background var(--dur-fast) var(--ease);
}
.bloc-choix:hover, .bloc-choix.est-survole { background: var(--surface-2); }
.bloc-choix .vignette {
  display: grid; place-items: center; width: 30px; height: 30px; flex: none;
  border-radius: var(--radius-sm); background: var(--surface-2);
  border: var(--filet-w) solid var(--border); color: var(--text-muted);
}
.bloc-choix .vignette i { font-size: var(--icon-sm); }
.bloc-choix b { display: block; font-size: 13px; font-weight: 600; }
.bloc-choix span { font-size: 11.5px; color: var(--text-subtle); }

/* ── Réglage d'un lien ───────────────────────────────────────────────────── */
.popover-lien {
  position: fixed; z-index: 40; width: 320px; padding: var(--space-3);
  display: flex; flex-direction: column; gap: var(--space-2);
  background: var(--surface); border: var(--filet-w) solid var(--border);
  border-radius: var(--radius-md); box-shadow: var(--shadow-lg);
  transform: translateX(-50%);
}
.popover-lien .ligne { display: flex; gap: var(--space-2); align-items: center; }
.popover-lien .input { height: var(--control-h-sm); font-size: 13px; }

/* ── Pied rédactionnel ───────────────────────────────────────────────────── */
.editeur-pied {
  display: flex; align-items: center; gap: var(--space-4);
  padding: var(--space-2) var(--space-4);
  border-top: var(--filet-w) solid var(--border);
  background: var(--surface-2);
  font-size: 12px; color: var(--text-subtle);
}
.editeur-pied .grow { flex: 1; }
.editeur-pied .num { font-family: var(--font-num); font-variant-numeric: tabular-nums; }

/* ═══════════════════════════════════════════════════════════════════════════
   SÉLECTEUR DE MÉDIAS
   Un seul composant pour trois usages : insérer dans l'éditeur, remplir un
   champ image, composer une galerie. Ce qui change est le pied, jamais le corps.
   ═══════════════════════════════════════════════════════════════════════════ */

.mediatheque {
  display: grid; grid-template-columns: 1fr 300px; grid-template-rows: auto 1fr auto;
  grid-template-areas: "barre barre" "corps panneau" "pied pied";
  height: var(--hauteur, 560px); overflow: hidden;
  background: var(--surface);
  border: var(--filet-w) solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
}
.mediatheque.sans-panneau { grid-template-columns: 1fr; grid-template-areas: "barre" "corps" "pied"; }

.mt-barre {
  grid-area: barre; display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-bottom: var(--filet-w) solid var(--border);
}
.mt-barre .grow { flex: 1; min-width: 0; }

.mt-corps { grid-area: corps; overflow-y: auto; padding: var(--space-4); position: relative; }

.mt-panneau {
  grid-area: panneau; overflow-y: auto;
  border-left: var(--filet-w) solid var(--border);
  background: var(--surface-2);
  padding: var(--space-4);
  display: flex; flex-direction: column; gap: var(--gap-form);
}
/* En colonne flex, un enfant se comprime AVANT que le conteneur ne défile :
   un bloc en aspect-ratio y tombe à zéro. Le panneau défile, ses blocs non. */
.mt-panneau > * { flex: none; }

.mt-pied {
  grid-area: pied; display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-top: var(--filet-w) solid var(--border);
  background: var(--surface-2);
}
.mt-pied .grow { flex: 1; font-size: 13px; color: var(--text-muted); }

/* ── Grille ──────────────────────────────────────────────────────────────── */
.mt-grille {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: var(--space-3);
}
.mt-tuile {
  position: relative; border-radius: var(--radius-md); overflow: hidden;
  border: 2px solid transparent; background: var(--surface-2);
  text-align: left; transition: border-color var(--dur-fast) var(--ease);
}
.mt-tuile .apercu {
  aspect-ratio: 1; display: grid; place-items: center; overflow: hidden;
  background: var(--surface-sunken); color: var(--text-subtle);
}
.mt-tuile .apercu img, .mt-rang .vignette img {
  width: 100%; height: 100%; object-fit: cover; display: block;
}
.mt-tuile .apercu i { font-size: 24px; }
/* display:block obligatoire : <b> est un bloc, et un bloc dans un élément en
   ligne s'en échappe — le padding du <span> ne s'applique alors plus au titre. */
.mt-tuile .legende { display: block; padding: var(--space-3); }
.mt-tuile b { display: block; font-size: 12.5px; font-weight: 500;
              overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mt-tuile span { font-family: var(--font-num); font-size: 11px; color: var(--text-subtle); }
.mt-tuile:hover { border-color: var(--border-strong); }
.mt-tuile.est-choisi { border-color: var(--accent); }

.mt-marque {
  position: absolute; top: var(--space-2); left: var(--space-2);
  width: 20px; height: 20px; border-radius: var(--radius-full);
  display: grid; place-items: center;
  background: var(--surface); border: var(--border-w) solid var(--border-strong);
  color: transparent; font-family: var(--font-num); font-size: 11px; font-weight: 700;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.mt-tuile.est-choisi .mt-marque { background: var(--accent); border-color: var(--accent); color: var(--accent-text); }

.mt-alerte {
  position: absolute; top: var(--space-2); right: var(--space-2);
  width: 20px; height: 20px; border-radius: var(--radius-full);
  display: grid; place-items: center;
  background: var(--warn); color: var(--warn-soft);
}
.mt-alerte i { font-size: 12px; }

/* ── Liste ───────────────────────────────────────────────────────────────── */
.mt-liste { display: flex; flex-direction: column; }
.mt-rang {
  display: flex; align-items: center; gap: var(--space-3); width: 100%;
  padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm);
  text-align: left; transition: background var(--dur-fast) var(--ease);
}
.mt-rang:hover { background: var(--surface-2); }
.mt-rang.est-choisi { background: var(--accent-soft); }
.mt-rang .vignette {
  width: 38px; height: 38px; flex: none; border-radius: var(--radius-sm);
  background: var(--surface-sunken); display: grid; place-items: center;
  color: var(--text-subtle); overflow: hidden;
}
.mt-rang .grow { flex: 1; min-width: 0; }
.mt-rang b { display: block; font-size: 13px; font-weight: 500;
             overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mt-rang .meta { font-family: var(--font-num); font-size: 11.5px; color: var(--text-subtle); }

/* ── Grille justifiée (façon Blok) ───────────────────────────────────────
   Écran Médias et fenêtre de choix : chaque image garde ses proportions, en
   rangées de même hauteur qui remplissent la largeur (calculées par
   medias.js, cinq tailles). Pas de légende sous l'image : la marque, l'alerte
   et le poids se posent dessus ; le nom est au survol et en vue liste. */
.mt-justifiee { display: flex; flex-wrap: wrap; gap: 6px; align-content: flex-start; }
.mt-bloc {
  position: relative; display: block; flex: none; padding: 0; overflow: hidden; cursor: pointer;
  border-radius: var(--radius-sm); border: var(--filet-w) solid var(--border); background: var(--surface-2);
}
.mt-justifiee.anime .mt-bloc { transition: width .3s var(--ease), height .3s var(--ease); }
.mt-bloc img { display: block; width: 100%; height: 100%; object-fit: cover; }
.mt-bloc-doc { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; width: 100%; height: 100%; color: var(--text-subtle); }
.mt-bloc-doc i { font-size: 26px; }
.mt-bloc-doc span { font-size: 10px; font-weight: 600; letter-spacing: .08em; }
.mt-bloc:hover { border-color: var(--border-strong); }
.mt-bloc:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.mt-bloc.est-choisi { border: 2px solid var(--accent); }
.mt-bloc.est-ouvert { outline: 2px solid var(--accent); outline-offset: 2px; }
.mt-bloc .mt-marque {
  position: absolute; top: 6px; left: 6px; width: 20px; height: 20px; border-radius: 50%; display: grid; place-items: center;
  background: rgb(0 0 0 / .45); border: 1.5px solid rgb(255 255 255 / .75); color: #fff; font-size: 11px; font-weight: 600;
  opacity: 0; transition: opacity var(--dur-fast) var(--ease);
}
.mt-bloc:hover .mt-marque, .mt-bloc.est-choisi .mt-marque { opacity: 1; }
.mt-bloc.est-choisi .mt-marque { background: var(--accent); border-color: var(--accent); }
.mt-bloc .mt-alerte {
  position: absolute; top: 6px; right: 6px; width: 20px; height: 20px; border-radius: 50%; display: grid; place-items: center;
  background: rgb(0 0 0 / .5); color: #f4b740; font-size: 12px;
}
.mt-bloc .mt-poids {
  position: absolute; right: 5px; bottom: 5px; padding: 1px 5px; border-radius: 3px; pointer-events: none;
  background: rgb(0 0 0 / .55); color: rgb(255 255 255 / .85); font-family: var(--font-num); font-size: 10px;
}
.mt-taille { display: inline-flex; align-items: center; gap: 6px; flex: none; color: var(--text-subtle); }
.mt-taille[hidden] { display: none; }
.mt-taille input { width: 90px; }

/* ── Filtres rapides ─────────────────────────────────────────────────────
   Une pastille qui se presse (aria-pressed), avec son compte ; elles se
   cumulent. Écran Médias : à compléter, orphelins, lourds, doublons. */
.filtre {
  display: inline-flex; align-items: center; gap: 6px; height: 28px; padding: 0 var(--space-3);
  border-radius: var(--radius-pill); border: var(--filet-w) solid var(--border); background: var(--surface);
  color: var(--text-muted); font: inherit; font-size: 12.5px; font-weight: 500; cursor: pointer; white-space: nowrap; flex-shrink: 0;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.filtre:hover { color: var(--text); border-color: var(--border-strong); }
.filtre:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.filtre.est-actif { background: var(--accent-soft); border-color: var(--accent); color: var(--accent-soft-text); }
.filtre .compte { font-family: var(--font-num); font-size: 11px; opacity: .75; }
/* Filtres et barre de sélection se relaient au même endroit, à la même
   hauteur : cocher une vignette ne déplace pas la grille sous le pointeur.
   Sur l'écran Médias, ils restent en vue sous la barre collée. */
.mt-outils { display: block; height: var(--th-h); margin-bottom: var(--space-4); }
.mt-plein .mt-outils { position: sticky; top: 65px; z-index: 4; height: calc(var(--th-h) + var(--space-4)); margin: calc(-1 * var(--space-2)) 0 var(--space-2);
  padding: var(--space-2) 0; background: var(--bg); }
/* Trop étroit (détail ouvert) : les pastilles défilent de côté plutôt que
   de casser leur libellé. */
.mt-filtres { display: flex; align-items: center; gap: var(--space-2); height: 100%; overflow-x: auto; overflow-y: hidden; scrollbar-width: none; }
.mt-filtres > .btn { flex-shrink: 0; white-space: nowrap; }
.mt-filtres[hidden] { display: none; }
.mt-filtres .grow { flex: 1; }
.mt-selection { height: 100%; border: 0; border-radius: var(--radius-md); }
[data-bilan] .message { margin-bottom: var(--space-4); }

/* Aperçus de recadrage : trois cadres (paysage, portrait, carré) de même
   hauteur, où l'image se place selon le point focal — on voit ce que chaque
   format gardera. */
.mt-recadrages { display: grid; grid-template-columns: 1.78fr .75fr 1fr; gap: var(--space-2); align-items: start; }
.mt-recadrages figure { display: flex; flex-direction: column; gap: 4px; margin: 0; }
.mt-recadrages span { display: block; overflow: hidden; border-radius: var(--radius-sm); border: var(--filet-w) solid var(--border); background: var(--surface-2); }
.mt-recadrages img { display: block; width: 100%; height: 100%; object-fit: cover; }
.mt-recadrages figcaption { font-size: 11px; color: var(--text-subtle); text-align: center; }

/* Écran Médias : plein cadre. La barre de la médiathèque est la barre
   collée, la page défile ; le détail d'un média est un tiroir, ouvert au
   clic, qui pousse la grille (colonne de 0 à sa largeur ; le panneau garde
   sa largeur pleine pendant l'ouverture, rogné par clip). */
.mediatheque.mt-plein {
  flex: 1; height: auto; overflow: clip; border: 0; border-radius: 0; box-shadow: none; background: none;
  grid-template-columns: minmax(0, 1fr) 0px; grid-template-areas: "barre barre" "corps panneau" "pied panneau";
  transition: grid-template-columns var(--dur) var(--ease-sortie);
}
.mediatheque.mt-plein.avec-tiroir {
  grid-template-columns: minmax(0, 1fr) 400px;
  transition-duration: var(--dur-lent); transition-timing-function: var(--ease);
}
.mt-plein .mt-barre { position: sticky; top: 0; z-index: 5; height: 65px; padding: 0 var(--pad-section); background: var(--surface); }
.mt-plein .mt-corps { overflow: visible; padding: var(--space-6) var(--pad-section); }
.mt-plein .mt-panneau {
  position: sticky; top: 65px; align-self: start; width: 400px; min-width: 400px;
  height: calc(100vh - 65px - var(--haut-visible)); overscroll-behavior: contain;
}
.mt-plein .mt-panneau[hidden] { display: none; }
.mt-plein .mt-panneau .entete { display: flex; align-items: center; gap: var(--space-2); }
.mt-plein .mt-panneau .entete b { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 14px; font-weight: 600; }
.mt-plein .mt-pied { padding: var(--space-3) var(--pad-section) var(--space-10); background: none; border-top: 0; }

/* ── Panneau de détail ───────────────────────────────────────────────────── */
/* Le panneau montre l'image ENTIÈRE (contain), jamais recadrée : c'est le seul
   endroit où l'on voit ce qu'on a vraiment. Le recadrage, lui, se règle ici. */
.mt-apercu-grand {
  position: relative; aspect-ratio: 4 / 3; border-radius: var(--radius-md);
  overflow: hidden; background: var(--surface-sunken);
  display: grid; place-items: center; color: var(--text-subtle);
}
.mt-apercu-grand img { width: 100%; height: 100%; object-fit: contain; display: block; }
.mt-apercu-grand.est-reglable { cursor: crosshair; }

.mt-focal {
  position: absolute; width: 22px; height: 22px; margin: -11px 0 0 -11px;
  border-radius: var(--radius-full); border: 2px solid var(--gray-0);
  box-shadow: var(--shadow-md), 0 0 0 1px var(--surface-inverse);
  background: color-mix(in srgb, var(--accent) 55%, transparent);
  pointer-events: none;
}
.mt-focal::after {
  content: ""; position: absolute; inset: 7px; border-radius: var(--radius-full);
  background: var(--gray-0);
}
.mt-faits { display: flex; flex-direction: column; gap: var(--space-1); }
.mt-fait { display: flex; gap: var(--space-3); font-size: 12.5px; }
.mt-fait dt { color: var(--text-subtle); width: 92px; flex: none; }
.mt-fait dd { color: var(--text); font-family: var(--font-num); }

/* ── Panneau : onglets, usages, rendus ───────────────────────────────────── */
.mt-onglets { gap: var(--space-4); margin: 0 calc(var(--space-4) * -1); padding: 0 var(--space-4); }
.mt-onglets button { font-size: 13px; padding-bottom: var(--space-2); }
.mt-onglets .badge { min-width: 15px; height: 15px; font-size: 9.5px; }

.mt-usage {
  display: flex; align-items: center; gap: var(--space-2); width: 100%;
  padding: var(--space-2); border-radius: var(--radius-sm);
  font-size: 12.5px; text-align: left;
}
.mt-usage:hover { background: var(--surface); }
.mt-usage i { font-size: var(--icon-sm); color: var(--text-subtle); flex: none; }
.mt-usage .grow { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Une étiquette minuscule et discrète : le « ou » d'un usage, l'étiquette d'un
   rang de schéma, le nom d'un champ dans Affiner. Même intention, une seule
   place — le cliquet des doublons la comptait trois fois. */
.mt-usage .ou, .sc-rang .etiq, .ap-fin-champs label span { font-size: 11px; color: var(--text-subtle); }

.mt-rendu {
  display: flex; align-items: baseline; gap: var(--space-2);
  font-size: 12px; padding: var(--space-1) 0;
}
.mt-rendu .nom { font-family: var(--font-mono); color: var(--text-muted); width: 92px; flex: none; }
.mt-rendu .poids { font-family: var(--font-num); color: var(--text); }
.mt-rendu .gain { color: var(--ok); font-family: var(--font-num); font-size: 11px; }

/* ── Envois en cours ─────────────────────────────────────────────────────── */
.mt-envois { display: flex; flex-direction: column; gap: var(--space-2);
             margin-bottom: var(--space-4); }
.mt-envoi {
  display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border: var(--filet-w) solid var(--border); border-radius: var(--radius-md);
  background: var(--surface);
}
.mt-envoi .grow { flex: 1; min-width: 0; }
.mt-envoi b { display: block; font-size: 12.5px; font-weight: 500;
              overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mt-envoi .progression { margin-top: 5px; }
/* Un envoi qui échoue EST un message d'erreur : il emprunte .message-danger
   plutôt que de redéfinir les mêmes couleurs une seconde fois. */
.mt-envoi.message { border: none; }
.mt-envoi .msg { font-size: 11.5px; opacity: .9; }

/* ── Voile de dépôt ──────────────────────────────────────────────────────── */
.mt-voile {
  position: absolute; inset: var(--space-3); z-index: 2;
  display: grid; place-items: center;
  border: 2px dashed var(--accent); border-radius: var(--radius-lg);
  background: var(--accent-soft); color: var(--accent-soft-text);
  font-size: 14px; font-weight: 600;
  opacity: 0; pointer-events: none; transition: opacity var(--dur-fast) var(--ease);
}
.mt-voile.est-visible { opacity: 1; }

/* ═══════════════════════════════════════════════════════════════════════════
   CONSTRUCTEUR DE BLOCS
   Le canevas montre le RENDU, pas une abstraction. Les réglages vivent dans le
   panneau : un bloc qui porte ses propres contrôles cesse d'être une page.
   ═══════════════════════════════════════════════════════════════════════════ */

.constructeur {
  display: grid; grid-template-columns: 1fr 300px;
  grid-template-rows: auto 1fr; grid-template-areas: "barre barre" "canevas panneau";
  height: 620px; overflow: hidden;
  background: var(--surface-sunken);
  border: var(--filet-w) solid var(--border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-lg);
}
.cv-barre {
  grid-area: barre; display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--surface); border-bottom: var(--filet-w) solid var(--border);
}
.cv-barre .grow { flex: 1; min-width: 0; }
.cv-barre .titre { font-weight: 600; font-size: 14px; }
.cv-barre .chemin { font-size: 12px; color: var(--text-subtle); }

.cv-canevas { display: block; grid-area: canevas; overflow-y: auto; padding: var(--space-6) var(--space-8) var(--space-16); }
.cv-page {
  max-width: 720px; margin: 0 auto;
  background: var(--surface); border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm); overflow: hidden;
}

/* ── Un bloc ─────────────────────────────────────────────────────────────── */
.cv-bloc { position: relative; cursor: default; }
.cv-bloc::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  border: 2px solid transparent; border-radius: var(--radius-sm);
  transition: border-color var(--dur-fast) var(--ease);
}
.cv-bloc:hover::after { border-color: var(--border-strong); }
.cv-bloc.est-choisi::after { border-color: var(--accent); }
.cv-bloc.est-saisi { opacity: .4; }

.cv-outils {
  position: absolute; top: var(--space-2); right: var(--space-2); z-index: 2;
  display: flex; gap: 2px; padding: 2px;
  background: var(--surface); border: var(--filet-w) solid var(--border);
  border-radius: var(--radius-sm); box-shadow: var(--shadow-md);
  opacity: 0; transition: opacity var(--dur-fast) var(--ease);
}
.cv-bloc:hover .cv-outils, .cv-bloc.est-choisi .cv-outils { opacity: 1; }
.cv-outils button {
  display: grid; place-items: center; width: 24px; height: 24px;
  border-radius: var(--radius-sm); color: var(--text-muted);
}
.cv-outils button:hover { background: var(--surface-2); color: var(--text); }
.cv-outils button:disabled { opacity: .3; cursor: not-allowed; }
.cv-outils button.est-danger:hover { background: var(--danger-soft); color: var(--danger-soft-text); }
.cv-outils i { font-size: var(--icon-sm); }

.cv-etiquette {
  position: absolute; top: var(--space-2); left: var(--space-2); z-index: 2;
  display: flex; align-items: center; gap: 5px;
  height: 20px; padding: 0 var(--space-2); border-radius: var(--radius-sm);
  background: var(--accent); color: var(--accent-text);
  font-size: 10.5px; font-weight: 600; letter-spacing: .04em;
  opacity: 0; transition: opacity var(--dur-fast) var(--ease);
}
.cv-bloc:hover .cv-etiquette, .cv-bloc.est-choisi .cv-etiquette { opacity: 1; }
.cv-etiquette i { font-size: 12px; }
.cv-etiquette.est-defaut { background: var(--warn); color: var(--warn-soft); }

/* ── Zone d'insertion entre deux blocs ───────────────────────────────────── */
.cv-inter {
  position: relative; height: var(--space-4); display: grid; place-items: center;
}
.cv-inter::before {
  content: ""; position: absolute; left: 0; right: 0; height: 2px;
  background: var(--accent); border-radius: var(--radius-full);
  opacity: 0; transition: opacity var(--dur-fast) var(--ease);
}
.cv-inter button {
  position: relative; z-index: 1;
  display: grid; place-items: center; width: 22px; height: 22px;
  border-radius: var(--radius-full);
  background: var(--accent); color: var(--accent-text);
  box-shadow: var(--shadow-sm);
  opacity: 0; transform: scale(.7);
  transition: opacity var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.cv-inter button i { font-size: 13px; }
.cv-inter:hover::before { opacity: .45; }
.cv-inter:hover button { opacity: 1; transform: scale(1); }
.cv-inter.est-cible::before { opacity: 1; }

/* ── Rendus de blocs ─────────────────────────────────────────────────────── */
.b-corps { display: block; padding: var(--space-8) var(--space-8); }
.b-hero { display: block; padding: var(--space-12) var(--space-8); text-align: center; background: var(--surface-2); }
.b-hero h1 { font-family: var(--font-display); font-size: 30px; font-weight: var(--display-weight);
             letter-spacing: var(--display-tracking); line-height: 1.15; }
.b-hero p { margin-top: var(--space-3); color: var(--text-muted); }
.b-hero .btn { margin-top: var(--space-5); }

.b-media { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-6);
           align-items: center; padding: var(--space-8); }
.b-media.est-inverse > figure { order: 2; }
.b-image { border-radius: var(--radius-md); overflow: hidden; background: var(--surface-sunken); }
.b-image img { width: 100%; height: 100%; object-fit: cover; display: block; aspect-ratio: 4/3; }
.b-image.est-vide { display: grid; place-items: center; aspect-ratio: 4/3; color: var(--text-subtle); }
.b-image.est-vide i { font-size: 28px; }

.b-galerie { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-2);
             padding: var(--space-8); }
.b-galerie .b-image img { aspect-ratio: 1; }

.b-citation { display: block; padding: var(--space-10) var(--space-12); text-align: center; }
.b-citation blockquote { font-family: var(--font-display); font-size: 20px; line-height: 1.45;
                         letter-spacing: var(--display-tracking); }
.b-citation cite { display: block; margin-top: var(--space-3); font-style: normal;
                   font-size: 13px; color: var(--text-subtle); }

.b-cta { display: block; padding: var(--space-10) var(--space-8); text-align: center;
         background: var(--accent-soft); color: var(--accent-soft-text); }
.b-cta h2 { font-family: var(--font-display); font-size: 22px; font-weight: var(--display-weight);
            letter-spacing: var(--display-tracking); }
.b-cta p { margin-top: var(--space-2); font-size: 14px; }

.b-liste { display: block; padding: var(--space-8); }
.b-liste .titre { font-family: var(--font-display); font-size: 18px; font-weight: 600;
                  letter-spacing: var(--display-tracking); margin-bottom: var(--space-4); }
.b-liste .cartes { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-3); }
.b-liste .carte .b-image img { aspect-ratio: 3/2; }
.b-liste .carte b { display: block; font-size: 13px; margin-top: var(--space-2); }
.b-liste .carte span { font-size: 11.5px; color: var(--text-subtle); }

.b-separateur { display: block; padding: var(--space-6) var(--space-8); }
.b-separateur hr { border: none; height: 1px; background: var(--border); }
.b-espace { background: repeating-linear-gradient(45deg, transparent, transparent 6px,
            var(--surface-2) 6px, var(--surface-2) 12px); }

/* ── Panneau du constructeur ─────────────────────────────────────────────── */
.cv-panneau {
  grid-area: panneau; overflow-y: auto;
  background: var(--surface); border-left: var(--filet-w) solid var(--border);
  padding: var(--space-4); display: flex; flex-direction: column; gap: var(--gap-form);
}
.cv-panneau > * { flex: none; }
.cv-panneau .entete { display: flex; align-items: center; gap: var(--space-2); }
.cv-panneau .entete b { font-size: 14px; font-weight: 600; flex: 1; }
.cv-panneau .entete i { font-size: var(--icon-md); color: var(--text-subtle); }

/* ═══════════════════════════════════════════════════════════════════════════
   ARBORESCENCE DE MENUS
   Déplacer et imbriquer sont deux gestes DISTINCTS. Les mêler dans un seul
   glissement rend le résultat imprévisible — c'est le défaut des menus qu'on
   n'arrive jamais à ranger.
   ═══════════════════════════════════════════════════════════════════════════ */

.arbo {
  display: grid; grid-template-columns: 1fr 300px;
  grid-template-rows: auto 1fr auto;
  grid-template-areas: "barre barre" "liste panneau" "apercu apercu";
  height: var(--hauteur, 740px); overflow: hidden;
  background: var(--surface);
  border: var(--filet-w) solid var(--border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-lg);
}
.arbre-barre {
  grid-area: barre; display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-bottom: var(--filet-w) solid var(--border);
}
.arbre-barre .grow { flex: 1; min-width: 0; }
.arbre-liste { display: block; grid-area: liste; overflow-y: auto; padding: var(--space-3); }
.arbre-panneau {
  grid-area: panneau; overflow-y: auto;
  border-left: var(--filet-w) solid var(--border); background: var(--surface-2);
  padding: var(--space-4); display: flex; flex-direction: column; gap: var(--gap-form);
}
.arbre-panneau > * { flex: none; }
.arbre-panneau .entete { display: flex; align-items: center; gap: var(--space-2); }
.arbre-panneau .entete b { flex: 1; font-size: 14px; font-weight: 600; }
.arbre-panneau .entete i { font-size: var(--icon-md); color: var(--text-subtle); }

/* ── Une entrée ──────────────────────────────────────────────────────────── */
.arbre-rang {
  position: relative; display: flex; align-items: center; gap: var(--space-2);
  height: var(--control-h); padding: 0 var(--space-2);
  border-radius: var(--radius-md);
  transition: background var(--dur-fast) var(--ease);
}
.arbre-rang { cursor: pointer; }   /* elle s'ouvre au clic : que le pointeur le dise */
.arbre-rang:hover { background: var(--surface-2); }
.arbre-rang.est-choisi { background: var(--accent-soft); }
.arbre-rang.est-saisi { opacity: .35; }
.arbre-rang .poignee {
  display: grid; place-items: center; width: 22px; height: 22px; flex: none;
  color: var(--text-subtle);
}
.arbre-rang .poignee i { font-size: var(--icon-sm); }
.arbre-rang > i.type { font-size: var(--icon-sm); color: var(--text-subtle); flex: none; }
.arbre-rang .lib { flex: 1; min-width: 0; font-size: 13.5px; font-weight: 500;
                overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.arbre-rang .cible { font-size: 11.5px; color: var(--text-subtle);
                  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 34%; }
.arbre-rang.est-masque .lib, .arbre-rang.est-masque .cible { opacity: .45; }

.arbre-outils { display: flex; gap: 1px; opacity: 0; transition: opacity var(--dur-fast) var(--ease); }
.arbre-rang:hover .arbre-outils, .arbre-rang.est-choisi .arbre-outils { opacity: 1; }
.arbre-outils button {
  display: grid; place-items: center; width: 24px; height: 24px;
  border-radius: var(--radius-sm); color: var(--text-muted);
}
.arbre-outils button:hover { background: var(--surface); color: var(--text); }
.arbre-outils button:disabled { opacity: .25; cursor: not-allowed; }
.arbre-outils button.est-danger:hover { background: var(--danger-soft); color: var(--danger-soft-text); }
.arbre-outils i { font-size: var(--icon-sm); }

/* Le trait de niveau rend la profondeur lisible sans compter les pixels. */
.arbre-niveau { position: relative; }
.arbre-niveau::before {
  content: ""; position: absolute; left: calc(var(--space-4) * -1); top: -2px; bottom: 50%;
  width: var(--space-3); border-left: var(--border-w) solid var(--border-strong);
  border-bottom: var(--border-w) solid var(--border-strong);
  border-bottom-left-radius: var(--radius-sm);
}

/* ── Repère de dépôt ─────────────────────────────────────────────────────── */
.arbre-trait { display: block;
  height: 2px; margin: 1px 0; border-radius: var(--radius-full);
  background: var(--accent); opacity: 0;
  transition: opacity var(--dur-fast) var(--ease);
}
.arbre-trait.est-cible { opacity: 1; }

/* ── Glisser-déposer : repère de dépôt ────────────────────────────────────
   Un seul repère, placé par le script d'après le pointeur (menus, types) :
   la ligne entière est une cible, plus besoin de viser un trait. Son retrait
   à gauche dit le niveau où l'entrée arrivera. Les listes l'hébergent en
   position relative. (.arbre-trait / .sc-trait restent pour les bancs.) */
.arbre-liste, .sc-champs { position: relative; }
.arbre-liste > .arbre-rang + .arbre-rang,
.sc-champs > .sc-rang + .sc-rang, .sc-champs > .sc-groupe + .sc-rang { margin-top: 4px; }
.glisse-repere {
  position: absolute; z-index: 3; display: block; height: 2px; pointer-events: none;
  border-radius: var(--radius-full); background: var(--accent);
}
.glisse-repere::before {
  content: ""; position: absolute; left: -5px; top: -3px; width: 8px; height: 8px;
  border-radius: 50%; border: 2px solid var(--accent); background: var(--surface); box-sizing: border-box;
}

.arbre-profondeur {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 11px; color: var(--text-subtle);
}

/* ── Aperçu du menu rendu ────────────────────────────────────────────────
   L'arbre dit la STRUCTURE, il ne dit pas ce que ça donne. L'aperçu est
   dessiné par le thème lui-même (un cadre, admin/menus.js) : aucune maquette
   ici, qui divergerait du site au premier thème différent. */
.arbre-apercu {
  grid-area: apercu; display: block; overflow: hidden;
  border-top: var(--filet-w) solid var(--border);
  background: var(--surface-2);
}
.ap-tete {
  display: flex; align-items: center; gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .08em;
  color: var(--text-subtle);
}
.ap-scene { display: block; margin: 0 var(--space-4) var(--space-4); overflow: hidden; border-radius: var(--radius-md);
             border: var(--filet-w) solid var(--border); background: var(--surface); }
.ap-scene[hidden] { display: none; }

/* ── Écran d'édition plein cadre ─────────────────────────────────────────
   Décidé au banc (banc/menus-defilement.html, « E sans cadre ») : l'éditeur
   quitte sa carte. Pas de titre visible — le fil d'Ariane et la barre le
   disent déjà —, mais un <h1 class="titre-lecteur"> pour les lecteurs
   d'écran. La barre, collée, court d'un bord à l'autre de la zone de
   contenu ; ses boutons restent alignés sur l'arbre (même gouttière). Un
   seul défilement : celui de la page. Les réglages s'ouvrent dans un tiroir
   accroché au bord droit, qui POUSSE la vue au lieu de la recouvrir et
   reste ouvert quand on passe de Structure à Aperçu. */
.titre-lecteur, .lecteur-seul {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}
.content:has(> .editeur-plein) { flex: 1; padding: 0; gap: 0; }
.content:has(> .editeur-plein) > .message { margin: var(--space-4) var(--pad-section) 0; }
.editeur-plein { flex: 1; display: flex; flex-direction: column; }
/* Deux éditeurs le portent : les menus (.arbo, zones barre/vue/panneau) et
   les types (.schema, zones barre/champs/reglages). */
.arbo.arbo-plein, .schema.schema-plein, .entree.entree-plein {
  --barre-h: 65px; --tiroir-l: 360px;
  flex: 1; height: auto;
  border: 0; border-radius: 0; box-shadow: none; background: none;
  grid-template-rows: auto 1fr;
  /* Le tiroir POUSSE : sa colonne existe toujours et passe de 0 à sa
     largeur, la vue se resserre avec elle. Le panneau garde sa largeur
     pleine pendant ce temps (rien ne se tasse) ; ce qui dépasse est rogné —
     par clip, pas hidden, qui casserait la barre collée. */
  grid-template-columns: minmax(0, 1fr) 0px;
  overflow: clip;
  transition: grid-template-columns var(--dur-lent) var(--ease);
}
.schema.schema-plein { --tiroir-l: 380px; }
.entree.entree-plein { --tiroir-l: 400px; display: grid; }
.arbo.arbo-plein { grid-template-areas: "barre barre" "vue panneau"; }
.schema.schema-plein { grid-template-areas: "barre barre" "champs reglages"; }
.entree.entree-plein { grid-template-areas: "barre barre" "corps panneau"; }
.arbo.arbo-plein.avec-tiroir, .schema.schema-plein.avec-tiroir, .entree.entree-plein.avec-tiroir {
  grid-template-columns: minmax(0, 1fr) var(--tiroir-l);
}
/* À la fermeture (la transition est celle de l'état d'arrivée), la colonne
   se referme au rythme de la sortie du panneau. */
.arbo.arbo-plein:not(.avec-tiroir), .schema.schema-plein:not(.avec-tiroir), .entree.entree-plein:not(.avec-tiroir) {
  transition-duration: var(--dur); transition-timing-function: var(--ease-sortie);
}
.arbo-plein .arbre-barre, .schema-plein .sc-barre, .entree-plein .en-barre {
  position: sticky; top: 0; z-index: 5; height: var(--barre-h);
  padding: 0 var(--pad-section); background: var(--surface);
}
.arbo-plein .arbre-vue { grid-area: vue; min-width: 0; }
.arbo-plein .arbre-liste, .schema-plein .sc-champs { overflow: visible; padding: var(--space-4) calc(var(--pad-section) - var(--space-2)) var(--space-3); }
.schema-plein .sc-zone { grid-area: champs; min-width: 0; }
.schema-plein .sc-champs { padding-bottom: var(--space-6); }
.schema-plein .sc-pied { padding: 0 var(--pad-section) var(--space-10); }
.arbo-plein .arbre-aide { padding: 0 var(--pad-section) var(--space-10); }
.arbo-plein .arbre-apercu { border-top: 0; background: none; padding: var(--pad-section); }
.arbo-plein .arbre-apercu .help { margin-top: var(--space-3); }
.arbo-plein .ap-scene { margin: 0; }
.arbo-plein .arbre-panneau, .schema-plein .sc-reglages, .entree-plein .en-historique {
  position: sticky; top: var(--barre-h); align-self: start;
  width: var(--tiroir-l); min-width: var(--tiroir-l);
  height: calc(100vh - var(--barre-h) - var(--haut-visible)); overscroll-behavior: contain;
}
.arbo-plein [hidden], .schema-plein [hidden], .entree-plein [hidden] { display: none; }

/* Plein cadre générique, pour un écran sans grille à lui (Équipe, Réglages) :
   .editeur-plein > .plein-barre (collée) + .plein-corps (gouttière de page). */
.plein-barre {
  position: sticky; top: 0; z-index: 5; height: 65px; flex: none;
  display: flex; align-items: center; gap: var(--space-3);
  padding: 0 var(--pad-section); background: var(--surface); border-bottom: var(--filet-w) solid var(--border);
}
.plein-barre .grow { flex: 1; min-width: 0; }
.plein-barre > b { font-size: 14px; font-weight: 600; white-space: nowrap; }
.plein-meta { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12.5px; color: var(--text-subtle); }
.plein-corps { flex: 1; display: flex; flex-direction: column; gap: var(--gap-form); padding: var(--space-6) var(--pad-section) var(--space-10); }
/* ⚠ LE RAIL SUIT LA LECTURE, SUR TOUTES LES PAGES QUI EN ONT UN. La règle
   était limitée aux écrans en plein cadre ; l'aide en a un aussi et n'en est
   pas un, son rail s'en allait donc avec la page. Deux pages seulement ont un
   rail (Aide, Réglages) : la règle générale les couvre toutes les deux.
   ⚠ Et il se borne à la fenêtre : onze entrées tiennent sur un écran de
   portable, pas sur tous — sans « max-height », le bas du rail devient
   inatteignable dès que la page est plus longue que haute. */
.grid-2.avec-rail > .rail { position: sticky; top: var(--space-6); align-self: start;
  max-height: calc(100svh - var(--space-6) * 2); overflow-y: auto; }
/* En plein cadre, la barre de la page reste au-dessus : le rail se cale sous
   elle, pas sous le bord de la fenêtre. */
.plein-corps .grid-2.avec-rail > .rail { top: calc(65px + var(--space-6));
  max-height: calc(100svh - 65px - var(--space-6) * 2); }

/* Rôles plein cadre : la page défile ; le panneau du rôle — toujours là, un
   rôle est toujours choisi — reste collé à droite sur toute la hauteur. */
.perm.perm-plein { flex: 1; height: auto; overflow: visible; border: 0; border-radius: 0; box-shadow: none; background: none; grid-template-rows: auto 1fr; }
.perm-plein .pm-barre { position: sticky; top: 0; z-index: 5; height: 65px; padding: 0 var(--pad-section); background: var(--surface); }
.perm-plein .pm-corps { overflow-x: auto; overflow-y: visible; padding: var(--space-4) var(--pad-section) var(--space-10); }
.perm-plein .pm-panneau { position: sticky; top: 65px; align-self: start; height: calc(100vh - 65px - var(--haut-visible)); overscroll-behavior: contain; }

/* Éditeur d'entrée plein cadre : barre (langues, historique, Enregistrer),
   corps (messages, formulaire à colonne latérale), panneau d'historique.
   Panneau ouvert, la colonne latérale passe sous le formulaire : trois
   colonnes ne tiendraient pas. */
.en-barre { grid-area: barre; display: flex; align-items: center; gap: var(--space-3); border-bottom: var(--filet-w) solid var(--border); }
.en-barre .grow { flex: 1; min-width: 0; }
.en-annuler { display: inline-flex; gap: var(--space-1); }
.en-barre [data-historique][aria-expanded="true"] { background: var(--surface-2); color: var(--text); }
.en-meta { font-size: 12.5px; color: var(--text-subtle); white-space: nowrap; }
.en-corps { grid-area: corps; min-width: 0; display: flex; flex-direction: column; gap: var(--gap-form);
            padding: var(--space-6) var(--pad-section) var(--space-10); }
.en-corps > form:not(.grid-2) { align-self: flex-start; }
.entree-plein.avec-tiroir .grid-2.avec-cote { grid-template-columns: minmax(0, 1fr); }
.en-historique {
  grid-area: panneau; display: flex; flex-direction: column; gap: var(--space-3);
  border-left: var(--filet-w) solid var(--border); background: var(--surface-2);
  padding: var(--space-4); overflow-y: auto;
}
.en-historique > * { flex: none; }
.en-historique .entete { display: flex; align-items: center; gap: var(--space-2); }
.en-historique .entete b { flex: 1; font-size: 14px; font-weight: 600; outline: none; }
.en-historique .entete > i { font-size: var(--icon-md); color: var(--text-subtle); }
.en-historique[aria-busy="true"] { opacity: .6; }
.hi-versions { display: flex; flex-direction: column; gap: 2px; margin: 0; padding: 0; list-style: none; }
.hi-version {
  display: grid; grid-template-columns: minmax(0, 1fr) auto 14px; grid-template-areas: "quand etat fleche" "qui etat fleche";
  align-items: center; gap: 2px var(--space-2); padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md); color: inherit; text-decoration: none;
}
a.hi-version:hover { background: var(--surface); }
a.hi-version:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.hi-version.est-courant { background: var(--surface); }
.hi-quand { grid-area: quand; color: var(--text); }
.hi-qui { grid-area: qui; font-size: 12px; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hi-etat { grid-area: etat; display: flex; gap: 4px; }
.hi-fleche { grid-area: fleche; color: var(--text-subtle); font-size: var(--icon-sm); }
.hi-diffs { display: flex; flex-direction: column; gap: var(--space-1); margin: 0; }
.hi-diffs dt { font-size: 13px; font-weight: 600; margin-top: var(--space-2); }
.hi-diffs dd { margin: 0; padding: var(--space-2) var(--space-3); border-radius: var(--radius-md);
               font-size: 13px; white-space: pre-wrap; overflow-wrap: anywhere; }
.hi-diffs dd > span { display: block; margin-bottom: 2px; font-size: 10.5px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; opacity: .75; }
.hi-avant { background: var(--danger-soft); color: var(--danger-soft-text); }
.hi-apres { background: var(--ok-soft); color: var(--ok-soft-text); }
.hi-pleine { display: inline-flex; align-items: center; gap: var(--space-1); align-self: flex-start; }
.arbre-modifie { font-size: 12px; color: var(--text-subtle); }
.sc-nb { display: inline-flex; align-items: center; gap: var(--space-1); font-size: 13px; color: var(--text-muted); }
.sc-nb:hover { color: var(--text); }
.visible-etroit { display: none; }
@media (max-width: 60rem) {
  .arbo.arbo-plein, .arbo.arbo-plein.avec-tiroir { grid-template-columns: minmax(0, 1fr); grid-template-areas: "barre" "vue"; }
  .schema.schema-plein, .schema.schema-plein.avec-tiroir { grid-template-columns: minmax(0, 1fr); grid-template-areas: "barre" "champs"; }
  .entree.entree-plein, .entree.entree-plein.avec-tiroir { grid-template-columns: minmax(0, 1fr); grid-template-areas: "barre" "corps"; }
  .arbo.arbo-plein, .schema.schema-plein, .entree.entree-plein { transition: none; }
  .entree-plein .en-barre { flex-wrap: nowrap; gap: var(--space-2); padding: 0 var(--space-4); }
  .entree-plein .en-barre > * { flex-shrink: 0; }
  .entree-plein .en-barre > .grow { flex: 1 1 auto; min-width: 0; }
  .entree-plein .en-barre .libelle, .en-meta { display: none; }
  .entree-plein .en-barre > .seg { flex-shrink: 1; min-width: 0; overflow-x: auto; }
  .en-corps { padding: var(--space-4); }
  .plein-barre, .perm-plein .pm-barre { flex-wrap: nowrap; gap: var(--space-2); padding: 0 var(--space-4); }
  .plein-barre > *, .perm-plein .pm-barre > * { flex-shrink: 0; }
  .plein-barre > .grow, .perm-plein .pm-barre > .grow { flex: 1 1 auto; min-width: 0; }
  .plein-barre .libelle, .perm-plein .pm-barre .libelle, .plein-meta { display: none; }
  .plein-corps { padding: var(--space-4) var(--space-4) var(--space-10); }
  .grid-2.avec-rail > .rail { position: static; max-height: none; overflow: visible; }
  .perm-plein .pm-corps { padding: var(--space-3) var(--space-4); }
  .perm-plein .pm-panneau { position: static; height: auto; }
  .mediatheque.mt-plein, .mediatheque.mt-plein.avec-tiroir { grid-template-columns: minmax(0, 1fr); grid-template-areas: "barre" "corps" "pied"; transition: none; }
  .mt-plein .mt-barre { gap: var(--space-2); padding: 0 var(--space-4); }
  .mt-plein .mt-corps { padding: var(--space-4); max-height: none; }
  .mt-plein .mt-panneau {
    position: fixed; inset: 0 0 0 auto; z-index: 60; width: min(380px, 100%); min-width: 0; height: auto; align-self: stretch;
    overflow-y: auto; border-top: 0; border-left: var(--filet-w) solid var(--border); box-shadow: var(--shadow-lg);
    --entree-distance: 100%;
  }
  .mt-taille { display: none; }
  .arbo-plein .arbre-barre, .schema-plein .sc-barre { flex-wrap: nowrap; gap: var(--space-2); padding: 0 var(--space-4); }
  .arbo-plein .arbre-barre > *, .schema-plein .sc-barre > * { flex-shrink: 0; }
  .arbo-plein .arbre-barre > .grow, .schema-plein .sc-barre > .grow { flex: 1 1 auto; min-width: 0; }
  .arbo-plein .arbre-barre .libelle, .schema-plein .sc-barre .libelle, .arbo-plein .arbre-profondeur i { display: none; }
  .arbo-plein .visible-large, .schema-plein .visible-large { display: none; }
  .arbo-plein .visible-etroit { display: block; width: auto; min-width: 8.5rem; height: 32px; }
  /* Non enregistré : un point, le détail au survol et pour les lecteurs. */
  .arbre-modifie::before { content: ""; display: block; width: 8px; height: 8px; border-radius: 50%; background: var(--warn); }
  .arbo-plein .arbre-liste, .schema-plein .sc-champs { max-height: none; padding: var(--space-3) var(--space-2); }
  .arbo-plein .arbre-aide { padding: 0 var(--space-4) var(--space-10); }
  .arbo-plein .arbre-apercu { padding: var(--space-4); }
  .arbo-plein .arbre-panneau, .schema-plein .sc-reglages, .entree-plein .en-historique {
    position: fixed; inset: 0 0 0 auto; z-index: 60; width: min(380px, 100%); min-width: 0; height: auto; align-self: stretch;
    --entree-distance: 100%; /* le tiroir traverse l'écran depuis le bord */
    border-top: 0; border-left: var(--filet-w) solid var(--border); box-shadow: var(--shadow-lg);
  }
  .schema-plein .sc-pied { padding: 0 var(--space-4) var(--space-10); }
}

/* ── Label d'entrée de menu ──────────────────────────────────────────────
   Cinq représentations, parce qu'un « 17 » et un « new » ne se placent pas au
   même endroit : un compte se lit à côté du mot, une nouveauté se lit au-dessus. */
.mn-label {
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--font-num); font-weight: 300; line-height: 1;
  background: var(--accent); color: var(--accent-text);
}
.mn-label.est-pastille { min-width: 18px; height: 18px; padding: 0 7px;
                         border-radius: var(--radius-full); font-size: 9.5px; margin-left: 5px; }
.mn-label.est-avant    { min-width: 18px; height: 18px; padding: 0 7px;
                         border-radius: var(--radius-full); font-size: 9.5px; margin-right: 5px; }
.mn-label.est-exposant { font-size: 8.5px; padding: 2px 6px; border-radius: var(--radius-full);
                         vertical-align: super; margin-left: 2px; align-self: flex-start; }
.mn-label.est-indice   { font-size: 8.5px; padding: 2px 6px; border-radius: var(--radius-full);
                         vertical-align: sub; margin-left: 2px; align-self: flex-end; }
.mn-label.est-point    { width: 6px; height: 6px; padding: 0; min-width: 0;
                         border-radius: var(--radius-full); margin-left: 4px;
                         align-self: flex-start; font-size: 0; }
.mn-label.est-neutre { background: color-mix(in srgb, currentColor 22%, transparent); color: inherit; }

.ap-fond .marque-video {
  position: absolute; right: var(--space-3); bottom: var(--space-2);
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 10px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--gray-0); opacity: .7;
}

.ap-col.est-image { gap: var(--space-2); }
.ap-col.est-image .visuel {
  display: block; width: 100%; aspect-ratio: 4 / 3; border-radius: var(--radius-sm);
  background-size: cover; background-position: center;
}

/* ── Sélecteur à deux temps ──────────────────────────────────────────────── */
.mn-retour {
  display: flex; align-items: center; gap: var(--space-2); width: 100%;
  padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm);
  font-size: 12px; color: var(--text-subtle);
}
.mn-retour:hover { background: var(--surface-2); color: var(--text); }
.mn-retour i { font-size: var(--icon-sm); }

/* ═══════════════════════════════════════════════════════════════════════════
   ÉDITEUR DE SCHÉMA DE CONTENU
   L'ordre des champs EST l'ordre du formulaire : cet éditeur ne décrit pas une
   base de données, il dessine l'écran que les rédacteurs verront tous les jours.
   ═══════════════════════════════════════════════════════════════════════════ */

.schema {
  /* Deux zones : les champs, leurs réglages. (L'aperçu du formulaire, une
     imitation qui divergeait à chaque genre nouveau, est retiré : le vrai
     formulaire est à un clic, « Voir le formulaire ».) */
  display: grid; grid-template-columns: 1fr 400px;
  grid-template-rows: auto 1fr;
  grid-template-areas: "barre barre" "champs reglages";
  height: var(--hauteur, 760px); overflow: hidden;
  background: var(--surface);
  border: var(--filet-w) solid var(--border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-lg);
}
.sc-barre {
  grid-area: barre; display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-bottom: var(--filet-w) solid var(--border);
}
.sc-barre .grow { flex: 1; min-width: 0; }
.sc-champs { grid-area: champs; display: block; overflow-y: auto; padding: var(--space-3); }
/* ⚠ Le tiroir ne défile plus lui-même : chacun de ses deux panneaux a son
   propre défilement, sinon le panneau qui RECOUVRE hériterait de la position
   de celui qu'il cache. */
.sc-reglages {
  grid-area: reglages; position: relative; overflow: hidden;
  border-left: var(--filet-w) solid var(--border); background: var(--surface-2);
}
.sc-pan { position: absolute; inset: 0; overflow-y: auto; overscroll-behavior: contain;
  padding: var(--space-4); display: flex; flex-direction: column; gap: var(--gap-form); }
.sc-pan > * { flex: none; }
/* Les volets du type (Réglages, Mise en page) : ils reprennent l'espacement du panneau, sans quoi leurs champs se touchent. */
.sc-pan > [data-pane] { display: flex; flex-direction: column; gap: var(--gap-form); }
.sc-pan > [data-pane][hidden] { display: none; }
.sc-pan > [data-pane] > * { flex: none; }
/* Deux listes côte à côte dans un panneau étroit se tronquaient (« Sans ligne sous le tit ») : elles passent à la ligne. */
.sc-pan [data-pane] .ligne-date { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.sc-pan [data-pane] .ligne-date > .select, .sc-pan [data-pane] .ligne-date > .input { flex: 1 1 11rem; min-width: 0; max-width: none; }
/* Le panneau d'un champ glisse par la droite et couvre celui du type. Il porte
   son propre fond : par-dessus un panneau transparent, les deux se liraient
   l'un à travers l'autre. */
.sc-pan-champ { z-index: 2; background: var(--surface-2); box-shadow: -12px 0 28px rgb(0 0 0 / .10);
  transform: translateX(100%); transition: transform var(--dur) var(--ease-sortie); }
.sc-pan-champ.est-ouvert { transform: none; transition: transform var(--dur-lent) var(--ease); }
@media (prefers-reduced-motion: reduce) { .sc-pan-champ { transition: none; } }
.sc-reglages > * { flex: none; }
.sc-reglages .entete { display: flex; align-items: center; gap: var(--space-2); }
.sc-reglages .entete b { flex: 1; font-size: 14px; font-weight: 600; }
.sc-reglages .entete i { font-size: var(--icon-md); color: var(--text-subtle); }

/* ── Une ligne de champ ──────────────────────────────────────────────────── */
/* Le formulaire de saisie : une grille de six colonnes, chaque champ disant
   la largeur qu'il prend. Six plutôt que quatre — les tiers et les moitiés y
   tombent juste. ⚠ Un titre de groupe et tout ce qui n'est pas un champ
   prennent la ligne entière : sans cela ils se rangeraient dans la première
   colonne libre, au milieu d'une rangée. */
.champs-grille { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: var(--space-4) var(--space-3); align-items: start; }
.champs-grille > :not(.field) { grid-column: 1 / -1; }
/* ⚠ Sous 44rem, tout reprend la pleine largeur : un champ d'un tiers de
   téléphone ne se saisit pas. La règle passe APRÈS le `span` posé en ligne
   sur chaque champ, d'où le `!important` — seul moyen de reprendre un style
   d'attribut. */
@media (max-width: 44rem) {
  .champs-grille { grid-template-columns: minmax(0, 1fr); }
  .champs-grille > .field { grid-column: 1 / -1 !important; }
}

/* ── Affiner : la typographie, niveau par niveau ──────────────────────────
   Une ligne par élément, six champs. Un champ vide veut dire « hérité » —
   c'est le repère (placeholder) qui le dit, jamais une valeur pré-remplie :
   afficher la valeur héritée la figerait au premier enregistrement. */
.ap-fin { display: grid; gap: var(--space-2); margin-top: var(--space-3);
  padding: var(--space-3); border: var(--filet-w) solid var(--border); border-radius: var(--radius-md); background: var(--surface-2); }
/* ⚠ UNE SEULE COLONNE, TOUJOURS. Ce panneau vit dans le volet d'Apparence,
   large de moins de 300 px même sur un grand écran : une requête média sur la
   largeur de l'ÉCRAN ne se déclenchait jamais, et les six libellés se
   chevauchaient. Les champs se replient donc d'eux-mêmes (auto-fit), sans
   dépendre de la taille de la fenêtre. */
.ap-fin-ligne { display: grid; gap: var(--space-2); align-items: start;
  padding: var(--space-3) 0; border-top: var(--filet-w) solid var(--border); }
.ap-fin-ligne:first-child { border-top: 0; }
.ap-fin-nom { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 0 var(--space-2);
  align-items: center; font-size: 13px; }
.ap-fin-nom .subtle { grid-column: 1; }
/* ⚠ La COLONNE est explicite. Avec la seule ligne, le bouton se plaçait de
   lui-même en colonne 1 et renvoyait le nom à droite : nom et flèche
   inversés. */
.ap-fin-nom .retablir { grid-row: 1 / span 2; grid-column: 2; }
.ap-fin-nom .subtle { font-size: 11.5px; }
.ap-fin-ligne.est-deroge .ap-fin-nom b { color: var(--accent); }
.ap-fin-champs { display: grid; grid-template-columns: repeat(auto-fit, minmax(92px, 1fr)); gap: var(--space-2); align-items: end; }
.ap-fin-champs label { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.ap-fin-champs :is(.input, .select) { padding: 5px 7px; font-size: 12.5px; }

/* La rangée qu'on déplace s'efface un peu, comme ailleurs. */
/* ⚠ Le repère de glissement se positionne DANS son hôte : il lui faut un
   ancêtre positionné, que le cadre de tableau n'a pas de lui-même. */
.ct-lignes.avec-repere, .table-wrap.avec-repere { position: relative; }
tbody[data-ranger] .poignee { color: var(--text-subtle); display: grid; place-items: center; width: 20px; flex: none; }
tbody[data-ranger] tr.est-saisi { opacity: .35; }

.sc-rang {
  display: flex; align-items: center; gap: var(--space-2);
  height: var(--control-h); padding: 0 var(--space-2);
  border-radius: var(--radius-md);
  /* ⚠ La rangée entière ouvre les réglages du champ : sans ce curseur, rien ne
     le disait — le survol changeait le fond, ce qui se lit comme un simple
     effet de liste, pas comme « ceci s'ouvre ». La poignée garde `grab`. */
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease);
}
.sc-rang:hover { background: var(--surface-2); }
.sc-rang.est-choisi { background: var(--accent-soft); }
.sc-rang.est-saisi { opacity: .35; }
.sc-rang .poignee { display: grid; place-items: center; width: 22px; height: 22px;
                    flex: none; color: var(--text-subtle); }
.sc-rang .poignee i { font-size: var(--icon-sm); }
.sc-rang > i.genre { font-size: var(--icon-sm); color: var(--text-subtle); flex: none; }
.sc-rang .lib { font-weight: 500; font-size: 13.5px; }
.sc-rang .cle { font-family: var(--font-mono); font-size: 11px; color: var(--text-subtle); }
.sc-rang .grow { flex: 1; min-width: 0; }
.sc-outils { display: flex; gap: 1px; opacity: 0; transition: opacity var(--dur-fast) var(--ease); }
.sc-rang:hover .sc-outils, .sc-rang.est-choisi .sc-outils { opacity: 1; }
.sc-outils button { display: grid; place-items: center; width: 24px; height: 24px;
                    border-radius: var(--radius-sm); color: var(--text-muted); }
.sc-outils button:hover { background: var(--surface); color: var(--text); }
.sc-outils button.est-danger:hover { background: var(--danger-soft); color: var(--danger-soft-text); }
.sc-outils i { font-size: var(--icon-sm); }

.sc-groupe {
  display: flex; align-items: center; gap: var(--space-2);
  margin: var(--space-4) 0 var(--space-1); padding: 0 var(--space-2);
  font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .08em;
  color: var(--text-subtle);
}
.sc-groupe::after { content: ""; flex: 1; height: 1px; background: var(--border); }
.sc-trait { display: block; height: 2px; margin: 1px 0; border-radius: var(--radius-full);
            background: var(--accent); opacity: 0; transition: opacity var(--dur-fast) var(--ease); }
.sc-trait.est-cible { opacity: 1; }

.sc-oblig { color: var(--danger); font-weight: 700; }

/* ═══════════════════════════════════════════════════════════════════════════
   GRILLE DE PERMISSIONS
   Une capacité est un VERBE, une portée est un OBJET. Et le masquage de
   l'interface n'est jamais une permission : il rend l'écran lisible, il ne
   protège rien. Chaque capacité se vérifie au serveur.
   ═══════════════════════════════════════════════════════════════════════════ */

.perm {
  display: grid; grid-template-columns: 1fr 320px;
  grid-template-rows: auto 1fr;
  grid-template-areas: "barre barre" "corps panneau";
  height: var(--hauteur, 700px); overflow: hidden;
  background: var(--surface);
  border: var(--filet-w) solid var(--border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-lg);
}
.pm-barre {
  grid-area: barre; display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-bottom: var(--filet-w) solid var(--border);
}
.pm-barre .grow { flex: 1; min-width: 0; }
.pm-corps { grid-area: corps; display: block; overflow: auto; padding: var(--space-3); }
.pm-panneau {
  grid-area: panneau; overflow-y: auto;
  border-left: var(--filet-w) solid var(--border); background: var(--surface-2);
  padding: var(--space-4); display: flex; flex-direction: column; gap: var(--gap-form);
}
.pm-panneau > * { flex: none; }
.pm-panneau .entete { display: flex; align-items: center; gap: var(--space-2); }
.pm-panneau .entete b { flex: 1; font-size: 14px; font-weight: 600; }
.pm-panneau .entete i { font-size: var(--icon-md); color: var(--text-subtle); }

/* ── La grille capacités × rôles ─────────────────────────────────────────── */
/* table-layout:fixed : en mise en table automatique, « width » n'est qu'une
   suggestion — la colonne qui porte les pastilles de portée s'élargissait et
   poussait les autres à chaque changement de rôle. En fixe, les largeurs
   déclarées sont tenues et le contenu ne les discute plus. */
.pm-grille { width: 100%; table-layout: fixed; border-collapse: separate; border-spacing: 0; }
.pm-grille th, .pm-grille td { padding: var(--space-2) var(--space-3); }
.pm-grille thead th {
  position: sticky; top: 0; z-index: 1; background: var(--surface);
  border-bottom: var(--filet-w) solid var(--border);
  font-size: 12px; font-weight: 600; text-align: center; white-space: nowrap;
}
.pm-grille thead th:first-child { text-align: left; }
.pm-grille thead th.est-choisi { background: var(--accent-soft); color: var(--accent-soft-text);
                                border-radius: var(--radius-sm) var(--radius-sm) 0 0; }
.pm-grille td { border-bottom: var(--filet-w) solid var(--border); }
.pm-grille tbody tr:hover td { background: var(--surface-2); }
.pm-cap { width: 100%; }
.pm-cap b { display: block; font-size: 13.5px; font-weight: 500; }
.pm-cap span { font-size: 11.5px; color: var(--text-subtle); }
.pm-cap code { font-family: var(--font-mono); font-size: 10.5px; color: var(--text-subtle); }
.pm-col { width: 132px; text-align: center; }
.pm-cellule { display: inline-flex; align-items: center; gap: 6px; }

.pm-case {
  display: inline-grid; place-items: center; width: 24px; height: 24px;
  border-radius: var(--radius-sm); border: var(--border-w) solid var(--border-strong);
  background: var(--surface); color: transparent;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease),
              color var(--dur-fast) var(--ease);
}
.pm-case i { font-size: 14px; }
.pm-case:hover { border-color: var(--accent); }
.pm-case.est-oui { background: var(--accent); border-color: var(--accent); color: var(--accent-text); }
.pm-case.est-implique { background: var(--accent-soft); border-color: var(--accent-soft);
                        color: var(--accent-soft-text); }
.pm-case.est-fige { background: var(--surface-2); border-color: var(--border);
                    color: var(--text-subtle); cursor: not-allowed; }
.pm-case.est-fige.est-oui { background: var(--surface-sunken); color: var(--text-muted); }

.pm-titre-groupe {
  font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .08em;
  color: var(--text-subtle); background: var(--surface-2);
}
/* Une seule ligne, jamais coupée : répétée dans quinze cellules et cassée sur
   trois lignes, elle rendait la grille illisible. Elle n'apparaît d'ailleurs
   que dans la colonne du rôle qu'on règle. */
.pm-portee {
  display: inline-flex; align-items: center; gap: 4px; white-space: nowrap;
  max-width: 76px; min-width: 0;
  padding: 1px 6px; border-radius: var(--radius-sm);
  background: var(--surface-sunken); color: var(--text-muted);
  font-size: 10.5px; font-weight: 500; font-family: var(--font-num);
}
.pm-portee i { font-size: 10px; flex: none; }
/* Le libellé se coupe plutôt que de faire déborder la cellule : le détail
   complet reste dans l'infobulle. */
.pm-portee span { overflow: hidden; text-overflow: ellipsis; min-width: 0; }

/* Puces de portée : un .seg est fait pour une seule ligne — au-delà de quatre
   entrées il se casse en marches d'escalier. */
.pm-chips { display: flex; flex-wrap: wrap; gap: 4px; }
.pm-chip {
  display: inline-flex; align-items: center; height: 26px; padding: 0 var(--space-3);
  border-radius: var(--radius-pill); border: var(--filet-w) solid var(--border);
  background: var(--surface); color: var(--text-muted);
  font-size: 12.5px; font-weight: 500;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease);
}
.pm-chip:hover { border-color: var(--border-strong); color: var(--text); }
.pm-chip.est-courant { background: var(--accent); border-color: var(--accent); color: var(--accent-text); }

/* ── Membres ─────────────────────────────────────────────────────────────── */
.pm-membre {
  display: flex; align-items: center; gap: var(--space-3); width: 100%;
  padding: var(--space-2) var(--space-3); border-radius: var(--radius-md); text-align: left;
}
.pm-membre:hover { background: var(--surface-2); }
.pm-membre.est-choisi { background: var(--accent-soft); }
.pm-membre .qui { flex: 1; min-width: 0; }
.pm-membre b { display: block; font-size: 13.5px; font-weight: 500; }
.pm-membre .mail { font-size: 11.5px; color: var(--text-subtle); }
.pm-effectif {
  display: flex; flex-wrap: wrap; gap: 4px; margin-top: var(--space-2);
}

/* ═══════════════════════════════════════════════════════════════════════════
   CHAMPS-LISTES DU FORMULAIRE D'ENTRÉE
   Galerie (vignettes ordonnées), dates (date + précision libre), cases
   multiples (relation, choix multiple) dans une boîte qui défile.
   ═══════════════════════════════════════════════════════════════════════════ */
.champ-galerie { display: flex; flex-direction: column; gap: var(--space-2); }
.galerie-liste {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(112px, 1fr)); gap: var(--space-2);
  list-style: none; margin: 0; padding: 0;
}
.galerie-liste:empty { display: none; }
.galerie-liste li {
  position: relative; aspect-ratio: 1; border-radius: var(--radius-md); overflow: hidden;
  background: var(--surface-sunken); display: block;
}
.galerie-liste img { width: 100%; height: 100%; object-fit: cover; display: block; }
.galerie-liste .outils {
  position: absolute; inset: auto 0 0 0; display: flex; justify-content: center; gap: 2px;
  padding: 2px; background: var(--surface); box-shadow: 0 -1px 0 var(--border);
  opacity: 0; transition: opacity var(--dur-fast) var(--ease);
}
.galerie-liste li:hover .outils, .galerie-liste li:focus-within .outils { opacity: 1; }
.galerie-liste .outils .btn { color: var(--text); }
@media (hover: none) { .galerie-liste .outils { opacity: 1; } }

.champ-dates { display: flex; flex-direction: column; gap: var(--space-3); }
.ligne-date { display: grid; grid-template-columns: 11rem 1fr; gap: var(--space-2); }

.choix-liste {
  display: flex; flex-direction: column; gap: var(--space-1);
  max-height: 16rem; overflow: auto; padding: var(--space-2) var(--space-3);
  border: var(--filet-w) solid var(--border); border-radius: var(--radius-md);
}
.champ-selections { display: flex; flex-direction: column; gap: var(--space-2); }
.selections-liste { display: flex; flex-direction: column; gap: var(--space-2); }
.selections-liste:empty { display: none; }
/* Deux rangs : le titre et les outils, puis type · ordre · nombre · filtre. */
.ligne-selection {
  display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, 1.2fr) 4.5rem minmax(0, 1.6fr);
  gap: var(--space-2); align-items: center; padding: var(--space-2);
  border: var(--filet-w) solid var(--border); border-radius: var(--radius-md); background: var(--surface-sunken);
}
.ligne-selection > [data-k="titre"] { grid-column: 1 / 4; grid-row: 1; }
.ligne-selection > .outils { grid-column: 4; grid-row: 1; justify-self: end; display: flex; gap: 2px; }
.ligne-selection > :not([data-k="titre"]):not(.outils) { grid-row: 2; }
.doc-nom { display: inline-flex; align-items: center; gap: var(--space-2); font-size: 13px; padding: var(--space-3); text-align: center; }

/* ═══════════════════════════════════════════════════════════════════════════
   RECHERCHE (⌘K) — une fenêtre haute, un champ, des résultats groupés ;
   le clavier d'abord (↑ ↓ Entrée Échap).
   ═══════════════════════════════════════════════════════════════════════════ */
.palette {
  width: min(720px, 100%); max-height: min(600px, 80vh); display: flex; flex-direction: column;
  background: var(--surface); border: var(--filet-w) solid var(--border); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg); overflow: hidden; align-self: start; margin-top: 12vh;
}
/* Le champ est la fenêtre : grand, et sans l'anneau de focus général
   (:focus-visible) — seul champ du dialogue, le curseur dit déjà où l'on tape,
   et le halo violet l'encadrait comme un champ de formulaire parmi d'autres. */
.palette-champ { display: flex; align-items: center; gap: var(--space-4); padding: var(--space-5) var(--space-6); border-bottom: var(--filet-w) solid var(--border); }
.palette-champ i { font-size: 26px; color: var(--text-subtle); }
.palette-champ input { flex: 1; min-width: 0; border: 0; background: transparent; font: inherit; font-size: 26px; line-height: 1.2; letter-spacing: -.01em; color: var(--text); outline: none; }
.palette-champ input:focus-visible { box-shadow: none; }
.palette-champ input::placeholder { color: var(--text-subtle); }
.palette-champ input::-webkit-search-cancel-button { display: none; }
.palette-resultats { overflow: auto; padding: var(--space-2); display: flex; flex-direction: column; gap: 1px; }
.palette-groupe { display: block; padding: var(--space-2) var(--space-2) var(--space-1); }
.palette-item {
  display: flex; align-items: center; gap: var(--space-3); padding: var(--space-2); border-radius: var(--radius-md);
  color: var(--text); text-decoration: none; min-width: 0;
}
.palette-item[aria-selected="true"] { background: var(--accent-soft); }
/* Le mot cherché, en gras dans les résultats (P6) : pas de surlignage jaune. */
.palette mark { background: none; color: inherit; font-weight: 700; }
.palette-item .vignette { width: 32px; height: 32px; flex: none; border-radius: var(--radius-sm); background: var(--surface-sunken);
  display: grid; place-items: center; overflow: hidden; color: var(--text-subtle); }
.palette-item .vignette img { width: 100%; height: 100%; object-fit: cover; }
.palette-item b { display: block; font-size: 13.5px; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.palette-item span.sous { display: block; font-size: 11.5px; color: var(--text-subtle); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.palette-item .texte { min-width: 0; }
/* Les médias en vignettes : c'est l'image qu'on reconnaît, pas son nom de
   fichier. Même sélection que les lignes (aria-selected), même ordre au
   clavier — ↑ ↓ parcourent la grille dans le sens de la lecture. */
.palette-vignettes { display: grid; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); gap: var(--space-1); padding: 0 0 var(--space-2); }
.palette-tuile { display: flex; flex-direction: column; gap: 6px; min-width: 0; padding: 5px; border-radius: var(--radius-md); color: var(--text); text-decoration: none; }
/* Choisie : le fond teinté ne se voit que dans la marge, l'image couvrant le
   reste — d'où le cadre à la couleur d'action, comme la vignette ouverte de
   la médiathèque. */
.palette-tuile[aria-selected="true"] { background: var(--accent-soft); }
.palette-tuile[aria-selected="true"] .tuile-img { box-shadow: 0 0 0 2px var(--accent); }
.palette-tuile[aria-selected="true"] .tuile-nom { color: var(--accent-soft-text); }
.palette-tuile .tuile-img { display: grid; place-items: center; aspect-ratio: 1; overflow: hidden; border-radius: var(--radius-sm);
  background: var(--surface-sunken); color: var(--text-subtle); font-size: 28px; }
.palette-tuile .tuile-img img { width: 100%; height: 100%; object-fit: cover; }
.palette-tuile .tuile-nom { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 11.5px; color: var(--text-muted); }
.palette-vide { display: block; padding: var(--space-6) var(--space-4); text-align: center; color: var(--text-subtle); font-size: 13px; }
.palette-pied { display: flex; gap: var(--space-4); padding: var(--space-2) var(--space-4); border-top: var(--filet-w) solid var(--border);
  font-size: 11.5px; color: var(--text-subtle); }
kbd { font-family: var(--font-num); font-size: 11px; padding: 1px 5px; border-radius: 4px; border: var(--filet-w) solid var(--border); background: var(--surface-sunken); color: var(--text-muted); }

/* Histogramme simple (statistiques) : une barre par jour ou par heure. */
.histogramme { display: flex; align-items: flex-end; gap: 3px; height: 140px; padding-top: var(--space-2); }
.histogramme > span { flex: 1; height: max(var(--h), 2px); background: var(--accent); border-radius: 2px 2px 0 0; opacity: .85; display: block; }
.histogramme > span:hover { opacity: 1; }
.histogramme.est-heures { height: 80px; }
.histogramme.est-mini { height: 56px; gap: 2px; }

/* Courbe (statistiques) : le trait se dessine de gauche à droite au chargement,
   l'aire monte dessous, et le chiffre de la carte suit le pointeur.

   Le viewBox (1000 × 260, repère utile de 10 en haut à 250 en bas) est étiré en
   largeur sans conserver les proportions, pour remplir la carte quelle que soit
   sa taille — d'où vector-effect sur le trait, sans quoi son épaisseur suivrait
   l'étirement. La révélation se fait par clip-path et non par stroke-dashoffset :
   ce dernier se calcule sur la longueur du tracé, que non-scaling-stroke rend
   fausse, et laisse le bout droit de la courbe non dessiné. */
.courbe { position: relative; display: block; height: 180px; }
.courbe.est-basse { height: 120px; }
.courbe.est-mini { height: 80px; }
.courbe svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.courbe-trait { fill: none; stroke: var(--accent); stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke;
  animation: xx-courbe-trace 1.1s var(--ease) both; }
.courbe-aire { animation: xx-courbe-monte 900ms var(--ease) 350ms both; }
@keyframes xx-courbe-trace { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
@keyframes xx-courbe-monte { from { opacity: 0; } to { opacity: 1; } }
/* Repères de lecture : le dernier point reste visible au repos, le guide et le
   point suiveur n'apparaissent que sous le pointeur. */
.courbe-fin, .courbe-curseur {
  position: absolute; display: block; width: 9px; height: 9px; border-radius: 50%;
  background: var(--accent); border: 2px solid var(--surface); box-sizing: border-box;
  transform: translate(-50%, -50%); pointer-events: none;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}
.courbe-guide { position: absolute; display: block; top: 0; bottom: 0; width: 1px;
  background: var(--border-strong); opacity: 0; pointer-events: none; transform: translateX(-.5px); }
.courbe-curseur { opacity: 0; }
.courbe.est-survole .courbe-guide, .courbe.est-survole .courbe-curseur { opacity: 1; }
.courbe.est-survole .courbe-fin { opacity: 0; }
/* Le chiffre de tête : en gros, jamais en gras — c'est sa taille qui le porte. */
.courbe-tete { display: flex; flex-direction: column; align-items: flex-end; gap: 1px; text-align: right; }
.courbe-chiffre { display: block; font-family: var(--font-num); font-size: 30px; font-weight: 400;
  line-height: 1.05; letter-spacing: -.01em; font-variant-numeric: tabular-nums; color: var(--text); }
.courbe-legende { display: block; font-size: 11.5px; color: var(--text-subtle); }
@media (prefers-reduced-motion: reduce) {
  .courbe-trait { animation: none; clip-path: none; }
  .courbe-aire { animation: none; opacity: 1; }
}

/* L'axe sous un graphe : mêmes repères pour l'histogramme et pour la courbe. */
.graphe-axe { display: flex; justify-content: space-between; font-size: 11.5px; color: var(--text-subtle); margin-top: var(--space-1); }

/* Cartes de santé du tableau de bord : la couleur dit la gravité. */
.carte-sante { display: flex; flex-direction: column; color: var(--text); text-decoration: none; border-left: 3px solid var(--border); }
.carte-sante.est-danger { border-left-color: var(--danger); }
.carte-sante.est-danger .ph { color: var(--danger); }
.carte-sante.est-warn { border-left-color: var(--warn); }
.carte-sante.est-warn .ph { color: var(--warn); }
.carte-sante.est-info .ph { color: var(--accent); }

/* Aperçu d'un résultat de recherche (carte Référencement). */
.apercu-serp {
  display: flex; flex-direction: column; gap: 2px; padding: var(--space-3);
  border: var(--filet-w) solid var(--border); border-radius: var(--radius-md); background: var(--surface);
  font-family: arial, sans-serif; min-width: 0;
}
.apercu-serp .serp-url { font-size: 12px; color: var(--text-subtle); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.apercu-serp .serp-titre { font-size: 17px; line-height: 1.3; color: #1a0dab; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.apercu-serp .serp-desc { font-size: 13px; line-height: 1.45; color: var(--text-muted);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .apercu-serp .serp-titre { color: #8ab4f8; } }
:root[data-theme="dark"] .apercu-serp .serp-titre { color: #8ab4f8; }

/* ═══════════════════════════════════════════════════════════════════════════
   LARGEURS ÉTROITES
   Deux seuils, fixes (une variable CSS ne peut pas servir dans @media) :
   · 60rem : la barre latérale devient un tiroir, les éditeurs à panneaux
     empilent leurs zones, les grilles à colonne latérale se replient ;
   · 40rem : téléphone — marges resserrées, en-têtes qui passent à la ligne,
     libellés secondaires des boutons de barre retirés.
   Rien n'est masqué qui ne soit accessible autrement.
   ═══════════════════════════════════════════════════════════════════════════ */
/* Tiroir de navigation : bouton et voile n'existent qu'en largeur étroite.
   Déclarés APRÈS .btn : le bouton porte aussi .btn, qui impose inline-flex
   à spécificité égale — placée avant, cette règle perdait. */
.nav-bascule { display: none; }
.side-voile { display: none; }

@media (max-width: 60rem) {
  .ligne-selection { grid-template-columns: 1fr 1fr; }
  .ligne-selection > [data-k="titre"] { grid-column: 1; }
  .ligne-selection > .outils { grid-column: 2; }
  .ligne-selection > :not([data-k="titre"]):not(.outils) { grid-row: auto; }
  .app { grid-template-columns: minmax(0, 1fr); }
  .side {
    position: fixed; inset: 0 auto 0 0; z-index: 55;
    width: min(280px, 86vw); overflow-y: auto;
    transform: translateX(-100%); visibility: hidden;
    transition: transform var(--dur) var(--ease), visibility 0s linear var(--dur);
  }
  .app.est-nav-ouverte .side {
    transform: none; visibility: visible; box-shadow: var(--shadow-lg);
    transition: transform var(--dur) var(--ease), visibility 0s;
  }
  .app.est-nav-ouverte .side-voile {
    display: block; position: fixed; inset: 0; z-index: 54;
    background: color-mix(in srgb, var(--surface-inverse) 45%, transparent);
  }
  .nav-bascule { display: inline-grid; place-items: center; }

  .grid-2.avec-cote, .grid-2.avec-rail { grid-template-columns: minmax(0, 1fr); gap: var(--gap-form); }
  .rail { flex-direction: row; overflow-x: auto; gap: var(--space-1); padding-bottom: var(--space-1); }
  .rail a { flex: none; }

  /* Tableaux : ils défilent plutôt que de se tasser jusqu'à l'illisible. */
  .table-wrap { overflow-x: auto; }
  .table-wrap > table { min-width: 36rem; }

  /* Éditeurs à panneaux : les zones s'empilent — liste, réglages, aperçu. */
  .schema, .perm, .arbo, .mediatheque { height: auto; overflow: visible; grid-template-columns: minmax(0, 1fr); }
  .schema { grid-template-areas: "barre" "champs" "reglages"; }
  .perm { grid-template-areas: "barre" "corps" "panneau"; }
  .arbo { grid-template-areas: "barre" "liste" "panneau" "apercu"; }
  .mediatheque { grid-template-areas: "barre" "corps" "panneau" "pied"; }
  .sc-champs, .arbre-liste, .mt-corps { max-height: 60vh; }
  .sc-reglages, .pm-panneau, .arbre-panneau, .mt-panneau { border-left: none; border-top: var(--filet-w) solid var(--border); }
  .sc-barre, .pm-barre, .arbre-barre, .mt-barre { flex-wrap: wrap; }
  /* L'élément extensible (recherche, mention) prend sa ligne plutôt que
     d'être écrasé entre les boutons. */
  .sc-barre > .grow, .pm-barre > .grow, .arbre-barre > .grow, .mt-barre > .grow { flex-basis: 100%; }
  /* La grille des rôles garde sa lisibilité : une colonne de libellés à
     largeur fixe, une colonne par rôle ; c'est le panneau qui défile.
     --nb-roles est posé par l'éditeur. */
  .pm-grille { width: calc(11rem + var(--nb-roles, 3) * 132px); }
}

@media (max-width: 40rem) {
  .ligne-date { grid-template-columns: 1fr; gap: var(--space-1); }
  .content { padding: var(--space-4); gap: var(--space-5); }
  .topbar { padding: 0 var(--space-3); gap: var(--space-2); }
  .topbar .libelle { display: none; }
  .crumb { min-width: 0; overflow: hidden; white-space: nowrap; }
  .crumb .crumb-site, .crumb > i { display: none; }
  /* Téléphone : les deux dernières étapes — d'où l'on vient, où l'on est. */
  .crumb li:not(:nth-last-child(-n+2)) { display: none; }
  .crumb li:nth-last-child(2) > i, .crumb li:nth-child(2):last-child > i { display: none; }
  .page-head { flex-wrap: wrap; }
  .page-head .grow { flex-basis: 100%; }
  .grid-2 { grid-template-columns: minmax(0, 1fr); }
  .editeur-corps { padding: var(--space-5) var(--space-4) var(--space-10); }
  /* Une ligne qui défile plutôt que trois lignes aux séparateurs orphelins. */
  .editeur-barre { flex-wrap: nowrap; overflow-x: auto; }
  .barre-groupe { flex: none; }
  /* Sur téléphone, une fenêtre est plein écran : ses contenus lisent --hauteur-fenetre. */
  .modal-veil { padding: 0; place-items: stretch; --hauteur-fenetre: 100%; }
  .mt-grille { grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); }
  /* Dans les lignes d'arbre, le détail technique (nom de champ, genre,
     adresse cible) cède la place au libellé ; il reste dans le panneau. */
  .sc-rang .cle, .sc-rang .etiq, .arbre-rang .cible { display: none; }
  .sc-outils, .arbre-outils { opacity: 1; }
  .seg { max-width: 100%; overflow-x: auto; }
}

@media (prefers-reduced-motion: reduce) {
  /* ⚠ LE FILET DE SÉCURITÉ. La liste ci-dessous dit QUI s'anime — elle a sa
     valeur de documentation — mais une liste tenue à la main prend toujours du
     retard : cinq surfaces ajoutées après coup (voile de fenêtre, notification,
     tiroir et menus du compositeur) s'animaient encore chez qui demande moins
     d'animations. Cette règle-ci les couvre toutes, et couvrira celles de
     demain sans qu'on y pense.
     Une durée minuscule plutôt que « none » : les scripts qui attendent la fin
     d'une animation (mouvement.js) reçoivent quand même leur événement. */
  *, *::before, *::after {
    animation-duration: .01ms !important; animation-iteration-count: 1 !important;
    transition-duration: .01ms !important; scroll-behavior: auto !important;
  }
  .side { transition: none; }
  .entree-droite, .entree-gauche, .entree-bas, .entree-haut, .entree-fondu, .est-sortant { animation: none; }
  .menu-blocs, .popover-lien, .menu-flottant, .coul-pop.est-ouvert, .message-flash { animation: none; }
  .mediatheque.mt-plein, .mt-justifiee.anime .mt-bloc { transition: none; }
  .arbo.arbo-plein, .schema.schema-plein, .entree.entree-plein { transition: none; }
}

/* ── Apparence (banc/apparence.html, variante B) ─────────────────────────
   L'aperçu en grand, les réglages dans un panneau à droite, sections en
   onglets à icônes. L'aperçu est un cadre sans script : la vraie page du
   site, dessinée à sa vraie largeur puis réduite. */
.content:has(> .ap-plein) { padding: 0; }
.ap-corps { display: grid; grid-template-columns: minmax(0, 1fr) 400px; align-items: start; min-height: calc(100vh - 65px - var(--haut-visible)); }
.ap-vue { display: block; padding: var(--space-5) var(--pad-section); position: sticky; top: 65px; }
.ap-barre .select { width: auto; max-width: 16rem; height: 32px; flex-shrink: 1; min-width: 8rem; }
.ap-barre [hidden] { display: none; }
.ap-barre .seg { flex: none; }
.ap-points { display: inline-flex; gap: 6px; margin-right: 6px; flex: none; }
.ap-points i { display: block; width: 10px; height: 10px; border-radius: 50%; background: var(--border-strong); }
.ap-cadre { display: block; border: var(--filet-w) solid var(--border); border-radius: var(--radius-lg); overflow: hidden; background: var(--surface-2); box-shadow: var(--shadow-sm); }
.ap-onglet-nav { display: flex; align-items: center; gap: 8px; height: 32px; padding: 0 12px; background: var(--surface); border-bottom: var(--filet-w) solid var(--border); font-size: 12px; color: var(--text-muted); }
.ap-fav { display: inline-block; width: 14px; height: 14px; border-radius: 3px; background: var(--surface-2) center / cover no-repeat; flex: none; }
.ap-url { margin-left: auto; font-family: var(--font-num); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ap-defile { display: block; max-height: calc(100vh - 65px - 90px - var(--haut-visible)); overflow-y: auto; overscroll-behavior: contain; }
.ap-echelle { display: block; position: relative; overflow: hidden; margin: 0 auto; min-height: 200px; }
.ap-echelle iframe { display: block; position: absolute; top: 0; left: 0; border: 0; transform-origin: 0 0; background: #fff; }
.ap-echelle.est-telephone { border-left: var(--filet-w) solid var(--border); border-right: var(--filet-w) solid var(--border); }
.ap-attente { display: flex; align-items: center; justify-content: center; gap: var(--space-2); height: 200px; color: var(--text-subtle); font-size: 13px; }
.ap-tiroir { display: block; border-left: var(--filet-w) solid var(--border); background: var(--surface); min-height: calc(100vh - 65px - var(--haut-visible)); }
.ap-onglets { display: flex; gap: 2px; padding: var(--space-3); border-bottom: var(--filet-w) solid var(--border); position: sticky; top: 65px; background: var(--surface); z-index: 2; }
.ap-onglets button { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 6px 2px; border: 0; background: none; border-radius: var(--radius-md);
  font: inherit; font-size: 10.5px; color: var(--text-muted); cursor: pointer; min-width: 0; }
.ap-onglets button i { font-size: 18px; }
.ap-onglets button:hover { background: var(--surface-2); color: var(--text); }
.ap-onglets button:focus-visible,
.cp-onglets button:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.ap-onglets button[aria-selected="true"] { background: var(--accent-soft); color: var(--accent-soft-text); font-weight: 600; }
.ap-form { display: block; padding: var(--space-5); }
.ap-panneau { display: flex; flex-direction: column; gap: var(--space-5); }
/* Les réglages ont parfois cinq ou six choix : le sélecteur passe à la ligne
   plutôt que de déborder du panneau, et ses segments se partagent la place. */
.ap-panneau .seg { display: flex; flex-wrap: wrap; }
.ap-panneau .seg button { flex: 1 0 auto; justify-content: center; }
.ap-panneau[hidden] { display: none; }
.label-ligne { display: flex; align-items: center; gap: 6px; }
.retablir { display: inline-flex; border: 0; background: none; color: var(--text-subtle); cursor: pointer; padding: 2px 4px; border-radius: var(--radius-sm); font-size: 14px; line-height: 1; }
.retablir[hidden] { display: none; }
.retablir:hover { color: var(--accent); background: var(--accent-soft); }
.retablir:focus-visible { outline: none; box-shadow: var(--focus-ring); }
/* Réglages qui dépendent d'un interrupteur (bouton, filet de l'en-tête). */
.est-dependant { display: flex; flex-direction: column; gap: var(--space-4); padding-left: var(--space-3); border-left: 2px solid var(--border); }
.est-dependant[hidden] { display: none; }
.ap-note { display: block; margin: 0; font-size: 12.5px; color: var(--text-muted); border-left: 2px solid var(--border-strong); padding-left: var(--space-3); }

.ap-couleurs { display: table; width: 100%; border-collapse: collapse; }
.ap-couleurs th { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .06em; color: var(--text-subtle); text-align: left; padding: 0 0 6px; }
.ap-couleurs td { padding: 4px 0; vertical-align: middle; font-size: 13px; }
.ap-couleurs td:first-child { width: 30%; }
.ap-couleurs td:first-child small { display: block; color: var(--text-subtle); font-size: 11.5px; }
.ap-couleurs .ap-sous { padding-top: var(--space-3); }
.ap-couleurs .ap-derivee td:first-child { color: var(--text-muted); }
.ap-couleurs .est-inactif { opacity: .35; }
.ap-couleurs .est-inactif input { pointer-events: none; }
.ap-teinte { display: inline-flex; align-items: center; gap: 5px; }
.ap-teinte input[type=color] { width: 28px; height: 28px; padding: 0; border: var(--filet-w) solid var(--border); border-radius: var(--radius-md); background: none; cursor: pointer; flex: none; }
.ap-teinte input[type=color]::-webkit-color-swatch-wrapper { padding: 0; }
.ap-teinte input[type=color]::-webkit-color-swatch { border: none; border-radius: calc(var(--radius-md) - 1px); }
.ap-teinte .input.ap-code-long { width: 150px; }
.ap-teinte .input { width: 74px; height: 28px; font-family: var(--font-num); font-size: 12px; padding: 0 6px; }
.ap-teinte .input[aria-invalid="true"] { border-color: var(--danger); }
.ap-puce { display: inline-block; width: 28px; height: 28px; border-radius: var(--radius-md); border: var(--filet-w) solid var(--border); flex: none; }
.ap-teinte code { font-size: 11.5px; color: var(--text-subtle); }
.ap-lisib { display: flex; flex-direction: column; gap: 4px; }
.ap-lisib > b { font-size: 13px; margin-bottom: 2px; }
.ap-lisib div { display: flex; align-items: flex-start; gap: 8px; font-size: 12.5px; }
.ap-lisib div > i { flex: none; margin-top: 2px; }
.ap-lisib .r { font-family: var(--font-num); font-size: 12px; margin-left: auto; color: var(--text-muted); white-space: nowrap; }
.ap-lisib .est-ok { color: var(--ok); } .ap-lisib .est-ko { color: var(--danger); } .ap-lisib .est-auto { color: var(--info); }
.ap-lisib .note { color: var(--text-subtle); }

.ap-filtre-polices { display: inline-flex; align-self: flex-start; }
.ap-polices { display: flex; flex-direction: column; position: relative; border: var(--filet-w) solid var(--border); border-radius: var(--radius-md); max-height: 232px; overflow: auto; }
.ap-polices label { display: flex; align-items: center; gap: 10px; padding: 7px 10px; border-bottom: var(--filet-w) solid var(--border); cursor: pointer; }
.ap-polices label:last-child { border-bottom: 0; }
.ap-polices label[hidden] { display: none; }
.ap-polices label:hover { background: var(--surface-2); }
.ap-polices label:has(input:checked) { background: var(--accent-soft); }
.ap-polices label:has(input:focus-visible) { box-shadow: inset var(--focus-ring); }
.ap-polices input { position: absolute; opacity: 0; pointer-events: none; }
.ap-spec { display: inline-block; font-size: 20px; width: 40px; flex: none; color: var(--text); line-height: 1; }
.ap-police-nom { display: inline; font-size: 13px; font-weight: 500; }
.ap-genre { display: inline; font-size: 11px; color: var(--text-subtle); margin-left: auto; }
.ap-envoyee { display: inline-block; font-size: 10.5px; padding: 1px 6px; border-radius: 99px; background: var(--surface-2); color: var(--text-muted); }
.ap-depot { display: flex; align-items: center; gap: 12px; border: 1.5px dashed var(--border-strong); border-radius: var(--radius-md); padding: 12px; font-size: 12.5px; color: var(--text-muted); }
.ap-envoi-police { display: flex; flex-direction: column; gap: var(--space-3); padding: var(--space-4); background: var(--surface-2); border-radius: var(--radius-md); }
.ap-envoi-police[hidden] { display: none; }

.ap-themes { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-3); }
.ap-theme { display: flex; flex-direction: column; border: var(--filet-w) solid var(--border); border-radius: var(--radius-lg); overflow: hidden; background: var(--surface); }
.ap-theme.est-actif { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.ap-theme.est-vu { border-color: var(--info); }
.ap-theme-vignette { display: flex; flex-direction: column; justify-content: flex-end; gap: 6px; height: 80px; padding: 10px; }
.ap-theme-vignette b { font-size: 19px; line-height: 1; }
.ap-pastilles { display: flex; gap: 4px; }
.ap-pastilles span { display: block; width: 13px; height: 13px; border-radius: 50%; border: 1px solid rgb(0 0 0 / .12); }
.ap-theme-corps { display: flex; flex-direction: column; gap: 6px; padding: 10px 12px; font-size: 12.5px; flex: 1; }
.ap-theme-corps p { margin: 0; color: var(--text-muted); }
.ap-theme-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; margin-top: auto; }
.ap-css { display: block; font-family: var(--font-num); font-size: 11.5px; line-height: 1.55; background: var(--surface-2); border-radius: var(--radius-md);
  padding: 10px 12px; margin: 0; white-space: pre; overflow: auto; max-height: 260px; color: var(--text-muted); }

@media (max-width: 60rem) {
  .ap-corps { grid-template-columns: minmax(0, 1fr); }
  .ap-vue { position: static; padding: var(--space-4); }
  .ap-barre [data-etat] { display: none; }
  .ap-defile { max-height: 60vh; }
  .ap-tiroir { border-left: 0; border-top: var(--filet-w) solid var(--border); min-height: 0; }
  .ap-onglets { top: 65px; }
}

/* ── Choix d'une image (champ Image, logo, favicon, 404, menus) ──────────
   La vignette entière se clique : pas de bouton « Choisir » à côté. Au
   survol, elle dit ce qu'un clic fera ; une croix, dans le coin, retire. */
.champ-image { display: block; position: relative; width: 100%; }
.choix-vignette { display: grid; place-items: center; width: 100%; padding: 0; border: var(--filet-w) solid var(--border); border-radius: var(--radius-md);
  background: var(--surface-sunken); color: var(--text-subtle); overflow: hidden; cursor: pointer; position: relative; font: inherit;
  transition: border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease); }
.choix-vignette.est-vide { border-style: dashed; border-color: var(--border-strong); }
.choix-vignette:hover { border-color: var(--accent); }
.choix-vignette.est-vide:hover { background: var(--accent-soft); color: var(--accent-soft-text); }
.choix-vignette:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.choix-vignette:disabled { cursor: default; }
.choix-vignette img { display: block; position: absolute; inset: 0; width: 100%; height: 100%; }
.choix-vignette .doc-nom { position: relative; }
.choix-vignette:not(.est-vide):not(:disabled)::after { content: "Changer"; position: absolute; left: 50%; bottom: 10px; transform: translateX(-50%);
  padding: 3px 10px; border-radius: var(--radius-pill); background: rgb(0 0 0 / .62); color: #fff; font-size: 12px; font-weight: 500;
  opacity: 0; transition: opacity var(--dur-fast) var(--ease); }
.choix-vignette:hover::after, .choix-vignette:focus-visible::after { opacity: 1; }
.choix-vide { display: flex; flex-direction: column; align-items: center; gap: 6px; font-size: 12.5px; font-weight: 500; }
.choix-vide i { font-size: 26px; }
.choix-retirer { display: grid; place-items: center; position: absolute; top: 8px; right: 8px; width: 28px; height: 28px; border-radius: 50%;
  border: var(--filet-w) solid var(--border); background: var(--surface); color: var(--text-muted); cursor: pointer; box-shadow: var(--shadow-sm); }
.choix-retirer[hidden] { display: none; }
.choix-retirer:hover { color: var(--danger); border-color: var(--danger); }
.choix-retirer:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* Un interrupteur dans la ligne d'un champ garde sa taille (la règle des
   libellés, flex: 1, l'étirait). */
.field .pied > label.switch { flex: none; }

/* ── Sélecteur de couleur (design-system/composants/couleurs.js) ────────
   Le composant commun de Blok (_color-picker.php) : une pastille à damier,
   un popover — aplat, dégradé, aléatoire ; saturation/valeur, teinte,
   transparence ; nom approché (Sanzō Wada) ; code. */
.coul-pastille { display: inline-block; position: relative; width: 34px; height: 28px; padding: 0; flex: none; cursor: pointer; overflow: hidden;
  border: var(--filet-w) solid var(--border); border-radius: var(--radius-md);
  background-image: linear-gradient(45deg, #8883 25%, transparent 25%, transparent 75%, #8883 75%), linear-gradient(45deg, #8883 25%, transparent 25%, transparent 75%, #8883 75%);
  background-size: 10px 10px; background-position: 0 0, 5px 5px; }
.coul-pastille::after { content: ""; position: absolute; inset: 0; background: var(--sw, transparent); }
.coul-pastille:hover { border-color: var(--border-strong); }
.coul-pastille:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.coul-pop { display: none; position: fixed; z-index: 90; width: 236px; padding: 12px; background: var(--surface);
  border: var(--border-w) solid var(--border-strong); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); font-size: 13px; }
.coul-pop.est-ouvert { display: block; }
.coul-pop [hidden] { display: none !important; }
.coul-onglets { display: flex; gap: 4px; margin-bottom: 10px; }
.coul-onglet { display: block; flex: 1; padding: 5px 0; border: var(--border-w) solid transparent; border-radius: var(--radius-md); background: var(--surface-2);
  color: var(--text-muted); font: inherit; font-size: 11px; text-align: center; cursor: pointer; }
.coul-onglet.est-actif { background: var(--accent); color: var(--accent-text); }
.coul-onglet:disabled { opacity: .4; cursor: not-allowed; }
.coul-onglet:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.coul-sv { display: block; position: relative; width: 100%; height: 132px; margin-bottom: 10px; border-radius: var(--radius-md); cursor: crosshair; touch-action: none;
  background: linear-gradient(to top, #000, transparent), linear-gradient(to right, #fff, transparent), var(--coul-teinte, #f00); }
.coul-sv-point { display: block; position: absolute; width: 12px; height: 12px; border: 2px solid #fff; border-radius: 50%; box-shadow: 0 0 0 1px #0006; transform: translate(-50%, -50%); pointer-events: none; }
.coul-curseur { display: block; position: relative; height: 12px; margin-bottom: 9px; border-radius: 6px; cursor: pointer; touch-action: none; }
.coul-teinte { background: linear-gradient(to right, #f00, #ff0, #0f0, #0ff, #00f, #f0f, #f00); }
.coul-alpha { background-image: linear-gradient(45deg, #8886 25%, transparent 25%, transparent 75%, #8886 75%), linear-gradient(45deg, #8886 25%, transparent 25%, transparent 75%, #8886 75%);
  background-size: 8px 8px; background-position: 0 0, 4px 4px; }
.coul-alpha::after { content: ""; position: absolute; inset: 0; border-radius: 6px; background: var(--coul-alpha-degrade, linear-gradient(to right, transparent, #000)); }
.coul-bouton { display: block; position: absolute; top: 50%; z-index: 2; width: 16px; height: 16px; border: 2px solid #fff; border-radius: 50%; box-shadow: 0 0 0 1px #0006; transform: translate(-50%, -50%); pointer-events: none; }
.coul-degrade { display: block; margin-bottom: 10px; }
.coul-degrade-barre { display: block; height: 22px; margin-bottom: 8px; border: var(--filet-w) solid var(--border); border-radius: var(--radius-md); background: var(--coul-apercu); }
.coul-arrets { display: flex; gap: 6px; margin-bottom: 8px; }
.coul-arret { display: block; flex: 1; position: relative; height: 26px; padding: 0; overflow: hidden; border: 2px solid transparent; border-radius: var(--radius-md); cursor: pointer; background: none; }
.coul-arret::after { content: ""; position: absolute; inset: 0; background: var(--st); }
.coul-arret.est-actif { border-color: var(--accent); }
.coul-angle-ligne { display: flex; align-items: center; gap: 8px; font-size: 11.5px; color: var(--text-muted); }
.coul-angle { flex: 1; accent-color: var(--accent); }
.coul-angle-v { display: inline-block; width: 30px; text-align: right; }
.coul-hasard { display: block; padding: 4px 0 2px; }
.coul-hasard-echantillon { display: block; height: 96px; margin-bottom: 4px; border: var(--filet-w) solid var(--border); border-radius: var(--radius-md);
  background: var(--coul-hasard, #888); transition: background .35s ease; }
.coul-nom { display: block; min-height: 1.1em; margin: 2px 0 8px; font-size: 12px; font-weight: 500; color: var(--text); }
.coul-approx { color: var(--text-muted); font-weight: 400; }
.coul-pied { display: flex; gap: 6px; align-items: center; margin-top: 4px; }
.coul-code { display: block; flex: 1; min-width: 0; padding: 6px 8px; border: var(--filet-w) solid var(--border); border-radius: var(--radius-md); background: var(--surface-2);
  color: var(--text); font-family: var(--font-num); font-size: 12px; outline: none; }
.coul-code:focus { border-color: var(--accent); }
.coul-note { display: block; margin-top: 8px; font-size: 11px; line-height: 1.4; color: var(--text-muted); }
.coul-note:empty { display: none; }

/* ── Journal d'activité (Réglages → Journal) ─────────────────────────────
   Une ligne par geste, groupées par jour : l'heure, l'icône du geste, la
   phrase (« Ronan a publié « … » »), le lien vers l'objet. */
.jn-outils { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); margin-bottom: var(--space-4); }
.jn-outils .seg a { display: inline-flex; align-items: center; gap: 4px; }
.jn-choix { display: flex; gap: var(--space-2); margin-left: auto; }
.jn-choix .select { width: auto; height: 32px; }
.journal { display: block; list-style: none; margin: 0; padding: 0; }
.jn-jour { display: block; padding: var(--space-4) 0 var(--space-2); font-size: 11px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: var(--text-subtle);
  border-bottom: var(--filet-w) solid var(--border); }
.jn-ligne { display: flex; align-items: flex-start; gap: var(--space-3); padding: 9px 0; border-bottom: var(--filet-w) solid var(--border); font-size: 13.5px; }
.jn-heure { display: inline-block; width: 38px; flex: none; font-family: var(--font-num); font-size: 12px; color: var(--text-subtle); padding-top: 2px; }
.jn-icone { display: grid; place-items: center; width: 24px; height: 24px; flex: none; border-radius: 50%; background: var(--surface-2); color: var(--text-muted); font-size: 13px; }
.jn-texte { display: block; flex: 1; min-width: 0; line-height: 1.5; }
.jn-texte a { color: var(--accent); }
.jn-detail { color: var(--text-subtle); }
.jn-pages { display: flex; align-items: center; margin: var(--space-4) 0; }
.jn-pages .grow { flex: 1; }
@media (max-width: 40rem) { .jn-outils .seg .libelle { display: none; } .jn-choix { margin-left: 0; } }
.jn-note { display: block; margin-top: var(--space-3); font-size: 12px; color: var(--text-subtle); }

/* ── Bloc repliable animé (<details class="depliable">, mouvement.js) ─────
   Le contenu arrive en fondu pendant que le bloc s'agrandit ; le résumé
   garde son chevron, qui pivote. */
details.depliable > summary { list-style: none; }
details.depliable > summary::-webkit-details-marker { display: none; }
details.depliable[open] > :not(summary) { animation: xx-surgit var(--dur-lent) var(--ease) both; }
details.depliable.est-replie > :not(summary) { opacity: 0; transition: opacity var(--dur) var(--ease-sortie); }
.chevron-depliable { display: inline-block; transition: transform var(--dur) var(--ease); }
details.depliable[open]:not(.est-replie) .chevron-depliable { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) {
  details.depliable[open] > :not(summary) { animation: none; }
  .chevron-depliable { transition: none; }
}

/* ⚠ L'écran scindé des contenus (liste à gauche, réglages à droite) a vécu :
   la page publique d'un type se modifie dans son propre éditeur, et un bouton
   de la barre y mène. Une colonne entière pour deux liens ne se justifiait
   plus. Retiré en 0.9.95 — si un écran scindé revient, c'est une occasion de
   le redessiner, pas de ressortir celui-ci. */
/* ── « Affiner » : les réglages fins, repliés (schema.js) ─────────────────
   Un résumé discret qui ne pèse pas dans le panneau tant qu'on n'en a pas
   besoin ; le chevron pivote comme partout ailleurs. */
details.affiner { margin-top: var(--space-2); }
details.affiner > summary { list-style: none; cursor: pointer; display: inline-flex; align-items: center; gap: 6px;
  font-size: 12.5px; font-weight: 600; color: var(--text-subtle); padding: 4px 0; }
details.affiner > summary::-webkit-details-marker { display: none; }
details.affiner > summary:hover { color: var(--text); }
details.affiner[open] > summary .chevron-depliable { transform: rotate(180deg); }

/* ── Petits menus flottants : ils s'ouvrent depuis leur bouton ───────────
   L'animation rejoue chaque fois que l'élément passe de caché à affiché ;
   la fermeture reste instantanée (on a fini, on ne fait pas attendre). */
@keyframes xx-ouvre { from { opacity: 0; transform: translateY(-4px) scale(.97); } }
.menu-blocs, .menu-flottant { animation: xx-ouvre var(--dur) var(--ease) both; transform-origin: top left; }
/* La fenêtre du compte s'ouvre vers le haut : elle arrive donc d'en bas, à
   l'inverse des menus qui tombent. */
@keyframes xx-ouvre-haut { from { opacity: 0; transform: translateY(4px) scale(.97); } }
.side-menu { animation: xx-ouvre-haut var(--dur) var(--ease) both; }
/* Le popover de lien est centré par translateX(-50%) : l'animation le garde. */
@keyframes xx-ouvre-centre { from { opacity: 0; transform: translateX(-50%) translateY(-4px) scale(.97); } }
.popover-lien { animation: xx-ouvre-centre var(--dur) var(--ease) both; transform-origin: top center; }
.coul-pop.est-ouvert { animation: xx-ouvre var(--dur) var(--ease) both; transform-origin: top left; }
/* Message après un enregistrement : il PASSE PAR-DESSUS la page, en BAS de la zone de contenu.
   Dans le flux, il la poussait vers le bas le temps de s'afficher, puis la tirait en arrière en
   partant : tout l'écran sautait deux fois pour une phrase.
   ⚠ Pas en haut : il y recouvre le titre de la page, ou les boutons d'action (« Enregistrer » est
   tout en haut à droite des éditeurs). Pas centré sur la FENÊTRE non plus : il débordait sur la
   barre latérale (constaté le 07/10 sur ouisimone.fr). Il est centré sur la zone de contenu — à
   droite des 240 px de la barre latérale, qui devient un tiroir sous 60 rem — sans transform
   (l'animation en a un). Une erreur reste plus longtemps (coque.js). */
@keyframes xx-entre-bas { from { opacity: 0; transform: translateY(var(--entree-distance, 24px)); } }
.message-flash { animation: xx-entre-bas var(--dur-lent) var(--ease) both; --entree-distance: 10px; }
.message-flash { align-items: center; position: fixed; z-index: 80; bottom: var(--space-5); top: auto;
  left: 240px; right: 0; margin-inline: auto;
  width: min(40rem, calc(100vw - 240px - 2 * var(--space-4))); box-shadow: var(--shadow-lg); }
@media (max-width: 60rem) { .message-flash { left: 0; width: min(40rem, calc(100vw - 2 * var(--space-4))); } }
.message-flash a { color: inherit; font-weight: 600; text-decoration: underline; }
.message-flash .message-fermer { margin: -6px -6px -6px 0; color: inherit; opacity: .7; }
.message-flash .message-fermer:hover { opacity: 1; background: color-mix(in srgb, currentColor 10%, transparent); }

/* Une version signée attend : un BLOC PLEIN en couleur d'accent, tout en haut du
   tableau de bord, avec son bouton. Texte en --accent-text (lisible sur l'accent, en
   clair comme en sombre) ; le bouton s'inverse — fond de la page, texte d'accent — pour
   se détacher du bloc au lieu de s'y fondre. */

/* Une ligne qui vient d'arriver (mouvement.js → flip) : elle entre, et un
   liseré d'accent la signale un instant. */
@keyframes xx-arrive {
  0%   { opacity: 0; transform: translateY(-6px); box-shadow: 0 0 0 2px var(--accent); }
  25%  { opacity: 1; transform: none; box-shadow: 0 0 0 2px var(--accent); }
  100% { box-shadow: 0 0 0 2px transparent; }
}
.vient-d-arriver { animation: xx-arrive 1.1s var(--ease) both; }
@media (prefers-reduced-motion: reduce) { .vient-d-arriver { animation: none; } }

/* ── Historique des menus, réglages, apparence (config_historique.php) ───
   Les versions à gauche, la comparaison à droite ; un menu se compare ligne
   à ligne (− dans cette version seulement, + aujourd'hui seulement). */
.cfg-hist { display: grid; grid-template-columns: 300px minmax(0, 1fr); gap: var(--space-8); align-items: start; }
.cfg-hist nav { position: sticky; top: 81px; }
.hi-version.est-choisi { background: var(--accent-soft); }
.cfg-comparaison { display: block; min-width: 0; }
.cfg-legende { display: flex; gap: var(--space-4); margin: 0 0 var(--space-2); font-size: 12px; }
.cfg-lignes { display: block; list-style: none; margin: 0; padding: 0; border: var(--filet-w) solid var(--border); border-radius: var(--radius-md); overflow: hidden;
  font-family: var(--font-num); font-size: 12.5px; }
.cfg-lignes li { display: flex; gap: var(--space-2); padding: 3px var(--space-3); border-bottom: var(--filet-w) solid var(--border); }
.cfg-lignes li:last-child { border-bottom: 0; }
.cfg-signe { display: inline-block; width: 12px; flex: none; font-weight: 700; }
.cfg-texte { display: block; white-space: pre-wrap; min-width: 0; }
.cfg-moins { color: var(--danger-soft-text); }
.cfg-lignes .cfg-moins { background: var(--danger-soft); }
.cfg-plus { color: var(--ok-soft-text); }
.cfg-lignes .cfg-plus { background: var(--ok-soft); }
@media (max-width: 60rem) { .cfg-hist { grid-template-columns: minmax(0, 1fr); } .cfg-hist nav { position: static; } }

/* Bandeau « session expirée » (ressources/admin/session.js) : au-dessus de
   tout, en haut au centre, tant que la session n'est pas retrouvée. */
.session-perdue { position: fixed; top: 12px; left: 50%; transform: translateX(-50%); z-index: 100; width: min(640px, calc(100vw - 32px)); box-shadow: var(--shadow-lg);
  animation: xx-session var(--dur-lent) var(--ease) both; }
@keyframes xx-session { from { opacity: 0; transform: translateX(-50%) translateY(-10px); } }
@media (prefers-reduced-motion: reduce) { .session-perdue { animation: none; } }

/* ── Composition d'une page (ressources/admin/composition.js) ─────────────
   banc/composition.html, variante « B + plan » : le plan (escamotable), la
   page telle que le thème la dessine, le tiroir — la page (le formulaire) ou
   le bloc choisi. Sur téléphone, le plan est la vue d'entrée. */
.en-corps.cp-corps { display: grid; grid-template-columns: 290px minmax(0, 1fr) 400px; align-items: start; gap: 0; padding: 0;
  transition: grid-template-columns var(--dur-lent) var(--ease); }
.entree-composition.sans-plan .cp-corps { grid-template-columns: 0px minmax(0, 1fr) 400px; }
.cp-plan, .cp-tiroir { display: block; position: sticky; top: var(--barre-h); height: calc(100vh - var(--barre-h) - var(--haut-visible)); overflow-y: auto; overscroll-behavior: contain; background: var(--surface); }
.cp-plan { border-right: var(--filet-w) solid var(--border); overflow-x: hidden; }
/* Le plan glisse : la colonne s'ouvre, son contenu arrive un peu après et
   repart un peu avant ; replié, il n'est plus atteignable (visibility, après
   la sortie). */
.cp-plan { transition: visibility 0s linear 0s; }
.sans-plan .cp-plan { visibility: hidden; transition: visibility 0s linear var(--dur-lent); }
.cp-plan-int { min-width: 290px; display: flex; flex-direction: column; gap: var(--space-2); padding: var(--space-4) var(--space-3);
  transition: opacity var(--dur) var(--ease) 80ms, transform var(--dur-lent) var(--ease); }
.sans-plan .cp-plan-int { opacity: 0; transform: translateX(-24px); transition: opacity var(--dur-fast) var(--ease-sortie), transform var(--dur) var(--ease-sortie); }
@media (prefers-reduced-motion: reduce) { .en-corps.cp-corps, .cp-plan-int { transition: none; } }
.cp-plan-tete { display: flex; align-items: baseline; gap: 6px; padding: 0 4px; font-size: 11px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: var(--text-subtle); }
.cp-plan-tete span { font-weight: 400; letter-spacing: 0; text-transform: none; font-family: var(--font-num); }
.cp-tiroir { border-left: var(--filet-w) solid var(--border); }
.cp-tiroir-page { display: flex; flex-direction: column; gap: var(--gap-form); padding: var(--space-4); }
.cp-tiroir-page .grid-2.avec-cote { grid-template-columns: minmax(0, 1fr); }
.cp-tiroir-bloc { display: flex; flex-direction: column; gap: var(--space-4); padding: var(--space-4) var(--space-5) var(--space-10); animation: xx-surgit var(--dur) var(--ease); }
.cp-tiroir-tete { display: flex; align-items: center; gap: var(--space-2); position: sticky; top: calc(-1 * var(--space-4)); z-index: 3; background: var(--surface);
  margin: calc(-1 * var(--space-4)) calc(-1 * var(--space-5)) 0; padding: var(--space-3) var(--space-4) var(--space-3) var(--space-5); border-bottom: var(--filet-w) solid var(--border); }
.cp-tiroir-tete b { flex: 1; font-size: 14px; }
.cp-ic { width: 30px; height: 30px; flex: none; display: grid; place-items: center; border-radius: var(--radius-md); background: var(--surface-2); color: var(--text-muted); font-size: 16px; }
.cp-tiroir-tete .cp-ic { background: var(--accent-soft); color: var(--accent-soft-text); }
.cp-scene { display: block; min-width: 0; padding: var(--space-5); position: sticky; top: var(--barre-h); }
.cp-defile { max-height: calc(100vh - var(--barre-h) - var(--haut-visible) - 2 * var(--space-5) - 34px); }
.cp-defile:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* Le plan : une ligne par bloc. */
.cp-blocs { display: flex; flex-direction: column; }
.cp-rang { border: var(--border-w) solid transparent; border-radius: var(--radius-md); }
.cp-rang:hover { background: var(--surface-2); }
.cp-rang.est-choisi { background: var(--accent-soft); }
.cp-rang.est-saisi { opacity: .4; }
.cp-rang.cible-avant { box-shadow: 0 -3px 0 var(--accent); }
.cp-rang.cible-apres { box-shadow: 0 3px 0 var(--accent); }
.cp-rang-tete { display: flex; align-items: center; gap: var(--space-2); padding: 6px; cursor: pointer; border-radius: var(--radius-md); }
.cp-rang-tete:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.cp-rang-tete .cp-ic { width: 26px; height: 26px; font-size: 14px; }
.cp-rang.est-choisi .cp-ic { background: var(--surface); color: var(--accent-soft-text); }
.cp-rang-txt { flex: 1; min-width: 0; display: flex; flex-direction: column; }
/* ⚠ LE TITRE SE TRONQUE, LUI AUSSI. Le résumé avait `overflow: hidden`,
   pas le nom du bloc : quand la colonne se resserrait, il débordait de sa
   case et se peignait par-dessus la pastille voisine. Rien n'était en
   défaut — ni PHP, ni JS — et l'œil seul le voyait. */
.cp-rang-txt b { font-size: 12.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cp-rang-txt span { font-size: 11.5px; color: var(--text-subtle); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cp-poignee { color: var(--text-subtle); cursor: grab; flex: none; }
.cp-defaut { display: inline-block; align-self: flex-start; max-width: 100%; font-size: 10.5px; color: var(--warn-soft-text);
  background: var(--warn-soft); border-radius: 99px; padding: 1px 6px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cp-outils { display: none; gap: 2px; flex: none; }
/* ⚠ PLUS D'OUTILS SUR UN RANG DU PLAN. Ils n'y montraient que monter et
   descendre — dup et suppr y étaient masqués — c'est-à-dire exactement les
   deux commandes que `ranger()` pose déjà après la poignée, toujours
   visibles pour le doigt. Le même geste deux fois, 54 px sur 252. */
.cp-tiroir-tete .cp-outils { display: flex; }
.cp-outils button { width: 26px; height: 26px; display: grid; place-items: center; border: 0; border-radius: var(--radius-sm); background: none; color: var(--text-muted); cursor: pointer; }
.cp-outils button:hover { background: var(--surface-2); color: var(--text); }
.cp-outils button.danger:hover { color: var(--danger); }
.cp-outils button:focus-visible, .cp-quand button:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.cp-inserer { position: relative; height: 10px; display: flex; align-items: center; justify-content: center; }
.cp-inserer::before { content: ""; position: absolute; left: 10px; right: 10px; top: 50%; height: 2px; background: var(--accent); opacity: 0; transition: opacity var(--dur-fast); }
.cp-inserer button { position: relative; z-index: 1; width: 22px; height: 22px; display: grid; place-items: center; border-radius: 50%; border: var(--border-w) solid var(--accent);
  background: var(--surface); color: var(--accent); cursor: pointer; opacity: 0; transition: opacity var(--dur-fast) var(--ease); }
.cp-inserer:hover::before { opacity: .5; }
.cp-inserer:hover button, .cp-inserer button:focus-visible { opacity: 1; }
.cp-plan-vide { display: block; font-size: 12.5px; color: var(--text-muted); padding: var(--space-2) 4px; }

/* Le menu des blocs (insertion). */
.cp-menu { display: block; position: fixed; z-index: 70; width: 300px; max-height: calc(100vh - 16px); overflow-y: auto; padding: 6px; background: var(--surface);
  border: var(--filet-w) solid var(--border); border-radius: var(--radius-md); box-shadow: var(--shadow-lg); animation: xx-ouvre var(--dur) var(--ease) both; }
.cp-menu[hidden] { display: none; }
.cp-menu button { display: flex; align-items: center; gap: 10px; width: 100%; padding: 8px; border: 0; border-radius: var(--radius-sm); background: none; color: var(--text); font: inherit; text-align: left; cursor: pointer; }
.cp-menu button:hover, .cp-menu button:focus-visible { background: var(--surface-2); outline: none; }
.cp-menu b { display: block; font-size: 13px; }
.cp-menu small { display: block; font-size: 11.5px; color: var(--text-subtle); }

/* Les formulaires des blocs. */
.cp-elements { display: flex; flex-direction: column; gap: var(--space-2); }
.cp-element { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--space-2); padding: 10px; border: var(--filet-w) solid var(--border); border-radius: var(--radius-md); background: var(--surface-2); }
.cp-element > div { display: flex; flex-direction: column; gap: var(--space-2); }
.cp-deux { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--space-3); }
.cp-images { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; }
.cp-images .choix-vignette { aspect-ratio: 1; }
.cp-images img, .cp-vignette img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.cp-vignette { position: relative; overflow: hidden; }
/* Ouverture : boutons (libellé, destination, style), placement, couleurs. */
.cp-bouton { display: flex; flex-direction: column; gap: var(--space-2); padding: 10px; border: var(--filet-w) solid var(--border); border-radius: var(--radius-md); background: var(--surface-2); }
.cp-bouton-tete { display: flex; align-items: center; gap: var(--space-2); font-size: 12px; font-weight: 600; color: var(--text-muted); }
.cp-bouton-tete .grow { flex: 1; }
.cp-styles { display: flex; align-self: stretch; }
.cp-styles button { flex: 1; font-size: 12px; justify-content: center; }
.cp-aligner { display: flex; flex-wrap: wrap; gap: var(--space-3); }
.cp-seg-icones button { width: 34px; justify-content: center; font-size: 16px; }
.ap-teinte .input.cp-code { width: 210px; }
.cp-mauvais { color: var(--danger); }
/* Sélecteur d'icônes (colonnes) : recherche, grille, la choisie marquée. */
/* Épinglés d'une sélection : une liste courte, réordonnable. */
.cp-epingles { display: flex; flex-direction: column; gap: 2px; margin: 0 0 var(--space-2); padding: 0; list-style: none; }
.cp-epingles li { display: flex; align-items: center; gap: var(--space-2); padding: 4px 4px 4px 10px; border: var(--filet-w) solid var(--border); border-radius: var(--radius-sm); background: var(--surface-2); font-size: 13px; }
.cp-epingles .cp-outils { display: flex; }
.cp-epingles li > .grow { flex: 1 1 auto; }
.cp-epingles .cp-outils { margin-inline-start: auto; }
.cp-epingles button:disabled { opacity: .35; cursor: default; }
.cp-icone-choix { display: flex; align-items: center; gap: var(--space-2); }
.cp-icones { display: flex; flex-direction: column; gap: var(--space-2); position: fixed; z-index: 70; width: 340px; max-height: min(420px, calc(100vh - 16px));
  padding: var(--space-3); background: var(--surface); border: var(--filet-w) solid var(--border); border-radius: var(--radius-md); box-shadow: var(--shadow-lg);
  animation: xx-ouvre var(--dur) var(--ease) both; }
.cp-icones[hidden] { display: none; }
.cp-icones > :is(.input, .help) { flex: none; }
.cp-icones-grille { display: grid; grid-template-columns: repeat(auto-fill, minmax(40px, 1fr)); gap: 4px; overflow-y: auto; min-height: 0; flex: 1; }
.cp-icones-grille button { display: grid; place-items: center; height: 40px; border: var(--border-w) solid transparent; border-radius: var(--radius-sm); background: none; color: var(--text); font-size: 20px; cursor: pointer; }
.cp-icones-grille button:hover, .cp-icones-grille button:focus-visible { background: var(--surface-2); border-color: var(--border); outline: none; }
.cp-icones-grille button.est-choisi { background: var(--accent-soft); color: var(--accent-soft-text); border-color: var(--accent); }

@media (max-width: 60rem) {
  .en-corps.cp-corps, .entree-composition.sans-plan .cp-corps { grid-template-columns: minmax(0, 1fr); }
  .cp-plan, .cp-tiroir { position: static; height: auto; border: 0; }
  .sans-plan .cp-plan { visibility: visible; }
  .entree-composition:not(.sans-plan) .cp-scene, .entree-composition.sans-plan .cp-plan { display: none; }
  .cp-plan-int { min-width: 0; }
  .cp-scene { position: static; padding: var(--space-3); }
  .cp-defile { max-height: 70vh; }
  .cp-tiroir-bloc { position: fixed; inset: 0; z-index: 65; overflow-y: auto; background: var(--surface); }
  .cp-outils { display: flex; }
}

/* L'icône qui ouvre un titre de bloc : deux fois la taille du mot, dans la
   couleur d'action. ⚠ À cette taille, « vertical-align » ne suffit plus — une
   lettre de 16 px et un glyphe de 30 px n'ont pas la même ligne de base, et
   l'icône dépassait sous le texte. Le titre devient donc une rangée qui aligne
   ses deux pièces par leur milieu. La taille reste liée au titre (« em »),
   pour suivre s'il change. */
.card-head h2:has(.icone-titre) { display: flex; align-items: center; gap: .4em; }
.icone-titre { color: var(--accent); font-size: 1.84em; line-height: 1; flex: none; }

/* La section qu'on vient de viser depuis le rail : un anneau à la couleur
   d'action qui s'efface.
   ⚠ NOM DISTINCT DE « vient-d-arriver », QUI DIT AUTRE CHOSE : celle-là est
   pour une ligne qui APPARAÎT (mouvement.js, champs.js) et commence donc à
   opacité zéro. Une section visée est déjà là : la faire apparaître en fondu
   serait faux, et reprendre le même nom aurait écrasé l'animation des lignes
   dans tout le back-office — la règle d'ici, plus bas dans le fichier, pèse
   autant et l'emporte.
   ⚠ L'anneau est posé par « box-shadow » : il ne déplace rien autour. */
@keyframes aide-visee {
  0%   { box-shadow: 0 0 0 2px var(--accent); }
  55%  { box-shadow: 0 0 0 2px var(--accent); }
  100% { box-shadow: 0 0 0 2px transparent; }
}
.est-visee { animation: aide-visee 1.2s cubic-bezier(.16, 1, .3, 1); }
/* Le focus est posé par le script pour que le clavier suive : l'anneau le dit
   déjà, un second liseré par-dessus ferait double emploi. */
.est-visee:focus-visible { outline: none; }
@media (prefers-reduced-motion: reduce) { .est-visee { animation: none; box-shadow: 0 0 0 2px var(--accent); } }

/* ── Messages (vues/messages.php) ──────────────────────────────────────────
   La liste à gauche, le message ouvert à droite ; un non-lu se signale par
   un point et son nom en gras. */
.nav-item .count.est-nouveau { opacity: 1; min-width: 18px; padding: 0 5px; border-radius: var(--radius-pill); background: var(--accent); color: var(--accent-text); text-align: center; }
/* 30 / 70 : la liste ne porte que de quoi reconnaître un message ; on le lit à droite. */
.msg-grille { display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 7fr); gap: var(--space-5); align-items: start; }
.msg-liste td { vertical-align: middle; }
/* Un début de message long ne doit pas élargir la liste : colonnes fixes, le texte se coupe par « … » et la date reste visible. */
.msg-liste table { table-layout: fixed; width: 100%; min-width: 0; }
.msg-liste td { overflow: hidden; }
.msg-lien { display: flex; align-items: center; gap: var(--space-3); min-width: 0; color: inherit; text-decoration: none; }
.msg-lien:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: var(--radius-sm); }
.msg-point { width: 8px; height: 8px; flex: none; border-radius: 50%; background: transparent; }
.est-non-lu .msg-point { background: var(--accent); }
.msg-textes { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.msg-tete { display: flex; align-items: baseline; gap: var(--space-2); min-width: 0; }
.msg-tete b { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.msg-tete .msg-date { flex: none; font-size: 11.5px; color: var(--text-subtle); font-family: var(--font-num); }
.msg-textes b { font-weight: 500; }
.est-non-lu .msg-textes b { font-weight: 700; }
.msg-adresse { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12.5px; color: var(--text-subtle); }
.msg-tete b { color: var(--text); }
.msg-liste tr.est-courant { background: var(--accent-soft); }
/* Tiroir du Formulaire : un réglage court sur une ligne (libellé, menu). */
.cp-reglage-ligne { display: flex; align-items: center; gap: var(--space-3); }
.cp-reglage-ligne label { flex: 1; font-size: 12.5px; color: var(--text-subtle); }
.cp-reglage-ligne .select { width: auto; min-width: 150px; }
/* Plusieurs formulaires : un filtre par formulaire, et l'origine sur chaque ligne. */
.msg-filtres { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-bottom: var(--space-4); }
.msg-textes .msg-origine { display: flex; align-items: center; gap: 4px; font-size: 11.5px; color: var(--text-subtle); }
.msg-champs { display: grid; grid-template-columns: minmax(110px, auto) 1fr; gap: var(--space-2) var(--space-4); margin: 0; }
.msg-champs dt { font-size: 12.5px; color: var(--text-subtle); padding-top: 1px; }
.msg-champs dd { margin: 0; overflow-wrap: anywhere; }
.msg-champs dd.msg-long { grid-column: 1 / -1; padding: var(--space-3) var(--space-4); border-radius: var(--radius-md); background: var(--surface-sunken); line-height: 1.6; }
.msg-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); padding-top: var(--space-2); }
.msg-actions .grow { flex: 1; }
.msg-attente { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--space-2); min-height: 220px;
  border: var(--filet-w) dashed var(--border); border-radius: var(--radius-lg); }
.msg-attente i { font-size: 28px; }
@media (max-width: 60rem) { .msg-grille { grid-template-columns: minmax(0, 1fr); } .msg-attente { display: none; } }

/* ── Aide : un aperçu animé par thème (vues/aide.php, apercu_aide) ─────────
   Un schéma de l'écran, pas une capture : il montre le GESTE — ce qui bouge,
   dans quel ordre — avec les couleurs du back-office, clair comme sombre.
   ⚠ L'ÉTAT DE REPOS EST L'ÉTAT D'ARRIVÉE. Chaque règle de base dessine la fin
   du geste (publié, recadré, traduit…) ; les animations, toutes rangées sous
   « no-preference », partent d'avant et y reviennent. Qui a réduit les
   animations voit donc un schéma juste, immobile.
   Rien que transform, opacity, et une teinte : le défilement n'en pâtit pas.
   Hors de l'écran, aide.js les met en pause (.aa-pause). */
.aide-apercu { --aa-t: 8s; position: relative; height: 168px; margin: 0; overflow: hidden;
  border-radius: var(--radius-md); background: var(--surface-sunken); border: var(--filet-w) solid var(--border); }
.aide-apercu.aa-pause, .aide-apercu.aa-pause * { animation-play-state: paused !important; }
.aa-fen { position: absolute; inset: 14px 18px; overflow: hidden; background: var(--surface);
  border: var(--filet-w) solid var(--border); border-radius: var(--radius-sm); box-shadow: var(--shadow-sm); }
.aa-l { display: block; flex: none; height: 6px; border-radius: 3px; background: var(--border-strong); }
.aa-l.aa-fort { height: 8px; background: var(--text-subtle); }
.aa-pile { display: flex; flex-direction: column; gap: 7px; }
.aide-apercu .grow { flex: 1; }
.aide-apercu b { font-size: 11px; font-weight: 600; color: var(--text); }
.aide-apercu small { font-size: 9.5px; color: var(--text-subtle); }
.aide-apercu i { line-height: 1; }
.aa-pastille { display: inline-flex; align-items: center; gap: 3px; height: 18px; padding: 0 8px; border-radius: var(--radius-pill);
  font-size: 9.5px; font-weight: 600; white-space: nowrap; background: var(--surface-2); color: var(--text-muted); }
.aa-btn { display: inline-flex; align-items: center; justify-content: center; gap: 4px; height: 20px; padding: 0 9px; border-radius: var(--radius-sm);
  font-size: 9.5px; font-weight: 600; white-space: nowrap; background: var(--accent); color: var(--accent-text); }
.aa-btn.aa-sec { background: var(--surface-2); color: var(--text-muted); }
.aa-curseur { position: absolute; z-index: 6; font-size: 17px; color: var(--text);
  filter: drop-shadow(0 1px 1px color-mix(in srgb, var(--text) 35%, transparent)); pointer-events: none; }
.aa-barre-ed { display: flex; align-items: center; gap: 8px; height: 34px; padding: 0 10px; border-bottom: var(--filet-w) solid var(--border); }
/* Une « photo » faite de jetons : un ciel, un soleil, deux collines. */
.aa-photo { background:
  radial-gradient(circle at 26% 32%, var(--warn) 0 7%, transparent 7.5%),
  radial-gradient(ellipse 70% 45% at 78% 102%, var(--ok) 0 98%, transparent 100%),
  radial-gradient(ellipse 60% 38% at 18% 104%, color-mix(in srgb, var(--ok) 65%, var(--text)) 0 98%, transparent 100%),
  linear-gradient(var(--info-soft), var(--accent-soft)); }

/* Premiers pas : ⌘K ouvre la recherche, on tape, on choisit. */
.aa-bo { display: grid; grid-template-columns: 22% 1fr; }
.aa-side { padding: 12px 10px; background: var(--surface-2); border-right: var(--filet-w) solid var(--border); }
.aa-main { padding: 14px 16px; }
.aa-touche { position: absolute; z-index: 4; right: 28px; top: 22px; padding: 2px 5px; border-radius: 4px; font: 600 10px/1.2 var(--font-mono);
  background: var(--surface-2); border: var(--filet-w) solid var(--border); color: var(--text-muted); }
.aa-palette { position: absolute; z-index: 3; left: 50%; top: 24px; width: 56%; padding: 6px; transform: translateX(-50%);
  background: var(--surface); border: var(--filet-w) solid var(--border); border-radius: var(--radius-md); box-shadow: var(--shadow-lg); }
.aa-palette .aa-champ { display: flex; align-items: center; gap: 6px; height: 24px; padding: 0 6px; margin-bottom: 4px;
  font-size: 11px; color: var(--text); border-bottom: var(--filet-w) solid var(--border); }
.aa-frappe { display: inline-block; overflow: hidden; white-space: nowrap; max-width: 27ch; padding-right: 1px; border-right: 1.5px solid var(--accent); }
.aa-res { position: relative; z-index: 1; display: flex; align-items: center; gap: 8px; height: 20px; padding: 0 6px; font-size: 12px; color: var(--text-muted); }
.aa-choix { position: absolute; left: 6px; right: 6px; top: 54px; height: 20px; border-radius: var(--radius-sm); background: var(--accent-soft); }

/* Apparence : la couleur d'accent change, le site suit aussitôt. */
.aa-app { display: grid; grid-template-columns: 1fr 34%; }
.aa-site { display: flex; flex-direction: column; gap: 8px; padding: 12px 14px; }
.aa-heros { display: block; height: 38px; border-radius: var(--radius-sm); background: color-mix(in srgb, var(--accent) 22%, var(--surface)); }
.aa-site .aa-btn { align-self: flex-start; }
.aa-reglages { display: flex; flex-direction: column; gap: 10px; padding: 12px; background: var(--surface-2); border-left: var(--filet-w) solid var(--border); }
.aa-nuancier { display: flex; gap: 6px; }
.aa-nuancier span { width: 18px; height: 18px; border-radius: 50%; border: var(--border-w) solid var(--border-strong); }
.aa-n-fond { background: var(--bg); } .aa-n-surface { background: var(--surface); } .aa-n-texte { background: var(--text); }
.aa-n-accent { background: var(--accent); box-shadow: 0 0 0 2px var(--surface-2), 0 0 0 3.5px var(--accent); }

/* Écrire et publier : brouillon → publié, la page passe en ligne. */
.aa-statut { display: block; height: 18px; overflow: hidden; }
.aa-statuts { display: flex; flex-direction: column; transform: translateY(-18px); }
.aa-p-brouillon { background: var(--surface-2); color: var(--text-muted); }
.aa-p-publie { background: var(--ok-soft); color: var(--ok-soft-text); }
.aa-page { padding: 14px 16px; }
.aa-en-ligne { position: absolute; right: 12px; bottom: 10px; display: inline-flex; align-items: center; gap: 4px; font-size: 10px; font-weight: 600; color: var(--ok); }

/* Le texte riche : sélectionner un mot, la barre flottante, le gras. */
.aa-texte { display: flex; flex-direction: column; gap: 10px; padding: 18px 20px; }
.aa-ligne { display: flex; align-items: center; gap: 6px; height: 9px; }
.aa-mot { position: relative; display: flex; align-items: center; width: 22%; height: 9px; }
.aa-sel { position: absolute; inset: -4px -3px; border-radius: 3px; background: var(--accent-soft); transform-origin: left; }
.aa-motl { position: relative; width: 100%; height: 9px; background: var(--text); }
.aa-flottante { position: absolute; z-index: 2; bottom: calc(100% + 9px); left: 50%; display: flex; gap: 2px; padding: 3px; transform: translateX(-50%);
  border-radius: var(--radius-sm); background: var(--surface-inverse); color: var(--text-inverse); box-shadow: var(--shadow-md); font-size: 12px; }
.aa-flottante i, .aa-gras { display: grid; place-items: center; width: 20px; height: 20px; border-radius: 4px; }
.aa-gras { background: color-mix(in srgb, var(--text-inverse) 22%, transparent); }

/* Les médias : le point focal guide les trois recadrages. */
.aa-med { display: grid; grid-template-columns: 44% 1fr; gap: 14px; padding: 12px; }
.aa-grande { position: relative; border-radius: var(--radius-sm); background-size: 100% 100%; }
.aa-focal { position: absolute; left: 72%; top: 58%; width: 14px; height: 14px; margin: -7px 0 0 -7px; border-radius: 50%;
  background: color-mix(in srgb, var(--surface) 50%, transparent); border: 2px solid var(--surface); box-shadow: 0 0 0 1.5px var(--accent); }
/* Même grille que les vrais cadres (.mt-recadrages) : des largeurs au prorata
   des formats, donc trois cadres de même hauteur, à toute largeur. */
.aa-cadres { display: grid; grid-template-columns: 1.78fr .75fr 1fr; align-items: center; align-content: center; gap: 8px; }
.aa-cadres > span { display: flex; flex-direction: column; align-items: center; gap: 4px; min-width: 0; }
.aa-cadre { display: block; border-radius: 3px; border: var(--filet-w) solid var(--border); background-size: 230% 230%; background-position: 72% 58%; }
.aa-cadre { width: 100%; } .aa-paysage { aspect-ratio: 16 / 9; } .aa-portrait { aspect-ratio: 3 / 4; } .aa-carre { aspect-ratio: 1; }

/* Types de contenu : un type déclare ses champs, un à un. */
.aa-types { display: flex; flex-direction: column; gap: 6px; padding: 10px 12px; }
.aa-type-tete { display: flex; align-items: center; gap: 6px; margin-bottom: 2px; color: var(--accent); font-size: 14px; }
.aa-champ-l { display: flex; align-items: center; gap: 8px; height: 21px; padding: 0 8px; border: var(--filet-w) solid var(--border);
  border-radius: var(--radius-sm); font-size: 12px; color: var(--text-muted); }
.aa-champ-l .aa-pastille { margin-left: auto; height: 15px; }
.aa-poignee { color: var(--text-subtle); font-size: 11px; }

/* Menus : une entrée glisse à sa place, puis passe en sous-menu. */
.aa-menus { padding: 12px 14px; }
/* La marge de droite fait la place du décalage en sous-menu (22 px). */
.aa-entree { position: relative; margin-right: 22px; display: flex; align-items: center; gap: 8px; height: 22px; padding: 0 8px; background: var(--surface);
  border: var(--filet-w) solid var(--border); border-radius: var(--radius-sm); font-size: 12px; color: var(--text-muted); }
.aa-m2 { transform: translateY(29px); }
.aa-m3 { z-index: 2; transform: translate(22px, -29px); border-color: var(--accent); }
.aa-cur-menu { left: 40px; top: 80px; opacity: 0; }

/* Composer une page : un bloc choisi dans le plan s'ouvre dans le tiroir. */
.aa-comp { display: grid; grid-template-columns: 24% 1fr 30%; }
.aa-plan { position: relative; display: flex; flex-direction: column; gap: 5px; padding: 10px 8px; border-right: var(--filet-w) solid var(--border); }
.aa-pl { display: flex; align-items: center; gap: 6px; height: 21px; padding: 0 5px; border-radius: var(--radius-sm); }
.aa-pic { display: grid; place-items: center; width: 15px; height: 15px; flex: none; border-radius: 3px; background: var(--surface-2); color: var(--text-muted); font-size: 10px; }
.aa-p2 { background: var(--accent-soft); }
.aa-cur-plan { left: 60%; top: 42px; opacity: 0; }
.aa-scene { display: flex; flex-direction: column; gap: 6px; padding: 10px; background: var(--surface-2); }
.aa-s1 { display: block; height: 34px; border-radius: 3px; background: color-mix(in srgb, var(--accent) 24%, var(--surface)); }
.aa-s2 { padding: 7px; border-radius: 3px; background: var(--surface); gap: 5px; box-shadow: 0 0 0 1.5px var(--accent); }
.aa-s3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; }
.aa-s3 span { height: 22px; border-radius: 3px; background: var(--surface); }
.aa-tiroir { display: flex; flex-direction: column; gap: 6px; padding: 10px; border-left: var(--filet-w) solid var(--border); background: var(--surface); }
.aa-tiroir-tete { display: flex; align-items: center; gap: 5px; padding-bottom: 6px; margin-bottom: 2px; border-bottom: var(--filet-w) solid var(--border); color: var(--accent); font-size: 12px; }
.aa-saisie { display: block; height: 16px; border-radius: 3px; border: var(--border-w) solid var(--border-strong); }
.aa-saisie.aa-haute { height: 30px; }

/* Les langues : l'onglet EN, l'adresse /en/, le texte traduit ; la date reste commune. */
.aa-lang { padding: 0 16px; }
.aa-onglets { position: relative; display: flex; align-items: center; height: 32px; margin-bottom: 12px; border-bottom: var(--filet-w) solid var(--border); font-size: 10.5px; font-weight: 600; color: var(--text-muted); }
.aa-onglets > span:not(.aa-souligne):not(.grow):not(.aa-adresse) { width: 30px; text-align: center; }
.aa-souligne { position: absolute; left: 0; bottom: -1px; width: 30px; height: 2px; background: var(--accent); transform: translateX(30px); }
.aa-adresse { font: 500 9.5px var(--font-mono); padding: 2px 6px; border-radius: var(--radius-pill); background: var(--accent-soft); color: var(--accent-soft-text); }
.aa-trad .aa-l { transform-origin: left; transform: scaleX(var(--k, 1)); }
.aa-trad .aa-l.aa-fort { transform: none; }
.aa-commun { display: flex; align-items: center; gap: 6px; margin-top: 4px; color: var(--text-subtle); font-size: 11px; }
.aa-commun .aa-l { transform: none; }

/* Historique : choisir une version, voir ce qui change, restaurer. */
.aa-hist { display: grid; grid-template-columns: 1fr 40%; }
.aa-page-h { padding: 14px; }
.aa-diff { display: block; margin: -3px -5px; padding: 3px 5px; border-radius: 3px; }
.aa-moins { background: var(--danger-soft); } .aa-plus { background: var(--ok-soft); }
.aa-versions { position: relative; display: flex; flex-direction: column; gap: 2px; padding: 8px; border-left: var(--filet-w) solid var(--border); background: var(--surface-2); }
.aa-versions > b { display: flex; align-items: center; gap: 4px; margin-bottom: 4px; }
.aa-version { position: relative; z-index: 1; display: flex; align-items: center; gap: 6px; height: 19px; padding: 0 6px; }
.aa-version small { margin-left: auto; }
.aa-rond { width: 6px; height: 6px; flex: none; border-radius: 50%; background: var(--border-strong); }
.aa-vchoix { position: absolute; left: 8px; right: 8px; top: 59px; height: 19px; border-radius: var(--radius-sm); background: var(--accent-soft); transform: translateY(21px); }
.aa-restaurer { margin-top: auto; align-self: flex-end; }

/* Référencement : ce que la page montre dans un moteur. */
.aa-serp { display: flex; flex-direction: column; gap: 10px; padding: 10px 16px; }
.aa-recherche { display: flex; align-items: center; gap: 8px; height: 24px; padding: 0 10px; border-radius: var(--radius-pill); border: var(--border-w) solid var(--border-strong); color: var(--text-muted); font-size: 12px; }
.aa-resultat { display: flex; flex-direction: column; gap: 5px; }
.aa-site-r { display: flex; align-items: center; gap: 5px; }
.aa-titre-r { font-size: 12px; font-weight: 600; color: var(--accent); }
.aa-titre-r .aa-frappe { border-right-color: transparent; }
.aa-desc { display: flex; flex-direction: column; gap: 5px; }
.aa-autre { opacity: .45; }

/* Partages : le lien collé dans un message devient une carte. */
.aa-msg { display: flex; flex-direction: column; gap: 8px; padding: 12px 14px; background: var(--surface-2); }
.aa-bulle { display: flex; flex-direction: column; gap: 6px; width: 44%; padding: 8px 10px; border-radius: 10px 10px 10px 3px; background: var(--surface); }
.aa-moi { align-self: flex-end; width: 56%; padding: 5px; border-radius: 10px 10px 3px 10px; background: var(--accent-soft); }
.aa-carte-lien { display: grid; grid-template-columns: 44% 1fr; gap: 8px; align-items: center; padding: 4px; border-radius: 7px; background: var(--surface); }
.aa-carte-img { display: block; height: 50px; border-radius: 4px; background-size: 100% 100%; }
.aa-carte-lien small { display: inline-flex; align-items: center; gap: 3px; }

/* Santé du site : les signalements se corrigent, un à un. */
.aa-sante { padding: 12px 14px; gap: 6px; }
.aa-sante-l { display: flex; align-items: center; gap: 8px; height: 23px; padding: 0 8px; border: var(--filet-w) solid var(--border); border-radius: var(--radius-sm); color: var(--text-subtle); font-size: 11px; }
.aa-etat { position: relative; display: grid; width: 15px; height: 15px; font-size: 15px; }
.aa-etat i { grid-area: 1 / 1; }
.aa-w { color: var(--warn); opacity: 0; } .aa-ok { color: var(--ok); }

/* Statistiques : sans cookie, l'audience se lit quand même. */
.aa-stats { display: flex; flex-direction: column; gap: 8px; padding: 10px 14px 14px; }
.aa-stats-tete { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }
.aa-stats-tete b { display: flex; align-items: center; gap: 5px; }
.aa-stats-ic { color: var(--accent); font-size: 14px; }
/* Le chiffre de tête et sa légende : une pile qu'on fait défiler d'un cran par
   arrêt du guide, comme courbe.js recopie la valeur du point survolé. */
.aa-stats-lu { display: flex; flex-direction: column; align-items: flex-end; }
.aa-defile-c, .aa-defile-l { display: flex; flex-direction: column; align-items: flex-end; overflow: hidden; }
.aa-defile-c { height: 22px; } .aa-defile-l { height: 12px; }
.aa-defile-c span { flex: none; height: 22px; font: 400 20px/22px var(--font-num); letter-spacing: -.01em; font-variant-numeric: tabular-nums; color: var(--text); }
.aa-defile-l span { flex: none; height: 12px; font-size: 9.5px; line-height: 12px; color: var(--text-subtle); white-space: nowrap; }
.aa-courbe.courbe { flex: 1; min-height: 0; height: auto; }
.aa-courbe .courbe-fin, .aa-courbe .courbe-curseur { width: 8px; height: 8px; }
.aa-courbe .courbe-guide, .aa-courbe .courbe-curseur { left: var(--x1); }
.aa-courbe .courbe-curseur { top: var(--y1); }

/* Cookies : le bandeau demande, la carte attend l'accord. */
.aa-cook { display: grid; grid-template-columns: 1fr 42%; gap: 12px; padding: 12px 14px; }
.aa-carte { position: relative; border-radius: var(--radius-sm);
  background: repeating-linear-gradient(90deg, transparent 0 18px, var(--border) 18px 19px), repeating-linear-gradient(0deg, var(--surface-2) 0 18px, var(--border) 18px 19px); }
.aa-epingle { position: absolute; left: 50%; top: 50%; margin: -18px 0 0 -9px; font-size: 18px; color: var(--accent); }
.aa-bandeau { position: absolute; left: 8px; right: 8px; bottom: 8px; display: flex; align-items: center; gap: 8px; padding: 8px 10px; font-size: 16px; color: var(--text-muted);
  border-radius: var(--radius-sm); background: var(--surface); border: var(--filet-w) solid var(--border); box-shadow: var(--shadow-lg); transform: translateY(140%); }

/* Équipe : une invitation, un membre de plus, avec son rôle. */
.aa-membres { display: flex; justify-content: flex-end; gap: 18px; padding: 16px 14px; }
.aa-membre { display: flex; flex-direction: column; align-items: center; gap: 6px; }
.aa-av { display: grid; place-items: center; width: 34px; height: 34px; border-radius: 50%; font-size: 11px; font-weight: 600; background: var(--accent-soft); color: var(--accent-soft-text); }
.aa-av2 { background: var(--info-soft); color: var(--info-soft-text); } .aa-av3 { background: var(--ok-soft); color: var(--ok-soft-text); }
.aa-enveloppe { position: absolute; right: 44px; top: 9px; font-size: 16px; color: var(--accent); opacity: 0; }

/* Messages : le formulaire part, le message arrive au back-office, non lu. */
.aa-msgs { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; padding: 12px 14px; }
.aa-form { display: flex; flex-direction: column; gap: 6px; }
.aa-envoyer { align-self: flex-start; }
.aa-boite { display: flex; flex-direction: column; gap: 4px; padding: 8px; border-radius: var(--radius-sm); background: var(--surface-2); }
.aa-boite > b { display: flex; align-items: center; gap: 4px; margin-bottom: 2px; }
.aa-recu { display: flex; align-items: center; gap: 6px; height: 21px; padding: 0 7px; border-radius: 3px; background: var(--surface); }
.aa-rond-msg { width: 6px; height: 6px; flex: none; border-radius: 50%; background: transparent; }
.aa-msg-neuf .aa-rond-msg { background: var(--accent); }
.aa-vol { position: absolute; left: 62%; top: 34%; font-size: 15px; color: var(--accent); opacity: 0; }

/* Sauvegarde : tout le site rentre dans un .zip. */
.aa-sauve { display: flex; align-items: center; justify-content: center; gap: 90px; }
.aa-fichiers { position: relative; display: grid; grid-template-columns: repeat(2, 30px); gap: 10px; font-size: 22px; color: var(--text-muted); }
.aa-fichiers i { opacity: .25; }
.aa-zip { position: relative; display: flex; flex-direction: column; align-items: center; gap: 6px; font-size: 40px; color: var(--accent); }
.aa-jauge { display: block; width: 90px; height: 5px; border-radius: 3px; overflow: hidden; background: var(--surface-2); }
.aa-jauge span { display: block; height: 100%; background: var(--accent); transform-origin: left; }
.aa-fait { position: absolute; right: 18px; top: -4px; font-size: 16px; color: var(--ok); }

@media (prefers-reduced-motion: no-preference) {
  .aide-apercu * { animation-duration: var(--aa-t); animation-iteration-count: infinite; animation-timing-function: cubic-bezier(.45, 0, .2, 1); animation-fill-mode: both; }

  .aa-palette { animation-name: aa-palette; }
  .aa-touche { animation-name: aa-touche; }
  .aa-palette .aa-frappe { animation-name: aa-frappe; animation-timing-function: steps(7, end); }
  .aa-res { animation-name: aa-res; }
  .aa-choix { animation-name: aa-choix; }
  @keyframes aa-palette { 0%, 8% { opacity: 0; transform: translateX(-50%) scale(.95); } 14%, 88% { opacity: 1; transform: translateX(-50%) scale(1); } 96%, 100% { opacity: 0; transform: translateX(-50%) scale(.98); } }
  @keyframes aa-touche { 0%, 3% { transform: scale(1); } 6% { transform: scale(.85); background: var(--accent-soft); color: var(--accent-soft-text); } 10%, 100% { transform: scale(1); } }
  @keyframes aa-frappe { 0%, 16% { max-width: 0; } 38%, 100% { max-width: 7ch; } }
  @keyframes aa-res { 0%, 38% { opacity: 0; } 46%, 100% { opacity: 1; } }
  @keyframes aa-choix { 0%, 38% { opacity: 0; transform: translateY(-20px); } 46%, 54% { opacity: 1; transform: translateY(-20px); } 62%, 72% { transform: translateY(0); } 75% { transform: translateY(0) scale(.96); } 78%, 100% { opacity: 1; transform: translateY(0); } }

  .aa-teinte { animation-name: aa-teinte; animation-timing-function: ease-in-out; }
  .aa-n-accent { animation-name: aa-teinte, aa-clic; }
  @keyframes aa-teinte { 0%, 18% { filter: hue-rotate(0deg); } 30%, 52% { filter: hue-rotate(115deg); } 64%, 86% { filter: hue-rotate(225deg); } 98%, 100% { filter: hue-rotate(360deg); } }
  @keyframes aa-clic { 0%, 18%, 30%, 52%, 64%, 100% { transform: scale(1); } 22%, 56% { transform: scale(.82); } }

  .aa-statuts { animation-name: aa-statuts; }
  .aa-page { animation-name: aa-page; }
  .aa-en-ligne { animation-name: aa-en-ligne; }
  @keyframes aa-statuts { 0%, 40% { transform: translateY(0); } 50%, 100% { transform: translateY(-18px); } }
  @keyframes aa-page { 0%, 60% { opacity: .4; } 68%, 100% { opacity: 1; } }
  @keyframes aa-en-ligne { 0%, 64% { opacity: 0; transform: translateY(4px); } 72%, 100% { opacity: 1; transform: none; } }

  .aa-sel { animation-name: aa-sel; }
  .aa-flottante { animation-name: aa-flottante; }
  .aa-motl { animation-name: aa-motl; }
  .aa-gras { animation-name: aa-gras; }
  @keyframes aa-sel { 0%, 10% { transform: scaleX(0); } 24%, 86% { transform: scaleX(1); } 94%, 100% { transform: scaleX(0); } }
  @keyframes aa-flottante { 0%, 26% { opacity: 0; transform: translateX(-50%) translateY(4px); } 34%, 86% { opacity: 1; transform: translateX(-50%); } 92%, 100% { opacity: 0; transform: translateX(-50%); } }
  @keyframes aa-motl { 0%, 52% { height: 6px; background: var(--border-strong); } 58%, 100% { height: 9px; background: var(--text); } }
  @keyframes aa-gras { 0%, 46% { background: transparent; } 50%, 58% { background: var(--accent); } 64%, 100% { background: color-mix(in srgb, var(--text-inverse) 22%, transparent); } }

  .aa-focal { animation-name: aa-focal; }
  .aa-cadre { animation-name: aa-cadre; }
  @keyframes aa-focal { 0%, 12% { left: 30%; top: 36%; box-shadow: 0 0 0 1.5px var(--accent); } 20% { box-shadow: 0 0 0 5px color-mix(in srgb, var(--accent) 35%, transparent); }
    30%, 56% { left: 72%; top: 58%; box-shadow: 0 0 0 1.5px var(--accent); } 64% { box-shadow: 0 0 0 5px color-mix(in srgb, var(--accent) 35%, transparent); } 78%, 100% { left: 30%; top: 36%; box-shadow: 0 0 0 1.5px var(--accent); } }
  @keyframes aa-cadre { 0%, 12% { background-position: 30% 36%; } 30%, 56% { background-position: 72% 58%; } 78%, 100% { background-position: 30% 36%; } }

  .aa-champ-l { animation-name: aa-surgit; animation-delay: calc(var(--i) * .45s); }
  @keyframes aa-surgit { 0%, 4% { opacity: 0; transform: translateY(6px); } 11%, 82% { opacity: 1; transform: none; } 92%, 100% { opacity: 0; transform: none; } }

  .aa-m2 { animation-name: aa-m2; }
  .aa-m3 { animation-name: aa-m3; }
  .aa-cur-menu { animation-name: aa-cur-menu; }
  @keyframes aa-m2 { 0%, 26% { transform: none; } 44%, 88% { transform: translateY(29px); } 98%, 100% { transform: none; } }
  @keyframes aa-m3 { 0%, 12% { transform: none; box-shadow: none; border-color: var(--border); } 18% { transform: scale(1.03); box-shadow: var(--shadow-md); border-color: var(--accent); }
    44% { transform: translateY(-29px) scale(1.03); box-shadow: var(--shadow-md); } 50%, 58% { transform: translateY(-29px); box-shadow: none; }
    68%, 88% { transform: translate(22px, -29px); box-shadow: none; border-color: var(--accent); } 98%, 100% { transform: none; border-color: var(--border); } }
  @keyframes aa-cur-menu { 0%, 8% { opacity: 0; transform: translate(10px, 10px); } 14% { opacity: 1; transform: none; } 44% { transform: translateY(-29px); } 50% { opacity: 1; transform: translateY(-29px); } 56%, 100% { opacity: 0; transform: translateY(-29px); } }

  .aa-tiroir { animation-name: aa-tiroir; }
  .aa-p2 { animation-name: aa-p2; }
  .aa-s2 { animation-name: aa-s2; }
  .aa-cur-plan { animation-name: aa-cur-plan; }
  @keyframes aa-tiroir { 0%, 24% { transform: translateX(105%); } 34%, 86% { transform: none; } 96%, 100% { transform: translateX(105%); } }
  @keyframes aa-p2 { 0%, 20% { background: transparent; } 24%, 90% { background: var(--accent-soft); } 96%, 100% { background: transparent; } }
  @keyframes aa-s2 { 0%, 20% { box-shadow: 0 0 0 1.5px transparent; } 24%, 90% { box-shadow: 0 0 0 1.5px var(--accent); } 96%, 100% { box-shadow: 0 0 0 1.5px transparent; } }
  @keyframes aa-cur-plan { 0%, 4% { opacity: 0; transform: translate(14px, 22px); } 12% { opacity: 1; transform: none; } 18% { transform: scale(.85); } 22% { opacity: 1; transform: none; } 30%, 100% { opacity: 0; transform: none; } }

  .aa-souligne { animation-name: aa-souligne; }
  .aa-adresse { animation-name: aa-apparait; }
  .aa-trad .aa-l:not(.aa-fort) { animation-name: aa-traduit; }
  .aa-commun { animation-name: aa-commun; }
  @keyframes aa-souligne { 0%, 24% { transform: none; } 32%, 86% { transform: translateX(30px); } 94%, 100% { transform: none; } }
  @keyframes aa-apparait { 0%, 28% { opacity: 0; } 36%, 86% { opacity: 1; } 94%, 100% { opacity: 0; } }
  @keyframes aa-traduit { 0%, 26% { transform: scaleX(1); opacity: 1; } 31% { opacity: .3; } 38%, 86% { transform: scaleX(var(--k, 1)); opacity: 1; } 94%, 100% { transform: scaleX(1); } }
  @keyframes aa-commun { 0%, 40%, 70%, 100% { color: var(--text-subtle); } 50%, 62% { color: var(--accent); } }

  .aa-vchoix { animation-name: aa-vchoix; }
  .aa-moins { animation-name: aa-moins; }
  .aa-plus { animation-name: aa-plus; }
  .aa-restaurer { animation-name: aa-clic-btn; }
  @keyframes aa-vchoix { 0%, 14% { transform: none; } 26%, 90% { transform: translateY(42px); } 98%, 100% { transform: none; } }
  @keyframes aa-moins { 0%, 30% { background: transparent; } 38%, 90% { background: var(--danger-soft); } 96%, 100% { background: transparent; } }
  @keyframes aa-plus { 0%, 32% { background: transparent; } 40%, 90% { background: var(--ok-soft); } 96%, 100% { background: transparent; } }
  @keyframes aa-clic-btn { 0%, 64% { transform: scale(1); } 68% { transform: scale(.88); } 72%, 100% { transform: scale(1); } }

  .aa-titre-r .aa-frappe { animation-name: aa-titre-r; animation-timing-function: steps(26, end); }
  .aa-desc { animation-name: aa-res; }
  @keyframes aa-titre-r { 0%, 10% { max-width: 0; border-right-color: var(--accent); } 40% { max-width: 27ch; border-right-color: var(--accent); } 44%, 100% { max-width: 27ch; border-right-color: transparent; } }

  .aa-moi { animation-name: aa-bulle; }
  .aa-carte-img { animation-name: aa-carte-img; }
  @keyframes aa-bulle { 0%, 10% { opacity: 0; transform: translateY(14px); } 20%, 88% { opacity: 1; transform: none; } 96%, 100% { opacity: 0; transform: none; } }
  @keyframes aa-carte-img { 0%, 26% { opacity: 0; } 36%, 100% { opacity: 1; } }

  .aa-sante-l { animation-name: aa-sante-l; animation-delay: calc(var(--i) * .6s); }
  .aa-w { animation-name: aa-w; animation-delay: calc(var(--i) * .6s); }
  .aa-ok { animation-name: aa-ok; animation-delay: calc(var(--i) * .6s); }
  @keyframes aa-w { 0%, 22% { opacity: 1; } 28%, 90% { opacity: 0; } 96%, 100% { opacity: 1; } }
  @keyframes aa-ok { 0%, 22% { opacity: 0; transform: scale(.6); } 30% { opacity: 1; transform: scale(1.15); } 34%, 90% { opacity: 1; transform: none; } 96%, 100% { opacity: 0; } }
  @keyframes aa-sante-l { 0%, 22% { border-color: color-mix(in srgb, var(--warn) 45%, var(--border)); } 30%, 90% { border-color: var(--border); } 96%, 100% { border-color: color-mix(in srgb, var(--warn) 45%, var(--border)); } }

  /* Le trait se dessine (même révélation que l'écran : clip-path), l'aire
     monte, puis le guide lit quatre jours et le chiffre de tête les suit. */
  .aa-courbe .courbe-trait { animation-name: aa-courbe-trace; }
  .aa-courbe .courbe-aire { animation-name: aa-courbe-aire; }
  .aa-courbe .courbe-fin { animation-name: aa-courbe-fin; }
  .aa-courbe .courbe-guide { animation-name: aa-courbe-guide; }
  .aa-courbe .courbe-curseur { animation-name: aa-courbe-guide, aa-courbe-curseur; }
  .aa-defile-c span { animation-name: aa-defile-c; }
  .aa-defile-l span { animation-name: aa-defile-l; }
  @keyframes aa-courbe-trace { 0%, 3% { clip-path: inset(0 100% 0 0); opacity: 1; } 30%, 92% { clip-path: inset(0 0 0 0); opacity: 1; } 99%, 100% { clip-path: inset(0 0 0 0); opacity: 0; } }
  @keyframes aa-courbe-aire { 0%, 16% { opacity: 0; } 34%, 92% { opacity: 1; } 99%, 100% { opacity: 0; } }
  @keyframes aa-courbe-fin { 0%, 28% { opacity: 0; } 32%, 40% { opacity: 1; } 43%, 85% { opacity: 0; } 89%, 92% { opacity: 1; } 99%, 100% { opacity: 0; } }
  @keyframes aa-courbe-guide { 0%, 41% { opacity: 0; left: var(--x1); } 44%, 51% { opacity: 1; left: var(--x1); } 55%, 61% { left: var(--x2); } 65%, 71% { left: var(--x3); } 75%, 82% { opacity: 1; left: var(--x4); } 86%, 100% { opacity: 0; left: var(--x4); } }
  @keyframes aa-courbe-curseur { 0%, 51% { top: var(--y1); } 55%, 61% { top: var(--y2); } 65%, 71% { top: var(--y3); } 75%, 100% { top: var(--y4); } }
  @keyframes aa-defile-c { 0%, 43% { transform: none; } 45%, 52% { transform: translateY(-22px); } 55%, 62% { transform: translateY(-44px); } 65%, 72% { transform: translateY(-66px); } 75%, 83% { transform: translateY(-88px); } 86%, 100% { transform: none; } }
  @keyframes aa-defile-l { 0%, 43% { transform: none; } 45%, 52% { transform: translateY(-12px); } 55%, 62% { transform: translateY(-24px); } 65%, 72% { transform: translateY(-36px); } 75%, 83% { transform: translateY(-48px); } 86%, 100% { transform: none; } }

  .aa-bandeau { animation-name: aa-bandeau; }
  .aa-accepter { animation-name: aa-clic-btn; animation-delay: -1.6s; }
  .aa-carte { animation-name: aa-carte; }
  .aa-epingle { animation-name: aa-epingle; }
  @keyframes aa-bandeau { 0%, 6% { transform: translateY(140%); } 16%, 50% { transform: none; } 58%, 100% { transform: translateY(140%); } }
  @keyframes aa-carte { 0%, 54% { opacity: .35; } 62%, 92% { opacity: 1; } 100% { opacity: .35; } }
  @keyframes aa-epingle { 0%, 56% { opacity: 0; transform: translateY(-12px); } 62% { opacity: 1; transform: none; } 66% { transform: translateY(-3px); } 70%, 92% { opacity: 1; transform: none; } 100% { opacity: 0; } }

  .aa-enveloppe { animation-name: aa-enveloppe; }
  .aa-nouveau { animation-name: aa-nouveau; }
  .aa-equipe .aa-btn { animation-name: aa-clic-btn; animation-delay: -4.5s; }
  @keyframes aa-enveloppe { 0%, 12% { opacity: 0; transform: none; } 16% { opacity: 1; transform: none; } 38% { opacity: 1; transform: translate(0, 52px) scale(.8); } 42%, 100% { opacity: 0; transform: translate(0, 52px) scale(.6); } }
  @keyframes aa-nouveau { 0%, 38% { opacity: 0; transform: scale(.4); } 46% { opacity: 1; transform: scale(1.08); } 50%, 88% { opacity: 1; transform: none; } 96%, 100% { opacity: 0; transform: none; } }

  .aa-envoyer { animation-name: aa-clic-btn; animation-delay: -3.84s; }
  .aa-vol { animation-name: aa-vol; }
  .aa-msg-neuf { animation-name: aa-msg-neuf; }
  @keyframes aa-vol { 0%, 21% { opacity: 0; left: 14%; top: 80%; } 24% { opacity: 1; left: 14%; top: 80%; } 42% { opacity: 1; left: 62%; top: 34%; } 46%, 100% { opacity: 0; left: 62%; top: 34%; } }
  @keyframes aa-msg-neuf { 0%, 42% { opacity: 0; transform: translateY(-6px); } 48%, 90% { opacity: 1; transform: none; } 97%, 100% { opacity: 0; transform: none; } }

  .aa-fichiers i { animation-name: aa-fichier; }
  .aa-f2 { animation-delay: .4s; } .aa-f3 { animation-delay: .8s; } .aa-f4 { animation-delay: 1.2s; }
  .aa-jauge span { animation-name: aa-jauge; animation-timing-function: linear; }
  .aa-fait { animation-name: aa-fait; }
  @keyframes aa-fichier { 0%, 6% { opacity: 1; transform: none; } 22% { opacity: 1; transform: translateX(150px) scale(.5); } 26%, 100% { opacity: .25; transform: none; } }
  @keyframes aa-jauge { 0%, 8% { transform: scaleX(0); } 44%, 90% { transform: scaleX(1); } 96%, 100% { transform: scaleX(0); } }
  @keyframes aa-fait { 0%, 46% { opacity: 0; transform: scale(.5); } 52% { opacity: 1; transform: scale(1.2); } 56%, 90% { opacity: 1; transform: none; } 96%, 100% { opacity: 0; } }
}

/* Le choix de la place des champs, dans les Réglages : trois petites vues du
   même écran plutôt que trois mots. On choisit une disposition en la voyant ;
   « à gauche » et « à droite » se confondent en liste, pas en image. */
.choix-places { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-3); }
.choix-places .place { display: grid; gap: var(--space-1); cursor: pointer;
  border: var(--filet-w) solid var(--border); border-radius: var(--radius-md);
  padding: var(--space-3); background: var(--surface); }
.choix-places .place:hover { border-color: var(--text-subtle); }
/* ⚠ C'EST LA CASE COCHÉE QUI MARQUE LA VUE, PAS UNE CLASSE POSÉE AU CHARGEMENT.
   Le serveur ne rend la page qu'une fois : une classe calculée en PHP restait
   sur le choix ENREGISTRÉ, et cliquer sur un autre ne changeait rien à l'écran
   — on ne voyait sa sélection qu'après avoir enregistré. « :has(:checked) »
   suit le formulaire en direct, et sans script. */
.choix-places .place:has(input:checked) { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.choix-places .place:has(input:checked) .place-nom { color: var(--accent); }
.choix-places input { position: absolute; opacity: 0; pointer-events: none; }
/* ⚠ L'anneau de focus doit se voir : la case est masquée, c'est donc la vue
   qui le porte — sans ça, on perd le repère au clavier. */
.choix-places input:focus-visible + .place-vue { outline: 2px solid var(--accent); outline-offset: 2px; }
.place-vue { display: flex; gap: 2px; aspect-ratio: 16 / 10; border-radius: var(--radius-sm);
  overflow: hidden; background: var(--surface-2); }
.place-image { flex: 1; background: var(--accent); opacity: .22; }
.place-bande { width: 34%; background: var(--text-subtle); opacity: .35; }
.place-gauche { flex-direction: row-reverse; }
/* Au centre, la bande se pose SUR l'image : la petite vue le dit comme
   l'écran le fera. */
.place-centre { position: relative; }
.place-centre .place-bande { position: absolute; inset: 22% 30%; width: auto; border-radius: 2px; opacity: .55; }
.place-nom { font-size: 13px; font-weight: 600; }
.place-dit { font-size: 12px; color: var(--text-subtle); line-height: 1.4; }
@media (max-width: 48rem) { .choix-places { grid-template-columns: minmax(0, 1fr); } }

/* Une ligne de réglage : le libellé, son explication, l'interrupteur à droite. */
.ligne-reglage { display: flex; align-items: center; gap: var(--space-4); padding: var(--space-3) 0; border-top: var(--filet-w) solid var(--border); }
.ligne-reglage:first-of-type { border-top: 0; }
.ligne-reglage .grow { flex: 1; font-size: 13.5px; }
.ligne-reglage .grow span { display: block; color: var(--text-muted); font-size: 12.5px; }

/* Typographie : les caractères invisibles de l'éditeur de texte riche (bouton ¶). L'espace insécable et la fine
   insécable sont surlignées chacune d'une teinte (API CSS highlight : le texte n'est pas modifié) ; chaque
   paragraphe se termine par ¶. */
::highlight(invisible-nbsp) { background-color: color-mix(in srgb, var(--accent) 30%, transparent); }
::highlight(invisible-fine) { background-color: color-mix(in srgb, var(--warn) 50%, transparent); }
body.invisibles .prose :is(p, h2, h3, li)::after { content: "¶"; margin-left: .2em; font-size: .85em; color: var(--text-subtle); opacity: .6; user-select: none; }

/* Tiroir d'un bloc : la barre d'onglets (composition.js, monterOnglets). Des icônes, collée en haut quand le corps
   défile, et le nom de l'onglet actif à droite. Un panneau (.cp-pan) ne change pas la mise en page du tiroir : ses
   enfants se rangent comme avant dans la colonne. */
.cp-onglets { position: sticky; top: 0; z-index: 3; display: flex; align-items: center; gap: 2px; margin: calc(var(--space-4) * -1) calc(var(--space-5) * -1) 0; padding: 4px var(--space-4);
  background: var(--surface); border-bottom: var(--filet-w) solid var(--border); }
.cp-onglets button { width: 36px; height: 34px; display: grid; place-items: center; border: 0; border-radius: var(--radius-md); background: none; color: var(--text-muted); font-size: 18px; cursor: pointer; }
.cp-onglets button[aria-selected="true"] { background: var(--accent-soft); color: var(--accent-soft-text); }
.cp-onglet-nom { margin-left: auto; padding-left: var(--space-2); font-size: 12.5px; font-weight: 600; white-space: nowrap; }
.cp-pan { display: contents; }
.cp-pan[hidden] { display: none; }

/* Grille (composition) : le choix de répartition en douzièmes, les colonnes repliables, leurs éléments. */
.cp-reparts, .cp-modeles { display: flex; flex-wrap: wrap; gap: 6px; }
.cp-repart { display: grid; place-items: center; width: 4.4rem; padding: 6px; border: var(--border-w) solid var(--border-strong); border-radius: var(--radius-md); background: var(--surface-2); cursor: pointer; }
.cp-repart:is(:hover, :focus-visible) { border-color: var(--text-muted); }
.cp-repart.est-courant { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent) inset; }
.cp-mini { display: flex; gap: 2px; width: 100%; height: 1.1rem; }
.cp-mini i { display: block; min-width: 0; border-radius: 2px; background: var(--text-subtle); }
.cp-repart.est-courant .cp-mini i { background: var(--accent); opacity: .9; }
.help.est-alerte { color: var(--danger); font-weight: 500; }
.cp-col { border: var(--filet-w, 1px) solid var(--border); border-radius: var(--radius-md); background: var(--surface-2); }
.cp-col > summary { padding: 10px; cursor: pointer; list-style: none; display: flex; gap: var(--space-2); align-items: baseline; }
.cp-col > summary::marker { content: ""; }
.cp-col > summary::before { content: "›"; display: inline-block; width: 1em; transition: rotate .2s ease; }
.cp-col[open] > summary::before { rotate: 90deg; }
.cp-col-corps { display: flex; flex-direction: column; gap: var(--space-3); padding: 0 10px 12px; }
.cp-el { display: flex; flex-direction: column; gap: var(--space-2); padding: 10px; border: var(--filet-w, 1px) solid var(--border); border-radius: var(--radius-md); background: var(--surface); }
.cp-el-tete { display: flex; align-items: center; gap: 6px; min-height: 2rem; }
.cp-el-outils { display: inline-flex; margin-inline-start: auto; }
.cp-el-ajout { display: flex; gap: 10px; align-items: center; }
@media (prefers-reduced-motion: reduce) { .cp-col > summary::before { transition-duration: 0s; } }

/* Le premier bloc d'une page (titre, adresse) n'a pas de cadre : ses champs se posent sur le fond. */
.card.card-nu { border-color: transparent; box-shadow: none; background: transparent; }
/* … et ses champs vont jusqu'aux bords des blocs encadrés qui le suivent (pas de marge intérieure de carte). */
.card.card-nu > .card-body { padding-inline: 0; }
/* Un champ à préfixe ou à bouton (adresse, lien d'aperçu) se laisse rétrécir : rien ne déborde du groupe. */
.champ-groupe .input { min-width: 0; flex: 1 1 auto; text-overflow: ellipsis; }
.champ-groupe > .btn { flex: none; align-self: center; }

/* Sélection : « Ce qu'on affiche » — une ligne par information (ordre, quand, forme) — et les réglages du curseur. */
.cp-infos { display: grid; gap: var(--space-2); }
.cp-info { display: grid; gap: var(--space-2); padding: var(--space-2) var(--space-3); border: var(--filet-w) solid var(--border); border-radius: var(--radius-md); background: var(--surface-2); }
.cp-info-tete { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); }
.cp-info-nom { display: flex; align-items: center; gap: var(--space-2); font-size: 13px; }
.cp-quand { display: inline-flex; gap: 2px; padding: 2px; border-radius: var(--radius-md); background: var(--surface-2); border: var(--filet-w) solid var(--border); }
.cp-quand button { width: 28px; height: 26px; display: grid; place-items: center; border: 0; border-radius: var(--radius-sm); background: none; color: var(--text-subtle); font-size: 15px; cursor: pointer; }
.cp-quand button:hover { color: var(--text); }
.cp-quand .cp-quand-suppr { margin-left: 4px; }
.cp-quand .cp-quand-suppr:hover { color: var(--danger); }
.cp-ajout { margin-top: var(--space-1); }
.cp-quand button.est-courant { background: var(--surface); color: var(--text); box-shadow: var(--shadow-sm); }
.cp-mini { font-size: 12.5px; height: 32px; padding-block: 0; }
.cp-sous { display: flex; flex-direction: column; gap: var(--space-3); padding: var(--space-3); border: var(--filet-w) solid var(--border); border-radius: var(--radius-md); }

/* Les effets au survol cumulables (Apparence → En-tête, Logo) : une rangée par effet — son nom, un échantillon qui
   joue au survol de la rangée, un interrupteur. Un effet qui ne peut pas rejoindre ceux déjà choisis se grise. */
.ap-effets { display: grid; border: var(--filet-w) solid var(--border); border-radius: var(--radius-md); overflow: hidden; }
.ap-effet { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-2) var(--space-3); }
.ap-effet + .ap-effet { border-top: var(--filet-w) solid var(--border); }
.ap-effet:has(input:disabled) { opacity: .45; }
.ap-effet-nom { flex: 1; }

/* Le bouton du menu sur téléphone (Apparence → En-tête → Téléphone) : une rangée par forme — sa miniature, qui joue
   son survol quand on survole la rangée, et un interrupteur (un seul est allumé). */
.ap-miniature { display: inline-grid; place-items: center; min-width: 76px; height: 34px; color: var(--text); font-size: 12px; font-weight: 500; letter-spacing: .1em; text-transform: uppercase; }
.ap-miniature .traits { position: relative; display: block; width: 22px; height: 14px; }
.ap-miniature .traits i { position: absolute; left: 0; width: 100%; height: 2px; border-radius: 2px; background: currentColor; transition: transform .35s cubic-bezier(.16, 1, .3, 1), width .35s cubic-bezier(.16, 1, .3, 1); }
.ap-miniature .traits i:nth-child(1) { top: 0; }
.ap-miniature .traits i:nth-child(2) { top: 6px; }
.ap-miniature .traits i:nth-child(3) { top: 12px; }
.ap-effet:hover .ap-miniature-trois i:nth-child(1) { transform: translateY(6px) rotate(90deg); }
.ap-effet:hover .ap-miniature-trois i:nth-child(3) { transform: translateY(-6px) rotate(90deg); }
.ap-miniature-deux-courts .traits i:nth-child(2) { left: auto; right: 0; top: 8px; width: 60%; }
.ap-miniature-deux-courts .traits i:nth-child(1) { top: 2px; }
.ap-effet:hover .ap-miniature-deux-courts i:nth-child(2) { width: 100%; }
.ap-miniature-pastille { width: 34px; min-width: 34px; border: 1.5px solid currentColor; border-radius: 50%; transition: background-color .3s, color .3s; }
.ap-miniature-pastille .traits { width: 14px; height: 8px; }
.ap-miniature-pastille .traits i:nth-child(2) { top: 6px; }
.ap-miniature-mot-fermer .mots { display: block; height: 1.3em; line-height: 1.3; overflow: hidden; }
.ap-miniature-mot-fermer .mots span { display: block; transition: transform .4s cubic-bezier(.25, 1, .33, 1); }
.ap-effet:hover .ap-miniature-mot-fermer .mots span { transform: translateY(-100%); }
.ap-miniature-pilule { gap: 8px; padding: 0 12px; border: 1.5px solid currentColor; border-radius: 999px; grid-auto-flow: column; min-width: 0; transition: background-color .3s, color .3s; text-transform: none; letter-spacing: 0; }
.ap-miniature-pilule .plus { position: relative; display: block; width: 10px; height: 10px; transition: transform .35s cubic-bezier(.16, 1, .3, 1); }
.ap-miniature-pilule .plus::before, .ap-miniature-pilule .plus::after { content: ""; position: absolute; background: currentColor; }
.ap-miniature-pilule .plus::before { left: 0; right: 0; top: 4px; height: 2px; }
.ap-miniature-pilule .plus::after { top: 0; bottom: 0; left: 4px; width: 2px; }
.ap-effet:hover :is(.ap-miniature-pastille, .ap-miniature-pilule) { background: var(--text); color: var(--text-inverse); }
.ap-effet:hover .ap-miniature-pilule .plus { transform: rotate(45deg); }
.ap-point { display: inline-block; width: 10px; height: 10px; margin-right: 6px; border-radius: 50%; box-shadow: inset 0 0 0 1px rgb(128 128 128 / .5); }
@media (prefers-reduced-motion: reduce) { .ap-miniature .traits i, .ap-miniature-pastille, .ap-miniature-pilule, .ap-miniature-pilule .plus, .ap-miniature-mot-fermer .mots span { transition: none; } }
/* Le choix d'une couleur de la palette : des pastilles sur une ligne (la première : « celle de l'en-tête »). */
.ap-pastilles { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.ap-pastilles button { width: 36px; height: 36px; padding: 3px; border: 2px solid transparent; border-radius: 50%; background: none; cursor: pointer; }
.ap-pastilles button[aria-pressed="true"] { border-color: var(--accent); }
.ap-pastilles i { display: block; width: 100%; height: 100%; border-radius: 50%; box-shadow: inset 0 0 0 1px rgb(128 128 128 / .5); }
.ap-pastilles .est-defaut { background: linear-gradient(135deg, var(--surface) 50%, var(--text) 50%); }
/* Dans le tiroir du compositeur, un titre se reconnaît à sa taille : le gras que l'éditeur lui posait faisait croire que
   le texte avait été mis en gras (le site, lui, rend le titre selon son thème). */
.cp-tiroir .prose :is(h2, h3) { font-weight: 400; }

/* Compositeur sans la structure (capacité « structure ») : le tiroir ne montre que le contenu ; les commandes qui ajoutent,
   retirent ou déplacent des éléments disparaissent (le serveur refuserait de toute façon). */
.cp-verrou-note { display: flex; align-items: center; gap: var(--space-2); margin: var(--space-3) 0 0; }
.cp-tiroir.cp-verrou :is([data-cp-el-ajout], [data-cp-el-suppr], [data-cp-col-ajout], [data-cp-col-suppr], [data-cp-bouton-ajout], [data-cp-bouton-suppr],
  [data-cp-it-ajout], [data-cp-fc-ajout], [data-cp-inf-ajout], [data-cp-inf-suppr], [data-cp-it-type], [data-cp-col-filet], [data-cp-repart], [data-cp-modele],
  [data-cp-convertir], [data-cp-defaut-bloc]) { display: none; }

/* ── Le panneau du type : onglets à icône, sections repliables avec résumé, vignettes, schéma de page ──────── */
.tp-tete { display: flex; align-items: center; gap: var(--space-3); }
.tp-ic { width: 40px; height: 40px; border-radius: var(--radius-md); background: var(--accent-soft); color: var(--accent-soft-text); display: grid; place-items: center; font-size: 20px; flex: none; }
.tp-tete b { font-size: 16px; display: block; } .tp-tete small { color: var(--text-subtle); font-size: 12px; font-family: var(--font-mono); }
.tp-onglets { display: grid; grid-template-columns: 1fr 1fr; gap: 4px; background: var(--surface-sunken, var(--surface)); border: var(--filet-w) solid var(--border); border-radius: var(--radius-md); padding: 4px; }
.tp-onglets button { display: flex; flex-direction: column; align-items: center; gap: 2px; padding: var(--space-2); border: 0; background: transparent; border-radius: var(--radius-sm); cursor: pointer; font: inherit; color: var(--text-muted); }
.tp-onglets button i { font-size: 20px; } .tp-onglets button span { font-size: 12.5px; font-weight: 600; }
.tp-onglets button.est-courant { background: var(--surface); color: var(--text); box-shadow: var(--shadow-sm); }
.tp-onglets button.est-courant i { color: var(--accent); }
.tp-sec { background: var(--surface); border: var(--filet-w) solid var(--border); border-radius: var(--radius-lg); }
.tp-sec > summary { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3) var(--space-4); cursor: pointer; list-style: none; font-weight: 600; font-size: 14px; }
.tp-sec > summary::-webkit-details-marker { display: none; }
.tp-sec > summary > i:first-child { color: var(--accent); font-size: 18px; flex: none; }
.tp-sec .tp-titre { flex: none; }
.tp-sec .tp-res { margin-left: auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text-subtle); font-weight: 400; font-size: 12.5px; text-align: right; }
.tp-sec .tp-chev { color: var(--text-subtle); transition: transform .15s; flex: none; }
.tp-sec[open] > summary .tp-chev { transform: rotate(180deg); }
.tp-corps { padding: 0 var(--space-4) var(--space-4); display: flex; flex-direction: column; gap: var(--space-3); }
.tp-corps > * { flex: none; }
.tp-vignettes { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-2); }
.tp-vignettes.deux { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.tp-v { border: var(--filet-w) solid var(--border); border-radius: var(--radius-md); background: var(--surface); padding: var(--space-2); cursor: pointer; text-align: center; font: inherit; color: var(--text-muted); }
.tp-v .fig { display: block; height: 64px; border-radius: 6px; background: var(--surface-2); margin-bottom: 6px; position: relative; overflow: hidden; }
.tp-v .nom { display: block; font-size: 12px; font-weight: 600; }
.tp-v.est-choisi { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); background: var(--accent-soft); color: var(--accent-soft-text); }
.tp-v:focus-visible, .tp-p:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.fig i { position: absolute; display: block; background: var(--border-strong); border-radius: 2px; }
.fig i.cv { background: linear-gradient(135deg, var(--violet-200, #c4b5fd), var(--blue-300, #93c5fd)); }
.tp-pastilles { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.tp-p { display: inline-flex; align-items: center; gap: 6px; border: var(--border-w) solid var(--border-strong); background: var(--surface); border-radius: 999px; padding: 4px 12px; font: inherit; font-size: 13px; cursor: pointer; color: var(--text); }
.tp-p.est-choisi { background: var(--accent-soft); border-color: var(--accent); color: var(--accent-soft-text); }
.tp-sens { margin-top: var(--space-2); }
.tp-url { font-family: var(--font-mono); font-size: 12.5px; background: var(--surface-2); border-radius: var(--radius-sm); padding: 6px 10px; color: var(--text-muted); overflow-wrap: anywhere; }
.tp-url b { color: var(--text); }
.tp-page { background: var(--surface); border: var(--border-w) solid var(--border-strong); border-radius: var(--radius-lg); overflow: hidden; }
.tp-page .z { padding: var(--space-3) var(--space-4); border-bottom: 1px dashed var(--border); font-size: 12px; color: var(--text-subtle); display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; }
.tp-page .z:last-child { border-bottom: 0; }
.tp-page .z .t { font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase; margin-left: auto; }
.tp-page .couv { height: 74px; background: linear-gradient(135deg, var(--violet-200, #c4b5fd), var(--blue-300, #93c5fd)); border-bottom: 0; flex-direction: column; align-items: flex-start; justify-content: flex-end; gap: 0; color: #fff; }
.tp-page .couv.bandeau { height: 46px; }
.tp-page .couv b { font-size: 15px; text-shadow: 0 1px 3px rgb(0 0 0 / .4); }
.tp-page .couv .sous { font-size: 11.5px; opacity: .92; }
.tp-page .titre-seul { font-size: 15px; font-weight: 700; color: var(--text); }
.tp-page .pil { padding: 1px 8px; border-radius: 999px; background: var(--accent-soft); color: var(--accent-soft-text); font-size: 11px; }
.tp-page .etat { padding: 1px 8px; border-radius: 999px; background: var(--warn-soft, #fff4d6); color: var(--warn-soft-text, #7a5200); font-size: 11px; }
.tp-page .mini { width: 100%; display: grid; gap: 6px; } .tp-page .mini i { display: block; height: 6px; border-radius: 3px; background: var(--border-strong); }
.tp-page .liees-c { width: 100%; display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; } .tp-page .liees-c i { display: block; height: 26px; border-radius: 4px; background: var(--border-strong); }
.tp-page .liees-l { width: 100%; display: grid; gap: 5px; } .tp-page .liees-l i { display: block; height: 6px; border-radius: 3px; background: var(--border-strong); }
.tp-page .nav { justify-content: space-between; }

.tp-deux { display: flex; flex-wrap: wrap; gap: var(--space-2); } .tp-deux > .select { flex: 1 1 10rem; min-width: 0; }

/* ── La colonne de droite des écrans d'édition : une seule, 400 px, fond gris, collante ───────────────── */
/* 400 px VISIBLES : la colonne déborde du remplissage de la page (marge négative), la piste en tient compte. */
.entree-plein:not(.entree-composition) .grid-2.avec-cote { --cote: calc(400px - var(--pad-section)); }
.tp-colonne { min-width: 0; display: flex; flex-direction: column; gap: var(--space-3); background: var(--surface-2);
  border: var(--filet-w) solid var(--border); border-radius: var(--radius-lg); padding: var(--space-4);
  position: sticky; top: var(--space-4); max-height: calc(100vh - var(--barre-h, 0px) - var(--haut-visible, 0px) - var(--space-8)); overflow-y: auto; align-self: start; }
.tp-colonne > * { flex: none; }
.tp-colonne .tp-sec { background: var(--surface); }
.tp-colonne .tp-tete small { overflow-wrap: anywhere; }
.tp-colonne .tp-tete b { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tp-colonne .tp-tete > div { min-width: 0; }
/* Dans le tiroir du compositeur, la colonne EST déjà le panneau : ni second cadre, ni second défilement. */
.cp-tiroir-page .tp-colonne { position: static; max-height: none; overflow: visible; background: transparent; border: 0; padding: 0; }

/* La colonne de la fiche, calée sur celle de l'éditeur de type : pleine hauteur, collée au bord droit, fond gris, filet à gauche
   (plus de carte arrondie posée dans la page). Les marges négatives la sortent du remplissage de .en-corps. */
.entree-plein:not(.entree-composition) .tp-colonne {
  margin: calc(-1 * var(--space-6)) calc(-1 * var(--pad-section)) calc(-1 * var(--space-10)) 0;
  border: 0; border-left: var(--filet-w) solid var(--border); border-radius: 0;
  top: var(--barre-h); height: calc(100vh - var(--barre-h) - var(--haut-visible)); max-height: none;
}
/* Les autres colonnes d'édition prennent le même fond que celle du type. */
.ap-tiroir { background: var(--surface-2); }
.cp-tiroir { background: var(--surface-2); }

/* Titre et adresse : une rangée, deux tiers et un tiers ; elles se replient l'une sous l'autre quand la place manque. */
.tp-titre-adresse { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--space-3); align-items: start; margin-bottom: var(--space-3); }
.tp-titre-adresse .field { margin: 0; min-width: 0; }
.tp-titre-adresse .champ-groupe { min-width: 0; }
.tp-titre-adresse .affixe { max-width: 55%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 52rem) { .tp-titre-adresse { grid-template-columns: minmax(0, 1fr); } }
.cp-scene > .tp-titre-adresse { margin-bottom: var(--space-4); }

/* L'historique REMPLACE la colonne de droite (il n'en ajoute pas une troisième) et ne lui ressemble pas : fond blanc, filet
   d'accent, bandeau « Historique » avec le retour à la page. */
.entree-plein.avec-tiroir .tp-colonne, .entree-plein.avec-tiroir .cp-tiroir { display: none; }
.entree-plein.avec-tiroir .en-corps.cp-corps { grid-template-columns: 290px minmax(0, 1fr); }
.entree-composition.sans-plan.avec-tiroir .cp-corps { grid-template-columns: 0px minmax(0, 1fr); }
.en-historique { background: var(--surface); border-left: 2px solid var(--accent); }
.hi-bandeau { display: flex; align-items: center; gap: var(--space-2);
  margin: calc(-1 * var(--space-4)) calc(-1 * var(--space-4)) var(--space-1); padding: var(--space-3) var(--space-4);
  background: var(--accent-soft); color: var(--accent-soft-text); border-bottom: var(--filet-w) solid var(--border); }
.hi-bandeau > i:first-child { font-size: var(--icon-md); }
.hi-bandeau b { flex: 1; min-width: 0; font-size: 14px; font-weight: 600; outline: none; }

/* Dans le tiroir d'une page composée, rien au-dessus de la colonne : le titre et l'adresse sont partis au-dessus de l'aperçu. */
.cp-tiroir-page .card-nu > .card-body { padding: 0; }
.cp-tiroir-page .champs-grille:empty { display: none; }

/* Fiche non composée : la rangée titre / adresse est à 20 px sous la barre, comme dans une page composée (.cp-scene). */
.fiche-carte { margin-top: calc(var(--space-5) - var(--space-6)); }
.fiche-carte > .card-body { padding-top: 0; }

/* Colonne d'une page composée : si la carte des champs ne montre rien (le champ Blocs est caché, il n'y en a pas d'autre),
   elle ne laisse pas non plus son interstice de 20 px au-dessus de la colonne. */
.cp-tiroir-page .card-nu:not(:has(.champs-grille > :not([hidden], input[type="hidden"]))) { display: none; }

/* Éditeur de zones de la page (type › Mise en page). */
.tp-zones { display: flex; flex-direction: column; gap: var(--space-2); }
.zone { border: var(--filet-w) solid var(--border); border-radius: var(--radius-md, 8px); background: var(--surface); }
.zone-lecture { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-2) var(--space-3); background: transparent; }
.zone-lecture > span, .zone-tete > .grow { display: flex; flex-direction: column; min-width: 0; }
.zone small { color: var(--text-muted); font-size: 12px; font-weight: 400; }
.zone-tete { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-2) var(--space-3); }
.zone-poignee { width: 18px; color: var(--text-muted); display: inline-flex; }
.zone.est-glisse { opacity: .45; }
.zone-corps { display: flex; flex-direction: column; gap: var(--space-3); padding: var(--space-3); border-top: var(--filet-w) solid var(--border); }
.zone-champs { list-style: none; margin: 0 0 var(--space-2); padding: 0; display: flex; flex-direction: column; gap: 2px; }
.zone-champs li { display: flex; align-items: center; gap: var(--space-1); }
.zone-champs li > span { flex: 1; min-width: 0; }
.zone-ajout { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-3); }
.zone-tete small { display: none; }

.zone-apercu { margin-top: var(--space-3); border: var(--filet-w) solid var(--border); border-radius: var(--radius-md, 8px); overflow: hidden; }
.zone-apercu > summary { cursor: pointer; padding: var(--space-2) var(--space-3); font-weight: 600; font-size: 13px; }
.zone-apercu-cadre { overflow: hidden; background: var(--surface-2); min-height: 80px; }
.zone-apercu-cadre iframe { pointer-events: none; }

/* Réglages d'une entrée de menu portés par un style nommé : visibles, non modifiables ici. */
.regle-par-style { opacity: .55; pointer-events: none; }
