/* ==========================================================================
   ARTAWEB — Administration · admin-editeurs.css
   --------------------------------------------------------------------------
   Éditeurs : sélecteur de lien, charte graphique, comptes, grille de composants, répéteur.

   CE FICHIER EST UNE PART D'UN TOUT. `admin.css` faisait 8 026 lignes et
   274 Ko : impossible à parcourir, impossible à situer. Il a été DÉCOUPÉ le
   2026-09-09 — découpé, pas réécrit : la concaténation des cinq parts, dans
   l'ordre où adminStylesheetLinks() les charge, redonne l'original CARACTÈRE
   POUR CARACTÈRE. L'audit le demandait dans ces termes : « le découper, oui ;
   le réécrire, non — le risque dépasse largement le gain ».

   L'ORDRE COMPTE. Ces feuilles se surchargent l'une l'autre ; les charger
   dans un autre ordre change le rendu. Elles sont donc listées en UN seul
   endroit : adminStylesheetLinks(), dans includes/admin-assets.php.
   ========================================================================== */

/* ======================================================================
   SÉLECTEUR DE LIEN
   Le champ (.link-picker) reprend la mise en ligne du champ image ; la
   modale (.link-modal) reprend celle du sélecteur de médias. Rien d'inédit
   ici : seules les particularités du lien sont décrites.
   ====================================================================== */
.link-picker {
    display: flex;
    align-items: center;
    gap: var(--ad-space-3);
    flex-wrap: wrap;
}
/* Le résumé remplace le champ de saisie : c'est LUI qui dit vers quoi pointe
   le lien. Il doit donc rester lisible même long, sans pousser les boutons
   hors de la ligne. */
.link-picker__summary {
    flex: 1 1 12rem;
    min-width: 0;
    overflow-wrap: anywhere;
    font-size: var(--ad-fs-sm);
    color: var(--ad-text);
}
.link-picker__summary--empty { color: var(--ad-text-mute); font-style: italic; }
.link-picker__summary--url   { font-family: var(--ad-font-mono); }
.link-picker__summary--media { overflow-wrap: anywhere; }
.link-picker__actions { display: flex; flex-wrap: wrap; gap: var(--ad-space-2); margin-left: auto; }

.link-modal__panel {
    max-width: 720px;
    display: flex;
    flex-direction: column;
    max-height: 88vh;
    overflow: hidden;                 /* c'est le corps qui défile */
    padding: var(--ad-space-4) var(--ad-space-5);
}
.link-modal__body { flex: 1 1 auto; overflow-y: auto; padding-right: 2px; }
.link-modal__search { width: 100%; margin-bottom: var(--ad-space-3); }

.link-modal__list {
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-r-md);
    background: var(--ad-bg-sunk);
    max-height: 40vh;
    overflow-y: auto;
}
/* Une ligne = une page. Le décalage à gauche est posé par le script (profondeur
   dans l'arborescence) : il n'est pas dans la feuille de style parce qu'une
   RECHERCHE aplatit la liste et le remet à zéro. */
.link-modal__page {
    display: flex;
    align-items: baseline;
    gap: var(--ad-space-2);
    width: 100%;
    padding: 7px 12px;
    border: 0;
    border-bottom: 1px solid var(--ad-border);
    background: none;
    font: inherit;
    text-align: left;
    cursor: pointer;
    color: var(--ad-text);
}
.link-modal__page:last-child { border-bottom: 0; }
.link-modal__page:hover { background: var(--ad-bg-alt); }
.link-modal__page.is-active {
    background: var(--ad-accent, var(--ad-text));
    color: #fff;
}
.link-modal__page-label { font-weight: 550; }
.link-modal__page-path {
    font-size: var(--ad-fs-sm);
    opacity: .7;
    overflow-wrap: anywhere;
}
.link-modal__badge {
    margin-left: auto;
    font-size: var(--ad-fs-xs, 11px);
    text-transform: uppercase;
    letter-spacing: .04em;
    opacity: .75;
}

/* Onglet « Fichier » : les dossiers au-dessus de la liste, et le type du
   fichier poussé à droite de chaque ligne (le badge porte déjà margin-left). */
.link-modal__folders { margin: 0 0 var(--ad-space-3); }
.link-modal__folders:empty { display: none; }
[data-lk-media-list]:empty { display: none; }
[data-lk-media-list] .link-modal__badge { text-transform: none; white-space: nowrap; }

.link-modal__anchors { margin-top: var(--ad-space-4); }
.link-modal__anchors[hidden] { display: none; }
.link-modal__subtitle { font-size: var(--ad-fs-md); font-weight: 600; margin: 0 0 var(--ad-space-1); }
.link-modal__chips { display: flex; flex-wrap: wrap; gap: var(--ad-space-2); margin-top: var(--ad-space-2); }
/* Même pastille que les dossiers de la médiathèque : un choix parmi N, court. */
.link-modal__chip {
    display: inline-flex;
    align-items: center;
    padding: 5px 12px;
    border: 1px solid var(--ad-border);
    border-radius: 999px;
    background: var(--ad-bg);
    color: var(--ad-text);
    font: inherit;
    font-size: var(--ad-fs-sm);
    cursor: pointer;
}
.link-modal__chip:hover { border-color: var(--ad-accent, var(--ad-text)); }
.link-modal__chip.is-active {
    background: var(--ad-accent, var(--ad-text));
    border-color: var(--ad-accent, var(--ad-text));
    color: #fff;
}

.link-modal__foot {
    flex: 0 0 auto;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--ad-space-2);
    margin-top: var(--ad-space-3);
    padding-top: var(--ad-space-3);
    border-top: 1px solid var(--ad-border);
}
/* L'adresse qui sera réellement écrite, en clair : c'est la seule vérification
   possible avant de valider, le champ lui-même ne montrant qu'un libellé. */
.link-modal__preview {
    font-family: var(--ad-font-mono);
    font-size: var(--ad-fs-sm);
    color: var(--ad-text-mute);
    overflow-wrap: anywhere;
}
.link-modal__actions { display: flex; gap: var(--ad-space-2); }
.link-modal__actions .btn[disabled] {
    opacity: .45;
    cursor: not-allowed;
    pointer-events: none;
}

.admin-block {
    background: var(--ad-bg);
    border: 1px solid var(--ad-border);
    border-left: 2px solid var(--ad-lvl4);      /* rail du NIVEAU 4 (composant) */
    border-radius: var(--ad-r-md);
    overflow: hidden;
    box-shadow: var(--ad-shadow-sm);            /* relief : carte « composant » */
}

/* LE MENU DE L'ŒIL DOIT POUVOIR SORTIR DE LA CARTE.
   `overflow: hidden` ci-dessus découpe le contenu sur les coins arrondis et le
   rail de gauche : on ne peut pas le retirer. Mais il coupait aussi le panneau
   de visibilité, qui s'ouvre SOUS l'œil, en position absolue — mesuré sur la
   carte d'un composant Image : un menu de 177 px dont 169 passaient sous le
   bord. Autrement dit invisible, alors que le bouton répondait.
   La coupe se lève le temps que le menu soit ouvert, et revient dès qu'il se
   ferme : les coins restent nets le reste du temps. `:has()` est déjà employé
   par le socle (.admin-alert:has(), .admin-content:has()).
   ⚠️ Seules les cartes de COMPOSANT coupaient — les œils de section et de ligne
   n'ont aucun ancêtre à overflow, vérifié sur les six de l'écran. */
.admin-block:has(.vis-eye.is-open) { overflow: visible; }

/* En cours d'édition. Trois signaux cumulés, les mêmes que pour une page dépliée :
   halo, ombre montée d'un cran, en-tête teinté — plus le rail qui remonte au
   niveau 1, parce que c'est L'élément actif de l'écran.
   Le box-shadow remplace l'ancien outline, désormais réservé au focus clavier
   (.admin-block__toggle:focus-visible) : les deux se superposaient à l'identique.
   Doublement de classe = spécificité (0,2,0), pour ne pas dépendre de l'ordre. */
.admin-block.admin-block--editing {
    border-left-color: var(--ad-lvl1);
    box-shadow: var(--ad-open-ring), var(--ad-shadow-md);
}
.admin-block--editing .admin-block__header { background: var(--ad-open-bg); }

.admin-block__header {
    display: flex;
    flex-wrap: wrap;                /* en colonne étroite (3, 4 colonnes), les boutons passent à la ligne */
    align-items: center;
    gap: var(--ad-space-1) var(--ad-space-2);
    padding: 8px var(--ad-space-3);
    background: var(--ad-bg);                    /* blanc, distinct du fond de ligne */
    border-bottom: 1px solid var(--ad-border);
}

.admin-block__drag {
    cursor: grab;
    color: var(--ad-text-mute);
    font-size: var(--ad-fs-md);
    user-select: none;
    padding: 0 4px;
}
.admin-block__drag:active { cursor: grabbing; }

/* Zone cliquable de l'en-tête : ouvre/ferme l'éditeur du bloc (remplace le bouton « Éditer ») */
.admin-block__toggle {
    flex: 1 1 8rem;                 /* place minimale du nom : en dessous, les actions descendent d'une ligne */
    min-width: 0;
    display: inline-flex;
    align-items: center;
    gap: var(--ad-space-1) 6px;
    flex-wrap: wrap;
    background: none;
    border: 0;
    padding: 4px 6px;
    margin: -4px 0;
    text-align: left;
    cursor: pointer;
    font: inherit;
    color: inherit;
    border-radius: var(--ad-r-sm);
    transition: background var(--ad-trans) ease;
}
.admin-block__toggle:hover { background: var(--ad-bg-sunk); }
.admin-block__toggle:focus-visible { outline: 2px solid var(--ad-accent); outline-offset: 1px; }
.admin-block__chev {
    display: inline-flex;
    flex: 0 0 auto;
    color: var(--ad-text-mute);
    transition: transform var(--ad-trans) ease;
}
.admin-block--editing .admin-block__chev { transform: rotate(180deg); }

/* Nom du type, à droite de la pastille colorée. Plus de cadre : la pastille porte
   désormais l'identité visuelle, un badge encadré par-dessus faisait doublon. */
.admin-block__type {
    font-size: var(--ad-fs-label);
    font-weight: var(--ad-fw-label);
    text-transform: uppercase;
    letter-spacing: var(--ad-ls-label);
    color: var(--ad-text-soft);
    line-height: 1;                 /* sinon la pastille de 22 px fait grandir l'en-tête */
    white-space: nowrap;            /* « TITRE », jamais « TITR » coupé */
}

/* Le niveau de titre RENDU (H1…H6) d'un composant Titre, et le début du contenu d'un
   composant, dans son en-tête (admin/includes/block-apercu.php). L'aperçu prend la place qui
   reste et se tronque : plus l'écran est large, plus on en lit. */
.admin-block__niveau {
    flex: 0 0 auto;
    padding: 2px 6px;
    border-radius: 4px;
    background: var(--ad-bg-sunk);
    color: var(--ad-text);
    font-size: var(--ad-fs-label);
    font-weight: 700;
    line-height: 1;
    letter-spacing: .02em;
}
.admin-block__niveau.is-ecart { background: color-mix(in srgb, var(--ad-accent) 18%, transparent); color: var(--ad-accent); }
.admin-block__niveau.is-muet { opacity: .5; }
.admin-block__apercu {
    flex: 1 1 6rem;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--ad-text-mute);
    font-size: var(--ad-fs-sm);
    font-weight: 400;
}

/* Type du bloc affiché en lecture seule dans le formulaire d'édition */
.admin-block__type-static {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-weight: 600;
    color: var(--ad-text);
}

.admin-block__actions {
    margin-left: auto;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ad-space-1);
}

.admin-block__body { padding: var(--ad-space-4); }

/* --- Pastille de type de composant (blockChip) -----------------------------
   Glyphe SVG blanc sur un fond porté par la CATÉGORIE. Remplace les anciennes
   icônes en caractères texte (H, ¶, ▣, 📄…), dépareillées et à moitié en emoji.
   C'est aussi le marqueur du niveau 4 de la hiérarchie : rien d'autre dans
   l'admin n'a de pastille pleine colorée, la signature est donc sans ambiguïté. */
.block-chip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    background: var(--cat, var(--ad-cat-advanced));
    color: #fff;
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .06);   /* détache la pastille du blanc */
}
.block-chip--sm { width: 22px; height: 22px; border-radius: 6px; margin-right: 2px; }
.block-chip--lg { width: 34px; height: 34px; border-radius: 9px; margin-bottom: 4px; }
.block-chip--sm svg { width: 14px; height: 14px; }
.block-chip--lg svg { width: 20px; height: 20px; }
/* Le trait de 1.75 s'efface sur fond coloré à cette taille : on écrase l'attribut
   de présentation stroke-width porté par le <svg>. */
.block-chip svg { stroke-width: 2; }

/* Le mapping catégorie → teinte est posé une seule fois, sur [data-cat], près du
   picker : il sert à la fois aux pastilles et aux puces de titre de catégorie. */

/* --- Étiquette de niveau (levelTag) ---------------------------------------
   Page (1) > Section (2) > Ligne (3). Le composant n'en porte pas : sa pastille
   colorée le désigne déjà, une étiquette de plus ferait doublon.
   La couleur du niveau est portée par le LISERÉ, jamais par le fond : --ad-lvl3
   est trop délavé pour porter du texte, et --ad-lvl1 suit l'accent de marque,
   qui peut être clair. Le chiffre est donc sur un neutre. */
.lvl-tag {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex: 0 0 auto;
    padding: 2px 9px 2px 7px;
    border: 1px solid var(--ad-border);
    border-left: 3px solid var(--lvl, var(--ad-lvl4));
    border-radius: var(--ad-r-pill);
    background: var(--ad-bg-alt);
    color: var(--ad-text-soft);
    font-size: var(--ad-fs-badge);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .07em;
    line-height: 1.6;
    white-space: nowrap;
}
/* Puce de rang : reprend exactement la puce du fil « Repères » en tête d'écran,
   pour qu'une étiquette de ligne et la légende se lisent comme un seul système.
   Remplace un chiffre de niveau, qui se confondait avec les compteurs voisins
   (« 2 SECTION » à côté de « 2 composants »). */
.lvl-tag__dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--lvl, var(--ad-lvl4));
    flex: 0 0 auto;
}
.lvl-tag--1 { --lvl: var(--ad-lvl1); }
.lvl-tag--2 { --lvl: var(--ad-lvl2); }
.lvl-tag--3 { --lvl: var(--ad-lvl3); }

/* ----------------------------------------------------------
   Block picker (bibliothèque de composants)
   ---------------------------------------------------------- */
.block-picker {
    margin-top: var(--ad-space-5);
    background: var(--ad-bg);
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-r-md);
    padding: var(--ad-space-4);
}

.block-picker__header {
    margin-bottom: var(--ad-space-3);
    padding-bottom: var(--ad-space-3);
    border-bottom: 1px solid var(--ad-border);
}

.block-picker__title {
    font-size: var(--ad-fs-lg);
    font-weight: 600;
    margin: 0 0 2px;
}

.block-picker__sub {
    font-size: var(--ad-fs-sm);
    color: var(--ad-text-mute);
    margin: 0;
}

.block-picker__category {
    margin-bottom: var(--ad-space-4);
}

/* Préfixé `body.admin-body` à dessein : cette étiquette est posée sur un titre,
   et la remise à zéro des titres (`body.admin-body h1…h6 { letter-spacing: 0 }`)
   l'emporterait sinon en spécificité — l'interlettrage serait perdu en silence. */
body.admin-body .block-picker__category-title {
    font-size: var(--ad-fs-label);
    font-weight: var(--ad-fw-label);
    text-transform: uppercase;
    letter-spacing: var(--ad-ls-label);
    color: var(--ad-text-mute);
    margin: 0 0 var(--ad-space-2);
}
/* Puce de la couleur de la famille : le titre de groupe et les pastilles en
   dessous se répondent, on relie le nom de catégorie à sa teinte sans légende. */
.block-picker__category-title::before,
.components-gallery__cat::before {
    content: "";
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 2px;
    margin-right: 7px;
    vertical-align: baseline;
    background: var(--cat, var(--ad-cat-advanced));
}
[data-cat="text"]      { --cat: var(--ad-cat-text); }
[data-cat="action"]    { --cat: var(--ad-cat-action); }
[data-cat="media"]     { --cat: var(--ad-cat-media); }
[data-cat="structure"] { --cat: var(--ad-cat-structure); }
[data-cat="blog"]      { --cat: var(--ad-cat-blog); }
[data-cat="events"]    { --cat: var(--ad-cat-events); }
[data-cat="advanced"]  { --cat: var(--ad-cat-advanced); }

.block-picker__grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(178px, 1fr));
    gap: 8px;
}

/* Démo publique (crochet 5) : un composant fermé, grisé, sa raison en description. */
.block-picker__item.is-ferme { opacity: .6; cursor: not-allowed; filter: grayscale(.6); }
.block-picker__item.is-ferme .block-picker__desc { font-style: italic; }
.block-picker__cadenas svg { width: 13px; height: 13px; vertical-align: -1px; }

.block-picker__item {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 3px;
    padding: 10px 12px;
    background: var(--ad-bg);
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-r-sm);
    text-align: left;
    font: inherit;
    color: var(--ad-text);
    cursor: pointer;
    transition: border-color .12s, background .12s, transform .08s;
    width: 100%;
}

.block-picker__item:hover {
    border-color: var(--ad-accent);
    background: var(--ad-accent-sf);
    transform: translateY(-1px);
}
/* Variante « catalogue » (tableau de bord) : consultation seule, pas d'action. */
.block-picker__item--static { cursor: default; }
.block-picker__item--static:hover { transform: none; }

/* Galerie de composants (tableau de bord), dépliable */
.components-gallery__toggle {
    display: inline-flex;
    align-items: center;
    gap: var(--ad-space-2);
    cursor: pointer;
    font-weight: 650;
    color: var(--ad-text);
    list-style: none;
    padding: 8px 14px;
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-r-sm);
    background: var(--ad-bg);
    transition: border-color var(--ad-trans) ease, background var(--ad-trans) ease;
}
.components-gallery__toggle::-webkit-details-marker { display: none; }
.components-gallery__toggle:hover { border-color: var(--ad-accent); background: var(--ad-accent-sf); }
.components-gallery[open] .components-gallery__toggle { margin-bottom: var(--ad-space-3); }
/* Préfixé `body.admin-body` à dessein : c'est un <h3>, et la remise à zéro des
   titres (`body.admin-body h1…h6 { letter-spacing: 0 }`) l'emporterait sinon en
   spécificité — l'interlettrage était perdu sans que rien ne le signale. */
body.admin-body .components-gallery__cat {
    margin: var(--ad-space-3) 0 var(--ad-space-2);
    font-size: var(--ad-fs-label);
    font-weight: var(--ad-fw-label);
    letter-spacing: var(--ad-ls-label);
    text-transform: uppercase;
    color: var(--ad-text-mute);
}

/* .block-picker__icon a disparu du HTML : l'icône est désormais .block-chip--lg,
   posée par blockChip(). */

.block-picker__label {
    font-size: var(--ad-fs-sm);
    font-weight: 600;
    color: var(--ad-text);
}

.block-picker__desc {
    font-size: var(--ad-fs-xs);
    color: var(--ad-text-mute);
    line-height: 1.35;
}

/* ----------------------------------------------------------
   Media grid
   ---------------------------------------------------------- */
.admin-media-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: var(--ad-space-3);
}

.admin-media-item {
    background: var(--ad-bg);
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-r-sm);
    overflow: hidden;
}

.admin-media-item__preview {
    aspect-ratio: 1;
    overflow: hidden;
    background: var(--ad-bg-sunk);
}

.admin-media-item__preview img {
    width: 100%; height: 100%; object-fit: cover;
}

.admin-media-item__preview--file {
    display: flex; align-items: center; justify-content: center;
    font-size: var(--ad-fs-xl);
    font-weight: 700;
    color: var(--ad-text-mute);
}
.admin-media-item__preview--video { position: relative; }
.admin-media-item__preview--video video { width: 100%; height: 100%; object-fit: cover; }
.admin-media-item__badge {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 22px;
    color: #fff;
    text-shadow: 0 1px 4px rgba(0,0,0,.6);
    pointer-events: none;
}

.admin-media-item__info {
    padding: var(--ad-space-2);
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: var(--ad-fs-xs);
}

.admin-media-item__alt { display: flex; flex-direction: column; gap: 3px; }

/* Chemin cliquable (copie) : dossier discret + nom du fichier mis en avant. */
.admin-media-item__path {
    display: block;
    width: 100%;
    text-align: left;
    background: none;
    border: none;
    padding: 0;
    margin: 0;
    font-family: inherit;
    font-size: var(--ad-fs-xs);
    line-height: 1.35;
    cursor: pointer;
    word-break: break-all;
}
.admin-media-item__dir  { color: var(--ad-text-mute); }
.admin-media-item__base { color: var(--ad-text); font-weight: 700; }
.admin-media-item__path:hover .admin-media-item__base { text-decoration: underline; }
.admin-media-item__path.is-copied::after {
    content: " ✓ copié";
    color: var(--ad-accent, #2e7d32);
    font-weight: 600;
    white-space: nowrap;
}
.admin-media-item__size { color: var(--ad-text-mute); font-size: var(--ad-fs-xs); }

.media-search {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ad-space-2);
    flex: 1 1 320px;
}
.media-search__input { flex: 1 1 200px; min-width: 0; }

.media-viewtoggle {
    display: inline-flex;
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-r-sm);
    overflow: hidden;
}
/* Préfixé `body.admin-body` : sans cela la règle de base (0,2,1) l'emportait
   et le padding défini ici n'était jamais appliqué. */
body.admin-body .media-viewtoggle .btn {
    border: none;
    border-radius: 0;
    margin: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* Icônes seules : hauteur du gabarit normal, largeur réduite. */
    padding: var(--ad-btn-py) var(--ad-btn-px-icon);
    color: var(--ad-text-mute);
}
/* Ces icônes ne portent pas la classe .lt-icon : sans taille imposée elles
   mesurent 18 px et rendent le bouton 2 px plus haut que tous les autres. */
body.admin-body .media-viewtoggle .btn svg {
    display: block;
    width: 16px;
    height: 16px;
}
/* Préfixé comme la règle de base ci-dessus : sans cela `color` y perdait
   (0,3,0 contre 0,3,1) et l'icône restait grise sur le fond vert actif. */
body.admin-body .media-viewtoggle .btn.is-active {
    background: var(--ad-accent, var(--ad-text));
    color: #fff;
}

.media-folders {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ad-space-2);
    margin-bottom: var(--ad-space-3);
}
.media-folder {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 12px;
    border: 1px solid var(--ad-border);
    border-radius: 999px;
    background: var(--ad-bg);
    color: var(--ad-text);
    font-size: var(--ad-fs-sm);
    text-decoration: none;
    white-space: nowrap;
}
.media-folder:hover { border-color: var(--ad-accent, var(--ad-text)); }
.media-folder.is-active {
    background: var(--ad-accent, var(--ad-text));
    border-color: var(--ad-accent, var(--ad-text));
    color: #fff;
}
.media-folder__count {
    font-size: var(--ad-fs-xs);
    font-weight: 700;
    opacity: .7;
}

/* Vue liste : chaque média sur une ligne (aperçu réduit + infos en ligne). */
.media-explorer.is-list .admin-media-grid {
    grid-template-columns: 1fr;
    gap: var(--ad-space-2);
}
.media-explorer.is-list .admin-media-item {
    display: grid;
    grid-template-columns: 56px 1fr;
    align-items: center;
    gap: var(--ad-space-3);
    padding: var(--ad-space-2);
}
.media-explorer.is-list .admin-media-item__preview {
    aspect-ratio: 1;
    width: 56px;
    border-radius: var(--ad-r-sm);
}
.media-explorer.is-list .admin-media-item__info {
    padding: 0;
    display: grid;
    grid-template-columns: minmax(120px, 1fr) auto auto;
    align-items: center;
    gap: var(--ad-space-2);
}
.media-explorer.is-list .admin-media-item__alt {
    flex-direction: row;
    flex-wrap: wrap;
    grid-column: 1 / -1;
}
.media-explorer.is-list .admin-media-item__path { grid-column: 1 / -1; }

@media (max-width: 640px) {
    .media-explorer.is-list .admin-media-item__info {
        grid-template-columns: 1fr;
    }
}

/* ----------------------------------------------------------
   Médiathèque : explorateur (fil d'ariane, tuiles, dépôt de fichiers)
   ---------------------------------------------------------- */
.media-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--ad-space-3);
    margin-bottom: var(--ad-space-3);
}
.media-bar__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: var(--ad-space-2);
    /* Prend l'espace libre : en `0 1 auto`, le conteneur se calait sur une
       largeur trop courte et renvoyait le sélecteur de vue à la ligne. */
    flex: 1 1 auto;
    min-width: 0;
}
/* Tous les contrôles de la barre partagent la même hauteur : sans cela le
   champ de recherche et les menus dépassent les boutons. */
.media-bar__actions > * { margin: 0; }

/* La recherche ne doit pas manger la barre : largeur bornée, pas de flex-grow
   (la règle générique .media-search est en `flex: 1 1 320px`). */
.media-bar .media-search {
    flex: 0 1 180px;      /* 240 px jusqu'au 2026-10-19 : raccourci à la demande de Patrick */
    min-width: 140px;
}
.media-bar .media-search__input { flex: 1 1 auto; width: 100%; }

.media-sort {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
/* BARRE CONDENSÉE (2026-10-19, demande de Patrick) : ni « ? » ni « Trier »
   visibles (libellés lus par les lecteurs d'écran), boutons « + Dossier » et
   « + Fichiers ». Tous les contrôles à la hauteur d'un champ (38 px) : les
   boutons en faisaient 40, le sélecteur de vue 42. Le filtre par emplacement
   prend la largeur de son texte (« — Tout le site — » était coupé à 120 px). */
.media-bar #media-ou { max-width: 190px; width: auto; }
body.admin-body .media-bar__actions > .btn {
    height: var(--ad-field-h);
    min-height: 0;
    padding-block: 0;
}
body.admin-body .media-bar .media-viewtoggle .btn {
    height: calc(var(--ad-field-h) - 2px);   /* + la bordure du groupe = 38 px */
    min-height: 0;                           /* le gabarit des boutons imposait 40 px */
    padding-block: 0;
}

.media-crumbs {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px;
    min-width: 0;
}
.media-crumb {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 8px;
    border-radius: var(--ad-r-sm);
    color: var(--ad-text-soft);
    text-decoration: none;
    font-size: var(--ad-fs-md);
}
.media-crumb:hover { background: var(--ad-bg-alt); color: var(--ad-text); text-decoration: none; }
.media-crumb.is-current { color: var(--ad-text); font-weight: 600; }
.media-crumb svg { width: 16px; height: 16px; }
.media-crumbs__sep { color: var(--ad-text-mute); }

.media-newfolder {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ad-space-2);
    margin-bottom: var(--ad-space-3);
    padding: var(--ad-space-3);
    background: var(--ad-bg-sunk);
    border-radius: var(--ad-r-sm);
}
.media-newfolder[hidden] { display: none; }

/* Zone d'affichage : accepte le dépôt de fichiers sur toute sa surface. */
.media-explorer { position: relative; }
.media-explorer.is-dropping { outline: 2px dashed var(--ad-accent, var(--ad-text)); outline-offset: -6px; }
.media-explorer__drop-hint {
    position: absolute;
    inset: 0;
    display: none;
    align-items: center;
    justify-content: center;
    border-radius: var(--ad-r-md);
    background: color-mix(in srgb, var(--ad-bg) 86%, transparent);
    font-weight: 600;
    text-align: center;
    padding: var(--ad-space-4);
    pointer-events: none;                 /* ne doit pas voler l'événement drop */
    z-index: 3;
}
.media-explorer.is-dropping .media-explorer__drop-hint { display: flex; }

.media-explorer__scope {
    margin-bottom: var(--ad-space-3);
    font-size: var(--ad-fs-sm);
    color: var(--ad-text-mute);
}
.media-explorer__progress {
    height: 6px;
    margin-bottom: var(--ad-space-3);
    background: var(--ad-border);
    border-radius: 999px;
    overflow: hidden;
}
.media-explorer__progress[hidden] { display: none; }
.media-explorer__progress-bar {
    height: 100%;
    width: 0;
    background: var(--ad-accent, var(--ad-text));
    transition: width .15s linear;
}
/* Pages de la liste des médias (120 fiches par page). */
.admin-pager {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: var(--ad-space-3);
    margin-top: var(--ad-space-4);
}
.admin-pager__etat {
    font-size: var(--ad-fs-sm);
    color: var(--ad-text-mute);
}
.media-explorer__errors {
    margin-bottom: var(--ad-space-3);
    color: var(--ad-danger, #c0392b);
    font-size: var(--ad-fs-sm);
}
.media-explorer__errors[hidden] { display: none; }

/* Sélection multiple et barre de traitement par lot. */
.media-batch {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ad-space-3);
    margin-bottom: var(--ad-space-3);
    padding-bottom: var(--ad-space-2);
    border-bottom: 1px solid var(--ad-border);
}
.media-batch__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ad-space-3);
}
.media-batch__actions[hidden] { display: none; }
.media-batch__count { font-size: var(--ad-fs-sm); font-weight: 600; }
.media-batch__move { display: inline-flex; align-items: center; gap: 6px; font-size: var(--ad-fs-sm); }

/* Case de sélection : en surimpression sur la vignette, à l'opposé de la
   poignée de réordonnancement (qui occupe le coin haut-gauche). */
.admin-media-item__pick {
    position: absolute;
    top: 6px;
    right: 6px;
    z-index: 2;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    border-radius: var(--ad-r-sm);
    background: color-mix(in srgb, var(--ad-bg) 82%, transparent);
    border: 1px solid var(--ad-border);
    cursor: pointer;
}
.admin-media-item__pick input { margin: 0; cursor: pointer; }
.admin-media-item.is-picked {
    outline: 2px solid var(--ad-accent, var(--ad-text));
    outline-offset: 1px;
}
/* En vue liste, la case reprend sa place dans le flux, en tête de ligne. */
.media-explorer.is-list .admin-media-item__pick {
    position: static;
    background: none;
    border: none;
    width: auto;
}
.media-explorer.is-list .admin-media-item { grid-template-columns: 24px 56px 1fr; }
.media-explorer.is-list [data-media-reorder] .admin-media-item { grid-template-columns: 24px 24px 56px 1fr; }

/* Compteur d'utilisations, affiché avant toute suppression. Cliquable dès qu'il
   y a au moins un emplacement : il déplie la liste. */
.admin-media-item__used {
    font-size: var(--ad-fs-xs);
    font-weight: 600;
    color: var(--ad-text-soft);
}
button.admin-media-item__used {
    padding: 0;
    border: none;
    background: none;
    font-family: inherit;
    text-align: left;
    text-decoration: underline dotted;
    text-underline-offset: 2px;
    cursor: pointer;
}
button.admin-media-item__used:hover { color: var(--ad-text); }
.admin-media-item__used.is-unused { color: var(--ad-text-mute); font-weight: 400; }

/* Liste des emplacements où le fichier est utilisé. */
.admin-media-item__where {
    margin: 4px 0 0;
    padding-left: 1.1em;
    font-size: var(--ad-fs-xs);
    color: var(--ad-text-soft);
}
.admin-media-item__where[hidden] { display: none; }
.admin-media-item__where li { margin-bottom: 2px; }

/* Renommage en ligne + boutons d'outils de la fiche. */
.admin-media-item__rename {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ad-space-2);
    margin-top: var(--ad-space-2);
}
.admin-media-item__rename[hidden] { display: none; }
.admin-media-item__rename input { flex: 1 1 120px; min-width: 0; }
.admin-media-item__tools {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ad-space-2);
}

/* ---------------------------------------------------------------------------
   Conversion WebP — écran de lot (admin/media-webp.php).
   --------------------------------------------------------------------------- */
.webp-bulk {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ad-space-3, 12px);
    margin-bottom: var(--ad-space-3, 12px);
}
.webp-check { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; }
.webp-count { font-size: var(--ad-fs-xs); color: var(--ad-text-mute); }
.webp-nowrap { white-space: nowrap; }
.webp-table code { font-size: var(--ad-fs-xs); word-break: break-all; }
.webp-table .is-blocked td { color: var(--ad-text-mute); }
.webp-warn {
    display: block;
    margin-top: 2px;
    font-size: var(--ad-fs-xs);
    color: var(--ad-text-soft);
}
/* Damier, comme sur le bandeau de fiche : sans lui, impossible de distinguer
   une transparence préservée d'un aplat blanc. */
.webp-thumb {
    display: block;
    width: 56px;
    height: 40px;
    object-fit: contain;
    background-color: var(--ad-bg);
    background-image:
        linear-gradient(45deg, var(--ad-border) 25%, transparent 25%, transparent 75%, var(--ad-border) 75%),
        linear-gradient(45deg, var(--ad-border) 25%, transparent 25%, transparent 75%, var(--ad-border) 75%);
    background-size: 10px 10px;
    background-position: 0 0, 5px 5px;
}
.webp-pct {
    display: inline-block;
    margin-left: 4px;
    padding: 1px 6px;
    border-radius: 999px;
    background: var(--ad-accent, var(--ad-text));
    color: #fff;
    font-weight: 600;
}
/* Compteur des ORIGINAUX ORPHELINS, à côté de celui des conversions en attente.
   Teinte distincte : « en attente » appelle une décision qu'on a demandée ;
   « à trier » signale des fichiers dont plus personne ne veut et que l'on ignore
   sans le savoir. Deux urgences différentes ne doivent pas se ressembler. */
.webp-pct--orphelins {
    background: var(--ad-warn-bg, #fff4e5);
    color: var(--ad-warn, #9a6200);
}
.webp-details { margin-top: var(--ad-space-3, 12px); }
.webp-details summary { cursor: pointer; color: var(--ad-text-soft); font-size: var(--ad-fs-xs); }

/* Progression du lot. Réutilise le vocabulaire visuel de la zone d'upload. */
.webp-progress { margin-bottom: var(--ad-space-3, 12px); }
.webp-progress[hidden] { display: none; }
.webp-progress__bar {
    height: 6px;
    border-radius: 999px;
    background: var(--ad-bg-alt);
    overflow: hidden;
}
.webp-progress__bar span {
    display: block;
    width: 0;
    height: 100%;
    background: var(--ad-accent, var(--ad-text));
    transition: width .2s ease;
}
.webp-progress__label {
    margin: 4px 0;
    font-size: var(--ad-fs-xs);
    color: var(--ad-text-soft);
}
.webp-log {
    max-height: 16rem;
    overflow-y: auto;
    margin: 0;
    padding-left: 1.1em;
    font-size: var(--ad-fs-xs);
    color: var(--ad-text-soft);
}
.webp-log li { margin-bottom: 2px; }
.webp-log li.is-error { color: var(--ad-danger, #b3261e); }

/* ---------------------------------------------------------------------------
   Conversion WebP — bandeau de décision d'une fiche.
   Affiché tant qu'un original attend en quarantaine : l'état vient du disque,
   donc ce bloc réapparaît après n'importe quel rechargement.
   --------------------------------------------------------------------------- */
.media-webp-decide {
    margin-top: var(--ad-space-2);
    padding: var(--ad-space-2);
    border: 1px solid var(--ad-accent, var(--ad-border));
    border-radius: var(--ad-radius);
    background: var(--ad-accent-sf, var(--ad-bg-alt));
}
.media-webp-decide__gain {
    margin: 0 0 var(--ad-space-2);
    font-size: var(--ad-fs-xs);
    color: var(--ad-text);
}
.media-webp-decide__pct {
    display: inline-block;
    margin-left: 4px;
    padding: 1px 6px;
    border-radius: 999px;
    background: var(--ad-accent, var(--ad-text));
    color: #fff;
    font-weight: 600;
    white-space: nowrap;
}
/* Comparaison avant/après : c'est elle qui permet de juger de la qualité. */
.media-webp-decide__compare {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--ad-space-2);
    margin-bottom: var(--ad-space-2);
}
.media-webp-decide__compare figure { margin: 0; min-width: 0; }
.media-webp-decide__compare img {
    display: block;
    width: 100%;
    height: 72px;
    object-fit: contain;
    /* Damier : sans lui, on ne distingue pas une transparence préservée d'un
       aplat blanc — c'est précisément ce que l'utilisateur doit vérifier. */
    background-color: var(--ad-bg);
    background-image:
        linear-gradient(45deg, var(--ad-border) 25%, transparent 25%, transparent 75%, var(--ad-border) 75%),
        linear-gradient(45deg, var(--ad-border) 25%, transparent 25%, transparent 75%, var(--ad-border) 75%);
    background-size: 12px 12px;
    background-position: 0 0, 6px 6px;
}
.media-webp-decide__compare figcaption {
    margin-top: 2px;
    font-size: var(--ad-fs-xs);
    color: var(--ad-text-mute);
    text-align: center;
}
.media-webp-decide__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ad-space-2);
}

/* Cibles de dépôt d'un fichier : tuiles de dossiers et fil d'ariane. */
[data-media-folder-drop].is-droptarget {
    outline: 2px solid var(--ad-accent, var(--ad-text));
    outline-offset: 1px;
    background: var(--ad-accent-sf, var(--ad-bg-alt));
}
.admin-media-item[draggable="true"] { cursor: grab; }
.admin-media-item[draggable="true"]:active { cursor: grabbing; }
/* Les contrôles internes restent cliquables/sélectionnables normalement :
   la fiche entière est en `grab` (elle se glisse), mais pas ce qu'elle contient. */
.admin-media-item input  { cursor: auto; }
.admin-media-item button { cursor: pointer; }

/* Tuiles de dossiers, façon explorateur de fichiers. */
.media-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: var(--ad-space-3);
    margin-bottom: var(--ad-space-4);
}
.media-tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    padding: var(--ad-space-3);
    background: var(--ad-bg);
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-r-sm);
    color: var(--ad-text);
    text-decoration: none;
    text-align: center;
}
.media-tile:hover {
    border-color: var(--ad-accent, var(--ad-text));
    background: var(--ad-bg-alt);
    text-decoration: none;
}
.media-tile__icon { color: var(--ad-accent, var(--ad-text-mute)); }
.media-tile__icon svg { width: 34px; height: 34px; }
.media-tile__name { font-weight: 600; overflow-wrap: anywhere; }
.media-tile__meta { font-size: var(--ad-fs-xs); color: var(--ad-text-mute); }

/* Vue liste : une tuile de dossier devient une ligne, alignée sur les fichiers
   (icône de 56 px comme leur vignette, puis nom et compteur). */
.media-explorer.is-list .media-tiles {
    grid-template-columns: 1fr;
    gap: var(--ad-space-2);
}
.media-explorer.is-list .media-tile {
    display: grid;
    grid-template-columns: 56px 1fr auto;
    align-items: center;
    gap: var(--ad-space-3);
    padding: var(--ad-space-2);
    text-align: left;
}
.media-explorer.is-list .media-tile__icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 56px;
    height: 56px;
}
.media-explorer.is-list .media-tile__icon svg { width: 26px; height: 26px; }

.media-overrides { margin: 0 0 var(--ad-space-2); padding-left: 1.2em; }
.media-overrides li { margin-bottom: 2px; }

/* Réglage « Ordre d'affichage général » (pilote aussi les galeries du site). */
.media-display__opts {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ad-space-3);
    margin-bottom: var(--ad-space-2);
}

/* Poignée de réordonnancement. En vignettes elle se superpose à l'aperçu ; en
   vue liste elle occupe une colonne dédiée (d'où la grille à 3 colonnes). */
.admin-media-item { position: relative; }
.admin-media-item__drag {
    position: absolute;
    top: 6px;
    left: 6px;
    z-index: 2;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    border-radius: var(--ad-r-sm);
    background: color-mix(in srgb, var(--ad-bg) 82%, transparent);
    border: 1px solid var(--ad-border);
    color: var(--ad-text-mute);
    cursor: grab;
}
.admin-media-item__drag:active { cursor: grabbing; }
.admin-media-item__drag svg { display: block; width: 16px; height: 16px; }

/* La grille du mode réordonnancement est définie plus haut (4 colonnes : case,
   poignée, vignette, infos). Une redéfinition à 3 colonnes vivait ici et
   l'écrasait — la poignée perdait sa colonne. Supprimée le 2026-08-24. */
.media-explorer.is-list .admin-media-item__drag {
    position: static;
    background: none;
    border: none;
}

.admin-media-item.is-droptarget {
    outline: 2px solid var(--ad-accent, var(--ad-text));
    outline-offset: 1px;
}

/* ----------------------------------------------------------
   Empty state
   ---------------------------------------------------------- */
.admin-empty {
    text-align: center;
    color: var(--ad-text-mute);
    padding: var(--ad-space-6);
    font-style: italic;
    background: var(--ad-bg-alt);
    border: 1px dashed var(--ad-border);
    border-radius: var(--ad-r-md);
}

/* ============================================================
   DESIGN SYSTEM PAGE — Charte graphique
   Grille 2 colonnes : contrôles (gauche) / aperçu (droite sticky)
   ============================================================ */

/* ============================================================
   CHARTE GRAPHIQUE — résumé, rubriques, tiroir d'aperçu (2026-10-20)
   ============================================================
   L'écran était une colonne de réglages de 9 700 px à côté d'un aperçu figé.
   Il devient : sept cases qui résument la charte et mènent à leur rubrique,
   des onglets (moteur commun), des rubriques dépliables, et un aperçu rangé
   dans un tiroir derrière une languette au bord droit. */
.design-layout { display: block; }
.design-col--controls { min-width: 0; }

/* Le résumé : une case par grand choix. Toute la case est un bouton. */
.charte-resume {
    list-style: none;
    margin: 0 0 var(--ad-space-4);
    padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
    gap: var(--ad-space-2);
}
.charte-resume > li { margin: 0; min-width: 0; }
.charte-resume__case {
    display: flex;
    flex-direction: column;
    gap: 6px;
    width: 100%;
    height: 100%;
    min-height: 74px;
    padding: 10px 12px;
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-r-md);
    background: var(--ad-bg);
    box-shadow: var(--ad-shadow-sm);
    font: inherit;
    color: var(--ad-text);
    text-align: left;
    cursor: pointer;
    transition: border-color var(--ad-trans) ease, box-shadow var(--ad-trans) ease, transform var(--ad-trans) ease;
}
.charte-resume__case:hover { border-color: var(--ad-border-str); box-shadow: var(--ad-shadow-md); transform: translateY(-1px); }
.charte-resume__case:focus-visible { outline: 2px solid var(--ad-accent); outline-offset: 2px; }
.charte-resume__titre {
    font-size: var(--ad-fs-label);
    font-weight: var(--ad-fw-label);
    letter-spacing: var(--ad-ls-label);
    text-transform: uppercase;
    color: var(--ad-text-soft);
}
.charte-resume__valeur {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 6px;
    min-width: 0;
    font-size: var(--ad-fs-sm);
    line-height: 1.35;
    color: var(--ad-text);
}
.charte-resume__ligne { display: block; width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.charte-resume__ligne--doux { color: var(--ad-text-soft); font-size: var(--ad-fs-xs); }
.charte-resume__pastille {
    width: 18px; height: 18px;
    border-radius: 50%;
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .12);
}
.charte-resume__logo { max-width: 100%; max-height: 28px; width: auto; height: auto; display: block; }
.charte-resume__police { font-size: 17px; line-height: 1.2; }
.charte-resume__verdict--ok     { color: var(--ad-success); font-weight: 600; }
.charte-resume__verdict--alerte { color: var(--ad-warn); font-weight: 600; }

/* Les rubriques dépliables, dans chaque section. */
.charte-rub { border-top: 1px solid var(--ad-border); }
.design-section__body > .charte-rub:first-child { border-top: 0; }
.design-section__body:has(> .charte-rub) { padding: 0; }
.charte-rub__titre {
    display: flex;
    align-items: center;
    gap: var(--ad-space-2);
    padding: 14px 18px;
    font-size: 16px;      /* niveau 2, comme les intertitres de groupe (15 px jusqu'au 2026-10-22) */
    font-weight: 650;
    color: var(--ad-text);
    cursor: pointer;
    list-style: none;
}
.charte-rub__titre::-webkit-details-marker { display: none; }
.charte-rub__titre::after {
    content: "";
    margin-left: auto;
    width: 8px; height: 8px;
    border-right: 2px solid var(--ad-text-mute);
    border-bottom: 2px solid var(--ad-text-mute);
    transform: rotate(45deg) translate(-2px, -2px);
    transition: transform var(--ad-trans) ease;
}
.charte-rub[open] > .charte-rub__titre::after { transform: rotate(-135deg) translate(-2px, -2px); }
.charte-rub__titre:hover { background: var(--ad-bg-alt); }
.charte-rub__titre:focus-visible { outline: 2px solid var(--ad-accent); outline-offset: -2px; }
.charte-rub__corps { padding: 4px 18px 20px; }
/* Atteinte depuis une case du résumé : un bref liseré, pour que l'œil la trouve. */
.charte-rub.is-signalee > .charte-rub__titre { box-shadow: inset 3px 0 0 var(--ad-accent); background: var(--ad-accent-sf); }
.charte-rub, .design-section { scroll-margin-top: calc(var(--ad-header-h) + 16px); }

/* La languette : collée au bord droit, à mi-hauteur. */
.charte-languette {
    position: fixed;
    right: 0;
    top: 50%;
    z-index: 40;
    transform: translateY(-50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    padding: 12px 8px 12px 10px;
    border: 1px solid var(--ad-border-str);
    border-right: 0;
    border-radius: var(--ad-r-md) 0 0 var(--ad-r-md);
    background: var(--ad-bg);
    box-shadow: var(--ad-shadow-md);
    color: var(--ad-accent);
    font: inherit;
    cursor: pointer;
    transition: padding var(--ad-trans) ease, background var(--ad-trans) ease;
}
.charte-languette svg { width: 20px; height: 20px; }
.charte-languette__mot {
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    font-size: var(--ad-fs-xs);
    font-weight: 600;
    letter-spacing: .04em;
    color: var(--ad-text-soft);
}
.charte-languette:hover { padding-right: 12px; background: var(--ad-accent-sf); }
.charte-languette:focus-visible { outline: 2px solid var(--ad-accent); outline-offset: 2px; }
/* LE SCINTILLEMENT : un réglage vient de changer ce que l'aperçu montre. */
.charte-languette.is-nouveau { animation: charte-lueur 1.6s ease-in-out infinite; }
@keyframes charte-lueur {
    0%, 100% { box-shadow: var(--ad-shadow-md), 0 0 0 0 color-mix(in srgb, var(--ad-accent) 0%, transparent); }
    50%      { box-shadow: var(--ad-shadow-md), 0 0 14px 4px color-mix(in srgb, var(--ad-accent) 45%, transparent); }
}
@media (prefers-reduced-motion: reduce) {
    .charte-languette.is-nouveau { animation: none; box-shadow: var(--ad-shadow-md), 0 0 0 3px color-mix(in srgb, var(--ad-accent) 45%, transparent); }
}
.charte.is-apercu-ouvert .charte-languette { opacity: 0; pointer-events: none; }

/* Le tiroir. */
.design-col--preview.charte-tiroir {
    position: fixed;
    top: var(--ad-header-h);
    right: 0;
    bottom: 0;
    z-index: 45;
    width: min(460px, 100vw);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    border-left: 1px solid var(--ad-border);
    background: var(--ad-bg);
    box-shadow: var(--ad-shadow-lg);
    transform: translateX(105%);
    visibility: hidden;
    transition: transform .28s ease, visibility 0s linear .28s;
}
.charte.is-apercu-ouvert .charte-tiroir {
    transform: none;
    visibility: visible;
    transition: transform .28s ease, visibility 0s;
}
@media (prefers-reduced-motion: reduce) {
    .design-col--preview.charte-tiroir, .charte.is-apercu-ouvert .charte-tiroir { transition: none; }
}
.charte-tiroir__fermer {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px; height: 30px;
    border: 0;
    border-radius: var(--ad-r-sm);
    background: transparent;
    color: var(--ad-text-mute);
    cursor: pointer;
}
.charte-tiroir__fermer:hover { background: var(--ad-bg-sunk); color: var(--ad-text); }
.charte-tiroir__fermer svg { width: 18px; height: 18px; }

/* Une version regardée dans le tiroir : le bandeau dit laquelle, et comment revenir. */
.charte-tiroir__version {
    display: flex;
    align-items: center;
    gap: var(--ad-space-2);
    padding: 8px 14px;
    background: var(--ad-accent-sf);
    border-bottom: 1px solid var(--ad-border);
    font-size: var(--ad-fs-sm);
}
.charte-tiroir__version[hidden] { display: none; }
.charte-tiroir__version strong { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Les versions : une grille de mini-cartes. */
.charte-versions {
    list-style: none;
    margin: 0;
    padding: 18px;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: var(--ad-space-3);
}
.charte-carte {
    display: flex;
    flex-direction: column;
    margin: 0;
    min-width: 0;
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-r-md);
    background: var(--ad-bg);
    box-shadow: var(--ad-shadow-sm);
    overflow: hidden;
}
.charte-carte--actuelle { border-color: color-mix(in srgb, var(--ad-accent) 45%, var(--ad-border)); }
/* La charte en petit : MAQUETTE, pas interface — ses tailles sont celles d'une
   page réduite (même exception que .dp-mock). */
.charte-carte__apercu {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-height: 104px;
    padding: 16px 16px 12px;
    border-bottom: 1px solid var(--ad-border);
}
.charte-carte__titre { font-size: 22px; font-weight: 700; line-height: 1.15; }
.charte-carte__texte { font-size: 13px; line-height: 1.4; }
.charte-carte__pastilles { display: flex; gap: 6px; margin-top: auto; padding-top: 8px; }
.charte-carte__pastilles span { width: 22px; height: 10px; border-radius: 5px; }
.charte-carte__pied { display: flex; flex-direction: column; gap: 8px; padding: 12px 14px 14px; flex: 1; }
.charte-carte__nom { margin: 0; font-weight: 600; font-size: var(--ad-fs-md); line-height: 1.3; }
.charte-carte__date { margin: -6px 0 0; font-size: var(--ad-fs-xs); color: var(--ad-text-soft); }
.charte-carte__commentaire { display: flex; gap: 6px; margin: 0; }
.charte-carte__commentaire .admin-form__input { flex: 1; min-width: 0; }
.charte-carte__actions { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-top: auto; }
.charte-carte__actions form { margin: 0; }
.charte-carte__actions form:last-child { margin-left: auto; }
.charte-essai-encours {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 14px;
    margin: 18px 18px 0;
    padding: 10px 14px;
    border-radius: var(--ad-r-md);
    background: var(--ad-warn-sf);
    font-size: var(--ad-fs-sm);
}
.charte-essai-encours form { margin: 0; }
/* La barre des chartes, en tête de l'écran : quelle charte on modifie. */
.charte-barre {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ad-space-2) var(--ad-space-3);
    margin: 0 0 var(--ad-space-4);
    padding: 10px 14px;
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-r-md);
    background: var(--ad-bg);
    box-shadow: var(--ad-shadow-sm);
}
.charte-barre.is-hors-ligne { border-color: color-mix(in srgb, var(--ad-warn) 45%, var(--ad-border)); background: color-mix(in srgb, var(--ad-warn-sf) 45%, var(--ad-bg)); }
.charte-barre__choix { display: flex; align-items: center; gap: var(--ad-space-2); margin: 0; }
.charte-barre__label {
    font-size: var(--ad-fs-label);
    font-weight: var(--ad-fw-label);
    letter-spacing: var(--ad-ls-label);
    text-transform: uppercase;
    color: var(--ad-text-soft);
}
.charte-barre__choix .admin-form__select { min-width: 220px; font-weight: 600; }
.charte-barre__etat {
    padding: 2px 10px;
    border-radius: var(--ad-r-pill);
    font-size: var(--ad-fs-xs);
    font-weight: 600;
    background: var(--ad-success-sf);
    color: var(--ad-success);
}
.charte-barre.is-hors-ligne .charte-barre__etat { background: var(--ad-warn-sf); color: var(--ad-warn); }
.charte-barre__actions { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-left: auto; }
.charte-barre__actions form { margin: 0; }
.charte-barre__pop { position: relative; }
.charte-barre__pop > summary { list-style: none; }
.charte-barre__pop > summary::-webkit-details-marker { display: none; }
.charte-barre__panneau {
    position: absolute;
    right: 0;
    top: calc(100% + 6px);
    z-index: 30;
    display: flex;
    flex-direction: column;
    gap: 6px;
    width: 280px;
    padding: 14px;
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-r-md);
    background: var(--ad-bg);
    box-shadow: var(--ad-shadow-lg);
}
.charte-barre__panneau .btn { align-self: flex-start; margin-top: 4px; }
.charte-barre__note { flex-basis: 100%; margin: 0; font-size: var(--ad-fs-sm); color: var(--ad-text-soft); }

/* Les cartes des chartes. */
.charte-carte.is-editee { outline: 2px solid var(--ad-accent); outline-offset: -1px; }
.charte-carte__badge {
    display: inline-block;
    margin-left: 6px;
    padding: 1px 8px;
    border-radius: var(--ad-r-pill);
    background: var(--ad-success-sf);
    color: var(--ad-success);
    font-size: var(--ad-fs-xs);
    font-weight: 600;
    vertical-align: 2px;
}
.charte-carte__modifier { align-self: flex-start; }
.charte-sauvegardes { margin: 0 18px 18px; border: 1px solid var(--ad-border); border-radius: var(--ad-r-md); }
.charte-versions--petites { padding: 0; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); }
.charte-versions--petites .charte-carte__apercu { min-height: 76px; padding: 10px 12px 8px; }
.charte-versions--petites .charte-carte__titre { font-size: 17px; }

/* « Rien n'est sauvegardé avant Enregistrer » ne concerne pas les versions. */
.charte:has(#sec-versions.is-active) .design-savebar__hint { display: none; }

.design-preview__header {
    display: flex;
    align-items: center;
    gap: var(--ad-space-2);
    justify-content: space-between;
    padding: 10px 14px;
    border-bottom: 1px solid var(--ad-border);
    background: var(--ad-bg-alt);
    font-size: var(--ad-fs-label);
    text-transform: uppercase;
    letter-spacing: var(--ad-ls-label);
    color: var(--ad-text-soft);
    font-weight: var(--ad-fw-label);
    flex-shrink: 0;
}

.design-preview__theme-toggle {
    margin-left: auto;
    display: flex;
    gap: 2px;
    background: var(--ad-bg-sunk);
    padding: 2px;
    border-radius: var(--ad-r-xs);
}
.design-preview__theme-toggle button {
    border: none;
    background: transparent;
    font: inherit;
    font-size: var(--ad-fs-label);
    font-weight: var(--ad-fw-label);
    letter-spacing: var(--ad-ls-label);
    text-transform: uppercase;
    padding: 2px 8px;
    border-radius: 2px;
    cursor: pointer;
    color: var(--ad-text-mute);
}
.design-preview__theme-toggle button.is-active {
    background: var(--ad-bg);
    color: var(--ad-text);
    box-shadow: 0 1px 2px rgba(0,0,0,.08);
}

.design-preview__frame {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding: var(--ad-space-4);
    background: var(--dp-bg, #FAF7F2);
    color: var(--dp-text, #1A1A1A);
    transition: background .15s, color .15s;
}

.design-preview__frame[data-theme="dark"] {
    background: var(--dp-bg-dark, #1A1710);
    color: var(--dp-text-dark, #F0EBE0);
}

.design-preview__logo-wrap {
    padding: 10px 0 18px;
    border-bottom: 1px solid currentColor;
    border-bottom-color: rgba(0,0,0,.08);
    margin-bottom: 18px;
    opacity: .95;
}

.design-preview__logo-wrap img {
    max-width: 160px;
    max-height: 60px;
    width: auto;
    height: auto;
    display: block;
}

.design-preview__frame[data-theme="dark"] .design-preview__logo-wrap img {
    filter: brightness(0) invert(1);
}

.dp-h1, .dp-h2, .dp-h3, .dp-h4, .dp-h5, .dp-h6, .dp-p {
    display: block;
    font-family: var(--dp-font-heading, inherit);
}
/* Les titres de l'aperçu suivent la couleur « Titres » (repli : couleur du texte) */
.dp-h1, .dp-h2, .dp-h3, .dp-h4, .dp-h5, .dp-h6 { color: var(--color-heading, inherit); }
.dp-p { font-family: var(--dp-font-body, inherit); }

/* Color swatches preview row */
/* Aperçu : maquette d'éléments réels.
   Les variables --color-* sont posées sur la frame par admin-design-live.js
   (valeurs du thème courant), donc ces éléments s'adaptent au toggle clair/sombre. */
.dp-mock {
    margin-top: 22px;
    padding-top: 18px;
    border-top: 1px solid var(--color-border, rgba(0,0,0,.1));
}
.dp-mock__card {
    background: var(--color-surface, #f0ebe0);
    border: 1px solid var(--color-border, rgba(0,0,0,.12));
    border-radius: 12px;
    padding: 16px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}
/* MAQUETTE MINIATURE — ne pas appliquer le plancher de 12,5 px ici. Ces règles
   dessinent une page RÉDUITE dans l'écran « Charte graphique » : le 12 px est un
   texte de corps vu en petit, pas un libellé d'interface. L'agrandir détruirait
   ce que la maquette montre. Cf. --ad-fs-badge. */
.dp-mock__title {
    font-weight: 700;
    font-size: 15px;
    color: var(--color-text, #1a1a1a);
    font-family: var(--dp-font-heading, inherit);
}
.dp-mock__muted {
    font-size: 12px;
    color: var(--color-muted, #6b6358);
}
.dp-mock__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 4px;
}
.dp-mock__btn {
    font-size: 12px;
    font-weight: 600;
    padding: 7px 14px;
    border-radius: 8px;
    color: #fff;
    white-space: nowrap;
}
.dp-mock__btn--primary   { background: var(--color-accent, #8b6914); }
.dp-mock__btn--secondary { background: var(--color-secondary, #2c4a6e); }
/* Spécificité renforcée pour battre la règle générique « .admin-main a » (couleur or) */
.design-preview__frame a.dp-mock__link {
    font-size: 12px;
    font-weight: 600;
    color: var(--color-accent, #8b6914);
    text-decoration: none;
    margin-top: 2px;
}
.design-preview__frame a.dp-mock__link:hover { color: var(--color-accent, #8b6914); text-decoration: underline; }

/* L'en-tête de l'aperçu : le logo et un menu dans la police, la taille et la
   casse réglées (variables posées par js/admin-charte.js). */
.dp-entete {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding-bottom: 14px;
    margin-bottom: 18px;
    border-bottom: 1px solid var(--color-border, rgba(0,0,0,.1));
}
/* Un SVG sans dimensions propres vaut 0 px dans une rangée flex : la place du
   logo est donc réservée, pas laissée au contenu. */
.dp-entete .design-preview__logo-wrap { flex: 0 1 150px; min-width: 80px; padding: 0; margin: 0; border: 0; }
.dp-entete .design-preview__logo-wrap img { max-width: 100%; max-height: 44px; }
.dp-menu { display: flex; gap: 12px; flex-wrap: wrap; justify-content: flex-end; }
.dp-menu__lien {
    font-family: var(--dp-font-menu, var(--dp-font-heading, inherit));
    font-size: var(--dp-menu-size, 12px);
    text-transform: var(--dp-menu-case, uppercase);
    letter-spacing: var(--dp-menu-ls, .06em);
    color: var(--color-text, inherit);
    padding-bottom: 3px;
    border-bottom: 2px solid transparent;
}
.dp-menu__lien.is-actif { color: var(--color-accent, inherit); border-bottom-color: var(--dp-nav-rule, var(--color-accent, currentColor)); }
.dp-etiquette {
    display: inline-block;
    margin-bottom: 4px;
    font-size: var(--dp-label-size, .8rem);
    font-weight: var(--dp-label-weight, 600);
    color: var(--dp-label-color, var(--color-accent, inherit));
    letter-spacing: .08em;
    text-transform: uppercase;
    border-bottom: 2px solid var(--dp-label-rule, currentColor);
}
.dp-sombre {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-top: 22px;
    padding: 20px;
    border-radius: 12px;
    background: var(--dp-sombre-fond, #1A1710);
    color: var(--dp-sombre-texte, #F0EBE0);
}
.dp-sombre__titre { font-family: var(--dp-font-heading, inherit); font-size: 18px; font-weight: 700; }
.dp-sombre__texte { font-family: var(--dp-font-body, inherit); font-size: 13px; opacity: .85; }
.dp-sombre__lien { font-size: 12px; font-weight: 600; color: var(--dp-sombre-accent, #E0B860); }
.dp-pied {
    margin-top: 22px;
    padding: 14px 16px;
    border-radius: 8px;
    background: var(--dp-pied-fond, var(--color-text, #1A1A1A));
    color: var(--dp-pied-texte, #fff);
    font-family: var(--dp-font-body, inherit);
    font-size: 12px;
}

/* Controls : rows (dense, grid) */
.design-section {
    background: var(--ad-bg);
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-r-md);
    margin-bottom: var(--ad-space-4);
    overflow: hidden;
}

.design-section__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 10px 14px;
    background: var(--ad-bg-alt);
    border-bottom: 1px solid var(--ad-border);
}

.design-section__title {
    font-size: 20px;      /* niveau 1, comme les titres de carte (admin-socle.css, 2026-10-22) */
    font-weight: 650;
    margin: 0;
    display: flex;
    align-items: center;
    gap: var(--ad-space-2);
}

.design-section__body { padding: var(--ad-space-4) var(--ad-space-4) var(--ad-space-5); }

/* ===========================================================================
   LA CHARTE RESPIRE, ET CHAQUE CHAMP A SA LARGEUR (2026-09-16)
   ===========================================================================
   Trois griefs de Patrick, une seule cause : cette grille était écrite « dense »
   et l'assumait — son commentaire disait « Dense form grid ».

   1. DIX PIXELS ENTRE DEUX RANGÉES. Un champ fait 38 px de haut, l'étiquette
      suivante s'écrit en 13 px : dix pixels entre les deux, c'est moins que
      l'interligne du texte qu'ils encadrent. L'œil ne voyait plus où finissait
      un réglage et où commençait le suivant. L'écart de rangée passe à 22 px,
      celui des colonnes à 20 — l'un et l'autre mesurés sur la hauteur réelle
      des champs, pas choisis au jugé.

   2. TROIS PIXELS ENTRE L'ÉTIQUETTE ET SON CHAMP, ce qui les collait sans les
      lier : à dix pixels de la rangée du dessus, l'étiquette appartenait
      visuellement autant au champ PRÉCÉDENT qu'au sien. Six pixels ici, vingt-
      deux au-dessus : le rapport de un à trois suffit à trancher le groupe.

   3. TOUS LES CHAMPS À 100 %. Deux colonnes égales, et chaque contrôle
      remplissait la sienne — un champ de quatre chiffres aussi large qu'un nom
      de police. La règle est plus bas : un select prend la largeur de ses
      options, un nombre celle de son nombre. */
.design-grid {
    display: grid;
    gap: 22px 20px;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: start;
}

.design-field {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
    /* `stretch` est le défaut d'un conteneur flex : il étirait TOUS les enfants
       à la largeur de la colonne, y compris les contrôles à qui l'on vient de
       demander leur largeur naturelle. C'est lui qui annulait la règle, pas la
       spécificité. */
    align-items: flex-start;
}
/* L'ÉTIQUETTE, PUIS LE CHAMP, PUIS L'EXPLICATION — dans cet ordre.
   Le balisage place l'aide ENTRE le libellé et le contrôle, si bien que le nom
   du réglage se trouvait plus près du champ précédent que du sien : c'est ce qui
   rendait l'écran illisible bien plus que la densité elle-même. On ne touche pas
   au HTML — quarante champs à reprendre —, l'ordre visuel suffit, et il ne
   change rien à l'ordre de lecture d'un lecteur d'écran, qui suit le DOM. */
.design-field > .design-field__label { order: 0; }
.design-field > .design-field__hint  { order: 2; }
.design-field > *                    { order: 1; max-width: 100%; }

/* --- LA LARGEUR SUIT LE CONTENU, PAS LA COLONNE ---------------------------
   Ciblé par TYPE plutôt que par une classe posée sur chacun des quarante
   champs : le type dit déjà la nature de ce qu'on saisit, et une classe de plus
   sur chaque champ serait quarante occasions de l'oublier.

   Un <select> laissé en `width: auto` prend la largeur de son option la plus
   longue — c'est exactement « la largeur de son contenu », et le navigateur la
   calcule mieux que nous. Le `max-width` l'empêche de déborder sa colonne
   quand une option est à rallonge. */
.design-grid select.design-field__input {
    width: auto;
    max-width: 100%;
}
/* Un champ de texte garde sa colonne, mais pas plus : sans cette borne, le
   `flex-start` ci-dessus le réduirait à la largeur de son contenu — c'est-à-dire
   à rien quand il est vide. */
.design-grid input[type="text"].design-field__input,
.design-grid input[type="url"].design-field__input,
.design-grid textarea.design-field__input { width: 100%; }
/* Un nombre : 7,5rem tient six chiffres et les flèches natives. Au-delà, le
   champ promet une saisie qu'il ne recevra jamais. */
/* 11rem : mesuré. Le placeholder de ces champs ne porte plus un tiret mais la
   valeur qui s'applique — « 1280 (selon le choix) » —, et 7,5rem le coupait au
   milieu. Un champ dont l'indication ne se lit pas ne renseigne personne. */
.design-grid input[type="number"].design-field__input { width: 11rem; }
/* Une mesure DÉCIMALE (taille en rem, interligne, interlettrage) : plus court —
   on y écrit « 1.25 ». Le sélecteur vise `step` contenant un point, et non tout
   `step` : les champs en PIXELS en ont un aussi (10 pour la largeur, 4 pour
   l'espacement), et cette règle les rabotait à 104 px alors que la règle
   ci-dessus leur en donnait 176. Deux sélecteurs de même poids, le dernier
   gagnait — sans que rien ne le dise. */
.design-grid input.design-field__input[step*="."] { width: 9.5rem; }
/* Un aplat de couleur n'a aucune raison d'être large : il ne contient rien à
   lire. Il occupait toute la colonne — 345 px mesurés — pour un carré qu'on
   clique. 4,5rem le laisse confortablement cliquable, bien au-delà de la cible
   tactile du critère WCAG 2.5.8. */
.design-grid input[type="color"].design-field__input {
    width: 4.5rem;
    padding: 3px;
    cursor: pointer;
}
/* Le texte garde toute sa colonne : un nom de police, une adresse ou un slogan
   n'ont pas de longueur prévisible. */
.design-field__label {
    /* NIVEAU 3, le dessin de toutes les étiquettes de l'administration (2026-10-22,
       « aérer les écrans ») : la Charte seule écrivait les siennes en petites
       capitales grises, plus faibles que les champs qu'elles nomment. */
    font-size: var(--ad-fs-sm);
    font-weight: 600;
    color: var(--ad-text);
}
/* MÊME HAUTEUR QUE LES AUTRES CHAMPS (2026-09-16). Cette famille-ci rendait
   35px — texte en `--ad-fs-sm`, 6px de padding, aucun `min-height` —, quand la
   famille `admin-form` en rendait 38 et les listes 30. La Charte graphique en
   aligne 85 à côté de 53 listes : trois hauteurs sur un seul écran.
   Le `min-height` gouverne désormais des deux côtés, et le padding suit la même
   variable que partout. La taille du TEXTE ne bouge pas : elle est plus petite
   ici à dessein, sur un écran qui empile beaucoup de réglages courts. */
.design-field__input {
    width: 100%;
    box-sizing: border-box;
    min-height: var(--ad-field-h);
    padding: var(--ad-field-py) var(--ad-field-px);
    border: 1px solid var(--ad-field-bd);
    border-radius: var(--ad-r-sm);
    background: var(--ad-bg);
    font: inherit;
    font-size: var(--ad-fs-sm);
    /* 1,3 comme la famille `admin-form`, et pour la même raison qu'elle
       documente : sans cela, la hauteur de ligne héritée (1,5) portait le champ
       à 39px et débordait le `min-height` d'un pixel. Un pixel, c'est peu ; sur
       une colonne de quatre-vingts champs, cela se voit. */
    line-height: 1.3;
    color: var(--ad-text);
}
.design-field__input:focus {
    outline: 2px solid transparent; /* la bordure le dit ; le contour reparaît en contraste élevé */
    border-color: var(--ad-accent);
    box-shadow: 0 0 0 3px var(--ad-focus);
}

/* Ligne typo par niveau : étiquette (H1…) + 2 sous-lignes de réglages */
.design-typo-row {
    display: flex;
    align-items: flex-start;
    gap: var(--ad-space-3);
    padding: 10px 0;
    border-top: 1px solid var(--ad-bg-sunk);
}
.design-typo-row:first-of-type { border-top: none; }

.design-typo-row__label {
    flex: 0 0 44px;
    font-weight: 700;
    font-size: var(--ad-fs-md);
    padding-top: 16px;
}

.design-typo-row__lines {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* Sous-ligne : grille de champs */
.design-typo-line {
    display: grid;
    gap: 6px;
}
.design-typo-line--text {
    grid-template-columns: minmax(150px, 2fr) repeat(4, minmax(64px, 1fr));
}
.design-typo-line--box {
    grid-template-columns: repeat(8, minmax(54px, 1fr));
}
/* Espacement avant / après (échelle partagée) : deux menus larges */
.design-typo-line--space {
    grid-template-columns: repeat(2, minmax(120px, 220px));
}
/* Volet « Avancé » : réglages fins repliés par défaut */
.design-typo-advanced {
    margin-top: 2px;
}
.design-typo-advanced > summary {
    cursor: pointer;
    font-size: var(--ad-fs-label);
    font-weight: var(--ad-fw-label);
    color: var(--ad-text-soft, var(--ad-muted));
    text-transform: uppercase;
    letter-spacing: var(--ad-ls-label);
    list-style: none;
    padding: 2px 0;
}
.design-typo-advanced > summary::-webkit-details-marker { display: none; }
.design-typo-advanced > summary::before { content: "▸ "; }
.design-typo-advanced[open] > summary::before { content: "▾ "; }
.design-typo-advanced .design-typo-line--box { margin-top: 6px; }

/* Champ unitaire : mini-label au-dessus du contrôle */
.design-typo-field {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
}
.design-typo-field__label {
    font-size: var(--ad-fs-label);
    font-weight: var(--ad-fw-label);
    color: var(--ad-text-soft);
    text-transform: uppercase;
    letter-spacing: var(--ad-ls-label);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Cellule couleur : sélecteur (couleur du thème / personnalisé) + picker libre */
.design-typo-color {
    display: flex;
    gap: 4px;
    min-width: 0;
}
.design-typo-color__mode {
    flex: 1;
    min-width: 0;
}
.design-typo-color__picker {
    flex: 0 0 32px;
    width: 32px;
    padding: 0;
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-r-xs);
    background: var(--ad-bg);
    cursor: pointer;
    display: none; /* visible uniquement en mode « Personnalisé » */
}
.design-typo-color.is-custom .design-typo-color__picker { display: block; }

/* Color row (light / dark colors) */
.design-colors {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 8px;
}
/* Champs code de l'animation d'intro (HTML/CSS/JS) */
.design-intro-code {
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-r-sm);
    margin-bottom: var(--ad-space-2);
    background: var(--ad-bg);
}
.design-intro-code > summary {
    cursor: pointer;
    padding: 8px 12px;
    font-weight: 650;
    font-size: var(--ad-fs-sm);
    color: var(--ad-text-soft);
}
.design-intro-code[open] > summary { border-bottom: 1px solid var(--ad-border); }
textarea.design-code {
    font-family: var(--ad-font-mono);
    font-size: var(--ad-fs-sm);
    line-height: 1.5;
    tab-size: 2;
    white-space: pre;
    overflow-wrap: normal;
    overflow-x: auto;
    border: none;
    border-radius: 0 0 var(--ad-r-sm) var(--ad-r-sm);
    width: 100%;
    resize: vertical;
}

/* Sous-titre de groupe (Mode clair / Mode sombre) dans l'onglet Couleurs fusionné */
/* Préfixé `body.admin-body` à dessein : cette étiquette est posée sur un titre,
   et la remise à zéro des titres (`body.admin-body h1…h6 { letter-spacing: 0 }`)
   l'emporterait sinon en spécificité — l'interlettrage serait perdu en silence. */
body.admin-body .design-subtitle {
    /* Il nomme un champ ou une petite série (« Texte alternatif (alt) ») : le dessin d'une
       étiquette, niveau 3, et non plus des capitales grises plus faibles que les champs
       (2026-10-22, « aérer les écrans »). */
    margin: var(--ad-rythme-champ) 0 6px;
    font-size: var(--ad-fs-sm);
    font-weight: 600;
    color: var(--ad-text);
}
.design-subtitle:first-child { margin-top: 0; }

/* Générateur de palette (haut de la section Couleurs) */
.palette-gen {
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-radius);
    background: var(--ad-surface-2, var(--ad-surface));
    padding: var(--ad-space-3);
    margin-bottom: var(--ad-space-4);
}
.palette-gen .design-subtitle { margin-top: 0; }
.palette-gen__row {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--ad-space-3);
    margin: var(--ad-space-2) 0;
}
.palette-gen__field { display: flex; flex-direction: column; gap: 4px; }
.palette-gen__label {
    font-size: var(--ad-fs-hint, .82rem);
    font-weight: var(--ad-fw-label, 600);
    color: var(--ad-text-mute);
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.palette-gen__inputs {
    display: inline-flex;
    align-items: center;
    gap: var(--ad-space-2);
    flex-wrap: wrap;
}
.palette-gen__inputs[hidden] { display: none; }
.palette-gen__row .design-color-picker { flex: 0 0 auto; }
.palette-gen__row .design-color-hex { width: 6.5rem; flex: 0 0 auto; }
/* Les trois étapes : un numéro, un titre, un geste. */
.palette-gen__etapes { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--ad-space-3); }
.palette-gen__etape { display: grid; grid-template-columns: 28px 1fr; gap: var(--ad-space-2); align-items: start; }
.palette-gen__etape + .palette-gen__etape { padding-top: var(--ad-space-3); border-top: 1px solid var(--ad-border); }
.palette-gen__num {
    width: 26px; height: 26px; border-radius: 50%;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--ad-text); color: var(--ad-surface);
    font-size: var(--ad-fs-xs); font-weight: 700;
}
.palette-gen__corps { min-width: 0; display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }
.palette-gen__corps > .palette-gen__row { margin: 0; }
.palette-gen__titre { margin: 3px 0 0; font-weight: 650; color: var(--ad-text); }
.palette-gen__actions { display: flex; flex-wrap: wrap; gap: var(--ad-space-2); }
.palette-gen__etat { margin: 0; min-height: 1.3em; font-size: var(--ad-fs-hint, .82rem); color: var(--ad-text-mute); }
.palette-gen__etat.is-modifie { color: var(--ad-warn, #9a6200); font-weight: 600; }

/* L'historique des palettes : trois choix au plus, chacun avec ses pastilles. */
.palette-gen__actions .btn:disabled { opacity: .5; cursor: not-allowed; }
.palette-historique { list-style: none; margin: 2px 0 0; padding: 0; display: grid; gap: 6px; width: 100%; }
.palette-historique[hidden] { display: none; }
.palette-historique__choix {
    display: flex; align-items: center; gap: 10px; width: 100%;
    padding: 6px 10px; border: 1px solid var(--ad-border); border-radius: var(--ad-r-sm);
    background: var(--ad-surface); color: var(--ad-text); font: inherit; font-size: var(--ad-fs-sm);
    text-align: left; cursor: pointer;
}
.palette-historique__choix:hover { border-color: var(--ad-text-mute); }
.palette-historique__choix:focus-visible { outline: 2px solid var(--ad-accent); outline-offset: 2px; }
.palette-historique__pastilles { display: inline-flex; flex: 0 0 auto; border-radius: var(--ad-r-xs); overflow: hidden; box-shadow: inset 0 0 0 1px rgba(18, 22, 31, .18); }
.palette-historique__pastilles span { width: 18px; height: 22px; }

/* Les couleurs du logo, par présence. */
.palette-logo { margin-top: var(--ad-space-2); width: 100%; }
.palette-logo[hidden] { display: none; }
.palette-logo__tete { display: flex; align-items: center; gap: 12px; margin-bottom: 8px; }
.palette-logo__vignette {
    flex: 0 0 auto; display: flex; align-items: center; justify-content: center;
    width: 64px; height: 44px; padding: 6px; border: 1px solid var(--ad-border); border-radius: var(--ad-r-sm); background: #fff;
}
.palette-logo__vignette img { max-width: 100%; max-height: 100%; width: auto; height: auto; display: block; }
.palette-logo__titre { display: block; font-weight: 600; font-size: var(--ad-fs-md); color: var(--ad-text); }
.palette-logo__sous { display: block; font-size: var(--ad-fs-sm); color: var(--ad-text-soft); }
.palette-logo__liste { list-style: none; margin: 4px 0 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 8px; }
.palette-logo__item {
    display: grid; grid-template-columns: 30px 1fr; gap: 4px 8px; align-items: center;
    padding: 6px 8px; border: 1px solid var(--ad-border); border-radius: var(--ad-r-sm); background: var(--ad-surface);
}
.palette-logo__pastille { width: 30px; height: 30px; border-radius: var(--ad-r-xs); box-shadow: inset 0 0 0 1px rgba(18, 22, 31, .18); }
.palette-logo__texte { display: flex; flex-direction: column; line-height: 1.2; min-width: 0; }
.palette-logo__texte strong { font-family: var(--ad-font-mono); font-size: var(--ad-fs-mono); }
.palette-logo__texte small { color: var(--ad-text-mute); font-size: var(--ad-fs-xs); }
.palette-logo__actions { grid-column: 1 / -1; display: flex; gap: 4px; }
.palette-logo__actions .btn { flex: 1 1 0; min-width: 0; justify-content: center; height: auto; min-height: 0; padding: 3px 6px; font-size: var(--ad-fs-xs); line-height: 1.3; }

/* Clair et sombre côte à côte : une ligne par rôle. */
.design-modes { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr) minmax(0, 1fr); border: 1px solid var(--ad-border); border-radius: var(--ad-r-sm); overflow: hidden; }
.design-modes__tete, .design-modes__ligne { display: contents; }
.design-modes__tete > span {
    padding: 8px 10px; background: var(--ad-bg-alt); border-bottom: 1px solid var(--ad-border);
    font-size: var(--ad-fs-label); font-weight: var(--ad-fw-label); letter-spacing: var(--ad-ls-label);
    text-transform: uppercase; color: var(--ad-text-mute);
}
.design-modes__role, .design-modes__cellule { padding: 8px 10px; border-bottom: 1px solid var(--ad-border); min-width: 0; }
.design-modes__ligne:last-child > * { border-bottom: 0; }
.design-modes__role { display: flex; flex-direction: column; gap: 2px; }
.design-modes__cellule { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; border-left: 1px solid var(--ad-border); }
.design-modes__cellule .design-color-hex { width: 6.2rem; }
.design-modes__cellule .contour-derive { flex-basis: 100%; }
/* Le mode sombre se lit sur une teinte à peine plus foncée : l'œil range les
   colonnes sans lire l'en-tête. */
.design-modes__cellule:nth-child(3), .design-modes__tete > span:nth-child(3) { background: color-mix(in srgb, var(--ad-bg-alt) 55%, var(--ad-border)); }
@media (max-width: 720px) {
    .design-modes { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
    .design-modes__role { grid-column: 1 / -1; border-bottom: 0; padding-bottom: 0; }
    .design-modes__tete > span:first-child { display: none; }
    .design-modes__cellule:nth-child(2) { border-left: 0; }
}

/* Couleurs supplémentaires : la ligne est en `display: contents`, que l'attribut
   `hidden` seul ne cache pas. */
.couleurs-sup__ligne[hidden] { display: none; }
.couleurs-sup:not(:has(.couleurs-sup__ligne:not([hidden]))) { display: none; }
.couleurs-sup__nom { max-width: 16rem; }
.couleurs-sup__retirer { align-self: flex-start; margin-top: 4px; }
.couleurs-sup__pied { display: flex; flex-wrap: wrap; align-items: center; gap: var(--ad-space-2); margin: var(--ad-space-2) 0 0; }

/* Lisibilité : la correction automatique. */
.contraste-corriger { display: flex; flex-wrap: wrap; align-items: center; gap: var(--ad-space-2); margin: var(--ad-space-2) 0; }
.contraste-corriger[hidden] { display: none; }
.contraste-corriger .design-color-hint { flex: 1 1 260px; }
.contraste-bilan { margin: 0 0 var(--ad-space-2); font-size: var(--ad-fs-hint, .82rem); color: var(--ad-text-soft); }
.contraste-bilan:empty { display: none; }

.design-color-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 8px;
    background: var(--ad-bg-alt);
    border-radius: var(--ad-r-sm);
    border: 1px solid var(--ad-border);
}

.design-color-picker {
    width: 32px;
    height: 32px;
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-r-xs);
    cursor: pointer;
    padding: 0;
    flex-shrink: 0;
    background: none;
}
.design-color-picker::-webkit-color-swatch-wrapper { padding: 1px; }
.design-color-picker::-webkit-color-swatch {
    border-radius: 2px;
    border: none;
}

.design-color-info {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}
.design-color-label {
    font-size: var(--ad-fs-xs);
    font-weight: 600;
    color: var(--ad-text);
    line-height: 1.2;
}
.design-color-hint {
    font-size: var(--ad-fs-xs);
    line-height: 1.3;
    color: var(--ad-text-mute);
    margin: 0;
}
/* Valeur hexadécimale : en chasse fixe et en majuscules, mais c'est une DONNÉE,
   pas une étiquette — l'interlettrage des étiquettes y nuirait à la lecture. */
.design-color-hex {
    font-family: var(--ad-font-mono);
    font-size: var(--ad-fs-label);
    font-weight: var(--ad-fw-label);
    padding: 2px 5px;
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-r-xs);
    background: var(--ad-bg);
    color: var(--ad-text);
    text-transform: uppercase;
    width: 85px;
}

/* Logo upload */
.design-logo-row {
    display: grid;
    grid-template-columns: 140px 1fr;
    gap: var(--ad-space-4);
    align-items: center;
}
.design-logo-preview {
    border: 1px solid var(--ad-border);
    background: var(--ad-bg-alt);
    border-radius: var(--ad-r-sm);
    height: 80px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 8px;
}
.design-logo-preview img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}
.design-logo-preview--dark {
    background: #0f1218;
}
.design-logo-preview--empty {
    color: var(--ad-text-mute);
    font-size: var(--ad-fs-xs);
    font-style: italic;
}

.design-logo-controls {
    display: flex;
    flex-direction: column;
    gap: var(--ad-space-2);
}

/* Save bar (sticky bottom) */
.design-savebar__hint {
    margin: var(--ad-space-4) 0 0;
    color: var(--ad-text-soft);
    font-size: var(--ad-fs-hint);
}

/* ----------------------------------------------------------
   Responsive
   ---------------------------------------------------------- */
@media (max-width: 900px) {
    /* Les champs des 2 sous-lignes se réorganisent automatiquement */
    .design-typo-line--text,
    .design-typo-line--box {
        grid-template-columns: repeat(auto-fit, minmax(92px, 1fr));
    }
}

@media (max-width: 768px) {
    /* La sidebar passe en volet (voir bloc « max-width: 860px ») — plus de
       rétrécissement à 200px ni de disparition. */
    /* MÊME SÉLECTEUR QUE LA DÉCLARATION D'ORIGINE. Les variables --ad-* vivent
       sur `body.admin-body`, pas sur `:root` : une redéfinition posée sur :root
       est bien lue par la racine, mais le `body` — plus proche de l'élément —
       continue de servir l'ancienne valeur. Mesuré : la racine disait 12px,
       .admin-content en recevait 36. Une déclaration nue dans un @media, elle,
       ne s'appliquerait à rien du tout. */
    body.admin-body,
    body.admin-login-body {
        --ad-content-px: 12px;   /* = --ad-space-3 */
        /* LES DEUX AXES, OU AUCUN. Seul l'horizontal était redéfini ici : le
           rembourrage vertical tombait bien à 12px (ligne suivante) mais aucune
           variable ne le disait, si bien que les barres collantes continuaient
           de remonter de 36px et se cachaient sous l'en-tête. */
        --ad-content-pt: 12px;
    }
    .admin-content { padding: var(--ad-content-pt) var(--ad-content-px); }
    .design-grid {
        grid-template-columns: 1fr 1fr;
    }
}

/* ============================================================
   Multi-utilisateurs : pastilles, badges rôle, palette de couleurs
   ============================================================ */

/* --- Pastille avec initiales (data-color → 8 couleurs de la palette) --- */
/* Initiales d'avatar : majuscules, mais ce n'est PAS une étiquette — c'est un
   glyphe. Il garde donc sa propre graisse, hors de l'échelle des étiquettes. */
.user-pastille {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border-radius: 50%;
    background: #888;
    color: #fff;
    font-size: var(--ad-fs-label);   /* 12,5 px : le plancher, cf. --ad-fs-badge */
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    flex-shrink: 0;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.18);
}
.user-pastille[data-color="#2f5e7d"] { background: #2f5e7d; }
.user-pastille[data-color="#3a7d44"] { background: #3a7d44; }
.user-pastille[data-color="#c2185b"] { background: #c2185b; }
.user-pastille[data-color="#c47b00"] { background: #c47b00; }
.user-pastille[data-color="#7b3f9e"] { background: #7b3f9e; }
.user-pastille[data-color="#00897b"] { background: #00897b; }
.user-pastille[data-color="#b08858"] { background: #b08858; }
.user-pastille[data-color="#2196c4"] { background: #2196c4; }

/* --- Sidebar user block : pastille + nom + rôle --- */
.admin-sidebar__user {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    background: var(--ad-bg-alt);
    border-radius: var(--ad-r-sm);
    /* Plus de marge basse : la déconnexion est ENTRÉE dans ce bloc, il n'y a
       plus de ligne en dessous à décoller. */
    margin-bottom: 0;
}
.admin-sidebar__user-info {
    flex: 1 1 auto;          /* prend l'espace restant → le texte ne s'écrase plus à 0 */
    display: flex;
    flex-direction: column;
    line-height: 1.2;
    min-width: 0;
    /* Un LIEN depuis le chantier 22 (vers « Mon compte ») : il garde l'allure
       d'un bloc d'identité, et ne se souligne qu'au survol. */
    text-decoration: none;
    color: inherit;
    border-radius: var(--ad-r-sm);
}
.admin-sidebar__user-info:hover strong,
.admin-sidebar__user-info:focus-visible strong { text-decoration: underline; }
.admin-sidebar__user-info strong {
    font-size: var(--ad-fs-sm);
    font-weight: 650;
    text-transform: none;    /* nom en casse normale (fin de l'ancien « uppercase ») */
    letter-spacing: 0;
    color: var(--ad-text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.admin-sidebar__user-info small {
    font-size: var(--ad-fs-badge);
    text-transform: none;
    letter-spacing: 0;
    color: var(--ad-text-mute);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* --- Badges de rôle --- */
.role-badge {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 999px;
    font-size: var(--ad-fs-badge);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .05em;
}
.role-badge.role-dev    { background: var(--ad-success-sf); color: var(--ad-success); }
.role-badge.role-admin  { background: var(--ad-accent-sf);  color: var(--ad-accent); }
.role-badge.role-editor { background: var(--ad-border);      color: var(--ad-text-soft); }

/* --- Palette de couleurs (color picker) --- */
.color-picker {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    border: none;
    padding: 0;
    margin: 0;
}
.color-picker .admin-form__label,
.color-picker legend {
    flex-basis: 100%;
    margin-bottom: 4px;
}
.color-swatch {
    position: relative;
    display: inline-block;
    width: 28px;
    height: 28px;
    cursor: pointer;
}
.color-swatch input {
    position: absolute;
    inset: 0;
    opacity: 0;
    cursor: pointer;
    z-index: 1;
}
.color-swatch__dot {
    display: block;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: #ccc;
    border: 2px solid transparent;
    transition: transform 100ms ease, border-color 100ms ease;
}
.color-swatch[data-color="#2f5e7d"] .color-swatch__dot { background: #2f5e7d; }
.color-swatch[data-color="#3a7d44"] .color-swatch__dot { background: #3a7d44; }
.color-swatch[data-color="#c2185b"] .color-swatch__dot { background: #c2185b; }
.color-swatch[data-color="#c47b00"] .color-swatch__dot { background: #c47b00; }
.color-swatch[data-color="#7b3f9e"] .color-swatch__dot { background: #7b3f9e; }
.color-swatch[data-color="#00897b"] .color-swatch__dot { background: #00897b; }

/* Pastille « couleur libre » : l'input color est la pastille visible, le radio masqué */
.color-swatch--custom [data-color-custom-radio] { display: none; }
.color-swatch--custom .color-swatch__free {
    position: static;
    opacity: 1;
    inset: auto;
    width: 28px;
    height: 28px;
    padding: 0;
    border: 2px dashed var(--ad-border-str);
    border-radius: 50%;
    background: none;
    cursor: pointer;
}
.color-swatch--custom .color-swatch__free::-webkit-color-swatch-wrapper { padding: 2px; }
.color-swatch--custom .color-swatch__free::-webkit-color-swatch { border: none; border-radius: 50%; }
.color-picker__used {
    flex-basis: 100%;
    margin-top: 4px;
    font-size: var(--ad-fs-sm);
    color: var(--ad-text-soft);
}
.color-picker__used code {
    background: var(--ad-bg-sunk);
    padding: 1px 5px;
    border-radius: var(--ad-r-xs);
}
.color-swatch[data-color="#b08858"] .color-swatch__dot { background: #b08858; }
.color-swatch[data-color="#2196c4"] .color-swatch__dot { background: #2196c4; }
.color-swatch:hover .color-swatch__dot { transform: scale(1.08); }
.color-swatch input:checked + .color-swatch__dot {
    border-color: var(--ad-text);
    box-shadow: 0 0 0 2px var(--ad-bg);
}
.color-swatch input:focus-visible + .color-swatch__dot {
    outline: 2px solid var(--ad-accent);
    outline-offset: 2px;
}
.color-swatch.is-taken {
    cursor: not-allowed;
    opacity: 0.35;
}
.color-swatch.is-taken .color-swatch__dot { transform: none; }
.color-swatch.is-taken::after {
    content: '';
    position: absolute;
    inset: 13px 4px;
    height: 2px;
    background: var(--ad-text);
    transform: rotate(-45deg);
    border-radius: 1px;
}

/* --- Page Utilisateurs : table & inline forms --- */
.admin-table--users { table-layout: auto; }
.admin-table--users td { vertical-align: middle; }
/* Garde le <td> en cellule de tableau (centrage vertical natif via vertical-align).
   Les boutons sont disposés en inline-block pour rester centrés sur la ligne. */
.admin-table__actions { vertical-align: middle; white-space: nowrap; }
.admin-table__actions > * { vertical-align: middle; }
.admin-table__actions > * + * { margin-left: 6px; }

/* .admin-inline-form était stylée DEUX fois : ici en `inline-block` avec des
   règles `> summary` et `[open]` héritées d'une version en <details> repliable,
   et plus bas en `inline-flex`. La seconde gagnait, donc `position: relative`
   était perdue — sans conséquence, puisque `.admin-inline-form__body` (le
   panneau absolu qui en dépendait) n'existe plus dans aucun gabarit.
   Bloc mort supprimé le 2026-08-24 ; la définition vivante est plus bas. */
.admin-inline-delete { display: inline-block; }

/* --- Ligne d'édition pleine largeur (Utilisateurs) --- */
.admin-edit-row > td {
    padding: 0;
    background: var(--ad-bg-alt);
    border-top: 2px solid var(--ad-accent);
}
.admin-edit-row__grid {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
    gap: var(--ad-space-5);
    align-items: start;
    padding: var(--ad-space-4) var(--ad-space-4);
}
.admin-edit-row__pw {
    border-left: 1px solid var(--ad-border);
    padding-left: var(--ad-space-5);
}
.admin-edit-row .color-picker { margin-top: var(--ad-space-3); }
@media (max-width: 768px) {
    .admin-edit-row__grid { grid-template-columns: 1fr; gap: var(--ad-space-4); }
    .admin-edit-row__pw {
        border-left: none;
        border-top: 1px solid var(--ad-border);
        padding-left: 0;
        padding-top: var(--ad-space-4);
    }
}

/* --- Ligne de form en colonnes --- */
.admin-form__row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: var(--ad-space-3);
}

/* --- Helpers --- */
.admin-muted { color: var(--ad-text-mute); font-size: var(--ad-fs-sm); }

/* ============================================================
   Éditeur « Grille de composants » (card-grid)
   ============================================================ */
.card-editor__items {
    display: flex;
    flex-direction: column;
    gap: var(--ad-space-3);
    margin: var(--ad-space-3) 0;
}
/* Grille des paramètres du card-grid (Colonnes / Fond / Titre / Texte) */
.card-editor__params {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--ad-space-3);
    margin-bottom: var(--ad-space-3);
}
.card-param { display: flex; flex-direction: column; gap: 4px; }
@media (max-width: 700px) { .card-editor__params { grid-template-columns: repeat(2, 1fr); } }

/* Sélecteur de couleur : les OPTIONS en pastilles, l'ÉTAT en toutes lettres.
   Les pastilles seules se confondaient — « Défaut » et la couleur courante
   portent le même carré barré, « Noir » et le bouton de couleur libre le même
   carré noir. On empile donc : la rangée d'options, puis le nom de ce qui est
   retenu. */
.admin-swatch-picker { display: flex; flex-direction: column; gap: 6px; align-items: flex-start; }
.admin-swatch__rangee { display: flex; align-items: center; gap: var(--ad-space-2); flex-wrap: wrap; }
.admin-swatch__palette { display: inline-flex; gap: 3px; flex-wrap: wrap; }
.admin-swatch {
    width: 22px; height: 22px;          /* 18 → 22 : la cible tenait mal au doigt */
    border: 1px solid var(--ad-border);
    border-radius: 3px;
    cursor: pointer;
    padding: 0;
    background-size: cover;
    transition: transform var(--ad-trans, .12s) ease;
}
.admin-swatch:hover { transform: scale(1.15); }
.admin-swatch.is-selected { outline: 2px solid var(--ad-accent); outline-offset: 1px; }
.admin-swatch:focus-visible { outline: 2px solid var(--ad-accent); outline-offset: 2px; }

/* « Autre… » : un carré de couleur SUIVI de son libellé. Le carré seul, posé
   avant la palette, se lisait comme une douzième option — et comme la même que
   « Noir », puisque le navigateur rend un input vide en noir. */
.admin-swatch__libre {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 2px 8px 2px 3px;
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-r-sm);
    cursor: pointer;
    font-size: var(--ad-fs-xs);
    color: var(--ad-text-mute);
    white-space: nowrap;
}
.admin-swatch__libre:hover { border-color: var(--ad-accent); color: var(--ad-text); }
.admin-swatch__libre input[type="color"] {
    width: 22px; height: 22px;
    padding: 0;
    border: 1px solid var(--ad-border);
    border-radius: 3px;
    cursor: pointer;
    background: none;
}
/* Le nom de ce qui est retenu — la seule chose qui ne se confond avec rien. */
.admin-swatch__nom {
    margin: 0;
    font-size: var(--ad-fs-xs);
    color: var(--ad-text-mute);
}
.admin-swatch__nom strong { color: var(--ad-text); font-weight: 600; }
.card-item {
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-r-md);
    padding: var(--ad-space-3);
    background: var(--ad-bg-alt);
}
.card-item__media {
    margin-bottom: var(--ad-space-3);
    display: flex;
    flex-direction: column;
    gap: var(--ad-space-1);
}
.card-item__langs { margin-top: var(--ad-space-2); }
.card-item__lang { display: none; flex-direction: column; gap: var(--ad-space-1); }
.card-item__lang.is-active { display: flex; }

/* Onglets de langue du card-grid (FR / EN / ES) */
/* Onglets de langue des éditeurs « cartes », « répéteur » et « horaires ».
   Ils gardent leur MÉCANIQUE propre (leurs panneaux vivent dans les éléments
   répétés, pas à côté des onglets — cf. js/admin.js), mais plus leur apparence :
   même gabarit et même noir que .admin-lang-tab, pour qu'un même geste se
   reconnaisse d'un éditeur à l'autre. */
.card-lang-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 2px;
    width: fit-content;
    padding: 2px;
    background: var(--ad-bg-sunk);
    border-radius: var(--ad-r-sm);
    margin: var(--ad-space-3) 0 var(--ad-space-2);
}
.card-lang-tab {
    padding: 6px 14px;
    border: none;
    background: transparent;
    border-radius: var(--ad-r-xs);
    cursor: pointer;
    font-weight: var(--ad-fw-label);
    font-size: var(--ad-fs-label);
    text-transform: uppercase;
    letter-spacing: var(--ad-ls-label);
    color: var(--ad-text-soft);
    transition: background .12s ease, color .12s ease;
}
.card-lang-tab:hover { color: var(--ad-text); background: rgba(0,0,0,.05); }
.card-lang-tab.is-active,
.card-lang-tab.is-active:hover {
    background: var(--ad-text);
    color: #fff;
}
.card-item__foot {
    margin-top: var(--ad-space-3);
    text-align: right;
}

/* ============================================================
   Éditeur « répéteur » (galerie, chiffres clés, FAQ, liste à icônes)
   ============================================================ */
.fields-editor .admin-form__group:last-child { margin-bottom: 0; }
/* Réglages de niveau bloc (ex. carrousel : défilement auto + intervalle) */
.repeater-editor__block-fields {
    display: flex;
    flex-wrap: wrap;
    /* LES RÉGLAGES S'ALIGNENT PAR LE HAUT, PAS PAR LEUR MILIEU.
       `center` centrait chaque champ par rapport à ses voisins de la même
       ligne. Or ils n'ont pas la même hauteur : celui qui porte une aide de
       deux lignes est plus grand, et le centrage décalait alors TOUS les
       autres — étiquette et contrôle compris. Signalé par Patrick le
       2026-09-18 sur l'éditeur du Slider : « les champs ne sont pas alignés à
       cause des textes d'aide en dessous ».
       La cause n'était pas la présence des aides mais ce centrage : par le
       haut, chaque champ part du même bord — voir la pile explicite juste
       après, qui fait tomber les contrôles à la même hauteur. */
    align-items: flex-start;
    gap: var(--ad-space-3) var(--ad-space-4);
    padding: var(--ad-space-3);
    margin-bottom: var(--ad-space-3);
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-r-md);
    background: var(--ad-bg-sunk, var(--ad-bg));
}
/* UN RÉGLAGE EST UNE PILE EXPLICITE : ÉTIQUETTE, CONTRÔLE, AIDE.
   ============================================================
   `.admin-form__inline-field` est un `inline-flex` qui REPLIE. Étiquette et
   contrôle tenaient donc côte à côte quand la place le permettait, et passaient
   l'un sous l'autre sinon — au gré de la longueur du libellé et de la largeur
   de la fenêtre. Chaque champ avait ainsi sa propre hauteur interne, sans que
   personne l'ait décidé, et les contrôles d'une même ligne ne tombaient pas à
   la même hauteur : jusqu'à 40 px d'écart, mesurés sur l'éditeur du Slider.

   Trois rangées nommées suppriment le hasard. `1fr` sur la troisième laisse
   l'aide occuper ce qui reste sans pousser les deux premières, et
   `align-content: start` garde les hauteurs naturelles quand l'aide manque.

   Mesuré sur un banc reprenant le balisage réel — écart entre les contrôles
   d'une même ligne :
     · « Mise en page du contenu » : 40 px → 0
     · « Voile et lisibilité »     : 30 px → 0

   PORTÉE VOLONTAIREMENT ÉTROITE : `>` et le conteneur nommé. La même classe
   sert ailleurs (filtres du blog, lignes de liens, sélecteur de dossier) avec
   d'autres attentes — on ne réforme pas ce qu'on n'a pas mesuré. */
.repeater-editor__block-fields > .admin-form__inline-field {
    display: grid;
    grid-template-rows: auto auto 1fr;
    align-content: start;
    row-gap: var(--ad-space-2);
}

/* INTERTITRE DE FAMILLE (clé `group` au registre des composants).
   `flex-basis: 100%` lui donne son rang à lui : les réglages qui suivent
   repartent donc à la ligne, sous leur nom. C'est ce qui transforme une bande
   de huit contrôles qui repliaient au hasard de la largeur en trois familles
   qu'on lit — image, voile, défilement.
   Le premier ne prend pas de marge haute : il touche déjà le bord du cadre. */
.repeater-editor__legend {
    flex-basis: 100%;
    margin-top: var(--ad-space-2);
    font-size: var(--ad-fs-xs);
    font-weight: 600;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--ad-text-mute);
}
.repeater-editor__legend:first-child { margin-top: 0; }

/* ------------------------------------------------------------------
   [hidden] : normalisation OBLIGATOIRE
   Le navigateur applique « display: none » à [hidden] via sa feuille par
   défaut, mais TOUTE règle d'auteur posant un `display` (flex, grid, block…)
   sur le même élément l'emporte — et l'élément reste visible malgré l'attribut.
   Ce piège a déjà masqué deux bugs (champs de cible du répéteur de boutons,
   onglets de sections). On tranche ici une fois pour toutes.
   ------------------------------------------------------------------ */
[hidden] { display: none !important; }

/* Un réglage de composant : son libellé, son contrôle, et — depuis le
   2026-09-11 — l'aide qui dit ce que l'exploitant ne peut pas deviner.
   `flex-wrap` est ce qui fait passer cette aide SOUS le champ plutôt qu'à sa
   droite, où elle repoussait les réglages suivants hors de vue. */
.admin-form__inline-field {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ad-space-2);
    max-width: 32rem;
}
.admin-form__inline-field input { width: 6rem; }
.admin-form__inline-field .admin-form__hint {
    flex-basis: 100%;   /* toute la largeur du réglage : l'aide passe dessous */
    margin: 0;
    line-height: 1.45;
}

/* UN MENU DÉROULANT DE COMPOSANT MONTRE UN MODE, PAS UN NOMBRE.
   Ces `<select>` héritaient de `admin-form__input--small`, plafonné à 120px :
   « Les points saisis ici » y était tronqué, et l'exploitant ne pouvait donc
   pas lire ce qu'il venait de choisir — sur le réglage qui commande tous les
   autres. On leur rend la largeur de leur contenu, sans dépasser le cadre. */
.repeater-editor__block-fields select.admin-form__input--small {
    max-width: min(100%, 24rem);
}

/* ----- Panneau « Mise en forme » d'un bloc (admin/blocks.php) ----- */
.block-fx-panel {
    margin-top: var(--ad-space-4);
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-r-md);
    background: var(--ad-bg-sunk, var(--ad-bg));
}
.block-fx-panel__summary {
    cursor: pointer;
    padding: var(--ad-space-3);
    font-weight: 600;
    list-style: none;
}
.block-fx-panel__summary::-webkit-details-marker { display: none; }
.block-fx-panel__summary::before { content: "▸ "; color: var(--ad-muted); }
.block-fx-panel[open] .block-fx-panel__summary::before { content: "▾ "; }
.block-fx-panel__grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: var(--ad-space-3);
    padding: 0 var(--ad-space-3) var(--ad-space-3);
}
.block-fx-panel__grid .admin-form__inline-field {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: var(--ad-space-1, 0.25rem);
}
.block-fx-panel__grid .admin-form__inline-field > span {
    font-size: 0.85em;
    color: var(--ad-muted);
}
.block-fx-panel__grid select { width: 100%; }
.block-fx-panel .admin-form__hint { padding: 0 var(--ad-space-3) var(--ad-space-3); }

/* ----- Constructeur de formulaires (admin/forms.php) ----- */
/* Les champs coulent comme sur le site : chaque champ occupe sa largeur réelle
   (100/75/50/25 %) et se replie en « chip ». Un clic ouvre l'éditeur, et le champ
   ouvert passe alors en pleine largeur pour laisser la place aux réglages. */
/* LA LISTE EST UNE GRILLE DE 60 COLONNES (js/form-builder.js, refreshLayout) : chaque carte occupe `--fb-span`
   colonnes. Une LIGNE de colonnes ouvre une bande ; les champs qui la suivent s'y rangent aux proportions de la
   ligne, comme sur le site. 60 est divisible par toutes les sommes de proportions (2, 3, 4, 5, 10). */
.fb-fields { display: grid; grid-template-columns: repeat(60, minmax(0, 1fr)); gap: var(--ad-space-2); margin: var(--ad-space-3) 0; align-items: start; }
.fb-field { grid-column: span var(--fb-span, 60); min-width: 0; border: 1px solid var(--ad-border); border-radius: var(--ad-r-md); background: var(--ad-bg); overflow: hidden; container-type: inline-size; }
.fb-field.is-open { grid-column: 1 / -1; border-color: var(--ad-accent); box-shadow: var(--ad-shadow-sm); }
/* LA LIGNE : une bande, toujours ouverte (ses réglages SONT sa bande), qui annonce ses colonnes. */
.fb-field[data-fb-role="row"] { grid-column: 1 / -1; background: color-mix(in srgb, var(--ad-accent) 7%, var(--ad-bg)); border: 1px dashed var(--ad-accent); border-left: 4px solid var(--ad-accent); margin-top: var(--ad-space-2); }
.fb-field[data-fb-role="row"] .fb-field__summary { cursor: default; padding-block: 6px; }
.fb-field[data-fb-role="row"] .fb-field__summary:hover { background: none; }
.fb-field[data-fb-role="row"] .fb-field__chev,
.fb-field[data-fb-role="row"] [data-fb-insert-after],
.fb-field[data-fb-role="row"] [data-fb-typewrap],
.fb-field[data-fb-role="row"] .fb-field__tabs { display: none; }
.fb-field[data-fb-role="row"] .fb-field__editor { padding-block: 0 var(--ad-space-2); border-top: 0; }
.fb-field[data-fb-role="row"].is-open { box-shadow: none; }
/* Les champs d'une ligne : un liseré à la teinte de la bande les y rattache. */
.fb-field[data-fb-role="in-row"] { border-left: 3px solid color-mix(in srgb, var(--ad-accent) 55%, transparent); }
/* LES CONTENEURS (js/form-builder.js, emboiter) : étape, groupe et ligne CONTIENNENT visuellement leurs champs, comme une
   section contient ses lignes. La liste enregistrée reste à plat ; seule la vue est emboîtée. */
.fb-box { --fb-box-c: var(--ad-border); grid-column: 1 / -1; display: flex; flex-direction: column; gap: var(--ad-space-2); min-width: 0;
          padding: var(--ad-space-2); border: 1px solid var(--fb-box-c); border-radius: var(--ad-r-lg, 12px);
          background: color-mix(in srgb, var(--fb-box-c) 6%, var(--ad-bg)); }
.fb-box--step  { --fb-box-c: color-mix(in srgb, var(--ad-text) 45%, var(--ad-bg)); border-width: 2px; }
.fb-box--group { --fb-box-c: var(--ad-accent); }
.fb-box--row   { --fb-box-c: color-mix(in srgb, var(--ad-accent) 55%, var(--ad-bg)); border-style: dashed; }
/* STRUCTURE EXPLICITE : une ligne contient des COLONNES, et une colonne EMPILE ce qu'on y pose. La grille de la ligne
   suit ses proportions (js/form-builder.js, relayout() pose `grid-template-columns` en ligne). */
.fb-box--col   { --fb-box-c: color-mix(in srgb, var(--ad-text) 28%, var(--ad-bg)); border-style: dotted; background: var(--ad-bg); padding: var(--ad-space-1, 4px) var(--ad-space-2); }
.fb-box--col { grid-column: auto; }   /* une colonne occupe SA piste de la grille de la ligne, pas toute la ligne */
.fb-box--col > .fb-box__body { display: flex; flex-direction: column; align-items: stretch; gap: var(--ad-space-2); }
.fb-box--col > .fb-box__body > .fb-field { grid-column: auto; }
.fb-col__tete { font-size: var(--ad-fs-sm); color: var(--ad-text-mute); padding: 2px 2px 0; }
/* La zone « hors de cet encadré » n'existe que pendant un glissement. */
.fb-box__sortie { display: none; }
.fb-fields.is-dnd .fb-box__sortie { display: block; margin-top: 6px; padding: 6px; text-align: center; border: 2px dashed var(--ad-border); border-radius: var(--ad-r-md); color: var(--ad-text-mute); font-size: var(--ad-fs-sm); }
.fb-fields.is-dnd .fb-box__sortie.is-drag-into { border-color: var(--ad-accent); background: color-mix(in srgb, var(--ad-accent) 12%, transparent); outline: none; }
.fb-box.is-folded > .fb-box__sortie { display: none; }
/* L'en-tête du conteneur est sa propre carte : elle perd son cadre, le conteneur lui en donne un. */
/* L'attribut `data-fb-struct` porte déjà un fond et un trait (étape) : on le surcharge ici, à spécificité égale. */
.fb-box > .fb-field,
.fb-box > .fb-field[data-fb-struct],
.fb-box > .fb-field[data-fb-struct="step"] { grid-column: auto; width: 100%; margin: 0; border: 0; border-radius: var(--ad-r-md);
          background: color-mix(in srgb, var(--fb-box-c) 14%, var(--ad-bg)); box-shadow: none; }
.fb-box > .fb-field.is-open { box-shadow: none; }
.fb-box--row > .fb-field[data-fb-role="row"] { border: 0; margin: 0; }
.fb-box__body { display: grid; grid-template-columns: repeat(60, minmax(0, 1fr)); gap: var(--ad-space-2); align-items: start; min-width: 0; }
.fb-box__body:empty { display: block; }
.fb-box__body:empty::before { content: "Vide : glissez un champ ici, ou « + Champ »."; display: block; padding: var(--ad-space-2); color: var(--ad-text-mute); font-size: var(--ad-fs-sm); font-style: italic; }
.fb-box .fb-field[data-fb-role="in-row"] { border-left: 1px solid var(--ad-border); }
/* Déplacer : à la souris, « monter / descendre » n'apparaissent que sur l'en-tête d'un conteneur, qu'ils emportent avec ses champs.
   Pendant un glissement (moteur commun, étape F), tout se replie sur sa barre (`.dnd-replie`, admin-socle.css) et
   l'unité se déplace en direct ; seule la zone « hors de l'encadré » visée prend un cadre. */
/* `.fb-iconbtn` (plus bas) pose un affichage : il faut au moins sa spécificité pour le masquer. */
.fb-field .fb-iconbtn.fb-move { display: none; }
.fb-box > .fb-field .fb-iconbtn.fb-move { display: inline-flex; }
/* Au doigt, sans clavier ni glisser précis, chaque carte a ses flèches : elles font entrer et sortir un champ d'un
   encadré (js/form-builder.js, deplacerPas()). À la souris, la poignée et le clavier suffisent. */
@media (pointer: coarse) {
    .fb-field .fb-iconbtn.fb-move { display: inline-flex; }
    /* Avec deux boutons de plus, une carte étroite (une colonne sur téléphone) n'avait plus de place pour son nom :
       les boutons passent à la ligne, le nom garde de quoi se lire. */
    .fb-field__summary { flex-wrap: wrap; row-gap: 4px; }
    .fb-field__name { min-width: 6rem; }
}
/* « + Champ » au bas d'une étape ou d'un groupe : il range le champ dedans, à la fin. Le bouton est le
   `.admin-col__add` du pied d'une colonne de section, sur toute la largeur de l'encadré. */
.fb-box__pied { display: flex; flex-direction: column; padding-top: var(--ad-space-1, 4px); }
.fb-box__pied[hidden], .fb-box.is-folded > .fb-box__pied { display: none; }
/* Replier : la barre garde le nom du conteneur et dit combien de champs elle cache. */
.fb-field .fb-iconbtn.fb-fold { display: none; }
.fb-box > .fb-field .fb-iconbtn.fb-fold { display: inline-flex; }
.fb-fold span { display: inline-flex; }
.fb-fold .fb-fold__deplier, .fb-box.is-folded > .fb-field .fb-fold .fb-fold__plier { display: none; }
.fb-box.is-folded > .fb-field .fb-fold .fb-fold__deplier { display: inline-flex; }
.fb-box.is-folded > .fb-box__body { display: none; }
.fb-box.is-folded > .fb-field .fb-field__summary-actions[data-fb-n]::before { content: attr(data-fb-n); flex: 0 0 auto; white-space: nowrap; padding: 2px 8px; border-radius: 999px; background: color-mix(in srgb, var(--fb-box-c) 22%, var(--ad-bg)); color: var(--ad-text); font-size: var(--ad-fs-sm); }
.fb-box.is-folded { padding-bottom: var(--ad-space-1, 4px); }
/* Sur une barre étroite, un conteneur replié cède la place du type à son NOM : c'est le nom qui le fait reconnaître. */
@container (max-width: 640px) {
    .fb-box.is-folded > .fb-field .fb-field__badge { display: none; }
}
.fb-field.is-dragging, .fb-box.is-dragging { opacity: .55; }
.fb-fields .is-drag-into { outline: 2px dashed var(--ad-accent); outline-offset: -2px; border-radius: var(--ad-r-md); }
/* « + Champ » : au bout d'une ligne seulement ; le « + » d'insertion, sur les champs et les repères. */
/* `body.admin-body .btn` (admin-socle.css) impose inline-flex : il faut au moins sa spécificité. */
body.admin-body .fb-field .fb-rowadd { display: none; }
body.admin-body .fb-field[data-fb-role="row"] .fb-rowadd { display: inline-flex; }
/* Un champ dans une colonne étroite : le résumé garde l'essentiel (nom et actions), la place manque pour le reste. */
@container (max-width: 300px) {
    .fb-field__badge { display: none; }
    .fb-field__chev { display: none; }
}
@container (max-width: 190px) {
    .fb-field [data-fb-insert-after], .fb-field [data-fb-dup] { display: none; }
}

/* Les deux gestes d'ajout de l'éditeur de section (moteur commun, étape F) : « + Champ » (la fenêtre de pastilles,
   #fb-ajout, la coquille de « + Composant ») au dessin du pied d'une colonne, puis « + Ajouter une ligne ». */
.fb-addbar { display: flex; flex-direction: column; align-items: flex-start; gap: var(--ad-space-3); }
.fb-addbar .fb-addbar__champ { align-self: stretch; }
/* La pastille du type, en tête de carte, comme celle d'un composant (blockChip()). */
.fb-field__chip { display: inline-flex; flex: 0 0 auto; }
.fb-field__chip:empty { display: none; }

/* Marqueurs de structure (ligne, groupe).
   Ce ne sont pas des questions posées au visiteur mais des repères de mise en
   page : le trait discontinu et le fond gris les distinguent au premier coup
   d'œil dans une pile de champs, sans ajouter ni icône ni légende. */
.fb-field[data-fb-struct] { background: var(--ad-bg-alt); border-style: dashed; }
.fb-field[data-fb-struct] .fb-field__badge { background: var(--ad-border); color: var(--ad-text); }
/* Une ÉTAPE est une rupture plus forte qu'une ligne ou un groupe : c'est une
   page. Un filet plein au-dessus la fait lire comme telle dans la pile. */
.fb-field[data-fb-struct="step"] { border-top: 2px solid var(--ad-accent); }
/* Les deux menus chaînés « n colonnes » + « répartition ». */
.fb-field__cols { display: flex; gap: var(--ad-space-2); flex-wrap: wrap; }
.fb-field__cols select { width: auto; }
/* Les deux menus d'une LIGNE tiennent dans sa carte d'en-tête : un peu d'air sous la barre du titre, et des menus
   compacts (30 px au lieu des 38 px d'un champ de formulaire), qui n'ont ici qu'une courte valeur à porter. */
.fb-field__row[data-fb-colswrap]:not([hidden]) { align-items: center; padding: var(--ad-space-2) var(--ad-space-3) var(--ad-space-3); }
.fb-field__cols { align-items: center; }
.fb-field__cols select.admin-form__select { min-height: 30px; padding: 3px 28px 3px 10px; font-size: var(--ad-fs-sm); }
/* « 5 champs pour 4 colonnes » : un décompte qui ne colle pas n'est pas une
   erreur — le débordement passe proprement à la ligne suivante — mais il vaut
   d'être signalé, sinon on ne le découvre que sur la page publique. */
.fb-hint--warn { color: var(--ad-warn, #b45309); font-weight: 500; }

/* Résumé replié (chip cliquable) */
.fb-field__summary { display: flex; align-items: center; gap: var(--ad-space-2); padding: 10px var(--ad-space-2); cursor: pointer; min-width: 0; max-width: 100%; }
.fb-field__summary:hover { background: var(--ad-bg-alt); }
.fb-field__summary:focus-visible { outline: 2px solid var(--ad-accent); outline-offset: -2px; }
.fb-field__drag { display: inline-flex; cursor: grab; color: var(--ad-text-mute); flex: 0 0 auto; touch-action: none; }
.fb-field__drag:active { cursor: grabbing; }
.fb-field__badge { flex: 0 0 auto; font-size: var(--ad-fs-badge); font-weight: 600; letter-spacing: .01em; padding: 2px 8px; border-radius: 999px; background: var(--ad-accent-sf); color: var(--ad-accent-dk); white-space: nowrap; }
.fb-field__name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--ad-fs-sm); }
/* Le nom est le bouton qui ouvre la carte (A8) : il garde l'allure d'un texte. */
button.fb-field__name { appearance: none; margin: 0; padding: 0; border: 0; background: none; color: inherit; font: inherit; font-size: var(--ad-fs-sm); text-align: left; cursor: pointer; }
button.fb-field__name:focus-visible { outline: 2px solid var(--ad-accent); outline-offset: 2px; border-radius: 2px; }
.fb-field__name em { color: var(--ad-text-mute); }
.fb-field__reqdot { flex: 0 0 auto; color: var(--ad-danger); font-weight: 700; }
.fb-field__summary-actions { flex: 0 0 auto; display: flex; align-items: center; gap: 2px; margin-left: auto; }
.fb-field__chev { display: inline-flex; color: var(--ad-text-mute); transition: transform .15s ease; }
.fb-field.is-open .fb-field__chev { transform: rotate(180deg); }
/* Chip layout (heading / note) : bandeau distinct */
.fb-field[data-fb-layout] .fb-field__badge { background: var(--ad-bg-alt); color: var(--ad-text-mute); }

/* Bouton icône compact (dupliquer / supprimer / retirer option) */
.fb-iconbtn { display: inline-flex; align-items: center; justify-content: center; width: 30px; height: 30px; padding: 0; border: 1px solid transparent; border-radius: var(--ad-r-sm); background: none; color: var(--ad-text-mute); cursor: pointer; }
.fb-iconbtn:hover { background: var(--ad-bg-alt); color: var(--ad-text); border-color: var(--ad-border); }
.fb-iconbtn--danger:hover { background: var(--ad-danger-sf); color: var(--ad-danger); border-color: var(--ad-danger); }

/* Éditeur déplié */
.fb-field__editor { border-top: 1px solid var(--ad-border); padding: var(--ad-space-3); display: flex; flex-direction: column; gap: var(--ad-space-2); background: var(--ad-bg-alt); }
/* L'attribut hidden doit l'emporter sur les display: flex/grid ci-dessous. */
.fb-field__editor[hidden], .fb-field__cond[hidden], .fb-field__cond-detail[hidden] { display: none; }
/* Contenu / Réglages d'un champ : même allure que les onglets d'une page, en plus petit. */
/* Les onglets Contenu / Réglages d'un champ ont le dessin de ceux d'un composant (`.block-onglets`, étape F). */
.fb-field__tab[hidden], .fb-field__panel[hidden] { display: none; }
.fb-field__panel { display: flex; flex-direction: column; gap: var(--ad-space-2); }
/* Ligne de réglage : libellé à gauche, contrôle à droite.

   ALIGNEMENT — le libellé doit tomber sur la PREMIÈRE ligne de texte du champ.
   Deux fausses pistes écartées :
     · `align-items: baseline` — juste pour un champ d'une ligne, faux pour une
       zone de texte, dont la ligne de base est en BAS de la boîte : le libellé
       « Message de succès » descendait au niveau de la troisième ligne.
     · un `padding-top: 8px` écrit à la main — c'était l'état d'avant, et il
       redevenait faux dès que les mesures du champ changeaient.
   L'écart est donc DÉRIVÉ des variables du champ lui-même : sa marge intérieure
   haute, plus son trait de bordure. Il reste juste si ces valeurs bougent.

   La colonne passe de 8 à 10.5rem : « Accusé de réception » y tenait sur deux
   lignes. */
.fb-field__row, .fb-field__opts { display: grid; grid-template-columns: 10.5rem minmax(0, 1fr); gap: var(--ad-space-3); align-items: start; }
/* Même graisse et même couleur que .admin-form__label, qui habille les libellés
   de tous les AUTRES écrans : un libellé de réglage se lit, il ne s'efface pas. */
.fb-field__lbl {
    font-size: var(--ad-fs-sm);
    font-weight: 500;
    color: var(--ad-text);
    line-height: 1.4;
    padding-top: calc(var(--ad-field-py) + 1px);
}
.fb-langrow { display: block; }
.fb-langrow__cell { display: none; }
.fb-langrow__cell.is-active { display: block; }
.fb-langrow__cell input, .fb-langrow__cell textarea { width: 100%; }
/* Bloc « Réglages du formulaire ».
   Ses lignes étaient collées les unes aux autres, sans séparation ni rythme :
   quatre champs pleine largeur empilés se lisaient comme un seul pavé. Un filet
   par ligne suffit à les rendre dénombrables. Portée à la carte des réglages
   seule — les cartes de CHAMP sont denses à dessein, un filet par ligne y
   ferait du bruit. */
.fb-settings .fb-field__row { padding: var(--ad-space-3) 0; border-top: 1px solid var(--ad-border); }
.fb-settings .fb-field__row:first-of-type { border-top: 0; padding-top: var(--ad-space-1); }
/* Un champ de titre n'a pas besoin de 750 px. La borne garde une longueur de
   ligne confortable sur grand écran, sans imposer de largeur fixe en dessous. */
.fb-settings .fb-langrow__cell input,
.fb-settings .fb-langrow__cell textarea { max-width: 34rem; }
.fb-settings .admin-form__check { line-height: 1.45; }

.fb-field__namehint { display: block; margin-top: 3px; font-size: var(--ad-fs-hint); color: var(--ad-text-soft); }
.fb-field__namehint code { font-size: inherit; }
.fb-field__flags-inner { display: flex; gap: var(--ad-space-4); flex-wrap: wrap; align-items: center; padding-top: 4px; }
.fb-field__widthwrap { display: inline-flex; align-items: center; gap: 6px; font-size: var(--ad-fs-sm); color: var(--ad-text-mute); }
.fb-field__widthwrap select { width: auto; }

/* Options (listes / radios / cases) */
.fb-option { display: flex; gap: var(--ad-space-2); align-items: flex-start; flex-wrap: wrap; margin-bottom: var(--ad-space-2); padding: var(--ad-space-2); border: 1px dashed var(--ad-border); border-radius: var(--ad-r-sm); background: var(--ad-bg); }
.fb-option > [data-fb-opt-val] { flex: 0 0 8rem; }
.fb-option .fb-langrow { flex: 1 1 12rem; }

/* Affichage conditionnel (show_if) */
.fb-field__cond-inner { display: flex; flex-direction: column; gap: var(--ad-space-2); }
.fb-field__cond-detail { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; font-size: var(--ad-fs-sm); color: var(--ad-text-mute); padding: var(--ad-space-2); border-left: 3px solid var(--ad-accent); background: var(--ad-bg); border-radius: 0 var(--ad-r-sm) var(--ad-r-sm) 0; }
.fb-field__cond-detail select { width: auto; min-width: 8rem; }
/* La case « moyens acceptés » du bloc Paiement (chantier 58) : sa propre ligne,
   sous les listes, plutôt que glissée dans la rangée. */
.fb-field__cond-detail > .admin-form__check { flex-basis: 100%; margin-top: 4px; }
/* Les moyens proposés à l'acheteur (chantier 85) : une colonne sous la ligne du
   montant, chaque sous-réglage décalé sous la case qu'il précise. */
.fb-pay-modes { flex-basis: 100%; display: flex; flex-direction: column; align-items: flex-start; gap: 6px; margin-top: var(--ad-space-2); }
.fb-pay-modes__titre { font-weight: 600; color: var(--ad-text); }
.fb-pay-modes__sous { margin-left: 1.6rem; }
.fb-pay-modes > select { margin-left: 1.6rem; }
.fb-pay-modes [data-fb-pay-invoice-detail] { display: flex; flex-direction: column; gap: 4px; width: calc(100% - 1.6rem); }
.fb-pay-modes [data-fb-pay-invoice-detail][hidden] { display: none; }
/* Ce qui compose le montant, et la carte Conditions (chantier 85, étape 2). */
.fb-pay-part { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-left: 1.6rem; }
.fb-pay-part > span:first-child { min-width: 9.5rem; color: var(--ad-text); }
.fb-cond-ligne { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.fb-cond-ligne .admin-form__input--small { width: 6rem; }
.fb-cond-ligne > small { flex-basis: 100%; }
.fb-cond-ligne > small[hidden] { display: none; }
/* Les liens personnalisés (chantier 85, étape 3). */
.fb-liens tr.is-inactive td { color: var(--ad-text-mute); }
.fb-lien-url { font-family: var(--ad-font-mono, monospace); font-size: var(--ad-fs-sm); color: var(--ad-text-mute); word-break: break-all; }
/* Le QR code d'un lien (espace partenaire) : fond blanc gardé en mode sombre, pour rester lisible. */
.fb-lien-qr summary { cursor: pointer; color: var(--ad-text-mute); font-size: var(--ad-fs-sm); }
.fb-lien-qr .qr-code { display: block; width: 10rem; height: 10rem; margin: .5rem 0; }
.fb-lien-types { display: flex; flex-direction: column; gap: 6px; }
.fb-lien-effet { margin: var(--ad-space-2) 0 0; }
.fb-lien-suppr { margin-top: var(--ad-space-4, 1.5rem); }
/* Accès « Sans liens personnalisés » : la zone reste lisible, pâle et inerte. */
.fb-liens-zone.is-off { opacity: .45; }
.fb-liens-zone.is-off * { cursor: not-allowed; }

/* Onglets de langue (une langue affichée à la fois) */
/* Sélecteur de langue du constructeur de formulaires. Il reste un `role="group"`
   et non un `tablist` — ses boutons ne commandent pas UN panneau mais des dizaines
   de cellules dispersées (cf. forms.php). Seule l'APPARENCE est ralliée à la barre
   de langues : même gabarit, même noir sur l'option retenue. */
.fb-langtabs { display: flex; align-items: center; gap: var(--ad-space-2); margin-bottom: var(--ad-space-3); flex-wrap: wrap; }
.fb-langtabs__label { font-size: var(--ad-fs-sm); color: var(--ad-text-soft); margin-right: var(--ad-space-1); }
.fb-langtabs > .fb-langtab { margin-right: 2px; }
.fb-langtab {
    padding: 6px 14px;
    border: none;
    background: var(--ad-bg-sunk);
    border-radius: var(--ad-r-xs);
    font-size: var(--ad-fs-label);
    font-weight: var(--ad-fw-label);
    text-transform: uppercase;
    letter-spacing: var(--ad-ls-label);
    color: var(--ad-text-soft);
    cursor: pointer;
    transition: background .12s ease, color .12s ease;
}
.fb-langtab:hover { color: var(--ad-text); }
.fb-langtab.is-active,
.fb-langtab.is-active:hover { background: var(--ad-text); color: #fff; }
/* Le bouton « Traduire » est poussé à droite, comme dans la barre de langues. */
.fb-langtabs > .fb-translate { margin-left: auto; }
/* Bouton « Traduire le FR → … » aligné avec les onglets (pas de marge verticale). */
.fb-translate { display: inline-flex; align-items: center; gap: 8px; margin-left: var(--ad-space-3); }
.fb-translate .btn-translate__msg { font-size: var(--ad-fs-hint); color: var(--ad-text-soft); }

/* Modale de sortie (modifications non enregistrées) */
.fb-exit-panel { max-width: 460px; }
.fb-exit-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--ad-space-2); margin-top: var(--ad-space-4); }

@media (max-width: 900px) {
    /* Sur petit écran, la maquette « frontend » n'a pas de sens : une colonne.
       On repasse en flux bloc (pas de flex) pour éviter que la rigidité
       flex-basis/shrink des chips ne force une largeur mini et déborde. */
    .fb-fields, .fb-box__body { display: block; }
    .fb-field, .fb-field[data-fb-w] { width: auto; margin-bottom: var(--ad-space-2); }
    .fb-box > .fb-field { margin-bottom: 0; }
    .fb-field[data-fb-role="row"] { margin-top: 0; }
    .fb-field:last-child { margin-bottom: 0; }
}
@media (max-width: 768px) {
    /* Une seule colonne : le libellé repasse AU-DESSUS de son champ. L'écart
       calé sur la marge intérieure du champ n'a alors plus d'objet — il
       creuserait un trou entre le libellé et ce qu'il nomme. */
    .fb-field__row, .fb-field__opts { grid-template-columns: 1fr; gap: var(--ad-space-1); }
    .fb-field__lbl { padding-top: 0; }
    .fb-settings .fb-field__row { padding: var(--ad-space-3) 0; }
}

.repeater-editor__items {
    display: flex;
    flex-direction: column;
    gap: var(--ad-space-3);
    margin: var(--ad-space-3) 0;
}
.repeater-item {
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-r-md);
    padding: var(--ad-space-3);
    background: var(--ad-bg-alt);
}
/* Poignée (glisser, ou flèches au clavier) et Monter / Descendre. */
.repeater-item__head { display: flex; align-items: center; gap: var(--ad-space-2); margin-bottom: var(--ad-space-2); }
.repeater-item__drag, .card-item__drag { cursor: grab; color: var(--ad-text-mute); user-select: none; font-size: 16px; padding: 0 var(--ad-space-1); }
.repeater-item__drag:focus-visible, .card-item__drag:focus-visible { outline: 2px solid var(--ad-accent); outline-offset: 2px; border-radius: 4px; }
.repeater-item.is-dragging, .card-item.is-dragging { opacity: .5; }
/* Monter / Descendre : deux flèches discrètes, de la famille de la poignée — ni bord ni fond. */
.repeater-item__head { gap: var(--ad-space-1); }
.repeater-item__move {
    display: inline-flex; align-items: center; justify-content: center;
    padding: 2px; border: 0; background: none; border-radius: 4px;
    color: var(--ad-text-mute); cursor: pointer; line-height: 1;
}
.repeater-item__move svg { width: 14px; height: 14px; }
.repeater-item__move:hover { color: var(--ad-text); }
.repeater-item__move:focus-visible { outline: 2px solid var(--ad-accent); outline-offset: 2px; }
.repeater-item__shared { margin-bottom: var(--ad-space-2); }
.repeater-item__langs + .repeater-item__shared { margin: var(--ad-space-3) 0 0; }
.repeater-item__lang { display: none; flex-direction: column; gap: var(--ad-space-1); }
.repeater-item__lang.is-active { display: flex; }
/* Champs côte à côte (`largeur` au registre) : rangée qui passe à la ligne, chaque
   champ pleine largeur par défaut ; un demi ou un tiers ne descend pas sous sa
   largeur minimale — en deçà, il reprend toute la ligne. */
.repeater-item__lang.is-active:has(.repeater-item__f--demi, .repeater-item__f--tiers, .repeater-item__f--quart),
.repeater-item__shared:has(.repeater-item__f--demi, .repeater-item__f--tiers, .repeater-item__f--quart) {
    flex-direction: row; flex-wrap: wrap; column-gap: var(--ad-space-3);
}
.repeater-item__shared:has(.repeater-item__f--demi, .repeater-item__f--tiers, .repeater-item__f--quart) { display: flex; }
.repeater-item__lang > .admin-form__group,
.repeater-item__shared > .admin-form__group { flex: 1 1 100%; min-width: 0; }
.repeater-item__lang > .repeater-item__f--demi,
.repeater-item__shared > .repeater-item__f--demi { flex: 1 1 calc(50% - var(--ad-space-3)); min-width: 14rem; }
.repeater-item__lang > .repeater-item__f--tiers,
.repeater-item__shared > .repeater-item__f--tiers { flex: 1 1 calc(33% - var(--ad-space-3)); min-width: 10rem; }
.repeater-item__lang > .repeater-item__f--quart,
.repeater-item__shared > .repeater-item__f--quart { flex: 1 1 calc(25% - var(--ad-space-3)); min-width: 9rem; }
.repeater-item__lang > .admin-form__group[hidden],
.repeater-item__shared > .admin-form__group[hidden] { display: none; }
.repeater-item__foot { margin-top: var(--ad-space-3); text-align: right; }

.repeater-editor__add {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ad-space-2);
}

/* Champ image avec popup de sélection (galerie) : vignette + actions. */
.image-picker {
    display: flex;
    align-items: center;
    /* `wrap` pour que le CHEMIN passe à la ligne : il occupe une base de 100 %
       et se retrouve donc seul sur son rang, sous la vignette et les boutons.
       `row-gap` plus serré que l'écart horizontal — le chemin appartient à ce
       qui le précède, il ne doit pas flotter à mi-distance. */
    flex-wrap: wrap;
    gap: var(--ad-space-1) var(--ad-space-3);
}
.image-picker__preview {
    flex: 0 0 auto;
    width: 72px;
    height: 72px;
    border-radius: var(--ad-r-sm);
    overflow: hidden;
    background: var(--ad-bg-sunk);
    border: 1px solid var(--ad-border);
}
.image-picker__preview[hidden] { display: none; }
.image-picker__preview img { width: 100%; height: 100%; object-fit: cover; display: block; }
.image-picker__none {
    color: var(--ad-text-mute);
    font-size: var(--ad-fs-sm);
    font-style: italic;
}
.image-picker__none[hidden] { display: none; }
.image-picker__none.is-missing { color: var(--ad-warn); font-style: normal; font-weight: 600; }
/* LE CHEMIN DU FICHIER — lisible, et qui ne pousse jamais les boutons dehors.
   `min-width: 0` avec `flex: 1` : sans lui, un chemin long refuse de se
   tronquer et déborde le conteneur, emportant les boutons hors du champ. C'est
   le couple habituel de ce projet pour un texte élidé dans une rangée flex.
   En chiffres tabulaires et un cran plus petit : c'est une référence qu'on
   compare, pas une phrase qu'on lit. */
.image-picker__path {
    /* BASE 100 % : il prend sa propre ligne au lieu de se serrer entre la
       vignette et les boutons, où le dossier se faisait rogner dès qu'un chemin
       était un peu long. À pleine largeur, l'élision ne sert plus que de filet. */
    flex: 1 1 100%;
    /* `order` APRÈS les boutons : dans le balisage le chemin les précède — il
       appartient à l'image, pas aux actions. Sans cette ligne, sa base de 100 %
       le glissait ENTRE la vignette et les boutons, qui partaient sur un
       troisième rang. Un rang de plus pour rien, à chaque champ d'image. */
    order: 1;
    min-width: 0;
    display: flex;
    white-space: nowrap;
    font-family: var(--ad-font-mono, ui-monospace, monospace);
    font-size: var(--ad-fs-xs);
    color: var(--ad-text-soft);
}
/* Le DOSSIER cède : il peut se tronquer, on le lit en second.
   `direction: rtl` a été essayé ici et rendait « img/x.jpg/ » — la barre
   oblique de tête est un caractère neutre que le sens inverse replace à
   l'autre bout. Deux boîtes valent mieux qu'une astuce bidirectionnelle. */
.image-picker__path [data-ip-dir] {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* Le NOM DU FICHIER ne cède jamais : c'est ce qu'on vient lire. */
.image-picker__path [data-ip-file] {
    flex: 0 0 auto;
    color: var(--ad-text);
}
.image-picker__path[hidden] { display: none; }

.image-picker__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ad-space-2);
    margin-left: auto;
}
/* Variante « carte de partage » : la vignette adopte le cadrage réel des
   réseaux sociaux (1,91:1). Un carré donnait une idée fausse de ce qui serait
   visible — les bords gauche et droit d'une image panoramique disparaissaient
   de l'aperçu alors qu'ils sont bien affichés une fois partagée. */
.image-picker--wide .image-picker__preview {
    width: 200px;
    height: 105px;
}

/* Diagnostic de l'image de partage (Réglages → Partage & app). Habillage
   d'.admin-alert : seuls le rythme et l'atténuation « périmé » sont propres. */
.og-check {
    margin: var(--ad-space-3) 0 0;
    font-size: var(--ad-fs-sm);
}
.og-check__thumb {
    flex: 0 0 auto;
    width: 150px;
    border-radius: var(--ad-r-sm);
    overflow: hidden;
    border: 1px solid var(--ad-border);
    background: var(--ad-bg-sunk);
}
.og-check__thumb img { width: 100%; height: auto; display: block; }
.og-check__line { margin: 0 0 .4em; }
.og-check__line:last-child { margin-bottom: 0; }
.og-check__specs { opacity: .85; }
.og-check.is-stale .og-check__line:not(.og-check__stale) { opacity: .45; }
.og-check__stale { font-weight: 600; }

/* --- Éditeur d'horaires (bloc « hours ») --- */
.hours-editor__lang { display: none; }
.hours-editor__lang.is-active { display: block; }
.hours-grid-head,
.hours-row {
    display: grid;
    grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr) minmax(0, 1fr) auto;
    gap: var(--ad-space-2);
    align-items: center;
}
.hours-grid-head {
    margin-bottom: var(--ad-space-1);
    font-size: var(--ad-fs-label);
    font-weight: var(--ad-fw-label);
    letter-spacing: var(--ad-ls-label);
    text-transform: uppercase;
    color: var(--ad-text-mute);
}
.hours-rows { display: flex; flex-direction: column; gap: var(--ad-space-2); }
.hours-row__del { justify-self: center; }
.hours-add { margin-top: var(--ad-space-3); }
@media (max-width: 640px) {
    .hours-grid-head { display: none; }
    .hours-row { grid-template-columns: 1fr; gap: var(--ad-space-1); }
    .hours-row__del { justify-self: end; }
}

.admin-redirects { display: flex; flex-direction: column; gap: var(--ad-space-2); }
.admin-redirect-row {
    display: flex;
    align-items: center;
    gap: var(--ad-space-3);
    flex-wrap: wrap;
    padding: var(--ad-space-3);
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-r-md);
    background: var(--ad-bg);
}
.admin-redirect-row.is-inactive { opacity: .55; }
/* Une ligne désignée par « À traiter » (#redir-<id>) : sous la barre du haut, et repérée. */
.admin-redirect-row { scroll-margin-top: calc(var(--ad-header-h) + var(--ad-space-4)); }
.admin-redirect-row:target { border-color: var(--ad-accent); box-shadow: 0 0 0 3px var(--ad-focus); }
.admin-redirect-row__old { font-weight: 600; }
.admin-redirect-row__arrow { color: var(--ad-muted); }
.admin-redirect-row__note { flex: 1 1 12rem; min-width: 8rem; }
.admin-sections { display: flex; flex-direction: column; gap: var(--ad-space-2); }
.admin-section-row {
    display: flex;
    align-items: center;
    gap: var(--ad-space-3);
    flex-wrap: wrap;
    padding: var(--ad-space-3);
    border: 1px solid var(--ad-border);
    border-left: 3px solid var(--ad-lvl2);   /* rail du NIVEAU 2 (section) */
    border-radius: var(--ad-r-md);
    background: var(--ad-bg);
}
.admin-section-row__drag { cursor: grab; color: var(--ad-text-mute); user-select: none; font-size: 16px; flex: 0 0 auto; }
.admin-section-row__main { display: flex; align-items: center; gap: var(--ad-space-2); flex: 1 1 10rem; min-width: 0; flex-wrap: wrap; }
/* La zone du nom ouvre l'éditeur de contenu (clic sur la ligne). */
a.admin-section-row__main {
    text-decoration: none;
    color: var(--ad-text);
    cursor: pointer;
    padding: 4px 8px;
    margin: -4px -8px;
    border-radius: var(--ad-r-sm);
    transition: background var(--ad-trans) ease;
}
a.admin-section-row__main:hover { background: var(--ad-accent-sf); }
a.admin-section-row__main:hover .admin-section-row__name { color: var(--ad-accent); text-decoration: underline; }
.admin-section-row__edit { display: inline-flex; flex: 0 0 auto; color: var(--ad-text-mute); }
a.admin-section-row__main:hover .admin-section-row__edit { color: var(--ad-accent); }
.admin-section-row__name { font-weight: 600; overflow-wrap: anywhere; }
.admin-section-row__check {
    display: inline-flex; align-items: center; gap: 4px;
    font-size: var(--ad-fs-sm); white-space: nowrap;
}

/* Lignes de section : le nom prend une ligne pleine, les contrôles s'enroulent
   en dessous (zéro scroll horizontal), sur petits écrans. */
@media (max-width: 768px) {
    .admin-section-row { align-items: flex-start; gap: var(--ad-space-2); }
    .admin-section-row__main { flex-basis: 100%; }
    
    .admin-page-add-section { flex-direction: column; align-items: stretch; }
    .admin-page-add-section .admin-form__input,
    .admin-page-add-section .btn { width: 100%; }
}

/* Case à cocher inline dans un formulaire (ex. Réglages → Animation d'intro) */
.admin-form__check {
    display: inline-flex; align-items: center; gap: 8px;
    cursor: pointer; font-weight: 500;
}
.admin-form__check input { cursor: pointer; }

/* ----- Admin : demandes reçues (soumissions) ----- */
.admin-nav__badge {
    margin-left: auto;
    background: var(--ad-accent, #4F7A17);
    color: #fff;
    font-size: var(--ad-fs-badge);
    font-weight: 700;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    border-radius: 9px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.admin-subs { display: flex; flex-direction: column; gap: var(--ad-space-2); }
/* Intertitre d'un formulaire dans les demandes reçues (2026-10-28). */
/* Préfixé comme « body.admin-body .admin-card h2 » (trait, 20 px), qui l’emportait sinon. */
body.admin-body .admin-subs > .admin-subs__groupe {
    margin: var(--ad-space-4) 0 0;
    padding: 0;
    border: 0;
    font-size: 1rem;
    font-weight: 600;
}
body.admin-body .admin-subs > .admin-subs__groupe:first-child { margin-top: 0; }
body.admin-body .admin-subs > .admin-subs__groupe .admin-muted { font-weight: 400; font-size: .875rem; margin-left: .35em; }
.admin-sub {
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-r-md);
    background: var(--ad-bg);
    padding: var(--ad-space-3);
}
.admin-sub--unread { border-left: 3px solid var(--ad-accent, #4F7A17); }
.subs-bulk [hidden] { display: none; }
/* Comme une boîte de réception : le nom n'est en gras que tant que la demande n'est pas lue. */
.admin-sub__name { font-weight: 400; }
.admin-sub--unread .admin-sub__name { font-weight: 700; }
/* La chaîne d'une commande passée par un lien personnalisé : discrète, juste
   avant le nom ; le lien, son type et sa référence se lisent au survol. */
.admin-sub__lien { display: inline-flex; align-items: center; color: var(--ad-text-mute); margin-right: -4px; }
.admin-sub__lien svg { width: 14px; height: 14px; }
/* Marquer lu / non lu depuis la ligne, sans déplier (déplier marque la demande lue). */
.admin-sub__lu {
    display: inline-flex; align-items: center; justify-content: center;
    width: 28px; height: 28px; padding: 0; flex: 0 0 auto;
    border: 1px solid transparent; border-radius: var(--ad-r-md);
    background: transparent; color: var(--ad-text-mute); cursor: pointer;
}
.admin-sub__lu:hover, .admin-sub__lu:focus-visible { background: var(--ad-bg-soft, rgba(0,0,0,.05)); color: var(--ad-text); border-color: var(--ad-border); }
.admin-sub__lu svg { width: 16px; height: 16px; }
/* Non lue : l'action est « Marquer lu » (coche) ; lue : « Marquer non lu » (enveloppe). */
.admin-sub__lu span { display: inline-flex; }
.admin-sub--unread .admin-sub__ico-nl, .admin-sub:not(.admin-sub--unread) .admin-sub__ico-lu { display: none; }
.admin-sub > summary {
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: var(--ad-space-2);
    flex-wrap: wrap;
}
.admin-sub__ref { font-variant-numeric: tabular-nums; font-weight: 700; color: var(--ad-text-mute); font-size: var(--ad-fs-sm); }
.admin-sub__date { color: var(--ad-text-mute); font-size: var(--ad-fs-sm); margin-left: auto; }
.admin-badge--accent { background: var(--ad-accent, #4F7A17); color: #fff; }
.admin-sub__table { width: 100%; margin-top: var(--ad-space-3); border-collapse: collapse; table-layout: fixed; }
.admin-sub__table th, .admin-sub__table td { text-align: left; padding: 6px 10px; border-bottom: 1px solid var(--ad-border); vertical-align: top; }
.admin-sub__table th { width: 34%; color: var(--ad-text-mute); font-weight: 600; }
/* UNE ADRESSE N'A PAS D'ESPACE OÙ SE COUPER. Une adresse e-mail ou une URL un
   peu longue — donc un seul « mot » de 80 caractères — élargissait le tableau
   au-delà de l'écran, et avec lui toute la page : mesuré à +92 px sur un
   téléphone, +1344 px sur une tablette, et +932 px sur un écran de 1440. Le
   champ que le client vient chercher (à qui répondre) était coupé par le bord.
   `anywhere` autorise la coupure au milieu d'un mot, mais seulement quand rien
   d'autre ne marche ; `fixed` empêche la colonne de valeur de réclamer la
   largeur de son plus long mot. Les deux sont nécessaires. */
.admin-sub__table td { overflow-wrap: anywhere; }
.admin-sub__actions { margin-top: var(--ad-space-2); }

/* Journal des envois vers un service externe. Replié par défaut : il n'intéresse
   que le jour où quelque chose cloche, et déplié il pousserait les boutons hors
   de l'écran. */
.admin-sub__log { margin-top: var(--ad-space-2); }
.admin-sub__log > summary {
    cursor: pointer;
    font-size: .85rem;
    color: var(--ad-text-mute);
    padding: var(--ad-space-1) 0;
}
.admin-sub__log > summary:hover { color: var(--ad-text); }
/* La réponse d'un service distant est du texte brut, souvent long et sans
   espaces : sans ces deux règles, une ligne de JSON étire la page entière. */
.admin-sub__logbody {
    display: block;
    margin-top: 4px;
    font-size: .78rem;
    color: var(--ad-text-mute);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* ---- Sélection par lot des demandes (inbox + spam) ---- */
/* Case à cocher d'une demande : 16 px dessinés par le navigateur, donc huit de
   moins que les 24 du critère 2.5.8. Deux impasses avant la bonne porte — un
   `<input>` n'accepte pas de pseudo-élément, et un champ à apparence native
   IGNORE le rembourrage (mesuré : 16 × 16 malgré `padding: 4px`). C'est donc
   l'ÉTIQUETTE qui porte la cible : elle entoure la case, transmet le clic, et
   sa marge négative lui rend la place qu'elle prend. La case, elle, ne bouge
   pas d'un pixel. */
.admin-sub__hit {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    margin: -4px;
    flex: 0 0 auto;
    cursor: pointer;
}
.admin-sub__check { width: 16px; height: 16px; flex: 0 0 auto; cursor: pointer; }
.subs-tabs { margin-bottom: var(--ad-space-4); }   /* 16 px sous toute barre d'onglets */
.subs-bulk {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--ad-space-2) var(--ad-space-3);
    margin-bottom: var(--ad-space-3);
    padding: var(--ad-space-2) var(--ad-space-3);
    background: var(--ad-bg-sunk);
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-r-sm);
    position: sticky;
    top: var(--ad-header-h);
    z-index: 5;
}
.subs-bulk__all { display: inline-flex; align-items: center; gap: 6px; font-size: var(--ad-fs-sm); font-weight: 600; cursor: pointer; }
.subs-bulk__count { font-size: var(--ad-fs-sm); color: var(--ad-text-mute); }
.subs-bulk__btns { display: inline-flex; flex-wrap: wrap; gap: var(--ad-space-2); margin-left: auto; }

/* ----- Admin : APERÇU DU MENU (haut de l'écran « Pages & menu ») -----
   Une MAQUETTE de barre de navigation, pas un tableau. Le menu du site n'a pas
   d'écran à lui : il est déduit de sept réglages répartis sur trois écrans. Le
   seul moyen de rendre cette déduction lisible est de montrer le résultat sous
   la forme où l'éditeur le reconnaîtra — celle qu'il a sous les yeux sur le
   site. Une liste à puces aurait décrit le menu ; elle ne l'aurait pas montré. */
.admin-menu-preview__bar {
    /* Rangée, comme la barre du site : le menu à gauche, le bouton d'action
       poussé à droite par sa marge automatique. Sans ce flex ici, le bouton
       — qui est un frère de la liste, pas un de ses éléments — retomberait à
       la ligne, et l'aperçu ne ressemblerait plus à l'en-tête. */
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ad-space-3);
    padding: var(--ad-space-3) var(--ad-space-4);
    background: var(--ad-bg-sunk);
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-r-md);
}
.admin-menu-preview__top {
    flex: 1 1 auto;
    display: flex;
    flex-wrap: wrap;
    /* `center`, et non `flex-start` : les sous-menus ne sont plus dans le flux,
       la barre redevient une LIGNE — comme celle du site. */
    align-items: center;
    gap: var(--ad-space-2) var(--ad-space-4);
    margin: 0;
    padding: 0;
    list-style: none;
}
.admin-menu-preview__item { list-style: none; }
/* Le sous-menu se comporte comme celui du SITE : un déroulant flottant, révélé
   au survol et au focus clavier (cf. `.main-nav__sub` dans components.css).
   Rendu ouvert en permanence, il étirait la barre — une page à vingt ancres la
   faisait monter à mille pixels, et les entrées courtes se retrouvaient
   surmontées d'un vide de la même hauteur. Or personne ne voit jamais tous les
   déroulants ouverts en même temps sur le site : les montrer ainsi ne montrait
   pas le menu, cela le déformait. */
.admin-menu-preview__sub {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 6;
    min-width: 220px;
    margin: 0;
    padding: var(--ad-space-2) 0;
    list-style: none;
    background: var(--ad-bg);
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-r-sm);
    box-shadow: var(--ad-shadow-md);
    opacity: 0;
    visibility: hidden;
    transform: translateY(4px);
    transition: opacity var(--ad-trans) ease, transform var(--ad-trans) ease,
                visibility var(--ad-trans) ease;
}
/* `--sub` autant que `--has-sub` : une entrée de 2e niveau doit ancrer le
   déroulant du 3e, qu'elle en porte un ou non au moment du rendu. */
.admin-menu-preview__item--has-sub,
.admin-menu-preview__item--sub { position: relative; }
/* Combinateur ENFANT : en descendant, survoler une entrée de 1er niveau
   ouvrirait d'un coup tous les déroulants qu'elle contient, 3e niveau compris. */
.admin-menu-preview__item--has-sub:hover > .admin-menu-preview__sub,
.admin-menu-preview__item--has-sub:focus-within > .admin-menu-preview__sub {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}
/* 3e niveau : en cascade sur le côté, comme sur le site (components.css). */
.admin-menu-preview__sub .admin-menu-preview__sub {
    top: 0;
    left: 100%;
    margin-left: 2px;
    transform: translateX(-6px);
}
.admin-menu-preview__sub .admin-menu-preview__item--has-sub:hover > .admin-menu-preview__sub,
.admin-menu-preview__sub .admin-menu-preview__item--has-sub:focus-within > .admin-menu-preview__sub {
    transform: translateX(0);
}
/* Le chevron d'une entrée de 2e niveau pointe à DROITE : c'est là que son
   déroulant s'ouvre. */
.admin-menu-preview__item--sub .admin-menu-preview__caret { margin-left: auto; }
.admin-menu-preview__item--sub .admin-menu-preview__caret svg { transform: rotate(-90deg); }
/* Le chevron annonce qu'il y a quelque chose à survoler : sans lui, un
   déroulant caché est un déroulant que personne ne cherche. */
.admin-menu-preview__caret { display: inline-flex; opacity: .55; }
/* `chevron` pointe DÉJÀ vers le bas (m6 9 6 6 6-6) : le faire pivoter le
   couchait sur le côté. */
.admin-menu-preview__caret svg { width: 14px; height: 14px; }
.admin-menu-preview__link {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    /* Un bouton n'hérite PAS de line-height : la feuille du navigateur lui
       impose « normal ». Sans cette ligne, l'entrée est plus courte que le
       texte voisin — le piège déjà mesuré sur .admin-nav__link. */
    line-height: inherit;
    font: inherit;
    font-weight: 600;
    text-align: left;
    color: var(--ad-text);
    background: none;
    border: 0;
    padding: 4px 8px;
    margin: 0;
    border-radius: var(--ad-r-sm);
    cursor: pointer;
    transition: background var(--ad-trans) ease, color var(--ad-trans) ease;
}
.admin-menu-preview__link:hover:not([disabled]) {
    background: var(--ad-accent-sf);
    color: var(--ad-accent-h);
}
.admin-menu-preview__link[disabled] { cursor: default; }
.admin-menu-preview__link--child {
    display: flex;
    width: 100%;
    font-weight: 400;
    /* Relevée de --ad-fs-xs implicite à --ad-fs-sm : une entrée de sous-menu
       se lit autant qu'une entrée de premier niveau, elle est seulement moins
       affirmée. La graisse et la couleur portent déjà cette hiérarchie. */
    font-size: var(--ad-fs-sm);
    color: var(--ad-text-soft);
    border-radius: 0;
    padding: 5px var(--ad-space-3);
}

.admin-menu-preview__tag {
    font-size: var(--ad-fs-badge);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--ad-ls-label);
    color: var(--ad-text-mute);
    display: inline-flex;
    align-items: center;
    gap: 3px;
}
.admin-menu-preview__tag svg { width: 12px; height: 12px; }

.admin-menu-preview__warn {
    display: flex;
    align-items: flex-start;
    gap: var(--ad-space-2);
    margin: var(--ad-space-3) 0 0;
    padding: var(--ad-space-3);
    font-size: var(--ad-fs-sm);
    background: var(--ad-warn-sf);
    color: var(--ad-warn);
    border-radius: var(--ad-r-sm);
}
.admin-menu-preview__warn svg { flex: 0 0 auto; width: 18px; height: 18px; }

/* Les absents : repliés par défaut. Ils répondent à la question la plus
   fréquente (« pourquoi ma page n'est-elle pas là ? »), mais ils ne doivent
   pas concurrencer l'aperçu lui-même. */
.admin-menu-preview__hidden { margin-top: var(--ad-space-3); font-size: var(--ad-fs-sm); }
.admin-menu-preview__hidden > summary { cursor: pointer; color: var(--ad-text-soft); }
.admin-menu-preview__hidden-list {
    margin: var(--ad-space-2) 0 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.admin-menu-preview__hidden-link {
    font: inherit;
    line-height: inherit;
    font-weight: 600;
    color: var(--ad-text);
    background: none;
    border: 0;
    padding: 0;
    text-decoration: underline;
    text-decoration-style: dotted;
    cursor: pointer;
}
.admin-menu-preview__reason { color: var(--ad-text-mute); }

/* Repère au clic depuis l'aperçu : sur un écran de vingt lignes, arriver au bon
   endroit ne dit pas LAQUELLE on vient de demander. */
.admin-page.is-flash > .admin-page-row {
    border-color: var(--ad-accent);
    box-shadow: 0 0 0 3px var(--ad-focus);
}

/* La section qu'on vient de dupliquer : même repère que ci-dessus, posé sur sa ligne. */
.admin-section-row.is-flash {
    border-color: var(--ad-accent);
    box-shadow: 0 0 0 3px var(--ad-focus);
}

/* Badge de sous-menu sur une ligne de section. */
.admin-badge--nav {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    text-transform: none;
    letter-spacing: 0;
    background: var(--ad-accent-sf);
    color: var(--ad-accent-h);
}
.admin-badge--nav svg { width: 12px; height: 12px; }
.admin-badge--nav-off { text-transform: none; letter-spacing: 0; }

/* ----- Admin : gestion des Pages ----- */
.admin-pages { display: flex; flex-direction: column; gap: var(--ad-space-3); }
.admin-page-row {
    border: 1px solid var(--ad-border);
    border-left: 4px solid var(--ad-lvl1);   /* rail du NIVEAU 1 (page) */
    border-radius: var(--ad-r-lg);
    background: var(--ad-bg);
    padding: var(--ad-space-4);
    box-shadow: var(--ad-shadow-sm);
    transition: box-shadow var(--ad-trans) ease, border-color var(--ad-trans) ease;
}
.admin-page-row__head {
    display: flex; align-items: center; gap: var(--ad-space-3); flex-wrap: wrap;
}
.admin-page-row__name { font-weight: 650; display: inline-flex; align-items: center; gap: var(--ad-space-2); flex-wrap: wrap; }
.admin-page-row__name code { font-weight: 400; }

/* Toggles de dépliage (Gérer les sections / Libellés & SEO / Renommer) :
   puces discrètes cliquables avec chevron animé — remplace l'aspect « lien Joomla ». */
.admin-page-row__i18n { margin-top: var(--ad-space-2); }
.admin-page-row__i18n > summary {
    cursor: pointer;
    list-style: none;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 12px 4px 10px;
    font-size: var(--ad-fs-sm);
    font-weight: 500;
    color: var(--ad-text-soft);
    background: var(--ad-bg-alt);
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-r-pill);
    transition: background var(--ad-trans) ease, color var(--ad-trans) ease, border-color var(--ad-trans) ease;
}
.admin-page-row__i18n > summary::-webkit-details-marker { display: none; }
.admin-page-row__i18n > summary::before {
    content: "";
    width: 8px; height: 8px;
    border-right: 1.6px solid currentColor;
    border-bottom: 1.6px solid currentColor;
    transform: rotate(-45deg);
    transition: transform var(--ad-trans) ease;
    margin-left: 1px;
    opacity: .65;
}
.admin-page-row__i18n[open] > summary::before { transform: rotate(45deg); }
.admin-page-row__i18n > summary:hover {
    color: var(--ad-accent);
    border-color: color-mix(in srgb, var(--ad-accent) 45%, var(--ad-border));
    background: var(--ad-accent-sf);
}
.admin-page-row__i18n[open] > summary {
    color: var(--ad-accent);
    border-color: color-mix(in srgb, var(--ad-accent) 45%, var(--ad-border));
    background: var(--ad-accent-sf);
}
/* Bloc de champs traduits. C'était une GRILLE : une colonne encadrée par
   langue, côte à côte. Tenable à trois langues, illisible au-delà — et la
   largeur d'un champ fondait à mesure qu'on en ajoutait. C'est désormais une
   barre d'onglets et un seul panneau visible : le coût d'affichage ne dépend
   plus du nombre de langues. */
.admin-page-row__langs { margin-top: var(--ad-space-2); }
.admin-page-row__langs > .admin-lang-content {
    display: none;
    flex-direction: column;
    gap: var(--ad-space-2);
}
.admin-page-row__langs > .admin-lang-content.is-active { display: flex; }

/* ----- Admin : sections gérées sous chaque page ----- */
.admin-page-sections,
.admin-orphan-sections {
    display: flex; flex-direction: column; gap: var(--ad-space-2);
    margin-top: var(--ad-space-2);
}
.admin-page-add-section {
    display: flex; align-items: center; gap: var(--ad-space-2);
    margin-top: var(--ad-space-2);
    flex-wrap: wrap;
}
/* Le bouton prend la hauteur du champ qu'il accompagne. Sans cela, un
   `.btn--sm` (32px) posé à côté d'un champ (38px) laisse 3px de vide en haut
   et en bas : les deux sont pourtant bien centrés, mais l'œil lit un
   désalignement. Même règle pour la rangée d'ajout d'onglet.
   Scopé sur `body.admin-body` comme `.btn--sm` lui-même : sans cela la règle
   perd la bataille de spécificité (0,2,0 contre 0,2,1) et ne s'applique pas. */
body.admin-body .admin-page-add-section .btn,
body.admin-body .admin-tab-add .btn { min-height: var(--ad-field-h); }
.admin-page-row--orphans { border-left: 3px solid var(--ad-accent, #4F7A17); }

/* ---- Ajout de section plus visible + espacements (lifting) ----
   `.admin-tabs-wrap` avait une marge haute de 8 px : les écrans qui s'ouvrent sur
   des onglets commençaient 44 px sous le titre, les autres 36 (mesuré le
   2026-10-19). Retirée : tous les écrans commencent au même endroit. */

/* Barre d'ajout EN HAUT de la liste des sections. L'encadré d'accent (fond,
   bordure, coins, rembourrage) a été retiré le 2026-09-07 : dans un panneau qui
   liste déjà des sections encadrées, un cadre de plus faisait lire la barre
   d'ajout comme une section. Il ne reste que l'écart qui la sépare de la liste. */
.admin-page-add-section--top {
    margin: 0 0 var(--ad-space-4);
}

/* État vide « page sans section » : vrai appel à l'action (pas un texte gris). */
.admin-empty--cta {
    font-style: normal;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--ad-space-3);
    color: var(--ad-text-soft);
}
.admin-empty--cta p { margin: 0; }
.admin-page-add-section--cta { justify-content: center; }
.admin-page-add-section--cta .admin-form__input { min-width: 220px; }

/* « + Nouvelle section » à côté des onglets de l'éditeur de contenu. */
.admin-tab-add {
    display: inline-flex;
    align-items: center;
    gap: var(--ad-space-1);
    margin-left: auto;              /* poussé à droite de la rangée d'onglets */
    padding-bottom: 4px;
}
.admin-tab-add .admin-form__input--small { width: 160px; }
@media (max-width: 640px) {
    .admin-tab-add { margin-left: 0; width: 100%; margin-top: var(--ad-space-2); }
    .admin-tab-add .admin-form__input--small { flex: 1; width: auto; }
}

/* ===========================================================================
   RÉGLAGES DE SECTION — une seule convention de champ
   ===========================================================================
   L'écran mêlait trois façons d'écrire un champ, héritées de trois moments :
   une étiquette collée à sa liste, des PASTILLES de barre de langues détournées
   en libellés (« IMG », « VID », « FORME », « HAUT. »), et des largeurs posées
   au cas par cas avec `--small`. Sur une même ligne, les champs n'avaient donc
   ni la même hauteur, ni la même largeur, ni le même alignement.

   Ici, un champ = une étiquette en toutes lettres AU-DESSUS de son contrôle,
   qui occupe toute la largeur de sa cellule. La grille répartit ; rien n'est
   dimensionné à la main. Un réglage qui a besoin de place (une forme, une
   adresse de vidéo) demande deux cellules, et c'est le seul écart permis. */
.admin-section-settings {
    display: flex;
    flex-direction: column;
    gap: var(--ad-space-4);
    margin: var(--ad-space-2) 0 var(--ad-space-3);
    padding: var(--ad-space-4);
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-r-md);
    background: var(--ad-bg);
}

.admin-secset__group + .admin-secset__group {
    /* De l'air AVANT le filet (2026-10-22) : il touchait le champ du dessus. */
    margin-top: var(--ad-rythme-groupe);
    padding-top: 28px;
    border-top: 1px solid var(--ad-border);
}
/* L'intertitre porte le nom du groupe et, s'il y a lieu, sa bulle d'aide : il
   remplace les phrases « Réglages de la section : », « Fond média : », « Bord
   bas : » qui servaient d'étiquettes à des rangées entières. */
.admin-secset__group-title {
    /* Le dessin — taille, graisse, casse, trait d'accent — est celui de tous les
       intertitres de groupe (admin-socle.css, « TROIS NIVEAUX DE TITRE »). */
    margin: 0;
}

/* TROIS COLONNES DÉCLARÉES, PAS `auto-fit` — et c'est une correction, pas un
   goût. Mesuré à l'écran le 2026-09-16 : avec `repeat(auto-fit, minmax(200px,
   1fr))`, le groupe « Apparence » tombait à DEUX colonnes (319 px par champ)
   pendant que « Mise en page » et « Bord bas » en gardaient trois (208 px). La
   cause est le sélecteur d'image, dont le contenu a une largeur minimale
   intrinsèque : `auto-fit` en tient compte et retire une colonne à tout le
   groupe. Deux grilles voisines n'alignaient donc pas leurs champs — exactement
   le défaut qu'on venait corriger.

   Un nombre de colonnes DÉCLARÉ ne dépend d'aucun contenu. `minmax(0, 1fr)`
   plutôt que `1fr` : sans le 0, une colonne ne peut pas descendre sous la
   largeur intrinsèque de ce qu'elle contient, et le problème reviendrait. */
.admin-secset__grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--ad-rythme-champ) 24px;   /* le rythme commun (2026-10-22) */
    align-items: start;
}
@media (max-width: 1100px) {
    .admin-secset__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 640px) {
    .admin-secset__grid { grid-template-columns: 1fr; }
}
.admin-secset__field {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;   /* sans quoi un <select> à longue option pousse sa colonne */
}
/* Le sélecteur d'image porte son propre balisage : on lui demande seulement de
   savoir rétrécir, sans quoi il impose sa largeur à toute la colonne. */
.admin-secset__field > * { min-width: 0; max-width: 100%; }
/* Deux cellules pour ce qui ne tient pas en une : le nom d'une forme de bord,
   une adresse de vidéo, le sélecteur d'image et son bouton. La grille retombe
   à une colonne sur petit écran, où la règle s'annule d'elle-même. */
.admin-secset__field--large { grid-column: span 2; }
@media (max-width: 640px) {
    .admin-secset__field--large { grid-column: auto; }
}

.admin-secset__label {
    font-size: var(--ad-fs-sm);
    font-weight: 600;
    color: var(--ad-text);
}
.admin-secset__hint {
    margin: 0;
    font-size: var(--ad-fs-xs, .75rem);
    line-height: 1.4;
    color: var(--ad-text-mute);
}

/* LE CONTRÔLE NE REDÉFINIT RIEN. Il porte en plus `admin-form__input` ou
   `admin-form__select`, et n'ajoute ici que sa largeur. C'était le défaut
   d'origine de cet écran — trois façons d'écrire un champ, donc trois
   apparences — et le reproduire une quatrième fois aurait été le comble.

   Mesuré avant de comprendre : avec une définition locale, les <input>
   rendaient 41 px et les <select> 38. Ni le padding ni le `box-sizing` n'en
   étaient la cause — c'était la HAUTEUR DE LIGNE, héritée à 1,5 sur l'input et
   « normal » sur le select. Le socle avait déjà tranché la question (1,3, sous
   les 38 px de `min-height`, donc c'est la hauteur minimale qui gouverne des
   deux côtés). Il n'y avait qu'à s'en servir. */
.admin-secset__control { width: 100%; }

/* L'unité (px, %) accolée au nombre, plutôt que flottant après le champ comme
   un mot orphelin. Le champ garde sa hauteur, l'unité ne la change pas. */
.admin-secset__unit {
    display: flex;
    align-items: center;
    gap: .5em;
}
.admin-secset__unit .admin-secset__control { flex: 1 1 auto; min-width: 0; }
.admin-secset__suffix {
    flex: 0 0 auto;
    font-size: var(--ad-fs-sm);
    color: var(--ad-text-mute);
}

/* Une case à cocher occupe la place d'un contrôle, pour que sa ligne s'aligne
   sur ses voisines au lieu de flotter à mi-hauteur. */
.admin-secset__check {
    display: flex;
    align-items: center;
    gap: .5em;
    min-height: var(--ad-field-h);
    font-size: var(--ad-fs-md);
    cursor: pointer;
}
.admin-secset__check input { flex: 0 0 auto; }

/* Les libellés de sous-menu gardent leur barre de langues : c'est la même
   mécanique que partout (langBar / langPanelOpen), on ne la réinvente pas. */
.admin-secset__langs { display: block; }

.admin-section-settings__note {
    margin: 0;
    padding-top: var(--ad-space-3);
    border-top: 1px solid var(--ad-border);
    font-style: italic;
}

/* ----------------------------------------------------------
   Aide SEO : compteurs + aperçu Google (SERP)
   Voir js/admin-seo.js (admin/seo.php, admin/pages.php)
   ---------------------------------------------------------- */
.seo-counter {
    font-size: var(--ad-fs-sm, .8rem);
    margin: .25rem 0 .5rem;
    color: var(--ad-text-mute, #667);
}
.seo-counter[data-state="ok"]    { color: #2e7d32; }
.seo-counter[data-state="warn"]  { color: #b8860b; }
.seo-counter[data-state="bad"]   { color: #c0392b; }
.seo-counter[data-state="muted"] { color: var(--ad-text-mute, #99a); }

.seo-serp {
    border: 1px solid var(--ad-border, #e2e2e6);
    border-radius: var(--ad-radius, 8px);
    padding: .85rem 1rem;
    margin: .5rem 0 1rem;
    background: var(--ad-surface, #fff);
    max-width: 600px;
}
.seo-serp__label {
    font-size: var(--ad-fs-label);
    font-weight: var(--ad-fw-label);
    text-transform: uppercase;
    letter-spacing: var(--ad-ls-label);
    color: var(--ad-text-mute, #99a);
    margin-bottom: .4rem;
}
.seo-serp__url {
    font-size: .8rem;
    color: #4d5156;
}
.seo-serp__title {
    color: #1a0dab;
    font-size: 1.15rem;
    line-height: 1.3;
    margin: .1rem 0 .2rem;
}
.seo-serp__desc {
    font-size: .85rem;
    line-height: 1.45;
    color: #4d5156;
}
:root[data-theme="dark"] .seo-serp__title { color: #8ab4f8; }
:root[data-theme="dark"] .seo-serp__url,
:root[data-theme="dark"] .seo-serp__desc { color: #bdc1c6; }


/* Note « composant de module », en tête de l'éditeur d'un composant relié à un
   module (Blog, Agenda, Portfolio). Le texte est GÉNÉRÉ à partir de la
   catégorie du composant — voir blockTypeModuleNote(), includes/block-types.php :
   il n'est écrit qu'une fois pour tous les composants concernés. */
.admin-block__module-note {
    margin: 0 0 var(--ad-space-md, 1rem);
    padding: var(--ad-space-sm, .5rem) var(--ad-space-md, 1rem);
    border-left: 3px solid var(--ad-accent, #ff8736);
    background: var(--ad-surface-2, #f6f7f9);
    border-radius: 0 var(--ad-radius-sm, 4px) var(--ad-radius-sm, 4px) 0;
}

/* Avertissement « aucune page ne porte ce module », en tête de l'éditeur d'un
   composant de module. Généré par contentTypeNoPageWarning() ; il disparaît de
   lui-même dès qu'une page est reliée. */
.admin-block__nopage-note {
    margin: 0 0 var(--ad-space-md, 1rem);
    padding: var(--ad-space-sm, .5rem) var(--ad-space-md, 1rem);
    border-left: 3px solid var(--ad-warn, #b8860b);
    background: var(--ad-warn-sf, #fdf6e3);
    border-radius: 0 var(--ad-r-sm, 4px) var(--ad-r-sm, 4px) 0;
}

/* ---------------------------------------------------------------------------
   « SUR QUELLES PAGES ? » — le ciblage d'un composant d'emplacement
   ---------------------------------------------------------------------------
   Ce panneau n'apparaît que dans l'éditeur d'un emplacement « autour des
   pages » : un composant posé DANS une page s'affiche là où il est, la
   question n'a pas de sens pour lui.

   LA LISTE SE MASQUE EN CSS, PAS EN JAVASCRIPT. Le gestionnaire délégué
   `data-toggle-class` de js/admin.js bascule une classe sur l'état `checked`
   de l'élément cliqué : il convient à une case à cocher, pas à un GROUPE DE
   RADIOS, où c'est le retour à « toutes les pages » qui doit refermer la
   liste — or ce bouton-là n'a rien à basculer. `:has()` dit exactement la
   règle voulue, sans une ligne de script, et le socle l'emploie déjà
   (`.content-item:not(:has(> .content-item__link))`, components.css).
   ------------------------------------------------------------------------ */
.block-scope__modes {
    display: flex;
    flex-direction: column;
    gap: .3rem;
    margin-bottom: .7rem;
}
/* UNE SEULE COLONNE, comme la liste jumelle de l'écran « Autour des pages ».
   C'était une grille multi-colonnes : les pages s'y écoulaient de haut en bas
   puis reprenaient à côté, si bien qu'une rubrique finissait en bas d'une
   colonne et ses filles en haut de la suivante. L'indentation était bien là —
   c'est la grille qui coupait l'arborescence en morceaux.
   Corrigé sur l'écran des emplacements le 2026-09-17, mais PAS ici : deux
   listes qui font la même chose et ne se ressemblaient plus. Relevé par
   Patrick le jour même. La liste défile désormais au lieu de s'étaler. */
.block-scope__pages {
    display: flex;
    flex-direction: column;
    gap: 2px;
    max-height: 18rem;
    overflow-y: auto;
    padding: .6rem .7rem;
    border: 1px solid var(--ad-line, #d9dde3);
    border-radius: var(--ad-radius-sm, 4px);
    background: var(--ad-bg, #fff);
}
/* « Sur toutes les pages » : la liste n'a plus d'objet, elle disparaît. */
.block-scope:has(input[value="all"]:checked) .block-scope__pages { display: none; }

/* L'indentation rend l'arborescence lisible : une sous-page se lit comme une
   sous-page. `--niv` est posé en ligne par le gabarit, comme partout ailleurs
   dans le CMS. */
.block-scope__page { padding-left: calc(var(--niv, 0) * 1.1rem); }

/* UN TITRE QUI AFFICHE LE NOM DE SA PAGE N'A RIEN À SAISIR.
   On masque le seul champ de TEXTE, pas le panneau : le niveau de titre y vit
   aussi, et il reste réglable dans les deux modes. La barre de langues part
   avec — trois onglets pour un champ absent n'ont plus d'objet.
   `:has()` plutôt qu'une classe posée sur chaque champ : la saisie d'un
   composant se rend par une longue alternative selon l'éditeur, et il aurait
   fallu la marquer à chaque branche — donc en oublier une au prochain ajout. */
.admin-block__body.is-titre-auto .admin-form__group:has(> input[name^="content_"]),
.admin-block__body.is-titre-auto .admin-form__group:has(> textarea[name^="content_"]),
.admin-block__body.is-titre-auto > .admin-lang { display: none; }

/* DEUX COLONNES, QUOI QU'IL ARRIVE — pour les grilles dont les champs vont PAR
   PAIRES : un réglage et sa valeur libre, un réglage et sa valeur libre. À trois
   colonnes, la seconde paire se décalerait d'un cran et chaque champ perdrait
   son voisin. La grille ordinaire, elle, garde ses trois colonnes : ses champs
   sont indépendants les uns des autres. */
.design-grid--paires { grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (max-width: 640px) {
    .design-grid--paires { grid-template-columns: 1fr; }
}

/* ==========================================================================
   CHARTE GRAPHIQUE — tableau « Lisibilité »
   --------------------------------------------------------------------------
   Le rapport de contraste de chaque couple encre/fond, en clair et en sombre.
   Rendu par PHP, tenu à jour par js/admin-design-contraste.js.

   L'INTITULÉ DE LIGNE EST UN `th`, et il faut le désarmer : `.admin-table th`
   met les en-têtes en capitales espacées, ce qui convient à « MODE CLAIR » et
   rend « TEXTE PRINCIPAL SUR LE FOND » pénible à lire sur neuf lignes.

   LA COULEUR NE PORTE PAS SEULE LE VERDICT (WCAG 1.4.1) : chaque case dit un
   symbole ET un mot. Un écran qui mesure la lisibilité serait mal venu de
   n'être lisible qu'en vision trichromate.
   ========================================================================== */
.contraste-intro { max-width: var(--ad-measure); margin-bottom: var(--ad-space-2); }

.contraste-table { table-layout: auto; }

/* Intitulé de ligne : du texte courant, pas une étiquette de colonne. */
.contraste-table th[scope="row"] {
    text-transform: none;
    letter-spacing: normal;
    font-size: var(--ad-fs-sm);
    background: var(--ad-bg);
    vertical-align: top;
    width: 40%;
}
.contraste-couple__nom { display: block; color: var(--ad-text); }
.contraste-couple__ou {
    display: block;
    margin-top: 2px;
    font-weight: 400;
    font-size: var(--ad-fs-xs);
    line-height: 1.3;
    color: var(--ad-text-mute);
}

.contraste-seuil {
    font-family: var(--ad-font-mono);
    font-size: var(--ad-fs-mono);
    color: var(--ad-text-mute);
    white-space: nowrap;
    vertical-align: top;
}

.contraste-cell { vertical-align: top; white-space: nowrap; }
.contraste-sym {
    display: inline-block;
    width: 1.4em;
    font-weight: 700;
    font-size: var(--ad-fs-lg);
    line-height: 1;
}
/* Le chiffre est une DONNÉE qu'on compare d'une ligne à l'autre : chasse fixe,
   et tabular-nums pour que les virgules tombent les unes sous les autres. */
.contraste-val {
    font-family: var(--ad-font-mono);
    font-size: var(--ad-fs-mono);
    font-variant-numeric: tabular-nums;
}
.contraste-dit {
    display: block;
    margin-top: 2px;
    margin-left: 1.4em;
    font-size: var(--ad-fs-xs);
    line-height: 1.3;
    white-space: normal;
    color: var(--ad-text-mute);
}

.contraste-cell--ok        .contraste-sym { color: var(--ad-success); }
.contraste-cell--limite    .contraste-sym { color: var(--ad-warn); }
.contraste-cell--faible    .contraste-sym { color: var(--ad-danger); }
.contraste-cell--illisible .contraste-sym { color: var(--ad-text-mute); }

/* Un fond très doux sur ce qui ne va pas — assez pour attirer l'œil de loin,
   assez discret pour ne pas transformer une charte sobre en alarme. */
.contraste-cell--limite { background: var(--ad-warn-sf); }
.contraste-cell--faible { background: var(--ad-danger-sf); }
.admin-table tr:hover .contraste-cell--limite { background: var(--ad-warn-sf); }
.admin-table tr:hover .contraste-cell--faible { background: var(--ad-danger-sf); }

/* LA PHRASE D'EXPLICATION NE SE MASQUE PAS EN ÉTROIT. Elle l'était, jusqu'à ce
   qu'on mesure : le volet d'administration fait 668px de large dans le
   navigateur intégré, donc sous le seuil — et « Le corps de toutes les pages »
   est exactement ce qu'un client débutant vient chercher pour comprendre ce
   qu'il regarde. On lui laisse la place de s'enrouler ; c'est la colonne fixe
   de 40% qui cède, pas le texte. */
@media (max-width: 700px) {
    .contraste-table th[scope="row"] { width: auto; }
}

/* Sous le champ « Bordure » : le contour de champ que le CMS dérive.
   Une information, pas un réglage — d'où l'absence d'encadré et de bouton. */
.contour-derive {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 5px;
    margin: 5px 0 0;
    font-size: var(--ad-fs-xs);
    line-height: 1.3;
    color: var(--ad-text-mute);
}
.contour-derive__pastille {
    width: 13px;
    height: 13px;
    flex: 0 0 auto;
    border-radius: 3px;
    /* Un filet foncé AUTOUR de la pastille : sans lui, un contour très sombre
       posé sur le fond clair de l'administration se lirait comme un trou. */
    box-shadow: inset 0 0 0 1px rgba(18, 22, 31, .22);
}
.contour-derive__hex {
    font-family: var(--ad-font-mono);
    font-size: var(--ad-fs-mono);
    color: var(--ad-text-soft);
}


/* =============================================================================
   ONGLETS « CONTENU / RÉGLAGES » D'UN COMPOSANT ET D'UNE LIGNE (2.9.4)
   =============================================================================
   Voir js/admin-onglets.js et admin/includes/block-reglages.php. Les morceaux
   d'un formulaire portent data-mini-for ; le script ne fait que poser `hidden`.
   Une règle d'affichage posée sur un morceau (flex, grid…) l'emporterait sur
   `hidden` : on le rend donc prioritaire. */
[data-mini-for][hidden] { display: none !important; }

.block-onglets {
    display: flex;
    gap: var(--ad-space-1);
    border-bottom: 1px solid var(--ad-border);
    margin: 0 0 var(--ad-space-3);
}
.block-onglet {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: none;
    border: 0;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    padding: 7px var(--ad-space-3);
    font: inherit;
    font-size: var(--ad-fs-sm);   /* la même que les onglets de la section (.admin-page-tab) */
    font-weight: 600;
    color: var(--ad-text-mute);
    cursor: pointer;
}
.block-onglet .lt-icon, .admin-page-tab--icone .lt-icon { width: 16px; height: 16px; flex: none; }
.admin-page-tab--icone { display: inline-flex; align-items: center; gap: 6px; }
.block-onglet:hover { color: var(--ad-text); }
.block-onglet.is-active { color: var(--ad-accent); border-bottom-color: var(--ad-accent); }

/* Les réglages d'un composant reprennent la grille de ceux d'une section
   (.admin-secset__*), sans le cadre : le composant est déjà dans une carte. */
.block-reglages { display: flex; flex-direction: column; gap: var(--ad-space-4); margin-bottom: var(--ad-space-3); }
.block-reglages__groupe + .block-reglages__groupe,
.block-reglages + .block-reglages__groupe,
.block-reglages__groupe + .block-reglages { padding-top: 28px; border-top: 1px solid var(--ad-border); }
/* LES RÉGLAGES ET LE CONTENU D'UN COMPOSANT, séparés comme deux groupes (2026-10-22) :
   « Image (FR) » suivait « Comportement » sans rien entre eux. */
.block-reglages:not([hidden]) { margin-bottom: var(--ad-rythme-groupe); padding-bottom: 8px; border-bottom: 1px solid var(--ad-border); }
.block-reglages--bas { margin-top: var(--ad-space-3); }
/* Un groupe posé par un éditeur (les cartes d'une grille, les réglages d'un diaporama)
   n'est pas voisin du panneau : même séparation, par son étiquette. */
.block-reglages__groupe[data-mini-for] { margin-top: var(--ad-space-3); padding-top: var(--ad-space-3); border-top: 1px solid var(--ad-border); }
.block-reglages .admin-secset__hint { margin-top: var(--ad-space-1, 4px); }

/* Les réglages d'une LIGNE, dans leur onglet : un champ « Colonnes » qui porte deux
   listes (nombre, puis disposition) côte à côte dans sa cellule. */
.admin-row__reglages {
    margin: var(--ad-space-2) 0 var(--ad-space-3);
    padding: var(--ad-space-3) var(--ad-space-4);
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-r-md);
    background: var(--ad-bg);
}
.admin-row__reglages .admin-row__layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
    gap: var(--ad-space-2);
}
.admin-row__reglages .admin-row__layout select { width: 100%; }
.admin-row__header .block-onglets { margin: 0; border-bottom: 0; }
/* L'aide du composant, au bout de la barre d'onglets. */
.block-onglets__aide { margin-left: auto; align-self: center; display: inline-flex; }

/* Étiquette d'un réglage suivie de son « ? » : sur une même ligne, le « ? » hors de l'étiquette. */
.admin-secset__label-row { display: flex; align-items: center; gap: .4em; }


/* =============================================================================
   « PARTIR DE » — le choix d'un modèle de section (chantier 2)
   =============================================================================
   Des cartes à cocher, une vignette dessinée au-dessus du nom. Le bouton radio reste
   dans la page (accessible au clavier) mais se voit par le cadre de la carte. */
.modele-choix { border: 0; margin: 0 0 var(--ad-space-3); padding: 0; min-width: 0; }
.modele-choix__liste {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));   /* une vignette et un nom : on en met plus par ligne */
    gap: var(--ad-space-2);
    margin-top: var(--ad-space-1);
}
.modele-choix__famille { grid-column: 1 / -1; margin: var(--ad-space-2) 0 0; font-size: var(--ad-fs-xs, 12px); font-weight: 600; letter-spacing: .04em; text-transform: uppercase; color: var(--ad-text-mute); }
.modele-choix__item { position: relative; display: flex; }
.modele-choix__item .modele-choix__carte { flex: 1; min-width: 0; }
.modele-choix__suppr {
    position: absolute; top: 8px; right: 8px; z-index: 1;
    display: inline-flex; padding: 4px; border: 0; border-radius: var(--ad-r-sm, 4px);
    background: var(--ad-bg); color: var(--ad-text-mute); cursor: pointer;
}
.modele-choix__suppr:hover { color: var(--ad-danger, #b42318); }
.modele-choix__suppr .lt-icon { width: 16px; height: 16px; }
.modele-choix__carte {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: var(--ad-space-2);
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-r-md);
    background: var(--ad-bg);
    cursor: pointer;
}
.modele-choix__carte:hover { border-color: var(--ad-text-mute); }
.modele-choix__carte input { position: absolute; top: 10px; left: 10px; accent-color: var(--ad-accent); }
.modele-choix__carte:has(input:checked) { border-color: var(--ad-accent); box-shadow: 0 0 0 1px var(--ad-accent); }
.modele-choix__carte:has(input:focus-visible) { outline: 2px solid var(--ad-accent); outline-offset: 2px; }
.modele-choix__vignette { display: block; border-radius: var(--ad-r-sm, 4px); overflow: hidden; line-height: 0; }
.modele-choix__vignette svg { display: block; width: 100%; height: auto; }
.modele-choix__vignette--vide { aspect-ratio: 8 / 5; border: 1px dashed var(--ad-border); background: transparent; }
.modele-choix__nom { font-weight: 600; font-size: var(--ad-fs-sm); }

/* Le champ « Nom de la section » des Réglages : le champ et son bouton « Renommer » sur une ligne. */
.admin-secset__renommer { display: flex; gap: var(--ad-space-2); align-items: center; }
.admin-secset__renommer .admin-form__input { flex: 1; min-width: 0; }

/* Nom de la section + sous-menu (ancre) : deux colonnes d'une même ligne, pour
   qu'on comprenne que l'un fabrique l'ancre et l'autre la montre dans le menu. */
.admin-secset__pair {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--ad-space-4);
    align-items: start;
}
.admin-secset__pair > .admin-secset__group + .admin-secset__group {
    padding-top: 0;
    border-top: 0;
}
@media (max-width: 900px) {
    .admin-secset__pair { grid-template-columns: 1fr; }
}
.admin-secset__pair .admin-secset__grid { grid-template-columns: 1fr; }
.admin-secset__pair .admin-secset__field--large { grid-column: auto; }

/* ============================================================
   UNE PAGE, TOUTES SES SECTIONS (chantier 87, demande de Patrick)
   ============================================================
   L'écran Contenus montre la page entière : la section éditée garde son
   éditeur complet, à sa place, et les autres l'entourent, repliées en résumé
   — nom, état, composants. Un clic sur l'une d'elles l'ouvre. */
.admin-section-resume {
    margin: 0 0 var(--ad-space-3);
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-radius, 10px);
    background: var(--ad-surface, #fff);
}
/* La poignée et le nom, sur une barre. La poignée sert aussi dans l'en-tête de la section ouverte. */
.admin-section-resume__barre { display: flex; align-items: center; }
.admin-section-resume__barre .admin-section-resume__drag { padding-left: var(--ad-space-4); }
.admin-section-resume__drag { cursor: grab; color: var(--ad-text-mute); user-select: none; font-size: 16px; flex: 0 0 auto; }
.admin-section-resume__drag:focus-visible { outline: 2px solid var(--ad-accent); outline-offset: 2px; border-radius: 4px; }
.admin-section-editor__head .admin-section-resume__drag { margin-right: var(--ad-space-2); }
/* Dans la page, l'en-tête de la section ouverte porte plus de gestes (dupliquer, supprimer) : il passe à la
   ligne plutôt que d'écraser le nom. */
.admin-section-editor--dans-page .admin-section-editor__head { flex-wrap: wrap; row-gap: var(--ad-space-2); }
.admin-section-editor--dans-page .admin-section-editor__head h2 { flex: 1 1 16rem; min-width: 0; overflow-wrap: anywhere; }
.admin-section-resume.is-dragging, .admin-section-editor.is-dragging { opacity: .5; }
.admin-main .admin-section-resume__tete {
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    gap: var(--ad-space-2);
    padding: var(--ad-space-3) var(--ad-space-4);
    color: var(--ad-text);
    text-decoration: none;
    font-weight: 650;
}
.admin-main .admin-section-resume__tete:hover { background: var(--ad-bg-sunk); text-decoration: none; }
.admin-section-resume__nom { flex: 0 1 auto; }
.admin-section-resume__ouvrir {
    margin-left: auto;
    font-size: var(--ad-fs-sm);
    font-weight: 600;
    color: var(--ad-accent);
}
.admin-section-resume__liste {
    list-style: none;
    margin: 0;
    padding: 0 var(--ad-space-4) var(--ad-space-3);
    display: grid;
    grid-template-columns: minmax(0, 1fr);   /* sans quoi un long aperçu élargit la carte */
    gap: 2px;
}
.admin-section-resume__liste li { min-width: 0; }
.admin-main .admin-section-resume__liste a {
    display: flex;
    align-items: center;
    gap: var(--ad-space-2);
    min-width: 0;
    padding: 4px var(--ad-space-2);
    border-radius: 6px;
    color: var(--ad-text);
    text-decoration: none;
    font-size: var(--ad-fs-sm);
}
.admin-main .admin-section-resume__liste a:hover { background: var(--ad-bg-sunk); text-decoration: none; }
.admin-section-resume__type { font-weight: 600; flex: 0 0 auto; }
.admin-section-resume__apercu {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    color: var(--ad-text-mute);
}
/* Les lignes d'une section repliée, en colonnes comme la page (2026-10-26). */
.admin-section-resume__lignes { padding: 0 var(--ad-space-4) var(--ad-space-3); display: grid; gap: var(--ad-space-2); }
.admin-section-resume__lignes > .admin-section-resume__liste { padding: 0; }
.admin-section-resume__ligne {
    display: grid;
    grid-template-columns: var(--cols, 1fr);
    gap: var(--ad-space-2);
    align-items: start;
}
.admin-section-resume__ligne > .admin-section-resume__col {
    padding: 4px;
    border: 1px dashed var(--ad-border);
    border-radius: var(--ad-r-md, 8px);
    align-self: stretch;
}
.admin-section-resume__col-vide {
    padding: 4px var(--ad-space-2);
    font-size: var(--ad-fs-sm);
    color: var(--ad-text-mute);
    font-style: italic;
}
@media (max-width: 900px) {
    .admin-section-resume__ligne { grid-template-columns: 1fr; }
}
.admin-section-resume__vide {
    margin: 0;
    padding: 0 var(--ad-space-4) var(--ad-space-3);
    font-size: var(--ad-fs-sm);
    color: var(--ad-text-mute);
}
/* La section ouverte se détache des résumés qui l'entourent. */
.admin-section-editor--dans-page {
    margin: var(--ad-space-4) 0;
    padding: var(--ad-space-4);
    border: 2px solid var(--ad-accent);
    border-radius: var(--ad-radius, 10px);
    scroll-margin-top: calc(var(--ad-header-h, 64px) + 12px);
}
.admin-section-resume { scroll-margin-top: calc(var(--ad-header-h, 64px) + 12px); }

/* LISTE | VISUEL : le bouton vit dans css/admin-bascule.css (commun à la Liste et au Visuel). */
