/**
 * Coaxia RH — Base stylesheet
 */

/* "D-DIN" (famille libre, licence SIL Open Font License — voir
   assets/font/D-DIN-SIL-Open-Font-License.txt) remplace "din-next-w01-light"
   (police commerciale Monotype, kit de sous-polices par plage Unicode
   incomplet — seul le fichier "w01" était réellement présent) et "Raleway"
   (Google Fonts) comme polices de titres/corps. "D-DIN Bold" et "D-DIN
   Regular" sont ici deux familles DISTINCTES (pas une seule famille avec
   deux graisses) : conforme au nommage interne des fichiers eux-mêmes
   (chaque .otf se déclare comme sa propre famille, "D-DIN Bold"/"D-DIN",
   plutôt que deux graisses d'une même famille "D-DIN") — "font-weight: 400"
   sur les deux évite toute synthèse de gras/italique par le navigateur
   (qui ne surviendrait que si le poids demandé ne correspond à aucun
   @font-face déclaré pour cette famille). */
@font-face {
  font-family: 'D-DIN Bold';
  font-style: normal;
  font-weight: 400;
  src: url('../font/D-DIN-Bold.otf') format('opentype');
  font-display: swap;
}

@font-face {
  font-family: 'D-DIN Regular';
  font-style: normal;
  font-weight: 400;
  src: url('../font/D-DIN-Regular.otf') format('opentype');
  font-display: swap;
}

/**
 * Design tokens
 */
:root {
  --color-brand: #59BB9D;
  --color-brand-soft: #93CDB7;
  /* "--color-brand-light" (#E9F6F2) = "--color-brand" (#59BB9D) rendu à
     l'opacité 14% du filigrane (assets/img/01-filigrane.svg, fill
     "#59BB9D", opacity 0.14), aplati en hexadécimal opaque sur un fond
     blanc — pas une valeur rgba() : calcul par canal, result = 0.14*fg +
     0.86*255 (fond blanc), arrondi à l'entier le plus proche :
     (101,191,160) → (233,246,242) → #E9F6F2. Anciennement la valeur de
     "--color-brand-soft" elle-même, avant la mise à jour des couleurs de
     marque (devenue #93CDB7, nettement plus saturée) — extrait dans son
     propre jeton pour que les filigranes/watermarks (teinte très pâle,
     superposée à faible opacité) restent visuellement inchangés quelle
     que soit la couleur de "--color-brand-soft" (désormais un fond plein,
     pas une teinte de filigrane). */
  --color-brand-light: #E9F6F2;
  --color-black: #231F20;
  --color-white: #FFFFFF;
  --color-gray: #46504C;
  --color-gray-soft: #7D8682;
  --color-transp: rgba(194, 161, 90, 0.08);

  /* Typography */
  --font-heading: "D-DIN Bold", sans-serif;
  --font-body: "D-DIN Regular", sans-serif;

  /* Font sizes — mobile defaults */
  --text-xs: 10px;
  --text-sm: 14px;
  --text-md: 18px;
  --text-base: 20px;
  --text-lg: 25px;
  --text-xl: 35px;

  /* Spacing (8px base) */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.25rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
  --space-10: 2.5rem;
  --space-12: 3rem;
  --space-16: 4rem;
  --space-20: 5rem;
  --space-24: 6rem;

  /* Radii */
  --radius-sm: 4px;
  --radius-md: 8px;
  --radius-lg: 16px;
  --radius-xl: 24px;
  --radius-full: 9999px;

  /* Shadows */
  --shadow-sm: 0 1px 3px rgba(35, 31, 32, 0.06);
  --shadow-md: 0 4px 16px rgba(35, 31, 32, 0.10);
  --shadow-lg: 0 8px 32px rgba(35, 31, 32, 0.14);
  --shadow-xl: 0 0 40px rgba(35, 31, 32, 0.25);

  /* Easing — mockup convention */
  --ease-refined: cubic-bezier(0.25, 0.46, 0.45, 0.94);
  --transition: 0.25s var(--ease-refined);

  /* Layout */
  --container-max: 1200px;
  --container-padding: var(--space-5);
  --header-height: 72px;
}

@media (min-width: 640px) {
  :root {
    --container-padding: var(--space-6);
  }
}

/**
 * Reset & base
 */
*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  scroll-behavior: smooth;
  font-size: 20px;
  -webkit-text-size-adjust: 100%;
}

body {
  font-family: var(--font-body);
  font-size: var(--text-base);
  color: var(--color-black);
  background-color: var(--color-white);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Tous les titres utilisent --font-heading par défaut (hérité par cascade
   partout où aucune règle plus spécifique ne le redéfinit déjà — beaucoup
   de "& h2"/"& h3" le font explicitement dans leur contexte, mais plusieurs
   "h1" de hero, entre autres, n'avaient aucun "font-family" propre et
   héritaient donc à tort de --font-body). */
h1,
h2,
h3,
h4,
h5,
h6 {
  font-family: var(--font-heading);
}

img {
  max-width: 100%;
  height: auto;
  display: block;
}

a {
  color: inherit;
  text-decoration: none;

  &.link-arrow {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--color-brand);
    font-weight: 600;
    border-bottom: 1.5px solid transparent;
    transition: gap .2s var(--ease), border-color .2s var(--ease);

    &:hover {
      gap: 10px;
      border-color: var(--brand);
    }
  }
}

ul,
ol {
  list-style: none;
}

button {
  cursor: pointer;
  border: none;
  background: none;
  font-family: var(--font-body);
}

/**
 * Utilities
 */
.container {
  max-width: var(--container-max);
  margin: 0 auto;
  padding: 0 var(--container-padding);
}

/**
 * Section patterns
 */

section {
  & header {
    max-width: 760px;
    margin: 0 auto 52px;
    /* mobile: 2rem */

    @media (min-width: 640px) {
      & {
        margin-bottom: var(--space-12);
        /* tablet+: 3rem */
      }
    }

    & h2 {
      font-size: var(--text-xl);
      font-weight: 600;
      color: var(--color-black);
      line-height: 1.2;
      margin-bottom: var(--space-4);
    }

    & .text {
      color: var(--color-gray);
      max-width: 600px;
      margin: 0 auto;
      line-height: 1.7;
    }

    &.centered {
      text-align: center;

      & .text {
        margin: 0 auto;
      }
    }
  }

  /**
   * Hero section
   */
  &.hero {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-8);
    /* Espace entre ".container" et "ul.badges" (voir plus bas) quand ce
       dernier est encore en flux normal, sous 1024px — sans effet une fois
       "ul.badges" passé en "position: absolute" (retiré du flux flex) à
       partir de ce point de rupture. */
    position: relative;
    padding: var(--space-12) 0;
    /* Fond plein clair (jamais une photo), pas de halos décoratifs,
       filigrane du « A » directement lisible en fond — même modèle que le
       hero de la page d'accueil ("&.full" plus bas n'a donc plus besoin de
       redéfinir le fond, seul l'alignement du filigrane diffère encore).
       Remplace l'ancien fond photo + halos, dont la richesse visuelle
       écrasait le filigrane au point de le rendre quasi-invisible sur
       toutes les pages utilisant "section/hero.php". */
    background-color: var(--color-white);
    /* Pas de photo pour l'instant (voir ci-dessus), mais la chaîne
       d'intégration WordPress (kiweb-fse-base ≥ 1.49.0) pose déjà l'image
       mise en avant de la page en "background-image" ici dès qu'elle
       existe (frontend ET canevas de l'éditeur) — ce mécanisme ne pose
       JAMAIS "background-size"/"position"/"repeat" lui-même, il attend
       que ce soit déjà réglé ici, une fois pour toutes, quelle que soit la
       page. Préparé par anticipation (aucun effet tant qu'aucune image
       n'est définie) : jamais de répétition, toujours étirée pour
       recouvrir l'intégralité de la section, cadrée au centre. Suppose
       une photo au format paysage et de résolution suffisante (le
       pré-réglage WordPress "kiweb-theme-hero" recadre en 1920×960,
       ratio 2:1) — un format portrait ou une image trop petite sera
       recadré(e)/agrandi(e) sans distorsion par "cover", mais restera
       visuellement moins satisfaisant(e) qu'une vraie photo paysage.
       "background-color" ci-dessus reste le filet de sécurité derrière
       une image partiellement transparente ou pendant son chargement. */
    background-repeat: no-repeat;
    background-position: center;
    background-size: cover;
    /* Pas d'"overflow: hidden" ici : "ul.badges" (hero de la page
       d'accueil) doit pouvoir chevaucher le bord inférieur de la section. */

    @media (min-width: 640px) {
      & {
        padding: var(--space-20) 0;
      }
    }

    @media (min-width: 1024px) {
      & {
        padding: var(--space-24) 0;
      }
    }

    /* Signe — filigrane du « A » (voir .kiweb/mockup/coaxia/CLAUDE.md) : une
       fois par page, derrière le titre, en marge. Porté par "::before" sur
       "section.hero" lui-même — calé en haut de la section, juste sous
       le menu principal. Aligné à DROITE par défaut (pages intérieures,
       "section/hero.php" — une seule colonne de texte, rien à droite pour
       le recouvrir) ; "&.full" (hero de la page d'accueil) le réaligne à
       gauche juste en dessous, seule différence entre les deux modèles : à
       droite sur la page d'accueil, il finirait en grande partie masqué
       derrière la carte du widget de rendez-vous
       ("component('block/availability')"). Opacité 14% déjà intégrée au
       SVG (01-filigrane.svg) : ne jamais la resurcharger ici. Absent par
       défaut (mobile) ; apparaît à partir de 700px seulement — sous ce
       seuil il finirait pile derrière le texte (règle "sous 700px, le
       filigrane sort ou disparaît"). */
    &::before {
      content: '';
      position: absolute;
      /* "top: 0" correspondrait au sommet de "section.hero" — masqué sous le
         menu principal, fixe ("position: fixed", voir "& .container"
         ci-dessous : son "margin-top: var(--header-height)" compense déjà ce
         chevauchement). On aligne donc plutôt sur le haut réel de
         ".container", juste sous le menu. */
      top: var(--header-height);
      /* Aligné sur le bord droit du contenu de ".container" (centré, même
         formule que ".container" lui-même) plutôt que sur le bord de la
         section — évite de dépendre d'un décalage négatif arbitraire. */
      right: max(var(--container-padding), calc((100% - var(--container-max)) / 2 + var(--container-padding)));
      width: 260px;
      height: 240px;
      background-repeat: no-repeat;
      background-position: top right;
      background-size: 260px auto;
      pointer-events: none;
      z-index: 0;
      display: none;
    }

    /* Exception d'alignement pour le hero de la page d'accueil UNIQUEMENT
       (voir le commentaire ci-dessus) : filigrane à gauche plutôt qu'à
       droite. */
    &.full::before {
      right: auto;
      left: max(var(--container-padding), calc((100% - var(--container-max)) / 2 + var(--container-padding)));
      background-position: top left;
    }

    /* "@media { &::before {...} }" plutôt que "&::before { @media { & {...} } }"
       ci-dessus : nester un "@media" DIRECTEMENT à l'intérieur d'une règle de
       pseudo-élément et y référencer "&" ne s'applique pas dans Chrome
       (testé isolément — fonctionne pour un élément réel, jamais pour un
       pseudo-élément). Le "@media" doit donc rester au niveau de "&.hero"
       (élément réel) et re-cibler "&::before" explicitement à l'intérieur. */
    @media (min-width: 700px) {
      &::before {
        display: block;
        background-image: url('../img/01-filigrane.svg');
      }
    }

    & h1 {
      font-size: clamp(30px, 8vw, 40px);
      /* Explicite (absent jusqu'ici, ce H1 retombait sur la taille par
         défaut du navigateur, "2em" — soit 40px, la police ambiante du
         site étant déjà de 20px) : sur les plus petits écrans (320px), le
         mot le plus long du titre ("fonctionnement") ne tenait plus à
         40px, débordant la page de quelques px horizontalement malgré le
         retour à la ligne. Fluide (clamp) plutôt qu'une valeur fixe plus
         petite : garde 40px dès que l'écran laisse assez de place. */
      font-weight: 600;
      color: var(--color-black);
      line-height: 1.15;
      margin-bottom: var(--space-4);
      animation: fade-up 500ms var(--ease-refined) 180ms both;

      & em {
        font-family: var(--font-heading);
        color: var(--color-brand);
      }

      @media (min-width: 640px) {
        & {
          margin-bottom: var(--space-6);
        }
      }
    }

    /* HERO SUBTITLE — Mobile-first responsive */
    & .text {
      font-size: 0.95rem;
      color: var(--color-gray);
      line-height: 1.6;
      margin-bottom: var(--space-6);
      max-width: 100%;
      padding: 0 var(--space-2);
      animation: fade-up 500ms var(--ease-refined) 280ms both;

      @media (min-width: 480px) {
        & {
          font-size: 1rem;
          /* Small phones: 16px */
          line-height: 1.7;
          margin-bottom: var(--space-8);
        }
      }

      @media (min-width: 640px) {
        & {
          padding: 0;
          /* Remove extra padding on tablet+ */
        }
      }

      @media (min-width: 1024px) {
        & {
          max-width: 500px;
        }
      }
    }

    /* HERO ACTIONS (Buttons) — Mobile-first */
    & nav {
      display: flex;
      flex-direction: column;
      gap: var(--space-3);
      /* Reduced gap on mobile (from var(--space-4)) */
      flex-wrap: wrap;
      align-items: center;
      /* Center buttons horizontally */
      justify-content: center;
      /* Center buttons vertically in container */
      width: 100%;
      max-width: calc(100% - 2rem);
      /* Relative width: 100% minus 1rem padding each side (prevents overflow @320px) */
      margin: 0 auto;
      /* Center the button container itself */
      animation: fade-up 500ms var(--ease-refined) 360ms both;

      & .btn {
        width: 100%;
        /* Full-width buttons on mobile (touch-friendly) */
      }

      @media (min-width: 480px) {
        & {
          max-width: 330px;
          /* Small phones: safe limit for two-button rows (future) */
        }
      }

      @media (min-width: 640px) {
        & {
          flex-direction: row;
          gap: var(--space-4);
          /* Restore original gap on tablet+ */
          max-width: 100%;
        }

        & .btn {
          width: auto;
          /* Buttons auto-width on tablet+ (not full-width) */
        }
      }

      @media (min-width: 1024px) {
        &.left {
          justify-content: flex-start;
          /* Align button to left on desktop (index2 variant only) */
        }
      }
    }

    /* HERO CONTAINER — Content layout (height handled by .hero padding) */
    & .container {
      position: relative;
      z-index: 1;
      display: flex;
      flex-direction: column;
      align-items: center;
      text-align: center;
      gap: var(--space-5);
      width: 100%;
      /* Sans ça : ".container" est un flex item de ".hero" ("display: flex;
         align-items: center" — pas "stretch"), donc dimensionné selon son
         CONTENU plutôt que selon la largeur disponible. Le ".container"
         générique (règle plus haut) suppose un "width: auto" qui vaut 100%
         dans un contexte de bloc normal — faux ici. Sans "width: 100%"
         explicite, tout sous-contenu ayant lui-même un plancher de largeur
         (ex. la grille du mini-calendrier de ".appointment", ~287px de
         min-content) remonte jusqu'à ".container" et l'empêche de rétrécir
         sous ce plancher, débordant la page horizontalement sous ~390px. */
      margin-top: var(--header-height);
      /* Offset content below header height (72px) for visual balance under fixed header */

      @media (min-width: 480px) {
        & {
          gap: var(--space-6);
        }
      }

      @media (min-width: 640px) {
        & {
          gap: var(--space-10);
        }
      }

      /* Single buttons inside hero (for service pages /*) */
      & .btn {
        width: 100%;
        /* Mobile: full-width for touch-friendly buttons */

        @media (min-width: 640px) {
          & {
            width: auto;
            max-width: none;
            /* Tablet+: auto-width */
          }
        }
      }

      /* Info list — générique : héritée par TOUT ".hero .container & ul"
         (y compris, par ex., le <nav><ul><li><a class="btn"></li></ul></nav>
         des CTA de "section/hero.php", partagé par les pages de service).
         Le rond "badges" ci-dessous est un design PROPRE à la page d'accueil
         (index.php) et ne doit pas déteindre sur ce cas générique — il est
         donc conditionné à la classe ".badges", posée dans le HTML
         uniquement sur la liste de statistiques d'index.php, plutôt que sur
         "ul" seul. */
      & ul {
        display: flex;
        flex-direction: column;
        gap: 16px;
        padding: 24px;
        background: var(--color-white);
        border-radius: 12px;

        @media (min-width: 640px) {
          & {
            flex-direction: row;
            flex-wrap: wrap;
            gap: var(--space-5) var(--space-8);
            padding: 32px;
          }

          /* Items share the row equally; the last item (longer title/text) gets extra room to wrap */
          & li {
            flex: 1 1 150px;
            min-width: 150px;

            &:last-child {
              flex: 1.6 1 220px;
            }
          }
        }

        & li {
          display: flex;
          flex-direction: column;
          gap: 2px;
        }

        & strong {
          font-weight: 600;
          color: var(--color-black);
        }

        & span {
          color: var(--color-gray-soft);
          line-height: 1.4;
          /* Wraps instead of nowrap: the 3rd item's text is long and would otherwise overflow the card */
        }
      }

      /* HERO GRID LAYOUT — Two-column layout for hero content + availability card */
      &.grid-row {
        display: flex;
        flex-direction: column;
        gap: var(--space-8);
        /* Mobile: stacked vertically */
        text-align: left;

        @media (min-width: 1024px) {
          & {
            display: grid;
            grid-template-columns: minmax(0, 1.5fr) minmax(300px, 420px);
            gap: var(--space-10);
            align-items: flex-start;
            /* Desktop: text column absorbs available space, availability card capped so it stays card-sized */
          }
        }

        /* Hero content (left column) */
        & article {
          display: flex;
          flex-direction: column;
          gap: var(--space-5);
        }
      }
    }
  }

  &.header-grid {
    & header {
      max-width: 760px;
      margin: 0 auto 52px;
      text-align: center;

      & h2 {
        letter-spacing: -0.025em;
      }

      & .text {
        margin-top: 14px;
        color: var(--color-gray);
      }
    }

    & .card {
      background: var(--color-white);
      padding: 28px 22px;
      display: flex;
      flex-direction: column;
      position: relative;
      overflow: hidden;
      transition: border-color .3s var(--ease-refined), transform .3s var(--ease-refined);
      background-image: none;

      &::before {
        content: "";
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 3px;
        background: var(--color-brand);
        transform: scaleX(0);
        transform-origin: left;
        transition: transform .35s var(--ease-refined);
        opacity: 1;
      }

      &:hover {
        transform: translateY(-3px);
        border-color: var(--color-brand);
        box-shadow: none;

        &::before {
          transform: scaleX(1);
        }
      }

      & .icon {
        width: 48px;
        height: 48px;

        & svg {
          width: 24px;
          height: 24px;
        }
      }

      & h3 {
        color: var(--color-black);
        margin-bottom: 8px;
        white-space: normal;
        overflow: visible;
        text-overflow: clip;
      }

      & .text {
        flex: 1;
      }

      /* "margin-top: auto" (et non le seul "flex: 1" de ".text" ci-dessus) :
         garantit que "footer" reste TOUJOURS collé au bas de ".card", quelle
         que soit la hauteur de ".text" — même principe que "&.section-bg-
         dark & .card & footer"/"&.section-bg-brand & .card & footer" plus
         bas dans ce fichier. Avec ".text" qui absorbe déjà tout l'espace
         disponible (flex-grow), cette marge se résout à 0 dans le cas
         courant (comportement inchangé) ; elle protège seulement le cas où
         ".text" serait un jour vide/absent, où "footer" resterait sinon
         collé juste sous le titre plutôt qu'en bas de la carte. */
      & footer {
        margin-top: auto;
      }

      & nav {

        /* Flex horizontale : 1er lien à gauche, 2e à droite (space-between).
          Avec un seul lien, il reste naturellement à gauche.
          "flex-wrap: nowrap" + "flex: 0 1 auto" sur les <li> : base.css leur
          applique par ailleurs "flex-grow: 1" (hérité d'un contexte .card
          générique), ce qui les fait chacun remplir toute la largeur du <ul> et
          forcer un retour à la ligne dès qu'il y a 2 liens ; on neutralise ce
          comportement ici pour garder les deux liens sur une seule ligne. */
        & ul {
          display: flex;
          flex-wrap: nowrap;
          justify-content: space-between;
          gap: var(--space-4);
          list-style: none;
          padding: 0;
          margin: var(--space-1) 0 0;

          & li {
            flex: 0 1 auto;
          }
        }

        & a {
          display: inline-flex;
          align-items: center;
          gap: 6px;
          color: var(--color-brand);
          font-weight: 600;
          border-bottom: 1.5px solid transparent;
          transition: gap .2s var(--ease-refined), border-color .2s var(--ease-refined);

          &:hover {
            gap: 10px;
            border-color: var(--color-brand);
          }
        }
      }
    }
  }

  &.pains {

    /* Override .header-grid's centered/760px header: left-aligned, full container width */
    & header {
      max-width: none;
      margin: 0 0 52px;
      text-align: left;

      & .text {
        max-width: none;
        margin-left: 0;
        margin-right: 0;
      }
    }
  }

  &.services {

    /* Override the markup's "centered" class + the generic 760px/auto header: left-aligned, full container width */
    & header {
      max-width: none;
      margin: 0 0 52px;
      text-align: left;

      &.centered {
        text-align: left;
      }

      & .text {
        max-width: none;
        margin-left: 0;
        margin-right: 0;
      }
    }
  }

  &.targets {

    /* Override .header-grid's centered/760px header: left-aligned, full container width */
    & header {
      max-width: none;
      margin: 0 0 52px;
      text-align: left;
    }
  }

  &.method {
    position: relative;

    /* Spécificité : "&.section-padding" (plus bas dans ce fichier, "padding:
       var(--space-16) 0" / "var(--space-20) 0") a la MÊME spécificité que
       "&.method" seule (0,1,1 chacune, une classe sur "section") — à égalité,
       la règle la PLUS TARDIVE dans le fichier l'emporte, donc
       "section-padding" écraserait un simple "padding-top" posé ici.
       Combiner les deux classes ("&.section-padding" imbriqué DANS
       "&.method") force le composé "section.method.section-padding"
       (0,2,1), qui gagne quel que soit l'ordre. Valeur : dégage la place de
       la ligne de crête ci-dessous ("top: var(--space-6)" + "height: 180px"
       = bord inférieur à 204px du haut de la section) + une respiration —
       le header (et donc ".grid-4c" qui le suit) démarre ainsi toujours
       SOUS la crête, jamais à cheval dessus. */
    &.section-padding {
      /* Mobile-first : la ligne de crête (::after) mesure min(80vw,1040px)
         de large et son SVG (520×170) se scale par contain → hauteur réelle
         ≈ 80vw × 170/520 ≈ 26vw. Le padding suit cette hauteur + espace
         minimal. À 640px+, 80vw ≈ 512px → hauteur ≈ 167px ≈ 180px :
         on revient à la valeur fixe basée sur la boîte entière (180px). */
      padding-top: calc(var(--space-6) + 26vw + var(--space-4));

      @media (min-width: 640px) {
        & { padding-top: calc(var(--space-6) + 180px + var(--space-8)); }
      }
    }

    /* Signe — ligne de crête (voir .kiweb/mockup/coaxia/CLAUDE.md) : frise
       Méthode UNIQUEMENT, nulle part ailleurs. Statique : contrairement aux
       ".reveal" de "& .card" ci-dessous, cette décoration n'anime jamais au
       scroll ("le site a déjà des apparitions au scroll qui laissent des
       écrans vides ; on n'en ajoute pas"). Purement décorative — posée en
       CSS globale, jamais en <img> dans la page (voir index.php). Variante
       menthe (jamais la version blanche) : ".method" porte désormais le
       fond CLAIR de "&.section-bg-brand-soft" (background-color:
       var(--color-brand-soft), #E9F6F2) — un tracé blanc y serait
       quasiment invisible, d'où "03-ligne-de-crete.svg" (menthe,
       var(--color-brand)) plutôt que la variante blanche utilisée
       auparavant sur le fond plein "&.section-bg-brand".
       Portée par "::after" (et non "::before" comme les autres décorations
       de section) : ".method" porte aussi ".section-transition-arrow", qui
       réserve "::before" pour son demi-cercle de transition — les deux
       pseudo-éléments d'un même élément ne peuvent héberger qu'UNE seule
       décoration chacun ; les faire cohabiter sur le même "::before" les
       écrasait partiellement l'un l'autre (largeur/hauteur de la crête
       ramenées à 0 par les valeurs du demi-cercle, demi-cercle hérité à
       "opacity: 0.5" de la crête — visible mais délavé). */
    &::after {
      content: '';
      position: absolute;
      top: var(--space-6);
      left: 50%;
      transform: translateX(-50%);
      /* 2× la taille d'origine (520×90) en conservant les proportions du
         SVG (viewBox 520×170, "background-size: contain") : doubler les
         deux dimensions de la boîte revient à doubler uniformément le
         rendu, sans le déformer. */
      width: min(1040px, 80%);
      height: 180px;
      background-image: url('../img/03-ligne-de-crete.svg');
      background-repeat: no-repeat;
      background-position: center top;
      background-size: contain;
      opacity: 0.5;
      pointer-events: none;
    }

    /* Override .header-grid's centered/760px header: left-aligned, full container width */
    & header {
      position: relative;
      z-index: 1;
      max-width: none;
      margin: 0 0 52px;
      text-align: left;

      & .text {
        max-width: none;
        margin-left: 0;
        margin-right: 0;
      }
    }

    /* Step cards — formation.php only (.grid-5c exists nowhere else).
       Scoped via "& .grid-5c .card" rather than "& .card" to avoid
       applying to section.method on index.php (grid-4c, icon cards).
       (0,0,3,1) comfortably beats "section.page-content article
       { text-align: justify }" at (0,0,1,2).
       gap: uniform spacing between .label / h3 / .text (replaces h3's
       margin-bottom: 8px from ".header-grid .card h3" at (0,0,2,2) —
       higher specificity here wins regardless of source order). */
    & .grid-5c .card {
      gap: var(--space-3);
      justify-content: center;
      align-items: center;
      text-align: center;
      cursor: pointer;

      /* Allow the bottom arc (<span class="card-arc">) to protrude 18 px
         below the card's bottom border. Hover bar ::before gets matching
         top border-radius to compensate for the removed overflow: hidden. */
      overflow: visible;

      &::before {
        border-radius: var(--radius-md) var(--radius-md) 0 0;
      }

      /* Bottom arc — protrudes 18 px below the card's bottom border.
         Same geometry as .section-transition-arrow (36 × 18 px,
         border-radius: 0 0 18px 18px), but stroked rather than filled:
         border color matches the card's own border (--color-gray-soft
         default, --color-brand on hover / .is-open), border-top: none so
         it connects seamlessly with the card's bottom edge.
         Uses a <span> (not ::after) because the chevron inside needs its
         own ::before — nested pseudo-elements on a pseudo are impossible. */
      & .card-arc {
        position: absolute;
        bottom: -18px;
        left: 50%;
        transform: translateX(-50%);
        transform-origin: 50% 0;
        width: 36px;
        height: 18px;
        border-radius: 0 0 18px 18px;
        border: 1px solid var(--color-gray-soft);
        border-top: none;
        background-color: var(--color-white);
        color: var(--color-gray-soft);
        display: flex;
        align-items: center;
        justify-content: center;
        transition:
          border-color .3s var(--ease-refined),
          color .3s var(--ease-refined),
          transform .25s var(--ease-refined);

        /* Chevron ↓ (card closed) — border L-shape rotated 45°.
           Flex centering places the element's geometric center at 9 px
           (half of 18). The visual tip of the ∨ sits at +5.66 px below
           the element's center, so translateY(-3px) shifts the whole
           shape upward to bring the tip closer to the arc's middle.
           Symmetric translateY(+3px) for the ↑ open state. */
        &::before {
          content: '';
          display: block;
          flex-shrink: 0;
          width: 8px;
          height: 8px;
          border-right: 1.5px solid currentColor;
          border-bottom: 1.5px solid currentColor;
          transform: translateY(-3px) rotate(45deg);
          transition: transform .25s var(--ease-refined);
        }
      }

      /* Arc + chevron → brand color and scale on hover / when open.
         transform-origin: 50% 0 anchors the growth at the junction with
         the card's bottom edge, mirroring the section-toggle::before
         behaviour (same scale(1.18), same origin). translateX(-50%)
         preserved to maintain horizontal centering. */
      &:hover .card-arc,
      &.is-open .card-arc {
        border-color: var(--color-brand);
        color: var(--color-brand);
        transform: translateX(-50%) scale(1.18);
      }

      /* Flip chevron ↑ when open — translateY(+3px) is the symmetric
         correction: the ∧ tip is +5.66 px above the element center,
         so shifting the element down by 3 px centers the tip visually. */
      &.is-open .card-arc::before {
        transform: translateY(3px) rotate(-135deg);
      }

      & h3 {
        margin-block: 0;
      }

      & .text {
        flex: none;
        white-space: nowrap;
      }

      /* Square only when closed; auto-height when detail is expanded */
      @media (min-width: 640px) {
        &:not(.is-open) {
          aspect-ratio: 1;
        }
      }

      /* Open state — top bar + brand border (mirrored from :hover, persisted).
         border-bottom-color: transparent suppresses the horizontal bottom line
         that would otherwise appear above the arc (the arc's own border provides
         the bottom visual, making the card's bottom-border redundant and — when
         brand-colored — visually noisy). Same override on :hover below. */
      &.is-open {
        border-color: var(--color-brand);
        border-bottom-color: transparent;

        &::before {
          transform: scaleX(1);
        }
      }

      &:hover {
        border-bottom-color: transparent;
      }

      /* Detail text — hidden by default, revealed in-flow when .is-open.
         CSS grid rows trick: 0fr → 1fr animates height without knowing it.
         Open/close transitions are intentionally asymmetric:
         — Close (this block, "target" state after removing .is-open):
             <p> slides up + fades fast (no delay); height collapses after
             a short delay (0.1s) so the slide-up is visible before clipping.
         — Open (&.is-open .detail below, "target" state after adding it):
             height expands immediately; <p> slides down after a tiny delay. */
      & .detail {
        display: grid;
        grid-template-rows: 0fr;
        overflow: hidden;
        align-self: stretch;
        text-align: left;
        margin-top: 0;
        transition:
          grid-template-rows 0.3s ease 0.05s,
          margin-top 0.3s ease 0.05s;

        & p {
          overflow: hidden; /* required: removes min-height constraint for 0fr */
          color: var(--color-gray);
          font-size: var(--text-sm);
          line-height: 1.65;
          margin: 0;
          padding-top: var(--space-3);
          border-top: 1px solid var(--color-brand);
          white-space: normal;
          transform: translateY(-10px);
          opacity: 0;
          transition:
            transform 0.3s ease,
            opacity 0.25s ease;
        }
      }

      &.is-open .detail {
        grid-template-rows: 1fr;
        margin-top: var(--space-3);
        transition:
          grid-template-rows 0.3s ease,
          margin-top 0.3s ease;

        & p {
          transform: translateY(0);
          opacity: 1;
          transition:
            transform 0.3s ease 0.05s,
            opacity 0.25s ease 0.05s;
        }
      }
    }
  }

  &.section-padding {
    padding: var(--space-16) 0;

    @media (min-width: 640px) {
      & {
        padding: var(--space-20) 0;
      }
    }
  }

  &.section-bg-dark {
    background-color: var(--color-black);
    color: var(--color-white);

    & header {
      & .label {
        color: var(--color-brand);
      }

      & h2 {
        color: var(--color-white);
      }

      & .text {
        color: rgba(255, 255, 255, 0.65);
      }
    }

    & .card {
      padding: var(--space-6);
      position: relative;
      overflow: hidden;
      background-image: none;
      background-color: rgba(255, 255, 255, 0.03);
      border-color: rgba(255, 255, 255, 0.1);
      display: flex;
      flex-direction: column;

      /* Même animation que "section.method .card" (règle générique
         "&.header-grid & .card" plus haut dans ce fichier) : barre pleine
         largeur qui se déploie depuis la gauche au survol ("transform:
         scaleX", pas un fondu d'opacité comme auparavant ici). */
      &::before {
        content: '';
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 3px;
        background: var(--color-brand);
        transform: scaleX(0);
        transform-origin: left;
        transition: transform .35s var(--ease-refined);
      }

      @media (min-width: 640px) {
        & {
          padding: var(--space-8);
        }
      }

      &:hover {
        transform: translateY(-3px);
        border-color: transparent;

        &::before {
          transform: scaleX(1);
        }
      }

      /* Badge "Nouveauté 2026" (card/title-text-cta.php, <span
         class="highlight">) — étiquette collée au coin supérieur gauche de
         la carte ("top: 0; left: 0", au lieu d'une pastille flottante
         comme la variante "&.section-bg-brand & .card & .highlight" plus
         bas dans ce fichier) : seul le coin INTÉRIEUR (bas-droit, celui qui
         pointe vers le contenu de la carte) est arrondi — les 3 autres
         coins restent droits, épousant les bords de la carte. Le coin
         supérieur gauche de l'étiquette coïncide avec celui, arrondi, de
         ".card" ("overflow: hidden" sur ".card" le découpe donc
         automatiquement selon cette même courbe, sans avoir besoin de le
         re-arrondir ici). */
      & .highlight {
        position: absolute;
        top: 0;
        left: 0;
        /* "align-self: flex-start" nécessaire : ".card" est un conteneur
           flex ("display: flex; flex-direction: column") sans
           "align-items" propre, donc "stretch" (la valeur par défaut) —
           un enfant "position: absolute" SANS "right"/"width" hérite
           quand même de cet alignement flex pour son axe transversal
           (horizontal ici) et s'étire pleine largeur de la carte au lieu
           de garder la largeur de son contenu ("shrink-to-fit", le
           comportement attendu d'un élément positionné classique hors
           d'un contexte flex). */
        align-self: flex-start;
        background: var(--color-brand);
        color: var(--color-black);
        font-size: var(--text-sm);
        font-weight: 700;
        letter-spacing: 0.05em;
        padding: 6px 12px;
        border-radius: 0 0 var(--radius-md) 0;
        text-transform: uppercase;
      }

      & .icon {
        width: 52px;
        height: 52px;
        background-color: var(--color-transp);
        border-radius: var(--radius-md);
        margin-bottom: var(--space-5);
        color: var(--color-brand);
      }

      & h3 {
        color: var(--color-white);
      }

      /* Numéro "01"/"02"… (cartes sans .card-bg-lightdark, ex. "Les accompagnements") */
      &>.label {
        font-family: var(--font-heading);
        font-size: var(--text-xl);
        font-weight: 500;
        color: var(--color-brand);
        margin-bottom: 12px;
        line-height: 1;
        font-style: italic;
        text-transform: none;
        letter-spacing: 0;
      }

      & .text {
        flex-grow: 1;
        color: rgba(255, 255, 255, 0.78);

        & ul {
          margin-bottom: 6px;
        }

        & ul li {
          color: rgba(255, 255, 255, 0.78);

          &::before {
            color: var(--color-brand);
          }
        }
      }

      & footer {
        padding-top: var(--space-3);
        margin-top: auto;

        & .label2 {
          font-size: var(--text-sm);
          font-weight: 600;
          color: var(--color-white);
          text-transform: none;
          letter-spacing: 0;
        }

        /* Mise en page flexbox déplacée depuis "& footer" (ci-dessus) : elle
           arrange le contenu propre de "nav" (son "<ul>"), pas la relation
           entre ".label2" et "nav" au sein de "footer". */
        & nav {
          display: flex;
          align-items: center;
          justify-content: space-between;
          gap: 12px;
          flex-wrap: wrap;
          margin-top: var(--space-3);
        }

        & nav a.btn-outline {
          color: var(--color-white);
          border-color: var(--color-brand);

          &:hover {
            color: var(--color-brand);
            border-color: var(--color-brand);
          }
        }
      }

      /* Carte mise en avant (card/title-text-cta.php, "highlight" +
         "&.card--highlight") — PAS le même principe que la variante
         "&.section-bg-brand & .card & .card--highlight" plus bas dans ce
         fichier (fond plein inversé, blanc → noir) : un premier essai en
         fond plein "var(--color-brand)" ici entrait en collision de
         couleur avec ".highlight" ci-dessus (même vert) — le badge,
         censé se détacher par-dessus la carte, s'y fondait complètement,
         illisible comme pastille distincte. Cette variante se contente
         donc d'une bordure "var(--color-brand)" (au lieu de la bordure
         translucide ambiante) et d'un fond légèrement plus opaque que ses
         voisines (0.06 contre 0.03) — le texte reste blanc, inchangé :
         seuls le contour et le badge signalent la mise en avant, sans
         reproduire le mécanisme d'inversion de contraste de la variante
         "section-bg-brand" (non pertinent ici, l'ambiance étant déjà
         sombre). */
      &.card--highlight {
        border-color: var(--color-brand);
        background-color: rgba(255, 255, 255, 0.06);
      }

    }

  }

  &.section-bg-brand {
    position: relative;
    background-image: none;
    background-color: var(--color-brand);
    color: var(--color-white);

    &:is(.hero) {

      h1,
      .text {
        color: var(--color-white);
      }
    }

    &>.container {
      position: relative;
      z-index: 1;
    }

    & header {

      & .label,
      & h2,
      & .text {
        color: var(--color-white);
      }
    }

    .btn-outline {
      color: var(--color-white);
      border-color: var(--color-white);

      &:hover {
        color: var(--color-white);
        border-color: var(--color-black);
      }
    }

    & .card {
      position: relative;
      background: var(--color-white);
      padding: 36px 30px 30px;
      display: flex;
      flex-direction: column;
      transition: transform .3s var(--ease-refined), box-shadow .3s var(--ease-refined);

      &::before {
        background: var(--color-gray-soft);
      }

      &:hover {
        transform: translateY(-6px);
        box-shadow: var(--shadow-lg);
      }

      /* Badge "Le plus demandé" */
      & .highlight {
        position: absolute;
        top: -12px;
        left: 30px;
        background: var(--color-brand);
        color: var(--color-black);
        font-weight: 700;
        letter-spacing: 0.05em;
        padding: 6px 12px;
        border-radius: var(--radius-full);
        text-transform: uppercase;
      }

      /* Numéro 01 / 02 / 03 */
      &>.label {
        font-family: var(--font-heading);
        font-size: var(--text-xl);
        font-weight: 500;
        color: var(--color-brand);
        margin-bottom: 12px;
        line-height: 1;
        font-style: italic;
        text-transform: none;
        letter-spacing: 0;
      }

      & h3 {
        color: var(--color-black);
        margin-bottom: 6px;
        overflow: hidden;
        text-overflow: ellipsis;
      }

      & .text {
        flex-grow: 1;

        &>p {
          color: var(--color-gray);
          margin-bottom: 22px;
        }
      }

      & footer {
        padding-top: 22px;
        margin-top: auto;

        & .label2 {
          font-weight: 600;
          color: var(--color-black);
          text-transform: none;
          letter-spacing: 0;
        }

        /* Mise en page flexbox déplacée depuis "& footer" (ci-dessus) : elle
           arrange le contenu propre de "nav" (son "<ul>"), pas la relation
           entre ".label2" et "nav" au sein de "footer". */
        & nav {
          display: flex;
          align-items: center;
          justify-content: space-between;
          gap: 12px;
          flex-wrap: wrap;
        }
      }

      /* Carte mise en avant */
      &.card--highlight {
        background: var(--color-black);
        border-color: var(--color-black);
        color: var(--color-white);

        & h3 {
          color: var(--color-white);
        }

        & .text {

          &>p,
          & ul li {
            color: rgba(255, 255, 255, 0.78);
          }

          & ul li::before {
            color: var(--color-brand);
          }
        }

        & footer {
          border-color: rgba(255, 255, 255, 0.15);

          & .label2 {
            color: var(--color-white);
          }
        }
      }
    }
  }

  &.section-bg-brand-soft {
    position: relative;
    background-image: none;
    background-color: var(--color-brand-soft);

    /* Tout lien affiché directement sur ce fond (sans fond propre, ex. un
       lien de texte dans ".section-body") : "--color-brand" y tombe à
       1,29 de contraste (couleurs de marque mises à jour, #93CDB7
       nettement plus saturé) — illisible. "--color-white" au repos,
       "--color-black" au survol (9,05, conforme) — même convention que
       ".btn-outline-white.btn-hover-black" (section.about, index.php).
       Spécificité volontairement faible (1 classe) : un lien à sa propre
       classe plus spécifique (".btn-white", ".btn-outline-white"…)
       continue de définir sa propre couleur, cette règle ne s'applique
       qu'aux liens sans styling dédié. */
    & a {
      color: var(--color-white);

      &:hover {
        color: var(--color-black);
      }
    }

    /* Même logique pour les titres "h2" : "--color-brand" (#59BB9D) sur
       fond "--color-brand-soft" (#93CDB7) tombe à 1,29 de contraste —
       quasi invisible (même problème que pour les liens ci-dessus).
       Couvre les sections "section-bg-brand-soft" hors "section.page-content
       article" : index.php ("section.about", "section.stats", "section.method",
       "section.blog-related"). Les sections de service/about (conseil,
       coaching, facilitation, conseillere-rh) sont déjà couvertes par la
       règle haute-spécificité dans "@scope (.page-service, .page-about)"
       (voir "&:is(.decor-mountain, .decor-collectif, .decor-echange,
       .decor-mouvement) &:is(.section-bg-brand-soft) & h2" plus bas dans
       ce fichier). La surcharge pour les sections à l'intérieur de
       "section.page-content article" (formation.php : "section.method",
       "section.handicap") suit juste après le bloc
       "section.page-content article .section-bg-brand-soft a:not(.btn)"
       en fin de fichier. */
    & h2 {
      color: var(--color-white);
    }
  }

  /* Demi-cercle de transition — plein, bord plat en haut, arrondi vers le
     bas, en haut au centre de la section : fait le lien visuel avec la
     section précédente (voir les 3 variantes de couleur ci-dessous —
     chacune reprend la couleur de fond de la section qui précède celle qui
     porte la classe). Système générique, réutilisé par plusieurs sections
     d'index.php et de section/testimonials.php : forme/positionnement dans
     ".section-transition-arrow", couleur dans un modificateur dédié
     (".section-transition-arrow--white/--brand-soft/--dark"). CSS pur
     (boîte pleine + border-radius), pas un SVG : pas de nouvel asset pour
     une forme aussi simple. Demi-cercle géométriquement exact : largeur
     36px, hauteur moitié (18px, = rayon), rayon de bordure 18px sur les
     deux coins du bas — un rayon en pixels (jamais atteint par le haut de
     la boîte) vaut à la fois comme rayon horizontal (18px = moitié de la
     largeur) et vertical (18px = hauteur entière), ce qui ferme exactement
     le bas en arc de cercle plutôt qu'en ellipse partielle.
     "position: relative" posé ICI (et non compté sur un éventuel
     "&.section-bg-*" déjà positionné) : plusieurs sections l'utilisant
     ("section.services"/"&.section-bg-dark", "section.testimonials")
     n'ont position: relative nulle part ailleurs sur la SECTION
     elle-même — sans lui, le demi-cercle ("position: absolute") remontait
     jusqu'au containing block initial (aucun ancêtre positionné entre
     "body" et la section), et s'affichait donc au tout début du
     document, hors de vue, plutôt qu'en haut de sa propre section. Rendre
     la classe autonome (elle pose son propre contexte de positionnement)
     évite ce piège pour tout usage futur, plutôt que de compter sur
     chaque section pour l'avoir déjà. */
  &.section-transition-arrow {
    position: relative;

    &::before {
      content: '';
      position: absolute;
      top: 0;
      left: 50%;
      transform: translateX(-50%);
      width: 36px;
      height: 18px;
      border-radius: 0 0 18px 18px;
      z-index: 1;
    }

    /* Manquant jusqu'ici : "section.stats" (badges) suit "section.about",
       fond identique ("section-bg-brand-soft") — un demi-cercle
       "--brand-soft" s'y fondrait totalement. "--brand" (menthe pleine)
       sert ici d'accent volontaire entre deux sections de même couleur,
       plutôt que de représenter littéralement le fond de la section
       précédente. Sans ce modificateur, ".section-transition-arrow--brand"
       ne posait aucune couleur de fond, donc aucun demi-cercle visible du
       tout, malgré la classe correctement posée dans le HTML. */
    &.section-transition-arrow--brand {
      &::before {
        background-color: var(--color-brand);
      }
    }

    &.section-transition-arrow--brand-soft {
      &::before {
        background-color: var(--color-brand-soft);
      }
    }

    &.section-transition-arrow--white {
      &::before {
        background-color: var(--color-white);
      }
    }

    &.section-transition-arrow--dark {
      &::before {
        background-color: var(--color-black);
      }
    }
  }

  /* Cercle décoratif : un par section, toujours découpé par le
     "overflow: hidden" de sa section (voir plus haut) — jamais de
     débordement hors de sa propre section. Ciblé par une classe dédiée à
     chaque coin ("decor-tl/tr/bl/br", posée dans le HTML) plutôt que par
     ":nth-of-type" : la position d'une section dans le DOM peut changer
     (".article-extras" notamment) sans que cela ne doive jamais affecter
     QUEL coin revient à QUELLE section — un sélecteur purement positionnel
     comme ":nth-of-type" se serait décalé à chaque réordonnancement.
     Mobile d'abord : rond à 220px, agrandi à 300px à partir de 640px (voir
     le "@media" juste en dessous, imbriqué directement dans "@scope" en
     référençant chaque sélecteur complet — nester le "@media" à
     l'intérieur du bloc "::after" lui-même ne surchargeait pas fiablement
     la taille de base dans ce moteur de rendu). */
  &.decor-tl::after,
  &.decor-tr::after,
  &.decor-bl::after,
  &.decor-br::after {
    content: '';
    position: absolute;
    z-index: 0;
    border-radius: 50%;
    width: 220px;
    height: 220px;
  }

  @media (min-width: 640px) {

    &.decor-tl::after,
    &.decor-tr::after,
    &.decor-bl::after,
    &.decor-br::after {
      width: 300px;
      height: 300px;
    }
  }

  /* Coin haut-gauche : décalage vertical ("top") de -50px (au lieu du
     rayon complet, -90px, utilisé en horizontal) — le cercle remonte
     moins haut au-dessus de la section, réduisant d'autant son
     empiètement dans le texte qui précède (l'espace entre sections,
     "margin-top: var(--space-20)" plus haut, reste lui fixe). */
  &.decor-tl::after {
    top: -50px;
    left: -90px;
    background: var(--color-brand);
  }

  /* Coin haut-droit. */
  &.decor-tr::after {
    top: -50px;
    right: -90px;
    background: var(--color-brand);
  }

  /* Coin haut-gauche (variante de teinte, 2e/4e section "decor-bl" d'une
     série de 4) — tous les cercles de la page sont en haut de leur
     section. */
  &.decor-bl::after {
    top: -50px;
    left: -90px;
    background: var(--color-brand);
  }

  /* Coin haut-droit (variante de teinte). */
  &.decor-br::after {
    top: -50px;
    right: -90px;
    background: var(--color-brand);
  }

  /* Variantes de masque du filigrane ".decor-mountain" : ".decor-collectif",
     ".decor-echange" et ".decor-mouvement" reprennent EXACTEMENT le même
     modèle (mêmes couleur, opacité, animation "reveal"/"is-visible",
     positionnement de coin "decor-tl/tr/bl/br" hérité) — seul le masque
     change : le "A" du logo ("logo-brand-a.svg") est remplacé par l'un des
     3 pictos de la famille du signe (voir CLAUDE.md, « Pictos dérivés »).
     Le bloc ci-dessous est donc partagé via ":is()" plutôt que dupliqué ;
     la surcharge du masque de chaque variante suit "&&::after" plus bas. */
  &:is(.decor-mountain, .decor-collectif, .decor-echange, .decor-mouvement) {

    /* Variante "montagne" du cercle décoratif : le "A" du logo Coaxia RH
     (chevron + point, symbolique d'une montagne à gravir pour relever les
     enjeux RH — voir CLAUDE.md, section « Symbole visuel ») remplace le
     rond de couleur uni. Posé sur CHAQUE section "decor-tl/tr/bl/br" des
     pages de service (facilitation.php, conseil.php, coaching.php,
     formation.php, conseillere-rh.php) depuis sa généralisation — à
     l'origine limité à la seule 1ère section de facilitation.php ("un
     clin d'œil visuel dans une section clé", CLAUDE.md), il apparaît
     aujourd'hui 3 à 7 fois par page selon la page (l'ancien commentaire
     ici, "cette section clé (première question posée par la page)",
     décrivait cet état d'origine et n'avait jamais été mis à jour après
     la généralisation — corrigé). Se pose EN PLUS d'un
     "decor-tl/tr/bl/br" existant dans le HTML (garde son positionnement de
     coin et sa taille responsive, hérités des règles ci-dessus) : cette
     classe ne redéfinit que l'apparence et l'animation d'entrée du
     "::after" — même spécificité que les règles de couleur ci-dessus,
     donc l'ordre (après elles) suffit à les surclasser. Couleur en pleine
     opacité (voir "&&::after" plus bas) alors que CLAUDE.md prescrit un
     usage "discret, à faible opacité" pour ce motif en fond de bloc —
     écart relevé par l'audit de satisfaction client
     (.kiweb/mockup/rh/.audit/localhost/, écart majeur), pas encore
     corrigé à ce jour. */

    /* Le "A" doit s'animer au SCROLL (pas au chargement de la page) : la
       classe "reveal", posée sur cette section dans le HTML, la fait
       observer par l'IntersectionObserver déjà utilisé site-wide (voir
       "base.js"), qui ajoute "is-visible" une fois la section visible à
       l'écran. Problème : "reveal" applique aussi, par défaut
       (".coax-js .reveal"), un fondu+décalage à TOUT ce qui la porte — ici,
       le CONTENU RÉEL de la section (h2/p), pas seulement le "::after".
       Neutralisé ci-dessous : le texte reste toujours visible, seul le "A"
       réagit au scroll. */
    &.reveal {
      opacity: 1;
      transform: none;
    }

    &&::after {
      /* Opacité faible (0.36, même valeur que les halos décoratifs de
         "&.section-bg-dark-gradient" plus haut dans ce fichier — motif de
         fond de bloc déjà "discret" au sens de CLAUDE.md) : le "A" reste un
         repère visuel en filigrane plutôt qu'une forme pleinement saturée
         qui rivaliserait avec le contenu réel de la section. Posée ici (la
         règle de base) plutôt que seulement sur l'état "is-visible"
         ci-dessous : sans JS actif (pas de ".coax-js", ex. canevas éditeur),
         ni "opacity: 0" ni "is-visible" ne s'appliquent jamais — c'est
         cette valeur de base qui est alors seule à s'afficher. */
      opacity: 0.36;

      /* 1. On applique la couleur exacte souhaitée en fond — "--color-
         brand-light" (teinte très pâle dédiée aux filigranes, voir sa
         définition) et non "--color-brand-soft" (désormais un fond plein
         nettement plus saturé, #93CDB7, qui rendrait ce filigrane bien
         trop présent/saturé à 36% d'opacité). */
      background-color: var(--color-brand-light);

      /* 2. On utilise le SVG comme un masque de découpe */
      -webkit-mask: url('../img/logo-brand-a.svg') no-repeat center / contain;
      mask: url('../img/logo-brand-a.svg') no-repeat center / contain;
      background-size: contain;
      border-radius: 0;
      transition: opacity 900ms var(--ease-refined), transform 900ms var(--ease-refined);
    }

    /* Masque propre à chaque variante — "&&&" (3 fois le sélecteur parent)
       pour battre la spécificité de "&&::after" ci-dessus (voir le
       commentaire de "decor-mountain--photo" plus bas : chaque "&" reprend
       le sélecteur PARENT ENTIER, y compris son type "section"). */
    &&&.decor-collectif::after {
      -webkit-mask: url('../img/picto-collectif.svg') no-repeat center / contain;
      mask: url('../img/picto-collectif.svg') no-repeat center / contain;
    }

    &&&.decor-echange::after {
      -webkit-mask: url('../img/picto-echange.svg') no-repeat center / contain;
      mask: url('../img/picto-echange.svg') no-repeat center / contain;
    }

    &&&.decor-mouvement::after {
      -webkit-mask: url('../img/04-point.svg') no-repeat center / contain;
      mask: url('../img/04-point.svg') no-repeat center / contain;
    }

    /* &&&.decor-mouvement::after {
      -webkit-mask: url('../img/picto-mouvement.svg') no-repeat center / contain;
      mask: url('../img/picto-mouvement.svg') no-repeat center / contain;
    } */

    /* Modificateur "decor-mountain--photo" : remplace le masque "A" par une
       photo/logo en fond (ex. section MANAHOP, formation2.php) — jamais le
       "A" ET une photo en même temps sur la même section. Une photo n'a
       pas de canal alpha exploitable par "mask" (contrairement au SVG "A"
       ci-dessus) : on repasse donc par un simple "background-image", avec
       le rond plein d'origine ("border-radius: 50%") plutôt que le
       contour du "A". Cette règle ne fixe QUE ce comportement structurel,
       commun à toute section adoptant ce modificateur — jamais l'URL de
       l'image elle-même (propre à CHAQUE section, déclarée à part, voir
       plus bas dans ce fichier). Une propriété personnalisée type
       "--decor-photo" posée en style en ligne aurait semblé plus généri
       que/réutilisable, mais un "url()" qu'elle contiendrait se résout
       relativement à CE fichier CSS (où le "var()" est consommé), pas à
       la page HTML qui la déclare — un chemin relatif "media/..." écrit
       dans le HTML y pointerait donc au mauvais endroit
       ("assets/css/media/...", constaté à l'écran). "&&" (et non un seul
       "&") : la règle ci-dessus ("&&::after") a en réalité une
       spécificité plus élevée que sa simple lecture ne le suggère (chaque
       "&" reprend le sélecteur PARENT ENTIER, "section.decor-mountain" —
       la répéter deux fois compte aussi "section" deux fois) ; un seul
       "&" ici (constaté à l'écran : "mask"/"border-radius" restaient
       hérités de la règle "A") ne suffisait donc pas à l'égaler. */
    /* &&.decor-mountain--photo::after {
      background-color: var(--color-brand-soft);
      background-size: cover;
      background-position: center;
      mask: none;
      -webkit-mask: none;
      border-radius: 50%;
    } */

    /* Image spécifique à la section MANAHOP (formation2.php, seule section
       à porter "decor-mountain--photo" pour l'instant) — chemin relatif à
       CE fichier CSS ("assets/css/base.css"), pas à la page HTML qui
       déclare la section (voir le commentaire ci-dessus) : "../../"
       remonte de "assets/css/" à la racine du site, avant de redescendre
       dans "media/manahop/". Qualifié par "[aria-labelledby=manahop-
       title]" en plus de la classe (déjà unique à cette section à ce
       jour) uniquement pour rendre explicite, à la lecture, à QUELLE
       section précise cette image appartient. */
    /* &.decor-mountain--photo[aria-labelledby="manahop-title"]::after {
      background-image: url('../../media/manahop/logo-manahop.jpg');
    } */

    /* État initial caché — gated par ".coax-js" (comme ".coax-js .reveal"
       ailleurs) : sans JS (ou dans le canevas éditeur), le "A" reste visible
       d'emblée plutôt que caché indéfiniment (jamais de "is-visible" sans
       IntersectionObserver actif). */
    .coax-js &::after {
      opacity: 0;
      transform: translateY(40px);
    }

    /* Ajoutée par le JS une fois la section entrée dans le viewport — même
       spécificité que la règle ci-dessus (1 classe + 1 pseudo-élément
       chacune) : doit rester déclarée APRÈS elle pour l'emporter une fois
       les deux présentes (".coax-js" ET "is-visible" simultanément).
       "opacity: 0.36" (pas 1) : l'état révélé reste le motif discret défini
       sur "&&::after" plus haut — l'animation ne fait qu'apparaître/
       disparaître ce même filigrane, jamais une forme pleinement saturée. */
    &.is-visible::after {
      opacity: 0.36;
      transform: translateY(0);
    }

    @media (prefers-reduced-motion: reduce) {
      .coax-js &::after {
        opacity: 0.36;
        transform: translateY(0);
      }
    }

    @media (min-width: 768px) {

      &:is(.decor-tl)> :not(h2),
      &:is(.decor-tr)> :not(h2),
      &:is(.decor-bl)> :not(h2),
      &:is(.decor-br)> :not(h2) {
        max-width: inherit;
        margin-left: inherit;
        margin-right: inherit;
      }
    }
  }

  /* En vue large (≥768px), le contenu de chaque section "decor-*" (tout
     SAUF le h2, qui reste pleine largeur) est limité en largeur et décalé
     à l'opposé du cercle décoratif de sa section, pour ne jamais s'étendre
     jusque sous lui : "max-width" + une marge automatique du côté du
     cercle pour pousser le contenu de l'autre côté : "margin-left: auto"
     (pousse à droite) pour les cercles à gauche ("decor-tl"/"decor-bl"),
     "margin-right: auto" (pousse à gauche) pour les cercles à droite
     ("decor-tr"/"decor-br"). L'empiètement du carré englobant le cercle
     sur la zone de contenu est de 210px (300px de diamètre en vue large,
     dont 90px seulement débordent hors de la section — voir
     "top/left/right" des ".decor-*::after" ci-dessus) ; la marge retenue
     ici (195px) est plus étroite, le contenu gagnant donc 15px de largeur
     — sans risque de collision visuelle : le cercle est ROND, pas carré,
     et son emprise réelle près de ce coin (l'angle du carré englobant,
     hors du disque lui-même) reste vide. Valeur choisie par mesure directe
     (point du contenu le plus proche du centre du cercle vs son rayon) sur
     les 4 pages de service et leurs 16 sections "decor-*" — 210px laissait
     ~9px de marge non exploitée ; en dessous de 195px, au moins une
     section (titre `h2` tenant sur une seule ligne, donc paragraphe
     suivant plus proche du centre du cercle) entre en collision. */
  @media (min-width: 768px) {

    &.decor-tl> :not(h2),
    &.decor-bl> :not(h2) {
      max-width: calc(100% - 195px);
      margin-left: auto;
      margin-right: 0;
    }

    &.decor-tr> :not(h2),
    &.decor-br> :not(h2) {
      max-width: calc(100% - 195px);
      margin-left: 0;
      margin-right: auto;
    }
  }

  /* Titre aligné à droite pour les sections dont le cercle est côté droit
     ("decor-tr"/"decor-br") — cohérent avec le cercle qui déborde de ce
     même côté. */
  &.decor-tr h2,
  &.decor-br h2 {
    text-align: right;
  }
}

.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;
}

/**
 * Shared patterns
 */

/* Higlighted label */
h1.label,
h2.label,
p.label,
li.label {
  display: inline-block;
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--color-brand);
  margin-bottom: var(--space-3);
}

/* 2-column section grids */
.grid-2c {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4);

  @media (min-width: 640px) {
    & {
      gap: var(--space-8);
    }
  }

  @media (min-width: 640px) {
    & {
      grid-template-columns: repeat(2, 1fr);
    }
  }
}

/* 3-column section grids */
.grid-3c {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4);

  @media (min-width: 640px) {
    & {
      gap: var(--space-8);
    }
  }

  @media (min-width: 640px) {
    & {
      grid-template-columns: repeat(2, 1fr);
    }
  }

  @media (min-width: 1024px) {
    & {
      grid-template-columns: repeat(3, 1fr);
    }
  }
}

/* 4-column section grids */
/* Stretched link: makes a whole .card clickable via a single invisible <a>
   overlaying it, without nesting an <a> inside another (see card/title-text-cta.php:
   only rendered when $href is passed without $linkLabel, i.e. no visible button already) */
.card-link-overlay {
  position: absolute;
  inset: 0;
  z-index: 1;
}

.grid-4c {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4);

  @media (min-width: 640px) {
    & {
      gap: var(--space-8);
    }
  }

  @media (min-width: 640px) {
    & {
      grid-template-columns: repeat(2, 1fr);
    }
  }

  @media (min-width: 1024px) {
    & {
      grid-template-columns: repeat(4, minmax(0, 1fr));
    }
  }
}

.grid-5c {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4);

  @media (min-width: 640px) {
    & {
      grid-template-columns: repeat(3, minmax(0, 1fr));
    }
  }

  @media (min-width: 1024px) {
    & {
      grid-template-columns: repeat(5, minmax(0, 1fr));
    }
  }
}

/* Flexbox with columns and a specific space between */
.flex-col-8gp {
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
}

/* 2 columuns-grid with an aside and an article */
.aside-article-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 60px;
  align-items: center;

  @media (min-width: 768px) {
    & {
      grid-template-columns: 0.85fr 1fr;
    }
  }
}

/* Badge circulaire réutilisable (component "block/badges.php") — <ul
   class="badges">, avec ses items ".badge" (rond blanc, ombre portée,
   <strong>/<span>, ou une <img> à la place pour un logo). Mobile first,
   3 paliers : 1 colonne < 640px, 2 colonnes 640-1023px, 1 seule ligne (4
   colonnes égales) à partir de 1024px — ce socle commun s'applique à tout
   usage de ".badges" (hero de la page d'accueil, grilles de notation/
   certification des pages internes...). Le hero de la page d'accueil y
   ajoute ses propres particularités (chevauchement du bord de section,
   dernière colonne élargie pour le 4ème item — voir "section.hero &
   .badges" plus haut dans ce fichier), qui ne s'appliquent JAMAIS à un
   usage autonome de cette classe. */
ul.badges {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  justify-items: center;
  gap: 16px;
  padding: 0;
  /* Reset explicite nécessaire : plus spécifique qu'un simple "ul.badges"
     (tag + 1 classe), la règle générique de puces du contenu éditorial
     ("section.page-content article ul:not(.values-grid)") pose un
     "padding-left: var(--space-6)" qui s'appliquerait sinon à un usage
     autonome de ".badges" niché dans cet article (ex. grilles de
     notation des pages internes) — un "<ul>" reste un "<ul>" pour cette
     règle, quelle que soit sa propre classe. */

  /* RÈGLE PAR DÉFAUT — MONO-LIGNE dès 640px : quel que soit le nombre
     d'items, ils restent sur UNE seule ligne ("grid-auto-flow: column"),
     chaque colonne valant au plus 200px (taille "au repos" d'un
     ".badge") et rétrécissant à parts égales quand la place manque
     ("minmax(0, 200px)") — le rond suit la colonne ("max-width: 100%" +
     "aspect-ratio: 1"). Grille plutôt que flex : cela n'interfère pas avec
     les usages qui posent leur propre "display: flex" sur ce même
     ".badges" (pied de page). En dessous de 640px : une colonne.
     Exceptions documentées : "section.stats" (page d'accueil, mono-ligne
     seulement dès 1024px à cause du 4ème item, très long) — voir plus bas. */
  /* TAILLE DU CONTENU DES ".badge" — harmonisée au sein d'un même
     "ul.badges" : tout ce qui est dans un rond (chiffre, libellé,
     marges) est proportionnel à SON DIAMÈTRE, "--badge-d" (200px "au
     repos", rétréci avec la largeur du <ul>). "--badge-d" est calculé
     PAR LE <ul>, pas par chaque item : tous les items d'une même liste
     lisent la même formule et obtiennent donc exactement la même taille
     de contenu — y compris un item "badge--wide", dont la largeur (donc
     un "cqw" propre) diffère de celle des ronds.
     - ".badges" est un conteneur de taille ("container-type: inline-size",
       uniquement quand il contient des ".badge" : le <ul> du pied de page,
       lui, est un item flex sans largeur propre — la containment le
       ferait tomber à 0) ; les "cqw" de ses items se rapportent à lui.
     - "--badge-cols" = nombre de colonnes (fractionnaires possibles) et
       "--badge-gaps" = nombre d'espaces entre elles, pour la mise en page
       mono-ligne par défaut (voir plus bas) : un item par colonne, "cols"
       = "gaps + 1" = nombre d'items (2 à 6, comptés par ":has()") ;
       "--badge-gap" = largeur d'un espace. Une exception de mise en page
       (ex. "section.stats") redéfinit simplement ces 3 variables. */
  &:has(> .badge) {
    container-type: inline-size;
    --badge-cols: 4;
    --badge-gaps: 3;
    --badge-gap: var(--space-5);

    &:has(> .badge:nth-child(2):last-child) {
      --badge-cols: 2;
      --badge-gaps: 1;
    }

    &:has(> .badge:nth-child(3):last-child) {
      --badge-cols: 3;
      --badge-gaps: 2;
    }

    &:has(> .badge:nth-child(5):last-child) {
      --badge-cols: 5;
      --badge-gaps: 4;
    }

    &:has(> .badge:nth-child(6):last-child) {
      --badge-cols: 6;
      --badge-gaps: 5;
    }
  }

  @media (min-width: 1024px) {
    &:has(> .badge) {
      --badge-gap: var(--space-8);
    }
  }

  @media (min-width: 640px) {
    & {
      grid-template-columns: none;
      grid-auto-flow: column;
      grid-auto-columns: minmax(0, 200px);
      justify-content: center;
      gap: var(--space-5);
    }
  }

  @media (min-width: 1024px) {
    & {
      gap: var(--space-5) var(--space-8);
    }
  }

  & .badge {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    text-align: center;
    min-width: 0;
    width: 200px;
    max-width: 100%;
    aspect-ratio: 1;
    border-radius: 50%;
    background: var(--color-white);
    box-shadow: var(--shadow-lg);

    /* Diamètre du rond : 200px au plus, sinon la largeur d'une colonne
       (mobile : 1 colonne = toute la largeur du <ul>). Coefficients
       calqués sur la mise en page "au repos" (200px) : padding 16px =
       0,08 ; espace 10px = 0,05 ; "--text-xl" 35px = 0,175 ; "--text-md"
       18px = 0,09. Plancher de police pour rester lisible. */
    --badge-d: min(200px, calc(100cqw * var(--badge-k, 1)));
    padding: calc(var(--badge-d) * 0.08);
    gap: calc(var(--badge-d) * 0.05);

    @media (min-width: 640px) {
      & {
        --badge-d: min(200px, calc((100cqw - var(--badge-gaps) * var(--badge-gap)) / var(--badge-cols) * var(--badge-k, 1)));
      }
    }

    & strong {
      font-weight: 600;
      color: var(--color-brand);
      font-size: max(14px, calc(var(--badge-d) * 0.175));
    }

    & span:not(.digit) {
      font-size: max(11px, calc(var(--badge-d) * 0.09));
      line-height: 1.3;
      /* Replie sur plusieurs lignes plutôt que nowrap : un libellé long ne
         tiendrait pas sur une seule ligne dans le rond. Pas de "color"
         explicite (volontaire, ne pas en ajouter ici) : ".digit" (voir
         plus bas) est imbriqué dans "& strong" ci-dessus, pas dans ce
         "<span>" — poser une couleur ici n'aurait de toute façon aucun
         effet sur ".digit", et priverait ce libellé de l'héritage neutre
         (texte noir du "body") actuellement voulu. */
    }

    /* Variante "logo" (ex. Qualiopi) : <img> à la place de <strong>/<span>,
       dans le même rond. <img> nu côté maquette ; <figure class="wp-block-
       image"> côté thème WordPress (bloc natif core/image, remplaçable
       depuis wp-admin) — même traitement visuel sur les deux structures. */
    & img,
    & figure.wp-block-image {
      width: 100%;
      height: 100%;
    }

    & figure.wp-block-image img,
    & img {
      object-fit: contain;
    }
  }

  /* Modificateur explicite (posé via la prop "class" d'un item, "block/
     badges.php") pour un item dont le contenu ne tient pas dans un rond à
     la même taille que ses voisins — texte trop long (ex. "RNCP · PCM® ·
     Codéveloppement") ou logo au ratio large plutôt que carré (ex. le
     logo Qualiopi, 487×170 — deux lignes de texte ajoutées sous le sceau
     dans sa version actuelle, qualiopi.png, le rendant nettement moins
     carré que l'ancien qualiopi.webp) — posés tous deux directement dans
     index.php : un RECTANGLE aux coins arrondis à la place du rond —
     plutôt qu'un ancien "&:last-child" structurel (dépendait de la
     POSITION de l'item dans le DOM, pas de son contenu), qui aurait à
     tort transformé le dernier item de N'IMPORTE quelle liste ".badges"
     en rectangle, même quand tous ses items sont des ronds ordinaires
     (ex. les grilles de notation des pages internes, formation2.php). */
  & .badge--wide {
    aspect-ratio: auto;
    width: 460px;
    max-width: 100%;
    padding: calc(var(--badge-d) * 0.06) calc(var(--badge-d) * 0.1);
    border-radius: 24px;

    /* En dessous de 1024px (grille à 2 colonnes ou 1 colonne), sa colonne
       fait 1fr comme celle des autres items — "aspect-ratio: auto" (sa
       hauteur suit son propre contenu) est donc correct à ce palier,
       aucune ligne unique à aligner. */
    @media (min-width: 1024px) {
      & {
        aspect-ratio: 1.8;
        max-height: 200px;
        overflow: hidden;
        /* "aspect-ratio: 1.8" : à ce palier, les ronds voisins (grille à
           colonnes égales, "1fr" chacune) rétrécissent en hauteur en
           suivant leur propre "aspect-ratio: 1" ; ce ratio fait retomber
           la hauteur de CET item sur cette même largeur de colonne,
           l'alignant sur celle des ronds à n'importe quel degré de
           pincement — un "height: 100%" ne fonctionne pas ici (la hauteur
           de la ligne de grille, en mode "auto", dépend elle-même du
           contenu de ses cellules : dépendance circulaire résolue par le
           navigateur en ignorant le pourcentage). "overflow: hidden"
           tronque proprement le texte si jamais il ne tenait pas dans la
           hauteur ainsi obtenue, plutôt que de déborder visuellement.
           "max-height: 200px" : au-delà du pincement, les ronds
           eux-mêmes sont plafonnés à leur taille "au repos" (200px,
           "width: 200px" hérité de ".badge") et ne grandissent plus, alors
           que cet item continuerait de s'agrandir en hauteur
           (proportionnellement à sa propre largeur, jusqu'à son propre
           plafond "width: 460px") sans ce même plafond — recréant un
           écart de hauteur, cette fois une fois le pincement dépassé. */
      }
    }

    & strong {
      line-height: 1.2;
      /* Resserré (par défaut, hérité du "body", 1.6 — pensé pour du texte
         de paragraphe, pas un intitulé court sur 2 lignes) : fait gagner
         la marge verticale nécessaire pour tenir dans les 200px de
         hauteur commune aux autres items. */
    }
  }

  /* Compteur animé (voir "@property --num"/"@keyframes digit-count-up",
     section Animations) : ".digit" affiche un nombre qui s'incrémente de
     0 jusqu'à "--num-target", posé en style en ligne par "block/
     badges.php" (prop "counterTarget" de l'item) — réutilisable pour
     N'IMPORTE quel item de N'IMPORTE quelle liste ".badges", plutôt que
     codé en dur par position ("li:first-child"/"li:nth-child(2)",
     ancienne version spécifique aux 2 premiers items du hero). Le
     "::before" (même couleur/police héritées de ".badge" ci-dessus)
     affiche la valeur qui s'incrémente, positionné en superposition
     EXACTE du texte réel ("position: absolute; inset: 0" dans un ".digit"
     qui l'encadre en "position: relative") plutôt qu'à sa place : le
     texte réel reste normalement visible et accessible aux lecteurs
     d'écran d'un bout à l'autre (jamais masqué via "visibility"/
     "display"), simplement recouvert par le fond blanc du "::before"
     pendant le comptage, qui disparaît d'un coup une fois l'animation
     terminée pour le révéler — sans saut visuel puisque les deux
     affichent alors la même valeur. Nécessite "counterTarget" (entier)
     sur l'item : sans lui, "--num-target" reste indéfini et le "::before"
     affiche "0" jusqu'à la disparition de l'overlay — un item numérique
     sans "counterTarget" (ex. les scores décimaux de formation2.php, non
     pris en charge par ce mécanisme entier) ne doit donc PAS porter la
     classe ".digit", au risque de ce même défaut visuel. */
  & .digit {
    position: relative;
    display: inline-block;
    color: inherit;

    &::before {
      content: counter(num);
      counter-reset: num var(--num);
      --num: var(--num-target, 0);
      position: absolute;
      inset: 0;
      background: var(--color-white);
      animation:
        digit-count-up 1.8s var(--ease-refined) both,
        digit-count-hide 0s linear 1.8s forwards;
    }
  }

  @media (prefers-reduced-motion: reduce) {
    & .digit::before {
      animation: none;
      visibility: hidden;
      /* Révèle directement le texte réel (déjà la bonne valeur, jamais
         masqué — voir commentaire ci-dessus), sans décompte. */
    }
  }

  /* Items sans compteur (logo, texte) : entrée en fondu depuis la gauche
     ("fade-left", section Animations) plutôt que le compteur des items
     numériques — pertinent uniquement pour un item en 3ème/4ème
     position. Délai du 4ème légèrement supérieur à celui du 3ème : les
     deux entrées se succèdent alors de la gauche vers la droite, dans
     l'ordre où les items sont disposés dans la grille. */
  & li:nth-child(3) {
    animation: fade-left 600ms var(--ease-refined) 200ms both;
  }

  & li:nth-child(4) {
    animation: fade-left 600ms var(--ease-refined) 350ms both;
  }

  @media (prefers-reduced-motion: reduce) {

    & li:nth-child(3),
    & li:nth-child(4) {
      animation: none;
    }
  }
}

/* "Démarche qualité" : les indicateurs-clés (taux de présence, abandons,
   satisfaction) — component "block/stat-lines.php", <ul class="stat-
   lines"><li class="stat-line">. Mobile d'abord : empilés en 1 colonne ;
   côte à côte dès 768px. "ul.stat-lines" est elle-même le conteneur flex
   ("gap" natif entre chaque "<li>", plus besoin du bricolage "margin-
   right"/"margin-bottom" d'une ancienne version à base de <p> frères
   indépendants) — et, étant un vrai élément de niveau bloc (contrairement
   à ces anciens <p> en "inline-flex", immunisés contre "margin: auto"),
   elle bénéficie nativement de la règle générique "section.page-content
   article>section.decor-*> :not(h2)" (plus haut dans ce fichier) pour
   s'écarter du cercle décoratif de sa section, quel que soit le coin
   ("margin-left"/"margin-right: auto" selon "decor-tl/tr/bl/br") — plus
   besoin de dupliquer une valeur fixe ("margin-left: 195px") ici, qui
   assumait à tort un cercle à GAUCHE quelle que soit la section
   utilisatrice (correct pour "decor-tl"/"decor-bl", faux dans une section
   "decor-br"/"decor-tr" — un vrai écart resté invisible tant que le
   "inline-flex" d'origine ignorait de toute façon "margin: auto"). */
ul.stat-lines {
  & .stat-line {
    position: relative;
    display: block;
    width: 100%;
    border: 1px solid var(--color-brand);
    border-radius: var(--radius-md);
    /* "overflow: hidden" : rogne les coins carrés du "::before" (ci-dessous,
       plaqué contre le bord du "<li>") sur le "border-radius" du chip —
       sans lui, ce pseudo-élément dépasserait visuellement des coins
       arrondis. "padding-left" réserve la place de ce "::before" (36px de
       large) + son espacement avec le texte ("--space-3") : le contenu
       réel (texte, "<strong>") suit ensuite le flux normal du bloc, sans
       flexbox — il retourne à la ligne de lui-même si trop long, comme un
       paragraphe ordinaire. */
    overflow: hidden;
    padding: var(--space-2) var(--space-4) var(--space-2) calc(36px + var(--space-3));

    /* Coche blanche sur fond "--color-brand", en URI de données (voir
       "icon/check.php" pour la forme source) : un "::before" plutôt qu'un
       élément du balisage (pas de <span>/<svg> dans "block/stat-lines.
       php"). "position: absolute" avec "top"/"bottom" à 0 (et non "height:
       100%", qui dépendrait circulairement de la hauteur intrinsèque du
       "<li>") donne la hauteur COMPLÈTE du chip, bord à bord, quel que
       soit son contenu — et reste "sur la même ligne" que le texte
       puisqu'il se cale sur le bord gauche pendant que le
       "padding-left" ci-dessus réserve exactement sa largeur, sans jamais
       le chevaucher. */
    &::before {
      content: '';
      position: absolute;
      top: 0;
      bottom: 0;
      left: 0;
      width: 36px;
      background-color: var(--color-brand);
      background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3'%3E%3Cpolyline points='4 12 9 17 20 6'/%3E%3C/svg%3E");
      background-repeat: no-repeat;
      background-position: center;
      background-size: 14px;
    }

    & strong {
      font-family: var(--font-heading);
      color: var(--color-brand);
    }
  }
}

/* Card base */
.card {
  border: 1px solid var(--color-gray-soft);
  border-radius: var(--radius-md);
  transition: all var(--transition);

  &:hover {
    box-shadow: var(--shadow-md);
  }

  /* Icon */
  & .icon {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    border-radius: 12px;
    background-color: var(--color-brand);
    color: var(--color-white);
    margin-bottom: 18px;
  }

  /* Section card titles */
  & h3 {
    font-size: var(--text-base);
    font-weight: 600;
    color: var(--color-black);
    margin-bottom: var(--space-3);
  }

  /* Card body text */
  .text {
    color: var(--color-gray);
    font-size: var(--text-sm);
    line-height: 1.55;

    & ul {
      display: flex;
      flex-direction: column;
      gap: 12px;
      margin-bottom: 28px;
      list-style: none;

      & li {
        position: relative;
        padding-left: 24px;
        color: var(--color-gray);
        line-height: 1.5;

        &::before {
          content: "→";
          position: absolute;
          left: 0;
          top: 0;
          color: var(--color-brand);
          font-weight: 600;
        }
      }
    }
  }

  /* Card links (card/news.php's single <a class="link">, not the <nav> below) */
  .link {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-weight: 600;
    color: var(--color-brand);
  }

  /* Card links — one or more, card/title-text-cta.php's <nav><ul><li><a> */
  & nav {
    & ul {
      display: flex;
      flex-wrap: wrap;
      gap: var(--space-4);
      list-style: none;
    }

    & a {
      display: inline-flex;
      align-items: center;
      gap: var(--space-2);
      font-size: var(--text-sm);
      font-weight: 600;
      color: var(--color-brand);
    }
  }
}

address {
  font-style: normal;
}

/**
 * Buttons
 * Design aligné sur la maquette leadcraft (styles.css §Buttons).
 * Variables leadcraft résolues vers tokens rh :
 *   --brand               → --color-brand
 *   --black (#231F20)     → --color-black
 *   --white (#FFFFFF)     → --color-white
 *   --radius-pill (999px) → --radius-full
 *   --ease                → cubic-bezier(.2,.7,.2,1) (valeur directe, pas de token rh équivalent)
 */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 12px 20px;
  border-radius: var(--radius-full);
  font-family: var(--font-body);
  font-size: var(--text-md);
  letter-spacing: -0.005em;
  border: 1.5px solid transparent;
  white-space: normal;
  /* Mobile first : autorise le retour à la ligne sous 480px. Un bouton
     pleine largeur ("width: 100%" à ces tailles) au libellé long (ex.
     "Découvrir les accompagnements") passait en "nowrap" à toutes les
     tailles, imposant un plancher de largeur qu'aucun bouton ne pouvait
     descendre en dessous — remontant jusqu'à provoquer un débordement
     horizontal de la page entière sur les plus petits écrans (~320px). */
  text-align: center;
  text-decoration: none;
  transition: transform .25s cubic-bezier(.2, .7, .2, 1),
    background .25s cubic-bezier(.2, .7, .2, 1),
    color .25s cubic-bezier(.2, .7, .2, 1),
    box-shadow .25s cubic-bezier(.2, .7, .2, 1);

  @media (min-width: 480px) {
    & {
      white-space: nowrap;
      /* À partir d'ici, les boutons ne sont plus forcément pleine largeur
         (voir leurs usages) et disposent de assez de place : revient au
         confort visuel d'un libellé sur une seule ligne. */
    }
  }

  &.btn-brand {
    background-color: var(--color-brand);
    color: var(--color-white);

    &:hover {
      transform: translateY(-1px);
      box-shadow: 0 8px 22px rgba(56, 128, 107, .28);
    }
  }

  &.btn-brand-soft {
    background-color: var(--color-brand-soft);
    color: var(--color-white);

    &:hover {
      transform: translateY(-1px);
      box-shadow: 0 8px 22px rgba(56, 128, 107, .28);
    }
  }

  &.btn-brand-light {
    background-color: var(--color-brand-light);
    color: var(--color-white);

    &:hover {
      transform: translateY(-1px);
      box-shadow: 0 8px 22px rgba(56, 128, 107, .28);
    }
  }

  &.btn-black {
    background-color: var(--color-black);
    color: var(--color-white);

    &:hover {
      transform: translateY(-1px);
      box-shadow: 0 8px 22px rgba(56, 128, 107, .28);
    }
  }

  &.btn-white {
    background-color: var(--color-white);
    color: var(--color-brand);

    &:hover {
      transform: translateY(-1px);
      box-shadow: 0 8px 22px rgba(56, 128, 107, .28);
    }
  }

  &.btn-outline {
    background-color: transparent;
    color: var(--color-black);
    border-color: var(--color-black);

    &:hover {
      background-color: var(--color-black);
      color: var(--color-white);
    }
  }

  &.btn-outline-white {
    background-color: transparent;
    color: var(--color-white);
    border-color: var(--color-white);

    &:hover {
      color: var(--color-brand);
      border-color: var(--color-brand);
    }

    &.btn-hover-black {
      &:hover {
        color: var(--color-black);
        border-color: var(--color-black);
      }
    }
  }

  /**
   * Buttons — full-width on mobile
   */
  &.btn-lg {
    padding: 15px 26px;
    width: 100%;
    justify-content: center;
  }

  @media (min-width: 640px) {
    &.btn-lg {
      width: auto;
      justify-content: initial;
    }
  }

  &.btn-sm {
    padding: 0.5rem 1.25rem;
    font-size: var(--text-sm);
  }
}

/**
 * Header & navigation
 */
.site-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 1000;
  background-color: var(--color-white);
  transition: box-shadow var(--transition), background-color var(--transition);

  &.scrolled {
    box-shadow: var(--shadow-md);
  }

  & .container {
    padding: 0 var(--space-3);

    /* iPhone SE / smallest supported width and up: full container padding fits comfortably */
    @media (min-width: 375px) {
      & {
        padding: 0 var(--container-padding);
      }
    }
  }

  & .header-inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    height: var(--header-height);

    & .header-cta {
      margin-left: auto;
      margin-right: var(--space-2);
    }

    @media (min-width: 375px) {
      & {
        gap: var(--space-3);
      }

      & .header-cta {
        margin-right: var(--space-3);
      }
    }

    @media (min-width: 1024px) {
      & .header-cta {
        margin-left: 0;
        margin-right: 0;
      }
    }
  }
}

.logo {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  text-decoration: none;
  flex-shrink: 0;

  & .icon {
    --size: 32px;
    height: var(--size);

    & svg,
    & img {
      display: block;
      width: auto;
      height: var(--size);
      max-width: none;
    }

    @media (min-width: 375px) {
      & {
        --size: 38px;
      }
    }

    @media (min-width: 400px) {
      & {
        --size: 49px;
      }
    }
  }

  & h1 {
    display: flex;
    flex-direction: column;
    line-height: 1;

    & .brand {
      font-family: var(--font-body);
      font-weight: 300;
      color: var(--color-black);
      text-transform: lowercase;
      letter-spacing: 0.06em;

      @media (min-width: 400px) {
        & {
          font-size: var(--text-base);
        }
      }

      & .brand-highlight {
        color: var(--color-brand);
        font-weight: 400;
      }
    }

    & .tagline {
      display: none;
      margin-top: 5px;
      font-family: var(--font-body);
      font-size: var(--text-xs);
      font-weight: 500;
      color: var(--color-gray);
      text-transform: uppercase;
      letter-spacing: 0.32em;

      @media (min-width: 475px) {
        & {
          display: block;
        }
      }
    }
  }
}

/* Mobile: hide desktop nav, show CTA compact next to burger.
   Desktop (>= 1024px): show desktop nav, hide burger, reset CTA to full size. */
.main-nav {
  display: none;

  @media (min-width: 1024px) {
    & {
      display: flex;
    }
  }

  align-items: center;
  gap: var(--space-1);

  & ul {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    list-style: none;
  }

  & .nav-item {
    position: relative;

  }

  & .nav-link {
    display: block;
    position: relative;
    padding: var(--space-2) var(--space-3);
    font-size: var(--text-md);
    font-weight: 500;
    color: var(--color-gray);
    border-radius: var(--radius-sm);
    transition: color .2s var(--ease-refined);
    white-space: nowrap;

    /* Palier intermédiaire (1024-1439px) uniquement : resserre l'espace
       horizontal entre les liens ("var(--space-1)" au lieu de
       "var(--space-3)") pour que le menu tienne sans se compresser
       davantage sur les largeurs desktop les plus étroites — revient au
       padding standard dès 1440px, où la place ne manque plus. */
    @media (min-width: 1024px) and (max-width: 1439px) {
      & {
        font-size: var(--text-sm);
        padding: var(--space-2) var(--space-1);
      }
    }

    /* Signe — le point (hover + page active du menu, voir
       .kiweb/mockup/coaxia/CLAUDE.md) : puce ronde 6px centrée
       horizontalement, à la place du trait qui occupait auparavant ce
       "::after" — seule taille utilisée pour ce rôle du signe, quel que
       soit l'écran ("une seule taille par usage"). Repos : invisible
       (opacity 0) et décalée 6px au-dessus de sa position finale ;
       apparition : translation verticale du haut vers le bas jusqu'à
       "bottom: 0", pas un agrandissement ("scaleX") comme l'ancien trait. */
    &::after {
      content: "";
      position: absolute;
      left: 50%;
      bottom: 0;
      width: 6px;
      height: 6px;
      border-radius: 50%;
      background: var(--color-brand);
      opacity: 0;
      transform: translate(-50%, -6px);
      transition: transform .25s var(--ease-refined), opacity .25s var(--ease-refined);
    }

    &:hover,
    &.active {
      color: var(--color-brand);
      background-color: transparent;

      &::after {
        opacity: 1;
        transform: translate(-50%, 0);
      }
    }

  }

}

.header-cta {
  display: flex;
  flex-shrink: 0;

  & .btn {
    font-size: var(--text-md);
    padding: 6px 10px;

    @media (min-width: 375px) {
      & {
        padding: 8px 14px;
      }
    }

    @media (min-width: 1024px) {
      & {
        padding: 12px 20px;
      }
    }

    @media (min-width: 1024px) and (max-width: 1439px) {
      & {
        font-size: var(--text-sm);
      }
    }
  }
}

.burger-btn {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-sm);
  color: var(--color-black);
  transition: background-color var(--transition);

  &:hover {
    background-color: var(--color-white);
  }

  & .burger-icon,
  & .close-icon {
    position: absolute;
    transition: opacity .2s var(--ease-refined), transform .25s var(--ease-refined);
  }

  & .burger-icon {
    opacity: 1;
    transform: scale(1) rotate(0deg);
  }

  & .close-icon {
    opacity: 0;
    transform: scale(0.6) rotate(-45deg);
  }

  &[aria-expanded='true'] {
    & .burger-icon {
      opacity: 0;
      transform: scale(0.6) rotate(45deg);
    }

    & .close-icon {
      opacity: 1;
      transform: scale(1) rotate(0deg);
    }
  }

  @media (min-width: 1024px) {
    & {
      display: none;
    }
  }
}

.mobile-menu {
  display: none;
  flex-direction: column;
  gap: 4px;
  padding: 16px 24px 24px;
  border-top: 1px solid var(--color-gray-soft);
  background-color: var(--color-white);

  &:not([hidden]) {
    display: flex;
  }

  & ul {
    list-style: none;
  }

  & .mobile-nav-link {
    display: block;
    padding: 12px 4px;
    font-weight: 500;
    color: var(--color-black);
    border-bottom: 1px solid #EFEAE0;

    &:hover {
      color: var(--color-brand);
    }
  }

}

/**
 * Hero section — calque de lisibilité quand une photo de fond est posée
 * (image mise en avant WordPress — jamais le cas dans cette maquette) :
 * AUCUNE règle CSS ici, par conception. Le calque (teinte blanche
 * translucide, 60 %, calibrée par analyse réelle des photos de test puis
 * relevée trois fois sur demande explicite — voir
 * `coaxiarh-fse/CHANGELOG.md @ 1.1.38`) est fondu avec la photo dans la
 * MÊME déclaration `background-image` (`linear-gradient(teinte, teinte),
 * url(…)`), injectée en une fois côté WordPress
 * (`coaxiarh_hero_overlay_background()`) : `background-image` est une
 * propriété unique, une règle CSS posée ici serait entièrement REMPLACÉE
 * (jamais superposée) par cette injection, qui doit donc porter la teinte
 * elle-même. `--color-black` reste la couleur de texte du hero partout —
 * aucun changement de couleur de texte, seul le fond est concerné.
 */

/**
 * Hero section — simple pages (page-base)
 */
@scope (.page-base) {
  section.hero {
    background-image: none;
    background-color: var(--color-black);
    padding: var(--space-8) 0;

    &::before,
    &::after {
      display: none;
    }

    & h1 {
      color: var(--color-white);
      font-weight: 600;
      letter-spacing: -0.02em;
    }

    & .text {
      color: rgba(255, 255, 255, 0.7);
    }
  }

  /* Demi-cercle de connexion hero -> contenu : ce hero est un DÉGRADÉ (noir
     vers "#0E1614", 135deg), pas un aplat — le "--dark" générique (le noir
     de départ) jurerait avec la teinte réelle du dégradé au centre du bord
     bas, là où pend le demi-cercle. On reprend donc la couleur du dégradé à
     cet endroit (≈ 60 % du chemin, un peu moins en vue étroite) : 40 % de
     noir pour 60 % de "#0E1614". */
  & section.page-content.section-transition-arrow--dark::before {
    background-color: color-mix(in srgb, var(--color-black) 40%, #0E1614);
  }
}

/**
 * Hero section — contact page (page-contact)
 */
@scope (.page-contact) {
  section.hero {
    & .text {
      max-width: none;
    }
  }
}

/**
 * Hero section — blog listing page (page-blog)
 * Overrides the generic .hero .container gap (base.css:411, @media 640px+)
 */
@scope (.page-blog) {
  section {
    &.hero {
      & .container {

        h1,
        .text {
          margin: 0;
        }

        @media (min-width: 640px) {
          & {
            gap: var(--space-4);
          }
        }
      }
    }
  }
}

/**
 * Blog section header — homepage only (page-index)
 * section/blog.php is shared with every blog article page ("Articles sur le
 * même thème"), so this is scoped here rather than in the generic &.blog rule
 */
@scope (.page-index) {

  /* "section.pains" (« Le constat ») : "figure.blockquote" sortie du
     ".container" pour devenir un enfant DIRECT de la section, sur le
     modèle (chevauchement du bord inférieur) autrefois partagé avec
     "section.offers > figure.blockquote" de formation.php — cette dernière
     a depuis été déplacée dans une section d'article "article-extras"
     à part, ce modèle ne vit donc plus qu'ici.
     "position: relative" déjà porté par ".section-bg-brand" (classe
     posée sur ".pains") : pas besoin de le redéclarer ici. */
  & section.pains {
    &>figure.blockquote {
      /* "z-index: 2" : ne sert ici qu'à garantir que la citation reste
         TOUJOURS peinte au-dessus du fond/contenu de "section.services"
         qui la chevauche juste en dessous — cette dernière n'a pas de
         cercle décoratif "z-index: 1" comme les sections "page-content"
         (même principe : la section suivante porte des "z-index" propres). */
      z-index: 2;
      /* Même largeur que ".grid-4c" (formule complète de ".container",
         pas seulement sa soustraction de padding). */
      width: calc(100% - 2 * var(--container-padding));
      max-width: calc(var(--container-max) - 2 * var(--container-padding));
      /* Centrage horizontal en flux normal ("margin-left/right: auto") ;
         "margin-top: G" (espace ".grid-4c" → figure, homogène avec le
         padding supérieur de la section) et "margin-bottom: -2G"
         (chevauchement du bord inférieur de ".pains", donc de "section.
         services" qui suit immédiatement) — mêmes valeurs que
         ".section-padding" (haut = bas = G), pour un chevauchement de
         même ampleur que le "gap" au-dessus. L'espace
         SUPPLÉMENTAIRE demandé sous la carte (voir "section.pains ~
         section.services" plus bas) est volontairement gardé SÉPARÉ de ce
         chevauchement : le réduire ici (en ajoutant à ce "margin-bottom")
         diminuerait au passage le chevauchement lui-même — les deux
         réglages doivent pouvoir varier indépendamment. */
      margin: var(--space-16) auto calc(-2 * var(--space-16));

      @media (min-width: 640px) {
        margin: var(--space-20) auto calc(-2 * var(--space-20));
      }
    }
  }

  /* Espace supplémentaire, dédié, entre le bas de la citation qui chevauche
     "section.pains" (ci-dessus) et le header de "section.services" qui
     suit — demandé explicitement pour ne pas laisser ce header collé au
     bord de la carte blanche. Ciblé par le frère PRÉCÉDENT ("section.pains
     ~"), jamais par ".services" seule : n'affecte que ce cas précis, pas
     un futur usage de ".services" ailleurs sur le site. */
  section.pains~section.services>.container>header {
    margin-top: var(--space-20);
  }

  section.blog {
    & header {
      max-width: none;
      margin: 0 0 52px;
      text-align: left;

      &.centered {
        margin: 0;
        text-align: left;
      }
    }
  }

  /* CTA du hero (2 boutons, "nav.left") : à partir de 1024px, restent sur
     UNE seule ligne — "flex-wrap: nowrap" (le "& nav" générique de
     "section.hero", partagé avec les pages de service, autorise le retour
     à la ligne à tous les paliers) — sans changer leur taille : chaque
     "& .btn" garde son "width: auto" existant, "flex-shrink: 0" annule
     seulement le rétrécissement implicite ("flex-shrink: 1" par défaut)
     qu'appliquerait sinon le passage en "nowrap" si l'espace venait à
     manquer. Le <nav> reçoit aussi un espace identique au-dessus et
     en-dessous ("margin-bottom: var(--space-5)", même valeur que le "gap"
     de "article" au-dessus de lui) — sans cela, rien ne suit le <nav> dans
     sa colonne à ce palier (mise en page 2 colonnes du hero), laissant un
     espace nul en dessous contre "var(--space-5)" au-dessus. */
  section.hero nav {
    @media (min-width: 1024px) {
      & {
        flex-wrap: nowrap;
        margin-bottom: var(--space-5);
      }

      & .btn {
        flex-shrink: 0;
      }
    }
  }
}

/**
 * Sections "decor-*" (voir plus bas, "Contenu — service pages") : les
 * cercles décoratifs débordent volontairement de la colonne de texte
 * (max-width: 820px, "section.page-content") jusque dans les marges de la
 * page, ce qui créerait un débordement horizontal (scroll indésirable) sur
 * les écrans où le rond déborde plus loin que la largeur de la fenêtre. La
 * spec CSS prévoit qu'un "overflow" posé sur "body" (quand "html" n'en a
 * pas) se propage à la zone de défilement du document — dans les faits,
 * cette propagation ne s'est pas produite avec la valeur "clip" (le
 * débordement horizontal persistait, mesuré via
 * "document.documentElement.scrollWidth"), d'où la règle posée
 * explicitement sur "html" en plus, pour ne pas dépendre de cette
 * propagation.
 */
html:has(body.page-service, body.page-about) {
  overflow-x: clip;
}

/**
 * Hero section — service pages (page-base)
 */
@scope (.page-service, .page-about) {

  /* Ce bloc est PARTAGÉ par les pages de service ET par "Autour de Coaxia
     RH" (".page-about", conseillere-rh.php) : contenu d'article en bandes
     alternées, accordéon, filigranes de pictos, alignement à gauche. Seule
     la mise en page du hero (ci-dessous) est propre aux pages de service —
     celle de ".page-about" est définie dans son propre "@scope" plus bas
     (photo + titre en grille). */
  :scope.page-service section.hero {
    & article.container {
      gap: 0;

      @media (min-width: 1024px) {
        & .text {
          max-width: 1024px;
        }
      }

      & ul {
        background: transparent;
        padding: var(--space-5) 0 0;
      }
    }
  }

  /* Les 4 photos dédiées par page (conseiller-rh.jpg, discussion-table.jpg,
     formation-rh.jpg, coaching-individuel.jpg), auparavant posées ici via
     "&.page--conseil/--facilitation/--formation/--coaching", sont retirées :
     "section.hero" suit désormais le même modèle que le hero de la page
     d'accueil (fond plein clair, filigrane du « A » visible), quelle que
     soit la page — une photo de fond y écraserait à nouveau le filigrane. */

  /**
   * Contenu — service pages : structure "decor-*", conçue et validée sur
   * la page Facilitation (voir historique dans base2.css), généralisée ici
   * à TOUTES les pages de type service (portée par ".page-service", pas
   * un modificateur "&.page--…" spécifique) — chaque bloc de contenu de
   * l'article devient un <section> à part entière (regroupement
   * thématique nommé par un h2 — <section> plutôt que <div>), avec une
   * identité visuelle propre : un cercle décoratif DÉCOUPÉ par les limites
   * de la section elle-même ("overflow: hidden"), alterné dans l'un de
   * ses 4 coins selon la classe posée dans le HTML ("decor-tl/tr/bl/br").
   * Toute page de service qui adopte cette structure HTML (actuellement
   * Facilitation ; à étendre à Coaching/Formation/Conseil) en hérite
   * automatiquement.
   */
  & {
    overflow-x: clip;
  }

  /* Bandes pleine largeur, collées les unes aux autres : ".page-content"
     ne borne plus la largeur (820px) ni ne pose de padding — chaque section
     d'article occupe toute la largeur du viewport, sans marge entre elles
     (le demi-cercle de transition en haut de chacune relie ainsi vraiment la
     section précédente). Le texte reste dans la colonne de 820px d'origine
     via "--article-gutter" (marge intérieure de chaque bande). */
  & section.page-content {
    /* Aligne le bord gauche des <h2> avec celui d'un .container standard :
       même formule miroir — padding = --container-padding jusqu'à
       --container-max, puis grandit avec le viewport au-delà. */
    --article-gutter: max(var(--container-padding), calc((100% - var(--container-max)) / 2 + var(--container-padding)));
    max-width: none;
    padding: 0;

    & article {
      &>section {

        /* ".method"/".offers" (formation.php) : bandes pleine largeur
           PROPRES (".container" centré, grille de cartes) qui gardent leur
           propre identité même déplacées à l'intérieur de "<article>" — la
           contrainte de largeur/alignement ci-dessous (colonne de texte
           820px) ne doit PAS s'y appliquer, sous peine d'y écraser leur
           grille de cartes et d'empêcher le centrage de leur ".container".
           Exclues ici comme à la ligne "&:not(.article-extras)" plus bas —
           rien d'autre n'est exclu (le "& h2"/"&>*{z-index:1}" plus bas
           restent sans effet indésirable, voir leurs propres commentaires). */
        &:not(.method):not(.offers) {
          margin-top: 0;
          padding: var(--space-16) var(--article-gutter);
        }

        /* Espacement UNIFORME entre TOUTES les sections de l'article (les 4
           "decor-*" comme les 2 ".article-extras", quelle que soit leur position
           dans le DOM) : un seul "margin-top", jamais de "margin-bottom" (qui
           aurait pu fusionner différemment selon la paire de sections adjacentes
           et casser l'uniformité — les marges verticales adjacentes se
           fusionnant en ne retenant que la plus grande des deux). Valeur unique
           "var(--space-20)", identique pour toutes les sections — y compris
           ".article-extras"/".article-callout" (ancien cas particulier à
           "margin-top: 20px", supprimé : il n'a plus lieu d'être dès lors que
           la règle générique ci-dessous utilise elle-même directement ce même
           token, sans plus dépendre du débordement du cercle décoratif d'une
           éventuelle section voisine). */
        /* Identité visuelle propre à chaque section : pas de fond de carte,
           mais toujours "position: relative" pour ancrer le cercle décoratif
           (voir "::after" plus bas). PAS de "overflow: hidden" ici : le cercle
           déborde volontairement de la hauteur de sa section pour rester
           totalement visible (un "overflow: hidden" le découpait pile à la
           limite haute/basse de la section, alors que son rayon dépasse le
           padding vertical disponible) — sans risque pour le texte : chaque
           enfant direct de la section reçoit son propre "z-index: 1" (voir plus
           bas) alors que le cercle reste à "z-index: 0", il passe donc toujours
           au-dessus, y compris celui d'une section voisine. Ces sections sont à
           la largeur commune de la colonne de texte (max-width: 820px, héritée
           de "section.page-content") ; le cercle garde le même ancrage par coin
           (voir chaque ".decor-*" plus bas), relatif à cette largeur commune. */
        &:not(.article-extras):not(.method):not(.offers) {
          margin-top: 0;

          position: relative;
          padding: var(--space-16) var(--article-gutter);

          &> :not(h2) {
            margin-left: 0;
            margin-right: auto;
          }
        }

        /* Tout le contenu direct de la section (titre, texte, listes, callout,
           témoignage…) doit rester au-dessus du cercle décoratif : chaque enfant
           direct reçoit son propre "position: relative" + "z-index: 1". Non
           pertinent pour ".article-extras" (pas de cercle décoratif derrière),
           mais sans effet indésirable non plus — inutile de l'exclure. */
        &>* {
          position: relative;
          z-index: 1;
        }

        /* Titre de chaque section : typographie affirmée (grande taille,
           graisse forte, tracking resserré), sans le hairline "border-bottom"
           générique de "section.page-content article h2" (base.css) — espacement
           au-dessus géré par le "margin-top" de la section elle-même (voir
           ci-dessus), plus besoin du "margin-top" propre au h2. */
        /* Toutes les sections d'article alignées À GAUCHE : le titre ne passe
           plus à droite pour "decor-tr/br", et le contenu ne se décale plus à
           droite pour "decor-tl/bl" (règles génériques "decor-*> :not(h2)" et
           "h2" plus haut, conçues pour éviter le cercle décoratif du côté
           opposé). Le filigrane garde son coin : il passe désormais derrière le
           texte pour "tl/bl" (faible opacité, le texte reste au-dessus via son
           "z-index: 1"). ".article-extras" (citation centrée) exclue — ainsi
           que ".method"/".offers" (même raison que plus haut : leur propre
           h2, par ex. "section-bg-dark & header & h2 { color: white }" pour
           "offers", ne doit pas être écrasé par cette typographie de prose). */
        &:not(.method):not(.offers) h2 {
          font-size: var(--text-xl);
          font-weight: 800;
          letter-spacing: -0.02em;
          color: var(--color-brand);
          border-bottom: none;
          padding-bottom: 0;
          margin-top: 0;
          text-align: left;
        }

        &.article-extras {
          background: var(--color-brand);
          padding-block: var(--space-8);
        }

        /* Cercles décoratifs : ancrés sur la colonne de texte (et non plus sur
           les bords de la bande pleine largeur), comme avant. */
        &.decor-tl::after,
        &.decor-bl::after {
          left: calc(var(--article-gutter) - 90px);
        }

        &.decor-tr::after,
        &.decor-br::after {
          right: calc(var(--article-gutter) - 90px);
        }

        /* Alternance "--color-brand-soft" (1re section) / "--color-white" des
           sections d'article : "section-bg-brand-soft" (classe existante) donne
           le fond menthe clair à une section sur deux ; l'absence de classe laisse
           le fond blanc par défaut — jamais de classe ".section-bg-*" pour la
           variante blanche. Les couleurs de texte par défaut sont déjà lisibles
           sur les deux fonds. ".article-extras" (".blockquote") n'entre pas dans
           l'alternance : il conserve son fond "--color-brand".

           Filigrane (le "A" en "::after" de ".decor-mountain") : la teinte
           "--color-brand-soft" d'origine disparaît sur un fond brand-soft, alors
           que la partie qui déborde sur la section précédente (blanche, brand-soft
           ou brand) doit rester visible. On prend donc "--color-brand" à 55 %
           (couleur, pas opacité : les états "reveal"/"is-visible" pilotent déjà
           l'opacité 0.36 du "::after"), visible sur blanc comme sur brand-soft. */
        &:is(.decor-mountain, .decor-collectif, .decor-echange, .decor-mouvement) {
          &::after {
            background-color: color-mix(in srgb, var(--color-brand) 55%, transparent);
          }

          &:is(.section-bg-brand-soft) {
            &::after {
              background-color: color-mix(in srgb, var(--color-brand-light) 55%, transparent);
            }

            & h2 {
              color: var(--color-white);
            }
          }
        }

        &:is(.decor-tl, .decor-bl):not(.article-extras)> :not(h2) {
          max-width: none;
        }

        /* Accordéon des sections d'article : chaque section (sauf
           ".article-extras") est FERMÉE au chargement — seul le "h2" reste
           visible — et se déroule au clic sur ce titre (bouton créé par
           "base.js", classe ".is-open" sur la section). Tout est gated par
           ":root.coax-js" : sans JS, aucune section n'est jamais fermée (pas de
           contenu inaccessible). Le déroulé anime "grid-template-rows" (0fr →
           1fr), seule technique qui anime une hauteur "auto" sans JS de mesure ;
           ".section-body" (grille) reste l'enfant direct de la section pour
           hériter des règles "decor-*> :not(h2)" (largeur/décalage du contenu),
           ".section-body-inner" porte le "overflow: hidden" nécessaire.
           "visibility" (avec délai à la fermeture) sort le contenu replié de
           l'ordre de tabulation et de l'arbre d'accessibilité. */
        &:has(>.section-body) {
          transition: padding-block 450ms var(--ease-refined);

          &>h2 {
            transition: margin-bottom 450ms var(--ease-refined);

            & button {
              display: inline-flex;
              align-items: center;
              gap: var(--space-3);
              padding: 0;
              border: 0;
              background: none;
              font: inherit;
              letter-spacing: inherit;
              color: inherit;
              text-align: inherit;
              cursor: pointer;

              &:focus-visible {
                outline: 2px solid var(--color-brand);
                outline-offset: 6px;
              }
            }
          }

          &>.section-body {
            display: grid;
            grid-template-rows: 1fr;
            transition: grid-template-rows 450ms var(--ease-refined), opacity 350ms var(--ease-refined), visibility 0s;

            /* "overflow: hidden" nécessaire au déroulé (piste à 0fr) coupait aussi
               net les ombres portées débordant du contenu (ex. ".badge" de
               « Démarche qualité et résultats », "--shadow-lg" : 32px de flou +
               8px de décalage), aux bords de la liste. Marge de sécurité : un
               padding de "--space-10" (50px, > 40px d'ombre) compensé par la
               marge négative opposée — la boîte de découpe s'élargit, mais le
               contenu garde exactement la même largeur/position et la hauteur
               repliée reste 0 (padding − marge = 0 dans le calcul de la piste). */
            &>.section-body-inner {
              min-height: 0;
              overflow: hidden;
              padding: var(--space-10);
              margin: calc(-1 * var(--space-10));
            }
          }

          /* Bouton posé sur le demi-cercle de connexion du BAS de la section
             — en réalité le "::before" de la section suivante (ou de la
             ".article-extras" qui suit), qui pend visuellement sous celle-ci.
             Un pseudo-élément n'étant pas cliquable, "base.js" crée ce bouton
             (aria-hidden, hors tabulation : le bouton du "h2" reste le contrôle
             accessible) et il REDESSINE le demi-cercle, en plus grand
             (64 × 32px, contre 36 × 18px pour l'original, qu'il recouvre
             entièrement) et avec un chevron : c'est ce qui signale
             visuellement qu'il est cliquable. "z-index: 3" > "z-index: 1" du
             contenu et du demi-cercle d'origine. Zone cliquable : 64 × 36px
             (4px de tolérance au-dessus de la jonction). Couleur du
             demi-cercle = fond de CETTE section (blanc, ou brand-soft avec
             ".section-bg-brand-soft"), comme l'original. Même recette
             géométrique que l'original (largeur 64px, hauteur moitié 32px,
             rayon de bordure 32px sur les deux coins du bas) plutôt qu'un
             "clip-path" — un rayon en pixels vaut à la fois comme rayon
             horizontal (32px = moitié de la largeur) et vertical (32px =
             hauteur entière), fermant le bas en arc de cercle exact. */
          &>.section-toggle {
            position: absolute;
            z-index: 3;
            left: 50%;
            bottom: -26px;
            width: 64px;
            height: 36px;
            padding: 0;
            border: 0;
            background: none;
            transform: translateX(-50%);
            cursor: pointer;
            -webkit-tap-highlight-color: transparent;

            &::before {
              content: "";
              position: absolute;
              inset: 4px 0 0;
              background: var(--color-white);
              border-radius: 0 0 32px 32px;
              transform-origin: 50% 0;
              transition: transform 250ms var(--ease-refined);
            }

            /* Chevron : bas = "déplier" (section fermée), haut = "replier".
               Léger rebond en boucle tant que la section est fermée, pour
               inviter au clic. */
            &::after {
              content: "";
              position: absolute;
              top: 12px;
              left: 50%;
              width: 11px;
              height: 11px;
              border: solid var(--color-brand);
              border-width: 0 3px 3px 0;
              transform: translateX(-50%) rotate(45deg);
              transition: transform 250ms var(--ease-refined), border-color 250ms var(--ease-refined);
            }

            /* Survol : le demi-cercle grossit (ancré à la jonction) et le
               chevron fonce. */
            &:hover::before {
              transform: scale(1.18);
            }

            &:hover::after {
              border-color: var(--color-black);
            }
          }

          &.section-bg-brand-soft>.section-toggle::before {
            background: var(--color-brand-soft);
          }

          /* Chevron presque invisible sur ce demi-cercle "--brand-soft" :
             contraste 1,29 avec "--color-brand" d'origine (couleurs de
             marque mises à jour), bien en dessous du minimum WCAG (3:1 pour
             un composant d'interface). "--color-white" choisi ici (1,80 de
             contraste mesuré, encore sous ce seuil, mais retenu à dessein) —
             "--color-black" (9,05) serait le choix le plus conforme WCAG,
             mais le blanc reste plus cohérent avec le reste de la charte
             graphique sur cet élément précis. */
          &.section-bg-brand-soft>.section-toggle::after {
            border-color: var(--color-white);
          }

          &.is-open>.section-toggle::after {
            top: 18px;
            transform: translateX(-50%) rotate(-135deg);
          }

          &:not(.is-open)>.section-toggle {
            &::after {
              animation: section-toggle-hint 1.8s ease-in-out infinite;
            }

            &:hover::after {
              animation: none;
            }
          }

          @media (prefers-reduced-motion: reduce) {

            &,
            &>h2,
            &>.section-body {
              transition: none;
            }
          }
        }

        /* Sections ".article-extras" (citations) : fermées par défaut et
           ouvertes/fermées EN MÊME TEMPS que la section d'accordéon qui les
           précède immédiatement (sélecteur de frère adjacent sur ".is-open" —
           aucun JS supplémentaire). Même technique de déroulé que ci-dessus
           (grid-template-rows 0fr → 1fr) : "figure" est l'élément replié.
           Une ".article-extras" sans section d'accordéon devant elle (ex.
           formation.php : elle suit "section.offers", non repliable) n'est pas
           ciblée et reste toujours visible — sinon rien ne pourrait l'ouvrir. */
        &:has(>.section-body)+section.article-extras {
          display: grid;
          grid-template-rows: 1fr;
          transition: grid-template-rows 450ms var(--ease-refined), padding-block 450ms var(--ease-refined), visibility 0s;

          &>figure {
            min-height: 0;
            /* "clip" + marge : les guillemets décoratifs de la citation dépassent
               légèrement de la figure, "hidden" les coupait net. */
            overflow: clip;
            overflow-clip-margin: 40px;
            transition: margin-block 450ms var(--ease-refined), padding-block 450ms var(--ease-refined);
          }

          &::before {
            transition: opacity 350ms var(--ease-refined);
          }
        }

        /* Citation à paragraphes ("blockquote > p", ex. formation.php) : "section.
           page-content p" cible "p" directement et l'emporterait sur la couleur
           héritée du "blockquote" — on la réaffirme ici (héritage explicite). */
        &.article-extras blockquote {

          & p,
          & strong {
            color: inherit;
          }
        }
      }
    }
  }

  :root.coax-js & section.page-content {
    & article {
      &>section {
        &:has(>.section-body):not(.is-open) {
          padding-block: var(--space-8);

          &>h2 {
            margin-bottom: 0;
          }

          &>.section-body {
            grid-template-rows: 0fr;
            opacity: 0;
            visibility: hidden;
            transition: grid-template-rows 450ms var(--ease-refined), opacity 350ms var(--ease-refined), visibility 0s linear 450ms;
          }

          /* Filigrane caché tant que la section est fermée : il apparaît à
             l'ouverture avec l'animation déjà définie sur "decor-*" ("::after"
             de opacity 0 / translateY(40px) → 0.36 / 0, voir ".is-visible"). */
          &:is(.decor-mountain, .decor-collectif, .decor-echange, .decor-mouvement)::after {
            opacity: 0;
            transform: translateY(40px);
          }

          /* Compteurs animés ("span.digit", voir ".digit" plus haut) dans une
             section d'accordéon : leur animation ne doit démarrer QU'À
             L'OUVERTURE de la section — ni au chargement de la page (elle
             tournerait dans le vide, section repliée et invisible), ni quand le
             scroll atteint la section (elle est alors encore fermée). Section
             fermée : "animation: none" (le "::before" reste le cache blanc à
             "0", invisible car la section est repliée) ; à l'ouverture, l'animation
             repart de zéro (retour de "none" vers les animations d'origine), y
             compris à chaque réouverture. Gaté par ":root.coax-js" : sans JS, la
             section est ouverte d'office et le compteur suit son cours normal. */
          & .digit::before {
            animation: none;
          }

          &+section.article-extras {
            grid-template-rows: 0fr;
            padding-block: 0;
            visibility: hidden;
            transition: grid-template-rows 450ms var(--ease-refined), padding-block 450ms var(--ease-refined), visibility 0s linear 450ms;

            /* "margin"/"padding" verticaux de la figure : ils gardent la piste de
               grille ouverte même à "0fr" (un élément de grille ne peut pas être
               plus petit que ses marges/paddings) — à annuler aussi pour replier. */
            &>figure {
              margin-block: 0;
              padding-block: 0;

              /* Guillemet-filigrane de la citation : caché tant qu'elle est
                 repliée, il apparaît (fondu + montée de 40px, comme le filigrane
                 des sections) à son ouverture. */
              &::before {
                opacity: 0;
                transform: translateY(40px);
              }
            }

            &::before {
              opacity: 0;
            }
          }
        }

        /* Demi-cercle de la section qui SUIT une ".article-extras" repliée :
           sa couleur ("--brand", posée en dur dans le HTML) suppose la
           citation visible juste au-dessus. Citation repliée = la section
           d'accordéon précédente (fond brand-soft ou blanc, jamais brand)
           touche directement la suivante : le demi-cercle reprend donc le
           fond de CETTE section. */
        &:not(.section-bg-brand-soft):has(>.section-body):not(.is-open)+section.article-extras+section::before {
          background-color: var(--color-white);
        }

        &.section-bg-brand-soft:has(>.section-body):not(.is-open)+section.article-extras+section::before {
          background-color: var(--color-brand-soft);
        }
      }
    }

    /* Idem pour "section.cta" (hors ".page-content", juste après) quand la
       dernière ".article-extras" de l'article est repliée. */
    &:has(>article>section.article-extras:last-child) {
      &:has(>article>section:nth-last-child(2):not(.is-open):not(.section-bg-brand-soft))+section.cta::before {
        background-color: var(--color-white);
      }

      &:has(>article>section.section-bg-brand-soft:nth-last-child(2):not(.is-open))+section.cta::before {
        background-color: var(--color-brand-soft);
      }
    }
  }
}

/**
 * Contenu — page Formation (page--formation) : mise en forme des groupes
 * d'éléments (logos/documents, statistiques, images, boutons, contacts) que
 * le HTML de "Démarche qualité et résultats", "PCM", "MANAHOP" et "Accueil
 * et handicap" liste sous forme de <ul>/<p> génériques — sans introduire de
 * nouveaux éléments HTML, seulement des classes posées sur les balises déjà
 * présentes (voir formation.php). Mobile d'abord partout.
 */
@scope (.page--formation) {

  & section.page-content article>section {

    /* "Démarche qualité" : logo Qualiopi + lien du certificat, listés en
       <li> — rangée horizontale (et non une liste à puces verticale).
       Sélecteur qualifié par la chaîne d'ancêtres complète (et non
       simplement ".badge-row") : nécessaire pour dépasser la spécificité de
       "section.page-content article ul:not(.values-grid)" (base.css) qui,
       sinon, l'emporterait sur "list-style"/"margin"/"padding" ici — même
       principe pour chaque ".CLASSNAME" basé sur un <ul> ci-dessous. */
    & ul.badge-row {
      list-style: none;
      /* Uniquement les marges verticales : ne pas déclarer "margin-left"/
         "margin-right" ici (même un raccourci "margin: Xpx 0" les mettrait à
         0) — le décalage horizontal (gauche ou droite selon le coin du
         cercle décoratif de la section) est déjà géré par la règle générique
         "section.page-content article > section.decor-* > :not(h2)" plus
         haut dans ce fichier ; la redéclarer ici l'écraserait. Même principe
         pour ".stat-line"/".badges"/".media-row"/".btn-group"/
         ".contact-list" ci-dessous. */
      margin-top: var(--space-5);
      margin-bottom: var(--space-5);
      padding: 0;
      display: flex;
      flex-wrap: wrap;
      align-items: center;
      gap: var(--space-5);

      & li {
        margin: 0;
        /* Nécessaire pour que l'image (ci-dessous) puisse rétrécir en
           dessous de sa taille intrinsèque sur petit écran : par défaut
           ("min-width: auto"), un item flex ne rétrécit jamais sous la
           taille "au contenu" de son contenu (ici l'image), quel que soit
           "flex-shrink" — même piège/solution que ".logos-scroller" plus
           bas dans ce fichier. */
        min-width: 0;
      }

      /* Qualiopi affiché à sa taille réelle (487px, grandeur nature —
         l'attribut HTML "width=487" ferait sinon brièvement flasher cette
         taille avant que le CSS ne s'applique, undesired) ; "width: 100%"
         + "height: auto" (conservés, au lieu d'une largeur fixe) : l'image
         rétrécit proportionnellement en dessous de 487px si son <li>
         (flex, "min-width: 0" ci-dessus) manque de place — mobile first,
         jamais de débordement horizontal, quelle que soit la largeur de
         l'écran. */
      & img {
        max-width: 487px;
        width: 100%;
        height: auto;
      }
    }

    /* "Démarche qualité" : répartition de la satisfaction par thématique —
       ex-"ul.rating-grid", désormais un usage autonome de ".badges" (voir
       plus haut dans ce fichier) comme n'importe quel autre — plus de
       classe ni de règle dédiée à cette liste, à une exception près :
       "ul.badges" seule (spécificité 0,1,1) ne suffit pas à l'emporter sur
       "section.page-content article ul:not(.values-grid)" (0,2,3, plus
       bas dans ce fichier — puces du contenu éditorial), qui reposerait
       sinon un "padding-left" sur cette liste une fois nichée ici. Même
       principe de qualification complète par la chaîne d'ancêtres que
       ".badge-row"/".media-row"/etc. ci-dessus pour dépasser cette
       spécificité. */
    & ul.badges {
      padding: 0;
    }

    /* "Démarche qualité" : même piège de spécificité pour "ul.stat-lines"
       (voir commentaire ci-dessus, identique pour ".badges") — "list-style:
       none" ajouté en plus de "padding: 0" : sans lui, "list-style: disc"
       (même règle générique) s'appliquerait aussi, restant certes invisible
       tant que ".stat-line" garde son "display: inline-flex" (aucun
       "<li>" en "display: list-item" ne reçoit de puce), mais sans raison
       de le laisser traîner si ce "display" venait à changer. */
    & ul.stat-lines {
      padding: 0;
      list-style: none;
    }

    /* "Démarche qualité" : mention de source des statistiques — repasse tout
       juste sur 2 lignes dès 768px (la colonne de texte, réduite par le
       décalage horizontal des sections "decor-*", passe alors sous la
       largeur nécessaire à cette phrase sur une seule ligne à la taille de
       texte courante). Réduction minimale mesurée pour tenir sur une seule
       ligne à la largeur la plus contrainte (768px, ~477px de large) — reste
       valable à toutes les largeurs supérieures (colonne plus large, jamais
       plus étroite qu'à 768px). */
    & p.data-source {
      @media (min-width: 768px) {
        & {
          font-size: var(--text-sm);
        }
      }
    }

    /* "PCM"/"MANAHOP" : photos et logos listés en <li> — grille responsive
       mobile d'abord : 2 colonnes (< 640px), 4 colonnes (>= 640px, les 4
       photos MANAHOP tiennent alors sur une seule ligne). Chaque case garde un ratio CARRÉ fixe ("aspect-ratio:
       1" + "object-fit: cover") plutôt que la hauteur naturelle de chaque
       image : les sources mélangent portrait (256×342, 266×348) et
       paysage/carré (249×165, 188×165) — sans ce recadrage uniforme, une
       grille à plusieurs colonnes aurait des rangées de hauteurs inégales
       (chaque ligne calée sur sa case la plus haute), rendu peu soigné pour
       une galerie. L'ancienne disposition "flex-wrap" (tailles naturelles,
       1-2 images par ligne selon la largeur restante) laissait plus de
       lignes que de colonnes réelles et un rendu déséquilibré (portraits
       bien plus hauts que paysages sur la même ligne). */
    & ul.media-row {
      list-style: none;
      margin-top: var(--space-5);
      margin-bottom: var(--space-5);
      padding: 0;
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: var(--space-4);

      @media (min-width: 640px) {
        & {
          grid-template-columns: repeat(4, minmax(0, 1fr));
          gap: var(--space-5);
        }
      }

      & li {
        margin: 0;
      }

      & img {
        display: block;
        width: 100%;
        aspect-ratio: 1;
        object-fit: cover;
        border-radius: var(--radius-md);
      }
    }

    /* "PCM" : liens de téléchargement des fiches formation — mobile d'abord empilés pleine
       largeur (plus facile à toucher), rangée qui s'enroule dès 480px (même
       seuil/logique que les boutons du hero, voir plus haut dans ce
       fichier). */
    & ul.btn-group {
      list-style: none;
      margin-top: var(--space-5);
      margin-bottom: var(--space-5);
      padding: 0;
      display: flex;
      flex-direction: column;
      gap: var(--space-3);

      @media (min-width: 480px) {
        & {
          flex-direction: row;
          flex-wrap: wrap;
        }
      }

      & li {
        margin: 0;
      }

      & .btn {
        width: 100%;
        text-align: center;

        @media (min-width: 480px) {
          & {
            width: auto;
          }
        }
      }
    }

    /* "Accueil et handicap" : coordonnées listées en <li> — chacune mise en
       valeur comme un bloc contact (fond + liseré), plutôt qu'une puce
       générique, cohérent avec ".article-callout"/".testimonial-quote"
       (même liseré à gauche) déjà utilisés ailleurs sur les pages service. */
    & ul.contact-list {
      list-style: none;
      margin-top: var(--space-4);
      margin-bottom: var(--space-4);
      padding: 0;
      display: flex;
      flex-direction: column;
      gap: var(--space-3);

      & li {
        margin: 0;
        background: var(--color-white);
        border-left: 3px solid var(--color-brand);
        border-radius: 0 var(--radius-md) var(--radius-md) 0;
        padding: var(--space-3) var(--space-4);

        a {
          color: var(--color-brand);
          text-decoration: none;

          &:hover {
            text-decoration: underline;
          }
        }
      }
    }
  }

  /* Accordéon ouvert/fermé sur "section.offers" : même langage visuel/
     interaction que l'accordéon générique "section.page-content article >
     section" (base.css, @scope (.page-service, .page-about)) — bouton créé
     par "base.js" sur le h2, chevron cliquable redessinant le demi-cercle de
     connexion, déroulé "grid-template-rows" — mais dupliqué ICI plutôt que
     d'élargir le sélecteur générique : "section.offers" vit HORS de
     "section.page-content article" (bande pleine largeur, fond sombre,
     grille de cartes 3 colonnes) et ne doit PAS hériter des règles de
     largeur / decor-* / filigrane qui accompagnent ce sélecteur générique
     (elles écraseraient sa mise en page). Classe ".section-body" ici NICHÉE dans
     ".container" (pas enfant direct de la section, contrairement aux
     sections "decor-*") : "base.js" cherche "h2"/".section-body" en
     descendant simple (pas ":scope >"), donc cette imbrication fonctionne
     sans changement JS. Portée par la classe ".section-accordion" (ajoutée
     dans le HTML en plus de ".offers") pour que "base.js" la cible aussi. */
  & .section-accordion {
    transition: padding-block 450ms var(--ease-refined);

    &:not(.is-open) {
      padding-block: var(--space-8);
    }

    & h2 {
      transition: margin-bottom 450ms var(--ease-refined);

      & button {
        display: inline-flex;
        align-items: center;
        gap: var(--space-3);
        padding: 0;
        border: 0;
        background: none;
        font: inherit;
        letter-spacing: inherit;
        color: inherit;
        text-align: inherit;
        cursor: pointer;

        &:focus-visible {
          outline: 2px solid var(--color-brand);
          outline-offset: 6px;
        }
      }
    }

    & .section-body {
      display: grid;
      grid-template-rows: 1fr;
      transition: grid-template-rows 450ms var(--ease-refined), opacity 350ms var(--ease-refined), visibility 0s;

      & .section-body-inner {
        min-height: 0;
        overflow: hidden;
      }
    }

    /* Bouton sur le demi-cercle de connexion du bas (même recette que
       l'accordéon générique) : couleur = fond de CETTE section, soit
       "--color-black" (approximation plate du dégradé "section-bg-dark",
       même convention que "section-transition-arrow--dark"). */
    &>.section-toggle {
      position: absolute;
      z-index: 3;
      left: 50%;
      bottom: -26px;
      width: 64px;
      height: 36px;
      padding: 0;
      border: 0;
      background: none;
      transform: translateX(-50%);
      cursor: pointer;
      -webkit-tap-highlight-color: transparent;

      &::before {
        content: "";
        position: absolute;
        inset: 4px 0 0;
        background: var(--color-black);
        border-radius: 0 0 32px 32px;
        transform-origin: 50% 0;
        transition: transform 250ms var(--ease-refined);
      }

      &::after {
        content: "";
        position: absolute;
        top: 12px;
        left: 50%;
        width: 11px;
        height: 11px;
        border: solid var(--color-white);
        border-width: 0 3px 3px 0;
        transform: translateX(-50%) rotate(45deg);
        transition: transform 250ms var(--ease-refined), border-color 250ms var(--ease-refined);
      }

      &:hover::before {
        transform: scale(1.18);
      }
    }

    &.is-open>.section-toggle::after {
      top: 18px;
      transform: translateX(-50%) rotate(-135deg);
    }

    &:not(.is-open)>.section-toggle::after {
      animation: section-toggle-hint 1.8s ease-in-out infinite;
    }

    &:not(.is-open)>.section-toggle:hover::after {
      animation: none;
    }

    @media (prefers-reduced-motion: reduce) {

      &,
      & h2,
      & .section-body {
        transition: none;
      }
    }
  }

  /* Fermée par défaut : gated par ":root.coax-js" (même garde que
     l'accordéon générique) — sans JS, "section.offers" reste toujours
     visible (aucun bouton créé, rien ne pourrait la rouvrir). */
  :root.coax-js & .section-accordion:not(.is-open) {

    & .section-body {
      grid-template-rows: 0fr;
      opacity: 0;
      visibility: hidden;
      transition: grid-template-rows 450ms var(--ease-refined), opacity 350ms var(--ease-refined), visibility 0s linear 450ms;
    }
  }

  & .offers.section-accordion {

    /* Supprime le centrage horizontal imposé par la règle sitewide
     "section & header { max-width: 760px; margin: 0 auto }" (0,0,2) :
     le <header> doit rester calé à gauche comme dans section.method,
     sans décalage supplémentaire. (0,2,2) bat (0,0,2). */
    & header {
      max-width: none;
      margin-inline: 0;
    }

    /* "section.offers" : sans marge (haut ET bas) sur son "header"/son "h2" —
     surcharge de la règle sitewide "section.page-content article h2
     {margin-top:var(--space-10); margin-bottom:var(--space-4)}" qui a une
     spécificité (0,1,3) (1 classe + 3 éléments). ".offers h2" seul n'atteint
     que (0,1,1) — insuffisant. La double classe ".offers.section-accordion"
     donne (0,2,1) : 2 classes > 1 classe, gagne quel que soit le nombre
     d'éléments. De même pour "header" : la règle sitewide "section header
     {margin-bottom:52px}" est (0,0,2) — ".offers.section-accordion header"
     à (0,2,2) la bat. "margin-top: 0" répété explicitement ici car la règle
     ".page-content article > section:not(.method):not(.offers) h2" exclut
     précisément ".offers" — cette règle-ci est donc la seule garantie. */
    &:not(.is-open) {

      & header,
      & h2 {
        margin-block: 0;
        padding-block: 0;
      }
    }

    /* ".card" à l'intérieur de "section.offers" — re-assertion de l'identité
     graphique native du composant, court-circuitée par les règles de prose
     "section.page-content article { … }" qui s'appliquent désormais à tous
     ses descendants depuis le déplacement de "section.offers" à l'intérieur
     de "<article>".
     Concurrents par spécificité :
       • text-align:justify    → section.page-content article      (0,0,1,2)
       • h3 margin-top         → section.page-content article h3   (0,0,1,3)
       • p font-size/margin    → section.page-content article p    (0,0,1,2)
       • ul list-style/padding → …article ul:not(.values-grid)     (0,0,2,3)
       • ul li color/margin    → …article ul:not(.values-grid) li  (0,0,2,4)
     Sélecteur ".offers.section-accordion .card" à (0,0,3,0) : 3 classes > 2
     classes max côté concurrent — gagne quel que soit le nombre d'éléments. */
    & .card {
      text-align: left;

      & h3 {
        margin-top: 0;
        /* article prose pose margin-top:var(--space-6) sur h3 */
      }

      & .text {
        & p {
          font-size: inherit;
          /* hérite de ".text{font-size:var(--text-sm)}" */
          line-height: inherit;
          /* hérite de ".text{line-height:1.55}" */
          color: inherit;
          margin-bottom: 0;
        }

        & ul {
          list-style: none;
          padding-inline-start: 0;

          & li {
            line-height: 1.5;
            /* valeur d'origine ".card .text ul li" */
            margin-bottom: 0;
            /* la carte utilise "gap", pas de marge individuelle */
          }
        }
      }

      & nav ul {
        list-style: none;
        padding-inline-start: 0;
        margin-bottom: 0;

        & li {
          margin-bottom: 0;
        }
      }
    }

    /* section.offers is always open: the bottom connector arc stays as a
       visual link to the next section, but carries no chevron and is not
       interactive (no hover scale, no pointer cursor, no click target). */
    & > .section-toggle {
      pointer-events: none;
      cursor: default;

      &:hover::before {
        transform: none;
      }

      &::after {
        display: none;
      }
    }
  }
}

/**
 * Hero section — about page (page-about)
 */
@scope (.page-about) {
  & section.hero {
    padding: var(--space-16) 0;

    /* Le filigrane du « A » ("::before", voir "section.hero" générique plus
       haut : aligné à droite, à partir de 700px) s'applique ici comme sur
       les pages de service ; seuls les halos ("::after") restent
       désactivés. */
    &::after {
      display: none;
    }

    /* Ce hero garde son fond "--color-brand" (classe "section-bg-brand") :
       le filigrane générique (« A » menthe à 14 % d'opacité, "background-
       image") y serait invisible, menthe sur menthe. On le redessine donc
       en BLANC, avec le même SVG utilisé comme masque : son opacité de 14 %
       (déjà dans le SVG) devient l'alpha du masque. Même position/taille
       que le filigrane générique (droite, sous le menu, 260px). "@media" au
       niveau de l'élément réel (voir le commentaire du filigrane
       générique : nester un "@media" dans un pseudo-élément ne
       s'applique pas dans Chrome). */
    @media (min-width: 700px) {
      &::before {
        background-image: none;
        background-color: var(--color-white);
        -webkit-mask: url('../img/01-filigrane.svg') no-repeat top right / 260px auto;
        mask: url('../img/01-filigrane.svg') no-repeat top right / 260px auto;
      }
    }

    /* Grid layout — mobile: 1 col (img / title / text), desktop: img gauche + title+text droite */
    & article.container {
      display: grid;
      grid-template-columns: 1fr;
      grid-template-areas:
        "img"
        "title"
        "text";
      gap: var(--space-6);
      text-align: center;
      justify-items: center;

      @media (min-width: 640px) {
        & {
          grid-template-columns: auto 1fr;
          grid-template-areas:
            "img title"
            "img text";
          column-gap: var(--space-20);
          row-gap: var(--space-4);
          text-align: left;
          justify-items: start;
          align-items: center;
        }
      }
    }

    & h1 {
      grid-area: title;
      color: var(--color-white);
      letter-spacing: -0.025em;
      line-height: 1.15;
      margin-bottom: 0;
      align-self: end;
    }

    & .text {
      grid-area: text;
      color: rgba(255, 255, 255, 0.72);
      line-height: 1.6;
      margin-bottom: 0;
      align-self: start;
    }

    /* Portrait circulaire — <p class="img"> (maquette) et <figure
       class="wp-block-image"> (bloc natif core/image sur le site WordPress
       coaxiarh-fse, kiweb-mockup-php n'ayant pas de notion de CMS) partagent
       le même traitement visuel, seul le tag racine diffère selon la
       cible. */
    & p.img,
    & figure.wp-block-image {
      grid-area: img;

      & img {
        display: block;
        width: 180px;
        height: 180px;
        object-fit: cover;
        object-position: top center;
        border-radius: 50%;
        border: 3px solid rgba(255, 255, 255, 0.25);
        box-shadow:
          0 0 0 8px rgba(255, 255, 255, 0.08),
          0 24px 64px rgba(0, 0, 0, 0.35);

        @media (min-width: 768px) {
          & {
            width: 260px;
            height: 260px;
          }
        }

        @media (min-width: 1024px) {
          & {
            width: 300px;
            height: 300px;
          }
        }
      }
    }
  }

  & section.badges {
    padding-bottom: 0;
  }
}

/**
 * About / Founder section
 */
/* Fondatrice (page d'accueil) — contenu allégé (2 paragraphes + la liste de
   3 cartes "Engagée/Pragmatique/Autonomisante" ont été retirés d'index.php,
   ne laissant qu'un label, un titre, un paragraphe et une ligne de repères
   chiffrés). Design refait en conséquence sur le modèle du bloc
   ".wireframe .wf-profile" (planche 3, .kiweb/mockup/coaxia/.html/index.html) :
   photo simple, plate, SANS découpe (ni cercle, ni anneau animé, ni bordure
   épaisse colorée — cf. .kiweb/mockup/coaxia/CLAUDE.md, "Rien — photo de
   Caroline, sans découpe"), posée à plat à côté d'un texte compact. Reprend
   directement la grille générique ".aside-article-grid" (photo | texte,
   0.85fr/1fr dès 768px) au lieu de la mise en page par flottant + habillage
   de texte ("shape-outside") de l'ancienne version, devenue disproportionnée
   une fois le texte réduit à un seul paragraphe. */
section.about {

  /* le <header> ici est le cadre de l'image (aside), pas un header de
     section : neutralise le "margin: 0 auto 52px;" générique de "section
     header" (l.180), à toutes les tailles */
  & header {
    margin: 0;
  }

  & .aside-article-grid {
    & aside {
      & header {
        aspect-ratio: 4 / 5;
        border-radius: var(--radius-md);
        overflow: hidden;

        /* "figure.wp-block-image" (bloc natif core/image, coaxiarh/about-
           aside sur le site WordPress coaxiarh-com) partage la même règle —
           seul le tag racine diffère selon la cible. */
        & .img,
        & figure.wp-block-image {
          display: block;
          width: 100%;
          height: 100%;
          margin: 0;

          & img {
            display: block;
            width: 100%;
            height: 100%;
            object-fit: cover;
            object-position: top center;
          }
        }
      }
    }

    & article {

      /* "section.about" porte ".section-bg-brand-soft" (index.php) :
         "--color-brand" sur "--color-brand-soft" tombe à 1,29 de contraste
         avec les couleurs de marque mises à jour — illisible.
         "--color-black" (9,05) remplace, même convention que
         ".sidebar-card.profile"/".contact-info-card". */
      & .label {
        color: var(--color-black);
        font-weight: 600;
        text-transform: uppercase;
        letter-spacing: 0.1em;
        margin: 0;
      }

      & h2 {
        font-size: var(--text-xl);
        margin: 12px 0 18px;
        color: var(--color-black);
      }

      & .text {
        color: var(--color-black);
        margin-bottom: 18px;
        line-height: 1.55;
      }

      & p {
        color: var(--color-gray);
        margin-bottom: 24px;
        line-height: 1.65;
      }

      & nav {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        justify-content: center;
        gap: var(--space-6);

        @media (min-width: 640px) {
          & {
            gap: var(--space-10);
          }
        }

        @media (min-width: 1024px) {
          & {
            justify-content: flex-start;
          }
        }
      }
    }
  }
}

/**
 * Statistics
 */
section.stats {
  /* Padding réduit + filet vert conservés (décision) : plus compact que le
     rythme standard de "section-padding" (déjà posée dans le HTML, mais
     écrasée ici — même spécificité que "section.stats" seule, 0,1,1
     chacune, cette règle étant plus tardive dans le fichier l'emporte,
     volontairement). Le demi-cercle de transition s'ajoute au filet, ne le
     remplace pas. */
  padding: var(--space-10) 0;
  border-top: 1px solid var(--color-white);

  /* Garde-fou : le logo Qualiopi (".badge--img", plus bas) s'affiche à sa
     taille réelle (487px de large) même quand sa colonne de grille est
     plus étroite (dès ~1024px, "max-width: inherit" assumé plutôt qu'un
     rétrécissement proportionnel — voir son propre commentaire). "clip"
     contient ce débordement dans les limites de LA SECTION plutôt que de
     laisser le logo s'étendre jusqu'au bord du viewport et provoquer un
     ascenseur horizontal sur toute la page. */
  overflow-x: clip;

  /* "section.stats & .badges" — chiffres-clés + certifications, remontés
       ici depuis l'ex-"section.stats" (supprimée). Contrairement à son
       ancien emplacement dans le hero, ".badges" est ici un DESCENDANT
       normal d'un vrai "<div class="container">" (voir index.php) — la
       mise en grille de base et le compteur animé, communs à tout usage
       de ".badges", restent définis une seule fois dans la classe
       ".badges" elle-même (voir plus haut dans ce fichier) ; seule la
       largeur de la dernière colonne (item au texte trop long) est
       propre à cet usage. */
  & ul.badges {
    /* Mobile (1 colonne) : même réduction "--badge-k" que 640-1023px (voir
       plus bas) — à 320px le "badge--wide" ne fait que 270px de large. */
    --badge-k: 0.6;

    /* Exception à la règle par défaut de "ul.badges" (mono-ligne dès
       640px) : ici le 4ème item ("badge--wide", texte très long) ne tient
       sur une ligne qu'à partir de 1024px. En dessous : 1 colonne (< 640px)
       puis 2 colonnes (640-1023px), comme avant la règle par défaut. */
    @media (min-width: 640px) {
      & {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        grid-auto-flow: row;
        grid-auto-columns: auto;
        justify-content: normal;
        gap: var(--space-5);
        /* Taille du contenu des ".badge" : 2 colonnes égales. "--badge-k" (0,6)
           réduit le diamètre de référence — donc la taille du contenu,
           commune à tous les items — pour que le mot le plus long du
           "badge--wide" ("Codéveloppement") tienne dans sa colonne, qui
           reste ici plus étroite qu'au-delà de 1024px. */
        --badge-cols: 2;
        --badge-gaps: 1;
        --badge-k: 0.6;
      }
    }

    @media (min-width: 1024px) {
      & {
        /* ERREUR CORRIGÉE (toutes les itérations précédentes de cette règle
           la commettaient) : l'ordre réel des 4 items dans le DOM (voir
           "block/badges" dans index.php) n'est PAS "3 ronds puis 1 item
           large" mais "2 ronds (25 ans, 2019), PUIS le logo Qualiopi
           (".badge--img", 3ème position), PUIS le texte RNCP (".badge--wide"
           seul, 4ème/dernière position)". "grid-template-columns" DOIT donc
           élargir la 3ème colonne (pas la dernière) pour accueillir le
           logo — poser la colonne large en dernière position (comme
           auparavant) l'assignait à tort au texte RNCP, laissant au logo
           Qualiopi une colonne étroite (~1fr, ~145px) dans laquelle sa
           largeur fixe (487px, voir ".badge--img" plus bas) débordait sur
           ses deux voisins ET laissait un vide visible entre la fin du logo
           (qui déborde, mais pas jusqu'au bord) et le bord droit réel de la
           grille (occupé par la 4ème colonne, dimensionnée pour RNCP).
           Colonne 3 (Qualiopi) : "minmax(490px, auto)", et non
           "minmax(490px, 3.5fr)" (essayé puis abandonné) — "3,5fr" fait
           grandir cette colonne PROPORTIONNELLEMENT à l'espace disponible,
           donc avec le viewport (≈506px à 1024px, mais bien plus au-delà,
           ex. ≈600px à 1280px) : le logo (largeur fixe 487px) se
           retrouvait alors centré dans une colonne de plus en plus large,
           avec un espace vide grandissant de chaque côté — confirmé en
           conditions réelles. "auto" comme maximum fait de cette colonne
           une piste DIMENSIONNÉE SUR SON CONTENU (la largeur intrinsèque du
           logo, 487px) plutôt que proportionnelle à l'espace disponible :
           elle ne grandit plus avec le viewport, plafonnée à son contenu
           réel (le plancher "490px" du minmax reste la seule garantie
           contre un débordement si jamais le contenu venait à changer).
           Colonnes 1/2/4 (ronds + RNCP) en "minmax(0, 1fr)" : elles se
           partagent TOUT l'espace restant une fois la colonne 3 satisfaite
           (space libéré par la colonne 3 ne grandissant plus avec le
           viewport, les 3 autres colonnes en profitent à la place). */
        grid-template-columns: repeat(2, minmax(0, 1fr)) minmax(490px, auto) minmax(0, 1fr);
        gap: var(--space-5) var(--space-3);
        /* Centrage vertical : depuis que le logo Qualiopi (".badge--img",
           487×170) dépasse la hauteur des 3 autres ".badge" (144px — voir
           plus bas), la ligne de grille fait 170px de haut (la plus grande
           hauteur définie parmi les 4 items). Sans "align-items: center",
           le comportement par défaut de la grille ("normal", équivalent à
           "start" pour un item à hauteur définie) aligne tout le monde en
           HAUT de cette ligne — les 3 ronds, plus petits, se retrouveraient
           collés en haut avec un vide visible dessous, au lieu d'être
           centrés par rapport au logo. */
        align-items: center;
        /* "--badge-cols"/"--badge-gap" DOIVENT rester cohérents avec
           "grid-template-columns"/"gap" ci-dessus : cette formule sert
           uniquement à calculer "--badge-d" (taille du CONTENU des ronds,
           padding/police — voir plus bas), pas la mise en grille
           elle-même, mais les deux doivent décrire la même réalité pour
           que le contenu des ronds corresponde à leur taille réellement
           rendue. Colonne 3 (Qualiopi) désormais dimensionnée sur son
           contenu ("minmax(490px, auto)" ci-dessus, pas une part de
           l'espace flexible) : elle n'entre donc plus dans ce calcul — ses
           490px sont soustraits de l'espace disponible AVANT de diviser le
           reste entre les 3 colonnes réellement flexibles (ronds + RNCP),
           "--badge-cols: 3". */
        --badge-cols: 3;
        --badge-gaps: 3;
        --badge-gap: var(--space-3);
        --badge-k: 1;

        /* Plafond commun des 4 ".badge" calé sur 170px — hauteur réelle du
           logo Qualiopi (".badge--img", 487×170, grandeur nature) : les 3
           autres ".badge" (2 compteurs + le texte RNCP) partagent ainsi
           exactement la même hauteur que lui, plutôt qu'un plafond choisi
           indépendamment (200px à l'origine, 144px dans une itération
           intermédiaire). Même formule que ".badge" (juste un plafond
           différent) pour conserver le rétrécissement responsive si la
           colonne devient plus étroite que 170px. "- 490px" supplémentaire
           (voir commentaire ci-dessus) : réserve la largeur de la colonne
           Qualiopi, dimensionnée sur son contenu, avant de répartir le
           reste entre les 3 colonnes flexibles. */
        --badge-d: min(170px, calc((100cqw - var(--badge-gaps) * var(--badge-gap) - 490px) / var(--badge-cols) * var(--badge-k, 1)));
      }

      /* "width"/"height" identiques (170px chacun) : le rond garde ses
         proportions (cercle parfait, "aspect-ratio: 1" déjà posé par la
         règle de base ".badge" — réaffirmé ici en valeurs absolues pour
         matcher exactement la hauteur de ".badge--img"). */
      & .badge {
        width: 170px;
        height: 170px;
      }

      /* Réduction de police nécessaire (au-delà de la simple proportion
         "--badge-d" de la formule par défaut, ".badge strong"/"span" plus
         haut) : à 144px de diamètre (plafond intermédiaire, avant le calage
         sur 170px ci-dessus), la formule par défaut (0.175/0.09, 25px/13px)
         faisait déborder le contenu du rond (confirmé en conditions
         réelles) — gardée par précaution au nouveau plafond de 170px
         (20px/11px, plancher), la même proportion réduite restant
         cohérente quelle que soit la valeur de "--badge-d". */
      & .badge strong {
        font-size: max(14px, calc(var(--badge-d) * 0.12));
      }

      /* Réduit UNIQUEMENT le "<strong>" de l'item RNCP (".badge--wide",
         "RNCP · PCM® · Codéveloppement" — jamais ".badge--img", qui n'a pas
         de "<strong>") : sa colonne, plus étroite que celle d'un simple
         rond au repos (voir "grid-template-columns" plus haut) et son
         texte nettement plus long rendent la taille par défaut ci-dessus
         (0.12, pensée pour un court chiffre de compteur) excessive ici —
         même sélecteur de base (".badge strong"), simplement qualifié par
         ".badge--wide" pour l'emporter (même spécificité, règle plus
         tardive dans le fichier). */
      & .badge--wide strong {
        font-size: max(12px, calc(var(--badge-d) * 0.08));
      }

      & .badge span:not(.digit) {
        font-size: max(11px, calc(var(--badge-d) * 0.062));
      }

      /* ERREUR CORRIGÉE : caler l'item RNCP (".badge--wide" simple, sans
         ".badge--img") sur 170px de haut + "aspect-ratio: 1.8" (hérité de
         la règle de base, plus haut) supposait une colonne large (~506px,
         l'ancien calcul erroné — voir "grid-template-columns" ci-dessus) ;
         avec une colonne plus étroite (ronds + RNCP se partageant l'espace
         restant une fois la colonne Qualiopi satisfaite, voir ci-dessus),
         ce même ratio donnait une largeur cible bien supérieure à la
         largeur de colonne réellement disponible — la boîte se retrouvait
         RÉTRÉCIE à une largeur proche de sa hauteur (170px), un rapport
         proche du carré, confirmé en conditions réelles.
         "aspect-ratio: auto" (au lieu d'hériter "1.8" de la règle de base)
         : supprime ce ratio forcé — la largeur suit uniquement la largeur
         disponible de sa colonne de grille (jamais calculée à partir de la
         hauteur), un rectangle plus ou moins allongé selon l'espace réel,
         jamais un carré. "height: 170px" (comme auparavant, CONSERVÉ tel
         quel) : même hauteur que les 3 autres ".badge" de la ligne — pas
         de "height: auto" (essayé puis abandonné : réintroduisait une
         hauteur variable, hors exigence d'uniformité avec les ronds et le
         logo). "width: auto" (plutôt que le "460px" fixe de la règle de
         base) : la largeur suit la largeur disponible de sa colonne, pas
         une valeur fixe pensée pour une mise en page large. Le plafond/
         troncature ("max-height: 200px"/"overflow: hidden") de la règle de
         base restent hérités tels quels, sans effet tant que le contenu
         tient dans les 170px de hauteur fixée ici. */
      & .badge--wide {
        width: auto;
        height: 170px;
        aspect-ratio: auto;
      }

      /* Modificateur supplémentaire, posé UNIQUEMENT sur l'item logo
         Qualiopi (".badge--img", index.php — jamais sur "RNCP · PCM® ·
         Codéveloppement", qui reste un ".badge--wide" simple) : affiche ce
         logo à sa taille réelle (487×170, grandeur nature — aucune mise à
         l'échelle, contenu net), SANS CONDITION.
         "max-width: inherit" (et non "100%", essayé puis abandonné de
         nouveau) : "100%" était censé rester relatif à la propre zone de
         grille de l'item, mais s'est avéré, en conditions réelles (panneau
         "Computed" de l'inspecteur Chrome), se résoudre à une valeur
         minuscule (168px), bien en-deçà de la largeur réelle de la colonne
         — un comportement du moteur de rendu avec CE contexte précis
         (pourcentage sur un item de grille à largeur ET hauteur explicites,
         au sein d'une piste "fr"), pas un bug côté maquette. "inherit" va
         chercher le "max-width" du <ul> PARENT (qui n'en a pas, "none") et
         supprime donc toute limite — le logo s'affiche enfin à sa taille
         réelle, confirmé en conditions réelles. Le risque de débordement
         que cela réintroduit (le logo, non borné, pourrait chevaucher ses
         voisins si sa colonne devenait plus étroite que 487px) est
         neutralisé en amont par le plancher "minmax(490px, …)" posé sur
         "grid-template-columns" ci-dessus, plutôt que par une limite posée
         ici sur l'item lui-même. "height: 170px" reste fixe (pas
         d'"aspect-ratio") : la hauteur commune aux 4 badges (voir le
         plafond ci-dessus) est ainsi TOUJOURS garantie. "max-height: 170px"
         : désormais la même valeur que le plafond hérité de ".badge--wide"
         juste au-dessus (plus de conflit entre les deux comme auparavant),
         réaffirmée ici par explicite plutôt que par simple héritage, pour
         que cette règle reste autonome si la valeur partagée venait à
         changer. */
      & .badge--img {
        width: 487px;
        height: 170px;
        max-width: inherit;
        max-height: 170px;
        padding-left: 0;
        padding-right: 0;
      }
    }
  }
}

/**
 * Trust strip/logos clients
 */
section.trust-strip {
  padding: var(--space-10) 0;
  background-color: var(--color-white);
  display: flex;
  align-items: center;
  gap: 28px;
  flex-wrap: wrap;
  position: relative;
  z-index: 1;

  /* flex-item : sans min-width:0, la piste width:max-content du défilant
     impose sa largeur intrinsèque (min-width:auto) et déborde la page */
  &>.container {
    min-width: 0;
    width: 100%;
  }

  & header {
    margin: 0 0 var(--space-10) 0;

    & h2 {
      margin: 0;
    }
  }

  & .logos-scroller {
    overflow: hidden;
    /* fondu des bords pour une entrée/sortie douce des logos */
    -webkit-mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);
    mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);

    &:hover .logos {
      animation-play-state: paused;
    }
  }

  & .logos {
    --logos-gap: var(--space-6);
    --logos-speed: 40s;
    display: flex;
    align-items: center;
    gap: var(--logos-gap);
    width: max-content;
    animation: logos-marquee var(--logos-speed) linear infinite;

    & li {
      flex: 0 0 auto;
      display: flex;
      align-items: center;
      justify-content: center;

      & a {
        display: flex;
        align-items: center;
        justify-content: center;
      }

      & img {
        display: block;
        max-height: 40px;
        max-width: none;
        width: auto;
        height: auto;
        transition: filter var(--transition), opacity var(--transition);
      }

      &:hover img {
        filter: none;
        /* monochrome teinté brand : gris → sépia → rotation vers le teal profond (#38806B ≈ 163°) */
        filter: grayscale(1) sepia(1) hue-rotate(130deg) saturate(1.4) brightness(0.9);
        opacity: 0.8;
      }
    }

    @media (min-width: 640px) {
      & {
        --logos-gap: var(--space-8);
      }
    }

    @media (min-width: 1024px) {
      & {
        --logos-gap: var(--space-12);
        --logos-speed: 48s;

        & li img {
          max-height: 48px;
        }
      }
    }
  }

  @media (prefers-reduced-motion: reduce) {
    & .logos {
      animation: none;
      width: auto;
      flex-wrap: wrap;
      justify-content: center;

      & li[aria-hidden="true"] {
        display: none;
      }
    }

    & .logos-scroller {
      -webkit-mask-image: none;
      mask-image: none;
    }
  }
}

/* Piste = 2 moitiés identiques ; -50% ± demi-gap = décalage exact d'une moitié,
   la boucle repart donc sans saut visible */
@keyframes logos-marquee {
  to {
    transform: translateX(calc(-50% - var(--logos-gap) / 2));
  }
}

/**
 * Services/offers section
 */
section.services {
  & .card {
    padding: var(--space-6);
    display: flex;
    flex-direction: column;
    text-decoration: none;
    color: inherit;
    background-repeat: no-repeat;
    background-size: auto, cover;
    background-position: center;
    /* .card is an <article>, not the link anymore (CMS imports render it as
       a Group block, which can't be <a>) — the real link lives in .link;
       stretch it over the whole card so the click target is unchanged. */
    position: relative;

    @media (min-width: 640px) {
      & {
        padding: var(--space-8);
      }
    }

    @media (min-width: 1024px) {
      & {
        /* Less horizontal padding than vertical: frees up the width the h3
           needs to stay on one line (nowrap, below) without shrinking font-size */
        padding: var(--space-8) var(--space-4);
      }
    }

    &:hover {
      transform: translateY(-4px);
      border-color: var(--color-brand);

      & .icon {
        background-color: var(--color-brand);
      }
    }

    & .icon {
      width: 38px;
      height: 38px;
      background-color: var(--color-brand);
      border-radius: var(--radius-md);
      margin-bottom: var(--space-5);
      color: var(--color-white);
      transition: background-color var(--transition);
    }

    & h3 {
      @media (min-width: 1024px) {
        & {
          white-space: nowrap;
          /* Grid stays at 4 columns — the reduced horizontal .card padding above
             frees the width needed for "Conseil RH stratégique" (longest title)
             to fit on one line without shrinking font-size */
        }
      }
    }

    & .text {
      flex: 1;
      margin-bottom: var(--space-5);
    }

    & nav {
      & ul {
        gap: var(--space-3);
        transition: gap var(--transition);
      }

      & a {
        position: static;
        text-decoration: none;

        &::after {
          content: '';
          position: absolute;
          inset: 0;
        }
      }
    }

    &.card--highlight {
      border-color: transparent;

      & .icon {
        background-color: rgba(194, 161, 90, 0.36);
      }

      & h3 {
        color: #fff;
      }

      & .text {
        color: rgba(255, 255, 255, 0.7);
      }

      & nav a {
        color: var(--color-brand);
      }
    }
  }
}

/**
 * Testimonials section
 */
section.testimonials {
  & .carousel {
    position: relative;
  }

  /* Single-row horizontal scroll track (CSS-only carousel, no JS) */
  & .grid-2c {
    display: flex;
    /* Mobile (<640px, 1 card visible at a time): natural height per card — no
       reason to stretch a short card to match a long, currently off-screen
       sibling (they're all one flex row regardless of scroll position) */
    align-items: flex-start;
    overflow-x: auto;
    overflow-y: auto;
    /* "auto" (pas "hidden") sur l'axe vertical, bien qu'il n'y ait jamais de
       vrai débordement à faire défiler ici (cards de même hauteur, voir
       "align-items: stretch" ci-dessous) : sans ça, la navigation par ancre
       des flèches (§ "Prev/Next arrows" plus bas) fait défiler TOUTE LA
       PAGE verticalement, pas seulement la piste horizontalement.
       "overflow-y: hidden" ne fait pas de ".grid-2c" un conteneur de scroll
       valide aux yeux de l'algorithme natif "scroll to fragment" (déclenché
       par le clic sur un lien `#ancre`) : n'y trouvant rien à faire défiler
       verticalement, il remonte jusqu'au document et aligne son bord
       supérieur sur celui de la fenêtre. "auto" fait de ".grid-2c" un
       conteneur de scroll vertical valide (même vide, sans overflow réel),
       ce qui arrête cette remontée avant qu'elle n'atteigne la page — sans
       barre de défilement visible ni scroll utilisateur réellement possible
       (règles ci-dessous, déjà présentes pour l'axe horizontal, masquent
       aussi celle-ci si elle apparaissait). */
    scroll-snap-type: x proximity;
    /* "proximity" plutôt que "mandatory" : les flèches déplacent la piste de
       plusieurs cards à la fois (V = 2, voir plus haut), et
       "mandatory" force le navigateur à respecter l'alignement de CHAQUE
       card traversée en route pendant le "scroll-behavior: smooth" — d'où
       l'effet de "vague"/à-coups au clic. La card d'arrivée (calculée par
       "nextTarget"/"prevTarget" ci-dessus) tombe de toute façon déjà
       exactement sur un point d'ancrage : "proximity" n'a donc aucun effet
       sur le résultat final, seulement sur le trajet parcouru pour y
       arriver. */
    scroll-behavior: smooth;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    -ms-overflow-style: none;
    padding: 6px 2px 16px;

    &::-webkit-scrollbar {
      display: none;
    }

    @media (min-width: 640px) {
      & {
        /* 2 cards visible together: match their height so the blockquote
           (flex-grow: 1, see .card) stays top-aligned and the header lines up
           at the same bottom position across every visible card */
        align-items: stretch;
      }
    }
  }

  /* Prev/Next arrows — pure CSS3, no JS. The arrows page by full batches of V
     visible cards (V = 2 between 640-1023px, V = 3 from 1024px; one .set of
     baked hrefs per V, gated by media query below). Fragment navigation uses
     inline:nearest — a rightward target lands aligned to the viewport END, a
     leftward one to the START — so "Next" targets the END card of the next
     batch (its first card lands in FIRST position; the browser's scroll clamp
     puts the LAST card in LAST position when fewer than V cards remain) and
     "Prev" targets the FIRST card of the previous batch.
     A given card lands differently depending on travel direction, so each
     card carries two invisible anchors (.anchor-fwd / .anchor-bwd) and each
     (direction, position) combination owns a .pair of arrows; the rules at
     the end of this block show the single pair matching the current :target.
     Matched by :nth-child() rather than by id: those rules are generic and
     keep working unchanged if the number of testimonials in the JSON table
     changes — nothing here is tied to specific testimonial content. */
  & .carousel-arrows {
    display: none;

    @media (min-width: 640px) {
      & {
        display: block;
      }
    }

    & .set {
      display: none;
    }

    /* Un seul palier désormais (V = 2, jamais 3) : affiché dès 640px, sans
       jamais être masqué à nouveau à 1024px+ (il n'y a plus de second
       ".set" à faire prendre le relais). */
    & .set.step-2 {
      @media (min-width: 640px) {
        & {
          display: block;
        }
      }
    }

    & .pair {
      display: none;
    }

    /* Default, before any card has been targeted: same window as arriving
       backward on card 1 (cards 1..V visible) */
    & .pair[data-state="bwd-1"] {
      display: flex;
    }

    & .carousel-arrow {
      display: flex;
      align-items: center;
      justify-content: center;
      position: absolute;
      top: 44%;
      transform: translateY(-50%);
      width: 44px;
      height: 44px;
      border-radius: 50%;
      background: var(--color-white);
      border: 1px solid var(--color-gray-soft);
      box-shadow: var(--shadow-md);
      color: var(--color-black);
      transition: background-color var(--transition), color var(--transition), border-color var(--transition);

      &:hover {
        background: var(--color-brand);
        border-color: var(--color-brand);
        color: var(--color-white);
      }

      & svg {
        width: 18px;
        height: 18px;
      }
    }

    & .next {
      right: -18px;
    }

    & .prev {
      left: -18px;
      transform: translateY(-50%) rotate(180deg);
    }

    @media (min-width: 1280px) {
      & .next {
        right: -22px;
      }

      & .prev {
        left: -22px;
      }
    }
  }

  /* One rule per (direction, card position) — positions 1..12; extend if a
     page ever needs more than 12 testimonials. While that position's anchor
     is the fragment target, hide the default bwd-1 pair and reveal the
     matching state's own pair. */
  &:has(.grid-2c > :nth-child(1) .anchor-fwd:target) {
    & .pair[data-state="bwd-1"] {
      display: none;
    }

    & .pair[data-state="fwd-1"] {
      display: flex;
    }
  }

  &:has(.grid-2c > :nth-child(2) .anchor-fwd:target) {
    & .pair[data-state="bwd-1"] {
      display: none;
    }

    & .pair[data-state="fwd-2"] {
      display: flex;
    }
  }

  &:has(.grid-2c > :nth-child(3) .anchor-fwd:target) {
    & .pair[data-state="bwd-1"] {
      display: none;
    }

    & .pair[data-state="fwd-3"] {
      display: flex;
    }
  }

  &:has(.grid-2c > :nth-child(4) .anchor-fwd:target) {
    & .pair[data-state="bwd-1"] {
      display: none;
    }

    & .pair[data-state="fwd-4"] {
      display: flex;
    }
  }

  &:has(.grid-2c > :nth-child(5) .anchor-fwd:target) {
    & .pair[data-state="bwd-1"] {
      display: none;
    }

    & .pair[data-state="fwd-5"] {
      display: flex;
    }
  }

  &:has(.grid-2c > :nth-child(6) .anchor-fwd:target) {
    & .pair[data-state="bwd-1"] {
      display: none;
    }

    & .pair[data-state="fwd-6"] {
      display: flex;
    }
  }

  &:has(.grid-2c > :nth-child(7) .anchor-fwd:target) {
    & .pair[data-state="bwd-1"] {
      display: none;
    }

    & .pair[data-state="fwd-7"] {
      display: flex;
    }
  }

  &:has(.grid-2c > :nth-child(8) .anchor-fwd:target) {
    & .pair[data-state="bwd-1"] {
      display: none;
    }

    & .pair[data-state="fwd-8"] {
      display: flex;
    }
  }

  &:has(.grid-2c > :nth-child(9) .anchor-fwd:target) {
    & .pair[data-state="bwd-1"] {
      display: none;
    }

    & .pair[data-state="fwd-9"] {
      display: flex;
    }
  }

  &:has(.grid-2c > :nth-child(10) .anchor-fwd:target) {
    & .pair[data-state="bwd-1"] {
      display: none;
    }

    & .pair[data-state="fwd-10"] {
      display: flex;
    }
  }

  &:has(.grid-2c > :nth-child(11) .anchor-fwd:target) {
    & .pair[data-state="bwd-1"] {
      display: none;
    }

    & .pair[data-state="fwd-11"] {
      display: flex;
    }
  }

  &:has(.grid-2c > :nth-child(12) .anchor-fwd:target) {
    & .pair[data-state="bwd-1"] {
      display: none;
    }

    & .pair[data-state="fwd-12"] {
      display: flex;
    }
  }

  &:has(.grid-2c > :nth-child(2) .anchor-bwd:target) {
    & .pair[data-state="bwd-1"] {
      display: none;
    }

    & .pair[data-state="bwd-2"] {
      display: flex;
    }
  }

  &:has(.grid-2c > :nth-child(3) .anchor-bwd:target) {
    & .pair[data-state="bwd-1"] {
      display: none;
    }

    & .pair[data-state="bwd-3"] {
      display: flex;
    }
  }

  &:has(.grid-2c > :nth-child(4) .anchor-bwd:target) {
    & .pair[data-state="bwd-1"] {
      display: none;
    }

    & .pair[data-state="bwd-4"] {
      display: flex;
    }
  }

  &:has(.grid-2c > :nth-child(5) .anchor-bwd:target) {
    & .pair[data-state="bwd-1"] {
      display: none;
    }

    & .pair[data-state="bwd-5"] {
      display: flex;
    }
  }

  &:has(.grid-2c > :nth-child(6) .anchor-bwd:target) {
    & .pair[data-state="bwd-1"] {
      display: none;
    }

    & .pair[data-state="bwd-6"] {
      display: flex;
    }
  }

  &:has(.grid-2c > :nth-child(7) .anchor-bwd:target) {
    & .pair[data-state="bwd-1"] {
      display: none;
    }

    & .pair[data-state="bwd-7"] {
      display: flex;
    }
  }

  &:has(.grid-2c > :nth-child(8) .anchor-bwd:target) {
    & .pair[data-state="bwd-1"] {
      display: none;
    }

    & .pair[data-state="bwd-8"] {
      display: flex;
    }
  }

  &:has(.grid-2c > :nth-child(9) .anchor-bwd:target) {
    & .pair[data-state="bwd-1"] {
      display: none;
    }

    & .pair[data-state="bwd-9"] {
      display: flex;
    }
  }

  &:has(.grid-2c > :nth-child(10) .anchor-bwd:target) {
    & .pair[data-state="bwd-1"] {
      display: none;
    }

    & .pair[data-state="bwd-10"] {
      display: flex;
    }
  }

  &:has(.grid-2c > :nth-child(11) .anchor-bwd:target) {
    & .pair[data-state="bwd-1"] {
      display: none;
    }

    & .pair[data-state="bwd-11"] {
      display: flex;
    }
  }

  &:has(.grid-2c > :nth-child(12) .anchor-bwd:target) {
    & .pair[data-state="bwd-1"] {
      display: none;
    }

    & .pair[data-state="bwd-12"] {
      display: flex;
    }
  }

  & .card {
    padding: 24px;
    position: relative;
    /* Comme "section.method .card" (règle générique "&.header-grid & .card"
       plus haut) : découpe la barre "::before" ci-dessous sur l'arrondi
       ("border-radius: var(--radius-md)", ".card" générique) au lieu de
       laisser ses coins carrés déborder du coin arrondi de la carte. */
    overflow: hidden;
    display: flex;
    flex-direction: column;
    gap: 0;
    background-image: none;
    background-color: var(--color-white);
    flex-shrink: 0;
    scroll-snap-align: start;
    /* Mobile-first: 1 card visible, then 2 (from 640px, jamais plus — voir
       "@media (min-width: 640px)" ci-dessous, seul palier restant) */
    flex-basis: 100%;

    /* Invisible fragment anchors (see card/testimonial.php) — same box as the
       card so fragment navigation scrolls exactly as if the card itself were
       targeted; display:none would drop the box and kill the scroll */
    & .anchor {
      position: absolute;
      inset: 0;
      pointer-events: none;
    }

    @media (min-width: 640px) {
      & {
        flex-basis: calc((100% - var(--space-8)) / 2);
        align-self: stretch;
        /* Renforce "align-items: stretch" du ".grid-2c" parent (ci-dessus) :
           dans un flex container avec "overflow-x", certains navigateurs ne
           stretchent pas toujours fiablement les items sur l'axe croisé —
           explicite ici pour garantir des cards de même hauteur, condition
           nécessaire à un scroll horizontal sans "vague" verticale. */
      }
    }

    /* Même animation que "section.method .card" (règle générique
       "&.header-grid & .card" plus haut dans ce fichier) : barre pleine
       largeur qui se déploie depuis la gauche au survol — absente ici
       jusqu'à présent (seuls "translateY"/"box-shadow" existaient). */
    &::before {
      content: '';
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 3px;
      background: var(--color-brand);
      transform: scaleX(0);
      transform-origin: left;
      transition: transform .35s var(--ease-refined);
    }

    &:hover {
      transform: translateY(-4px);
      box-shadow: var(--shadow-md);

      &::before {
        transform: scaleX(1);
      }
    }

    & blockquote {
      position: relative;
      /* Nécessaire pour que les guillemets ci-dessous ("position: absolute")
         se positionnent par rapport à CE "blockquote" (ses propres coins),
         pas par rapport à ".card" (l'ancêtre positionné le plus proche à
         défaut) — sans quoi le guillemet fermant, calé en bas de la carte,
         chevaucherait "header" (lui-même poussé en bas via "margin-top:
         auto", voir plus bas). */
      color: var(--color-black);
      line-height: 1.55;
      margin: 0;
      flex-grow: 1;
      /* Texte d'un avis : en italique (règle générale des citations/avis). */
      font-style: italic;

      & p {
        position: relative;
        margin: 0;
        padding: 60px 0 40px;
        /* "margin: 0" annule la marge par défaut du <p>. Le padding, lui,
           ne déplace QUE le texte — pas les guillemets ci-dessous
           ("position: absolute", calés à 8px du bord réel de ce <p>, pas
           du texte) : un simple "padding: 24px" ne suffisait donc pas, le
           guillemet (haut de 48px, débutant à 8px du bord) empiétant
           jusqu'au texte. En haut, "calc()" explicite les 3 quantités qui
           s'additionnent verticalement, du bord de ce <p> jusqu'au texte :
           8px (retrait du guillemet depuis le bord) + 48px (sa hauteur,
           même valeur que le "font-size" ci-dessous) + 24px (espace demandé
           entre le guillemet et le texte). En bas, volontairement réduit
           (60px → 40px, asymétrique avec le haut) : resserre l'espace entre
           le guillemet fermant et le "<header>" qui suit (avatar/nom),
           réduisant d'autant la hauteur de ".card" — un chevauchement
           léger avec la dernière ligne du texte le plus long devient
           possible (le guillemet ne demande plus que 40-8-48 = -16px de
           marge, contre 4px avant), accepté ici pour ce gain de hauteur. */

        /* Guillemets décoratifs, sous forme de gros points-virgules arrondis
       (plutôt que le guillemet courbe "“”", jugé pas assez rond) : entourés
       d'un peu d'espace, à l'intérieur du coin supérieur gauche pour
       l'ouvrant, du coin inférieur droit pour le fermant — un léger
       décalage ("top"/"left" ou "bottom"/"right" à 8px, pas 0) écarte
       chaque guillemet du coin exact plutôt que de le coller dessus.
       Réduits (80px → 48px) pour tenir dans une carte moins haute. */
        &::before,
        &::after {
          position: absolute;
          font-family: var(--font-heading);
          font-size: 48px;
          color: var(--color-brand);
          line-height: 1;
          opacity: 0.5;
          pointer-events: none;
        }

        &::before {
          content: '\275D';
          top: 8px;
          left: 8px;
        }

        &::after {
          content: '\275E';
          bottom: 8px;
          right: 8px;
          /* Coin inférieur droit DE "blockquote" (et non de la carte, ni un
           décalage fixe de 160px hérité d'une carte plus haute) : reste
           correct quelle que soit la hauteur réelle du texte cité. */
        }
      }
    }

    & header {
      display: flex;
      align-items: center;
      gap: 12px;
      margin-top: auto;
      margin-bottom: 0;
      /* Pousse le header en bas de la carte, même si "blockquote" (au-dessus,
         "flex-grow: 1") ne remplissait pas déjà tout l'espace disponible —
         garantie plus explicite/robuste que de compter uniquement sur ce
         "flex-grow" du frère précédent. */
      padding-top: 0;

      & .avatar {
        width: 44px;
        height: 44px;
        border-radius: 50%;
        background: linear-gradient(135deg, var(--color-brand), var(--color-brand));
        display: flex;
        align-items: center;
        justify-content: center;
        color: var(--color-black);
        font-family: var(--font-body);
        font-weight: 600;
        font-size: var(--text-sm);
        letter-spacing: 0.02em;
        flex-shrink: 0;
      }

      & h2 {
        display: block;
        font-weight: 600;
        font-size: var(--text-base);
        color: var(--color-black);
        margin: 0;
      }

      & h3 {
        font-family: var(--font-body);
        font-weight: 400;
        font-size: var(--text-sm);
        color: var(--color-gray-soft);
        margin: 0;
      }

      & .rate {
        color: var(--color-brand);
        font-size: var(--text-sm);
        margin-top: 2px;
      }
    }
  }
}

/**
 * Contact section
 */
section.contact {
  position: relative;
  overflow: hidden;

  & .container {
    position: relative;
    z-index: 1;
    display: grid;
    grid-template-columns: 1fr;
    gap: 40px;
    align-items: center;

    @media (min-width: 768px) {
      & {
        grid-template-columns: 1fr 1fr;
        gap: 60px;
      }
    }
  }

  & header {
    & h2 {
      font-size: var(--text-xl);
      margin: 12px 0 18px;
      letter-spacing: -0.025em;
    }

    & .text {
      & p {
        color: rgba(255, 255, 255, 0.78);
        margin-bottom: 28px;
        max-width: 480px;
      }

      & ul {
        display: flex;
        flex-direction: column;
        gap: 12px;
        margin-top: 16px;
        padding: 0;
        list-style: none;

        & li {
          display: flex;
          align-items: center;
          gap: 12px;
          color: rgba(255, 255, 255, 0.92);

          &::before {
            content: "✓";
            display: inline-flex;
            align-items: center;
            justify-content: center;
            width: 22px;
            height: 22px;
            border-radius: 50%;
            background-color: rgba(84, 192, 160, 0.15);
            color: var(--color-brand);
            font-size: var(--text-sm);
            font-weight: 700;
            flex-shrink: 0;
          }
        }
      }
    }

    & footer {
      border: none;
      padding: 0;
      background: none;
      padding-top: 24px;

      & ul {
        display: flex;
        gap: 18px;
        flex-wrap: wrap;
        list-style: none;
        padding: 0;
        margin: 0;

        & li a {
          display: inline-flex;
          align-items: center;
          gap: 8px;
          color: rgba(255, 255, 255, 0.85);
          font-weight: 500;
          transition: color .2s var(--ease-refined);

          &:hover {
            color: var(--color-brand);
          }

          & svg {
            width: 18px;
            height: 18px;
            color: var(--color-brand);
          }
        }
      }
    }
  }

  & article {
    background: var(--color-white);
    color: var(--color-black);
    border-radius: var(--radius-md);
    padding: 36px;
    box-shadow: var(--shadow-lg);
  }
}

/**
 * CTA section
 */
section.cta {
  & .container {
    text-align: center;

    & .label {
      margin-bottom: var(--space-3);
    }

    & h2 {
      margin-bottom: var(--space-4);
    }

    & nav {
      margin-top: 52px;
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: var(--space-4);

      @media (min-width: 480px) {
        & {
          flex-direction: row;
          justify-content: center;
          gap: var(--space-6);
        }
      }
    }
  }
}

/**
 * News section
 */
section.blog {
  & .news-grid {
    & .card {
      padding: 0;
      overflow: hidden;
      text-decoration: none;
      color: inherit;
      background-color: var(--color-white);
      display: flex;
      flex-direction: column;
      height: 100%;
      /* Fill the stretched grid cell so every card in a row is the same height */
      position: relative;
      /* Anchor for the stretched read-more link overlay */

      &:hover {
        transform: translateY(-3px);

        & .img {
          & img {
            transform: scale(1.03);
          }
        }
      }

      & .img {
        height: 220px;
        overflow: hidden;

        & img {
          width: 100%;
          height: 100%;
          object-fit: cover;
          transition: transform 600ms var(--ease-refined);
        }
      }

      & .body {
        padding: var(--space-6);
        flex: 1;
        display: flex;
        flex-direction: column;
      }

      & header {
        display: flex;
        align-items: center;
        gap: var(--space-3);
        margin: 0 0 var(--space-4) 0;
      }

      & .category {
        font-size: var(--text-xs);
        font-weight: 600;
        text-transform: uppercase;
        letter-spacing: 0.08em;
        color: var(--color-brand);
        background-color: var(--color-transp);
        padding: 2px 10px;
        border-radius: var(--radius-full);
      }

      & time {
        font-size: var(--text-xs);
        color: var(--color-gray);
      }

      & h3 {
        font-size: inherit;
      }

      /* Carte entière cliquable SANS <a> englobant (lien étiré, "stretched
         link") : la carte est un <article> sémantique dont le SEUL lien réel
         est ".link" (« Lire l'article »). Son "::after" recouvre toute la
         carte ("position: absolute; inset: 0") : le "position: relative" de
         ".card" (plus haut) est son ancre, et ".link" lui-même reste en
         "position: static" — sans quoi le recouvrement se limiterait à la
         boîte du lien. Un clic n'importe où dans la carte suit donc le lien
         (curseur « main » compris), alors que le HTML reste accessible : un
         seul lien annoncé par carte, au libellé explicite, et pas de bloc
         <a> contenant des titres/paragraphes. Même technique que la maquette
         ODL Notaires (notaire2.1). */
      & .link {
        &::after {
          content: "";
          position: absolute;
          inset: 0;
        }
      }

      /* Le contour de focus du lien ne suit que sa propre boîte : on le porte
         aussi sur la carte entière pour la navigation au clavier. */
      &:has(.link:focus-visible) {
        outline: 2px solid var(--color-brand);
        outline-offset: 2px;
      }
    }
  }

  & nav {
    text-align: center;
  }
}

/**
 * Footer
 */
/* Couleurs de marque mises à jour (--color-brand/--color-brand-soft) :
   "--color-brand" sur ce fond "--color-brand-soft" tombe à 1,29 de
   contraste — illisible. Chaque élément de texte/icône du pied de page
   auparavant coloré "--color-brand" passe à "--color-black" ci-dessous
   (9,05 de contraste, même convention que ".sidebar-card.profile"/
   ".contact-info-card") — "--color-white" ne suffirait pas non plus ici
   (1,80), ce "--color-brand-soft" restant relativement clair.
   "--color-gray-soft" (texte du bandeau légal, ".bottom") tombe lui aussi
   sous le seuil (2,08, contre 3,38 auparavant) — remplacé par
   "--color-gray" (4,64, conforme), déjà utilisé ailleurs dans ce pied de
   page. */
.site-footer {
  background-color: var(--color-brand-soft);
  /* Même recette que ".site-header.scrolled" ("box-shadow: var(--shadow-md)",
     soit "0 4px 16px rgba(35,31,32,.10)") — décalage vertical inversé
     ("-4px" au lieu de "4px") pour porter l'ombre au-dessus du footer (vers
     le contenu qui le précède) plutôt qu'en dessous. */
  box-shadow: 0 -4px 16px rgba(35, 31, 32, 0.10);
  padding: 70px 0 30px;
  font-size: var(--text-sm);

  & .footer-main {
    display: grid;
    grid-template-columns: 1fr 1fr;
    grid-template-areas:
      "brand  brand"
      "offres savoir"
      "contact contact";
    gap: var(--space-8);
    padding-bottom: 50px;
    border-bottom: 1px solid var(--color-black);

    & .brand {
      grid-area: brand;
    }

    & nav:nth-of-type(1) {
      grid-area: offres;
    }

    & nav:nth-of-type(2) {
      grid-area: savoir;
    }

    & nav:nth-of-type(3) {
      grid-area: contact;
    }

    /* Smallest supported width and up: all three nav columns fit on one row */
    @media (min-width: 425px) {
      & {
        grid-template-columns: repeat(3, 1fr);
        grid-template-areas:
          "brand  brand  brand"
          "offres savoir contact";
      }
    }

    @media (min-width: 768px) {
      & {
        grid-template-columns: 2.2fr 1fr 1fr 1fr;
        grid-template-areas: "brand offres savoir contact";
        gap: 20px;
      }
    }

    @media (min-width: 1024px) {
      & {
        gap: 40px;
      }
    }
  }

  & .brand {
    & .desc {
      margin-top: 16px;
      line-height: 1.55;
      color: var(--color-gray);
      max-width: 320px;
    }

    & .certifications {
      display: flex;
      flex-wrap: wrap;
      align-items: center;
      gap: 16px;
      margin-top: 18px;
    }

    & .certified {
      display: inline-flex;
      align-items: center;
      gap: 8px;
      padding: 8px 14px;
      background: var(--color-white);
      border: 1px solid var(--color-brand);
      border-radius: var(--radius-full);
      font-size: var(--text-sm);
      font-weight: 600;
      color: var(--color-brand);

      &::before {
        content: '';
        width: 8px;
        height: 8px;
        border-radius: 50%;
        background: var(--color-brand);
        box-shadow: 0 0 0 3px var(--color-brand);
        flex-shrink: 0;
      }
    }

    & .badges {
      display: flex;
      /* Explicite : la règle par défaut de "ul.badges" (mono-ligne dès
         640px, "justify-content: center") ne doit pas centrer cette
         rangée de logos, alignée à gauche depuis toujours. */
      justify-content: flex-start;
      align-items: center;
      gap: 12px;
      list-style: none;

      & img {
        width: 44px;
        height: 44px;
      }
    }
  }

  & h2 {
    font-family: var(--font-body);
    font-weight: 600;
    color: var(--color-black);
    text-transform: uppercase;
    letter-spacing: 0.12em;
    margin-bottom: 14px;
  }

  & nav {
    & a {
      display: block;
      padding: 4px 0;
      color: var(--color-gray);
      transition: color .2s var(--ease-refined);

      &:hover {
        color: var(--color-black);
      }
    }

  }

  & nav.contact ul li:last-child a {
    color: var(--color-black);
    font-weight: 600;

    &:hover {
      color: var(--color-black);
      text-decoration: underline;
    }
  }

  & .contact address {
    & div {
      display: flex;
      align-items: flex-start;
      gap: var(--space-3);
      color: var(--color-gray);
      margin-bottom: var(--space-4);

      & .icon {
        width: 16px;
        height: 16px;
        flex-shrink: 0;
        margin-top: 2px;
        color: var(--color-black);
      }
    }
  }

  & .bottom {
    padding-top: 24px;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    flex-wrap: wrap;
    gap: 16px;
    color: var(--color-gray);

    @media (min-width: 560px) {
      & {
        flex-direction: row;
        justify-content: space-between;
        align-items: center;
      }
    }

    & .copy {
      color: var(--color-gray);
    }

    & ul {
      display: flex;
      gap: 18px;

      & a {
        color: var(--color-gray);
        transition: color .2s var(--ease-refined);

        &:hover {
          color: var(--color-black);
        }
      }
    }
  }
}

/**
 * Cookie banner
 */
.cookie-banner {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 2000;
  background-color: var(--color-black);
  border-top: 2px solid var(--color-brand);
  transform: translateY(100%);
  transition: transform 400ms var(--ease-refined);
  box-shadow: 0 -8px 32px rgba(0, 0, 0, 0.20);

  &.visible {
    transform: translateY(0);
  }

  & .cookie-banner-inner {
    padding: var(--space-5) 0;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-4);
    flex-wrap: wrap;

    @media (min-width: 640px) {
      & {
        flex-direction: row;
        align-items: center;
        gap: var(--space-8);
      }
    }
  }

  & article {
    flex: 1;
    font-size: var(--text-sm);
    color: rgba(255, 255, 255, 0.75);
    line-height: 1.6;
    min-width: 280px;

    & strong {
      color: var(--color-white);
      display: block;
      margin-bottom: var(--space-1);
    }

    & a {
      color: var(--color-brand);
      text-decoration: underline;
    }
  }

  & nav {
    display: flex;
    gap: var(--space-3);
    flex-shrink: 0;
    width: 100%;

    & .btn {
      flex: 1;
      justify-content: center;
    }

    & .btn-outline {
      color: var(--color-white);
      border-color: rgba(255, 255, 255, 0.4);

      &:hover {
        background-color: rgba(255, 255, 255, 0.1);
        border-color: var(--color-white);
        color: var(--color-white);
      }
    }

    @media (min-width: 640px) {
      & {
        width: auto;
      }

      & .btn {
        flex: none;
        justify-content: initial;
      }
    }
  }
}

/* Scroll reveals
   Hidden state gated behind .coax-js (added to <html> by a one-line inline
   script in <head>). Without the gate, JS-disabled visitors and the WordPress
   block-editor canvas (where theme JS never runs) would see blank sections. */
.coax-js {
  & .reveal {
    opacity: 0;
    transform: translateY(10px);
    transition: opacity 500ms var(--ease-refined),
      transform 500ms var(--ease-refined);
  }

  & .reveal-item {
    opacity: 0;
    transform: translateY(8px);
    transition: opacity 400ms var(--ease-refined),
      transform 400ms var(--ease-refined);
  }
}

.reveal.is-visible,
.reveal-item.is-visible {
  opacity: 1;
  transform: translateY(0);
}

/**
 * Accessibility
 */
:focus-visible {
  outline: 2px solid var(--color-brand);
  outline-offset: 2px;
  border-radius: 2px;
}

/**
 * Subpage styles
 */

/* PAGE CONTENT — Harmonize spacing below hero */
section.page-content {
  max-width: 820px;
  margin: 0 auto;
  padding: var(--space-12) var(--space-4);

  @media (min-width: 640px) {
    & {
      padding: var(--space-16) var(--space-6);
    }
  }

  @media (min-width: 1024px) {
    & {
      padding: var(--space-20) 0;
    }
  }

  & article {
    @media (min-width: 640px) {
      & {
        text-align: justify;
      }
    }

    & h2 {
      font-family: var(--font-heading);
      font-size: var(--text-xl);
      font-weight: 600;
      color: var(--color-brand);
      margin-top: var(--space-10);
      margin-bottom: var(--space-4);
      padding-bottom: var(--space-3);

      &:first-child {
        margin-top: 0;
      }
    }

    & h3 {
      font-family: var(--font-heading);
      font-size: var(--text-lg);
      font-weight: 600;
      color: var(--color-black);
      margin-top: var(--space-6);
      margin-bottom: var(--space-3);
    }

    & p {
      font-size: var(--text-base);
      line-height: 1.8;
      color: var(--color-gray);
      margin-bottom: var(--space-4);
    }

    & ul:not(.values-grid) {
      list-style: disc;
      padding-left: var(--space-6);
      margin-bottom: var(--space-4);

      & li {
        color: var(--color-gray);
        margin-bottom: var(--space-2);
        line-height: 1.7;
      }
    }

    & ol {
      list-style: decimal;
      padding-left: var(--space-6);
      margin-bottom: var(--space-4);

      & li {
        color: var(--color-gray);
        margin-bottom: var(--space-2);
        line-height: 1.7;
      }
    }

    /* ":not(.btn)" : un lien stylé en bouton (".btn"/".btn-brand"/…) définit
       entièrement sa propre identité visuelle (couleur, fond, soulignement)
       et ne doit pas hériter du traitement "lien de prose" ci-dessous — sans
       cette exclusion, "text-decoration: underline" (ici) rajoute un
       soulignement que ".btn { text-decoration: none }" ne peut pas annuler
       (spécificité insuffisante : une seule classe contre 3 sélecteurs de
       type ici), et "&:hover { color: … }" recolore le texte du bouton au
       survol alors qu'aucune variante ".btn-*" ne définit sa propre couleur
       de survol (seuls le fond/l'ombre changent). */
    & a:not(.btn) {
      color: var(--color-brand);
      text-decoration: underline;
      text-underline-offset: 3px;
      transition: var(--transition);

      &:hover {
        color: var(--color-black);
      }
    }

    & .table {
      background: var(--color-white);
      border-radius: var(--radius-md);
      overflow: hidden;
      border: 1px solid var(--color-gray-soft);
      margin: var(--space-5) 0;
    }

    & table {
      width: 100%;
      border-collapse: collapse;
      font-size: var(--text-sm);

      & thead {
        & tr {
          background: var(--color-black);
          color: var(--color-white);
        }

        & th {
          padding: var(--space-3) var(--space-4);
          text-align: left;
          font-weight: 600;
        }
      }

      & tbody {
        & tr:nth-of-type(odd) {
          border-bottom: 1px solid var(--color-gray-soft);
        }

        & td {
          padding: var(--space-3) var(--space-4);
          color: var(--color-gray-soft);

          &.monospace {
            font-family: monospace;
          }
        }
      }
    }
  }
}

/* "section.page-content article a:not(.btn)" ci-dessus (0,2,3 : 2 classes
   — ".page-content" + le ".btn" de ":not()" —, 3 types) réécrit en
   "--color-brand" tout lien de prose, y compris à l'intérieur d'une
   section ".section-bg-brand-soft" (les accordéons "decor-*" des pages de
   service en sont, voir plus haut dans ce fichier) — où elle l'emporte sur
   la règle "&.section-bg-brand-soft & a" (0,1,2 : 1 classe, 2 types),
   recréant le problème de lisibilité (1,29 de contraste) que cette
   dernière règle visait à corriger. Battue ici en qualifiant le sélecteur
   par ".section-bg-brand-soft" en plus (3 classes au total avec le ".btn"
   de ":not()", contre 2 pour la règle d'origine — nul besoin de la
   répéter, chaque classe compte une fois) — gagne quel que soit le nombre
   de types, sans risque de dépasser la spécificité d'un ".btn" (jamais
   dans le même sous-arbre : "section.page-content" n'est utilisé que sur
   les pages de service, jamais sur index.php, où vivent les boutons
   ".btn-white"/".btn-outline-white" de "section.about"). ":not(.btn)"
   présent ici aussi, par sécurité structurelle : même si la spécificité
   dépassait un jour celle d'un bouton, cette règle ne pourrait alors
   toujours pas le cibler. */
section.page-content article .section-bg-brand-soft a:not(.btn) {
  color: var(--color-white);

  &:hover {
    color: var(--color-black);
  }
}

/* Même logique que la règle "a:not(.btn)" juste au-dessus : la règle
   sitewide "&.section-bg-brand-soft & h2 { color: var(--color-white) }"
   (0,0,1,2 : 1 classe + 2 types) perd face à "section.page-content
   article h2" (0,0,1,3 : 1 classe + 3 types) pour les sections
   "section-bg-brand-soft" déplacées à l'intérieur de "<article>"
   (formation.php : "section.method" sans classe "decor-*", donc non couverte
   par la règle "@scope (.page-service, .page-about)"; "section.handicap"
   avec "decor-echange" mais sur ".page--formation" hors de ce scope).
   Sélecteur qualifié par ".section-bg-brand-soft" → (0,0,2,3) :
   2 classes > 1 classe — gagne quel que soit le nombre de types. */
section.page-content article .section-bg-brand-soft h2 {
  color: var(--color-white);
}

/* Lien "Agefiph" (page Formation, section "Accueil et handicap",
   ".section-bg-brand-soft") devenu blanc : la règle juste au-dessus
   l'emporte sur la couleur "--color-brand" posée à l'intérieur de
   "@scope (.page--formation) { & section.page-content article>section {
   & ul.contact-list { & li { a {...} } } } }" (ligne ~3576) — malgré un
   calcul de spécificité qui, sur le papier, donnait l'avantage à cette
   dernière (le "&" en tête d'un bloc "@scope" résout en ":scope", qui ne
   semble pas compter comme attendu ici, constaté en conditions réelles).
   Même recette que la règle juste au-dessus (qualifiée par 3 classes :
   ".page-content" + ".contact-list" + le ".btn" de ":not()", contre 3
   pour la règle d'origine — gagne ici sur le nombre de types, 4 contre
   3), mais hors "@scope" : tout lien de ".contact-list" (n'importe quelle
   page utilisant "section.page-content") reste "--color-brand", y
   compris sur un fond "--color-brand-soft". */
section.page-content article ul.contact-list a:not(.btn) {
  color: var(--color-brand);

  &:hover {
    text-decoration: underline;
  }
}

/**
 * FAQ accordion
 */
.faq {
  & .container {
    display: grid;
    grid-template-columns: 1fr;
    gap: 36px;
    align-items: start;

    @media (min-width: 768px) {
      & {
        grid-template-columns: 0.9fr 1.1fr;
        gap: 60px;
      }
    }
  }

  & header {
    position: static;
    text-align: left;

    & .label {
      color: var(--color-brand);
    }

    & h2 {
      font-size: var(--text-xl);
      margin: 12px 0 18px;
    }

    & .text {
      margin-bottom: 22px;
    }

    @media (min-width: 768px) {
      & {
        position: sticky;
        top: 100px;
      }
    }
  }
}

.faq-list {
  display: flex;
  flex-direction: column;

  & details {
    border-bottom: 1px solid var(--color-white);
    transition: background .25s var(--ease-refined);

    &:first-child {
      border-top: 1px solid var(--color-white);
    }

    & summary {
      list-style: none;
      cursor: pointer;
      padding: 22px 0;
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 20px;
      font-weight: 600;
      color: var(--color-white);
      transition: color .2s var(--ease-refined);

      &::-webkit-details-marker {
        display: none;
      }

      &:hover {
        color: var(--color-brand-soft);
      }

      & h3 {
        font-family: var(--font-body);
        font-weight: 600;
        color: inherit;
        margin: 0;
      }

      & .faq-toggle {
        position: relative;
        width: 24px;
        height: 24px;
        flex-shrink: 0;

        &::before,
        &::after {
          content: "";
          position: absolute;
          background: currentColor;
          border-radius: 1px;
          transition: transform .25s var(--ease-refined);
        }

        &::before {
          left: 4px;
          right: 4px;
          top: 11px;
          height: 2px;
        }

        &::after {
          top: 4px;
          bottom: 4px;
          left: 11px;
          width: 2px;
        }
      }
    }

    &[open] summary {
      color: var(--color-white);

      & .faq-toggle::after {
        transform: scaleY(0);
      }
    }

    & div {
      padding: 0 0 24px;
      color: var(--color-white);
      line-height: 1.65;
      max-width: 620px;

      & p {
        margin: 0;
      }
    }
  }
}

/**
 * Content layout (2-col: body + sidebar)
 */
.content-layout {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-8);
  align-items: start;

  @media (min-width: 1024px) {
    & {
      grid-template-columns: 2fr 1fr;
      gap: var(--space-16);
    }
  }

  & article {
    & h2 {
      font-family: var(--font-heading);
      font-size: var(--text-xl);
      font-weight: 600;
      color: var(--color-brand);
      margin-top: var(--space-10);
      margin-bottom: var(--space-4);
      padding-bottom: var(--space-3);

      &:first-child {
        margin-top: 0;
      }
    }

    & h3 {
      font-family: var(--font-heading);
      font-size: var(--text-lg);
      font-weight: 600;
      color: var(--color-black);
      margin-top: var(--space-8);
      margin-bottom: var(--space-3);
    }

    & p {
      color: var(--color-gray);
      line-height: 1.8;
      margin-bottom: var(--space-4);
      font-size: var(--text-base);
    }

    & ul {
      list-style: disc;
      padding-left: var(--space-6);
      margin-bottom: var(--space-4);
    }

    & ol {
      list-style: decimal;
      padding-left: var(--space-6);
      margin-bottom: var(--space-4);
    }

    & ul li,
    & ol li {
      color: var(--color-gray);
      line-height: 1.8;
      margin-bottom: var(--space-2);
    }

    /* Puces personnalisées (article PCM : "J'ai besoin de...") */
    & ul.needs-list {
      list-style: none;
      padding-left: 0;

      & li {
        position: relative;
        padding-left: var(--space-6);

        &::before {
          content: "💬";
          position: absolute;
          left: 0;
        }
      }
    }

    & blockquote {
      margin: var(--space-6) 0;
      padding: var(--space-5) var(--space-6);
      border-left: 4px solid var(--color-brand);
      border-radius: var(--radius-md);
      background-color: var(--color-white);
      color: var(--color-black);
      font-family: var(--font-heading);
      font-style: italic;
      line-height: 1.6;

      & p {
        color: inherit;
        margin-bottom: 0;
      }
    }

    & figure {
      margin: var(--space-6) 0;

      & blockquote {
        margin: 0;
      }

      & figcaption {
        margin-top: var(--space-3);
        text-align: center;
        font-size: var(--text-sm);
        font-style: italic;
        font-weight: 400;
        color: var(--color-gray-soft);
      }
    }

    /* Citation du corps d'un article : <figure class="blockquote"> (comme sur
       les autres pages, voir ".blockquote" plus bas) — le composant n'ayant ici
       pas de variante de fond dans le HTML, ".content-layout article" lui
       donne le fond "--color-brand" de ".blockquote-bg-brand" (guillemet-
       filigrane blanc, texte blanc, attribution en romain) et neutralise les
       styles de citation génériques de l'article ci-dessus (carte blanche à
       bordure gauche, "figure"/"figcaption" gris italique), plus spécifiques
       que ".blockquote". Padding horizontal en plus de celui du composant : la
       figure est ici une carte dans la colonne de texte, pas une bande
       pleine largeur. */
    & figure.blockquote {
      margin: var(--space-6) 0;
      padding: var(--space-4) var(--space-6);
      background: var(--color-brand);
      --quote-mark: var(--color-white);

      & blockquote {
        margin: 0;
        padding: var(--space-2) 0;
        border: 0;
        border-radius: 0;
        background: none;
        color: var(--color-white);
        font-family: inherit;
        font-size: var(--text-base);
        font-style: italic;

        & p {
          margin: 0;
          text-align: center;
          color: inherit;

          &+p {
            margin-top: var(--space-3);
          }
        }
      }

      & figcaption {
        margin-top: 0;
        font-size: inherit;
        font-style: normal;
        font-weight: 600;
        color: var(--color-white);
      }
    }

    & a {
      color: var(--color-brand);
      text-decoration: underline;
      text-underline-offset: 3px;
    }
  }
}

/**
 * Sidebar
 */
.content-sidebar {
  position: static;
  display: flex;
  flex-direction: column;
  gap: var(--space-5);

  @media (min-width: 1024px) {
    & {
      position: sticky;
      top: calc(72px + var(--space-8));
    }
  }
}

.sidebar-card {
  position: relative;
  background-color: var(--color-black);
  border-radius: var(--radius-md);
  padding: var(--space-6);
  color: var(--color-white);
  /* Couleur et opacité du filigrane (voir plus bas), assorties au fond de
     chaque variante : "--color-brand" sur le fond noir (défaut) et sur le
     fond blanc de ".light", blanc sur le fond menthe de ".profile"
     (blog.css). */
  --sidebar-mark: var(--color-brand);
  --sidebar-mark-opacity: 0.4;
  --sidebar-mark-size: 48px;

  /* Filigrane de la carte — même famille de signes que celui des sections
     d'article (".decor-mountain/-collectif/-echange/-mouvement") : forme
     unie découpée par un masque SVG ("mask"), couleur de variable, faible
     opacité, en HAUT À GAUCHE (48px). Espacement : "--space-4" (20px) du
     bord haut et du bord gauche — la forme respire dans le coin sans jamais
     toucher le bord ni le contour arrondi (rayon "--radius-md") — et le
     contenu démarre 15px ("--space-3") sous elle (voir "padding-top" plus
     bas). Elle reste derrière le contenu (chaque enfant direct est
     "position: relative; z-index: 1", plus bas). Ces
     classes ne sont posées que sur des <div> ".sidebar-card" : elles ne
     collisionnent pas avec les règles ".decor-*" des <section>. */
  &:is(.decor-mountain, .decor-collectif, .decor-echange, .decor-mouvement)::before {
    content: '';
    position: absolute;
    top: var(--space-4);
    left: var(--space-4);
    width: var(--sidebar-mark-size);
    height: var(--sidebar-mark-size);
    background-color: var(--sidebar-mark);
    opacity: var(--sidebar-mark-opacity);
    pointer-events: none;
  }

  /* Le contenu démarre SOUS le filigrane (bord haut + forme + un espace de
     respiration) pour que le titre ne le chevauche jamais — sauf ".profile" :
     son contenu (médaillon centré) est à l'écart du coin, le filigrane y
     tient à côté sans rien décaler. */
  &:is(.decor-mountain, .decor-collectif, .decor-echange, .decor-mouvement):not(.profile) {
    padding-top: calc(var(--space-4) + var(--sidebar-mark-size) + var(--space-3));
  }

  &.decor-mountain::before {
    -webkit-mask: url('../img/logo-brand-a.svg') no-repeat center / contain;
    mask: url('../img/logo-brand-a.svg') no-repeat center / contain;
  }

  &.decor-collectif::before {
    -webkit-mask: url('../img/picto-collectif.svg') no-repeat center / contain;
    mask: url('../img/picto-collectif.svg') no-repeat center / contain;
  }

  &.decor-echange::before {
    -webkit-mask: url('../img/picto-echange.svg') no-repeat center / contain;
    mask: url('../img/picto-echange.svg') no-repeat center / contain;
  }

  &.decor-mouvement::before {
    -webkit-mask: url('../img/04-point.svg') no-repeat center / contain;
    mask: url('../img/04-point.svg') no-repeat center / contain;
  }

  /* &.decor-mouvement::before {
    -webkit-mask: url('../img/picto-mouvement.svg') no-repeat center / contain;
    mask: url('../img/picto-mouvement.svg') no-repeat center / contain;
  } */

  &>* {
    position: relative;
    z-index: 1;
  }

  /* Avatar (photo ronde de la personne) : même design que les ".badge" (voir
     "ul.badges .badge") — rond sans bordure ni anneau, seulement l'ombre
     "--shadow-lg", fond blanc. Classe réutilisable pour tout avatar d'une
     ".sidebar-card" (<img class="avatar"> : auteure de l'article, carte de
     contact…). Taille : "--avatar-size", 110px par défaut ; le recadrage
     garde le haut de la photo (visage). */
  & .avatar {
    display: block;
    width: var(--avatar-size, 110px);
    height: var(--avatar-size, 110px);
    object-fit: cover;
    object-position: top center;
    border-radius: 50%;
    background: var(--color-white);
    box-shadow: var(--shadow-lg);
  }

  & h3 {
    font-family: var(--font-heading);
    font-size: var(--text-base);
    font-weight: 700;
    margin-bottom: var(--space-3);
    color: inherit;
  }

  & ul,
  & nav {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    margin-top: var(--space-3);
  }

  & nav {
    margin-top: 0;
  }

  & ul {
    & li {
      display: flex;
      align-items: center;
      gap: var(--space-2);
      padding: var(--space-2) 0 var(--space-3);
      font-size: var(--text-sm);
      color: var(--color-gray);
      border-bottom: 1px solid var(--color-gray-soft);

      &:last-child {
        padding-bottom: 0;
        border-bottom: 0;
      }

      & a {
        font-size: var(--text-sm);
        color: var(--color-black);
        font-weight: 500;
        transition: var(--transition);
        line-height: 1.4;

        &:hover {
          color: var(--color-brand);
        }
      }

      &.highlight a {
        font-size: var(--text-sm);
        color: var(--color-brand);
        font-weight: 600;
      }
    }
  }

  & .text {
    line-height: 1.7;
    color: rgba(255, 255, 255, 0.75);
    margin-bottom: var(--space-5);
  }

  &:not(.light) {
    .btn-outline {
      color: var(--color-white);
      border-color: rgba(255, 255, 255, 0.55);

      &:hover {
        background-color: rgba(255, 255, 255, 0.10);
        border-color: var(--color-white);
      }
    }
  }

  & .btn-lg {
    padding: 1rem 2.25rem;
  }

  &.contact {

    & nav,
    & ul {
      margin-top: var(--space-5);
    }

    & ul {
      gap: 0;

      & li {
        display: flex;
        align-items: center;
        font-size: var(--text-sm);
        color: rgba(255, 255, 255, 0.7);
        border: 0;

        & .icon {
          width: 16px;
          height: 16px;
          color: var(--color-brand);
          flex-shrink: 0;
        }
      }
    }
  }

  &.light {
    background-color: var(--color-white);
    color: var(--color-black);
    border: 1px solid var(--color-gray-soft);
    --sidebar-mark-opacity: 0.22;

    & h3 {
      color: var(--color-black);
    }

    & .text {
      color: var(--color-gray-soft);
    }
  }
}

/* Badges de certification (page À propos) — déplacée hors de
   "section.profile" (elle vivait auparavant dans un <aside> à côté de
   l'article) dans son propre <section>, juste avant "section.profile".
   Chaque badge devient un rond (même principe que les statistiques du
   hero d'index.php, ".badges") plutôt que le bloc rectangulaire unique
   précédent. Mobile d'abord : rangée centrée qui s'enroule selon la
   largeur disponible (5 badges, pas de nombre de colonnes imposé — un
   nombre fixe créerait une dernière ligne à un seul item selon la
   largeur). */
section.badges {
  & .container {
    max-width: 820px;
  }

  /* Le <ul> porte aussi la classe générique "badges" et ses <li> la classe
     "badge" (rond blanc à ombre, voir "ul.badges" plus haut dans ce
     fichier). À partir de 640px, c'est la RÈGLE PAR DÉFAUT de "ul.badges"
     qui s'applique telle quelle (mono-ligne, ronds de 200px max qui
     rétrécissent avec le conteneur) — rien à redéfinir ici. Seul le
     mobile (< 640px) garde sa présentation propre : rangée centrée qui
     s'enroule, ronds de 96px, plutôt qu'une colonne de ronds de 200px. */
  & ul.badges {
    list-style: none;
    margin: 0;

    @media (max-width: 639px) {
      & {
        display: flex;
        flex-wrap: wrap;
        justify-content: center;
        align-items: flex-start;
        gap: var(--space-4);
      }
    }
  }

  & ul.badges li.badge {
    @media (max-width: 639px) {
      & {
        flex-shrink: 0;
        width: 96px;
        --badge-d: 96px;
      }
    }
  }

  & img {
    width: 100%;
    height: 100%;
    object-fit: contain;
  }
}

/* Réseau de compétences complémentaires (page "Autour de Coaxia RH",
   entre ".badges" et ".profile" — voir la proposition validée avec la
   cliente) — portrait circulaire + nom + rôle + courte présentation,
   volontairement photo-avant-texte : c'est l'incarnation demandée par la
   cliente (inspiration Coop Time, retour client du 10/09/2026), SANS
   reprendre sa mise en page, jugée trop textuelle — voir CLAUDE.md,
   section « Direction visuelle ». Le header (label/h2/texte) hérite déjà
   du style générique "section & header" (haut de ce fichier) : rien à
   redéfinir ici pour lui. */
section.team {
  & .grid-2c {
    max-width: 720px;
    margin: 0 auto;
  }

  /* "list-style: none" nécessaire malgré ".grid-2c" (utilitaire de mise en
     grille pur, sans reset de liste) : ces cartes sont des <li>, pas des
     <div>, pour rester une liste sémantique de personnes. */
  & .card {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: var(--space-2);
    list-style: none;
    padding: var(--space-6) var(--space-4);
    border: 1px solid var(--color-gray-soft);
    border-radius: var(--radius-md);
    background: var(--color-white);
    position: relative;
    overflow: hidden;
    transition: border-color .3s var(--ease-refined), transform .3s var(--ease-refined);

    /* Même design de survol que les cartes de l'accueil (".header-grid &
       .card" — "Le constat"/"Pour qui ?"/"Ils nous font confiance") :
       liseré haut qui se déploie en vert de marque + légère élévation,
       plutôt que le simple "box-shadow" générique de ".card" (base.css,
       "Card base") — remplace ce comportement par défaut sur cette
       section précise, demande explicite de cohérence avec l'accueil. */
    &::before {
      content: "";
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 3px;
      background: var(--color-brand);
      transform: scaleX(0);
      transform-origin: left;
      transition: transform .35s var(--ease-refined);
    }

    &:hover {
      transform: translateY(-3px);
      border-color: var(--color-brand);
      box-shadow: none;

      &::before {
        transform: scaleX(1);
      }
    }

    /* Portrait circulaire — même principe que le hero de cette page
       (bordure pleine + ombre), décliné plus petit et sur fond blanc :
       bordure "--color-brand" pleine (pas blanche translucide, qui ne se
       verrait pas ici) pour rester dans la même famille visuelle. */
    & .img {
      width: 140px;
      height: 140px;
      margin: 0 0 var(--space-3);
      border-radius: 50%;
      overflow: hidden;
      border: 4px solid var(--color-brand);
      box-shadow: var(--shadow-md);

      @media (min-width: 768px) {
        & {
          width: 160px;
          height: 160px;
        }
      }

      & img {
        display: block;
        width: 100%;
        height: 100%;
        object-fit: cover;
      }
    }

    & h3 {
      font-size: var(--text-base);
      font-weight: 600;
      color: var(--color-black);
      margin: 0;
    }

    & .role {
      font-size: var(--text-sm);
      font-weight: 600;
      color: var(--color-brand);
      margin: 0;
    }

    & .text {
      font-size: var(--text-sm);
      color: var(--color-gray);
      line-height: 1.5;
      margin: 0;
    }
  }

  /* "Quelques médaillons plus courts présentant les partenaires et leur
     domaine d'intervention" (demande client distincte de "une place
     particulière pour deux autres personnes" ci-dessus, voir CLAUDE.md,
     "Structure du site") — même donnée/composant que ".card" (voir
     card/team-member.php), juste sans "text" : rangée compacte de
     portrait + nom + rôle, volontairement plus discrète (pas de carte, pas
     de survol) que les 2 cartes complètes au-dessus. */
  & .medallions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--space-6) var(--space-8);
    max-width: 900px;
    margin: var(--space-8) auto 0;
    list-style: none;
  }

  & .medallion {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: var(--space-2);
    width: 140px;

    & .img {
      width: 88px;
      height: 88px;
      margin: 0;
      border-radius: 50%;
      overflow: hidden;
      border: 3px solid var(--color-brand);
      box-shadow: var(--shadow-sm);

      & img {
        display: block;
        width: 100%;
        height: 100%;
        object-fit: cover;
      }
    }

    & h3 {
      font-size: var(--text-md);
      font-weight: 600;
      color: var(--color-black);
      margin: 0;
    }

    & .role {
      font-size: var(--text-sm);
      font-weight: 600;
      color: var(--color-brand);
      margin: 0;
      line-height: 1.3;
    }
  }
}

/* Citation contextuelle : <figure class="blockquote blockquote-bg-<couleur>">
   <blockquote>…</blockquote><h3>…</h3 ou <figcaption>…</figcaption></figure>.
   Design fusionné depuis "section.pains & figure.blockquote" (carte centrée,
   guillemets agrandis à cheval sur le bord supérieur) — devenu la structure
   commune à toutes les citations du site, service pages incluses (ex-
   ".testimonial-quote"/ancien ".blockquote" à bordure gauche, désormais
   unifiés). Cette règle ne fixe AUCUNE couleur de fond : chaque instance
   choisit sa variante via une classe ".blockquote-bg-<couleur>" à côté
   (voir plus bas), qui porte aussi bien le fond que les couleurs de texte
   assorties (contraste différent selon fond clair/sombre). */
.blockquote {
  position: relative;
  width: 100%;
  margin: 0;
  padding: var(--space-4) 0;
  border-radius: var(--radius-md);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  /* Couleur du guillemet-filigrane (voir "::before"), assortie au fond par
     chaque variante ci-dessous. */
  --quote-mark: var(--color-brand);

  /* Guillemet OUVRANT en filigrane — même technique que le filigrane des
     sections d'article (".decor-*::after", voir "@scope (.page-service)") :
     forme unie découpée par un masque SVG (assets/img/quote-open.svg),
     couleur de fond de variable, opacité faible, calé sur le coin haut
     gauche, JAMAIS dans le contenu. Remplace les anciens 2 guillemets
     décoratifs (ouvrant + fermant) portés par "blockquote::before/::after",
     supprimés : plus de guillemet fermant. Se dévoile avec la citation
     (voir ".article-extras" dans "@scope (.page-service)"). */
  &::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    width: 120px;
    height: 93px;
    background-color: var(--quote-mark);
    -webkit-mask: url('../img/quote-open.svg') no-repeat center / contain;
    mask: url('../img/quote-open.svg') no-repeat center / contain;
    opacity: 0.18;
    pointer-events: none;
    transition: opacity 900ms var(--ease-refined), transform 900ms var(--ease-refined);
  }

  & blockquote {
    position: relative;
    margin: 0;
    padding: var(--space-2) 0;
    font-size: var(--text-base);
    line-height: 1.6;
    /* Texte d'une citation : en italique (règle générale des citations/
       avis) — l'attribution ("figcaption"/"h3") reste en romain. */
    font-style: italic;
  }

  /* Ligne d'attribution — même traitement, que la maquette utilise un
     "<h3>" (index.php) ou un "<figcaption>" (pages de service). */
  & h3,
  & figcaption {
    position: relative;
    font-weight: 600;
    text-align: center;
  }

  /* Variantes de fond — voir le commentaire de ".blockquote" ci-dessus.
   Chacune fixe le fond ET les couleurs de texte/guillemet assorties
   (contraste selon fond clair/sombre), jamais l'inverse. */

  &.blockquote-bg-brand {
    background: var(--color-brand);
    --quote-mark: var(--color-white);

    & blockquote {
      color: var(--color-white);
    }

    & h3,
    & figcaption {
      color: var(--color-white);
    }
  }
}

/**
 * Bloc de prise de rendez-vous — composant réutilisable
 *
 * `<aside class="appointment">` : contenu centré horizontalement.
 * `<h2>` calé sur le texte "Prenons rendez-vous" affiché dans l'image
 * de l'icône calendrier (`assets/img/icon/appointment.jpg`) :
 * même taille que les `<h2>` de section (`--text-xl`), même gris
 * medium-foncé (`--color-gray`).
 * – img    : affichée à 1/1.5 de la largeur du conteneur
 * – a      : surface cliquable étendue sur tout le bloc (`::after` absolu)
 * – hover  : changement animé de couleur (icône via `filter`, titre via `color`)
 */
.appointment {
  text-align: center;
  position: relative;

  & img {
    display: block;
    max-width: calc(100% / 1.5);
    height: auto;
    margin-inline: auto;
    transition: filter var(--transition);
  }

  & a {
    &::after {
      content: '';
      position: absolute;
      inset: 0;
    }
  }

  & h2 {
    font-size: var(--text-xl);
    color: var(--color-gray);
    transition: color var(--transition);
  }

  &:hover {
    /* saturate(0.72) brightness(1.12) : approximation CSS-filter de --color-brand → --color-brand-soft */
    & img { filter: saturate(0.72) brightness(1.12); }
    & h2  { color: var(--color-brand); }
  }
}

/**
 * Animations — discrètes et raffinées
 */

/* Compteur ".digit" (hero, ul.badges — voir plus bas) : propriété
   personnalisée typée "<integer>", seule façon d'animer un nombre entier de
   façon FLUIDE en CSS pur (une "custom property" non enregistrée via
   "@property" n'est jamais interpolée par les animations, seulement
   commutée d'une valeur à l'autre). Non héritée : chaque ".digit" gère la
   sienne indépendamment. */
@property --num {
  syntax: '<integer>';
  inherits: false;
  initial-value: 0;
}

/* "to" lit "--num-target" (valeur cible posée par instance, non typée —
   voir ".digit" plus bas) plutôt que de coder la valeur en dur ici : un seul
   "@keyframes" partagé sert aux 2 compteurs (25 / 2019), quelle que soit
   leur valeur cible. */
@keyframes digit-count-up {
  from {
    --num: 0;
  }

  to {
    --num: var(--num-target);
  }
}

/* Fait disparaître d'un coup le "::before" du compteur une fois le comptage
   terminé (voir ".digit" — hero, ul.badges) : révèle le texte réel, jamais
   masqué, qui affiche déjà la même valeur finale — aucun saut visuel. */
@keyframes digit-count-hide {
  to {
    visibility: hidden;
  }
}

@keyframes fade-up {
  from {
    opacity: 0;
    transform: translateY(10px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* Même principe que "fade-up" (fondu + léger déplacement), horizontal :
   utilisé par les items "Qualiopi"/"RNCP..." de "ul.badges" (hero) — voir
   plus bas — pour un contenu qui apparaît en venant de la gauche. */
@keyframes fade-left {
  from {
    opacity: 0;
    transform: translateX(-24px);
  }

  to {
    opacity: 1;
    transform: translateX(0);
  }
}

@keyframes subtle-zoom {
  from {
    transform: scale(1.04);
  }

  to {
    transform: scale(1);
  }
}

@keyframes bounce {

  0%,
  100% {
    transform: translateX(-50%) translateY(0);
  }

  50% {
    transform: translateX(-50%) translateY(-8px);
  }
}

@keyframes section-toggle-hint {

  0%,
  100% {
    transform: translateX(-50%) translateY(0) rotate(45deg);
  }

  50% {
    transform: translateX(-50%) translateY(3px) rotate(45deg);
  }
}

@media (prefers-reduced-motion: reduce) {
  .page-service .section-toggle::after {
    animation: none !important;
  }
}