/* =====================================================
   CIVIKA — Site public · design system
   Variables injectées par commune :
   --c-primaire, --c-liens, --c-footer, --police,
   --police-titres, --rayon
   Variantes par classe body : cartes-ombre|bordure|plat
   Les fonds (page, sections, en-tête, pied de page) sont choisis par la
   commune ; les couleurs de texte en découlent par la luminance (Core\Couleur).
   ===================================================== */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
    margin: 0;
    font-family: var(--police);
    font-weight: 380;
    color: var(--encre, #1c2434);
    background: var(--fond, #ffffff);
    font-size: 16.5px;
    line-height: 1.7;
    -webkit-font-smoothing: antialiased;
}
/* Pied de page calé en bas même quand le contenu ne remplit pas l'écran.
   Traité en CSS et non en JavaScript : le calcul est fait avant le premier
   rendu, donc sans saut visible, et il se refait seul au redimensionnement,
   au chargement des images ou à l'ouverture d'un menu.

   `100dvh` plutôt que `100vh` : sur mobile, `vh` inclut la barre d'adresse
   rétractable, ce qui ajoutait une bande vide et faisait apparaître une barre
   de défilement sur des pages pourtant courtes. */
body { min-height: 100dvh; display: flex; flex-direction: column; }
main { flex: 1 0 auto; display: flex; flex-direction: column; }
/* Les enfants de `main` deviennent des éléments flex : on leur rend
   explicitement la pleine largeur. Sans cela, un enfant portant des marges
   automatiques se réduit à la largeur de son contenu au lieu de s'étirer —
   c'est ce qui rétrécissait les actualités peu fournies. `min-width: 0`
   autorise par ailleurs les grilles internes à se comprimer normalement. */
main > * { width: 100%; min-width: 0; }
/* Seule une SECTION absorbe la hauteur restante, et uniquement parce que son
   fond doit descendre jusqu'au pied de page. Les autres conteneurs (page
   libre, article) portent le fond de page : les étirer n'apporterait rien
   visuellement, `main` suffit déjà à repousser le pied de page en bas. */
main > section:last-child { flex: 1 0 auto; }
.site-footer { flex: 0 0 auto; }

/* Utilitaire d'accessibilité : masqué visuellement mais lu par les
   synthèses vocales. Motif standard (pas de display:none qui priverait
   les technologies d'assistance de l'élément). */
.sr-only {
    position: absolute !important;
    width: 1px !important; height: 1px !important;
    padding: 0 !important; margin: -1px !important;
    overflow: hidden !important;
    clip: rect(0, 0, 0, 0) !important;
    white-space: nowrap !important;
    border: 0 !important;
}

img { max-width: 100%; height: auto; }
a { color: var(--c-liens); }
h1, h2, h3 {
    font-family: var(--police-titres);
    line-height: 1.15;
    letter-spacing: -0.015em;
    color: var(--encre-titres, #0e1526);
    font-weight: 650;
    text-wrap: balance;
}
h1 { font-size: clamp(30px, 4.5vw, 46px); margin: 0 0 18px; }
.ico { vertical-align: -0.18em; stroke-width: 2; flex-shrink: 0; }
:focus-visible { outline: 2px solid var(--c-primaire); outline-offset: 2px; border-radius: 4px; }
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after { transition: none !important; animation: none !important; }
    html { scroll-behavior: auto; }
}

.conteneur {
    --conteneur-pad: 24px;
    max-width: 1380px; margin: 0 auto; padding: 0 var(--conteneur-pad);
}
.skip-link { position: absolute; left: -9999px; top: 0; background: #fff; padding: 8px 14px; z-index: 200; }
.skip-link:focus { left: 8px; }

/* =====================================================
   En-tête — sticky, translucide (variante clair) ou plein
   ===================================================== */
.site-header {
    position: sticky; top: 0; z-index: 50;
    transition: box-shadow .2s ease;
}
/* L'en-tête a sa propre couleur de fond, indépendante de la couleur
   principale et du pied de page. Son texte est déduit de sa luminance :
   une teinte claire comme sombre reste lisible. */
.site-header {
    background: color-mix(in srgb, var(--c-header, #fff) 86%, transparent);
    -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
    /* Filet dérivé de `--nav-texte` (couleur du texte du header) pour
       s'adapter automatiquement au thème :
         - thème clair (texte foncé) → filet foncé semi-transparent
         - thème sombre (texte clair) → filet clair semi-transparent
       Reste visible dans les deux cas, sans avoir à switcher via
       une classe body dédiée. */
    border-bottom: 1px solid color-mix(in srgb, var(--nav-texte, #1c2434) 12%, transparent);
    --nav-texte: var(--header-texte, #1c2434);
    --nav-survol: var(--header-survol, rgba(15, 23, 42, .06));
    --panneau-fond: var(--c-header, #ffffff);   /* opaque sur mobile */
}
/* Bandeau foncé sur corps clair : on garde une ombre portée douce
   EN PLUS du filet adaptatif (qui devient clair-transparent en
   contexte sombre). Filet actif/hover du menu forcé en blanc
   (sinon la couleur primaire souvent foncée devient invisible sur
   le fond du header). */
body.header-fond-fonce .site-header {
    box-shadow: 0 4px 14px -8px rgba(0, 0, 0, .28);
    --nav-indicator-color: rgba(255, 255, 255, .85);
}
/* En-tête sur 2 lignes : logo à gauche · à droite barre utilitaire puis menu */
.header-grid {
    display: flex; align-items: center; justify-content: space-between; gap: 24px;
    min-height: 92px; padding-top: 10px; padding-bottom: 10px; position: relative;
}
.site-marque { display: flex; align-items: center; gap: 13px; text-decoration: none; flex-shrink: 0; }
.site-logo { height: 56px; width: auto; }
.site-nom {
    font-weight: 700; font-size: 20px; letter-spacing: -0.02em;
    color: var(--nav-texte); font-family: var(--police-titres);
}
.header-right { display: flex; flex-direction: column; align-items: flex-end; gap: 4px; }

/* Le .conteneur du hero prend toute la largeur disponible (flex:1) — sinon
   il resterait plafonné à max-width et le contenu ne se centrerait qu'à
   l'intérieur de cette bande. */
.hero { display: flex; }
.hero > .conteneur { flex: 1; }

/* Alignement du contenu du bandeau d'accueil — piloté par body.hero-align-* */
body.hero-align-centre .hero .conteneur { text-align: center; }
body.hero-align-centre .hero h1,
body.hero-align-centre .hero-texte,
body.hero-align-centre .hero-recherche {
    margin-left: auto; margin-right: auto;
}
/* Les alignements « gauche » utilisent des propriétés LOGIQUES (start/end)
   pour être respectés en RTL : « gauche » devient naturellement « droite »
   quand la langue est arabe. `text-align: start` = left en LTR, right en RTL. */
body.hero-align-gauche .hero .conteneur { text-align: start; }
body.hero-align-gauche .hero-recherche { margin-inline-start: 0; margin-inline-end: auto; }

/* Taille du logo dans le header — piloté par body.logo-taille-*, et le
   header s'ajuste en hauteur pour donner un padding visuel cohérent
   quelle que soit la taille. */
/* Hauteur du logo pilotée par une variable pour que le mode « header réduit »
   (au scroll) puisse plafonner sans jamais dépasser la taille NORMALE — on
   veut réduire, pas agrandir. Sur un logo « petit » (36 px), la valeur
   plafond ne s'applique donc jamais. */
body.logo-taille-petit { --logo-h: 36px; }
body.logo-taille-moyen { --logo-h: 56px; }
body.logo-taille-grand { --logo-h: 80px; }
.site-logo { height: var(--logo-h, 56px); }
body.logo-taille-petit .header-grid { min-height: 72px; }
body.logo-taille-moyen .header-grid { min-height: 92px; }
body.logo-taille-grand .header-grid { min-height: 116px; }
body.logo-taille-petit .site-nom { font-size: 17px; }
body.logo-taille-grand .site-nom { font-size: 22px; }

/* Ligne 1 : météo · accessibilité · recherche · langues
   Barre minimaliste : plus de pastilles grises hors-charte. Chaque outil est
   un bouton icône neutre (36×36), avec tooltip pour l'accessibilité. La
   recherche est repliée derrière une loupe : l'input glisse au clic. */
.header-utils {
    display: flex; align-items: center; gap: 4px; font-size: 13px;
    /* Léger décalage vertical : plus d'air au-dessus des utilitaires
       (météo/a11y/recherche/langues), moins d'air entre eux et la nav
       en dessous — l'ensemble « respire mieux » sans agrandir la
       hauteur totale du header. */
    margin-top: 6px; margin-bottom: -6px;
}
.util-icone {
    display: inline-flex; align-items: center; justify-content: center;
    width: 36px; height: 36px; padding: 0;
    border: 0; border-radius: 999px;
    background: transparent; color: var(--nav-texte);
    font: inherit; cursor: pointer; text-decoration: none;
    position: relative;
    transition: background .15s ease, color .15s ease;
}
.util-icone:hover {
    background: color-mix(in srgb, var(--c-primaire, currentColor) 12%, transparent);
    color: var(--c-primaire, currentColor);
}
/* Header foncé sur corps clair : la couleur primaire de l'ambiance est
   souvent une teinte foncée (bleu Prusse, bordeaux, vert forêt…) — au
   hover elle deviendrait invisible sur le fond foncé du header. On
   force le hover à jouer sur `--nav-texte` (clair) pour rester lisible.
   Regroupe util-icone / util-lien / sélecteur de langue. */
body.header-fond-fonce .util-icone:hover,
body.header-fond-fonce .util-lien:hover,
body.header-fond-fonce .lang-dd > summary:hover,
body.header-fond-fonce .lang-dd[open] > summary {
    background: color-mix(in srgb, var(--nav-texte, #fff) 14%, transparent);
    color: var(--nav-texte, #fff);
}
/* Tooltip natif via data-tooltip */
.util-icone[data-tooltip]::after {
    content: attr(data-tooltip);
    position: absolute; top: calc(100% + 6px); left: 50%; transform: translateX(-50%);
    background: #0f172a; color: #fff; padding: 4px 8px; border-radius: 6px;
    font-size: 11.5px; font-weight: 500; white-space: nowrap; pointer-events: none;
    opacity: 0; transition: opacity .12s ease; z-index: 5;
}
.util-icone:hover::after, .util-icone:focus-visible::after { opacity: 1; }

/* Météo : lecture directe, pas de bouton — mais mêmes dimensions/rythme */
.util-meteo {
    display: inline-flex; align-items: center; gap: 6px; padding: 0 10px;
    height: 36px; color: var(--nav-texte); font-weight: 550; font-size: 13px;
    cursor: default;
}
.util-meteo .ico { opacity: .85; }

/* Bouton avec icône + libellé (accessibilité) — comme .util-icone mais garde
   du padding horizontal pour accueillir le texte. */
.util-lien {
    display: inline-flex; align-items: center; gap: 7px; padding: 0 12px;
    height: 36px; border: 0; border-radius: 999px;
    background: transparent; color: var(--nav-texte);
    font: inherit; font-size: 13px; font-weight: 600; cursor: pointer;
    text-decoration: none;
    transition: background .15s ease, color .15s ease;
}
.util-lien:hover {
    background: color-mix(in srgb, var(--c-primaire, currentColor) 12%, transparent);
    color: var(--c-primaire, currentColor);
    text-decoration: none;
}

/* En mode header superposé (tant que le header n'est pas encore décollé du
   bandeau d'accueil), on garde les boutons d'utilité neutres au survol :
   changer le fond ou la couleur casserait l'effet « header transparent »
   qu'on cherche justement à préserver. Une fois le header décollé
   (`.est-decolle`), le fond redevient plein et les hovers normaux reviennent. */
/* Pastilles utilitaires (accessibilité, loupe recherche, sélecteur de
   langue) en mode header SUPERPOSÉ (avant décollement) : on garde la
   couleur `--nav-texte` (blanche sur voile sombre, encre sur voile
   clair) et on remplace le fond primaire du hover par un voile discret
   qui suit la couleur du texte. Cohérent avec le hero derrière — le
   bleu primaire cassait la charte quand la commune avait choisi une
   ambiance colorée ou un hero image sombre. */
body.hero-superpose .site-header:not(.est-decolle) .util-icone:hover,
body.hero-superpose .site-header:not(.est-decolle) .util-lien:hover,
body.hero-superpose .site-header:not(.est-decolle) .lang-dd > summary:hover,
body.hero-superpose .site-header:not(.est-decolle) .lang-dd[open] > summary {
    background: color-mix(in srgb, currentColor 14%, transparent);
    color: var(--nav-texte);
}

/* Recherche à ouverture progressive : loupe seule au repos, input glisse
   au clic. Le bouton d'envoi (flèche) est INTÉGRÉ à l'input, position
   absolue à droite, invisible tant que l'input est replié. */
.header-search { display: inline-flex; align-items: center; position: relative; }
.header-search input {
    height: 36px; width: 0; padding: 0; opacity: 0;
    border: none; border-radius: 999px;
    background: color-mix(in srgb, var(--c-primaire, currentColor) 8%, transparent);
    color: var(--nav-texte); font: inherit; font-size: 14px; font-weight: 500;
    transition: width .22s cubic-bezier(0.4, 0, 0.2, 1), opacity .18s ease, padding .22s ease;
    pointer-events: none;
}
.header-search input::placeholder { color: var(--nav-texte); opacity: .55; }
.header-search.est-ouvert input {
    width: 240px; padding: 0 40px 0 14px; opacity: 1; pointer-events: auto;
}
.header-search.est-ouvert input:focus {
    outline: 2px solid var(--c-primaire, currentColor); outline-offset: -1px;
}
/* Header superposé (avant décollage) : le focus outline doit contraster
   avec le hero, pas garder la couleur d'accent d'ambiance (invisible sur
   fond sombre ou hors charte sur fond image). Blanc ou noir selon la
   luminance du hero, comme le texte du nav. Repasse à la couleur
   d'accent une fois le header décollé (fond opaque de la commune). */
body.hero-superpose-sombre .site-header:not(.est-decolle) .header-search.est-ouvert input:focus {
    outline-color: #ffffff;
}
body.hero-superpose-clair .site-header:not(.est-decolle) .header-search.est-ouvert input:focus {
    outline-color: #0f172a;
}
.header-search.est-ouvert [data-search-open] { display: none; }
/* Bouton d'envoi : caché par défaut, visible SEULEMENT quand l'input est
   déplié, positionné en absolu dans l'input (à droite). */
.header-search [data-search-submit] {
    display: none;
    position: absolute; right: 3px; top: 50%; transform: translateY(-50%);
    width: 30px; height: 30px;
}
.header-search.est-ouvert [data-search-submit] { display: inline-flex; }

/* Sélecteur de langue (menu déroulant sans JavaScript) */
.lang-dd { position: relative; }
.lang-dd > summary {
    display: inline-flex; align-items: center; gap: 6px; padding: 0 10px; height: 36px;
    list-style: none; cursor: pointer; border-radius: 999px;
    color: var(--nav-texte); font: inherit; font-size: 13px; font-weight: 600;
    text-decoration: none; transition: background .15s ease, color .15s ease;
}
.lang-dd > summary::-webkit-details-marker { display: none; }
.lang-dd > summary:hover {
    background: color-mix(in srgb, var(--c-primaire, currentColor) 12%, transparent);
    color: var(--c-primaire, currentColor);
}
.lang-dd[open] > summary {
    background: color-mix(in srgb, var(--c-primaire, currentColor) 14%, transparent);
    color: var(--c-primaire, currentColor);
}
.lang-menu {
    position: absolute; right: 0; top: calc(100% + 8px); z-index: 60; min-width: 170px;
    background: var(--carte-fond, #fff); border: 1px solid var(--carte-bordure, #e6eaf1);
    border-radius: var(--rayon, 14px); padding: 6px;
    box-shadow: 0 16px 40px -8px rgba(15, 23, 42, .22);
}
.lang-menu a {
    display: block; padding: 8px 14px; border-radius: calc(var(--rayon, 12px) * .6); text-decoration: none;
    color: var(--encre, #1c2434); font-size: 14px; font-weight: 500;
}
.lang-menu a:hover { background: color-mix(in srgb, var(--encre, #1c2434) 8%, transparent); }
/* L'état actif prime sur le survol (fond ET couleur) : sans le sélecteur
   :hover explicite, `.lang-menu a:hover` l'emporterait en spécificité. */
.lang-menu a.lang-active,
.lang-menu a.lang-active:hover {
    background: var(--c-primaire); color: #fff; font-weight: 650;
}

/* Ligne 2 : menu principal (2 niveaux maximum)
   `position: relative` : ancre le .nav-indicator (barre glissante). */
.site-nav {
    display: flex; align-items: center; gap: 2px; flex-wrap: wrap;
    justify-content: flex-end; position: relative;
}
.site-nav > a, .nav-parent {
    display: inline-flex; align-items: center; gap: 5px;
    text-decoration: none; color: var(--nav-texte); font: inherit; font-weight: 600; font-size: 16.5px;
    padding: 9px 12px; background: none; border: none; border-radius: 0;
    cursor: pointer; transition: color .18s ease;
}
/* Les enfants du sous-menu gardent leur taille compacte : la hiérarchie
   visuelle reste, on n'agrandit que le premier niveau. */
.nav-sousmenu a { font-size: 14.5px; font-weight: 500; }
/* Plus de capsule NI de changement de couleur au survol : la barre
   glissante en bas de nav (voir .nav-indicator) est le seul signal
   visuel. La couleur du lien reste identique quelle que soit l'action —
   on force --nav-texte pour éviter tout inversion parasite en mode
   superposé (là où color:inherit tirait sur le fond de la page). */
.site-nav > a:hover, .nav-parent:hover {
    background: none;
    color: var(--nav-texte);
}
.site-nav > a[aria-current="page"], .nav-parent[aria-current="page"] {
    color: var(--nav-texte);
}

/* Barre glissante : injectée par site.js. Position calée sur le bas de la
   barre de nav, sa position et sa largeur suivent le lien survolé (ou le
   lien de la page courante quand la souris quitte la zone). Transitions
   fluides sur les seules propriétés composées (transform + width) pour
   rester GPU-friendly. */
.nav-indicator {
    /* `--nav-indicator-bottom` est posé par site.js et vaut la distance
       entre le bas de `.site-nav` et le bas de `.site-header` — le
       filet reste toujours collé au bas du header quelle que soit la
       taille du logo. Fallback à -4px si le JS n'a pas encore tourné. */
    position: absolute; left: 0; bottom: var(--nav-indicator-bottom, -4px);
    height: 5px; border-radius: 0;
    background: var(--nav-indicator-color, var(--c-primaire, var(--c-liens)));
    width: var(--nav-w, 0);
    transform: translate3d(var(--nav-x, 0), 0, 0);
    /* Le déplacement latéral reste long (glisse continue), la largeur et
       l'opacité sont plus rapides — le filet apparaît / disparaît net.
       bottom: -4px : reste dans l'emprise du header, ne mange plus sur
       le contenu qui suit (hero, page). */
    transition:
        transform .32s cubic-bezier(0.65, 0, 0.35, 1),
        width .14s cubic-bezier(0.4, 0, 0.2, 1),
        opacity .12s ease;
    opacity: 0; pointer-events: none;
}
/* Bloque la transition la toute première fois : sinon le filet part de
   x=0/w=0 puis glisse vers la position du lien actif au chargement,
   effet parasite. Le JS retire la classe .init après un tick. */
.nav-indicator.init { transition: opacity .12s ease; }
/* Filet au hover, ET sur la page courante SI un lien de niveau 1 y
   correspond exactement (calculé côté JS, cf. site.js). Un sous-menu
   qui pointe vers un module n'active PAS son parent — on garde
   uniquement la sémantique juste. */
.site-nav:hover .nav-indicator,
.nav-indicator.est-actif { opacity: 1; }
/* Survol d'un lien à sous-menu : le filet s'efface (le sous-menu qui
   s'ouvre est déjà le signal visuel — le filet ferait doublon). */
.site-nav.survole-parent .nav-indicator { opacity: 0; }
/* Sur petit écran, le menu bascule en tiroir : la barre glissante n'a plus
   de sens dans ce contexte vertical. */
@media (max-width: 900px) { .nav-indicator { display: none; } }

/* Sous-menu : survol à la souris, focus au clavier */
.nav-groupe { position: relative; }
.nav-groupe .ico { opacity: .6; transition: transform .15s ease; }
.nav-sousmenu {
    position: absolute; left: 0; top: 100%; z-index: 60; min-width: 240px;
    display: none; flex-direction: column; padding: 8px;
    background: var(--carte-fond, #fff); border: 1px solid var(--carte-bordure, #e6eaf1);
    border-radius: var(--rayon, 14px);
    box-shadow: 0 16px 40px -8px rgba(15, 23, 42, .22);
}
.nav-groupe:hover .nav-sousmenu, .nav-groupe:focus-within .nav-sousmenu { display: flex; }
/* Éléments injectés par le JS pour le pattern slide mobile — masqués
   par défaut (desktop), rendus visibles dans la media query mobile. */
.nav-retour, .nav-sousmenu-titre { display: none; }
.nav-groupe:hover .ico, .nav-groupe:focus-within .ico { transform: rotate(180deg); }
.nav-sousmenu a {
    padding: 9px 14px; border-radius: calc(var(--rayon, 12px) * .6); text-decoration: none;
    color: var(--encre, #1c2434); font-size: 14.5px; font-weight: 500; white-space: nowrap;
}
.nav-sousmenu a:hover { background: color-mix(in srgb, var(--encre, #1c2434) 8%, transparent); color: var(--c-liens); }
.menu-toggle { display: none; }
.menu-burger { display: none; cursor: pointer; padding: 10px; border-radius: 10px; }
.menu-burger span {
    display: block; width: 22px; height: 2px; background: var(--nav-texte);
    margin: 5px 0; border-radius: 2px; transition: transform .2s ease, opacity .2s ease;
}

/* =====================================================
   Bandeau d'alertes — fixé en bas de fenêtre, au-dessus de tout
   ===================================================== */
/* Conteneur en fixed bottom, empile les alertes multiples verticalement.
   Z-index très élevé pour flotter au-dessus du header sticky, du hero
   plein écran et du footer sans se faire recouvrir. */
.alertes-bandeau {
    position: fixed; left: 0; right: 0; bottom: 0;
    display: flex; flex-direction: column;
    z-index: 1000;
    pointer-events: none;   /* le conteneur laisse passer les clics */
}
.alertes-bandeau .alerte { pointer-events: auto; }
.alerte {
    display: flex; gap: 12px; align-items: flex-start; padding: 13px 24px; font-size: 15px;
    box-shadow: 0 -6px 20px -8px rgba(15, 23, 42, .2);
}
.alerte-icone { display: flex; margin-top: 2px; }
.alerte-texte { flex: 1 1 auto; }
/* Bouton « fermer » : croix discrète alignée au titre, hérite la couleur
   du bandeau (blanc sur urgent, encre sur info/attention). */
.alerte-fermer {
    flex: 0 0 auto; margin-left: 8px; margin-top: -2px;
    background: transparent; border: 0; padding: 4px; cursor: pointer;
    color: inherit; opacity: .7; border-radius: 6px;
    display: inline-flex; align-items: center; justify-content: center;
    transition: opacity .15s ease, background .15s ease;
}
.alerte-fermer:hover { opacity: 1; background: color-mix(in srgb, currentColor 15%, transparent); }
.alerte-info      { background: #eef4fd; color: #173e6b; border-top: 1px solid #d8e6f8; }
.alerte-attention { background: #fef6e0; color: #8a4b0f; border-top: 1px solid #f8e8bd; }
.alerte-urgent    { background: #c22030; color: #fff; }
.alerte-urgent a  { color: #fff; }

/* =====================================================
   Héros — 3 variantes
   ===================================================== */
.hero { position: relative; color: #fff; overflow: hidden; }
/* Titre et introduction bornés à la même largeur en pixels — ils cassent
   à la même verticale, ce qui aligne visuellement le bord droit du bloc
   quel que soit le rapport de taille entre les deux. Valeur posée en
   `:root` par _layout.php à partir du réglage admin. */
.hero h1 {
    color: inherit; margin: 0 0 14px;
    font-size: clamp(34px, 5.2vw, 60px);
    line-height: 1.15;
    max-width: var(--hero-titre-largeur, 640px);
}
.hero-texte {
    font-size: clamp(17px, 2vw, 21px);
    max-width: var(--hero-titre-largeur, 640px);
    margin: 0; opacity: .93; line-height: 1.6;
    /* text-wrap: balance équilibre le nombre de mots par ligne — un texte
       d'intro sur 3 lignes ne finit plus par une orpheline d'un mot. */
    text-wrap: balance;
}
/* ---- Taille du titre principal du hero : petit / moyen / grand ----
   Le champ de recherche et le paragraphe d'intro suivent la même proportion
   pour garder un rythme visuel cohérent. Le line-height diminue quand le
   titre grandit — un très grand titre à line-height 1.6 aère au point de
   casser la composition. */
body.hero-titre-petit .hero h1 { font-size: clamp(28px, 4vw, 42px); line-height: 1.25; }
body.hero-titre-petit .hero-texte { font-size: clamp(15px, 1.6vw, 17px); }
body.hero-titre-petit .hero-recherche input { height: 46px; font-size: 15px; padding: 0 50px 0 46px; }
body.hero-titre-moyen .hero h1 { line-height: 1.15; }
body.hero-titre-grand .hero h1 { font-size: clamp(42px, 6.6vw, 76px); line-height: 1.05; }
body.hero-titre-grand .hero-texte { font-size: clamp(19px, 2.4vw, 25px); }
body.hero-titre-grand .hero-recherche input { height: 62px; font-size: 18px; padding: 0 62px 0 54px; }
/* Bandeaux en dégradé : la couleur du texte suit la luminance des teintes
   choisies (une commune peut retenir des tons clairs). La variante image garde
   du blanc, son voile sombre le garantit. */
.hero-plein, .hero-carte { color: var(--hero-texte, #fff); }

/* Bandeau standard OU plein écran — même règle de fond : image si chargée
   (background-image: url(...) posé en inline par home.php), sinon aplat aux
   couleurs de la commune via `--c-primaire`. Le voile assombrissant du bas
   n'est appliqué que lorsqu'il y a effectivement une image (règles plus bas). */
.hero-plein {
    position: relative;
    display: flex; flex-direction: column;
    background: linear-gradient(125deg, var(--primaire-fonce), var(--c-primaire) 118%);
    background-size: cover; background-position: center;
}
/* Voile assombrissant du bas : uniquement quand le hero porte réellement
   une photo — sans image le dégradé du bas parasitait l'aplat coloré et
   donnait un effet radial disgracieux (bandeau sombre en bas / clair en haut). */
.hero-plein[style*="background-image"]::before {
    content: ""; position: absolute; inset: 0; z-index: 0;
    background: linear-gradient(200deg, rgba(8, 15, 30, 0) 30%, rgba(8, 15, 30, .78) 100%);
}
/* Le `.conteneur` est un flex-item d'un `.hero-plein` en flex-column ; sans
   `width: 100%` explicite, l'item se dimensionne selon son contenu et
   provoque une indentation à gauche (visible sur le bandeau standard sans
   image, où le contenu texte est étroit). On force la largeur pleine pour
   laisser le `max-width: 1300px` + `margin: 0 auto` de `.conteneur` opérer
   normalement. */
.hero-plein .conteneur { position: relative; z-index: 1; width: 100%; }

/* Halos décoratifs quand le hero est un aplat coloré (pas d'image) — ils
   reprennent l'ambiance visuelle du bandeau couleur. Neutralisés dès qu'il
   y a une image (le voile assombrissant prend le relais). */
.hero-plein:not([style*="background-image"])::before,
.hero-plein:not([style*="background-image"])::after {
    content: ""; position: absolute; border-radius: 50%; filter: blur(70px); opacity: .4; pointer-events: none;
}
.hero-plein:not([style*="background-image"])::before { width: 480px; height: 480px; background: var(--primaire-clair); top: -220px; right: -120px; }
.hero-plein:not([style*="background-image"])::after  { width: 340px; height: 340px; background: var(--primaire-clair); bottom: -200px; left: -80px; opacity: .18; }

/* Plein écran : le bandeau prend TOUTE la hauteur de la viewport, contenu
   centré verticalement. `100dvh` sur les navigateurs récents, fallback
   `100vh`. On passe en flex-ROW (axe principal horizontal), ce qui rend
   `align-items: center` équivalent à un vrai centrage vertical du
   `.conteneur` — c'est le pattern flexbox le plus lisible pour cet usage.
   Les paddings servent de marges de sécurité quand la fenêtre est plus
   courte que le contenu. */
.hero.hero-plein-ecran {
    min-height: 100vh; min-height: 100dvh;
    display: flex;
    flex-direction: row;       /* override du column hérité de .hero-plein */
    align-items: center;       /* axe transverse (vertical en row) — centrage vertical */
    padding: clamp(80px, 12vh, 140px) 0;
}
/* Header NON superposé : le header sticky occupe déjà le haut du viewport,
   donc le hero rendu à 100dvh dépasse d'autant sous la fold — le chevron
   `bottom: 24px` se retrouve hors écran. On soustrait la hauteur du header
   (`--hero-header-offset`, calibrée sur la taille du logo) pour que le
   plein écran corresponde bien à la fenêtre visible restante. */
body:not(.hero-superpose) .hero.hero-plein-ecran {
    min-height: calc(100vh - var(--hero-header-offset));
    min-height: calc(100dvh - var(--hero-header-offset));
}

/* Indicateur « scroll » en bas du hero plein écran : chevron animé qui
   invite à descendre. Bouton (a11y : appuyer défile), disparait dès qu'on
   scrolle (retiré par le JS via .est-cache), et hors flow pour ne pas
   perturber la mise en page. Masqué si la hauteur est trop faible pour
   éviter les collisions sur mobile. */
.hero-scroll-cue {
    position: absolute; left: 50%; bottom: 24px;
    transform: translateX(-50%);
    width: 44px; height: 44px; padding: 0;
    display: inline-flex; align-items: center; justify-content: center;
    background: transparent; border: 0; cursor: pointer;
    color: currentColor; opacity: .7; z-index: 3;
    transition: opacity .3s ease, transform .3s ease;
    animation: heroScrollCueBounce 2s ease-in-out infinite;
}
.hero-scroll-cue span {
    display: block; width: 14px; height: 14px;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: rotate(45deg);
    margin-top: -6px;
}
.hero-scroll-cue:hover { opacity: 1; }
.hero-scroll-cue.est-cache {
    opacity: 0; pointer-events: none; transform: translateX(-50%) translateY(12px);
}
@keyframes heroScrollCueBounce {
    0%, 100% { transform: translateX(-50%) translateY(0); }
    50%      { transform: translateX(-50%) translateY(8px); }
}
/* Masqué sur écran très bas pour éviter la superposition avec le titre */
@media (max-height: 560px) { .hero-scroll-cue { display: none; } }

/* Option VOILE — dégradé teinté par l'ambiance posé au-dessus du hero.
   Le voile utilise `--c-primaire` (couleur d'accent) mélangée à du noir
   (voile sombre) ou du blanc (voile clair), à intensité forte pour être
   visible mais garder la photo lisible en arrière-plan. */
.hero.hero-voile-clair {
    position: relative;
}
/* Voile monochrome — élément dédié <div class="hero-voile"> inséré par
   home.php entre le fond et le contenu. Simple, pas de pseudo-élément
   qui entre en conflit avec les halos décoratifs des variantes bandeau
   ou plein-écran. Blanc pur pour clair, noir pur pour sombre. */
.hero-voile {
    position: absolute; inset: 0; pointer-events: none; z-index: 1;
    opacity: var(--hero-voile-opacite, .6);
}
.hero.hero-voile-clair .hero-voile { background: #ffffff; }
.hero.hero-voile-sombre .hero-voile { background: #000000; }
.hero.hero-voile-clair .conteneur,
.hero.hero-voile-sombre .conteneur { position: relative; z-index: 2; }
/* Quand un voile est demandé, on désactive tous les enrichissements
   visuels du hero pour n'avoir que le voile pur (uniforme) :
     - halos décoratifs ::before / ::after des `.hero-plein` sans image
     - gradient d'assombrissement ::before des `.hero-plein` avec image
     - linear-gradient de fond de `.hero-plein` / `.hero-carte` (le
       dégradé aux couleurs de la commune transparait au travers du voile) */
.hero.hero-voile-clair::before,
.hero.hero-voile-sombre::before,
.hero.hero-voile-clair::after,
.hero.hero-voile-sombre::after { display: none; }
/* Fond APLAT (couleur primaire pure) au lieu du linear-gradient — la
   teinte de la commune est conservée mais uniforme, et le voile posé
   par-dessus reste un simple aplat sans variation qui simulerait un
   dégradé radial. Uniquement pour les hero SANS image (avec image, on
   veut voir la photo au travers du voile). */
.hero.hero-plein:not([style*="background-image"]).hero-voile-clair,
.hero.hero-plein:not([style*="background-image"]).hero-voile-sombre,
.hero.hero-carte.hero-voile-clair,
.hero.hero-carte.hero-voile-sombre {
    background: var(--c-primaire);
}
/* Voile appliqué à un hero-plein avec image : on masque le voile
   assombrissant du bas et les halos décoratifs, seul le voile monochrome
   reste. */
.hero.hero-plein.hero-voile-clair::before,
.hero.hero-plein.hero-voile-sombre::before,
.hero.hero-plein.hero-voile-clair::after,
.hero.hero-plein.hero-voile-sombre::after { display: none; }
.hero.hero-voile-clair { color: #0f172a; }
.hero.hero-voile-sombre { color: #ffffff; }
.hero.hero-voile-clair .hero-texte { opacity: .85; }
.hero.hero-voile-sombre .hero-texte { opacity: .92; }

/* Recherches — on masque la croix de reset native de type="search"
   (Chromium ::-webkit-search-cancel-button, Edge ::-ms-clear) : elle
   est colorée par le navigateur sans tenir compte du fond (invisible
   sur un hero sombre, contrastée hors charte sur un hero clair). Le
   bouton d'envoi et l'échap clavier suffisent — pas besoin d'un clear. */
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; appearance: none; }
input[type="search"]::-ms-clear { display: none; width: 0; height: 0; }

/* Champ de recherche dans le hero — transparent bordé, prend le contexte :
   voile clair → bordure sombre / texte sombre ; voile sombre → bordure
   claire / texte clair. Flèche sur fond transparent (couleur héritée). */
.hero-recherche {
    display: flex; align-items: center; gap: 0;
    margin-top: clamp(24px, 3vw, 32px);
    max-width: 460px; position: relative;
}
/* Loupe fixe à gauche du champ. Position absolue par-dessus l'input, le
   padding-left de l'input laisse la place. */
.hero-recherche-loupe {
    position: absolute; left: 18px; top: 50%; transform: translateY(-50%);
    display: inline-flex; align-items: center; justify-content: center;
    color: inherit; opacity: .7; pointer-events: none;
}
.hero-recherche input {
    flex: 1; height: 54px; padding: 0 56px 0 52px;
    font-size: 16px; font-weight: 500; font-family: inherit;
    color: inherit;
    background: transparent;
    border: 1.5px solid currentColor;
    /* S'aligne sur le rayon des CTA de la commune : pill si rayon 999px,
       plus rectangulaire si la commune a choisi des boutons carrés. */
    border-radius: var(--rayon-cta, 999px);
    outline: none; opacity: .9;
    transition: opacity .18s ease, background .18s ease, box-shadow .18s ease;
}
/* Ajustement fin selon le contexte : voile clair = fond légèrement blanchi ;
   voile sombre = fond légèrement noirci — subtil, pas franc. */
.hero.hero-voile-clair .hero-recherche input {
    background: rgba(255, 255, 255, .35);
    border-color: rgba(15, 23, 42, .35);
    color: #0f172a;
}
.hero.hero-voile-sombre .hero-recherche input {
    background: rgba(15, 23, 42, .18);
    border-color: rgba(255, 255, 255, .55);
    color: #ffffff;
}
.hero-recherche input::placeholder { color: currentColor; opacity: .6; }
.hero-recherche input:focus {
    opacity: 1;
    box-shadow: 0 0 0 3px color-mix(in srgb, currentColor 20%, transparent);
}
.hero-recherche button {
    position: absolute; right: 5px; top: 50%; transform: translateY(-50%);
    width: 44px; height: 44px; padding: 0;
    display: inline-flex; align-items: center; justify-content: center;
    background: transparent; color: inherit;
    border: 0; border-radius: var(--rayon-cta, 999px); cursor: pointer;
    /* Estompé au repos : signale visuellement qu'il n'y a rien à envoyer.
       Bascule à 100 % dès qu'il y a du contenu (classe `.a-contenu` posée
       par JS sur le form, voir site.js). */
    opacity: .25;
    transition: opacity .18s ease, transform .12s ease;
}
.hero-recherche.a-contenu button { opacity: 1; }
.hero-recherche button:hover { transform: translateY(-50%) translateX(2px); }
.hero-recherche.a-contenu button:hover { opacity: 1; }

/* Raccourcis dans le HERO — chips compactes sous la recherche, prennent
   le contexte de couleur du hero (idem `.hero-recherche`). Alternative à
   la section indépendante `.raccourcis` : option activée dans l'admin.
   Grille auto-fit à colonnes égales : les libellés courts (Carte) et longs
   (Rendez-vous État-civil) reçoivent la MÊME largeur, ce qui uniformise le
   rendu quelle que soit la sélection de modules (2 à 5 raccourcis). Sans
   ça, une largeur qui s'ajuste au texte laisserait la 2ᵉ ligne orpheline
   et déséquilibrée dès qu'un module s'ajoute ou disparaît. */
.hero-raccourcis {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 10px;
    margin-top: clamp(16px, 2vw, 24px);
    max-width: 720px;
}
body.hero-align-centre .hero-raccourcis { margin-left: auto; margin-right: auto; }
body.hero-align-gauche .hero-raccourcis { margin-inline-start: 0; margin-inline-end: auto; }
.hero-raccourci {
    /* Contenu ancré à gauche — le centrage horizontal dans une cellule
       large laissait l'icône flotter à gauche pendant que le texte se
       centrait, avec un vide bizarre entre les deux dès qu'un libellé
       enroulait sur 2 lignes. En gauche, l'icône ouvre la lecture et le
       texte suit naturellement à côté puis sous lui-même s'il enroule.
       line-height compact (1.15) pour un libellé sur 2 lignes qui reste
       lisible sans étirer la hauteur du bouton. */
    display: flex; align-items: center; gap: 10px;
    padding: 14px 20px 14px 18px; border-radius: var(--rayon-cta, 999px);
    background: transparent; color: inherit; font-size: 15px; font-weight: 600;
    line-height: 1.15;
    border: 1.5px solid currentColor;
    text-decoration: none; opacity: .9;
    transition: opacity .18s ease, background .18s ease, transform .12s ease;
}
.hero-raccourci-icone { flex: 0 0 auto; }
.hero-raccourci:hover {
    opacity: 1; text-decoration: none; transform: translateY(-2px);
    background: color-mix(in srgb, currentColor 12%, transparent);
}
.hero.hero-voile-clair .hero-raccourci {
    background: rgba(255, 255, 255, .35);
    border-color: rgba(15, 23, 42, .35); color: #0f172a;
}
.hero.hero-voile-clair .hero-raccourci:hover { background: rgba(255, 255, 255, .55); }
.hero.hero-voile-sombre .hero-raccourci {
    background: rgba(15, 23, 42, .18);
    border-color: rgba(255, 255, 255, .55); color: #ffffff;
}
.hero.hero-voile-sombre .hero-raccourci:hover { background: rgba(15, 23, 42, .32); }
.hero-raccourci-icone { display: inline-flex; opacity: .85; }

/* Bascule des 2 logos selon le contexte du header :
   - Par défaut : logo clair (sur fond header clair)
   - Fond header foncé (body.header-fond-fonce) : logo sombre s'il existe
   - Header superposé sombre : logo sombre s'il existe
   - Après décollage du header superposé : retour à la logique du fond header
   Le :has() garantit que si le logo sombre n'est pas fourni, le clair reste
   affiché à sa place — dégradation propre. */
.site-logo-sombre { display: none; }
/* Fond header foncé (indépendant du superposé) : bascule sur logo sombre */
body.header-fond-fonce .site-marque:has(.site-logo-sombre) .site-logo-clair { display: none; }
body.header-fond-fonce .site-marque:has(.site-logo-sombre) .site-logo-sombre { display: block; }
/* Header superposé sur voile sombre : idem, MAIS uniquement tant que le
   menu mobile n'est pas ouvert. Quand le menu s'ouvre, le header prend
   un fond solide `--c-header` (blanc par défaut) et le panneau derrière
   lui aussi : un logo blanc devient invisible. On revient donc au logo
   clair, comme quand le header se décolle au scroll. */
body.hero-superpose-sombre .site-header:not(.est-decolle) .site-marque:has(.site-logo-sombre) .site-logo-clair { display: none; }
body.hero-superpose-sombre .site-header:not(.est-decolle) .site-marque:has(.site-logo-sombre) .site-logo-sombre { display: block; }
body.hero-superpose-sombre:has(.menu-toggle:checked) .site-marque:has(.site-logo-sombre) .site-logo-sombre { display: none; }
body.hero-superpose-sombre:has(.menu-toggle:checked) .site-marque:has(.site-logo-sombre) .site-logo-clair { display: block; }
/* Une fois décollé, on retombe sur la règle "fond header foncé" (déjà appliquée). */

/* ---------- Header superposé au hero (option) ----------
   Le header n'a plus de fond, il flotte au-dessus du bandeau image. Ses
   liens s'adaptent au voile (blancs sur sombre, encre sur clair). Au
   scroll (> 50px), le JS ajoute `.est-decolle` sur le header qui reprend
   son fond solide — transition douce. */
body.hero-superpose .site-header {
    /* `fixed` (pas `absolute`) et jamais changé en `.est-decolle` : le
       basculement position:absolute → position:sticky provoquait un saut
       visuel du hero au scroll (le header entrait dans le flux). Ici on
       reste fixed en permanence, seule la couleur/le blur change. Le
       bandeau d'alerte est désormais fixé EN BAS de fenêtre — plus
       besoin de compenser un décalage haut. */
    position: fixed; top: 0; left: 0; right: 0;
    background: transparent; border-bottom-color: transparent;
    backdrop-filter: none; -webkit-backdrop-filter: none;
    box-shadow: none;
    transition: background .25s ease, border-color .25s ease, backdrop-filter .25s ease;
}
body.hero-superpose.hero-superpose-sombre .site-header {
    --nav-texte: #ffffff;
    /* Filet du menu hover : blanc quand le header flotte sur un voile sombre,
       pour rester visible. Retour à la couleur d'accent une fois décollé. */
    --nav-indicator-color: rgba(255, 255, 255, .85);
}
body.hero-superpose.hero-superpose-clair .site-header {
    --nav-texte: #0f172a;
    --nav-indicator-color: rgba(15, 23, 42, .75);
}
/* Marge basse supplémentaire au header superposé pour éviter que le filet
   hover ou les sous-menus ouverts ne mordent sur le contenu qui suit. */
body.hero-superpose .site-header .header-grid { padding-bottom: 14px; }
body.hero-superpose .site-header.est-decolle {
    /* Position reste `fixed` — voir commentaire ci-dessus. Seul le rendu
       visuel change (fond + blur + couleurs texte). */
    background: color-mix(in srgb, var(--c-header, #fff) 86%, transparent);
    border-bottom-color: var(--header-filet, rgba(15, 23, 42, .07));
    backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
    --nav-texte: var(--header-texte, #1c2434);
    /* Le header décollé reprend la couleur d'accent d'ambiance pour son
       filet hover — cohérent avec le reste du site. */
    --nav-indicator-color: var(--c-primaire);
}
/* Le hero doit commencer HAUT de page (pas sous le header) quand superposé */
/* --- Marge verticale du hero : petite / moyenne / grande ---
   Appliquée uniformément aux trois variantes (bandeau, carte, image
   plein) pour que le rythme visuel ne change pas quand on ajoute ou
   retire une image d'accueil.

   La marge de BASE est visible (mesurée entre le bas du header et le
   haut du titre). En mode superposé, le header flotte au-dessus du
   hero — pour garder la MÊME marge VISIBLE au-dessus du titre, on
   ajoute la hauteur du header via --hero-header-offset (calé sur
   logo-taille). Cohérence garantie que le header soit collé ou non. */
:root { --hero-marge-base: 110px; --hero-header-offset: 92px; }
body.logo-taille-petit { --hero-header-offset: 72px; }
body.logo-taille-moyen { --hero-header-offset: 92px; }
body.logo-taille-grand { --hero-header-offset: 116px; }
/* Marges verticales du hero : dépendent de la hauteur de la fenêtre (vh)
   avec un plancher et un plafond en px. Sur un grand écran, le bandeau
   respire davantage ; sur un petit écran (mobile paysage, écran ras),
   le plancher évite un bandeau écrasé. */
body.hero-marge-petite      { --hero-marge-base: clamp(30px,  8vh, 110px); }
body.hero-marge-moyenne     { --hero-marge-base: clamp(30px, 14vh, 180px); }
body.hero-marge-grande      { --hero-marge-base: clamp(30px, 22vh, 260px); }
body.hero-marge-tres_grande { --hero-marge-base: clamp(30px, 30vh, 340px); }

.hero-carte, .hero-plein:not(.hero-plein-ecran) {
    padding-top: var(--hero-marge-base);
    padding-bottom: var(--hero-marge-base);
}
/* Superposé : on ajoute la hauteur du header à la marge de base — la
   distance visible entre le bas du header et le haut du titre reste la
   même qu'en mode non superposé. On EXCLUT explicitement le plein écran
   pour ne pas casser son centrage vertical (padding-top asymétrique
   pousserait le contenu vers le bas). */
body.hero-superpose .hero-carte,
body.hero-superpose .hero-plein:not(.hero-plein-ecran) {
    padding-top: calc(var(--hero-marge-base) + var(--hero-header-offset));
}

/* Variante image en carte */
.hero-carte { padding: clamp(56px, 7vw, 96px) 0; background: linear-gradient(125deg, var(--primaire-fonce), var(--c-primaire) 135%); }
.hero-carte .conteneur { display: grid; grid-template-columns: 1.1fr .9fr; gap: clamp(28px, 5vw, 64px); align-items: center; position: relative; z-index: 1; }
.hero-carte-image {
    width: 100%; aspect-ratio: 4 / 3; object-fit: cover; display: block;
    border-radius: calc(var(--rayon) * 1.4);
    box-shadow: 0 24px 60px -12px rgba(0, 0, 0, .45);
    transform: rotate(1.2deg);
}
@media (max-width: 760px) {
    .hero-carte .conteneur { grid-template-columns: 1fr; }
    .hero-carte-image { transform: none; }
}

/* =====================================================
   Vidéo dans le héros
   ===================================================== */
.hero-video {
    position: absolute; inset: 0; width: 100%; height: 100%;
    object-fit: cover; z-index: 0;
}
.hero-plein .conteneur { z-index: 2; }
.hero-plein::before { z-index: 1; }
.hero-carte-video {
    width: 100%; aspect-ratio: 4 / 3; object-fit: cover; display: block;
    border-radius: calc(var(--rayon) * 1.4);
    box-shadow: 0 24px 60px -12px rgba(0, 0, 0, .45);
}

/* =====================================================
   Raccourcis (tuiles modernes sous le héros)
   ===================================================== */
/* « En un clic » participe à l'alternance : elle porte `.section` et prend donc
   les mêmes marges verticales que toute autre section. L'espacement resserré
   qu'elle avait auparavant se justifiait quand elle n'avait pas de fond propre ;
   dans un bandeau coloré il donnait un bloc à l'étroit.
   La variante placée DANS le hero n'est pas concernée : elle utilise un
   balisage distinct (`.hero-raccourcis`, voir plus haut) avec ses marges à elle. */
.raccourcis { margin: 0; padding: 1px 0; }
/* Cinq par ligne au maximum, puis retour à la ligne.
   `(100% - 4 gouttières) / 5` fixe la largeur MINIMALE d'une colonne à un
   cinquième de la rangée : six raccourcis ne peuvent donc plus se tasser sur
   une seule ligne, le sixième passe dessous. Sans ce plancher, `minmax(150px,
   1fr)` en laissait tenir huit, chacun trop étroit pour son libellé.
   `auto-fit` et non `auto-fill` : à cinq raccourcis ou moins, les colonnes
   vides s'effondrent et la rangée occupe toute la largeur — le rendu d'avant.
   `max(150px, …)` garde la main sur petit écran, où un cinquième de rangée
   serait illisible. */
.raccourcis-grille {
    --rc-gap: 16px;
    display: grid;
    grid-template-columns:
        repeat(auto-fit, minmax(max(150px, (100% - 4 * var(--rc-gap)) / 5), 1fr));
    gap: var(--rc-gap);
}
.raccourci {
    display: flex; flex-direction: column; align-items: center; gap: 10px; text-align: center;
    padding: 28px 16px 24px; border-radius: var(--rayon); text-decoration: none;
    background: var(--carte-fond, #fff); color: inherit; font-weight: 650; font-size: 14.5px;
    line-height: 1.3; /* libellés courts : interligne resserré */
    border: 1.5px solid var(--carte-bordure, #e6eaf1);
    transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}
.raccourci:hover { transform: translateY(-4px); border-color: var(--c-primaire); box-shadow: 0 12px 30px -8px rgba(15, 23, 42, .16); }
.raccourci-icone {
    display: flex; align-items: center; justify-content: center; width: 58px; height: 58px;
    border-radius: 18px;
    /* Fond primaire semi-transparent : joue avec le fond de la carte
       (blanc sur clair, sombre sur foncé) au lieu du blanc dur, sinon
       la pastille reste très claire sur les ambiances sombres. */
    background: color-mix(in srgb, var(--c-primaire) 15%, transparent);
    color: var(--c-primaire);
}
/* Trait légèrement affiné : à 30 px, l'épaisseur de 2 px héritée de Lucide
   alourdit le picto — elle est calibrée pour les tailles d'interface (16-20 px).
   Posé en CSS et non dans le fichier SVG, qui est mutualisé par tout le site. */
.raccourci-icone svg { stroke-width: 1.75; }
/* Une règle annulait ici le padding-top de la section suivant « En un clic »
   sur l'accueil. Elle a été retirée : ce padding d'1px empêche la marge du
   conteneur de s'échapper hors de la section, et l'annuler faisait fusionner
   cette marge avec la section voisine. Sans conséquence tant que « En un clic »
   n'avait pas de fond ; depuis qu'elle entre dans l'alternance, la marge
   traversait une frontière de couleur. Ne pas la réintroduire. */

/* =====================================================
   Header compact au défilement
   ===================================================== */
.site-logo, .header-grid, .header-utils { transition: height .2s ease, min-height .2s ease, opacity .2s ease; }
.site-header.reduit .header-utils {
    height: 0; opacity: 0; overflow: hidden; pointer-events: none; margin: 0; padding: 0;
}
.site-header.reduit .header-grid { min-height: 62px; }
/* `min()` plafonne : jamais plus grand que la taille normale du logo.
   Petit (36px) → reste à 36 ; Moyen (56px) → passe à 48 ; Grand (80px) → 48.
   Bumpé de 38 → 48 pour garder une présence de marque au scroll. */
.site-header.reduit .site-logo { height: min(48px, var(--logo-h, 56px)); }
.site-header.reduit .site-nom { font-size: 18px; }


/* =====================================================
   Accessibilité — panneau de confort de lecture
   Classes appliquées sur <html>, cohérentes sur tout le site
   ===================================================== */
/* La modale d'accessibilité est INDÉPENDANTE de l'ambiance du site : elle
   force son propre fond blanc + texte sombre, quel que soit le thème
   choisi par la commune. Sans ça, sur une ambiance foncée, --encre passe
   à blanc et le texte devient invisible sur le fond blanc du <dialog>. */
.a11y-modal {
    /* Centrage par translate — bat les règles user-agent `dialog:modal`
       (spécificité plus haute qu'une simple classe) et reste immunisé
       à la hauteur du body : peu importe qu'un `line-height: 2` sur
       body étire tout, le viewport reste la référence via `position:
       fixed` + `top/left: 50%`.
       IMPORTANT : `inset: auto` doit venir AVANT `top`/`left` sinon
       il expand en top/right/bottom/left:auto et écrase nos 50 %. */
    position: fixed !important;
    inset: auto !important;
    top: 50% !important; left: 50% !important;
    right: auto !important; bottom: auto !important;
    transform: translate(-50%, -50%) !important;
    margin: 0 !important;
    border: none; border-radius: 18px; padding: 0;
    max-width: 440px; width: calc(100% - 40px);
    max-height: calc(100vh - 40px);
    box-shadow: 0 30px 80px -10px rgba(0, 0, 0, .4);
    background: #ffffff; color: #1c2434;
    font-family: var(--police);
    line-height: 1.4;
    animation: a11yModalIn .22s cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes a11yModalIn {
    /* Compose avec le translate(-50%, -50%) de centrage — sinon la
       keyframe écrase la transform et la modale part dans le
       quadrant bas-droit du viewport. */
    from { opacity: 0; transform: translate(-50%, calc(-50% + 6px)) scale(.98); }
    to   { opacity: 1; transform: translate(-50%, -50%); }
}
.a11y-modal::backdrop { background: rgba(10, 18, 32, .55); backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); }
.a11y-entete {
    display: flex; align-items: center; justify-content: space-between;
    padding: 18px 22px 14px; border-bottom: 1px solid #eef2f7;
    color: #1c2434;
}
.a11y-entete h2 { margin: 0; font-size: 17px; font-weight: 700; display: flex; align-items: center; gap: 10px; color: #1c2434; letter-spacing: -.01em; }
.a11y-fermer {
    border: none; background: transparent; border-radius: 999px;
    width: 34px; height: 34px; padding: 0; cursor: pointer;
    display: inline-flex; align-items: center; justify-content: center;
    color: #64748b;
    transition: background .15s ease, color .15s ease;
}
.a11y-fermer:hover { background: #f1f5f9; color: #1c2434; }
.a11y-corps { padding: 18px 22px 20px; color: #1c2434; }
.a11y-groupe {
    border: none; padding: 0; margin: 0 0 18px; color: #1c2434;
}
.a11y-groupe legend {
    font-weight: 650; font-size: 12.5px; padding: 0 0 8px; color: #1c2434;
    text-transform: uppercase; letter-spacing: .04em;
}

/* Segment control (pills) — pour taille et contraste (3 options).
   Radios masquées, le label sert de bouton visuel ; l'option cochée
   se remplit à la couleur d'accent. */
.a11y-segments {
    display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px;
    padding: 4px; background: #f1f5f9; border-radius: 12px;
}
.a11y-seg { position: relative; }
.a11y-seg input {
    position: absolute; opacity: 0; inset: 0; margin: 0; cursor: pointer;
}
.a11y-seg span {
    display: block; text-align: center;
    padding: 8px 10px; border-radius: 9px;
    font-size: 13.5px; font-weight: 600; color: #475569;
    background: transparent;
    transition: background .15s ease, color .15s ease, box-shadow .15s ease;
    line-height: 1.25;
}
.a11y-seg input:hover + span,
.a11y-seg:hover span { color: #1c2434; }
.a11y-seg input:checked + span {
    background: #ffffff; color: var(--c-primaire, #1c2434);
    box-shadow: 0 1px 3px rgba(15, 23, 42, .08), 0 0 0 1px rgba(15, 23, 42, .04);
}
.a11y-seg input:focus-visible + span {
    outline: 2px solid var(--c-primaire, #1c2434); outline-offset: 2px;
}
/* Toggle switch — pour les 3 options booléennes (dys, liens, interligne).
   Structure : label > texte + input caché + span.switch. Le clic sur la
   ligne entière bascule ; le switch s'anime. */
.a11y-toggle {
    display: flex; align-items: center; justify-content: space-between; gap: 14px;
    padding: 12px 14px; margin: 0 0 8px !important;
    background: #f8fafc; border-radius: 12px;
    font-size: 14.5px; color: #1c2434; cursor: pointer;
    transition: background .15s ease;
}
.a11y-toggle:hover { background: #eff3f9; }
.a11y-toggle-ico {
    flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center;
    width: 20px; color: #64748b;
    transition: color .15s ease;
}
.a11y-toggle:has(input:checked) .a11y-toggle-ico { color: var(--c-primaire, #1c2434); }
.a11y-toggle-texte { flex: 1; line-height: 1.35; }
.a11y-toggle input { position: absolute; opacity: 0; width: 0; height: 0; pointer-events: none; }
.a11y-switch {
    flex-shrink: 0; position: relative;
    width: 42px; height: 24px; border-radius: 999px;
    background: #cbd5e1;
    transition: background .18s ease;
}
.a11y-switch::after {
    content: ''; position: absolute; top: 3px; left: 3px;
    width: 18px; height: 18px; border-radius: 50%;
    background: #ffffff; box-shadow: 0 1px 3px rgba(15, 23, 42, .2);
    transition: transform .18s cubic-bezier(0.4, 0, 0.2, 1);
}
.a11y-toggle input:checked ~ .a11y-switch { background: var(--c-primaire, #1c2434); }
.a11y-toggle input:checked ~ .a11y-switch::after { transform: translateX(18px); }
.a11y-toggle input:focus-visible ~ .a11y-switch {
    outline: 2px solid var(--c-primaire, #1c2434); outline-offset: 2px;
}

.a11y-pied {
    display: flex; justify-content: space-between; align-items: center;
    margin-top: 20px; padding-top: 16px; border-top: 1px solid #e6eaf1;
    font-size: 13.5px;
}
.a11y-reset {
    border: none; background: #f1f5f9; border-radius: var(--rayon-cta, 999px);
    padding: 9px 18px; cursor: pointer; font: inherit; font-size: 13.5px; font-weight: 600; color: #1c2434;
}
.a11y-reset:hover { background: var(--c-primaire); color: #fff; }
.a11y-pied a { color: var(--c-primaire); }

/* Taille du texte (zoom global : cohérent sur toutes les pages) */
html.a11y-grand body { zoom: 1.12; }
html.a11y-tgrand body { zoom: 1.28; }

/* Contraste élevé — filtre CSS non-destructif : désaturation quasi-
   totale + contraste renforcé. Préserve la structure visuelle et la
   charte de la commune (on force juste la lisibilité). Une seule
   règle couvre tout le site, y compris les futurs modules.
   Le filtre est appliqué aux enfants directs de body sauf .a11y-modal :
   la modale d'accessibilité doit rester à son rendu naturel pour que
   l'utilisateur voie exactement ce qu'il coche/décoche. */
html.a11y-contraste body > *:not(.a11y-modal):not(dialog) {
    filter: saturate(.12) contrast(1.35);
}
/* Header superposé en mode contraste : on coupe transparence + blur
   et on force un fond franc dans le sens du thème choisi par la
   commune — blanc + texte sombre pour un thème clair, noir + texte
   blanc pour un thème sombre. Sans ça on tombe soit en blanc-sur-
   blanc soit en dark-sur-dark selon la variante. */

/* Hero superposé CLAIR : header blanc, texte sombre */
html.a11y-contraste body.hero-superpose-clair .site-header:not(.est-decolle) {
    background: #ffffff !important;
    backdrop-filter: none !important; -webkit-backdrop-filter: none !important;
    box-shadow: 0 1px 0 rgba(0, 0, 0, .15) !important;
    --nav-texte: #1c2434;
    --nav-indicator-color: #1c2434;
    color: #1c2434 !important;
}
html.a11y-contraste body.hero-superpose-clair .site-header:not(.est-decolle) a,
html.a11y-contraste body.hero-superpose-clair .site-header:not(.est-decolle) .util-icone,
html.a11y-contraste body.hero-superpose-clair .site-header:not(.est-decolle) .util-lien,
html.a11y-contraste body.hero-superpose-clair .site-header:not(.est-decolle) .lang-dd > summary,
html.a11y-contraste body.hero-superpose-clair .site-header:not(.est-decolle) .site-nom {
    color: #1c2434 !important;
}

/* Hero superposé SOMBRE : header noir, texte blanc */
html.a11y-contraste body.hero-superpose-sombre .site-header:not(.est-decolle) {
    background: #000000 !important;
    backdrop-filter: none !important; -webkit-backdrop-filter: none !important;
    box-shadow: 0 1px 0 rgba(255, 255, 255, .15) !important;
    --nav-texte: #ffffff;
    --nav-indicator-color: #ffffff;
    color: #ffffff !important;
}
html.a11y-contraste body.hero-superpose-sombre .site-header:not(.est-decolle) a,
html.a11y-contraste body.hero-superpose-sombre .site-header:not(.est-decolle) .util-icone,
html.a11y-contraste body.hero-superpose-sombre .site-header:not(.est-decolle) .util-lien,
html.a11y-contraste body.hero-superpose-sombre .site-header:not(.est-decolle) .lang-dd > summary,
html.a11y-contraste body.hero-superpose-sombre .site-header:not(.est-decolle) .site-nom {
    color: #ffffff !important;
}

/* Le sous-menu déroulant échappe aux deux règles ci-dessus.
   C'est un panneau FLOTTANT, avec son propre fond (`--carte-fond`) : il ne
   suit pas le fond du header. Or les sélecteurs ci-dessus visent tout `a`
   contenu dans le header — donc aussi ses liens, repeints en blanc sur un
   panneau resté blanc. Le sous-menu devenait une carte vide.
   On lui rend donc son couple de couleurs, celui qui contraste par
   construction. Réservé au desktop : en mobile le panneau prend le fond du
   header et doit garder `--nav-texte` (voir la media query 900 px). */
@media (min-width: 901px) {
    /* Les deux variantes sont reprises telles quelles, avec `.nav-sousmenu`
       en plus : deux règles `!important` de même origine se départagent à la
       SPÉCIFICITÉ, et un sélecteur plus court aurait perdu sans rien changer
       à l'écran. */
    html.a11y-contraste body.hero-superpose-clair .site-header:not(.est-decolle) .nav-sousmenu a,
    html.a11y-contraste body.hero-superpose-sombre .site-header:not(.est-decolle) .nav-sousmenu a {
        color: var(--encre, #1c2434) !important;
    }
    html.a11y-contraste body.hero-superpose-clair .site-header:not(.est-decolle) .nav-sousmenu a:hover,
    html.a11y-contraste body.hero-superpose-sombre .site-header:not(.est-decolle) .nav-sousmenu a:hover {
        color: var(--c-liens) !important;
    }
}

/* Logo : chaque variante réclame le logo adapté à son fond header.
   - Clair : fond blanc → logo pensé pour fond clair (.site-logo-clair,
     déjà l'affichage par défaut, rien à faire).
   - Sombre : fond noir → logo pensé pour fond sombre (.site-logo-sombre,
     déjà basculé par la règle body.hero-superpose-sombre existante). */

/* Cartes et raccourcis : bordure franche de 2 px en mode contraste
   pour qu'ils se détachent nettement du fond, quel que soit le skin
   choisi (ombre, bordure fine ou plat). Le filtre CSS général
   désature les couleurs — sans bord franc, le contour disparaît sur
   les fonds proches. */
html.a11y-contraste .carte,
html.a11y-contraste .event-ligne,
html.a11y-contraste .actu-ligne,
html.a11y-contraste .events-compact li,
html.a11y-contraste .raccourci {
    border: 2px solid currentColor !important;
    box-shadow: none !important;
}

/* Police adaptée à la dyslexie */
html.a11y-dys body, html.a11y-dys h1, html.a11y-dys h2, html.a11y-dys h3,
html.a11y-dys .site-nom, html.a11y-dys input, html.a11y-dys button {
    font-family: 'OpenDyslexic', 'Comic Sans MS', Verdana, sans-serif !important;
    letter-spacing: .02em; word-spacing: .14em;
}

/* Soulignement systématique des liens */
html.a11y-liens a { text-decoration: underline !important; }

/* Interlignage augmenté */
html.a11y-interligne body { line-height: 2; }
html.a11y-interligne p { margin-bottom: 1.2em; }

/* ---------- Modale a11y : verrouillage TOTAL ----------
   Toute option cochée dans la modale (taille, dys, liens, interligne)
   modifie normalement l'ensemble du DOM, y compris la modale elle-même.
   On isole la modale de son propre effet pour que l'utilisateur voie
   toujours des switches à la taille et à la position prévues, quelles
   que soient les préférences enregistrées. */
html.a11y-grand .a11y-modal,
html.a11y-tgrand .a11y-modal {
    zoom: 1 !important;
    font-size: 14.5px !important;
}
html.a11y-dys .a11y-modal,
html.a11y-dys .a11y-modal *,
html.a11y-dys .a11y-modal input,
html.a11y-dys .a11y-modal button {
    font-family: var(--police, system-ui, sans-serif) !important;
    letter-spacing: normal !important;
    word-spacing: normal !important;
}
html.a11y-liens .a11y-modal a { text-decoration: none !important; }
html.a11y-liens .a11y-modal a:hover { text-decoration: underline !important; }
/* Interligne : force les valeurs DE DESIGN de la modale (1.4 sur le
   container, 1.35 sur les libellés de toggle) plutôt que « normal »
   qui resserre plus que la modale prévue. On ne touche PAS aux
   marges — la règle générique interligne ne cible que les <p> (qui
   n'existent pas dans la modale) et un reset des margin-bottom
   écraserait le `margin: 0 0 8px` posé sur .a11y-toggle. */
html.a11y-interligne .a11y-modal,
html.a11y-interligne .a11y-modal * { line-height: 1.4 !important; }
html.a11y-interligne .a11y-modal .a11y-toggle-texte { line-height: 1.35 !important; }

/* =====================================================
   Sections & cartes
   ===================================================== */
/* Sections : jamais de margin (fusion de marges = filets de couleur entre sections).
   Padding 1px : le fond de la section couvre les marges du wrapper interne. */
.section { margin: 0; padding: 1px 0; }
.section > .conteneur { margin-top: clamp(48px, 7vw, 84px); margin-bottom: clamp(48px, 7vw, 84px); }
/* Section alternée : son fond est choisi par la commune, clair ou sombre.
   Le texte et les cartes qu'elle contient suivent son propre contraste. */
.section-alt {
    background: var(--section-alt, #f5f7fa);
    color: var(--section-texte, inherit);
}
.section-alt h1, .section-alt h2, .section-alt h3 { color: var(--section-texte, inherit); }
.section-alt .muted { color: var(--section-gris, inherit); }
/* L'alternance n'est plus rattrapée ici : elle est décidée au rendu par
   `section_classe()` (app/views/site/_sections.php), qui ne pose `section-alt`
   qu'une section sur deux. La cascade `.section-alt + .section-alt + …` qui
   occupait cette place ne tenait que jusqu'à cinq sections consécutives et se
   trompait dès qu'une section était masquée par un module inactif. */
.section-entete { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; flex-wrap: wrap; margin-bottom: 30px; }
.section-entete h2 { margin: 0; font-size: clamp(24px, 3vw, 33px); }
.lien-plus {
    font-weight: 650; text-decoration: none; color: var(--c-liens);
    display: inline-flex; align-items: center; gap: 6px;
}
/* Pas de soulignement au survol : la flèche animée fait déjà l'affordance,
   ajouter un souligné rendrait le lien visuellement bruyant. */
.lien-plus:hover { text-decoration: none; }
/* La flèche accompagne le survol : discret et actuel */
.lien-plus .ico { transition: transform .18s ease; }
.lien-plus:hover .ico { transform: translateX(3px); }
.retour .ico { transition: transform .18s ease; }
.retour:hover .ico { transform: translateX(-3px); }
.titre-secondaire {
    display: flex; align-items: center; gap: 12px;
    margin-top: 48px; font-size: clamp(20px, 2.4vw, 26px);
}
/* Premier titre d'une liste de groupes (annuaire / Docuthèque) : pas
   de marge haute — le H1 de page fournit déjà l'espacement. */
.annuaire-contenu > .annuaire-groupe:first-child .titre-secondaire,
.documents-contenu > .documents-groupe:first-child .titre-secondaire {
    margin-top: 0;
}
.titre-secondaire .ico { flex-shrink: 0; opacity: .8; }
/* Titres cliquables (ex. lien vers la page catégorie d'annuaire) —
   jamais soulignés, couleur du titre héritée, transition au hover. */
.titre-secondaire a {
    color: inherit; text-decoration: none;
    transition: color .12s ease;
}
.titre-secondaire a:hover { color: var(--c-primaire, currentColor); text-decoration: none; }

/* Annuaire : layout à deux colonnes — sidebar de filtres à gauche,
   contenu à droite. Style ALIGNÉ sur la convention `.article-cote` :
   pas de carte encadrée, juste une étiquette majuscule + liste. La
   cohérence vient de l'uniformité, pas de la décoration. */
.annuaire-layout {
    display: grid; grid-template-columns: 240px minmax(0, 1fr);
    gap: 40px; align-items: start;
}
@media (max-width: 820px) {
    .annuaire-layout { grid-template-columns: 1fr; gap: 24px; }
}
.annuaire-filtres {
    position: sticky; top: 100px;
    display: flex; flex-direction: column; gap: 12px;
}
@media (max-width: 820px) { .annuaire-filtres { position: static; } }
.annuaire-filtres-liste { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 2px; }
.annuaire-filtres-liste a,
.annuaire-filtres-liste button {
    /* Lien cliquable en bloc — jamais souligné, prend toute la largeur.
       Le lien actif (page catégorie courante) porte un fond gris franc
       pour signaler qu'on est bien dans son contexte. */
    width: 100%; text-align: left; cursor: pointer;
    display: flex; align-items: center; gap: 10px;
    padding: 8px 10px; border-radius: 8px;
    background: transparent; border: 0; font: inherit; font-size: 14.5px;
    color: var(--encre, #1c2434);
    text-decoration: none;
    transition: background .12s ease, color .12s ease;
}
.annuaire-filtres-liste a:hover,
.annuaire-filtres-liste button:hover {
    background: color-mix(in srgb, var(--c-primaire, currentColor) 8%, transparent);
    text-decoration: none;
}
.annuaire-filtres-liste a.is-actif,
.annuaire-filtres-liste button.is-actif {
    background: color-mix(in srgb, var(--c-primaire, currentColor) 18%, transparent);
    color: var(--c-primaire, currentColor); font-weight: 650;
}
.annuaire-filtres-liste .compteur {
    margin-left: auto; font-size: 12.5px; color: var(--gris, #64748b);
}
.annuaire-filtres-liste a.is-actif .compteur,
.annuaire-filtres-liste button.is-actif .compteur { color: inherit; opacity: .8; }
.annuaire-filtres-liste .ico { flex-shrink: 0; }
/* Un groupe de catégorie qu'un filtre a caché. */
.annuaire-groupe[hidden] { display: none; }
/* « Proposer une entrée » — pied de sidebar filtres, seulement affiché
   quand au moins une catégorie est ouverte au public. Pas un bouton
   plein — un CTA doux, aligné visuellement sur les éléments de la
   sidebar, avec un séparateur discret. Picto rond aux couleurs primaires,
   texte + baseline explicative. */
.annuaire-proposer {
    display: flex; align-items: center; gap: 12px;
    margin-top: 16px; padding: 12px 10px;
    border-top: 1px solid var(--carte-bordure, rgba(15, 23, 42, .1));
    text-decoration: none; color: var(--encre, #1c2434);
    /* Filet haut plein bord au repos ; les arrondis apparaissent au hover
       en même temps que le fond, pour un effet de « pilule » qui se forme. */
    border-radius: 0;
    transition: background .15s ease, transform .15s ease, border-radius .18s ease;
}
.annuaire-proposer:hover {
    background: color-mix(in srgb, var(--c-primaire, currentColor) 8%, transparent);
    text-decoration: none; transform: translateX(2px);
    border-radius: 8px;
}
.annuaire-proposer-picto {
    flex-shrink: 0;
    width: 34px; height: 34px;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 999px;
    background: color-mix(in srgb, var(--c-primaire, #64748b) 14%, transparent);
    color: var(--c-primaire, #2563eb);
    transition: background .15s ease;
}
.annuaire-proposer:hover .annuaire-proposer-picto {
    background: var(--c-primaire, #2563eb);
    color: #fff;
}
.annuaire-proposer-texte { font-size: 14.5px; font-weight: 650; line-height: 1.2; }

.cartes { display: grid; gap: 26px; }
/* Cartes 4-par-4 en large — le nom `.cartes-3` est resté par historique
   mais l'auto-fill à 240 px min garantit 4 colonnes sur un conteneur de
   1252 px (max-width 1300 - 48 padding) et redescend proprement à 3, 2, 1
   au fur et à mesure que l'écran rétrécit. */
.cartes-3 { grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); }
.cartes-2 { grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); }
/* Actualités en cartes : trois par ligne, soit un tiers de la largeur.
   Volontairement moins dense que la grille générique ci-dessus, dont l'auto-fill
   à 240 px donne jusqu'à cinq colonnes sur un grand écran : une actualité porte
   un titre et un chapô, elle a besoin de largeur pour rester lisible. Déclarée
   après `.cartes-3` pour l'emporter à spécificité égale. */
.cartes-actus { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 980px) { .cartes-actus { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 620px) { .cartes-actus { grid-template-columns: 1fr; } }
/* Agenda en cartes : quatre par ligne, soit un quart de la largeur. Plus dense
   que les actualités, ce que la carte permet — elle porte une date, un titre et
   un lieu, pas de chapô. L'accueil en charge justement quatre. */
.events-cartes { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 1100px) { .events-cartes { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 860px)  { .events-cartes { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px)  { .events-cartes { grid-template-columns: 1fr; } }
/* Une carte emprunte TOUJOURS l'autre fond que celui de sa section : posée sur
   le fond de page elle prend le fond alterné, et inversement. Elle se détache
   ainsi quel que soit le couple de teintes choisi par la commune. */
.carte, .event-ligne, .actu-ligne, .events-compact li, .document-ligne, .publication-carte {
    --sur-carte: var(--section-texte, inherit);
    --sur-carte-gris: var(--section-gris, var(--gris));
    --sur-carte-bordure: var(--section-bordure, var(--carte-bordure));
    background: var(--section-alt);
    color: var(--sur-carte);
}
.section-alt .carte, .section-alt .event-ligne,
.section-alt .actu-ligne, .section-alt .events-compact li,
.section-alt .document-ligne, .section-alt .publication-carte {
    --sur-carte: var(--encre);
    --sur-carte-gris: var(--gris);
    --sur-carte-bordure: var(--carte-bordure);
    background: var(--fond);
}
.carte p, .actu-ligne p, .carte .event-lieu, .actu-ligne .event-lieu { color: var(--sur-carte-gris); }

.carte {
    border-radius: var(--rayon);
    overflow: hidden;
    transition: transform .2s ease, box-shadow .2s ease, border-color .2s ease;
}
.cartes-ombre .carte { border: none; box-shadow: 0 4px 18px -4px rgba(15, 23, 42, .1), 0 1px 3px rgba(15, 23, 42, .05); }
.cartes-ombre .carte:hover { transform: translateY(-4px); box-shadow: 0 18px 38px -8px rgba(15, 23, 42, .18); }
.cartes-bordure .carte { border: 1.5px solid var(--sur-carte-bordure); }
.cartes-bordure .carte:hover { border-color: var(--c-primaire); transform: translateY(-3px); }
.cartes-plat .carte { border: none; }
.cartes-plat .carte:hover { transform: translateY(-3px); }
.carte > a { display: block; text-decoration: none; color: inherit; height: 100%; }
.carte-image { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; display: block; }
.carte-corps { padding: 20px 22px 22px; }
/* Titre et chapô plafonnés à 3 lignes chacun (line-clamp), au-delà
   passe en ellipsis. Garde une hauteur de card prévisible dans les
   grilles, sans coupure brutale des textes courts. */
.carte-corps h2, .carte-corps h3 {
    margin: 8px 0 8px; font-size: 18.5px; font-weight: 650;
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3;
    overflow: hidden;
}
.carte-corps p {
    margin: 0 0 10px; font-size: 14.5px; color: var(--gris, #5a6779); line-height: 1.6;
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3;
    overflow: hidden;
}
.carte-date {
    font-size: 12.5px; color: var(--c-primaire); font-weight: 700;
    text-transform: uppercase; letter-spacing: .07em;
}
.carte-titre { font-size: 19px; }

/* =====================================================
   Actualités — variantes de mise en page
   ===================================================== */

/* Liste illustrée : vignette à gauche, chapô développé */
.actus-liste { display: flex; flex-direction: column; gap: 18px; }
.actu-ligne {
    border-radius: var(--rayon); overflow: hidden;
    transition: transform .2s ease, box-shadow .2s ease, border-color .2s ease;
}
.cartes-ombre .actu-ligne { box-shadow: 0 3px 14px -4px rgba(15, 23, 42, .1); }
.cartes-ombre .actu-ligne:hover { transform: translateX(4px); box-shadow: 0 12px 30px -8px rgba(15, 23, 42, .17); }
.cartes-bordure .actu-ligne { border: 1.5px solid var(--sur-carte-bordure); }
.cartes-bordure .actu-ligne:hover { border-color: var(--c-primaire); transform: translateX(4px); }
.actu-ligne > a { display: grid; grid-template-columns: 260px 1fr; text-decoration: none; color: inherit; }
.actu-ligne-image { width: 100%; height: 100%; min-height: 170px; object-fit: cover; display: block; }
.actu-ligne-corps { padding: 20px 24px; }
.actu-ligne-corps h3 { margin: 8px 0 10px; font-size: 21px; }
.actu-ligne-corps p { margin: 0; color: var(--gris, #5a6779); font-size: 15px; line-height: 1.6; }
@media (max-width: 720px) {
    .actu-ligne > a { grid-template-columns: 1fr; }
    .actu-ligne-image { aspect-ratio: 16 / 9; min-height: 0; }
}

/* Une à la une : article vedette + colonne d'actualités secondaires */
/* `align-items: stretch` (défaut) et non `start` : la colonne secondaire épouse
   la hauteur de la vedette, et ses cartes se répartissent la hauteur à parts
   égales au lieu de laisser un vide sous la dernière. */
.actus-magazine { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; }
/* Variante landing : deux vedettes égales côte à côte au sommet.
   `align-items: stretch` (défaut du grid) — les deux vedettes prennent
   la hauteur de la plus grande, chapô plus court simplement suivi
   d'un peu plus d'espace, l'ensemble reste équilibré. */
.actus-magazine-landing { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; align-items: stretch; }
.actus-magazine-landing > .actu-vedette { display: flex; flex-direction: column; }
.actus-magazine-landing > .actu-vedette > a { flex: 1; display: flex; flex-direction: column; }
.actus-magazine-landing > .actu-vedette .carte-corps { flex: 1; }
@media (max-width: 720px) {
    .actus-magazine-landing { grid-template-columns: 1fr; }
}
/* Suite en grille — quand plus de 5 articles à afficher (landing surtout).
   Marge haute pour bien séparer du bloc magazine. */
.actus-magazine-suite { margin-top: 32px; }
/* Ratio 21/9 : nettement moins haute qu'un 16/10, la vedette gagne en
   largeur et laisse plus de place au texte en dessous — ce qui est
   attendu pour une « une » éditoriale. */
.actu-vedette .carte-image { aspect-ratio: 21 / 9; }
.actu-vedette .carte-corps { padding: 22px 26px 26px; }
.actu-vedette h3 { font-size: clamp(22px, 2.6vw, 30px); margin: 8px 0 12px; }
.actu-vedette p { font-size: 15.5px; }
.actus-secondaires { display: flex; flex-direction: column; gap: 16px; height: 100%; }
/* Chaque secondaire prend une part égale de la hauteur disponible. La base 0
   force un partage strictement égal : avec `auto`, une carte au titre plus long
   garderait un avantage et l'ensemble redeviendrait irrégulier. */
.actus-secondaires > .actu-secondaire { flex: 1 1 0; min-height: 92px; }
/* Une seule secondaire à répartir : l'étirer sur toute la hauteur de la vedette
   donnerait une carte démesurée. Elle garde alors sa hauteur naturelle. */
.actus-secondaires > .actu-secondaire:only-child { flex: 0 0 auto; }
.actu-secondaire > a { display: grid; grid-template-columns: 104px 1fr; align-items: stretch; height: 100%; }
.actu-secondaire-image { width: 100%; height: 100%; min-height: 92px; object-fit: cover; display: block; }
/* Carte plus haute : le texte se centre verticalement plutôt que de rester
   collé en haut, sinon l'espace gagné apparaît comme un vide sous le titre. */
.actu-secondaire .carte-corps {
    padding: 14px 16px; display: flex; flex-direction: column; justify-content: center;
}
/* Deux lignes maximum : avec quatre cartes à répartir sur la hauteur de la
   vedette, un titre long en trois ou quatre lignes déséquilibrerait la colonne
   et écraserait les cartes voisines. */
.actu-secondaire h3 {
    font-size: 16px; margin: 6px 0 0;
    display: -webkit-box; -webkit-box-orient: vertical;
    -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden;
}
/* Aperçu 2 lignes maximum sur les secondaires du format « à la une » —
   line-clamp CSS pour la coupure propre quel que soit le texte source
   (chapo court, contenu long tronqué à 110 caractères côté PHP). */
.actu-secondaire-apercu {
    font-size: 13.5px; line-height: 1.45; margin: 6px 0 0;
    color: color-mix(in srgb, var(--c-encre, #1c2434) 72%, transparent);
    display: -webkit-box; -webkit-box-orient: vertical;
    -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden;
}
@media (max-width: 860px) {
    .actus-magazine { grid-template-columns: 1fr; }
}

/* =====================================================
   Agenda
   ===================================================== */
.events-liste { display: flex; flex-direction: column; gap: 14px; }
.event-ligne {
    display: flex; align-items: center; gap: 20px; text-decoration: none; color: inherit;
    border-radius: var(--rayon); padding: 14px 20px;
    transition: transform .2s ease, box-shadow .2s ease, border-color .2s ease;
}
.cartes-ombre .event-ligne { box-shadow: 0 2px 10px -2px rgba(15, 23, 42, .08); }
.cartes-ombre .event-ligne:hover { transform: translateX(4px); box-shadow: 0 10px 26px -6px rgba(15, 23, 42, .16); }
.cartes-bordure .event-ligne { border: 1.5px solid var(--sur-carte-bordure); }
.cartes-bordure .event-ligne:hover { border-color: var(--c-primaire); transform: translateX(4px); }
.cartes-plat .event-ligne:hover { transform: translateX(4px); }
/* La pastille de date est un aplat de la couleur principale : son texte suit
   le contraste calculé, jamais un blanc codé en dur. */
.event-date-bloc {
    flex-shrink: 0; width: 68px; text-align: center;
    /* La pastille est un aplat décoratif de la couleur principale : on
       privilégie le blanc (biaisé via --sur-primaire-accent), qui rend
       mieux et est visuellement plus attendu. Bascule sur du texte foncé
       uniquement pour les teintes vraiment pâles. */
    color: var(--sur-primaire-accent, #fff);
    background: var(--c-primaire);
    border-radius: calc(var(--rayon) * .7); padding: 10px 4px; line-height: 1.1;
}
.event-jour { display: block; font-size: 23px; font-weight: 750; font-family: var(--police-titres); }
.event-mois { display: block; font-size: 11.5px; text-transform: uppercase; letter-spacing: .05em; margin-top: 2px; }

/* Événement sur plusieurs jours : un rectangle unique regroupant les deux
   dates, séparées par un trait oblique traversant toute la hauteur (façon
   « / » gravé dans la pastille). Plus lisible qu'un chevron entre deux
   petits carrés, et plus compact aussi. */
.event-date-multi {
    display: inline-grid;
    grid-template-columns: auto auto;
    width: auto;
    padding: 0;
    position: relative;
    overflow: hidden;
}
.event-date-part {
    display: block; padding: 10px 14px; text-align: center;
    min-width: 46px;
}
/* Trait oblique séparant les deux dates. `left: 50%` + skewX -14° et
   `top: -6px; bottom: -6px` pour que le trait déborde légèrement au-dessus
   et en-dessous (effet slash traversant), largeur fine (2px) en
   demi-opacité de la couleur de texte pour rester cohérent avec la
   pastille (blanc sur aplat sombre, foncé sur aplat clair). */
.event-date-multi::before {
    content: "";
    position: absolute; left: 50%; top: -6px; bottom: -6px;
    width: 2px; background: currentColor; opacity: .35;
    transform: translateX(-1px) skewX(-14deg);
    pointer-events: none;
}

/* Flottant sur un visuel : badge autonome avec ombre portée pour se
   décrocher de la photo derrière, sans pill unificateur ni chevron
   séparé (plus pertinent depuis le passage au badge unique multi-date). */
.event-date-bloc.event-date-flottante,
.event-date-multi.event-date-flottante {
    position: absolute; left: 14px; bottom: 14px; z-index: 1;
    box-shadow: 0 6px 18px -4px rgba(15, 23, 42, .4);
}
.event-infos { display: flex; flex-direction: column; gap: 3px; }
.event-infos strong { font-size: 16.5px; font-weight: 650; }
.event-lieu { color: var(--gris, #5a6779); font-size: 14px; display: inline-flex; align-items: center; gap: 5px; }
.events-passes { opacity: .65; }

/* Visuel de remplacement : la grille garde son rythme même sans photo */
/* Le voile se compose par-dessus le fond de la carte, quel qu'il soit */
.visuel-absent {
    display: flex; align-items: center; justify-content: center;
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--c-primaire) 18%, transparent),
        color-mix(in srgb, var(--c-primaire) 5%, transparent));
    color: color-mix(in srgb, var(--c-primaire) 60%, transparent);
}
.visuel-absent .ico { stroke-width: 1.5; }
.carte-image.visuel-absent { aspect-ratio: 16 / 9; }
.actu-ligne-image.visuel-absent { min-height: 170px; }
.actu-secondaire-image.visuel-absent { min-height: 92px; }
.actu-vedette .carte-image.visuel-absent { aspect-ratio: 21 / 9; }

/* Agenda en cartes : date en surimpression sur le visuel */
.event-carte-visuel { position: relative; }
.event-date-flottante {
    position: absolute; left: 14px; bottom: 14px; z-index: 1;
    box-shadow: 0 6px 18px -4px rgba(15, 23, 42, .4);
}
.event-carte .carte-corps h3 { margin-top: 0; }
.event-carte .event-lieu { margin: 6px 0 0; }

/* Programme condensé : mini-cards horizontales, marges entre chacune,
   pas de filet séparateur — respire mieux et respecte les arrondis
   choisis par la commune (var(--rayon)) ainsi que le style de cartes
   (ombre / bordure / plat) via les classes body.cartes-* comme .carte. */
.events-compact { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
/* Le background est géré plus haut par la règle « .carte, ..., .events-compact li »
   qui prend TOUJOURS le fond opposé de la section (--section-alt sur le fond
   de page, --fond dans .section-alt). Ne pas le forcer ici. */
.events-compact li {
    border-radius: var(--rayon, 10px);
    overflow: hidden;
    transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}
/* Variantes de style de carte, alignées sur .carte / .actu-ligne / .event-ligne */
.cartes-ombre .events-compact li {
    box-shadow: 0 2px 10px -2px rgba(15, 23, 42, .08);
}
.cartes-ombre .events-compact li:hover {
    box-shadow: 0 10px 26px -6px rgba(15, 23, 42, .16);
    transform: translateX(4px);
}
.cartes-bordure .events-compact li {
    border: 1.5px solid var(--sur-carte-bordure);
}
.cartes-bordure .events-compact li:hover {
    border-color: var(--c-primaire);
    transform: translateX(4px);
}
.cartes-plat .events-compact li:hover { transform: translateX(4px); }
.events-compact a {
    display: grid; grid-template-columns: 210px 1fr auto auto; gap: 16px; align-items: center;
    padding: 15px 20px; text-decoration: none; color: inherit;
    border-radius: var(--rayon, 10px);
}
.events-compact a .ico { align-self: center; color: var(--c-primaire); }
.event-compact-date { color: var(--c-primaire); font-weight: 700; font-size: 14px; }
/* Multi-jours dans le programme condensé : les deux dates l'une sous
   l'autre, empilées sans filet séparateur. Plus lisible qu'un
   « du X au Y » qui ferait déborder la colonne étroite. */
.event-compact-date-multi {
    display: inline-flex; flex-direction: column; gap: 2px; line-height: 1.25;
}
.event-compact-titre { font-weight: 600; font-size: 16px; }
.event-compact-lieu { color: var(--gris, #5a6779); font-size: 14px; }
@media (max-width: 760px) {
    .events-compact a { grid-template-columns: 1fr auto; row-gap: 4px; }
    .event-compact-date { grid-column: 1 / -1; }
    .event-compact-lieu { grid-column: 1 / -1; }
}

/* =====================================================
   Pages / articles
   ===================================================== */
.page-conteneur { padding: clamp(40px, 6vw, 64px) 24px clamp(56px, 8vw, 88px); }

/* Titre de page — cohérent sur toutes les pages intérieures
   (annuaire, équipe, contact, agenda, actualités, pages libres).
   Volontairement GROS pour marquer la hiérarchie éditoriale et
   uniformiser tous les modules du site public. */
.page-titre {
    font-family: var(--police-titres, var(--police));
    font-size: clamp(36px, 5.2vw, 60px);
    line-height: 1.1;
    margin: 12px 0 clamp(24px, 3vw, 36px);
    color: var(--encre, #1c2434);
    letter-spacing: -.015em;
    font-weight: 750;
}
/* En vue « article » (contenu long à colonne unique) : titre à peine
   plus mesuré pour ne pas dominer la lecture d'un texte long. */
.page-conteneur.article .page-titre { font-size: clamp(32px, 4.4vw, 48px); margin-bottom: clamp(18px, 2.5vw, 28px); }

/* =====================================================
   Équipe municipale — vue publique
   ===================================================== */
.equipe-page .page-titre { margin: 12px 0 6px; }
.equipe-page .page-baseline { color: var(--gris, #56606f); margin: 0 0 40px; font-size: 17px; }

/* Le Maire : fiche « pleine largeur » avec photo légèrement plus
   grande à gauche et biographie à droite. Tailles réduites par
   rapport à la première version. Sur mobile la photo passe au-dessus. */
.equipe-maire { margin: 0 0 clamp(40px, 5vw, 60px); }
/* La fiche Maire = une .carte (thème du site : ombre / bordure / plat)
   avec sa propre disposition à 2 colonnes. Les styles de bordure et
   d'ombre viennent des règles `.cartes-* .carte` — on ne réinvente
   pas la charte, on empile la disposition par-dessus. */
.equipe-maire-carte {
    display: grid; grid-template-columns: minmax(200px, 260px) 1fr;
    gap: clamp(24px, 3.5vw, 44px); align-items: start;
    padding: clamp(22px, 3vw, 34px);
    text-align: left; color: inherit; font: inherit; width: 100%;
    cursor: pointer;
}
.equipe-maire-photo {
    width: 100%; aspect-ratio: 1 / 1; object-fit: cover;
    border-radius: calc(var(--rayon, 12px) * 1.1);
    display: block;
}
/* Label « Maire » — présenté au-dessus du nom, en petites capitales
   colorées (accent primaire) : c'est le seul repère spécifique au
   Maire, la fonction elle est traitée comme les autres. */
.equipe-role {
    text-transform: uppercase; letter-spacing: .1em; font-size: 12.5px;
    color: var(--c-primaire); font-weight: 700; margin: 0 0 8px;
}
.equipe-maire-nom {
    font-size: clamp(24px, 2.6vw, 34px); line-height: 1.15;
    margin: 0 0 6px; letter-spacing: -0.015em; text-wrap: balance;
}
/* Fonction — MÊME rendu pour tous (maire ou autres) : gris sobre,
   pas de couleur d'accent. Cohérence totale des fiches. */
.equipe-fonction {
    font-size: 14.5px; color: var(--gris); font-weight: 500;
    margin: 0 0 14px;
}
.equipe-maire-desc { font-size: 15px; line-height: 1.6; color: var(--encre); }
.equipe-lien-modal {
    display: inline-flex; align-items: center; gap: 5px; margin-top: 14px;
    font-size: 13.5px; color: var(--c-primaire); font-weight: 600;
}
@media (max-width: 760px) {
    .equipe-maire-carte { grid-template-columns: 1fr; }
    .equipe-maire-photo { max-width: 220px; }
}

/* Autres catégories : titre de section + grille de fiches compactes. */
.equipe-groupe { margin: 0 0 clamp(36px, 4.5vw, 48px); }
.equipe-groupe > h2 {
    font-size: clamp(19px, 1.8vw, 24px);
    margin: 0 0 18px; letter-spacing: -0.01em;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--carte-bordure, rgba(15, 23, 42, .08));
}
.equipe-grille {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
    gap: 18px;
}
/* Fiche secondaire = une .carte (thème site). On ne redéfinit ici
   que le reset button + la disposition colonne, la bordure/ombre
   viennent des règles `.cartes-* .carte`. */
.equipe-fiche {
    display: flex; flex-direction: column;
    text-align: left; color: inherit; font: inherit; padding: 0;
    cursor: pointer;
}
.equipe-fiche-photo {
    width: 100%; aspect-ratio: 1 / 1; object-fit: cover; display: block;
}
.equipe-fiche-corps { padding: 14px 16px; }
.equipe-fiche h3 { font-size: 16px; margin: 0 0 4px; letter-spacing: -0.01em; }
.equipe-fiche .equipe-fonction { margin: 0; }

/* Placeholder photo (aucune image chargée) — carré neutre avec un
   picto centré, valable pour Maire ET fiches compactes. */
.equipe-photo-vide {
    display: flex; align-items: center; justify-content: center;
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--c-primaire) 15%, transparent),
        color-mix(in srgb, var(--c-primaire) 5%, transparent));
    color: color-mix(in srgb, var(--c-primaire) 60%, transparent);
}

/* Modale de fiche membre (via civikaModal) — colonne gauche sticky
   (photo + coordonnées de contact regroupées) puis corps texte à
   droite. Sur mobile la colonne gauche passe au-dessus dans un
   format plus compact. */
.fiche-modal {
    display: grid; grid-template-columns: 30% 1fr;
    gap: 28px; align-items: start;
}
/* Colonne de gauche en sticky : la photo et le tel restent visibles
   pendant qu'on lit la biographie et qu'on remplit le formulaire.
   `align-self: start` + top calé sur le padding du modal. */
.fm-cote {
    position: sticky; top: 4px;
    display: flex; flex-direction: column; gap: 14px;
    align-self: start;
}
.fm-photo {
    width: 100%; aspect-ratio: 1 / 1; object-fit: cover; display: block;
    border-radius: 10px;
}
.fm-photo-vide {
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--c-primaire) 15%, transparent),
        color-mix(in srgb, var(--c-primaire) 5%, transparent));
}
.fm-corps h3 { margin: 0 0 6px; font-size: 26px; letter-spacing: -0.01em; }
.fm-fonction { color: var(--gris); font-size: 15px; margin: 0 0 14px; }
.fm-desc { font-size: 16px; line-height: 1.65; color: var(--encre); margin-bottom: 18px; }
/* Bloc contact sous la photo — deux boutons empilés (téléphone puis
   « Contacter »), tous les deux prenant TOUTE la largeur de la
   colonne, texte centré. Le CSS unifie tel + CTA sous `.fm-btn`. */
.fm-contact { display: flex; flex-direction: column; gap: 10px; }
.fm-btn {
    display: flex; align-items: center; justify-content: center; gap: 8px;
    width: 100%; text-align: center;
    padding: 10px 14px; border-radius: 10px;
    font-weight: 600; font-size: 14.5px; text-decoration: none;
    border: 1px solid transparent;
    transition: background .15s ease, transform .12s ease, border-color .15s ease;
}
.fm-btn-tel {
    color: var(--c-primaire);
    background: color-mix(in srgb, var(--c-primaire) 12%, transparent);
    border-color: color-mix(in srgb, var(--c-primaire) 25%, transparent);
}
.fm-btn-tel:hover { background: color-mix(in srgb, var(--c-primaire) 20%, transparent); }
.fm-btn-primary {
    /* Texte adaptatif à la teinte primaire (foncé sur teintes claires
       comme Ambre/Aurore, blanc sur teintes sombres) — même variable
       que `.btn-envoyer` pour rester cohérent partout. */
    color: var(--sur-primaire-accent, #ffffff);
    background: var(--c-primaire);
    border-color: var(--c-primaire);
}
.fm-btn-primary:hover { filter: brightness(.92); }
.fm-form {
    margin-top: 20px; padding-top: 16px;
    border-top: 1px solid var(--carte-bordure, rgba(15, 23, 42, .08));
}
.fm-form h4 { margin: 0 0 10px; font-size: 15px; }
.fm-form label {
    display: block; margin-bottom: 10px; font-size: 13px; color: var(--gris);
}
.fm-form input, .fm-form textarea {
    display: block; width: 100%; margin-top: 4px; padding: 8px 10px;
    font: inherit; font-size: 14px;
    border: 1px solid var(--carte-bordure, rgba(15, 23, 42, .12));
    border-radius: 6px; background: #fff; color: var(--encre);
    box-sizing: border-box;
}
.fm-form textarea { resize: none; }
.fm-form-actions { display: flex; align-items: center; gap: 12px; }
.fm-form-status { font-size: 13px; color: var(--gris); }
.fm-form-erreur { color: #dc2626; }
.fm-form-succes {
    padding: 14px; border-radius: 8px; text-align: center;
    background: #ecfdf5; color: #065f46; font-weight: 600;
}
@media (max-width: 680px) {
    .fiche-modal { grid-template-columns: 1fr; }
    .fm-cote { position: static; flex-direction: row; align-items: center; gap: 18px; }
    .fm-photo { max-width: 160px; aspect-ratio: 1 / 1; }
}

/* Page « Contacter un élu » — se GREFFE sur `.contact-grid` (utilisé par
   /contact) pour hériter du layout, des styles de champ, du bouton
   « envoyer » et de la case RGPD. On n'ajoute ici que le sélecteur
   d'interlocuteur et la vignette photo dans la colonne latérale. */
.ec-selecteur select {
    /* Aligné sur la hauteur des inputs texte de `.contact-form`
       (padding 12/14, font-size 15.5) — cohérence de la colonne. */
    width: 100%; padding: 12px 14px;
    border: 1px solid var(--carte-bordure);
    border-radius: calc(var(--rayon, 8px) * .55);
    background: var(--fond); color: var(--encre);
    font: inherit; font-size: 15.5px; font-weight: 500;
    cursor: pointer; box-sizing: border-box;
}
.ec-selecteur select:focus {
    outline: none; border-color: var(--c-primaire);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--c-primaire) 20%, transparent);
}
.ec-photo-bloc { padding: 0; }
.ec-photo {
    width: 100%; aspect-ratio: 1 / 1; object-fit: cover;
    border-radius: var(--rayon, 10px); display: block;
}
.ec-photo-vide {
    display: flex; align-items: center; justify-content: center;
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--c-primaire) 15%, transparent),
        color-mix(in srgb, var(--c-primaire) 5%, transparent));
    color: color-mix(in srgb, var(--c-primaire) 60%, transparent);
}

/* CTA « Contacter » dans la modale fiche membre. */
.fm-cta { margin-top: 22px; }
.fm-cta-btn { display: inline-flex; align-items: center; gap: 6px; }

/* ---------------- Case anti-bot souveraine (Humain::champ) ----------------
   Style inspiré du widget reCAPTCHA v2 mais purement local — pas de
   dépendance, pas de tracking, pas de cookie. Coche verte à la
   validation JS pour signaler visuellement l'état « vérifié ». */
.humain-case {
    margin: 18px 0 26px;
    padding: 14px 18px;
    border: 1px solid var(--carte-bordure, rgba(15, 23, 42, .12));
    /* Suit le rayon CTA (cohérent avec les inputs voisins), cappé à
       1.5rem — le bloc étant haut, un pill 999px déformerait tout. */
    border-radius: min(var(--rayon-cta, 999px), 1.5rem);
    background: rgba(255, 255, 255, .12);
    max-width: 380px;
}
/* Case + bloc texte côte à côte, aligné comme la case RGPD
   (`.contact-consent > label`) : gap 10 px, alignement au début.
   Sélecteur `.humain-case .humain-label` (0,2,0) pour battre
   `.contact-form label { display: block }` (0,1,1) lorsque le bloc
   est rendu dans un formulaire de contact. */
.humain-case .humain-label {
    display: flex; align-items: flex-start; gap: 10px;
    cursor: pointer; font-weight: 400; margin: 0;
}
.humain-case .humain-label input[type="checkbox"] {
    flex: 0 0 auto;
    width: 20px; height: 20px; margin: 2px 0 0;
    accent-color: var(--c-primaire);
    cursor: pointer;
}
.humain-texte-bloc { display: flex; flex-direction: column; gap: 4px; }
.humain-titre { font-weight: 500; font-size: 14.5px; line-height: 1.3; }
.humain-mention { font-size: 11.5px; color: var(--section-gris, var(--gris)); line-height: 1.4; }
.article-meta { color: var(--gris, #5a6779); font-size: 14.5px; margin-top: -8px; }
.article-image { border-radius: var(--rayon); margin: 16px 0 8px; }
.article-chapo { font-size: 20px; color: var(--gris, #414e60); font-weight: 480; line-height: 1.6; }
.retour { text-decoration: none; font-weight: 650; font-size: 14.5px; display: inline-flex; align-items: center; gap: 6px; }
.prose { max-width: 720px; }
/* Images insérées par l'utilisateur dans le corps d'un article — même
   rayon que l'image d'en-tête, pour rester cohérent avec la charte
   choisie dans l'admin Apparence. */
.prose img { border-radius: var(--rayon, 12px); display: block; max-width: 100%; height: auto; }
.prose a { color: var(--c-liens); }
.prose h2 { font-size: 30px; margin-top: 38px; }
.prose h3 { font-size: 23px; }
.prose h4 { font-size: 19px; }
/* Citation — convention éditoriale standard : taille du body,
   italique, teinte grise, filet coloré à gauche. Rendu identique
   entre admin et front. */
.prose blockquote {
    border-left: 3px solid var(--c-primaire); margin: 20px 0; padding: 4px 20px;
    color: var(--gris, #5a6779); font-style: italic;
}
/* Listes non ordonnées dans le contenu éditorial — tirets cadratin
   à la place des puces disc/circle par défaut. Réalisé via `::before`
   plutôt que `list-style-type: "—"` pour supporter Safari plus
   ancien qui ne gère pas les chaînes personnalisées comme puces.
   Propriétés logiques (`padding-inline-*`, `inset-inline-*`) pour
   support RTL automatique (arabe). Les listes ordonnées gardent
   leurs chiffres — la numérotation porte du sens.
   Alignement : léger `margin-inline-start: 0.6em` pour poser la liste
   avec une petite respiration par rapport au bord du paragraphe (sans
   plus la faire hanger dans la gouttière), et `padding-inline-start:
   1.9em` sur les <li> augmente l'espace entre le tiret et le texte. */
.prose ul { list-style: none; padding-inline-start: 0;
            margin: 16px 0; margin-inline-start: 0.6em; }
.prose ul li {
    position: relative;
    padding-inline-start: 1.9em;
    margin-bottom: 6px;
}
.prose ul li::before {
    content: "—";
    position: absolute;
    inset-inline-start: 0;
    top: 0;
    color: var(--gris, #64748b);
    font-weight: 400;
}
.prose ul ul li::before { content: "–"; }   /* niveau imbriqué : tiret court */
.prose table { border-collapse: collapse; width: 100%; }
.prose th, .prose td { border: 1px solid var(--carte-bordure, #e6eaf1); padding: 9px 12px; }
.vide { color: var(--gris, #5a6779); }
.pagination-site { display: flex; gap: 8px; margin-top: 34px; flex-wrap: wrap; }
.page-num {
    text-decoration: none; min-width: 40px; text-align: center; padding: 8px 10px;
    border-radius: var(--rayon-cta, 999px); font-weight: 650; border: 1.5px solid var(--carte-bordure, #e6eaf1); color: inherit;
    transition: border-color .15s ease;
}
.page-num:hover { border-color: var(--c-primaire); }
.page-num.actif { background: var(--c-primaire); color: #fff; border-color: var(--c-primaire); }
.page-404 { text-align: center; padding-top: 90px; padding-bottom: 110px; }
.annuaire-contacts { list-style: none; margin: 12px 0 0; padding: 0; font-size: 14.5px; }
.annuaire-contacts li { margin-bottom: 6px; display: flex; align-items: center; gap: 8px; }
.annuaire-contacts .ico { color: var(--c-primaire); }

/* =====================================================
   Recherche (page /recherche) — mêmes visuels que `.hero-recherche`
   (loupe à gauche, flèche à droite, rayon-cta théme) mais adapté au
   contexte de page (fond `--carte-fond` + couleur `--encre`).
   ===================================================== */
.recherche-form {
    position: relative; display: flex; align-items: center;
    margin-bottom: 30px; max-width: 560px;
}
.recherche-form-loupe {
    position: absolute; left: 18px; top: 50%; transform: translateY(-50%);
    display: inline-flex; align-items: center; justify-content: center;
    color: var(--gris, #64748b); pointer-events: none;
}
.recherche-form input {
    flex: 1; height: 54px; padding: 0 60px 0 52px;
    font-size: 16px; font-weight: 500; font-family: inherit;
    color: var(--encre, #1c2434);
    background: var(--carte-fond, #ffffff);
    border: 1.5px solid var(--carte-bordure, #e6eaf1);
    border-radius: var(--rayon-cta, 999px);
    outline: none;
    transition: border-color .18s ease, box-shadow .18s ease;
}
.recherche-form input::placeholder { color: var(--gris, #94a3b8); opacity: .8; }
.recherche-form input:focus {
    border-color: var(--c-primaire, currentColor);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--c-primaire, currentColor) 20%, transparent);
}
.recherche-form button {
    position: absolute; right: 5px; top: 50%; transform: translateY(-50%);
    width: 44px; height: 44px; padding: 0;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--c-primaire, #2563eb); color: #fff;
    border: 0; border-radius: var(--rayon-cta, 999px); cursor: pointer;
    transition: transform .12s ease, opacity .18s ease;
}
.recherche-form button:hover { transform: translateY(-50%) translateX(2px); }

/* =====================================================
   Formulaire de contact
   ===================================================== */
/* Ancienne grille (compat pour vues non refactorisées) */
.contact-grille { display: grid; grid-template-columns: 1fr 1.4fr; gap: 26px; align-items: start; }
@media (max-width: 820px) { .contact-grille { grid-template-columns: 1fr; } }

/* Nouvelle grille contact — cohérente avec le pattern magazine :
   coordonnées à gauche en liste minimaliste, formulaire à droite sans
   carte encadrée, tout respire. */
.contact-grid {
    display: grid; grid-template-columns: 300px minmax(0, 1fr);
    gap: 64px; align-items: start;
    padding-bottom: 80px;
}
@media (max-width: 1280px) {
    .contact-grid { grid-template-columns: 260px minmax(0, 1fr); gap: 48px; }
}
@media (max-width: 820px) { .contact-grid { grid-template-columns: 1fr; gap: 40px; } }
.contact-coordonnees {
    display: flex; flex-direction: column; gap: 28px;
    position: sticky; top: 90px;
}
@media (max-width: 820px) { .contact-coordonnees { position: static; } }
.contact-coordonnees .cote-etiquette {
    display: inline-flex; align-items: center; gap: 6px;
}
.contact-coordonnees .cote-etiquette .ico { opacity: .7; }
.contact-valeur {
    margin: 0; font-size: 17px; line-height: 1.5; color: var(--encre, #1c2434);
    font-weight: 500;
}
.contact-valeur a { color: inherit; text-decoration: none; }
.contact-valeur a:hover { color: var(--c-primaire, var(--c-liens)); text-decoration: none; }

.contact-form-zone { min-width: 0; }
.contact-form-titre { margin: 0 0 24px; font-size: 22px; font-weight: 650; letter-spacing: -0.01em; }

/* Labels + inputs : typographie 15 px pour la lisibilité tous âges, focus
   qui pop avec ombre douce et bordure d'accent. */
.contact-form label { display: block; font-size: 15px; font-weight: 600; margin-bottom: 5px; }
.contact-form input[type="text"], .contact-form input[type="email"], .contact-form input[type="tel"],
.contact-form input[type="password"], .contact-form input[type="url"], .contact-form input[type="number"],
.contact-form select, .contact-form textarea {
    width: 100%; font: inherit; font-size: 15.5px; padding: 12px 14px;
    /* Suit le rayon CTA choisi par la commune — même valeur que
       .btn-envoyer et les inputs de recherche pour un rendu uniforme. */
    border-radius: var(--rayon-cta, 999px);
    /* Voile blanc 15 % — même pattern que le bloc RGPD juste dessous, marche
       sur toutes les ambiances : sur fond sombre ça éclaircit légèrement le
       champ, sur fond clair c'est presque invisible mais le contraste texte
       reste porté par la couleur du placeholder / du texte saisi qui hérite
       de --section-texte. */
    background: rgba(255, 255, 255, .15);
    color: var(--section-texte, currentColor);
    /* Bordure noir 15 % — visible sur fond clair (où un blanc se
       fondrait) et discrète sur fond sombre. Pattern partagé avec le bloc
       RGPD juste dessous pour une lecture homogène. */
    border: 1px solid rgba(0, 0, 0, .15);
    transition: border-color .15s ease, box-shadow .15s ease;
}
/* Textarea : cap à 1.5rem — un « très arrondi » (999px) sur un bloc
   haut donne des coins qui bouffent le contenu, alors qu'un rayon
   maîtrisé garde l'esprit du choix sans dérailler visuellement. */
.contact-form textarea {
    border-radius: min(var(--rayon-cta, 999px), 1.5rem);
    resize: none; min-height: 140px;
}
.contact-form input:focus, .contact-form textarea:focus {
    border-color: var(--c-primaire, var(--c-liens));
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--c-primaire, var(--c-liens)) 15%, transparent);
    outline: none;
}
.contact-form input::placeholder, .contact-form textarea::placeholder {
    color: var(--section-texte, currentColor); opacity: .55;
}

/* Case RGPD obligatoire — hors flux typographique, aligné haut, texte 14 px */
.contact-consent {
    margin: 6px 0 22px !important;
    /* Mêmes règles que les inputs : voile blanc 15 %, bordure noir 15 %,
       texte hérité du thème. Cohérence visuelle entre les champs et ce bloc
       de consentement qui est fonctionnellement un input coché en plus. */
    background: rgba(255, 255, 255, .15);
    border: 1px solid rgba(0, 0, 0, .15);
    padding: 14px 16px;
    /* Même règle que le textarea : suit le rayon CTA mais cappé à
       1.5rem pour éviter un bloc pill-shape absurde en « très arrondi ». */
    border-radius: min(var(--rayon-cta, 999px), 1.5rem);
    color: var(--section-texte, currentColor);
}
.contact-consent > label {
    display: flex; align-items: flex-start; gap: 10px;
    font-size: 14px; font-weight: 400; line-height: 1.5; cursor: pointer; margin: 0;
    color: inherit;
}
.contact-consent input[type="checkbox"] {
    flex: 0 0 auto; width: 20px; height: 20px; margin: 2px 0 0;
    accent-color: var(--c-primaire, var(--c-liens));
}
.contact-consent a { color: var(--c-primaire, var(--c-liens)); text-decoration: underline; }

/* Bouton envoyer — suit le rayon CTA de la commune (var --rayon-cta),
   pour être uniforme avec les inputs de formulaire et la recherche. */
.btn-envoyer {
    display: inline-flex !important; align-items: center; gap: 10px;
    padding: 13px 26px !important; border: none;
    border-radius: var(--rayon-cta, 999px) !important;
    background: var(--c-primaire, var(--c-liens));
    text-decoration: none !important;   /* jamais souligné, même sur <a> */
    /* `--sur-primaire-accent` est calculé par Couleur::surAccent — texte
       clair sur primaire foncé, texte foncé sur primaire clair (jaunes,
       ambres, pastels). Évite le blanc illisible sur teintes lumineuses. */
    color: var(--sur-primaire-accent, #fff) !important;
    font: inherit; font-weight: 650; font-size: 16px; cursor: pointer;
    transition: transform .18s cubic-bezier(0.4, 0, 0.2, 1),
                box-shadow .18s ease, filter .15s ease;
    box-shadow: 0 2px 8px -2px color-mix(in srgb, var(--c-primaire, var(--c-liens)) 40%, transparent);
}
.btn-envoyer:hover {
    transform: translateY(-1px);
    box-shadow: 0 6px 16px -3px color-mix(in srgb, var(--c-primaire, var(--c-liens)) 45%, transparent);
    filter: none;
}
/* Le glissement au survol est RÉSERVÉ aux flèches vers l'avant, qui se
   placent toujours après le libellé : le mouvement y prolonge le sens du
   picto — « on continue par là ».
   Sur un picto qui PRÉCÈDE le libellé — une coche, un téléchargement, un
   livre ouvert — le même mouvement ne veut rien dire et donne l'impression
   que le bouton se disloque. D'où le ciblage par `data-ico` plutôt que par
   `.ico` : `:last-child` ne suffirait pas, une icône seule en tête de bouton
   est aussi enfant unique, donc dernier enfant. */
.btn-envoyer .ico[data-ico="arrow-right"] { transition: transform .2s ease; }
.btn-envoyer:hover .ico[data-ico="arrow-right"] { transform: translateX(3px); }
.contact-form p { margin: 0 0 14px; }
.form-2col { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
@media (max-width: 560px) { .form-2col { grid-template-columns: 1fr; } }
.hp-field { position: absolute !important; left: -9999px; height: 0; overflow: hidden; }
.form-rgpd { font-size: 12.5px; color: var(--gris, #5a6779); }
.btn-envoyer {
    display: inline-block; padding: 12px 26px; border: none; border-radius: var(--rayon-cta, 999px);
    background: var(--c-primaire); color: var(--sur-primaire-accent, #fff);
    font: inherit; font-weight: 650; font-size: 15.5px;
    cursor: pointer; transition: transform .15s ease, filter .15s ease;
}
.btn-envoyer:hover { filter: brightness(1.08); transform: translateY(-1px); }
.form-retour { display: flex; gap: 10px; align-items: center; padding: 13px 16px; border-radius: calc(var(--rayon) * .55); margin-bottom: 16px; font-weight: 550; }
.form-retour-ok { background: #e5f6ec; color: #166534; }
.form-retour-erreur { background: #fdeaea; color: #b42323; }

/* =====================================================
   Article / Événement : en-tête pleine largeur + grid 2 colonnes ==== */
/* Structure moderne : le titre et son eyebrow occupent toute la largeur en
   tête, PUIS le corps de texte et la sidebar se répartissent en dessous —
   la sidebar s'aligne ainsi avec le premier paragraphe, pas avec le h1.
   Le conteneur commun centre tout dans une bande de largeur raisonnable. */
.page-conteneur {
    max-width: 1380px; margin: 0 auto;
    padding: clamp(24px, 4vw, 40px) clamp(16px, 4vw, 32px) clamp(60px, 8vw, 100px);
}
.landing-liste { margin-top: 24px; }
.landing-liste-secondaire { margin-top: 64px; padding-top: 48px; border-top: 1px solid var(--carte-bordure, #e6eaf1); }
.landing-sous-titre {
    margin: 0 0 24px; font-size: clamp(22px, 2.4vw, 30px);
    font-weight: 650; letter-spacing: -0.01em; color: var(--encre, #1c2434);
}

/* Fil d'Ariane public : discret, en petites lettres, chevron entre étapes.
   Placé juste sous le header et au-dessus du titre. */
.page-conteneur .fil {
    margin: 24px 0 0; font-size: 13px; color: var(--gris, #56606f);
}
.page-conteneur .fil ol {
    display: flex; flex-wrap: wrap; align-items: center; gap: 4px;
    list-style: none; margin: 0; padding: 0;
}
.page-conteneur .fil li { display: inline-flex; align-items: center; gap: 4px; }
.page-conteneur .fil a {
    color: var(--gris, #56606f); text-decoration: none;
    display: inline-flex; align-items: center; gap: 4px;
}
.page-conteneur .fil a:hover { color: var(--c-primaire, var(--c-liens)); text-decoration: none; }
.page-conteneur .fil [aria-current="page"] {
    color: var(--encre, #1c2434); font-weight: 550;
    display: inline-flex; align-items: center; gap: 4px;
    max-width: 60ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.page-conteneur .fil .fil-sep { opacity: .5; display: inline-flex; }
.page-conteneur .fil .ico { opacity: .8; }
/* Compensation optique : le picto « maison » a un centre de gravité
   plus bas que sa boîte englobante (toit en haut), ce qui donne
   l'impression qu'il descend sous la ligne de base. Petit décalage
   négatif de 2 px pour rétablir l'alignement visuel avec le texte. */
.page-conteneur .fil li:first-child .ico { margin-top: -2px; }
.article-entete {
    margin: 40px 0 56px;
    max-width: 960px;
}
.article-eyebrow, .evt-eyebrow {
    margin: 0 0 22px; font-size: 11.5px; font-weight: 700;
    letter-spacing: 1.4px; text-transform: uppercase;
    color: var(--gris, #56606f); display: flex; align-items: center; gap: 10px;
}
/* Titre de type magazine : très grand, très serré, hiérarchie par la
   taille plutôt que par la couleur. */
.article-entete h1 {
    margin: 0 0 22px;
    font-size: clamp(36px, 5.5vw, 72px);
    line-height: 1.05; letter-spacing: -0.03em;
    font-weight: 700;
    color: var(--encre, #1c2434);
}
.article-chapo {
    margin: 0; font-size: 21px; line-height: 1.55; color: var(--gris, #56606f);
    /* Exprimé en `ch` : la mesure suit la police choisie par la commune, là où
       une largeur en pixels donnerait des lignes plus ou moins longues selon
       la fonte. Reste sous l'en-tête qui la contient (1020 px). */
    max-width: 72ch; font-weight: 400;
    /* Équilibre le nombre de mots par ligne : un chapô de trois lignes ne se
       termine plus par une orpheline d'un seul mot. Même traitement que les
       titres et l'intro du hero. */
    text-wrap: balance;
}

/* Hero événement : étiquette colorée + date en gros au-dessus du titre.
   Fond = tint 12 % du primaire de l'ambiance → toujours harmonisé avec la
   palette de la commune (contrairement à `--nav-survol` qui dérivait du
   header et donnait parfois un rendu peachy sur une palette bleue). */
.evt-etiquette {
    display: inline-flex; align-items: center; padding: 4px 12px;
    background: color-mix(in srgb, var(--c-primaire, var(--c-liens)) 12%, transparent);
    color: var(--c-primaire, var(--c-liens));
    border-radius: 999px; font-size: 11px; font-weight: 700;
    letter-spacing: 1.3px; text-transform: uppercase;
}
.evt-etiquette-passe { background: #fef3c7; color: #92400e; }
.evt-date-hero {
    margin: 6px 0 14px; font-size: clamp(22px, 2.6vw, 32px);
    font-weight: 650; color: var(--c-primaire, var(--c-liens));
    font-feature-settings: "tnum"; line-height: 1.2; letter-spacing: -0.01em;
}
.evt-lieu-hero {
    margin: 6px 0 0; font-size: 16px; color: var(--gris, #56606f);
    display: inline-flex; align-items: center; gap: 8px;
}
/* Dans le hero événement, le titre est immédiatement suivi du lieu :
   on resserre la marge basse du h1 pour créer un couple cohérent
   (titre + lieu comme un bloc identifiant), au lieu d'hériter du
   `margin-bottom: clamp(24px, 3vw, 36px)` global de .page-titre. */
.evt-entete .page-titre { margin-bottom: 6px; }
.evt-lieu-hero .ico { opacity: .7; }
.evt-lieu-hero a { color: inherit; text-decoration: none; }
.evt-lieu-hero a:hover { color: var(--c-primaire, currentColor); }

/* Plan interactif (module Cartes) — rendu maplibre-gl. Hauteur fixe
   pour éviter les CLS, ratio légèrement augmenté (400 px au lieu de
   340) pour une lecture plus confortable. `hidden` posé par le JS
   quand le vendor est absent. */
.evt-plan {
    height: 400px; margin: 28px 0 4px;
    border-radius: var(--rayon, 10px);
    overflow: hidden; position: relative;
    border: 1px solid var(--carte-bordure, rgba(15, 23, 42, .08));
    background: #eef1f5;
}
.evt-plan[hidden] { display: none; }
/* Bug Firefox : overflow:hidden + border-radius sur le parent ne clippe
   PAS un canvas WebGL enfant (le compositor GPU ignore le radius). Chrome
   applique naturellement. Correctif portable : appliquer le border-radius
   directement au canvas et à son wrapper MapLibre. Cible générique pour
   toutes nos cartes (`.evt-plan` ponctuelles et `.carte-conteneur` multi). */
.evt-plan .maplibregl-canvas-container,
.evt-plan .maplibregl-canvas,
.carte-conteneur .maplibregl-canvas-container,
.carte-conteneur .maplibregl-canvas {
    border-radius: inherit;
}
/* Bouton « Agrandir » — se glisse dans le groupe de contrôles
   top-right maplibre (à côté du zoom). Icône par défaut = flèches
   d'expansion, remplacée par flèches de repli en mode plein écran. */
.evt-plan-plein-btn { color: #1e293b; }

/* Overlay plein écran — inset 24 px pour la marge autour de la carte,
   fond assombri pour focus visuel. La carte passe en plein cadre
   (position: relative → position: absolute inset: 24px) et maplibre
   se resize automatiquement. */
.evt-plan-overlay {
    position: fixed; inset: 0; z-index: 9998;
    background: rgba(15, 23, 42, .82);
    padding: 24px;
    backdrop-filter: blur(4px);
    animation: evt-plan-in .15s ease-out;
}
@keyframes evt-plan-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}
.evt-plan.evt-plan-plein {
    position: absolute; inset: 24px;
    height: auto; width: auto; margin: 0;
    border-radius: var(--rayon, 12px);
    box-shadow: 0 24px 60px -12px rgba(0, 0, 0, .5);
}
.evt-plan-overlay-fermer {
    position: absolute; top: 12px; right: 12px; z-index: 10;
    width: 40px; height: 40px;
    background: rgba(255, 255, 255, .95); color: #0f172a;
    border: 0; border-radius: 50%; cursor: pointer;
    font-size: 24px; line-height: 1;
    display: flex; align-items: center; justify-content: center;
    box-shadow: 0 4px 12px rgba(0, 0, 0, .3);
    transition: background .12s ease, transform .12s ease;
}
.evt-plan-overlay-fermer:hover {
    background: #ffffff; transform: scale(1.05);
}

/* Contenus WYSIWYG (Trix) rendus côté public — mêmes classes que côté
   admin pour un rendu strictement identique en édition et en lecture.
   Alignement porté par le PARAGRAPHE via `wy-align-*` (Word-like) : la
   figure inline-block suit le text-align de son bloc parent. */
.prose figure.attachment figcaption { display: none; }
/* Alignements paragraphe WYSIWYG en propriétés LOGIQUES : « gauche » et
   « droite » suivent le sens de lecture. En LTR (FR/EN/…) le comportement
   reste identique ; en RTL (AR) « gauche » devient l'alignement de bord
   « début de ligne » (droite visuellement) et « droite » l'inverse. */
.prose .wy-align-gauche { text-align: start; }
.prose .wy-align-centre { text-align: center; }
.prose .wy-align-droite { text-align: end; }
.prose figure { display: inline-block; max-width: 100%; margin: 8px 0; vertical-align: top; }
/* Rayon des images de contenu : `var(--rayon)` = valeur configurée
   par la commune dans Apparence (cohérent avec cartes, boutons, image
   d'en-tête). Fallback à 12px si la variable n'est pas définie. */
.prose figure img { display: block; max-width: 100%; height: auto; border-radius: var(--rayon, 12px); }
.prose img { max-width: 100%; height: auto; border-radius: var(--rayon, 12px); }
/* Séparateur horizontal — teinte adaptative via `currentColor` (auto
   noire sur fond clair, blanche sur fond sombre) à 20 % d'alpha.
   Marges verticales 28 px pour marquer la coupure sans agresser. */
.prose hr {
    border: 0; height: 1px; margin: 28px 0;
    background: color-mix(in srgb, currentColor 20%, transparent);
}
/* Exposant / Indice — 60% + line-height 0 pour ne pas décaler la
   ligne parente (UA défaut fait stretcher la line-height). */
.prose sup, .prose sub {
    font-size: 66%; line-height: 0;
    position: relative; vertical-align: baseline;
}
.prose sup { top: -0.5em; }
.prose sub { top:  0.3em; }
/* Alignement horizontal Quill (classe posée par l'éditeur, préservée
   par le Sanitizer sur p/h2-h4/li/blockquote). */
.prose .ql-align-center  { text-align: center; }
.prose .ql-align-right   { text-align: right; }
.prose .ql-align-justify { text-align: justify; }

/* Vidéo embed (YouTube / Vimeo / Dailymotion) — RGPD strict, la carte
   de consentement est affichée d'entrée, l'iframe n'est chargée qu'au
   clic sur « Regarder la vidéo » (site.js). Ratio 16/9 stable pour
   éviter les CLS pendant le swap carte→iframe. */
.prose .wy-video {
    position: relative; margin: 24px 0; user-select: none;
    aspect-ratio: 16/9; overflow: hidden;
    border-radius: var(--rayon, 12px); background: #0f172a;
}
.prose .wy-video-carte {
    position: absolute; inset: 0;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    padding: 24px; gap: 12px; text-align: center; color: #f8fafc;
    background: linear-gradient(135deg, #1e293b, #0f172a);
}
.prose .wy-video-picto {
    width: 68px; height: 68px; border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    background: rgba(255, 255, 255, .12); color: #f8fafc;
    margin-bottom: 4px;
}
.prose .wy-video-titre {
    margin: 0; font-size: 14px; font-weight: 700; letter-spacing: .3px;
    text-transform: uppercase; color: #cbd5e1;
}
.prose .wy-video-consent {
    margin: 0; font-size: 14px; line-height: 1.55;
    max-width: 52ch; color: #cbd5e1;
}
/* Lien vers la politique de confidentialité de la plateforme — MÊME
   couleur que le texte du consentement, seulement souligné. Le lien
   dorloté sur fond sombre (bleu du .prose a par défaut) créait un
   contraste violent qui hiérarchisait mal le message : le texte de
   consentement est le contenu principal, pas ce lien secondaire. */
.prose .wy-video-consent a {
    color: inherit;
    text-decoration: underline;
    text-underline-offset: 2px;
    text-decoration-thickness: 1px;
}
.prose .wy-video-consent a:hover {
    color: #ffffff;
    text-decoration-thickness: 2px;
}
.prose .wy-video-lire {
    margin-top: 8px; padding: 12px 22px;
    background: #ffffff; color: #0f172a; border: 0; border-radius: 8px;
    font: inherit; font-size: 14.5px; font-weight: 700; cursor: pointer;
    transition: background .12s ease, transform .12s ease;
}
.prose .wy-video-lire:hover { background: #e2e8f0; }
.prose .wy-video-lire:focus-visible {
    outline: 2px solid var(--c-liens, #2563eb); outline-offset: 3px;
}
/* Après clic : le wrapper est vidé et remplacé par une iframe qui
   remplit intégralement le cadre 16/9. */
.prose .wy-video iframe {
    position: absolute; inset: 0; width: 100%; height: 100%; border: 0;
}
/* Version minimaliste (Dailymotion + consentement mémorisé) :
   même fond dégradé et même `.wy-video-picto` que la carte de
   consentement, sans le texte — cohérence visuelle 1:1 avec
   l'état avant clic (le visiteur reconnaît le même point d'action).
   Le rond translucide vient de la règle générique `.wy-video-picto`
   plus haut dans le fichier, on ne re-définit ici que le bouton
   plein cadre et l'effet hover. */
.prose .wy-video .wy-video-play-min {
    position: absolute; inset: 0; width: 100%; height: 100%;
    display: flex; align-items: center; justify-content: center;
    background: linear-gradient(135deg, #1e293b, #0f172a);
    border: 0; padding: 0; cursor: pointer;
    color: #f8fafc;
}
.prose .wy-video .wy-video-play-min .wy-video-picto {
    transition: background .15s ease, transform .15s ease;
}
.prose .wy-video .wy-video-play-min:hover .wy-video-picto {
    background: rgba(255, 255, 255, .22);
    transform: scale(1.06);
}
.prose .wy-video .wy-video-play-min:focus-visible {
    outline: 3px solid #ffffff; outline-offset: -6px;
}
/* Tableau : `border-collapse: collapse` — bordures adjacentes fusionnées
   nativement. Teinte via `color-mix(currentColor, transparent)` —
   s'adapte automatiquement au contexte : text noir (fond clair) →
   bordure noire semi-transparente ; text blanc (fond sombre) →
   bordure blanche semi-transparente. Alpha 15 % pour rester discret. */
.prose table,
.prose table.wy-table {
    border-collapse: collapse;
    width: 100%; margin: 20px 0; font-size: 14.5px;
    /* `table-layout: fixed` : les widths `%` posées sur les cellules
       de la première ligne (via redimensionnement en éditeur) sont
       respectées proportionnellement — le tableau prend 100 % de sa
       colonne, chaque colonne son % relatif. Sans ce fixed, le
       moteur de layout auto ignore les widths et redistribue selon
       le contenu. */
    table-layout: fixed;
}
.prose table th,
.prose table td,
.prose table.wy-table th,
.prose table.wy-table td {
    border: 1px solid color-mix(in srgb, currentColor 15%, transparent);
    padding: 10px 12px;
}
/* td = valign top (contenu ancré haut), th et lignes d'en-tête via
   `wy-th-row` = valign bottom (accroche l'œil au bas de l'entête,
   au ras de la première ligne de données). */
.prose table td { vertical-align: top; }
.prose table th,
.prose table tr.wy-th-row td,
.prose table.wy-table tr.wy-th-row td { vertical-align: bottom; }

/* Coupure des mots longs dans les cellules (toutes tailles). Un URL,
   un mot allemand ou un token sans espace force sinon la colonne à
   déborder de la table (qui elle-même déborde de l'article →
   rupture de layout). `overflow-wrap: anywhere` casse au dernier
   caractère possible ; `hyphens: auto` insère un tiret typographique
   quand la langue du contenu est déclarée. */
.prose table td,
.prose table th,
.prose table.wy-table td,
.prose table.wy-table th {
    overflow-wrap: anywhere;
    word-break: break-word;
    hyphens: auto;
}
.prose table th,
.prose table.wy-table th,
.prose table tr.wy-th-row td,
.prose table tr.wy-th-row th {
    background: var(--section-alt, #f1f5f9);
    font-weight: 600; text-align: left;
}

/* Encarts (info / attention / succès / astuce) — rendu public identique
   à l'aperçu éditeur (mêmes SVG Lucide en data URI, mêmes teintes).
   Peuvent contenir plusieurs paragraphes (pattern Container : le
   `<div class="wy-encart">` enveloppe N `<p>`, gérés par CSS enfant).
   Toujours ≥ 44 px de haut pour cible tactile confortable. */
/* Pattern éditorial : padding généreux du wrapper + reset des marges
   externes du premier/dernier enfant. Les enfants (p, h2, h3, h4,
   table…) gardent leurs marges naturelles entre eux mais ne collent
   pas aux bords du cadre. Rendu prévisible quel que soit le contenu. */
.prose .wy-encart {
    margin: 24px 0; padding: 24px 24px 24px 88px;
    border-radius: var(--rayon, 10px); border-left: 4px solid transparent;
    position: relative;
    min-height: 44px;
}
.prose .wy-encart > *:first-child { margin-top: 0; }
.prose .wy-encart > *:last-child  { margin-bottom: 0; }
/* Force la couleur du type d'encart sur les h2/h3/h4 contenus — sinon
   les rules `.prose h2/h3/h4` reprennent la couleur d'encre par
   défaut et le titre paraît hors-charte dans un encart coloré. */
.prose .wy-encart > * { color: inherit; }
/* Icône alignée en haut, calée sur la première ligne de texte.
   Calcul : padding-top (24px) + demi-line-height (~13px pour 16.5px/1.6)
   − demi-hauteur icône (12px) = 25px du haut du wrapper. */
.prose .wy-encart::before {
    content: ''; position: absolute; left: 22px; top: 25px;
    width: 24px; height: 24px;
    background-repeat: no-repeat; background-size: contain;
}
/* Filet vertical entre picto et contenu — pleine hauteur bord-à-bord. */
.prose .wy-encart::after {
    content: ''; position: absolute;
    left: 66px; top: 0; bottom: 0;
    width: 1px; background: currentColor; opacity: .25;
}
/* Continuité visuelle entre paragraphes encart consécutifs de même
   type : trois `<div class="wy-encart-info">` d'affilée fusionnent
   visuellement en un seul encart à 3 paragraphes. */
.prose .wy-encart-info      + .wy-encart-info,
.prose .wy-encart-attention + .wy-encart-attention,
.prose .wy-encart-succes    + .wy-encart-succes,
.prose .wy-encart-astuce    + .wy-encart-astuce {
    margin-top: 0;
    border-top-left-radius: 0; border-top-right-radius: 0;
    padding-top: 6px;
}
.prose .wy-encart-info:has(+ .wy-encart-info),
.prose .wy-encart-attention:has(+ .wy-encart-attention),
.prose .wy-encart-succes:has(+ .wy-encart-succes),
.prose .wy-encart-astuce:has(+ .wy-encart-astuce) {
    margin-bottom: 0;
    border-bottom-left-radius: 0; border-bottom-right-radius: 0;
    padding-bottom: 6px;
}
.prose .wy-encart-info      + .wy-encart-info::before,
.prose .wy-encart-attention + .wy-encart-attention::before,
.prose .wy-encart-succes    + .wy-encart-succes::before,
.prose .wy-encart-astuce    + .wy-encart-astuce::before {
    display: none;
}
/* Fonds légèrement saturés + alpha .95 — compromis entre bloc vif et
   pastel très pâle : identifiable comme encart mais discret. */
.prose .wy-encart-info      { background: rgba(212, 226, 245, .95); border-left-color: #2563eb; color: #1e3a8a; }
.prose .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>");
}
.prose .wy-encart-attention { background: rgba(246, 232, 199, .95); border-left-color: #ca8a04; color: #713f12; }
.prose .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>");
}
.prose .wy-encart-succes    { background: rgba(207, 235, 217, .95); border-left-color: #16a34a; color: #14532d; }
.prose .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>");
}
.prose .wy-encart-astuce    { background: rgba(228, 214, 240, .95); border-left-color: #9333ea; color: #581c87; }
.prose .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é pour signaler une information
   critique (interdiction, risque). Différencié d'Attention (jaune)
   qui est une simple vigilance. */
.prose .wy-encart-danger    { background: rgba(248, 215, 218, .95); border-left-color: #dc2626; color: #7f1d1d; }
.prose .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>");
}
.prose .wy-encart a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }

/* Lien en mode CTA — bouton d'action mis en valeur. Reprend la couleur
   primaire de la commune (`--c-primaire`) pour rester cohérent avec la
   charte, arrondis via `--rayon` comme les autres CTAs du site. Padding
   généreux pour cible tactile confortable. Ombre discrète pour le
   détacher du flux de lecture sans dominer. */
.prose a.wy-cta {
    display: inline-block; text-decoration: none;
    padding: 12px 24px; margin: 8px 0;
    background: var(--c-primaire, #2563eb); color: #ffffff !important;
    border-radius: var(--rayon-cta, 8px);
    font-weight: 700; font-size: 15px; line-height: 1.3;
    box-shadow: 0 4px 12px -4px rgba(15, 23, 42, .3);
    transition: background .15s ease, transform .1s ease, box-shadow .15s ease;
}
.prose a.wy-cta:hover {
    background: color-mix(in srgb, var(--c-primaire, #2563eb) 88%, #000);
    transform: translateY(-1px);
    box-shadow: 0 6px 16px -4px rgba(15, 23, 42, .4);
}
.prose a.wy-cta:focus-visible {
    outline: 2px solid var(--c-primaire, #2563eb); outline-offset: 3px;
}
/* Dans un encart : le CTA prend la teinte du type d'encart pour ne pas
   dominer la carte. Fond blanc + texte de la teinte du type. */
.prose .wy-encart a.wy-cta {
    background: #ffffff; color: currentColor !important;
    border: 1.5px solid currentColor;
}
.prose .wy-encart a.wy-cta:hover {
    background: currentColor;
    color: #ffffff !important;
}
/* Curseur zoom UNIQUEMENT sur les images qui bénéficient réellement
   d'un agrandissement (facteur ≥ 1.5). La classe est posée par le JS
   à l'événement `load` de chaque image dans .prose — indispensable :
   afficher un curseur « zoom-in » sur une image déjà à taille réelle
   crée une attente qui n'est pas honorée au clic. */
.prose img.wy-zoomable { cursor: zoom-in; }
.prose a img { cursor: pointer; }

/* Lightbox — overlay sombre + image centrée, fermeture au clic hors
   image, à Échap ou sur la croix. Pas de dépendance JS externe. */
.wy-lightbox {
    position: fixed; inset: 0; z-index: 9999;
    background: rgba(0, 0, 0, .82);
    display: flex; align-items: center; justify-content: center;
    padding: 32px;
    animation: wy-lightbox-in .18s ease-out;
}
.wy-lightbox img {
    max-width: 100%; max-height: 100%;
    border-radius: 6px;
    box-shadow: 0 20px 60px -12px rgba(0, 0, 0, .5);
}
.wy-lightbox-fermer {
    position: absolute; top: 20px; right: 24px;
    width: 40px; height: 40px; border-radius: 999px;
    border: 0; background: rgba(255, 255, 255, .12);
    color: #fff; font-size: 22px; cursor: pointer;
    display: inline-flex; align-items: center; justify-content: center;
    transition: background .15s ease;
}
.wy-lightbox-fermer:hover { background: rgba(255, 255, 255, .22); }
@keyframes wy-lightbox-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

/* CTA « Ajouter à mon agenda » — pastille pleine largeur en pied de
   sidebar, très cliquable au pouce sur mobile. Couleur primaire de
   l'ambiance + texte calculé WCAG (--sur-primaire) pour le contraste. */
/* Wrapper des CTA événement — regroupe « Ajouter à mon agenda » et
   « Réserver / s'inscrire » dans un même bloc, avec un gap resserré
   propre. Le parent `.article-cote` garde son gap de 32 px entre ce
   bloc et les autres sections de la sidebar (partager, etc.). */
.evt-ctas { display: flex; flex-direction: column; gap: 10px; }

/* CTA « Ajouter à mon agenda » — utilise `--sur-primaire-accent` (biais
   vers le blanc sur aplats colorés, contraste 3:1 minimum). Sur les
   teintes très claires où le blanc ne passe pas, retombe automatiquement
   sur l'encre grâce à Couleur::surAccent. */
.evt-ajout-agenda {
    display: flex; align-items: center; gap: 14px;
    padding: 14px 18px;
    background: var(--c-primaire, #2563eb);
    color: var(--sur-primaire-accent, #ffffff);
    /* Bordure transparente pour s'aligner exactement sur la hauteur du
       CTA billetterie qui, lui, porte une bordure visible de 1.5 px. */
    border: 1.5px solid transparent;
    border-radius: var(--rayon, 12px);
    text-decoration: none;
    box-shadow: 0 6px 18px -6px color-mix(in srgb, var(--c-primaire, #2563eb) 60%, transparent);
    transition: transform .15s ease, box-shadow .15s ease;
}
.evt-ajout-agenda:hover {
    transform: translateY(-2px);
    box-shadow: 0 10px 24px -6px color-mix(in srgb, var(--c-primaire, #2563eb) 70%, transparent);
    text-decoration: none; color: var(--sur-primaire-accent, #ffffff);
}
.evt-ajout-agenda-picto {
    flex-shrink: 0;
    display: inline-flex; align-items: center; justify-content: center;
    width: 40px; height: 40px; border-radius: 999px;
    background: color-mix(in srgb, var(--sur-primaire-accent, #ffffff) 22%, transparent);
}
.evt-ajout-agenda-texte {
    display: flex; flex-direction: column; gap: 2px;
    line-height: 1.25; min-width: 0;
}
.evt-ajout-agenda-texte strong { font-size: 15.5px; font-weight: 650; }
.evt-ajout-agenda-texte span {
    font-size: 12.5px;
    color: color-mix(in srgb, var(--sur-primaire-accent, #ffffff) 80%, transparent);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* CTA « Billetterie / inscription » — variante ghost sous le CTA agenda,
   bordure primaire + fond neutre pour ne pas doubler le fort visuel de
   la première pastille. Hover : léger tint de la primaire. */
.evt-billeterie {
    display: flex; align-items: center; gap: 14px;
    padding: 14px 18px;
    background: transparent;
    color: var(--c-primaire, #2563eb);
    border: 1.5px solid var(--c-primaire, #2563eb);
    border-radius: var(--rayon, 12px);
    text-decoration: none;
    transition: background .15s ease, transform .15s ease;
}
.evt-billeterie-texte span {
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.evt-billeterie:hover {
    transform: translateY(-2px);
    background: color-mix(in srgb, var(--c-primaire, #2563eb) 10%, transparent);
    text-decoration: none; color: var(--c-primaire, #2563eb);
}
.evt-billeterie-picto {
    flex-shrink: 0;
    display: inline-flex; align-items: center; justify-content: center;
    width: 40px; height: 40px; border-radius: 999px;
    background: color-mix(in srgb, var(--c-primaire, #2563eb) 12%, transparent);
}
.evt-billeterie-texte {
    display: flex; flex-direction: column; gap: 2px;
    line-height: 1.25; min-width: 0;
}
.evt-billeterie-texte strong { font-size: 15.5px; font-weight: 650; }
.evt-billeterie-texte span {
    font-size: 12.5px;
    color: color-mix(in srgb, var(--c-primaire, #2563eb) 80%, transparent);
}

/* Cartes des pages portail — visuel placeholder si aucune image, et
   suppression du soulignement de titre (le <a> englobe toute la carte
   → hériterait autrement du soulignement de la règle `a` globale). */
.carte-portail { text-decoration: none; color: inherit; display: block; }
.carte-portail:hover { text-decoration: none; }
.carte-portail h3 { text-decoration: none; }
.carte-portail-vide {
    aspect-ratio: 16/9;
    display: flex; align-items: center; justify-content: center;
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--c-primaire, #64748b) 15%, transparent),
        color-mix(in srgb, var(--c-primaire, #64748b) 5%, transparent));
    color: color-mix(in srgb, var(--c-primaire, #64748b) 55%, transparent);
}
.carte-portail-vide .ico { opacity: .8; }

/* Grille 2 colonnes SOUS l'en-tête : corps + sidebar */
/* Annuaire — variantes carte avec photo, fiche détaillée */
.carte-annuaire {
    /* la carte est un <a> pour être cliquable en entier — on neutralise
       le décor de lien natif et on garde le style carte du thème. */
    display: block; text-decoration: none; color: inherit;
    transition: transform .18s ease, box-shadow .18s ease;
    overflow: hidden;
}
.carte-annuaire:hover {
    transform: translateY(-3px);
    box-shadow: 0 10px 24px -8px rgba(15, 23, 42, .18);
}
.carte-image-annuaire {
    width: 100%; aspect-ratio: 16 / 10; object-fit: cover;
    display: block;
}
/* Placeholder pour les cartes sans photo — dégradé subtil de la
   couleur d'accent + picto de la catégorie centré. Garde la même
   emprise que .carte-image-annuaire pour ne pas casser le rythme. */
.carte-image-annuaire-vide {
    width: 100%; aspect-ratio: 16 / 10;
    display: flex; align-items: center; justify-content: center;
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--c-primaire, #64748b) 18%, transparent),
        color-mix(in srgb, var(--c-primaire, #64748b)  6%, transparent));
    color: color-mix(in srgb, var(--c-primaire, #64748b) 60%, transparent);
}
.carte-image-annuaire-vide .ico { width: 36px; height: 36px; opacity: .75; }

/* Docuthèque publique — items empilés, un document téléchargeable
   par ligne. Rendu minimaliste, aligné sur la charte du site.
   Le layout (sidebar filtres + contenu) reprend celui de l'annuaire :
   grille 2 colonnes en large, empilée sur mobile. */
.documents-layout {
    display: grid; grid-template-columns: 240px minmax(0, 1fr);
    gap: 40px; align-items: start;
}
@media (max-width: 820px) {
    .documents-layout { grid-template-columns: 1fr; gap: 24px; }
}
.documents-groupe + .documents-groupe { margin-top: 24px; }

/* Docuthèque : liste verticale de lignes-cartes. Le décor (ombre /
   bordure / plat / fond alterné) est celui du thème via `.document-ligne`
   ajouté au sélecteur de base commun avec `.actu-ligne` / `.event-ligne`
   — même mécanique, aucune règle spécifique à dupliquer. */
.documents-liste { display: flex; flex-direction: column; gap: 10px; }
/* Une ligne = grille [lien téléchargement | bouton info] ; le panel
   description (quand il existe) s'insère en dessous sur toute la largeur.
   Les variantes de décor du thème s'appliquent au conteneur externe. */
.document-ligne {
    display: grid; grid-template-columns: 1fr auto;
    border-radius: var(--rayon);
    transition: transform .2s ease, box-shadow .2s ease, border-color .2s ease;
    overflow: hidden;
}
.cartes-ombre .document-ligne { box-shadow: 0 2px 10px -2px rgba(15, 23, 42, .08); }
.cartes-ombre .document-ligne:hover { box-shadow: 0 10px 26px -6px rgba(15, 23, 42, .16); }
.cartes-bordure .document-ligne { border: 1.5px solid var(--sur-carte-bordure); }
.cartes-bordure .document-ligne:hover { border-color: var(--c-primaire); }
/* Lien principal — occupe la 1ʳᵉ colonne, absorbe le clic de téléchargement. */
.document-lien {
    grid-column: 1;
    display: flex; align-items: center; gap: 18px;
    padding: 14px 20px; text-decoration: none; color: inherit;
    min-width: 0;
}
.document-lien:hover { text-decoration: none; }
/* Bouton info : discret par défaut, s'anime au hover. Sépare visuellement
   son action (afficher la description) du lien de téléchargement voisin.
   `grid-row: 1 / span 2` : couvre le lien ET la description dépliée
   (la rangée implicite du panel a 0 px de haut quand `hidden`). */
.document-info {
    grid-column: 2; grid-row: 1 / span 2;
    background: transparent; border: 0; cursor: pointer;
    padding: 0 16px; align-self: stretch;
    display: inline-flex; align-items: center; justify-content: center;
    color: var(--sur-carte-gris, #64748b);
    transition: color .12s ease, background .12s ease;
    border-left: 1px solid color-mix(in srgb, var(--sur-carte-bordure, currentColor) 40%, transparent);
}
.document-info:hover,
.document-info[aria-expanded="true"] {
    color: var(--c-primaire, currentColor);
    background: color-mix(in srgb, var(--c-primaire, currentColor) 6%, transparent);
}
.document-info[aria-expanded="true"] .ico { transform: rotate(180deg); }
.document-info .ico { transition: transform .18s ease; }
/* Panel description : sous le lien de téléchargement, aligné visuellement
   sur le titre (padding-left calculé sur la vignette + gap + padding).
   Reste en col 1 : le bouton info couvre déjà la col 2 sur toute la hauteur. */
.document-desc {
    grid-column: 1;
    padding: 12px 20px 14px 86px;
    font-size: 14px; line-height: 1.55;
    color: var(--sur-carte-gris, #64748b);
    border-top: 1px solid color-mix(in srgb, var(--sur-carte-bordure, currentColor) 30%, transparent);
}
@media (max-width: 560px) {
    .document-desc { padding-left: 20px; }
}

/* Vignette carrée à gauche : picto + micro badge d'extension en dessous. */
.document-picto {
    flex-shrink: 0; position: relative;
    width: 48px; height: 48px;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 10px;
    background: color-mix(in srgb, var(--c-primaire, #64748b) 12%, transparent);
    color: var(--c-primaire, #64748b);
}
.document-ext {
    position: absolute; bottom: -6px; right: -6px;
    padding: 1px 6px; border-radius: 999px;
    background: var(--c-primaire, #334155); color: #fff;
    font-size: 9.5px; font-weight: 700; letter-spacing: .04em;
    line-height: 1.4;
}
.document-corps { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.document-titre { font-size: 15.5px; }
.document-meta {
    display: inline-flex; align-items: center; flex-wrap: wrap; gap: 4px 8px;
    margin-top: 2px;
    font-size: 12.5px; color: var(--sur-carte-gris, #64748b);
}
.document-meta .ico { opacity: .8; }
.document-action { flex-shrink: 0; color: var(--sur-carte-gris, #64748b); transition: color .12s ease; }
.document-ligne:hover .document-action { color: var(--c-primaire, currentColor); }


/* Templates d'affichage annuaire (choix Apparence — 4 variantes) :
   la classe wrapper `.annuaire-style-*` module le layout des cartes,
   la structure HTML reste unique. */

/* CARTES PLATES : mêmes cartes en grille mais sans zone image. */
.annuaire-style-cartes-plates .carte-image-annuaire,
.annuaire-style-cartes-plates .carte-image-annuaire-vide { display: none; }

/* LISTE (avec ou sans photo) : passe la grille en une seule colonne,
   chaque carte devient une ligne horizontale pleine largeur. */
.annuaire-style-liste .cartes,
.annuaire-style-liste-photo .cartes {
    display: flex; flex-direction: column; gap: 10px;
    grid-template-columns: none;
}
.annuaire-style-liste .carte-annuaire,
.annuaire-style-liste-photo .carte-annuaire {
    display: flex; flex-direction: row; align-items: stretch;
}
.annuaire-style-liste .carte-annuaire:hover,
.annuaire-style-liste-photo .carte-annuaire:hover {
    transform: translateX(3px);   /* décalage horizontal — plus adapté au format ligne */
}
.annuaire-style-liste .carte-corps,
.annuaire-style-liste-photo .carte-corps { padding: 14px 18px; flex: 1; }

/* LISTE seule : masque la zone image, plus dense. */
.annuaire-style-liste .carte-image-annuaire,
.annuaire-style-liste .carte-image-annuaire-vide { display: none; }

/* En mode liste (compacte ou avec photo), on gagne de la largeur : on
   met téléphone + email sur DEUX colonnes, et l'adresse — souvent plus
   longue — passe pleine largeur en dessous. Sur mobile, retour empilé. */
.annuaire-style-liste .annuaire-contacts,
.annuaire-style-liste-photo .annuaire-contacts {
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 4px 24px;
}
.annuaire-style-liste .annuaire-contacts li,
.annuaire-style-liste-photo .annuaire-contacts li { margin-bottom: 0; }
.annuaire-style-liste .annuaire-contacts .ac-adresse,
.annuaire-style-liste-photo .annuaire-contacts .ac-adresse { grid-column: 1 / -1; }
@media (max-width: 560px) {
    .annuaire-style-liste .annuaire-contacts,
    .annuaire-style-liste-photo .annuaire-contacts { grid-template-columns: 1fr; gap: 4px 0; }
}

/* LISTE AVEC PHOTO : petite vignette carrée à gauche. */
.annuaire-style-liste-photo .carte-image-annuaire,
.annuaire-style-liste-photo .carte-image-annuaire-vide {
    width: 120px; height: auto; aspect-ratio: 1 / 1;
    flex-shrink: 0; align-self: stretch;
}
@media (max-width: 560px) {
    .annuaire-style-liste-photo .carte-image-annuaire,
    .annuaire-style-liste-photo .carte-image-annuaire-vide { width: 88px; }
}

/* Fiche détaillée : fil d'ariane discret au-dessus du titre + bloc
   contact latéral façon vCard. */
.fil-ariane { font-size: 13.5px; color: var(--gris, #64748b); margin: 4px 0 12px; }
.fil-ariane a { color: inherit; text-decoration: none; }
.fil-ariane a:hover { color: var(--c-primaire); text-decoration: underline; }

.carte-contact {
    background: var(--carte-fond, #f8fafc);
    border: 1px solid var(--carte-bordure, rgba(15, 23, 42, .08));
    border-radius: var(--rayon, 12px);
    padding: 20px 22px;
}
.carte-contact h2 { margin: 0 0 14px; font-size: 17px; }
.contact-liste { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 12px; font-size: 14.5px; }
.contact-liste li { display: flex; align-items: flex-start; gap: 10px; line-height: 1.45; }
.contact-liste li .ico { flex-shrink: 0; margin-top: 2px; color: var(--c-primaire); }
.contact-liste a { color: inherit; text-decoration: none; }
.contact-liste a:hover { color: var(--c-primaire); text-decoration: underline; }

.article-grid {
    display: grid; grid-template-columns: minmax(0, 1fr) 300px;
    gap: 56px; align-items: start;
    padding-bottom: 60px;
}
@media (max-width: 1280px) {
    .article-grid { grid-template-columns: minmax(0, 1fr) 260px; gap: 44px; }
}
@media (max-width: 900px) {
    .article-grid { grid-template-columns: 1fr; gap: 40px; }
}
.article-corps { min-width: 0; }
.article-corps .article-image {
    width: 100%; height: auto; margin: 0 0 24px; display: block;
    /* Rayon issu de la config Apparence de la commune — cohérent avec
       les cartes, boutons et autres éléments arrondis du site. */
    border-radius: var(--rayon, 12px);
}
/* Cap éditorial à 920 px : compromis entre confort de lecture (une
   ligne trop longue fatigue) et occupation de la colonne (une ligne
   trop courte fait ressembler la page à un mémo). Cette valeur est
   partagée avec l'éditeur admin (.wysiwyg .ql-editor) pour un WYSIWYG
   fidèle — ce que le rédacteur voit dans l'éditeur = ce que le
   visiteur voit sur le site. */
.article-corps .prose {
    font-size: 16.5px; line-height: 1.75; color: var(--encre, #1c2434);
    max-width: 920px;
}
.article-corps .prose p { margin: 0 0 18px; }
/* Marges basses ≥ marge entre paragraphes (18px) : sans ça la
   respiration sous un titre est plus petite que celle entre deux
   paragraphes, ce qui inverse la hiérarchie visuelle. */
.article-corps .prose h2 { font-size: 26px; margin: 32px 0 20px; }
.article-corps .prose h3 { font-size: 21px; margin: 26px 0 18px; }
.article-corps .prose h4 { font-size: 18px; margin: 22px 0 18px; }

/* Colonne latérale UNIFIÉE : uniquement des « groupes » minimalistes,
   étiquette majuscule espacée + contenu compact. Zéro carte encadrée,
   zéro variation typographique. La cohérence vient de l'uniformité. */
.article-cote {
    display: flex; flex-direction: column; gap: 32px;
    position: sticky; top: 90px;
}
@media (max-width: 900px) { .article-cote { position: static; } }

.cote-groupe { display: flex; flex-direction: column; gap: 12px; }
/* CTA sidebar « Aller au formulaire » : bouton pleine largeur qui
   scroll doux vers l'ancre `#formulaire-{id}`. Style aligné sur les
   CTAs de partage — reprend `--c-primaire` de la commune. */
.cote-cta {
    display: flex; align-items: center; gap: 10px;
    padding: 12px 18px;
    background: var(--c-primaire, #2563eb);
    color: var(--sur-primaire-accent, #fff) !important;
    /* Rayon issu de la config Apparence de la commune, comme les autres
       CTAs (bouton envoyer, recherche…). */
    border-radius: var(--rayon-cta, 999px);
    font-weight: 600; font-size: 14.5px;
    text-decoration: none;
    transition: transform .12s ease, box-shadow .18s ease;
}
.cote-cta > span {
    flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cote-cta:hover {
    transform: translateY(-1px);
    box-shadow: 0 10px 24px -12px color-mix(in srgb, var(--c-primaire, #2563eb) 60%, transparent);
}
.cote-etiquette {
    font-size: 11px; font-weight: 700; letter-spacing: 1.2px;
    text-transform: uppercase; color: var(--gris, #56606f);
    padding-bottom: 8px; border-bottom: 1px solid var(--carte-bordure, #e6eaf1);
}
.partager-pastilles { display: flex; flex-wrap: wrap; gap: 8px; }
.partager-pastille {
    display: inline-flex; align-items: center; justify-content: center;
    width: 42px; height: 42px; padding: 0;
    border: 0; border-radius: 999px;
    /* Fond ambient : le fond alterné de l'ambiance (--section-alt),
       toujours très légèrement teinté de la couleur d'accent choisie par la
       commune. Ainsi la pastille ne « flotte » plus hors ambiance. */
    background: var(--section-alt, #eef2f7); color: var(--c-primaire, #56606f);
    font: inherit; cursor: pointer; text-decoration: none;
    position: relative;
    transition: color .15s ease, background .15s ease, transform .12s ease;
}
.partager-pastille:hover {
    text-decoration: none; transform: translateY(-2px);
    /* Petit renforcement du fond ambient, sans couleur de marque — reste
       dans la palette de la commune. */
    background: color-mix(in srgb, currentColor 14%, transparent);
}
.partager-pastille .ico { flex: 0 0 auto; }
/* Retour visuel « Copié ! » — bulle temporaire lue par ::after depuis
   data-feedback, apparaît seulement pendant les 2 s post-clic. */
.partager-pastille[data-feedback]::after {
    content: attr(data-feedback);
    position: absolute; bottom: calc(100% + 8px); left: 50%; transform: translateX(-50%);
    background: #0f172a; color: #fff; padding: 4px 8px; border-radius: 6px;
    font-size: 11.5px; font-weight: 500; white-space: nowrap; pointer-events: none;
    opacity: 1;
}
.partager-copier.est-copie {
    color: #fff; background: #16a34a;
}

/* Bloc « événement » de la colonne latérale : rappel date/lieu à côté du texte */
.cote-ligne { display: flex; gap: 8px; align-items: baseline; margin: 0 0 10px; font-size: 14.5px; }
.cote-ligne .ico { position: relative; top: 2px; opacity: .65; flex: 0 0 auto; }
.cote-ligne strong { color: var(--encre, #1c2434); font-weight: 650; }
.cote-note {
    display: flex; gap: 6px; align-items: baseline; margin: 12px 0 0;
    padding-top: 12px; border-top: 1px solid var(--carte-bordure, #e6eaf1);
    color: var(--gris, #56606f); font-size: 13px;
}
.cote-note .ico { opacity: .55; }

/* Bloc « À lire aussi » : liste d'actualités connexes, format compact */
.cote-aussi-liste { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; }
.cote-aussi-lien {
    display: block; padding: 10px 12px; margin: 0 -12px;
    border-radius: 10px; text-decoration: none;
    transition: background .15s ease;
}
.cote-aussi-lien:hover {
    /* Tint 10 % du primaire — reste dans la palette de l'ambiance, ne
       dépend pas du header. */
    background: color-mix(in srgb, var(--c-primaire, var(--c-liens)) 10%, transparent);
    text-decoration: none;
}
.cote-aussi-titre {
    display: block; font-size: 14px; font-weight: 600;
    color: var(--encre, #1c2434); line-height: 1.35;
}
.cote-aussi-date {
    display: block; margin-top: 3px;
    font-size: 12px; color: var(--gris, #56606f);
}

/* =====================================================
   Bandeau « aperçu d'un brouillon » ==================== */
/* Injecté sur toute vue publique quand ?preview=xxx est valide. Volontairement
   voyant (ambre) : celui qui a le lien doit voir qu'il ne consulte pas la
   version publique. */
/* Bandeau « Aperçu d'un brouillon » — fixe en bas de fenêtre pour ne
   plus recouvrir le contenu, avec un bouton × pour le masquer sur la
   page courante (aucune persistance : c'est un rappel de contexte). */
.bandeau-brouillon {
    position: fixed; left: 12px; right: 12px; bottom: 12px;
    z-index: 90;
    display: flex; align-items: center; gap: 12px;
    background: #fef3c7; color: #78350f;
    border-left: 4px solid #f59e0b;
    padding: 12px 14px 12px 16px; border-radius: 10px;
    box-shadow: 0 12px 32px -10px rgba(15, 23, 42, .28);
    font-size: 14px; font-weight: 500;
    max-width: 720px; margin: 0 auto;
    animation: bandeau-brouillon-apparaitre .28s ease-out both;
}
.bandeau-brouillon .ico { flex: 0 0 auto; color: #b45309; }
.bandeau-brouillon > span { flex: 1; line-height: 1.4; }
.bandeau-brouillon-fermer {
    flex-shrink: 0; padding: 4px; margin: -4px;
    background: transparent; border: 0; cursor: pointer;
    color: #78350f; border-radius: 6px;
    display: inline-flex; align-items: center; justify-content: center;
    transition: background .15s ease;
}
.bandeau-brouillon-fermer:hover { background: rgba(180, 83, 9, .12); }
.bandeau-brouillon[hidden] { display: none; }
@keyframes bandeau-brouillon-apparaitre {
    from { transform: translateY(20px); opacity: 0; }
    to   { transform: translateY(0);    opacity: 1; }
}

/* =====================================================
   Pied de page
   ===================================================== */
/* Le texte s'adapte à la luminance du fond choisi (clair comme sombre) */
.site-footer {
    background: var(--c-footer); color: var(--footer-attenue, rgba(255, 255, 255, .82));
    margin: 0; padding: 1px 0 0;
}
.footer-grille {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 30px;
    padding-top: 68px; padding-bottom: 48px;
}
.footer-grille p { margin: 6px 0; font-size: 14.5px; line-height: 1.6; }
.footer-ligne { display: flex; gap: 9px; align-items: baseline; }
.footer-ligne .ico { position: relative; top: 2px; opacity: .65; }
.footer-titre {
    font-weight: 700; color: var(--footer-texte, #fff); margin-bottom: 12px;
    font-size: 16px; font-family: var(--police-titres);
    /* Équilibre les lignes quand un nom de commune long fait wrapper
       « Mairie de X ». Sans balance, une orpheline d'un mot pouvait
       traîner en fin de titre. */
    text-wrap: balance;
}
/* Colonne « Suivez-nous » : pastilles rondes, sobres — le pastille reste
   dans la teinte du pied de page au survol (petit relèvement pour le retour
   d'appui), et le picto est plus généreux qu'un bouton d'icône classique
   pour la lisibilité même sur écran mobile. */
.footer-rs { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 10px; }
.footer-rs-pastille {
    display: inline-flex; align-items: center; justify-content: center;
    width: 42px; height: 42px; border-radius: 999px;
    background: color-mix(in srgb, currentColor 8%, transparent);
    color: var(--footer-attenue, rgba(255, 255, 255, .82));
    text-decoration: none; position: relative;
    transition: background .15s ease, transform .12s ease;
}
.footer-rs-pastille svg { width: 22px; height: 22px; }
.footer-rs-pastille:hover {
    transform: translateY(-2px);
    background: color-mix(in srgb, currentColor 14%, transparent);
    text-decoration: none;
}
.footer-rs-pastille[data-tooltip]::after {
    content: attr(data-tooltip);
    position: absolute; bottom: calc(100% + 6px); left: 50%; transform: translateX(-50%);
    background: #0f172a; color: #fff; padding: 4px 8px; border-radius: 6px;
    font-size: 11.5px; font-weight: 500; white-space: nowrap; pointer-events: none;
    opacity: 0; transition: opacity .12s ease;
}
.footer-rs-pastille:hover::after, .footer-rs-pastille:focus-visible::after { opacity: 1; }

.footer-liens { list-style: none; margin: 0; padding: 0; }
.footer-liens li { margin-bottom: 8px; font-size: 13.5px; }
/* Liens du footer : discrets par défaut, soulignés seulement au survol.
   Un footer d'institution n'a pas besoin d'appeler l'attention comme un
   texte courant — le soulignement systématique brouille la hiérarchie. */
.footer-liens a, .site-footer a {
    color: var(--footer-attenue, rgba(255, 255, 255, .82));
    text-decoration: none;
    font-size: 13.5px;
}
.footer-liens a:hover, .site-footer a:hover {
    color: var(--footer-texte, #fff);
    text-decoration: underline;
    text-underline-offset: 3px;
}
/* Lien d'appel à l'action « Nous écrire » sous les coordonnées de la mairie */
.footer-cta { margin-top: 12px !important; }
.footer-cta a {
    display: inline-flex; align-items: center; gap: 6px;
    color: var(--footer-texte, #fff) !important; font-weight: 550;
    text-decoration: none;
}
.footer-cta a:hover { text-decoration: underline; text-underline-offset: 3px; }
.footer-cta .ico { opacity: .85; }
/* Le filet s'aligne sur le TEXTE, pas sur la bande.
   Il ne peut donc pas être une `border` : une bordure couvre toujours la
   boîte entière, padding compris, et dépasserait des colonnes de 24 px de
   chaque côté. D'où le `::before`, posé à l'intérieur du padding — dont il
   reprend la valeur par `--conteneur-pad` au lieu de la recopier, pour que
   les deux restent solidaires si la mesure change. */
.footer-filet-cale { position: relative; }
.footer-filet-cale::before {
    content: ""; position: absolute; top: 0;
    left: var(--conteneur-pad); right: var(--conteneur-pad);
    border-top: 1px solid var(--footer-filet, rgba(255, 255, 255, .12));
}
.footer-bas {
    padding: 0; font-size: 13px;
    color: var(--footer-discret, rgba(255, 255, 255, .55));
}
.footer-bas > .conteneur { padding-top: 30px; padding-bottom: 30px; }
.footer-bas strong { color: var(--footer-attenue, #fff); }

/* Bande partenaires — juste au-dessus du bandeau légal, logos en ligne
   centrés, wrap sur petits écrans.
   AUCUN fond propre : un aplat plus clair courant sur toute la largeur
   découpait le pied de page en bandes horizontales et faisait ressortir les
   logos comme un encart rapporté. Même règle que `.footer-bas` pour le
   filet — porté par le conteneur intérieur, donc borné à la mesure. */
.footer-partenaires { padding: 0; }
.footer-partenaires-inner {
    display: flex; align-items: center; justify-content: center; flex-wrap: wrap;
    gap: 28px; padding: 32px var(--conteneur-pad);
}
.footer-partenaire {
    display: inline-flex; align-items: center; justify-content: center;
    max-height: 72px;
    transition: transform .15s ease, opacity .15s ease;
    opacity: .88;
}
.footer-partenaire:hover { opacity: 1; transform: translateY(-1px); }
.footer-partenaire img {
    max-height: 68px; max-width: 190px;
    object-fit: contain;
    display: block;
    /* Uniformise les logos disparates : conversion en teinte claire sur
       fond sombre. La mairie peut aussi importer des logos monochromes
       directement pour un rendu plus net. */
    filter: brightness(1) contrast(1);
}

/* =====================================================
   Responsive
   ===================================================== */
@media (max-width: 900px) {
    .site-header { --header-h: 66px; }
    .site-logo { height: 42px; }
    .site-nom { font-size: 18px; }
    .header-grid { flex-wrap: nowrap; min-height: var(--header-h); padding-top: 0; padding-bottom: 0; }
    .menu-burger { display: block; order: 2; margin-right: -8px; }
    .site-marque { order: 1; }

    /* Menu mobile : panneau plein écran en overlay fixe, AU-DESSUS de tout
       le contenu (hero, alertes, cartes). Le z-index doit dépasser tous les
       éléments possibles de la page — 300 laisse la marge pour un dialogue
       modal éventuel (accessibilité, cookies) qui reste au sommet.
       Hauteur : `dvh` (dynamic viewport) pour tenir compte de la barre
       d'adresse mobile qui se rétracte au scroll, avec repli `vh` pour les
       vieux navigateurs. Sans ça, le panneau se limitait à la hauteur de
       ses enfants et n'occupait qu'une bande étroite. */
    /* Menu mobile simplifié — 2 cas seulement :
         - site clair (--c-header clair) → menu clair, texte foncé
         - site sombre (--c-header foncé) → menu sombre, texte clair
       Le fond du menu prend simplement la couleur du header, et
       le texte hérite via `--nav-texte` (déjà calculé par thème).
       Résultat : cohérence visuelle, plus d'overrides multiples,
       lisibilité garantie quel que soit le mode. */
    .header-right {
        display: none; order: 3;
        position: fixed; top: var(--header-h); left: 0; right: 0; z-index: 300;
        height: calc(100vh - var(--header-h));
        height: calc(100dvh - var(--header-h));
        background: var(--c-header, #fff);
        color: var(--nav-texte);
        overflow-y: auto; overscroll-behavior: contain;
        padding: 14px 24px calc(28px + env(safe-area-inset-bottom, 0px));
        align-items: stretch; gap: 4px;
        /* Le panneau glisse via `left`/`right` — PAS de `transform`, sinon
           .nav-sousmenu (position: fixed) prendrait le panneau pour
           containing block au lieu du viewport. */
        transition: left .28s cubic-bezier(0.4, 0, 0.2, 1),
                    right .28s cubic-bezier(0.4, 0, 0.2, 1);
    }
    .header-right.a-un-sousmenu {
        left: -100%; right: 100%;
    }
    /* Le header reste au-dessus du panneau pour que le burger reste
       cliquable et pour matérialiser la continuité header/menu. */
    .site-header { z-index: 310; }
    .menu-toggle:checked ~ .header-right { display: flex; }
    /* Le fond de page ne défile plus derrière le panneau ouvert. */
    body:has(.menu-toggle:checked) { overflow: hidden; }

    /* Menu ouvert → header FORCÉ en état posé (fond solide, texte
       encre lisible sur le panneau clair/sombre en dessous). Ceci
       remplace tout le stack d'overrides hero-superpose : une seule
       règle simple qui déclenche dès que le menu est checked.
       `position: fixed` (au lieu de sticky) : quand `body { overflow:
       hidden }` s'active pour bloquer le scroll d'arrière-plan, le
       sticky perd son ancrage. Fixed garantit que le header reste
       épinglé en haut, au-dessus du panneau menu. */
    body:has(.menu-toggle:checked) .site-header {
        background: var(--c-header, #fff);
        backdrop-filter: none; -webkit-backdrop-filter: none;
        position: fixed; top: 0; left: 0; right: 0;
        /* Header et panneau partagent le même fond (--c-header) : sans
           séparation nette, l'œil les confond. On renforce le filet et
           on ajoute une ombre portée douce pour matérialiser le fait que
           le header repose SUR le panneau. Filet et ombre sont dérivés
           de --nav-texte pour rester lisibles dans les deux thèmes. */
        border-bottom-color: color-mix(in srgb, var(--nav-texte, #1c2434) 22%, transparent);
        box-shadow: 0 6px 16px -10px color-mix(in srgb, var(--nav-texte, #1c2434) 55%, transparent);
        /* Bumpé de 310 à 500 : dépasser toute couche fixe potentielle
           (sous-menu z-305, alertes, cartes) — le burger doit rester
           cliquable en toute circonstance quand le menu est ouvert. */
        z-index: 500;
        /* Réinitialise --nav-texte à l'encre du header : sans ça, en
           hero-superpose-sombre, la variable reste à #ffffff (héritée
           de la règle de voile) et le texte du panneau (blanc) devient
           invisible sur son fond blanc. Aligné sur .est-decolle (l.817)
           — même effet : le header revient à son état « posé ». */
        --nav-texte: var(--header-texte, #1c2434);
        --nav-indicator-color: var(--c-primaire);
    }

    /* En mode superposé, la règle desktop pose padding-bottom: 14px seul
       (contre les hover indicators qui mordraient le contenu). Sur mobile
       ce padding asymétrique laisse le logo trop haut, mal centré par
       rapport à un header non superposé. On équilibre en padding
       vertical symétrique — plus de hover en tactile, on peut assumer. */
    body.hero-superpose .site-header .header-grid { padding-top: 8px; padding-bottom: 8px; }
    .menu-toggle:checked ~ .menu-burger span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
    .menu-toggle:checked ~ .menu-burger span:nth-child(2) { opacity: 0; }
    .menu-toggle:checked ~ .menu-burger span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

    /* Le menu passe en premier, les outils en bas du panneau. Liens de
       niveau 1 grossis pour une cible tactile confortable et un rendu
       éditorial. */
    .site-nav { order: 1; flex-direction: column; align-items: stretch; padding: 0; gap: 4px; position: relative; }
    .site-nav > a, .nav-parent {
        padding: 16px 14px; border-radius: 12px;
        font-size: 20px; font-weight: 650; letter-spacing: -0.01em;
    }
    .nav-parent { width: 100%; justify-content: space-between; }
    /* Chevron droit sur le parent, plus gros, statique (jamais tourné au
       hover / focus / open) — c'est le SLIDE qui traduit l'ouverture,
       pas une rotation d'icône. */
    .nav-parent .ico {
        width: 22px !important; height: 22px !important;
        transform: rotate(-90deg) !important;
        opacity: .5; margin-left: 8px; transition: none !important;
    }
    .nav-groupe:hover .nav-parent .ico,
    .nav-groupe:focus-within .nav-parent .ico,
    .nav-groupe.est-ouvert .nav-parent .ico {
        transform: rotate(-90deg) !important;
    }

    /* Sous-menu niveau 2 : plein écran, glisse depuis la droite. Le niveau 1
       (panneau .header-right) glisse simultanément vers la gauche pour dégager.
       Positionnement par `left`/`right` (pas de transform) pour la même raison
       que .header-right — cohérence de containing block.
       IMPORTANT : .nav-groupe passe en static pour ne pas être containing
       block ; height explicite pour couvrir toute la viewport ; border-radius
       remis à zéro pour un rendu plein-écran cohérent avec le panneau parent. */
    .nav-groupe { position: static; }
    .nav-sousmenu {
        position: fixed; top: var(--header-h); left: 100%; right: -100%; bottom: 0; z-index: 305;
        height: calc(100vh - var(--header-h));
        height: calc(100dvh - var(--header-h));
        display: flex !important; flex-direction: column; align-items: stretch; gap: 4px;
        background: var(--panneau-fond, var(--c-header, #fff));
        padding: 14px 24px calc(28px + env(safe-area-inset-bottom, 0px));
        visibility: hidden;
        transition: left .28s cubic-bezier(0.4, 0, 0.2, 1),
                    right .28s cubic-bezier(0.4, 0, 0.2, 1),
                    visibility 0s .28s;
        border: none; border-radius: 0; box-shadow: none;
        margin: 0; min-width: 0; max-width: none;
        overflow-y: auto; overscroll-behavior: contain;
    }
    .nav-groupe.est-ouvert > .nav-sousmenu {
        left: 0; right: 0; visibility: visible;
        transition: left .28s cubic-bezier(0.4, 0, 0.2, 1),
                    right .28s cubic-bezier(0.4, 0, 0.2, 1),
                    visibility 0s 0s;
    }
    .nav-sousmenu a {
        color: var(--nav-texte); padding: 14px 14px; font-size: 17px;
        border-radius: 12px; font-weight: 550;
    }
    /* La règle desktop `.nav-sousmenu a:hover` (bas de fichier) force
       `color: var(--c-liens)` — sur un panneau mobile qui prend le
       fond du header, si celui-ci est foncé et la couleur de lien
       aussi (thème clair avec header foncé), le texte devient
       illisible sur illisible. On force ici la couleur du texte
       standard du header, qui contraste par construction. */
    .nav-sousmenu a:hover {
        background: color-mix(in srgb, var(--nav-texte, currentColor) 10%, transparent);
        color: var(--nav-texte);
    }

    /* Bouton « ← Retour » injecté par JS en tête de chaque sous-menu mobile.
       Couleur : `--nav-texte` (et NON `--c-primaire`) — sur un header foncé
       avec un thème clair, `--c-primaire` reste une couleur foncée et le
       « Retour » devient illisible sur le panneau. `--nav-texte` contraste
       par construction avec `--c-header`. Léger effet d'atténuation pour
       hiérarchiser vs. le titre. */
    .nav-retour {
        display: flex; align-items: center; gap: 10px;
        margin: 0 -8px 4px; padding: 10px 12px;
        background: none; border: 0; cursor: pointer;
        font: inherit; font-size: 14px; font-weight: 600;
        color: var(--nav-texte); opacity: .75;
        border-radius: 999px; align-self: flex-start;
    }
    .nav-retour:hover {
        background: color-mix(in srgb, var(--nav-texte, currentColor) 10%, transparent);
        opacity: 1;
    }
    .nav-retour .ico { flex: 0 0 auto; }

    /* Titre parent (page mère) toujours cliquable en tête du niveau 2 :
       injecté par JS si le parent est un <a> avec href. Visuellement
       distinct des enfants — plus grand, avec séparation. */
    .nav-sousmenu-titre {
        display: block; padding: 12px 14px 20px !important;
        font-size: 22px !important; font-weight: 700 !important;
        letter-spacing: -0.02em !important;
        color: var(--nav-texte) !important;
        border-bottom: 1px solid color-mix(in srgb, var(--nav-texte) 10%, transparent);
        margin-bottom: 8px !important; border-radius: 0 !important;
    }
    /* Hover : on garde la couleur du titre (--nav-texte, lisible par
       construction sur le header) et on signale l'interactivité par
       un fond subtil dérivé de la même couleur. `--c-primaire` était
       ici une régression : sur un header foncé + thème clair, il
       tirait la couleur vers le foncé et le titre s'effaçait. */
    .nav-sousmenu-titre:hover {
        background: color-mix(in srgb, var(--nav-texte, currentColor) 8%, transparent) !important;
        color: var(--nav-texte) !important;
    }

    /* Header utils : la recherche prend TOUTE la largeur en haut, toujours
       ouverte sur mobile (le format pilule + toggle n'a pas de sens sur
       un panneau vertical). */
    .header-utils {
        order: 2; flex-wrap: wrap; justify-content: flex-start;
        margin-top: 14px; padding-top: 16px; border-top: 1px solid var(--nav-survol);
    }
    .header-search { flex: 1 1 100%; order: -1; margin-bottom: 4px; position: relative; }
    .header-search input,
    .header-search.est-ouvert input {
        width: 100%; opacity: 1; padding: 0 44px 0 14px; pointer-events: auto;
        background: color-mix(in srgb, var(--c-primaire, currentColor) 8%, transparent);
    }
    .header-search [data-search-open] { display: none; }
    .header-search [data-search-submit] { display: inline-flex; }
    .lang-menu { right: auto; left: 0; bottom: calc(100% + 8px); top: auto; }

    /* Au défilement : logo compacté uniquement. La barre d'outils vit dans le
       panneau mobile, la masquer n'aurait aucun sens. */
    .site-header.reduit .header-utils {
        height: auto; opacity: 1; overflow: visible; pointer-events: auto;
        margin-top: 14px; padding-top: 16px;
    }
    .site-header.reduit .header-grid { min-height: 58px; }
    .site-header.reduit .site-logo { height: 42px; }   /* bumpé 34→42 pour rester visible en compact */

    /* Menu OUVERT → on force le header en état RÉDUIT (obligatoire,
       demandé). Libère un maximum de place pour le panneau à
       l'écran, quel que soit l'état de scroll précédent. */
    body:has(.menu-toggle:checked) .site-header .header-grid { min-height: 58px; }
    body:has(.menu-toggle:checked) .site-header .site-logo    { height: 42px; }
    body:has(.menu-toggle:checked) .site-header { --header-h: 58px; }
    .site-header.reduit .site-nom { font-size: 17px; }
    .site-header.reduit .header-right { top: 58px; }

    .hero-plein { min-height: 46vh; }
}

/* Modales de confirmation Civika — voile sombre + carte centrée qui
   remplace `window.confirm` natif (voir assets/dialog.js). Chargée aussi
   côté public pour tout futur bouton d'action utilisateur (formulaire
   de contact, désabonnement newsletter…). */
.civika-dialog-overlay {
    position: fixed; inset: 0; z-index: 10000;
    display: flex; align-items: center; justify-content: center;
    padding: 20px;
    /* Voile NOIR à 75 % — règle constante pour toutes les modales
       Civika, quel que soit le contexte (site public / admin, confirm
       / fiche riche). La carte se détache franchement, le contenu
       en dessous disparaît complètement. */
    background: rgba(0, 0, 0, .75);
    opacity: 0;
    transition: opacity .16s ease;
}
.civika-dialog-overlay.est-visible { opacity: 1; }
.civika-dialog {
    max-width: 420px; width: 100%;
    background: var(--carte-fond, #ffffff); color: var(--encre, #0f172a);
    border-radius: var(--rayon, 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(--carte-bordure, rgba(15, 23, 42, .12));
    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: color-mix(in srgb, var(--encre) 8%, transparent); }
.civika-dialog-btn-ok {
    background: var(--c-primaire, #2563eb);
    border-color: var(--c-primaire, #2563eb);
    color: #ffffff;
}
.civika-dialog-btn-ok:hover { filter: brightness(.92); }
.civika-dialog-btn-danger {
    background: #dc2626; border-color: #dc2626; color: #ffffff;
}
.civika-dialog-btn-danger:hover { background: #b91c1c; border-color: #b91c1c; }
.civika-dialog-btn:focus-visible {
    outline: 2px solid var(--c-primaire, #2563eb); outline-offset: 2px;
}

/* Modale RICHE (fiches trombinoscope, futures fiches annuaire) :
   largeur pleine plafonnée à 860 px, position:relative pour ancrer
   la croix flottante, scroll interne pour que le sticky de la
   colonne gauche fonctionne. IMPORTANT : ce bloc DOIT venir APRÈS
   la règle `.civika-dialog { max-width: 420px }` pour que la
   cascade CSS écrase bien la valeur par défaut à même spécificité. */
.civika-dialog-riche,
.civika-dialog-large {
    max-width: 860px; width: 100%; position: relative;
    max-height: 90vh; display: flex; flex-direction: column;
    padding: 0;
}
.civika-dialog-riche .civika-dialog-contenu,
.civika-dialog-large .civika-dialog-contenu {
    /* Padding IDENTIQUE sur les quatre côtés (32 px) — donne un cadre
       homogène, l'œil ne remarque plus de « colle » sur le contenu.
       La réserve à droite (56 px) reste pour la croix flottante. */
    padding: 32px; padding-right: 56px;
    overflow-y: auto; overflow-x: hidden;
    scrollbar-width: thin;
}
/* Croix flottante en haut à droite — pastille ronde qui SUIT
   L'AMBIANCE de la commune (fond carte + encre courants), pour
   rester lisible aussi bien sur une ambiance claire que sur une
   ambiance sombre. */
.civika-dialog-riche .civika-dialog-fermer,
.civika-dialog-large .civika-dialog-fermer {
    position: absolute; top: 12px; right: 12px; z-index: 2;
    width: 36px; height: 36px; padding: 0;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 999px;
    border: 1px solid var(--carte-bordure, rgba(15, 23, 42, .1));
    background: var(--carte-fond, #ffffff); color: var(--encre, #0f172a);
    cursor: pointer;
    box-shadow: 0 4px 12px -4px rgba(15, 23, 42, .25);
    transition: background .12s ease, transform .12s ease;
}
.civika-dialog-riche .civika-dialog-fermer:hover,
.civika-dialog-large .civika-dialog-fermer:hover {
    background: color-mix(in srgb, var(--encre) 12%, var(--carte-fond, #ffffff));
    transform: scale(1.06);
}
.civika-dialog-riche .civika-dialog-fermer:focus-visible,
.civika-dialog-large .civika-dialog-fermer:focus-visible {
    outline: 2px solid var(--c-primaire, #2563eb); outline-offset: 2px;
}

/* =====================================================
   Albums photo — grille publique (site/albums.php)
   =====================================================
   Utilise la structure standard `.cartes .cartes-3 .carte` :
   ambiance (ombre / bordure / plat), rayon, transitions et
   contraste sont hérités du système global. Seul ajout ici :
   l'overlay compteur de photos sur la couverture. */
.album-carte-media {
    position: relative; display: block;
}
.album-carte-badge {
    position: absolute; bottom: 10px; right: 10px;
    padding: 4px 10px; border-radius: 999px;
    background: rgba(15, 23, 42, .78); color: #fff;
    font-size: 12.5px; font-weight: 600;
    letter-spacing: .01em;
}

/* =====================================================
   Home — section « En images »
   =====================================================
   Deux dispositions : grille 2 colonnes égales (2 albums) ou
   vedette pleine largeur (1 album) — image paysage à gauche +
   carte texte à droite. Sur mobile tout passe en colonne. */
.home-albums-duo {
    display: grid; grid-template-columns: 1fr 1fr; gap: 22px;
}
.home-albums-badge, .home-album-badge {
    position: absolute; bottom: 12px; right: 12px;
    padding: 5px 12px; border-radius: 999px;
    background: rgba(15, 23, 42, .78); color: #fff;
    font-size: 13px; font-weight: 600;
}

.home-album-vedette {
    display: grid; grid-template-columns: 1.35fr 1fr; gap: 0;
    background: var(--carte-fond, #fff);
    border-radius: var(--rayon, 14px); overflow: hidden;
    text-decoration: none; color: inherit;
    transition: transform .18s ease, box-shadow .18s ease;
}
.cartes-ombre .home-album-vedette { box-shadow: 0 4px 18px -4px rgba(15, 23, 42, .1), 0 1px 3px rgba(15, 23, 42, .05); }
.cartes-bordure .home-album-vedette { border: 1.5px solid var(--carte-bordure, #e6eaf1); }
.home-album-vedette:hover {
    transform: translateY(-3px);
    box-shadow: 0 18px 38px -8px rgba(15, 23, 42, .18);
}
.home-album-vedette-image {
    position: relative;
    aspect-ratio: 16 / 9;
    background: color-mix(in srgb, var(--encre, #1c2434) 6%, var(--carte-fond, #fff));
    overflow: hidden;
}
.home-album-vedette-image img {
    width: 100%; height: 100%; object-fit: cover; display: block;
    transition: transform .3s ease;
}
.home-album-vedette:hover .home-album-vedette-image img { transform: scale(1.03); }
.home-album-vedette-corps {
    display: flex; flex-direction: column;
    padding: clamp(20px, 3vw, 34px);
    gap: 12px;
    background: var(--carte-fond, #fff);
    color: var(--sur-carte, var(--encre, #1c2434));
}
.home-album-date {
    font-size: 13px; font-weight: 600;
    color: var(--sur-carte-gris, var(--gris, #64748b));
    text-transform: uppercase; letter-spacing: .05em;
}
.home-album-vedette-corps h3 {
    margin: 0; font-size: clamp(22px, 2.4vw, 30px);
    font-weight: 700; line-height: 1.2; letter-spacing: -0.01em;
}
.home-album-vedette-corps p {
    margin: 0; font-size: 15.5px; line-height: 1.55;
    color: var(--sur-carte-gris, var(--gris, #64748b));
    flex: 1;
}
.home-album-cta {
    display: inline-flex; align-items: center; gap: 8px;
    margin-top: 4px;
    color: var(--c-primaire, #2563eb);
    font-weight: 650; font-size: 15px;
}
.home-album-vedette:hover .home-album-cta { transform: translateX(2px); transition: transform .12s ease; }

@media (max-width: 760px) {
    .home-albums-duo { grid-template-columns: 1fr; gap: 16px; }
    .home-album-vedette { grid-template-columns: 1fr; }
    .home-album-vedette-image { aspect-ratio: 16 / 9; }
}

/* =====================================================
   Albums photo — galerie détail (site/album.php)
   =====================================================
   Grille uniforme : toutes les vignettes ont la même dimension
   (paysage 4:3), les images sont rognées via `object-fit: cover`
   pour composer une mosaïque visuellement cohérente quel que
   soit le mélange portrait/paysage. Le lightbox affiche ensuite
   l'image dans son ratio d'origine (contain), pas de perte de
   contenu à l'ouverture. */
.album-galerie {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 14px;
}
@media (max-width: 700px) {
    .album-galerie {
        grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
        gap: 10px;
    }
}
.album-photo-front {
    display: block; margin: 0;
    position: relative; overflow: hidden;
    aspect-ratio: 1 / 1;
    border-radius: var(--rayon, 12px);
    background: color-mix(in srgb, var(--encre, #1c2434) 6%, var(--carte-fond, #fff));
    text-decoration: none; color: inherit;
    cursor: zoom-in;
    transition: transform .18s ease, box-shadow .18s ease;
}
.album-photo-front:hover {
    transform: translateY(-2px);
    box-shadow: 0 14px 34px -18px rgba(15, 23, 42, .35);
}
.album-photo-front img {
    width: 100%; height: 100%; display: block;
    object-fit: cover;
    transition: transform .3s ease;
}
.album-photo-front:hover img { transform: scale(1.04); }
.album-photo-front-legende {
    position: absolute; left: 0; right: 0; bottom: 0;
    padding: 40px 14px 12px;
    background: linear-gradient(to top, rgba(0, 0, 0, .72) 0%, rgba(0, 0, 0, 0) 100%);
    color: #fff; font-size: 13.5px; line-height: 1.4;
    opacity: 0; transition: opacity .18s ease;
    pointer-events: none;
}
.album-photo-front:hover .album-photo-front-legende,
.album-photo-front:focus-visible .album-photo-front-legende { opacity: 1; }

/* =====================================================
   Aperçu d'album lié à une actu ou une page (_album_apercu.php)
   =====================================================
   Section PLEINE LARGEUR du conteneur (page-conteneur), placée
   sous le corps d'article et sa sidebar — on donne à l'album son
   propre espace visuel plutôt que de le fourrer sous le texte.

   Composition : eyebrow + titre, puis rangée uniforme de vignettes
   (auto-fit, aspect 1:1), puis CTA discret centré. Volontairement
   sans fond ni bordure : le titre + les vignettes suffisent à
   marquer la section, un cadre alourdirait la mise en page. */
/* La section utilise `.section .section-alt` (fond alterné, calé sur
   --section-alt/--section-texte du thème). Espacements verticaux du
   contenu interne fournis par `.section > .conteneur` (clamp responsive).
   Rien à ajouter au bloc : plus de filet, plus de margin en dur.

   `scroll-margin-top` pour compenser le header fixed : sans ça, le
   scroll d'ancre (#formulaire-N ou depuis un menu) place le haut de
   la section EXACTEMENT à y=0, où le header opaque le recouvre. Le
   fallback 80 px couvre les thèmes qui ne définissent pas --header-h. */
.album-lie,
.formulaire-lie { scroll-margin-top: calc(var(--header-h, 80px) + 16px); }
.album-lie-entete { margin-bottom: 18px; }
.album-lie-eyebrow {
    display: block; margin-bottom: 6px;
    text-transform: uppercase; letter-spacing: .08em;
    font-size: 12px; font-weight: 700;
    color: var(--c-primaire, #2563eb);
}
.album-lie-titre {
    margin: 0; font-size: 30px; line-height: 1.2; font-weight: 700;
    letter-spacing: -0.01em;
}
.album-lie-titre a { color: inherit; text-decoration: none; }

.album-lie-grille {
    display: grid;
    /* 4 vignettes sur une seule ligne — jamais 3 (motif visuel
       impair moche avec 4 photos, on préfère basculer d'un coup
       en 2×2 sur les écrans étroits). */
    grid-template-columns: repeat(4, 1fr);
    gap: 12px;
    /* Chaque vignette est son propre lien lightbox — pas de lien
       parent (sinon les clics sur les vignettes déclenchent la
       navigation à la page album au lieu du zoom). */
}
.album-lie-vignette {
    display: block; position: relative;
    /* Même ratio que les vignettes de la galerie détail (album.php)
       pour une cohérence visuelle sur tout le module. */
    aspect-ratio: 1 / 1; overflow: hidden;
    border-radius: 10px;
    background: color-mix(in srgb, var(--encre, #1c2434) 6%, var(--carte-fond, #fff));
    cursor: zoom-in;
    transition: transform .18s ease, box-shadow .18s ease;
}
.album-lie-vignette:hover {
    transform: translateY(-2px);
    box-shadow: 0 12px 28px -14px rgba(15, 23, 42, .3);
}
.album-lie-vignette img {
    width: 100%; height: 100%; object-fit: cover; display: block;
    transition: transform .3s ease;
}
.album-lie-vignette:hover img { transform: scale(1.04); }

.album-lie-cta {
    display: inline-flex; align-items: center; gap: 10px;
    margin-top: 20px; padding: 10px 18px;
    background: var(--c-primaire, #2563eb);
    /* `--sur-primaire-accent` (biaisé vers le blanc, calculé par
       Couleur::surAccent) + !important : la règle globale
       `a { color: var(--c-liens) }` (ligne 23) l'emporterait sinon
       et le libellé se retrouverait bleu sur bleu. Même pattern
       que les autres CTA du site (cf. .btn-primaire l.1970). */
    color: var(--sur-primaire-accent, #ffffff) !important;
    border-radius: 999px; font-weight: 600; font-size: 14.5px;
    text-decoration: none;
    transition: transform .12s ease, box-shadow .18s ease;
}
.album-lie-cta:hover {
    transform: translateX(2px);
    box-shadow: 0 10px 24px -12px color-mix(in srgb, var(--c-primaire, #2563eb) 60%, transparent);
}
.album-lie-cta-total {
    padding-left: 10px; margin-left: 4px;
    border-left: 1px solid color-mix(in srgb, var(--sur-primaire-accent, #ffffff) 40%, transparent);
    font-weight: 500; opacity: .85;
}

/* Bascule 4-en-ligne → 2×2 (jamais 3 par ligne). Seuil calibré pour
   qu'à 4-en-ligne chaque vignette reste au-dessus de ~140 px : en
   dessous, on préfère passer à 2×2 avec des vignettes plus généreuses
   que de garder 4 vignettes trop petites. */
@media (max-width: 720px) {
    .album-lie-grille { grid-template-columns: repeat(2, 1fr); gap: 10px; }
}
@media (max-width: 640px) {
    .album-lie-titre { font-size: 24px; }
}

/* =====================================================
   Lightbox générique (site.js)
   =====================================================
   Surcouche fixe, fond noir 92 %, image centrée, contrôles
   d'ergonomie standard : croix en haut-droite, flèches
   latérales, compteur + légende en bas. Le voile passe par-dessus
   TOUT le contenu (z-index très haut) — on veut interrompre
   l'expérience, pas la partager. `html.lightbox-ouvert` bloque
   le scroll de la page derrière. */
html.lightbox-ouvert { overflow: hidden; }
.lightbox {
    position: fixed; inset: 0; z-index: 20000;
    display: flex; align-items: center; justify-content: center;
    background: rgba(0, 0, 0, .92);
    padding: 40px 60px 80px;
    animation: lightbox-in .16s ease-out;
}
@keyframes lightbox-in { from { opacity: 0; } to { opacity: 1; } }
.lightbox[hidden] { display: none; }
.lightbox-scene {
    max-width: 100%; max-height: 100%;
    display: flex; align-items: center; justify-content: center;
}
.lightbox-scene img {
    max-width: 100%; max-height: 100%;
    display: block;
    border-radius: 4px;
    box-shadow: 0 20px 60px -20px rgba(0, 0, 0, .8);
    object-fit: contain;
}
.lightbox-fermer,
.lightbox-nav {
    position: absolute; background: rgba(255, 255, 255, .1); color: #fff;
    border: 1px solid rgba(255, 255, 255, .2);
    border-radius: 999px; cursor: pointer;
    display: flex; align-items: center; justify-content: center;
    transition: background-color .12s ease, transform .12s ease;
}
.lightbox-fermer { top: 16px; right: 16px; width: 44px; height: 44px; }
.lightbox-nav { top: 50%; transform: translateY(-50%); width: 48px; height: 48px; }
.lightbox-prec { left: 16px; }
.lightbox-suiv { right: 16px; }
.lightbox-fermer:hover,
.lightbox-nav:hover { background: rgba(255, 255, 255, .2); }
.lightbox-fermer:focus-visible,
.lightbox-nav:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.lightbox-legendebar {
    position: absolute; left: 0; right: 0; bottom: 0;
    padding: 12px 24px 20px;
    background: linear-gradient(to top, rgba(0, 0, 0, .6) 0%, rgba(0, 0, 0, 0) 100%);
    color: #fff; text-align: center;
    display: flex; flex-direction: column; align-items: center; gap: 4px;
    pointer-events: none;
}
.lightbox-compteur { font-size: 12px; font-weight: 600; opacity: .8; letter-spacing: .06em; }
.lightbox-legende { font-size: 14px; line-height: 1.4; max-width: 720px; }
@media (max-width: 640px) {
    .lightbox { padding: 12px 8px 60px; }
    .lightbox-fermer { top: 8px; right: 8px; width: 40px; height: 40px; }
    .lightbox-nav { width: 40px; height: 40px; }
    .lightbox-prec { left: 8px; }
    .lightbox-suiv { right: 8px; }
}

/* =====================================================
   Formulaires personnalisés — rendu public
   ===================================================== */
.formulaire-public {
    display: flex; flex-direction: column; gap: 18px;
    max-width: 640px;
}
.formulaire-lie .formulaire-public { max-width: 720px; }
/* Réservation de salle : layout à 2 colonnes qui doit occuper toute la
   largeur du conteneur — pas de plafond 640 px hérité de .formulaire-public. */
.formulaire-public.reservation-form { max-width: none; }
/* Le bouton d'envoi ne doit pas s'étirer sur toute la largeur du
   formulaire (flex-column stretch par défaut) — on lui rend sa
   largeur naturelle et on l'aligne à gauche. */
.formulaire-public .btn-envoyer { align-self: flex-start; }

/* Zone géoloc du formulaire de signalement : bouton « Me localiser » au-dessus,
   texte d'aide en dessous. Empilement propre, pas d'alignement inline
   pénible. Le bouton hérite de .btn-envoyer.btn-envoyer-outline.btn-envoyer-sm
   (couleur de la commune, compact). */
.signalement-geoloc {
    display: flex; flex-direction: column; align-items: flex-start; gap: 8px;
    margin-top: 10px;
}
.signalement-geoloc .formulaire-aide { margin: 0; }

/* Formulaire de signalement : grille 2 colonnes (gauche = le problème,
   droite = localisation + contact), passe en 1 colonne sous 780 px. Le
   consentement + humain + bouton envoi restent PLEINE LARGEUR sous la
   grille (hors .signalement-grille). */
.signalement-grille {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 24px 32px;
}
.signalement-colonne {
    display: flex; flex-direction: column; gap: 18px;
    min-width: 0;
}
@media (max-width: 780px) {
    .signalement-grille { grid-template-columns: 1fr; gap: 18px; }
}

/* Bloc coordonnées optionnelles — encadré discret avec titre en légende,
   différencie visuellement la partie « obligatoire » de la partie
   « facultative » (contact) au sein de la colonne droite. */
.signalement-coords {
    border: 1px solid var(--carte-bordure);
    border-radius: 10px;
    padding: 16px 18px;
    margin: 0;
}
.signalement-coords legend {
    padding: 0 8px;
    font-size: 14px; font-weight: 600;
    color: color-mix(in srgb, currentColor 85%, transparent);
}

.formulaire-ligne {
    display: flex; flex-direction: column; gap: 6px;
}
.formulaire-ligne > label {
    font-weight: 600; font-size: 14px;
    color: color-mix(in srgb, currentColor 85%, transparent);
}
.formulaire-ligne input[type="text"],
.formulaire-ligne input[type="email"],
.formulaire-ligne input[type="tel"],
.formulaire-ligne input[type="number"],
.formulaire-ligne input[type="date"],
.formulaire-ligne textarea,
.formulaire-ligne select {
    width: 100%; padding: 12px 14px;
    font: inherit; font-size: 15.5px;
    /* Suit l'ambiance du thème comme .contact-form : voile blanc 15 %
       lisible sur fond sombre et discret sur fond clair, bordure noir
       15 % qui reste visible dans les deux cas, texte piloté par
       --section-texte / --encre. Rayon `--rayon-cta` pour rester cohérent
       avec le bouton d'envoi et les inputs de recherche. */
    background: rgba(255, 255, 255, .15);
    color: var(--section-texte, var(--encre, currentColor));
    border: 1px solid rgba(0, 0, 0, .15);
    border-radius: var(--rayon-cta, 10px);
    transition: border-color .15s ease, box-shadow .15s ease;
}
/* Textarea : rayon plafonné à 1.5rem pour éviter que les coins arrondis
   « bouffent » le contenu quand la commune a choisi un rayon extrême. */
.formulaire-ligne textarea {
    border-radius: min(var(--rayon-cta, 10px), 1.5rem);
    resize: none; min-height: 140px;
}
/* Select : sans ces règles explicites, la hauteur rendue par le navigateur
   est un peu plus courte que celle des `<input>` (différence de line-height
   par défaut) — l'alignement visuel dans un formulaire mixte apparaît
   déséquilibré. On force la même line-height + un `height: auto` pour laisser
   padding + line-height calculer la hauteur exactement comme les inputs. */
.formulaire-ligne select,
.contact-form select,
.ec-selecteur select {
    line-height: 1.5;
    height: auto;
    /* Retire le styling natif OS : sans ça, la chevron native est collée à
       ~4-8 px du bord droit (très à droite, déséquilibré face au padding
       textuel de 14 px à gauche). On la remplace par une chevron custom
       via ::after sur le parent (voir plus bas) pour pouvoir suivre
       --section-texte via currentColor — une SVG data URI en
       background-image est un document ISOLÉ, elle n'hérite pas de la
       couleur CSS parente, donc `stroke='currentColor'` y valait toujours
       noir et devenait invisible sur les sections sombres. */
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    padding-right: 36px;
}
/* Chevron du select — mask-image + background-color: currentColor sur le
   pseudo-élément du parent (les <select> ne peuvent pas porter de pseudo).
   Résultat : la chevron prend automatiquement la couleur du texte de la
   section (noir sur fond clair, blanc sur fond sombre) ET se place à la
   même distance du bord droit quel que soit le contexte (contact,
   signalements, sélecteur d'élu…). */
.formulaire-ligne,
.contact-form p,
.ec-selecteur { position: relative; }
.formulaire-ligne:has(> select)::after,
.contact-form p:has(> select)::after,
.ec-selecteur:has(> select)::after {
    content: '';
    position: absolute;
    right: 14px; bottom: 20px;
    width: 12px; height: 7px;
    background-color: currentColor;
    color: var(--section-texte, currentColor);
    opacity: .6;
    -webkit-mask-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='7' viewBox='0 0 12 7'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round' fill='none'/%3E%3C/svg%3E");
            mask-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='7' viewBox='0 0 12 7'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round' fill='none'/%3E%3C/svg%3E");
    -webkit-mask-repeat: no-repeat;
            mask-repeat: no-repeat;
    -webkit-mask-position: center;
            mask-position: center;
    -webkit-mask-size: contain;
            mask-size: contain;
    pointer-events: none;
}
/* Chrome hérite la couleur du <select> pour ses <option>, mais garde un fond
   BLANC natif pour la popup — sur une section à texte clair (fond sombre du
   site), les options deviennent blanc-sur-blanc et illisibles. Firefox n'a
   pas le souci (il applique son propre thème à la popup). On force donc une
   paire texte/fond neutre indépendante du thème de la section parente, sur
   TOUS les selects du site public (formulaire-ligne, contact-form, ec-selecteur). */
.formulaire-ligne select option,
.contact-form select option,
.ec-selecteur select option {
    color: #111;
    background-color: #fff;
}
.formulaire-ligne input::placeholder,
.formulaire-ligne textarea::placeholder {
    color: var(--section-texte, currentColor); opacity: .55;
}
.formulaire-ligne input:focus,
.formulaire-ligne textarea:focus,
.formulaire-ligne select:focus {
    outline: none;
    border-color: var(--c-primaire, #2563eb);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--c-primaire, #2563eb) 18%, transparent);
}
.formulaire-ligne input[type="file"] {
    padding: 8px 0;
}
.formulaire-ligne.est-en-erreur input,
.formulaire-ligne.est-en-erreur textarea,
.formulaire-ligne.est-en-erreur select {
    border-color: var(--danger, #dc2626);
}
.formulaire-aide,
.formulaire-aide-fichier {
    font-size: 12.5px;
    color: color-mix(in srgb, currentColor 65%, transparent);
}
.formulaire-erreur {
    margin: 0; font-size: 13px; font-weight: 600;
    color: var(--danger, #dc2626);
    display: inline-flex; align-items: center; gap: 4px;
}
.formulaire-choix {
    display: flex; flex-direction: column; gap: 8px;
    padding: 8px 12px;
    background: color-mix(in srgb, currentColor 3%, transparent);
    border-radius: 10px;
}
.formulaire-choix-ligne {
    display: flex; align-items: center; gap: 10px;
    padding: 4px 0; cursor: pointer; font-size: 15px;
}
.formulaire-choix-ligne input { margin: 0; flex: 0 0 auto; }
.formulaire-case-unique {
    display: flex; align-items: flex-start; gap: 10px;
    cursor: pointer; font-size: 14.5px; line-height: 1.5;
}
.formulaire-case-unique input { margin-top: 3px; flex: 0 0 auto; }

/* La case RGPD du formulaire reprend `.contact-consent` — même look
   que celui du formulaire /contact, pas de traitement bordé propre.
   Les règles globales de ces composants (`.contact-consent`,
   `.humain-case`) posent des margins verticales calibrées pour un
   formulaire sans gap. Dans notre `.formulaire-public` (flex-column
   gap:18px) ces margins s'ajoutent au gap et gonflent l'espacement
   entre les blocs — on les neutralise ici. */
.formulaire-public .contact-consent,
.formulaire-public .humain-case { margin: 0 !important; }

/* Section « Formulaire associé » injectée sous une actu / page / event.
   Même patron visuel qu'un aperçu album lié. */
.formulaire-lie-entete { margin-bottom: 20px; }
.formulaire-lie-eyebrow {
    display: block; margin-bottom: 6px;
    text-transform: uppercase; letter-spacing: .08em;
    font-size: 12px; font-weight: 700;
    color: var(--c-primaire, #2563eb);
}
.formulaire-lie-titre {
    margin: 0 0 8px; font-size: 30px; line-height: 1.2;
    font-weight: 700; letter-spacing: -0.01em;
}
.formulaire-lie-desc {
    margin: 0; font-size: 15px; line-height: 1.55;
    color: color-mix(in srgb, currentColor 70%, transparent);
    max-width: 720px;
}

/* Message de succès après soumission valide */
.formulaire-succes,
.formulaire-ferme {
    display: flex; align-items: center; gap: 14px;
    max-width: 640px;
    padding: 18px 22px;
    border-radius: 12px;
    font-weight: 550;
}
.formulaire-succes {
    background: color-mix(in srgb, var(--succes, #16a34a) 12%, var(--carte-fond, #fff));
    border: 1px solid color-mix(in srgb, var(--succes, #16a34a) 40%, transparent);
    color: color-mix(in srgb, var(--succes, #16a34a) 80%, #0f172a);
}
/* Formulaire fermé (péremption ou quota atteint) : ton neutre-sérieux,
   pas alarmant — c'est un état normal de fin de collecte. */
.formulaire-ferme {
    background: color-mix(in srgb, currentColor 5%, var(--carte-fond, #fff));
    border: 1px solid color-mix(in srgb, currentColor 20%, transparent);
    color: inherit;
}
.formulaire-succes p, .formulaire-ferme p { margin: 0; }

@media (max-width: 640px) {
    .formulaire-lie-titre { font-size: 24px; }
}

/* ==================================================================
   Sondages — bloc intégré dans un contenu WYSIWYG (page, actualité,
   événement). Une seule question, N réponses, résultats agrégés.
   Le bloc respire visuellement (encadré léger, coloré) pour signaler
   à l'internaute qu'il s'agit d'un appel à participer.
   ================================================================== */
/* Bloc sondage : suit les couleurs du thème ambiant (--fond, --encre)
   pour rester lisible en mode clair ET en mode sombre. L'aplat teinté
   du bloc est calculé à partir de --fond (le fond du site), pas d'une
   valeur hardcodée blanche — sinon en dark mode on aurait un aplat
   clair sur un fond sombre + texte clair héritée = illisible. */
.sondage-bloc {
    background: var(--fond);
    background: color-mix(in srgb, var(--c-primaire) 8%, var(--fond));
    border: 1px solid color-mix(in srgb, var(--c-primaire) 20%, transparent);
    border-left: 4px solid var(--c-primaire);
    border-radius: 12px;
    padding: 24px 26px;
    margin: 32px 0;
    box-shadow: 0 2px 12px rgba(15, 23, 42, .04);
    color: var(--encre);
}
.sondage-question {
    font-size: 18px;
    font-weight: 600;
    color: var(--encre);
    margin: 0 0 16px;
    line-height: 1.35;
}
.sondage-form { display: flex; flex-direction: column; gap: 10px; }
.sondage-option {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 14px;
    background: var(--carte-fond);
    border: 1px solid var(--carte-bordure);
    border-radius: 8px;
    cursor: pointer;
    transition: border-color .15s, background .15s;
    font-size: 15px;
    color: var(--encre);
}
.sondage-option:hover { border-color: var(--c-primaire); }
.sondage-option input { accent-color: var(--c-primaire); flex: 0 0 auto; }
.sondage-option span { flex: 1; }
.sondage-actions {
    display: flex;
    align-items: center;
    gap: 16px;
    flex-wrap: wrap;
    margin-top: 8px;
}
.sondage-bloc .sondage-note { font-size: 14px; margin: 0; color: var(--encre); }
.sondage-bloc .sondage-note.muted { color: var(--gris); }
/* Résultats — barres horizontales avec pourcentage et compteur */
.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: 15px;
}
.sondage-resultat-libelle { font-weight: 500; color: var(--encre); }
.sondage-resultat-pct { font-weight: 600; color: var(--c-primaire); font-size: 14px; }
.sondage-resultat-jauge {
    background: var(--carte-fond);
    border: 1px solid var(--carte-bordure);
    border-radius: 999px;
    height: 12px;
    overflow: hidden;
}
.sondage-resultat-jauge-remplie {
    background: var(--c-primaire);
    height: 100%;
    border-radius: 999px;
    transition: width .3s ease;
}
.sondage-bloc .sondage-resultat-nb { font-size: 12.5px; color: var(--gris); }
.sondage-bloc .sondage-resultat-total { color: var(--gris); }
/* Pied de tableau : total à gauche, mention « Sondage terminé » à droite
   quand le sondage n'accepte plus de votes (échéance atteinte ou seuil
   max_votes dépassé). Alignés en flex. */
.sondage-resultat-pied {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    margin-top: 4px;
    font-size: 13px;
}
.sondage-resultat-total { margin: 0; }
.sondage-resultat-termine {
    color: #dc2626; /* rouge Tailwind red-600, lisible sur fond blanc et --fond */
    font-weight: 600;
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.sondage-resultat-termine::before {
    content: "";
    display: inline-block;
    width: 8px; height: 8px;
    background: #dc2626;
    border-radius: 50%;
}

/* Page dédiée d'un sondage (/sondages/{id}) — le titre <h1> reprend
   déjà la question et l'alignement doit suivre celui de l'en-tête
   d'article : on retire donc l'encadré, le padding et le libellé
   dupliqué de .sondage-question. Le bulletin/les résultats restent
   alignés à gauche avec le titre de page. */
.sondage-page .sondage-bloc {
    background: transparent;
    border: none;
    border-left: none;
    border-radius: 0;
    padding: 0;
    margin: 20px 0 0;
    box-shadow: none;
}
.sondage-page .sondage-bloc .sondage-question { display: none; }

/* Lien discret sous les résultats pour rouvrir le bulletin de vote
   quand le sondage est en mode « modifiable ». Bouton stylé en lien
   pour rester léger — l'action principale reste la lecture. */
/* `!important` : dans un contenu d'article `.prose p { margin: 0 0 18px }`
   remporte le combat de spécificité et pousse un espace parasite sous le
   lien. Le bloc sondage a ses propres règles de rythme, on l'isole. */
.sondage-modif,
.article-corps .prose .sondage-modif { margin: 14px 0 0 !important; text-align: right; }
.sondage-modif-lien {
    background: none;
    border: none;
    padding: 4px 8px;
    margin: 0;
    color: var(--c-primaire);
    font-size: 13.5px;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    border-radius: 6px;
    text-decoration: none;
}
.sondage-modif-lien:hover {
    background: color-mix(in srgb, var(--c-primaire) 10%, transparent);
    text-decoration: none;
}
.sondage-form-cachee { display: none; }
.sondage-form-cachee.est-affiche { display: flex; }
.sondage-note {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0;
    font-size: 15px;
    color: var(--noir, #0f172a);
}

/* ==================================================================
   Location de salles — front public
   Cartes en grille (liste), hero + galerie + calendrier (fiche),
   formulaire de demande (héritant des styles .formulaire-public).
   ================================================================== */
.salles-grille {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: 20px;
    margin: 24px 0;
}
.salle-carte {
    background: var(--carte-fond);
    border: 1px solid var(--carte-bordure);
    border-radius: 14px;
    overflow: hidden;
    transition: transform .18s ease, box-shadow .18s ease;
}
.salle-carte:hover { transform: translateY(-2px); box-shadow: 0 8px 24px rgba(15, 23, 42, .08); }
.salle-carte-lien { display: block; color: inherit; text-decoration: none; }
.salle-carte-photo {
    aspect-ratio: 16 / 10;
    background: var(--fond);
    overflow: hidden;
}
.salle-carte-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.salle-carte-photo-vide {
    display: flex; align-items: center; justify-content: center;
    color: color-mix(in srgb, var(--encre) 40%, transparent);
}
.salle-carte-corps { padding: 16px 18px 20px; }
.salle-carte-titre { margin: 0 0 8px; font-size: 20px; font-weight: 700; color: var(--encre); line-height: 1.25; }
.salle-carte-meta {
    display: flex; flex-wrap: wrap; gap: 12px; margin: 0 0 10px;
    font-size: 13.5px; color: var(--gris);
}
.salle-carte-meta span { display: inline-flex; align-items: center; gap: 5px; }
.salle-carte-desc { margin: 0; font-size: 14.5px; line-height: 1.55; color: var(--encre); }

/* Fiche salle — mêmes largeurs qu'un article. */
.salle-grille {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 300px;
    gap: 56px;
    align-items: start;
    margin-top: 20px;
    padding-bottom: 60px;
}
@media (max-width: 1280px) {
    .salle-grille { grid-template-columns: minmax(0, 1fr) 260px; gap: 44px; }
}
@media (max-width: 900px) {
    .salle-grille { grid-template-columns: 1fr; gap: 40px; }
}
.salle-corps { min-width: 0; }
.salle-photo-principale {
    margin: 0 0 24px;
    border-radius: var(--rayon, 14px);
    overflow: hidden;
    background: var(--fond);
}
.salle-photo-principale img {
    display: block; width: 100%; height: auto;
    max-height: 480px; object-fit: cover;
}
.salle-description { margin-bottom: 24px; }
.salle-section { margin-top: 32px; }
.salle-section h2 {
    font-size: 20px;
    display: flex; align-items: center; gap: 8px;
    margin: 0 0 14px;
    color: var(--encre);
}
.evt-plan {
    height: 320px;
    border-radius: var(--rayon, 14px);
    overflow: hidden;
    background: var(--fond);
}

.salle-equipements {
    list-style: none;
    padding: 0;
    margin: 0;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: 10px 16px;
}
.salle-equipements li {
    display: inline-flex; align-items: center; gap: 8px;
    padding: 8px 12px;
    background: var(--carte-fond);
    border: 1px solid var(--carte-bordure);
    border-radius: 8px;
    font-size: 14px;
    color: var(--encre);
}

.salle-galerie {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: 8px;
}
.salle-galerie-photo {
    display: block;
    aspect-ratio: 1 / 1;
    border-radius: 10px;
    overflow: hidden;
    background: var(--fond);
}
.salle-galerie-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Colonne latérale sticky de la fiche salle — style .article-cote :
   aucune bordure, aucun fond, uniquement des groupes minimalistes espacés
   (étiquette majuscule + valeur compacte). Cohérent avec les fiches
   article/annuaire/agenda. */
.salle-cote {
    display: flex; flex-direction: column; gap: 32px;
    position: sticky; top: 90px;
}
@media (max-width: 900px) { .salle-cote { position: static; } }
.cote-meta { display: flex; flex-direction: column; gap: 20px; }
.cote-meta-item { display: flex; flex-direction: column; gap: 3px; }
.salle-cote .cote-cta { width: 100%; justify-content: center; }
.salle-cote .cote-note {
    font-size: 12.5px; margin: 0;
    display: flex; align-items: center; gap: 5px;
}

/* Calendrier compact dans la sidebar (disponibilité mois-par-mois). */
.salle-calendrier {
    background: var(--fond);
    border-radius: 10px;
    padding: 10px;
}
.salle-calendrier-tete {
    display: flex; align-items: center; justify-content: space-between;
    margin-bottom: 8px;
    font-size: 13.5px;
}
.salle-calendrier-tete strong { text-transform: capitalize; }
.salle-calendrier-nav {
    display: inline-flex; align-items: center; justify-content: center;
    width: 26px; height: 26px;
    border-radius: 999px;
    background: var(--fond);
    color: var(--encre);
    border: 1px solid var(--carte-bordure);
    text-decoration: none;
    transition: background .12s, border-color .12s, transform .1s;
}
.salle-calendrier-nav:hover {
    background: color-mix(in srgb, var(--c-primaire) 12%, var(--fond));
    border-color: var(--c-primaire);
    transform: scale(1.08);
}
.salle-calendrier-nav.est-desactivee {
    opacity: .3; cursor: not-allowed;
}
.salle-calendrier-grille {
    display: grid; grid-template-columns: repeat(7, 1fr); gap: 3px;
}
.salle-calendrier-jour-nom {
    text-align: center; font-size: 10.5px; font-weight: 600;
    text-transform: uppercase; color: var(--gris); padding: 2px 0;
}
.salle-calendrier-jour {
    aspect-ratio: 1;
    display: flex; align-items: center; justify-content: center;
    border-radius: 6px;
    font-size: 12.5px; font-weight: 500;
    border: 1px solid transparent;
    text-decoration: none;
    color: inherit;
}
.salle-calendrier-jour-vide { visibility: hidden; }
.salle-calendrier-jour.est-libre {
    background: color-mix(in srgb, #10b981 12%, transparent);
    color: var(--encre);
    border-color: color-mix(in srgb, #10b981 30%, transparent);
    transition: transform .12s, background .12s;
}
.salle-calendrier-jour.est-libre:hover {
    background: color-mix(in srgb, #10b981 25%, transparent);
    transform: scale(1.08);
}
.salle-calendrier-jour.est-complet {
    background: color-mix(in srgb, #dc2626 10%, transparent);
    color: color-mix(in srgb, var(--encre) 60%, transparent);
}
.salle-calendrier-jour.est-passe {
    background: transparent;
    color: color-mix(in srgb, var(--encre) 30%, transparent);
}
/* Voir `.rdv-cal-legende` : pastille et libellé regroupés, sans quoi le flex
   les sépare et l'alignement vertical est perdu. */
.salle-calendrier-legende {
    margin: 8px 0 0; font-size: 11.5px;
    display: flex; flex-wrap: wrap; gap: 8px;
    align-items: center; justify-content: center;
}
.salle-calendrier-item { display: inline-flex; align-items: center; gap: 5px; }
.salle-calendrier-pastille {
    width: 10px; height: 10px; border-radius: 3px;
    flex: none;
}
.salle-calendrier-pastille.est-libre { background: color-mix(in srgb, #10b981 45%, transparent); }
.salle-calendrier-pastille.est-complet { background: color-mix(in srgb, #dc2626 45%, transparent); }

/* --- Page réservation : picker 2 mois + étapes + sélection --- */
.reservation-form { margin: 24px 0 0; }
/* Grille : rail récap 300px à droite (260px sous 1200), reste pour
   les étapes. Sur petit écran on rebascule sur 1 colonne empilée. */
.reservation-grille {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 300px;
    gap: 48px;
    align-items: start;
    padding-bottom: 60px;
}
@media (max-width: 1200px) {
    .reservation-grille { grid-template-columns: minmax(0, 1fr) 260px; gap: 36px; }
}
@media (max-width: 900px) {
    .reservation-grille { grid-template-columns: 1fr; gap: 32px; }
}
.reservation-colonne { min-width: 0; display: flex; flex-direction: column; gap: 8px; }

/* Sidebar récap — style aligné sur `.article-cote` / `.salle-cote` :
   pas de carte encadrée, juste des groupes espacés sticky sous le header. */
.reservation-cote {
    position: sticky; top: 108px;
    display: flex; flex-direction: column; gap: 24px;
}
@media (max-width: 900px) { .reservation-cote { position: static; } }
.reservation-cote-carte {
    display: flex; flex-direction: column; gap: 12px;
}
.reservation-cote-titre {
    display: inline-flex; align-items: center; gap: 6px;
    font-size: 11px; font-weight: 700; letter-spacing: 1px;
    text-transform: uppercase;
    color: color-mix(in srgb, var(--encre) 55%, transparent);
    margin: 0 0 4px;
}
.recap-ligne {
    display: flex; align-items: flex-start; gap: 10px;
    padding: 10px 0;
    border-top: 1px dashed color-mix(in srgb, var(--encre) 15%, transparent);
    font-size: 14px;
}
.recap-ligne:first-of-type { border-top: none; padding-top: 0; }
.recap-num {
    display: inline-flex; align-items: center; justify-content: center;
    width: 22px; height: 22px;
    border-radius: 50%;
    background: color-mix(in srgb, var(--encre) 12%, transparent);
    color: var(--encre);
    font-size: 12px; font-weight: 700;
    flex: 0 0 auto;
}
.recap-corps { flex: 1; min-width: 0; }
.recap-label { font-weight: 600; color: var(--encre); font-size: 13px; }
.recap-valeur { font-size: 13.5px; margin-top: 2px; word-break: break-word; }
.recap-effacer-dates {
    display: inline-flex;
    align-items: center; gap: 4px;
    padding: 3px 8px 3px 6px;
    margin-top: 6px;
    background: transparent;
    border: 1px solid color-mix(in srgb, var(--c-primaire) 30%, transparent);
    color: var(--c-primaire);
    border-radius: 999px;
    font-size: 11.5px; font-weight: 500;
    cursor: pointer;
}
.recap-effacer-dates:hover {
    background: color-mix(in srgb, var(--c-primaire) 12%, transparent);
    border-color: var(--c-primaire);
}
/* Priorité forte sur [hidden] : sans ça, `display: inline-flex` du
   base rule écrase la règle browser `[hidden] { display: none }`
   et le bouton reste visible même avec l'attribut posé. */
.recap-effacer-dates[hidden] { display: none !important; }
.recap-statut { flex: 0 0 auto; color: color-mix(in srgb, var(--encre) 30%, transparent); }
.recap-ligne.est-validee .recap-num {
    background: var(--c-primaire); color: var(--sur-primaire, #fff);
}
.recap-ligne.est-validee .recap-statut { color: #10b981; }
.reservation-cote-cta { width: 100%; margin-top: 6px; justify-content: center; }
.reservation-effacer-tout { align-self: flex-end; }

/* Étapes désactivées tant que la précédente n'est pas remplie. */
.reservation-etape.est-desactivee {
    opacity: .45; pointer-events: none;
    filter: grayscale(.4);
    transition: opacity .18s, filter .18s;
}
.reservation-etape.est-desactivee .reservation-etape-num {
    background: color-mix(in srgb, var(--encre) 25%, transparent);
}
.reservation-etape { margin-top: 28px; }
/* Respiration entre les blocs (grid-2, formulaire-ligne) DANS une étape :
   sans ça, un label vient coller l'input du bloc précédent. On applique le
   même 18 px que la convention `.form-actions { margin: 6px 0 30px }`. */
.reservation-etape > .grid-2 + .grid-2,
.reservation-etape > .grid-2 + .formulaire-ligne,
.reservation-etape > .formulaire-ligne + .grid-2,
.reservation-etape > .formulaire-ligne + .formulaire-ligne {
    margin-top: 18px;
}
/* `.grid-2` — paires de champs côte à côte (prénom/nom, email/tel).
   Défini localement au site pour ne pas dépendre de l'admin.css. */
.reservation-etape .grid-2 {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 16px;
}
@media (max-width: 640px) {
    .reservation-etape .grid-2 { grid-template-columns: 1fr; }
}
/* Cases du picker : réduire l'aspect ratio pour un calendrier plus
   compact verticalement (moins d'espace mort). */
.reservation-mois-jour { aspect-ratio: 1.35 / 1; font-size: 13px; }
.reservation-mois-jour-nom { padding: 2px 0; font-size: 10.5px; }
.reservation-mois { padding: 12px; }
.reservation-mois-tete { margin-bottom: 8px; font-size: 14.5px; }
.reservation-etape-titre {
    display: flex; align-items: center; gap: 10px;
    font-size: 18px; margin: 0 0 12px;
}
.reservation-etape-num {
    display: inline-flex; align-items: center; justify-content: center;
    width: 28px; height: 28px;
    background: var(--c-primaire); color: var(--sur-primaire, #fff);
    border-radius: 50%; font-size: 14px; font-weight: 700;
    flex: 0 0 auto;
}
.reservation-selection {
    display: flex; align-items: center; justify-content: space-between;
    gap: 12px; flex-wrap: wrap;
    padding: 12px 16px; margin-bottom: 14px;
    background: color-mix(in srgb, var(--c-primaire) 8%, var(--fond));
    border: 1px solid color-mix(in srgb, var(--c-primaire) 20%, transparent);
    border-radius: 10px;
    font-size: 15px;
}
.reservation-selection p { margin: 0; }

.reservation-calendriers {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 20px;
}
/* Adaptatif : 3 mois côte à côte sur desktop, 2 sur tablette, 1 sur
   mobile. On aligne le NOMBRE de colonnes sur le nombre de mois
   visibles (pas d'`auto-fit`) : les calendriers doivent TOUJOURS
   rester côte à côte, jamais s'empiler. Les mois masqués restent
   dans le DOM (léger) mais invisibles ; la nav < / > reste opérationnelle.
   Idem pour les libellés dans l'entête. */
@media (max-width: 1100px) {
    .reservation-calendriers { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .reservation-calendriers .reservation-mois:nth-child(n+3) { display: none; }
    .reservation-picker-libelle strong:nth-child(n+3) { display: none; }
}
@media (max-width: 720px) {
    .reservation-calendriers { grid-template-columns: 1fr; }
    .reservation-calendriers .reservation-mois:nth-child(n+2) { display: none; }
    .reservation-picker-libelle strong:nth-child(n+2) { display: none; }
}
.reservation-mois {
    background: var(--carte-fond);
    border: 1px solid var(--carte-bordure);
    border-radius: 12px;
    padding: 14px;
}
.reservation-mois-tete {
    text-align: center; font-weight: 600;
    text-transform: capitalize;
    margin-bottom: 10px;
    color: var(--encre);
}
.reservation-mois-grille {
    display: grid; grid-template-columns: repeat(7, 1fr); gap: 3px;
}
.reservation-mois-jour-nom {
    text-align: center; font-size: 11px; font-weight: 600;
    text-transform: uppercase; color: var(--gris); padding: 3px 0;
}
.reservation-mois-jour {
    aspect-ratio: 1;
    display: flex; align-items: center; justify-content: center;
    border-radius: 6px;
    font-size: 13px; font-weight: 500;
    border: 1px solid transparent;
    background: transparent; color: inherit;
    padding: 0; cursor: pointer;
    transition: transform .1s, background .1s;
}
.reservation-mois-jour.vide { visibility: hidden; }
.reservation-mois-jour.est-libre {
    background: color-mix(in srgb, #10b981 10%, transparent);
    border-color: color-mix(in srgb, #10b981 25%, transparent);
    color: var(--encre);
}
.reservation-mois-jour.est-libre:hover {
    background: color-mix(in srgb, #10b981 25%, transparent);
    transform: scale(1.08);
}
.reservation-mois-jour.est-complet,
.reservation-mois-jour.est-passe {
    color: color-mix(in srgb, var(--encre) 30%, transparent);
    cursor: not-allowed;
}
.reservation-mois-jour.est-complet {
    background: color-mix(in srgb, #dc2626 8%, transparent);
    text-decoration: line-through;
}
.reservation-mois-jour.est-debut,
.reservation-mois-jour.est-fin {
    background: var(--c-primaire);
    color: var(--sur-primaire, #fff);
    border-color: var(--c-primaire);
}
.reservation-mois-jour.est-dans-range {
    background: color-mix(in srgb, var(--c-primaire) 25%, transparent);
    border-color: color-mix(in srgb, var(--c-primaire) 35%, transparent);
    color: var(--encre);
}
/* Hover sur une case DÉJÀ sélectionnée (début / fin / range) : on
   garde le look actif au lieu de repasser en vert « libre ». */
.reservation-mois-jour.est-debut:hover,
.reservation-mois-jour.est-fin:hover {
    background: var(--c-primaire);
    color: var(--sur-primaire, #fff);
    border-color: var(--c-primaire);
    transform: none;
}
.reservation-mois-jour.est-dans-range:hover {
    background: color-mix(in srgb, var(--c-primaire) 25%, transparent);
    border-color: color-mix(in srgb, var(--c-primaire) 35%, transparent);
    transform: none;
}
/* Preview au survol (mode multi-jours) — plus subtil que la sélection
   effective, pour signaler l'aperçu sans confusion avec le range validé. */
.reservation-mois-jour.est-hover-range {
    background: color-mix(in srgb, var(--c-primaire) 12%, transparent);
    border-color: color-mix(in srgb, var(--c-primaire) 20%, transparent);
}
.reservation-mois-jour.est-hover-fin {
    background: color-mix(in srgb, var(--c-primaire) 35%, transparent);
    border-color: color-mix(in srgb, var(--c-primaire) 50%, transparent);
    color: var(--encre);
    font-weight: 600;
}

/* En-tête du picker : nav flèches ronds + libellé des 2 mois centré */
.reservation-picker-tete {
    display: flex; justify-content: space-between; align-items: center;
    gap: 12px; margin-bottom: 12px;
}
.reservation-picker-libelle {
    display: inline-flex; gap: 20px;
    font-weight: 600; color: var(--encre);
    text-transform: capitalize;
    font-size: 16px;
}
/* Flèches < > : cercles neutres avec un léger fond, plus lisibles
   qu'un bouton .btn générique de la charte. */
.reservation-picker-tete [data-picker-nav] {
    display: inline-flex; align-items: center; justify-content: center;
    width: 36px; height: 36px; padding: 0;
    background: var(--carte-fond);
    border: 1px solid var(--carte-bordure);
    color: var(--encre);
    border-radius: 999px;
    cursor: pointer;
    transition: background .15s, border-color .15s, transform .1s;
}
.reservation-picker-tete [data-picker-nav]:hover:not([disabled]) {
    background: color-mix(in srgb, var(--c-primaire) 10%, var(--carte-fond));
    border-color: var(--c-primaire);
    transform: scale(1.06);
}
.reservation-picker-tete [data-picker-nav][disabled] {
    opacity: .35; cursor: not-allowed;
}

/* Encart « Sélection » avec le récapitulatif de la plage + bouton × */
.reservation-selection {
    padding: 14px 18px;
}
[data-effacer-selection] {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 4px 10px 4px 8px;
    background: transparent;
    border: 1px solid color-mix(in srgb, var(--c-primaire) 30%, transparent);
    color: var(--c-primaire);
    border-radius: 999px;
    font-size: 12.5px; font-weight: 500;
    cursor: pointer;
    transition: background .12s, border-color .12s;
}
[data-effacer-selection]:hover {
    background: color-mix(in srgb, var(--c-primaire) 12%, transparent);
    border-color: var(--c-primaire);
}
[data-effacer-selection] svg { flex: 0 0 auto; }

/* Liste des créneaux cochables (checkbox + rail switch) */
.reservation-creneaux-choix {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 8px 14px;
}
.reservation-creneau-choix-journee {
    grid-column: 1 / -1;
    padding-bottom: 8px;
    border-bottom: 1px dashed var(--carte-bordure);
    margin-bottom: 4px;
}
.reservation-creneau-choix {
    display: flex; align-items: center; gap: 10px;
    padding: 10px 14px;
    background: var(--carte-fond);
    border: 1px solid var(--carte-bordure);
    border-radius: 10px;
    cursor: pointer;
    font-size: 15px;
    color: var(--encre);
    transition: border-color .15s, background .15s;
}
.reservation-creneau-choix:hover { border-color: var(--c-primaire); }
.reservation-creneau-choix input {
    accent-color: var(--c-primaire);
    flex: 0 0 auto;
    width: 18px; height: 18px;
}
/* Libellé de créneau : titre (libellé libre s'il existe) au-dessus, horaires
   en petit gris en dessous. Si aucun libellé, l'horaire prend le rôle de
   titre principal (rendu inchangé). */
.reservation-creneau-lib {
    display: flex; flex-direction: column; gap: 2px; line-height: 1.3;
}
.reservation-creneau-lib strong { font-weight: 600; }
.reservation-creneau-lib small { font-size: 12.5px; }
.reservation-creneau-choix:has(input:checked) {
    background: color-mix(in srgb, var(--c-primaire) 12%, var(--carte-fond));
    border-color: var(--c-primaire);
}

/* État MULTI-JOURS : quand l'utilisateur a sélectionné une plage de dates,
   la section « Créneau » n'est plus modifiable (le backend force journée
   entière pour toutes les dates du range). Plutôt que de masquer la section
   comme avant (l'étape semblait disparaître, effet perturbant), on la garde
   visible en mode « pré-rempli grisé » avec un bandeau explicatif au-dessus.
   Le bandeau (::before) reste à opacité pleine — c'est LUI qui doit rester
   lisible ; le titre + le sous-texte + la grille des choix passent à 0.5. */
.reservation-etape[data-creneau-section].est-multi-jours .reservation-etape-titre,
.reservation-etape[data-creneau-section].est-multi-jours > p,
.reservation-etape[data-creneau-section].est-multi-jours .reservation-creneaux-choix {
    opacity: .5;
}
.reservation-etape[data-creneau-section].est-multi-jours .reservation-creneaux-choix {
    pointer-events: none;
}
.reservation-etape[data-creneau-section].est-multi-jours::before {
    content: attr(data-msg-multi);
    display: block;
    margin: 0 0 22px;
    padding: 10px 14px;
    background: color-mix(in srgb, var(--c-primaire) 8%, var(--carte-fond));
    border: 1px solid color-mix(in srgb, var(--c-primaire) 25%, transparent);
    border-radius: 8px;
    font-size: 14px;
    color: var(--encre);
}

/* ============================================================
   Module Publications — grille de couvertures + fiche parution
   ============================================================ */
/* Barre de filtres façon onglets ; aucun cadre autour, juste les puces. */
.publications-filtres {
    display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
    margin: 0 0 24px;
}
.publications-filtre-lien {
    display: inline-block; padding: 5px 12px;
    font-size: 13px; font-weight: 500;
    background: transparent; color: var(--encre);
    border: 1px solid var(--carte-bordure); border-radius: 999px;
    text-decoration: none;
    transition: background .12s ease, color .12s ease, border-color .12s ease;
}
.publications-filtre-lien:hover {
    background: color-mix(in srgb, var(--c-primaire) 8%, transparent);
    border-color: var(--c-primaire);
    color: var(--c-primaire);
}
.publications-filtre-lien.est-actif {
    background: var(--c-primaire); border-color: var(--c-primaire); color: var(--sur-primaire, #fff);
}

/* Grille responsive : 2 cards par ligne en desktop large, 1 en dessous.
   Chaque card est HORIZONTALE (couverture à gauche ~40 %, info à droite). */
.publications-grille {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(440px, 1fr));
    gap: 20px;
}
/* Aligné sur le breakpoint où la card bascule en vertical (640px) —
   éviter 2 cartes verticales côte à côte, chacune très étroite. */
@media (max-width: 640px) {
    .publications-grille { grid-template-columns: 1fr; }
}
.publication-carte {
    position: relative;   /* ancre les stretched-links */
    display: grid;
    /* Couverture en LARGEUR FIXE choisie proche d'un A4 par rapport à
       la hauteur minimale d'une card (titre + description 2 lignes +
       3 CTA ≈ 230 px). 165 px de large donne ~A4 (0.71 = 165/230). La
       couverture s'étend sur TOUTE la hauteur de la card via le grid,
       sans aspect-ratio imposé (l'image en object-fit: cover remplit
       ce rectangle sans zone vide). */
    grid-template-columns: 165px minmax(0, 1fr);
    /* Fond/bordure gérés par la règle générique `.carte, .actu-ligne…`
       — la card prend le fond alterné (le contraire de sa section) pour
       se détacher sur toutes les ambiances. */
    border: 1px solid var(--sur-carte-bordure);
    border-radius: var(--rayon, 12px);
    overflow: hidden;
    transition: transform .18s ease, box-shadow .18s ease;
    cursor: pointer;
}
.publication-carte:hover {
    transform: translateY(-2px);
    box-shadow: 0 10px 28px -12px rgba(0, 0, 0, .22);
}
/* Stretched links : couvrent toute la card, z-index bas — les CTA en
   pied (z-index plus haut) captent leur propre clic. */
.publication-carte-lien {
    position: absolute; inset: 0; z-index: 1;
    background: transparent;
    text-indent: -9999px; overflow: hidden;
}
.publication-carte-lien:focus-visible {
    outline: 3px solid var(--c-primaire);
    outline-offset: 2px;
    border-radius: var(--rayon, 12px);
}
.publication-carte-lien-desktop { display: block; }
.publication-carte-lien-mobile  { display: none; }
@media (max-width: 720px) {
    .publication-carte-lien-desktop { display: none; }
    .publication-carte-lien-mobile  { display: block; }
}

/* Pied de card : bloc invisible, juste les CTA. Les boutons sont en
   `position: relative; z-index: 2` pour rester au-dessus des stretched
   links et recevoir leurs propres clics (télécharger PDF ≠ feuilleter). */
.publication-carte-pied {
    margin-top: auto;   /* pousse au bas de la card, hauteurs alignées */
    padding-top: 12px;
    display: flex; flex-wrap: wrap; gap: 8px;
    position: relative; z-index: 2;
}
.publication-carte-pied .btn-envoyer {
    padding: 7px 14px !important;
    font-size: 12.5px;
    gap: 6px;
}
.publication-carte-pied .btn-envoyer .ico {
    width: 14px; height: 14px;
}

/* Visibilité par device — 2 CTA à chaque fois.
   Desktop : Feuilleter (primary) + Télécharger (outline). Consulter caché.
   Mobile  : Consulter (primary) + Télécharger (outline). Feuilleter caché.
   `!important` obligatoire ici car `.btn-envoyer` définit lui-même
   `display: inline-flex !important` (règle globale des CTA du site). */
.publication-carte-cta-feuilleter  { display: inline-flex !important; }
.publication-carte-cta-consulter   { display: none !important; }
.publication-carte-cta-telecharger { display: inline-flex !important; }
@media (max-width: 720px) {
    .publication-carte-cta-feuilleter { display: none !important; }
    .publication-carte-cta-consulter  { display: inline-flex !important; }
    /* Consulter mobile = CTA primaire (fond plein, par défaut de .btn-envoyer) */
}
.publication-carte-couverture {
    display: block;
    background: #f1f5f9;
    overflow: hidden;
    border-right: 1px solid var(--carte-bordure, #e6eaf1);
    /* Pas d'aspect-ratio en desktop — la couverture s'étire à la hauteur
       de la card via `align-self: stretch` (défaut du grid). L'image
       en cover remplit sans zone vide. */
}
.publication-carte-couverture img { width: 100%; height: 100%; object-fit: cover; display: block; }
.publication-carte-couverture-vide { display: flex; align-items: center; justify-content: center; height: 100%; color: var(--gris); }
/* Mobile : couverture pleine largeur au-dessus, corps en dessous.
   On repasse en 1 colonne + on rétablit l'aspect-ratio A4 (sans
   contrainte de hauteur de card horizontale, on peut se permettre
   la forme A4 exacte). Bordure droite → bordure basse. */
@media (max-width: 640px) {
    .publication-carte { grid-template-columns: 1fr; }
    .publication-carte-couverture {
        aspect-ratio: 210 / 297;
        border-right: 0;
        border-bottom: 1px solid var(--carte-bordure, #e6eaf1);
    }
}
.publication-carte-corps {
    display: flex; flex-direction: column;
    padding: 16px 18px;
    gap: 8px;
    min-width: 0;
}
/* Chip magazine — style badge coloré aligné sur l'ambiance de la commune
   (utilise --bleu-clair / --bleu du site). */
.publication-carte-chip {
    display: inline-block;
    padding: 3px 10px;
    background: color-mix(in srgb, var(--c-primaire) 12%, transparent);
    color: var(--c-primaire);
    border-radius: 999px;
    font-size: 11px; font-weight: 700;
    letter-spacing: .3px; text-transform: uppercase;
    align-self: flex-start;
    text-decoration: none;
    transition: background .12s ease;
}
a.publication-carte-chip:hover {
    background: color-mix(in srgb, var(--c-primaire) 22%, transparent);
}

/* Bouton secondaire (variante outline de .btn-envoyer) — même forme
   pilulée, mais fond transparent + bordure primaire. Utilisé sur la
   fiche publication pour « Télécharger » à côté du CTA « Feuilleter ». */
.btn-envoyer.btn-envoyer-outline {
    background: transparent !important;
    color: var(--c-primaire) !important;
    box-shadow: inset 0 0 0 1.5px var(--c-primaire);
}
.btn-envoyer.btn-envoyer-outline:hover {
    background: color-mix(in srgb, var(--c-primaire) 8%, transparent) !important;
    box-shadow: inset 0 0 0 1.5px var(--c-primaire);
    transform: translateY(-1px);
}
/* Variante COMPACTE de .btn-envoyer — même identité (pilulé, couleur de
   la commune) mais moins imposante. Utilisée pour les actions secondaires
   dans un formulaire (ex. « Me localiser » dans le signalement). */
.btn-envoyer.btn-envoyer-sm {
    padding: 8px 16px !important;
    font-size: 14px;
    gap: 7px;
}
.btn-envoyer.btn-envoyer-sm svg { width: 14px; height: 14px; }
.publication-carte-titre {
    margin: 0;
    font-size: 20px; line-height: 1.25; font-weight: 700;
    color: var(--encre);
}
.publication-carte-meta {
    margin: 0;
    font-size: 13px;
    display: flex; align-items: center; gap: 6px;
    color: var(--gris);
}
.publication-carte-meta-sep { opacity: .5; }
/* Description : plafonnée à 2 lignes (ellipsis) pour garder une hauteur
   de card stable dans la grille — sinon 1 description longue étire toute
   sa ligne et rend la grille irrégulière. */
.publication-carte-desc {
    margin: 0;
    font-size: 13.5px; line-height: 1.4; color: var(--sur-carte-gris, var(--gris));
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow: hidden;
}

/* ============================================================
   Section « En kiosque » home — coverflow 3D style présentoir
   Perspective sur le scene, chaque item positionné absolute au centre
   et transformé selon sa distance à l'actif (translateX + translateZ
   + rotateY + scale + opacité). Info centralisée sous, mise à jour
   par JS depuis les data-* de l'item actif.
   ============================================================ */
/* Layout 2 colonnes STRICTEMENT ÉGALES (moitié/moitié). Le coverflow
   à gauche peut déborder — mais la marge entre les 2 colonnes protège
   la lisibilité du texte info à droite.
   Variables `--cf-gap` / `--cf-depth` : lues par le JS pour calculer
   les décalages — ajustables via media queries pour resserrer
   l'éventail en mobile sans dupliquer la logique JS. */
.pub-coverflow {
    --cf-gap: 130px;
    --cf-depth: 100px;
    /* Hauteur des vignettes — largeur dérivée automatiquement du ratio
       propre à chaque couverture (`aspect-ratio: var(--ratio)`).
       Barème par taille d'écran : plus petit en tablette/desktop standard,
       plus grand aux extrêmes (mobile ET wide desktop >1300). */
    --cf-h: 320px;
    /* Ancre horizontale de l'item (préfixe du transform JS) :
         -50% = centrage sur `left: X%` (desktop, ancre au centre)
           0% = ancrage sur BORD GAUCHE (mobile, alignement avec le texte
                en dessous). Change via media queries — pas de duplication JS. */
    --cf-anchor-x: -50%;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 56px;
    align-items: center;
}
.pub-coverflow-scene {
    position: relative;
    width: 100%;
    /* Hauteur = hauteur des vignettes + marge visuelle (ombre portée). */
    height: calc(var(--cf-h) + 40px);
    perspective: 1400px;
    transform-style: preserve-3d;
    /* Débordement autorisé côté droit — la vignette active est ancrée
       près de la colonne info, les récentes disparaissent hors champ. */
    overflow: visible;
    z-index: 1;
}
.pub-coverflow-cote {
    display: flex; flex-direction: column; gap: 20px;
    min-width: 0;
    /* La colonne info passe DEVANT la scène : si une vignette latérale
       déborde à droite, le texte info reste lisible dessus. */
    position: relative;
    z-index: 5;
}
/* Chaque item est un <button> — bouton natif pour l'accessibilité clavier
   (Tab + Enter), transformé à l'absolute au centre puis translaté par JS. */
.pub-coverflow-item {
    position: absolute;
    top: 50%;
    /* Ancre à ~62 % : la vignette active penche vers la droite dans
       sa colonne mais garde une bonne marge de sécurité côté info,
       et laisse plus de place aux latérales qui s'étalent à gauche. */
    left: 62%;
    /* Hauteur fixe (`--cf-h`), largeur dérivée du RATIO PROPRE à chaque
       couverture (calculé côté PHP via getimagesize, injecté en `--ratio`
       inline). Fallback A4 (24/34 ≈ 0.706) si la lecture échoue. Le
       centrage est fait par le préfixe `translate(-50%, -50%)` appliqué
       en JS, plus par des marges hardcodées. */
    height: var(--cf-h);
    width: auto;
    aspect-ratio: var(--ratio, 24 / 34);
    padding: 0;
    /* Aplat de fond qui reste TOUJOURS 100 % opaque — même quand
       l'image s'estompe (voir img plus bas). On prend explicitement
       `--fond` (fond de section CLAIRE, jamais l'alt) pour rester
       stable quelle que soit la position d'alternance de la section. */
    background: var(--fond, #ffffff);
    border: 0;
    border-radius: var(--rayon, 12px);
    overflow: hidden;
    cursor: pointer;
    /* Transform initial (sera écrasé par le JS). Transition 500 ms,
       easing doux type "présentoir qui pivote". */
    transform: translate3d(0, 0, 0);
    transition: transform .5s cubic-bezier(.22, .61, .36, 1),
                box-shadow .5s ease;
    /* Ombre par DÉFAUT (non-active) : discrète, juste un liseré. */
    box-shadow: 0 4px 14px -6px rgba(0, 0, 0, .25);
}
/* Ombre APPUYÉE sur la vignette active — elle "pop" en avant du présentoir. */
.pub-coverflow-item.est-actif {
    box-shadow: 0 24px 60px -20px rgba(0, 0, 0, .55);
}
/* L'IMAGE porte l'opacité et le brightness — pas l'item entier. Ainsi
   les latérales sont visuellement en retrait (image estompée) mais
   leur silhouette (aplat de fond) reste bien découpée.
   `object-fit: contain` : la couverture garde SON ratio (pas coupée),
   l'aplat de fond opaque remplit l'éventuel espace autour. */
.pub-coverflow-item img {
    width: 100%; height: 100%; object-fit: cover; display: block;
    pointer-events: none;   /* le clic remonte au bouton */
    transition: opacity .5s ease, filter .5s ease;
}
.pub-coverflow-vide {
    display: flex; align-items: center; justify-content: center;
    height: 100%; color: var(--gris);
}
/* Item actif : pas de transform (translate/rotate/scale = 0), premier plan. */
.pub-coverflow-item.est-actif {
    z-index: 10;
    cursor: default;
}
.pub-coverflow-item.est-actif:hover {
    transform: translate3d(0, -4px, 0);
}

/* Bloc info (chip + titre + date + CTAs) — à droite du coverflow.
   Aligné à gauche (colonne droite), pas centré comme en single-col. */
.pub-coverflow-info {
    display: flex; flex-direction: column; gap: 12px;
    min-height: 180px;   /* évite un saut vertical à chaque changement de slide */
}
.pub-coverflow-titre {
    margin: 0;
    font-size: clamp(28px, 3vw, 40px); line-height: 1.15; font-weight: 700;
    color: var(--encre);
}
.pub-coverflow-date { margin: 0; font-size: 14px; }
.pub-coverflow-actions {
    display: flex; flex-wrap: wrap; gap: 10px;
    margin-top: 8px;
}

/* Nav prev/next — sous l'info, aligné à gauche.
   Boutons ronds au ton de la commune, halo subtil au hover — cohérent
   avec les autres CTAs du site (rayon `--rayon-cta`). */
.pub-coverflow-nav {
    display: flex; align-items: center; gap: 12px;
}
.pub-coverflow-btn {
    display: inline-flex; align-items: center; justify-content: center;
    width: 44px; height: 44px;
    padding: 0;
    background: color-mix(in srgb, var(--c-primaire) 10%, transparent);
    color: var(--c-primaire);
    border: 0; border-radius: 999px;
    cursor: pointer;
    transition: background .18s ease, color .18s ease, transform .18s ease;
}
.pub-coverflow-btn:hover {
    background: var(--c-primaire);
    color: var(--sur-primaire-accent, #fff);
    transform: translateY(-1px);
}
.pub-coverflow-btn:active { transform: translateY(0); }
/* État désactivé — utilisé au démarrage sur la flèche « suivant » tant
   que la rotation cyclique n'a pas été enclenchée par un premier « prev ». */
.pub-coverflow-btn:disabled,
.pub-coverflow-btn[disabled] {
    opacity: .35;
    cursor: not-allowed;
    pointer-events: none;
}

/* Responsive : on garde les 2 colonnes en toutes tailles — juste réduire
   les tailles des couvertures + resserrer l'éventail. La colonne des
   miniatures rétrécit plus vite que la colonne info pour préserver la
   lisibilité du texte. Les miniatures excédentaires partent hors champ
   à gauche via la rotation cyclique (voir JS). */
/* Wide desktop (>1300) : couvertures un cran au-dessus du barème standard,
   les grands écrans peuvent absorber davantage de matière visuelle. */
@media (min-width: 1301px) {
    .pub-coverflow {
        --cf-h: 370px;
    }
}
@media (max-width: 900px) {
    .pub-coverflow {
        grid-template-columns: 1fr 1.2fr;
        gap: 56px;            /* espace couverture ↔ titre élargi (était 28) */
        --cf-gap: 90px;
        --cf-depth: 65px;
        --cf-h: 245px;
    }
}
/* Mobile : passe en mono-colonne. Tout est aligné à gauche, y compris
   la couverture active (son BORD GAUCHE aligné avec le contenu texte
   dessous — via `--cf-anchor-x: 0%` qui bascule le préfixe JS de
   `translate(-50%…)` à `translate(0…)`).
   La scène déborde à droite (margin-right négative) pour que les
   latérales partent hors du .conteneur — clippées par overflow-x hidden
   sur la section, pas de scrollbar horizontale. */
@media (max-width: 640px) {
    .pub-coverflow {
        grid-template-columns: 1fr;
        gap: 20px;
        --cf-gap: 85px;        /* éventail élargi en mobile */
        --cf-depth: 50px;
        --cf-h: 300px;         /* couvertures un cran au-dessus vs desktop médian */
        /* --cf-anchor-x reste à -50% (défaut) : ancrage au CENTRE de l'item,
           couverture active centrée sur la scène. Les latérales partent hors
           champ des DEUX côtés symétriquement (peek droit d=1 + fan gauche). */
    }
    .pub-coverflow-scene {
        /* Élargissement SYMÉTRIQUE : la scène déborde du padding .conteneur
           des deux côtés, autorisant les latérales à sortir à gauche ET à
           droite. `overflow-x: hidden` sur .home-publications (plus bas)
           empêche la scrollbar horizontale. */
        margin: 0 -24px;
        width: calc(100% + 48px);
    }
    .pub-coverflow-item {
        /* Ancre au centre horizontal de la scène élargie. */
        left: 50%;
    }
    .pub-coverflow-cote {
        max-width: none;
        margin: 0;
        /* Contenu centré : titre, date, CTAs, flèches. */
        align-items: center;
        text-align: center;
    }
    .pub-coverflow-info { align-items: center; }
    /* Chip magazine : inline-block, `align-self: center` explicite pour
       s'affranchir de toute règle de flex-item qui pourrait le stretcher. */
    .pub-coverflow-info .publication-carte-chip { align-self: center; }
    .pub-coverflow-actions { justify-content: center; }
    .pub-coverflow-nav { justify-content: center; }
    /* CTAs plus compacts en mobile — pas d'étirement sur toute la largeur. */
    .pub-coverflow-actions .btn-envoyer {
        padding: 8px 14px !important;
        font-size: 12.5px;
        gap: 6px;
    }
    .pub-coverflow-actions .btn-envoyer .ico { width: 13px; height: 13px; }
}
/* .home-publications : coupe l'overflow horizontal pour que la scène
   élargie n'introduise pas de scrollbar (mobile uniquement — desktop
   laisse déborder sous la colonne info, z-index gère la lisibilité). */
@media (max-width: 640px) {
    .home-publications { overflow-x: hidden; }
}
@media (max-width: 480px) {
    .pub-coverflow {
        gap: 16px;
        --cf-gap: 75px;        /* éventail élargi (mobile étroit) */
        --cf-h: 260px;
    }
    .pub-coverflow-actions .btn-envoyer {
        padding: 6px 12px !important;
        font-size: 12px;
    }
}

/* Fiche d'une parution — layout 2 colonnes */
.publication-fiche {
    display: grid; grid-template-columns: 340px minmax(0, 1fr); gap: 40px;
    margin-top: 12px;
}
@media (max-width: 900px) {
    .publication-fiche { grid-template-columns: 1fr; gap: 24px; }
    .publication-fiche-couverture { max-width: 300px; margin: 0 auto; }
}
.publication-fiche-couverture {
    background: #f1f5f9; border-radius: var(--rayon, 12px); overflow: hidden;
    box-shadow: 0 14px 40px -14px rgba(0, 0, 0, .28);
    aspect-ratio: 3 / 4;
}
.publication-fiche-couverture img { width: 100%; height: 100%; object-fit: cover; display: block; }
.publication-fiche-couverture-vide { display: flex; align-items: center; justify-content: center; height: 100%; color: var(--gris); }
.publication-fiche-corps { min-width: 0; }
.publication-meta { display: flex; flex-wrap: wrap; gap: 14px; font-size: 13px; margin: 4px 0 20px; }
.publication-meta span { display: inline-flex; align-items: center; gap: 6px; }
.publication-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 26px; }


/* ==========================================================================
   Module Rendez-vous — pages publiques
   ==========================================================================
   Aucune couleur en dur hormis le vert et le rouge de disponibilité : ceux-là
   portent un SENS et doivent rester lisibles quelle que soit la palette de la
   commune. Tout le reste suit --c-primaire, --rayon et --carte-*.
   ========================================================================== */

/* --------- Liste des démarches --------- */
.rdv-type-carte {
    /* gap: 12px (au lieu de 8) — donne de l'air à la pastille durée
       qui se retrouvait autrement collée au h2 sur une démarche sans
       description (uniquement titre + pastille). Le gap agit aussi
       entre h2 et description, pour un rythme cohérent. */
    display: flex; flex-direction: column; gap: 12px;
    padding: 22px 24px; text-decoration: none; color: inherit;
    background: var(--carte-fond, #fff);
    border: 1.5px solid var(--carte-bordure, rgba(15, 23, 42, .12));
    border-radius: var(--rayon, 12px);
    transition: transform .2s ease, border-color .2s ease, box-shadow .2s ease;
}
.rdv-type-carte:hover {
    border-color: var(--c-primaire);
    transform: translateY(-3px);
    box-shadow: 0 14px 30px -10px rgba(15, 23, 42, .18);
}
.rdv-type-carte h2 { margin: 0; font-size: 20px; }
.rdv-type-carte p { margin: 0; font-size: 15px; opacity: .8; line-height: 1.5; }
/* `margin-top: auto` colle la durée en bas : les textes d'une même rangée ont
   des longueurs différentes, sans cela le badge flotte au milieu. */
.rdv-duree {
    margin-top: auto; align-self: flex-start;
    font-size: 13px; font-weight: 600; padding: 4px 12px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--c-primaire) 12%, transparent);
    color: var(--c-primaire);
}

/* --------- Étapes du parcours --------- */
.rdv-etape { margin: 34px 0 0; }
.rdv-etape-titre {
    display: flex; align-items: center; gap: 12px;
    font-size: 21px; margin: 0 0 18px;
}
.rdv-etape-num {
    flex: 0 0 auto;
    width: 30px; height: 30px; border-radius: 999px;
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 15px; font-weight: 700;
    background: var(--c-primaire);
    color: var(--sur-primaire-accent, #fff);
}
/* Étape pas encore accessible : grisée et inerte. `pointer-events: none`
   plutôt qu'un masquage — le visiteur voit ce qui l'attend, ce qui rend le
   parcours prévisible au lieu de faire surgir un bloc sans prévenir. */
.rdv-etape.est-desactivee { opacity: .45; pointer-events: none; }
.rdv-etape.est-desactivee .rdv-etape-num {
    background: color-mix(in srgb, var(--encre) 25%, transparent);
}

/* --------- Questions conditionnelles --------- */
.rdv-questions fieldset {
    border: 1.5px solid var(--carte-bordure, rgba(15, 23, 42, .12));
    border-radius: var(--rayon, 12px);
    padding: 16px 20px 18px; margin: 0 0 16px;
}
.rdv-questions legend { font-weight: 650; padding: 0 8px; font-size: 15.5px; }
/* Réponses en pastilles : la cible tactile d'un bouton radio nu fait 13 px,
   celle-ci fait toute la pastille. */
.rdv-choix {
    display: inline-flex; align-items: center; gap: 9px;
    padding: 9px 16px; margin: 4px 8px 4px 0; cursor: pointer;
    border: 1.5px solid var(--carte-bordure, rgba(15, 23, 42, .12));
    border-radius: 999px;
    transition: border-color .15s ease, background .15s ease;
}
.rdv-choix:hover { border-color: var(--c-primaire); }
.rdv-choix input { accent-color: var(--c-primaire); margin: 0; }
.rdv-choix:has(input:checked) {
    border-color: var(--c-primaire);
    background: color-mix(in srgb, var(--c-primaire) 10%, transparent);
    font-weight: 600;
}

/* --------- Pièces à apporter --------- */
.rdv-pieces-bloc {
    margin: 22px 0 0; padding: 18px 22px;
    background: color-mix(in srgb, var(--c-primaire) 6%, transparent);
    border-left: 3px solid var(--c-primaire);
    border-radius: var(--rayon, 12px);
}
.rdv-pieces-bloc h3 { margin-top: 0; font-size: 17px; }
.rdv-pieces { margin: 0; padding-left: 20px; }
.rdv-pieces li { margin-bottom: 7px; line-height: 1.55; }

/* --------- Sélecteur date / heure, deux colonnes --------- */
/* minmax(0, …) des deux côtés : sans le minimum à zéro, une liste d'heures
   fournie élargit sa colonne et déforme le calendrier d'en face. */
.rdv-picker {
    display: grid;
    /* Colonne de gauche fixee au calendrier (une grille de sept jours n'a rien a
       gagner a s'etirer), le reste aux creneaux : plus de largeur = plus
       d'horaires par ligne, donc moins de defilement. */
    grid-template-columns: minmax(0, 440px) minmax(0, 1fr);
    gap: 32px; align-items: start;
}
.rdv-picker-carte {
    background: var(--carte-fond, #fff);
    border: 1.5px solid var(--carte-bordure, rgba(15, 23, 42, .12));
    border-radius: var(--rayon, 12px);
    padding: 20px 22px;
}
.rdv-picker-titre {
    display: flex; align-items: center; gap: 8px;
    margin: 0 0 16px; font-size: 16px; font-weight: 650;
}
.rdv-picker-titre .ico { opacity: .7; }
.rdv-picker-jour {
    margin: 0 0 14px; font-weight: 600; text-transform: capitalize;
}
/* Colonne de droite au repos : même hauteur visuelle que le calendrier, pour
   que le choix d'un jour ne fasse pas sauter la page. */
.rdv-picker-vide {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 12px; min-height: 260px; text-align: center;
    color: color-mix(in srgb, var(--encre) 45%, transparent);
}
.rdv-picker-vide p { margin: 0; font-size: 14.5px; line-height: 1.5; }

/* --------- Calendrier mensuel --------- */
.rdv-cal-tete {
    display: flex; align-items: center; justify-content: space-between;
    gap: 10px; margin-bottom: 12px;
}
.rdv-cal-tete strong { font-size: 15.5px; }
.rdv-cal-nav {
    width: 30px; height: 30px; border-radius: 999px;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--fond); color: var(--encre);
    border: 1px solid var(--carte-bordure, rgba(15, 23, 42, .12));
    text-decoration: none;
    transition: background .12s, border-color .12s;
}
.rdv-cal-nav:hover {
    background: color-mix(in srgb, var(--c-primaire) 12%, var(--fond));
    border-color: var(--c-primaire);
}
.rdv-cal-nav.est-desactivee { opacity: .3; cursor: not-allowed; }

.rdv-cal-grille { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; }
.rdv-cal-jour-nom {
    text-align: center; font-size: 10.5px; font-weight: 600;
    text-transform: uppercase; color: var(--gris); padding: 2px 0;
}
.rdv-cal-jour {
    aspect-ratio: 1;
    display: flex; align-items: center; justify-content: center;
    border-radius: 7px; font-size: 13px; font-weight: 500;
    border: 1px solid transparent; text-decoration: none; color: inherit;
}
.rdv-cal-jour.est-vide { visibility: hidden; }
/* Le vert et le rouge sont les seules couleurs en dur du module. Ils portent
   le sens « ouvert / fermé » : les dériver de --c-primaire rendrait la grille
   illisible pour une commune dont la couleur est déjà rouge ou verte. */
.rdv-cal-jour.est-libre {
    background: color-mix(in srgb, #10b981 12%, transparent);
    border-color: color-mix(in srgb, #10b981 30%, transparent);
    font-weight: 600;
    transition: transform .12s, background .12s;
}
/* La couleur du chiffre est FIXEE au survol. Les cases sont des `<a>`, qui
   heritent de `--c-liens` : sur un fond vert clair, une teinte communale claire
   rendait le numero du jour illisible au moment precis ou l'on vise. Le vert de
   fond porte deja le sens « disponible », le chiffre n'a qu'a rester lisible. */
.rdv-cal-jour.est-libre,
.rdv-cal-jour.est-libre:hover,
.rdv-cal-jour.est-libre:focus-visible { color: var(--encre); }
.rdv-cal-jour.est-libre:hover {
    background: color-mix(in srgb, #10b981 25%, transparent);
    transform: scale(1.08);
}
.rdv-cal-jour.est-choisi {
    background: var(--c-primaire);
    color: var(--sur-primaire-accent, #fff);
    border-color: var(--c-primaire);
}
.rdv-cal-jour.est-indisponible {
    background: color-mix(in srgb, var(--encre) 5%, transparent);
    color: color-mix(in srgb, var(--encre) 32%, transparent);
}
/* La légende est un conteneur flex : chaque pastille et chaque libellé y
   seraient des éléments SÉPARÉS, écartés par le `gap` et hors de portée de
   `vertical-align`, qui n'a aucun effet sur un élément flex. D'où le
   regroupement dans `.rdv-cal-item` — c'est lui qui aligne la pastille sur
   le texte. Même correctif sur `.salle-calendrier-legende`. */
.rdv-cal-legende {
    margin: 12px 0 0; font-size: 11.5px;
    display: flex; flex-wrap: wrap; gap: 6px;
    align-items: center; justify-content: center;
}
.rdv-cal-item { display: inline-flex; align-items: center; gap: 5px; }
.rdv-cal-pastille {
    width: 10px; height: 10px; border-radius: 3px;
    flex: none;   /* une pastille ne se comprime jamais */
}
.rdv-cal-pastille.est-libre { background: color-mix(in srgb, #10b981 45%, transparent); }
.rdv-cal-pastille.est-indisponible { background: color-mix(in srgb, var(--encre) 15%, transparent); }

/* --------- Créneaux horaires --------- */
.rdv-heures { display: flex; flex-wrap: wrap; gap: 8px; }
.rdv-heure {
    font: inherit; font-size: 15px; font-weight: 600;
    padding: 10px 18px; min-width: 84px; text-align: center;
    text-decoration: none;
    background: var(--carte-fond, #fff);
    color: var(--c-primaire);
    border: 1.5px solid color-mix(in srgb, var(--c-primaire) 35%, transparent);
    /* Plafonné à 1.5rem : un rayon « très arrondi » choisi par la commune
       déformerait ces boutons larges. Même règle que les textarea. */
    border-radius: min(var(--rayon-cta, 999px), 1.5rem);
    transition: background .15s ease, color .15s ease, border-color .15s ease;
}
.rdv-heure:hover { background: color-mix(in srgb, var(--c-primaire) 12%, transparent); }
.rdv-heure.est-choisi {
    background: var(--c-primaire);
    color: var(--sur-primaire-accent, #fff);
    border-color: var(--c-primaire);
}

/* --------- Récapitulatif et formulaire --------- */
.rdv-recap {
    margin: 0 0 22px; padding: 18px 20px;
    background: color-mix(in srgb, var(--c-primaire) 8%, transparent);
    border-radius: var(--rayon, 12px);
}
.rdv-recap p { margin: 0 0 4px; font-size: 17px; }
.rdv-recap p:last-child { margin-bottom: 0; font-size: 14.5px; }
.rdv-formulaire {
    display: flex; flex-direction: column; gap: 16px;
    padding: 26px 28px;
    background: var(--carte-fond, #fff);
    border: 1.5px solid var(--carte-bordure, rgba(15, 23, 42, .12));
    border-radius: var(--rayon, 12px);
}
.rdv-formulaire .formulaire-rgpd {
    display: flex; gap: 10px; align-items: flex-start;
    font-size: 14px; font-weight: 400; line-height: 1.5;
}
.rdv-formulaire .formulaire-rgpd input {
    width: 17px; height: 17px; margin: 2px 0 0; flex: 0 0 auto;
    accent-color: var(--c-primaire);
}
/* `align-self: flex-start` : le formulaire est une colonne flex, dont les
   enfants s'etirent par defaut sur toute la largeur. Sans cette ligne le bouton
   fait 100 % et ressemble a une barre, pas a une action. Elle visait `.btn-cta`,
   une classe qui n'existe plus dans le balisage — d'ou le bouton etire. */
.rdv-formulaire .btn-envoyer { align-self: flex-start; }

/* Piège à robots : hors flux, sans aria-hidden ni tabindex qui le trahiraient. */
.fm-piege { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.rdv-vide {
    padding: 24px; text-align: center; opacity: .7;
    border: 1.5px dashed var(--carte-bordure, rgba(15, 23, 42, .18));
    border-radius: var(--rayon, 12px);
}

@media (max-width: 860px) {
    .rdv-picker { grid-template-columns: 1fr; }
}
@media (max-width: 600px) {
    .rdv-formulaire { padding: 20px 18px; }
    .rdv-heure { min-width: 72px; padding: 10px 14px; }
}

/* Echange AJAX du calendrier : on attenue sans masquer, pour que la page ne
   saute pas et que l'usager garde ses reperes pendant le chargement. */
[data-rdv-dynamique] { transition: opacity .12s ease; }
[data-rdv-dynamique].est-en-chargement { opacity: .5; pointer-events: none; }
/* --------- Parcours en un écran par étape --------- */
/* Le rail latéral a disparu avec l'empilement : chaque étape tient dans un
   écran, la mesure est donc centrée et bornée pour rester lisible. */
.rdv-retour { margin: 0 0 18px; font-size: 15px; }
.rdv-retour a {
    display: inline-flex; align-items: center; gap: 4px;
    text-decoration: none; color: var(--c-primaire);
}
.rdv-retour a:hover { text-decoration: underline; }

/* Les deux ecrans prennent toute la mesure de `.page-conteneur`, comme le reste
   du site. Le decoupage en deux colonnes suffit a garder des lignes lisibles :
   c'est la LARGEUR DE COLONNE qui borne le confort de lecture, pas celle du
   bloc entier. */
.rdv-picker { margin: 0 auto; }
.rdv-recap { margin: 0 auto 22px; }

/* Ecran de validation : formulaire a gauche, pieces a apporter a droite.
   `align-items: start` pour que la colonne des pieces ne s'etire pas a la
   hauteur du formulaire, qui est bien plus long. */
.rdv-deux-colonnes {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 430px);
    gap: 44px; align-items: start;
}
.rdv-deux-colonnes .rdv-formulaire {
    max-width: none; margin: 0;
    background: var(--carte-fond, #fff);
    border: 1.5px solid var(--carte-bordure, rgba(15, 23, 42, .12));
    border-radius: var(--rayon, 12px);
    padding: 28px 30px;
}
/* Colonne de droite : le rappel du rendez-vous, puis les justificatifs.
   Collante a 90 px, la valeur commune a tous les rails du site — l'en-tete est
   lui-meme collant (`.site-header`, top: 0) et un rail cale plus haut glisse
   dessous des le premier defilement. Le formulaire est long : sans cela, ce
   qu'il faut apporter sort de l'ecran juste au moment ou on le remplit. */
.rdv-cote {
    display: flex; flex-direction: column; gap: 20px; min-width: 0;
    position: sticky; top: 90px;
}
.rdv-cote .rdv-recap { margin: 0; }
.rdv-cote .rdv-pieces-bloc { margin: 0; }
.rdv-cote .rdv-pieces-bloc h3 {
    display: flex; align-items: center; gap: 8px;
    margin: 0 0 12px; font-size: 17px;
}

@media (max-width: 900px) {
    /* La colonne passe SOUS le formulaire et cesse d'etre collante : sur un
       ecran etroit, deux colonnes ne laissent de place ni a l'une ni a l'autre,
       et un bloc fige mangerait la moitie de la hauteur utile. */
    .rdv-deux-colonnes { grid-template-columns: 1fr; gap: 24px; }
    .rdv-cote { position: static; }
}

/* Prénom et nom côte à côte : deux champs courts sur une ligne évitent un
   formulaire inutilement long. */
.rdv-form-2 { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 16px; }

/* Encart d'avertissement — la pré-demande ANTS. Placé AVANT le champ : quelqu'un
   qui ne l'a pas faite doit s'en apercevoir avant de saisir, pas après. */
.rdv-encart {
    margin: 20px 0; padding: 16px 18px;
    background: color-mix(in srgb, #f59e0b 12%, transparent);
    border: 1px solid color-mix(in srgb, #f59e0b 40%, transparent);
    border-radius: var(--rayon, 12px);
    font-size: 14.5px; line-height: 1.55;
}
.rdv-encart p { margin: 0 0 8px; }
.rdv-encart p:last-child { margin-bottom: 0; }
.rdv-encart-titre {
    display: flex; align-items: center; gap: 8px;
    font-weight: 650;
}
.rdv-encart a { font-weight: 600; }

/* Rappel des pièces sur l'écran des coordonnées : c'est là que le visiteur
   prépare sa venue. */
.rdv-formulaire .rdv-pieces-bloc { margin: 4px 0 0; }
.rdv-formulaire .rdv-pieces-bloc h3 {
    display: flex; align-items: center; gap: 8px;
    margin: 0 0 10px; font-size: 16px;
}

@media (max-width: 600px) {
    .rdv-form-2 { grid-template-columns: 1fr; }
    .rdv-carte-ecran { padding: 22px 18px; }
}

/* Variante sobre du bouton d'envoi : meme forme, sans le fond plein, pour une
   action secondaire qui ne doit pas concurrencer la validation. */
.btn-envoyer.btn-envoyer-outline {
    background: transparent;
    color: var(--c-primaire, var(--c-liens)) !important;
    border: 1.5px solid color-mix(in srgb, var(--c-primaire, var(--c-liens)) 40%, transparent);
    box-shadow: none;
}
.btn-envoyer.btn-envoyer-outline:hover {
    background: color-mix(in srgb, var(--c-primaire, var(--c-liens)) 10%, transparent);
    box-shadow: none;
}

/* ---------- Mention « traduction automatique » --------------------------
   Bandeau discret injecté sous le titre d'un contenu (actu / event / page /
   salle / publication / album) quand le visiteur consulte une version
   non française. Fond neutre, encre atténuée, jamais aligné sur la
   couleur primaire : c'est un avertissement, pas un accent. */
.traduction-auto-mention {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    margin: 12px 0 20px;
    padding: 10px 14px;
    background: color-mix(in srgb, var(--gris, #64748b) 10%, transparent);
    border-left: 3px solid color-mix(in srgb, var(--gris, #64748b) 40%, transparent);
    border-radius: 6px;
    color: var(--gris, #56606f);
    font-size: 13.5px; line-height: 1.5;
}
.traduction-auto-mention svg {
    flex-shrink: 0;
    margin-top: 2px;
    color: color-mix(in srgb, var(--gris, #64748b) 70%, transparent);
}
/* RTL (arabe) : le filet colore le bord droit à la place du bord gauche. */
html[dir="rtl"] .traduction-auto-mention {
    border-left: 0;
    border-right: 3px solid color-mix(in srgb, var(--gris, #64748b) 40%, transparent);
}

/* ==========================================================================
   Support RTL (arabe) — règles minimales.
   Le module `lang_ar` ajoute `dir="rtl"` sur <html>. Le layout global suit
   naturellement (flexbox, block, `text-align: start`), mais certains
   composants asymétriques nécessitent une inversion explicite.
   ========================================================================== */

/* Filet de sécurité contre le scroll horizontal en RTL — un élément
   isolé qui utilise encore `padding-left/right` ou `right:` physique
   au lieu de propriétés logiques dépasse par la droite (côté négatif
   en RTL) et déclenche une scrollbar horizontale sur mobile. On
   clippe silencieusement, sans casser le sticky ni les modales
   (`overflow-x: clip` respecte les positionnements fixed/sticky,
   contrairement à `hidden`). */
html[dir="rtl"], html[dir="rtl"] body {
    overflow-x: clip;
    max-width: 100vw;
}

/* Alignement par défaut du texte : right en RTL. La règle est portée par
   <html dir> nativement, on la re-affirme sur les conteneurs de contenu
   qui portent des `text-align: left` explicites hérités du LTR. */
html[dir="rtl"] .prose,
html[dir="rtl"] .article-corps,
html[dir="rtl"] .article-chapo,
html[dir="rtl"] .article-entete,
html[dir="rtl"] .page-titre {
    text-align: right;
}

/* Fil d'Ariane : le chevron ">" pointe naturellement dans le sens de la
   lecture (à droite en LTR). En RTL, on retourne le glyphe pour qu'il
   pointe à gauche — cohérent avec la direction du texte. */
html[dir="rtl"] .fil-ariane svg,
html[dir="rtl"] .breadcrumb svg {
    transform: scaleX(-1);
}

/* Flèches SVG dessinées à la main via icon('arrow-right' / 'arrow-left' /
   'chevron-*'). `icon()` pose `data-ico="{nom}"` sur le SVG résultant.
   Le glyphe est retourné pour pointer dans la direction de lecture RTL.
   Les caractères "→" / "←" Unicode utilisés en texte pur restent gérés
   nativement par le moteur bidi du navigateur, on n'y touche pas. */
html[dir="rtl"] svg[data-ico^="arrow-"],
html[dir="rtl"] svg[data-ico^="chevron-"],
html[dir="rtl"] svg[data-ico="move-right"],
html[dir="rtl"] svg[data-ico="move-left"] {
    transform: scaleX(-1);
}

/* Champs de recherche (hero + page /recherche) en RTL :
   - la loupe (loupe fixe visuelle, indication du contenu) reste à côté
     du DÉBUT du champ → passe à droite en RTL ;
   - le bouton d'envoi (action, "faire progresser la recherche") reste
     à côté de la FIN du champ → passe à gauche en RTL, avec un
     `translateX(-2px)` au hover pour prolonger la direction de lecture ;
   - les paddings horizontaux du champ sont inversés en conséquence. */
html[dir="rtl"] .hero-recherche-loupe {
    left: auto; right: 18px;
}
html[dir="rtl"] .hero-recherche input {
    padding: 0 52px 0 56px;
}
html[dir="rtl"] body.hero-titre-petit .hero-recherche input {
    padding: 0 46px 0 50px;
}
html[dir="rtl"] body.hero-titre-grand .hero-recherche input {
    padding: 0 54px 0 62px;
}
html[dir="rtl"] .hero-recherche button {
    right: auto; left: 5px;
}
html[dir="rtl"] .hero-recherche button:hover {
    transform: translateY(-50%) translateX(-2px);
}

html[dir="rtl"] .recherche-form-loupe {
    left: auto; right: 18px;
}
html[dir="rtl"] .recherche-form input {
    padding: 0 52px 0 60px;
}
html[dir="rtl"] .recherche-form button {
    right: auto; left: 5px;
}
html[dir="rtl"] .recherche-form button:hover {
    transform: translateY(-50%) translateX(-2px);
}
