/*
 * brand.css — overrides de marque secomprendre. Chargé après components.css,
 * tout dans @layer brand, var(--token) uniquement (pas de :root ici).
 */
@layer brand {

  /* @font-face Google Sans — désactivés : .woff2 absents, cf. fonts/README-FONTS.txt

  @font-face {
    font-family: 'Google Sans';
    src: url('../fonts/GoogleSans-Regular.woff2') format('woff2');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
  }
  @font-face {
    font-family: 'Google Sans';
    src: url('../fonts/GoogleSans-SemiBold.woff2') format('woff2');
    font-weight: 600;
    font-style: normal;
    font-display: swap;
  }
  */

  @font-face {
    font-family: 'Source Serif 4';
    src: url('../fonts/SourceSerif4-Regular.woff2') format('woff2');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
  }

  /* .icon-arrow : classe posée aussi par le JS du carrousel (cards.php). */
  .icon-arrow {
    display: inline-block;
    flex: none;
    width: 1em;
    height: 1em;
    background-color: currentColor;
    -webkit-mask: url('../images/arrow.svg') center / contain no-repeat;
    mask: url('../images/arrow.svg') center / contain no-repeat;
  }
  .icon-arrow--left {
    transform: scaleX(-1);
  }
  .icon-arrow--down {
    transform: rotate(90deg);
  }
  .icon-arrow--up {
    transform: rotate(-90deg);
  }

  body {
    background-color: var(--color-bg);
    line-height: 1.2;
  }

  /* —— Header : burger à toutes les largeurs, sur le JS partagé nav-disclosure.js
     (contrat .nav-toggle / #nav-menu / [aria-expanded] / .nav-open). */
  /* Le header sticky recouvre les cibles d'ancre ; pas de token de hauteur de
     header, la grille est content-driven. */
  html {
    scroll-padding-block-start: calc(var(--size-logo-height) + 1.5rem);
  }
  header[role="banner"] {
    position: sticky;
    inset-block-start: 0;
    z-index: 10;
    border-bottom: none;
    /* Neutralise le `padding: 1rem 2rem` du socle (`@layer blocks`) : le rythme
       de la barre est porté par `.header-inner` seul. */
    padding-inline: 0;
    padding-block: 0;
  }
  .header-inner {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    max-width: none;
    margin-inline: 0;
    /* `--header-pad` : padding horizontal de la barre, réutilisé par le panneau
       ouvert (`inset-inline` négatif) — une seule valeur à tenir. */
    --header-pad: 2rem;
    padding: 0.5rem var(--header-pad);
    position: relative;
  }
  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    .header-inner {
      gap: 2rem;
      --header-pad: 1rem;
      /* Hauteur figée : à l'ouverture, `.nav-toggle` et `#nav-menu` passent en
         `position: absolute` et quittent le calcul de la grille ; sans plancher,
         la rangée se recalcule et tout ce qui suit sautait vers le bas. */
      min-height: var(--size-logo-height);
    }
  }
  /* Positions explicites : la nav (rangée 2, pleine largeur) précède le second
     logo dans le DOM (header.php) — en auto-placement il tomberait sous la nav. */
  .header-start {
    grid-row: 1;
    grid-column: 1;
    justify-self: start;
    display: flex;
    align-items: center;
    gap: var(--space-block);
  }
  .header-connexion {
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-semibold);
    color: var(--color-text);
    text-decoration: none;
    white-space: nowrap;
  }
  .header-connexion:hover,
  .header-connexion:focus-visible {
    text-decoration: none;
  }
  /* < 768px : barre = logo à gauche · bouton Menu au centre · Connexion à droite
     (FR/DE n'est plus dans la barre — il passe en 1ᵉ item du menu ouvert, plus
     bas). Connexion sortie du flux de `.header-start` et calée au bord droit de
     `.header-inner` (position: relative). Logo Caritas secondaire retiré. */
  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    .header-connexion {
      display: block;
      position: absolute;
      inset-inline-end: var(--header-pad);
      inset-block-start: 50%;
      transform: translateY(-50%);
    }
    .logo-secondary {
      display: none;
    }
    .header-start .language-switch {
      display: none;
    }
  }
  .language-switch {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
  }
  /* 2ᵉ rendu dans `#nav-menu` (header.php) : caché par défaut, montré seulement
     dans le panneau ouvert < 768px (règle plus bas). */
  nav#nav-menu .language-switch {
    display: none;
  }
  .language-switch__link {
    display: inline-flex;
    align-items: center;
    min-height: var(--size-control);
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-semibold);
    color: var(--color-text);
    text-decoration: none;
  }
  .language-switch__link:hover,
  .language-switch__link:focus-visible {
    text-decoration: underline;
  }
  /* Langue courante mise en avant en rouge (demande) ; l'autre langue reste en encre. */
  .language-switch__link[aria-current="true"] {
    color: var(--color-primary);
  }
  /* Séparateur en ::before : un « / » dans le HTML serait lu par les lecteurs d'écran. */
  .language-switch__link + .language-switch__link::before {
    content: "/";
    margin-inline-end: var(--space-xs);
    color: var(--color-text);
  }
  .logo-secondary {
    grid-row: 1;
    grid-column: 3;
    justify-self: end;
    max-height: var(--size-logo-height);
  }
  /* `padding: 0` explicite : @layer brand ne bat @layer blocks que sur les
     longhands redéclarés — le 0.5rem du socle ferait varier la hauteur du
     header à l'ouverture (le bouton ouvert sort du flux). */
  .nav-toggle {
    /* Affiché seulement avec JS (html.js posé par header.php) : sans JS le
       bouton serait inerte, la nav reste inline. */
    display: none;
    align-items: center;
    justify-content: center;
    grid-row: 1;
    grid-column: 2;
    justify-self: center;
    width: auto;
    height: auto;
    border: none;
    background: none;
    padding: 0;
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-semibold);
    color: var(--color-text);
  }
  html.js .nav-toggle {
    display: inline-flex;
  }
  /* Ouvert : « Fermer » reste simplement à sa place dans la barre (plus de
     carte encadrée) — le panneau pleine largeur descend en dessous. */
  .nav-toggle-icon {
    display: none;
  }
  /* Deux <span> togglés plutôt qu'un aria-label statique : le nom accessible
     suit l'état (WCAG 2.5.3). */
  .nav-toggle-label--open {
    display: none;
  }
  .nav-toggle[aria-expanded="true"] .nav-toggle-label--closed {
    display: none;
  }
  .nav-toggle[aria-expanded="true"] .nav-toggle-label--open {
    display: inline;
  }
  /* Scopé `#nav-menu`, pas `nav[role="navigation"]` : ce dernier matcherait
     aussi la pagination du socle. */
  nav#nav-menu {
    grid-row: 2;
    grid-column: 1 / -1;
    width: 100%;
  }
  /* Fermé par défaut seulement avec JS : sans JS le panneau reste inline. */
  html.js nav#nav-menu:not(.nav-open) {
    display: none;
  }
  /* Panneau ouvert : bande blanche PLEINE LARGEUR sous la barre, sans bordure —
     juste deux coins bas arrondis. `absolute` + `grid-row/column: auto` le
     sortent du calcul de hauteur de .header-inner. */
  nav#nav-menu.nav-open {
    display: block;
    position: absolute;
    grid-row: auto;
    grid-column: auto;
    /* Annule le padding horizontal de `.header-inner` (contexte de
       positionnement) pour toucher les deux bords de l'écran. */
    inset-inline: calc(-1 * var(--header-pad));
    width: auto;
    inset-block-start: 100%;
    z-index: 10;
    border: none;
    border-radius: 0 0 var(--radius-xl) var(--radius-xl);
    background: var(--color-bg);
    max-block-size: 65svh;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding-block: 0 var(--space-block);
    padding-inline: 1rem;
  }
  /* `margin-block-start: 0` : le socle pose `margin-block-start` sur
     `nav[role="navigation"].nav-open` ≤ 767.98px, longhand non redéclarée ici. */
  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    nav#nav-menu.nav-open {
      margin-block-start: 0;
      max-block-size: 100svh;
    }
  }
  nav#nav-menu ul {
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 0;
  }
  nav#nav-menu ul li a {
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-semibold);
    /* Interligne resserré dans le panneau ouvert : ~moitié du padding socle
       (`nav[role="navigation"] ul li a { padding: 0.5rem 0 }`). */
    padding-block: 0.25rem;
  }
  /* < 768px : la bascule FR/DE (2ᵉ rendu, en tête de `#nav-menu`) devient le
     1ᵉ item du panneau ouvert ; celle de `.header-start` est masquée en parallèle. */
  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    nav#nav-menu .language-switch {
      display: flex;
      justify-content: center;
      padding-block: 0.25rem var(--space-xs);
    }
  }
  nav#nav-menu ul ul {
    position: static;
    border: none;
    background: none;
    min-width: 0;
    padding: 0;
    /* Sous-menus toujours dépliés : dans un burger toutes largeurs, un parent
       tapé sur tablette naviguerait au lieu de déplier. */
    display: flex;
    flex-direction: column;
  }

  h1, h2, h3, h4, h5, h6 {
    font-family: var(--font-family-base);
    font-weight: var(--font-weight-semibold);
    line-height: 1.1;
  }

  h4 {
    font-size: var(--font-size-m);
  }

  .hero__title {
    text-transform: uppercase;
  }

  /* Tokens redéclarés via `:where(html)` (spécificité nulle) : @layer brand
     bat @layer tokens par ordre de couche ; pas de `:root` (lint-brand-css).
     Rayon : tout consommateur de ces tokens, pas seulement les titres. */
  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    :where(html) {
      --font-size-h3: 1.4rem;
      --font-size-h1: 2rem;
      --font-size-h2: 2rem;
      --font-size-display: 2rem;
      --font-size-lg: 1.2rem;
      --font-size-m: 1.1rem;
      --font-size-base: 0.9rem;
      --font-size-sm: 0.7rem;
    }

    /* Le socle fait lire à h1/h2 le token du palier du dessous
       (`h1 { font-size: var(--font-size-h2) }`) ; `:not(.hero__title)` : le
       hero reste sur --font-size-display. */
    h1:not(.hero__title) {
      font-size: var(--font-size-h1);
    }

    h2 {
      font-size: var(--font-size-h2);
    }
  }

  .hero {
    background: none;
    padding-inline: 0;
  }

  .hero:not(.hero--full):not(.hero--media) {
    min-height: 0;
    padding-block: 0;
  }

  /* Hero avec image = plein écran quel que soit le champ `hauteur` ;
     --size-header : s'arrête sous le header sticky. */
  .hero--media {
    min-height: calc(100svh - var(--size-header, 0px)); /* allow-naked-px: fallback du token optionnel — calc() exige une unité */
    /* `--color-scrim` : token optionnel lu par `.hero__media::after` (socle),
       neutralisé — vérifier la lisibilité des surtitre/CTAs en blanc. */
    --color-scrim: transparent;
  }

  /* Chevron du socle masqué : le clic-pour-défiler (app.js) suffit ; le markup
     vient du snippet partagé. */
  .hero__scroll {
    display: none;
  }

  /* Zone de clic-pour-défiler (app.js). */
  .hero--full,
  .hero--media {
    cursor: pointer;
  }

  /* `contain` en mobile : un `cover` recadre lourdement une image cadrée pour
     le desktop ; le letterboxing laisse voir le fond de page. */
  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    .hero--media .hero__img {
      object-fit: contain;
      object-position: center;
    }
  }

  /* Masqué visuellement seulement (h1 conservé pour lecteurs d'écran / SEO) ;
     pattern .visually-hidden dupliqué faute de classe dans le snippet partagé. */
  .hero--media .hero__title {
    position: absolute;
    width: 1px; /* allow-naked-px: clip a11y (rect), pas une dimension tokenisable */
    height: 1px; /* allow-naked-px: clip a11y */
    margin: -1px; /* allow-naked-px: clip a11y */
    padding: 0;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    border: 0;
  }

  .hero__title {
    /* Override local, pas du token --font-size-display (partagé avec
       .block-slider__title). */
    font-size: var(--font-size-h2);
    line-height: 1.05;
    overflow-wrap: break-word;
    hyphens: auto;
  }
  /* Span animé (app.js) : le dictionnaire `lang="fr"` césurerait à tort les
     mots non français du cycle. */
  .hero__title-typewriter {
    hyphens: none;
  }

  .hero:not(.hero--media) .hero__title {
    color: var(--color-text);
  }

  .hero__subtitle {
    font-family: var(--font-family-text);
    line-height: 1.3;
    max-width: none;
  }

  /* —— Home : le hero est `hero--media hero--full` (image plein écran). Fond posé
     derrière l'image — invisible en `cover` desktop, visible dans le letterbox
     `contain` mobile. */
  body.page-accueil .hero--media {
    background: var(--color-hero-accueil-bg);
  }
  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    body.page-accueil .hero--media {
      overflow: hidden;
    }
    /* Illustration agrandie dans son cadre letterbox (excédent rogné). */
    body.page-accueil .hero--media .hero__img {
      transform: scale(1.5);
    }
    /* Liste des langues de la home : 3 colonnes sur mobile (défaut générique : 2). */
    body.page-accueil .block-list--columns ul,
    body.page-accueil .block-list--columns ol {
      column-count: 3;
    }
  }

  /* Nom de marque « Se Comprendre » en italique partout dans le texte (règle
     éditoriale) — enrobé en `<i class="brand-name">` par app.js, jamais dans le
     menu. Sans JS : nom en romain, aucune régression. `<i>` est déjà italique,
     la règle explicite fixe l'intention et sert de point d'accroche. */
  .brand-name {
    font-style: italic;
  }

  .block-text {
    font-family: var(--font-family-base);
    font-size: var(--font-size-base);
    font-weight: normal;
    line-height: 1.3;
  }

  /* Paliers du champ `taille` (text.yml). « Grand » garde la serif Source
     Serif 4 et un interlignage 1.2 : décision de marque, les 3 autres clients
     restent sans-serif. */
  .block-text--size-sm {
    font-size: var(--font-size-base);
  }
  .block-text--size-m {
    font-size: var(--font-size-m);
  }
  .block-text--size-lg {
    font-family: var(--font-family-text);
    font-size: var(--font-size-lg);
    line-height: 1.2;
  }

  .block-list ul,
  .block-list ol {
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-semibold);
    /* 1.1 : les lignes d'un même item doivent rester plus proches que l'écart
       entre items (décision de marque ; le socle reste à 1.7). */
    line-height: 1.1;
  }
  .block-list li + li {
    margin-block-start: 0.25rem;
  }
  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    .block-list ul,
    .block-list ol {
      margin-block-start: var(--space-xs);
    }
  }
  /* `:not(.block)` obligatoire : layout-section.php enveloppe chaque bloc dans
     `<div class="block block-list">` et list.php rend un second `.block-list`
     dedans, seul à porter les modificateurs — sans lui, les `:not(--*)`
     matchent l'enveloppe. */
  .block-list:not(.block):not(.block-list--columns):not(.block-list--bullet) ul,
  .block-list:not(.block):not(.block-list--columns):not(.block-list--bullet) ol,
  .block-text ul,
  .block-text ol {
    padding-inline-start: 1.5rem;
  }
  .block-list:not(.block):not(.block-list--columns):not(.block-list--bullet) li + li,
  .block-text li + li {
    margin-block-start: 1rem;
  }
  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    .block-list:not(.block):not(.block-list--columns):not(.block-list--bullet) li + li,
    .block-text li + li {
      margin-block-start: 0.5rem;
    }
  }
  .block-text ul,
  .block-text ol {
    line-height: 1.1;
  }
  /* 2 colonnes gardées en mobile : `column-width: auto` retire la largeur
     minimale du socle (11rem) qui forçait le repli à 1 colonne. */
  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    .block-list--columns ul,
    .block-list--columns ol {
      column-width: auto;
      column-count: 2;
    }
  }

  /* `--list-color` est posé en style inline par snippets/blocks/list.php. */
  .block-list--accent ul,
  .block-list--accent ol {
    color: var(--list-color, var(--color-text));
  }

  .block-list--accent li::marker {
    color: var(--list-color, var(--color-text));
  }

  /* `--list-bullet` (URL du SVG) est posé en inline par list.php. */
  .block-list--bullet ul,
  .block-list--bullet ol {
    padding-inline-start: 0;
  }
  .block-list--bullet li {
    position: relative;
    list-style: none;
    padding-inline-start: 1.75em;
  }
  .block-list--bullet li::before {
    content: "";
    position: absolute;
    inset-inline-start: 0;
    inset-block-start: 0.35em;
    width: 1em;
    height: 1em;
    background-color: var(--list-color, var(--color-text));
    -webkit-mask: var(--list-bullet) center / contain no-repeat;
    mask: var(--list-bullet) center / contain no-repeat;
  }

  /* Champ `taille` (list.yml) ; « Grand » = défaut `.block-list ul/ol`, sans classe. */
  .block-list--size-m ul,
  .block-list--size-m ol {
    font-size: var(--font-size-m);
  }
  .block-list--size-sm ul,
  .block-list--size-sm ol {
    font-size: var(--font-size-sm);
  }

  /* —— Cartes (bloc cards) */
  .block-cards__item {
    background: var(--color-secondary);
    border: none;
    border-radius: var(--radius-lg);
    --card-accent: var(--color-secondary);
  }
  .block-cards__body {
    padding: 1.25rem;
  }
  /* Encre sur mauve plein : AA ≈6.2:1 ; le gris atténué du socle ne passe pas. */
  .block-cards__title,
  .block-cards__desc {
    color: var(--color-text);
  }
  /* Le titre rendu en `<span>` (pilules) n'est pas un heading : sans cette
     règle il reste au poids 400. */
  .block-cards__title {
    font-family: var(--font-family-base);
    font-weight: var(--font-weight-semibold);
  }
  /* Texte en encre, pas en accent : contraste insuffisant sur fond pâle. */
  .block-cards__badge {
    background: var(--color-bg);
    color: var(--color-text);
    border: var(--border-width-strong) solid var(--color-secondary);
    border-radius: var(--radius-pill);
    font-weight: var(--font-weight-semibold);
  }
  .block-cards__item:has(.block-cards__link:hover) {
    filter: brightness(0.97);
  }

  /* Vignette avec image (markup : snippets/blocks/cards.php). Le lien est une
     vraie boîte (absolute, inset 0), pas `display: contents` : un lien sans
     boîte ne matche pas `:hover`/`:focus-visible` de façon fiable. */
  .block-cards__item--media {
    position: relative;
    border-radius: 0;
    aspect-ratio: 1 / 1; /* allow-naked-px: ratio, var() illégal ici */
  }
  .block-cards__item--media .block-cards__link {
    position: absolute;
    inset: 0;
    display: block;
  }
  .block-cards__item--media .block-cards__figure {
    position: absolute;
    inset: 0;
    margin: 0;
  }
  .block-cards__item--media .block-cards__figure img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
  /* Cadre vide : même gabarit que l'image pour garder la même taille dans le
     groupe (cards.php, $hasAnyImage). */
  .block-cards__item--media .block-cards__figure-empty {
    position: absolute;
    inset: 0;
  }
  /* Déclenché sur l'item, pas le lien : `lien` est optionnel (cards.yml) et
     une fiche sans URL n'émet aucun `<a>`. `:focus-within` : sans lien, jamais
     matché — voulu. */
  .block-cards__item--media .block-cards__figure-img--hover {
    position: absolute;
    inset: 0;
    opacity: 0;
    transition: opacity 0.3s ease-out; /* allow-naked-px: durée, var() illégal ici */
  }
  .block-cards__item--media:hover .block-cards__figure-img--hover,
  .block-cards__item--media:focus-within .block-cards__figure-img--hover {
    opacity: 1;
  }
  /* Masqué au survol seulement si l'item a une image de survol
     (`.block-cards__figure--hover`, classe émise par cards.php quand $imageHover). */
  .block-cards__overlay {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1em;
    padding: 1.25rem;
    text-align: center;
    transition: opacity 0.3s ease-out; /* allow-naked-px: durée, var() illégal ici */
  }
  .block-cards__item--media:has(.block-cards__figure--hover):hover .block-cards__overlay,
  .block-cards__item--media:has(.block-cards__figure--hover):focus-within .block-cards__overlay {
    opacity: 0;
  }
  .block-cards__item--media .block-cards__title,
  .block-cards__item--media .block-cards__desc {
    margin: 0;
    font-family: var(--font-family-base);
    font-size: var(--font-size-base);
    color: var(--color-white);
  }
  .block-cards__item--media .block-cards__desc > :first-child { margin-block-start: 0; }
  .block-cards__item--media .block-cards__desc > :last-child { margin-block-end: 0; }
  .block-cards__item--media .block-cards__desc p + p { margin-block-start: 0.5em; }

  /* —— Vignette sans image : pilule <details>/<summary> (cards.php).
     Corps déplié = pilule séparée glissée entièrement sous le bandeau titre
     (marge négative = hauteur du bandeau), z-index sur le bandeau pour qu'il
     peigne par-dessus. Grid (même grid-area) abandonné : `<summary>` interfère
     avec son statut d'item de grille. */
  .block-cards__item--pill {
    padding: 0;
    border-radius: var(--radius-pill);
    /* Rayon calculé (moitié de la hauteur réelle du bandeau) : `--radius-pill`
       (999px) est clampé par le navigateur à une valeur qu'aucun token ne
       connaît, et `--radius-lg` ne tombe pas dessus — raccord visible.
       Partagé par le summary et le pill-body. */
    --pill-corner: calc((1.75rem + 2 * 0.9rem) / 2);
  }
  .block-cards__item--pill[open] {
    /* Le clip radius-pill du parent rognerait les deux pilules à sa forme. */
    overflow: visible;
    /* Sinon le fond mauve du parent dessine un lobe derrière les deux pilules. */
    background: transparent;
  }
  .block-cards__item--pill > .block-cards__title,
  .block-cards__item--pill > .block-cards__link {
    display: block;
    padding: 0.9rem 1.5rem;
    text-align: center;
    font-size: var(--font-size-sm);
  }
  .block-cards__pill-summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-xs);
    padding: 0.9rem 1.25rem;
    /* `--pill-corner`, pas `--radius-pill` : même rayon que .block-cards__pill-body. */
    border-radius: var(--pill-corner);
    background: var(--color-secondary);
    cursor: pointer;
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-semibold);
    list-style: none;
    position: relative;
    z-index: 1;
  }
  .block-cards__pill-summary::-webkit-details-marker {
    display: none;
  }
  /* Le socle cible `.block-cards__title` directement (font-size-lg) : une
     correspondance directe gagne sur l'héritage du `<summary>`. */
  .block-cards__pill-summary .block-cards__title {
    font-size: var(--font-size-sm);
  }
  /* Marge négative = 2 × --pill-corner = hauteur pleine du bandeau ; le
     padding-block-start la compense. */
  .block-cards__pill-body {
    margin-block-start: calc(-2 * var(--pill-corner));
    padding: calc(2 * var(--pill-corner) + 0.75rem) 1.25rem 1.1rem;
    border-radius: var(--pill-corner);
    background: var(--color-text);
  }
  .block-cards__item--pill .block-cards__desc {
    margin: 0;
    padding-block: 0.5rem;
    padding-inline-start: 0.5rem;
    font-family: var(--font-family-base);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-semibold);
  }
  .block-cards__item--pill .block-cards__desc > :first-child { margin-block-start: 0; }
  .block-cards__item--pill .block-cards__desc > :last-child { margin-block-end: 0; }
  .block-cards__item--pill .block-cards__desc p + p { margin-block-start: 0.5em; }
  /* Hors de la règle `> .block-cards__link` (enfant direct) ; classe partagée,
     hérite du survol de la carte. */
  .block-cards__pill-body .block-cards__link {
    display: block;
    margin-block-start: 1rem;
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-semibold);
  }
  /* Bandeau mauve : AA ≈2.8:1, compromis assumé (à surveiller) ; corps encre :
     le blanc tient l'AA. */
  .block-cards__item--pill .block-cards__title,
  .block-cards__pill-summary,
  .block-cards__item--pill .block-cards__desc,
  .block-cards__item--pill .block-cards__link {
    color: var(--color-white);
  }
  .block-cards__toggle-icon {
    flex: none;
    width: 1.75rem;
    height: 1.75rem;
    border-radius: 50%;
    background: var(--color-text);
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
  .block-cards__toggle-icon::before {
    content: "+";
    color: var(--color-white);
    line-height: 1;
  }
  .block-cards__item--pill[open] .block-cards__toggle-icon::before {
    content: "\2212"; /* signe moins (U+2212), pas un trait d'union */
  }

  /* —— Carrousel (`.block-cards--carousel` ; flèches injectées par le JS de
     cards.php, absentes sans JS). `.block-cards` seul reste la grille du socle,
     partagée avec children-list. Full-bleed : `calc(50% - 50vw)` (pas 100vw,
     faussé par la barre de scroll) ; --carousel-inset = distance
     viewport→contenu de .layout-container, en padding + scroll-padding des deux
     côtés pour que le scroll max natif tombe sur la dernière vignette alignée. */
  .block-cards-carousel {
    --carousel-inset: calc(max(0px, (100vw - var(--container-max)) / 2) + var(--container-padding)); /* allow-naked-px: borne basse de max() — calc() exige une unité */
    margin-inline: calc(50% - 50vw);
  }
  .block-cards.block-cards--carousel {
    display: flex;
    flex-wrap: nowrap;
    /* flex-start : une pilule dépliée n'étire pas les autres vignettes. */
    align-items: flex-start;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    padding-inline: var(--carousel-inset);
    scroll-padding-inline: var(--carousel-inset);
    gap: 0;
    margin-block-start: 0;
  }
  .block-cards.block-cards--carousel > .block-cards__item {
    flex: 0 0 auto;
    scroll-snap-align: start;
    /* 3.5 : la 4ᵉ vignette dépasse en amorce, signe qu'on peut défiler. */
    width: calc(100% / 3.5);
  }
  @media (max-width: 1080px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    .block-cards.block-cards--carousel > .block-cards__item {
      width: calc(100% / 2);
    }
  }
  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    .block-cards.block-cards--carousel > .block-cards__item {
      width: calc(100% - 2.5rem); /* allow-naked-px: amorce visuelle, pas un token de marque */
    }
  }
  .block-cards__controls {
    display: flex;
    justify-content: flex-start;
    padding-inline-start: var(--carousel-inset);
    gap: var(--space-xs);
    margin-block-end: var(--space-xs);
  }
  .block-cards__arrow {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--size-control);
    height: var(--size-control);
    border: none;
    border-radius: 50%;
    background: var(--color-secondary);
    color: var(--color-white);
    /* Dimensionne l'icône `.icon-arrow` (1em) injectée par le JS. */
    font-size: var(--font-size-lg);
    cursor: pointer;
  }
  .block-cards__arrow:hover,
  .block-cards__arrow:focus-visible {
    background: var(--color-primary);
  }
  .block-cards__arrow:disabled {
    opacity: 0.35;
    cursor: default;
  }

  /* —— Carte événement (snippets/cards/event.php) */
  .event-card {
    /* Seam redéfini par les modificateurs `.event-card--tag-*` ; repli primary
       si le modificateur manque. */
    background: var(--event-card-color, var(--color-primary));
    border: none;
    border-radius: var(--radius-lg);
    padding: 1rem;
    display: flex;
    flex-direction: column;
    color: var(--color-text);
    line-height: 1.2;
    aspect-ratio: 4 / 5;
    overflow: hidden;
    /* `container-type: size` sûr ici : la hauteur vient de l'aspect-ratio,
       jamais du contenu ; `.event-card__desc` lit `cqh`. */
    container-type: size;
    container-name: event-card;
    transition: transform var(--motion-duration-fast, 0.15s) var(--motion-ease-standard, ease);
  }
  .event-card:has(.event-card__link:hover) {
    transform: scale(0.95);
  }
  /* Indice stable calculé en PHP (`crc32()` du premier tag, cards/event.php)
     sur 5 tints ; l'encre tient l'AA sur chacun. Au-delà de 5 tags distincts,
     deux partagent une couleur — assumé (ADR-031). */
  .event-card--tag-0 {
    --event-card-color: var(--color-secondary-light);
  }
  .event-card--tag-1 {
    --event-card-color: var(--color-tertiary-light);
  }
  .event-card--tag-2 {
    --event-card-color: var(--color-quaternary-light);
  }
  .event-card--tag-3 {
    --event-card-color: var(--color-quinary-light);
  }
  .event-card--tag-4 {
    --event-card-color: var(--color-primary-light);
  }
  /* `display: flex` + `flex: 1`, pas `display: contents` : avec `contents`,
     seule la zone couverte par le texte des enfants était cliquable. */
  .event-card__link {
    display: flex;
    flex-direction: column;
    flex: 1;
    color: inherit;
    text-decoration: none;
  }
  /* `.article-card` a `overflow: hidden` : un outline sur le lien serait rogné
     → reporté sur la carte via `:has()` (WCAG 2.4.7), offset hors du clip. */
  .article-card:has(.article-card__link:focus-visible) {
    outline: var(--focus-ring-width) solid var(--color-primary);
    outline-offset: var(--focus-ring-offset);
  }
  .event-card__header {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--space-xs);
    font-weight: var(--font-weight-semibold);
    padding-block-end: 0.5rem;
    margin-block-end: 1rem;
    border-block-end: var(--border-width-strong) solid var(--color-text);
  }
  .event-card time,
  .event-card__city {
    color: inherit;
    font-size: var(--font-size-base);
  }
  .event-card__badge {
    display: inline-block;
    align-self: flex-start;
    background: var(--color-text);
    color: var(--color-white);
    border-radius: var(--radius-pill);
    padding: 0.5rem 1.25rem;
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-semibold);
    margin-block-end: 1.25rem;
  }
  /* Badge « Complet » (`.badge.badge-full`, cards/event.php) aligné sur la
     pilule `.event-card__badge`. `align-self: flex-start` : l'inline-block
     blockifié en enfant flex s'étirerait sinon. */
  .event-card .badge-full {
    align-self: flex-start;
    margin-block-end: 1.25rem;
    padding: 0.5rem 1.25rem;
    border-radius: var(--radius-pill);
    background: var(--color-primary);
    color: var(--color-white);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-semibold);
  }
  .event-card__meta {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
  }
  .event-card__title {
    margin: 0;
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-semibold);
    line-height: inherit;
  }
  /* `.event-time`/`.event-location` sont atténuées au socle ; tout `<p>` nu de
     la méta suit (cards/event.php). */
  .event-card .event-time,
  .event-card .event-location,
  .event-card__meta p {
    color: inherit;
    font-size: var(--font-size-base);
  }
  .event-card__desc {
    margin-block-start: auto;
    padding-block-start: 2rem;
    font-weight: var(--font-weight-semibold);
    color: inherit;
    /* Seuil d'ellipse = moitié de la carte : `50cqh` (container `.event-card`)
       / `1.2em` (line-height hérité) = nombre de lignes. `3` déclaré avant en
       repli : un moteur qui rejette le calc() ignore la déclaration entière. */
    display: -webkit-box;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    -webkit-line-clamp: calc(50cqh / 1.2em);
    line-clamp: calc(50cqh / 1.2em);
    -webkit-box-orient: vertical;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  /* —— Carte article (snippets/cards/article.php) */
  .article-card {
    background: var(--color-quinary-light);
    padding: 0;
    border: 0;
    display: flex;
    flex-direction: column;
    color: var(--color-text);
    line-height: 1.2;
    overflow: hidden;
    transition: transform var(--motion-duration-fast, 0.15s) var(--motion-ease-standard, ease);
  }
  .article-card:has(.article-card__link:hover) {
    transform: scale(0.95);
  }
  /* Vraie boîte plutôt que `display: contents` : sans image, un lien en
     `contents` laissait le haut de la carte inerte. */
  .article-card__link {
    display: flex;
    flex-direction: column;
    flex: 1;
    color: inherit;
    text-decoration: none;
  }
  .article-card__figure {
    margin: 0;
    aspect-ratio: 1 / 1;
    overflow: hidden;
  }
  .article-card__figure img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
  }
  /* `padding: 0` neutralise `.article-card h2, .article-card time { padding }`
     du socle (cible le tag h2 nu, atteint aussi .article-card__title). */
  .article-card time,
  .article-card__title {
    padding: 0;
    margin: 0;
  }
  .article-card__body {
    padding: 1.25rem 1.5rem 1.5rem;
    display: flex;
    flex-direction: column;
  }
  .article-card__date {
    color: var(--color-primary);
    font-weight: var(--font-weight-semibold);
    font-size: var(--font-size-sm);
    margin-block-end: 0.4rem;
  }
  .article-card__title {
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-semibold);
    line-height: 1.25;
    padding-inline-end: var(--space-xs);
  }
  .article-card__desc {
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
    margin-block-start: 0.6rem;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  /* Sans image, `.article-card__body` resterait collé en haut de la carte
     étirée par la grille ; `auto` l'aligne sur le bas comme les cartes illustrées. */
  .article-card:not(:has(.article-card__figure)) .article-card__body {
    margin-block-start: auto;
  }

  /* Encadré : une seule présentation — le champ `variant` du blueprint partagé
     est ignoré par snippets/blocks/callout.php (conservé pour tcbellaria). */
  .callout {
    position: relative;
    overflow: visible; /* la queue de bulle déborde de la boîte */
    border-inline-start: none;
    background: var(--color-primary);
    color: var(--color-white);
    border-radius: var(--radius-lg);
    /* Repère partagé par `.callout__tail`/`.callout__link`, redéfini par `.callout--sm`. */
    --callout-padding: 2.5rem;
    padding: var(--callout-padding);
    /* La queue de bulle déborde ~2.65rem sous la boîte. */
    margin-block-end: calc(var(--space-block) + var(--space-xs));
  }
  .callout--sm {
    --callout-padding: 1.5rem;
    border-radius: var(--radius);
  }
  /* Tracé exact du SVG source (cf. callout.php) : forme asymétrique
     irréalisable en CSS simple. `100%` : l'origine du path est le bord bas du panneau. */
  .callout__tail {
    position: absolute;
    inset-block-start: 100%;
    inset-inline-start: var(--callout-padding, 2.5rem);
    width: 4rem;
    height: auto;
  }
  .callout__tail path {
    fill: var(--color-primary);
  }
  .callout__title {
    margin: 0 0 1rem;
    font-size: var(--font-size-h3);
    /* Semibold, pas 700 : pas de face 700 self-hostée — le faux-gras du
       navigateur produit un contour parasite. */
    font-weight: var(--font-weight-semibold);
    line-height: 1.05;
  }
  .callout--sm .callout__title {
    font-size: var(--font-size-lg);
  }
  .callout__body {
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-semibold);
  }
  .callout--sm .callout__body {
    font-size: var(--font-size-base);
  }
  .callout__body ul {
    list-style: none;
    margin: 0.75em 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.9rem;
  }
  .callout__body li {
    position: relative;
    padding-inline-start: 1.5em;
  }
  .callout__body li::before {
    content: "";
    position: absolute;
    inset-inline-start: 0;
    inset-block-start: 0.55em;
    width: 0.5em;
    height: 0.5em;
    border-radius: 50%;
    background: currentColor;
  }
  /* Le socle pose `a { color: primary }` : rouge sur rouge ici. */
  .callout__body a {
    color: var(--color-white);
    text-decoration: underline;
  }
  /* À cheval sur le bord bas (translateY(50%)) — exige `position: relative;
     overflow: visible` sur `.callout`. Radius pilule explicite : gagne sur le
     radius-xl de `.btn` par ordre source. */
  .callout__link {
    position: absolute;
    inset-inline-end: var(--callout-padding, 2.5rem);
    inset-block-end: 0;
    transform: translateY(50%);
    border: none;
    border-radius: var(--radius-pill);
    background: var(--color-text);
    color: var(--color-white);
    font-size: var(--font-size-sm);
  }
  .callout__link:hover,
  .callout__link:focus-visible {
    background: var(--color-text-subtle, var(--color-text));
  }

  /* Mobile : tout encadré passe au format `.callout--sm` (mêmes valeurs). */
  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    .callout {
      --callout-padding: 1.5rem;
      border-radius: var(--radius);
      /* Marge ≥ débord de la queue (4rem de large, inchangée en petit format) :
         la valeur de base ne suffisait pas. */
      margin-block-end: calc(var(--space-block) * 2);
    }
    .callout__title {
      font-size: var(--font-size-lg);
    }
    .callout__body {
      font-size: var(--font-size-base);
    }
  }

  /* Sauge `--color-tertiary` (cycle des aplats de marque), pas `--color-success`
     (token d'état). BUILDER.md §7.1 */
  .comparison__side {
    background: var(--color-quinary-light);
  }
  .comparison__side--negatif { --comparison-accent: var(--color-primary); }
  .comparison__side--positif { --comparison-accent: var(--color-tertiary); }
  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    .comparison__points {
      font-size: var(--font-size-base);
    }
  }

  .block-quote__body {
    font-style: normal;
  }

  figure.block-quote {
    background: none;
    border: none;
    border-radius: 0;
    padding-inline: 0;
    padding-block: var(--space-block);
  }
  figure.block-quote::before {
    content: none;
  }

  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    .block-button {
      margin-block: 0;
    }
  }

  .btn,
  button[type="submit"] {
    border-radius: var(--radius-xl);
    font-weight: var(--font-weight-semibold);
  }

  .btn--secondary {
    border: none;
  }
  .btn--secondary:hover {
    background: transparent;
    color: var(--color-primary);
  }

  /* Flèche en ::after masqué : `.btn` est un `<a>`/`<button>` sans enfant
     dédié pour `.icon-arrow`. */
  .btn::after {
    content: "";
    display: inline-block;
    width: 0.8em;
    height: 0.8em;
    margin-inline-start: 0.5em;
    vertical-align: -0.1em;
    background-color: currentColor;
    -webkit-mask: url('../images/arrow.svg') center / contain no-repeat;
    mask: url('../images/arrow.svg') center / contain no-repeat;
    transition: transform 0.15s ease;
  }
  .btn:hover::after,
  .btn:focus-visible::after {
    transform: translateX(0.25rem);
  }

  /* Le snippet logo-row.php de ce thème émet toujours piste + duplicat `[inert]` :
     masqués hors mobile (rangée statique non doublée) ; sous 768px la boucle du
     socle est réappliquée sans la garde `--defilement`, et sa pause au survol
     est neutralisée à cette largeur seulement. */
  .logo-row:not(.logo-row--defilement) .logo-row__list[inert] {
    display: none;
  }
  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    /* La piste en `max-content` ferait défiler le document horizontalement. */
    .logo-row:not(.logo-row--defilement) {
      overflow: clip;
    }
    .logo-row:not(.logo-row--defilement) .logo-row__list[inert] {
      display: flex;
    }
    .logo-row:not(.logo-row--defilement) .logo-row__track {
      display: flex;
      flex-wrap: nowrap;
      width: max-content;
      animation: logo-row-scroll var(--logo-row-scroll-duration, 32s) linear infinite;
    }
    .logo-row:not(.logo-row--defilement) .logo-row__list {
      flex-wrap: nowrap;
      gap: var(--space-section);
      padding-inline: var(--space-section) 0;
    }
    .logo-row--defilement .logo-row__track:hover,
    .logo-row--defilement .logo-row__track:focus-within,
    .logo-row:not(.logo-row--defilement) .logo-row__track:hover,
    .logo-row:not(.logo-row--defilement) .logo-row__track:focus-within {
      animation-play-state: running;
    }
  }

  /* reduced-motion : la règle `*` du socle neutralise `animation-duration`
     mais pas `iteration-count: infinite` — repli du socle dupliqué pour ce cas. */
  @media (max-width: 767.98px) and (prefers-reduced-motion: reduce) { /* allow-naked-px: breakpoint, var() illégal en media query */
    /* La liste repasse en wrap : `clip` couperait verticalement. */
    .logo-row:not(.logo-row--defilement) {
      overflow: visible;
    }
    .logo-row:not(.logo-row--defilement) .logo-row__track {
      animation: none;
      width: auto;
    }
    .logo-row:not(.logo-row--defilement) .logo-row__list[inert] {
      display: none;
    }
    .logo-row:not(.logo-row--defilement) .logo-row__list {
      flex-wrap: wrap;
      justify-content: center;
      padding-inline: 0;
    }
  }

  /* —— Accordéon (FAQ). `--accordion-couleur` est posé en style inline par le
     snippet ; `--section-bg` = fond de section ; `--accordion-color` = valeur
     résolue. */
  .block-accordion .accordion {
    --accordion-color: var(--accordion-couleur, var(--section-bg, var(--color-secondary)));
    border: none;
    border-radius: var(--radius-xl);
    background: var(--accordion-color);
    padding: var(--space-section);
    overflow: visible;
  }
  /* Une section contenant un accordéon ne peint pas sa bande : le panneau
     absorbe la couleur. */
  .layout-section:has(.block-accordion) {
    background: transparent;
  }

  /* Variantes de fond exposées par `Agency\SectionVariant` (flag
     `agency.core.builder.section-variants`, ADR-034). `periwinkle`/`violet` ne
     correspondent plus aux couleurs portées : non renommés, la valeur `bgcolor`
     est déjà écrite dans le contenu. */
  .section-secondary  { --section-bg: var(--color-secondary);   --section-text: var(--color-text); }
  .section-periwinkle { --section-bg: var(--color-tertiary);    --section-text: var(--color-text); }
  .section-violet     { --section-bg: var(--color-quaternary); --section-text: var(--color-text); }
  .section-quinary    { --section-bg: var(--color-quinary);    --section-text: var(--color-text); }

  .section-accent-light     { --section-bg: var(--color-primary-light);    --section-text: var(--color-text); }
  .section-secondary-light  { --section-bg: var(--color-secondary-light);  --section-text: var(--color-text); }
  .section-periwinkle-light { --section-bg: var(--color-tertiary-light);   --section-text: var(--color-text); }
  .section-violet-light     { --section-bg: var(--color-quaternary-light); --section-text: var(--color-text); }
  .section-quinary-light    { --section-bg: var(--color-quinary-light);    --section-text: var(--color-text); }

  .block-accordion .accordion__item {
    border: none;
  }
  .block-accordion .accordion__item + .accordion__item {
    border-block-start: none;
  }
  .block-accordion .accordion__title {
    background: transparent;
    padding: 0.6rem 0;
    color: var(--color-text);
    font-weight: var(--font-weight-semibold);
    font-size: var(--font-size-lg);
    list-style: none;
    display: flex;
    /* `stretch` se comporte en flex-start dès qu'un enfant a une hauteur
       explicite (le ::before) : la flèche collerait en haut du titre. */
    align-items: center;
    /* Repris dans le padding-inline de `.accordion__body` : la réponse démarre
       sous la 1ʳᵉ lettre du titre. */
    gap: 0.75rem;
  }
  .block-accordion .accordion__title::-webkit-details-marker { display: none; }
  /* `.accordion__item` est le `<details>` (snippets/blocks/accordion.php).
     Largeur fixe : référence d'alignement de `.accordion__body`. */
  .block-accordion .accordion__title::before {
    content: "";
    flex: none;
    width: var(--accordion-arrow-width, 1.25rem);
    height: var(--accordion-arrow-width, 1.25rem);
    background-color: currentColor;
    -webkit-mask: url('../images/arrow.svg') center / contain no-repeat;
    mask: url('../images/arrow.svg') center / contain no-repeat;
    transition: transform 0.2s ease;
  }
  .block-accordion .accordion__item[open] > .accordion__title::before {
    transform: rotate(90deg);
  }
  .block-accordion .accordion__title:hover::before,
  .block-accordion .accordion__title:focus-visible::before {
    transform: rotate(90deg);
  }

  /* `[dir="rtl"]` posé par templates/default.php : la flèche doit pointer vers
     le texte. `rotate(180deg)` plutôt que `scaleX(-1)` : compose avec le
     rotate(90deg) des états survol/ouvert. */
  [dir="rtl"] .block-accordion .accordion__title::before {
    transform: rotate(180deg);
  }
  [dir="rtl"] .block-accordion .accordion__title:hover::before,
  [dir="rtl"] .block-accordion .accordion__title:focus-visible::before,
  [dir="rtl"] .block-accordion .accordion__item[open] > .accordion__title::before {
    transform: rotate(90deg);
  }

  /* Item ouvert : titre soudé à la bulle blanche. `margin-inline: -bleed` +
     `padding-inline: bleed` s'annulent pour le contenu (la flèche ne bouge pas)
     et font déborder le fond ; `.accordion { overflow: visible }` l'autorise.
     Même --accordion-bleed sur .accordion__body pour la même largeur. */
  .block-accordion .accordion__item[open] > .accordion__title {
    --accordion-bleed: 1rem;
    background: var(--color-surface);
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    margin-inline: calc(-1 * var(--accordion-bleed));
    padding: 0.9rem var(--accordion-bleed);
  }
  /* padding-inline-start = flèche + gap + bleed : la réponse démarre sous la
     1ʳᵉ lettre du titre. */
  .block-accordion .accordion__body {
    --accordion-bleed: 1rem;
    /* Sinon hérite `--section-text` (blanc sur `.section-accent`) : invisible
       sur le panneau blanc. */
    color: var(--color-text);
    background: var(--color-surface);
    border-radius: 0 0 var(--radius-lg) var(--radius-lg);
    margin-inline: calc(-1 * var(--accordion-bleed));
    padding-block: 0 1.25rem;
    padding-inline-start: calc(var(--accordion-arrow-width, 1.25rem) + 0.75rem + var(--accordion-bleed));
    padding-inline-end: calc(0.75rem + var(--accordion-bleed));
    margin-block: 0 0.2rem;
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-semibold);
  }

  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    .block-accordion .accordion {
      padding: var(--space-block);
      border-radius: var(--radius-lg);
    }
    /* Posé sur `.accordion__item` (ancêtre commun) : `.accordion__body` est
       sibling du `<summary>`, n'hériterait pas d'une propriété posée sur le titre. */
    .block-accordion .accordion__item {
      --accordion-arrow-width: calc(var(--font-size-base) * 0.8);
    }
    /* flex-start : un titre sur 2+ lignes centrerait la flèche sur tout le bloc. */
    .block-accordion .accordion__title {
      font-size: var(--font-size-base);
      padding: 0.3rem 0;
      align-items: flex-start;
    }
    .block-accordion .accordion__title::before {
      margin-block-start: 0.2rem;
    }
    /* Redéclaré aux deux endroits : pas de parenté DOM entre titre et corps. */
    .block-accordion .accordion__item[open] > .accordion__title {
      --accordion-bleed: 0.5rem;
    }
    .block-accordion .accordion__body {
      --accordion-bleed: 0.5rem;
    }
    /* `:not([open])` : sans lui, cette règle (même spécificité, plus bas dans
       le source) annulerait la rotation d'un item ouvert et survolé. */
    .block-accordion .accordion__item:not([open]) .accordion__title:hover::before,
    .block-accordion .accordion__item:not([open]) .accordion__title:focus-visible::before {
      transform: none;
    }
    [dir="rtl"] .block-accordion .accordion__item:not([open]) .accordion__title:hover::before,
    [dir="rtl"] .block-accordion .accordion__item:not([open]) .accordion__title:focus-visible::before {
      transform: rotate(180deg);
    }
  }

  /* —— Footer : repeint par les variables `--footer-*` du socle, posées sur
     `footer.footer-core` seul (`.newsletter` en est descendant, footer.php). */
  footer.footer-core {
    /* AA sur le pêche : muted et hover primary du socle trop justes → encre
       (≈12.9:1), soulignement au survol. */
    --footer-bg: var(--color-quinary-light);
    --footer-link-color: var(--color-text);
    --footer-bottom-color: var(--color-text);
  }
  footer.footer-core {
    border-block-start: none;
    font-weight: var(--font-weight-semibold);
    /* `main { padding-block-end: 0 }` laisserait la dernière section coller au footer. */
    margin-block-start: 2rem;
  }

    .footer-inner{
      max-width: initial;
    }

    .footer-bottom{
      border-block-start: 0;
    }

  /* Scopé `.newsletter__nav` : le formulaire DreamForm reste en poids normal. */
  .newsletter__nav {
    font-weight: var(--font-weight-semibold);
  }
  /* `footer_contact` (kirbytext) livre 2 paragraphes, étalés côte à côte. */
  .footer-contact {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
    gap: var(--space-block);
    font-size: var(--font-size-base);
    padding-block-end: var(--space-block);
  }
  .footer-contact a {
    text-decoration: underline;
  }
  /* En propriété directe, pas via `--footer-title-color` : la variable n'est
     plus surchargée par le thème. */
  .footer-nav__title {
    color: var(--color-text);
    letter-spacing: normal;
  }
  .footer-nav__list {
    gap: 0;
  }
  /* `.footer-to-top` exclu : porte sa propre encre (blanc sur pastille). */
  footer.footer-core .footer-bottom a:not(.footer-to-top) {
    color: var(--color-text);
  }
  /* Survol en propriété, pas via `--footer-link-hover-color` : cette règle bat
     par ordre de couche celle du socle qui lit la variable — la variable serait
     du code mort. Répété sur `.newsletter__nav`, rendu hors du sous-arbre. */
  footer.footer-core a:not(.footer-to-top):hover,
  footer.footer-core a:not(.footer-to-top):focus-visible,
  .newsletter__nav a:hover,
  .newsletter__nav a:focus-visible {
    color: var(--color-text);
    text-decoration: underline;
  }
  /* Dernier enfant de `.footer-bottom` (footer.php) ; défilement animé par
     app.js, sans JS le lien saute à `#main`. 2.75rem = cible tactile AA ;
     align-self: center car `.footer-bottom` aligne sur la ligne de base. */
  .footer-to-top {
    align-self: center;
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.75rem;
    height: 2.75rem;
    border-radius: var(--radius-pill);
    background: var(--color-primary);
    color: var(--color-white);
    font-size: 1.25rem;
    text-decoration: none;
    transition: transform 0.2s ease;
  }
  .footer-to-top:hover,
  .footer-to-top:focus-visible {
    transform: translateY(-0.15rem);
    text-decoration: none;
  }

  /* —— Filtres à pastilles (ADR-030 section-filter, ADR-031 children-filter,
     language-selector). `:not([aria-current])` sur les règles suivantes :
     @layer brand bat @layer blocks quelle que soit la spécificité — sans
     l'exclusion, fond neutre et survol écraseraient la pastille active du
     socle, pilotée par les tokens `--*-active`. */
  .section-filter__pill,
  .children-filter__pill,
  .language-selector__pill {
    padding: 0.2rem 0.6rem;
    font-size: var(--font-size-sm);
  }
  .section-filter__pill:not([aria-current="true"]),
  .children-filter__pill:not([aria-current="true"]),
  .language-selector__pill:not([aria-current="page"]) {
    background: var(--color-bg);
    border-color: var(--color-primary);
    color: var(--color-primary);
  }
  .section-filter__pill:not([aria-current="true"]):hover,
  .section-filter__pill:not([aria-current="true"]):focus-visible,
  .children-filter__pill:not([aria-current="true"]):hover,
  .children-filter__pill:not([aria-current="true"]):focus-visible,
  .language-selector__pill:not([aria-current="page"]):hover,
  .language-selector__pill:not([aria-current="page"]):focus-visible {
    background: var(--color-primary-light);
  }
  .section-filter {
    --section-filter-active: var(--color-primary);
    --section-filter-active-text: var(--color-bg);
  }
  .children-filter {
    --children-filter-active: var(--color-primary);
    --children-filter-active-text: var(--color-bg);
  }
  /* Sticky sur `.children-filter` seul : `.section-filter`/`.language-selector`
     n'ont pas de conteneur assez haut pour rester accrochés (children-list.php
     partage le wrapper de la liste filtrée). Pas de fond opaque : voulu. */
  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    .children-filter {
      position: sticky;
      inset-block-start: var(--size-header, 0px); /* allow-naked-px: fallback du token optionnel */
      z-index: 5;
      padding-block: var(--space-xs);
    }
  }

  /* Piste horizontale pleine largeur : marge négative = padding du
     `.layout-container`, compensée par le même padding — plutôt que retirer le
     padding du conteneur, qui porte aussi le hero-titre et le filtre. */
  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    .children-list {
      display: flex;
      overflow-x: auto;
      scroll-snap-type: x mandatory;
      margin-inline: calc(-1 * var(--container-padding));
      padding-inline: var(--container-padding);
      /* Sinon la zone de snap démarre au bord du scrollport et le navigateur
         défile au chargement jusqu'à masquer le padding. */
      scroll-padding-inline: var(--container-padding);
    }
    .children-list > * {
      flex: 0 0 82%;
      scroll-snap-align: start;
    }
  }
  .language-selector {
    --language-selector-active: var(--color-primary);
    --language-selector-active-text: var(--color-bg);
  }
  .language-selector__list {
    margin-block-end: var(--space-xs);
  }

  /* Le socle ne pose `text-decoration: none` qu'au repos : `a:hover { underline }`
     gagne par spécificité (classe+pseudo > élément+pseudo). */
  .section-filter__pill:hover,
  .section-filter__pill:focus-visible,
  .children-filter__pill:hover,
  .children-filter__pill:focus-visible,
  .language-selector__pill:hover,
  .language-selector__pill:focus-visible {
    text-decoration: none;
  }

  /* Pagination : `.pagination .active` est un `<span>` (pagination.php), jamais
     un `<a>` — pas de garde `:not()` nécessaire. */
  .pagination {
    border-top: none;
  }
  .pagination ul {
    gap: 1rem;
  }
  .pagination a,
  .pagination .active {
    border-radius: var(--radius-lg);
  }
  /* Padding explicite : `nav[role="navigation"] ul li a` (socle, menu) gagne
     par spécificité sur `.pagination a` et posait `padding: 0.5rem 0` —
     pastilles plus étroites que `.active`. */
  .pagination a {
    padding: 0.4rem 0.8rem;
    background: var(--color-bg);
    border-color: var(--color-primary);
    color: var(--color-primary);
  }
  .pagination a:hover,
  .pagination a:focus-visible {
    background: var(--color-primary-light);
    /* Sinon `a:hover { underline }` du socle souligne la pastille. */
    text-decoration: none;
  }
  .pagination .active {
    background: var(--color-primary);
    border-color: var(--color-primary);
    color: var(--color-bg);
  }

  /* `padding-block-end: 0` : les gabarits sans builder (`.article`/`.event`)
     doivent coller au footer. min-height : sur une page courte, le footer ne
     flotte pas au milieu ; `dvh` pour la barre d'URL mobile. */
  main {
    margin-block-start: 2rem;
    padding-block-end: 0;
    min-height: calc(100dvh - var(--size-header, 0px)); /* allow-naked-px: fallback du token optionnel — calc() exige une unité */
  }
  /* Hero plein écran : la marge laisserait un liseré de fond sous le header. */
  main:has(.hero--full),
  main:has(.hero--media) {
    margin-block-start: 0;
  }
  /* —— Newsletter (footer.php, snippet DreamForm `dreamform/form`, classes
     `newsletter__*` injectées par `attr`). Deux lignes : formulaire (moitié
     gauche) puis colonnes de liens `footer-sections` pleine largeur
     (`showNav: false` sur footer-default). Premier enfant de `footer.footer-core` :
     marges négatives = padding du socle (`2.5rem` / `--container-padding`). */
  .newsletter {
    background: var(--color-quinary-light);
    padding-block: var(--space-block);
    margin-inline: calc(-1 * var(--container-padding));
    margin-block-start: -2.5rem;
  }
  .newsletter__inner {
    margin-inline: auto;
    /* Aucun `.layout-container` autour de ce bloc dans footer.php. */
    padding-inline: var(--container-padding);
    display: grid;
    grid-template-columns: 1fr 1fr;
    align-items: start;
    gap: var(--space-section);
    position: relative;
  }
  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    .newsletter__inner {
      grid-template-columns: 1fr;
    }
  }
  /* Illustration hors grille (en flux, un ::after deviendrait un item de
     grille). Calage à l'œil : bord gauche sur la 4ᵉ colonne de `.footer-nav`
     (75% de la largeur de contenu ; le `%` d'un inset porte sur la padding-box,
     d'où `- 0.5·CP`). Valeurs de rendu, pas dynamiques. aspect-ratio = viewBox. */
  .newsletter__inner::after {
    content: "";
    position: absolute;
    inset-inline-start: calc(75% - 0.5 * var(--container-padding) - .5rem);
    inset-block-start: var(--space-block);
    width: min(15rem, 22%);
    aspect-ratio: 250 / 188;
    background: url("../images/footer-illustration.svg") bottom center / contain no-repeat;
    pointer-events: none;
  }
  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    footer.footer-core {
      margin-block-start: 0;
    }
    .newsletter__inner::after {
      display: none;
    }
  }
  .newsletter__signup {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 0.9rem;
    grid-column: 1 / 2;
  }
  .newsletter__title {
    margin: 0;
    font-size: var(--font-size-base);
  }
  .newsletter__nav {
    min-width: 0;
    grid-column: 1 / -1;
  }
  .newsletter__nav .footer-nav {
    grid-template-columns: repeat(4, 1fr);
  }
  @media (max-width: 1080px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    .newsletter__nav .footer-nav {
      grid-template-columns: repeat(2, 1fr);
    }
  }
  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    .newsletter__nav .footer-nav {
      grid-template-columns: 1fr;
    }
  }
  .newsletter__form {
    display: flex;
    flex-direction: column;
    gap: 0.7rem;
  }
  /* Grille 12 colonnes posée en `style` inline par le snippet DreamForm. */
  .newsletter__row {
    gap: 0.7rem;
  }
  .newsletter__col {
    min-width: 0;
  }
  .newsletter__field {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
  }
  .newsletter__label {
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-semibold);
    color: var(--color-text);
  }
  .newsletter__label em {
    color: var(--color-danger);
    font-style: normal;
  }
  .newsletter__input {
    width: 100%;
    border: var(--border-width) solid var(--color-input-border);
    background: transparent;
    color: var(--color-text);
    border-radius: var(--radius);
    padding: 0.6rem 0.9rem;
    font: inherit;
  }
  .newsletter__check {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
  }
  /* Le snippet DreamForm applique aussi `newsletter__input` à la case à cocher. */
  .newsletter__check .newsletter__input {
    width: auto;
    flex: none;
    margin-block-start: 0.2rem;
    padding: 0;
    border: none;
    background: none;
    border-radius: 0;
  }
  .newsletter__check-label {
    font-size: var(--font-size-sm);
    color: var(--color-text);
  }
  .newsletter__submit {
    align-self: flex-start;
    background: var(--section-dark-bg);
    color: var(--color-white);
    border: none;
    border-radius: var(--radius);
    padding: 0.65rem 1.3rem;
    font-weight: var(--font-weight-semibold);
    cursor: pointer;
  }
  .newsletter__submit:hover,
  .newsletter__submit:focus-visible {
    background: var(--color-text);
  }
  /* Le snippet émet un conteneur d'erreur vide (`hideEmptyErrors` off) ;
     `:empty` exige zéro whitespace. */
  .newsletter__error:empty,
  .newsletter [data-error]:empty {
    display: none;
  }
  /* Danger sur rose ≈4.58:1, trop juste : erreur en encre + gras ; le signal
     vient de la bordure danger et d'`aria-invalid`. */
  .newsletter__error {
    margin: 0.15rem 0 0;
    color: var(--color-text);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-semibold);
  }
  .newsletter__input[aria-invalid="true"] {
    border-color: var(--color-danger);
  }
  .newsletter__success {
    flex: 1 1 22rem;
    color: var(--color-text);
    font-weight: var(--font-weight-semibold);
  }

  /* `<h1>` nu sous `<main>` (listings, subpage) : le socle ne pose pas de
     padding-inline sur main. */
  main > h1 {
    max-width: var(--container-max);
    margin-inline: auto;
    padding-inline: var(--container-padding);
  }

  /* —— Article éditorial (rail méta | colonne de lecture) */
  .article--editorial {
    margin-block-end: var(--space-section);
  }
  .article--editorial .article__header h1 {
    margin-block-end: var(--space-section);
  }
  .article__layout {
    display: grid;
    grid-template-columns: minmax(0, 11rem) minmax(0, 1fr);
    gap: var(--space-block) var(--space-section);
    align-items: start;
  }
  .article__meta {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    font-size: var(--font-size-sm);
  }
  .article__date {
    font-weight: var(--font-weight-semibold);
    color: var(--color-text);
  }
  .article__rule {
    width: 100%;
    height: 0;
    margin: 0;
    border: none;
    border-block-start: var(--border-width) solid var(--color-text);
  }
  .article__pager {
    display: flex;
    gap: 1.25rem;
    font-size: var(--font-size-lg);
    line-height: 1;
  }
  .article__pager-link {
    color: var(--color-text);
    text-decoration: none;
  }
  .article__pager-link:hover,
  .article__pager-link:focus-visible {
    color: var(--color-primary-light);
  }
  .article__pager-link.is-disabled {
    color: var(--color-disabled-text);
    pointer-events: none;
  }
  .article__content {
    max-width: 46rem;
  }
  .article__figure {
    margin: 0 0 var(--space-block);
  }

  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    .article__layout {
      grid-template-columns: 1fr;
    }
    .article__meta {
      flex-flow: row wrap;
      align-items: baseline;
      gap: 0.75rem 1.25rem;
    }
    .article__rule {
      display: none;
    }
  }

  /* —— Événement éditorial (rail méta | contenu) */
  .event--editorial .event__header {
    margin-block-end: var(--space-section);
  }
  .event--editorial .event__title {
    margin-block-end: var(--space-block);
  }
  /* Serif Source Serif 4 : avec `.block-text--size-lg`, seule surface serif du thème. */
  .event--editorial .event__intro {
    max-width: 34rem;
    color: var(--color-text);
    font-family: var(--font-family-text);
    font-size: var(--font-size-lg);
  }
  .event--editorial .event__layout {
    display: grid;
    grid-template-columns: minmax(0, 20rem) minmax(0, 1fr);
    gap: var(--space-block) var(--space-section);
    align-items: start;
  }

  .event__pager {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-block-end: var(--space-block);
  }
  .event__pager-retour {
    color: var(--color-text);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-semibold);
    text-decoration: none;
  }
  .event__pager-retour:hover,
  .event__pager-retour:focus-visible {
    color: var(--color-interactive);
  }
  .event__pager-arrows {
    display: flex;
    gap: 1.25rem;
    font-size: var(--font-size-lg);
    line-height: 1;
  }
  .event__pager-link {
    color: var(--color-text);
    text-decoration: none;
  }
  .event__pager-link:hover,
  .event__pager-link:focus-visible {
    color: var(--color-primary-light);
  }
  .event__pager-link.is-disabled {
    color: var(--color-disabled-text);
    pointer-events: none;
  }
  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    .event__pager-retour,
    .event__pager-arrows {
      font-size: var(--font-size-base);
    }
  }

  .event__facts {
    margin: 0;
  }
  .event__fact {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35em;
    padding-block: 0.6rem;
    border-block-end: var(--border-width) solid var(--color-border);
    font-size: var(--font-size-sm);
  }
  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    .event__fact {
      font-size: var(--font-size-base);
    }
  }
  .event__fact dt {
    margin: 0;
    font-weight: var(--font-weight-semibold);
    color: var(--color-text);
  }
  /* `:` décoratif en ::after : pas dans la donnée. */
  .event__fact dt::after {
    content: ":";
  }
  .event__fact dd {
    margin: 0;
    color: var(--color-text);
  }

  .event-form-alternative {
    padding: var(--space-block) 0;
  }
  .event-form-alternative p + p {
    margin-block-start: 0.75em;
  }
  .event-form-alternative a {
    color: var(--color-primary);
  }

  .event-form form > div:last-child {
    text-align: end;
  }
  /* Case à cocher (ex. acceptation des CGV) : libellé sur la même ligne que la
     case, comme le formulaire newsletter (`.newsletter__check`). Le snippet
     DreamForm ne pose aucune classe ici — on cible la ligne par sa structure. */
  .event-form div:has(> input[type="checkbox"]) {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    text-align: start;
  }
  .event-form div:has(> input[type="checkbox"]) > input {
    width: auto;
    flex: none;
    margin-block-start: 0.2rem;
  }

  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    .event--editorial .event__layout {
      grid-template-columns: 1fr;
    }
    .event-form form > div:last-child {
      text-align: start;
    }
  }

  /* Seulement le `<video>` de fichier uploadé, pas l'iframe d'un embed. */
  .video-embed video {
    mix-blend-mode: darken;
  }

  .block-image figcaption,
  .block-serie-images__caption {
    font-weight: var(--font-weight-semibold);
    text-align: center;
  }

  /* —— Compositions d'instance (accueil), scopées par `section_id` — ADR-028.
     #notre-mission : flex plutôt que la grille 12 col, le pictogramme colle au
     titre. `flex: none` + largeur fixe : en colonne flex `auto`,
     `.block-image img { width: 100% }` retombe sur la taille native du fichier. */
  @media (min-width: 768px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    #notre-mission .layout-row {
      display: flex;
      align-items: center;
      gap: var(--space-xs);
    }
    #notre-mission .layout-column:empty {
      display: none;
    }
    #notre-mission .layout-column:has(.block-image) {
      flex: none;
      width: 15rem; /* allow-naked-px: taille d'icône décorative, aucun token dédié */
    }
  }

  /* `flex: 1 1 0` + `min-width: 0` sur la colonne titre : sans base explicite
     la colonne se dimensionne à son contenu et pousse l'icône hors ligne ; le
     `min-width: auto` des flex-items empêcherait le retour à la ligne. */
  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    #notre-mission .layout-row {
      display: flex;
      align-items: center;
      gap: var(--space-xs);
    }
    #notre-mission .layout-column:empty {
      display: none;
    }
    #notre-mission .layout-column:has(.block-heading) {
      flex: 1 1 0;
      min-width: 0;
    }
    #notre-mission .layout-column:has(.block-image) {
      flex: none;
      width: 5rem; /* allow-naked-px: taille d'icône décorative en mobile, aucun token dédié */
    }
  }

  /* #nos-prestations : colonne image hors flux, le fond de section suit la
     hauteur de la colonne texte seule. `grid-column: 7 / -1` explicite : sans
     l'image en flux, l'auto-placement ramènerait le texte à gauche.
     margin-block-end sur la section (pas du padding, repeint par --section-bg) :
     l'image hors flux chevaucherait la section suivante. */
  @media (min-width: 768px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    #nos-prestations {
      margin-block-end: calc(var(--space-section-airy) * 2);
    }
    #nos-prestations .layout-row {
      position: relative;
    }
    #nos-prestations .layout-column:has(.block-image) {
      position: absolute;
      inset-block-start: 0;
      inset-inline-start: 0;
      width: calc(50% - var(--grid-gap) / 2);
    }
    #nos-prestations .layout-column:has(.block-heading) {
      grid-column: 7 / -1;
    }
  }

  /* —— CTA « Réserver » (reservation-cta.php) : seul enfant direct de `<body>`
     (header.php), hors flux, `fixed`. En haut à droite ≥ 768px ; masqué < 768px
     sauf sur la home où il devient flottant centré en bas (plus bas).
     inset-block-start : même estimation de hauteur de header que
     `html { scroll-padding-block-start }`. Visuel SVG : le lien n'est qu'un cadre. */
  .reservation-cta {
    position: fixed;
    inset-block-start: calc(var(--size-logo-height) + var(--space-section-standard));
    inset-inline-end: var(--space-block);
    z-index: 12;
    display: block;
    line-height: 0;
  }
  .reservation-cta__img {
    display: block;
    width: 8rem;
    height: auto;
    /* Sur l'image, pas sur le lien : la zone cliquable garde sa boîte. */
    transition: transform 0.2s ease;
  }
  .reservation-cta:hover .reservation-cta__img,
  .reservation-cta:focus-visible .reservation-cta__img {
    transform: scale(1.1);
  }
  /* `body > .reservation-cta` : seul enfant direct de `<body>` (header.php).
     < 768px il est masqué PARTOUT sauf sur la home, où il devient un CTA
     flottant centré en bas d'écran. */
  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    body > .reservation-cta {
      display: none;
    }
    body.page-accueil > .reservation-cta {
      display: block;
      inset-block-start: auto;
      inset-block-end: var(--space-block);
      inset-inline-start: 50%;
      inset-inline-end: auto;
      transform: translateX(-50%);
    }
    body.page-accueil > .reservation-cta .reservation-cta__img {
      width: 6.5rem;
    }
  }

  /* —— Utilitaire « bleed » (ADR-028) : sortie de flux mutualisée ; la
     géométrie vient des `--bleed-*` posées à chaque site d'appel, où le
     conteneur de référence reçoit `position: relative` (jamais ici). Classes
     `page-<slug>` posées sur body par header.php. */
  body.page-a-propos .layout-section.section-quinary-light .layout-column:nth-child(2) > .block-callout:first-child,
  body.page-a-propos .layout-row:has(.block-list):has(.block-image) > .layout-column:has(> .block-image),
  body.page-pourquoi-interprete .layout-row:has(.block-heading):has(.block-image) > .layout-column:has(> .block-image):not(:has(> .block-heading)),
  body.page-pourquoi-interprete .layout-row:has(.block-heading):has(.block-image) > .layout-column:has(> .block-heading) > .block-image:last-child,
  body.page-formulaire-de-demande-institution .layout-section.section-violet-light .layout-row > .layout-column:has(> .block-image),
  body.page-formulaire-de-demande-prive .layout-section.section-violet-light .layout-row > .layout-column:has(> .block-image),
  body.page-beneficiaire-langue .layout-section.section-periwinkle-light .layout-row > .layout-column:has(> .block-image) {
    position: absolute;
    z-index: var(--bleed-z, 1);
    inset-inline-start: var(--bleed-inset-start, 0);
    inset-block-start: var(--bleed-block-start, auto);
    inset-block-end: var(--bleed-block-end, auto);
    width: var(--bleed-width, 100%);
  }

  body.page-a-propos .layout-section.section-quinary-light .layout-row {
    align-items: end;
  }
  /* `:has(.block-callout)` : `section-quinary-light` seul matcherait aussi
     « Nos valeurs ». Marge sur la section, pas sur le callout : un absolu
     ancré par le bas remonte avec une marge haute. */
  body.page-a-propos .layout-section.section-quinary-light:has(.block-callout) {
    margin-block-start: calc(var(--space-section-airy) + var(--space-block) * 2);
  }
  /* Callout ancré sur sa colonne (`inset-block-end: 100%`) : ne chevauche
     jamais le contenu qui suit quelle que soit sa hauteur. `:nth-child(2)`
     épargne le callout de la section précédente. */
  body.page-a-propos .layout-section.section-quinary-light .layout-column:nth-child(2) {
    position: relative;
  }
  body.page-a-propos
    .layout-section.section-quinary-light
    .layout-column:nth-child(2)
    > .block-callout:first-child {
    --bleed-block-end: 100%;
    margin-block-end: var(--space-block);
  }
  /* Mobile : les colonnes s'empilent, « 100% au-dessus de ma colonne »
     recouvrirait la liste de la colonne 1 — retour en flux. */
  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    body.page-a-propos
      .layout-section.section-quinary-light
      .layout-column:nth-child(2)
      > .block-callout:first-child {
      position: static;
      margin-block-start: var(--space-block);
    }
  }

  /* Illustration « Nos valeurs » : débord par le haut, le bas de la colonne
     image calé sur le bas de la ligne. Géométrie 8/12 + 4/12 avec un seul
     `--grid-gap`. `:has(> .block-image)` direct : ne descend pas dans une
     autre colonne. */
  body.page-a-propos .layout-row:has(.block-list):has(.block-image) {
    position: relative;
  }
  body.page-a-propos
    .layout-row:has(.block-list):has(.block-image)
    > .layout-column:has(> .block-image) {
    --bleed-block-end: 0;
    --bleed-inset-start: calc((100% - var(--grid-gap)) * 2 / 3 + var(--grid-gap));
    --bleed-width: calc(((100% - var(--grid-gap)) / 3) * 0.85);
  }
  /* L'image hors flux n'est plus comptée : sans cette marge elle chevauche la
     section précédente. */
  body.page-a-propos .layout-section:has(.block-list):has(.block-image) {
    margin-block-start: var(--space-section-airy);
  }
  /* `:not(.section-full-padded)` distingue « Nos valeurs » de la section
     Objectifs/Principes (même fond). */
  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    body.page-a-propos .layout-section.section-quinary-light:not(.section-full-padded) .block-list ul,
    body.page-a-propos .layout-section.section-quinary-light:not(.section-full-padded) .block-list ol {
      font-size: var(--font-size-m);
    }
  }

  /* Illustration remontée par marge négative (section en flux, pas de recalage
     de largeur). `:not(:has(.block-heading))` : garde prospective.
     `padding-block-end: 0` : sinon s'ajoute au padding-top de la section suivante. */
  body.page-pourquoi-interprete .layout-section.section-full:not(:has(.block-heading)) {
    margin-block-start: -18rem;
    padding-block-end: 0;
  }
  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    body.page-pourquoi-interprete .layout-section.section-full:not(:has(.block-heading)) {
      display: none;
    }
  }

  /* Deux débords dans la même ligne : (1) illustration, colonne sans titre,
     gabarit fixe calé au bord droit de la ligne (`inset-start: 100% - width`) ;
     (2) icône bulle, après le titre dans le Panel mais affichée au-dessus
     (`--bleed-block-end: 100%`, colonne = référence), largeur fixe (viewBox 231×67). */
  body.page-pourquoi-interprete .layout-row:has(.block-heading):has(.block-image) {
    position: relative;
  }
  body.page-pourquoi-interprete
    .layout-row:has(.block-heading):has(.block-image)
    > .layout-column:has(> .block-image):not(:has(> .block-heading)) {
    --bleed-block-end: 0;
    --bleed-width: 11rem; /* allow-naked-px: gabarit fixe de l'illustration, aucun token dédié */
    --bleed-inset-start: calc(100% - var(--bleed-width));
  }
  body.page-pourquoi-interprete
    .layout-row:has(.block-heading):has(.block-image)
    > .layout-column:has(> .block-heading) {
    position: relative;
  }
  body.page-pourquoi-interprete
    .layout-row:has(.block-heading):has(.block-image)
    > .layout-column:has(> .block-heading)
    > .block-image:last-child {
    --bleed-block-end: 100%;
    --bleed-width: 12rem; /* allow-naked-px: gabarit fixe de l'icône décorative (viewBox 231×67), aucun token dédié */
    margin-block-end: var(--space-xs);
  }
  body.page-pourquoi-interprete .layout-section:has(.block-heading):has(.block-image) {
    margin-block-start: var(--space-section-airy);
  }
  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    body.page-pourquoi-interprete
      .layout-row:has(.block-heading):has(.block-image)
      > .layout-column:has(> .block-image):not(:has(> .block-heading)) {
      display: none;
    }
  }

  /* Comparatif : largeurs/insets posés sur `.comparison__side--positif`
     (conteneur commun) — image et texte lisent les mêmes custom properties, le
     texte déduit sa largeur de `--comparison-image-width` et `-inset-end`
     (négatif : rend de la largeur). `--comparison-image-transform: none` :
     sinon cumulatif avec l'ancrage bas. */
  body.page-pourquoi-interprete .comparison__side--negatif .comparison__image {
    --comparison-image-width: 6rem;
  }
  body.page-pourquoi-interprete .comparison__side--positif {
    --comparison-image-width: 16rem;
    --comparison-image-inset-end: -1.5rem;
  }
  body.page-pourquoi-interprete .comparison__side--positif .comparison__image {
    --comparison-image-block-start: auto;
    --comparison-image-block-end: 0;
    --comparison-image-transform: none;
  }
  body.page-pourquoi-interprete .comparison__side--positif .comparison__points {
    max-width: calc(100% - var(--comparison-image-width, 9rem) - var(--comparison-image-inset-end, var(--space-block)) - var(--space-block));
  }
  /* Mobile : 50% (65% recouvrait le titre à 390px). max-width fixe plutôt que
     le calc : avec un inset-end différent, la formule s'effondrait à ~35%. */
  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    body.page-pourquoi-interprete .comparison__side--negatif .comparison__image {
      --comparison-image-width: 4.5rem;
    }
    body.page-pourquoi-interprete .comparison__side--positif {
      --comparison-image-width: 50%;
      --comparison-image-inset-end: var(--space-xs);
    }
    body.page-pourquoi-interprete .comparison__side--positif .comparison__points {
      max-width: 60%;
    }
  }

  /* Bénéficiaires (`page-beneficiaire-langue`) : même débord que « Nos
     valeurs ». Scopé par `section-periwinkle-light` : la 2ᵉ ligne de la page
     porte aussi heading + image, `:has()` seul matcherait les deux. */
  body.page-beneficiaire-langue .layout-section.section-periwinkle-light .layout-row {
    position: relative;
  }
  body.page-beneficiaire-langue
    .layout-section.section-periwinkle-light
    .layout-row
    > .layout-column:has(> .block-image) {
    --bleed-block-end: 0;
    --bleed-inset-start: calc((100% - var(--grid-gap)) * 2 / 3 + var(--grid-gap));
    --bleed-width: calc(((100% - var(--grid-gap)) / 3) * 0.8);
    /* Illustration décorative en débord : sans ça sa boîte (absolute, au-dessus
       du flux) intercepte les clics sur les pastilles de langue qu'elle
       recouvre selon la langue courante. */
    pointer-events: none;
  }
  body.page-beneficiaire-langue .layout-section.section-periwinkle-light {
    margin-block-start: var(--space-section-airy);
  }
  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    body.page-beneficiaire-langue
      .layout-section.section-periwinkle-light
      .layout-row
      > .layout-column:has(> .block-image) {
      display: none;
    }
  }

  /* `formulaire-de-demande-{institution,prive}` : illustration de la section
     d'intro en débord par le haut, comme les sous-pages bénéficiaires
     (« Nos valeurs »). Les deux pages ont le même contenu de section
     (`section-violet-light`, heading 2/3 + image 1/3) ; le `position: absolute`
     de la colonne image vient de l'utilitaire « bleed » commun plus haut. */
  body.page-formulaire-de-demande-institution .layout-section.section-violet-light .layout-row,
  body.page-formulaire-de-demande-prive .layout-section.section-violet-light .layout-row {
    position: relative;
  }
  body.page-formulaire-de-demande-institution .layout-section.section-violet-light .layout-row > .layout-column:has(> .block-image),
  body.page-formulaire-de-demande-prive .layout-section.section-violet-light .layout-row > .layout-column:has(> .block-image) {
    --bleed-block-end: 0;
    --bleed-inset-start: calc((100% - var(--grid-gap)) * 2 / 3 + var(--grid-gap));
    --bleed-width: calc(((100% - var(--grid-gap)) / 3) * 0.8);
  }
  body.page-formulaire-de-demande-institution .layout-section.section-violet-light,
  body.page-formulaire-de-demande-prive .layout-section.section-violet-light {
    margin-block-start: var(--space-section-airy);
  }
  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    body.page-formulaire-de-demande-institution .layout-section.section-violet-light .layout-row > .layout-column:has(> .block-image),
    body.page-formulaire-de-demande-prive .layout-section.section-violet-light .layout-row > .layout-column:has(> .block-image) {
      display: none;
    }
  }

  /* Le chaînage `:not(.block):not(--columns):not(--bullet)` recopie la règle
     « structure verticale » (0,4,1) : sans lui, `body.page-prestations
     .block-list--accent` (0,2,2) perd et l'alinéa revient. */
  body.page-prestations .block-list--accent:not(.block):not(.block-list--columns):not(.block-list--bullet) ul,
  body.page-prestations .block-list--accent:not(.block):not(.block-list--columns):not(.block-list--bullet) ol {
    list-style: none;
    padding-inline-start: 0;
  }

  /* Résumé coloré sous chaque titre de prestation : le palier `sm` (0.875rem)
     est trop discret pour un texte de mise en valeur — relevé d'un cran. */
  body.page-prestations .block-list--size-sm ul,
  body.page-prestations .block-list--size-sm ol {
    font-size: var(--font-size-m);
  }
  /* Le titre et sa ligne de mots-clés forment un bloc : on resserre le blanc
     entre les deux (défaut `--space-block` entre blocs frères). */
  body.page-prestations .layout-column > .block-heading + .block-list {
    margin-block-start: var(--space-xs);
  }
  /* La section « attached » a déjà `padding-block-start: 0` ; on grignote encore
     un chouïa le blanc au-dessus du premier titre de prestation. */
  body.page-prestations .layout-section.section-spacing-attached .block-heading:first-child {
    margin-block-start: calc(-1 * var(--space-xs));
  }

  /* Domaines d'intervention : légende sur l'image, masquée au survol avec la
     silhouette (même déclencheur que l'effet découpe du socle). */
  body.page-a-propos .block-serie-images__list figure {
    position: relative;
  }
  body.page-a-propos .block-serie-images__caption {
    position: absolute;
    /* 45 % : la bande où toutes les icônes ont de la matière (object-position: bottom). */
    inset-inline: 0;
    inset-block-end: 0;
    block-size: 45%;
    margin: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    transition: opacity 0.2s ease;
    font-size: var(--font-size-lg);
    color: var(--color-white);
  }
  body.page-a-propos .block-serie-images__item:hover .block-serie-images__caption,
  body.page-a-propos .block-serie-images__item:focus-within .block-serie-images__caption {
    opacity: 0;
  }
  /* `--serie-images-per-row` est aussi posée en inline par serie-images.php
     (`par_rangee: 5`) : `!important` nécessaire. `justify-content: center` :
     la 2ᵉ ligne incomplète se centre. */
  body.page-a-propos .block-serie-images__list {
    --serie-images-per-row: 3 !important;
    justify-content: center;
    /* Variable locale : synchro avec le `flex-basis` de l'item. */
    --domaines-gap: calc(var(--space-section-airy) * 1.5);
    gap: var(--domaines-gap);
  }
  /* Le calcul du socle soustrait un gap figé (0.75rem) : repris avec
     `--domaines-gap` pour que 3 vignettes + 2 gaps tiennent sur une ligne. */
  body.page-a-propos .block-serie-images__item {
    flex-basis: calc((100% - 2 * var(--domaines-gap)) / 3);
  }
  /* Hauteur écrasée ici, pas via `--gallery-thumb-height` (partagé avec
     Galerie). `bottom` : les icônes de ratios différents posent sur la même ligne. */
  body.page-a-propos .block-serie-images__item img {
    height: 18rem;
    object-position: center bottom;
  }
  /* mask-position aligné sur l'image (sinon la silhouette saute à la
     révélation). Longhand, pas le raccourci `mask` qui réinitialiserait
     `--cutout-mask`/contain/no-repeat du socle. */
  body.page-a-propos .block-serie-images__cutout {
    mask-position: center bottom;
    -webkit-mask-position: center bottom;
  }

  /* Mobile : silhouette masquée, légende repassée en flux sous l'image
     (proche du défaut socle). */
  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    body.page-a-propos .block-serie-images__cutout {
      display: none;
    }
    body.page-a-propos .block-serie-images__caption {
      position: static;
      inset: auto;
      block-size: auto;
      margin-block-start: 0.375rem;
      display: block;
      transition: none;
      font-size: var(--font-size-sm);
      color: var(--color-text-muted);
    }
    body.page-a-propos .block-serie-images__item:hover .block-serie-images__caption,
    body.page-a-propos .block-serie-images__item:focus-within .block-serie-images__caption {
      opacity: 1;
    }
    body.page-a-propos .block-serie-images__list {
      --domaines-gap: var(--space-block);
      /* `stretch` étire le `<li>` mais pas la figure, qui resterait calée en haut. */
      align-items: flex-end;
    }
    body.page-a-propos .block-serie-images__item img {
      height: auto;
    }
  }

  /* Équipe : neutralise le carrousel (cards.php) sans toucher au composant —
     le JS insère quand même `.block-cards__controls`, masqué. */
  body.page-a-propos .block-cards-carousel {
    margin-inline: 0;
  }
  body.page-a-propos .block-cards.block-cards--carousel {
    flex-wrap: wrap;
    overflow-x: visible;
    scroll-snap-type: none;
    padding-inline: 0;
    gap: 0;
  }
  body.page-a-propos .block-cards.block-cards--carousel > .block-cards__item {
    flex: 0 0 25%;
    width: 25%;
  }
  @media (max-width: 767.98px) { /* allow-naked-px: breakpoint, var() illégal en media query */
    body.page-a-propos .block-cards.block-cards--carousel > .block-cards__item {
      flex-basis: 50%;
      width: 50%;
    }
  }
  body.page-a-propos .block-cards__controls {
    display: none;
  }

  input[type="text"],
  input[type="email"],
  input[type="tel"],
  input[type="number"],
  input[type="url"],
  input[type="search"],
  input[type="date"],
  input[type="time"],
  textarea,
  select {
    background: none;
  }

  /* Le socle n'énumère pas `date`/`time` : sans cette règle l'input natif sort
     nu. Recopie du gabarit du socle — divergera en silence s'il change ; à
     promouvoir (ADR-006) dès qu'un 2ᵉ client adopte ces types. Pas
     `font: inherit` : réinitialiserait line-height. */
  .block-form input[type="date"],
  .block-form input[type="time"] {
    inline-size: 100%;
    padding: 0.7rem 0.85rem;
    color: var(--color-text);
    border: var(--border-width) solid var(--color-input-border);
    border-radius: var(--radius);
    font-size: var(--font-size-base);
    font-family: inherit;
  }
  .block-form input[type="date"]:hover,
  .block-form input[type="time"]:hover {
    border-color: var(--color-text-muted);
  }

  /* —— Toggle « Privé | Institution » (form-toggle.php) : deux `<a>` vers des
     pages distinctes ; le pouce (::before) suit `[data-active]`, basculé par
     app.js avant navigation. */
  .form-toggle {
    position: relative;
    /* grid + `fit-content`, pas inline-flex + `flex: 1` : sans largeur de
       conteneur, les segments prennent leur largeur de contenu et le pouce à
       50% se décale. Bloc : autorise `margin-inline: auto`. */
    display: grid;
    width: fit-content;
    grid-template-columns: repeat(2, minmax(7rem, 1fr));
    margin-inline: auto;
    margin-block: calc(var(--space-block) + var(--space-xs));
    padding: 0.25rem;
    background: var(--color-bg);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-pill);
    isolation: isolate;
  }
  /* Pouce = un segment (50% moins le padding gauche) ; translateX(100%) = l'autre segment. */
  .form-toggle::before {
    content: "";
    position: absolute;
    z-index: -1;
    inset-block: 0.25rem;
    inset-inline-start: 0.25rem;
    inline-size: calc(50% - 0.25rem);
    background: var(--color-primary);
    border-radius: var(--radius-pill);
    transition: transform 0.24s ease;
  }
  .form-toggle[data-active="institution"]::before {
    transform: translateX(100%);
  }
  .form-toggle__option {
    padding: 0.5rem 1.25rem;
    text-align: center;
    text-decoration: none;
    font-weight: var(--font-weight-semibold);
    color: var(--color-text);
    border-radius: var(--radius-pill);
    transition: color 0.24s ease;
  }
  .form-toggle__option[aria-current="page"] {
    color: var(--color-bg);
  }
  .form-toggle__option:not([aria-current="page"]):hover {
    color: var(--color-primary);
  }
}
