/* Thème prof_de_oops — TechnoLab.
   ------------------------------------------------------------------
   Dérivé du thème par défaut, dont il garde toute la structure (mêmes
   classes, mêmes blocs) : seuls la charte, les polices et les trois zones
   d'identité — bandeau, barre de navigation, pied de page — changent.
   Reprendre le thème par défaut pour tout ce qui n'est pas redéfini ici. */

/* :host (en plus de :root) : quand cette feuille est chargée dans le shadow
   root d'un aperçu de bloc côté éditeur (voir PageEditor.js), :root ne
   correspond à rien dans l'arbre du shadow root — :host cible alors
   l'élément hôte, qui transmet ces variables/le reset par héritage normal
   à son contenu. Sur le vrai site (pas de shadow DOM), :host ne
   correspond à rien : seul :root s'applique, sans changement de comportement.
   Un nouveau thème doit reprendre ce doublet pour être compatible avec
   l'aperçu fusionné de l'éditeur — voir README.md. */
:root, :host {
    /* Charte « atelier »
       ------------------------------------------------------------------
       Trois couleurs portent le site : le violet nuit des bandeaux, le rose
       qui signe la marque, le turquoise des rubriques ouvertes à tous. Un
       violet moyen les relie. Le fond n'est plus du papier crème mais un gris
       très légèrement violacé, sur lequel les cartes restent blanches.

       Deux nuances par couleur, et c'est volontaire : la vive sert aux aplats,
       aux dégradés et aux filets ; la sombre à tout ce qui porte du texte. Les
       roses et turquoises de la maquette (#e0559a, #12a19d) plafonnent à 3:1
       sur blanc, sous le seuil RGAA pour du texte courant — les distinguer
       évite d'avoir à y penser à chaque usage. */
    --site-accent: #b8286f;
    --site-accent-vivid: #e0559a;
    --site-accent-bg: #fce3f0;
    --site-night: #3a2350;
    --site-night-soft: #5c2775;

    /* Le créneau « doré » du thème par défaut porte ici le rose pâle : c'est
       lui qui surligne les mots dans les titres et qui éclaire les intitulés
       de colonne du pied de page. Le nom de la variable ne change pas — il est
       utilisé par les réglages enregistrés en base et par tous les blocs
       partagés — mais sa valeur, elle, quitte le jaune : la maquette n'a pas
       une seule touche de jaune. */
    --site-gold: #f7c6e2;
    --site-gold-bg: #fdeaf5;
    --site-gold-ink: #7c1c50;
    --site-teal: #0a7472;
    --site-teal-vivid: #12a19d;
    --site-teal-bg: #d9f2f0;

    /* Le violet moyen n'est pas réglable : il n'a de sens qu'entre le nuit et
       le rose, et le laisser choisir romprait la progression des trois cartes
       d'entrée (turquoise, violet, rose). */
    --site-violet: #6c3f92;
    --site-violet-vivid: #8a5aa8;

    /* Le dégradé des deux bandeaux violets — barre de navigation et pied de
       page. Écrit une seule fois : les deux doivent rester identiques, ce sont
       les deux extrémités de la même page. */
    --site-nav-gradient: linear-gradient(90deg, #4a1e5f, #5c2775 50%, #4a1e5f);

    /* Durées d'animation. Regroupées ici pour qu'un thème dérivé puisse tout
       ralentir ou tout couper d'un coup. */
    --site-transition: .2s cubic-bezier(.22, .61, .36, 1);
    --site-reveal-duration: .7s;

    --site-text: #3a2350;
    --site-muted: #5a5766;
    --site-muted-bg: #e9e7ef;
    --site-bg: #f4f4f7;
    --site-bg-card: #ffffff;
    --site-bg-alt: #eceaf2;
    --site-success: #1d6b33;
    --site-success-bg: #dff0dd;
    --site-warning: #8a5300;
    --site-warning-bg: #ffeec9;
    --site-danger: #a8352a;
    --site-danger-bg: #fbdfd7;

    /* Familles. Une seule police de texte — Montserrat — déclinée en graisse :
       régulière pour les paragraphes, très grasse et en capitales pour les
       titres et les libellés. C'est le contraste de graisse, et non de famille,
       qui structure la page.
       Les deux autres polices ne servent qu'à l'identité et n'apparaissent
       qu'une fois chacune : Fredoka pour le logotype, Caveat pour l'accroche
       manuscrite du bandeau. Les sortir de là les banaliserait. */
    --site-font: 'Montserrat', system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    --site-font-title: var(--site-font);

    /* Le créneau « monospace » du contrat des thèmes (voir README.md) ne porte
       plus de police à chasse fixe : il désigne les surtitres et les libellés
       courts, et la maquette les veut dans la même famille que le reste, en
       capitales espacées. Le nom de la variable ne change pas — c'est celui que
       le README documente et que tous les blocs partagés utilisent. */
    --site-font-mono: var(--site-font);
    --site-font-display: 'Fredoka', 'Trebuchet MS', var(--site-font);
    --site-font-hand: 'Caveat', 'Segoe Script', 'Brush Script MT', cursive;

    /* Traits de dessin. Une seule source pour les rayons et les ombres :
       un thème dérivé change l'allure de tout le site en surchargeant ces
       variables, sans réécrire un sélecteur. Les ombres sont teintées de
       violet plutôt que grises — une ombre neutre sous une carte colorée la
       fait paraître décollée. */
    --site-border: #e4e1ec;
    --site-border-strong: #d3cee0;
    --site-radius: 18px;
    --site-radius-lg: 24px;
    --site-radius-sm: 12px;
    --site-radius-pill: 999px;
    --site-shadow: 0 2px 10px rgba(60, 30, 80, .06);
    --site-shadow-hover: 0 16px 36px -14px rgba(60, 30, 80, .38);

    /* Largeurs
       --site-container : en-tête, pied de page et colonne par défaut des blocs.
       --site-reading   : mesure de confort du texte suivi (~68 caractères).
         Elle s'applique au texte lui-même, pas au bloc : un bandeau garde
         toute sa largeur, seules ses lignes de texte sont bornées. */
    --site-container: 1320px;
    --site-reading: 44rem;

    /* Rythme vertical : l'écart entre deux blocs, et le souffle d'une section
       pleine largeur (qui ne se règle pas comme une marge entre paragraphes). */
    --site-block-gap: clamp(2rem, 4vw, 3rem);
    --site-section-padding: clamp(3rem, 6vw, 5.5rem);
    --site-main-padding: clamp(2rem, 4vw, 3rem);
}

/* Palette dérivée
   ------------------------------------------------------------------
   Six couleurs seulement sont réglables depuis Site web → Configuration
   (celles déclarées dans theme.json) : rose, violet nuit, rose pâle,
   turquoise, fond de page et texte courant. Les autres en découlent ici —
   même teinte, clarté et saturation recalculées.

   C'est ce qui rend la configuration honnête : sans cela, un établissement
   qui remplacerait le rose par du vert garderait des aplats roses et des
   fonds d'étiquette roses, sans rien pour l'en avertir. Les nuances suivent
   désormais la couleur dont elles dépendent.

   Deux familles de règles, pour deux intentions différentes :
   - clarté absolue (.942 pour un pastel, .351 pour une encre) — un fond
     pastel doit rester pastel et une encre rester lisible dessus, quelle que
     soit la couleur de départ ; c'est ce qui garantit le contraste du couple ;
   - clarté relative (calc(l ± …)) pour tout ce qui se détache du fond de
     page — bandes, filets, texte secondaire : ceux-là doivent suivre la page
     si elle s'assombrit, pas viser une clarté fixe.
   La saturation est toujours proportionnelle : un accent gris donne un fond
   gris, pas un pastel coloré sorti de nulle part.

   Les valeurs statiques ci-dessus restent la solution de repli des
   navigateurs sans syntaxe de couleur relative (avant Chrome 119 /
   Safari 16.4 / Firefox 128) : le site y garde la charte du thème. */
@supports (color: oklch(from white l c h)) {
    :root, :host {
        --site-accent-vivid: oklch(from var(--site-accent) calc(l + .105) calc(c * 1.12) h);
        --site-accent-bg: oklch(from var(--site-accent) .942 calc(c * .21) h);
        --site-night-soft: oklch(from var(--site-night) calc(l + .09) calc(c * 1.31) h);
        --site-gold-bg: oklch(from var(--site-gold) .96 calc(c * .69) h);
        --site-gold-ink: oklch(from var(--site-gold) .351 calc(c * 1.9) h);
        --site-teal-vivid: oklch(from var(--site-teal) calc(l + .13) calc(c * 1.2) h);
        --site-teal-bg: oklch(from var(--site-teal) .937 calc(c * .33) h);

        /* Le violet moyen n'est pas réglable, mais il doit rester à mi-chemin
           entre le nuit et le rose : il est calculé sur le nuit pour suivre un
           changement de bandeau. */
        --site-violet: oklch(from var(--site-night) calc(l + .16) calc(c * 1.15) h);
        --site-violet-vivid: oklch(from var(--site-night) calc(l + .27) calc(c * 1.1) h);

        --site-nav-gradient: linear-gradient(90deg,
            oklch(from var(--site-night) calc(l + .03) c h),
            oklch(from var(--site-night) calc(l + .1) calc(c * 1.15) h) 50%,
            oklch(from var(--site-night) calc(l + .03) c h));

        --site-muted: oklch(from var(--site-text) calc(l + .239) calc(c * .5) h);
        --site-bg-alt: oklch(from var(--site-bg) calc(l - .019) calc(c * 1.13) h);
        --site-muted-bg: oklch(from var(--site-bg) calc(l - .037) calc(c * 1.25) h);
        --site-border: oklch(from var(--site-bg) calc(l - .048) calc(c * 1.31) h);
        --site-border-strong: oklch(from var(--site-bg) calc(l - .099) calc(c * 1.25) h);
    }
}

* {
    box-sizing: border-box;
}

/* Défilement fluide : c'est ce qui rend le bouton « revenir en haut » du pied
   de page lisible — un saut instantané en haut de page fait perdre le fil.
   Le réglage système « réduire les animations » le repasse en `auto` plus bas. */
html {
    scroll-behavior: smooth;
    /* La barre de navigation est collante : sans cette marge, une ancre
       viserait un titre qui se retrouverait caché dessous. */
    scroll-padding-top: 4.5rem;
}

/* Accessibilité (RGAA)
   ------------------------------------------------------------------ */

/* Contenu réservé aux lecteurs d'écran : retiré visuellement sans être
   retiré de l'arbre d'accessibilité (display:none le masquerait aussi
   pour les technologies d'assistance). */
.site-sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* Lien d'évitement : hors écran jusqu'à ce qu'il reçoive le focus. */
.site-skip-link {
    position: absolute;
    left: -9999px;
    top: 0;
    z-index: 100;
    padding: .75rem 1rem;
    background: var(--site-accent);
    color: #fff;
    text-decoration: none;
}

.site-skip-link:focus {
    left: 0;
}

/* Focus toujours visible : :focus-visible ne s'affiche qu'au clavier, donc
   sans gêner la navigation à la souris. */
:focus-visible {
    outline: 3px solid var(--site-accent);
    outline-offset: 2px;
}

.site-skip-link:focus-visible {
    outline-color: #fff;
}

/* Respecte le réglage système « réduire les animations ». */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: .01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .01ms !important;
        scroll-behavior: auto !important;
    }
}

body, :host {
    margin: 0;
    font-family: var(--site-font);
    font-size: 1.0625rem;
    color: var(--site-text);
    background: var(--site-bg);
    line-height: 1.65;
    -webkit-font-smoothing: antialiased;
    text-wrap: pretty;
}

/* Échelle typographique
   ------------------------------------------------------------------
   Les tailles par défaut du navigateur donnent une hiérarchie molle : un h2
   à peine plus gros qu'un h3, aucun resserrement. L'échelle ci-dessous est
   fluide (clamp) pour éviter une série de points de rupture, avec un
   interlignage court et un léger resserrement des lettres sur les grands
   titres — sans quoi un titre de deux lignes paraît décousu.
   Elle s'applique aussi au HTML saisi dans le bloc Texte, qui produit ses
   propres h2/h3 : le rendu d'un titre est le même qu'il vienne du bloc Titre
   ou de l'éditeur riche. */
/* Les titres sont dans la même famille que le texte, mais en graisse extrême
   (800) : c'est le seul écart de graisse aussi large de la page, et c'est lui
   qui fait le titre. D'où des tailles plus contenues qu'avec un serif — un
   Montserrat 800 de 40 px pèse déjà autant qu'un serif de 60. */
h1, h2, h3, h4, h5, h6 {
    font-family: var(--site-font-title);
    font-weight: 800;
    color: var(--site-night);
    line-height: 1.12;
    letter-spacing: -.015em;
    text-wrap: balance;
}

h1 {
    font-size: clamp(2rem, 1.4rem + 2.4vw, 2.75rem);
    margin: 0 0 1rem;
}

h2 {
    font-size: clamp(1.625rem, 1.2rem + 1.7vw, 2.25rem);
    margin: 0 0 .875rem;
}

h3 {
    font-size: clamp(1.3125rem, 1.1rem + .9vw, 1.625rem);
    line-height: 1.2;
    margin: 0 0 .625rem;
}

h4 {
    font-size: 1.125rem;
    line-height: 1.25;
    margin: 0 0 .5rem;
}

/* Pas d'italique dessinée dans Montserrat variable : l'accent dans un titre
   passe par la couleur rose, celle du logotype, plutôt que par la pente. */
h1 em, h2 em, h3 em {
    font-style: normal;
    color: var(--site-accent);
}

/* Surlignage au feutre : le dégradé s'arrête au quart de la hauteur, ce qui
   imite un trait passé sous le mot plutôt qu'un fond de couleur. */
.site-mark {
    background: linear-gradient(to top, var(--site-gold) 34%, transparent 34%);
    padding: 0 .15em;
}

/* Dans le texte suivi, un titre ouvre une section : il lui faut plus d'air
   au-dessus qu'en dessous. */
.block-text h2,
.block-text h3,
.block-text h4,
.news-article-content h2,
.news-article-content h3 {
    margin-top: 2em;
}

.block-text > :first-child,
.news-article-content > :first-child {
    margin-top: 0;
}

.site-container {
    max-width: var(--site-container);
    margin: 0 auto;
    padding: 0 1.25rem;
}

/* Header
   Trois bandes empilées : la barre d'accès, le bandeau d'identité, la barre de
   navigation. Seule la dernière est collante — sur une page longue (règlement
   intérieur, article), le visiteur garde la navigation à portée sans remonter,
   sans traîner pour autant le bandeau de 220 px derrière lui. */
/* Barre d'accès (layout.twig)
   ------------------------------------------------------------------
   La première ligne du bandeau : état d'ouverture à gauche, services externes
   à droite. Elle porte l'information que les familles cherchent en premier —
   « est-ce ouvert maintenant ? » — sans occuper la navigation principale.

   Elle reprend le pastel du bandeau qui la suit, dont elle n'est que le haut :
   deux aplats différents collés l'un à l'autre feraient deux barres là où il
   n'y a qu'un en-tête.

   Le dernier lien pratique prend l'aplat violet plein : c'est la place de la
   connexion à l'espace privé, la seule entrée de cette barre qu'un visiteur
   cherche vraiment. Mettre l'entrée « Connexion » en dernier dans le menu
   Liens pratiques suffit à obtenir le bouton de la maquette. */
.site-accessbar {
    background: var(--site-gold-bg);
    color: var(--site-night-soft);
    font-size: .8125rem;
    font-weight: 600;
}

.site-accessbar .site-container {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: .5rem 1.5rem;
    min-height: 44px;
    padding-top: .375rem;
    padding-bottom: .375rem;
}

.site-accessbar-status {
    display: flex;
    align-items: center;
    gap: .625rem;
    margin: 0;
    letter-spacing: .02em;
}

/* La pastille double l'information portée par le texte : elle ne la remplace
   pas — une couleur seule ne peut pas être le seul vecteur d'un état (RGAA). */
.site-accessbar-dot {
    width: .4375rem;
    height: .4375rem;
    border-radius: 50%;
    background: var(--site-teal-vivid);
}

.site-accessbar-status.is-closed .site-accessbar-dot {
    background: color-mix(in oklab, var(--site-night) 35%, #fff);
}

.site-accessbar-hours {
    color: var(--site-muted);
    font-weight: 500;
}

.site-accessbar-nav ul {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .375rem;
    margin: 0;
    padding: 0;
}

.site-accessbar-nav a {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    padding: .4375rem 1rem;
    border-radius: var(--site-radius-pill);
    color: var(--site-night-soft);
    text-decoration: none;
    transition: background-color var(--site-transition), color var(--site-transition);
}

.site-accessbar-nav a:hover {
    background: rgba(255, 255, 255, .7);
    color: var(--site-accent);
}

.site-accessbar-nav li:last-child a {
    background: var(--site-nav-gradient);
    color: #fff;
    box-shadow: 0 4px 14px rgba(70, 25, 90, .3);
}

.site-accessbar-nav li:last-child a:hover {
    background: var(--site-night);
    color: #fff;
}

/* Un seul lien pratique : rien ne le distingue d'un bouton isolé, autant lui
   laisser l'allure discrète du reste de la barre. */
.site-accessbar-nav li:only-child a {
    background: none;
    color: var(--site-night-soft);
    box-shadow: none;
}

.site-accessbar-nav li:only-child a:hover {
    background: rgba(255, 255, 255, .7);
    color: var(--site-accent);
}

.site-accessbar :focus-visible {
    outline-color: var(--site-accent);
}

/* En-tête : le bandeau d'identité
   ------------------------------------------------------------------
   Le haut de la page n'est pas une barre mais un bandeau : un aplat pastel où
   flottent trois formes molles, le logotype au centre, l'accroche manuscrite
   en dessous. Il ne défile pas avec la page — c'est la barre de navigation,
   juste en dessous, qui reste collée en haut. Un bandeau de 370 px collant
   mangerait la moitié de l'écran d'un portable.

   Les formes décoratives sont posées en pseudo-éléments plutôt qu'en balises :
   elles n'ont rien à dire à un lecteur d'écran, et le gabarit n'a pas à porter
   trois <div> vides. */
.site-header {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    color: var(--site-night);
    background: var(--site-accent-bg);
    background: linear-gradient(120deg,
        var(--site-gold-bg) 0%,
        var(--site-accent-bg) 40%,
        color-mix(in oklab, var(--site-night) 8%, #fff) 100%);
}

.site-header .site-container {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: .25rem;
    min-height: 13.5rem;
    padding-top: clamp(1.75rem, 4vw, 2.75rem);
    padding-bottom: clamp(1.75rem, 4vw, 2.75rem);
    text-align: center;
}

/* Les deux illustrations du bandeau. Elles remplacent les formes molles
   dessinées en CSS : chacune apporte son propre cercle rose, ses cubes et ses
   tracés.

   Ce sont les WebP qui sont servis, pas les SVG d'origine restés à côté
   (header_left.svg, header_right.svg) : ces derniers ne sont des vecteurs que
   par l'enveloppe, ils encapsulent des images matricielles de ~870 × 1020 px et
   pèsent 3,05 Mo à eux deux, une fois compressés — sur chaque page du site,
   puisqu'ils sont dans l'en-tête. Les WebP, rendus à 608 px de haut (le double
   de la hauteur d'affichage) puis recadrés au dessin, font 382 Ko pour un
   résultat indiscernable à l'écran.
   Garder les SVG comme sources : c'est d'eux qu'il faut repartir pour changer
   la taille de rendu — en recadrant de nouveau sur le dessin, sans quoi la
   marge basse revient.

   Pas de repli pour les navigateurs sans WebP : il est lu partout depuis
   Safari 14 (2020), et une illustration décorative absente ne casse rien — le
   dégradé pastel tient le bandeau tout seul, comme il le fait sur téléphone.

   Elles sont posées en fond de pseudo-éléments plutôt qu'en <img> : elles ne
   disent rien, elles décorent. Une image de contenu demanderait un texte de
   remplacement, et un texte de remplacement vide sur une <img> n'est qu'une
   balise de plus à lire dans le gabarit.

   Les WebP sont recadrés au dessin : plus un pixel transparent sur aucun des
   quatre bords. Les SVG d'origine, eux, sont des toiles de bandeau entières
   (750 × 171,12) dont un seul côté est dessiné et où le dessin s'arrête à
   94,2 % de la hauteur — c'est cette marge basse qui empêchait le dessin de
   toucher le bas du bandeau. Recadrer une fois pour toutes à la génération
   évite d'avoir à la compenser ici.

   Les deux sont donc simplement mis à la hauteur du bandeau (`auto 100%`) : le
   dessin la remplit exactement, et les deux sont à la même échelle — deux
   illustrations d'une même paire dessinées à deux tailles se remarquent
   immédiatement.

   Les boîtes prennent toute la largeur plutôt qu'une fraction : le dessin de
   droite fait 3,05 pour 1, soit 826 px de large pour un bandeau de 271 px, là
   où il ne reste que 448 px de part et d'autre du logotype. Aucune largeur
   fixe ne peut à la fois le contenir en entier et l'en tenir à l'écart ; une
   boîte pleine largeur, elle, ne le coupe jamais. C'est le voile plus bas qui
   le rend inoffensif là où il passe sous le texte. */
.site-header::before,
.site-header::after {
    content: '';
    position: absolute;
    inset: 0;
    /* -2, et non -1 : le voile central est à -1, et à couche égale c'est
       l'ordre du document qui tranche — l'illustration de droite, dernier
       enfant de l'en-tête, se peindrait alors par-dessus le voile. */
    z-index: -2;
    pointer-events: none;
    background-repeat: no-repeat;
    background-size: auto 100%;
}

.site-header::before {
    background-image: url('header_left.webp');
    background-position: left center;
}

.site-header::after {
    background-image: url('header_right.webp');
    background-position: right center;
}

/* Voile central
   ------------------------------------------------------------------
   Les deux illustrations, à pleine hauteur, viennent nécessairement sous le
   logotype : leur dessin est trois fois plus large que haut, la place ne suffit
   pas. Ce halo pastel les efface là où le texte se pose — sans lui, le rose du
   « Lab » se retrouverait sur les cubes violets, très en dessous du rapport de
   contraste exigé.

   Il est porté par le conteneur, et non par l'en-tête : les deux
   pseudo-éléments de celui-ci sont déjà pris. Comme .site-container est en
   `position: relative` sans z-index, il ne crée pas de contexte d'empilement :
   ce voile rejoint donc la couche négative de l'en-tête, où il se place à -1,
   au-dessus des illustrations laissées à -2. Le texte, lui, n'est pas
   positionné : il se peint après toute la couche négative, donc par-dessus le
   voile. */
.site-header .site-container::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    /* Un dégradé horizontal, et non un halo : ce qu'il faut protéger est une
       colonne — le logotype, la baseline et l'accroche s'empilent sur presque
       toute la hauteur du bandeau. Un halo elliptique laissait justement
       l'accroche, la plus basse des trois, sortir par le bas du voile. */
    background: linear-gradient(to right,
        transparent 8%,
        color-mix(in srgb, var(--site-gold-bg) 94%, transparent) 26%,
        color-mix(in srgb, var(--site-gold-bg) 94%, transparent) 74%,
        transparent 92%);
}

/* Sous 900 px le bandeau se resserre et le logotype prend presque toute la
   largeur : les formes reculent vers les coins et s'éclaircissent, sans quoi le
   rose du logotype se retrouverait sur un aplat violet, où il ne tient plus le
   rapport de contraste. La troisième forme disparaît : il n'y a plus la place
   de trois taches sans en mettre une derrière le texte. */
@media (max-width: 900px) {
    /* Le logotype occupe alors presque toute la largeur : les illustrations
       passent en grande partie derrière lui. Elles s'estompent, et le voile
       s'élargit d'autant. */
    .site-header::before,
    .site-header::after {
        opacity: .5;
    }

    .site-header .site-container::before {
        background: linear-gradient(to right,
            transparent 0%,
            color-mix(in srgb, var(--site-gold-bg) 95%, transparent) 16%,
            color-mix(in srgb, var(--site-gold-bg) 95%, transparent) 84%,
            transparent 100%);
    }
}

/* Sur téléphone, il ne reste plus de marge de part et d'autre du logotype :
   les illustrations disparaissent, le dégradé pastel porte seul le bandeau. */
@media (max-width: 640px) {
    .site-header::before,
    .site-header::after,
    .site-header .site-container::before {
        display: none;
    }
}

/* Logotype
   ------------------------------------------------------------------
   La seule apparition de Fredoka du site. Le nom se coupe en deux : tout sauf
   le dernier morceau en violet nuit, le dernier en rose — c'est ce contraste
   qui fait la marque, pas la police seule. Le découpage est fait dans le
   gabarit (voir layout.twig), pour qu'il suive le nom saisi en configuration
   plutôt qu'un nom écrit en dur. */
.site-brand {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .5rem;
    color: var(--site-night);
    text-decoration: none;
}

/* À défaut de logo téléversé, le logotype seul suffit : cette initiale n'a
   plus lieu d'être ici (le thème par défaut la garde). */
.site-brand-initial {
    display: none;
}

.site-brand-text {
    display: block;
    font-family: var(--site-font-display);
    font-weight: 700;
    font-size: clamp(2.75rem, 1.5rem + 5.5vw, 5.75rem);
    line-height: .9;
    letter-spacing: -.02em;
}

.site-brand-accent {
    color: var(--site-accent-vivid);
}

/* Baseline : trois mots en capitales, séparés par des puces. Chaque mot prend
   une couleur de la charte, dans l'ordre rose / turquoise / nuit, et le cycle
   reprend au quatrième — la règle vaut donc pour deux mots comme pour cinq.
   Les encres, pas les couleurs vives : à 13 px en capitales, le rose vif de la
   maquette tombe sous le seuil de contraste RGAA. */
.site-brand-tagline {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: .25rem .5rem;
    margin-top: .5rem;
    font-family: var(--site-font-mono);
    font-weight: 700;
    font-size: clamp(.8125rem, .7rem + .45vw, 1.1875rem);
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--site-night);
}

.site-brand-tagline-word:nth-child(3n+1) { color: var(--site-accent); }
.site-brand-tagline-word:nth-child(3n+2) { color: var(--site-teal); }
.site-brand-tagline-word:nth-child(3n+3) { color: var(--site-night); }

/* Les puces sont dessinées ici, et non écrites dans le gabarit : un lecteur
   d'écran énoncerait « puce » entre chaque mot. */
.site-brand-tagline-word + .site-brand-tagline-word::before {
    content: '•';
    margin-right: .5rem;
    color: color-mix(in oklab, var(--site-violet) 45%, #fff);
}

/* Accroche manuscrite : la seule apparition de Caveat. Elle dit le ton du
   site là où la baseline en dit la matière. */
.site-header-accroche {
    margin: .875rem 0 0;
    font-family: var(--site-font-hand);
    font-weight: 700;
    font-size: clamp(1.5rem, 1.1rem + 1.6vw, 2.125rem);
    line-height: 1.1;
    color: var(--site-night-soft);
}

.site-logo {
    max-height: 72px;
    width: auto;
}

.site-socials {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    margin: .75rem 0 0;
    padding: 0;
}

.site-contact {
    margin: .75rem 0 0;
    font-style: normal;
}

.site-contact-item {
    display: inline-block;
    margin-right: 1rem;
}

/* Barre de navigation
   ------------------------------------------------------------------
   Le bandeau violet, collant : c'est lui qui suit le visiteur, pas l'en-tête.
   Les intitulés sont en capitales grasses et largement espacés — une barre de
   navigation d'établissement compte cinq entrées, elle a la place. */
.site-header-nav {
    position: sticky;
    top: 0;
    z-index: 30;
    background: var(--site-night);
    background: var(--site-nav-gradient);
    box-shadow: 0 2px 14px rgba(60, 30, 80, .28);
}

.site-header-nav .site-container {
    display: flex;
    justify-content: center;
    padding-top: 0;
    padding-bottom: 0;
}

.site-nav ul {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    align-items: stretch;
    justify-content: center;
    gap: 0 clamp(.125rem, 1vw, .75rem);
    margin: 0;
    padding: 0;
}

.site-header-nav .site-nav a {
    display: flex;
    align-items: center;
    gap: .6875rem;
    padding: 1.125rem clamp(.625rem, 1.4vw, 1.25rem);
    color: #efe4f5;
    text-decoration: none;
    font-weight: 700;
    font-size: clamp(.8125rem, .75rem + .2vw, 1rem);
    letter-spacing: .02em;
    text-transform: uppercase;
    white-space: nowrap;
    /* Le filet est déjà là au repos, en transparent : sans lui, l'intitulé
       sauterait de 4 px au survol. */
    border-bottom: 4px solid transparent;
    transition: color var(--site-transition), border-color var(--site-transition);
}

/* Page courante et survol : le filet rose vif de la maquette, mais un rose
   éclairci pour l'intitulé lui-même — le rose vif sur ce violet ne tient pas
   le rapport de contraste exigé pour du texte de cette taille. Le filet, lui,
   est décoratif : il n'a pas à le tenir. */
.site-header-nav .site-nav a:hover,
.site-header-nav .site-nav a:focus-visible,
.site-header-nav .site-nav a[aria-current="page"] {
    color: color-mix(in oklab, var(--site-accent-vivid) 70%, #fff);
    border-bottom-color: var(--site-accent-vivid);
}

.site-header-nav :focus-visible {
    outline-color: color-mix(in oklab, var(--site-accent-vivid) 70%, #fff);
    outline-offset: -4px;
}

/* Sous-menus (un seul niveau, voir WebsiteMenuItem::MAX_DEPTH).
   Ouverture au survol ET au focus clavier : sans :focus-within, le sous-menu
   serait inatteignable sans souris. */
.site-header-nav .site-nav li {
    position: relative;
}

.site-header-nav .site-nav .site-submenu {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 10;
    flex-direction: column;
    gap: 0;
    min-width: 13rem;
    padding: .5rem;
    background: var(--site-bg-card);
    border: 1px solid var(--site-border);
    border-radius: var(--site-radius-sm);
    box-shadow: var(--site-shadow-hover);
}

.site-header-nav .site-nav li:hover > .site-submenu,
.site-header-nav .site-nav li:focus-within > .site-submenu {
    display: flex;
}

.site-header-nav .site-nav .site-submenu a {
    display: block;
    padding: .5rem .75rem;
    color: var(--site-night);
    font-size: .875rem;
    letter-spacing: 0;
    text-transform: none;
    white-space: nowrap;
    border-bottom: 0;
    border-radius: calc(var(--site-radius-sm) - 4px);
}

.site-header-nav .site-nav .site-submenu a:hover,
.site-header-nav .site-nav .site-submenu a[aria-current="page"] {
    background: var(--site-accent-bg);
    color: var(--site-accent);
}

/* Sur petit écran, pas de survol fiable : le sous-menu est déplié en dessous. */
@media (max-width: 700px) {
    .site-header-nav .site-nav a {
        padding: .75rem .625rem;
    }

    .site-header-nav .site-nav .site-submenu {
        display: flex;
        position: static;
        min-width: 0;
        padding: 0 0 .5rem 1rem;
        background: none;
        border: 0;
        box-shadow: none;
    }

    .site-header-nav .site-nav .site-submenu a {
        color: #d9c7e4;
    }
}

/* Main */
.site-main {
    padding: var(--site-main-padding) 0 calc(var(--site-main-padding) * 1.5);
}

.site-page h1 {
    margin-top: 0;
}

/* Une page qui s'ouvre sur un bloc pleine largeur démarre au ras de
   l'en-tête : le padding du <main> laisserait une bande de papier avant le
   bandeau, qui ressemble à un défaut d'intégration. Le bandeau d'accueil,
   lui, reste dans le conteneur (cadre arrondi) et garde ce padding. */
.site-page-content > .block-width-full:first-child,
.site-home > .block-width-full:first-child {
    margin-top: calc(-1 * var(--site-main-padding));
}

/* Mesure de lecture
   ------------------------------------------------------------------
   Le conteneur s'est élargi pour que les grilles (liens, équipe, actualités)
   respirent, mais une ligne de texte de 1120 px est illisible. La contrainte
   porte donc sur le texte suivi lui-même, jamais sur le bloc : le fond d'un
   encadré ou d'un bandeau garde toute sa largeur. */
.block-text,
.block-toc,
.block-quote blockquote,
.block-callout p,
.accordion-content,
.news-article-content {
    max-width: var(--site-reading);
}

/* Un bloc centré centre aussi sa colonne de texte, sans quoi le texte
   resterait calé à gauche dans une boîte centrée. */
.align-center.block-text,
.align-center .block-callout p,
.align-center.block-quote blockquote,
.block-width-full .align-center p {
    margin-left: auto;
    margin-right: auto;
}

/* Archive des actualités (news.twig) */
.news-categories {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    margin-bottom: 1.5rem;
}

.news-categories a {
    padding: .375rem .75rem;
    border: 1px solid var(--site-muted-bg);
    border-radius: var(--site-radius-pill);
    color: var(--site-muted);
    text-decoration: none;
    font-size: .875rem;
}

.news-categories a.active,
.news-categories a:hover {
    border-color: var(--site-accent);
    background: var(--site-accent-bg);
    color: var(--site-accent);
}

.news-item {
    display: flex;
    gap: 1.5rem;
    padding: 1.25rem;
    margin-bottom: 1rem;
    border: 1px solid var(--site-border);
    border-radius: var(--site-radius);
    transition: box-shadow .18s ease, border-color .18s ease;
}

.news-item:hover {
    border-color: transparent;
    box-shadow: var(--site-shadow-hover);
}

.news-item-cover {
    flex: 0 0 220px;
    overflow: hidden;
    border-radius: var(--site-radius-sm);
}

.news-item-cover img {
    width: 100%;
    height: 150px;
    object-fit: cover;
    display: block;
    transition: transform .4s ease;
}

.news-item:hover .news-item-cover img {
    transform: scale(1.04);
}

.news-item-date {
    color: var(--site-accent);
    font-size: .75rem;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
}

@media (max-width: 640px) {
    .news-item {
        flex-direction: column;
    }

    .news-item-cover {
        flex: 0 0 auto;
    }
}

.news-item-title {
    margin: .25rem 0 .5rem;
    font-size: 1.25rem;
}

.news-item-title a {
    color: var(--site-text);
    text-decoration: none;
}

.news-item-title a:hover {
    color: var(--site-accent);
}

.news-item-excerpt {
    margin: 0;
    color: var(--site-muted);
}

.news-pagination {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 1rem;
    margin-top: 2rem;
}

@media (max-width: 700px) {
    .news-item {
        flex-direction: column;
    }

    .news-item-cover {
        flex-basis: auto;
    }
}

.news-item-tags {
    margin: 0;
    display: flex;
    flex-wrap: wrap;
    gap: .35rem;
}

/* Article (newsArticle.twig) */
.news-article-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem;
    color: var(--site-muted);
    font-size: .875rem;
    margin-bottom: 1.5rem;
}

.news-article-cover {
    width: 100%;
    max-height: 420px;
    object-fit: cover;
    border-radius: var(--site-radius-sm);
    margin-bottom: 1.5rem;
}

.news-article-content {
    margin-bottom: 2rem;
}

.news-article-back {
    margin-top: 2rem;
    padding-top: 1rem;
    border-top: 1px solid var(--site-muted-bg);
}

/* Bloc Bandeau d'accueil (blocks/hero.twig)
   Toujours pleine largeur : la sortie de conteneur est faite ici, pas par
   l'option commune de largeur (que ce bloc n'expose pas). */
.block-hero {
    position: relative;
    display: flex;
    align-items: flex-end;
    background: var(--site-night);
    background-size: cover;
    background-position: center;
    border-radius: var(--site-radius-lg);
    overflow: hidden;
    isolation: isolate;
    padding: 3rem;
}

.hero-medium { min-height: 420px; }
.hero-large { min-height: min(70vh, 620px); }

/* Deux halos qui dérivent lentement derrière la photo : purement décoratifs,
   coupés par `prefers-reduced-motion` (règle globale plus haut). */
.block-hero::before,
.block-hero::after {
    content: '';
    position: absolute;
    z-index: -1;
    border-radius: 50%;
    filter: blur(10px);
    pointer-events: none;
}

.block-hero::before {
    width: 42vw;
    height: 42vw;
    top: -16vw;
    left: -8vw;
    background: radial-gradient(circle at 35% 35%, rgba(249, 212, 107, .3), transparent 65%);
    animation: hero-drift 22s ease-in-out infinite alternate;
}

.block-hero::after {
    width: 34vw;
    height: 34vw;
    right: -10vw;
    bottom: -18vw;
    background: radial-gradient(circle at 60% 40%, rgba(210, 80, 48, .35), transparent 62%);
    animation: hero-drift 28s ease-in-out infinite alternate-reverse;
}

@keyframes hero-drift {
    from { transform: translate3d(0, 0, 0) scale(1); }
    to { transform: translate3d(3vw, 2vw, 0) scale(1.12); }
}

/* La carte de contenu : c'est elle qui porte le texte, sur un fond blanc
   opaque. Aucune photo n'a donc besoin d'être assombrie pour rester
   lisible — le contraste ne dépend plus de l'image choisie par le
   rédacteur, ce qui était la faiblesse du voile sombre. */
.hero-inner {
    position: relative;
    width: 100%;
    max-width: 40rem;
    background: rgba(253, 247, 236, .95);
    border-radius: var(--site-radius);
    padding: 2.5rem 2.75rem;
    color: var(--site-text);
}

.hero-center {
    justify-content: center;
    text-align: center;
}

.hero-center .hero-inner { text-align: center; }

.hero-title {
    margin: 0;
    font-family: var(--site-font-title);
    font-weight: 400;
    font-size: clamp(2.25rem, 1.4rem + 3.4vw, 3.75rem);
    line-height: 1.03;
    letter-spacing: -.015em;
}

.hero-subtitle {
    max-width: 34rem;
    margin: 1.125rem 0 0;
    font-size: clamp(1rem, .95rem + .4vw, 1.125rem);
    line-height: 1.6;
    color: var(--site-muted);
}

.hero-center .hero-subtitle {
    margin-left: auto;
    margin-right: auto;
}

.hero-actions {
    display: flex;
    flex-wrap: wrap;
    gap: .75rem;
    margin: 1.75rem 0 0;
}

/* Entrée en cascade : titre, accroche, puis boutons. Sans JS, l'animation
   joue quand même et s'achève à l'état normal — rien ne peut rester caché. */
.hero-title,
.hero-subtitle,
.hero-actions {
    animation: hero-enter .85s cubic-bezier(.22, .61, .36, 1) both;
}

.hero-subtitle { animation-delay: .12s; }
.hero-actions { animation-delay: .24s; }

@keyframes hero-enter {
    from {
        opacity: 0;
        transform: translateY(18px);
    }
    to {
        opacity: 1;
        transform: none;
    }
}

.hero-center .hero-actions { justify-content: center; }

/* Sur la carte blanche, le bouton « contour » reprend le style commun : plus
   besoin de la variante blanche qu'imposait le fond sombre. */
.block-hero .site-btn-outline {
    border-color: var(--site-border-strong);
    color: var(--site-text);
}

.block-hero .site-btn-outline:hover {
    background: var(--site-bg-card);
    border-color: var(--site-accent-vivid);
    color: var(--site-accent);
}

/* Bloc Tableau (blocks/table.twig)
   .table-scroll est focusable (tabindex="0") pour qu'un tableau plus large que
   l'écran reste défilable au clavier — critère RGAA. */
/* L'encadrement et l'arrondi sont portés par le conteneur, pas par la table :
   `border-collapse: collapse` fait passer les bordures des cellules par-dessus
   les coins arrondis de la table elle-même. */
.table-scroll {
    overflow-x: auto;
    border: 1px solid var(--site-border);
    border-radius: var(--site-radius);
}

.site-table {
    width: 100%;
    border-collapse: collapse;
}

.site-table caption {
    margin-bottom: .625rem;
    text-align: left;
    font-weight: 600;
    color: var(--site-muted);
}

.site-table th,
.site-table td {
    padding: .875rem 1rem;
    border-bottom: 1px solid var(--site-border);
    text-align: left;
    vertical-align: top;
}

.site-table tbody tr:last-child th,
.site-table tbody tr:last-child td {
    border-bottom: 0;
}

.site-table thead th {
    background: var(--site-bg-alt);
    color: var(--site-muted);
    font-family: var(--site-font-mono);
    font-weight: 500;
    font-size: .6875rem;
    letter-spacing: .1em;
    text-transform: uppercase;
    white-space: nowrap;
}

.site-table tbody th[scope="row"] {
    font-weight: 600;
}

.site-table tbody tr:nth-child(even) {
    background: var(--site-bg-alt);
}

/* Titre d'un bloc (liens, chiffres, équipe, documents, agenda, « à lire
   aussi »…) : un seul style pour tous, sinon chaque bloc introduit sa propre
   taille et la page perd sa hiérarchie. */
.links-title,
.stats-title,
.team-title,
.documents-title,
.events-title,
.related-title,
.tiles-title,
.partners-title,
.form-block-title {
    margin: 0 0 1.5rem;
    font-family: var(--site-font-title);
    font-weight: 400;
    font-size: clamp(1.5rem, 1.25rem + 1vw, 2.125rem);
    letter-spacing: -.015em;
    line-height: 1.12;
}

/* Surtitre (bloc Titre, option « surtitre »)
   ------------------------------------------------------------------
   Le petit libellé en capitales espacées posé au-dessus d'un titre de
   section. C'est ce qui distingue une page composée d'une suite de
   paragraphes : il annonce la rubrique là où le titre annonce le sujet.
   Le carré coloré est décoratif, d'où l'absence de texte alternatif. */
.block-overline {
    display: flex;
    align-items: center;
    gap: .625rem;
    margin: 0 0 .75rem;
    font-family: var(--site-font-mono);
    font-size: .75rem;
    font-weight: 500;
    letter-spacing: .16em;
    text-transform: uppercase;
    color: var(--site-accent);
}

.align-center .block-overline,
.align-center.block-heading .block-overline {
    justify-content: center;
}

.align-right .block-overline {
    justify-content: flex-end;
}

/* Sur un fond coloré ou une image, le surtitre reprend la couleur du texte
   ambiant : l'accent y serait illisible. */
.bg-accent .block-overline,
.block-hero .block-overline,
.block-width-full .bg-accent .block-overline {
    color: inherit;
    opacity: .85;
}

/* Bloc Liens utiles (blocks/links.twig)
   ------------------------------------------------------------------
   Le bandeau d'informations de la maquette : un seul panneau blanc, découpé
   en colonnes par des filets pointillés, chaque entrée avec sa grande icône
   colorée, son intitulé de la même couleur et son lien d'appel. Les couleurs
   tournent sur quatre temps — turquoise, violet, rose, turquoise.

   Les colonnes sont ici en nombre fixe, et non en `auto-fit` comme dans le
   thème par défaut : les filets sont posés au nth-child, ce qui suppose de
   savoir où finit une ligne. Deux points de rupture explicites remplacent le
   repli automatique, et le filet passe alors à l'horizontale. */
.links-grid {
    list-style: none;
    display: grid;
    gap: 0;
    margin: 0;
    padding: 1.5rem .5rem;
    background: var(--site-bg-card);
    border: 1px solid var(--site-border);
    border-radius: var(--site-radius);
    box-shadow: var(--site-shadow);
}

.links-cols-2 { grid-template-columns: repeat(2, 1fr); }
.links-cols-3 { grid-template-columns: repeat(3, 1fr); }
.links-cols-4 { grid-template-columns: repeat(4, 1fr); }

.links-grid > li {
    border-right: 2px dotted var(--site-border-strong);
}

.links-cols-2 > li:nth-child(2n),
.links-cols-3 > li:nth-child(3n),
.links-cols-4 > li:nth-child(4n),
.links-grid > li:last-child {
    border-right: 0;
}

/* Deux colonnes à partir de 1000 px, une seule sous 640 px. Le filet suit :
   vertical tant qu'il sépare des colonnes, horizontal quand il sépare des
   lignes — un pointillé vertical sous une entrée empilée ne sépare rien. */
@media (max-width: 1000px) {
    .links-cols-3,
    .links-cols-4 {
        grid-template-columns: repeat(2, 1fr);
    }

    .links-grid > li {
        border-right: 2px dotted var(--site-border-strong);
    }

    .links-grid > li:nth-child(2n),
    .links-grid > li:last-child {
        border-right: 0;
    }
}

@media (max-width: 640px) {
    .links-grid {
        grid-template-columns: 1fr;
        padding: .5rem;
    }

    .links-cols-2,
    .links-cols-3,
    .links-cols-4 {
        grid-template-columns: 1fr;
    }

    .links-grid > li {
        border-right: 0;
        border-bottom: 2px dotted var(--site-border-strong);
    }

    .links-grid > li:last-child {
        border-bottom: 0;
    }
}

.links-grid > li:nth-child(4n+1) { --link-color: var(--site-teal); }
.links-grid > li:nth-child(4n+2) { --link-color: var(--site-violet); }
.links-grid > li:nth-child(4n+3) { --link-color: var(--site-accent); }
.links-grid > li:nth-child(4n+4) { --link-color: var(--site-teal); }

.links-item {
    display: flex;
    align-items: flex-start;
    gap: 1rem;
    height: 100%;
    padding: .625rem 1.5rem;
    color: var(--site-text);
    text-decoration: none;
    border-radius: var(--site-radius-sm);
    transition: background-color var(--site-transition);
}

.links-item:hover {
    background: color-mix(in oklab, var(--link-color) 7%, transparent);
}

/* Chevron d'appel : il indique que la carte entière est cliquable, ce que
   ne dit pas un simple changement de fond au survol. Il suit la couleur de
   l'entrée, comme l'icône et l'intitulé. */
.links-item::after {
    content: '';
    align-self: center;
    width: .5rem;
    height: .5rem;
    margin-left: auto;
    flex: 0 0 auto;
    border-top: 2px solid var(--link-color);
    border-right: 2px solid var(--link-color);
    transform: rotate(45deg);
    transition: transform .18s ease;
}

.links-item:hover::after {
    transform: rotate(45deg) translate(2px, -2px);
}

/* Icône à plat, sans pastille : à 46 px, un aplat de couleur derrière l'icône
   ferait un deuxième bloc de couleur à côté de l'intitulé, déjà coloré. */
.links-item-icon {
    width: 2.875rem;
    height: 2.875rem;
    flex: 0 0 auto;
    fill: var(--link-color);
}

.links-item-body {
    display: flex;
    flex-direction: column;
    gap: .25rem;
    min-width: 0;
}

.links-item-label {
    font-weight: 700;
    font-size: 1.0625rem;
    color: var(--link-color);
}

.links-item-description {
    color: var(--site-muted);
    font-size: .875rem;
    line-height: 1.4;
}

/* Variante « pilules » : une barre de raccourcis, pas un panneau
   d'informations. Pensée pour être posée juste sous le bandeau d'accueil, avec
   les trois ou quatre démarches que les familles viennent chercher en premier.
   Elle reprend donc la mise en page du thème par défaut : ni panneau, ni
   filets, ni colonnes. */
.block-links.style-pills .links-grid {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: .625rem;
    padding: 0;
    background: none;
    border: 0;
    box-shadow: none;
}

.block-links.style-pills .links-grid > li {
    border: 0;
}

.block-links.style-pills .links-item {
    padding: .75rem 1.375rem;
    border-radius: var(--site-radius-pill);
    background: var(--site-bg-card);
    border: 1px solid var(--site-border);
    box-shadow: var(--site-shadow);
    font-weight: 700;
    font-size: .9375rem;
    gap: .5rem;
    align-items: center;
}

.block-links.style-pills .links-item:hover {
    border-color: var(--link-color);
    background: color-mix(in oklab, var(--link-color) 8%, var(--site-bg-card));
}

.block-links.style-pills .links-item-icon {
    width: 1.25rem;
    height: 1.25rem;
}

.block-links.style-pills .links-item-label {
    font-size: .9375rem;
}

/* Ni description ni chevron sur une pilule : elle doit rester lisible d'un
   coup d'œil, en une ligne. */
.block-links.style-pills .links-item-description,
.block-links.style-pills .links-item::after {
    display: none;
}

/* Bloc Chiffres clés (blocks/stats.twig) */
.stats-grid {
    list-style: none;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 2rem 1.5rem;
    margin: 0;
    padding: 0;
    text-align: center;
}

.stats-item {
    display: flex;
    flex-direction: column;
    gap: .375rem;
}

/* Un chiffre clé se lit de loin ou ne sert à rien : il est en serif, à la
   taille d'un grand titre. La couleur change d'un chiffre à l'autre — quatre
   nombres de la même teinte se lisent comme un tableau, pas comme des repères
   distincts. */
.stats-item-value {
    font-family: var(--site-font-title);
    font-size: clamp(2.75rem, 2rem + 3vw, 3.5rem);
    font-weight: 400;
    line-height: 1;
    letter-spacing: -.01em;
    color: var(--site-accent);
    font-variant-numeric: tabular-nums;
}

.stats-item:nth-child(4n+2) .stats-item-value { color: var(--site-teal); }
.stats-item:nth-child(4n+3) .stats-item-value { color: #267d30; }
.stats-item:nth-child(4n+4) .stats-item-value { color: #974391; }

.block-width-full > .bg-accent .stats-item-value,
.block-width-full > .bg-accent .stats-item:nth-child(n) .stats-item-value {
    color: var(--site-gold);
}

.stats-item-label {
    color: var(--site-muted);
    font-family: var(--site-font-mono);
    font-size: .6875rem;
    font-weight: 400;
    letter-spacing: .14em;
    text-transform: uppercase;
}

/* Bloc Équipe (blocks/team.twig) */
.team-grid {
    list-style: none;
    display: grid;
    gap: 1.5rem;
    margin: 0;
    padding: 0;
}

.team-cols-2 { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.team-cols-3 { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
.team-cols-4 { grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); }

.team-member {
    text-align: center;
}

.team-member-photo {
    width: 132px;
    height: 132px;
    object-fit: cover;
    border-radius: 50%;
    margin: 0 auto .875rem;
    display: block;
    /* L'anneau détache le portrait du fond de la page sans lui ajouter de
       cadre : sur une photo claire, sans lui, la tête flotte. */
    box-shadow: 0 0 0 4px var(--site-bg), 0 0 0 5px var(--site-border);
}

.team-member-name {
    margin: 0;
    font-weight: 700;
}

.team-member-role {
    margin: .125rem 0 0;
    color: var(--site-accent);
    font-size: .9375rem;
}

.team-member-description {
    margin: .5rem 0 0;
    color: var(--site-muted);
    font-size: .875rem;
}

/* Bloc Formulaire (blocks/form.twig) — le titre suit le style commun des
   titres de bloc, défini plus haut. */
.form-block-description {
    margin: 0 0 1rem;
    color: var(--site-muted);
}

.form-block-confirmation {
    padding: 1rem;
    border-radius: var(--site-radius-sm);
    background: var(--site-success-bg);
    color: var(--site-success);
    font-weight: 600;
}

.form-block-actions {
    margin-top: 1.5rem;
}

/* Questions du formulaire
   ------------------------------------------------------------------
   Les questions ne sont pas écrites par le thème mais par FormRenderer.js,
   partagé avec le module Formulaires de l'intranet : son HTML porte les
   classes du back-office (.card, .form-control, label.checkbox…) et
   css/form/display.css, chargé avec lui, ne fait que les compléter (notes,
   grilles, RGPD) — il ne les définit jamais. Elles viennent de format.css,
   la feuille de l'intranet, qui n'a rien à faire sur le site public. C'est
   donc au thème de les habiller.

   Tout est sous `.block-form` pour deux raisons : ne rien imposer au reste
   de la page, et passer devant display.css, chargé après cette feuille
   (voir le bloc `assets` de page.twig) et qui gagnerait à spécificité égale.
   Un thème dérivé qui accepte le bloc Formulaire doit reprendre cette
   section — voir README.md. */
.form-block-questions {
    display: grid;
    gap: 1rem;
}

/* Une question = une carte, plus discrète que les cartes éditoriales du
   site : c'est un support de saisie, il ne doit pas concurrencer le
   contenu de la page. */
.block-form .card {
    margin: 0;
    /* Sans min-width:0, la largeur minimale d'une case de grille est celle
       de son contenu : une question en tableau (large) élargirait la carte
       au-delà de l'écran au lieu de défiler dans son .table-responsive. */
    min-width: 0;
    border: 1px solid var(--site-border);
    border-radius: var(--site-radius-sm);
    background: var(--site-bg-card);
    box-shadow: var(--site-shadow);
}

.block-form .card-content {
    padding: 1.25rem 1.375rem;
}

/* Le libellé arrive dans un <h3> : sans cela il hériterait du serif et de
   la taille des titres de section, alors qu'il annonce un champ. */
.block-form .form-question-label {
    margin: 0 0 .875rem;
    font-family: var(--site-font);
    font-weight: 600;
    font-size: 1.0625rem;
    line-height: 1.35;
    letter-spacing: 0;
    color: var(--site-text);
}

.block-form .form-question-label.required::after {
    color: var(--site-danger);
}

.block-form .form-question-media img {
    border-radius: var(--site-radius-sm);
}

/* Champs de saisie */
.block-form .form-control {
    display: block;
    width: 100%;
    padding: .6875rem .875rem;
    border: 1px solid var(--site-border-strong);
    border-radius: var(--site-radius-sm);
    background: var(--site-bg-card);
    color: var(--site-text);
    font: inherit;
    line-height: 1.5;
}

.block-form .form-control::placeholder {
    color: var(--site-muted);
}

/* Aucune règle de focus ici : un champ de saisie déclenche :focus-visible
   même à la souris, l'anneau global suffit — une bordure colorée en plus
   ne ferait que doubler le liseré. */

.block-form textarea.form-control {
    min-height: 8rem;
    resize: vertical;
}

/* Cases à cocher et boutons radio
   ------------------------------------------------------------------
   format.css masque la commande native et redessine tout en ::before /
   ::after sur le <div> du libellé. Ici on garde la commande native, mise
   à la couleur du site par accent-color : moins de CSS à maintenir, et le
   rendu suit les réglages d'accessibilité du système. */
.block-form .checkbox-group,
.block-form .radio-group {
    display: flex;
    flex-direction: column;
    gap: .125rem;
}

.block-form label.checkbox,
.block-form label.radio {
    display: flex;
    align-items: center;
    gap: .625rem;
    padding: .375rem 0;
    cursor: pointer;
}

.block-form label.checkbox input,
.block-form label.radio input {
    flex: none;
    width: 1.125rem;
    height: 1.125rem;
    margin: 0;
    accent-color: var(--site-accent);
    cursor: pointer;
}

.block-form label.checkbox > div,
.block-form label.radio > div {
    line-height: 1.4;
}

/* Option « Autre » : la case et son champ de précision sur une même ligne
   (le .d-flex de FormRenderer vient de la grille de l'intranet, absente
   ici ; le gap remplace le .mr-3 qui l'accompagne). */
.block-form .d-flex {
    display: flex;
    align-items: center;
    gap: .625rem;
}

.block-form .other-input-container {
    min-width: 0;
}

/* Pavé de consentement RGPD */
.block-form .rgpd-consent {
    padding: 1rem 1.125rem;
    border: 1px solid var(--site-border);
    border-radius: var(--site-radius-sm);
    background: var(--site-bg-alt);
}

.block-form .rgpd-consent label.checkbox > div {
    color: var(--site-muted);
}

/* Échelles de notation
   ------------------------------------------------------------------
   display.css met la commande radio en display:none, ce qui la sort aussi
   du parcours clavier : on la repasse hors écran pour qu'elle reste
   focusable, et le focus est reporté sur l'étiquette visible. */
.block-form .rating-option {
    position: relative;
}

.block-form .rating-input {
    display: block;
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}

.block-form .rating-input:focus-visible + .rating-label {
    outline: 3px solid var(--site-accent);
    outline-offset: 2px;
}

.block-form .rating-label:hover {
    background: var(--site-bg-alt);
}

/* Le choix retenu prend l'aplat coloré ; les étoiles et les smileys, eux,
   portent déjà leur couleur — un aplat par-dessus la rendrait illisible. */
.block-form .rating-input:checked + .rating-label {
    background: var(--site-bg-alt);
    color: var(--site-text);
}

.block-form .rating-scale-numbers .rating-input:checked + .rating-label {
    background: var(--site-accent);
    color: #fff;
}

.block-form .rating-scale-numbers .rating-input:checked + .rating-label .rating-number {
    color: inherit;
}

.block-form .rating-scale-numbers .rating-number {
    font-family: var(--site-font-title);
    font-weight: 400;
}

.block-form .rating-label-text {
    color: var(--site-muted);
}

.block-form .rating-input:checked + .rating-label .rating-label-text {
    color: inherit;
}

/* Grille (une question par ligne, une réponse par colonne) */
.block-form .grid-table th,
.block-form .grid-table td,
.block-form .grid-table th:first-child,
.block-form .grid-table td:first-child {
    border-color: var(--site-border);
    background: var(--site-bg-card);
}

.block-form .grid-table th,
.block-form .grid-table thead th:first-child {
    background: var(--site-bg-alt);
    color: var(--site-muted);
    font-family: var(--site-font-mono);
    font-weight: 500;
    font-size: .6875rem;
    letter-spacing: .1em;
    text-transform: uppercase;
}

.block-form .grid-table tbody tr:hover td,
.block-form .grid-table tbody tr:hover td:first-child {
    background: var(--site-bg-alt);
}

.block-form .grid-table td:first-child {
    text-align: left;
}

/* Bloc Documents (blocks/documents.twig) */
.documents-list,
.documents-grid {
    list-style: none;
    margin: 0;
    padding: 0;
}

.documents-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: .875rem;
}

.documents-item a {
    display: flex;
    align-items: center;
    gap: .875rem;
    padding: .875rem 1.125rem;
    border: 1px solid var(--site-border);
    border-radius: var(--site-radius);
    color: var(--site-text);
    text-decoration: none;
    transition: box-shadow .18s ease, border-color .18s ease;
}

.documents-list .documents-item + .documents-item {
    margin-top: .625rem;
}

.documents-item a:hover {
    border-color: transparent;
    box-shadow: var(--site-shadow-hover);
}

.documents-item svg {
    width: 2.25rem;
    height: 2.25rem;
    padding: .5rem;
    flex: 0 0 auto;
    border-radius: var(--site-radius-sm);
    background: var(--site-accent-bg);
    fill: var(--site-accent);
}

.documents-item-title {
    font-weight: 600;
}

.documents-item-meta {
    margin-left: auto;
    color: var(--site-muted);
    font-size: .8125rem;
    white-space: nowrap;
}

/* Bandeau de prévisualisation (layout.twig) */
.site-preview-banner {
    padding: .625rem 1rem;
    background: var(--site-warning, #b45309);
    color: #fff;
    text-align: center;
    font-size: .875rem;
    font-weight: 600;
}

/* Page 404 (404.twig) */
.site-page-error {
    text-align: center;
    padding: 3rem 0;
}

.site-error-code {
    margin: 0;
    font-size: 4rem;
    font-weight: 700;
    line-height: 1;
    color: var(--site-muted);
}

/* Footer
   ------------------------------------------------------------------
   Le pied de page reprend le dégradé violet de la barre de navigation : les
   deux extrémités de la page se répondent, et le contenu tient entre elles.
   Deux étages — les colonnes de liens, puis la ligne de mentions qui referme
   vraiment la page. */
.site-footer {
    margin-top: 5rem;
    background: var(--site-night);
    background: var(--site-nav-gradient);
    color: #e7dcef;
    padding: 3.5rem 0 0;
    font-size: .9375rem;
}

/* Colonnes du pied de page : leur nombre vient du menu `footer` (une colonne
   par entrée de premier niveau), pas d'une valeur écrite ici. `auto-fit` les
   répartit donc quel qu'en soit le nombre. */
.site-footer-top {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 2.5rem 3rem;
}

.site-footer-name {
    margin: 0 0 .75rem;
    font-family: var(--site-font-display);
    font-weight: 700;
    font-size: 1.875rem;
    line-height: 1;
    color: #fff;
}

.site-footer-column-title {
    margin: 0 0 .75rem;
    font-family: var(--site-font-mono);
    font-weight: 700;
    font-size: .6875rem;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--site-gold);
}

.site-footer-column ul {
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: .625rem;
    margin: 0;
    padding: 0;
}

.site-footer a {
    color: #e7dcef;
    text-decoration: none;
}

.site-footer a:hover {
    color: #fff;
    text-decoration: underline;
}

.site-footer :focus-visible {
    outline-color: color-mix(in oklab, var(--site-accent-vivid) 70%, #fff);
}

/* Réseaux sociaux : des pastilles rondes, comme sur la maquette — une liste de
   noms de réseaux en clair se lit comme un menu de plus. */
.site-footer .site-socials a {
    display: inline-flex;
    align-items: center;
    padding: .4375rem .875rem;
    border: 2px solid rgba(255, 255, 255, .35);
    border-radius: var(--site-radius-pill);
    font-size: .8125rem;
    font-weight: 600;
}

.site-footer .site-socials a:hover {
    border-color: var(--site-accent-vivid);
    background: var(--site-accent-vivid);
    color: #fff;
    text-decoration: none;
}

/* Ligne de mentions : légèrement plus sombre que le reste du dégradé, elle
   forme la dernière bande de la page. Le bouton de retour en haut est un
   simple lien d'ancre — pas de JS pour remonter une page. */
.site-footer-credit p {
    margin: 0;
}

.site-footer-credit {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 1rem;
    margin: 3rem 0 0;
    padding: 1.25rem 0;
    border-top: 1px solid rgba(255, 255, 255, .18);
    font-size: .875rem;
    color: #d9c7e4;
}

.site-footer-totop {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.75rem;
    height: 2.75rem;
    flex: 0 0 auto;
    border: 2px solid rgba(255, 255, 255, .45);
    border-radius: 50%;
    color: #e7dcef;
    fill: currentcolor;
    transition: background-color var(--site-transition), border-color var(--site-transition), transform var(--site-transition);
}

.site-footer-totop:hover {
    background: var(--site-accent-vivid);
    border-color: var(--site-accent-vivid);
    color: #fff;
    transform: translateY(-2px);
}

.site-footer-totop svg {
    width: 1.25rem;
    height: 1.25rem;
}

/* Blocs de contenu */
.block {
    margin-bottom: var(--site-block-gap);
}

/* Largeur des blocs (App\Class\WebsiteBlocks::WIDTH)
   ------------------------------------------------------------------
   Sortie du conteneur centré : `left: 50%` puis recentrage par translation,
   ce qui fonctionne quelle que soit la largeur du conteneur parent, sans
   marges négatives calculées à la main. */
.block-width {
    position: relative;
    left: 50%;
    transform: translateX(-50%);
}

.block-width-full {
    width: 100vw;
}

/* Bandeau pleine largeur : le fond va d'un bord à l'autre, mais le contenu
   reste aligné sur le conteneur du site. Le padding fait le centrage, ce qui
   évite d'ajouter un conteneur interne à chacun des templates de blocs. */
/* Le `+ 1.25rem` reprend le padding interne de .site-container : sans lui, le
   texte d'un bandeau serait décalé de 20 px vers la gauche par rapport à
   celui des blocs qui l'entourent — un désalignement discret mais visible dès
   qu'un bandeau suit un paragraphe. */
.block-width-full > .block {
    padding-left: max(1.25rem, calc(50vw - var(--site-container) / 2 + 1.25rem));
    padding-right: max(1.25rem, calc(50vw - var(--site-container) / 2 + 1.25rem));
    border-radius: 0;
}

/* Une bande colorée est une section, pas un paragraphe sur fond de couleur :
   sans souffle vertical, elle se lit comme un encadré qui aurait débordé.
   Le padding horizontal reste celui calculé ci-dessus. */
.block-width-full > .bg-default,
.block-width-full > .bg-muted,
.block-width-full > .bg-accent,
.block-width-full > .bg-success,
.block-width-full > .bg-warning,
.block-width-full > .bg-danger,
.block-width-full > .block-articleheader {
    padding-top: var(--site-section-padding);
    padding-bottom: var(--site-section-padding);
}

/* Deux bandes de même fond qui se suivent doivent se lire comme une seule
   section : l'écart entre blocs ferait apparaître une couture blanche. */
.block-width-full + .block-width-full {
    margin-top: calc(-1 * var(--site-block-gap));
}

/* 100vw inclut la barre de défilement : sans ça, un bloc pleine largeur
   provoquerait un défilement horizontal de quelques pixels.
   `clip` et non `hidden` : `overflow-x: hidden` fait du <body> un conteneur
   de défilement, ce qui neutralise le `position: sticky` de l'en-tête. */
body {
    overflow-x: clip;
}

/* Options communes (App\Class\WebsiteBlocks::ALIGN/BACKGROUND/SPACING) */
.align-left { text-align: left; }
.align-center { text-align: center; }
.align-right { text-align: right; }

.bg-default,
.bg-muted,
.bg-accent,
.bg-success,
.bg-warning,
.bg-danger {
    padding: 1.75rem;
    border-radius: var(--site-radius);
}

/* Les fonds ne changent que le fond : le texte garde la couleur du corps.
   `bg-muted` forçait la couleur atténuée sur tout son contenu, y compris les
   titres — le contraste tombait sous le seuil RGAA sans que l'auteur de la
   page l'ait demandé. */
.bg-default { background: var(--site-bg-alt); }
.bg-muted { background: var(--site-muted-bg); }
.bg-accent { background: var(--site-accent-bg); }
.bg-success { background: var(--site-success-bg); }
.bg-warning { background: var(--site-warning-bg); }
.bg-danger { background: var(--site-danger-bg); }

/* Sections pleine largeur : elles ne se contentent pas d'un aplat.
   ------------------------------------------------------------------
   En pleine largeur, le fond « accent » devient le vrai bandeau de marque —
   dégradé plein et texte blanc — tandis que les fonds neutres reçoivent une
   trame de points très discrète, qui suffit à les distinguer du blanc de la
   page sans attirer l'œil. */
.block-width-full > .bg-accent {
    background: var(--site-nav-gradient);
    color: #fff;
}

.block-width-full > .bg-accent a:not(.site-btn) {
    color: #fff;
    text-decoration-thickness: 2px;
    text-underline-offset: 3px;
}

.block-width-full > .bg-accent .site-btn-solid {
    background: #fff;
    color: var(--site-accent);
    box-shadow: 0 12px 26px -14px rgba(0, 0, 0, .6);
}

/* Opacité volontairement haute : sous 0.9, un libellé de 13 px en capitales
   sur la partie la plus claire du dégradé passe sous le seuil de contraste. */
.block-width-full > .bg-accent .stats-item-label,
.block-width-full > .bg-accent .block-overline {
    color: inherit;
    opacity: .94;
}

.block-width-full > .bg-default,
.block-width-full > .bg-muted {
    border-top: 1px solid var(--site-border);
    border-bottom: 1px solid var(--site-border);
}

.color-muted { color: var(--site-muted); }
.color-accent { color: var(--site-accent); }
.color-success { color: var(--site-success); }
.color-warning { color: var(--site-warning); }
.color-danger { color: var(--site-danger); }

.spacing-none { margin-bottom: 0; }
.spacing-sm { margin-bottom: 1rem; }
.spacing-lg { margin-bottom: calc(var(--site-block-gap) * 1.75); }

/* Bloc Titre
   L'en-tête collant recouvrirait le titre visé depuis le sommaire : la marge
   de défilement le décale d'autant. */
.block-heading {
    scroll-margin-top: 6rem;
}

.block-heading h2,
.block-heading h3,
.block-heading h4 {
    margin: 0;
}

/* Bloc Image et Bloc Vidéo (la classe .block-image/.block-video est portée
   par le <figure> lui-même) : ne touchent pas margin-bottom, laissé à
   .block / .spacing-* (cascade). La largeur est portée par l'option commune
   (.block-width-*), pas par ces blocs. */
.block-image,
.block-video {
    margin-top: 0;
    margin-left: 0;
    margin-right: 0;
}

.block-image img {
    max-width: 100%;
    height: auto;
    border-radius: var(--site-radius-sm);
    display: block;
}

.block-image img { width: 100%; }
/* Sortie de conteneur : gérée par l'option commune de largeur
   (.block-width-*), plus par des classes propres à ces deux blocs. */
.block-width-full .block-image img { border-radius: 0; }
.block-width-full .block-video .video-responsive,
.block-width-full .block-video video { border-radius: 0; }

.block-image figcaption,
.block-video figcaption {
    margin-top: .5rem;
    font-size: .875rem;
    color: var(--site-muted);
}

.block-image figcaption .credit {
    opacity: .8;
}

/* Bloc Vidéo */
.block-video video {
    max-width: 100%;
    border-radius: var(--site-radius-sm);
    display: block;
}

.video-responsive {
    position: relative;
    padding-bottom: 56.25%; /* 16:9 */
    height: 0;
    overflow: hidden;
    border-radius: var(--site-radius-sm);
}

.video-responsive iframe {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    border: 0;
}

.video-fallback a {
    color: var(--site-accent);
}

/* Bloc Galerie */
.gallery-grid {
    display: grid;
    gap: 1rem;
}

.gallery-cols-2 { grid-template-columns: repeat(2, 1fr); }
.gallery-cols-3 { grid-template-columns: repeat(3, 1fr); }
.gallery-cols-4 { grid-template-columns: repeat(4, 1fr); }

.gallery-item {
    margin: 0;
    overflow: hidden;
    border-radius: var(--site-radius);
}

.gallery-item img {
    width: 100%;
    height: 100%;
    aspect-ratio: 4 / 3;
    object-fit: cover;
    display: block;
    transition: transform .4s ease;
}

.gallery-item:hover img {
    transform: scale(1.05);
}

/* Disposition « bande » : une frise d'images bord à bord, qui défile
   horizontalement. Elle sert de respiration entre deux sections de texte,
   là où une grille demanderait au visiteur de la regarder image par image.
   Le défilement reste manuel (pas d'animation automatique) : une bande qui
   bouge toute seule est ingérable au clavier et fatigante à lire. */
.gallery-strip {
    display: flex;
    gap: .5rem;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    padding-bottom: .5rem;
    /* La bande touche les bords de l'écran même quand le bloc est dans le
       conteneur : c'est ce débord qui fait la frise. */
    scrollbar-width: thin;
}

.gallery-strip .gallery-item {
    flex: 0 0 clamp(240px, 30vw, 420px);
    scroll-snap-align: start;
    border-radius: 0;
}

.gallery-strip .gallery-item img {
    aspect-ratio: 3 / 2;
}

.gallery-strip .gallery-item:first-child { border-radius: var(--site-radius) 0 0 var(--site-radius); }
.gallery-strip .gallery-item:last-child { border-radius: 0 var(--site-radius) var(--site-radius) 0; }

/* En pleine largeur, la frise touche vraiment les bords : le padding qui
   recentre le contenu des bandeaux la ramènerait dans le conteneur, et une
   frise qui s'arrête à 1120 px n'est plus une frise. */
.block-width-full > .block-gallery.has-strip {
    padding-left: 0;
    padding-right: 0;
}

.block-width-full .gallery-strip .gallery-item {
    border-radius: 0;
}

.gallery-item figcaption {
    margin-top: .4rem;
    font-size: .8125rem;
    color: var(--site-muted);
}

@media (max-width: 640px) {
    .gallery-cols-3,
    .gallery-cols-4 {
        grid-template-columns: repeat(2, 1fr);
    }
}

/* Bloc Embed */
.embed-map {
    position: relative;
    height: 400px;
    border-radius: var(--site-radius-sm);
    overflow: hidden;
}

.embed-map iframe {
    width: 100%;
    height: 100%;
    border: 0;
}

.embed-link-card {
    display: flex;
    align-items: center;
    gap: .6rem;
    padding: 1rem 1.25rem;
    background: var(--site-bg-alt);
    border-radius: var(--site-radius-sm);
    color: var(--site-text);
    text-decoration: none;
    word-break: break-all;
}

.embed-link-card:hover {
    background: var(--site-muted-bg);
}

.embed-link-card svg {
    flex-shrink: 0;
    width: 1.25rem;
    height: 1.25rem;
    fill: var(--site-accent);
}

/* Bloc Citation */
.block-quote blockquote {
    margin: 0;
    padding: 0;
    font-style: italic;
}

.block-quote.style-boxed blockquote {
    padding: 2rem 2.25rem;
    border-radius: var(--site-radius);
    background: var(--site-gold-bg);
}

/* Citation mise en avant : le guillemet ouvrant, en très grand et en
   filigrane, sert de signal visuel — la seule italique ne suffit pas à
   détacher la citation du texte qui l'entoure. */
.block-quote.style-large blockquote {
    position: relative;
    padding-top: 2.25rem;
    font-family: var(--site-font-title);
    font-size: clamp(1.75rem, 1.3rem + 1.8vw, 2.5rem);
    line-height: 1.22;
    font-style: normal;
    font-weight: 400;
    letter-spacing: -.015em;
}

.block-quote.style-large blockquote::before {
    content: '\201C';
    position: absolute;
    top: -.75rem;
    left: -.25rem;
    font-family: var(--site-font-title);
    font-size: 5rem;
    line-height: 1;
    color: var(--site-accent-vivid);
    opacity: .25;
}

.align-center.block-quote.style-large blockquote::before {
    left: 50%;
    transform: translateX(-50%);
}

.block-quote cite {
    display: block;
    margin-top: 1.25rem;
    font-family: var(--site-font-mono);
    font-style: normal;
    font-size: .75rem;
    font-weight: 500;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--site-muted);
}

/* Bloc Encadré
   ------------------------------------------------------------------
   Une information de service (dates d'inscription, fermeture exceptionnelle)
   se présente comme le bandeau « à la une » d'un journal : un aplat clair,
   un pictogramme en pastille, et le texte sur une seule ligne de lecture. */
.block-callout {
    display: flex;
    gap: 1.25rem;
    align-items: center;
    padding: 1.375rem 1.75rem;
    border-radius: var(--site-radius);
}

/* Le type « info » — le plus courant — prend le jaune du bandeau « à la une ».
   Les trois autres gardent la couleur de leur nature (succès, attention,
   danger), sans quoi une alerte se lirait comme une simple information. */
.block-callout.bg-accent {
    background: var(--site-gold-bg);
}

.block-callout svg {
    flex-shrink: 0;
    width: 2.5rem;
    height: 2.5rem;
    padding: .5rem;
    border-radius: var(--site-radius-pill);
    background: var(--site-accent);
    fill: #fff;
}

.block-callout.bg-success svg { background: var(--site-success); }
.block-callout.bg-warning svg { background: var(--site-warning); }
.block-callout.bg-danger svg { background: var(--site-danger); }

.block-callout p {
    margin: 0;
    line-height: 1.55;
}

/* Bloc Bouton
   Le bouton plein porte le dégradé de marque et une ombre teintée : c'est le
   point le plus regardé d'une page, celui qui doit avoir de la couleur. Le
   reflet qui le traverse au survol (::before) remplace le classique
   changement d'opacité, qui ne se voit pas. */
.site-btn {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .5rem;
    padding: .75rem 1.75rem;
    border-radius: var(--site-radius-pill);
    text-decoration: none;
    font-weight: 600;
    line-height: 1.25;
    border: 2px solid transparent;
    overflow: hidden;
    transition: transform var(--site-transition), box-shadow var(--site-transition), background-color var(--site-transition);
}

.site-btn-sm { padding: .5rem 1.125rem; font-size: .9375rem; }
.site-btn-lg { padding: .9375rem 2.25rem; font-size: 1.125rem; }

/* Bouton principal : le dégradé violet de la maquette, celui du bouton de
   connexion. Le reflet qui le traverse au survol remplace le changement
   d'opacité, qui ne se voyait pas. */
.site-btn-solid {
    background: linear-gradient(135deg, var(--site-night), var(--site-violet));
    color: #fff;
    box-shadow: 0 4px 14px -4px color-mix(in oklab, var(--site-night) 60%, transparent);
}

.site-btn-solid::before {
    content: '';
    position: absolute;
    top: 0;
    left: -60%;
    width: 45%;
    height: 100%;
    background: linear-gradient(100deg, transparent, rgba(255, 255, 255, .28), transparent);
    transform: skewX(-18deg);
    transition: left .55s ease;
}

.site-btn-solid:hover {
    background: linear-gradient(135deg, var(--site-night-soft), var(--site-violet-vivid));
    transform: translateY(-2px);
    box-shadow: var(--site-shadow-hover);
}

.site-btn-solid:hover::before {
    left: 115%;
}

/* Bouton secondaire : simple contour, sans remplissage — deux aplats côte à
   côte se disputeraient l'attention. */
.site-btn-outline {
    background: transparent;
    border-color: var(--site-border-strong);
    color: var(--site-text);
}

.site-btn-outline:hover {
    background: var(--site-bg-card);
    border-color: var(--site-accent-vivid);
    color: var(--site-accent);
}

/* Appel à l'action secondaire, rose : réservé aux actions d'inscription et
   de contact, celles qu'un visiteur doit trouver sans chercher. */
.site-btn-accent.site-btn-solid {
    background: linear-gradient(135deg, var(--site-accent), var(--site-accent-vivid));
    color: #fff;
    box-shadow: 0 4px 14px -4px color-mix(in oklab, var(--site-accent) 60%, transparent);
}

.site-btn-accent.site-btn-solid:hover {
    background: linear-gradient(135deg, var(--site-accent-vivid), var(--site-accent));
}

.site-btn-success.site-btn-solid { background: var(--site-success); }
.site-btn-success.site-btn-outline { border-color: var(--site-success); color: var(--site-success); }
.site-btn-warning.site-btn-solid { background: var(--site-warning); }
.site-btn-warning.site-btn-outline { border-color: var(--site-warning); color: var(--site-warning); }
.site-btn-danger.site-btn-solid { background: var(--site-danger); }
.site-btn-danger.site-btn-outline { border-color: var(--site-danger); color: var(--site-danger); }

/* Bloc Séparateur */
.site-divider-line {
    border: none;
    border-top: 1px solid var(--site-muted-bg);
}

.site-divider-line.size-sm { margin: 1rem 0; }
.site-divider-line.size-md { margin: 2rem 0; }
.site-divider-line.size-lg { margin: 3.5rem 0; }

.site-spacer.size-sm { height: 1rem; }
.site-spacer.size-md { height: 2.5rem; }
.site-spacer.size-lg { height: 5rem; }
.site-spacer.size-xl { height: 8rem; }

/* Bloc Accordéon (<details>/<summary> natifs) */
.block-accordion {
    border-top: 1px solid var(--site-muted-bg);
}

.accordion-item {
    border-bottom: 1px solid var(--site-muted-bg);
}

.accordion-item summary {
    display: flex;
    align-items: center;
    gap: .875rem;
    padding: 1.125rem 0;
    font-weight: 600;
    cursor: pointer;
    list-style: none;
}

.accordion-item summary::-webkit-details-marker {
    display: none;
}

/* Chevron plutôt que +/− : la rotation dit l'état (ouvert/fermé) sans
   changer de glyphe, et se lit à la même vitesse qu'un signe. */
.accordion-item summary::before {
    content: '';
    width: .5rem;
    height: .5rem;
    flex: 0 0 auto;
    margin-right: .25rem;
    border-right: 2px solid var(--site-accent);
    border-bottom: 2px solid var(--site-accent);
    transform: rotate(-45deg);
    transition: transform .2s ease;
}

.accordion-item[open] summary::before {
    transform: rotate(45deg);
}

.block-accordion.marker-success .accordion-item summary::before { border-color: var(--site-success); }
.block-accordion.marker-warning .accordion-item summary::before { border-color: var(--site-warning); }
.block-accordion.marker-danger .accordion-item summary::before { border-color: var(--site-danger); }

.accordion-content {
    padding: 0 0 1.25rem 1.75rem;
    white-space: pre-line;
}

/* Bloc Colonnes */
.block-columns {
    display: grid;
    gap: 2rem;
}

.block-columns.columns-2 { grid-template-columns: repeat(2, 1fr); }
.block-columns.columns-3 { grid-template-columns: repeat(3, 1fr); }
.block-columns.valign-center { align-items: center; }

.columns-col > .block:last-child {
    margin-bottom: 0;
}

@media (max-width: 640px) {
    .block-columns.columns-2,
    .block-columns.columns-3 {
        grid-template-columns: 1fr;
    }
}

.block-text-images {
    display: flex;
    gap: 2rem;
    align-items: flex-start;
    flex-wrap: wrap;
}

.block-text-images .block-text-images-text {
    flex: 3;
    min-width: 260px;
}

.block-text-images .block-text-images-media {
    flex: 2;
    min-width: 260px;
    /* Contient l'agrandissement au survol (voir plus bas) : sans lui, l'image
       déborderait de son coin arrondi. */
    overflow: hidden;
    border-radius: var(--site-radius);
}

.block-text-images.media-left .block-text-images-media {
    order: -1;
}

.block-text-images img {
    width: 100%;
    height: auto;
    border-radius: var(--site-radius-sm);
    display: block;
}

/* Carrousel */
.site-carousel {
    position: relative;
}

.site-carousel-prev,
.site-carousel-next {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    background: rgba(0, 0, 0, .45);
    color: #fff;
    border: none;
    border-radius: 50%;
    width: 36px;
    height: 36px;
    font-size: 1.25rem;
    line-height: 1;
    cursor: pointer;
}

.site-carousel-prev { left: .5rem; }
.site-carousel-next { right: .5rem; }

.site-carousel-prev:hover,
.site-carousel-next:hover {
    background: rgba(0, 0, 0, .7);
}

.site-carousel-dots {
    display: flex;
    justify-content: center;
    gap: .4rem;
    margin-top: .5rem;
}

.site-carousel-dots button {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    border: none;
    background: #c4c8cf;
    cursor: pointer;
    padding: 0;
}

.site-carousel-dots button.active {
    background: var(--site-accent);
}

/* Bloc En-tête d'article */
.block-articleheader {
    padding: clamp(2.5rem, 5vw, 4.5rem) 1.5rem;
    text-align: center;
    background-size: cover;
    background-position: center;
    border-radius: var(--site-radius);
}

.block-articleheader.align-left { text-align: left; }

.block-articleheader.has-bg {
    color: #fff;
}

.block-articleheader h1 {
    margin: 0 auto .75rem;
    max-width: 22ch;
}

.block-articleheader.align-left h1 {
    margin-left: 0;
}

.articleheader-category {
    display: inline-block;
    padding: .3125rem .875rem;
    border-radius: var(--site-radius-pill);
    background: var(--site-accent-bg);
    color: var(--site-accent);
    font-size: .75rem;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    margin-bottom: 1rem;
}

.block-articleheader.has-bg .articleheader-category {
    background: rgba(255, 255, 255, .15);
    color: #fff;
}

.articleheader-excerpt {
    font-size: 1.1875rem;
    line-height: 1.5;
    max-width: 46ch;
    margin: 0 auto 1.25rem;
    opacity: .9;
}

.block-articleheader.align-left .articleheader-excerpt {
    margin-left: 0;
}

.articleheader-meta {
    display: flex;
    gap: 1rem;
    justify-content: center;
    flex-wrap: wrap;
    font-size: .875rem;
    margin: 0;
    opacity: .8;
}

.block-articleheader.align-left .articleheader-meta {
    justify-content: flex-start;
}

/* Bloc Sommaire */
.block-toc {
    padding: 1.25rem 1.5rem;
    background: var(--site-bg-alt);
    border: 1px solid var(--site-border);
    border-radius: var(--site-radius);
}

.toc-title {
    margin: 0 0 .625rem;
    font-family: var(--site-font-mono);
    font-size: .6875rem;
    font-weight: 500;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--site-muted);
}

.block-toc li {
    margin-bottom: .25rem;
}

.block-toc ul {
    margin: 0;
    padding-left: 1.1rem;
}

.block-toc .toc-level-3 { padding-left: 1rem; }
.block-toc .toc-level-4 { padding-left: 2rem; }

.block-toc a {
    color: var(--site-text);
}

.toc-sidebar {
    float: right;
    width: 260px;
    margin-left: 2rem;
}

@media (max-width: 720px) {
    .toc-sidebar {
        float: none;
        width: auto;
        margin-left: 0;
    }
}

/* Blocs À lire aussi et Actualités (mêmes cartes)
   ------------------------------------------------------------------
   Une carte d'actualité est d'abord une image : c'est elle qui donne envie
   de cliquer, le titre confirme. La photo occupe donc tout le haut de la
   carte, le titre est en serif, et la date passe en monospace — trois
   familles pour trois natures d'information. */
.related-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 1.5rem;
}

.related-list {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

.related-item {
    display: flex;
    flex-direction: column;
    border: 1px solid var(--site-border);
    border-radius: var(--site-radius);
    background: var(--site-bg-card);
    color: var(--site-text);
    text-decoration: none;
    overflow: hidden;
    transition: transform var(--site-transition), box-shadow var(--site-transition);
}

.related-item:hover {
    transform: translateY(-4px);
    box-shadow: var(--site-shadow-hover);
}

.related-item-cover {
    display: block;
    width: 100%;
    aspect-ratio: 16 / 9;
    object-fit: cover;
    transition: transform .5s ease;
}

.related-item:hover .related-item-cover {
    transform: scale(1.04);
}

/* Le corps de la carte : tout ce qui n'est pas la photo. Le padding est posé
   ici plutôt que sur la carte, sinon la photo ne pourrait pas aller d'un
   bord à l'autre. */
.related-item-date,
.related-item-title,
.related-item-excerpt {
    padding-left: 1.625rem;
    padding-right: 1.625rem;
}

.related-item-date {
    display: block;
    padding-top: 1.5rem;
    margin-bottom: .5rem;
    font-family: var(--site-font-mono);
    font-size: .6875rem;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--site-muted);
}

.related-item-title {
    display: block;
    font-family: var(--site-font-title);
    font-weight: 400;
    font-size: 1.5rem;
    line-height: 1.15;
}

.related-item-title:first-child {
    padding-top: 1.5rem;
}

.related-item-excerpt {
    display: block;
    margin-top: .625rem;
    padding-bottom: 1.75rem;
    font-size: .9375rem;
    line-height: 1.6;
    color: var(--site-muted);
}

.related-item-title:last-child {
    padding-bottom: 1.75rem;
}

/* En liste, la carte reste compacte : ni photo pleine largeur ni gros titre,
   c'est une file de liens, pas une deuxième grille. */
.related-list .related-item-cover {
    aspect-ratio: 21 / 9;
}

.related-list .related-item-title {
    font-size: 1.25rem;
}

/* Bloc Auteur
   ------------------------------------------------------------------
   Une carte blanche, comme les autres cartes du site, mais bordée à gauche d'un
   filet rose : c'est la seule chose qui la distingue d'un encadré, et il en
   faut une — sur la page d'accueil, ce bloc est la section « qui suis-je ? »,
   pas une note de bas de page. */
.block-authorbox {
    display: flex;
    align-items: center;
    gap: 1.25rem;
    padding: 1.75rem 2rem;
    background: var(--site-bg-card);
    border: 1px solid var(--site-border);
    border-left: 5px solid var(--site-accent-vivid);
    border-radius: var(--site-radius);
    box-shadow: var(--site-shadow);
}

.block-authorbox.align-center {
    flex-direction: column;
    align-items: center;
    text-align: center;
}

/* Sans photo téléversée, l'initiale tient lieu de portrait : une carte
   « qui suis-je ? » sans rien à gauche n'est qu'un paragraphe encadré. */
.authorbox-avatar {
    width: 72px;
    height: 72px;
    border-radius: 50%;
    object-fit: cover;
    flex-shrink: 0;
    border: 3px solid var(--site-accent-bg);
}

.authorbox-name {
    font-family: var(--site-font-title);
    font-weight: 800;
    font-size: 1.25rem;
    color: var(--site-night);
    margin: 0 0 .35rem;
}

.authorbox-bio {
    margin: 0 0 .5rem;
    color: var(--site-muted);
}

.authorbox-bio:last-child {
    margin-bottom: 0;
}

.authorbox-socials {
    display: flex;
    gap: .6rem;
}

.authorbox-socials svg {
    width: 1.1rem;
    height: 1.1rem;
    fill: var(--site-accent);
}

/* Bloc Portes d'entrée (blocks/tiles.twig)
   ------------------------------------------------------------------
   La pièce maîtresse de la page d'accueil, et la seule où la couleur porte le
   texte plutôt que l'inverse. La première question d'un visiteur sur un site
   d'établissement n'est pas « que proposez-vous ? » mais « laquelle de ces
   entrées est la mienne ? » : d'où trois grandes cartes de couleurs franches,
   photo en bandeau, pastille ronde à cheval sur la photo, intitulé en capitales.

   Les couleurs tournent sur trois temps — turquoise, violet, rose — et le cycle
   reprend à la quatrième carte. Chaque carte pose ses deux nuances dans
   --tile-vivid et --tile-ink ; tout le reste de la carte (dégradé, pastille,
   ombre) s'y réfère, ce qui évite de redéclarer trois fois chaque règle. */
.tiles-grid {
    list-style: none;
    display: grid;
    grid-template-columns: var(--tiles-columns);
    gap: 1.75rem;
    margin: 0;
    padding: 0;
}

/* Le gabarit de colonnes passe par une variable, et non directement par ces
   trois règles : en disposition « slider », c'est le ruban intérieur de Swiper
   qui doit le porter, pas la piste. Une variable descend jusqu'à lui, une
   déclaration de grille non. */
.tiles-cols-2 { --tiles-columns: repeat(auto-fit, minmax(320px, 1fr)); }
.tiles-cols-3 { --tiles-columns: repeat(auto-fit, minmax(290px, 1fr)); }
.tiles-cols-4 { --tiles-columns: repeat(auto-fit, minmax(250px, 1fr)); }

/* Les couleurs des cartes sont éclaircies vers le blanc, pour qu'elles
   dialoguent avec le bandeau pastel au lieu de lui répondre par trois aplats
   saturés. Deux contraintes ont fixé les valeurs :

   - l'encre porte le texte blanc. Elle ne peut donc pas descendre sous 4,5:1,
     ce qui laisse peu de marge : le turquoise n'a que cinq points à donner
     avant de passer sous le seuil. Les trois sont calées à ~5,05:1, avec la
     marge qu'il faut sur le plancher ;
   - la nuance vive, elle, ne porte aucun texte — elle ne sert qu'à la bande
     photo et au haut du dégradé, le texte commençant plus bas. C'est donc là
     qu'on peut être franchement pastel, et c'est ce qui fait l'essentiel de
     l'adoucissement.

   Les pourcentages diffèrent d'une couleur à l'autre parce qu'elles ne partent
   pas de la même clarté : mélangées à l'identique, le violet resterait
   nettement plus lourd que les deux autres. Ceux-ci les amènent toutes trois au
   même poids à l'œil. */
.tiles-item:nth-child(3n+1) {
    --tile-vivid: color-mix(in oklab, var(--site-teal-vivid) 65%, #fff);
    --tile-ink: color-mix(in oklab, var(--site-teal) 95%, #fff);
}

.tiles-item:nth-child(3n+2) {
    --tile-vivid: color-mix(in oklab, var(--site-violet-vivid) 49%, #fff);
    --tile-ink: color-mix(in oklab, var(--site-violet) 83%, #fff);
}

.tiles-item:nth-child(3n+3) {
    --tile-vivid: color-mix(in oklab, var(--site-accent-vivid) 61%, #fff);
    --tile-ink: color-mix(in oklab, var(--site-accent) 93%, #fff);
}

/* Le dégradé atteint sa nuance sombre à 40 % de la hauteur, c'est-à-dire juste
   sous le bandeau photo : tout le texte de la carte repose donc sur l'aplat
   sombre, seul à tenir le contraste du blanc. Un dégradé étalé sur toute la
   hauteur ferait passer l'intitulé sur la nuance vive, où le blanc décroche. */
.tiles-link {
    position: relative;
    display: flex;
    flex-direction: column;
    height: 100%;
    border-radius: var(--site-radius);
    overflow: hidden;
    background: linear-gradient(180deg, var(--tile-vivid) 0, var(--tile-ink) 40%);
    color: #fff;
    text-decoration: none;
    box-shadow: 0 12px 30px -10px color-mix(in oklab, var(--tile-ink) 55%, transparent);
    transition: transform var(--site-transition), box-shadow var(--site-transition);
}

.tiles-link:hover {
    transform: translateY(-4px);
    box-shadow: 0 20px 40px -12px color-mix(in oklab, var(--tile-ink) 65%, transparent);
}

.tiles-item-media {
    position: relative;
    display: block;
    height: 150px;
    overflow: hidden;
}

/* Voile teinté sur la photo : il pose la couleur de la carte sur une image
   dont on ne maîtrise ni le cadrage ni la dominante, et fait la jointure avec
   l'aplat qui suit. Il finit sur la nuance sombre, celle que le dégradé de la
   carte a atteinte juste sous la bande : sans cela, une arête franche
   marquerait le bas de la photo. */
.tiles-item-media::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg,
        color-mix(in oklab, var(--tile-vivid) 40%, transparent) 0,
        var(--tile-vivid) 55%,
        var(--tile-ink) 100%);
}

/* Sans photo, la bande resterait un aplat vide : la nuance vive s'y suffit,
   la carte reste finie. */
.tiles-link:not(.has-image) .tiles-item-media {
    background: var(--tile-vivid);
}

.tiles-item-media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    transition: transform .5s ease;
}

.tiles-link:hover .tiles-item-media img {
    transform: scale(1.04);
}

/* Pastille à cheval sur la bande photo : elle identifie la rubrique d'un coup
   d'œil, y compris quand la photo est encore en cours de chargement. Le liseré
   blanc la détache de la photo comme de l'aplat.
   Elle est positionnée sur la carte, pas sur la bande photo : celle-ci rogne
   son contenu (c'est ce qui permet à la photo de s'agrandir sans déborder), et
   la pastille doit justement déborder. `top` reprend donc la hauteur de la
   bande — les deux valeurs vont ensemble. */
.tiles-item-icon {
    position: absolute;
    left: 50%;
    top: 150px;
    z-index: 2;
    transform: translate(-50%, -50%);
    width: 5.375rem;
    height: 5.375rem;
    padding: 1.25rem;
    border: 4px solid #fff;
    border-radius: 50%;
    background: var(--tile-ink);
    fill: #fff;
    box-shadow: 0 6px 16px rgba(0, 0, 0, .2);
    transition: transform var(--site-transition);
}

.tiles-link:hover .tiles-item-icon {
    transform: translate(-50%, -50%) scale(1.05);
}

.tiles-item-body {
    display: flex;
    flex-direction: column;
    align-items: center;
    flex: 1;
    padding: 3.25rem 1.75rem 2rem;
    text-align: center;
}

/* Sans pastille, le texte n'a pas à réserver la place qu'elle occupait. */
.tiles-link:not(.has-icon) .tiles-item-body {
    padding-top: 1.75rem;
}

.tiles-item-label {
    display: block;
    font-family: var(--site-font-title);
    font-weight: 800;
    font-size: clamp(1.25rem, 1.05rem + .7vw, 1.6875rem);
    line-height: 1.15;
    letter-spacing: .02em;
    text-transform: uppercase;
    color: #fff;
    margin-bottom: 1rem;
}

.tiles-item-description {
    display: block;
    max-width: 17rem;
    margin-bottom: 1.25rem;
    font-size: .9375rem;
    line-height: 1.45;
    color: rgba(255, 255, 255, .95);
}

/* Appel à l'action décoratif (aria-hidden dans le gabarit) : la carte entière
   est déjà le lien, cette pastille ne fait que le dire. Poussée en bas par
   `margin-top: auto`, elle s'aligne d'une carte à l'autre même quand les
   descriptions n'ont pas la même longueur. */
.tiles-item-cta {
    display: inline-flex;
    align-items: center;
    gap: .75rem;
    margin-top: auto;
    padding: .5rem .5rem .5rem 1.375rem;
    border: 2px solid rgba(255, 255, 255, .7);
    border-radius: var(--site-radius-pill);
    font-weight: 700;
    font-size: 1rem;
    transition: background-color var(--site-transition), border-color var(--site-transition);
}

.tiles-item-cta-arrow {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.125rem;
    height: 2.125rem;
    border-radius: 50%;
    background: rgba(255, 255, 255, .22);
    font-size: 1.125rem;
    line-height: 1;
    transition: transform var(--site-transition);
}

.tiles-link:hover .tiles-item-cta {
    background: rgba(255, 255, 255, .14);
    border-color: #fff;
}

.tiles-link:hover .tiles-item-cta-arrow {
    transform: translateX(3px);
}

.tiles-link:focus-visible {
    outline: 3px solid var(--site-night);
    outline-offset: 3px;
}

/* Slider de portes d'entrée (disposition « slider »)
   ------------------------------------------------------------------
   Une bande qui défile horizontalement plutôt qu'une grille qui se replie sur
   plusieurs lignes. C'est ce qu'il faut dès que les entrées sont nombreuses et
   de même nature — une série d'articles, une série de niveaux — là où la
   grille dit « voici tout », la bande dit « en voici le début ».

   Le mécanisme est Swiper (vendor/swiper/swiper-bundle.min.css, chargé avant
   cette feuille, initialisé dans theme.js). Ce qui suit ne fait que l'habiller :
   Swiper pose la mécanique de défilement et laisse ses flèches et ses points
   sans forme arrêtée, ce qui tombe bien — le thème a les siennes. */
.tiles-slider {
    position: relative;
}

/* La piste rogne ce qui la déborde : sans ce padding, l'ombre portée des cartes
   serait coupée en bas et sur les côtés. La marge négative rend au bloc la
   largeur que le padding lui prend, pour que la bande reste alignée sur les
   autres blocs de la page. */
.tiles-track.swiper {
    /* La piste est une fenêtre, pas une mise en page : elle doit lâcher la
       grille héritée de .tiles-grid, sinon le ruban de Swiper se retrouverait
       casé dans une colonne de 290 px au lieu de la largeur entière. */
    display: block;
    padding: .25rem .25rem 1.5rem;
    margin: -.25rem -.25rem -1.5rem;
}

/* Hauteurs égales. Swiper donne à ses diapositives la hauteur de la piste, ce
   qui laisse les cartes à la hauteur de leur contenu : trois cartes aux
   descriptions inégales finissent dépareillées. `height: auto` les étire toutes
   sur la plus haute — c'est aussi ce qui permet à la pastille « Découvrir » de
   s'aligner d'une carte à l'autre. */
.tiles-track .swiper-slide {
    height: auto;
}

/* Avant que Swiper n'ait pris la main — et pour toujours si le script ne se
   charge pas —, la piste n'est qu'un conteneur qui rogne, avec un ruban de
   tuiles pleine largeur : une seule serait visible, les autres inatteignables.
   Ces trois règles lui rendent l'allure d'une grille, celle du gabarit en
   disposition « grille ». C'est à la fois le repli sans JavaScript et ce qui
   évite le soubresaut au moment de l'initialisation. */
.tiles-track:not(.swiper-initialized) {
    overflow: visible;
}

.tiles-track:not(.swiper-initialized) .swiper-wrapper {
    display: grid;
    grid-template-columns: var(--tiles-columns);
    gap: 1.75rem;
}

.tiles-track:not(.swiper-initialized) .swiper-slide {
    width: auto;
}

/* Les flèches et les points sont hors de la piste, qui rogne : ils ne
   s'afficheraient pas dedans. Ils restent donc masqués tant que Swiper ne les
   a pas armés — sans lui, ils ne commanderaient rien. */
.tiles-slider-nav,
.tiles-slider-dots {
    display: none;
}

/* Flèches
   ------------------------------------------------------------------
   Posées sur les bords de la bande, à cheval sur les cartes. */
.swiper-initialized ~ .tiles-slider-nav {
    display: flex;
    position: absolute;
    top: 4.6875rem;
    z-index: 3;
    width: 2.75rem;
    height: 2.75rem;
    padding: 0;
    align-items: center;
    justify-content: center;
    border: 0;
    border-radius: 50%;
    background: var(--site-bg-card);
    color: var(--site-night);
    box-shadow: 0 6px 18px -4px rgba(60, 30, 80, .35);
    cursor: pointer;
    transition: background-color var(--site-transition), color var(--site-transition), opacity var(--site-transition);
}

.tiles-slider-nav.is-prev { left: -1.125rem; }
.tiles-slider-nav.is-next { right: -1.125rem; }

.tiles-slider-nav svg {
    width: 1.25rem;
    height: 1.25rem;
}

.tiles-slider-nav:hover:not(.swiper-button-disabled) {
    background: var(--site-accent-vivid);
    color: #fff;
}

/* Estompée plutôt que masquée : une flèche qui disparaît au bout de la bande
   décale l'autre et fait sauter la mise en page à chaque saut. */
.tiles-slider-nav.swiper-button-disabled {
    opacity: .35;
    cursor: default;
}

/* `swiper-button-lock` : Swiper la pose quand tout tient dans la largeur —
   trois tuiles affichées sur trois n'ont rien à faire défiler. */
.tiles-slider-nav.swiper-button-lock,
.tiles-slider-dots.swiper-pagination-lock {
    display: none;
}

/* Points
   ------------------------------------------------------------------
   Ils disent combien de vues il reste, ce que les flèches ne disent pas. Des
   barres plutôt que des pastilles : à 8 px, un rond actif et un rond inactif se
   distinguent mal, deux barres de longueurs différentes non. */
.swiper-initialized ~ .tiles-slider-dots {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: .5rem;
    margin-top: 1.25rem;
}

.tiles-slider-dots .swiper-pagination-bullet {
    width: 1.25rem;
    height: .375rem;
    margin: 0;
    border: 0;
    border-radius: var(--site-radius-pill);
    background: var(--site-border-strong);
    opacity: 1;
    cursor: pointer;
    transition: background-color var(--site-transition), width var(--site-transition);
}

.tiles-slider-dots .swiper-pagination-bullet-active {
    width: 2.25rem;
    background: var(--site-accent-vivid);
}

.tiles-slider-dots .swiper-pagination-bullet:hover {
    background: var(--site-accent);
}

/* Sur téléphone, les flèches n'ont plus la place de se poser à cheval sur les
   cartes sans en masquer la moitié : les points et le glissé au doigt
   suffisent. */
@media (max-width: 640px) {
    .tiles-track:not(.swiper-initialized) .swiper-wrapper {
        gap: 1rem;
    }

    .swiper-initialized ~ .tiles-slider-nav {
        display: none;
    }
}

/* Bloc Logos partenaires (blocks/partners.twig)
   Les logos sont désaturés au repos : une rangée de logos multicolores
   attire plus l'œil que le contenu de la page, alors qu'elle n'est qu'une
   mention. La couleur revient au survol. */
.partners-row {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 2rem 2.5rem;
    margin: 0;
    padding: 0;
}

.partners-item img {
    max-height: 34px;
    max-width: 140px;
    width: auto;
    display: block;
    filter: grayscale(1);
    opacity: .65;
    transition: filter .2s ease, opacity .2s ease;
}

.partners-item:hover img,
.partners-item a:focus-visible img {
    filter: grayscale(0);
    opacity: 1;
}

/* Bloc Agenda (blocks/events.twig)
   ------------------------------------------------------------------
   Un agenda se consulte, il ne se lit pas comme le reste. Le turquoise l'y
   aide sans reprendre le rose, déjà porteur des appels à l'action. */
.block-events {
    background: var(--site-teal);
    color: #fff;
    border-radius: var(--site-radius-lg);
    padding: 2.25rem 2rem;
}

.block-events .events-title {
    color: #fff;
}

.events-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
}

.events-item {
    display: flex;
    align-items: center;
    gap: 1.125rem;
    padding: 1.125rem .25rem;
    border-top: 1px solid rgba(255, 255, 255, .22);
}

.events-item:first-child {
    border-top: 0;
}

/* Pastille de date translucide : sur l'aplat turquoise, un fond blanc plein
   ferait tache — la transparence garde l'unité du bloc. */
.events-item-date {
    flex: 0 0 3.875rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: .5rem 0;
    border-radius: var(--site-radius-sm);
    background: rgba(255, 255, 255, .14);
    color: #fff;
    line-height: 1.05;
}

.events-item-day {
    font-family: var(--site-font-title);
    font-size: 1.75rem;
    line-height: 1;
}

.events-item-month {
    font-family: var(--site-font-mono);
    font-size: .625rem;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--site-gold);
}

.events-item-title {
    margin: 0;
    font-weight: 600;
    font-size: 1.03125rem;
    line-height: 1.3;
}

.events-item-when {
    margin: .25rem 0 0;
    color: rgba(255, 255, 255, .8);
    font-size: .84375rem;
}

.events-item-description {
    margin: .5rem 0 0;
    font-size: .9375rem;
    color: rgba(255, 255, 255, .88);
}

/* ======================================================================
   Animations et effets
   ======================================================================
   Trois principes, pour que le mouvement reste au service de la lecture :

   1. Rien ne dépend du JavaScript pour être visible. Les apparitions au
      défilement ne sont armées que si `theme.js` a posé `.js-enabled` sur
      <html> ; sans lui, tout s'affiche normalement.
   2. Rien ne bouge pour ceux qui n'en veulent pas : la règle globale
      `prefers-reduced-motion` (tout en haut de ce fichier) neutralise
      transitions et animations, et theme.js n'arme alors aucun observateur.
   3. Le mouvement porte l'attention, il ne la disperse : une seule
      apparition par bloc, jamais d'animation en boucle sur du texte.
   ====================================================================== */

/* Apparition au défilement. `theme.js` pose `.reveal` sur les blocs de la
   page puis `.is-visible` quand ils entrent dans le champ. */
.js-enabled .reveal {
    opacity: 0;
    transform: translateY(28px);
    transition:
        opacity var(--site-reveal-duration) cubic-bezier(.22, .61, .36, 1),
        transform var(--site-reveal-duration) cubic-bezier(.22, .61, .36, 1);
    will-change: opacity, transform;
}

.js-enabled .reveal.is-visible {
    opacity: 1;
    transform: none;
    will-change: auto;
}

/* À l'impression, aucun défilement n'a lieu : tout ce qui attend encore son
   apparition sortirait blanc sur le papier. Le PDF d'une page doit contenir
   la page entière, animations ou pas. */
@media print {
    .js-enabled .reveal,
    .js-enabled .block-width.reveal {
        opacity: 1 !important;
        transform: none !important;
    }

    .js-enabled .block-width.reveal {
        transform: translateX(-50%) !important;
    }
}

/* Les blocs « full » sortent du conteneur avec
   `left: 50%; transform: translateX(-50%)`. Le déplacement de l'apparition
   doit donc s'y ajouter, sinon il remplace le recentrage et le bloc part de
   50 % de l'écran vers la droite — ce qui provoque un défilement horizontal
   sur toute la page. */
.js-enabled .block-width.reveal {
    transform: translateX(-50%) translateY(28px);
}

.js-enabled .block-width.reveal.is-visible {
    transform: translateX(-50%);
}

/* Les enfants d'une grille se révèlent en cascade : chaque carte arrive un
   souffle après la précédente. Le décalage est plafonné à la cinquième,
   sinon une grille de vingt éléments finirait par se remplir trop lentement. */
.js-enabled .reveal.is-visible > .links-grid > li,
.js-enabled .reveal.is-visible > .tiles-grid > li,
.js-enabled .reveal.is-visible > .team-grid > li,
.js-enabled .reveal.is-visible .related-grid > a,
.js-enabled .reveal.is-visible > .stats-grid > li {
    animation: reveal-item .55s cubic-bezier(.22, .61, .36, 1) both;
}

.js-enabled .reveal.is-visible > :is(.links-grid, .tiles-grid, .team-grid, .stats-grid) > li:nth-child(2),
.js-enabled .reveal.is-visible .related-grid > a:nth-child(2) { animation-delay: .08s; }
.js-enabled .reveal.is-visible > :is(.links-grid, .tiles-grid, .team-grid, .stats-grid) > li:nth-child(3),
.js-enabled .reveal.is-visible .related-grid > a:nth-child(3) { animation-delay: .16s; }
.js-enabled .reveal.is-visible > :is(.links-grid, .tiles-grid, .team-grid, .stats-grid) > li:nth-child(4),
.js-enabled .reveal.is-visible .related-grid > a:nth-child(4) { animation-delay: .24s; }
.js-enabled .reveal.is-visible > :is(.links-grid, .tiles-grid, .team-grid, .stats-grid) > li:nth-child(n+5),
.js-enabled .reveal.is-visible .related-grid > a:nth-child(n+5) { animation-delay: .3s; }

@keyframes reveal-item {
    from {
        opacity: 0;
        transform: translateY(20px) scale(.98);
    }
    to {
        opacity: 1;
        transform: none;
    }
}

/* Cartes cliquables : un filet rose se déploie sur le bord haut au survol.
   C'est le signal qui manquait pour dire « cette carte est un lien » sans
   ajouter de texte.
   Les liens utiles n'en font plus partie : ce ne sont plus des cartes mais les
   colonnes d'un même panneau, et un filet posé en haut d'une colonne se lirait
   comme un séparateur de plus. */
.news-item,
.documents-item a {
    position: relative;
}

.news-item::before,
.documents-item a::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 3px;
    border-radius: var(--site-radius) var(--site-radius) 0 0;
    background: var(--site-accent-vivid);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform .35s cubic-bezier(.22, .61, .36, 1);
}

.news-item:hover::before,
.documents-item a:hover::before {
    transform: scaleX(1);
}

/* La pastille d'icône prend la couleur d'accent au survol de sa carte : le
   changement se lit d'un coup d'œil, même en vision périphérique. */
.documents-item svg {
    transition: background-color var(--site-transition), fill var(--site-transition), transform var(--site-transition);
}

.documents-item a:hover svg {
    background: var(--site-accent-vivid);
    fill: #fff;
    transform: rotate(-6deg) scale(1.06);
}

/* L'icône des liens utiles garde sa couleur — c'est elle qui identifie la
   colonne — et se contente de s'incliner. */
.links-item-icon {
    transition: transform var(--site-transition);
}

.links-item:hover .links-item-icon {
    transform: rotate(-6deg) scale(1.06);
}

/* Pilules : le survol les teinte de la couleur de l'entrée. */
.block-links.style-pills .links-item {
    transition: transform var(--site-transition), background-color var(--site-transition), border-color var(--site-transition);
}

.block-links.style-pills .links-item:hover .links-item-icon {
    transform: none;
}

/* Compteurs animés (theme.js) : la valeur est comptée à partir de zéro quand
   le bloc entre dans le champ. `tabular-nums` est posé plus haut, ce qui
   évite que le chiffre gigote pendant le décompte. */
.stats-item-value[data-count-to] {
    display: inline-block;
    min-width: 1ch;
}

/* Images : léger agrandissement au survol pour le bloc « texte + images »,
   qui n'en avait pas. */
.block-text-images .block-text-images-media img {
    transition: transform .5s ease;
}

.block-text-images:hover .block-text-images-media img {
    transform: scale(1.03);
}
