/*
 * console.css : l'habillage de l'espace d'administration.
 *
 * --- Refondue le 2026-09-07, et pourquoi -----------------------------------
 * L'ossature de la version du 2026-08-24 est conservée : un cadre permanent à
 * gauche, un écran à droite qui ne contient que sa matière. Ce qui change, ce
 * sont les couleurs, l'identité, et l'arrivée d'un thème sombre.
 *
 * Trois raisons à cette refonte :
 *
 *  1. DEUX IDENTITÉS DANS LE MÊME PRODUIT. La page de vente porte le jaune de
 *     l'agence sur du zinc quasi noir ; la console portait un marine #1F4789 et
 *     un bleu #0097D7 qui ne viennent de nulle part. Un client qui signe sur la
 *     page de vente et qui ouvre son espace changeait de marque en chemin.
 *     L'espace prend donc la charte de l'agence, celle de vitrine.css.
 *
 *  2. L'ACTION N'EST PAS UNE COULEUR DE MARQUE. Chez Shopify comme chez
 *     Hostinger, le bouton qui agit est encre sur blanc, ou blanc sur encre. La
 *     couleur de marque, elle, ne sert qu'à MARQUER : l'étape en cours, la
 *     valeur du jour. Le jaune #FACC15 fait 1,7:1 sur blanc : il ne peut ni
 *     porter du texte, ni remplir un bouton. Il marque, et c'est tout.
 *
 *  3. LE THÈME EST UN RÉGLAGE, PAS UN INTERRUPTEUR. Trois valeurs, gardées sur
 *     le compte : clair (le défaut), sombre, ou comme le système. Le gabarit
 *     pose le choix sur <html> avant le premier octet de HTML : il n'y a donc
 *     aucun clignotement au chargement, et aucun JavaScript à exécuter avant
 *     de peindre.
 *
 * --- Les cinq règles de cette feuille --------------------------------------
 *  1. TOUT PASSE PAR UN JETON. C'est ce qui a rendu cette refonte possible :
 *     3 320 lignes ne portaient que 22 couleurs écrites en dur. Une couleur
 *     écrite en dur est une couleur qui ne sait pas devenir sombre.
 *  2. UN SEUL PLEIN PAR ÉCRAN. `--action` remplit le bouton qui agit, et rien
 *     d'autre. Le reste est un trait, un fond très clair, ou rien.
 *  3. AUCUNE OPACITÉ SUR DU TEXTE. Les gris sont des couleurs pleines, mesurées
 *     sur LEUR fond, pas sur du blanc théorique.
 *  4. LE TRAIT AVANT L'OMBRE. Un filet d'un pixel sépare mieux que trois ombres
 *     empilées. L'ombre dit « ceci flotte », rien de plus.
 *  5. LE MOUVEMENT SERT OU N'EST PAS. 140 ms sur un survol, jamais
 *     « transition: all ». Tout s'arrête sous prefers-reduced-motion.
 *
 * --- Sur la duplication du bloc sombre -------------------------------------
 * Les jetons sombres sont écrits DEUX FOIS : une fois pour `data-theme="sombre"`
 * (le choix explicite), une fois dans la requête média pour `data-theme="auto"`
 * (le choix « comme le système »). CSS ne sait pas fusionner un sélecteur qui
 * vit dans une requête média avec un sélecteur qui n'y vit pas, et la seule
 * façon d'éviter la répétition serait un script exécuté avant la peinture, donc
 * un script en ligne, donc une brèche dans la politique de sécurité du contenu.
 * Quarante lignes répétées coûtent moins cher que cette brèche.
 */

/* Inter, la police de la marque, déjà servie par le site de l'agence. La graisse
   variable va jusqu'à 900 ; l'administration n'en emploie pas plus de 700. */
@font-face {
  font-family: 'Inter Variable';
  font-style: normal;
  font-weight: 300 900;
  font-display: swap;
  src: url('/assets/fonts/inter-latin-variable.woff2') format('woff2-variations'),
       url('/assets/fonts/inter-latin-variable.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC,
                 U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ═══════════════════════════════════════════════════════════════════════════
   LES JETONS · thème clair, celui par défaut
   ═══════════════════════════════════════════════════════════════════════════ */
:root {
  /* -- La marque ---------------------------------------------------------- */
  --marque:        #FACC15;  /* le jaune de l'agence. Il marque, il ne porte rien. */
  --marque-fond:   #FEFCE8;  /* le fond d'une zone marquée */
  --marque-encre:  #854D0E;  /* 7,0:1 sur --marque-fond : le texte d'une zone marquée */
  --marque-sur:    #1C1917;  /* ce qui se pose SUR le jaune : 12,5:1 */

  /* -- L'action ----------------------------------------------------------- */
  /* Un seul plein par écran. L'encre remplit le bouton, jamais la marque. */
  --action:        #18181B;
  --action-survol: #34343B;
  --sur-plein:     #FFFFFF;  /* le texte posé sur --action, --danger, --ok */
  --sur-encre:     #FAFAFA;  /* le texte posé sur --encre (bulles d'aide) */
  --lien:          #1D4ED8;  /* 7,4:1 : le texte qui se clique */
  --anneau:        rgba(29, 78, 216, .18);  /* l'anneau d'un champ actif */

  /* -- Encres, en couleurs pleines et mesurées sur LEUR fond --------------- */
  --encre:     #09090B;   /* 19,6:1 - le texte courant et les titres */
  --encre-2:   #52525B;   /*  7,5:1 - le texte secondaire */
  --encre-3:   #6A6A73;   /*  5,3:1 sur blanc, 5,1:1 sur le gris du cadre.
                           * Mesuré à l'écran plutôt que calculé sur blanc : un
                           * seuil qui ne tient que sur une surface n'est pas
                           * tenu, et le cadre de gauche n'est pas blanc. */
  --encre-70:  #52525B;   /* alias conservés : quarante écrans les emploient */
  --encre-50:  #6A6A73;

  /* -- Surfaces ----------------------------------------------------------- */
  --fond:      #F4F4F5;   /* le fond de l'application */
  --carte:     #FFFFFF;
  --rail:      #FAFAFA;   /* le cadre de gauche, à peine détaché du fond */
  --trait:     #E4E4E7;   /* le filet : décoratif, jamais porteur d'information */
  --trait-fort:#D4D4D8;
  --survol:    #F4F4F5;   /* le fond d'une ligne survolée */
  --rail-actif:#EFEFF1;   /* l'entrée où l'on se trouve : un aplat, pas une couleur */

  /* -- Le cadre de gauche, sur son fond sombre ----------------------------- */
  /* Il a ses propres jetons, et c'est ce qui rend le cadre sombre possible sans
     toucher à un seul écran : les encres du contenu sont mesurées sur du blanc,
     celles du cadre sur son fond à lui. Le mélanger aux jetons généraux aurait
     demandé de vérifier trois cents contrastes au lieu de six.

     Le fond n'est pas noir mais un encre très légèrement violacé : un noir pur
     à côté d'un blanc pur fait un contraste de 21:1 qui fatigue, et la nuance
     froide s'accorde au gris du contenu. */
  --rail-fond:     #17161F;
  --rail-encre:    #FAFAFA;  /* 17,2:1 sur le fond du cadre, mesuré */
  --rail-encre-2:  #A6A5B4;  /*  7,4:1 : les entrées au repos et les intertitres */
  --rail-survol:   rgba(255, 255, 255, .06);
  --rail-plein:    rgba(255, 255, 255, .11);  /* l'entrée où l'on se trouve */
  --rail-filet:    rgba(255, 255, 255, .09);

  /* -- États -------------------------------------------------------------- */
  --ok:            #15803D;  /* 5,0:1 */
  --ok-fond:       #F0FDF4;
  --attention:     #B45309;  /* 5,0:1 */
  --att-fond:      #FFFBEB;
  --danger:        #B91C1C;  /* 6,4:1 */
  --danger-survol: #991B1B;
  --danger-fond:   #FEF2F2;
  --info-fond:     #EFF6FF;

  /* -- Jetons conservés pour compatibilité --------------------------------- */
  /* Ils ne sont plus employés par cette feuille, mais un écran écrit avant la
     refonte peut encore les nommer. Ils pointent vers le nouveau système
     plutôt que vers l'ancien marine, qui n'existe plus nulle part. */
  --marine:    #1D4ED8;
  --bleu:      #6A6A73;
  --sarcelle:  #0F766E;
  --jaune:     #FACC15;
  --nuit:      #18181B;
  --blanc:     #FFFFFF;

  /* -- Géométrie ---------------------------------------------------------- */
  /* Les arrondis ont grandi le 2026-09-16, sur retour : « c'est trop brouillon
     à côté du hPanel ». Une carte à douze pixels à côté d'un champ à huit fait
     deux familles de formes sur le même écran. Seize et dix se lisent comme une
     seule intention, et c'est ce que fait l'interface qui sert de référence. */
  --rayon:     16px;      /* les conteneurs */
  --rayon-s:   10px;      /* les commandes : plus serré que son contenant */
  --rayon-xs:  8px;
  --rail-l:    248px;
  /* 800 px tenaient d'une colonne de LECTURE. La console montre des tableaux de
     cinq colonnes, et ils y étaient à l'étroit pendant que l'écran restait vide
     à droite. */
  --largeur:   980px;

  /* Ombres teintées d'encre, pas du noir pur : une ombre grise sur un fond
     froid fait sale. Deux niveaux, le second pour ce qui flotte vraiment. */
  --ombre:     0 1px 2px rgba(9, 9, 11, .05);
  --ombre-flot:0 12px 32px rgba(9, 9, 11, .13), 0 2px 6px rgba(9, 9, 11, .06);
  --voile:     rgba(9, 9, 11, .45);   /* le voile derrière une fenêtre modale */

  /* -- Mouvement ---------------------------------------------------------- */
  /* Les courbes natives de CSS démarrent lentement, donc l'interface a l'air de
     réfléchir avant de répondre. Celle-ci démarre vite. */
  --sortie:    cubic-bezier(.23, 1, .32, 1);
  --court:     140ms;
  --moyen:     180ms;

  --police: 'Inter Variable', Inter, -apple-system, BlinkMacSystemFont,
            'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  color-scheme: light;
}

/* ═══════════════════════════════════════════════════════════════════════════
   LES JETONS · thème sombre, choisi explicitement dans les réglages
   ═══════════════════════════════════════════════════════════════════════════ */
:root[data-theme="sombre"] {
  --marque:        #FACC15;
  --marque-fond:   #2A2415;
  --marque-encre:  #FDE047;
  --marque-sur:    #1C1917;

  --action:        #FAFAFA;
  --action-survol: #E4E4E7;
  --sur-plein:     #09090B;
  --sur-encre:     #09090B;
  --lien:          #93C5FD;
  --anneau:        rgba(147, 197, 253, .26);

  --encre:     #FAFAFA;
  --encre-2:   #A1A1AA;
  --encre-3:   #8B8B95;
  --encre-70:  #A1A1AA;
  --encre-50:  #8B8B95;

  --fond:      #0E0E11;
  --carte:     #17171A;
  --rail:      #131316;
  --rail-fond:     #101014;
  --rail-encre:    #FAFAFA;
  --rail-encre-2:  #9A9AA4;
  --rail-survol:   rgba(255, 255, 255, .05);
  --rail-plein:    rgba(255, 255, 255, .09);
  --rail-filet:    rgba(255, 255, 255, .08);
  --trait:     #2A2A30;
  --trait-fort:#3A3A42;
  --survol:    #202024;
  --rail-actif:#26262C;

  --ok:            #4ADE80;
  --ok-fond:       #10261A;
  --attention:     #FBBF24;
  --att-fond:      #2A2113;
  --danger:        #F87171;
  --danger-survol: #FCA5A5;
  --danger-fond:   #2C1618;
  --info-fond:     #16202F;

  --marine:    #93C5FD;
  --bleu:      #8B8B95;
  --sarcelle:  #5EEAD4;
  --jaune:     #FACC15;
  --nuit:      #09090B;
  --blanc:     #FFFFFF;

  --ombre:     0 1px 2px rgba(0, 0, 0, .40);
  --ombre-flot:0 12px 32px rgba(0, 0, 0, .55), 0 2px 6px rgba(0, 0, 0, .35);
  --voile:     rgba(0, 0, 0, .65);

  color-scheme: dark;
}

/* ═══════════════════════════════════════════════════════════════════════════
   LES JETONS · « comme le système », pour qui a choisi de suivre son appareil
   ═══════════════════════════════════════════════════════════════════════════ */
@media (prefers-color-scheme: dark) {
  :root[data-theme="auto"] {
    --marque:        #FACC15;
    --marque-fond:   #2A2415;
    --marque-encre:  #FDE047;
    --marque-sur:    #1C1917;

    --action:        #FAFAFA;
    --action-survol: #E4E4E7;
    --sur-plein:     #09090B;
    --sur-encre:     #09090B;
    --lien:          #93C5FD;
    --anneau:        rgba(147, 197, 253, .26);

    --encre:     #FAFAFA;
    --encre-2:   #A1A1AA;
    --encre-3:   #8B8B95;
    --encre-70:  #A1A1AA;
    --encre-50:  #8B8B95;

    --fond:      #0E0E11;
    --carte:     #17171A;
    --rail:      #131316;
  --rail-fond:     #101014;
  --rail-encre:    #FAFAFA;
  --rail-encre-2:  #9A9AA4;
  --rail-survol:   rgba(255, 255, 255, .05);
  --rail-plein:    rgba(255, 255, 255, .09);
  --rail-filet:    rgba(255, 255, 255, .08);
    --trait:     #2A2A30;
    --trait-fort:#3A3A42;
    --survol:    #202024;
    --rail-actif:#26262C;

    --ok:            #4ADE80;
    --ok-fond:       #10261A;
    --attention:     #FBBF24;
    --att-fond:      #2A2113;
    --danger:        #F87171;
    --danger-survol: #FCA5A5;
    --danger-fond:   #2C1618;
    --info-fond:     #16202F;

    --marine:    #93C5FD;
    --bleu:      #8B8B95;
    --sarcelle:  #5EEAD4;
    --jaune:     #FACC15;
    --nuit:      #09090B;
    --blanc:     #FFFFFF;

    --ombre:     0 1px 2px rgba(0, 0, 0, .40);
    --ombre-flot:0 12px 32px rgba(0, 0, 0, .55), 0 2px 6px rgba(0, 0, 0, .35);
    --voile:     rgba(0, 0, 0, .65);

    color-scheme: dark;
  }
}

* { box-sizing: border-box; }

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

body {
  margin: 0;
  min-height: 100dvh;
  background: var(--fond);
  color: var(--encre);
  /* 14 px et non 15. Un point de moins sur le corps redescend TOUTE l'échelle,
   * puisque le reste de la feuille est en rem : c'est le seul écart qui séparait
   * encore cet espace d'un tableau de bord de SaaS, et il se voyait sur les onze
   * entrées du cadre avant de se voir ailleurs. */
  font: 400 14px/1.55 var(--police);
  -webkit-font-smoothing: antialiased;
  /* Les chiffres alignés partout : une colonne de dates ou de compteurs qui
   * danse d'une ligne à l'autre se relit deux fois. */
  font-variant-numeric: tabular-nums;
}

/* -- Le squelette : un cadre à gauche, un écran à droite -------------------- */
/*
 * Une grille de deux colonnes plutôt que deux blocs flottants : le cadre garde sa
 * largeur quoi qu'il arrive au contenu, et le contenu ne peut pas passer dessous.
 */
.appli {
  display: grid;
  grid-template-columns: var(--rail-l) minmax(0, 1fr);
  min-height: 100dvh;
}

.rail {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 16px 12px 14px;
  background: var(--rail-fond);
  color: var(--rail-encre);
  /* Pas de filet : le cadre se détache par sa couleur, et un trait clair entre
     un fond sombre et un fond gris fait une couture. */
  border-right: 0;
  /* Le cadre reste à l'écran quand l'écran de droite fait quatre hauteurs : c'est
   * toute sa raison d'être. Un menu qu'il faut remonter chercher n'est pas un
   * cadre, c'est un contenu. */
  position: sticky;
  top: 0;
  height: 100dvh;
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* L'identité du site en cours d'édition. Elle est ici et nulle part ailleurs :
 * quelqu'un qui gère deux JCE doit savoir laquelle il modifie sans lire le titre. */
.rail-marque {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 6px 8px 16px;
  color: var(--rail-encre);
  text-decoration: none;
  font-size: .875rem;
  font-weight: 600;
  letter-spacing: -.012em;
}
.marque-pastille {
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--marque);
  flex: none;
}
.rail-marque span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.rail-nav { display: flex; flex-direction: column; gap: 1px; }

/* Un intertitre de groupe. En minuscules et en gris : il classe, il ne s'annonce
 * pas. Les capitales espacées d'une interface d'admin sur trois crient plus fort
 * que les entrées qu'elles surmontent. */
.rail-titre {
  margin: 18px 0 6px;
  padding: 0 10px;
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--rail-encre-2);
}
.rail-nav > .rail-titre:first-child { margin-top: 4px; }

.rail-lien {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 9px 10px;
  border-radius: var(--rayon-s);
  color: var(--rail-encre-2);
  font-size: .855rem;
  font-weight: 500;
  text-decoration: none;
  transition: background-color var(--court) var(--sortie),
              color var(--court) var(--sortie);
}
.rail-lien svg { width: 18px; height: 18px; flex: none; color: currentColor; }
/* Le survol n'existe que là où il y a un vrai pointeur : sur un écran tactile il
 * se déclenche au doigt et reste allumé sur l'entrée qu'on vient de quitter. */
@media (hover: hover) and (pointer: fine) {
  .rail-lien:hover { background: var(--rail-survol); color: var(--rail-encre); }
}
/* L'écran où l'on se trouve. Fond plein et non pas un simple gras : à neuf
 * entrées, un gras se cherche, un aplat se voit sans lire. */
.rail-lien--actif,
.rail-lien--actif:hover {
  background: var(--rail-plein);
  color: var(--rail-encre);
  font-weight: 600;
}

/* Un compteur collé à une entrée : les demandes qui attendent. Il ne s'affiche
 * que s'il y a quelque chose, sinon c'est un zéro qui occupe de la place. */
.rail-compteur {
  margin-left: auto;
  min-width: 20px;
  padding: 1px 6px;
  border-radius: 999px;
  background: var(--danger);
  color: var(--sur-plein);
  font-size: .75rem;
  font-weight: 600;
  text-align: center;
}
.rail-lien--actif .rail-compteur { background: var(--danger); }

.rail-pied {
  margin-top: auto;
  padding: 13px 10px 2px;
  border-top: 1px solid var(--rail-filet);
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: .78rem;
}
.rail-pied .qui {
  color: var(--rail-encre-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.rail-pied .version { color: var(--rail-encre-2); font-size: .78rem; }

/* ─── Ce que le fond sombre du cadre entraîne ───────────────────────────────
   Quatre éléments y vivaient avec des encres mesurées sur du blanc. Ils sont
   repris ici plutôt qu'à leur place d'origine : c'est le CADRE qui a changé,
   pas eux, et un jour où il redeviendrait clair il n'y aura qu'un bloc à
   retirer. */
.rail .tuile-marque { background: var(--marque); color: var(--marque-sur); }
.rail .avatar { background: var(--rail-plein); color: var(--rail-encre); }
.rail .rail-qui-nom { color: var(--rail-encre); }
.rail .rail-qui-role { color: var(--rail-encre-2); }
.rail .rail-sortir { color: var(--rail-encre-2); }
.rail .rail-sortir:hover { background: var(--rail-survol); color: var(--rail-encre); }
.rail .rail-traceurs, .rail .rail-traceurs:hover { color: var(--rail-encre-2); }

/* Sur un téléphone, le cadre passe en bandeau horizontal qui défile. Pas de menu
 * escamotable : il demanderait un script, et un menu qui ne s'ouvre pas parce que
 * le script a échoué enferme l'utilisateur dehors. */
@media (max-width: 900px) {
  .appli { grid-template-columns: minmax(0, 1fr); }
  .rail {
    position: static;
    height: auto;
    flex-direction: row;
    align-items: center;
    gap: 8px;
    padding: 10px 12px;
    border-right: none;
    border-bottom: 1px solid var(--trait);
    overflow-x: auto;
  }
  .rail-marque { padding: 0 8px 0 4px; }
  .rail-nav { flex-direction: row; gap: 4px; }
  .rail-titre, .rail-pied .version { display: none; }
  .rail-lien { white-space: nowrap; padding: 7px 10px; }
  .rail-pied {
    margin: 0 0 0 auto;
    padding: 0 0 0 12px;
    border-top: none;
    border-left: 1px solid var(--trait);
  }
  .rail-pied .qui { display: none; }
}

/* -- L'anneau de focus, une fois pour toutes ------------------------------ */
/*
 * Posé sur tout ce qui peut recevoir le focus, et pas classe par classe : une
 * règle par composant se traduit toujours, tôt ou tard, par un composant écrit
 * plus tard qui n'en a pas. Le contour par défaut du navigateur existe, mais il
 * est fin, il change d'un navigateur à l'autre, et il disparaît sous un fond
 * coloré.
 *
 * :focus-visible et non :focus : le clic à la souris ne dessine rien, seul le
 * clavier le fait. C'est ce qui permet un anneau franc sans qu'il apparaisse à
 * chaque clic.
 */
:where(a, button, summary, input, select, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--lien);
  outline-offset: 2px;
  border-radius: var(--rayon-xs);
}
/* Sur l'entrée active du cadre, qui porte un aplat gris, l'anneau bleu manque de
 * contraste : il passe à l'encre, et à l'intérieur du bord plutôt qu'autour, où
 * il serait mangé par le bord de l'aplat. */
.rail-lien--actif:focus-visible {
  outline-color: var(--action);
  outline-offset: -3px;
}

/* Le lien d'évitement. Invisible jusqu'à ce qu'on tabule dessus. */
.saut { position: absolute; left: -9999px; z-index: 60; }
.saut:focus {
  left: 12px; top: 12px;
  padding: 10px 14px;
  background: var(--action);
  color: var(--sur-plein);
  border-radius: var(--rayon-s);
  text-decoration: none;
}

/* -- L'écran -------------------------------------------------------------- */

.corps {
  width: 100%;
  max-width: var(--largeur);
  margin: 0 auto;
  /* Plus d'air en haut : le titre d'écran ne doit pas toucher le bord du cadre.
     C'est la différence la plus visible entre une interface qui respire et une
     interface qui remplit, et elle ne coûte que des pixels. */
  padding: 44px 40px 80px;
}
body.large .corps { max-width: 1240px; }
/* L'éditeur : aucune marge, il occupe tout.
 *
 * Et le cadre de gauche s'efface. C'est le seul écran où il le fait, pour deux
 * raisons : l'éditeur est déjà une mise en page à deux volets, et lui retirer
 * 248 pixels écrase l'aperçu, qui est la moitié de son intérêt ; et on n'y entre
 * pas pour naviguer mais pour faire une chose et repartir. Sa propre barre porte
 * « Toutes les pages », donc la sortie reste à un clic.
 */
body.pleine .corps { max-width: none; padding: 0; }
body.pleine .appli { grid-template-columns: minmax(0, 1fr); }
body.pleine .rail { display: none; }

/* L'en-tête d'écran : le nom de l'écran à gauche, LA seule action primaire à
 * droite. C'est le gabarit qui la porte, donc aucun écran ne peut en avoir deux. */
.entete-ecran {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin: 0 0 24px;
}
.entete-ecran > div { min-width: 0; }
.entete-ecran h1 { margin: 0; }
.entete-ecran .chapeau { margin: 6px 0 0; }
.entete-ecran-actions { display: flex; align-items: center; gap: 10px; flex: none; }

/* Le fil d'Ariane : d'où l'on vient, en une ligne. Toujours présent sur un écran
 * de deuxième niveau, parce qu'un cul-de-sac oblige à repasser par le cadre. */
.fil {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0 0 14px;
  font-size: .88rem;
  color: var(--encre-3);
}
.fil a { color: var(--encre-2); text-decoration: none; }
.fil a:hover { color: var(--encre); text-decoration: underline; }

/* -- Typographie ---------------------------------------------------------- */

h1 {
  margin: 0 0 8px;
  font-size: 1.75rem;
  line-height: 1.2;
  font-weight: 600;
  /* Le resserrement va avec la taille : un titre à 26 px avec l'espacement d'un
   * paragraphe a l'air distendu. */
  letter-spacing: -.022em;
  text-wrap: balance;
}
h2 {
  margin: 40px 0 14px;
  font-size: 1.1rem;
  line-height: 1.3;
  font-weight: 600;
  letter-spacing: -.012em;
  text-wrap: balance;
}
h3 {
  margin: 26px 0 8px;
  font-size: .98rem;
  font-weight: 600;
  letter-spacing: -.006em;
}
p { margin: 0 0 14px; text-wrap: pretty; }
a { color: var(--lien); text-decoration-thickness: 1px; text-underline-offset: 2px; }
strong { font-weight: 600; }

/* Le chapeau : une seule phrase, et une largeur de lecture. Au-delà de 62
 * caractères l'oeil perd sa ligne en revenant à gauche. */
.chapeau { margin: 0 0 24px; max-width: 62ch; color: var(--encre-2); }
.note    { color: var(--encre-3); font-size: .89rem; }
.note--espacee { margin-top: 20px; }
.aide--erreur { color: var(--danger); }
code, .code { font-family: var(--mono); font-size: .88em; }

/* Un bloc à recopier : une ligne de cron, un enregistrement DNS, une commande.
 * Il défile HORIZONTALEMENT plutôt que de se replier sur plusieurs lignes, et
 * c'est le seul point qui compte ici : une ligne de cron coupée au milieu se
 * recopie coupée, et une tâche planifiée avec un chemin tronqué ne signale
 * jamais rien, elle ne fait simplement rien. Mieux vaut une barre de défilement
 * qu'une valeur fausse qu'on croit avoir lue en entier. */
.bloc-code {
  margin: 6px 0 16px;
  padding: 10px 12px;
  overflow-x: auto;
  background: var(--nuit);
  color: #E9EAF2;
  border-radius: 8px;
  font-size: .84rem;
  line-height: 1.5;
  white-space: pre;
  -webkit-user-select: all;
  user-select: all;
}
.bloc-code code { font-size: inherit; color: inherit; }

/* La variante claire : pour un texte à recopier qui est du FRANÇAIS et non une
 * commande. Une réponse à un avis en blanc sur fond nuit se lit comme du code,
 * et personne ne relit du code avant de le coller, ce qui est exactement ce que
 * cet écran demande de faire. */
.bloc-code--clair {
  background: var(--survol);
  color: var(--encre);
  font-family: var(--police);
  font-size: .95rem;
  white-space: pre-wrap;
  border: 1px solid var(--trait);
}
/* La police est reprise sur le `code` intérieur, sinon la règle générale
 * `code, .code` la ramène en chasse fixe et la réponse à un avis se relit comme
 * un extrait de terminal. */
.bloc-code--clair code { font-family: inherit; }

/* Le détail d'une ligne : il n'a pas de point d'état, donc il s'aligne sous le
 * titre de la rangée qui le précède plutôt que sous son point. */
.rangee--detail { padding-left: 34px; }
.rangee--detail .rangee__meta { display: block; margin-top: 4px; }

/* -- Cartes --------------------------------------------------------------- */
/*
 * Une carte n'existe que si l'élévation dit quelque chose : « ceci est un objet
 * distinct du fond ». Le filet fait le travail, l'ombre le confirme à peine.
 */
.carte {
  background: var(--carte);
  border: 1px solid var(--trait);
  border-radius: var(--rayon);
  /* Plus d'ombre du tout : la règle 4 de cette feuille dit « le trait avant
     l'ombre », et l'ombre à un pixel ne faisait que salir le bord. Les cartes de
     l'interface qui sert de référence n'en portent aucune. */
  box-shadow: none;
  padding: 26px 28px;
}
.carte + .carte { margin-top: 16px; }
/* Une carte qui n'est qu'un contenant de lignes : les lignes portent déjà leur
 * séparation, la carte n'a pas à rajouter de marge intérieure en haut. */
.carte--lignes { padding: 6px 24px; }

.centre { max-width: 420px; margin: 8vh auto; }

/* Une pile d'objets de même nature, à intervalle constant. Remplace les
 * margin-bottom posés à la main écran par écran. */
.pile { display: flex; flex-direction: column; gap: 16px; }
.pile--serree { gap: 8px; }

.deux-colonnes {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 0 20px;
}

/* -- Boutons -------------------------------------------------------------- */
/*
 * Trois niveaux, et un seul par écran peut être primaire. Le quatrième niveau est
 * un lien : quand une action n'a pas besoin d'un bouton, elle n'en prend pas.
 */
.bouton {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  padding: 10px 18px;
  border: 1px solid transparent;
  border-radius: var(--rayon-s);
  background: var(--action);
  color: var(--sur-plein);
  font: inherit;
  /* 13 px et 550 de graisse. Un bouton de 15 px en graisse 500 dans une barre
   * d'en-tête a l'air d'un bouton de formulaire ; à 13 px en 550 il a l'air
   * d'une commande. C'est la mesure relevée chez Shopify comme chez Wix. */
  font-size: .855rem;
  font-weight: 550;
  letter-spacing: -.005em;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  /* Jamais « all » : la liste explicite évite d'animer par accident une propriété
   * de mise en page, qui coûte un recalcul complet à chaque image. */
  transition: background-color var(--court) var(--sortie),
              border-color var(--court) var(--sortie),
              transform var(--court) var(--sortie),
              box-shadow var(--court) var(--sortie);
}
.bouton svg { width: 17px; height: 17px; }
@media (hover: hover) and (pointer: fine) {
  .bouton:hover { background: var(--action-survol); }
}
/* L'enfoncement. C'est le détail qui fait qu'une interface a l'air d'avoir
 * entendu le clic : sans lui, le bouton reste inerte jusqu'à ce que la page
 * change, et l'utilisateur clique deux fois. */
.bouton:active { transform: scale(.98); }
.bouton:focus-visible { outline: 2px solid var(--lien); outline-offset: 2px; }
/* Un bouton éteint. Il reste lisible, il ne fait que cesser d'appeler le clic :
 * un bouton à 30 % d'opacité ne se lit plus, et l'utilisateur croit à une panne
 * d'affichage plutôt qu'à une action indisponible. Son motif est dans son title. */
.bouton:disabled {
  background: var(--survol);
  border-color: var(--trait);
  color: var(--encre-3);
  cursor: default;
  box-shadow: none;
}
.bouton:disabled:active { transform: none; }

/* Secondaire : la même forme, sans l'aplat. C'est le niveau par défaut de toute
 * action qui n'est pas celle que l'utilisateur est venu faire. */
.bouton--sobre, .bouton--fantome {
  background: var(--carte);
  border-color: var(--trait-fort);
  color: var(--encre);
  box-shadow: var(--ombre);
}
@media (hover: hover) and (pointer: fine) {
  .bouton--sobre:hover, .bouton--fantome:hover { background: var(--survol); }
}
/* Détruire ne ressemble jamais à enregistrer : c'est le seul endroit de
 * l'administration où le rouge apparaît, et il n'apparaît que là. */
.bouton--danger {
  background: var(--carte);
  border-color: var(--danger);
  color: var(--danger);
}
@media (hover: hover) and (pointer: fine) {
  .bouton--danger:hover { background: var(--danger-fond); border-color: var(--danger); }
}
.bouton--danger:focus-visible { outline-color: var(--danger); }
/* L'aplat rouge, et il n'existe qu'à UN endroit : le bouton qui confirme une
 * destruction dans une boîte de dialogue. Ailleurs, détruire se dit en contour
 * (.bouton--danger) : un aplat rouge posé dans un écran de travail attire l'œil
 * sur ce qu'on ne veut surtout pas cliquer par erreur. Ici c'est l'inverse : on est
 * venu pour ça, et il doit se distinguer d'« Annuler » sans hésitation.
 * #B3261E porte du blanc à 6,5:1. */
.bouton--detruire {
  background: var(--danger);
  border-color: var(--danger);
  color: var(--sur-plein);
}
@media (hover: hover) and (pointer: fine) {
  .bouton--detruire:hover { background: var(--danger-survol); border-color: var(--danger-survol); }
}
.bouton--detruire:focus-visible { outline-color: var(--danger); }

/* ── Une boîte de dialogue ───────────────────────────────────────────────────
 *
 * Rendue par le serveur, pas ouverte par un script : l'adresse porte la demande de
 * confirmation, donc la protection existe même si le script ne s'est pas chargé.
 * C'est ce qui la distingue d'un `confirm()` du navigateur, qui ne se met pas en
 * forme et ne peut pas dire ce que l'action coûte vraiment.
 */
.voile {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  place-items: center;
  padding: 20px;
  /* Le voile est sombre et transparent : il ne cache pas ce qu'on est en train de
   * décider, il le met en retrait. Une boîte posée sur un écran net donne
   * l'impression qu'on peut encore cliquer derrière. */
  background: var(--voile);
  animation: voile-entree var(--moyen) var(--sortie);
}
.modale {
  width: min(420px, 100%);
  padding: 22px 24px 20px;
  background: var(--carte);
  border-radius: var(--rayon);
  box-shadow: var(--ombre-flot);
  animation: modale-entree var(--moyen) var(--sortie);
}
.modale-titre {
  margin: 0 0 8px;
  font-size: 1.08rem;
  font-weight: 600;
  letter-spacing: -.014em;
}
.modale-texte { margin: 0; color: var(--encre-2); font-size: .93rem; }
/* « Annuler » à gauche, l'action à droite, et l'action destructrice est la seule
 * en aplat : la main va à droite, mais l'œil a lu les deux. */
.modale-actions {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 10px;
  margin-top: 20px;
}

/* Elle arrive de très peu, et depuis 96 % de sa taille : rien dans le monde réel
 * n'apparaît à partir de rien, et une boîte qui surgit d'un point donne
 * l'impression d'un ressort. */
@keyframes modale-entree {
  from { opacity: 0; transform: translateY(6px) scale(.97); }
  to   { opacity: 1; transform: none; }
}
@keyframes voile-entree {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.bouton--bloc { width: 100%; }
.bouton--s { padding: 4px 10px; font-size: .78rem; border-radius: var(--rayon-xs); }
.bouton--s svg { width: 15px; height: 15px; }

/* Un bouton d'icône seule : les flèches de l'éditeur, la duplication, le retrait.
 * Discret au repos, il ne se révèle qu'au survol de sa ligne. */
.bouton--picto {
  padding: 6px;
  width: 30px; height: 30px;
  background: transparent;
  border-color: transparent;
  color: var(--encre-3);
  box-shadow: none;
}
@media (hover: hover) and (pointer: fine) {
  .bouton--picto:hover { background: var(--survol); color: var(--encre); }
}

.actions { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin-top: 24px; }
/* Un champ qui suit une rangée de boutons a besoin de sa propre respiration : sans
 * elle, son étiquette se colle au bas des boutons et paraît leur appartenir. */
.actions + .champ, .actions + form.champ { margin-top: 18px; }

.lien-discret { color: var(--encre-2); font-size: .89rem; }
.lien-sobre { color: var(--lien); font-size: .89rem; }

/* -- Formulaires ---------------------------------------------------------- */

.champ { margin-bottom: 18px; }
.champ label {
  display: block;
  margin-bottom: 7px;
  font-size: .89rem;
  font-weight: 500;
  color: var(--encre);
}
/* L'aide d'un champ passe SOUS le champ et en petit : au-dessus, elle se lit
 * avant l'étiquette et double la hauteur de chaque ligne du formulaire. */
.champ .aide {
  display: block;
  margin-top: 6px;
  color: var(--encre-3);
  font-size: .84rem;
}
/* L'erreur d'un champ reste écrite sous lui, en rouge (DESIGN-ADMIN, partie 10).
 * La règle `.aide--erreur` seule pèse moins que `.champ .aide` juste au-dessus :
 * l'erreur sortait grise, comme une aide, sous les champs de la création d'un
 * site. Le filet rouge du champ dit lequel est en cause avant même la phrase. */
.champ .aide--erreur { color: var(--danger); }
.champ input[aria-invalid="true"] { border-color: var(--danger); }

/* ── L'infobulle : le petit « i » ─────────────────────────────────────────────
 *
 * L'aide d'un champ ne s'écrit plus sous le champ. Elle se range derrière un
 * cercle de seize pixels et n'apparaît qu'au survol, au focus, ou au doigt.
 *
 * Trois points de construction :
 *  · la bulle est ancrée à la LIGNE de l'étiquette, pas à l'icône, et elle
 *    s'étire d'un bord à l'autre. Ancrée à l'icône, elle sortirait du panneau de
 *    l'éditeur, qui fait 260 px et qui défile en masquant ce qui dépasse ;
 *  · `visibility` en plus de `opacity` : sans elle, la bulle invisible reste
 *    cliquable et intercepte le clic destiné au champ qu'elle recouvre ;
 *  · fond encre et texte blanc, soit 15,8:1. Une bulle claire sur un formulaire
 *    clair ne se détacherait pas de ce qu'elle recouvre.
 */
.champ-tete {
  position: relative;
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 6px;
}
.champ-tete label { margin-bottom: 0; }
/* Le titre d'un bloc de réglages porte sa bulle comme une étiquette de champ
 * porte la sienne : même geste, même endroit, un seul mécanisme à comprendre. */
.carte-tete { margin-bottom: 12px; }
.carte-tete h2 { margin: 0; }
.carte-tete .info-bulle { top: calc(100% + 5px); }

/* Cinquième classe orpheline, trouvée le 2026-09-17 par la même méthode que les
   quatre du 16 : `.carte-intro` n'était stylée que dans `assets/css/admin.css`,
   que PLUS AUCUN écran ne charge. Les deux phrases d'introduction de l'onglet
   du site public se rendaient donc à la taille du corps de texte, en encre
   pleine, au lieu d'être la mention discrète voulue. Le style est repris
   ici, mais PAS mot pour mot : `admin.css` écrivait `var(--muted)`, un jeton
   qui n'existe pas dans le vocabulaire de `console.css`. Recopier la règle
   telle quelle aurait rendu la couleur invalide, donc héritée, et la mention
   serait restée en encre pleine sans que rien ne le signale. L'encre secondaire
   de cette feuille est `--encre-2`, celle de `.champ .aide`. */
.carte-intro { color: var(--encre-2); font-size: .89rem; margin: -6px 0 16px; }
.champ-tete--case { margin-bottom: 0; }
.champ-tete--case .case { margin: 0; }

/* L'astérisque d'un champ indispensable. Il se voit sans rien survoler : ce qui
 * conditionne la mise en ligne ne peut pas être caché dans une bulle. */
.requis {
  margin-left: 3px;
  color: var(--lien);
  font-weight: 600;
}

.info-i {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 17px;
  height: 17px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: none;
  color: var(--encre-3);
  cursor: help;
  transition: color var(--court) var(--sortie);
}
.info-i svg { width: 15px; height: 15px; display: block; }
.info-i:hover, .info-i:focus-visible { color: var(--lien); }

.info-bulle {
  position: absolute;
  z-index: 40;
  top: calc(100% + 7px);
  left: 0;
  right: 0;
  padding: 9px 12px;
  border-radius: var(--rayon-xs);
  background: var(--encre);
  color: var(--sur-encre);
  font-size: .84rem;
  font-weight: 400;
  line-height: 1.45;
  text-align: left;
  box-shadow: var(--ombre-flot);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  pointer-events: none;
  transition: opacity var(--court) var(--sortie),
              transform var(--court) var(--sortie),
              visibility var(--court) linear;
}
/* La pointe. Un carré tourné plutôt qu'une bordure biseautée : il suit la couleur
 * du fond de la bulle sans qu'on ait à la répéter. */
.info-bulle::before {
  content: "";
  position: absolute;
  top: -3px;
  left: 4px;
  width: 8px;
  height: 8px;
  border-radius: 1px;
  background: var(--encre);
  transform: rotate(45deg);
}
.info-i:hover + .info-bulle,
.info-i:focus-visible + .info-bulle,
.info-i:focus + .info-bulle {
  opacity: 1;
  visibility: visible;
  transform: none;
}

/* Le geste, et non l'explication du geste : « Ouvrir Médias » remplace trois
 * lignes qui disaient d'y aller. */
.champ-ailleurs {
  display: inline-block;
  margin-top: 8px;
  color: var(--lien);
  font-size: .84rem;
}

/* Un champ composé par le moteur : la valeur se lit, l'étiquette dit d'où elle
 * vient, et le pourquoi est dans la bulle. */
.champ--calcule .champ-label { font-size: .89rem; font-weight: 500; }
.champ--calcule .champ-calcule-valeur {
  margin: 0;
  padding: 9px 12px;
  border: 1px dashed var(--trait-fort);
  border-radius: var(--rayon-s);
  color: var(--encre-2);
  font-size: .91rem;
}

@media (prefers-reduced-motion: reduce) {
  .info-bulle { transition: none; }
}

input[type=text], input[type=email], input[type=password], input[type=url],
input[type=number], input[type=date], input[type=time], input[type=search],
input[type=tel], input[type=file], select, textarea {
  width: 100%;
  /* Quarante-quatre pixels de haut, ce qui est la cible tactile minimale ET la
     hauteur des champs de l'interface qui sert de référence. Un champ de trente-
     six pixels a l'air d'une grille de tableur. */
  padding: 12px 14px;
  border: 1px solid var(--trait);
  border-radius: var(--rayon-s);
  background: var(--carte);
  color: var(--encre);
  font: inherit;
  font-size: .92rem;
  transition: border-color var(--court) var(--sortie),
              box-shadow var(--court) var(--sortie);
}
input::placeholder, textarea::placeholder { color: var(--encre-3); }
/* Le halo plutôt que le contour épais : il marque le champ actif sans décaler
 * d'un pixel la ligne du formulaire, ce que faisait l'ancien outline. */
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--lien);
  box-shadow: 0 0 0 3px var(--anneau);
}
textarea { min-height: 96px; resize: vertical; line-height: 1.55; }
select {
  appearance: none;
  padding-right: 34px;
  /* La flèche est dessinée dans le fond : un SVG en data-uri ne demande aucune
   * requête et la politique de sécurité du contenu l'autorise. */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23676D80' stroke-width='1.7' stroke-linecap='round'%3E%3Cpath d='M4 6.5 8 10.5l4-4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 11px center;
  background-size: 16px;
}
input[type=checkbox], input[type=radio] { accent-color: var(--lien); }

input.code {
  font-family: var(--mono);
  font-size: 1.5rem;
  letter-spacing: .4em;
  text-align: center;
}

/* La barre d'enregistrement d'un formulaire long. Elle suit le défilement, son
 * fond est OPAQUE, et elle porte un filet en haut : sans le filet elle a l'air
 * posée au hasard sur le texte qui passe dessous. */
.reglages-form .carte + .carte { margin-top: 16px; }
.reglages-form .carte h2 { margin-top: 0; font-size: 1rem; }
.reglages-form .carte h2 .note { font-weight: 400; margin-left: 8px; }
.reglages-form .carte h3 { font-size: .94rem; margin: 22px 0 10px; }
.reglages-form .actions {
  position: sticky;
  bottom: 0;
  margin-top: 20px;
  padding: 14px 0;
  background: var(--fond);
  border-top: 1px solid var(--trait);
}

/* -- Listes et tableaux --------------------------------------------------- */

table { width: 100%; border-collapse: collapse; font-size: .93rem; }
th {
  text-align: left;
  padding: 0 12px 9px 0;
  border-bottom: 1px solid var(--trait);
  color: var(--encre-3);
  font-size: .82rem;
  font-weight: 500;
  /* Pas de capitales forcées : « ADRESSE » ne se lit pas plus vite que
   * « Adresse », il pèse seulement plus lourd dans l'image de la page. */
  text-transform: none;
  letter-spacing: 0;
}
td {
  padding: 12px 12px 12px 0;
  border-bottom: 1px solid var(--trait);
  vertical-align: middle;
}
tr:last-child td { border-bottom: none; }
td .note { display: block; margin-top: 2px; }

/* Une ligne dont le survol éclaire toute la largeur : ça donne la cible. */
@media (hover: hover) and (pointer: fine) {
  .table--lignes tbody tr { transition: background-color var(--court) var(--sortie); }
  .table--lignes tbody tr:hover { background: var(--survol); }
}
.table--lignes td:first-child { padding-left: 10px; border-radius: var(--rayon-xs) 0 0 var(--rayon-xs); }
.table--lignes td:last-child  { padding-right: 10px; text-align: right; border-radius: 0 var(--rayon-xs) var(--rayon-xs) 0; }

/* Une liste d'objets : le nom, un état, une action. Remplace les tableaux à
 * quatre colonnes dont trois étaient de l'explication. */
.rangee {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 0;
  border-bottom: 1px solid var(--trait);
}
.rangee:last-child { border-bottom: none; }
/* Ces trois-là sont tantôt des paragraphes, tantôt des span à l'intérieur d'une
 * rangée-lien : un <p> dans un <a> n'est pas du HTML valide. D'où le display posé
 * explicitement plutôt que laissé à la balise. */
.rangee__corps { display: block; flex: 1; min-width: 0; }
/* Un titre posé directement dans la rangée, sans corps autour : il prend la place
 * que le corps aurait prise, sinon le chevron se colle au dernier mot au lieu de
 * tenir le bord droit, et la ligne n'a plus de bord droit à suivre. */
.rangee > .rangee__titre { flex: 1; min-width: 0; }
.rangee__titre { display: block; margin: 0; font-size: .97rem; font-weight: 500; color: var(--encre); }
.rangee__titre a { color: var(--encre); text-decoration: none; }
.rangee__titre a:hover { text-decoration: underline; }
.rangee__meta { display: block; margin: 2px 0 0; color: var(--encre-3); font-size: .86rem; }
.rangee__actions { display: flex; align-items: center; gap: 8px; flex: none; }

/* ─── Le rangement d'une liste, sans glisser-déposer ───────────────────────
 * Un champ de nombre par fiche : l'écran fonctionne sans JavaScript, ce qu'un
 * glisser-déposer ne fait jamais. Les rangs sont espacés de dix, donc insérer
 * entre deux ne demande pas de renuméroter les autres. */
.rangee__rang {
  flex: none;
  width: 4.5rem;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.rangee--pied { justify-content: flex-start; gap: 16px; padding-top: 18px; }

/* ─── La ligne d'une commune de la zone (phase 13, point 17.1) ──────────────
 * Le nom à gauche, ses deux réglages à droite. Vu à l'écran : les libellés posés
 * dans la rangée avec la classe des formulaires de réglages prenaient 336 pixels
 * à eux deux, et le nom de la commune tombait dans une colonne d'un mot de large.
 * Les libellés sont donc minuscules et collés à leur champ, et le corps garde une
 * largeur plancher. */
.zone-ligne .rangee__corps { min-width: 13rem; }
.zone-reglages { flex-wrap: wrap; gap: 8px; }
.zone-mini { flex: none; color: var(--encre-3); font-size: .82rem; }
.zone-reglages select { min-width: 10rem; }
.zone-reglages .zone-delai { width: 9rem; }
@media (max-width: 720px) {
  /* Sous 720 pixels, les réglages passent SOUS le nom : deux champs et un nom de
   * commune sur la même ligne ne tiennent pas, et un champ de 40 pixels de large
   * ne se remplit pas. */
  .zone-ligne { flex-wrap: wrap; }
  .zone-ligne .rangee__corps { min-width: 100%; }

  /* ─── Une rangée se replie, elle ne pousse pas la page ──────────────────
     Mesuré le 2026-09-17 à 375 pixels, sur les cinquante-deux écrans rendus :
     trois faisaient défiler la page LATÉRALEMENT, ce qui est le défaut mobile
     le plus détestable parce qu'il ne se voit pas sur un simulateur de largeur
     qu'on n'a pas pensé à pousser assez bas. Une rangée de « L'équipe » sortait
     de 34 pixels : un nom, deux étiquettes et un bouton « Retirer » côte à côte
     ne tiennent pas dans un téléphone.

     Le bouton passe à la ligne plutôt que de déborder, et il s'aligne à droite
     pour rester reconnaissable comme l'action de la rangée. */
  .rangee { flex-wrap: wrap; }
  .rangee__actions,
  .rangee > form { margin-left: auto; }

  /* Et les actions de l'en-tête d'écran, pour la même raison : le tableau de
     bord porte un bouton « Compléter l'identité de l'entreprise » de 264 pixels
     à côté de « Voir le site ». */
  /* `flex: none` laissait ce bloc dépasser son parent sans jamais se replier :
     un `flex-wrap` ne sert à rien tant que le conteneur n'est pas contraint en
     largeur. Il prend donc une ligne entière sous le titre. */
  .entete-ecran-actions { flex: 1 1 100%; flex-wrap: wrap; justify-content: flex-start; }
  .entete-ecran-actions .bouton { max-width: 100%; }
}

/* Une rangée qui EST un lien. Toute la ligne est cliquable, ce qui remplace le
 * bouton « Ouvrir » qu'on répétait quinze fois : la cible passe de 60 pixels de
 * large à toute la largeur de la carte, et l'écran perd quinze boutons primaires.
 *
 * Les marges négatives font mordre le survol jusqu'aux bords de la carte : un
 * survol qui s'arrête à trois pixels du bord a l'air d'un défaut d'alignement. */
a.rangee {
  color: inherit;
  text-decoration: none;
  margin: 0 -12px;
  padding: 14px 12px;
  border-radius: var(--rayon-xs);
  transition: background-color var(--court) var(--sortie);
}
a.rangee:not(:last-child) { border-radius: var(--rayon-xs) var(--rayon-xs) 0 0; }
@media (hover: hover) and (pointer: fine) {
  a.rangee:hover { background: var(--survol); }
}
a.rangee:focus-visible { outline: 2px solid var(--lien); outline-offset: -2px; }
/* Le chevron dit « ça mène ailleurs » sans ajouter un mot. Il est dessiné dans le
 * fond : aucune requête, et la politique de sécurité du contenu l'autorise. */
a.rangee::after {
  content: "";
  width: 16px; height: 16px;
  flex: none;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23676D80' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 3.5 10.5 8 6 12.5'/%3E%3C/svg%3E") no-repeat center;
  background-size: 16px;
}
/* Les commandes d'une ligne n'apparaissent qu'au survol de la ligne. Sur une
 * liste de huit sections à quatre commandes, c'est trente-deux boutons qui
 * cessent d'être là en permanence. Au clavier et au doigt, elles restent
 * visibles : la révélation au survol serait un piège pour eux. */
@media (hover: hover) and (pointer: fine) {
  .rangee__actions--survol { opacity: 0; transition: opacity var(--court) var(--sortie); }
  .rangee:hover .rangee__actions--survol,
  .rangee:focus-within .rangee__actions--survol { opacity: 1; }
}

.liste-controle { list-style: none; padding: 0; margin: 12px 0 0; }
.liste-controle li {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  padding: 10px 0;
  border-bottom: 1px solid var(--trait);
  font-size: .93rem;
}
.liste-controle li:last-child { border-bottom: none; }
.liste-controle a { white-space: nowrap; }

/* -- Étiquettes d'état ---------------------------------------------------- */
/*
 * Une pastille de couleur et un mot, sans aplat de fond : trois pastilles
 * colorées sur une ligne de tableau font un sapin de Noël, alors que le point
 * suffit à dire l'état.
 */
.etiquette {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 2px 0;
  font-size: .85rem;
  font-weight: 500;
  color: var(--encre-2);
  white-space: nowrap;
}
.etiquette::before {
  content: "";
  width: 7px; height: 7px;
  border-radius: 50%;
  background: currentColor;
  flex: none;
}
.etiquette--ok        { color: var(--ok); }
.etiquette--tiede,
.etiquette--attention { color: var(--attention); }
/* La pastille d'un avertissement prend le jaune de la charte, pas l'encre olive
 * qui porte son texte : à sept pixels, #6B5600 se lit comme du vert. Une pastille
 * n'est pas du texte, elle n'a donc pas de seuil de contraste à tenir. */
.etiquette--tiede::before,
.etiquette--attention::before { background: var(--jaune); }
.etiquette--info      { color: var(--lien); }
.etiquette--neutre    { color: var(--encre-3); }
/* Une étiquette qui nomme une catégorie et non un état : pas de pastille, un
 * fond gris très clair. Elle classe, elle n'alerte pas. */
.etiquette--genre {
  padding: 2px 8px;
  border-radius: var(--rayon-xs);
  background: var(--survol);
  color: var(--encre-2);
  font-weight: 400;
}
.etiquette--genre::before { display: none; }

/* -- Encarts -------------------------------------------------------------- */
/*
 * Un encart interrompt la lecture : il n'y en a qu'un par écran, et il porte
 * toujours ce qu'il faut faire.
 */
.encart {
  margin: 0 0 22px;
  padding: 13px 16px;
  border: 1px solid var(--trait);
  border-left: 3px solid var(--trait-fort);
  border-radius: var(--rayon-s);
  background: var(--carte);
  font-size: .93rem;
}
.encart p { margin: 0; }
.encart p + p { margin-top: 6px; }
.encart--ok        { background: var(--ok-fond);     border-color: var(--ok);
                     border-left-color: var(--ok); }
.encart--attention { background: var(--att-fond);    border-color: var(--attention);
                     border-left-color: var(--jaune); }
.encart--info      { background: var(--info-fond);   border-color: var(--lien);
                     border-left-color: var(--lien); }
.encart--erreur    { background: var(--danger-fond); border-color: var(--danger);
                     border-left-color: var(--danger); color: var(--danger); }
.encart--erreur a  { color: var(--danger); }

/* -- Vide, et ce n'est pas une erreur ------------------------------------- */
/*
 * Un écran vide qui n'affiche rien laisse croire à une panne. Il dit donc ce
 * qu'on y met, et porte l'action qui l'y met.
 */
.vide {
  padding: 40px 24px;
  text-align: center;
  border: 1px dashed var(--trait-fort);
  border-radius: var(--rayon);
  background: var(--carte);
}
.vide svg { width: 26px; height: 26px; color: var(--encre-3); margin-bottom: 10px; }
.vide h3 { margin: 0 0 6px; font-size: 1rem; }
.vide p { margin: 0 auto 16px; max-width: 46ch; color: var(--encre-2); font-size: .93rem; }

/* -- Onglets -------------------------------------------------------------- */
/*
 * De vrais liens, pas des panneaux masqués en JavaScript : chaque onglet a son
 * adresse, donc il se met en favori et revient au bon endroit après un
 * enregistrement.
 *
 * Ils sont posés sur un rail gris plutôt que découpés dans un trait : à neuf
 * onglets sur deux lignes, les découpes se lisaient comme des dossiers empilés.
 */
.onglets {
  display: flex;
  flex-wrap: wrap;
  gap: 3px;
  margin: 0 0 26px;
  padding: 3px;
  border-radius: var(--rayon-s);
  background: var(--survol);
}
.onglet {
  padding: 7px 13px;
  border-radius: var(--rayon-xs);
  color: var(--encre-2);
  font-size: .9rem;
  font-weight: 500;
  text-decoration: none;
  transition: background-color var(--court) var(--sortie),
              color var(--court) var(--sortie);
}
@media (hover: hover) and (pointer: fine) {
  .onglet:hover { color: var(--encre); }
}
.onglet--actif {
  background: var(--carte);
  color: var(--encre);
  box-shadow: var(--ombre);
}
.onglets--sobres { font-size: .88rem; }

/* -- Indicateurs ---------------------------------------------------------- */

.indicateurs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 14px;
  margin: 0 0 24px;
}
/* La marge est annulée AVEC la même spécificité que `.carte + .carte`, qui la pose
 * seize pixels plus haut : `.carte--indicateur` seul perdait, et la deuxième carte
 * d'une grille d'indicateurs se retrouvait poussée de seize pixels vers le bas. Elle
 * gardait la hauteur de la rangée, donc son fond s'arrêtait plus haut que celui de
 * la première : à l'écran, la première paraissait plus grande. Vu à l'écran. */
.carte--indicateur,
.carte + .carte--indicateur { margin: 0; padding: 18px 20px; }
.indicateur__libelle {
  margin: 0;
  font-size: .86rem;
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
  color: var(--encre-3);
}
/* Le chiffre porte l'écran : grand, resserré, aligné avec les autres chiffres de
 * la grille grâce aux chiffres tabulaires posés sur body. */
.indicateur__valeur {
  margin: 4px 0 0;
  font-size: 2.1rem;
  line-height: 1.05;
  font-weight: 600;
  letter-spacing: -.03em;
  color: var(--encre);
}
.indicateur__unite { margin: 3px 0 0; font-size: .9rem; color: var(--encre-2); }
.indicateur__evolution { margin: 8px 0 0; font-size: .87rem; color: var(--encre-2); }

.carte--controle h2 { display: flex; align-items: center; gap: 10px; margin-top: 0; font-size: 1rem; }
.carte--controle + .carte--controle { margin-top: 14px; }

.source + .source { margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--trait); }
.source p { margin: 0; }
.source p + p { margin-top: 3px; }
.chiffres-cles p { margin: 0 0 8px; font-size: 1rem; }
.chiffres-cles p:last-child { margin-bottom: 0; }

.diag { width: 100%; font-size: .92rem; }
.diag td:last-child { text-align: right; font-weight: 500; }
.diag .non { color: var(--attention); }

/* -- Secrets à recopier --------------------------------------------------- */

.secret {
  font-family: var(--mono);
  font-size: 1.02rem;
  letter-spacing: .06em;
  background: var(--survol);
  border: 1px solid var(--trait);
  border-radius: var(--rayon-s);
  padding: 13px 15px;
  word-break: break-all;
  user-select: all;
}
/* L'adresse `otpauth://` fait une centaine de caractères et n'a pas à se lire :
   elle se sélectionne d'un clic et se colle. Plus petite et sans interlettrage,
   elle ne concurrence pas la clé juste au-dessus, qui, elle, se recopie. */
.secret--adresse { font-size: .82rem; letter-spacing: 0; }

/* Le code QR du second facteur. Noir sur blanc quel que soit le thème de la
   console : un lecteur de codes lit mal un code clair sur fond sombre, et
   certains pas du tout. Les deux couleurs sont donc écrites en dur, exprès. La
   marge blanche fait partie du code (la norme en demande quatre modules). */
.secret-qr-cadre {
  display: inline-block;
  background: #fff;
  color: #111;
  border: 1px solid var(--trait);
  border-radius: var(--rayon-s);
  padding: 6px;
  margin: 4px 0 12px;
}
.secret-qr { display: block; width: 188px; height: 188px; }

.codes {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 8px;
  padding: 0;
  margin: 12px 0 0;
}
.codes li {
  list-style: none;
  font-family: var(--mono);
  background: var(--survol);
  border: 1px solid var(--trait);
  border-radius: var(--rayon-xs);
  padding: 9px 12px;
  text-align: center;
}

/* -- L'écran de démarrage ------------------------------------------------- */

.demarrage { list-style: none; padding: 0; margin: 0; }
.demarrage__point { padding: 14px 0; border-bottom: 1px solid var(--trait); }
.demarrage__point:last-child { border-bottom: none; }
.demarrage__titre {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin: 0;
  font-size: .97rem;
}
.demarrage__titre a { font-weight: 500; }
.demarrage__etat {
  display: inline-block;
  width: 1.1em;
  flex: 0 0 1.1em;
  color: var(--ok);
  font-weight: 600;
}
/* Ce qui est fait s'estompe, et son explication disparaît : il n'y a plus rien à
 * y faire, donc plus rien à y lire. */
.demarrage__point--fait .demarrage__titre span { color: var(--encre-3); }
.demarrage__point--fait .demarrage__detail { display: none; }
/* Le premier point non fait. C'est toute la fonction de cet écran, donc il a
 * droit à un fond et à une marge négative qui le fait dépasser de la liste. */
.demarrage__point--maintenant {
  margin: 0 -14px;
  padding: 16px 14px;
  border-radius: var(--rayon-s);
  background: var(--info-fond);
  border-bottom-color: transparent;
}
.demarrage__detail { margin: 5px 0 0; font-size: .9rem; color: var(--encre-2); }
.demarrage-bilan { margin: 0 0 12px; font-size: .97rem; }
/* Un titre à l'intérieur d'une carte : la marge du haut appartient à l'espace
 * entre deux blocs, pas à l'intérieur d'un bloc. */
.sans-marge { margin-top: 0; }
/* Le repli des points déjà connus : il vient après une action, donc il se sépare
 * d'un filet plutôt que d'une marge, sinon il a l'air de flotter. */
.replie-liste {
  margin: 22px 0 0;
  padding-top: 14px;
  border-top: 1px solid var(--trait);
}
.replie-liste .demarrage__point { padding: 9px 0; }

/* Une barre de progression : neuf points, et savoir où l'on en est sans compter
 * les coches. */
.jauge {
  height: 5px;
  border-radius: 999px;
  background: var(--survol);
  overflow: hidden;
  margin: 0 0 16px;
}
.jauge > i {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--lien);
  /* La largeur arrive en variable posée par le PHP, pas en style en ligne : la
   * politique de sécurité du contenu interdit le second. */
  width: var(--part, 0%);
  transition: width var(--moyen) var(--sortie);
}
/* La part remplie arrive en classe et non en attribut « style » : la politique de
 * sécurité du contenu interdit le style en ligne, et un attribut posé quand même
 * ne s'applique pas du tout. Vingt et une classes par pas de cinq pour cent, ce
 * qui suffit à lire une progression et évite d'en générer cent. */
.jauge--p0{--part:0%}    .jauge--p5{--part:5%}    .jauge--p10{--part:10%}
.jauge--p15{--part:15%}  .jauge--p20{--part:20%}  .jauge--p25{--part:25%}
.jauge--p30{--part:30%}  .jauge--p35{--part:35%}  .jauge--p40{--part:40%}
.jauge--p45{--part:45%}  .jauge--p50{--part:50%}  .jauge--p55{--part:55%}
.jauge--p60{--part:60%}  .jauge--p65{--part:65%}  .jauge--p70{--part:70%}
.jauge--p75{--part:75%}  .jauge--p80{--part:80%}  .jauge--p85{--part:85%}
.jauge--p90{--part:90%}  .jauge--p95{--part:95%}  .jauge--p100{--part:100%}

/* -- Guides --------------------------------------------------------------- */

/* ── L'aide contextuelle ──────────────────────────────────────────────────────
 *
 * Refaite le 2026-08-25. Au repos, une ligne grise avec un « i » : le même
 * niveau visuel qu'une mention, et non celui d'une alerte. Elle ne s'ouvre que
 * si on la lui demande, et c'est alors seulement qu'elle prend une surface.
 *
 * La flèche native du <details> est retirée : le « i » dit déjà qu'il y a
 * quelque chose à ouvrir, et deux marqueurs pour un seul geste font deux fois
 * plus de bruit pour la même information.
 */
.aide-bloc { margin: 0 0 16px; font-size: .88rem; }
.aide-bloc > summary {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 3px 0;
  cursor: pointer;
  color: var(--encre-3);
  list-style: none;
  transition: color var(--court) var(--sortie);
}
.aide-bloc > summary::-webkit-details-marker { display: none; }
.aide-bloc > summary::marker { content: ""; }
.aide-bloc > summary:hover { color: var(--lien); }
/* Un <details> qui ne porte PAS le « i » de l'aide a besoin de son propre
 * marqueur : la flèche native est retirée pour tous, et sans elle une ligne
 * grise ne dit plus qu'elle s'ouvre. Vu à l'écran en phase 11 sur « les phrases
 * encore identiques » de l'assistant, et sur « les N points de mise en route »
 * du tableau de bord : les deux se lisaient comme du texte. */
.aide-bloc > .replie-titre::before {
  content: "";
  width: 6px;
  height: 6px;
  flex: none;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(-45deg);
  transition: transform var(--court) var(--sortie);
}
.aide-bloc[open] > .replie-titre::before { transform: rotate(45deg); }
.aide-i { width: 15px; height: 15px; flex: none; }
.aide-bloc[open] > summary { color: var(--lien); font-weight: 500; }
.aide-corps {
  margin-top: 8px;
  padding: 12px 14px;
  border-radius: var(--rayon-s);
  background: var(--info-fond);
  color: var(--encre-2);
  line-height: 1.55;
}
.aide-corps > p { margin: 0 0 9px; }
.aide-corps > p:last-child { margin-bottom: 0; }
.aide-corps .aide-verifier { color: var(--encre); }
.aide-bloc kbd {
  font-family: var(--mono);
  font-size: .8rem;
  padding: 1px 6px;
  border: 1px solid var(--trait-fort);
  border-bottom-width: 2px;
  border-radius: 5px;
  background: var(--carte);
  color: var(--encre);
}

/* ── Un repli : ce qui a déjà une bonne valeur ────────────────────────────────
 *
 * Les options d'une section et ses couleurs. Elles ont toutes un défaut qui
 * convient, c'est même leur définition : les afficher d'office fait chercher le
 * titre au milieu de quinze champs. Le compteur dit combien il y a derrière,
 * pour qu'on sache si ça vaut le clic.
 */
.repli {
  margin: 0 0 14px;
  border: 1px solid var(--trait);
  border-radius: var(--rayon-s);
  background: var(--carte);
}
.repli > summary {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 12px;
  cursor: pointer;
  font-size: .89rem;
  font-weight: 500;
  color: var(--encre);
  list-style: none;
  border-radius: var(--rayon-s);
}
.repli > summary::-webkit-details-marker { display: none; }
.repli > summary::marker { content: ""; }
/* Le chevron dessiné dans le fond, et qui pivote : il dit lequel des deux gestes
 * le clic va faire, le même mouvement que le sélecteur de page de la barre. */
.repli > summary::after {
  content: "";
  width: 15px;
  height: 15px;
  margin-left: auto;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23676D80' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6.5 8 10.5l4-4'/%3E%3C/svg%3E") center / contain no-repeat;
  transition: transform var(--court) var(--sortie);
}
.repli[open] > summary::after { transform: rotate(180deg); }
.repli-compte {
  min-width: 19px;
  padding: 1px 6px;
  border-radius: 9px;
  background: var(--survol);
  color: var(--encre-3);
  font-size: .76rem;
  font-weight: 600;
  text-align: center;
}
.repli-corps {
  padding: 4px 12px 14px;
  border-top: 1px solid var(--trait);
  margin-top: -1px;
}
.repli-corps > .champ:last-child { margin-bottom: 0; }

@media (hover: hover) and (pointer: fine) {
  .repli > summary:hover { background: var(--survol); }
}
@media (prefers-reduced-motion: reduce) {
  .repli > summary::after { transition: none; }
}

/* ── Une grille de tuiles ─────────────────────────────────────────────────────
 *
 * Ce qui remplace les listes de barres blanches identiques. Une tuile porte un
 * pictogramme, un nom court, et deux ou trois mentions en pied. On la reconnaît
 * à sa forme et à son dessin avant de lire son nom, ce qu'une ligne de texte ne
 * permet jamais : neuf lignes de dix mots ne sont pas une liste, c'est un
 * paragraphe.
 *
 * `auto-fill` avec un minimum de 232 px : trois colonnes sur un écran large,
 * deux sur un portable, une sur un téléphone, sans point de rupture écrit.
 */
.grille-cartes {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(232px, 1fr));
  gap: 12px;
  margin: 0 0 28px;
}

.tuile {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 16px;
  border: 1px solid var(--trait);
  border-radius: var(--rayon);
  background: var(--carte);
  color: inherit;
  text-decoration: none;
  transition: border-color var(--court) var(--sortie),
              box-shadow var(--court) var(--sortie),
              transform var(--court) var(--sortie);
}
.tuile-picto {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: var(--rayon-s);
  background: var(--info-fond);
  /* Le bleu de la charte, et c'est l'emploi qui lui reste : un pictogramme n'est
   * pas du texte, il n'a pas à tenir 4,5:1. */
  color: var(--encre-3);
}
.tuile-picto .picto { width: 21px; height: 21px; }
.tuile-titre {
  font-size: .97rem;
  font-weight: 600;
  color: var(--encre);
  line-height: 1.35;
}
.tuile-resume {
  font-size: .87rem;
  color: var(--encre-2);
  line-height: 1.45;
}
/* Le pied est poussé en bas : sur une grille, des mentions qui flottent à des
 * hauteurs différentes d'une tuile à l'autre font une grille de travers. */
.tuile-pied {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: auto;
  padding-top: 6px;
}
.tuile-pied .jauge { flex: 1; min-width: 46px; margin: 0; }
.tuile-action {
  margin-left: auto;
  color: var(--lien);
  font-size: .87rem;
  font-weight: 500;
}
/* Un parcours terminé s'estompe : il reste relançable, il cesse d'appeler. */
.tuile--faite .tuile-picto { background: var(--ok-fond); color: var(--ok); }

@media (hover: hover) and (pointer: fine) {
  .tuile:hover {
    border-color: var(--trait-fort);
    box-shadow: var(--ombre);
    transform: translateY(-1px);
  }
}
.tuile:focus-visible { outline: 2px solid var(--lien); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) {
  .tuile, .tuile:hover { transition: none; transform: none; }
}

/* Une tuile de catalogue : elle porte une ACTION et non un lien, donc elle n'est
 * pas elle-même cliquable et elle ne se soulève pas au survol. Une tuile qui a
 * l'air cliquable et qui ne l'est qu'à un endroit est un piège. */
.tuile--catalogue { gap: 6px; }
.tuile-tete {
  position: relative;
  display: flex;
  align-items: center;
  gap: 6px;
}
.tuile-tete .info-bulle { top: calc(100% + 6px); }
.tuile-adresse code { font-family: var(--mono); font-size: .78rem; color: var(--encre-3); }
.tuile--catalogue .etiquette { margin: 0; }
.tuile-forme { display: flex; align-items: center; gap: 10px; margin-left: auto; }
.tuile--catalogue .tuile-pied { padding-top: 12px; gap: 10px; }
/* Une page déjà en ligne s'estompe : elle reste dans le catalogue parce qu'on vient
 * aussi ici pour retirer, mais elle cesse d'appeler le clic. */
.tuile--faite.tuile--catalogue .tuile-titre { color: var(--encre-2); }

/* ── La bande « la prochaine chose à faire » ──────────────────────────────── */
.suite {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 16px;
  margin: 0 0 28px;
  border: 1px solid var(--trait);
  border-left: 3px solid var(--lien);
  border-radius: var(--rayon);
  background: var(--carte);
  color: inherit;
  text-decoration: none;
  transition: background-color var(--court) var(--sortie);
}
.suite-picto { display: inline-flex; color: var(--encre-3); flex: none; }
.suite-picto .picto { width: 22px; height: 22px; }
.suite-corps { display: block; flex: 1; min-width: 0; }
.suite-sur-titre {
  display: block;
  color: var(--encre-3);
  font-size: .8rem;
}
.suite-titre { display: block; font-weight: 600; color: var(--encre); }
.suite::after {
  content: "";
  width: 16px; height: 16px; flex: none;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%231F4789' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 3.5 10.5 8 6 12.5'/%3E%3C/svg%3E") no-repeat center / 16px;
}
@media (hover: hover) and (pointer: fine) {
  .suite:hover { background: var(--survol); }
}
.suite:focus-visible { outline: 2px solid var(--lien); outline-offset: 2px; }

/* ── La fiche d'un guide ──────────────────────────────────────────────────────
 *
 * Les étapes le long d'un fil vertical numéroté. Une liste ordonnée nue laissait
 * la personne compter les paragraphes pour savoir où elle en était ; le fil dit
 * combien il en reste sans qu'on ait à les compter.
 */
.guide-tete { display: flex; align-items: flex-start; gap: 16px; margin-bottom: 18px; }
.guide-tete h1 { margin: 0 0 8px; }
.guide-tete-picto {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 48px;
  height: 48px;
  border-radius: var(--rayon-s);
  background: var(--info-fond);
  color: var(--encre-3);
}
.guide-tete-picto .picto { width: 26px; height: 26px; }
.guide-puces { display: flex; flex-wrap: wrap; gap: 8px; margin: 0; }

.guide-cadre { margin-bottom: 20px; }
.guide-quand { margin: 0 0 8px; color: var(--encre-2); font-size: .92rem; }
.guide-pourquoi { margin: 0; color: var(--encre); }

.guide-fil { list-style: none; margin: 0 0 20px; padding: 0; }
.guide-etape {
  position: relative;
  display: flex;
  gap: 14px;
  padding: 0 0 22px;
}
/* Le fil relie un numéro au suivant, et s'arrête au dernier : une ligne qui
 * dépasse sous la dernière étape laisse croire qu'il en manque une. */
.guide-etape:not(:last-child)::before {
  content: "";
  position: absolute;
  left: 13px;
  top: 30px;
  bottom: 2px;
  width: 2px;
  background: var(--trait);
}
.guide-numero {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--action);
  color: var(--sur-plein);
  font-size: .84rem;
  font-weight: 600;
}
.guide-etape-corps { flex: 1; min-width: 0; padding-top: 3px; }
.guide-faire { margin: 0; line-height: 1.6; }
.guide-voir, .guide-piege {
  display: block;
  margin: 8px 0 0;
  padding: 9px 12px;
  border-left: 3px solid var(--trait);
  border-radius: 0 var(--rayon-xs) var(--rayon-xs) 0;
  background: var(--survol);
  font-size: .89rem;
  color: var(--encre-2);
  line-height: 1.5;
}
/* L'intitulé sur sa propre ligne, en capitales de petite taille : « Le piège : »
 * au fil du texte se lisait comme le début de la phrase. */
.guide-voir strong, .guide-piege strong {
  display: block;
  margin-bottom: 2px;
  font-size: .74rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
}
.guide-voir  { border-left-color: var(--ok); background: var(--ok-fond); }
.guide-voir strong { color: var(--ok); }
.guide-piege { border-left-color: var(--jaune); background: var(--att-fond); }
.guide-piege strong { color: var(--attention); }

.guide-verif { display: flex; flex-wrap: wrap; align-items: center; gap: 16px; }
.guide-verif .aide-verifier { margin: 0; flex: 1; min-width: 240px; }

/* ── L'écran de la charte ─────────────────────────────────────────────────────
 *
 * Un écran qui existe pour MONTRER une charte l'écrivait en tableaux de chiffres.
 * Ce qui suit habille les quatre vues : la carte d'une couleur, le spécimen
 * typographique à sa vraie taille, et le verdict d'un contrôle.
 */

/* Une carte par couleur : l'aplat d'abord, parce que c'est lui qu'on est venu
 * voir, et le code en dessous. `auto-fill` à 210 px : trois par rangée sur un
 * écran large, une sur un téléphone. */
.couleurs {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 14px;
  margin: 0 0 26px;
}
/* La palette actuellement appliquée, dans la galerie des douze. Un filet, pas un
   fond : un fond coloré sur une carte qui montre des couleurs ment sur ce qu'elle
   montre. */
/* Le sélecteur de commune, en deux temps et sans JavaScript. La commune retenue
   se lit d'un coup d'œil avec ses deux formes fléchies : c'est là qu'on voit tout
   de suite si on a choisi « Seyne » au lieu de « La Seyne-sur-Mer ». */
/* ─── Les neuf questions de la création d'un site (phase 8) ────────────────
   Une carte par question, numérotée. Le numéro n'est pas de l'ornement : il dit
   combien il en reste, et « trois sur neuf » est la seule chose qui rassure
   quelqu'un devant un formulaire qu'il découvre devant son client. */
/* ─── Les neuf questions de la création ───────────────────────────────────
   Refaites le 2026-09-16 avec le reste de la console. Le rang était un rond de
   vingt-huit pixels portant un chiffre seul : il disait « deuxième », jamais
   « deuxième SUR NEUF », et c'est la seconde moitié qui fait rester. Il porte
   maintenant les deux, en pastille, comme les compteurs d'étape de l'interface
   qui sert de référence. */
.question + .question { margin-top: 18px; }
.question-tete {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  margin-bottom: 20px;
}
.question-tete h2 { margin: 0; font-size: 1.05rem; }
.question-tete .note { margin: 5px 0 0; }
.question-rang {
  flex: none;
  display: inline-flex;
  align-items: baseline;
  gap: 1px;
  padding: 4px 11px;
  border-radius: 999px;
  background: var(--survol);
  border: 1px solid var(--trait);
  font-size: .82rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--encre);
  /* Le rang est aligné sur la PREMIÈRE ligne du titre, pas centré sur le bloc :
     un titre qui passe sur deux lignes ferait glisser la pastille au milieu. */
  margin-top: 1px;
}
/* Le « sur neuf » est plus discret que le rang : c'est le repère, pas la valeur. */
.question-rang span { font-weight: 500; color: var(--encre-3); font-size: .76rem; }

/* La barre de fin. Collée en bas de la fenêtre : le formulaire fait quatre
   hauteurs d'écran, et le bouton y vivait tout en bas, donc il fallait le
   chercher après chaque correction. */
.barre-creation {
  position: sticky;
  bottom: 0;
  z-index: 3;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin-top: 22px;
  padding: 16px 20px;
  background: var(--carte);
  border: 1px solid var(--trait);
  border-radius: var(--rayon);
  /* La seule ombre de la feuille, et elle est justifiée : cette barre FLOTTE
     au-dessus du formulaire qui défile dessous, et sans elle on ne voit pas où
     le contenu s'arrête. La règle 4 dit « le trait avant l'ombre », pas
     « jamais d'ombre ». */
  box-shadow: 0 -6px 18px rgba(9, 9, 11, .06);
}
.barre-creation .note { margin: 0; max-width: 56ch; }

/* Les cartes à cocher de l'habillage et des palettes. Le bouton radio lui-même
   est masqué mais RESTE dans le flux du clavier : `opacity: 0` sur un carré d'un
   pixel, jamais `display: none`, qui le retirerait de la tabulation et rendrait
   les deux questions impossibles à répondre sans souris. */
.choix-cartes {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 10px;
  margin: 0 0 8px;
}
.choix-cartes input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.choix-cartes label {
  display: block;
  padding: 12px 14px;
  border: 1px solid var(--trait);
  border-radius: var(--rayon);
  background: var(--carte);
  cursor: pointer;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.choix-cartes label:hover { border-color: var(--encre-3); }
.choix-cartes input:checked + label {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent);
}
.choix-cartes input:focus-visible + label {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}
.choix-titre {
  display: block;
  font-weight: 600;
  font-size: .95rem;
  color: var(--encre);
}
.choix-titre .etiquette { margin-left: 6px; font-weight: 500; }
.choix-cartes label small {
  display: block;
  margin-top: 4px;
  font-size: .84rem;
  line-height: 1.45;
  color: var(--encre-3);
}
/* Les quatre pastilles d'une palette, au-dessus de son nom : on choisit une
   palette sur ses couleurs, pas sur son nom, et l'ordre primaire, secondaire,
   accent, encre est celui de l'écran de la charte. */
.choix-pastilles { display: flex; gap: 4px; margin-bottom: 8px; }
.choix-pastilles svg { display: block; border-radius: 5px; }
.choix-cartes--palettes { grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); }

.commune-retenue { margin: .25rem 0 .5rem; }
.commune-retenue .note { display: block; margin-top: .15rem; }
.commune-choix { list-style: none; margin: .5rem 0 0; padding: 0; display: grid; gap: .25rem; }
.commune-choix .note { display: block; font-weight: 400; }

.couleur--actuelle { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }

.couleur {
  overflow: hidden;
  border: 1px solid var(--trait);
  border-radius: var(--rayon);
  background: var(--carte);
}
/* L'aplat est un SVG et non un fond CSS : la politique de sécurité du contenu
 * interdit le style en ligne, et un attribut `fill` de SVG n'est pas du CSS.
 * `preserveAspectRatio: none` le laisse s'étirer à la largeur de la carte. */
.couleur-aplat {
  display: block;
  width: 100%;
  height: 92px;
  /* Le blanc de la charte sur une carte blanche serait invisible : un filet
   * intérieur en dessous de l'aplat lui rend son bord. */
  box-shadow: inset 0 -1px 0 var(--trait);
}
.couleur-corps { padding: 12px 14px 14px; }
.couleur-tete {
  position: relative;
  display: flex;
  align-items: center;
  gap: 6px;
}
.couleur-tete h2 { margin: 0; font-size: .97rem; }
.couleur-tete .info-bulle { top: calc(100% + 6px); }
.couleur-code { margin: 4px 0 10px; }
.couleur-code code { font-family: var(--mono); font-size: .85rem; color: var(--encre-2); }
.couleur-declinaisons {
  display: flex;
  align-items: center;
  gap: 4px;
  margin: 0 0 10px;
}
.couleur-declinaisons .note { margin-left: 6px; font-size: .78rem; }
.declinaison svg { display: block; border-radius: 5px; }
.couleur .etiquette { margin: 0; }

/* Le verdict d'un contrôle de couleur : la pastille en grand à gauche, les trois
 * phrases à droite. Trois listes à puces les mettaient sur le même rang que le
 * reste de l'écran, alors qu'elles répondent à une question qu'on vient de poser. */
.verdict {
  display: flex;
  gap: 16px;
  align-items: flex-start;
  margin-top: 18px;
  padding-top: 18px;
  border-top: 1px solid var(--trait);
}
.verdict-pastille svg { display: block; border-radius: var(--rayon-xs); box-shadow: 0 0 0 1px var(--trait); }
.verdict-corps { flex: 1; min-width: 0; }
.verdict-titre { margin: 0 0 8px; font-weight: 500; }
.verdict-titre--ok        { color: var(--ok); }
.verdict-titre--attention { color: var(--attention); }
.verdict-ligne {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin: 0 0 6px;
  font-size: .9rem;
  color: var(--encre-2);
}
.verdict-ligne code { font-family: var(--mono); font-size: .82rem; }
.verdict-ligne svg { border-radius: 4px; }
/* L'étiquette du fond testé est dessinée à la couleur du fond testé : « sur nuit »
 * écrit sur du nuit vaut mieux que « sur nuit » écrit en gris. */
.verdict-fond {
  flex: none;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: .78rem;
  font-weight: 500;
}
.verdict-fond--blanc { background: var(--blanc); color: var(--encre); box-shadow: inset 0 0 0 1px var(--trait-fort); }
.verdict-fond--nuit  { background: var(--nuit);  color: var(--blanc); }

/* ── Les spécimens typographiques ────────────────────────────────────────────
 *
 * La taille est portée par une CLASSE et non par un attribut « style » : la
 * politique de sécurité du contenu interdit le second. Les cinq niveaux sont une
 * liste fermée, écrite dans charte_typographie() ; cinq classes suffisent, et
 * elles suffiront encore dans dix ans.
 *
 * Les valeurs sont celles de la charte, en pixels, telles que le site les rend.
 */
.specimens { margin: 0 0 26px; }
.specimen {
  padding: 20px 22px;
  border: 1px solid var(--trait);
  border-radius: var(--rayon);
  background: var(--carte);
}
.specimen + .specimen { margin-top: 12px; }
.specimen-mesures { margin: 0 0 10px; color: var(--encre-3); font-size: .8rem; }
.specimen-mesures strong { color: var(--encre-2); font-weight: 600; }
.specimen-texte {
  margin: 0;
  color: var(--encre);
  font-family: "Plus Jakarta Sans", var(--police);
  /* Un titre de 64 px sur un écran de téléphone déborderait : il rétrécit avec la
   * fenêtre au lieu de pousser une barre de défilement horizontale. */
  overflow-wrap: break-word;
}
.specimen--titre               { font-size: clamp(2rem, 7vw, 4rem);   line-height: 1.2; font-weight: 700; }
.specimen--sous_titre          { font-size: clamp(1.4rem, 4vw, 2rem); line-height: 1.3; font-weight: 500; }
.specimen--sous_titre_section  { font-size: 1.7rem; line-height: 1.4; font-weight: 600; }
.specimen--paragraphe          { font-size: 1.3rem; line-height: 1.4; font-weight: 400; }
.specimen--citation {
  font-size: clamp(1.4rem, 4vw, 2rem);
  line-height: 1.3;
  font-weight: 400;
  font-family: Arvo, Georgia, serif;
}

/* Une graisse se juge sur un dessin de lettre, pas sur son nombre. */
.graisse-specimen {
  flex: none;
  width: 44px;
  font-family: "Plus Jakarta Sans", var(--police);
  font-size: 1.5rem;
  line-height: 1;
  color: var(--encre);
}
.graisse--200 { font-weight: 200; }  .graisse--300 { font-weight: 300; }
.graisse--400 { font-weight: 400; }  .graisse--500 { font-weight: 500; }
.graisse--600 { font-weight: 600; }  .graisse--700 { font-weight: 700; }
.graisse--800 { font-weight: 800; }
.graisse .etiquette, .graisse .note { flex: none; }

/* Un champ et son bouton sur la même ligne : une recherche, un code couleur. */
.ligne-champ { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.ligne-champ input { flex: 1; min-width: 160px; width: auto; }
.ligne-champ input[type=text] { flex: 1; min-width: 160px; width: auto; }
.ligne-champ .bouton { flex: none; }

/* Quatre petits champs qui tiennent ensemble : ils forment un seul réglage. */
.grille-champs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 0 14px;
  align-items: end;
}
.grille-champs .actions { grid-column: 1 / -1; margin-top: 6px; }

/* Une étiquette qui existe pour les lecteurs d'écran et pour eux seuls : le champ
 * qu'elle nomme porte déjà son intitulé dans son texte de substitution. */
.visuellement-cache {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* -- Pictogrammes de la charte (écran de démonstration) ------------------- */

.pictos {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 6px;
  list-style: none;
  padding: 0;
}
.pictos li {
  display: flex;
  align-items: center;
  gap: .6rem;
  padding: .5rem .7rem;
  border: 1px solid var(--trait);
  border-radius: var(--rayon-xs);
  font-size: .87rem;
}
.pictos svg { width: 1.35rem; height: 1.35rem; flex: none; }
.pictos span { flex: 1; }
.pictos code { font-size: .7rem; color: var(--encre-3); }
.carte--motif { display: grid; place-items: center; padding: 2rem; }
.carte--motif svg { max-width: 420px; }

/* ── La porte : les écrans qu'on voit avant d'être entré ──────────────────────
 *
 * Connexion, second facteur, invitation, installateur. Une carte centrée dans la
 * hauteur de l'écran, et rien d'autre : ni barre du haut, ni cadre, ni pied de
 * page. Une barre qui portait le nom de la plateforme au-dessus d'une carte qui
 * portait le même nom l'écrivait deux fois, et la version du moteur n'aide en rien
 * quelqu'un qui essaie de se connecter.
 *
 * `min-height: 100dvh` et non `100vh` : sur un téléphone, la barre d'adresse du
 * navigateur mange la différence, et la carte se retrouvait coupée en bas.
 */
body.porte { background: var(--fond); }
body.porte .corps {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 100dvh;
  max-width: none;
  padding: 32px 20px;
}
.porte-carte {
  width: 100%;
  max-width: 400px;
  padding: 30px 30px 26px;
  border: 1px solid var(--trait);
  border-radius: var(--rayon);
  background: var(--carte);
  box-shadow: var(--ombre);
}
/* La marque au-dessus du titre, en petit : elle dit OÙ l'on est, le titre dit ce
 * qu'on y fait. L'inverse ferait lire deux fois le même mot. */
.porte-marque {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 22px;
  color: var(--encre-2);
  font-size: .88rem;
  font-weight: 500;
}
.porte-carte h1 { margin: 0 0 6px; font-size: 1.4rem; }
.porte-carte .chapeau { margin: 0 0 22px; font-size: .93rem; }
.porte-carte .champ:last-of-type { margin-bottom: 22px; }
.porte-carte h3 { font-size: .95rem; margin: 22px 0 8px; }
.porte-pied {
  margin: 22px 0 0;
  color: var(--encre-3);
  font-size: .8rem;
}
/* Un écran de porte qui explique une manipulation (l'activation du second facteur,
 * l'installateur) déborde de 400 px : il prend la largeur d'une colonne de lecture. */
body.porte .porte-carte--large { max-width: 620px; }

@media (max-width: 460px) {
  .porte-carte { padding: 24px 20px 22px; border-radius: var(--rayon-s); }
}

/* -- L'ancien en-tête, gardé pour les écrans sans session ----------------- */
/*
 * Connexion, second facteur, invitation, installateur : ces quatre écrans n'ont
 * pas de cadre de navigation, parce qu'il n'y a encore rien à naviguer. Ils
 * gardent donc un en-tête simple, et il est clair plutôt que nuit : une barre
 * sombre sur une page de connexion vide en fait un mur.
 */
.tete { background: var(--carte); border-bottom: 1px solid var(--trait); }
.tete .dedans {
  max-width: 1240px;
  margin: 0 auto;
  padding: 13px 24px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}
.marque {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  color: var(--encre);
  font-weight: 600;
  text-decoration: none;
  letter-spacing: -.01em;
}
.tete-nav { display: flex; align-items: center; gap: 14px; }
.tete .qui { color: var(--encre-2); font-size: .89rem; }

.pied {
  border-top: 1px solid var(--trait);
  color: var(--encre-3);
  font-size: .84rem;
}
.pied .dedans {
  max-width: 1240px;
  margin: 0 auto;
  padding: 16px 24px;
  display: flex;
  gap: 16px;
  justify-content: space-between;
}
.pied-mode { color: var(--encre-3); }

@media (max-width: 640px) {
  .corps { padding: 26px 18px 48px; }
  .carte { padding: 18px; }
  .carte--lignes { padding: 4px 18px; }
  .centre { margin: 4vh auto; }
  h1 { font-size: 1.45rem; }
  .entete-ecran { margin-bottom: 22px; }
}

/* -- La visite guidée ----------------------------------------------------- */
/*
 * LA règle du point 13.1 : « la visite ne bloque jamais l'écran, ne masque rien,
 * n'empêche aucune action ». D'où l'absence de voile : l'estompage vient d'une
 * OMBRE PORTÉE immense sur l'élément mis en évidence. Une ombre ne capte pas les
 * clics, donc l'écran entier reste utilisable sans qu'aucune ligne de code n'ait
 * à s'en occuper.
 */
.visite-cible {
  position: relative;
  z-index: 40;
  border-radius: var(--rayon-s);
  /* Pas de transition sur cette ombre : une mise en évidence qui s'installe en
   * fondu est illisible dans un onglet en arrière-plan, où le navigateur suspend
   * les animations. Elle apparaît d'un coup. */
  box-shadow: 0 0 0 3px var(--lien),
              0 0 0 9999px var(--voile);
}
.visite-bulle {
  position: fixed;
  z-index: 50;
  width: min(360px, calc(100vw - 32px));
  padding: 18px 20px 16px;
  background: var(--carte);
  border: 1px solid var(--trait);
  border-radius: var(--rayon);
  box-shadow: var(--ombre-flot);
}
.visite-bulle--centre { top: 50%; left: 50%; transform: translate(-50%, -50%); }
.visite-compteur {
  margin: 0 0 6px;
  font-size: .8rem;
  color: var(--encre-3);
  letter-spacing: 0;
  text-transform: none;
}
.visite-titre { margin: 0 0 8px; font-weight: 600; font-size: 1.02rem; letter-spacing: -.01em; }
.visite-texte { margin: 0; font-size: .93rem; line-height: 1.55; color: var(--encre-2); }
.visite-actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-top: 16px; }
.visite-fermer {
  position: absolute;
  top: 8px; right: 10px;
  border: none;
  background: none;
  font-size: 1.3rem;
  line-height: 1;
  color: var(--encre-3);
  cursor: pointer;
  padding: 4px 8px;
  border-radius: var(--rayon-xs);
}
.visite-fermer:hover { color: var(--encre); background: var(--survol); }

/* -- Impression ----------------------------------------------------------- */

@media print {
  /* Sur papier, le cadre de navigation, les actions et les bulles ne servent à
   * rien : ils prennent la moitié de la première page et ne sont pas cliquables. */
  .rail, .tete, .pied, .actions, .onglets, .visite-bulle,
  .entete-ecran-actions { display: none; }
  /* Sur papier, un repli fermé serait une information perdue : le lecteur du PDF
   * ne peut pas l'ouvrir. Tout ce qui est replié se déplie donc à l'impression,
   * ce qui est aussi ce qui rend l'export du point 14.3 complet. */
  details:not([open]) > *:not(summary) { display: block; }
  details > summary::after, .repli > summary::after { display: none; }
  .appli { display: block; }
  body { background: #FFF; }
  .corps { max-width: none; padding: 0; }
  .carte { break-inside: avoid; border: 1px solid #DDD; box-shadow: none; }
  .indicateurs { grid-template-columns: repeat(2, 1fr); }
  .visite-cible { box-shadow: none; }
  h2 { break-after: avoid; }
}

/* ── Un choix en segments ────────────────────────────────────────────────────
 *
 * Trois boutons collés, à la façon d'un sélecteur de période : à trois choix, une
 * liste déroulante demande deux clics pour montrer ce qu'un coup d'œil suffirait à
 * lire, et elle cache deux options sur trois.
 *
 * Ce sont de VRAIS boutons radio, seulement habillés. Le bouton natif n'est pas
 * masqué par `display: none`, qui le retirerait de l'ordre de tabulation : il est
 * rendu transparent et étalé sur toute l'étiquette, donc le clavier le trouve, le
 * lecteur d'écran l'annonce, et le formulaire l'envoie sans une ligne de script.
 */
.segments { border: none; margin: 0 0 18px; padding: 0; min-width: 0; }
.champ-legende {
  position: relative;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 0;
  margin-bottom: 6px;
  font-size: .89rem;
  font-weight: 500;
  color: var(--encre);
}
.champ-legende .info-bulle { top: calc(100% + 5px); }
.segments-choix {
  display: inline-flex;
  gap: 3px;
  padding: 3px;
  border-radius: var(--rayon-s);
  background: var(--survol);
}
.segment {
  position: relative;
  margin: 0;
  padding: 0;
  border-radius: var(--rayon-xs);
  cursor: pointer;
}
.segment input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}
.segment span {
  display: block;
  padding: 6px 13px;
  border-radius: var(--rayon-xs);
  font-size: .88rem;
  font-weight: 500;
  color: var(--encre-2);
  white-space: nowrap;
  transition: background-color var(--court) var(--sortie),
              color var(--court) var(--sortie);
}
.segment:has(input:checked) span {
  background: var(--carte);
  color: var(--encre);
  box-shadow: var(--ombre);
}
.segment:has(input:focus-visible) span { outline: 2px solid var(--lien); outline-offset: 1px; }
@media (hover: hover) and (pointer: fine) {
  .segment:hover span { color: var(--encre); }
}
@media (prefers-reduced-motion: reduce) {
  .segment span { transition: none; }
}

/* Ce qu'un champ PRODUIT, écrit sous lui : « le site écrira Trésorière ». C'est une
 * conséquence et non une consigne, donc elle ne se replie pas derrière un « i » et
 * ne s'affiche que s'il y a une différence à montrer. */
.champ-effet {
  margin: 6px 0 0;
  font-size: .84rem;
  color: var(--encre-2);
}
.champ-effet strong { color: var(--encre); font-weight: 600; }

/* ── Une fonction du bureau, repliée ─────────────────────────────────────────
 *
 * La question qu'on se pose devant cet écran est « qui porte quoi », et elle se
 * répond en une ligne. Les six champs de la fonction sont derrière.
 */
.fonction-nom { font-weight: 500; color: var(--encre); }
.fonction-qui {
  margin-left: auto;
  margin-right: 10px;
  color: var(--encre-3);
  font-size: .88rem;
  font-weight: 400;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* La seule couleur de l'écran : la fonction qui ne mène à aucune adresse valide. */
.fonction-alerte {
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--jaune);
}
/* Un intertitre à l'intérieur d'un formulaire : il sépare deux sujets sans prendre
 * le poids d'un titre de carte. */
.sous-titre {
  margin: 20px 0 10px;
  font-size: .8rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--encre-3);
}

/* La bulle se place par rapport à la ligne qui la porte. Plutôt que de déclarer
 * `position: relative` sur chacune des quinze lignes concernées, et d'oublier la
 * seizième dans six mois, la règle est posée une fois : est un repère tout élément
 * qui porte une bulle en enfant direct. Le sélecteur ne remonte pas plus haut, donc
 * il ne touche ni le corps du document ni les cartes. */
:has(> .info-bulle) { position: relative; }

/* Un état en trois points : acquis, manquant, invérifiable. Le mot est dans le
 * `title` et dans l'`aria-label`, et il ne s'écrit que si l'état n'est pas acquis.
 * « En place » répété trois fois de suite n'apprend rien. */
.etat-point {
  flex: none;
  width: 9px;
  height: 9px;
  border-radius: 50%;
}
.etat-point--ok     { background: var(--ok); }
.etat-point--manque { background: var(--jaune); }
.etat-point--flou   { background: none; box-shadow: inset 0 0 0 1.5px var(--trait-fort); }
.courriel-controle .rangee__titre { flex: none; }

/* ── Un chiffre du réseau ────────────────────────────────────────────────────
 *
 * Trois colonnes sur une ligne : ce que la valeur est, ce qui s'affiche
 * aujourd'hui, et le champ qui permet de dire autre chose. L'ordre du point 3.1
 * tient dans la lecture de gauche à droite : on lit avant de pouvoir contredire.
 */
.reseau-ligne { gap: 16px; }
.reseau-ligne .rangee__meta code { font-family: var(--mono); font-size: .78rem; }
.reseau-valeur {
  flex: none;
  width: 160px;
  text-align: right;
  font-weight: 500;
  color: var(--encre);
  font-size: .93rem;
}
.reseau-valeur .etiquette { display: block; margin: 3px 0 0; font-weight: 400; }
/* Une valeur de diagnostic qui ne convient pas. Elle porte la couleur, et le nom du
 * contrôle reste noir : c'est la valeur qu'on va corriger, pas le contrôle. */
.reseau-valeur--non { color: var(--attention); }
/* Le champ de surcharge est étroit et discret : c'est l'exception, pas le geste
 * qu'on vient faire. Un champ pleine largeur en ferait le sujet de la ligne.
 *
 * Le sélecteur passe par la balise : la règle générale des champs de saisie est
 * `input[type=text]`, dont la spécificité est celle d'une classe PLUS celle d'un
 * attribut. Une classe seule perdait, et le champ reprenait 100 % de largeur en
 * débordant de la carte. Vu à l'écran. */
input.reseau-champ { flex: none; width: 190px; font-size: .89rem; }
input.reseau-champ::placeholder { font-size: .85rem; }

@media (max-width: 760px) {
  .reseau-ligne { flex-wrap: wrap; }
  .reseau-valeur { width: auto; text-align: left; }
  input.reseau-champ { width: 100%; }
}

/* Le titre d'un habillage et son « i ». La bulle s'ancre sous la ligne du titre et
 * s'étire à la largeur de la vignette : ancrée à l'icône, elle sortirait de la
 * carte, qui est étroite. */
.modele-tete { display: flex; align-items: center; gap: 6px; }
.modele-tete h2 { margin: 0; }
.modele-tete .info-bulle { top: calc(100% + 6px); }

/* ── Les promesses d'un écran de décision ────────────────────────────────────
 *
 * L'écran de bascule d'habillage existe pour rassurer, et c'est la seule chose
 * qu'il fait : sans la phrase « rien n'est touché », personne n'ose cliquer. Les
 * phrases restent donc en toutes lettres, mais chacune sur une ligne, cochée. Une
 * liste à puces se lit comme une notice ; des lignes cochées se lisent comme un
 * contrat.
 */
.promesses {
  list-style: none;
  margin: 0 0 24px;
  padding: 0;
}
.promesses li {
  position: relative;
  padding: 0 0 12px 28px;
  color: var(--encre-2);
  line-height: 1.55;
}
.promesses li:last-child { padding-bottom: 0; }
.promesses li strong { color: var(--encre); }
.promesses li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 4px;
  width: 16px;
  height: 16px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%231F6B6B' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 8.5 6.5 11.5 12.5 4.5'/%3E%3C/svg%3E") no-repeat center / 16px;
}

/* « 4 → 7 sections » : un avant et un après sur la même ligne, ce qu'un tableau à
 * trois colonnes disait en trois cellules dont deux d'en-tête. */
.compo-delta {
  display: flex;
  align-items: center;
  gap: 7px;
  flex: none;
  font-size: .9rem;
  color: var(--encre-2);
}

/* ── Une redirection ─────────────────────────────────────────────────────────
 *
 * Elle se lit comme elle se dit : « ceci mène à cela ». Deux adresses séparées par
 * une flèche, et non quatre colonnes de tableau dont deux de gris.
 */
.redirection-trajet {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}
.redirection-trajet code {
  font-family: var(--mono);
  font-size: .85rem;
  color: var(--encre);
  padding: 1px 6px;
  border-radius: 5px;
  background: var(--survol);
}
.redirection-fleche {
  width: 14px;
  height: 14px;
  flex: none;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23676D80' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.5 8h11M10 4.5 13.5 8 10 11.5'/%3E%3C/svg%3E") no-repeat center / 14px;
}
.redirection-suivie { flex: none; font-size: .86rem; text-align: right; white-space: nowrap; }
.redirection .etiquette { margin: 0; }

/* ── La barre de création, et la barre de filtre ──────────────────────────────
 *
 * Deux cartes empilées portaient l'une un champ de titre et un bouton, l'autre un
 * champ de recherche, un menu et un bouton : quatre lignes de formulaire avant la
 * première fiche. Elles tiennent chacune sur une ligne.
 *
 * La création garde l'aplat marine et le filtre passe en contour : sur cet écran,
 * une seule des deux est ce qu'on est venu faire.
 */
.barre-creer, .barre-filtre {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin: 0 0 14px;
}
.barre-creer { padding: 12px 14px; border: 1px solid var(--trait); border-radius: var(--rayon); background: var(--carte); }
.barre-filtre { margin-bottom: 18px; }
.barre-creer input[type=text],
.barre-filtre input[type=search] { flex: 1; min-width: 200px; width: auto; }
.barre-filtre select { flex: none; width: auto; min-width: 170px; }
.barre-creer .bouton, .barre-filtre .bouton { flex: none; }

/* Le point d'état d'une fiche. Trois couleurs pour trois états qu'on distingue
 * sans lire ; le mot est dans le `title` et dans l'`aria-label`, parce que « en
 * ligne » écrit vingt fois de suite ne distingue plus rien. */
.etat-point--brouillon { background: none; box-shadow: inset 0 0 0 1.5px var(--lien); }

/* ── Une demande ─────────────────────────────────────────────────────────────
 *
 * Le point plein est le seul repère de la liste : plein, la demande attend ;
 * creux, elle est traitée. Le mot est dans le `title` et dans l'`aria-label`,
 * parce qu'un point de huit pixels ne porte pas de mot, et qu'une colonne
 * « statut » répétée quarante fois n'est pas une information.
 */
.demande-point {
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--lien);
}
.demande-point--faite { background: none; box-shadow: inset 0 0 0 1.5px var(--trait-fort); }

/* Un champ de demande : son intitulé à gauche sur une colonne fixe, sa valeur à
 * droite. Le tableau à deux colonnes disparaît, et le message long se replie sans
 * pousser la colonne des intitulés. */
.rangee--champ { align-items: flex-start; gap: 20px; }
.rangee-label {
  flex: none;
  width: 168px;
  color: var(--encre-3);
  font-size: .87rem;
  padding-top: 1px;
}
.rangee-valeur { flex: 1; min-width: 0; color: var(--encre); overflow-wrap: break-word; }

/* Les photos jointes à une demande (séance S5) : des vignettes qui ouvrent la photo
 * entière dans un onglet. */
.demande-photos { display: flex; flex-wrap: wrap; gap: 10px; padding: 14px 0 4px; }
.demande-photos a { display: block; border-radius: 10px; overflow: hidden; box-shadow: 0 0 0 1px var(--trait-fort); }
.demande-photos img { display: block; width: 168px; height: 126px; object-fit: cover; }

@media (max-width: 620px) {
  .rangee--champ { flex-direction: column; gap: 3px; }
  .rangee-label { width: auto; }
}

/* Un repli qui ouvre sur ce qui détruit. Il ne prend pas le rouge au repos : un
 * aplat rouge posé dans un écran de travail attire l'œil sur ce qu'on ne veut
 * surtout pas cliquer par erreur. Il le prend une fois ouvert, quand on est venu
 * pour ça. */
.repli--danger > summary { color: var(--encre-2); }
.repli--danger[open] { border-color: var(--danger); }
.repli--danger[open] > summary { color: var(--danger); }

/* ── Une ligne de journal ────────────────────────────────────────────────────
 *
 * Deux cents lignes dans un tableau de quatre colonnes, dont trois de gris : c'est
 * un mur, pas une liste. La ligne porte le dessin de sa famille à gauche, ce qui
 * s'est passé au milieu, et depuis quand à droite.
 *
 * La date exacte est dans le `title` de la durée : on cherche « avant-hier » dix
 * fois pour une fois qu'on cherche « le 12 à 14 h 03 ».
 */
.journal-ligne { padding: 11px 0; }
.journal-picto {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 28px;
  height: 28px;
  border-radius: var(--rayon-xs);
  background: var(--survol);
  color: var(--encre-3);
}
.journal-picto .picto { width: 16px; height: 16px; }
/* La seule couleur du journal, et elle ne marque que ce qui a détruit quelque
 * chose : c'est la ligne qu'on cherche six mois plus tard. */
.journal-picto--detruit { background: var(--danger-fond); color: var(--danger); }
.journal-ligne .rangee__titre { font-size: .93rem; font-weight: 500; }
.journal-ligne .rangee__meta code { font-family: var(--mono); font-size: .8rem; }
.journal-quand {
  flex: none;
  color: var(--encre-3);
  font-size: .84rem;
  white-space: nowrap;
  /* Le pointillé dit qu'il y a une date exacte derrière, sans ajouter un mot. */
  border-bottom: 1px dotted var(--trait-fort);
  cursor: help;
}

/* ── Une répartition, en barres ───────────────────────────────────────────────
 *
 * Les pages les plus vues, les provenances, les sorties immédiates : trois
 * tableaux de nombres devenus trois fois le même dessin. Un nom, une valeur, une
 * barre sous les deux.
 *
 * La barre passe SOUS et non à côté : à côté, elle serait rognée par le nom d'une
 * page longue, et deux blocs côte à côte ne partageraient plus la même échelle.
 * En dessous, elle occupe toute la largeur de la carte, donc toutes les barres
 * d'un bloc se comparent sur la même règle.
 *
 * La plus longue vaut cent pour cent : on lit un RAPPORT entre pages, ce qu'une
 * colonne de nombres oblige à calculer de tête.
 */
.barre {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  gap: 4px 14px;
  padding: 11px 0;
  border-bottom: 1px solid var(--trait);
}
.barre:last-child { border-bottom: none; }
.barre-nom {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  font-size: .93rem;
  color: var(--encre);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.barre-nom code { font-family: var(--mono); font-size: .85rem; color: var(--encre-2); }
.barre-valeur {
  font-size: .93rem;
  font-weight: 600;
  color: var(--encre);
  white-space: nowrap;
}
.barre-valeur .note { font-weight: 400; }
.barre .jauge {
  display: block;
  grid-column: 1 / -1;
  margin: 3px 0 0;
  height: 4px;
}
/* Une part qu'on préférerait basse : le jaune de la charte plutôt que le marine.
 * Sur une barre, le jaune passe : ce n'est pas du texte, il n'a pas à tenir 4,5:1. */
.jauge--attention > i { background: var(--jaune); }
/* Une ligne isolée sous une liste de barres : pas de barre, donc pas de place
 * réservée pour elle. */
.barre--seule { border-top: 1px solid var(--trait); border-bottom: none; }
/* La bulle d'un « i » posé dans une barre s'ancre sous la ligne, comme partout. */
.barre .info-bulle { top: calc(100% - 4px); }

/* Un intertitre entre deux grilles d'indicateurs. Il classe, il ne s'annonce pas :
 * même poids qu'un titre de groupe du cadre de gauche. */
.titre-section {
  margin: 30px 0 12px;
  font-size: .8rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--encre-3);
}
.titre-section:first-of-type,
.titre-section--premier { margin-top: 4px; }
/* Le compte d'une exception, collé à l'intertitre qui la porte : « 5 encore au
 * texte du réseau ». Il est en ambre parce que c'est une tâche, et il n'apparaît
 * que s'il y a quelque chose à compter. */
.titre-section-note {
  margin-left: 8px;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--att-fond);
  color: var(--attention);
  font-size: .72rem;
  font-weight: 500;
  text-transform: none;
  letter-spacing: 0;
}

/* Le dessin d'un objet dans une rangée. Sans fond ni cadre, contrairement à celui
 * d'une tête de carte : à seize lignes, seize pastilles colorées feraient une
 * colonne de confettis, alors qu'un tracé gris se lit comme une initiale. */
.rangee-picto {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 20px;
  color: var(--encre-3);
  /* Aligné sur la PREMIÈRE ligne et non sur le milieu de la rangée : sur une ligne
   * dont le détail fait trois lignes de texte, un dessin centré dérive au milieu du
   * paragraphe et ne désigne plus le titre. */
  align-self: flex-start;
  margin-top: 2px;
}
.rangee-picto .picto { width: 19px; height: 19px; }
/* Un nombre au bout d'une rangée. Largeur fixe et chiffres tabulaires, hérités du
 * corps : la colonne s'aligne, donc deux lignes se comparent sans être lues. */
.rangee-compte {
  flex: none;
  min-width: 34px;
  text-align: right;
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--encre);
  letter-spacing: -.01em;
}
@media (hover: hover) and (pointer: fine) {
  a.rangee:hover .rangee-picto { color: var(--lien); }
}

/* La tête d'un indicateur : son nom, et son « i » s'il a quelque chose à dire.
 * `position: relative` porte la bulle, qui s'étire d'un bord à l'autre de la carte. */
.indicateur__tete {
  position: relative;
  display: flex;
  align-items: center;
  gap: 6px;
}
.indicateur__tete .indicateur__libelle { margin: 0; }
.indicateur__tete .info-bulle { top: calc(100% + 6px); }

/* Une évolution : le nombre porte la couleur, le reste de la phrase reste gris.
 * Une phrase entière en vert se lit comme une alerte, or une hausse de visites
 * n'appelle aucun geste. */
.delta { font-weight: 600; }
.delta--hausse { color: var(--ok); }
.delta--baisse { color: var(--attention); }
.delta--stable { color: var(--encre-2); }

.indicateur__lien {
  display: inline-block;
  margin-top: 10px;
  color: var(--lien);
  font-size: .87rem;
  font-weight: 500;
}

/* ── Les graphiques ──────────────────────────────────────────────────────────
 *
 * Écrits en SVG par includes/graphes.php. Ce qui suit ne fait que les poser dans
 * la page : les couleurs, elles, sont des attributs du dessin, parce que la
 * politique de sécurité du contenu interdit le style en ligne.
 */

/* ── L'anneau ──────────────────────────────────────────────────────────────── */
.anneau {
  display: block;
  width: 100%;
  max-width: 190px;
  height: auto;
  margin: 0 auto;
}
/* Le chiffre du centre. En unités du VIEWBOX et non en pixels : il grandit et
 * rétrécit avec l'anneau, donc il reste centré à toutes les tailles de carte. */
.anneau-valeur {
  font: 600 28px/1 var(--police);
  font-variant-numeric: tabular-nums;
  fill: var(--encre);
  letter-spacing: -1px;
}
.anneau-libelle { font: 400 11px/1 var(--police); fill: var(--encre-3); }
/* Un arc grossit au survol pour se désigner, sans bouger de place : le trait
 * s'épaissit vers l'intérieur ET l'extérieur, donc le cercle reste centré. */
@media (hover: hover) and (pointer: fine) {
  .anneau circle[stroke-dasharray] { transition: stroke-width var(--court) var(--sortie); }
  .anneau circle[stroke-dasharray]:hover { stroke-width: 22; cursor: help; }
}
@media (prefers-reduced-motion: reduce) {
  .anneau circle { transition: none; }
}

/* ── Les courbes ────────────────────────────────────────────────────────────
 *
 * Le dessin vient du serveur. Ce qui suit lui donne sa place, et pose la bulle de
 * survol que `assets/js/courbes.js` remplit.
 */
.carte--courbes { padding: 20px 22px 16px; }
.courbes-cadre { position: relative; margin: 4px 0 6px; }
.courbes {
  display: block;
  width: 100%;
  /* Le rapport du viewBox est conservé, donc la hauteur suit la largeur : les
   * dates et les valeurs de l'axe ne sont jamais comprimées. Le plancher évite
   * qu'une courbe devienne un trait de trente pixels sur un téléphone. */
  height: auto;
  min-height: 180px;
  overflow: visible;
}
.courbes-axe  { font: 400 11px/1 var(--police); fill: var(--encre-3); font-variant-numeric: tabular-nums; }
.courbes-date { font: 400 11px/1 var(--police); fill: var(--encre-3); }

/* Le fil vertical et les points d'un seau ne se voient qu'au survol de sa bande.
 * Six séries de trente points feraient cent quatre-vingts pastilles en permanence,
 * et la courbe disparaîtrait sous ses propres points. */
.courbes-fil, .courbes-point { opacity: 0; transition: opacity var(--court) var(--sortie); }
.courbes-seau--actif .courbes-fil,
.courbes-seau--actif .courbes-point { opacity: 1; }
.courbes-bande { cursor: crosshair; }
.courbes-bande:focus { outline: none; }
.courbes-bande:focus-visible + * { outline: 2px solid var(--lien); }

/* La bulle. Sa position arrive en propriétés personnalisées posées par le script :
 * la politique de sécurité du contenu interdit un attribut `style` dans le
 * document, et une propriété personnalisée écrite par CSSOM n'en est pas un. */
.courbes-bulle {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 5;
  min-width: 168px;
  padding: 10px 12px;
  border-radius: var(--rayon-s);
  background: var(--encre);
  color: var(--sur-encre);
  font-size: .84rem;
  box-shadow: var(--ombre-flot);
  pointer-events: none;
  transform: translate(calc(var(--x, 0px) - 50%), calc(var(--y, 0px) - 8px));
  transition: transform var(--court) var(--sortie);
}
.courbes-bulle[hidden] { display: none; }
.courbes-bulle-titre {
  margin: 0 0 7px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--trait);
  font-weight: 600;
}
.courbes-bulle-liste { list-style: none; margin: 0; padding: 0; }
.courbes-bulle-liste li {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 2px 0;
}
.courbes-bulle-pastille {
  flex: none;
  width: 9px;
  height: 9px;
  border-radius: 3px;
  background: var(--teinte, var(--carte));
}
.courbes-bulle-nom {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--encre-2);
}
.courbes-bulle-valeur { flex: none; font-weight: 600; font-variant-numeric: tabular-nums; }

@media (prefers-reduced-motion: reduce) {
  .courbes-bulle, .courbes-fil, .courbes-point { transition: none; }
}

/* ── Le sélecteur de période ────────────────────────────────────────────────
 *
 * Il commande TOUT l'écran, donc il est en haut, seul sur sa ligne, et il ne
 * ressemble à aucun autre réglage de la page.
 */
.periodes {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  margin: 0 0 20px;
}
.periodes .info-bulle { top: calc(100% + 6px); max-width: 520px; }
/* Un segment qui est un LIEN et non un bouton radio : le choix est dans l'adresse,
 * donc il se met en favori et le retour du navigateur y revient. */
.segment--lien { text-decoration: none; }
.segment--actif span {
  background: var(--carte);
  color: var(--encre);
  box-shadow: var(--ombre);
}
.segment--lien:focus-visible span { outline: 2px solid var(--lien); outline-offset: 1px; }

.periode-plage { display: flex; align-items: center; gap: 8px; }
.periode-plage input[type=date] { width: auto; font-size: .86rem; padding: 6px 9px; }
.periode-a { color: var(--encre-3); }

/* La période affichée, rappelée dans la tête du graphique : sans elle, une courbe
 * mise en favori sur douze mois se lit comme une courbe de trente jours. */
.controle-periode {
  margin-left: auto;
  flex: none;
  color: var(--encre-3);
  font-size: .84rem;
}

@media (max-width: 620px) {
  .periodes { gap: 10px; }
  .periode-plage { width: 100%; }
  .periode-plage input[type=date] { flex: 1; min-width: 0; }
}

/* ── La légende d'un graphique ──────────────────────────────────────────────
 *
 * Elle porte le nom et le chiffre de chaque part. Ce n'est pas un ornement : un
 * graphique dont la couleur est le seul porteur d'information est illisible pour
 * une personne sur douze.
 */
.legende { list-style: none; margin: 0; padding: 0; }
/* La ligne est le conteneur, et l'éventuel lien qu'elle porte s'étale dedans :
 * une part de légende est tantôt cliquable (elle mène à son contrôle) tantôt non
 * (elle ne mène nulle part), et les deux doivent se dessiner pareil. */
.legende-ligne {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 0;
  border-bottom: 1px solid var(--trait);
}
.legende-ligne:last-child { border-bottom: none; }
.legende-ligne > a {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 1;
  min-width: 0;
  margin: -8px -10px;
  padding: 8px 10px;
  border-radius: var(--rayon-xs);
  color: inherit;
  text-decoration: none;
}
.legende-pastille { flex: none; width: 11px; }
.legende-pastille svg { display: block; width: 11px; height: 11px; }
.legende-nom {
  flex: 1;
  min-width: 0;
  font-size: .89rem;
  color: var(--encre);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.legende-valeur {
  flex: none;
  display: flex;
  align-items: baseline;
  gap: 8px;
  font-size: .93rem;
  font-weight: 600;
  color: var(--encre);
}
/* Le pourcentage est plus petit et gris : c'est le nombre brut qu'on lit d'abord,
 * la part sert à le situer. Largeur fixe, sinon la colonne danse d'une ligne à
 * l'autre entre « 4 % » et « 43 % ». */
.legende-part {
  min-width: 38px;
  text-align: right;
  font-size: .82rem;
  font-weight: 400;
  color: var(--encre-3);
}
@media (hover: hover) and (pointer: fine) {
  .legende-ligne > a:hover { background: var(--survol); }
  .legende-ligne > a:hover .legende-nom { color: var(--lien); }
}

/* La tête de l'écran de santé : l'anneau à gauche, sa légende à droite. Sous
 * 760 px ils s'empilent, l'anneau d'abord : c'est lui qu'on est venu voir. */
.sante-tete {
  display: grid;
  grid-template-columns: 260px minmax(0, 1fr);
  gap: 14px;
  margin: 0 0 24px;
}
.sante-anneau { display: grid; place-items: center; padding: 22px; }
.sante-legende { display: flex; flex-direction: column; padding: 18px 20px; }
/* La ligne de contexte est poussée en bas et détachée : c'est une mention, pas une
 * part du graphique. */
.sante-quand {
  margin: auto 0 0;
  padding-top: 12px;
  border-top: 1px solid var(--trait);
  color: var(--encre-3);
  font-size: .84rem;
}
@media (max-width: 760px) {
  .sante-tete { grid-template-columns: 1fr; }
}

/* ── Un contrôle de la santé ─────────────────────────────────────────────────
 *
 * Une carte dont la tête porte quatre choses et pas une de plus : le dessin du
 * contrôle, son nom, son « pourquoi » derrière un « i », et le nombre de points.
 * Le paragraphe d'explication qui suivait chaque titre faisait à lui seul quatre
 * lignes par contrôle, douze fois par écran.
 */
.controle + .controle { margin-top: 14px; }
.controle-tete {
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 4px;
}
.controle-tete h2 { margin: 0; font-size: 1rem; }
.controle-picto {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 32px;
  height: 32px;
  border-radius: var(--rayon-xs);
}
.controle-picto .picto { width: 18px; height: 18px; }
.controle-picto--info      { background: var(--info-fond); color: var(--encre-3); }
.controle-picto--attention { background: var(--att-fond);  color: var(--attention); }
/* Le seul contrôle qui BLOQUE la mise en ligne (point 7.9) : les avis inventés.
   Il se distingue à l'œil de ceux qui n'avertissent que, parce que la conséquence
   n'est pas la même. Le mot « refuse » est écrit dans son texte : la couleur
   confirme, elle n'informe pas seule. */
.controle-picto--erreur    { background: var(--danger-fond); color: var(--danger); }
/* Le nombre est poussé à droite, en gris : c'est une quantité, pas une alerte.
 * L'alerte, s'il y en a une, est déjà dans la couleur du pictogramme. */
.controle-compte {
  margin-left: auto;
  flex: none;
  min-width: 22px;
  padding: 2px 8px;
  border-radius: 10px;
  background: var(--survol);
  color: var(--encre-2);
  font-size: .82rem;
  font-weight: 600;
  text-align: center;
}
/* La bulle du « i » d'une tête de carte s'ancre sous la LIGNE entière, comme
 * celle d'un champ : ancrée à l'icône, elle sortirait de la carte. */
.controle-tete .info-bulle { top: calc(100% + 6px); }

.rangee--note { color: var(--encre-3); font-size: .86rem; }
/* Une rangée qui ne mène nulle part et ne demande rien : pas de chevron, pas de
 * survol, et le nom en gris. Elle est là pour être comptée, pas cliquée. */
.rangee--calme { padding: 9px 0; }
.rangee--calme .rangee__titre { font-weight: 400; color: var(--encre-2); font-size: .92rem; }
.controle-coche {
  flex: none;
  width: 16px;
  height: 16px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%231F6B6B' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 8.5 6.5 11.5 12.5 4.5'/%3E%3C/svg%3E") no-repeat center / 16px;
}
/* Un repli qui contient une liste et non un formulaire : il prend la largeur de
 * l'écran et non celle d'une colonne de panneau. */
.repli--large { margin-top: 18px; }
.repli--large .repli-corps { padding: 2px 14px 6px; }

/* Un indicateur dont la valeur est un mot et non un nombre : « il y a 3 jours »
 * à 2,1 rem déborde de sa carte. */
.indicateur__valeur--texte { font-size: 1.35rem; letter-spacing: -.01em; }
/* Le dénominateur d'un rapport : plus petit et gris, sinon « 11/12 » se lit comme
 * un seul nombre de quatre chiffres. */
.indicateur__sur { font-size: 1.1rem; font-weight: 500; color: var(--encre-3); }

/* ── La planche-contact des médias ────────────────────────────────────────────
 *
 * Une bibliothèque d'images se REGARDE. L'ancien écran empilait une carte par
 * fichier avec son formulaire, ses trois recadrages et leur légende d'usage :
 * douze fichiers faisaient 2 569 mots, et retrouver une photo demandait de lire
 * douze fois la même chose.
 *
 * Trois points de construction :
 *  · le rectangle est le même pour tous, image ou document, et il est tenu par
 *    `aspect-ratio` plutôt que par une hauteur : une grille dont une case se
 *    déforme au premier PDF n'est plus une grille ;
 *  · `auto-fill` avec un minimum de 168 px, donc six colonnes sur un grand écran
 *    et deux sur un téléphone, sans point de rupture écrit ;
 *  · rien n'est écrit sous une image sauf son nom de fichier, et la seule couleur
 *    de la planche est la pastille de ce qui manque.
 */
.planche {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
  gap: 16px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.planche-note {
  margin: 0 0 20px;
  padding: 9px 12px 9px 30px;
  position: relative;
  border-radius: var(--rayon-s);
  background: var(--att-fond);
  color: var(--attention);
  font-size: .89rem;
}
/* Le point plutôt qu'un pictogramme d'alerte : c'est une remarque, pas une panne. */
.planche-note::before {
  content: "";
  position: absolute;
  left: 12px;
  top: 15px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--jaune);
}

.media-case {
  display: flex;
  flex-direction: column;
  gap: 7px;
  text-decoration: none;
  color: inherit;
  border-radius: var(--rayon-s);
}
.media-cadre {
  position: relative;
  display: block;
  aspect-ratio: 3 / 2;
  overflow: hidden;
  border: 1px solid var(--trait);
  border-radius: var(--rayon-s);
  background: var(--carte);
  transition: border-color var(--court) var(--sortie),
              box-shadow var(--court) var(--sortie);
}
.media-image {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
}
/* Un document n'a pas d'image : il prend le même rectangle et le pictogramme de sa
 * nature, centré. Sans ce repli, la grille perdrait une case sur deux. */
.media-doc {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  background: var(--info-fond);
  color: var(--encre-3);
}
.media-doc .picto { width: 34px; height: 34px; }
.media-doc--grand { aspect-ratio: 3 / 2; border-radius: var(--rayon-s); }
.media-doc--grand .picto { width: 56px; height: 56px; }

/* Ce qui manque, et rien d'autre. Le libellé est dans le `title` et dans
 * l'`aria-label` : une pastille de huit pixels ne porte pas de mot. */
.media-manque {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--jaune);
  box-shadow: 0 0 0 2px var(--carte);
}
.media-nom {
  display: block;
  font-size: .82rem;
  color: var(--encre-3);
  /* Un nom de fichier long est coupé et non replié : deux lignes sous une vignette
   * décalent toute la rangée suivante. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
@media (hover: hover) and (pointer: fine) {
  .media-case:hover .media-cadre {
    border-color: var(--trait-fort);
    box-shadow: var(--ombre);
  }
  .media-case:hover .media-nom { color: var(--encre); }
}
.media-case:focus-visible { outline: 2px solid var(--lien); outline-offset: 3px; }
@media (prefers-reduced-motion: reduce) {
  .media-cadre { transition: none; }
}

/* ── La fiche d'un fichier ──────────────────────────────────────────────────
 *
 * L'image à gauche, ce qu'on peut en dire à droite. Sous 900 px la colonne de
 * droite passe dessous : côte à côte, à cette largeur, aucune des deux ne tient.
 */
.media-fiche {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 28px;
  align-items: start;
}
.media-fiche-vue { position: sticky; top: 28px; }
.media-grande {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--trait);
  border-radius: var(--rayon);
  background: var(--carte);
}
.media-meta { margin: 10px 0 0; color: var(--encre-3); font-size: .86rem; }
.media-fiche-cote > .encart { margin-top: 0; }
.media-ancrage {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin-top: 14px;
}
.media-ancrage label { font-size: .89rem; font-weight: 500; flex: none; }
.media-ancrage select { width: auto; flex: 1; min-width: 180px; }
/* La suppression est séparée par un filet et repoussée : elle ne se trouve pas
 * sous le doigt de quelqu'un qui vient d'enregistrer une légende. */
.media-detruire {
  margin-top: 28px;
  padding-top: 18px;
  border-top: 1px solid var(--trait);
}

@media (max-width: 900px) {
  .media-fiche { grid-template-columns: 1fr; gap: 20px; }
  .media-fiche-vue { position: static; }
}

/* -- Galerie des habillages ----------------------------------------------- */
/*
 * Chaque vignette est un CADRE, et dedans la vraie page d'accueil du site rendue
 * dans l'habillage candidat. Pas une capture d'écran : une capture montrerait le
 * site de quelqu'un d'autre, et l'équipe découvrirait le sien après la bascule.
 *
 * L'échelle est une variable et la largeur du cadre en découle, au lieu d'être
 * réglée à la main des deux côtés. Sans ce lien, la vignette et son contenu
 * divergent au premier ajustement, et il reste une bande blanche que personne ne
 * comprend.
 *
 * Le rendu se fait à 1320 px de large, la mesure d'un écran d'ordinateur : c'est la
 * composition qu'on veut juger. Rendre le cadre à sa taille réelle donnerait la
 * version téléphone du site, qui ne dit rien du choix qu'on est en train de faire.
 */
.modeles {
  --vignette-large: 1320px;
  --vignette-haute: 1080px;
  /* 0,26 et pas 0,3 : à 0,3 deux vignettes seulement tenaient par rangée, donc
     cinq habillages sur trois rangées, et comparer le premier au cinquième
     demandait de défiler. À 0,26 il en tient trois, et les cinq se voient sur
     deux rangées. Mesuré sur un écran de 1600 px, avec les cinq en face de soi. */
  --vignette-echelle: .26;
  display: grid;
  grid-template-columns: repeat(auto-fill, calc(var(--vignette-large) * var(--vignette-echelle)));
  justify-content: center;
  gap: 28px;
  margin-top: 8px;
}

.modele-carte {
  display: flex;
  flex-direction: column;
  background: var(--carte);
  border: 1px solid var(--trait);
  border-radius: var(--rayon);
  box-shadow: var(--ombre);
  overflow: hidden;
}
/* L'habillage en service se signale par un filet, pas par un aplat : un aplat de
 * couleur derrière une vignette fausserait la couleur de la vignette elle-même. */
.modele-carte--actif { border-color: var(--lien); box-shadow: 0 0 0 1px var(--lien), var(--ombre); }

.modele-vignette {
  position: relative;
  width: calc(var(--vignette-large) * var(--vignette-echelle));
  height: calc(var(--vignette-haute) * var(--vignette-echelle));
  overflow: hidden;
  background: var(--survol);
  border-bottom: 1px solid var(--trait);
}
.modele-vignette iframe {
  position: absolute;
  top: 0;
  left: 0;
  width: var(--vignette-large);
  height: var(--vignette-haute);
  border: 0;
  transform: scale(var(--vignette-echelle));
  transform-origin: 0 0;
  /* Le cadre ne prend pas les clics : c'est le lien posé par-dessus qui les
   * reçoit, et une vignette n'est pas un endroit où naviguer. */
  pointer-events: none;
}

/* Le lien couvre toute la vignette. Son libellé n'apparaît qu'au survol, mais il
 * reste dans l'arbre d'accessibilité : un lecteur d'écran l'annonce toujours. */
.modele-vignette-lien {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background: transparent;
  transition: background var(--court) var(--sortie);
}
.modele-vignette-lien span {
  padding: 8px 14px;
  border-radius: var(--rayon-xs);
  background: var(--carte);
  color: var(--lien);
  font-size: .87rem;
  font-weight: 600;
  opacity: 0;
  transition: opacity var(--court) var(--sortie);
}
.modele-vignette-lien:hover,
.modele-vignette-lien:focus-visible { background: var(--voile); }
.modele-vignette-lien:hover span,
.modele-vignette-lien:focus-visible span { opacity: 1; }

.modele-corps { display: flex; flex-direction: column; gap: 8px; padding: 18px 20px 20px; flex: 1; }
.modele-corps h2 { margin: 0; font-size: 1.15rem; }
.modele-registre {
  margin: 0;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--encre-3);
}
.modele-pour { margin: 0; font-size: .87rem; color: var(--encre-2); }
.modele-pied {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-top: auto;
  padding-top: 12px;
}

/* L'aperçu de l'écran de confirmation : presque grandeur réelle, parce qu'on y
 * décide. Une vignette suffit à comparer six habillages ; elle ne suffit pas à en
 * choisir un. */
.modele-plein {
  --vignette-large: 1320px;
  --vignette-haute: 1300px;
  --vignette-echelle: .7;
  position: relative;
  width: 100%;
  max-width: calc(var(--vignette-large) * var(--vignette-echelle));
  height: calc(var(--vignette-haute) * var(--vignette-echelle));
  margin: 12px 0;
  overflow: hidden;
  border: 1px solid var(--trait);
  border-radius: var(--rayon-s);
  background: var(--survol);
}
.modele-plein iframe {
  position: absolute;
  top: 0;
  left: 0;
  width: var(--vignette-large);
  height: var(--vignette-haute);
  border: 0;
  transform: scale(var(--vignette-echelle));
  transform-origin: 0 0;
}

.liste-points { margin: 12px 0 0; padding-left: 20px; }
.liste-points li { margin-bottom: 8px; font-size: .93rem; }
.liste-points li:last-child { margin-bottom: 0; }

/* Sous 1000 px, deux vignettes ne tiennent plus côte à côte : l'échelle descend
 * plutôt que la grille ne déborde. */
@media (max-width: 1000px) {
  .modeles { --vignette-echelle: .24; }
  .modele-plein { --vignette-echelle: .5; }
}
@media (max-width: 620px) {
  .modeles { --vignette-echelle: .2; }
  .modele-plein { --vignette-echelle: .3; }
}

/* -- Mouvement réduit ----------------------------------------------------- */
/*
 * « Mouvement réduit » ne veut pas dire « aucun retour ». Les changements de
 * couleur restent, parce qu'ils portent de l'information ; les déplacements et
 * les mises à l'échelle partent, parce qu'ils ne portent que du plaisir.
 */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * {
    transition-duration: 1ms !important;
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
  }
  .bouton:active { transform: none; }
}

/* ─── L'éditeur de la page de vente ────────────────────────────────────────── */
/* Vingt sections repliées, cent onze textes et dix-huit listes. Tout tient dans
   un seul formulaire : un bouton par section aurait permis de corriger un titre
   ici, un autre là, puis de perdre le premier en enregistrant le second. */
/* `.pliante` s'appelait `.vitrine-section` : le composant est né dans l'éditeur
   de la page de vente, et l'inventaire du site public en a besoin aussi. Une
   classe qui dit « vitrine » sur un écran qui ne parle pas de la vitrine se paie
   six mois plus tard, quand on cherche pourquoi ce nom est là. */
.pliante {
  border: 1px solid var(--trait);
  border-radius: 12px;
  margin-bottom: 10px;
  background: var(--carte);
}
.pliante[open] { box-shadow: var(--ombre); }
.pliante > summary {
  display: flex; align-items: center; gap: 10px;
  padding: 14px 18px; cursor: pointer;
  font-weight: 650; font-size: .95rem;
  list-style: none;
}
.pliante > summary::-webkit-details-marker { display: none; }
/* Le chevron est dessiné plutôt qu'écrit : le triangle natif ne se colore pas
   et ne s'aligne pas de la même façon d'un navigateur à l'autre. */
.pliante > summary::before {
  content: ''; flex: 0 0 auto;
  width: 8px; height: 8px; margin-right: 2px;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(-45deg); transition: transform .18s;
}
.pliante[open] > summary::before { transform: rotate(45deg); }
.pliante > summary:hover { background: var(--survol); border-radius: 12px; }
.pliante__nom { flex: 1; }
.pliante__jeton {
  font-size: .74rem; font-weight: 700; letter-spacing: .02em;
  padding: 3px 9px; border-radius: 999px;
  background: var(--info-fond); color: var(--lien);
}
.pliante__corps { padding: 4px 18px 20px; border-top: 1px solid var(--trait); }
.pliante__corps .champ:last-of-type { margin-bottom: 8px; }

/* Les listes : un tableau, une ligne par entrée. Le cadre défile de côté quand
   une liste a six colonnes, et la page ne défile jamais avec lui. */
.vitrine-liste {
  border: 1px solid var(--trait); border-radius: 10px;
  padding: 14px 16px 10px; margin: 18px 0;
}
.vitrine-liste > legend {
  font-size: .82rem; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--encre-3);
  padding-inline: 6px;
}
.vitrine-liste__cadre { overflow-x: auto; margin-top: 10px; }
.vitrine-liste__table { width: 100%; border-collapse: collapse; font-size: .86rem; }
.vitrine-liste__table th {
  text-align: left; font-size: .74rem; font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase; color: var(--encre-3);
  padding: 4px 6px 8px; white-space: nowrap;
}
.vitrine-liste__table td { padding: 3px 6px; vertical-align: top; }
.vitrine-liste__table input { width: 100%; min-width: 150px; }
.vitrine-liste__rang { width: 28px; color: var(--encre-3); font-size: .78rem; padding-top: 12px; }

/* Le bouton d'enregistrement reste atteignable après deux cents champs : il est
   collé en bas de la fenêtre, pas au bout du formulaire. */
.vitrine-editeur__pied {
  position: sticky; bottom: 0; z-index: 5;
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  margin-top: 20px; padding: 14px 18px;
  background: var(--carte);
  backdrop-filter: blur(8px);
  border: 1px solid var(--trait); border-radius: 12px;
  box-shadow: var(--ombre-flot);
}
.vitrine-editeur__pied .aide { margin: 0; }

.pour-lecteur-ecran {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ─── L'affichage : les trois fonds, avec leur aperçu ─────────────────────────
 *
 * Les deux palettes des vignettes sont écrites ICI, en dur, et c'est le seul
 * endroit du projet où une couleur écrite en dur est juste : une vignette qui
 * montre le fond sombre doit rester sombre pendant qu'on la regarde depuis le
 * fond clair. Prendre les jetons de la page rendrait les trois vignettes
 * identiques, donc inutiles.
 *
 * Elles ne pouvaient pas non plus passer par un attribut `style` : la politique
 * de sécurité du contenu l'interdit (router.php), comme partout ailleurs dans
 * ce projet.
 *
 * Les valeurs recopiées sont celles des trois blocs de jetons en tête de cette
 * feuille. Si elles y changent, elles changent ici : c'est le prix de vignettes
 * qui disent la vérité, et il se paie une fois tous les deux ans.
 */
.themes {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 12px;
  margin: 0 0 22px;
}
.themes-titre {
  grid-column: 1 / -1;
  margin: 0;
  font-size: .82rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--encre-3);
}

.theme {
  display: block;
  padding: 10px;
  border: 1px solid var(--trait);
  border-radius: var(--rayon);
  background: var(--carte);
  cursor: pointer;
  transition: border-color var(--court) var(--sortie),
              box-shadow var(--court) var(--sortie);
}
.theme:hover { border-color: var(--trait-fort); }

/* Le choix retenu porte un anneau, pas une couleur de fond : la carte contient
   un aperçu, et un fond teinté derrière un aperçu fausse ce qu'il montre. */
.theme--choisi {
  border-color: var(--action);
  box-shadow: 0 0 0 1px var(--action);
}

/* Le bouton radio reste dans le document : il porte l'état, le nom du champ et
   le clavier. Il est seulement rendu invisible, jamais retiré du flux
   d'accessibilité. */
.theme input[type=radio] {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.theme:focus-within {
  border-color: var(--action);
  box-shadow: 0 0 0 3px var(--anneau);
}

.theme-apercu {
  display: flex;
  height: 96px;
  margin-bottom: 10px;
  border: 1px solid var(--trait);
  border-radius: var(--rayon-s);
  overflow: hidden;
}
/* « Comme le système » montre les deux moitiés. La coupe est franche et
   verticale plutôt qu'en diagonale : une diagonale déforme le rail de gauche,
   qui est justement ce qu'on cherche à reconnaître. */
.theme-vue { display: flex; flex: 1; min-width: 0; }
.theme-vue--droite { border-left: 1px solid var(--trait); }

.theme-rail {
  width: 34%;
  padding: 8px 6px;
  border-right: 1px solid;
  border-right-color: inherit;
  display: flex;
  flex-direction: column;
  gap: 5px;
}
.theme-rail i { display: block; height: 4px; border-radius: 2px; }
.theme-rail i:nth-child(1) { width: 78%; }
.theme-rail i:nth-child(2) { width: 62%; }
.theme-rail i:nth-child(3) { width: 70%; }

.theme-page {
  flex: 1;
  min-width: 0;
  padding: 8px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.theme-carte {
  border: 1px solid;
  border-radius: 4px;
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.theme-carte i { display: block; height: 4px; border-radius: 2px; }
.theme-carte i:nth-child(1) { width: 64%; }
.theme-carte i:nth-child(2) { width: 88%; }
.theme-bouton { width: 42%; height: 11px; border-radius: 3px; }

.theme-nom {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
  font-size: .95rem;
  color: var(--encre);
}
.theme-note {
  display: block;
  margin-top: 3px;
  font-size: .84rem;
  line-height: 1.45;
  color: var(--encre-2);
}

@media (prefers-reduced-motion: reduce) {
  .theme { transition: none; }
}

/* Les deux palettes. Chaque vignette porte son fond, et ses enfants héritent
   des couleurs par les variables locales : une seule règle par palette. */
.theme-vue--clair {
  background: #F4F4F5;
  --v-rail: #FAFAFA;
  --v-carte: #FFFFFF;
  --v-trait: #E4E4E7;
  --v-encre: #09090B;
  --v-sourd: #A1A1AA;
  --v-action: #18181B;
}
.theme-vue--sombre {
  background: #0E0E11;
  --v-rail: #131316;
  --v-carte: #17171A;
  --v-trait: #2A2A30;
  --v-encre: #FAFAFA;
  --v-sourd: #6A6A73;
  --v-action: #FAFAFA;
}
.theme-vue .theme-rail   { background: var(--v-rail); border-right-color: var(--v-trait); }
.theme-vue .theme-rail i { background: var(--v-sourd); }
.theme-vue .theme-rail i:first-child { background: var(--v-encre); }
.theme-vue .theme-carte  { background: var(--v-carte); border-color: var(--v-trait); }
.theme-vue .theme-carte i { background: var(--v-sourd); }
.theme-vue .theme-carte i:first-child { background: var(--v-encre); }
.theme-vue .theme-bouton { background: var(--v-action); }

/* ═══════════════════════════════════════════════════════════════════════════
   LES COMPOSANTS DE LA REFONTE (2026-09-07)

   Six objets, écrits une fois, employés partout. Ils remplacent des mises en
   page recomposées écran par écran, et c'est ce qui rendait chaque écran
   légèrement différent du précédent.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ─── 1. La bande de faits ────────────────────────────────────────────────────
 *
 * Quatre informations sur une ligne, chacune avec son lien. Elle remplace quatre
 * encarts empilés, ou pire, un chapeau en prose qui les récitait.
 *
 * Chaque élément est court par construction : un libellé gris, une valeur qui se
 * clique. S'il faut une phrase, ce n'est pas un fait, c'est une alerte, et une
 * alerte est un encart.
 */
.bande {
  display: flex;
  align-items: stretch;
  flex-wrap: wrap;
  background: var(--carte);
  border: 1px solid var(--trait);
  border-radius: var(--rayon);
  box-shadow: var(--ombre);
  margin: 0 0 18px;
  overflow: hidden;
}
.bande-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 15px;
  font-size: .82rem;
  flex: 1 1 130px;
  min-width: 0;
}
.bande-item + .bande-item { border-left: 1px solid var(--trait); }
/* Un fait dont la valeur est longue par nature (un nom de domaine) prend deux
   parts au lieu d'une. Sans cela, quatre faits se partagent la largeur en parts
   égales et le seul qui avait besoin de place est le seul à être coupé. */
.bande-item--large { flex-grow: 2.2; flex-basis: 200px; }
/* Le libellé ne se coupe JAMAIS : c'est lui qui dit de quoi on parle, et
   « Ad... » ne dit rien. C'est la valeur qui rétrécit, puisqu'on peut deviner
   un domaine tronqué mais pas un libellé tronqué. */
.bande-item > span {
  color: var(--encre-2);
  white-space: nowrap;
  flex: none;
}
.bande-item > a {
  color: var(--encre);
  font-weight: 550;
  text-decoration: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.bande-item > a:hover { text-decoration: underline; }
/* Sous 700 px la bande se replie en colonne : quatre faits serrés côte à côte
   sur un téléphone deviennent quatre colonnes de deux caractères. */
@media (max-width: 700px) {
  .bande-item { flex-basis: 100%; }
  .bande-item + .bande-item { border-left: 0; border-top: 1px solid var(--trait); }
}

/* ─── 2. L'étiquette pleine ───────────────────────────────────────────────────
 *
 * La même étiquette, en pastille. Elle sert quand l'état est LA colonne qu'on
 * parcourt du regard, dans une liste ou une bande : le fond donne la limite que
 * la pastille de 7 px ne donne pas à elle seule.
 */
.etiquette--plein {
  padding: 3px 9px;
  border-radius: 999px;
  font-size: .78rem;
  font-weight: 600;
  background: var(--survol);
}
.etiquette--plein::before { width: 5px; height: 5px; }
.etiquette--plein.etiquette--ok        { background: var(--ok-fond); }
.etiquette--plein.etiquette--attention,
.etiquette--plein.etiquette--tiede     { background: var(--att-fond); }
.etiquette--plein.etiquette--info      { background: var(--info-fond); }
.etiquette--plein.etiquette--danger    { background: var(--danger-fond); color: var(--danger); }
.etiquette--plein.etiquette--danger::before { background: var(--danger); }
/* Sans pastille : quand l'étiquette porte un nombre, le point devant lui fait un
   doublon. « • 46 » ne dit rien de plus que « 46 ». */
.etiquette--muette::before { display: none; }

/* ─── 3. Le chiffre ───────────────────────────────────────────────────────────
 *
 * Un libellé, un nombre, un lien pour agir. Le nombre est en 1,7 rem et non en
 * 2,5 : sur un écran qui en porte trois, une taille d'affiche transforme trois
 * indicateurs en trois titres, et on ne sait plus lequel lire.
 */
.chiffres {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 12px;
  margin: 0 0 22px;
}
.chiffre {
  background: var(--carte);
  border: 1px solid var(--trait);
  border-radius: var(--rayon);
  box-shadow: var(--ombre);
  padding: 13px 15px 12px;
}
.chiffre-nom {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin: 0;
  font-size: .78rem;
  font-weight: 500;
  color: var(--encre-2);
}
.chiffre-val {
  margin: 6px 0 0;
  font-size: 1.7rem;
  font-weight: 650;
  letter-spacing: -.035em;
  line-height: 1.15;
  font-variant-numeric: tabular-nums;
}
.chiffre-lien { margin: 4px 0 0; font-size: .78rem; }

/* ─── 4. La liste repliée ─────────────────────────────────────────────────────
 *
 * Dix étapes, une seule ouverte : celle qui vient. Les faites sont barrées et
 * grises, les suivantes sont réduites à leur titre.
 *
 * C'est le remplacement direct du pavé de démarrage : la version précédente
 * affichait le titre, le motif ET le détail du point en cours, soit trois
 * paragraphes en permanence, au-dessus des chiffres qu'on venait lire.
 */
.etapes { list-style: none; margin: 0; padding: 0; }
.etape {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 10px 15px;
  font-size: .845rem;
}
.etape + .etape { border-top: 1px solid var(--trait); }
.etape-marque {
  width: 17px; height: 17px;
  flex: none;
  border-radius: 50%;
  border: 1.5px solid var(--trait-fort);
  display: grid;
  place-items: center;
  font-size: .62rem;
  line-height: 1;
}
.etape-nom { flex: 1; min-width: 0; font-weight: 500; }
.etape-nom a { color: inherit; text-decoration: none; }
.etape-nom a:hover { text-decoration: underline; }

.etape--faite { color: var(--encre-3); }
.etape--faite .etape-marque {
  background: var(--ok);
  border-color: var(--ok);
  color: var(--sur-plein);
}
.etape--faite .etape-nom { text-decoration: line-through; }

/* L'étape en cours : un aplat marqué, et le seul endroit de l'écran où le jaune
   de la marque apparaît en dehors de la pastille du cadre. */
.etape--ici {
  display: block;
  background: var(--marque-fond);
  box-shadow: inset 3px 0 0 var(--marque);
  padding: 14px 16px 15px;
}
.etape--ici .etape-tete {
  display: flex;
  align-items: center;
  gap: 11px;
}
.etape--ici .etape-marque { border-color: var(--marque-encre); }
.etape--ici .etape-nom { font-weight: 650; }
.etape-pourquoi {
  margin: 7px 0 0 28px;
  font-size: .82rem;
  line-height: 1.5;
  color: var(--encre-2);
  max-width: 66ch;
}
.etape-actions { margin: 11px 0 0 28px; display: flex; gap: 8px; flex-wrap: wrap; }

/* ─── 5. La tête de carte ─────────────────────────────────────────────────────
 * Un titre à gauche, une mesure à droite, un filet dessous. */
.carte-tete {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--trait);
}
.carte-tete h2 {
  margin: 0;
  font-size: .875rem;
  font-weight: 600;
  letter-spacing: -.012em;
}
.carte-mesure {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: .78rem;
  font-weight: 600;
  color: var(--encre-2);
  font-variant-numeric: tabular-nums;
  flex: none;
}
.carte-mesure .jauge { width: 92px; height: 4px; margin: 0; flex: none; }

/* ─── 6. La carte sans marges intérieures ─────────────────────────────────────
 * Pour les cartes qui ne portent qu'une liste : ce sont les rangées qui posent
 * leur propre respiration, et un padding de carte les décalerait toutes. */
.carte--liste { padding: 0; overflow: hidden; }

/* ─── La tuile de marque et le pied du cadre ──────────────────────────────────
 *
 * Le point de neuf pixels qui tenait lieu de marque ne disait rien : il était
 * identique sur les cinq sites. La tuile porte les initiales, donc elle dit
 * LEQUEL. C'est le geste de tous les outils qui gèrent plusieurs comptes, et sur
 * un écran d'agence qui passe d'un site à l'autre, c'est la différence entre
 * reconnaître et relire.
 */
.tuile-marque {
  width: 22px; height: 22px;
  flex: none;
  border-radius: 6px;
  background: var(--action);
  color: var(--sur-plein);
  display: grid;
  place-items: center;
  font-size: .66rem;
  font-weight: 700;
  letter-spacing: -.02em;
  /* Les initiales sont des capitales serrées : la mesure tabulaire les écarterait
     comme des chiffres de tableau. */
  font-variant-numeric: normal;
}

.avatar {
  width: 24px; height: 24px;
  flex: none;
  border-radius: 50%;
  background: var(--survol);
  color: var(--encre-2);
  display: grid;
  place-items: center;
  font-size: .62rem;
  font-weight: 600;
  font-variant-numeric: normal;
}

.rail-qui { min-width: 0; flex: 1; line-height: 1.25; }
.rail-qui-nom {
  display: block;
  font-weight: 550;
  color: var(--encre);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.rail-qui-role { display: block; font-size: .72rem; color: var(--encre-3); }

/* La déconnexion redevient un pictogramme : c'est un geste qu'on fait une fois
   par jour, et il occupait une ligne de texte en permanence. */
.rail-sortir {
  flex: none;
  display: grid;
  place-items: center;
  width: 26px; height: 26px;
  border-radius: var(--rayon-xs);
  color: var(--encre-3);
}
.rail-sortir svg { width: 15px; height: 15px; }
.rail-sortir:hover { background: var(--survol); color: var(--encre); }

/* ─── Les graphiques de tuile ─────────────────────────────────────────────────
 *
 * Le dessin prend la couleur de son conteneur par `currentColor` : une seule
 * règle suffit alors à le faire changer entre les deux thèmes, et il n'y a aucun
 * `fill` écrit dans le PHP qui puisse rester clair sur un fond noir.
 */
.chiffre-dessin {
  display: block;
  margin-top: 9px;
  color: var(--encre-3);
  line-height: 0;
}
.chiffre-dessin--encre { color: var(--encre); }
a.chiffre-dessin { transition: color var(--court) var(--sortie); }
a.chiffre-dessin:hover { color: var(--lien); }
a.chiffre-dessin:focus-visible {
  outline: 2px solid var(--lien);
  outline-offset: 3px;
  border-radius: var(--rayon-xs);
}

/* L'étincelle s'étire sur toute la largeur de la tuile : sa vue est en unités
   fixes, mais son rendu épouse la carte, quelle que soit la largeur de l'écran.
   Le trait, lui, garde son épaisseur grâce à `vector-effect` posé sur la ligne. */
.etincelle { display: block; width: 100%; height: 26px; }

/* Les parts de la barre segmentée. Elles sont ici et non dans un attribut du
   SVG parce qu'elles sont sémantiques : elles changent avec le thème, donc elles
   passent par des jetons, et un attribut de présentation ne résout pas var(). */
.seg--erreur    { fill: var(--danger); }
.seg--attention { fill: var(--attention); }
/* La part « pour information » prend l'encre sourde à 60 %, et non le filet :
   le filet est calculé pour se voir SUR une carte, pas DANS un dessin, et à
   #3A3A42 sur un fond #17171A il disparaissait en thème sombre. */
.seg--info      { fill: var(--encre-3); opacity: .6; }

/* Le suffixe d'unité collé au grand chiffre : « 243 30 j » se lirait comme un
   nombre à cinq chiffres sans cette mise en retrait. */
.chiffre-val small {
  font-size: .48em;
  font-weight: 500;
  color: var(--encre-3);
  letter-spacing: 0;
  margin-left: 5px;
}

/* ─── Le tableau ──────────────────────────────────────────────────────────────
 *
 * Il n'existe que là où l'on COMPARE des lignes entre elles : la liste des sites
 * de la console, le portefeuille de domaines. Partout ailleurs, une rangée
 * (.rangee) dit la même chose en moins de colonnes et se replie mieux sur un
 * téléphone. Un tableau qui ne sert qu'à empiler des lignes est une liste qui a
 * mal tourné.
 */
/* Le tableau vit dans une carte : c'est elle qui porte le bord et l'arrondi, et
   le cadre ne sert plus qu'au défilement horizontal sur un écran étroit. */
.tableau-cadre {
  overflow-x: auto;
  background: var(--carte);
  border: 1px solid var(--trait);
  border-radius: var(--rayon);
}
.carte > .tableau-cadre { border: 0; border-radius: 0; background: none; }
.tableau {
  width: 100%;
  border-collapse: collapse;
  font-size: .845rem;
}
.tableau th {
  text-align: left;
  padding: 12px 18px;
  border-bottom: 1px solid var(--trait);
  font-size: .74rem;
  font-weight: 600;
  /* Plus de capitales espacées : elles criaient plus fort que le contenu
     qu'elles surmontent, et l'interface qui sert de référence titre ses colonnes
     en minuscules grises. */
  letter-spacing: 0;
  text-transform: none;
  color: var(--encre-3);
  white-space: nowrap;
}
.tableau td {
  /* Des lignes hautes : une liste de cinquante-deux métiers se parcourt à l'oeil,
     et douze pixels d'interligne font la différence entre lire et déchiffrer. */
  padding: 15px 18px;
  border-bottom: 1px solid var(--trait);
  vertical-align: middle;
}
/* La dernière ligne n'a pas de filet : il doublait le bord de la carte. */
.tableau tbody tr:last-child td { border-bottom: 0; }
@media (hover: hover) and (pointer: fine) {
  .tableau tbody tr:hover td { background: var(--survol); }
}
.tableau tbody tr:last-child td { border-bottom: 0; }
.tableau tbody tr:hover { background: var(--survol); }
/* La dernière colonne se cale à droite : ce sont des dates et des nombres, et
   deux colonnes de chiffres alignées à gauche ne se comparent pas.
   Le sélecteur nomme `th` explicitement : `.tableau th` porte un élément en plus,
   donc il l'emportait sur `.tableau-fin` seul, et l'en-tête restait à gauche
   au-dessus de valeurs alignées à droite. */
.tableau td.tableau-fin,
.tableau th.tableau-fin { text-align: right; white-space: nowrap; }
.tableau td.tableau-fin { color: var(--encre-2); }
.tableau-mono { font-family: var(--mono); font-size: .95em; color: var(--encre-2); }
.tableau-vide { color: var(--encre-3); }

.site-nom {
  display: flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
  color: inherit;
  min-width: 0;
}
.site-nom-texte { min-width: 0; line-height: 1.3; }
.site-nom b {
  display: block;
  font-weight: 550;
  letter-spacing: -.008em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.site-nom small { display: block; font-size: .78rem; color: var(--encre-3); }
.site-nom:hover b { text-decoration: underline; }
.site-nom:focus-visible {
  outline: 2px solid var(--lien);
  outline-offset: 2px;
  border-radius: var(--rayon-xs);
}

/* ─── Bandeau de consentement ─────────────────────────────────────────────────
 *
 * Le même balisage que la coquille des sites publics (`#bandeau-cookies`,
 * `[data-cookies]`, consentement.js) : seul l'habillage change ici, parce que
 * l'administration a sa propre feuille et ses propres jetons. La logique, elle,
 * n'existe qu'à un endroit.
 *
 * Il flotte en bas et ne bloque rien : on doit pouvoir continuer à lire son écran
 * sans répondre. Un bandeau modal qui prend la main force le « accepter » du
 * premier réflexe, et un accord arraché n'est pas un accord.
 */
.bandeau-cookies {
  position: fixed; left: 16px; right: 16px; bottom: 16px; z-index: 80;
  max-width: 40rem; margin-inline: auto; padding: 18px 20px;
  background: var(--carte); color: var(--encre);
  border: 1px solid var(--trait-fort); border-radius: var(--rayon);
  box-shadow: var(--ombre-flot);
}
.bandeau-cookies[hidden] { display: none; }
.bandeau-cookies__titre { font-weight: 600; margin: 0 0 6px; }
.bandeau-cookies p { font-size: .86rem; line-height: 1.5; color: var(--encre-2); margin: 0; }
.bandeau-cookies__actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 16px; }
.bandeau-cookies__actions .bouton { flex: 1 1 10rem; justify-content: center; }
.bandeau-cookies__lien { margin-top: 12px; font-size: .78rem; }
.bandeau-cookies__lien a { color: var(--lien); }
/* Le premier écran tient en deux lignes et une rangée de boutons au téléphone,
 * comme sur les sites publics (PHASE-3-UX, UX-0.9) : les deux boutons côte à
 * côte, de même poids. Sans ces règles, les deux classes du premier écran
 * n'étaient stylées que dans les feuilles publiques (bin/_controler-espace.php). */
.bandeau-cookies__texte strong { color: var(--encre); }
@media (max-width: 600px) {
  .bandeau-cookies__premier .bandeau-cookies__actions { flex-wrap: nowrap; gap: 8px; margin-top: 12px; }
  .bandeau-cookies__premier .bandeau-cookies__actions .bouton { flex: 1 1 0; min-width: 0; }
}

/* Revenir sur son choix, depuis n'importe quel écran. Discret par sa taille, pas
 * par sa couleur : un lien de retrait grisé au point de ne plus se voir rendrait
 * le retrait moins simple que l'accord, ce qui est exactement ce qui est interdit. */
.rail-traceurs,
.pied-traceurs {
  background: none; border: 0; padding: 0; cursor: pointer;
  font: inherit; font-size: .78rem; color: var(--encre-3);
  text-decoration: underline; text-underline-offset: 2px;
}
.rail-traceurs { margin: 6px 9px 9px; text-align: left; }
.rail-traceurs:hover,
.pied-traceurs:hover { color: var(--encre); }
.rail-traceurs:focus-visible,
.pied-traceurs:focus-visible {
  outline: 2px solid var(--lien); outline-offset: 2px; border-radius: var(--rayon-xs);
}


/* ─── Le panneau des familles ─────────────────────────────────────────────────
 *
 * Écrit par consentement_bandeau(), commun aux trois documents. Il s'ouvre sous
 * le premier écran, dans le MÊME bandeau : une fenêtre par-dessus donnerait
 * l'impression d'un piège, et le visiteur perdrait de vue le bouton « tout
 * refuser » qu'il cherchait.
 *
 * La liste défile quand elle est longue, plutôt que de pousser les boutons hors
 * de l'écran sur un téléphone : un « tout refuser » qu'on ne peut pas atteindre
 * n'est pas un refus possible.
 */
.cookies-familles {
  list-style: none; margin: 14px 0 0; padding: 0;
  max-height: 46vh; overflow-y: auto;
}
.cookies-famille + .cookies-famille {
  margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--trait);
}
.cookies-famille__tete {
  display: flex; align-items: center; gap: .6rem; cursor: pointer; font-weight: 600;
}
.cookies-famille__tete input { flex: none; width: 1.05rem; height: 1.05rem; cursor: pointer; }
/* Une case qu'on ne peut pas décocher n'est pas un choix : elle doit le DIRE,
 * pas seulement refuser le clic. D'où la mention à côté, et le curseur normal. */
.cookies-famille__tete input:disabled { cursor: default; }
.cookies-famille__nom { flex: 1 1 auto; }
.cookies-famille__marque {
  flex: none; font-size: .72rem; font-weight: 500; text-transform: uppercase;
  letter-spacing: .04em; color: var(--encre-3);
}
.cookies-famille__quoi { margin: .35rem 0 0 1.65rem; }
.cookies-famille__services {
  margin: .25rem 0 0 1.65rem; font-size: .76rem; color: var(--encre-3);
}

/* Le panneau a TROIS boutons là où le premier écran en a deux. Sans cette règle,
 * le troisième passait seul à la ligne, ce qui lui donnait le poids d'une
 * conclusion alors que c'est « Enregistrer mes choix » qui conclut. */
.bandeau-cookies__panneau .bandeau-cookies__actions .bouton { flex: 1 1 7rem; }

/* ═══════════════════════════════════════════════════════════════════════════
   LA BIBLIOTHÈQUE D'IMAGES DU SITE PUBLIC
   ═══════════════════════════════════════════════════════════════════════════

   Une grille de tuiles plutôt qu'un tableau, et c'est le seul écran de la
   console dans ce cas : ce qu'on cherche ici est une IMAGE, et on la reconnaît
   à l'oeil avant de lire son nom. Un tableau à cinq colonnes aurait demandé de
   lire six lignes pour retrouver une photo qu'une vignette montre d'un coup.

   `auto-fill` et non `auto-fit` : à deux images, `auto-fit` les étire sur toute
   la largeur et une photo de bannière occupe alors la moitié de l'écran. */
.grille-medias {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: 18px;
  margin-top: 22px;
}

.media-tuile {
  margin: 0;
  display: flex;
  flex-direction: column;
  background: var(--carte);
  border: 1px solid var(--trait);
  border-radius: var(--rayon);
  overflow: hidden;
}

/* Le rapport est imposé et l'image recadrée dedans : sans cela une photo
   panoramique et un portrait donnent deux tuiles de hauteurs différentes, et la
   grille devient un mur de briques. */
.media-tuile img {
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  display: block;
  background: var(--survol);
  border-bottom: 1px solid var(--trait);
}

.media-tuile figcaption {
  padding: 14px 16px 12px;
  display: grid;
  gap: 4px;
  font-size: .86rem;
}
.media-tuile figcaption b { font-weight: 600; }
.media-tuile figcaption .note { font-size: .8rem; }
/* L'adresse du fichier se copie à la main pour la coller dans un article : elle
   doit donc être sélectionnable en entier, et ne jamais être coupée. */
.media-tuile figcaption code {
  overflow-wrap: anywhere;
  color: var(--encre-3);
  font-size: .76rem;
}

.media-tuile__gestes {
  margin-top: auto;
  padding: 12px 16px 14px;
  border-top: 1px solid var(--trait);
  display: grid;
  gap: 10px;
}
.media-tuile__gestes form { display: flex; gap: 8px; align-items: center; }
.media-tuile__gestes input[type=text] { font-size: .82rem; padding: 8px 10px; }
.media-tuile__gestes .note { margin: 0; font-size: .78rem; }

/* ═══════════════════════════════════════════════════════════════════════════
   L'ÉDITEUR D'ARTICLE
   ═══════════════════════════════════════════════════════════════════════════ */

/* La barre d'outils du corps, SOUDÉE au haut de la zone de texte.
   ─── L'essai abandonné, et ce qui l'a débloqué ──────────────────────────
   Elle devait être collée à la zone de texte, bords communs, comme dans un
   traitement de texte, et l'essai avait été abandonné : `champs_rendre()` rend
   l'étiquette « Le corps » AVEC son champ, donc la barre posée avant le champ se
   retrouvait au-dessus de l'étiquette, et le collage montrait une barre soudée à
   un mot. Le motif d'alors était qu'apprendre à la fonction de rendu qu'un champ
   peut porter une barre compliquerait les quarante écrans qui n'en ont pas.

   La clé `barre` de `champs.php` ne complique aucun écran : absente, elle ne
   fait rien. La barre est donc rendue entre l'étiquette et la zone, et les deux
   ne forment plus qu'un bloc. */
.outils-corps {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 7px;
  padding: 9px 10px;
  background: var(--survol);
  border: 1px solid var(--trait);
  border-bottom: 0;
  border-radius: var(--rayon-s) var(--rayon-s) 0 0;
}
.outils-corps .bouton { background: var(--carte); }
/* La zone du corps est la seule de l'écran où l'on écrit longtemps : elle a droit
   à de la hauteur, et à une chasse fixe qui rend les balises lisibles. */
.outils-corps + textarea {
  min-height: 340px;
  border-radius: 0 0 var(--rayon-s) var(--rayon-s);
  font-family: var(--mono);
  font-size: .84rem;
  line-height: 1.7;
}
/* Le filet du haut appartient à la barre : deux traits superposés font une ligne
   deux fois trop épaisse, et c'est ce qui trahit un collage. */
.outils-corps + textarea:not(:focus) { border-top-color: transparent; }

/* Le choix d'image part à droite : c'est le seul geste de la barre qui demande
   de lire avant de cliquer, et il n'a rien à faire au milieu des balises. */
.outils-corps__image {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 7px;
}
.outils-corps__image select {
  width: auto;
  max-width: 220px;
  padding: 5px 30px 5px 10px;
  font-size: .8rem;
}

/* Le texte à coller dans une IA. En pleine largeur et non tronqué : on le
   sélectionne pour le copier quand le bouton n'est pas disponible. */
.prompt-article {
  margin: 0 0 14px;
  padding: 16px 18px;
  background: var(--survol);
  border: 1px solid var(--trait);
  border-radius: var(--rayon-s);
  font-family: var(--mono);
  font-size: .8rem;
  line-height: 1.6;
  white-space: pre-wrap;
  max-height: 380px;
  overflow-y: auto;
}

/* La couverture, montrée au-dessus du formulaire. Bornée en hauteur : une photo
   de bannière de mille pixels de haut repousserait le formulaire hors de l'écran. */
.couverture-apercu {
  display: block;
  max-width: 340px;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: var(--rayon-s);
  border: 1px solid var(--trait);
}

/* ══ Les listes d'éléments d'un formulaire ═══════════════════════════════════
 *
 * `champs.php` rend une liste (une foire aux questions, un quiz, des puces, des
 * cartes) sur TOUS les écrans qui ont un formulaire. Ces classes vivaient dans
 * `editeur.css`, que seul l'éditeur à trois colonnes charge : la console les
 * servait donc sans bord, sans fond et sans commandes, et la foire aux questions
 * d'un article s'étalait sur trois écrans en champs nus. Trouvé le 16 septembre
 * au soir, et c'est la quatrième classe orpheline de la journée.
 *
 * Une classe rendue par un composant PARTAGÉ appartient à la feuille partagée.
 */

.liste { margin-top: 6px; }
.liste-ligne {
  position: relative;
  border: 1px solid var(--trait);
  border-radius: var(--rayon-s);
  padding: 10px 12px 14px;
  margin: 0 0 10px;
  background: var(--carte);
}
.liste-ligne legend {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: .85rem;
  font-weight: 600;
  color: var(--encre-70);
  padding: 0 6px;
}
.liste-ligne--vide { border-style: dashed; }

/* Le rang et le retrait ne sont pas du contenu : ce sont des commandes. Elles
 * viennent au survol, en haut à droite de la ligne, et ne prennent plus deux
 * lignes de hauteur sur CHACUN des éléments. Sur une liste de trois boutons,
 * c'étaient six lignes de commandes pour six lignes de contenu.
 *
 * Elles restent postées même invisibles : `opacity` et `visibility` ne changent
 * rien à ce qu'un formulaire envoie, contrairement à `display: none` sur lequel
 * le rang serait perdu et l'ordre des éléments avec. */
.liste-ligne-outils {
  position: absolute;
  top: 6px;
  right: 8px;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 3px 6px;
  border-radius: var(--rayon-xs);
  background: var(--carte);
}
.rang { font-size: .8rem; color: var(--encre-50); display: inline-flex; align-items: center; gap: 6px; }
.rang input { width: 54px; padding: 3px 6px; }
.case--retirer { font-size: .85rem; color: var(--encre-70); }

/* La poignée n'est qu'un repère visuel : c'est la ligne entière qui est
   déplaçable, et le glisser-déposer n'est qu'un raccourci des deux flèches. */
.poignee {
  display: inline-flex;
  align-items: center;
  color: var(--trait-fort);
  cursor: grab;
  flex: none;
}
.poignee svg { width: 14px; height: 14px; }

@media (hover: hover) and (pointer: fine) {
  .liste-ligne:hover .poignee { color: var(--encre-3); }
  .liste-ligne-outils {
    opacity: 0;
    visibility: hidden;
    transition: opacity var(--court) var(--sortie), visibility var(--court) linear;
  }
  /* `:focus-within` est le garde-fou du clavier : sans lui, tabuler jusqu'au rang
   * ferait défiler vers une commande qu'on ne voit pas. */
  .liste-ligne:hover > .liste-ligne-outils,
  .liste-ligne:focus-within > .liste-ligne-outils {
    opacity: 1;
    visibility: visible;
  }
}
@media (prefers-reduced-motion: reduce) {
  .liste-ligne-outils { transition: none; }
}

/* Une liste imbriquée, repliée par défaut. Sans cela, le menu du site déployait
 * ses quatre entrées ET leurs sous-menus : sept mille pixels de haut, et la
 * quatrième entrée introuvable. */
.liste-repliable { margin: 6px 0 0; }
.liste-repliable > summary {
  cursor: pointer;
  padding: 8px 10px;
  border: 1px dashed var(--trait);
  border-radius: var(--rayon-s);
  font-size: .9rem;
  font-weight: 500;
}
.liste-repliable > summary:hover { background: var(--fond); }
.liste-repliable[open] > summary { margin-bottom: 8px; }

/* ── Une ligne de liste qui se REPLIE ─────────────────────────────────────
 *
 * Une foire aux questions de vingt paires, c'est quarante champs dépliés : la
 * page fait six écrans de haut, et retrouver la question qu'on vient d'écrire
 * demande de la chercher à la molette. Chaque ligne se referme donc sur son
 * résumé, qui est sa première valeur : la question elle-même.
 *
 * `details` du navigateur, comme partout ailleurs dans ce dépôt : il s'ouvre
 * sans script, au clavier, et un champ replié est TOUJOURS envoyé par le
 * formulaire, contrairement à ce qu'un `display: none` sur un conteneur laisse
 * croire. Rien ne se perd en refermant. */
.liste-ligne--pliante { padding: 0; }
.liste-ligne--pliante > summary {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 12px;
  cursor: pointer;
  font-size: .87rem;
  list-style: none;
  border-radius: var(--rayon-s);
}
.liste-ligne--pliante > summary::-webkit-details-marker { display: none; }
/* Le chevron dit dans quel sens ça s'ouvre. Il tourne, plutôt que de changer de
   dessin : deux glyphes pour un même bouton font chercher lequel est lequel. */
.liste-ligne--pliante > summary::after {
  content: '';
  width: 7px; height: 7px;
  margin-left: auto;
  flex: none;
  border-right: 1.6px solid var(--encre-3);
  border-bottom: 1.6px solid var(--encre-3);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform var(--court) var(--sortie);
}
.liste-ligne--pliante[open] > summary::after { transform: rotate(225deg) translate(-2px, -2px); }
.liste-ligne--pliante[open] > summary { border-bottom: 1px solid var(--trait); border-radius: var(--rayon-s) var(--rayon-s) 0 0; }
@media (hover: hover) and (pointer: fine) {
  .liste-ligne--pliante > summary:hover { background: var(--survol); }
}
.liste-ligne--pliante > summary:focus-visible { outline: 2px solid var(--lien); outline-offset: -2px; }
/* Le rang de la ligne, en tête du résumé : c'est lui qu'on cherche quand on veut
   déplacer une question, et il doit se lire sans ouvrir. */
.liste-ligne__rang {
  flex: none;
  min-width: 20px;
  color: var(--encre-3);
  font-variant-numeric: tabular-nums;
}
/* Le résumé de la ligne : sa première valeur, coupée à une ligne. Une question
   vide dit « à remplir » plutôt que de laisser un blanc qu'on prend pour un
   défaut d'affichage. */
.liste-ligne__resume {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 500;
}
.liste-ligne__resume--vide { color: var(--encre-3); font-weight: 400; font-style: italic; }
.liste-ligne--pliante > .liste-ligne-corps { padding: 4px 12px 14px; }
/* Les commandes d'une ligne pliante sont DANS son corps, pas en surimpression :
   posées en haut à droite, elles recouvraient le résumé, c'est-à-dire la seule
   chose qu'on vient lire quand la ligne est fermée. */
.liste-ligne--pliante > .liste-ligne-corps > .liste-ligne-outils {
  position: static;
  justify-content: flex-end;
  padding: 0 0 8px;
  opacity: 1;
  visibility: visible;
}

/* ── L'écran du blog, refait le 2026-09-16 sur le modèle d'initiative-var ──
 *
 * Ce qui a été repris, et rien d'autre : la barre d'outils (le compte à gauche,
 * l'action à droite), la recherche avec son compteur, le formulaire en carte à
 * deux colonnes, la barre de mise en forme soudée, la bande d'astuce, et le pied
 * de formulaire. Les couleurs, les rayons et les ombres restent ceux d'ici : ce
 * qu'on emprunte est une DISPOSITION, pas une charte.
 */

/* La barre au-dessus d'une liste : ce qu'on compte à gauche, ce qu'on fait à
   droite. Elle existait sur trois écrans sous trois formes différentes. */
.barre-outils {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 0 0 16px;
}
.barre-outils .note { margin: 0; }

/* La recherche instantanée. Le champ, sa loupe, sa croix, et le compte des
   résultats en dessous. Elle est `hidden` dans le source : sans script elle ne
   filtre rien, et un champ qui ne cherche pas est pire qu'un champ absent. */
.recherche { margin: 0 0 16px; }
.recherche[hidden] { display: none; }
.recherche__champ { position: relative; display: flex; align-items: center; }
.recherche__picto {
  position: absolute;
  left: 12px;
  display: inline-flex;
  color: var(--encre-3);
  pointer-events: none;
}
.recherche__picto svg { width: 17px; height: 17px; }
/* La saisie porte son propre calage : la loupe occupe la gauche, la croix la
   droite, et le texte ne doit passer ni sous l'une ni sous l'autre.

   Le sélecteur porte le TYPE en plus de la classe, et ce n'est pas une
   coquetterie : la règle générale des champs est écrite `input[type=search]`,
   dont la spécificité est celle d'une classe plus celle d'un élément. Une classe
   seule perdait, le calage restait à quatorze pixels, et le premier mot tapé
   passait sous la loupe. Vu à l'écran. */
input.recherche__saisie[type=search] { padding-left: 38px; padding-right: 38px; }
.recherche__vider {
  position: absolute;
  right: 8px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px; height: 26px;
  padding: 0;
  border: 0;
  border-radius: var(--rayon-xs);
  background: transparent;
  color: var(--encre-3);
  cursor: pointer;
}
.recherche__vider svg { width: 14px; height: 14px; }
.recherche__vider[hidden] { display: none; }
@media (hover: hover) and (pointer: fine) {
  .recherche__vider:hover { background: var(--survol); color: var(--encre); }
}
.recherche__compte { margin: 8px 0 0; }
.recherche__compte[hidden] { display: none; }

/* Le titre d'une ligne de tableau, et sa seconde ligne. L'adresse sous le titre
   plutôt qu'en colonne : à six colonnes, la table débordait et la colonne qu'on
   perdait était toujours celle de droite. */
.tableau-fort b { display: block; font-weight: 600; }
/* Une date tient sur UNE ligne : coupée en deux, « 2026-05-06 » se lit comme
   deux nombres, et la colonne devient deux fois plus haute que son contenu. */
.tableau td.tableau-mono { white-space: nowrap; }
.tableau-note {
  display: block;
  margin-top: 2px;
  color: var(--encre-3);
  font-size: .82rem;
}

/* L'état d'un article EST son bouton : il se lit et se change au même endroit.
   L'étiquette garde son apparence, elle gagne seulement de quoi se cliquer. */
.etat-bascule { display: inline-flex; }
.etat-bascule button.etiquette {
  border: 0;
  cursor: pointer;
  font: inherit;
  font-size: .78rem;
}
.etat-bascule button.etiquette:focus-visible {
  outline: 2px solid var(--lien);
  outline-offset: 2px;
}
@media (hover: hover) and (pointer: fine) {
  .etat-bascule button.etiquette:hover { filter: brightness(.96); }
}

/* ── Le formulaire d'un article ──────────────────────────────────────────── */

/* Une carte qui contient un formulaire : elle a besoin de son air intérieur, et
   `.carte` seule n'en donne pas assez pour dix-sept champs. */
.carte--formulaire { padding: 26px 28px 0; }

/* Deux colonnes, et ce qui s'écrit longtemps traverse. Empilé, le formulaire
   faisait un écran de haut pour trois mots. */
.formulaire-grille {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 0 22px;
}
.formulaire-grille__large { grid-column: 1 / -1; }

/* Le titre est la seule chose de cet écran qu'on relit à voix haute avant de
   publier : il se lit comme un titre. */
.champ--titre input[type=text] {
  font-size: 1.12rem;
  font-weight: 600;
  padding-top: 11px;
  padding-bottom: 11px;
}

/* La couverture : l'aperçu à gauche, le choix à droite. Une adresse de fichier
   ne dit pas si on a choisi la bonne photo. */
.couverture {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 18px;
  margin-bottom: 18px;
}
.couverture__choix { flex: 1; min-width: 240px; }
.couverture__choix .champ { margin-bottom: 6px; }

/* La bande d'astuce, SOUS la zone de texte : elle sert au moment où l'on cherche
   comment écrire quelque chose, pas avant d'avoir commencé. */
.astuce {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: -8px 0 18px;
  padding: 10px 14px;
  border: 1px solid var(--trait);
  border-top: 0;
  border-radius: 0 0 var(--rayon-s) var(--rayon-s);
  background: var(--survol);
}
.astuce__texte { margin: 0; color: var(--encre-2); font-size: .85rem; max-width: 70ch; }
.astuce code {
  padding: 1px 5px;
  border-radius: 4px;
  background: var(--carte);
  font-family: var(--mono);
  font-size: .95em;
}
.astuce .bouton[hidden] { display: none; }

/* Les articles à lire ensuite. Deux colonnes de cases, bornées en hauteur : à
   vingt articles, la grille prendrait l'écran entier pour cinq choix. */
.lire-aussi {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 6px;
  max-height: 260px;
  overflow-y: auto;
  margin-bottom: 18px;
  padding: 10px;
  border: 1px solid var(--trait);
  border-radius: var(--rayon-s);
  background: var(--survol);
}
.lire-aussi__ligne {
  align-items: flex-start;
  padding: 8px 10px;
  border: 1px solid var(--trait);
  border-radius: var(--rayon-xs);
  background: var(--carte);
}
.lire-aussi__ligne b { display: block; font-weight: 500; font-size: .88rem; }
.lire-aussi__ligne .note { display: block; font-size: .78rem; }

/* Le pied du formulaire : « Annuler » à gauche, l'enregistrement à droite. Il
   colle au bas de la carte et porte son filet, pour qu'on sache que le
   formulaire s'arrête là. */
.formulaire-pied {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 8px -28px 0;
  padding: 18px 28px;
  border-top: 1px solid var(--trait);
}
.formulaire-pied__actions { display: flex; flex-wrap: wrap; gap: 10px; }

/* Une fenêtre plus large que les confirmations : elle porte un formulaire, et
   le texte à coller dans une IA fait quarante lignes. */
.modale--large { width: min(640px, 100%); }
.modale--large .champ:last-of-type { margin-bottom: 8px; }
/* Le voile d'une fenêtre ouverte par le script : `hidden` dans le source, et
   c'est le script qui le retire. Sans lui, ni la fenêtre ni le bouton qui
   l'appelle ne se voient. */
.voile[hidden] { display: none; }

/* Deux gestes en bout de ligne. `flex-end` et non `space-between` : à deux
   boutons de largeurs différentes, l'espacement les décollerait l'un de l'autre
   d'une ligne à l'autre, et la colonne aurait l'air de trembler. */
.actions-ligne {
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
}
.actions-ligne form { display: inline-flex; }

/* ═══════════════════════════════════════════════════════════════════════════
   LE CHOIX D'UN MÉTIER
   ═══════════════════════════════════════════════════════════════════════════

   Cinquante-deux métiers en pastilles plutôt qu'en lignes de tableau. On ne
   compare pas cinquante-deux accroches à l'oeil, on en corrige une : ce qu'on
   cherche est un NOM dans une liste qu'on connaît déjà. Quatre écrans de
   pastilles contre six de lignes, et le nom est au même endroit sur chacune.

   `auto-fill` avec un minimum de 200 px : à trois métiers dans une famille,
   `auto-fit` les étirerait sur toute la largeur et une pastille ferait trente
   centimètres. */
.grille-metiers {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 8px;
  margin-top: 4px;
}

.metier-pastille {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 11px 14px;
  border: 1px solid var(--trait);
  border-radius: var(--rayon-s);
  background: var(--carte);
  color: var(--encre);
  text-decoration: none;
  font-size: .88rem;
  font-weight: 500;
  transition: border-color var(--court) var(--sortie),
              background-color var(--court) var(--sortie);
}
.metier-pastille__nom { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.metier-pastille__etats { display: flex; align-items: center; gap: 5px; flex: none; }
@media (hover: hover) and (pointer: fine) {
  .metier-pastille:hover { border-color: var(--encre-3); background: var(--survol); }
}
.metier-pastille:focus-visible { outline: 2px solid var(--lien); outline-offset: 2px; }
/* Une page non annoncée est servie mais invisible de Google : son nom est en
   gris, comme le reste de l'interface traite ce qui existe sans être publié. */
.metier-pastille--muette .metier-pastille__nom { color: var(--encre-2); }

/* Les points d'état. Ils vivaient dans `editeur.css`, que cet écran ne charge
   pas : trois classes employées hors de leur feuille, donc trois points sans
   couleur ni taille. Même famille de défaut que `.rail-titre` réemployée dans
   le panneau de l'éditeur, trouvée le même jour. */
.pastille {
  display: block;
  width: 7px; height: 7px;
  border-radius: 50%;
  flex: none;
}
.pastille--masquee { background: var(--encre-3); }
.pastille--reseau  { background: var(--jaune); }
.pastille--tiede   { background: var(--attention); }
