/* =====================================================
   CIVIKA — Interface d'administration
   ===================================================== */
/* Protection globale : `[hidden]` doit toujours cacher, quel que soit le
   `display` explicite ajouté par une règle plus spécifique. Sans ce
   `!important`, tout `display: flex/block/grid` avec sélecteur composite
   (spé ≥ 0,2,0) écrase l'attribut `[hidden]` (spé 0,1,0) — piège
   récurrent (file inputs, sous-pickers, panneaux). */
[hidden] { display: none !important; }
:root {
    /* Hauteur reelle de la .topbar : padding 14 + 14, contenu 34 px
       (l'avatar, plus haut que le h1), bordure 1 px. Tout ce qui se colle
       SOUS elle en `position: sticky` s'y refere plutot que de recopier un
       nombre : la topbar a deja grandi une fois, et trois offsets ecrits en
       dur sont alors passes derriere elle sans que rien ne le signale.
       --sticky-sous-topbar ajoute la respiration : coller pile a la bordure
       donne l'impression que les deux barres n'en font qu'une. */
    --topbar-h: 63px;
    --sticky-sous-topbar: 71px;

    --bleu: #2563eb;
    --bleu-fonce: #0f172a;
    --bleu-clair: #eef2ff;
    --encre: #233044;
    --gris: #64748b;
    --fond: #f2f4f7;
    --blanc: #ffffff;
    --bordure: #dfe5ec;
    --ok: #15803d;
    --ok-fond: #dcf5e5;
    --warn: #b45309;
    --warn-fond: #fef3c7;
    --danger: #b91c1c;
    --danger-fond: #fee2e2;
    --rayon: 10px;
    --ombre: 0 1px 3px rgba(16, 24, 40, .08);
}
* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
    margin: 0;
    font-family: 'Roboto', -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Arial, sans-serif;
    font-size: 15px;
    font-weight: 350; /* Roboto Variable : texte courant légèrement allégé */
    color: var(--encre);
    background: var(--fond);
    line-height: 1.55;
}
a { color: var(--bleu); text-decoration: none; }
a:hover { text-decoration: underline; }
/* Un bouton-picto ne se déplace jamais : son icône est le bouton lui-même */
.btn-ico .ico, .btn-ico:hover .ico { transform: none; }
h1, h2, h3 { line-height: 1.25; }
h2 { font-size: 18px; margin: 0 0 14px; }
h3 { font-size: 15px; margin: 18px 0 10px; }

/* ---------- Connexion / 2FA ---------- */
.auth-body {
    display: flex; align-items: center; justify-content: center;
    min-height: 100vh; background: linear-gradient(150deg, var(--bleu-fonce), var(--bleu) 130%);
    padding: 20px;
}
.auth-card {
    background: var(--blanc); border-radius: 14px; box-shadow: 0 18px 50px rgba(0, 0, 0, .28);
    width: 100%; max-width: 400px; padding: 36px 34px;
}
.auth-logo { text-align: center; margin-bottom: 18px; }
.auth-logo img { height: 56px; }
.auth-card h1 { font-size: 20px; text-align: center; margin: 0 0 6px; }
.auth-intro { color: var(--gris); text-align: center; margin: 0 0 20px; font-size: 14px; }
.auth-note { text-align: center; color: var(--gris); font-size: 13px; margin-top: 18px; }
.input-code { text-align: center; font-size: 26px; letter-spacing: 10px; font-variant-numeric: tabular-nums; }

/* ---------- Structure ---------- */
.admin-shell { display: flex; min-height: 100vh; }
.sidebar {
    width: 240px; flex-shrink: 0; background: var(--bleu-fonce); color: #cfd9e6;
    display: flex; flex-direction: column; position: sticky; top: 0; height: 100vh; overflow-y: auto;
}
.sidebar-brand { padding: 18px 20px 10px; }
.sidebar-brand img { height: 42px; filter: brightness(0) invert(1); }
.sidebar-commune {
    padding: 4px 20px 14px; font-size: 13px; font-weight: 600; color: #8fb3d9;
    border-bottom: 1px solid rgba(255, 255, 255, .08);
}
.sidebar-nav { flex: 1; padding: 12px 10px; }
.nav-titre {
    font-size: 11px; text-transform: uppercase; letter-spacing: .8px;
    color: #7d93ac; padding: 14px 12px 4px;
}
.nav-link {
    display: flex; align-items: center; gap: 10px; padding: 8px 12px; border-radius: 8px;
    color: #cfd9e6; font-size: 14px; margin: 1px 0;
}
.nav-link .ico { opacity: .75; }
.nav-link.active .ico { opacity: 1; }
.ico { vertical-align: -0.18em; flex-shrink: 0; }
h2 .ico { vertical-align: -0.12em; color: var(--bleu); margin-right: 2px; }
/* Bandeau d'avertissement (nom de domaine, autres nudges orangés) : la
   règle globale `h2 .ico { color: var(--bleu) }` bat un simple `<span
   style="color">` parent (l'`.ico` est sur le SVG lui-même). On monte la
   spécificité pour reprendre la main sur la teinte du picto. */
h2.h2-orange .ico { color: #f59e0b; }
.btn .ico { vertical-align: -0.22em; }
.nav-link:hover { background: rgba(255, 255, 255, .07); text-decoration: none; }
.nav-link.active { background: var(--bleu); color: #fff; font-weight: 600; }
.sidebar-footer { padding: 10px; border-top: 1px solid rgba(255, 255, 255, .08); }
.nav-badge {
    margin-left: auto; background: #ef4444; color: #fff; font-size: 11px; font-weight: 700;
    border-radius: 999px; padding: 1px 7px; line-height: 1.5;
}
/* Modules non activés : présents dans le menu mais grisés, avec un
   cadenas discret pour signaler qu'un clic ouvre la landing
   d'activation plutôt que l'écran fonctionnel. */
.nav-link-inactif { opacity: .45; }
.nav-link-inactif:hover { opacity: .75; background: rgba(255, 255, 255, .05); }
.nav-link-cadenas { margin-left: auto; display: inline-flex; opacity: .8; }

/* Landing d'un module non souscrit — présentation centrée, pastille
   picto, tarif mis en avant et CTA vers l'écran des modules. */
.module-inactif-corps { text-align: center; padding: 26px 16px 32px; }
.module-inactif-picto {
    width: 68px; height: 68px; margin: 0 auto 14px;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 999px; background: var(--bleu-clair, #eef2ff);
    color: var(--bleu, #2563eb);
}
.module-inactif-corps h2 { margin: 0 0 4px; font-size: 24px; }
.module-inactif-baseline { font-size: 15px; color: var(--gris); margin: 0 0 14px; }
.module-inactif-tarif {
    /* Block-level flex : le pill prend juste la place de son contenu
       mais force un retour à la ligne — les CTA passent en-dessous. */
    display: flex; flex-direction: column; align-items: center; gap: 8px;
    width: fit-content;
    margin: 28px auto 24px; padding: 22px 34px;
    background: var(--bleu-clair, #eef2ff); border-radius: 12px;
}
/* Tarif mensuel en très gros, coup de projecteur commercial — le prix
   annuel reste discret juste en-dessous pour transparence, sans jamais
   masquer l'ancrage « 8 € par mois ». */
.module-inactif-tarif-mensuel {
    font-size: 44px; font-weight: 800; color: var(--bleu);
    line-height: 1; letter-spacing: -0.02em;
    display: inline-flex; align-items: baseline; gap: 6px;
}
.module-inactif-tarif-mensuel .muted { font-size: 16px; font-weight: 500; letter-spacing: 0; }
.module-inactif-tarif-annuel { font-size: 13px; }
.module-inactif-actions {
    /* Block-level flex : force le passage à la ligne sous le pill tarif.
       Les 2 boutons se centrent l'un à côté de l'autre, wrap sur mobile. */
    display: flex; gap: 12px; flex-wrap: wrap; justify-content: center;
    margin-top: 8px;
}
.module-inactif-note { margin-top: 36px; font-size: 12.5px; }
.row-non-lu td { background: #f4f7ff; }
.row-message-corps td { background: #f8fafc; }
.message-corps { padding: 6px 4px 10px; white-space: pre-line; max-width: 800px; }

.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.topbar {
    background: var(--blanc); border-bottom: 1px solid var(--bordure);
    padding: 14px 28px; display: flex; align-items: center; justify-content: space-between;
    position: sticky; top: 0; z-index: 10;
}
.topbar h1 { font-size: 19px; margin: 0; }
.topbar-user { color: var(--gris); font-size: 14px; display: flex; align-items: center; gap: 8px; flex-shrink: 0; }

/* ---------- Bouton « Voir le site » dans la topbar (droite) ----------
   Fond très léger, radius arrondi, look neutre pour ne pas concurrencer
   les CTA principaux des écrans. Le picto globe suffit à identifier. */
.topbar-btn {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 7px 12px; border-radius: 8px;
    background: var(--fond, #f7f9fb);
    color: var(--encre, #0f172a); text-decoration: none;
    font-size: 13.5px; font-weight: 500;
    border: 1px solid transparent;
    transition: background .15s ease, border-color .15s ease;
}
.topbar-btn:hover,
.topbar-btn:focus { background: #eef2f7; border-color: var(--bordure); text-decoration: none !important; }
.topbar-btn .ico { opacity: .75; }
/* Sur mobile on masque le label textuel, seule l'icône reste */
@media (max-width: 700px) {
    .topbar-btn span { display: none; }
    .topbar-btn { padding: 7px 9px; }
}

/* ---------- Menu utilisateur dans la topbar (<details>) ----------
   Avatar rond avec initiales + nom + rôle empilés + chevron. Au clic,
   dropdown positionné à droite avec Mon compte / Déconnexion. Le
   handler global dans admin.js ferme le menu au clic extérieur. */
.topbar-user-menu { position: relative; margin: 0; }
.topbar-user-menu > summary {
    list-style: none; cursor: pointer;
    display: inline-flex; align-items: center; gap: 10px;
    padding: 5px 10px 5px 5px; border-radius: 999px;
    background: transparent; transition: background .15s ease;
    color: var(--encre, #0f172a);
    user-select: none;
}
.topbar-user-menu > summary::-webkit-details-marker { display: none; }
.topbar-user-menu > summary:hover { background: var(--fond, #f7f9fb); }
.topbar-user-menu[open] > summary { background: var(--fond, #f7f9fb); }
.topbar-user-menu > summary .ico { color: var(--gris); transition: transform .15s ease; }
.topbar-user-menu[open] > summary .ico { transform: rotate(180deg); }

/* Avatar : cercle 34 px, initiales en gras sur pastille dégradée
   bleu → violet (cohérent avec les CTA Civika). */
.topbar-avatar {
    display: inline-flex; align-items: center; justify-content: center;
    width: 34px; height: 34px; border-radius: 50%;
    background: linear-gradient(135deg, #2563eb 0%, #7c3aed 100%);
    color: #ffffff; font-size: 13px; font-weight: 600;
    letter-spacing: .5px;
    flex-shrink: 0;
}
.topbar-user-nom {
    display: flex; flex-direction: column;
    line-height: 1.2; font-size: 13px;
    max-width: 180px;
}
.topbar-user-nom-plein {
    font-weight: 600; color: var(--encre, #0f172a);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.topbar-user-role { color: var(--gris); font-size: 11.5px; }
/* Sur mobile on garde juste l'avatar */
@media (max-width: 900px) {
    .topbar-user-nom { display: none; }
    .topbar-user-menu > summary { padding: 4px; }
}

/* Dropdown : positionnée sous le bouton, ombre marquée, radius 10 px,
   min-width raisonnable pour aérer les items. */
.topbar-user-drop {
    position: absolute; right: 0; top: calc(100% + 6px); z-index: 40;
    min-width: 200px;
    background: var(--blanc); border: 1px solid var(--bordure);
    border-radius: 10px; padding: 5px;
    box-shadow: 0 14px 34px -8px rgba(16, 24, 40, .26);
}
.topbar-user-drop-item {
    display: flex; align-items: center; gap: 10px;
    padding: 9px 12px; border-radius: 6px;
    color: var(--encre, #0f172a); text-decoration: none;
    font-size: 13.5px; font-weight: 500;
}
.topbar-user-drop-item:hover,
.topbar-user-drop-item:focus { background: var(--fond, #f7f9fb); text-decoration: none !important; }
.topbar-user-drop-item .ico { color: var(--gris); }

/* Fil d'Ariane — assure le retour en arrière sur tous les écrans d'édition */
.topbar-titre { min-width: 0; }
.fil {
    display: flex; align-items: center; gap: 3px; flex-wrap: wrap;
    font-size: 12.5px; color: var(--gris); margin-bottom: 3px;
}
.fil a {
    color: var(--gris); text-decoration: none; padding: 2px 6px; border-radius: 6px;
    display: inline-flex; align-items: center; font-weight: 500;
}
.fil a:hover { background: #eef2f7; color: var(--bleu); text-decoration: none; }
.fil-sep { display: inline-flex; color: #b6c0cd; }
.fil-courant { padding: 2px 6px; font-weight: 600; color: var(--encre); }
/* Le titre reprend le fil : inutile de l'afficher deux fois sur grand écran */
.fil + h1 { position: absolute; left: -9999px; }
@media (max-width: 700px) {
    .fil-courant, .fil-courant + * { display: none; }
    .fil + h1 { position: static; left: auto; }
}
.content { padding: 24px 34px 60px; max-width: 1800px; width: 100%; }

/* ---------- Badge d'impersonation ---------- */
/* Badge compact dans la topbar-user, fond orange vif + contenu
   orange foncé pour rester dans la palette « alerte » sans être
   aussi lourd que le bordeaux d'avant. Hauteur reste sous celle du
   h1 (~23px) pour ne PAS agrandir la topbar. */
.badge-impersonation {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 5px; margin-right: 4px;
    background: #fed7aa; color: #9a3412;
    border-radius: 4px; font-size: 11.5px; font-weight: 600;
    line-height: 1;
}
.badge-impersonation .ico { width: 12px; height: 12px; }
/* `display: contents` : le <form> disparaît du layout, le <button>
   devient enfant flex DIRECT du .badge-impersonation → plus de
   hauteur/baseline parasite ajoutée par le form. */
.badge-impersonation .inline-form { display: contents; }
.badge-impersonation-quit {
    display: inline-flex; align-items: center; justify-content: center;
    width: 16px; height: 16px; padding: 0;
    margin: 0 0 0 1px;   /* zéro top/bottom pour ne pas gonfler la hauteur */
    background: rgba(154, 52, 18, .18); color: #9a3412;
    border: 0; border-radius: 3px; cursor: pointer;
    transition: background .1s ease;
}
.badge-impersonation-quit .ico { width: 10px; height: 10px; }
.badge-impersonation-quit:hover { background: rgba(154, 52, 18, .3); }

/* ---------- Cartes / grilles ----------
   Convention Civika : chaque carte est une enveloppe fine (.card, padding 1px)
   contenant un wrapper .card-inner qui porte le vrai padding (1.5rem). Ce
   découpage isole les marges des enfants du bord de la carte — un h2 ou une
   liste avec margin-top ne « mange » plus le padding — et laisse la place à
   des éléments bord-à-bord (bandeau, ruban) quand on veut sortir du wrapper.
   Toute nouvelle carte doit adopter le pattern ; la règle :not(:has(...))
   ci-dessous préserve les cartes existantes qui n'ont pas encore été migrées. */
.card {
    background: var(--blanc); border: 1px solid var(--bordure); border-radius: var(--rayon);
    box-shadow: var(--ombre); padding: 1px; margin-bottom: 20px;
}
/* IMPORTANT : le wrapper interne utilise `margin` — pas `padding`. Avec un
   padding, les marges natives du premier <h2> ou dernier <p> s'ajoutent au
   padding et créent des espaces cumulés (24 px + 16 px = 40 px). Avec une
   marge, ces marges enfants FUSIONNENT avec la marge du wrapper (règle CSS
   du margin-collapse), on garde 24 px de respiration constants. Le
   `padding: 1px` sur .card l'isole du reste de la page. */
.card-inner { margin: 1.5rem; }
/* Rétro-compat : cartes non migrées → padding direct sur .card (le seul
   moyen d'obtenir l'espace visuel sans wrapper enfant). */
.card:not(:has(> .card-inner)) { padding: 1.5rem; }
.card-max { max-width: 640px; }
/* Carte « éclipsée » : contenu affiché en filigrane sous un message central.
   Sert quand une option est encore configurable mais désactivée par une
   autre option prioritaire (ex. 2FA e-mail masquée par la 2FA appli).
   La carte reste interactive au clic — un simple `pointer-events: none`
   sur .card-inner rendrait le message inaccessible aussi. */
.card-eclipse { position: relative; }
.card-eclipse > .card-inner { opacity: .25; filter: grayscale(.4); pointer-events: none; user-select: none; }
.card-eclipse-message {
    position: absolute; inset: 0; z-index: 2;
    display: flex; align-items: center; justify-content: center;
    padding: 24px; text-align: center; font-size: 14px; font-weight: 500;
    color: var(--encre); background: transparent;
}
.grid-2 { display: flex; gap: 20px; flex-wrap: wrap; margin-top: 24px; }
/* La toute première .grid-2 d'un conteneur ne prend pas de marge
   haute — le padding du .card-inner ou du form-page fait l'espace. */
.grid-2:first-child { margin-top: 0; }
.grid-2 > * { flex: 1; min-width: 300px; }
.grid-2-nowrap { align-items: flex-start; }

.stats-row { display: flex; gap: 16px; flex-wrap: wrap; margin-bottom: 20px; }
.stat-card {
    flex: 1; min-width: 150px; background: var(--blanc); border: 1px solid var(--bordure);
    border-radius: var(--rayon); box-shadow: var(--ombre); padding: 16px 20px;
}
.stat-value { font-size: 30px; font-weight: 700; color: var(--bleu-fonce); }
.stat-label { color: var(--gris); font-size: 13px; }
.stat-alerte { border-color: #fca5a5; background: #fff7f7; }
.stat-alerte .stat-value { color: var(--danger); }

/* ---------- Tableaux ---------- */
table { width: 100%; border-collapse: collapse; font-size: 14px; }
th { text-align: left; color: var(--gris); font-size: 12px; text-transform: uppercase; letter-spacing: .4px; }
th, td { padding: 12px 2px; border-bottom: 1px solid var(--bordure); vertical-align: top; }
td.col-actions, th.col-actions { padding: 9px 2px; }
/* Le formulaire ne doit pas contribuer à la hauteur de la cellule : ses
   enfants (boutons cachés + un bouton d'action) se comportent comme s'ils
   étaient enfants directs du td. Évite le décalage de baseline que provoque
   un inline-block wrapper autour d'un bouton icône. */
td .inline-form { display: contents; }
/* Un bouton nu directement enfant d'un <form> hérite parfois d'un margin
   vertical (agent utilisateur ou reset de bouton) : ça gonflait la hauteur
   du <tr> alors même que le form était en display: contents. On force la
   marge à zéro sur ce cas précis. */
td form > button.btn-ico { margin-top: 0; margin-bottom: 0; }
/* Neutralise la marge par défaut des <p> imbriqués dans une cellule :
   sans cela chaque paragraphe gonfle la hauteur de ligne du listing
   d'un ~1 em, rendant les tableaux illisiblement aérés. */
td p, th p { margin: 0; }
td p + p, th p + p { margin-top: 4px; }
tbody tr:hover { background: #f8fafc; }
/* Lignes cliquables : toute la ligne mène à l'édition, sans soulignement */
tbody tr[data-href] { cursor: pointer; }
/* Titres et libellés dans les listings : couleur ENCRE (pas de lien
   bleu qui alourdirait le tableau visuellement). Le hover reprend le
   bleu de charte pour signaler la nature cliquable. */
table a { text-decoration: none; color: var(--encre, #0f172a); }
table a:hover { text-decoration: none; color: var(--bleu); }
/* Sélecteur d'état : le badge ouvre un menu listant les états possibles */
.statut-dd { position: relative; display: inline-block; }
.statut-dd > summary {
    list-style: none; cursor: pointer; display: inline-flex; align-items: center; gap: 4px;
    transition: filter .12s ease;
}
.statut-dd > summary::-webkit-details-marker { display: none; }
.statut-dd > summary:hover { filter: brightness(.93); }
.statut-dd > summary .ico { opacity: .65; }
.statut-dd[open] > summary .ico { transform: rotate(180deg); }
.statut-dd.badge-chargement { opacity: .45; pointer-events: none; }
.statut-menu {
    position: absolute; left: 0; top: calc(100% + 6px); z-index: 40; min-width: 170px;
    background: var(--blanc); border: 1px solid var(--bordure); border-radius: 12px; padding: 5px;
    box-shadow: 0 14px 34px -8px rgba(16, 24, 40, .26);
}
.statut-option {
    display: flex; align-items: center; justify-content: space-between; gap: 10px; width: 100%;
    border: none; background: none; cursor: pointer; font: inherit; padding: 6px 8px;
    border-radius: 8px; text-align: left; color: var(--encre);
}
.statut-option:hover { background: #f1f5f9; }
/* Même règle que pour les langues : l'état actif reste identifiable au survol */
.statut-option.statut-option-actif,
.statut-option.statut-option-actif:hover { background: var(--bleu-clair); }
.statut-option-actif .ico { color: var(--ok); }
tbody tr:last-child .statut-menu, tbody tr:nth-last-child(2) .statut-menu { top: auto; bottom: calc(100% + 6px); }
.table-clean th { text-transform: none; font-size: 14px; width: 42%; color: var(--encre); }
/* Largeurs de colonnes standardisées pour l'ensemble des listings —
   pastilles de statut, dates et actions ont une empreinte régulière
   quel que soit le module (actus, agenda, alertes, équipe…). */
.col-actions { text-align: right; white-space: nowrap; width: 130px; }
/* Colonne Échéance des modules : héberge soit la date de fin, soit le
   bouton d'activation quand le module n'est pas encore souscrit. On
   aligne à droite pour que le bouton reste positionné comme dans
   l'ancienne colonne Actions dédiée. */
.col-echeance { text-align: right; white-space: nowrap; width: 180px; }
th.col-statut, td.col-statut { width: 130px; }
th.col-date,   td.col-date   { width: 160px; }
/* Variante « large » pour dates qui prennent plus d'espace : période
   d'événement multi-jours sur 2 lignes (du J1 / au J2), période
   d'alerte, etc. */
th.col-date-large, td.col-date-large { width: 250px; }
th.col-thumb, td.col-thumb { width: 84px; padding-right: 14px; }
/* Colonne avatar (équipe municipale, trombinoscopes) — carré compact
   juste ce qu'il faut pour un rond de 38 px + un peu de respiration. */
th.col-drag, td.col-drag { width: 36px; padding: 0 4px; }
th.col-avatar, td.col-avatar { width: 48px; padding-right: 10px; }
/* Colonne fonction — 30 % de la largeur pour laisser respirer les
   libellés longs (« 1er adjoint chargé du budget, de la culture et
   des affaires générales »). */
th.col-fonction, td.col-fonction { width: 30%; }
/* Colonnes propres au listing des messages : sujet en gros pavé
   central, date de réception à 200 px. */
th.col-sujet, td.col-sujet { width: 40%; }
th.col-recu,  td.col-recu  { width: 200px; }
/* Ligne d'un item passé (événement terminé, alerte expirée…) : le contenu
   textuel apparaît muté pour signaler visuellement que ce n'est plus actif,
   mais SANS toucher aux cellules interactives : la cellule contenant le
   badge de statut (souvent avec menu déroulant) et celle contenant les
   boutons d'action. L'opacité posée sur le <tr> lui-même cascadait sur le
   menu déroulant — options illisibles à ~30 % (0.55 * 0.55).
   On la déplace au niveau des <td>, en excluant :
     - `.col-actions` (par nom de classe)
     - toute cellule qui contient un badge/dropdown de statut (`:has()`) —
       les vues n'ont pas toutes la classe `col-statut` sur le <td>, seul
       le <th> l'a systématiquement (cas d'agenda.php notamment). */
.row-past > td { opacity: .55; }
.row-past > td.col-statut,
.row-past > td.col-actions,
.row-past > td:has(.statut-dd),
.row-past > td:has(> .badge) { opacity: 1; }
.pagination { margin-top: 14px; display: flex; gap: 6px; flex-wrap: wrap; }

/* ---------- Formulaires ---------- */
label { display: block; font-weight: 600; font-size: 13.5px; margin: 24px 0 7px; }
label:first-child { margin-top: 0; }
/* La liste est explicite plutot qu'un `input:not([type=checkbox])` : elle evite
   d'attraper les cases, les boutons radio, les curseurs et les champs fichier,
   qui ont chacun leur mise en forme. Contrepartie : un type oublie ressort en
   apparence native au milieu de champs styles — c'est arrive a `time`, qui
   manquait ici et detonnait dans les horaires de guichet. */
input[type="text"], input[type="email"], input[type="password"], input[type="search"], input[type="url"],
input[type="tel"], input[type="number"], input[type="date"], input[type="datetime-local"],
input[type="time"], input[type="month"], input[type="week"], select, textarea {
    width: 100%; padding: 9px 12px; border: 1px solid var(--bordure); border-radius: 8px;
    font: inherit; color: var(--encre); background: var(--blanc);
}
/* Largeur ajustee au contenu : ces champs ont une longueur fixe, les etirer
   sur toute la ligne comme un champ texte est inutile et disgracieux. */
input[type="time"], input[type="date"], input[type="month"], input[type="week"] {
    width: auto; min-width: 150px;
}
input[type="datetime-local"] { width: auto; min-width: 220px; }

input:focus, select:focus, textarea:focus, .editor-zone:focus {
    outline: 2px solid var(--bleu); outline-offset: 0; border-color: var(--bleu);
}
textarea { resize: vertical; }
.checkbox { display: flex; align-items: center; gap: 8px; font-weight: 500; margin: 12px 0; }
.checkbox input { width: auto; }

/* Toggle on/off — remplace la case à cocher pour les réglages binaires
   dont l'état visuel doit être immédiatement identifiable (activé /
   désactivé). Structure minimale : <label class="toggle"> avec un
   <input type="checkbox"> visuellement masqué, un <span class="toggle-switch">
   qui matérialise le rail + la poignée, puis le libellé texte. */
.toggle {
    display: flex; align-items: flex-start; gap: 12px;
    margin: 14px 0; cursor: pointer; user-select: none;
}
.toggle input[type="checkbox"] {
    position: absolute; opacity: 0; pointer-events: none;
    width: 0; height: 0;
}
.toggle-switch {
    flex: 0 0 auto;
    position: relative;
    width: 40px; height: 22px;
    background: #cbd5e1;
    border-radius: 999px;
    transition: background .18s ease;
    margin-top: 1px;
}
.toggle-switch::before {
    content: "";
    position: absolute; top: 2px; left: 2px;
    width: 18px; height: 18px;
    background: #ffffff;
    border-radius: 50%;
    box-shadow: 0 1px 3px rgba(0, 0, 0, .18);
    transition: transform .18s ease;
}
.toggle input:checked + .toggle-switch { background: var(--bleu); }
.toggle input:checked + .toggle-switch::before { transform: translateX(18px); }
.toggle input:focus-visible + .toggle-switch {
    outline: 2px solid var(--bleu); outline-offset: 2px;
}
.toggle-texte { display: block; font-weight: 500; line-height: 1.35; }
.toggle-texte strong { font-weight: 600; }
.toggle-desc {
    display: block; margin-top: 2px;
    color: var(--gris); font-weight: 400; font-size: 13px; line-height: 1.4;
}
/* Variante compacte (`.toggle-sm`) : mêmes proportions, moins de marges
   et un switch plus petit. Utile en sidebar où on empile plusieurs
   options (placement menu, image en tête…) sans casser le rythme. */
.toggle.toggle-sm { margin: 8px 0; gap: 10px; }
.toggle.toggle-sm .toggle-switch { width: 32px; height: 18px; }
.toggle.toggle-sm .toggle-switch::before { width: 14px; height: 14px; top: 2px; left: 2px; }
.toggle.toggle-sm input:checked + .toggle-switch::before { transform: translateX(14px); }
.toggle.toggle-sm .toggle-texte { font-size: 14px; }
.toggle.toggle-sm .toggle-desc { font-size: 12.5px; }
input[type="color"] { width: 52px; height: 34px; padding: 2px; border: 1px solid var(--bordure); border-radius: 8px; background: var(--blanc); }
.color-row { display: flex; align-items: center; justify-content: space-between; gap: 14px; margin-bottom: 8px; }
.color-row label { margin: 0; }
.muted { color: var(--gris); font-weight: 400; font-size: 13px; }
.empty-state { color: var(--gris); text-align: center; padding: 0; }
.page-intro { color: var(--gris); margin: 0 0 16px; }
.input-prix { width: 90px; display: inline-block; }
.input-ordre { width: 70px; }
.form-actions { margin: 6px 0 30px; }
.form-inline-block { max-width: 340px; }

/* Panneau de permissions (utilisateurs) — chaque droit est un mini switch
   on/off. Fieldset sans bordure, grille dense pour rester compacte. */
.perm-panneau { border: none; padding: 0; margin: 0; }
.perm-panneau > legend {
    font-size: 15px;
    font-weight: 600;
    color: var(--noir);
    padding: 0;
    margin-bottom: 6px;
}
.perm-grille {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 4px 12px;
    margin-top: 8px;
    align-items: stretch;
}
/* Un switch = case cachée + rail visuel + label. Hauteur uniforme pour
   éviter les décalages entre lignes courtes et longues. */
.perm-switch {
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 32px;
    padding: 4px 2px;
    margin: 0;
    font-size: 14px;
    font-weight: 400;
    color: var(--noir);
    cursor: pointer;
    user-select: none;
}
.perm-switch input[type="checkbox"] {
    position: absolute;
    opacity: 0;
    pointer-events: none;
    width: 0;
    height: 0;
}
/* Reprend la structure `.toggle-switch` du reste de l'admin mais en
   version compacte (32x18) car on empile beaucoup d'options ici. */
.perm-switch .toggle-switch {
    flex: 0 0 auto;
    width: 32px;
    height: 18px;
    margin-top: 0;
}
.perm-switch .toggle-switch::before { width: 14px; height: 14px; top: 2px; left: 2px; }
.perm-switch input:checked + .toggle-switch { background: var(--bleu); }
.perm-switch input:checked + .toggle-switch::before { transform: translateX(14px); }
.perm-switch input:focus-visible + .toggle-switch {
    outline: 2px solid var(--bleu);
    outline-offset: 2px;
}
.perm-switch-label { flex: 1; margin: 0; line-height: 1.3; font-weight: 400; }
.perm-sous-panneau {
    border-left: 3px solid var(--bleu-clair);
    padding: 10px 14px;
    background: var(--fond);
    border-radius: 0 8px 8px 0;
}

/* Mise en page édition : contenu + panneau latéral */
.form-page { display: flex; gap: 20px; align-items: flex-start; flex-wrap: wrap; }
.form-main { flex: 2.2; min-width: 320px; max-width: 1024px; }
/* Colonne latérale d'édition — sticky avec `top` calculé en JS
   (admin.js). Le sticky CSS `bottom: X` seul ne s'engage pas si la
   sidebar tient dans le viewport, d'où l'astuce du `top` négatif
   quand la sidebar est plus haute que le viewport (voir majSticky).
   Fallback CSS : sticky sous la topbar (--sticky-sous-topbar), JS ajuste
   au chargement. */
.form-side {
    flex: 1; min-width: 260px;
    position: sticky; top: var(--sticky-sous-topbar);
    align-self: flex-start;
}
.img-preview { max-width: 100%; border-radius: 8px; border: 1px solid var(--bordure); margin: 6px 0; display: block; }
.img-preview-small { max-height: 90px; width: auto; }

/* ---------- Boutons ---------- */
.btn {
    /* Bouton secondaire par défaut : PAS de fond, filet + texte en
       couleur primaire. `.btn-primary` reste rempli en bleu, les
       autres variantes gardent leurs teintes de charte.
       `inline-flex` (au lieu d'`inline-block`) : garantit un
       alignement vertical propre de l'icône SVG et du libellé, quel
       que soit le type d'élément (button / a / summary), avec le
       même gap partout. */
    display: inline-flex; align-items: center; gap: 6px;
    padding: 9px 18px; border-radius: 999px;
    border: 1px solid var(--bleu); background: transparent; color: var(--bleu);
    font: inherit; font-weight: 600; font-size: 14px;
    line-height: 1.15;
    cursor: pointer; text-align: center;
    /* Empêche un libellé multi-mots (« Modifier le formulaire ») de
       casser en deux lignes dans un groupe d'actions flex compact. */
    white-space: nowrap;
    text-decoration: none;
    transition: background .12s ease, color .12s ease, border-color .12s ease;
}
.btn > .ico { flex-shrink: 0; }
/* Pastille compteur dans un bouton d'onglet : sur un bouton neutre
   (fond transparent, bordure bleue), le bleu-clair par défaut de
   `.badge-info` disparaît. On force alors un fond bleu plein qui
   ressort. Sur un bouton primaire (`.btn-primary`, fond bleu plein),
   inversion : la pastille passe sur fond blanc lumineux. */
.btn:not(.btn-primary) > .badge-info {
    background: var(--bleu); color: #fff;
}
.btn.btn-primary > .badge-info {
    background: #fff; color: var(--bleu);
}
/* Texte `.muted` dans un bouton primaire (typiquement « (désactivé) »
   à côté du nom du service) : la teinte grise sombre par défaut
   disparaît sur fond bleu. On force un blanc atténué pour rester
   lisible tout en gardant l'effet de secondarité. */
.btn.btn-primary .muted {
    color: rgba(255, 255, 255, .75) !important;
}
/* Aération symétrique autour des boutons enfants directs d'un <form> :
   sans cela un bouton se colle au dernier champ ET au texte qui le suit
   (mention légale, lien secondaire…). Ne cible pas les boutons contenus
   dans .form-actions, .page-actions ou .inline-form — ces conteneurs
   portent déjà leur propre respiration. */
form > button, form > .btn, form > input[type="submit"] { margin: 18px 0; }
/* … sauf dans un formulaire en FLEX aligné sur une même ligne
   (input + bouton côte à côte). Sans ce reset, les marges du bouton
   font gonfler l'input via `align-items: stretch` et la ligne devient
   deux fois trop haute. Cible les formulaires flex connus + les
   futurs qui adopteraient la classe `.form-flex`. */
.form-inline-cat > button,      .form-inline-cat > .btn,
.form-inline-cat > input[type="submit"],
.search-form-multi > button,    .search-form-multi > .btn,
.search-form-multi > input[type="submit"],
.form-flex > button,            .form-flex > .btn,
.form-flex > input[type="submit"],
/* `.inline-form` : petit form d'action inline (bouton unique, ex.
   supprimer / marquer non lu). Le comment de la règle de margin
   ci-dessus annonçait l'exclusion, mais elle n'était jamais posée —
   d'où un décalage vertical des boutons `.inline-form > button`
   à côté de simples `<a class="btn">` dans un groupe flex. */
.inline-form > button,          .inline-form > .btn,
.inline-form > input[type="submit"] {
    margin-top: 0; margin-bottom: 0;
}
.btn:hover { background: var(--bleu-clair, #eef2ff); text-decoration: none; }
.btn-primary { background: var(--bleu); border-color: var(--bleu); color: #fff; }
.btn-primary:hover { background: #174a80; }
.btn-danger { background: var(--blanc); border-color: #fca5a5; color: var(--danger); }
.btn-danger:hover { background: var(--danger-fond); }
.btn-warn { border-color: #fcd34d; color: var(--warn); }
.btn-warn:hover { background: var(--warn-fond); }
/* Bouton d'action forte, ton orange (« Gérer les services », futurs
   raccourcis de config). Attire l'œil sans être aussi impérieux
   qu'un bouton primaire (bleu), mais plus visible qu'un bouton
   secondaire filet. */
.btn-orange {
    background: #ea580c; border-color: #ea580c; color: #fff !important;
}
.btn-orange:hover { background: #c2410c; border-color: #c2410c; color: #fff !important; }
.btn-light { background: #fff; }
.btn-small { padding: 4px 10px; font-size: 13px; font-weight: 500; }
.btn-block { display: block; width: 100%; margin-top: 14px; }
.inline-form { display: inline-block; margin: 0; }

/* ---------- Adresse verrouillée d'une page (SEO-sensible) ---------- */
/* Le slug n'est pas modifiable au premier coup d'œil : un clic sur le crayon
   déverrouille le champ. Rappelle au maire que changer une URL casse le
   référencement et les liens externes. */
.slug-verrou { display: flex; align-items: center; gap: 8px; margin: -4px 0 12px; }
.slug-verrou .slug-affichage { flex: 1; font-size: 13px; }
.slug-edit { flex: 1 0 100%; margin-top: 8px; }
.slug-edit input { width: 100%; }

/* ---------- Zones de menu (par page) ---------- */
.menu-zone + .menu-zone { margin-top: 10px; }
.menu-zone-libelle { margin: 6px 0 4px 26px; padding: 8px 10px; background: #f8fafc; border-radius: 6px; }
.menu-zone-libelle label { font-size: 12px; margin-bottom: 4px; color: var(--gris); }
.menu-zone-libelle input { width: 100%; }

/* ---------- Boutons d'action des listes (picto + infobulle) ----------
   Picto nu par défaut (pas de pastille visible), la pastille apparaît au
   survol. Allège fortement le rendu des listings — l'œil ne perçoit plus
   qu'une grille d'icônes discrète, et la surface cliquable reste 28×28. */
.btn-ico {
    display: inline-flex; align-items: center; justify-content: center;
    width: 28px; height: 28px; padding: 0; border-radius: 999px;
    border: 1px solid transparent; background: transparent; color: var(--gris);
    cursor: pointer; transition: background .13s ease, color .13s ease, border-color .13s ease;
}
/* Traits un peu plus épais que le stroke Lucide par défaut pour compenser
   l'absence de fond — un picto noir sur fond blanc a besoin d'un peu plus
   de matière pour rester lisible. */
.btn-ico svg { stroke-width: 2.2; }
.btn-ico:hover { background: var(--bleu-clair); color: var(--bleu); border-color: var(--bleu); text-decoration: none; }
/* Variante « petit crayon » à côté d'un champ verrouillé : plus discret que
   le picto standard, taille de bouton conforme à un input. */
.btn-ico-neutre { width: 26px; height: 26px; }
.btn-ico-danger:hover { background: var(--danger-fond); color: var(--danger); border-color: #fca5a5; }
/* Alignement : les boutons nus et ceux encapsulés dans un <form> doivent
   partager la même ligne médiane (le formulaire inline crée sinon un décalage
   de ligne de base). */
/* Motif d'une demande : lisible sans déformer la table, tronqué au-delà.
   -webkit-box ne doit JAMAIS être posé sur le <td> lui-même (le td cesse
   d'être une cellule et la ligne s'effondre) — il faut le mettre sur un
   wrapper <div> à l'intérieur. */
.demande-motif {
    max-width: 380px; font-size: 13px; line-height: 1.45;
    white-space: normal; overflow-wrap: anywhere;
    display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
.col-actions > * + * { margin-left: 2px; }
.col-actions .btn-ico { vertical-align: middle; }
.col-actions .inline-form { vertical-align: middle; line-height: 0; }
.col-actions .statut-dd { vertical-align: middle; }

/* Infobulle au survol / au clavier.
   La bulle peut se décaler horizontalement via la variable --tt-offset,
   posée par JS à l'entrée du curseur pour éviter que la bulle ne dépasse
   la fenêtre (bord droit ou gauche). La flèche, elle, reste centrée sur
   le bouton — c'est visuellement le point d'ancrage. */
[data-tooltip] { position: relative; }
[data-tooltip]::after {
    content: attr(data-tooltip); position: absolute; bottom: calc(100% + 9px); left: 50%;
    transform: translateX(calc(-50% + var(--tt-offset, 0px))) translateY(3px);
    background: #1f2937; color: #fff; font-size: 12px; font-weight: 500; line-height: 1.3;
    padding: 5px 9px; border-radius: 7px; white-space: nowrap;
    max-width: min(320px, 92vw);
    opacity: 0; pointer-events: none; z-index: 90;
    transition: opacity .14s ease, transform .14s ease;
}
[data-tooltip]::before {
    content: ""; position: absolute; bottom: 100%; left: 50%;
    transform: translateX(-50%) translateY(3px);
    border: 5px solid transparent; border-top-color: #1f2937;
    opacity: 0; pointer-events: none; z-index: 91;
    transition: opacity .14s ease, transform .14s ease;
}
[data-tooltip]:hover::after, [data-tooltip]:focus-visible::after {
    opacity: 1; transform: translateX(calc(-50% + var(--tt-offset, 0px))) translateY(0);
}
[data-tooltip]:hover::before, [data-tooltip]:focus-visible::before {
    opacity: 1; transform: translateX(-50%) translateY(0);
}
button + .btn, .btn + .btn { margin-left: 4px; }
/* Un bouton pleine largeur ne doit jamais hériter du décalage horizontal */
.btn-block + .btn-block, button.btn-block + .btn-block { margin-left: 0; }

/* Lien secondaire discret sous le CTA principal (annuler / retour) */
.lien-retour {
    display: block; text-align: center; margin-top: 12px; font-size: 13.5px;
    font-weight: 500; color: var(--gris);
}
.lien-retour:hover { color: var(--bleu); }
.quick-actions { display: flex; gap: 10px; flex-wrap: wrap; }

/* ---------- Badges / alertes ---------- */
.badge {
    /* `inline-flex + line-height: 1` : garantit un centrage vertical
       propre du chiffre dans la pastille, quel que soit le contexte
       (dans un bouton flex, à côté d'un mot, dans un titre…). Sans
       ça, le nombre pouvait apparaître décalé vers le haut ou le bas
       selon la line-height ambiante. */
    display: inline-flex; align-items: center; justify-content: center;
    padding: 3px 9px; border-radius: 20px;
    font-size: 12px; font-weight: 600; line-height: 1;
    min-height: 20px; min-width: 20px;
}
/* Un badge accolé à un contenu (nom, lien…) prend un petit décalage
   automatique. Seul en cellule ou en tête, il reste collé au bord — les
   styles inline `margin-left` ne sont plus nécessaires. */
.badge:not(:first-child) { margin-left: 6px; }
.badge-ok { background: var(--ok-fond); color: var(--ok); }
.badge-warn { background: var(--warn-fond); color: var(--warn); }
.badge-danger { background: var(--danger-fond); color: var(--danger); }
.badge-muted { background: #eef1f5; color: var(--gris); }
.badge-info { background: var(--bleu-clair); color: var(--bleu); }
.badge-niveau-info { background: var(--bleu-clair); color: var(--bleu); }
.badge-niveau-attention { background: var(--warn-fond); color: var(--warn); }
.badge-niveau-urgent { background: var(--danger-fond); color: var(--danger); }

.alert { padding: 12px 16px; border-radius: 8px; margin-bottom: 16px; font-size: 14px; }
.alert-success { background: var(--ok-fond); color: var(--ok); }
.alert-error { background: var(--danger-fond); color: var(--danger); }
.alert-warn { background: var(--warn-fond); color: var(--warn); }

/* ---------- Recherche / entêtes de page ---------- */
/* En-tête d'écran : texte d'introduction à gauche, action principale à droite */
.page-actions {
    display: flex; justify-content: space-between; align-items: flex-start;
    gap: 18px; margin-bottom: 16px; flex-wrap: wrap;
}
.page-actions .page-intro { margin: 0; flex: 1 1 260px; }
.page-actions > .btn { flex-shrink: 0; }
/* Sans texte d'introduction, l'action reste calée à droite */
.page-actions > .btn:only-child { margin-left: auto; }
/* Groupe de 2+ boutons à droite (ex. « Gérer les catégories » + « Nouvelle fiche »)
   séparés par un petit espace, alignés en fin de ligne comme un bouton unique. */
.page-actions-btns { display: inline-flex; gap: 8px; flex-shrink: 0; flex-wrap: wrap; }

/* --------- Statistiques : sélecteur de période --------- */
.stats-periode-form { display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap; }
/* Variante « barre » : pleine largeur, sous l'intro RGPD, sur sa propre ligne. */
.stats-periode-bar {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    padding: 12px 16px; margin: 0 0 16px;
    background: var(--fond-alt, #f8fafc);
    border-radius: 10px;
    border: 1px solid var(--fond-borne, #e6eaf1);
}
.stats-periode-form select,
.stats-periode-form input[type="text"] {
    padding: 6px 10px; font-size: 13.5px; margin: 0;
    border-radius: 8px; border: 1px solid var(--fond-borne, #e6eaf1);
    background: var(--fond, #ffffff);
    /* Force la largeur naturelle — sinon la règle globale
       `form input, form select { width: 100% }` du thème admin étale
       le select sur toute la ligne et pousse les inputs date dessous. */
    width: auto; max-width: none;
}
.stats-periode-range {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 4px 10px;
    background: var(--fond-alt, #f8fafc); border-radius: 8px;
}
.stats-periode-range input { min-width: 100px; text-align: center; background: transparent; border: 0; padding: 4px 0; }
.visually-hidden { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); border: 0; white-space: nowrap; }
.stats-pagination {
    display: flex; align-items: center; justify-content: center; gap: 12px;
    margin-top: 14px;
}

/* --------- Statistiques : teaser bluré + mini-graph SVG --------- */
.stats-teaser {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 16px; margin-top: 24px;
    /* Aperçu volontairement adouci — invite à activer le module sans
       dévoiler de vraies données (les nombres sont factices). */
    filter: blur(3px) opacity(.55);
    pointer-events: none; user-select: none;
}
.stats-teaser-carte {
    background: var(--fond, #ffffff);
    border: 1px solid var(--fond-borne, #e6eaf1);
    border-radius: 12px; padding: 16px;
}
.stats-teaser-carte h3 {
    font-size: 13px; margin: 0 0 14px; color: var(--gris, #64748b);
    display: flex; align-items: center; gap: 8px;
}
.stats-teaser-carte ul { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 8px; }
.stats-teaser-carte li { position: relative; padding: 4px 8px; font-size: 12.5px; }
.teaser-barre {
    position: absolute; inset: 0; z-index: 0;
    background: color-mix(in srgb, var(--bleu, #2563eb) 14%, transparent);
    border-radius: 4px;
}
.stats-teaser-carte li { z-index: 1; }
.teaser-graph {
    display: flex; align-items: flex-end; gap: 3px;
    height: 100px;
}
.teaser-graph-barre {
    flex: 1; min-width: 0;
    background: color-mix(in srgb, var(--bleu, #2563eb) 40%, transparent);
    border-radius: 2px 2px 0 0;
}

/* Graphique stats — rendu par Chart.js (lib auto-hébergée), on ne
   fournit qu'un conteneur stylé pour le canvas. Chart.js gère la
   légende cliquable et les tooltips en interne. */
.stats-graph-entete {
    display: flex; align-items: center; justify-content: space-between;
    flex-wrap: wrap; gap: 12px; margin-bottom: 12px;
}
.stats-graph {
    padding: 12px; border-radius: 10px;
    background: var(--fond-alt, #f8fafc);
    position: relative;
}

/* --------- Input file cohérent (docuthèque + autres écrans admin) ---------
   Utilise `::file-selector-button` qui stylise le bouton natif du
   navigateur — supporté par tous les moteurs modernes. Le texte
   « Aucun fichier sélectionné » reste géré par le navigateur mais on
   force une police et une taille cohérentes avec les autres inputs. */
input[type="file"]:not(.upload-input):not([hidden]) {
    display: block; width: 100%;
    padding: 8px 10px;
    font: inherit; font-size: 13.5px;
    color: var(--gris, #64748b);
    background: var(--fond, #ffffff);
    border: 1px dashed var(--fond-borne, #e6eaf1);
    border-radius: 10px;
    cursor: pointer;
    transition: border-color .12s ease, background .12s ease;
}
input[type="file"]:not(.upload-input):not([hidden]):hover {
    border-color: var(--bleu, #2563eb);
    background: color-mix(in srgb, var(--bleu, #2563eb) 4%, transparent);
}
input[type="file"]:not(.upload-input):not([hidden])::file-selector-button {
    margin-right: 12px;
    padding: 7px 14px;
    font: inherit; font-size: 13px; font-weight: 600;
    color: var(--sur-primaire-accent, #ffffff);
    background: var(--bleu, #2563eb);
    border: 0; border-radius: 8px;
    cursor: pointer;
    transition: background .12s ease, transform .12s ease;
}
input[type="file"]:not(.upload-input):not([hidden])::file-selector-button:hover {
    background: color-mix(in srgb, var(--bleu, #2563eb) 88%, #000);
}

/* --------- Champ compact `icone_field()` --------- */
.icone-field {
    display: inline-flex; align-items: center; gap: 10px; margin: 0 0 14px;
}
.icone-field-preview {
    display: inline-flex; align-items: center; justify-content: center;
    width: 40px; height: 40px; border-radius: 10px;
    background: var(--fond, #ffffff);
    border: 1.5px solid var(--fond-borne, #e6eaf1);
    color: var(--encre, #1c2434);
}
.icone-field-preview svg { display: block; }

/* --------- Modale globale de sélection d'icône --------- */
.admin-modal.admin-modal-large { width: min(930px, 95vw); max-width: min(930px, 95vw); }

/* Barre d'onglets minimaliste — pas de conteneur encadré, juste un
   trait de séparation en bas. L'onglet actif est signalé par un
   liseré coloré, sans pastille de fond (plus léger visuellement). */
.icone-modal-onglets {
    display: flex; flex-wrap: wrap; gap: 2px 4px;
    padding: 0; margin: 0 0 12px;
    border-bottom: 1px solid var(--fond-borne, #e6eaf1);
}
.icone-onglet {
    padding: 6px 10px 8px;
    background: transparent; border: 0; font: inherit; font-size: 12.5px; font-weight: 550;
    color: var(--gris, #64748b); cursor: pointer; white-space: nowrap;
    border-bottom: 2px solid transparent; margin-bottom: -1px;
    border-top-left-radius: 6px; border-top-right-radius: 6px;
    transition: color .12s ease, border-color .12s ease, background .12s ease;
}
.icone-onglet:hover {
    color: var(--encre, #1c2434);
    background: color-mix(in srgb, var(--encre, #1c2434) 4%, transparent);
}
.icone-onglet.is-actif {
    color: var(--bleu, #2563eb);
    border-bottom-color: var(--bleu, #2563eb);
    background: color-mix(in srgb, var(--bleu, #2563eb) 4%, transparent);
    font-weight: 650;
}
.icone-modal-recherche {
    display: flex; align-items: center; gap: 10px; padding: 10px 14px;
    background: var(--fond, #ffffff);
    border: 1.5px solid var(--fond-borne, #e6eaf1);
    border-radius: 10px;
    margin: 0 0 14px;
    color: var(--gris, #64748b);
}
.icone-modal-recherche input {
    flex: 1; border: 0; background: transparent; font: inherit;
    font-size: 15px; outline: none; padding: 0; color: var(--encre, #1c2434);
}
.icone-modal-recherche input::-webkit-search-cancel-button { -webkit-appearance: none; }
.icone-modal-corps {
    max-height: 460px; overflow-y: auto;
    padding: 2px 4px 4px 0;
}
.icone-modal-groupe + .icone-modal-groupe { margin-top: 14px; }
.icone-modal-grille {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
    gap: 6px; margin-top: 6px;
}
.icone-modal-choix {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 6px; padding: 10px 6px;
    background: transparent; border: 1.5px solid transparent; border-radius: 10px;
    cursor: pointer; font: inherit; color: var(--encre, #1c2434);
    transition: background .12s ease, border-color .12s ease, color .12s ease;
}
.icone-modal-choix:hover { background: var(--bleu-clair, #eff6ff); border-color: var(--bleu, #2563eb); color: var(--bleu, #2563eb); }
.icone-modal-choix.is-selected { background: var(--bleu-clair, #eff6ff); border-color: var(--bleu, #2563eb); color: var(--bleu, #2563eb); }
.icone-modal-vis { display: inline-flex; }
.icone-modal-nom {
    font-size: 11.5px; text-align: center;
    color: var(--gris, #64748b); line-height: 1.15;
}
.icone-modal-vide { text-align: center; color: var(--gris, #64748b); padding: 30px 0; font-style: italic; }

/* --------- Ancien picker inline (encore utilisé si icone_field
   n'a pas encore été appliqué à un écran) --------- */
.icone-picker-multi {
    max-height: 340px; overflow-y: auto;
    padding: 4px 4px 4px 0; margin: 4px 0 14px;
    border: 1px solid var(--fond-borne, #e6eaf1); border-radius: 12px;
    background: var(--fond, #ffffff);
}
.icone-picker-groupe { padding: 8px 10px; }
.icone-picker-groupe + .icone-picker-groupe { border-top: 1px dashed var(--fond-borne, #eef1f6); }
.icone-picker-theme {
    font-size: 11.5px; font-weight: 650;
    color: var(--gris, #64748b); text-transform: uppercase; letter-spacing: .05em;
    padding: 2px 0 6px;
}
.icone-picker {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(44px, 1fr));
    gap: 6px; margin: 0;
}
.icone-choice { position: relative; }
.icone-choice input { position: absolute; opacity: 0; inset: 0; margin: 0; cursor: pointer; }
.icone-choice-vis {
    display: inline-flex; align-items: center; justify-content: center;
    width: 100%; aspect-ratio: 1; border-radius: 10px;
    border: 1.5px solid var(--fond-borne, #e6eaf1);
    color: var(--gris, #64748b);
    background: var(--fond, #ffffff);
    transition: border-color .12s ease, color .12s ease, background .12s ease;
}
.icone-choice input:hover + .icone-choice-vis,
.icone-choice:hover .icone-choice-vis { color: var(--encre, #1c2434); border-color: var(--bleu, #2563eb); }
.icone-choice input:checked + .icone-choice-vis {
    border-color: var(--bleu, #2563eb);
    background: var(--bleu-clair, #eff6ff);
    color: var(--bleu, #2563eb);
    box-shadow: 0 0 0 1px var(--bleu, #2563eb) inset;
}
/* En-tête placé dans une carte : il se colle au haut de celle-ci */
.card > .page-actions:first-child, .card-inner > .page-actions:first-child { margin-bottom: 18px; }
/* Indentation d'une sous-page dans le listing des pages. Le padding-left
   est défini inline par PHP en fonction de la profondeur (0..3). */
.page-indent { display: inline-block; }
.page-indent + a { margin-left: 4px; }
.search-form { flex: 1; max-width: 380px; }
.search-form-multi { max-width: none; display: flex; gap: 10px; }

/* ---------- Choix de thème ---------- */
.theme-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 14px; }
.theme-choice {
    border: 2px solid var(--bordure); border-radius: 10px; padding: 12px; cursor: pointer;
    display: flex; flex-direction: column; gap: 4px; font-weight: 400; margin: 0;
}
.theme-choice input { position: absolute; opacity: 0; }
.theme-choice.selected { border-color: var(--bleu); background: var(--bleu-clair); }
.theme-choice strong { font-size: 14px; }
.theme-choice small { color: var(--gris); font-size: 12px; line-height: 1.4; }

/* ---------- Sélecteur visuel générique (actus, agenda, arrondis) ----------
   Pattern partagé : carte cliquable avec un aperçu graphique, le titre, une
   ligne descriptive. Sélection visible par un cadre bleu et un fond bleu clair.
   Utilisé partout où l'utilisateur choisit entre 2-4 options structurelles. */
.picker-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 14px; }
.picker-grid-arrondis { grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); }

/* Preview live du titre HERO : reproduit à L'IDENTIQUE le rendu du hero
   du site public (font-family, letter-spacing, line-height, text-wrap, poids),
   au format desktop (valeur max de chaque clamp). L'utilisateur voit à cet
   endroit exactement où sa dernière ligne va casser sur son site en vrai.
   La font-family est passée en inline style via `--police-titres` depuis PHP. */
.hero-preview-live {
    margin: 8px 0 4px;
    /* Padding généreux pour que l'outline en pointillé des titres puisse
       « respirer » à l'intérieur du bloc sans être coupée par l'overflow. */
    padding: 28px 30px;
    background: linear-gradient(115deg, #1e293b, #64748b 130%);
    color: #ffffff;
    border-radius: 10px;
    overflow: hidden;
}
.hero-preview-titre {
    margin: 0 0 14px;
    /* Taille max du clamp public pour « moyen ». Voir site.css .hero h1 :
       clamp(34px, 5.2vw, 60px). Sur desktop c'est bien 60 px qui rend. */
    font-size: 60px;
    line-height: 1.15;
    letter-spacing: -0.015em;
    font-weight: 650;
    font-family: var(--police-titres, inherit);
    text-wrap: balance;
    /* `width: 100%` combiné à `max-width` : le bloc prend toujours la
       largeur maximale, ce qui permet à l'outline en pointillé de
       matérialiser exactement la valeur du slider — l'utilisateur voit
       la « limite » bouger en temps réel, même sur un texte court. */
    width: 100%;
    max-width: var(--hero-titre-largeur, 640px);
    outline: 1px dashed rgba(255, 255, 255, .45);
    outline-offset: 6px;
}
.hero-preview-sous {
    margin: 0;
    /* Idem : max du clamp public pour la variante moyen (17→21 px). */
    font-size: 21px;
    line-height: 1.6;
    opacity: .93;
    font-family: var(--police, inherit);
    /* Même largeur maximale que le titre — c'est le comportement du site
       public (site.css .hero-texte utilise aussi var(--hero-titre-largeur)). */
    width: 100%;
    max-width: var(--hero-titre-largeur, 640px);
    text-wrap: balance;
    outline: 1px dashed rgba(255, 255, 255, .45);
    outline-offset: 6px;
}
/* Petit / Grand : mêmes valeurs max de clamp que dans site.css. */
.hero-preview-live[data-taille="petit"] .hero-preview-titre {
    font-size: 42px; line-height: 1.25;
}
.hero-preview-live[data-taille="petit"] .hero-preview-sous { font-size: 17px; }
.hero-preview-live[data-taille="grand"] .hero-preview-titre {
    font-size: 76px; line-height: 1.05;
}
.hero-preview-live[data-taille="grand"] .hero-preview-sous { font-size: 25px; }
.picker-grid-cartes { grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); }
.picker-choice {
    border: 2px solid var(--bordure); border-radius: 10px; padding: 12px; cursor: pointer;
    display: flex; flex-direction: column; gap: 4px; font-weight: 400; margin: 0;
    position: relative;
}
.picker-choice input { position: absolute; opacity: 0; }
.picker-choice.selected { border-color: var(--bleu); background: var(--bleu-clair); }
.picker-choice strong { font-size: 14px; }
.picker-choice small { color: var(--gris); font-size: 12px; line-height: 1.4; }
.picker-apercu {
    display: block; border-radius: 10px; overflow: hidden;
    border: 1px solid var(--bordure); margin-bottom: 10px; background: #fff;
    aspect-ratio: 16 / 8;
    position: relative;
}
/* Avertissement affiché sous le picker de mise en page du bandeau quand
   l'option « Image en carte » est sélectionnée mais qu'aucun média n'est
   chargé — l'option retomberait sur le bandeau standard côté public. Le
   ton orange doux signale une info non bloquante. */
.hero-carte-alerte {
    display: flex; align-items: flex-start; gap: 10px;
    margin: 14px 0 0; padding: 10px 14px;
    background: #fff7ed; color: #9a3412;
    border: 1px solid #fed7aa; border-left: 3px solid #f97316;
    border-radius: 8px;
    font-size: 13.5px; line-height: 1.45;
}
.hero-carte-alerte[hidden] { display: none; }
.hero-carte-alerte svg { flex: 0 0 auto; margin-top: 1px; color: #ea580c; }

/* Alerte inline générique — bandeau discret pour signaler qu'un
   fonctionnement dépend d'un module non activé, sans bloquer la saisie.
   Variantes de teinte selon le niveau (info/warn), fond doux + filet
   couleur à gauche pour ancrer le message. */
.alerte-inline {
    display: flex; align-items: flex-start; gap: 8px;
    padding: 8px 12px; border-radius: 6px;
    line-height: 1.4;
}
.alerte-inline svg { flex: 0 0 auto; margin-top: 2px; }
.alerte-inline a { color: inherit; text-decoration: underline; }
.alerte-inline-info { background: #eff6ff; color: #1e3a8a; border-left: 3px solid #2563eb; }
.alerte-inline-warn { background: #fff7ed; color: #9a3412; border-left: 3px solid #f97316; }

/* Module « Équipe municipale » — carte catégorie + membres ------------ */
.equipe-cat { margin-bottom: 18px; }
.equipe-cat-entete {
    display: flex; align-items: flex-start; justify-content: space-between;
    gap: 12px; flex-wrap: wrap; margin-bottom: 10px;
}
.equipe-cat-entete h2 {
    display: flex; align-items: center; gap: 10px; margin: 0;
    font-size: 17px; flex-wrap: wrap;
}
.equipe-cat-entete h2 .muted { font-size: 13px; font-weight: 400; }
.equipe-cat-actions {
    display: inline-flex; gap: 4px; align-items: center;
}
/* Catégorie Maire mise en avant : filet bleu à gauche pour signaler
   son statut protégé — cohérent avec le rendu XXL sur le site public. */
.equipe-cat-maire { border-left: 3px solid var(--bleu); }
/* Avatar rond des membres dans la table admin — un peu plus petit
   que les vignettes précédentes, plus lisible en scan visuel.
   Marges verticales NÉGATIVES pour que l'image ne fasse pas gonfler
   la hauteur de la ligne au-delà de ce qu'elle serait avec du texte
   seul (les autres cellules retrouvent leur alignement naturel). */
.equipe-thumb {
    width: 38px; height: 38px; object-fit: cover;
    border-radius: 999px; display: block; background: var(--fond);
    margin: -8px 0;
}

/* Miniature RECTANGULAIRE des listings de contenus (actualités,
   événements…) — cadrage 3:2 arrondi charte, placeholder neutre
   si aucune image. Marges négatives comme les avatars pour ne pas
   dilater la ligne au-delà de l'équivalent d'un contenu texte. */
.listing-thumb {
    width: 72px; height: 50px; object-fit: cover;
    border-radius: 6px; display: block; background: var(--fond);
    margin: -2px 0;
}
.listing-thumb-vide {
    display: inline-flex; align-items: center; justify-content: center;
    color: var(--gris);
    border: 1px solid var(--bordure);
}
/* Chapô sous le titre — jusqu'à 2 LIGNES, tronqué par ellipsis au-delà.
   Collé au titre (line-height serré + marge nulle) pour une lecture
   d'un bloc. `-webkit-line-clamp` couvre les moteurs Webkit/Blink
   (Chrome, Edge, Safari) et Firefox 68+ ; le fallback max-height
   assure une coupure propre partout. */
.listing-chapo {
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
    color: var(--gris); font-size: 12.5px;
    line-height: 1.35; margin-top: 0;
    overflow: hidden;
    max-height: calc(1.35em * 2);
}
/* Lieu affiché en sous-ligne d'un titre de listing (événement…) —
   picto pin + libellé, muted, une seule ligne avec ellipsis. */
.listing-lieu {
    display: flex; align-items: center; gap: 4px;
    color: var(--gris); font-size: 12.5px;
    margin-top: 2px;
    max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.listing-lieu .ico { opacity: .75; flex: 0 0 auto; }
.equipe-thumb-vide {
    display: inline-flex; align-items: center; justify-content: center;
    color: var(--gris);
}
/* Formulaire d'ajout rapide d'une catégorie — champ légèrement plus
   compact que les inputs standard (pas de gros padding vertical) car
   il vit à côté d'un bouton, aligné à la même hauteur. */
.form-inline-cat { display: flex; gap: 10px; align-items: stretch; margin-top: 8px; }
.form-inline-cat input[type="text"] { flex: 1; padding-top: 8px; padding-bottom: 8px; }

/* Pied de carte catégorie : le bouton « Ajouter un membre » à gauche,
   les boutons monter/descendre en bas-à-droite (invisibles pour la
   catégorie Maire, protégée). Marge haute généreuse pour laisser
   respirer entre la dernière ligne de la table et le CTA. */
.equipe-cat-pied {
    display: flex; align-items: center; justify-content: space-between;
    gap: 12px; margin-top: 22px;
}
.equipe-cat-ordre { display: inline-flex; gap: 6px; }
/* Boutons d'ordre — carrés, radius 4, bordure grise en permanence,
   chevron un peu plus gros et plus épais que la charte standard pour
   qu'ils se lisent bien même en repos. */
.equipe-btn-ordre {
    display: inline-flex; align-items: center; justify-content: center;
    width: 32px; height: 32px; padding: 0;
    background: #ffffff; color: var(--gris);
    border: 1px solid var(--bordure); border-radius: 4px;
    cursor: pointer;
    transition: background .13s ease, color .13s ease, border-color .13s ease;
}
.equipe-btn-ordre svg { stroke-width: 2.6; }
.equipe-btn-ordre:hover {
    background: var(--bleu-clair); color: var(--bleu); border-color: var(--bleu);
}

/* ---- Aperçus AGENDA (liste, cartes, compact) ---- */
/* Liste : trois rangées avec pastille de date colorée + trait de titre à côté.
   Pastilles construites via pseudo (backgrounds superposés), lignes de texte
   simulées par des sous-fonds — rendu proche du composant réel. */
.apercu-agenda-liste {
    background: #fff;
    background-image:
        /* Pastille date 1 */
        linear-gradient(#475569, #475569),
        /* Titre 1 */
        linear-gradient(#64748b, #64748b),
        /* Sous-ligne 1 */
        linear-gradient(#cbd5e1, #cbd5e1),
        /* Pastille date 2 */
        linear-gradient(#94a3b8, #94a3b8),
        /* Titre 2 */
        linear-gradient(#94a3b8, #94a3b8),
        /* Sous-ligne 2 */
        linear-gradient(#cbd5e1, #cbd5e1);
    background-repeat: no-repeat;
    background-size:
        22px 22px,
        60% 4px,
        40% 3px,
        22px 22px,
        50% 4px,
        30% 3px;
    background-position:
        16px 25%,
        50px 25%,
        50px calc(25% + 12px),
        16px 65%,
        50px 65%,
        50px calc(65% + 12px);
}
/* Cartes : deux vignettes côte à côte avec dégradé et petit badge de date
   en coin haut-gauche (via inset box-shadow qui joue les deux couleurs). */
.apercu-agenda-cartes {
    background: #fff;
    display: grid; grid-template-columns: 1fr 1fr; gap: 10px; padding: 14px;
}
.apercu-agenda-cartes::before,
.apercu-agenda-cartes::after {
    content: ""; background: linear-gradient(135deg, #94a3b8, #cbd5e1);
    border-radius: 6px; position: relative;
    box-shadow:
        inset 20px 20px 0 -14px #fff,
        inset 20px 20px 0 -15px #475569;
}
/* Compact : lignes denses de texte, alignées à gauche — « programme officiel ». */
.apercu-agenda-compact {
    background: #fff; padding: 12px 16px;
    background-image: repeating-linear-gradient(
        to bottom,
        transparent 0,
        transparent 8px,
        #94a3b8 8px, #94a3b8 10px,
        transparent 10px, transparent 18px,
        #cbd5e1 18px, #cbd5e1 20px
    );
    background-size: 82% 20px;
    background-repeat: repeat;
    background-position: 16px 12px;
}

/* ---- Aperçus ARRONDIS ----
   Une « fenêtre » avec barre de titre foncée + zone de contenu — le rayon
   d'arrondi s'applique aux quatre coins, on voit à quoi ressemblent les
   cartes du site avec ce paramètre. */
.apercu-arrondi {
    background: #f4f6fa;
    display: flex; align-items: center; justify-content: center;
    padding: 16px;
}
.apercu-arrondi::before {
    content: ""; display: block; width: 80%; height: 76%;
    background:
        linear-gradient(#475569 0, #475569 26%, transparent 26%),
        linear-gradient(135deg, #cbd5e1, #94a3b8);
    box-shadow: 0 4px 12px -4px rgba(15, 23, 42, .35);
}
.apercu-arrondi-aucun::before { border-radius: 0; }
.apercu-arrondi-francs::before { border-radius: 6px; }
.apercu-arrondi-doux::before { border-radius: 14px; }
.apercu-arrondi-ronds::before { border-radius: 26px; }

/* ---- Aperçus STYLE DES CARTES (ombre, bordure, plat) ---- */
.apercu-carte {
    background: #f4f6fa;
    display: flex; align-items: center; justify-content: center;
    padding: 18px;
}
.apercu-carte::before {
    content: ""; display: block; width: 82%; height: 76%;
    background: linear-gradient(135deg, #ffffff, #eef1f5);
    border-radius: 8px;
}
.apercu-carte-ombre::before {
    box-shadow: 0 8px 22px -6px rgba(15, 23, 42, .35),
                0 3px 8px -2px rgba(15, 23, 42, .18);
}
.apercu-carte-bordure::before {
    border: 1.5px solid #94a3b8;
}
.apercu-carte-plat::before {
    background: #ffffff;
    border: 1px dashed #e2e8f0;
}

/* ---- Aperçus HERO (image, bandeau, carte) — dans l'onglet Bandeau d'accueil ---- */
.apercu-hero {
    background: #fff;
    position: relative;
}
/* Image plein écran : photo simulée qui remplit toute la zone, titre bas */
.apercu-hero-image {
    background: linear-gradient(150deg, #1e293b, #64748b 90%);
}
.apercu-hero-image::before {
    content: ""; position: absolute; inset: 0;
    background: linear-gradient(180deg, transparent 45%, rgba(15, 23, 42, .55));
}
.apercu-hero-image::after {
    content: ""; position: absolute; left: 10%; bottom: 18%; width: 55%; height: 8px;
    background: #fff; border-radius: 3px;
}
/* Bandeau couleur : dégradé aux couleurs, occupe la partie haute */
.apercu-hero-bandeau {
    background:
        linear-gradient(180deg, #eef1f5 0, #eef1f5 55%, #fff 55%),
        linear-gradient(115deg, #475569, #94a3b8);
    background-position: 0 100%, 0 0;
    background-size: 100% 100%, 100% 55%;
    background-repeat: no-repeat;
}
.apercu-hero-bandeau::after {
    content: ""; position: absolute; left: 10%; top: 24%; width: 40%; height: 6px;
    background: #fff; border-radius: 3px; opacity: .95;
}
/* Image en carte : texte à gauche, photo dans un rectangle à droite */
.apercu-hero-carte {
    background: #f4f6fa;
    padding: 12% 10%;
}
.apercu-hero-carte::before {
    content: ""; position: absolute; left: 10%; top: 45%; width: 28%; height: 6px;
    background: #475569; border-radius: 3px;
    box-shadow: 0 12px 0 #94a3b8;
}
.apercu-hero-carte::after {
    content: ""; position: absolute; right: 10%; top: 15%; bottom: 15%; width: 40%;
    background: linear-gradient(135deg, #64748b, #cbd5e1);
    border-radius: 8px;
}
/* Aperçu de mise en page : schéma de STRUCTURE, chaque template a maintenant
   son ambiance visuelle propre pour évoquer clairement sa personnalité —
   forme du hero, densité du corps, présence d'un titre stylé. On reste en
   nuances neutres (la couleur d'accent viendra de l'ambiance choisie
   séparément) mais on marque fortement les différences de mise en page. */
.theme-apercu {
    display: block; border-radius: 10px; overflow: hidden;
    border: 1px solid var(--bordure); margin-bottom: 10px; background: #fff;
    aspect-ratio: 16 / 10;
    position: relative;
}
.theme-apercu > span { display: block; }

/* ---- HEROS ---- */
.ta-hero { position: relative; }
/* Image plein écran : dégradé sombre → moyen simulant une photo, titre imposant en surimpression */
.ta-hero-image {
    height: 62%;
    background: linear-gradient(150deg, #1e293b, #64748b 90%);
    position: relative;
}
.ta-hero-image::before {
    content: ""; position: absolute; inset: 0;
    background: linear-gradient(180deg, transparent 40%, rgba(15, 23, 42, .55));
}
.ta-hero-image::after {
    content: ""; position: absolute; left: 10%; bottom: 14%; width: 55%; height: 8px;
    background: rgba(255, 255, 255, .85); border-radius: 3px;
}
/* Bandeau couleur : rayures fines diagonales, occupe moins d'espace */
.ta-hero-bandeau {
    height: 38%;
    background: repeating-linear-gradient(115deg, #94a3b8, #94a3b8 6px, #cbd5e1 6px, #cbd5e1 12px);
    position: relative;
}
.ta-hero-bandeau::after {
    content: ""; position: absolute; left: 10%; top: 40%; width: 40%; height: 6px;
    background: #fff; border-radius: 3px; opacity: .9;
}
/* Image en carte : texte à gauche, photo dans une carte arrondie à droite */
.ta-hero-carte {
    height: 55%;
    background: #f4f7fb;
    position: relative;
    padding: 0 8px;
}
.ta-hero-carte::before {
    content: ""; position: absolute; left: 8%; top: 30%; width: 32%; height: 8px;
    background: #64748b; border-radius: 3px;
}
.ta-hero-carte::after {
    content: ""; position: absolute; right: 8px; top: 8px; bottom: 8px; width: 44%;
    background: linear-gradient(135deg, #64748b, #cbd5e1);
    border-radius: 8px;
}

/* ---- CORPS ---- */
.ta-corps { display: grid; gap: 4px; padding: 8px 10px; }
.ta-corps i { background: #cbd5e1; border-radius: 3px; display: block; }

/* Grille : quatre cartes avec vignette dégradée + une ligne de titre en bas.
   Reflet du comportement réel (nombre de colonnes qui s'adapte à la largeur).
   `.ta-corps` prend toute la hauteur du preview (aspect-ratio 16:8) sinon les
   cellules s'écrasent à zéro (pas de contenu réel dedans). */
.apercu-grille .ta-corps {
    height: 100%;
    grid-template-columns: repeat(4, 1fr); gap: 6px; padding: 10px;
}
.apercu-grille .ta-corps i {
    background: linear-gradient(135deg, #94a3b8, #cbd5e1);
    border-radius: 5px; position: relative;
    border: 0;
}
.apercu-grille .ta-corps i::after {
    content: ""; position: absolute; left: 12%; right: 30%; bottom: 12%; height: 4px;
    background: #fff; border-radius: 2px;
}

/* Liste : trois lignes avec vignette carrée à gauche + titre + description. */
.apercu-liste .ta-corps { grid-template-columns: 1fr; gap: 8px; padding: 12px; }
.apercu-liste .ta-corps i {
    height: 22px; position: relative;
    padding-left: 30px;
    background: transparent;
    border-radius: 0;
    border-bottom: 1px solid #e2e8f0;
    padding-bottom: 6px;
}
.apercu-liste .ta-corps i::before {
    content: ""; position: absolute; left: 0; top: 0; width: 22px; height: 22px;
    background: linear-gradient(135deg, #94a3b8, #cbd5e1);
    border-radius: 3px;
}
.apercu-liste .ta-corps i::after {
    content: ""; position: absolute; left: 30px; top: 4px; right: 20%; height: 5px;
    background: #64748b; border-radius: 2px;
    box-shadow: 0 9px 0 -1px #cbd5e1;
}
.apercu-liste .ta-corps i:last-child { border-bottom: none; padding-bottom: 0; }

/* Une à la une : grand bloc à gauche + 2 vignettes empilées à droite */
.apercu-magazine .ta-corps { grid-template-columns: 1.5fr 1fr; grid-template-rows: repeat(2, 1fr); gap: 6px; height: 100%; padding: 10px; }
.apercu-magazine .ta-corps i {
    background: #e2e8f0; border-radius: 5px; height: auto;
    position: relative;
    border: 1px solid #e2e8f0;
    overflow: hidden;
}
.apercu-magazine .ta-corps i:first-child {
    grid-row: span 2;
    background: linear-gradient(135deg, #64748b, #cbd5e1);
    border-color: transparent;
}
.apercu-magazine .ta-corps i:first-child::after {
    content: ""; position: absolute; left: 10%; bottom: 14%; width: 68%; height: 6px;
    background: #fff; border-radius: 2px;
}
.apercu-magazine .ta-corps i:not(:first-child) {
    background: #fff;
    display: flex; flex-direction: column;
}
.apercu-magazine .ta-corps i:not(:first-child)::before {
    content: ""; height: 40%;
    background: linear-gradient(135deg, #94a3b8, #cbd5e1);
}
.apercu-magazine .ta-corps i:not(:first-child)::after {
    content: ""; margin: 6px 8px; height: 4px;
    background: #64748b; border-radius: 2px;
    box-shadow: 0 6px 0 #cbd5e1;
}

/* ---------- Choix d'ambiance (couleurs + typographie accordées) ----------
   Chaque carte montre un aperçu miniature du site avec les 4 couleurs
   principales en pastilles, plus un « Aa » dans la police retenue. On repère
   la sélection courante par un cadre bleu et un fond légèrement teinté —
   même pattern que le sélecteur de mise en page pour cohérence. */
.ambiance-grille {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: 14px;
}
.ambiance-choice {
    position: relative;
    border: 2px solid var(--bordure); border-radius: 12px; padding: 12px;
    cursor: pointer; display: flex; flex-direction: column; gap: 6px;
    font-weight: 400; margin: 0; transition: border-color .15s ease, background .15s ease;
}
.ambiance-choice:hover { border-color: color-mix(in srgb, var(--bleu) 40%, var(--bordure)); }
.ambiance-choice input { position: absolute; opacity: 0; pointer-events: none; }
.ambiance-choice.selected { border-color: var(--bleu); background: var(--bleu-clair); }
.ambiance-choice strong {
    font-size: 14px; display: flex; align-items: center; justify-content: space-between; gap: 8px;
}
.ambiance-choice small { color: var(--gris); font-size: 12px; line-height: 1.4; }
.ambiance-tag {
    font-size: 10px; font-weight: 700; letter-spacing: .8px; text-transform: uppercase;
    background: #0f172a; color: #fff; padding: 2px 7px; border-radius: 999px;
}
/* Aperçu miniature : header + zone corps avec « Aa » (police) + pastilles */
.ambiance-apercu {
    display: block; border-radius: 8px; overflow: hidden;
    border: 1px solid var(--bordure); margin-bottom: 4px;
    aspect-ratio: 16 / 9;
}
.ambiance-header { display: block; height: 22%; }
.ambiance-corps {
    display: flex; flex-direction: column; justify-content: space-between;
    height: 78%; padding: 8px 10px 10px;
}
.ambiance-titre { font-size: 22px; font-weight: 700; letter-spacing: -0.02em; line-height: 1; }
.ambiance-palette { display: flex; gap: 4px; }
.ambiance-palette i {
    display: block; width: 16px; height: 16px; border-radius: 999px;
}

/* Aperçu typographique : gros titre + deux colonnes de texte lorem,
   change en direct quand l'ambiance ou la police est modifiée. */
.typo-preview {
    margin-top: 24px; padding: 26px 28px;
    background: #f8fafc; border-radius: 12px;
    border: 1px solid var(--bordure);
}
.typo-preview-titre {
    margin: 0 0 18px; font-size: 32px; line-height: 1.1;
    letter-spacing: -0.02em; font-weight: 700; color: var(--encre);
}
.typo-preview-cols {
    display: grid; grid-template-columns: 1fr 1fr; gap: 28px;
}
@media (max-width: 720px) { .typo-preview-cols { grid-template-columns: 1fr; gap: 16px; } }
.typo-preview-texte {
    margin: 0; font-size: 15px; line-height: 1.65; color: var(--gris);
}

/* ---------- Éditeur riche (Quill 2 — assets/vendor/quill/quill.snow.css)
   Habillage moderne aligné sur la charte admin : toolbar avec fond
   blanc opaque, boutons discrets, groupes séparés par un filet vertical
   subtil (Notion / Google Docs), zone d'édition avec hauteur généreuse. */
.wysiwyg { display: block; margin: 8px 0 14px; position: relative; }

/* Zone d'édition — Quill l'expose sous `.ql-editor` DANS le conteneur
   `[data-quill]` où on a instancié Quill. */
.wysiwyg .ql-container.ql-snow {
    border: 1px solid var(--bordure);
    border-top: 0;
    border-radius: 0 0 10px 10px;
    background: var(--blanc);
    font-family: inherit;
}
.wysiwyg .ql-editor {
    min-height: 360px;
    /* Pas de max-height : l'éditeur pousse la page. Le scroll est
       porté par la fenêtre entière. La toolbar principale reste
       accessible via `position: sticky` qui la colle juste sous la
       .topbar admin (voir plus bas). Bénéfice : l'utilisateur peut
       toujours atteindre la savebar (sticky en bas) et le reste du
       formulaire quel que soit le viewport, pas de zone bloquée. */
    padding: 16px 18px;
    line-height: 1.6; font-size: 15px; color: var(--encre);
}
.wysiwyg .ql-editor.ql-blank::before {
    color: #9aa5b1; font-style: normal; left: 18px;
}
.wysiwyg .ql-container.ql-snow:focus-within {
    border-color: var(--bleu);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--bleu, currentColor) 20%, transparent);
}

/* Toolbar — nos boutons SVG, nos groupes, notre séparateur vertical.
   Sélecteurs volontairement chaînés `.wy-toolbar.ql-toolbar` pour
   passer devant les règles de quill.snow.css (qui font `.ql-snow.ql-toolbar`
   = même spécificité que `.wysiwyg .ql-toolbar` sans chaînage, donc
   perdait sur width/height/padding par défaut). */
.wysiwyg .wy-toolbar.ql-toolbar {
    background: #ffffff;
    border: 1px solid var(--bordure);
    border-radius: 10px 10px 0 0;
    padding: 6px 8px;
    /* `row-gap: 4px` : petite respiration verticale entre les lignes
       quand la toolbar wrap (barre étroite), sans espace horizontal
       entre les groupes (`column-gap: 0`) qui casserait les filets. */
    display: flex; align-items: center; flex-wrap: wrap;
    column-gap: 0; row-gap: 4px;
    /* Sticky sous la .topbar admin — sans max-height sur l'éditeur,
       le scroll est porté par la fenêtre entière. L'offset vient de
       --sticky-sous-topbar : le recopier en dur l'avait déjà fait passer
       derrière la topbar le jour où celle-ci a grandi. */
    position: sticky; top: var(--sticky-sous-topbar); z-index: 6;
}
/* Sous-toolbar contextuelle « tableau » — centrée horizontalement
   sur le tableau, largeur intrinsèque. Fond sombre pour se démarquer
   du contenu de l'éditeur, ombre marquée pour flotter au-dessus. */
.wysiwyg .wy-table-toolbar {
    display: inline-flex; align-items: center;
    gap: 4px; padding: 5px 8px;
    background: #1e293b; color: #ffffff;
    border-radius: 8px;
    font-size: 12.5px;
    position: absolute; z-index: 5;
    box-shadow: 0 8px 24px -6px rgba(15, 23, 42, .45), 0 2px 6px rgba(15, 23, 42, .2);
    pointer-events: auto;
    white-space: nowrap;
}
.wysiwyg .wy-table-toolbar[hidden] { display: none; }
.wy-table-toolbar-label {
    font-weight: 700; color: rgba(255, 255, 255, .6);
    letter-spacing: .5px; text-transform: uppercase;
    font-size: 10px; padding: 0 6px 0 2px;
}
.wy-table-toolbar-groupe { display: inline-flex; gap: 1px; }
.wy-table-toolbar-groupe + .wy-table-toolbar-groupe {
    border-left: 1px solid rgba(255, 255, 255, .12);
    padding-left: 4px; margin-left: 3px;
}
.wy-table-toolbar button {
    width: 28px; height: 28px; padding: 0; border: 0;
    background: transparent; color: #ffffff;
    border-radius: 5px; cursor: pointer;
    display: inline-grid; place-items: center;
    transition: background .1s ease, color .1s ease;
}
.wy-table-toolbar button:hover { background: rgba(255, 255, 255, .15); }
.wy-table-toolbar .wy-table-toolbar-danger:hover {
    background: #dc2626; color: #ffffff;
}

/* Ligne d'entête de tableau (`<tr class="wy-th-row">`) — bascule via
   le bouton dédié de la toolbar tableau. Cellules en gras + fond gris
   pour un rendu type <th>, sans avoir à changer le tag lui-même. */
.wysiwyg .ql-editor tr.wy-th-row td,
.wysiwyg .ql-editor tr.wy-th-row th {
    background: #f1f5f9; font-weight: 700;
}

/* Overlay de redimensionnement de colonnes — poignées verticales
   positionnées aux frontières entre colonnes. */
.wysiwyg .wy-col-resize-overlay {
    position: absolute; z-index: 6; pointer-events: none;
}
.wy-col-resize-handle {
    position: absolute; top: 0; bottom: 0; width: 6px;
    cursor: col-resize; pointer-events: auto;
    background: transparent;
    transition: background .1s ease;
}
.wy-col-resize-handle:hover,
.wy-col-resize-handle:active {
    background: color-mix(in srgb, var(--bleu) 50%, transparent);
}
/* La zone d'édition ne double pas la bordure supérieure (partagée
   avec la toolbar). */
.wysiwyg .ql-container.ql-snow { border-top: 0; }
.wysiwyg .wy-toolbar.ql-toolbar .ql-formats {
    display: inline-flex; align-items: center; gap: 1px;
    padding: 0 6px; margin: 0; position: relative;
}
.wysiwyg .wy-toolbar.ql-toolbar .ql-formats:first-child { padding-left: 2px; }
/* Filet vertical entre groupes : élément HR dédié (`<hr class=
   "wy-toolbar-sep">`) inséré entre chaque groupe dans le HTML.
   Approche explicite, simple à maintenir. */
.wy-toolbar-sep {
    display: inline-block; vertical-align: middle;
    width: 1px; height: 20px; margin: 2px;
    background: var(--bordure); border: 0;
    flex: 0 0 auto;
}
/* ---------- Mode simple (data-mode="simple") ----------
   Utilisé dans les blocs libres de la newsletter et tout futur contexte
   court. Masque :
     - Sélecteur de bloc (Paragraphe ▾) : contient titres + encarts +
       blockquote, dont l'application via Quill posait problème dans le
       contexte newsletter (rendu incohérent selon les clients mail,
       encarts qui ne sortent pas des styles inline sans passe dédiée).
       Tout reste en paragraphe.
     - Insertions problématiques en mail : image (peu utile — les blocs
       actu/événement portent déjà l'image de leur ref), vidéo (embed
       non supporté par Gmail/Outlook/Yahoo), sondage (module-spécifique,
       hors mail), tableau (rendu Outlook capricieux).
   GARDE : gras/italique/barré/sup-sub, alignements, listes, lien,
   undo/redo. */
/* Le sélecteur de bloc « Paragraphe ▾ » est CONSERVÉ en mode simple — il
   donne accès aux encarts (Info / Attention / Succès / Astuce / Danger)
   qui sont convertis en styles inline au rendu mail (Newsletter::
   stylerClassesMail). Les titres H2/H3/H4/blockquote restent aussi
   accessibles depuis ce dropdown.
   Insertions restées masquées : image (peu utile en mail newsletter),
   vidéo (embed non supporté), sondage (module hors mail), tableau
   (rendu Outlook capricieux), séparateur horizontal (redondant avec les
   bordures d'encarts). */
.wysiwyg[data-mode="simple"] .ql-image,
.wysiwyg[data-mode="simple"] [data-wy-video],
.wysiwyg[data-mode="simple"] [data-wy-sondage],
.wysiwyg[data-mode="simple"] [data-wy-table],
.wysiwyg[data-mode="simple"] [data-wy-hr] { display: none !important; }

.wysiwyg .wy-toolbar.ql-toolbar .ql-spacer { flex: 1; padding: 0; }
.wysiwyg .wy-toolbar.ql-toolbar .ql-spacer::before,
.wysiwyg .wy-toolbar.ql-toolbar .ql-spacer::after { content: none; }
.wysiwyg .wy-toolbar.ql-toolbar button {
    width: 28px; height: 28px; padding: 0; margin: 2px 0;
    border: 0; background: transparent; border-radius: 6px;
    color: var(--encre); box-sizing: border-box;
    /* Grid centre proprement le SVG même quand Quill lui ajoute des
       styles inline. */
    display: inline-grid; place-items: center;
    float: none;   /* Quill le met à `left` par défaut → casse le flex */
    transition: background .12s ease, color .12s ease;
    cursor: pointer;
}
.wysiwyg .wy-toolbar.ql-toolbar button svg {
    width: 18px; height: 18px; display: block; margin: 0;
}
/* Lettres pour Gras (G) / Italique (I) / Barré (S) / Exposant (X²) /
   Indice (X₂) — convention française. Base graisse 700 pour matcher
   visuellement l'épaisseur des SVG Lucide (sinon apparaissent trop
   pâles/fines à côté). */
.wysiwyg .wy-toolbar.ql-toolbar button .wy-lettre {
    display: inline-block; font-family: Georgia, "Times New Roman", serif;
    font-size: 17px; line-height: 1; letter-spacing: 0;
    font-weight: 700;
}
.wysiwyg .wy-toolbar.ql-toolbar button .wy-lettre-gras     { font-weight: 900; }
.wysiwyg .wy-toolbar.ql-toolbar button .wy-lettre-italique { font-style: italic; }
.wysiwyg .wy-toolbar.ql-toolbar button .wy-lettre-barre    { text-decoration: line-through; text-decoration-thickness: 1.5px; }
/* Exposant/Indice : le <sup>/<sub> HTML natif applique lui-même
   font-size: smaller — assez visible avec la graisse 700 héritée. */
.wysiwyg .wy-toolbar.ql-toolbar button .wy-lettre sup,
.wysiwyg .wy-toolbar.ql-toolbar button .wy-lettre sub {
    font-size: 10px; font-weight: 700;
}
.wysiwyg .wy-toolbar.ql-toolbar button:hover {
    background: #f1f5f9; color: var(--bleu);
}
.wysiwyg .wy-toolbar.ql-toolbar button.ql-active {
    background: var(--bleu-clair); color: var(--bleu);
}
/* État désactivé — utilisé notamment par le bouton encart quand le
   curseur est sur un titre (encart pas applicable). Opacité réduite +
   curseur d'interdiction pour signaler visuellement l'indisponibilité,
   plus de hover/active possibles. */
.wysiwyg .wy-toolbar.ql-toolbar button:disabled {
    opacity: .35; cursor: not-allowed;
    background: transparent; color: var(--gris);
}
.wysiwyg .wy-toolbar.ql-toolbar button:disabled:hover {
    background: transparent; color: var(--gris);
}
/* Bouton trigger du dropdown « Type de bloc » — libellé + caret.
   Taille de texte réduite (12.5px) pour permettre une largeur plus
   compacte tout en restant lisible, hauteur alignée sur les boutons
   toolbar (30px). Le dropdown ouvert garde une typo confortable. */
.wysiwyg .wy-toolbar.ql-toolbar .wy-bloc-trigger {
    display: inline-flex; align-items: center; gap: 6px;
    height: 30px; padding: 0 8px 0 10px; width: auto; min-width: 140px;
    border: 1px solid var(--bordure); border-radius: 6px;
    background: #ffffff; color: var(--encre);
    font: inherit; font-size: 12.5px; font-weight: 600;
    cursor: pointer;
    justify-content: space-between;
}
.wysiwyg .wy-toolbar.ql-toolbar .wy-bloc-trigger:hover { border-color: var(--bleu); }
.wysiwyg .wy-toolbar.ql-toolbar .wy-bloc-trigger.est-ouvert {
    border-color: var(--bleu); box-shadow: 0 0 0 3px color-mix(in srgb, var(--bleu) 20%, transparent);
}
.wy-bloc-trigger-label {
    flex: 1; text-align: left;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.wy-bloc-trigger-caret {
    flex: 0 0 auto; color: var(--gris);
    transition: transform .15s ease;
}
.wy-bloc-trigger.est-ouvert .wy-bloc-trigger-caret { transform: rotate(180deg); }

/* Menu popup — layout en 2 colonnes : « Type de texte » à gauche,
   « Mettre en encart » à droite. Séparation par une bordure verticale
   fine entre les deux colonnes. Chaque item est stylé pour prévisualiser
   le rendu final (Paragraphe normal, Titre gros/gras, encarts colorés). */
.wy-blocmenu {
    position: fixed; z-index: 500;
    background: #ffffff; border: 1px solid var(--bordure);
    border-radius: 10px; padding: 8px;
    box-shadow: 0 14px 32px -6px rgba(15, 23, 42, .3);
    display: flex; gap: 12px;
    min-width: 480px;
}
.wy-blocmenu-groupe { flex: 1; padding: 4px; min-width: 0; }
.wy-blocmenu-groupe + .wy-blocmenu-groupe {
    border-left: 1px solid var(--bordure);
    padding-left: 12px;
}
.wy-blocmenu-groupe-label {
    padding: 2px 8px 8px;
    font-size: 10.5px; font-weight: 700;
    letter-spacing: .8px; text-transform: uppercase;
    color: var(--gris);
}
.wy-blocmenu-item {
    display: block; width: 100%;
    padding: 8px 12px; margin: 2px 0;
    border: 0; background-color: transparent;
    text-align: left; cursor: pointer;
    color: var(--encre); border-radius: 6px;
    font-family: inherit;
    transition: background-color .1s ease;
}
.wy-blocmenu-item:hover { background-color: #f1f5f9; }
/* IMPORTANT : utiliser `background-color` (pas `background` shorthand)
   pour ne PAS écraser `background-image` qui porte le SVG icône des
   items encart. Ancienne règle en shorthand faisait disparaître
   l'icône dès qu'un item encart était actif. */
.wy-blocmenu-item.est-actif {
    background-color: var(--bleu-clair);
    outline: 2px solid var(--bleu); outline-offset: -2px;
}
.wy-blocmenu-item-encart.est-actif { outline-color: currentColor; }
/* PRÉVISUALISATIONS — chaque item ressemble à ce qu'il produira. */
.wy-blocmenu-item-p  { font-size: 14.5px; font-weight: 400; line-height: 1.4; }
.wy-blocmenu-item-h2 { font-size: 21px;   font-weight: 700; line-height: 1.2; }
.wy-blocmenu-item-h3 { font-size: 17px;   font-weight: 700; line-height: 1.25; }
.wy-blocmenu-item-h4 { font-size: 15px;   font-weight: 600; line-height: 1.3; }
.wy-blocmenu-item-blockquote {
    font-size: 14.5px; font-style: italic; color: var(--gris);
}

/* Items encart — même palette que le rendu final. Petit filet
   vertical à gauche pour signaler qu'on met en cadre. */
.wy-blocmenu-item-encart {
    padding-left: 34px; margin: 2px 0;
    font-size: 13.5px; font-weight: 500;
    border-left: 3px solid transparent;
    background-repeat: no-repeat; background-size: 16px 16px;
    background-position: 10px center;
}
.wy-blocmenu-item-info {
    color: #1e3a8a; border-left-color: #2563eb;
    background-color: rgba(212, 226, 245, .5);
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232563eb' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='12' r='10'/><line x1='12' y1='16' x2='12' y2='12'/><line x1='12' y1='8' x2='12.01' y2='8'/></svg>");
}
.wy-blocmenu-item-attention {
    color: #713f12; border-left-color: #ca8a04;
    background-color: rgba(246, 232, 199, .5);
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ca8a04' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'><path d='M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z'/><line x1='12' y1='9' x2='12' y2='13'/><line x1='12' y1='17' x2='12.01' y2='17'/></svg>");
}
.wy-blocmenu-item-succes {
    color: #14532d; border-left-color: #16a34a;
    background-color: rgba(207, 235, 217, .5);
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2316a34a' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'><path d='M22 11.08V12a10 10 0 1 1-5.93-9.14'/><polyline points='22 4 12 14.01 9 11.01'/></svg>");
}
.wy-blocmenu-item-astuce {
    color: #581c87; border-left-color: #9333ea;
    background-color: rgba(228, 214, 240, .5);
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239333ea' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'><path d='M9 18h6'/><path d='M10 22h4'/><path d='M12 2a7 7 0 0 0-4 12.7c.9.7 1.5 1.8 1.5 3H14.5c0-1.2.6-2.3 1.5-3A7 7 0 0 0 12 2Z'/></svg>");
}
.wy-blocmenu-item-danger {
    color: #7f1d1d; border-left-color: #dc2626;
    background-color: rgba(248, 215, 218, .5);
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23dc2626' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'><path d='M15.312 2a2 2 0 0 1 1.414.586l4.688 4.688A2 2 0 0 1 22 8.688v6.624a2 2 0 0 1-.586 1.414l-4.688 4.688a2 2 0 0 1-1.414.586H8.688a2 2 0 0 1-1.414-.586l-4.688-4.688A2 2 0 0 1 2 15.312V8.688a2 2 0 0 1 .586-1.414l4.688-4.688A2 2 0 0 1 8.688 2z'/><path d='M12 8v4'/><path d='M12 16h.01'/></svg>");
}
.wy-blocmenu-item-encart:hover { filter: brightness(0.95); }

/* Rendu du contenu dans l'éditeur — reflet du rendu public .prose.
   Quill met tout à `margin: 0` par défaut (quill.snow.css) — on
   surcharge en profitant d'une spécificité supérieure (.wysiwyg
   ajoute une classe). */
/* Règle typo : la marge sous un titre doit être ≥ à la marge entre
   paragraphes (16px) — sinon la respiration du corps de texte paraît
   plus grande que celle des sections, hiérarchie visuelle inversée.
   `text-wrap: balance` = équilibre les mots par ligne sur les titres
   qui débordent, comme sur le front (cf. .page-titre / .prose h2). */
.wysiwyg .ql-editor p { margin: 0 0 16px; }
.wysiwyg .ql-editor h2 { font-size: 26px; font-weight: 700; margin: 28px 0 18px; text-wrap: balance; }
.wysiwyg .ql-editor h3 { font-size: 21px; font-weight: 700; margin: 24px 0 16px; text-wrap: balance; }
.wysiwyg .ql-editor h4 { font-size: 18px; font-weight: 600; margin: 20px 0 16px; text-wrap: balance; }
.wysiwyg .ql-editor ul,
.wysiwyg .ql-editor ol { margin: 0 0 16px; padding-inline-start: 24px; }
.wysiwyg .ql-editor li { margin: 0 0 4px; }
/* Listes non ordonnées Quill : la puce est portée par `.ql-ui::before`
   (marker DOM injecté par Quill dans chaque <li data-list="bullet">).
   On surcharge simplement `content` avec un tiret cadratin, cohérent
   avec le rendu public (site.css `.prose ul li::before`). Couleur
   discrète en gris pour ne pas capter l'œil. */
.wysiwyg .ql-editor li[data-list="bullet"] > .ql-ui::before {
    content: "— ";
    color: var(--gris, #64748b);
    font-weight: 400;
}
/* Citation — convention éditoriale standard : taille du body, italique,
   teinte grise, filet coloré à gauche. Le contexte (retrait + italique)
   suffit à distinguer. Rendu identique côté front (.prose). */
.wysiwyg .ql-editor blockquote {
    border-left: 3px solid var(--bleu);
    margin: 16px 0; padding: 4px 16px;
    color: var(--gris);
    font-style: italic;
}
.wysiwyg .ql-editor img { max-width: 100%; height: auto; border-radius: 6px; margin: 8px 0; cursor: pointer; }
/* Exposant / Indice — taille 60% + line-height 0 pour ne pas
   stretcher la hauteur de ligne parente (les valeurs UA par défaut
   font sortir sup au-dessus, décalant tout le baseline). */
.wysiwyg .ql-editor sup, .wysiwyg .ql-editor sub {
    font-size: 66%; line-height: 0;
    position: relative; vertical-align: baseline;
}
.wysiwyg .ql-editor sup { top: -0.5em; }
.wysiwyg .ql-editor sub { top:  0.3em; }
/* Alignement horizontal (Quill utilise `.ql-align-*` sur les blocs). */
.wysiwyg .ql-editor .ql-align-center  { text-align: center; }
.wysiwyg .ql-editor .ql-align-right   { text-align: right; }
.wysiwyg .ql-editor .ql-align-justify { text-align: justify; }
/* Séparateur horizontal (hr) — trait fin (1px) mais zone cliquable
   étendue verticalement via padding + `background-clip: content-box`
   qui limite le trait aux 1px de content-box. Résultat : hit area
   de 21px de haut pour un rendu visuel de 1px. Marges externes 20px
   pour aérer le flow. */
.wysiwyg .ql-editor hr {
    border: 0; height: 1px; margin: 20px 0;
    padding: 10px 0;
    background: rgba(0, 0, 0, .15);
    background-clip: content-box;
    box-sizing: content-box;
}
/* Tableau (module Quill 2 natif) : `border-collapse: collapse` pour
   fusionner naturellement les bordures adjacentes (jamais de cumul).
   `table-layout: fixed` : les largeurs `style="width:..."` posées sur
   les cellules de la première ligne sont propagées à toute la colonne
   (indispensable pour le redimensionnement manuel via poignées). */
.wysiwyg .ql-editor table {
    border-collapse: collapse;
    width: 100%; margin: 16px 0; font-size: 14.5px;
    table-layout: fixed;
}
.wysiwyg .ql-editor table td,
.wysiwyg .ql-editor table th {
    border: 1px solid rgba(0, 0, 0, .12);
    padding: 8px 12px; min-width: 60px;
    overflow-wrap: anywhere;
    word-break: break-word;
    hyphens: auto;
}
/* Alignement vertical typographique : contenu (td) en haut de cellule,
   en-têtes (th ou tr.wy-th-row) en bas — accroche l'œil sur la
   dernière ligne de l'entête, qui est la plus proche des données. */
.wysiwyg .ql-editor table td { vertical-align: top; }
.wysiwyg .ql-editor table th,
.wysiwyg .ql-editor table tr.wy-th-row td { vertical-align: bottom; }
.wysiwyg .ql-editor table th {
    background: #f8fafc; font-weight: 700; text-align: left;
}

/* Grille de sélection pour l'insertion de tableau — 8×10 cases carrées
   qui se remplissent au survol pour prévisualiser la taille. */
.wy-grid-picker {
    display: grid; grid-template-columns: repeat(var(--maxC, 10), 1fr);
    gap: 4px; max-width: 320px; margin: 0 auto;
    cursor: pointer;
}
.wy-grid-cell {
    aspect-ratio: 1; background: #f1f5f9;
    border: 1px solid var(--bordure); border-radius: 3px;
    transition: background .1s, border-color .1s;
}
.wy-grid-cell.est-actif {
    background: color-mix(in srgb, var(--bleu) 20%, transparent);
    border-color: var(--bleu);
}

/* Encarts (info / attention / succès / astuce) — `<div class="wy-encart
   wy-encart-{type}">` qui enveloppe N enfants block-level (p, h2, h3,
   h4, ul, blockquote, table).

   Pattern éditorial standard : padding généreux sur le wrapper (22 px
   vertical, 56 px à gauche pour l'icône), puis on annule les marges
   top du premier enfant et bottom du dernier. Résultat : les enfants
   gardent leurs marges naturelles entre eux MAIS ne collent pas au
   bord du cadre — respiration prévisible quel que soit le premier /
   dernier bloc (paragraphe, titre, tableau). */
.wysiwyg .ql-editor .wy-encart {
    margin: 18px 0; padding: 22px 22px 22px 82px;
    border-radius: 10px; border-left: 4px solid transparent;
    position: relative;
}
/* L'encart est maintenant un simple `<div>` block-level qui contient
   directement le texte (pas de wrap `<p>`). Marges des enfants
   éventuels réinitialisées si présents — mais dans l'usage normal
   l'encart est UNITAIRE : un paragraphe = un encart. */
.wysiwyg .ql-editor .wy-encart > *:first-child { margin-top: 0; }
.wysiwyg .ql-editor .wy-encart > *:last-child  { margin-bottom: 0; }
/* Icône alignée en HAUT de l'encart, calée pour être centrée
   verticalement sur la première LIGNE de texte (pas sur la hauteur
   totale de l'encart — mauvais rendu pour un encart multi-lignes).
   Calcul : padding-top (22px) + demi-line-height (~12px pour 15px/1.55)
   − demi-hauteur icône (11px) = 23px du haut du wrapper. */
.wysiwyg .ql-editor .wy-encart::before {
    content: ''; position: absolute; left: 20px; top: 23px;
    width: 22px; height: 22px;
    background-repeat: no-repeat; background-size: contain;
}
/* Filet vertical entre picto et contenu — pleine hauteur bord-à-bord
   (top:0, bottom:0). `currentColor` reprend la teinte du texte du
   type, opacité réduite pour rester discret. */
.wysiwyg .ql-editor .wy-encart::after {
    content: ''; position: absolute;
    left: 62px; top: 0; bottom: 0;
    width: 1px; background: currentColor; opacity: .25;
}
/* Continuité visuelle entre encarts consécutifs de même type — le
   sélecteur `:has()` isole le PREMIER d'une série pour lui garder
   coins arrondis + marge, les suivants collapsent. `+` inversé
   via `:not(:has(+ …))` cible le dernier. */
.wysiwyg .ql-editor .wy-encart-info      + .wy-encart-info,
.wysiwyg .ql-editor .wy-encart-attention + .wy-encart-attention,
.wysiwyg .ql-editor .wy-encart-succes    + .wy-encart-succes,
.wysiwyg .ql-editor .wy-encart-astuce    + .wy-encart-astuce {
    margin-top: 0;
    border-top-left-radius: 0; border-top-right-radius: 0;
    padding-top: 6px;
}
.wysiwyg .ql-editor .wy-encart-info:has(+ .wy-encart-info),
.wysiwyg .ql-editor .wy-encart-attention:has(+ .wy-encart-attention),
.wysiwyg .ql-editor .wy-encart-succes:has(+ .wy-encart-succes),
.wysiwyg .ql-editor .wy-encart-astuce:has(+ .wy-encart-astuce) {
    margin-bottom: 0;
    border-bottom-left-radius: 0; border-bottom-right-radius: 0;
    padding-bottom: 6px;
}
/* Icône masquée sur les continuations (paragraphes 2+ de la série). */
.wysiwyg .ql-editor .wy-encart-info      + .wy-encart-info::before,
.wysiwyg .ql-editor .wy-encart-attention + .wy-encart-attention::before,
.wysiwyg .ql-editor .wy-encart-succes    + .wy-encart-succes::before,
.wysiwyg .ql-editor .wy-encart-astuce    + .wy-encart-astuce::before {
    display: none;
}

/* Aperçu CTA dans l'éditeur — rendu identique au front pour un WYSIWYG
   fidèle. Boutton coloré avec fond primaire. */
.wysiwyg .ql-editor a.wy-cta {
    display: inline-block; text-decoration: none;
    padding: 10px 20px; margin: 6px 0;
    background: var(--bleu, #2563eb); color: #ffffff;
    border-radius: 8px;
    font-weight: 700; font-size: 14.5px; line-height: 1.3;
}

/* Ligne « Afficher en bouton d'action » dans le picker de liens —
   posée juste avant le pied de modale, séparée par une bordure haute
   discrète pour lever l'ambiguïté avec les onglets URL/Document/Interne. */
.wysiwyg-linkpicker-cta {
    padding: 12px 20px;
    border-top: 1px solid var(--bordure);
    background: #fafbfc;
}
/* Icônes SVG Lucide, injectées en data URI. `%23` = # url-encoded pour
   la couleur (stroke). Une variante par type = une couleur. */
/* Fonds légèrement plus saturés + alpha .95 : compromis entre bloc
   coloré agressif (originaux) et fond trop pâle (première version
   désaturée). Rendu identifiable comme encart mais discret. */
.wysiwyg .ql-editor .wy-encart-info {
    background: rgba(212, 226, 245, .95); border-left-color: #2563eb; color: #1e3a8a;
}
.wysiwyg .ql-editor .wy-encart-info::before {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232563eb' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='12' r='10'/><line x1='12' y1='16' x2='12' y2='12'/><line x1='12' y1='8' x2='12.01' y2='8'/></svg>");
}
.wysiwyg .ql-editor .wy-encart-attention {
    background: rgba(246, 232, 199, .95); border-left-color: #ca8a04; color: #713f12;
}
.wysiwyg .ql-editor .wy-encart-attention::before {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ca8a04' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'><path d='M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z'/><line x1='12' y1='9' x2='12' y2='13'/><line x1='12' y1='17' x2='12.01' y2='17'/></svg>");
}
.wysiwyg .ql-editor .wy-encart-succes {
    background: rgba(207, 235, 217, .95); border-left-color: #16a34a; color: #14532d;
}
.wysiwyg .ql-editor .wy-encart-succes::before {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2316a34a' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'><path d='M22 11.08V12a10 10 0 1 1-5.93-9.14'/><polyline points='22 4 12 14.01 9 11.01'/></svg>");
}
.wysiwyg .ql-editor .wy-encart-astuce {
    background: rgba(228, 214, 240, .95); border-left-color: #9333ea; color: #581c87;
}
.wysiwyg .ql-editor .wy-encart-astuce::before {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239333ea' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'><path d='M9 18h6'/><path d='M10 22h4'/><path d='M12 2a7 7 0 0 0-4 12.7c.9.7 1.5 1.8 1.5 3H14.5c0-1.2.6-2.3 1.5-3A7 7 0 0 0 12 2Z'/></svg>");
}
/* Encart Danger — rouge saturé, plus visible que Attention (jaune) qui
   sert plutôt aux notes de vigilance. Danger = information critique,
   risque, interdiction. */
.wysiwyg .ql-editor .wy-encart-danger {
    background: rgba(248, 215, 218, .95); border-left-color: #dc2626; color: #7f1d1d;
}
.wysiwyg .ql-editor .wy-encart-danger::before {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23dc2626' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'><path d='M15.312 2a2 2 0 0 1 1.414.586l4.688 4.688A2 2 0 0 1 22 8.688v6.624a2 2 0 0 1-.586 1.414l-4.688 4.688a2 2 0 0 1-1.414.586H8.688a2 2 0 0 1-1.414-.586l-4.688-4.688A2 2 0 0 1 2 15.312V8.688a2 2 0 0 1 .586-1.414l4.688-4.688A2 2 0 0 1 8.688 2z'/><path d='M12 8v4'/><path d='M12 16h.01'/></svg>");
}

/* Menu déroulant « type d'encart » — attaché sous le bouton toolbar,
   position: fixed pour survoler le formulaire sans être clippé. Chaque
   ligne = icône SVG + libellé, teinte de fond au hover selon le type. */
.wy-encart-menu {
    position: fixed; z-index: 500;
    background: #ffffff; border: 1px solid var(--bordure);
    border-radius: 10px; padding: 4px;
    box-shadow: 0 12px 28px -6px rgba(15, 23, 42, .35);
    min-width: 240px;
}
.wy-encart-menu-item {
    display: flex; align-items: center; gap: 12px; width: 100%;
    padding: 9px 12px; background: transparent; border: 0;
    border-radius: 6px; text-align: left; font: inherit; font-size: 14px;
    color: var(--encre); cursor: pointer;
    transition: background .1s ease, color .1s ease;
}
.wy-encart-menu-item:hover { background: #f1f5f9; }
.wy-encart-menu-item-info:hover      { background: #eff6ff; color: #1e3a8a; }
.wy-encart-menu-item-info:hover .wy-encart-menu-icone   { color: #2563eb; }
.wy-encart-menu-item-attention:hover { background: #fefce8; color: #713f12; }
.wy-encart-menu-item-attention:hover .wy-encart-menu-icone { color: #ca8a04; }
.wy-encart-menu-item-succes:hover    { background: #ecfdf5; color: #14532d; }
.wy-encart-menu-item-succes:hover .wy-encart-menu-icone { color: #16a34a; }
.wy-encart-menu-item-astuce:hover    { background: #faf5ff; color: #581c87; }
.wy-encart-menu-item-astuce:hover .wy-encart-menu-icone { color: #9333ea; }
.wy-encart-menu-icone {
    flex: 0 0 auto; display: inline-flex; align-items: center;
    color: var(--gris);
}
.wy-encart-menu-libelle { flex: 1; font-weight: 500; }
/* Placeholder d'upload : carte grise centrée avec spinner + texte
   d'étape (« Envoi sur le serveur… X % » → « Analyse de l'image… »).
   Volontairement en bloc plein-largeur pour signaler visuellement
   qu'un contenu s'insère à cet endroit — un simple flou aurait été
   ambigu. */
.wysiwyg .ql-editor .wy-image-placeholder {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    padding: 32px 20px; gap: 14px; margin: 12px 0;
    background: #f1f5f9; border: 1px dashed var(--bordure); border-radius: 8px;
    color: var(--gris); font-size: 13.5px; user-select: none;
    min-height: 140px;
}
.wy-image-placeholder-spinner {
    width: 30px; height: 30px;
    border: 3px solid #d3dbe6; border-top-color: var(--bleu);
    border-radius: 50%;
    animation: wy-spinner-rotate .9s linear infinite;
}
.wy-image-placeholder-etape { font-weight: 600; letter-spacing: .2px; }
@keyframes wy-spinner-rotate { to { transform: rotate(360deg); } }

/* ---------- Vidéo embed (carte de consentement RGPD) ----------
   Aperçu dans l'éditeur — le rendu public équivalent est dans
   site.css, structure et gradient identiques pour un WYSIWYG fidèle. */
.wysiwyg .ql-editor .wy-video {
    position: relative; margin: 16px 0; user-select: none;
    aspect-ratio: 16/9; overflow: hidden;
    border-radius: var(--rayon, 10px); background: #0f172a;
}
/* Aperçu simplifié en édition : play + nom du service, centré sur
   fond sombre. Suffisant pour reconnaître d'un coup d'œil qu'il s'agit
   d'une vidéo YouTube/Vimeo/Dailymotion sans encombrer la surface
   d'édition avec le texte de consentement (celui-là est régénéré au
   rendu public par contenu_public()). */
.wysiwyg .ql-editor .wy-video-carte {
    position: absolute; inset: 0;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    padding: 20px; gap: 14px; text-align: center; color: #f8fafc;
    background: linear-gradient(135deg, #1e293b, #0f172a);
}
.wysiwyg .ql-editor .wy-video-picto {
    width: 72px; height: 72px; border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    background: rgba(255, 255, 255, .14); color: #f8fafc;
}
.wysiwyg .ql-editor .wy-video-titre {
    margin: 0; font-size: 14px; font-weight: 700; letter-spacing: 1px;
    text-transform: uppercase; color: #cbd5e1;
}

/* Sondage dans l'éditeur — carte visuelle claire (fond bleuté) qui
   ressort du texte sans mimer l'aspect final du bloc (le vrai rendu
   est fait au vol par contenu_public()). Volontairement compact —
   l'admin doit reconnaître l'insertion, pas la consulter. */
.wysiwyg .ql-editor .wy-sondage {
    display: block;
    margin: 12px 0;
    border: 1px solid #cbd5e1;
    border-left: 4px solid #2563eb;
    border-radius: 10px;
    background: #eff6ff;
    padding: 14px 18px;
}
.wysiwyg .ql-editor .wy-sondage-carte {
    display: flex;
    align-items: center;
    gap: 14px;
}
.wysiwyg .ql-editor .wy-sondage-picto {
    flex: 0 0 auto;
    width: 44px; height: 44px;
    border-radius: 10px;
    background: #2563eb;
    color: #fff;
    display: flex; align-items: center; justify-content: center;
}
.wysiwyg .ql-editor .wy-sondage-corps { flex: 1; min-width: 0; }
.wysiwyg .ql-editor .wy-sondage-label {
    margin: 0 0 2px;
    font-size: 11px; font-weight: 700; letter-spacing: 1px;
    text-transform: uppercase; color: #1e40af;
}
.wysiwyg .ql-editor .wy-sondage-question {
    margin: 0;
    font-size: 15px; font-weight: 600; color: #0f172a;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Fallback visuel : un shortcode `[sondage:X]` inséré sous forme de
   texte (Blot embed indisponible, ex. cache navigateur) est décoré
   par decorerShortcodesSondage() qui pose data-sondage-shortcode sur
   le <p>. La CSS ci-dessous masque le texte brut et affiche à la
   place une pastille propre — l'admin voit toujours un aperçu clair. */
.wysiwyg .ql-editor p[data-sondage-shortcode],
.wysiwyg .ql-editor div[data-sondage-shortcode] {
    position: relative;
    /* font-size:0 masque le texte du shortcode plus proprement que
       color:transparent (pas de largeur invisible qui décalerait le
       curseur). Le ::after remet une taille visible pour l'aperçu. */
    font-size: 0;
    line-height: 0;
    caret-color: transparent; /* pas de curseur qui clignote sur la pastille */
    cursor: pointer;
    min-height: 64px;
    margin: 12px 0;
    padding: 0;
    background: #eff6ff;
    border: 1px solid #cbd5e1;
    border-left: 4px solid #2563eb;
    border-radius: 10px;
    box-sizing: border-box;
}
.wysiwyg .ql-editor p[data-sondage-shortcode]::after,
.wysiwyg .ql-editor div[data-sondage-shortcode]::after {
    content: "Sondage n°" attr(data-sondage-shortcode);
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    padding: 12px 18px;
    color: #0f172a;
    font-size: 15px;
    line-height: 1.3;
    font-weight: 600;
    pointer-events: none;
}
/* Outline SURVOL (jaune) et SÉLECTION (bleu) : les règles génériques
   `.wysiwyg .ql-editor .wy-embed-survol` / `.wy-embed-selectionne`
   plus bas dans le fichier s'appliquent naturellement puisque
   wysiwyg.js pose les mêmes classes sur cette pastille que sur les
   autres embeds (image, vidéo, tableau). */

/* Champ de recherche dans la modale « Insérer un sondage » */
.wy-sondage-recherche-label {
    display: block;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--gris);
    margin: 0 0 6px;
}
.wy-sondage-recherche {
    width: 100%;
    box-sizing: border-box;
    padding: 8px 12px;
    font-size: 14px;
    border: 1px solid var(--gris-clair);
    border-radius: 8px;
    margin-bottom: 12px;
}
.wy-sondage-recherche:focus { outline: 2px solid var(--bleu); outline-offset: -1px; }
.wy-sondage-vide {
    margin: 10px 0 0;
    padding: 12px;
    background: var(--fond);
    border-radius: 8px;
    text-align: center;
    color: var(--gris);
    font-size: 13px;
}

/* Modale « Voir les réponses » — rappel de la question au-dessus des
   jauges pour que l'admin sache quoi il regarde sans revenir à la liste. */
.sondage-modal-question {
    margin: 0 0 16px;
    padding: 0 0 12px;
    border-bottom: 1px solid var(--bordure);
    font-size: 16px;
    font-weight: 600;
    color: var(--noir);
    line-height: 1.4;
}

/* Éditeur de créneaux de réservation — grille hebdomadaire, 7 blocs
   empilés, chaque bloc a un titre + un bouton d'ajout + une liste. */
.reservation-creneaux-editeur { display: flex; flex-direction: column; gap: 10px; }
.reservation-jour {
    border: 1px solid var(--gris-clair);
    border-radius: 10px;
    padding: 10px 14px;
    background: var(--blanc, #fff);
}
.reservation-jour-tete {
    display: flex; align-items: center; justify-content: space-between;
    margin-bottom: 8px;
    font-size: 14px;
}
.reservation-jour-tete strong { color: var(--noir); }
.reservation-jour-liste {
    display: flex; flex-direction: column; gap: 6px;
}
.reservation-jour-liste:empty::after {
    content: "Aucun créneau — cliquez sur « Ajouter un créneau » pour en créer un.";
    display: block;
    color: var(--gris);
    font-size: 12.5px;
    font-style: italic;
    padding: 4px 2px;
}
.reservation-creneau {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 4px 0;
}
.reservation-creneau input[type="time"] {
    width: 110px;
    padding: 6px 10px;
    border: 1px solid var(--gris-clair);
    border-radius: 8px;
    font: inherit;
    font-size: 14px;
}
.reservation-creneau .reservation-creneau-libelle {
    flex: 1;
    padding: 6px 10px;
    border: 1px solid var(--gris-clair);
    border-radius: 8px;
    font: inherit;
    font-size: 14px;
}
.reservation-creneau .btn-ico {
    flex: 0 0 auto;
}

/* Panneau « Lien direct partageable » sur la page d'édition d'un sondage.
   Le lien absolu prend toute la largeur ; le bouton « Copier » est
   discret, sous le lien, aligné à droite. */
.sondage-partage-panneau {
    margin-top: 20px;
    padding: 12px 16px;
    background: var(--fond);
    border: 1px solid var(--bordure);
    border-radius: 8px;
}
.sondage-partage-titre {
    display: flex; align-items: center; gap: 6px;
    font-size: 13px; font-weight: 600; color: var(--noir);
    margin-bottom: 6px;
}
.sondage-partage-corps {
    display: flex; flex-direction: column; align-items: flex-start; gap: 6px;
}
.sondage-partage-corps a {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 13px;
    word-break: break-all;
}
.sondage-partage-panneau .muted {
    margin: 8px 0 0;
    font-size: 12.5px;
}
/* Variante « xs » de .btn — plus petite, discrète pour actions secondaires
   comme « Copier le lien ». */
.btn.btn-xs {
    padding: 4px 10px;
    font-size: 12.5px;
    gap: 5px;
}
/* Embed (image, vidéo, séparateur, tableau) — deux états visuels :
   - SURVOL       : outline JAUNE (`.wy-embed-survol`) — feedback
                    découverte, l'utilisateur passe sans avoir cliqué
   - SÉLECTIONNÉ  : outline BLEU  (`.wy-embed-selectionne`) — l'élément
                    est activement ciblé (clic ou setSelection Quill)
   Le `.wysiwyg` est en `position: relative` pour ancrer les flèches. */
.wysiwyg { position: relative; }
.wysiwyg .ql-editor .wy-embed-survol,
.wysiwyg .ql-editor img.wy-embed-survol,
.wysiwyg .ql-editor hr.wy-embed-survol {
    outline: 3px solid #eab308;
    outline-offset: 2px;
}
.wysiwyg .ql-editor .wy-embed-selectionne,
.wysiwyg .ql-editor img.wy-embed-selectionne,
.wysiwyg .ql-editor hr.wy-embed-selectionne {
    outline: 3px solid var(--bleu);
    outline-offset: 2px;
}
/* Retire l'overlay bleu que le navigateur applique par défaut aux
   embeds inclus dans une text-selection (Chrome/Edge). On veut
   uniquement l'outline autour, pas de teinte sur l'image entière.
   `::selection` seul ne suffit pas car le navigateur peint AUSSI la
   selection-box du <p> parent par-dessus l'image ; on bloque donc
   la user-select sur les embeds (Quill garde sa sélection interne
   via la Delta indépendamment de la sélection DOM). */
.wysiwyg .ql-editor img::selection,
.wysiwyg .ql-editor img::-moz-selection,
.wysiwyg .ql-editor .wy-video::selection,
.wysiwyg .ql-editor .wy-sondage::selection,
.wysiwyg .ql-editor [data-sondage-shortcode]::selection {
    background: transparent;
}
.wysiwyg .ql-editor img,
.wysiwyg .ql-editor .wy-video,
.wysiwyg .ql-editor .wy-sondage {
    -webkit-user-select: none;
    user-select: none;
}
/* Séparateur cliquable — curseur pointer pour indiquer qu'on peut
   le sélectionner (comme les images). */
.wysiwyg .ql-editor hr { cursor: pointer; }
/* Barre de flèches CKEditor-style — deux petits ronds jaunes qui
   flottent au-dessus et en dessous du bloc sélectionné. Ils
   permettent d'insérer un paragraphe vide avant/après (indispensable
   quand un doc commence ou finit par une image/vidéo, sinon le
   curseur ne peut pas s'y placer). */
.wy-embed-fleches[hidden] { display: none; }
/* Le CONTAINER `.wy-embed-fleches` n'a pas d'aire visible mais couvre
   virtuellement toute la zone du wrapper (position: absolute défini
   par JS). `pointer-events: none` évite qu'il capture les événements
   au-dessus de l'embed → sans ça, dès qu'on rentre dans la zone du
   container, l'embed perd le hover et les flèches clignotent.
   Les boutons enfants remettent explicitement `pointer-events: auto`
   pour rester cliquables. */
.wy-embed-fleches { pointer-events: none; }
.wy-embed-fleche {
    position: absolute; z-index: 5;
    pointer-events: auto;
    width: 28px; height: 28px; padding: 0;
    background: #eab308; color: #ffffff;
    border: 2px solid #ffffff; border-radius: 50%;
    display: inline-grid; place-items: center;
    cursor: pointer;
    box-shadow: 0 4px 10px -2px rgba(15, 23, 42, .35);
    transition: transform .12s ease, background .12s ease;
}
.wy-embed-fleche:hover { background: #ca8a04; transform: scale(1.1); }
.wy-embed-fleche:focus-visible {
    outline: 2px solid var(--bleu); outline-offset: 2px;
}
/* Quand l'embed est SÉLECTIONNÉ (pas juste survolé), les flèches
   basculent en bleu pour matcher l'outline bleu de sélection. */
.wy-embed-fleches.est-selectionne .wy-embed-fleche {
    background: var(--bleu);
}
.wy-embed-fleches.est-selectionne .wy-embed-fleche:hover {
    background: color-mix(in srgb, var(--bleu) 85%, #000);
}
/* Bouton × SUPPRIMER — même look/couleurs que les flèches : jaune
   par défaut (hover), bleu quand l'embed est sélectionné. Toujours
   visible dès que la barre est affichée (survol ou sélection). */
.wy-embed-supprimer {
    position: absolute;
    z-index: 5;
    pointer-events: auto;
    width: 28px; height: 28px; padding: 0;
    background: #eab308; color: #ffffff;
    border: 2px solid #ffffff; border-radius: 50%;
    display: inline-grid;
    place-items: center;
    cursor: pointer;
    box-shadow: 0 4px 10px -2px rgba(15, 23, 42, .35);
    transition: transform .12s ease, background .12s ease;
}
.wy-embed-supprimer:hover { background: #ca8a04; transform: scale(1.1); }
.wy-embed-fleches.est-selectionne .wy-embed-supprimer { background: var(--bleu); }
.wy-embed-fleches.est-selectionne .wy-embed-supprimer:hover {
    background: color-mix(in srgb, var(--bleu) 85%, #000);
}

/* Traduction FR des libellés de la tooltip de lien Quill — Quill met
   les textes en dur en `content:` dans quill.snow.css. On les
   surcharge ici plutôt que d'éditer le vendor. */
.wysiwyg .ql-snow .ql-tooltip::before { content: "Adresse :"; }
.wysiwyg .ql-snow .ql-tooltip a.ql-action::after { content: "Modifier"; }
.wysiwyg .ql-snow .ql-tooltip a.ql-remove::before { content: "Retirer"; }
.wysiwyg .ql-snow .ql-tooltip.ql-editing a.ql-action::after { content: "Enregistrer"; }
.wysiwyg .ql-snow .ql-tooltip[data-mode="link"]::before { content: "Adresse du lien :"; }
.wysiwyg .ql-snow .ql-tooltip[data-mode="video"]::before { content: "URL de la vidéo :"; }

/* Modal picker de liens (URL / Document / Page) déclenché depuis le
   bouton 🔗 de la toolbar Trix. Overlay sombre + boîte centrée, même
   pattern visuel que les modales `.admin-modal` du reste de l'admin. */
.wysiwyg-linkpicker {
    position: fixed; inset: 0; z-index: 400;
    background: rgba(15, 23, 42, .55);
    display: flex; align-items: center; justify-content: center; padding: 24px;
    backdrop-filter: blur(3px);
}
.wysiwyg-linkpicker-boite {
    width: min(680px, 100%);
    background: #ffffff; color: var(--encre);
    border: 1px solid var(--bordure); border-radius: 14px;
    box-shadow: 0 40px 80px -12px rgba(15, 23, 42, .35);
    overflow: hidden;
}
.wysiwyg-linkpicker-onglets {
    display: flex; border-bottom: 1px solid var(--bordure);
}
.wysiwyg-linkpicker-onglets .tab {
    flex: 1; padding: 12px 8px; border: 0; background: transparent;
    font: inherit; font-size: 14px; font-weight: 600; cursor: pointer;
    color: var(--gris); border-bottom: 2px solid transparent;
    transition: color .15s ease, border-color .15s ease;
    /* Centre le libellé horizontalement dans son onglet (bouton flex à
       largeur égale — sans ces règles, la valeur par défaut varie selon
       le browser et le libellé peut apparaître aligné à gauche). */
    display: inline-flex; align-items: center; justify-content: center;
    text-align: center;
}
.wysiwyg-linkpicker-onglets .tab:hover { color: var(--encre); }
.wysiwyg-linkpicker-onglets .tab.est-actif {
    color: var(--bleu); border-bottom-color: var(--bleu);
}
.wysiwyg-linkpicker-corps { padding: 18px 20px; }
.wysiwyg-linkpicker-panneau { display: none; }
.wysiwyg-linkpicker-panneau.est-actif { display: block; }
.wysiwyg-linkpicker-panneau label {
    display: block; font-size: 13.5px; font-weight: 600; margin: 4px 0;
}
.wysiwyg-linkpicker-panneau input {
    width: 100%; padding: 10px 12px; margin-bottom: 8px;
    border: 1px solid var(--bordure); border-radius: 8px;
    font: inherit; font-size: 14px;
}
.wysiwyg-linkpicker-liste {
    list-style: none; padding: 0; margin: 6px 0 0;
    max-height: 320px; overflow-y: auto;
    border: 1px solid var(--bordure); border-radius: 8px;
}
.wysiwyg-linkpicker-liste li {
    padding: 0; cursor: pointer; font-size: 14px;
    border-top: 1px solid var(--bordure);
}
.wysiwyg-linkpicker-liste li:first-child { border-top: 0; }
.wysiwyg-linkpicker-liste li:hover { background: var(--bleu-clair); }
.wysiwyg-linkpicker-liste li.est-actif { background: var(--bleu-clair); color: var(--bleu); }
.wysiwyg-linkpicker-liste li.est-actif .wy-picker-titre { color: var(--bleu); font-weight: 700; }
.wysiwyg-linkpicker-liste li.muted { cursor: default; color: var(--gris); padding: 10px 12px; }

/* Rendu enrichi d'un item — mise en page commune (padding, gap) puis
   variantes par type de contenu (document / média / défaut). */
.wy-picker-item {
    display: flex; align-items: center; gap: 12px;
    padding: 10px 12px;
}
.wy-picker-corps { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.wy-picker-titre {
    font-weight: 600; color: var(--encre);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.wy-picker-meta { font-size: 12.5px; color: var(--gris); }

/* Document : pastille d'extension colorée + poids en meta.
   Extensions les plus courantes ont leur teinte propre pour distinguer
   rapidement au scan visuel (rouge PDF = universel, bleu Word, etc.). */
.wy-picker-doc-ext {
    flex: 0 0 auto; min-width: 44px; text-align: center;
    padding: 6px 8px; border-radius: 6px;
    font-size: 10.5px; font-weight: 800; letter-spacing: .5px;
    background: #e2e8f0; color: #475569;
}
.wy-picker-doc-ext-pdf  { background: #fee2e2; color: #b91c1c; }
.wy-picker-doc-ext-doc,
.wy-picker-doc-ext-docx { background: #dbeafe; color: #1d4ed8; }
.wy-picker-doc-ext-xls,
.wy-picker-doc-ext-xlsx,
.wy-picker-doc-ext-ods  { background: #dcfce7; color: #166534; }
.wy-picker-doc-ext-ppt,
.wy-picker-doc-ext-pptx { background: #ffedd5; color: #9a3412; }
.wy-picker-doc-ext-odt  { background: #ede9fe; color: #6d28d9; }
.wy-picker-doc-ext-zip,
.wy-picker-doc-ext-rar  { background: #fef9c3; color: #a16207; }

/* Document non publié (planifié) : opacité réduite pour signaler qu'il
   ne sera pas encore accessible aux visiteurs si on lie maintenant. Reste
   sélectionnable — utile pour préparer un contenu qui accompagnera la
   publication programmée. */
.wy-picker-item-doc.est-non-publie { opacity: .55; }
.wy-picker-badge-planifie {
    display: inline-block; padding: 1px 6px; border-radius: 4px;
    background: #fef3c7; color: #92400e;
    font-size: 11px; font-weight: 700; letter-spacing: .3px;
    text-transform: uppercase;
}

/* Actualités / Événements : miniature carrée à gauche + date sous le
   titre. Fallback en emoji quand aucune image n'est associée. */
.wy-picker-vignette {
    flex: 0 0 auto; width: 52px; height: 52px;
    border-radius: 6px; overflow: hidden;
    background: #f1f5f9;
    display: flex; align-items: center; justify-content: center;
    font-size: 22px;
}
.wy-picker-vignette img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Fallback SVG (icône Lucide) quand pas d'image associée — teinte
   grise pour rester discret dans la liste. Pas d'emoji, jamais. */
.wy-picker-vignette-vide { color: var(--gris); }
.wy-picker-vignette-vide svg { display: block; }
/* Barre de recherche + bouton d'action dans l'onglet Document /
   sélecteur de type + recherche dans l'onglet Contenu interne.
   `flex: 1` sur les deux enfants (input + select) → 50/50 uniforme.
   `align-items: stretch` + hauteur explicite → même hauteur visuelle
   entre les deux, quelle que soit la boîte du navigateur. */
.wysiwyg-linkpicker-barre { display: flex; gap: 8px; margin-bottom: 6px; align-items: stretch; }
.wysiwyg-linkpicker-barre input,
.wysiwyg-linkpicker-barre select { flex: 1 1 0; min-width: 0; margin: 0; height: 36px; box-sizing: border-box; }
.wysiwyg-linkpicker-barre .btn { white-space: nowrap; flex: 0 0 auto; height: 36px; }
/* Icône loupe à l'intérieur des inputs de recherche du picker — SVG
   inline en data-URI (couleur figée en gris #94a3b8, currentColor
   ne fonctionne pas dans background-image). */
.wysiwyg-linkpicker-barre input[type="search"] {
    padding-left: 34px;
    background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.35-4.35'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: 10px center;
}
/* Pastille de type devant chaque entrée du picker interne — permet de
   distinguer page/actu/événement/annuaire/module sans jouer aux devinettes. */
.wy-badge-type {
    display: inline-block; padding: 1px 7px; margin-right: 8px;
    border-radius: 4px; font-size: 11px; font-weight: 700;
    letter-spacing: .3px; text-transform: uppercase;
    vertical-align: baseline;
    background: var(--bleu-clair); color: var(--bleu);
}
.wy-badge-module { background: #e0e7ff; color: #4338ca; }
.wy-badge-page   { background: #e0f2fe; color: #0369a1; }
.wy-badge-actu   { background: #fef3c7; color: #92400e; }
.wy-badge-event  { background: #fce7f3; color: #9f1239; }
.wy-badge-annuaire { background: #dcfce7; color: #166534; }
/* Dropdown type dans le panneau « Contenu interne ». La hauteur et le
   flex sont posés sur la règle générique `.wysiwyg-linkpicker-barre
   input, .wysiwyg-linkpicker-barre select` — ici on ne fait que
   l'habiller (padding pour la flèche, bordure, typographie). */
.wysiwyg-linkpicker-barre .wy-type-interne-select {
    padding: 0 26px 0 12px;
    border: 1px solid var(--bordure); border-radius: 8px;
    font: inherit; font-size: 14px; font-weight: 700;
    background: #ffffff; color: var(--encre); cursor: pointer;
}
.wysiwyg-linkpicker-barre .wy-type-interne-select:hover { border-color: var(--bleu); }
/* Message inline « module inactif » à l'intérieur d'un panneau du picker. */
.wy-module-inactif {
    padding: 24px 20px; text-align: center;
    background: #f8fafc; border-radius: 10px;
    color: var(--gris); font-size: 14px; line-height: 1.5;
}
.wy-module-inactif p { margin: 0 0 10px; }
.wy-module-inactif p:last-child { margin: 14px 0 0; }
.wy-module-inactif strong { color: var(--encre); }

/* Sur-modale (upload rapide) — au-dessus de la modale link picker. */
.wy-sur-modale { z-index: 500; }
.wy-sur-modale input[type="text"],
.wy-sur-modale input[type="file"] {
    width: 100%; padding: 10px 12px; margin-bottom: 8px;
    border: 1px solid var(--bordure); border-radius: 8px;
    font: inherit; font-size: 14px;
}
.wysiwyg-linkpicker-actions {
    display: flex; justify-content: flex-end; gap: 8px;
    padding: 14px 20px; border-top: 1px solid var(--bordure);
    background: #f8fafc;
}

/* ---------- Quota / divers ---------- */
.quota-bar { height: 10px; border-radius: 6px; background: #e8edf3; overflow: hidden; margin: 6px 0; }
.quota-fill { height: 100%; background: var(--bleu); border-radius: 6px; }
.quota-alerte { background: var(--danger); }
.totp-secret {
    font-family: ui-monospace, "Cascadia Mono", Consolas, monospace; font-size: 17px; letter-spacing: 1px;
    background: var(--bleu-clair); border-radius: 8px; padding: 10px 14px; margin: 8px 0; user-select: all;
}
/* QR code TOTP — sa propre ligne, aligné à gauche pour que le regard
   revienne à la marge après avoir lu l'instruction. Le SVG conserve sa
   taille native (modules × pixels + marge) : la forcer plus petit brouille
   les motifs pour un appareil photo mobile qui a besoin de distinguer
   nettement chaque cellule. */
.totp-qr {
    display: block; width: fit-content;
    padding: 4px; margin: 10px 0;
    background: #fff; border: 1px solid var(--bordure); border-radius: 8px;
}
.totp-qr svg { display: block; }
.totp-alternative { margin: 8px 0 0; font-size: 13px; }
.totp-alternative > summary { cursor: pointer; color: var(--bleu); user-select: none; }
.totp-alternative[open] > summary { margin-bottom: 6px; }
.steps li { margin-bottom: 12px; }
.footer-lien-row { display: flex; gap: 10px; margin-bottom: 8px; }
.module-gestion { position: relative; text-align: left; }
.module-gestion summary { list-style: none; display: inline-block; }
.module-gestion summary::-webkit-details-marker { display: none; }
.module-form { padding: 10px 0 4px; max-width: 240px; }

/* ---------- Onglets : rattachés au contenu, inactifs en transparence ---------- */
/* Padding nul à gauche + padding d'onglet égal à celui de la carte :
   le libellé du premier onglet tombe pile sur le contenu en dessous. */
.tabs {
    display: flex; gap: 3px; flex-wrap: wrap; padding: 0; margin: 0;
    position: relative; z-index: 1;
}
.tab {
    /* Flex row : l'icône et le libellé sont alignés à la baseline optique
       (align-items: center) au lieu de dépendre du bricolage vertical-align
       qui déraillait quand la ligne wrapait sur deux étages. */
    display: inline-flex; align-items: center; gap: 8px;
    padding: 10px 22px 11px; margin-bottom: -1px; text-decoration: none;
    font-weight: 600; font-size: 14px; color: var(--gris);
    border: 1px solid transparent; border-bottom: none;
    border-radius: 12px 12px 0 0; background: transparent;
    transition: background .13s ease, color .13s ease;
    /* Fonctionne aussi bien sur <a> (nav serveur) que sur <button> (nav
       client, pour un formulaire unique commutant ses sections). */
    cursor: pointer; font-family: inherit;
    line-height: 1.2;
}
.tab:hover { background: rgba(15, 23, 42, .05); color: var(--encre); text-decoration: none; }
/* L'onglet actif se fond dans la carte : même fond, pas de trait en bas */
.tab-actif, .tab-actif:hover {
    background: var(--blanc); border-color: var(--bordure); color: var(--encre);
    box-shadow: 0 -1px 0 var(--blanc) inset;
}
.tab .ico { opacity: .7; flex: 0 0 auto; }
.tab-actif .ico { opacity: 1; color: var(--bleu); }
/* Colle la 1ʳᵉ carte à la barre d'onglets (pas de vide vertical). */
.tabs + .card, .tabs + [data-tabs-panneaux] .tab-panneau > .card:first-child {
    margin-top: 0;
}
/* Angle sup-gauche mis à zéro UNIQUEMENT si le PREMIER onglet est actif —
   seul cas où l'onglet actif se pose sur le coin sup-gauche de la carte.
   Pour un onglet plus à droite, garder le coin rond (rien ne s'y appuie).
   `:has()` supporté sur tous les navigateurs modernes (Chrome 105+,
   Safari 15.4+, Firefox 121+). */
.tabs:has(> .tab:first-child.tab-actif) + .card,
.tabs:has(> .tab:first-child.tab-actif) + [data-tabs-panneaux] .tab-panneau.actif .card:first-child {
    border-top-left-radius: 0;
}
/* Panneaux commutés côté client (bascule via admin.js) */
.tab-panneau { display: none; }
.tab-panneau.actif { display: block; }

/* ---------- Sélecteur de lien (v1 legacy, plus utilisé) ---------- */
.link-picker { display: flex; gap: 10px; flex-wrap: wrap; }
.link-picker .lp-type { max-width: 170px; }
.link-picker .lp-valeur { flex: 1; min-width: 220px; }

/* ---------- Sélecteur de lien v2 (select unique + liste filtrable) ----------
   Un seul select en tête (rubriques + URL en optgroups), placeholder par
   défaut. Sous le select : soit un message d'aide (rien de choisi), soit
   un sous-picker filtrable (rubrique avec items), soit un input URL. */
.link-picker-v2 { display: block; }
.link-picker-v2 > .lp-cible { width: 100%; margin-bottom: 10px; }
.link-picker-v2 .lp-url { width: 100%; }
.link-picker-v2 .lp-hint {
    margin: 0 0 10px;
    padding: 8px 12px;
    font-size: 13px; color: var(--warn);
    background: var(--warn-fond); border: 1px dashed var(--warn); border-radius: 8px;
}
/* `:not([hidden])` sinon `display: flex` écraserait l'attribut [hidden]
   (spé 0,2,1 vs 0,1,0) — même piège que sur les file inputs plus haut :
   tous les sous-pickers modules restaient visibles en même temps. */
.link-picker-v2 .lp-souspicker:not([hidden]) {
    display: flex; flex-direction: column; gap: 8px;
    padding: 10px; border: 1px solid var(--bordure); border-radius: 10px;
    background: #f8fafc;
}
.link-picker-v2 .lp-search {
    height: 34px; padding: 0 12px 0 34px;
    border: 1px solid var(--bordure); border-radius: 8px;
    font: inherit; font-size: 13.5px;
    background-color: #fff;
    background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.35-4.35'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: 10px center;
}
.link-picker-v2 .lp-list {
    list-style: none; margin: 0; padding: 0;
    max-height: 260px; overflow: auto;
    border: 1px solid var(--bordure); border-radius: 8px;
    background: #fff;
}
.link-picker-v2 .lp-list li[data-lp-item] {
    padding: 8px 12px; border-bottom: 1px solid var(--bordure);
    cursor: pointer; font-size: 13.5px; color: var(--encre);
    transition: background .1s ease, color .1s ease;
}
.link-picker-v2 .lp-list li[data-lp-item]:last-child { border-bottom: 0; }
.link-picker-v2 .lp-list li[data-lp-item]:hover { background: var(--bleu-clair); }
.link-picker-v2 .lp-list li[data-lp-item].est-selectionne {
    background: var(--bleu); color: #fff; font-weight: 600;
}
.link-picker-v2 .lp-list li[data-lp-item][hidden] { display: none; }

/* ---------- Sélecteur de couleurs (palette curée + teinte libre) ---------- */
.degrade-apercu {
    height: 82px; border-radius: 12px; margin-bottom: 20px;
    display: flex; align-items: flex-end; padding: 12px 16px;
    color: #fff; font-size: 13px; font-weight: 600; text-shadow: 0 1px 3px rgba(0, 0, 0, .35);
    transition: background .25s ease;
}
.couleur-champ + .couleur-champ { margin-top: 18px; }
.badge-contraste { font-size: 11px; margin-left: 6px; font-variant-numeric: tabular-nums; cursor: help; }

/* La palette est repliée : seule la teinte courante est visible */
.couleur-dd { position: relative; }
.couleur-dd > summary {
    list-style: none; cursor: pointer; display: flex; align-items: center; gap: 10px;
    border: 1px solid var(--bordure); border-radius: 10px; padding: 7px 12px; background: var(--blanc);
}
.couleur-dd > summary::-webkit-details-marker { display: none; }
.couleur-dd > summary:hover { border-color: var(--bleu); }
.couleur-dd[open] > summary { border-color: var(--bleu); }
.couleur-dd[open] > summary .ico { transform: rotate(180deg); }
.couleur-dd > summary .ico { margin-left: auto; color: var(--gris); transition: transform .15s ease; }
.couleur-apercu {
    width: 24px; height: 24px; border-radius: 7px; flex-shrink: 0;
    box-shadow: 0 0 0 1px rgba(15, 23, 42, .12) inset;
}
.couleur-nom { font-size: 13px; }
.couleur-menu {
    position: absolute; left: 0; top: calc(100% + 6px); z-index: 50; width: 300px;
    background: var(--blanc); border: 1px solid var(--bordure); border-radius: 12px; padding: 12px;
    box-shadow: 0 16px 40px -8px rgba(16, 24, 40, .26);
}
/* Nuancier : 12 familles en colonnes, 7 intensités en lignes.
   Chaque ligne est une déclinaison plus claire de celle du dessus. */
.couleur-menu .couleur-palette { display: grid; grid-template-columns: repeat(12, 1fr); gap: 4px; }
.couleur-menu .pastille { width: 100%; aspect-ratio: 1; height: auto; border-radius: 50%; }
.couleur-perso { display: flex; align-items: center; gap: 10px; padding-top: 10px; border-top: 1px solid var(--bordure); }
.couleur-perso label { margin: 0; font-size: 13px; font-weight: 500; color: var(--gris); }
.couleur-perso input[type="color"] { width: 42px; height: 30px; margin-left: auto; }
.couleur-palette { display: flex; flex-wrap: wrap; gap: 7px; margin-bottom: 10px; }
.pastille {
    width: 26px; height: 26px; border-radius: 50%; border: 2px solid transparent;
    cursor: pointer; padding: 0; position: relative;
    box-shadow: 0 0 0 1px rgba(15, 23, 42, .12) inset;
    transition: transform .12s ease, border-color .12s ease;
}
.pastille:hover { transform: scale(1.22); z-index: 2; }
.pastille.pastille-active,
.pastille.pastille-active:hover {
    border-color: var(--encre); box-shadow: 0 0 0 2px var(--blanc) inset;
    transform: scale(1.15); z-index: 2;
}
.couleur-valeur {
    font-family: ui-monospace, Consolas, monospace; font-size: 12.5px; font-weight: 600;
    background: #f1f5f9; padding: 4px 9px; border-radius: 6px;
}

/* ---------- Aperçu typographique ---------- */
.typo-apercu {
    border: 1px solid var(--bordure); border-radius: 12px; padding: 16px 18px;
    background: #fbfcfe; margin-top: 16px;
}
.typo-apercu-titre { font-size: 24px; font-weight: 650; margin: 0 0 6px; line-height: 1.2; letter-spacing: -.015em; }
.typo-apercu-texte { font-size: 15px; margin: 0; color: #46525f; line-height: 1.65; }
.select-police { font-size: 15px; }
.select-police optgroup { font-family: var(--police-admin, inherit); font-size: 12px; }

/* ---------- Choix d'icône (raccourcis) ---------- */
.icone-grid { display: flex; flex-wrap: wrap; gap: 6px; }
.icone-choice { margin: 0; cursor: pointer; }
.icone-choice input { position: absolute; opacity: 0; }
.icone-choice span {
    display: flex; align-items: center; justify-content: center; width: 42px; height: 42px;
    border: 2px solid var(--bordure); border-radius: 12px; color: var(--encre);
}
.icone-choice input:checked + span { border-color: var(--bleu); background: var(--bleu-clair); color: var(--bleu); }

/* ---------- Glisser-déposer (menus) ---------- */
.drag-handle { cursor: grab; color: var(--gris); width: 34px; }
.drag-handle:active { cursor: grabbing; }
tr[draggable]:hover .drag-handle { color: var(--bleu); }

/* Glisser-déposer : la ligne déplacée reste bien visible à sa future place,
   les autres s'estompent pour matérialiser la destination. */
tbody.drag-actif tr:not(.drag-en-cours) { opacity: .45; }
tbody.drag-actif tr:not(.drag-en-cours):hover { background: transparent; }
tr.drag-en-cours td {
    background: var(--bleu-clair);
    box-shadow: inset 0 2px 0 var(--bleu), inset 0 -2px 0 var(--bleu);
}
tr.drag-en-cours td:first-child { box-shadow: inset 2px 0 0 var(--bleu), inset 0 2px 0 var(--bleu), inset 0 -2px 0 var(--bleu); }
tr.drag-en-cours td:last-child { box-shadow: inset -2px 0 0 var(--bleu), inset 0 2px 0 var(--bleu), inset 0 -2px 0 var(--bleu); }
tr.drag-en-cours .drag-handle { color: var(--bleu); }
tr.drag-en-cours .drag-handle::after {
    content: "Déposer ici"; position: absolute; margin-left: 30px; margin-top: -9px;
    background: var(--bleu); color: #fff; font-size: 11px; font-weight: 700;
    padding: 3px 8px; border-radius: 20px; white-space: nowrap; pointer-events: none;
}
tr.drag-en-cours { position: relative; }
/* Entrée de sous-menu (niveau 2) */
tr.menu-enfant td:nth-child(2) { padding-left: 4px; }
tr.menu-enfant strong { font-weight: 500; }
.menu-indent {
    display: inline-block; width: 26px; height: 13px; margin-right: 6px; vertical-align: 1px;
    border-left: 2px solid var(--bordure); border-bottom: 2px solid var(--bordure);
    border-bottom-left-radius: 5px;
}
/* Lignes d'entrées OBLIGATOIRES du menu du pied de page (pages légales
   auto). Grisées, non éditables, non draggables — signalées comme
   présentes mais figées. */
tr.menu-obligatoire { opacity: .55; background: color-mix(in srgb, var(--fond) 60%, transparent); }
tr.menu-obligatoire td:first-child { color: var(--gris); cursor: not-allowed; }
tr.menu-obligatoire strong { font-weight: 500; }
tr.menu-obligatoire .badge { font-size: 11px; margin-left: 8px; }
.badge-toggle-form { border: none; cursor: pointer; display: inline-flex; align-items: center; gap: 4px; }

/* ---------- Modales en overlay (ajout / édition) ---------- */
dialog.admin-modal {
    border: none; border-radius: 16px; padding: 0; width: 560px; max-width: calc(100vw - 40px);
    box-shadow: 0 30px 80px -10px rgba(0, 0, 0, .45);
}
dialog.admin-modal::backdrop { background: rgba(0, 0, 0, .75); }
.admin-modal-entete {
    display: flex; align-items: center; justify-content: space-between;
    padding: 16px 22px; border-bottom: 1px solid var(--bordure);
}
.admin-modal-entete h2 { margin: 0; font-size: 17px; }
.admin-modal-fermer { border: none; background: #f1f5f9; border-radius: 999px; padding: 8px; cursor: pointer; display: flex; }
.admin-modal-corps { padding: 18px 22px 22px; max-height: 72vh; overflow-y: auto; }
/* Les actions d'une modale respirent et sont séparées du dernier champ */
.admin-modal-corps .form-actions {
    display: flex; gap: 10px; margin: 26px 0 0; padding-top: 18px;
    border-top: 1px solid var(--bordure);
}
.admin-modal-corps .form-actions .btn { margin-left: 0; }

/* ---------- Picker de contenus newsletter (multi-sélection) ----------
   Utilisé dans les modales « Ajouter des actualités / événements » du
   composer newsletter. Grille de cartes cochables : vignette + titre +
   date + résumé. La sélection colore le bord et le fond ; case à cocher
   discrète en coin haut-gauche, la carte entière est cliquable via <label>. */
.nl-picker-grille {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 12px;
    margin-bottom: 16px;
}
.nl-picker-item {
    position: relative;
    display: flex; gap: 10px;
    padding: 10px;
    border: 2px solid var(--bordure);
    border-radius: 8px;
    background: var(--blanc);
    cursor: pointer;
    transition: border-color .15s ease, background-color .15s ease;
    margin: 0;  /* neutralise la marge globale des <label> */
}
.nl-picker-item:hover { border-color: color-mix(in srgb, var(--bleu) 50%, var(--bordure)); }
.nl-picker-item.est-selectionne {
    border-color: var(--bleu);
    background: color-mix(in srgb, var(--bleu) 6%, var(--blanc));
}
/* Item déjà présent dans la newsletter — grisé, non-cochable, message
   « Déjà ajouté » sous le titre. Empêche l'ajout d'un doublon. */
.nl-picker-item.est-deja-inseree {
    opacity: .55;
    background: var(--fond);
    cursor: not-allowed;
}
.nl-picker-item.est-deja-inseree:hover { border-color: var(--bordure); }
.nl-picker-item.est-deja-inseree .nl-picker-check { cursor: not-allowed; }
/* Case à cocher : masquée visuellement, on montre un ✓ personnalisé
   via ::after sur .nl-picker-item quand cochée. Positionnée en coin. */
.nl-picker-check {
    position: absolute; top: 8px; left: 8px;
    width: 20px; height: 20px;
    accent-color: var(--bleu);
    cursor: pointer;
    z-index: 2;
}
.nl-picker-img {
    width: 72px; height: 60px;
    object-fit: cover;
    border-radius: 4px;
    flex-shrink: 0;
    display: block;
}
.nl-picker-img-vide {
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--fond);
    color: var(--gris);
    border: 1px solid var(--bordure);
}
.nl-picker-corps {
    flex: 1; min-width: 0;
    padding-left: 20px;  /* laisse la place à la case en absolute */
}
.nl-picker-titre {
    font-weight: 600; font-size: 14px;
    color: var(--encre);
    overflow: hidden; text-overflow: ellipsis;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    line-height: 1.3;
}
.nl-picker-meta {
    font-size: 12px; color: var(--gris);
    margin-top: 2px;
}
.nl-picker-sub {
    font-size: 12.5px; color: var(--gris);
    margin-top: 4px;
    overflow: hidden; text-overflow: ellipsis;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    line-height: 1.4;
}

/* ---------- Composant média (image / vidéo) ----------
   Un seul champ visuel avec aperçu immédiat : plus de case à cocher
   « supprimer » séparée, un simple × sur la miniature. Le drop&drag et
   le click ouvrent le même sélecteur natif. Le recadrage est proposé en
   modal à la sélection d'une image quand data-crop est présent. */
.upload-media {
    display: block; margin: 8px 0 14px;
}
.upload-media .upload-input {
    position: absolute; left: -9999px; opacity: 0; pointer-events: none;
}
.upload-zone {
    position: relative; display: flex; align-items: center; justify-content: center;
    width: 100%; aspect-ratio: var(--upload-ratio, 3 / 2);
    max-height: 320px; overflow: hidden;
    background: #f8fafc; border: 2px dashed var(--bordure); border-radius: 12px;
    cursor: pointer; transition: border-color .18s ease, background .18s ease;
}
.upload-zone:hover { border-color: var(--bleu); background: var(--bleu-clair); }
.upload-zone.upload-zone-dragover { border-color: var(--bleu); background: var(--bleu-clair); border-style: solid; }
.upload-zone.upload-zone-refus { border-color: var(--danger, #dc2626); background: color-mix(in srgb, var(--danger, #dc2626) 6%, transparent); border-style: solid; }
.upload-zone-vide { color: var(--gris); }
.upload-media-vide { display: flex; flex-direction: column; align-items: center; gap: 6px; font-size: 14px; font-weight: 500; }
.upload-media-vide .ico { opacity: .5; }
.upload-media-preview {
    display: block; width: 100%; height: 100%; object-fit: cover;
}
.upload-media-x {
    position: absolute; top: 8px; right: 8px;
    width: 30px; height: 30px; padding: 0;
    display: inline-flex; align-items: center; justify-content: center;
    background: rgba(15, 23, 42, .78); color: #fff; border: 0; border-radius: 999px;
    cursor: pointer; opacity: 0;
    transition: opacity .18s ease, background .15s ease, transform .1s ease;
}
.upload-zone:hover .upload-media-x { opacity: 1; }
.upload-media-x:hover { background: var(--danger, #dc2626); transform: scale(1.08); }
.upload-media-x[hidden] { display: none; }

/* Aperçu voile hero sur les médias du bandeau — piloté par les data-*
   set en JS (data-voile="clair|sombre|sans", CSS var --upload-voile-opacite). */
.upload-zone[data-voile="clair"]::after,
.upload-zone[data-voile="sombre"]::after {
    content: ""; position: absolute; inset: 0; pointer-events: none;
    opacity: var(--upload-voile-opacite, .6);
    z-index: 1;
}
.upload-zone[data-voile="clair"]::after { background: #ffffff; }
.upload-zone[data-voile="sombre"]::after { background: #000000; }
.upload-zone[data-voile] .upload-media-x { z-index: 2; }

/* Sliders custom (opacité voile, largeur du bandeau) : rail neutre plein
   sans progression colorée du côté rempli — comportement identique de
   gauche à droite. Rail 10 px, ombre douce sur la poignée. */
input[type="range"][data-hero-opacite],
input[type="range"][data-hero-largeur] {
    -webkit-appearance: none; appearance: none;
    width: 100%; max-width: 940px; height: 10px; padding: 0;
    background: var(--bordure); border-radius: 999px; border: none;
    outline: none;
}
input[type="range"][data-hero-opacite]:focus,
input[type="range"][data-hero-largeur]:focus { outline: none; box-shadow: none; }
/* Chrome / Edge / Safari — la « progress track » est neutralisée en
   forçant le fond du rail à travers ces pseudo-éléments. */
input[type="range"][data-hero-opacite]::-webkit-slider-runnable-track,
input[type="range"][data-hero-largeur]::-webkit-slider-runnable-track {
    height: 10px; background: var(--bordure); border-radius: 999px;
}
input[type="range"][data-hero-opacite]::-moz-range-track,
input[type="range"][data-hero-largeur]::-moz-range-track {
    height: 10px; background: var(--bordure); border-radius: 999px;
}
/* Firefox rendait par défaut une portion « progress » colorée, on la
   remet dans la couleur du rail. */
input[type="range"][data-hero-opacite]::-moz-range-progress,
input[type="range"][data-hero-largeur]::-moz-range-progress {
    background: var(--bordure); height: 10px;
}
input[type="range"][data-hero-opacite]::-webkit-slider-thumb,
input[type="range"][data-hero-largeur]::-webkit-slider-thumb {
    -webkit-appearance: none; appearance: none;
    width: 20px; height: 20px; border-radius: 999px;
    background: var(--bleu); cursor: pointer; border: 2px solid #fff;
    box-shadow: 0 1px 4px rgba(15, 23, 42, .2);
    margin-top: -5px;
}
input[type="range"][data-hero-opacite]::-moz-range-thumb,
input[type="range"][data-hero-largeur]::-moz-range-thumb {
    width: 20px; height: 20px; border-radius: 999px;
    background: var(--bleu); cursor: pointer; border: 2px solid #fff;
    box-shadow: 0 1px 4px rgba(15, 23, 42, .2);
}

/* Variante compacte pour le logo : plus petite, largeur limitée.
   `contain` au lieu de `cover` : un logo ne doit jamais être rogné, on
   respecte ses proportions au sein du cadre. Damier subtil pour révéler
   les transparences PNG — décliné en 2 versions (fond clair / foncé)
   selon le champ (`data-nom="logo"` vs `data-nom="logo_sombre"`), pour
   que chaque logo ressorte comme il sera vu en usage réel. */
.upload-media-compact .upload-zone {
    max-width: 100%; max-height: 200px; aspect-ratio: 3 / 2;
}
.upload-media-compact .upload-media-preview {
    object-fit: contain;
    padding: 14px;
}

/* Logo clair : damier sur fond blanc — révèle une transparence sombre. */
.upload-media-compact[data-nom="logo"] .upload-zone {
    background:
        linear-gradient(45deg, #e7ecf3 25%, transparent 25%) 0 0/18px 18px,
        linear-gradient(-45deg, #e7ecf3 25%, transparent 25%) 0 9px/18px 18px,
        linear-gradient(45deg, transparent 75%, #e7ecf3 75%) 9px -9px/18px 18px,
        linear-gradient(-45deg, transparent 75%, #e7ecf3 75%) -9px 0/18px 18px,
        #ffffff;
    border-color: var(--bordure);
}
/* Logo foncé : damier sur fond charbon — révèle une transparence claire. */
.upload-media-compact[data-nom="logo_sombre"] .upload-zone {
    background:
        linear-gradient(45deg, #1c2534 25%, transparent 25%) 0 0/18px 18px,
        linear-gradient(-45deg, #1c2534 25%, transparent 25%) 0 9px/18px 18px,
        linear-gradient(45deg, transparent 75%, #1c2534 75%) 9px -9px/18px 18px,
        linear-gradient(-45deg, transparent 75%, #1c2534 75%) -9px 0/18px 18px,
        #0f172a;
    border-color: #334155;
    color: #cbd5e1;   /* couleur du placeholder "Cliquez ou déposez…" en clair */
}
/* Hover : glow ring bleu + bordure — beaucoup plus visible sur les cards
   logo (le checker background couvre déjà toute la zone, un simple
   changement de border-color passe inaperçu). Aligné sur le focus-ring
   des champs classiques (outline 2px + halo). */
.upload-media-compact .upload-zone:hover {
    border-color: var(--bleu);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--bleu) 22%, transparent);
}
/* Icône du placeholder — plus visible sur le checker (0.5 se noyait). */
.upload-media-compact .upload-media-vide .ico { opacity: .75; }
/* Card foncée : la croix ✕ (fond charbon + icône blanche) disparaissait
   sur le fond charbon du checker. On inverse : pastille blanche + icône
   sombre pour rester lisible. */
.upload-media-compact[data-nom="logo_sombre"] .upload-media-x {
    background: rgba(255, 255, 255, .9); color: #0f172a;
}
.upload-media-compact[data-nom="logo_sombre"] .upload-media-x:hover {
    background: var(--danger, #dc2626); color: #fff;
}
.upload-media-compact[data-nom="logo_sombre"] .upload-zone:hover {
    background:
        linear-gradient(45deg, #263045 25%, transparent 25%) 0 0/18px 18px,
        linear-gradient(-45deg, #263045 25%, transparent 25%) 0 9px/18px 18px,
        linear-gradient(45deg, transparent 75%, #263045 75%) 9px -9px/18px 18px,
        linear-gradient(-45deg, transparent 75%, #263045 75%) -9px 0/18px 18px,
        #1e293b;
    border-color: var(--bleu);
}

/* ---------- Barre d'enregistrement fixe ----------
   Position sticky bas d'écran, cachée tant qu'aucun formulaire n'est marqué
   dirty. Le contenu principal reçoit un padding-bottom quand la barre est
   visible, sinon le bouton flottant recouvrirait le pied de page. */
.admin-savebar {
    /* Barre détachée : marges 14 px, s'aligne à droite de la sidebar 240 px.
       En dessous du breakpoint mobile (où la sidebar passe en haut), on
       remet left à la marge simple — voir la règle plus bas.
       Fond orange = signal de « quelque chose reste à valider » — bien plus
       visible dans une interface majoritairement bleue/grise. */
    position: fixed; left: 254px; right: 14px; bottom: 14px; z-index: 200;
    background: #ea580c; color: #ffffff;
    border: 1px solid #c2410c; border-radius: 12px;
    box-shadow: 0 12px 32px -8px rgba(234, 88, 12, .45), 0 4px 12px -4px rgba(15, 23, 42, .3);
    padding: 12px 20px;
    transform: translateY(calc(100% + 20px));
    transition: transform .28s cubic-bezier(0.4, 0, 0.2, 1);
    pointer-events: none;
}
.admin-savebar.admin-savebar-visible {
    transform: translateY(0);
    pointer-events: auto;
}
.admin-savebar-conteneur {
    max-width: 1800px; margin: 0 auto;
    display: flex; align-items: center; justify-content: space-between; gap: 20px;
    flex-wrap: wrap;
}
.admin-savebar-message {
    display: inline-flex; align-items: center; gap: 10px;
    font-size: 14px; font-weight: 550; color: #ffffff;
}
.admin-savebar-message .ico { color: #ffedd5; }
.admin-savebar-actions { display: inline-flex; gap: 6px; align-items: center; }
/* CTA « Annuler » : texte clair sur fond orange, pas de bordure ni fond,
   contraste avec le CTA principal blanc. */
.admin-savebar-annuler {
    background: transparent !important; border: none !important;
    color: rgba(255, 255, 255, .82) !important; padding: 8px 12px !important;
    font-size: 13.5px; font-weight: 500;
    text-decoration: none;
}
.admin-savebar-annuler:hover { color: #fff !important; }
/* CTA « Enregistrer » : bouton blanc plein, texte orange foncé — inversion
   maximale de contraste sur le fond orange. */
.admin-savebar-enregistrer {
    background: #ffffff !important; color: #9a3412 !important;
    border: 1px solid #ffffff !important;
    font-weight: 600;
}
.admin-savebar-enregistrer:hover { background: #fff7ed !important; border-color: #fff7ed !important; }
.admin-savebar-enregistrer:disabled,
.admin-savebar-enregistrer[disabled] {
    opacity: .5; cursor: not-allowed;
}
/* Contenu principal reçoit une marge basse quand la barre est visible */
body.savebar-actif .content { padding-bottom: 110px; }

/* Message temporaire au-dessus de la barre — pas un toast global, juste un
   retour visuel court près du bouton d'enregistrement. */
.admin-flash-temp {
    position: fixed; left: 50%; bottom: 78px; transform: translateX(-50%);
    padding: 10px 18px; border-radius: 999px; z-index: 210;
    font-size: 14px; font-weight: 550;
    box-shadow: 0 8px 24px -6px rgba(15, 23, 42, .25);
    animation: admin-flash-in .18s ease-out;
}
.admin-flash-temp.sortie { opacity: 0; transition: opacity .35s ease; }
.admin-flash-success { background: #d1fae5; color: #065f46; }
.admin-flash-error   { background: #fee2e2; color: #991b1b; }
.admin-flash-info    { background: #dbeafe; color: #1e40af; }
@keyframes admin-flash-in {
    from { opacity: 0; transform: translate(-50%, 8px); }
    to   { opacity: 1; transform: translate(-50%, 0); }
}

/* Un formulaire avec data-savebar cache son propre bouton d'enregistrement :
   la barre fixe joue le rôle du bouton, éviter la duplication. */
form[data-savebar] > button[type="submit"],
form[data-savebar] > .form-actions {
    display: none;
}

/* ---------- Overlay obligatoire (définition du mot de passe) ----------
   Bloque toute interaction avec le reste du tableau de bord jusqu'à ce
   qu'une action obligatoire soit accomplie. Le refus des POST est fait
   côté serveur (voir admin/index.php + Auth::mustSetPassword) ; l'overlay
   est le versant visuel du garde-fou. */
.admin-obligatoire {
    position: fixed; inset: 0; z-index: 1000;
    background: rgba(15, 23, 42, .68); backdrop-filter: blur(4px);
    display: flex; align-items: center; justify-content: center; padding: 20px;
    animation: admin-obligatoire-fade .18s ease-out;
}
@keyframes admin-obligatoire-fade { from { opacity: 0 } to { opacity: 1 } }
.admin-obligatoire-dialog {
    background: var(--blanc); border-radius: 14px; width: 100%; max-width: 480px;
    box-shadow: 0 28px 80px -12px rgba(15, 23, 42, .55);
    padding: 26px 28px;
}
.admin-obligatoire-dialog h2 {
    margin: 0 0 12px; font-size: 20px; display: flex; align-items: center; gap: 10px;
    color: var(--bleu-fonce);
}
.admin-obligatoire-dialog h2 .ico { color: var(--bleu); }
.admin-obligatoire-dialog p { color: var(--gris); font-size: 14.5px; line-height: 1.5; margin: 0 0 4px; }
.admin-obligatoire-echap {
    font-size: 13px; color: var(--gris); margin-top: 18px; text-align: center;
}
.admin-obligatoire-echap a { color: var(--bleu); }

/* ---------- Overlay onboarding ----------
   Extension de `.admin-obligatoire` pour le wizard 5 étapes. Dialog plus
   large, hauteur limitée avec scroll interne, boutons scellés en bas via
   flex column. Toutes les classes ob-* déclarées ici (au lieu de vivre
   inline dans onboarding.php) parce que le partial est maintenant injecté
   dans admin_footer et bénéficie du CSS global admin. */
.onboarding-overlay .ob-dialog {
    max-width: 720px;
    max-height: calc(100vh - 60px);
    display: flex; flex-direction: column;
    overflow: hidden;
    padding: 24px 28px 20px;
}
/* Bandeau d'erreur AJAX du wizard — placé en tête du dialog, visible sans
   scroll. Alerte rouge classique, marge basse pour se détacher du contenu. */
.ob-error {
    background: #fee2e2; border: 1px solid #fca5a5;
    color: #991b1b; padding: 10px 14px; border-radius: 8px;
    font-size: 13.5px; line-height: 1.4;
    margin: 0 0 14px; flex-shrink: 0;
}
.ob-error[hidden] { display: none; }
.onboarding-overlay form { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; margin: 0; }
.ob-progress { display: flex; gap: 6px; margin: 0 0 16px; flex-shrink: 0; }
.ob-progress-etape { flex: 1; height: 4px; border-radius: 2px; background: #e2e8f0; }
.ob-progress-etape.faite { background: #22c55e; }
.ob-progress-etape.courante { background: var(--bleu, #2563eb); }
.ob-etape-label {
    font-size: 12px; letter-spacing: .06em; text-transform: uppercase;
    color: #64748b; margin: 0 0 8px; font-weight: 600; flex-shrink: 0;
}
.ob-scroll {
    flex: 1 1 auto; min-height: 0;
    overflow-y: auto;
}
/* Focus sur les champs de l'overlay : box-shadow INTERNE au lieu de
   l'outline natif. Un outline s'étend HORS de l'élément et se fait
   tronquer par les `overflow: hidden` du dialog parent (bord gauche des
   inputs coupé). Un box-shadow inset reste dans le border-box, invulnérable. */
.onboarding-overlay input:focus:not([type="radio"]):not([type="checkbox"]):not([type="file"]),
.onboarding-overlay textarea:focus,
.onboarding-overlay select:focus {
    outline: none;
    box-shadow: inset 0 0 0 2px var(--bleu, #2563eb);
    border-color: var(--bleu, #2563eb);
}
.ob-titre { font-size: 22px; margin: 0 0 6px; color: #0f172a; font-weight: 700; }
.ob-chapo { color: #475569; margin: 0 0 18px; line-height: 1.5; font-size: 14.5px; }
.onboarding-overlay textarea { resize: none; }

/* Ambiances — slider paginé (le JS vit dans admin.js, déjà en place). */
.ob-ambiances-viewport { position: relative; padding: 0 36px; }
.ob-ambiances-fenetre { overflow: hidden; padding: 4px 2px; }
.ob-ambiances { display: flex; gap: 12px; transition: transform .3s ease; }
.ob-ambiance {
    position: relative;
    flex: 0 0 calc((100% - 24px) / 3);
    height: 148px;
    box-sizing: border-box;
    margin: 0;
    border-radius: 12px; padding: 14px;
    border: 2px solid transparent; background: #f8fafc;
    cursor: pointer;
    transition: border-color .15s ease, background .15s ease;
    display: flex; flex-direction: column;
}
@media (max-width: 620px) {
    .ob-ambiance { flex-basis: calc((100% - 12px) / 2); }
}
.ob-ambiance input { position: absolute; opacity: 0; pointer-events: none; }
.ob-ambiance:has(input:checked) { border-color: var(--bleu, #2563eb); background: #eff6ff; }
.ob-ambiance-swatch { display: flex; gap: 4px; margin-bottom: 8px; }
.ob-ambiance-swatch span {
    flex: 1; height: 26px; border-radius: 4px;
    border: 1px solid rgba(15, 23, 42, .08);
}
.ob-ambiance strong { display: block; font-size: 14px; color: #0f172a; }
.ob-ambiance small {
    display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
    overflow: hidden;
    color: #64748b; font-size: 12px; margin-top: 2px; line-height: 1.35;
}
/* Ambiances sombres — carte en fond foncé pour mini-preview. */
.ob-ambiance[data-ton="sombre"] { background: #1e293b; }
.ob-ambiance[data-ton="sombre"] strong { color: #f8fafc; }
.ob-ambiance[data-ton="sombre"] small { color: #94a3b8; }
.ob-ambiance[data-ton="sombre"]:has(input:checked) { background: #0f172a; border-color: #60a5fa; }
.ob-ambiance-badge {
    position: absolute; top: 8px; right: 8px;
    font-size: 9.5px; font-weight: 700;
    padding: 2px 7px; border-radius: 4px;
    background: rgba(255, 255, 255, .12); color: #f1f5f9;
    text-transform: uppercase; letter-spacing: .06em;
}
.ob-slider-btn {
    position: absolute; top: 50%; transform: translateY(-50%);
    width: 32px; height: 32px; border-radius: 50%;
    background: #ffffff; border: 1px solid #e2e8f0;
    display: flex; align-items: center; justify-content: center;
    color: #475569; cursor: pointer; z-index: 2;
    transition: opacity .15s ease, background .15s ease;
    box-shadow: 0 2px 6px rgba(15, 23, 42, .08);
}
.ob-slider-btn:hover:not(:disabled) { background: #f8fafc; color: #0f172a; }
.ob-slider-btn:disabled { opacity: .3; cursor: default; }
.ob-slider-prev { left: 0; }
.ob-slider-next { right: 0; }

/* Modules — toggle switches. */
.ob-modules { display: grid; gap: 4px; }
.ob-module {
    display: flex; align-items: center; gap: 14px;
    padding: 10px 14px; border-radius: 8px; border: 1px solid #e2e8f0;
    background: #fff; cursor: pointer; margin: 0;
}
.ob-module:has(input:checked) { border-color: #22c55e; background: #f0fdf4; }
.ob-module-corps { flex: 1; min-width: 0; }
.ob-module strong { display: block; font-size: 14px; color: #0f172a; }
.ob-module small { display: block; color: #64748b; font-size: 12.5px; margin-top: 2px; line-height: 1.4; }
.ob-module-prix { font-size: 12px; color: #475569; font-weight: 600; white-space: nowrap; }
.ob-toggle {
    position: relative; flex-shrink: 0;
    appearance: none; -webkit-appearance: none;
    width: 40px; height: 22px;
    background: #cbd5e1; border-radius: 999px;
    cursor: pointer; margin: 0;
    transition: background .18s ease;
}
.ob-toggle::after {
    content: ''; position: absolute; top: 2px; left: 2px;
    width: 18px; height: 18px; background: #fff; border-radius: 50%;
    box-shadow: 0 1px 3px rgba(15, 23, 42, .3);
    transition: transform .18s ease;
}
.ob-toggle:checked { background: #22c55e; }
.ob-toggle:checked::after { transform: translateX(18px); }

/* Boutons de pied de wizard. */
.ob-actions {
    display: flex; align-items: center; gap: 10px;
    margin-top: 18px; padding-top: 16px; border-top: 1px solid #e2e8f0;
    flex-shrink: 0;
}
.ob-actions .ob-spacer { flex: 1; }
.ob-actions .ob-passer {
    color: #64748b; font-size: 13px; text-decoration: underline;
    background: none; border: 0; cursor: pointer; padding: 0;
}
.ob-actions .ob-passer:hover { color: #0f172a; }

/* ---------- Œil « afficher le mot de passe » ---------- */
/* Le conteneur enveloppe l'input existant sans changer sa position dans la
   page (display:block, largeur 100 %) ; l'œil est positionné en absolu
   dans l'espace à droite libéré par un padding accru sur l'input. */
.pwd-wrapper { position: relative; display: block; }
.pwd-wrapper > input { padding-right: 42px; }
/* Champ leurre servi à Firefox pour absorber le remplissage automatique
   du premier `input[type=password]` du formulaire — l'utilisateur ne doit
   ni le voir, ni pouvoir l'atteindre au tab. `display:none` ne suffit pas :
   Firefox le saute. On le place hors-écran avec taille 0. */
.champ-leurre {
    position: absolute; left: -9999px; top: -9999px;
    width: 1px; height: 1px; opacity: 0; pointer-events: none;
}
/* Picker de niveau d'alerte — 3 cards prévisualisant la couleur et l'icône
   avec lesquelles le bandeau apparaîtra sur le site public. Radio caché,
   la carte sélectionnée épaissit sa bordure et gagne une ombre légère.
   Les fonds/couleurs de chaque card MIROIRENT les règles publiques
   `.alerte-info`, `.alerte-attention`, `.alerte-urgent` de site.css. */
.niveau-picker {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 12px;
    margin: 4px 0 4px;
}
.niveau-choice {
    position: relative;
    display: flex; align-items: center; gap: 12px;
    padding: 14px 16px;
    border-radius: var(--rayon);
    border: 2px solid transparent;
    cursor: pointer;
    transition: transform .12s ease, box-shadow .18s ease;
    font-weight: 400;
    margin: 0;
}
.niveau-choice input { position: absolute; opacity: 0; pointer-events: none; }
.niveau-choice:hover { transform: translateY(-1px); }
.niveau-choice.selected {
    box-shadow: 0 6px 16px -4px rgba(15, 23, 42, .25);
    outline: 2px solid var(--bleu);
    outline-offset: 2px;
}
.niveau-icone { flex: 0 0 auto; display: inline-flex; align-items: center; }
.niveau-corps { display: flex; flex-direction: column; gap: 2px; line-height: 1.3; }
.niveau-corps strong { font-size: 14.5px; font-weight: 600; }
.niveau-corps small { font-size: 12.5px; opacity: .85; }

/* Miroir des règles publiques `.alerte-*` — fond identique, texte
   contrasté. Les valeurs sont copiées pour rester lisibles côté admin
   sans dépendre de site.css. */
.niveau-info      { background: #eef4fd; color: #173e6b; border-color: #d8e6f8; }
.niveau-attention { background: #fef6e0; color: #8a4b0f; border-color: #f8e8bd; }
.niveau-urgent    { background: #c22030; color: #ffffff; border-color: #a5192a; }

/* Autocomplétion d'adresse via l'API Adresse (BAN, data.gouv.fr) —
   input avec picto pin à gauche + liste de suggestions absolue en-dessous.
   Charte : bordure/rayons de la charte admin, hover bleu-clair, sélection
   flèches clavier en bleu. */
.ban-picker { position: relative; display: block; }
.ban-input-wrap { position: relative; display: block; }
.ban-input-wrap input { padding-left: 40px; padding-right: 40px; box-sizing: border-box; }
.ban-picto {
    position: absolute; left: 12px; top: 50%;
    transform: translateY(-50%);
    color: var(--gris);
    pointer-events: none;
    display: inline-flex; align-items: center;
}
.ban-picto[hidden] { display: none; }
/* Croix visible quand une adresse est validée : réinitialise le picker. */
.ban-clear {
    position: absolute; right: 8px; top: 50%;
    transform: translateY(-50%);
    background: transparent; border: 0; padding: 6px; cursor: pointer;
    color: var(--gris); border-radius: 6px;
    display: inline-flex; align-items: center; justify-content: center;
    transition: background .15s ease, color .15s ease;
}
.ban-clear[hidden] { display: none; }
.ban-clear:hover { background: color-mix(in srgb, var(--gris) 15%, transparent); color: var(--encre, #0f172a); }
/* Verrouillé : input readonly stylisé subtilement pour signaler l'état
   figé — pas grisé lourdement, juste un fond légèrement teinté. */
.ban-picker.ban-verrouille input[readonly] {
    background: var(--bleu-clair, #eef2ff);
    cursor: default;
    padding-left: 14px;   /* pas de picto à gauche, on récupère la place */
}
.ban-suggestions {
    list-style: none; margin: 4px 0 0; padding: 6px 0;
    position: absolute; left: 0; right: 0; top: 100%; z-index: 40;
    background: #ffffff;
    border: 1px solid var(--bordure);
    border-radius: var(--rayon);
    box-shadow: 0 12px 28px -8px rgba(15, 23, 42, .18);
    max-height: 260px; overflow-y: auto;
}
.ban-suggestion {
    padding: 8px 14px; cursor: pointer;
    display: flex; flex-direction: column; gap: 2px;
    font-size: 14px; line-height: 1.3;
}
.ban-suggestion strong { font-weight: 600; color: var(--encre, #0f172a); }
.ban-suggestion span { font-size: 12.5px; color: var(--gris); }
.ban-suggestion:hover,
.ban-suggestion.actif { background: var(--bleu-clair); }
.ban-position {
    display: inline-flex; align-items: center; gap: 5px;
    margin: 6px 0 0; font-size: 12.5px; color: var(--ok, #15803d);
}
.ban-position[hidden] { display: none; }

/* Champ date/heure Flatpickr — enveloppe qui pose l'icône calendrier à
   droite du champ visible. Flatpickr duplique l'input en `altInput` juste
   après l'original ; on cible les deux avec `.champ-date input` pour que
   le padding-right soit appliqué à l'input visible. */
.champ-date { position: relative; display: block; }
.champ-date input { padding-right: 40px; box-sizing: border-box; }
/* Flatpickr masque l'input original via `type=hidden` — pas de style à
   forcer côté display. L'alt input hérite du .champ-date input padding. */
.champ-date-picto {
    position: absolute; right: 12px; top: 50%;
    transform: translateY(-50%);
    color: var(--gris);
    pointer-events: none;
    display: inline-flex; align-items: center;
}

/* --- Uniformisation Flatpickr avec la charte admin ---------------------
   Rayons, ombre douce, bleu Civika pour la sélection, gris de la charte
   pour la nav et les jours désactivés. Overrides à specificité normale
   (.flatpickr-calendar est déjà ciblée par le CSS vendor). */
.flatpickr-calendar {
    border-radius: var(--rayon);
    border: 1px solid var(--bordure);
    box-shadow: 0 12px 32px -8px rgba(15, 23, 42, .18);
    font-family: inherit;
}
.flatpickr-calendar.arrowTop::before,
.flatpickr-calendar.arrowBottom::before { border-bottom-color: var(--bordure); border-top-color: var(--bordure); }
.flatpickr-calendar.arrowTop::after { border-bottom-color: #ffffff; }
.flatpickr-calendar.arrowBottom::after { border-top-color: #ffffff; }
.flatpickr-months .flatpickr-month {
    color: var(--encre, #0f172a);
    height: 44px;
}
.flatpickr-current-month { padding-top: 8px; font-size: 15px; font-weight: 600; }
.flatpickr-current-month input.cur-year { font-weight: 600; }
.flatpickr-months .flatpickr-prev-month,
.flatpickr-months .flatpickr-next-month {
    color: var(--gris);
    fill: var(--gris);
    padding: 10px;
}
.flatpickr-months .flatpickr-prev-month:hover,
.flatpickr-months .flatpickr-next-month:hover {
    color: var(--bleu);
    fill: var(--bleu);
}
.flatpickr-months .flatpickr-prev-month:hover svg,
.flatpickr-months .flatpickr-next-month:hover svg { fill: var(--bleu); }
span.flatpickr-weekday {
    color: var(--gris);
    font-weight: 600;
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: .02em;
}
.flatpickr-day {
    border-radius: 8px;
    color: var(--encre, #0f172a);
    font-weight: 500;
}
.flatpickr-day:hover,
.flatpickr-day:focus { background: var(--bleu-clair); border-color: var(--bleu-clair); }
.flatpickr-day.today {
    border-color: var(--bleu);
    color: var(--bleu);
    font-weight: 700;
}
.flatpickr-day.today:hover { background: var(--bleu-clair); color: var(--bleu); }
.flatpickr-day.selected,
.flatpickr-day.selected:hover,
.flatpickr-day.startRange,
.flatpickr-day.endRange {
    background: var(--bleu);
    border-color: var(--bleu);
    color: #ffffff;
}
.flatpickr-day.inRange,
.flatpickr-day.inRange:hover {
    background: var(--bleu-clair);
    border-color: var(--bleu-clair);
    color: var(--bleu);
    box-shadow: none;
}
.flatpickr-day.prevMonthDay,
.flatpickr-day.nextMonthDay { color: color-mix(in srgb, var(--gris) 70%, transparent); }
.flatpickr-day.flatpickr-disabled,
.flatpickr-day.flatpickr-disabled:hover {
    color: color-mix(in srgb, var(--gris) 50%, transparent);
    background: transparent;
}
.flatpickr-time { border-top: 1px solid var(--bordure); }
.flatpickr-time input {
    color: var(--encre, #0f172a);
    font-weight: 600;
}
.flatpickr-time input:hover,
.flatpickr-time input:focus,
.flatpickr-time .flatpickr-am-pm:hover,
.flatpickr-time .flatpickr-am-pm:focus {
    background: var(--bleu-clair);
}
.flatpickr-time .flatpickr-time-separator,
.flatpickr-time .flatpickr-am-pm { color: var(--gris); }

.pwd-toggle {
    position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
    border: 0; background: transparent; padding: 6px 8px; cursor: pointer;
    color: var(--gris); display: inline-flex; align-items: center;
    border-radius: 6px;
}
.pwd-toggle:hover { color: var(--bleu); background: rgba(37, 99, 235, .08); }
.pwd-toggle:focus-visible { outline: 2px solid var(--bleu); outline-offset: 1px; }

/* ---------- Recadrage d'image avant envoi ---------- */
/* Modale claire (l'assombrissement des zones perdues est fait dans le canvas
   lui-même) — l'utilisateur reste dans l'ambiance de l'admin, le contraste
   se joue à l'intérieur du cadre. */
.crop-overlay {
    position: fixed; inset: 0; z-index: 300; background: rgba(15, 23, 42, .55);
    display: flex; align-items: center; justify-content: center; padding: 20px;
    backdrop-filter: blur(3px);
}
.crop-boite {
    background: #ffffff; color: var(--encre);
    border: 1px solid var(--bordure);
    border-radius: 16px; padding: 18px 20px 20px;
    box-shadow: 0 40px 80px -12px rgba(15, 23, 42, .35);
    max-width: calc(100vw - 40px);
}
.crop-boite h3 {
    margin: 0 0 8px; font-size: 15px; font-weight: 600;
    letter-spacing: .2px;
}
/* Consigne sous le titre : rappelle que le recadrage est obligatoire
   pour préserver la cohérence visuelle (pas de bouton « Annuler »
   dans la modale — l'admin doit valider). */
.crop-consigne {
    margin: 0 0 12px; font-size: 12.5px; line-height: 1.5;
    color: color-mix(in srgb, var(--encre, #1c2434) 65%, transparent);
}
.crop-boite canvas {
    display: block; cursor: grab; border-radius: 12px;
    background: #eef1f5; touch-action: none;
    box-shadow: 0 2px 8px rgba(15, 23, 42, .12);
}
.crop-boite canvas:active { cursor: grabbing; }
.crop-zoom {
    display: flex; align-items: center; gap: 14px;
    margin: 14px 2px; font-size: 13px; font-weight: 500; color: var(--gris);
}
.crop-zoom input { flex: 1; }
.crop-actions { display: flex; justify-content: flex-end; gap: 10px; }
.crop-note { color: var(--ok); font-size: 13px; font-weight: 600; margin: 6px 0 0; }

/* ---------- Responsive ---------- */
@media (max-width: 900px) {
    .admin-shell { flex-direction: column; }
    .sidebar { width: 100%; height: auto; position: static; }
    .sidebar-nav { display: flex; flex-wrap: wrap; gap: 2px; }
    .nav-titre { width: 100%; padding-top: 8px; }
    .content { padding: 16px; }
    .topbar { padding: 12px 16px; }
    .form-side { position: static; }
    /* Sur mobile la sidebar passe en haut : la savebar prend toute la
       largeur, plaquée en bas, sans marges ni coins arrondis — plus lisible
       sur un petit écran où chaque pixel compte. */
    .admin-savebar { left: 0; right: 0; bottom: 0; border-radius: 0; border-left: none; border-right: none; border-bottom: none; }
}

/* Modales de confirmation Civika — voile sombre + carte centrée qui
   remplace `window.confirm` natif (voir assets/dialog.js). */
/* Utilisé comme <dialog> natif : `.showModal()` le pousse dans la
   « top layer » du navigateur, au-dessus des autres <dialog> ouverts
   (modales admin de contenu). On neutralise ses styles par défaut
   (bordure, padding, background) pour ne garder que notre voile. */
.civika-dialog-overlay {
    position: fixed; inset: 0; z-index: 10000;
    /* Nécessaire quand un `<dialog>` est ouvert : par défaut il applique
       max-width/max-height qui empêchent le voile de couvrir tout l'écran. */
    max-width: 100vw; max-height: 100vh;
    width: 100%; height: 100%;
    border: 0; padding: 20px; margin: 0;
    display: flex; align-items: center; justify-content: center;
    /* Voile NOIR à 75 % — règle constante partout, admin comme site. */
    background: rgba(0, 0, 0, .75);
    opacity: 0;
    transition: opacity .16s ease;
}
/* Backdrop du <dialog> natif : on le rend transparent, on gère notre
   propre voile via `background` de l'élément. Sans cette règle, le
   backdrop du dialog s'ajouterait par-dessus notre voile et rendrait
   la superposition trop sombre. */
.civika-dialog-overlay::backdrop { background: transparent; }
.civika-dialog-overlay.est-visible { opacity: 1; }
.civika-dialog {
    max-width: 420px; width: 100%;
    background: #ffffff; color: var(--encre, #0f172a);
    border-radius: 12px;
    padding: 28px 32px 24px;
    box-shadow: 0 20px 50px -12px rgba(15, 23, 42, .35);
    transform: translateY(6px) scale(.97);
    transition: transform .18s ease;
    font-family: inherit;
}
.civika-dialog-overlay.est-visible .civika-dialog { transform: translateY(0) scale(1); }
.civika-dialog-titre { margin: 0 0 8px; font-size: 17px; font-weight: 700; }
.civika-dialog-message { margin: 0 0 20px; font-size: 15px; line-height: 1.5; }
.civika-dialog-actions { display: flex; gap: 10px; justify-content: flex-end; }
.civika-dialog-btn {
    padding: 9px 18px; border-radius: 8px; border: 1px solid var(--bordure, #dfe5ec);
    background: #ffffff; color: var(--encre, #0f172a);
    font-size: 14px; font-weight: 600; cursor: pointer;
    transition: background .12s ease, border-color .12s ease, color .12s ease;
}
.civika-dialog-btn-cancel:hover { background: #f1f5f9; }
.civika-dialog-btn-ok {
    background: var(--bleu, #2563eb); border-color: var(--bleu, #2563eb); color: #ffffff;
}
.civika-dialog-btn-ok:hover { background: #1e4bb4; border-color: #1e4bb4; }
.civika-dialog-btn-danger {
    background: var(--danger, #dc2626); border-color: var(--danger, #dc2626); color: #ffffff;
}
.civika-dialog-btn-danger:hover { background: #b91c1c; border-color: #b91c1c; }
.civika-dialog-btn:focus-visible {
    outline: 2px solid var(--bleu, #2563eb); outline-offset: 2px;
}

/* =====================================================
   Module Albums photo — liste (admin/albums.php)
   =====================================================
   Grille de cartes carrées (1:1) qui met la couverture au premier
   plan et le titre + statut discrètement en dessous. On raisonne en
   cartes plutôt qu'en table : un album EST visuellement une
   couverture, la table n'apporterait rien. */
.albums-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 16px;
}
.album-card {
    display: flex; flex-direction: column;
    background: #fff; border: 1px solid var(--bordure, #e6eaf1);
    border-radius: 12px; overflow: hidden;
    text-decoration: none; color: inherit;
    transition: transform .12s ease, box-shadow .12s ease, border-color .12s ease;
}
.album-card:hover {
    transform: translateY(-2px);
    box-shadow: 0 8px 24px -12px rgba(15, 23, 42, .18);
    border-color: color-mix(in srgb, var(--bleu, #2563eb) 30%, var(--bordure, #e6eaf1));
}
.album-card-couverture {
    position: relative; aspect-ratio: 4 / 3; background: #f1f5f9;
}
.album-card-couverture img {
    width: 100%; height: 100%; object-fit: cover; display: block;
}
.album-card-vide {
    position: absolute; inset: 0;
    display: flex; align-items: center; justify-content: center;
    color: color-mix(in srgb, var(--encre, #1c2434) 25%, transparent);
}
.album-card-count {
    position: absolute; bottom: 8px; right: 8px;
    display: inline-flex; align-items: center; gap: 4px;
    padding: 3px 8px; border-radius: 999px;
    background: rgba(15, 23, 42, .72); color: #fff;
    font-size: 12px; font-weight: 600;
}
.album-card-corps {
    padding: 12px 14px;
    display: flex; align-items: center; justify-content: space-between; gap: 8px;
}
.album-card-corps strong {
    font-size: 14.5px; font-weight: 600; line-height: 1.3;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.album-card-meta { flex: 0 0 auto; }

/* =====================================================
   Module Albums photo — éditeur (admin/album_edit.php)
   ===================================================== */
.albums-editeur { display: flex; flex-direction: column; gap: 16px; }

.albums-dropzone {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 4px;
    padding: 24px 20px; border: 2px dashed var(--bordure, #e6eaf1);
    border-radius: 12px; background: #f8fafc;
    text-align: center; cursor: pointer;
    color: color-mix(in srgb, var(--encre, #1c2434) 65%, transparent);
    transition: border-color .12s ease, background-color .12s ease, color .12s ease;
}
.albums-dropzone:hover,
.albums-dropzone.est-actif {
    border-color: var(--bleu, #2563eb);
    background: color-mix(in srgb, var(--bleu, #2563eb) 6%, #fff);
    color: var(--bleu, #2563eb);
}
.albums-dropzone > .ico { flex: 0 0 auto; }
.albums-dropzone span { font-weight: 550; font-size: 14px; }
.albums-dropzone small { font-size: 12.5px; }
/* Les règles globales `input[type=file]` (upload-input) restent
   visibles malgré l'attribut `hidden` — on force le masquage ici,
   la dropzone gère elle-même l'ouverture du picker via le <label>. */
.albums-dropzone input[type="file"] { display: none !important; }

.albums-photos {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: 12px;
    min-height: 40px;
}
.album-photo {
    display: flex; flex-direction: column; gap: 6px;
    background: #fff; border: 1px solid var(--bordure, #e6eaf1);
    border-radius: 10px; padding: 6px; position: relative;
    transition: border-color .12s ease, box-shadow .12s ease;
}
.album-photo.est-couverture {
    border-color: color-mix(in srgb, var(--jaune, #eab308) 65%, var(--bordure, #e6eaf1));
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--jaune, #eab308) 20%, transparent);
}
.album-photo.est-en-drag { opacity: .4; }
.album-photo.est-cible {
    outline: 2px dashed var(--bleu, #2563eb); outline-offset: -2px;
}
.album-photo-vignette {
    position: relative; aspect-ratio: 4 / 3; background: #f1f5f9;
    border-radius: 6px; overflow: hidden; cursor: grab;
}
.album-photo-vignette:active { cursor: grabbing; }
.album-photo-vignette img {
    width: 100%; height: 100%; object-fit: cover; display: block;
    pointer-events: none; /* évite que l'image capture le drag à la place de la vignette */
}
.album-photo-badge {
    position: absolute; top: 6px; left: 6px;
    display: inline-flex; align-items: center; gap: 4px;
    padding: 3px 7px; border-radius: 999px;
    background: var(--jaune, #eab308); color: #1c2434;
    font-size: 11px; font-weight: 700;
}
.album-photo-actions {
    position: absolute; top: 6px; right: 6px;
    display: flex; gap: 4px;
    opacity: 0; transition: opacity .12s ease;
}
.album-photo:hover .album-photo-actions,
.album-photo:focus-within .album-photo-actions { opacity: 1; }
.album-photo-btn {
    display: inline-flex; align-items: center; justify-content: center;
    width: 28px; height: 28px; padding: 0;
    background: rgba(15, 23, 42, .72); color: #fff;
    border: none; border-radius: 999px; cursor: pointer;
    transition: background-color .12s ease;
}
.album-photo-btn:hover { background: rgba(15, 23, 42, .92); }
.album-photo.est-couverture .album-photo-btn:not(.album-photo-btn-danger) {
    background: var(--jaune, #eab308); color: #1c2434;
}
.album-photo-btn-danger:hover { background: var(--danger, #dc2626); }
.album-photo-legende {
    width: 100%; padding: 6px 8px;
    border: 1px solid transparent; border-radius: 6px;
    font-size: 12.5px; font-weight: 500;
    background: transparent; color: inherit;
    transition: border-color .12s ease, background-color .12s ease;
}
.album-photo-legende:hover { background: #f8fafc; }
.album-photo-legende:focus {
    background: #fff; border-color: var(--bleu, #2563eb); outline: none;
}
.album-photo-legende::placeholder {
    color: color-mix(in srgb, var(--encre, #1c2434) 45%, transparent);
}

/* =====================================================
   Module Formulaires — éditeur admin (formulaire_edit.php)
   =====================================================
   Chaque champ vit dans une carte plate avec sa poignée de drag.
   Le rendu doit rester très lisible : label bien visible, texte
   d'aide en gris, actions à droite (obligatoire + suppression). */
.formulaire-editeur { display: flex; flex-direction: column; gap: 16px; }

.formulaire-types {
    display: flex; flex-wrap: wrap; gap: 6px; align-items: center;
    padding: 12px; border-radius: 10px;
    background: color-mix(in srgb, var(--encre, #1c2434) 3%, #fff);
    border: 1px solid var(--bordure, #e6eaf1);
    /* Reste accessible à tout moment pendant la construction du
       formulaire : sticky en tête de son wrapper, sous la topbar admin.
       Le z-index doit dépasser les cartes
       voisines mais rester en dessous de la savebar (z-index: 200). */
    position: sticky; top: var(--sticky-sous-topbar); z-index: 20;
}
.formulaire-types-label {
    font-weight: 600; font-size: 13px; margin-right: 4px;
    color: color-mix(in srgb, var(--encre, #1c2434) 70%, transparent);
}
.formulaire-types .btn.btn-sm {
    padding: 5px 10px; font-size: 12.5px; font-weight: 500;
}

.formulaire-champs {
    display: flex; flex-direction: column; gap: 10px;
    min-height: 20px;
}
.formulaire-champ {
    display: flex; align-items: stretch;
    background: #fff; border: 1px solid var(--bordure, #e6eaf1);
    border-radius: 10px; overflow: hidden;
    transition: border-color .12s ease, box-shadow .12s ease;
}
.formulaire-champ:hover { border-color: color-mix(in srgb, var(--bleu, #2563eb) 25%, var(--bordure, #e6eaf1)); }
.formulaire-champ.est-en-drag { opacity: .4; }
.formulaire-champ.est-cible {
    outline: 2px dashed var(--bleu, #2563eb); outline-offset: -2px;
}
.formulaire-champ-poignee {
    display: flex; align-items: center; justify-content: center;
    width: 32px; flex: 0 0 auto;
    background: color-mix(in srgb, var(--encre, #1c2434) 4%, #fff);
    color: color-mix(in srgb, var(--encre, #1c2434) 40%, transparent);
    cursor: grab; user-select: none;
}
.formulaire-champ-poignee:active { cursor: grabbing; }
.formulaire-champ-corps {
    flex: 1; padding: 12px 16px;
    display: flex; flex-direction: column; gap: 6px;
}
.formulaire-champ-corps label {
    font-size: 12.5px; margin: 4px 0 0;
    color: color-mix(in srgb, var(--encre, #1c2434) 70%, transparent);
}
.formulaire-champ-corps input[type="text"],
.formulaire-champ-corps textarea {
    font-size: 13.5px; padding: 6px 10px;
}
.formulaire-champ-tete {
    display: flex; align-items: center; gap: 12px;
    margin-bottom: 4px;
}
.formulaire-champ-type {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 3px 8px; border-radius: 999px;
    background: color-mix(in srgb, var(--bleu, #2563eb) 10%, #fff);
    color: var(--bleu, #2563eb);
    font-size: 11.5px; font-weight: 600;
}
.formulaire-champ-obligatoire {
    margin: 0 !important; margin-left: auto !important;
    display: inline-flex; align-items: center; gap: 5px;
    font-size: 12.5px !important; font-weight: 500;
    color: color-mix(in srgb, var(--encre, #1c2434) 65%, transparent) !important;
    cursor: pointer;
}
.formulaire-champ-obligatoire input { margin: 0; }
/* Champ système (prénom / nom / e-mail créés d'office avec le
   formulaire) : badge « système » à côté du type + bouton
   supprimer absent (rendu conditionnel côté PHP). */
.formulaire-champ.est-systeme { background: color-mix(in srgb, var(--encre, #1c2434) 2%, #fff); }
.formulaire-champ-systeme-badge {
    display: inline-flex; align-items: center; gap: 3px;
    margin-left: 6px; padding: 2px 6px; border-radius: 999px;
    background: color-mix(in srgb, var(--encre, #1c2434) 12%, #fff);
    color: color-mix(in srgb, var(--encre, #1c2434) 75%, transparent);
    font-size: 10.5px; font-weight: 600;
    text-transform: uppercase; letter-spacing: .04em;
}

/* Bouton icône « danger » (corbeille) : couleur neutre au repos —
   c'est le hover qui signale l'action destructrice, pas la couleur
   par défaut (sinon la corbeille attire l'œil en permanence dans
   toutes les listings). La règle globale `.btn-ico-danger:hover`
   (voir plus haut) fournit déjà fond rouge + texte rouge + bordure. */

/* Panneau d'export CSV avec range de dates : bouton `details` qui
   déploie un mini-formulaire en dessous. Fixed-position pour flotter
   par-dessus le contenu sans pousser la page.
   Le `<summary>` DOIT avoir `display: inline-flex` pour s'aligner
   sur les autres `.btn` voisins — sans ça il devient block par
   défaut et casse l'alignement du groupe d'actions. */
.export-panneau { position: relative; display: inline-block; }
.export-panneau > summary {
    display: inline-flex; align-items: center; gap: 6px;
    list-style: none; cursor: pointer;
}
.export-panneau > summary::-webkit-details-marker { display: none; }
.export-panneau > summary::marker { display: none; content: ''; }
.export-form {
    position: absolute; top: calc(100% + 6px); right: 0; z-index: 30;
    min-width: 260px;
    padding: 14px 16px;
    background: #fff; border: 1px solid var(--bordure, #e6eaf1);
    border-radius: 12px;
    box-shadow: 0 12px 32px -12px rgba(15, 23, 42, .3);
    display: flex; flex-direction: column;
}
.export-form label { font-size: 13px; font-weight: 500; margin: 0 0 4px; }
.export-form input[type="date"] {
    width: 100%; padding: 6px 10px;
    border: 1px solid var(--bordure, #e6eaf1); border-radius: 6px;
    font: inherit; font-size: 13.5px;
}

/* Bouton icône « boîte de réception » : variante par défaut neutre,
   `.est-plein` = fond foncé + picto blanc (signal fort qu'il y a
   des réponses non consultées). Traduit visuellement le stock de
   soumissions sans passer par une pastille séparée. */
.btn-ico.btn-ico-inbox.est-plein {
    background: var(--encre, #1c2434);
    color: #fff;
    border-color: var(--encre, #1c2434);
}
.btn-ico.btn-ico-inbox.est-plein:hover {
    background: color-mix(in srgb, var(--encre, #1c2434) 90%, var(--bleu, #2563eb));
    color: #fff;
    border-color: transparent;
}

/* Liaisons (sélecteurs multi-formulaires dans page/actu/event) */
.liste-liaisons { display: flex; flex-direction: column; gap: 4px; }
.liaison-ligne {
    display: flex; align-items: center; gap: 8px;
    padding: 6px 8px; border-radius: 6px;
    cursor: pointer; font-size: 13.5px;
    transition: background-color .12s ease;
}
.liaison-ligne:hover { background: color-mix(in srgb, var(--encre, #1c2434) 4%, transparent); }
.liaison-ligne input { margin: 0; flex: 0 0 auto; }

/* Pastille « nouveau » sur le compteur de soumissions */
.pastille-nouveau {
    display: inline-block; margin-left: 6px;
    padding: 2px 7px; border-radius: 999px;
    background: var(--bleu, #2563eb); color: #fff;
    font-size: 11px; font-weight: 600;
}
.ligne-non-lu td { font-weight: 550; }
.badge-lien {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 4px 10px;
    background: color-mix(in srgb, var(--bleu) 10%, transparent);
    color: var(--bleu);
    border: none;
    border-radius: 999px;
    font: inherit;
    font-weight: 600;
    font-size: 13px;
    text-decoration: none;
    cursor: pointer;
    transition: background .15s;
}
.badge-lien:hover {
    background: color-mix(in srgb, var(--bleu) 18%, transparent);
    text-decoration: none;
}
.badge-lien strong { font-weight: 700; }
.badge-lien .muted { color: color-mix(in srgb, var(--bleu) 60%, transparent); font-weight: 500; }

/* Fiche « soumission » : table clé/valeur bien lisible */
.table-fiche { width: 100%; border-collapse: collapse; }
.table-fiche th {
    text-align: left; font-weight: 600; padding: 10px 0;
    color: color-mix(in srgb, var(--encre, #1c2434) 65%, transparent);
    border-bottom: 1px solid var(--bordure, #e6eaf1);
}
.table-fiche td {
    padding: 10px 0; border-bottom: 1px solid var(--bordure, #e6eaf1);
    font-size: 14px;
}
.soum-fichier {
    display: inline-flex; flex-direction: column; align-items: flex-start; gap: 4px;
    text-decoration: none; color: var(--bleu, #2563eb);
}

/* Éditeur d'options de sondage — liste réordonnable, ajout/suppression. */
.sondage-options-editeur { margin-top: 8px; }
.sondage-options-editeur > ol {
    list-style: none;
    padding: 0;
    margin: 0 0 12px;
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.sondage-options-editeur > ol > li {
    display: flex;
    align-items: center;
    gap: 8px;
    background: #fff;
    border: 1px solid var(--gris-clair);
    border-radius: 8px;
    padding: 6px 10px;
}
.sondage-option-poignee {
    cursor: grab;
    color: var(--gris);
    display: inline-flex;
    align-items: center;
    padding: 4px 2px;
}
.sondage-option-poignee:active { cursor: grabbing; }
.sondage-option-libelle {
    flex: 1;
    border: none;
    padding: 6px 4px;
    font-size: 14.5px;
    background: transparent;
}
.sondage-option-libelle:focus { outline: none; }
.sondage-option-suppr { color: var(--gris) !important; }
.sondage-option-suppr:hover { color: var(--rouge) !important; }

/* Résultats affichés en admin (jauges) — même style que le front, mais on
   les référence ici aussi car la page d'édition admin peut les afficher. */
.sondage-resultats { display: flex; flex-direction: column; gap: 14px; }
.sondage-resultat { display: flex; flex-direction: column; gap: 4px; }
.sondage-resultat-tete {
    display: flex; justify-content: space-between; align-items: baseline; gap: 12px;
    font-size: 14.5px;
}
.sondage-resultat-libelle { font-weight: 500; color: var(--noir); }
.sondage-resultat-pct { font-weight: 600; color: var(--bleu); font-size: 13.5px; }
.sondage-resultat-jauge {
    background: var(--fond);
    border: 1px solid var(--bordure);
    border-radius: 999px;
    height: 12px;
    overflow: hidden;
}
.sondage-resultat-jauge-remplie {
    background: var(--bleu);
    height: 100%;
    border-radius: 999px;
    transition: width .3s ease;
}
.sondage-resultat-nb { font-size: 12px; }
.sondage-resultat-total { text-align: right; font-size: 13px; margin: 0; }

/* Modale WYSIWYG « Insérer un sondage » */
.wy-sondage-liste {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
    max-height: 400px;
    overflow-y: auto;
}
.wy-sondage-item {
    width: 100%;
    text-align: left;
    background: #fff;
    border: 1px solid var(--gris-clair);
    border-radius: 8px;
    padding: 10px 14px;
    cursor: pointer;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    transition: border-color .15s, background .15s;
}
.wy-sondage-item:hover { border-color: var(--bleu); background: var(--fond); }
.wy-sondage-question { font-size: 14px; color: var(--noir); flex: 1; }
.wy-sondage-meta {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    flex: 0 0 auto;
    font-size: 12.5px;
}


/* --------------------------------------------------------------------------
   Relecture des traductions (?p=traductions)
   --------------------------------------------------------------------------
   La liste reste une table sobre ; tout le travail se fait dans une modale
   chargee a la demande. Deux colonnes par champ, le francais en lecture a
   gauche et la traduction editable a droite, de largeur STRICTEMENT egale —
   c'est la comparaison qui est l'outil, une colonne plus etroite que l'autre
   fait croire a une traduction plus courte qu'elle n'est.
   -------------------------------------------------------------------------- */
.filtres-ligne { display: flex; align-items: flex-end; gap: 16px; flex-wrap: wrap; }
.filtres-ligne label { margin: 0; font-size: 13px; }
.filtres-ligne select { width: auto; min-width: 150px; margin-top: 4px; }

.trad-table td strong { font-weight: 600; }
.trad-signature { font-size: 12.5px; margin-top: 3px; }

/* --------- Modale de relecture --------- */
/* `.admin-modal.trad-modale` et non `.trad-modale` seul : la modale porte
   aussi `admin-modal-large`, dont la regle `.admin-modal.admin-modal-large`
   pese (0,2,0). Un selecteur a une seule classe perdrait quelle que soit sa
   position dans le fichier, et la largeur resterait bloquee a 930 px. */
.admin-modal.trad-modale { width: min(1600px, 96vw); max-width: min(1600px, 96vw); }
.trad-modale-tete {
    display: flex; align-items: flex-start; justify-content: space-between; gap: 16px;
    padding: 18px 22px; border-bottom: 1px solid var(--bordure);
}
.trad-modale-tete h2 { margin: 8px 0 2px; font-size: 18px; }
.trad-modale-tete p { margin: 0; font-size: 13px; }
.trad-modale-corps { padding: 20px 22px; max-height: 68vh; overflow-y: auto; }
.trad-modale-pied {
    display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
    padding: 16px 22px; border-top: 1px solid var(--bordure); background: var(--alt);
}
.trad-aide { font-size: 12.5px; flex: 1 1 240px; }

.trad-champ { margin-bottom: 26px; }
.trad-champ:last-child { margin-bottom: 0; }
.trad-champ h4 { margin: 0 0 8px; font-size: 13.5px; font-weight: 600; }

/* minmax(0, 1fr) et non 1fr : sans le minimum a zero, une URL longue ou un
   tableau dans le contenu francais elargit sa colonne au lieu de defiler
   dans sa propre boite, et les deux colonnes cessent d'etre comparables. */
.trad-colonnes { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 18px; }
.trad-drapeau {
    display: block; font-size: 11.5px; text-transform: uppercase;
    letter-spacing: .04em; color: var(--gris); margin-bottom: 5px;
}
.trad-lecture {
    background: var(--alt); border: 1px solid var(--bordure); border-radius: 8px;
    padding: 12px 14px; font-size: 14px; line-height: 1.6;
    max-height: 420px; overflow-y: auto;
}
.trad-lecture > :first-child { margin-top: 0; }
.trad-lecture > :last-child { margin-bottom: 0; }
.trad-lecture img { max-width: 100%; height: auto; }
/* Le champ simple imite la boite de lecture d'en face : meme cadre, meme
   police, meme interligne. On compare alors deux blocs de meme nature, au lieu
   d'un texte a gauche et d'un formulaire a droite.
   `resize: none` parce que la hauteur suit deja le contenu (data-auto-hauteur) :
   la poignee ne servirait qu'a casser l'alignement des deux colonnes. */
.trad-cible textarea {
    font-size: 14px; line-height: 1.6; resize: none;
    padding: 12px 14px; border-radius: 8px; overflow: hidden;
}
.trad-cible textarea.trad-champ-simple { min-height: 0; }
/* L'editeur riche remplit la hauteur de la colonne de lecture en face, pour
   que les deux versions se lisent au meme niveau sans decalage vertical. */
.trad-colonnes-riche .trad-cible .wysiwyg-editeur { min-height: 300px; }

@media (max-width: 900px) {
    .trad-colonnes { grid-template-columns: 1fr; }
    .trad-lecture { max-height: 220px; }
}

/* --------------------------------------------------------------------------
   Module Rendez-vous — configuration et agenda
   -------------------------------------------------------------------------- */
.rdv-bloc { margin: 22px 0; padding-top: 18px; border-top: 1px solid var(--bordure); }
.rdv-bloc h3 { font-size: 15px; margin: 0 0 12px; }
.rdv-question {
    border: 1px solid var(--bordure); border-radius: 10px;
    padding: 14px 16px; margin-bottom: 12px; background: var(--alt);
}
.rdv-question-tete { display: flex; gap: 10px; align-items: center; }
.rdv-question-tete input { flex: 1; }
.rdv-options { margin: 10px 0 10px 18px; }
.rdv-option { display: flex; gap: 10px; align-items: center; margin-bottom: 8px; }
.rdv-option input { flex: 1; }
.rdv-piece { display: flex; gap: 10px; align-items: center; margin-bottom: 8px; }
.rdv-piece input { flex: 1; }
.rdv-piece select { flex: 0 0 260px; }

.rdv-plage { display: flex; gap: 10px; align-items: center; margin-bottom: 10px; }
.rdv-plage select { flex: 0 0 140px; }
/* `min-width: 0` annule le minimum global des champs `time` (150 px) : ici la
   largeur est portee par la base flex, sinon la ligne deborde sur mobile. */
.rdv-plage input[type="time"] { flex: 0 0 132px; min-width: 0; }

/* Jours fériés proposés à la fermeture : deux à quatre colonnes selon la
   place, la liste couvre deux années et ferait sinon une colonne interminable.
   `auto-fill` et non `auto-fit` : en décembre il ne reste qu'une poignée de
   dates, qui doivent rester alignées à gauche plutôt que s'étirer. */
.rdv-feries { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 2px 24px; }
.rdv-feries .checkbox { margin: 6px 0; }
.rdv-feries .muted { font-weight: 400; }

.rdv-blocage { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.rdv-blocage input[type="text"] { flex: 1 1 200px; }
.rdv-blocage select { width: auto; }
.rdv-blocage input[type="datetime-local"] { width: auto; min-width: 210px; }

.rdv-agenda-barre {
    display: flex; justify-content: space-between; align-items: flex-end;
    gap: 16px; flex-wrap: wrap; margin-bottom: 16px;
}
.rdv-agenda-nav { display: flex; gap: 6px; align-items: center; }

/* Sept colonnes de largeur EGALE : `minmax(0, 1fr)` et non `1fr`, sinon un nom
   long deborde sa colonne et decale toute la semaine. */
.rdv-semaine { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 8px; }
.rdv-jour {
    border: 1px solid var(--bordure); border-radius: 10px; padding: 10px 8px; min-height: 130px;
}
.rdv-jour.est-aujourdhui { border-color: var(--bleu); background: color-mix(in srgb, var(--bleu) 4%, transparent); }
.rdv-jour-tete { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 8px; }
.rdv-jour-nom { font-size: 11.5px; text-transform: uppercase; letter-spacing: .04em; color: var(--gris); }
.rdv-jour-num { font-weight: 700; font-size: 16px; }
.rdv-jour-vide { color: var(--gris); text-align: center; margin: 18px 0 0; }

.rdv-carte {
    display: block; text-decoration: none; color: inherit;
    background: var(--blanc); border: 1px solid var(--bordure);
    border-left: 3px solid var(--bleu); border-radius: 7px;
    padding: 7px 9px; margin-bottom: 6px; font-size: 12.5px;
}
/* `text-decoration: none` repete au survol : la regle globale `a:hover` de
   l'admin souligne tous les liens, et la carte est un `<a>`. Sans cela ses trois
   lignes — heure, nom, demarche — se soulignaient d'un coup au passage de la
   souris. La bordure bleue suffit a signaler qu'elle est cliquable. */
.rdv-carte:hover { border-color: var(--bleu); text-decoration: none; }
.rdv-carte-heure { font-weight: 700; display: block; }
.rdv-carte-qui { display: block; }
.rdv-carte-type { display: block; color: var(--gris); font-size: 11.5px; }
.rdv-statut-annule { opacity: .5; text-decoration: line-through; }
.rdv-statut-bloque { border-left-color: var(--gris); background: var(--alt); font-style: italic; }
.rdv-statut-absent { border-left-color: #f97316; }

@media (max-width: 1100px) {
    .rdv-semaine { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Exigence d'un champ complementaire : trois boutons radio sur une ligne. */
.rdv-exigence {
    display: inline-flex; align-items: center; gap: 6px;
    margin: 0 14px 0 0; font-weight: 400; font-size: 13.5px; cursor: pointer;
}
.rdv-exigence input { width: auto; margin: 0; accent-color: var(--bleu); }

/* Écran RGPD — une table par source, mais une seule grille de lecture.
   `table-layout: fixed` est indispensable : sans lui, le navigateur ignore
   largement le <colgroup> et redimensionne chaque table sur son contenu, ce
   qui décale les colonnes d'une section à l'autre.
   Contrepartie du mode fixe : plus rien ne s'élargit tout seul, il faut donc
   dire explicitement comment casser une adresse électronique longue. */
.rgpd-table { table-layout: fixed; }
.rgpd-table td { overflow-wrap: anywhere; }

/* -------------------------------------------------------------------
   Écran Traductions — table regroupée par contenu (une ligne = un
   contenu, les langues en pastilles).
   ------------------------------------------------------------------- */
.trad-pastilles {
    display: flex; flex-wrap: wrap; gap: 6px;
    align-items: center;
}
/* Pastille de langue — bouton cliquable qui ouvre la modale de relecture
   sur la (contenu, langue) correspondante. Quatre états visuels :
     - vide (pas encore traduit) : gris désaturé, non cliquable
     - auto (traduit par le cron) : vert doux
     - locked (corrigée à la main) : jaune + icône cadenas
     - obsolete (source modifiée depuis correction) : orange + alerte
     - error (Mistral a échoué) : rouge
     - pending (dans la file) : bleu neutre, non cliquable pour édition
   Chaque état a un fond léger et un liseré plus vif — lecture immédiate
   sans avoir à lire le texte. */
.trad-pastille {
    display: inline-flex; align-items: center; gap: 4px;
    padding: 3px 9px;
    font-size: 11.5px; font-weight: 700; letter-spacing: .04em;
    border-radius: 999px;
    border: 1px solid transparent;
    background: transparent;
    cursor: pointer;
    line-height: 1.4;
    transition: transform .12s ease, box-shadow .12s ease;
}
.trad-pastille:hover:not(.trad-pastille-vide):not(.trad-pastille-pending) {
    transform: translateY(-1px);
    box-shadow: 0 2px 6px rgba(15, 23, 42, .12);
}
.trad-pastille svg { display: block; }

/* Vide (jamais traduit) : gris désaturé, non interactif. */
.trad-pastille-vide {
    background: #f1f5f9;
    color: #94a3b8;
    border-color: #e2e8f0;
    cursor: default;
    opacity: .7;
}

/* Auto (traduit par le cron, jamais relu) : vert doux. */
.trad-pastille-auto {
    background: #dcfce7;
    color: #166534;
    border-color: #86efac;
}

/* Verrouillée (corrigée) : jaune moutarde + cadenas. */
.trad-pastille-locked {
    background: #fef3c7;
    color: #92400e;
    border-color: #fcd34d;
}

/* Obsolète : source modifiée depuis la correction. Orange + alerte. */
.trad-pastille-obsolete {
    background: #ffedd5;
    color: #9a3412;
    border-color: #fb923c;
}

/* En attente : bleu neutre, non éditable — le cron doit encore produire. */
.trad-pastille-pending {
    background: #e0f2fe;
    color: #075985;
    border-color: #7dd3fc;
    cursor: wait;
}

/* Erreur Mistral : rouge, cliquable pour lire le message d'erreur. */
.trad-pastille-error {
    background: #fee2e2;
    color: #991b1b;
    border-color: #fca5a5;
}

/* La table regroupée n'a plus la colonne actions à droite — on gagne de
   l'espace pour la colonne pastilles. La ligne libellé (col 1) reste
   dominante. */
.trad-table-regroupee th:nth-child(3),
.trad-table-regroupee td:nth-child(3) {
    width: 42%;
}
