/* ============================================================
   INTERFACE3 — PAGES À BLOCS MODULAIRES (CMS maison)
   ============================================================
   Style des 10 types de blocs assemblables depuis l'admin, plus le
   hero générique de ces pages. Rendu par public/static/page-blocks.js.

   PRINCIPE : ce fichier réutilise au maximum les composants qui
   existent déjà (design-system.css / pages.css / financeurs.css) —
   .container, .section, .section-label, .display-md, .page-hero,
   .badge, .btn, .service-card, .testimonial-card, .f-card__link…
   Il ne définit QUE ce qui n'existait pas : les variantes de fond
   par bloc, la grille de logos, le conteneur vidéo 16:9, la
   disposition texte+image, les statistiques et la liste enrichie.

   🔴 RÈGLE DE COULEUR À NE JAMAIS CONTOURNER
   design-system.css contient une règle générique `p { color:
   var(--text-secondary); }`. Une couleur seulement HÉRITÉE du parent
   perd toujours contre une règle qui cible directement l'élément,
   même moins spécifique — un <p> dans un bloc à fond sombre
   resterait donc gris foncé, illisible. Chaque variante de fond
   redéfinit donc EXPLICITEMENT la couleur de tous ses textes
   (titres, paragraphes, listes, légendes, intitulés, liens) via les
   sélecteurs `.pb-block <élément>` ci-dessous. Ne jamais retirer ces
   règles en supposant que l'héritage suffit.

   Les paires fond/texte utilisées ici sont celles validées par
   l'audit d'accessibilité du 21 août 2026 (--text-on-green,
   --text-on-yellow, --text-on-violet…), jamais recomposées
   autrement. Ratios mesurés (texte normal, seuil AA 4.5:1) :
     light  #FAF9F6 / #2e3232 → 12.9:1
     alt    #F0EFE9 / #2e3232 → 12.2:1
     dark   #2e3232 / #FAF9F6 → 12.9:1
     yellow #F5E32D / #2e3232 →  9.8:1
     violet #4B2BFF / #FAF9F6 →  6.4:1
     green  #00C46A / #2e3232 →  5.6:1
     fluo   #ff81f1 / #2e3232 →  6.0:1
   (custom = couleur choisie dans l'admin : le contraste dépend de
   la valeur saisie, il ne peut pas être garanti ici.)
   ============================================================ */

/* ── Socle commun à tous les blocs ──────────────────────────── */
.pb-block {
  /* Valeurs par défaut (fond clair) — chaque variante de fond
     ci-dessous ne fait que redéfinir ces 5 variables. */
  --pb-bg:     var(--bg);
  --pb-text:   var(--text-primary);
  --pb-label:  var(--text-secondary);
  --pb-accent: var(--violet);
  --pb-rule:   var(--yellow);
  --pb-hairline: var(--border);

  background: var(--pb-bg);
  color: var(--pb-text);
  /* Bug réel trouvé le 15 septembre 2026 (Sonia, en testant la barre
     d'ancres de Partenaires : « Trois façons de collaborer devrait
     descendre la page jusqu'à l'ancre concernée ») : le clic scrollait
     bien jusqu'au bloc, mais son sur-titre/titre atterrissait caché
     sous l'en-tête fixe (nav.css, position:fixed, --nav-h = 68px) —
     donnant l'impression que rien ne s'était passé. Aucun bloc n'avait
     de marge de défilement pour compenser. */
  scroll-margin-top: calc(var(--nav-h) + var(--s4));
}

/* Couleur de texte posée DIRECTEMENT sur chaque élément — voir la
   règle de couleur en tête de fichier. */
.pb-block h1,
.pb-block h2,
.pb-block h3,
.pb-block h4,
.pb-block p,
.pb-block li,
.pb-block strong,
.pb-block blockquote,
.pb-block figcaption { color: var(--pb-text); }

/* Intitulé de section (.section-label span cible --text-muted, sous
   le seuil AA) et légendes : ton secondaire, jamais hérité. */
.pb-block .section-label span,
.pb-block .pb-caption,
.pb-block .pb-note { color: var(--pb-label); }

/* Le filet du .section-label est jaune par défaut — invisible sur un
   fond jaune, d'où la variable. */
/* ── Nettoyage du 9 septembre 2026 ──────────────────────────────
   Ce fichier contenait DEUX feuilles concaténées : deux agents en
   avaient écrit chacun une version complète, et les deux avaient été
   gardées bout à bout. 512 lignes strictement identiques (vérifié par
   diff, aucune divergence) étaient donc du code mort — la dernière
   déclaration gagnant, un correctif atterrissant dans la première
   copie n'avait aucun effet, sans erreur ni avertissement. C'est
   exactement ce qui est arrivé aux logos le 8 septembre.
   Les deux copies mortes ont été retirées ici. */

/* ── 5. Bloc logos ──────────────────────────────────────────── */
/* Reprend la bande discrète du bas des fiches formation
   (.formation-partners-block, design-system.css) : même hauteur pour
   tous, en niveaux de gris, couleur au survol. Ce qui est ajouté ici,
   et réglable depuis l'admin :
     · --pb-logo-h       hauteur de référence de la rangée ;
     · --pb-logo-gap     espacement ;
     · --pb-logo-justify alignement (gauche / centré / réparti) ;
     · --pb-logo-scale   taille propre à UN logo, en pourcentage.

   Pourquoi une taille par logo : à hauteur égale, l'emblème européen
   (440×92, très allongé) et le logo de Porin (400×347, presque carré)
   font 128 px et 46 px de large. Ils n'ont donc pas du tout la même
   présence, et une hauteur unique ne suffit pas — même constat que
   pour le bandeau partenaires, d'où le même réglage en pourcentage.

   🔴 Bug corrigé le 8 septembre 2026 (remonté par Alexandra sur le bac
   à sable) : cette règle utilisait `gap: var(--s6) var(--s7)`, or le
   token --s7 N'EXISTE PAS. Une valeur invalide annule toute la
   déclaration : les logos se retrouvaient sans aucun espacement, seules
   les marges blanches internes des images en tenaient lieu. Les tokens
   d'espacement sautent de --s6 à --s8. */
.pb-logos {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: var(--pb-logo-justify, flex-start);
  row-gap: calc(var(--pb-logo-gap, var(--s8)) * 0.75);
  column-gap: var(--pb-logo-gap, var(--s8));
}
/* Aucune tuile, aucun fond : les logos sont posés directement sur la
   section. Le fond blanc opaque de cinq des sept fichiers fournis a été
   rendu transparent dans les images elles-mêmes — c'est le vrai
   correctif. La tuile blanche essayée d'abord se voyait : « ça n'a pas
   de sens de mettre le logo sur un fond coloré alors qu'il y a un fond
   blanc sur certains, c'est moche » (retour d'Alexandra).

   min-width : donne à chaque logo un emplacement d'une largeur
   plancher, pour que les blancs entre eux paraissent réguliers malgré
   des largeurs réelles allant de 46 à 128 px. Sans ça, un logo étroit
   semble flotter et un logo large semble collé à son voisin. */
.pb-logo {
  height: calc(var(--pb-logo-h, 2.5rem) * var(--pb-logo-scale, 1));
  min-width: 5.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.pb-logo img {
  height: 100%;
  width: auto;
  max-width: 11rem;
  object-fit: contain;
}
a.pb-logo { transition: opacity var(--t-fast), transform var(--t-fast); }
a.pb-logo:hover { opacity: 1; transform: translateY(-2px); }
.pb-note { color: var(--pb-label); }

/* Le filet du .section-label est jaune par défaut — invisible sur un
   fond jaune, d'où la variable. */
.pb-block .section-label::before { background: var(--pb-rule); }

/* Liens en clair dans un texte de bloc */
.pb-block .pb-body a {
  color: var(--pb-accent);
  text-decoration: underline;
  text-underline-offset: 0.15em;
}
.pb-block .pb-body a:hover { text-decoration-thickness: 2px; }

/* Liens d'accompagnement / sources sous un corps de texte (contrat
   v1.1, champ `links` des blocs text et text_image). Reprend
   .f-card__link (design-system.css), qui laisse revenir un libellé
   long à la ligne — contrairement à .btn (white-space: nowrap).
   La couleur est posée explicitement : --accent (violet) serait
   illisible sur un fond violet ou fluo. */
.pb-links {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--s2);
  margin-top: var(--s6);
}
.pb-links .f-card__link {
  color: var(--pb-accent);
  margin-top: 0;
  text-transform: none;
  letter-spacing: 0.02em;
}
.pb-links .f-card__link:hover { text-decoration: underline; }
/* Mention « (nouvel onglet) » : visible, mais discrète — elle informe
   sans voler la vedette au libellé du lien. */
.pb-newtab {
  /* Flèche ↗ des liens qui ouvrent un nouvel onglet — la mention écrite
     est passée en .sr-only le 8 septembre 2026 (voir page-blocks.js).
     Discrète et collée au libellé : c'est un repère, pas un mot. */
  /* Même poids visuel que la flèche « → » d'un lien interne : c'est la
     même flèche, elle pointe juste hors de la page. */
  font-weight: inherit;
  font-size: inherit;
  line-height: 1;
  text-transform: none;
  letter-spacing: 0;
}

/* .btn-outline utilise --text-primary (sombre) : invisible sur un
   fond sombre ou coloré. Même correctif que .financeurs-btn-group
   .btn-outline, déjà en place pour la même raison. */
.pb-bg--dark .btn-outline,
.pb-bg--violet .btn-outline,
.pb-bg--green .btn-outline,
.pb-bg--fluo .btn-outline,
.pb-bg--custom .btn-outline {
  color: var(--pb-text);
  border-color: currentColor;
}

/* ── Les 8 variantes de fond ────────────────────────────────── */
.pb-bg--light {
  --pb-bg: var(--bg);
  --pb-text: var(--text-primary);
  --pb-label: var(--text-secondary);
  --pb-accent: var(--violet);
}
.pb-bg--alt {
  --pb-bg: var(--bg-alt);
  --pb-text: var(--text-primary);
  --pb-label: var(--text-secondary);
  --pb-accent: var(--violet);
}
.pb-bg--dark {
  --pb-bg: var(--bg-dark);
  --pb-text: var(--text-inverse);
  /* Sur fond coloré/sombre, le ton "secondaire" reprend la couleur
     principale : n'importe quel gris intermédiaire replongerait sous
     le seuil AA selon le fond. La hiérarchie se fait à la taille et
     à la graisse, pas à l'opacité. */
  --pb-label: var(--text-inverse);
  --pb-accent: var(--yellow);
  --pb-rule: var(--yellow);
  --pb-hairline: rgba(250, 249, 246, 0.22);
}
.pb-bg--yellow {
  --pb-bg: var(--yellow);
  --pb-text: var(--text-on-yellow);
  --pb-label: var(--text-on-yellow);
  --pb-accent: var(--violet);
  --pb-rule: var(--text-on-yellow);
  --pb-hairline: rgba(13, 13, 13, 0.25);
}
.pb-bg--violet {
  --pb-bg: var(--violet);
  --pb-text: var(--text-on-violet);
  --pb-label: var(--text-on-violet);
  --pb-accent: var(--yellow);
  --pb-rule: var(--yellow);
  --pb-hairline: rgba(250, 249, 246, 0.28);
}
.pb-bg--green {
  --pb-bg: var(--green);
  --pb-text: var(--text-on-green);
  --pb-label: var(--text-on-green);
  /* Sur vert, ni violet ni jaune ne passent le seuil AA — l'accent
     reprend donc la couleur de texte validée (--text-on-green). */
  --pb-accent: var(--text-on-green);
  --pb-rule: var(--text-on-green);
  --pb-hairline: rgba(13, 13, 13, 0.25);
}
.pb-bg--fluo {
  --pb-bg: var(--bg-fluo);
  --pb-text: var(--text-primary);
  --pb-label: var(--text-primary);
  /* Violet sur fluo = 3.1:1, sous le seuil : on garde le texte. */
  --pb-accent: var(--text-primary);
  --pb-rule: var(--text-primary);
  --pb-hairline: rgba(13, 13, 13, 0.25);
}
/* custom : --pb-bg et --pb-text sont posés en style inline par le JS
   (couleur choisie dans l'admin + clair/foncé). */
.pb-bg--custom {
  --pb-label: var(--pb-text);
  --pb-accent: var(--pb-text);
  --pb-rule: var(--pb-text);
}

/* ── Bandeau "brouillon" ────────────────────────────────────── */
.pb-draft-banner {
  background: var(--yellow);
  color: var(--text-on-yellow);
  padding: var(--s3) 0;
}
.pb-draft-banner p {
  color: var(--text-on-yellow);
  font-size: var(--text-sm);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.pb-loading,
.pb-empty {
  padding: var(--s24) var(--gutter);
  text-align: center;
  color: var(--text-secondary);
}

/* ── Liste des projets (accueil + partenaires.html + page hub Projets) ──
   Réutilise .services-grid / .service-card (pages.css). Seule la
   règle de colonnes change : le nombre de projets est variable (1 à
   n). `auto-fill` réserve des colonnes vides tant que la largeur le
   permet — avec 1 seule carte sur un écran large, elle reste collée à
   gauche avec du vide à droite (repéré par Sonia le 14 septembre 2026).
   `auto-fit` retire les colonnes vides ; `minmax(20rem, 24rem)` évite
   qu'une carte isolée ne s'étire sur toute la largeur. Pas de
   `justify-content: center` (Sonia n'aime pas le centrage) : une carte
   seule reste alignée à gauche, comme le reste du contenu de la page —
   le vrai correctif au "ça a l'air vide" est éditorial (un seul bloc
   "Tous nos projets" tant que le contenu est rare, plutôt qu'une
   section par catégorie), pas visuel. Comportement à 3+ cartes
   inchangé. */
.pb-projets-grid {
  grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 24rem));
}

/* Nombre de colonnes FIXÉ depuis l'admin (au lieu du "autant que la
   largeur le permet" par défaut ci-dessus) — page-blocks.js pose cette
   classe + --pb-cols uniquement quand un nombre précis a été choisi
   (ex. la page "Nos projets", 3 colonnes). Mêmes seuils de repli que
   .pb-cards/.pb-gallery plus bas dans ce fichier : 960px → 2 colonnes
   au maximum, 640px → 1 colonne. Corrigé le 16 septembre 2026 (Sonia :
   « pas responsive sur la partie des projets ») — un style INLINE posé
   directement en JS (`repeat(3, ...)`), sans le moindre repli mobile,
   battait n'importe quelle media query et gardait 3 colonnes serrées
   jusqu'au plus petit écran. */
.pb-projets-grid--fixed-cols {
  grid-template-columns: repeat(var(--pb-cols, 3), minmax(0, 1fr));
}
@media (max-width: 960px) {
  .pb-projets-grid--fixed-cols { grid-template-columns: repeat(min(var(--pb-cols, 3), 2), minmax(0, 1fr)); }
}
@media (max-width: 640px) {
  .pb-projets-grid--fixed-cols { grid-template-columns: 1fr; }
}

/* ── Hero de page ───────────────────────────────────────────── */
/* Réutilise .page-hero (design-system.css) pour le rythme vertical ;
   .pb-hero est là uniquement pour battre `background: var(--bg)` de
   .page-hero quand une variante de fond est demandée. */
.pb-hero.pb-block { background: var(--pb-bg); }
.pb-hero.pb-bg--dark,
.pb-hero.pb-bg--violet,
.pb-hero.pb-bg--yellow,
.pb-hero.pb-bg--green,
.pb-hero.pb-bg--fluo,
.pb-hero.pb-bg--custom { border-bottom-color: var(--pb-hairline); }

.pb-hero__badges {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
  margin-bottom: var(--s5);
}
.pb-hero__title { color: var(--pb-text); }
.pb-hero__subtitle {
  font-size: var(--text-lg);
  color: var(--pb-text);
  max-width: 60ch;
  margin-bottom: var(--s8);
}
/* Photo du hero : le JS reprend les classes .formation-hero__photo-wrap
   / .formation-hero__photo (pages.css) du hero d'une page de
   formation. Seuls les coins arrondis et le filet sont ajoutés ici —
   pages.css les pose sur la version formation via son propre
   conteneur. */
/* Deux zones côte à côte : texte à gauche, photo à droite. Grille
   1fr 1fr, reprise du hero de la page d'accueil (.hero__main,
   home.css). Deux règles posées par Alexandra le 7 septembre : jamais
   de photo sur toute la largeur, et une bande ne reste jamais à moitié
   vide (sans photo, le JS ne génère pas cette grille du tout). */
/* Proportions et gouttière réglables depuis l'admin (--pb-split /
   --pb-gap, posées en style inline par page-blocks.js) : 50/50 par
   défaut, mais 60/40 ou 40/60 possibles sans toucher au CSS.
   align-items: stretch (et non center) pour que la photo occupe TOUTE
   la hauteur de la bande — demande d'Alexandra le 7 septembre : une
   photo qui flotte au milieu d'une colonne plus haute que lui laisse
   du vide en haut et en bas. */
.pb-hero__split {
  display: grid;
  grid-template-columns: var(--pb-split, 1fr 1fr);
  gap: var(--pb-gap, var(--s16));
  align-items: stretch;
}
/* Sans ça, une colonne "1fr" garde pour plancher le min-content de son
   contenu (un titre en display, ici) — le texte peut alors écraser la
   photo/mosaïque à quelques px de large. Même correctif déjà posé sur
   .pb-textimg pour la même raison ; jamais reproduit ici jusqu'au
   15 septembre 2026 (trouvé en mesurant la mosaïque du hero, pas à la
   relecture). */
.pb-hero__split > * { min-width: 0; }
.pb-hero__split .pb-hero__text { align-self: center; }
/* mediaSide = "left" : la photo passe devant le texte à l'écran, sans
   changer l'ordre du HTML (le texte reste lu en premier). */
.pb-hero__split--media-left .pb-hero__media { order: -1; }
.pb-hero__split .pb-hero__subtitle { margin-bottom: 0; }
@media (max-width: 960px) {
  .pb-hero__split {
    grid-template-columns: 1fr;
    gap: var(--s10);
  }
  .pb-hero__split--media-left .pb-hero__media { order: 0; }
}
.pb-hero__media { margin-top: 0; }
/* Hors grille (photo sans texte à côté, cas résiduel), on garde l'air
   d'avant sous le chapô. */
.pb-hero > .container > .pb-hero__media { margin-top: var(--s10); }
/* Aucun arrondi, aucune bordure : les photos des fiches formation
   (.formation-hero__photo, pages.css) sont à angles vifs et sans
   cadre. Vérifié dans la feuille avant de retirer — remarque
   d'Alexandra le 7 septembre. */
/* La colonne de droite du hero est étirée par la grille, mais son
   contenu ne l'était pas : la photo s'arrêtait à sa hauteur minimale
   et laissait du vide sous elle. height:100% à chaque étage jusqu'à
   l'image. */
.pb-hero__right { display: flex; flex-direction: column; }
.pb-hero__media {
  display: flex;
  flex-direction: column;
  height: 100%;
  flex: 1;
  min-height: 0;
}
.pb-hero__media .formation-hero__photo-wrap {
  margin-top: 0;
  flex: 1;
  min-height: 0;
}
.pb-hero__media .formation-hero__photo {
  width: 100%;
  height: 100%;
  min-height: 20rem;
  object-fit: cover;
  display: block;
}
@media (max-width: 960px) {
  .pb-hero__media .formation-hero__photo {
    height: auto;
    max-height: 26rem;
  }
}
.pb-hero__media .formation-hero__caption { color: var(--pb-label); }

/* ── En-tête commune d'un bloc (intitulé + titre) ───────────── */
.pb-block__head { margin-bottom: var(--s10); }
/* Largeur de colonne commune au titre ET au corps de texte d'un bloc.
   Sans ça, le titre s'étalait sur toute la largeur du conteneur au-dessus
   d'un paragraphe deux fois plus étroit — incohérence relevée par
   Alexandra le 7 septembre, captures à l'appui. La valeur (48rem = 768px)
   est celle du paragraphe qu'elle a jugé « déjà plus équilibré », et tient
   sous les ~90 caractères par ligne au-delà desquels la lecture décroche.
   Exprimée en rem et non en ch : l'unité ch dépend de la police, donc un
   titre en Barlow Condensed et un texte en Barlow ne tomberaient pas à la
   même largeur. */
.pb-block { --pb-col: 48rem; }
.pb-block__title { color: var(--pb-text); max-width: var(--pb-col); }

/* ── 1. Bloc texte ──────────────────────────────────────────── */
.pb-body { max-width: var(--pb-col); }
.pb-body p + p { margin-top: var(--s5); }

/* ── 2. Bloc texte + image ──────────────────────────────────── */
.pb-textimg {
  display: grid;
  grid-template-columns: var(--pb-split, 1fr 1fr);
  gap: var(--pb-gap, clamp(var(--s8), 5vw, var(--s16)));
  align-items: stretch;
}
.pb-textimg > div:not(.pb-textimg__media) { align-self: center; }
.pb-textimg > * { min-width: 0; }
/* imageSide = "left" : l'image passe devant le texte, sans changer
   l'ordre du HTML (le texte reste lu en premier au lecteur d'écran). */
.pb-textimg--image-left .pb-textimg__media { order: -1; }
/* Même règle que le hero : angles vifs, pas de cadre, et la photo
   remplit toute la hauteur de la bande. */
.pb-textimg__media {
  display: flex;
  flex-direction: column;
}
.pb-textimg__media img {
  width: 100%;
  height: 100%;
  min-height: 18rem;
  object-fit: cover;
  flex: 1;
  min-width: 0;
  display: block;
}
@media (max-width: 768px) {
  .pb-textimg__media img {
    height: auto;
    max-height: 24rem;
  }
}
.pb-caption {
  font-size: var(--text-xs);
  margin-top: var(--s3);
  line-height: var(--lh-snug);
}

/* Logo (17 septembre 2026) : montré en entier sur un fond neutre,
   jamais recadré en plein cadre comme une vraie photo ci-dessus. */
.pb-textimg__media--logo {
  align-items: center;
  justify-content: center;
  background: var(--white);
  padding: var(--s10);
}
.pb-textimg__media--logo .pb-textimg__img--logo {
  width: 100%;
  height: auto;
  min-height: 0;
  /* Taille en pourcentage (17 septembre 2026, retour de Sonia : « je ne
     peux pas changer le pourcentage ») — même mécanisme que le bloc
     Logos (--pb-logo-scale) : un multiplicateur numérique posé en style
     inline par page-blocks.js, jamais 3 tailles fixes. 100% = 16rem. */
  max-height: calc(16rem * var(--pb-textimg-logo-scale, 1));
  object-fit: contain;
  flex: none;
}
/* Niveaux de gris (17 septembre 2026, « comme à d'autres endroits du
   site ») — même traitement que le bloc Logos/le bandeau des fiches
   formation : gris par défaut, couleur reprise au survol de TOUTE la
   bande (pas seulement du logo), pour rester cohérent avec la mosaïque
   ci-dessous qui applique déjà cette règle. */
.pb-textimg__media--logo-gray .pb-textimg__img--logo {
  filter: grayscale(1);
  transition: filter var(--t-base);
}
.pb-textimg__media--logo-gray:hover .pb-textimg__img--logo { filter: grayscale(0); }
@media (prefers-reduced-motion: reduce) {
  .pb-textimg__media--logo-gray .pb-textimg__img--logo { transition: none; }
}

/* ── 2bis. Mosaïque photo + 3 blocs de couleur superposés ─────
   Variante du média de "text_image" (11-15 septembre 2026). Reprise
   TELLE QUELLE (positions/tailles) du composant que Sonia avait
   conçu pour sa brochure partenaires — une seule photo pleine largeur,
   les 3 aplats de couleur débordent volontairement de ses bords
   (positionnement absolu, valeurs négatives). Un premier essai en
   grille (photo + 3 blocs bien rangés côte à côte) a été jugé "trop
   équilibré" par Sonia : ce n'était pas ce composant-ci, l'idée est
   bien le débordement, jamais des zones séparées. Jamais un arrondi
   ni un cadre sur la photo (même règle que toute photo du site).
   Hérite gratuitement de imageSide/split/gap puisqu'elle vit dans le
   même .pb-textimg__media que la photo simple. */
.pb-textimg__media--mosaic { display: block; }
.pb-mosaic {
  position: relative;
  width: 100%;
  aspect-ratio: 408 / 521;
}
.pb-mosaic__photo {
  position: absolute;
  inset: 0;
  overflow: hidden;
}
.pb-mosaic__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  filter: grayscale(1) contrast(1.05);
  transition: filter var(--t-base);
}
/* Colorisée au survol de toute la mosaïque, pas seulement de la photo
   — l'effet doit se déclencher même en survolant un bloc de couleur
   voisin, pas seulement un pixel de la photo elle-même. */
.pb-mosaic:not(.pb-mosaic--static):hover .pb-mosaic__img { filter: grayscale(0) contrast(1.05); }
.pb-mosaic--static .pb-mosaic__img { filter: contrast(1.05); }
@media (prefers-reduced-motion: reduce) {
  .pb-mosaic__img { transition: none; }
}
/* Positions/tailles reprises à l'identique de la brochure — le seul
   réglage laissé à l'admin est la couleur de chaque bloc, jamais sa
   position (c'est elle qui fait "mosaïque", pas un choix éditorial). */
.pb-mosaic__tile { position: absolute; display: block; }
.pb-mosaic__tile--1 { width: 20%; height: 24%; right: -10%; top: 4%; }
.pb-mosaic__tile--2 { width: 24%; height: 17%; left: -13%; top: 30%; }
.pb-mosaic__tile--3 { width: 17%; height: 13%; left: -8%; bottom: 8%; }
.pb-mosaic__tile--green  { background: var(--green); }
.pb-mosaic__tile--violet { background: var(--violet); }
.pb-mosaic__tile--yellow { background: var(--yellow); }
.pb-mosaic__tile--orange { background: var(--orange); }
.pb-mosaic__tile--fluo   { background: var(--fluo); }
/* Une composition à proportions fixes (comme une couverture), pas une
   photo qui s'étire pour remplir la colonne : elle se centre dans la
   hauteur disponible plutôt que de se déformer.
   🔴 Bug réel trouvé le 16 septembre 2026 (Sonia : « sur la partie
   mobile il y a un vrai bug, c'est pas responsive sur la partie des
   projets ») — mesuré au navigateur à 390/360px : les 3 blocs de
   couleur qui débordent volontairement de la photo (voir .pb-mosaic__tile
   ci-dessous) débordaient alors carrément de la PAGE elle-même, pas
   seulement de la photo. Sur desktop, la colonne qui contient la
   mosaïque est bien plus large que son plafond de 28rem — le débordement
   reste alors un simple bleed dans de l'espace vide, comme voulu. Sur
   mobile, la colonne fait à peine la largeur de la mosaïque (aucune
   marge autour) : le même débordement franchissait donc le bord réel de
   l'écran, provoquant un vrai défilement horizontal de toute la page (20px
   à 390px, 17px à 360px, mesuré). `overflow: hidden` sur CE conteneur
   (la colonne elle-même, pas .pb-mosaic ni .pb-mosaic__photo) rend le
   bleed inoffensif : sur desktop, où la colonne a de la marge autour de
   la mosaïque, rien ne change visuellement (le clip tombe bien après le
   bord visible des blocs de couleur) — seul le cas mobile, où il n'y a
   plus de marge, est concerné. */
.pb-hero__media--mosaic,
.pb-textimg__media--mosaic {
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.pb-hero__media--mosaic .pb-mosaic,
.pb-textimg__media--mosaic .pb-mosaic {
  max-width: 28rem;
}

/* ── 3. Bloc cartes ─────────────────────────────────────────── */
/* Réutilise .service-card (pages.css). La grille est propre au bloc
   car le nombre de colonnes est réglable dans l'admin (2, 3 ou 4). */
.pb-cards {
  display: grid;
  gap: var(--s6);
  grid-template-columns: repeat(var(--pb-cols, 3), minmax(0, 1fr));
}
.pb-cards > * { min-width: 0; }
.pb-card__num {
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  font-weight: 900;
  line-height: 1;
  color: var(--violet);
}
/* Photo en tête de carte. La grille reste impeccable si seulement
   certaines cartes en ont une : le média est un enfant de plus dans
   une carte en flex-column, il ne change pas la hauteur des autres
   (les lignes de la grille s'alignent d'elles-mêmes). */
.pb-card__media {
  margin: calc(var(--s8) * -1) calc(var(--s8) * -1) 0;
  border-radius: calc(var(--r-lg) - 1.5px) calc(var(--r-lg) - 1.5px) 0 0;
  overflow: hidden;
}
.pb-card__media img,
.pb-card__img {
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  display: block;
}

/* ── Carte mise en avant ────────────────────────────────────────
   Reprend exactement .f-card--featured (design-system.css) : une
   carte remplie en violet au milieu de cartes blanches, comme la
   grille des formations sur l'accueil et se-former.html. Les textes
   sont recolorés explicitement, parce que la carte utilise les
   classes .service-card__* (et non .f-card__*), que les règles de
   .f-card--featured ne ciblent pas.
   Ratios sur #3618E0 : titre/texte #FAF9F6 ≈ 9.3:1, texte
   rgba(.85) ≈ 7.1:1, lien jaune ≈ 5.4:1. */
.pb-card--featured {
  background: var(--accent-hover);
  border-color: transparent;
}
/* Sélecteurs à 2 classes (0,2,0) : ils battent `.pb-block h3` /
   `.pb-block p` (0,1,1) de façon non ambiguë, ET fonctionnent aussi
   hors d'un bloc — la même carte sert à la liste des projets sur
   l'accueil et sur employeurs.html, qui ne sont pas des .pb-block. */
.pb-card--featured .service-card__title,
.pb-card--featured .pb-card__num { color: var(--text-inverse); }
.pb-card--featured .service-card__desc { color: rgba(250, 249, 246, 0.85); }
.pb-card--featured .f-card__link { color: var(--yellow); }
.pb-card--featured:hover { border-color: transparent; }

/* ── Cartes à accent (niveaux de partenariat, ex. Allié/Sponsor/
   Partenaire) ───────────────────────────────────────────────────
   Corrigé le 15 septembre 2026 : la 1ʳᵉ version posait un filet de
   4px en haut de la carte, un signal que le modèle d'origine de
   Sonia n'a jamais eu — chez elle, seuls le prix entre crochets et
   un petit point à côté du titre portent la couleur, jamais un
   bloc/filet de carte entier. Retiré ; remplacé par .pb-card__dot
   juste après le titre. Le corps de texte et les puces restent
   noir sur blanc quel que soit l'accent choisi. */
/* Centrage du point, en flexbox plutôt qu'en vertical-align (15
   septembre 2026, retour de Sonia, signalé une 2e fois) : un
   vertical-align:middle centre sur la métrique de la police (autour
   de l'x-height), pas sur la hauteur visuelle réelle des capitales
   d'un titre en majuscules gras — l'écart ne se voit qu'à l'usage,
   jamais en relisant juste le code. .service-card__title--with-dot
   n'existe QUE sur les cartes à accent (Allié/Sponsor/Partenaire) :
   les titres de cartes sans point (ex. liste de pages) gardent leur
   disposition d'origine, inchangée. */
.service-card__title--with-dot {
  display: flex;
  align-items: center;
}
.pb-card__dot {
  display: inline-block;
  flex-shrink: 0;
  /* Agrandi 2 fois le 15 septembre 2026 (retour de Sonia) : 0.55em
     → 0.85em. Purement décoratif (aucune information qui ne soit
     déjà dans le titre juste à côté) — aucune règle de contraste ne
     s'applique à un point sans texte, sa taille est donc libre. */
  width: 0.85em;
  height: 0.85em;
  margin-left: 0.5em;
  border-radius: 50%;
}
.pb-card--accent-green  .pb-card__dot { background: var(--green); }
.pb-card--accent-violet .pb-card__dot { background: var(--violet); }
.pb-card--accent-yellow .pb-card__dot { background: var(--yellow); }
.pb-card--accent-orange .pb-card__dot { background: var(--orange); }
.pb-card--accent-fluo   .pb-card__dot { background: var(--fluo); }

/* Prix / étiquette : les crochets sont ajoutés en CSS, jamais tapés
   dans l'admin — la mise en forme reste cohérente quel que soit le
   texte ("Gratuit", "< 20k €"…).
   Couleur : SEULS les crochets sont colorés (retour de Sonia le 15
   septembre — "seuls les chevrons étaient en couleur" dans son
   modèle d'origine), jamais le texte entre eux. ::before/::after
   acceptent leur propre color, indépendamment du texte réel de
   l'élément : le texte reste dans la couleur de corps par défaut,
   seuls les pseudo-éléments prennent l'accent.
   Couleurs vraies restaurées le 15 septembre (retour explicite de
   Sonia : "je tiens à mes couleurs") — le crochet est un signe de
   ponctuation purement décoratif, pas une information : le prix lui-
   même ("Gratuit", "< 20k €") reste en texte de corps, entièrement
   lisible, juste à côté. Rien n'est perdu si le crochet coloré ne
   ressort pas assez pour une personne malvoyante, contrairement à un
   vrai texte qui porterait l'information à lui seul — c'est la même
   distinction que pour .pb-card__dot ci-dessus. Agrandis (1.3em) en
   même temps que le point, pour la même raison. */
.pb-card__tag {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: 900;
  margin-top: var(--s2);
  color: var(--text-primary);
}
.pb-card__tag::before,
.pb-card__tag::after {
  font-size: 1.3em;
}
.pb-card__tag::before { content: '[ '; }
.pb-card__tag::after  { content: ' ]'; }
.pb-card--accent-green  .pb-card__tag::before,
.pb-card--accent-green  .pb-card__tag::after  { color: var(--green); }
.pb-card--accent-violet .pb-card__tag::before,
.pb-card--accent-violet .pb-card__tag::after  { color: var(--violet); }
.pb-card--accent-yellow .pb-card__tag::before,
.pb-card--accent-yellow .pb-card__tag::after  { color: var(--yellow); }
.pb-card--accent-orange .pb-card__tag::before,
.pb-card--accent-orange .pb-card__tag::after  { color: var(--orange); }
.pb-card--accent-fluo   .pb-card__tag::before,
.pb-card--accent-fluo   .pb-card__tag::after  { color: var(--fluo); }

/* Puces : point coloré, compact — jamais .competence-item (pensée
   pour une grille à part, avec fond et coin arrondi, pas pour une
   liste courte à l'intérieur d'une carte). */
.pb-card__bullets {
  list-style: none;
  margin: var(--s2) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s2);
}
.pb-card__bullets li {
  position: relative;
  padding-left: var(--s5);
  font-size: var(--text-sm);
  color: var(--text-secondary);
  line-height: var(--lh-snug);
}
.pb-card__bullets li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.5em;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--violet);
}
.pb-card--accent-green  .pb-card__bullets li::before { background: var(--green); }
.pb-card--accent-violet .pb-card__bullets li::before { background: var(--violet); }
.pb-card--accent-yellow .pb-card__bullets li::before { background: var(--yellow); }
.pb-card--accent-orange .pb-card__bullets li::before { background: var(--orange); }
.pb-card--accent-fluo   .pb-card__bullets li::before { background: var(--fluo); }

/* ── Cartes sur fond sombre ou coloré ───────────────────────────
   .service-card garde son fond blanc quel que soit le fond de la
   section : une grille de cartes blanches sur une section noire ne
   ressemble à rien de ce que fait le site. Sur fond sombre, les
   pages de référence utilisent des cartes SANS fond, bordées d'un
   filet, avec le titre en JAUNE (a-propos.html, section « Nos
   valeurs », .value-card / .value-card__title) — c'est ce qui
   réchauffe une section noire. Mêmes valeurs reprises ici.
   Ratios sur #2e3232 : titre jaune 9.8:1, texte #FAF9F6 12.9:1. */
.pb-bg--dark .service-card,
.pb-bg--violet .service-card {
  background: transparent;
  border-color: var(--pb-hairline);
}
.pb-bg--dark .service-card:hover,
.pb-bg--violet .service-card:hover { border-color: var(--pb-accent); }
.pb-bg--dark .service-card .service-card__title,
.pb-bg--violet .service-card .service-card__title { color: var(--pb-accent); }
.pb-bg--dark .service-card .service-card__desc,
.pb-bg--violet .service-card .service-card__desc { color: var(--pb-text); }
/* La carte mise en avant reste violette sur fond sombre : elle doit
   ressortir, pas se fondre. */
.pb-bg--dark .pb-card--featured,
.pb-bg--violet .pb-card--featured { background: var(--accent-hover); }
.pb-bg--dark .pb-card--featured .service-card__title,
.pb-bg--violet .pb-card--featured .service-card__title { color: var(--text-inverse); }
/* Un lien de carte peut avoir un libellé long : .f-card__link
   (design-system.css) le laisse revenir à la ligne, contrairement à
   .btn qui a `white-space: nowrap` et déborderait de la carte. */
.pb-card__link { margin-top: auto; }

/* ── 4. Bloc statistiques ───────────────────────────────────── */
/* Reprend l'aspect des chiffres clés d'a-propos.html
   (.about-stats / .about-stat-card, pages.css) : une pastille sur
   fond légèrement teinté, grand chiffre VIOLET sur fond clair (jaune
   sur fond sombre, via --pb-accent), intitulé en petites capitales. */
/* Rangée horizontale de chiffres — copie fidèle de la bande de
   l'accueil (.hero__stats / .hero__stat, home.css) : filet en tête,
   colonnes égales séparées par un trait vertical, texte aligné à
   gauche, aucun fond ni arrondi. Les valeurs sont recopiées ici
   parce que page-preview.html ne charge pas home.css — à garder
   synchronisées si cette bande change un jour côté accueil (même
   précaution que LANGUAGE_LEVEL_BANDS, carnet section 8.1).
   Remplace l'ancienne grille de pastilles arrondies centrées :
   remarque d'Alexandra le 7 septembre, capture de cette bande à
   l'appui. */
.pb-stats-intro { margin-bottom: var(--s10); }
/* Même espacement pour l'intro du bloc Cartes (15 septembre 2026). */
.pb-cards__intro { margin-bottom: var(--s10); max-width: 70ch; }
.pb-stats {
  border-top: 1.5px solid var(--pb-hairline);
  display: grid;
  grid-template-columns: repeat(var(--pb-stat-cols, 4), 1fr);
}
.pb-stat {
  padding: var(--s6) var(--gutter);
  border-right: 1.5px solid var(--pb-hairline);
  display: flex;
  flex-direction: column;
  gap: var(--s1);
}
.pb-stat:last-child { border-right: none; }
.pb-stat__value {
  font-family: var(--font-display);
  font-size: var(--text-3xl);
  font-weight: 900;
  line-height: 1;
  color: var(--pb-text);
}
/* Premier et dernier chiffre accentués, comme « 300+ » et « 12 » sur
   l'accueil. --pb-accent vaut le violet sur fond clair, le jaune sur
   fond sombre : même bascule que .hero__stat-num--accent. */
.pb-stat__value--accent { color: var(--pb-accent); }
.pb-stat__label {
  font-size: var(--text-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  line-height: var(--lh-snug);
  color: var(--pb-label);
}
@media (max-width: 900px) {
  .pb-stats { grid-template-columns: repeat(2, 1fr); }
  .pb-stat:nth-child(2n) { border-right: none; }
  .pb-stat:nth-child(n + 3) { border-top: 1.5px solid var(--pb-hairline); }
}
@media (max-width: 480px) {
  .pb-stats { grid-template-columns: 1fr; }
  .pb-stat { border-right: none; }
  .pb-stat + .pb-stat { border-top: 1.5px solid var(--pb-hairline); }
}

/* Variante 2 colonnes du bloc statistiques (contrat v1.1, champ
   `body`) : réutilise .funder-fse / .funder-fse__visual /
   .funder-fse__stat de financeurs.css — exactement la mise en page
   "texte à gauche, chiffres à droite" qui existe déjà sur la page
   Financeurs. Ce composant porte son PROPRE fond sombre et ses
   propres couleurs de texte, donc il reste lisible quelle que soit
   la couleur du bloc ; on ajoute juste un filet quand le bloc est
   lui-même sombre, pour que la carte ne s'y fonde pas. */
.pb-stats-split { margin: 0; }
.pb-bg--dark .pb-stats-split,
.pb-bg--custom .pb-stats-split { border: 1.5px solid var(--pb-hairline); }

/* 🔴 Cette carte a son propre fond sombre : ses textes ne doivent
   JAMAIS suivre --pb-text (qui est foncé sur un bloc clair — texte
   foncé sur carte sombre = illisible, le bug rejeté). Sélecteurs à
   2 classes pour battre `.pb-block p` / `.pb-block h2` (1 classe +
   1 élément) de façon non ambiguë, pas par ordre d'écriture.
   Ratios sur #2e3232 : titre/label #FAF9F6 12.9:1, texte
   rgba(.80) ≈ 8.1:1, chiffre jaune 9.8:1, légende rgba(.60) ≈ 4.9:1. */
.pb-stats-split .funder-fse__title,
.pb-stats-split .funder-fse__title span { color: var(--text-inverse); }
.pb-stats-split .funder-fse__label { color: var(--yellow); }
.pb-stats-split .funder-fse__text { color: rgba(250, 249, 246, 0.80); }
.pb-stats-split .funder-fse__text + .funder-fse__text { margin-top: var(--s4); }
.pb-stats-split .funder-fse__stat-num { color: var(--yellow); }
.pb-stats-split .funder-fse__stat-desc { color: rgba(250, 249, 246, 0.60); }
.pb-stats-split .pb-links .f-card__link { color: var(--yellow); }

.pb-note {
  font-size: var(--text-xs);
  margin-top: var(--s8);
  max-width: 68ch;
  line-height: var(--lh-base);
}

/* ── 6. Bloc vidéo ──────────────────────────────────────────── */
.pb-video {
  position: relative;
  width: 100%;
  max-width: 56rem;
  aspect-ratio: 16 / 9;
  /* Sans arrondi (11 septembre 2026, demande explicite de Sonia pour
     la vidéo) — contrairement aux autres composants du site, cette
     règle n'est pas mise en question ici. */
  overflow: hidden;
  background: var(--bg-dark-alt);
  border: 1.5px solid var(--pb-hairline);
  /* Espace au-dessus (15 septembre 2026, retour de Sonia : collée au
     titre) + centrée plutôt que collée à gauche — sa largeur (56rem)
     est déjà plus étroite que le conteneur. */
  margin-top: var(--s10);
  margin-inline: auto;
}
.pb-video iframe,
.pb-video video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
}

/* ── 7. Bloc citations ──────────────────────────────────────── */
/* Réutilise .testimonial-card / .testimonials-grid (pages.css) : la
   carte garde son fond clair (--bg-alt) quelle que soit la couleur du
   bloc, donc ses textes restent lisibles sans retouche. */
/* align-items:start (15 septembre 2026, même correctif que
   .testimonials-grid, pages.css — une grille étire ses lignes par
   défaut, chaque témoignage prenait la hauteur du plus long). */
.pb-quotes { display: grid; gap: var(--s6); grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr)); align-items: start; }
.pb-quotes > * { min-width: 0; }
/* .testimonial-card__role est en --text-muted (4.08:1, sous AA) —
   relevé ici pour ne pas introduire de texte sous le seuil. */
.pb-quotes .testimonial-card__quote { color: var(--text-primary); }
.pb-quotes .testimonial-card__name { color: var(--text-primary); }
.pb-quotes .testimonial-card__role { color: var(--text-secondary); }

/* ── 8. Bloc appel à l'action ───────────────────────────────── */
.pb-cta__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--s6);
}
/* .cta-light (financeurs.css) fournit déjà le fond, le centrage et
   l'espacement ; seul le titre est mis à l'échelle du site (les CTA
   de référence utilisent .display-sm). */
.pb-cta__title {
  color: var(--pb-text);
  font-family: var(--font-display);
  font-size: clamp(2rem, 4.5vw, 3.25rem);
  font-weight: 900;
  line-height: var(--lh-tight);
  text-transform: uppercase;
}
.pb-cta__desc {
  font-size: var(--text-lg);
  color: var(--pb-text);
  max-width: 52ch;
}
.pb-cta__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--s4);
}

/* ── 9. Bloc galerie ────────────────────────────────────────── */
.pb-gallery {
  display: grid;
  gap: var(--s6);
  grid-template-columns: repeat(var(--pb-cols, 3), minmax(0, 1fr));
}
.pb-gallery > * { min-width: 0; }
.pb-gallery img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--r-md);
  border: 1.5px solid var(--pb-hairline);
}

/* ── 10. Liste enrichie ─────────────────────────────────────── */
/* Le JS pose .competences-grid / .competence-item (pages.css) : la
   liste à 2 colonnes avec un point VERT des pages de formation.
   Rien à redéfinir sur fond clair — seuls les fonds sombres/colorés
   ont besoin d'un correctif, la pastille .competence-item étant en
   --bg-alt (clair) et son texte en --text-secondary (foncé). */
.pb-richlist { max-width: 78rem; }
.pb-bg--dark .competence-item,
.pb-bg--violet .competence-item,
.pb-bg--green .competence-item,
.pb-bg--yellow .competence-item,
.pb-bg--fluo .competence-item,
.pb-bg--custom .competence-item {
  background: transparent;
  border: 1.5px solid var(--pb-hairline);
  color: var(--pb-text);
}
/* Le point reste VERT sur fond clair et sur fond sombre (5.6:1 avec
   le texte foncé du site) ; sur un fond vert il disparaîtrait, il
   reprend donc la couleur de texte validée pour ce fond. */
.pb-bg--green .competence-item::before,
.pb-bg--fluo .competence-item::before { background: var(--pb-text); }

/* ── 8bis. Appel à l'action : panneau arrondi sur fond coloré ───
   Reprend le panneau « Candidature spontanée » d'emploi.html et le
   panneau FSE de financeurs.html (.funder-fse) : sur le site, une
   couleur pleine occupe TOUJOURS un panneau arrondi inséré dans une
   section claire, jamais un bandeau pleine largeur — et jamais deux
   bandeaux colorés qui se suivent en fin de page.
   Le panneau porte la classe de fond demandée dans l'admin
   (.pb-bg--dark / --violet / --yellow…), donc --pb-bg / --pb-text /
   --pb-accent y sont déjà les paires validées par l'audit
   d'accessibilité. */
.pb-cta-panel {
  background: var(--pb-bg);
  color: var(--pb-text);
  border-radius: var(--r-lg);
  padding: var(--s12) var(--s10);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  text-align: left;
  gap: var(--s5);
}
.pb-cta-panel__label {
  font-size: var(--text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--pb-accent);
  margin: 0;
}
.pb-cta-panel .pb-cta__title,
.pb-cta-panel .pb-cta__desc { color: var(--pb-text); }
.pb-cta-panel .pb-cta__title { font-size: clamp(1.8rem, 4vw, 3rem); }
.pb-cta-panel .pb-cta__desc { max-width: 60ch; }
.pb-cta-panel .pb-cta__actions { justify-content: flex-start; }

@media (max-width: 768px) {
  .pb-cta-panel { padding: var(--s8) var(--s6); }
}

/* ── Responsive ─────────────────────────────────────────────────
   Réutilise les seuils déjà présents dans le projet (960 / 768 /
   640px) — aucun nouveau système de breakpoints. */
@media (max-width: 960px) {
  .pb-cards,
  .pb-gallery { grid-template-columns: repeat(min(var(--pb-cols, 3), 2), minmax(0, 1fr)); }
}

@media (max-width: 768px) {
  .pb-textimg { grid-template-columns: 1fr; }
  /* Sur une seule colonne, l'image repasse toujours après le texte,
     quelle que soit la position choisie dans l'admin. */
  .pb-textimg--image-left .pb-textimg__media { order: 0; }
}

@media (max-width: 640px) {
  .pb-cards,
  .pb-gallery { grid-template-columns: 1fr; }
  /* Sur mobile, la rangée passe à gauche et se resserre, quel que
     soit le réglage choisi dans l'admin — « réparti sur la largeur »
     n'a pas de sens sur deux logos par ligne. */
  .pb-logos {
    justify-content: flex-start;
    column-gap: var(--s5);
    row-gap: var(--s4);
  }
  .pb-logo { min-width: 4.5rem; }
  .pb-block__head { margin-bottom: var(--s8); }
}

/* Le CTA en fond clair reprend le fond légèrement teinté et le filet
   supérieur de .cta-light (financeurs.html) : c'est ce qui détache
   visuellement le CTA de la dernière section de contenu. Posé ici
   parce que `.pb-block { background: var(--pb-bg) }` est déclaré
   après financeurs.css et l'emporterait sinon. */
.pb-cta.cta-light {
  background: var(--bg-alt);
  border-top: 1.5px solid var(--border);
}

/* Deux blocs CTA à la suite (cas réel : « supports de cours » puis
   « une question ? ») : les pages de référence terminent sur UN seul
   CTA. À défaut de pouvoir fusionner deux blocs saisis séparément
   dans l'admin, le second ne rouvre pas une nouvelle zone — pas de
   filet en double, pas de double respiration verticale : les deux se
   lisent comme une seule fin de page. */
.pb-cta + .pb-cta {
  padding-top: 0;
  border-top: 0;
}

/* ── Surlignement dans un PANNEAU sombre ────────────────────────
   Sur les pages de référence, un fragment mis en valeur est un vrai
   BLOC jaune dans un titre de section (a-propos.html, « ce qui nous
   *anime.* »), mais du TEXTE jaune à l'intérieur d'un panneau sombre
   (financeurs.html, « Fonds social *européen* »). Un bloc jaune qui
   repasse à la ligne dans la colonne étroite d'un panneau produit
   deux pavés empilés — jamais vu sur le site. Même distinction
   reproduite ici. Jaune #F5E32D sur #2e3232 = 9.8:1. */
.pb-stats-split .highlight,
.pb-stats-split .highlight--violet,
.pb-stats-split .highlight--green,
.pb-cta-panel.pb-bg--dark .highlight,
.pb-cta-panel.pb-bg--dark .highlight--violet,
.pb-cta-panel.pb-bg--dark .highlight--green {
  display: inline;
  background: transparent;
  padding: 0;
  line-height: inherit;
  color: var(--yellow);
}

/* Lien d'une carte sur fond sombre : .f-card__link est en --accent
   (violet) — 1,91:1 sur #2e3232, mesuré, largement sous le seuil AA.
   Il reprend l'accent validé du fond (jaune, 9,8:1), comme le fait
   déjà .f-card--featured pour la même raison. */
.pb-bg--dark .service-card .f-card__link,
.pb-bg--violet .service-card .f-card__link { color: var(--pb-accent); }

/* Fil d'Ariane : .breadcrumb est en --text-muted (3,73:1 mesuré sur
   les fonds clairs du site, sous le seuil AA — point resté ouvert au
   niveau du token, section 12bis du carnet). Relevé ici pour les
   pages à blocs uniquement, sans toucher au token partagé. */
/* 🔴 Corrigé le 8 septembre 2026 (remonté par Alexandra en mettant un
   hero mauve) : cette règle imposait --text-secondary, un gris foncé,
   quel que soit le fond choisi. Sur un hero violet ou sombre, le fil
   d'Ariane devenait illisible. Il suit maintenant --pb-label, qui est
   déjà défini par fond (clair sur fond sombre, foncé sur fond clair),
   comme tous les autres textes de ces pages. */
.pb-hero .breadcrumb,
.pb-hero .breadcrumb a { color: var(--pb-label); }
.pb-hero .breadcrumb a:hover { color: var(--pb-text); }
.pb-hero .breadcrumb-sep { color: var(--pb-label); opacity: 0.6; }
/* Retour de Sonia (15 septembre) : trop d'espace perdu entre le fil
   d'Ariane et le bloc suivant. .breadcrumb est une classe partagée
   par tout le site (jamais touchée ici pour ne rien changer
   ailleurs) — resserré seulement dans ce contexte. */
.pb-hero .breadcrumb { margin-bottom: var(--s3); }
/* Quand le fil d'Ariane est apparié à la barre d'ancres dans le même
   .pb-block__head-row (15 septembre 2026, page Partenaires) : sa
   propre marge basse gonflait sa boîte flex par rapport à la barre
   d'ancres (qui n'en a pas), donc align-items:center centrait deux
   boîtes de hauteurs différentes — le texte réel ne s'alignait pas
   malgré le centrage (mesuré : 6px d'écart). Sélecteur à 3 classes
   pour l'emporter sur la règle juste au-dessus, à spécificité égale. */
.pb-hero .pb-block__head-row .breadcrumb { margin-bottom: 0; }

/* Boutons du hero, rangée resserrée (15 septembre) : deux boutons
   côte à côte plutôt qu'empilés avec un grand espace entre eux.
   margin-top : .pb-hero__split .pb-hero__subtitle met son propre
   margin-bottom à 0 (voir plus haut) — sans compensation ici, le
   texte et les boutons se touchaient (repéré par Sonia, ligne rouge
   à l'appui sur sa capture). */
.employer-hero__cta--tight {
  gap: var(--s3);
  flex-wrap: nowrap;
  margin-top: var(--s6);
}
@media (max-width: 480px) {
  .employer-hero__cta--tight { flex-wrap: wrap; }
}

/* Sur-titre d'une carte de projet (liste sur l'accueil et
   employeurs.html) : .f-card__domain est en --text-muted (4,08:1,
   sous le seuil AA — point resté ouvert au niveau du token). Relevé
   ici, comme ailleurs dans ce fichier, sans toucher au token. */
.service-card .f-card__domain { color: var(--text-secondary); }
.pb-card--featured .f-card__domain { color: rgba(250, 249, 246, 0.9); }

/* Lien de source à libellé long en mobile : .f-card__link est en
   inline-flex, donc la mention « (nouvel onglet) » et la flèche
   restaient sur une ligne à part, poussées à droite. Elles reviennent
   simplement à la ligne avec le libellé. */
.pb-links .f-card__link { flex-wrap: wrap; }


/* ── Étiquettes d'une page, sur les cartes de liste ──────────────
   (7 septembre 2026) Discrètes : ce sont des repères de rangement,
   pas des boutons — d'où un simple filet, sans aplat de couleur qui
   entrerait en concurrence avec le badge de la carte. */
.pb-tags {
  list-style: none;
  margin: var(--s4) 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
}
.pb-tag {
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-secondary);
  border: 1.5px solid var(--border);
  border-radius: var(--r-full);
  padding: 0.125rem 0.625rem;
}
/* Carte mise en avant (fond violet) : le filet et le texte gris
   deviendraient illisibles. */
.pb-card--featured .pb-tag {
  color: var(--text-inverse);
  border-color: rgba(250, 249, 246, 0.45);
}

/* ── Recherche d'un bloc « liste de pages » (8 septembre 2026) ───
   Reprend .filter-search-input (design-system.css), le champ de
   recherche libre déjà utilisé par « Se former » — même apparence,
   même comportement, rien de nouveau à comprendre. */
.pb-list-search {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s3) var(--s4);
  margin-bottom: var(--s8);
}
.pb-list-search__label {
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--pb-label);
}
.pb-list-search .filter-search-input { min-width: min(22rem, 100%); }
.pb-list-search__status {
  font-size: var(--text-xs);
  color: var(--pb-label);
  margin: 0;
}
/* Sur fond sombre ou coloré, le champ garde son fond clair (il vient du
   design system) : le texte saisi doit rester foncé. */
.pb-bg--dark .pb-list-search .filter-search-input,
.pb-bg--violet .pb-list-search .filter-search-input,
.pb-bg--green .pb-list-search .filter-search-input,
.pb-bg--fluo .pb-list-search .filter-search-input,
.pb-bg--custom .pb-list-search .filter-search-input { color: var(--text-primary); }

/* ── 12. Bloc « Groupe de personnes » (organigramme) ──────────────
   21 septembre 2026. Grille de portraits pour Direction / Conseil
   d'administration / Ambassadeurs. Le contenu vient de la table
   `people` (écran Personnes de l'admin), jamais du bloc lui-même.

   Règle du site, valable ici comme partout : une photo est à ANGLES
   VIFS, sans cadre ni arrondi, et occupe toute la largeur de sa carte
   (voir .formation-hero__photo, .pb-textimg__media). Le ratio est le
   seul réglage — il vient de l'admin en variable CSS (--pb-portrait). */
.pb-people {
  display: grid;
  /* Ecart LONG entre les rangees, COURT entre les colonnes. L'ecart de
     32px entre deux rangees ne valait que le double de l'ecart photo-nom
     a l'interieur d'une carte : sur deux rangees, l'oeil regroupait mal. */
  gap: var(--s10) var(--s6);
  /* La grille occupe TOUTE la largeur disponible et decide elle-meme du
     nombre de colonnes, a partir d'une largeur de carte plutot que d'un
     nombre fige. Deux essais ecartes avant celui-ci : un nombre fixe de
     colonnes en 1fr donnait des portraits de 405x540 sur un grand ecran
     (et 589x785 sous 640px, plus haut qu'un telephone), et le meme
     nombre plafonne a 15rem laissait un grand vide a droite.

     11rem, et PAS 13 : a 13rem la grille tombe a 5 colonnes, donc un
     groupe de 6 (le CA, les ambassadrices) laisse une carte orpheline
     seule sur sa deuxieme ligne. 11rem + une gouttiere de 24px donnent
     6 colonnes des 1280px. Les deux valeurs vont ensemble : rabaisser
     l'une sans l'autre ne change pas le compte de colonnes.

     🔴 Plancher dur a 10rem : le nom est en Barlow Condensed capitales
     800 a 20px, et un patronyme d'un seul tenant de 15 caracteres
     (VANDERSTRAETEN) fait ~156px INSECABLES. Sous 160px il deborde de
     sa piste, sans erreur ni avertissement. Descendre plus bas
     demanderait d'abord de reduire la taille du nom.

     auto-fill et JAMAIS auto-fit : avec auto-fit, le bloc Direction et
     ses 2 personnes verrait ses cartes absorber toute la largeur, soit
     628px de portrait — exactement ce qui a ete rejete. auto-fill garde
     les pistes vides, donc une carte a la meme taille dans les quatre
     blocs de la page. */
  grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
}

/* Taille des portraits, reglee par bloc depuis l'admin. Les trois
   valeurs ne sont pas rondes par hasard : a 1440px (1280px de contenu
   utile) et avec une gouttiere de 24px, elles donnent respectivement
   8, 6 et 4 colonnes. Un groupe de 6 tombe donc soit pile (6), soit en
   4+2 — jamais sur une carte orpheline seule sur sa deuxieme ligne,
   ce qui etait le vrai defaut de la premiere version.
   Deux classes pour passer devant la regle mobile, declaree plus bas. */
.pb-people.pb-people--s { grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr)); }
.pb-people.pb-people--l { grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr)); }
.pb-people > * { min-width: 0; }

.pb-person { display: flex; flex-direction: column; gap: var(--s2); }
/* 🔴 Enveloppe indispensable des que .pb-person devient une grille ou
   une rangee (mode « presentation ») : sans elle, le nom, la fonction
   et la presentation sont des enfants DIRECTS et se repartissent chacun
   dans une case differente — la fonction atterrit sous la photo et la
   presentation a cote. Mesure a l'appui. En carte verticale, `contents`
   fait disparaitre l'enveloppe de la mise en page : rien ne change. */
.pb-person__text { display: contents; }

/* Aucun border-radius, aucune bordure : c'est volontaire et c'est la
   règle. Ne pas « harmoniser » avec .pb-gallery, qui est le seul bloc
   à en poser (et qui est justement resté une question ouverte). */
/* 12px, pas 16 : la photo et le nom forment une seule unite. C'est la
   rangee qui doit respirer (gap --s10 ci-dessus), pas l'interieur. */
.pb-person__media { margin-bottom: var(--s3); }
.pb-person__img {
  width: 100%;
  aspect-ratio: var(--pb-portrait, 3 / 4);
  object-fit: cover;
  display: block;
}

/* Sans photo, le nom flotterait dans le vide et la carte aurait l'air
   cassée : un filet de 3px en tête lui redonne une assise. --pb-accent
   vaut --violet sur les fonds clairs (le cas normal) et bascule tout
   seul sur un fond violet/sombre, où un violet plein disparaîtrait. */
.pb-person--nophoto {
  border-top: 3px solid var(--pb-accent);
  padding-top: var(--s4);
}
/* 🔴 Mais quand TOUT le groupe est sans photo, le violet cesse d'etre un
   signal : six traits identiques qui repondent tous a la meme question
   ne repondent plus a rien, c'est de la decoration (regle du carnet 32).
   Le violet reste alors reserve a son vrai sens — « il manque une photo
   ICI, au milieu de gens qui en ont une ». La classe etait deja posee
   par renderPeopleGroup, elle n'avait simplement aucune regle. */
.pb-people--nophoto .pb-person--nophoto {
  border-top: 1.5px solid var(--pb-hairline);
}

.pb-person__name {
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: 800;
  line-height: var(--lh-snug);
  text-transform: uppercase;
  /* 0.04em : les petits titres en capitales de ce site ont tous un
     interlettrage POSITIF de 0,04 a 0,12em (carnet 19.4) ; seuls les
     tres grands titres d'affichage vont vers le negatif. 0,01em etait
     en decalage avec tout le reste. Coute ~4% de largeur de nom, d'ou
     le plancher de 11rem et non 10. */
  letter-spacing: 0.04em;
  color: var(--pb-text);
  margin: 0;
  /* 🔴 Un patronyme d'un seul tenant ne se coupe jamais tout seul : mesure
     avec les vrais noms de l'equipe, « Marie-Christine Vandenbroucke »
     debordait de sa carte de 25 a 49px selon la largeur, et mordait sur
     la carte voisine. Une largeur de carte plus grande ne reglait rien —
     il y aura toujours un nom plus long. `break-word` ne coupe QUE quand
     le mot ne tient pas, donc les noms courts ne sont jamais touches. */
  overflow-wrap: break-word;
}
/* --pb-label (= --text-secondary) et NON --text-muted : ce dernier est
   mesuré à 4,08:1 sur fond clair, sous le seuil AA de 4,5:1 (carnet
   section 12.2). --pb-label suit en plus le fond du bloc. */
.pb-person__role {
  font-size: var(--text-xs);
  line-height: var(--lh-base);
  color: var(--pb-label);
  margin: 0;
}

/* La presentation est du texte courant, pas une etiquette : elle prend
   donc la couleur de texte du bloc (--pb-text) et non le gris des
   fonctions, sinon trois lignes de gris clair deviennent illisibles. */
.pb-person__bio {
  font-size: var(--text-xs);
  line-height: var(--lh-base);
  color: var(--pb-text);
  margin: var(--s1) 0 0;
}

/* ── Carte HORIZONTALE : photo a gauche, texte a droite ──────────
   Posee par renderPeopleGroup des qu'une personne du groupe a une
   presentation. Ce n'est pas une invention : c'est le schema de
   .pb-textimg, deja en place sur ce site. La photo y devient bien
   PLUS PETITE que dans la carte verticale (8rem contre ~12), et le
   texte recupere la largeur dont il a besoin pour se lire.

   La piste passe a 20rem : en dessous, le texte retombe sous les
   ~40 caracteres par ligne en dessous desquels un paragraphe se lit
   mal. 3 colonnes a 1440px, 2 a 1024. */
/* Deux classes et non une : la regle mobile de .pb-people est declaree
   PLUS BAS dans ce fichier, donc a specificite egale elle gagnerait et
   ce reglage serait mort en silence. */
.pb-people.pb-people--bio { grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr)); }

.pb-people--bio .pb-person {
  display: grid;
  grid-template-columns: 8rem minmax(0, 1fr);
  gap: var(--s4);
  align-items: start;
}
/* Ici l'enveloppe redevient une vraie boite : c'est elle qui occupe la
   colonne de droite, et qui empile nom / fonction / presentation. */
.pb-people--bio .pb-person__text {
  display: flex;
  flex-direction: column;
  gap: var(--s2);
  min-width: 0;
}
/* La photo ne s'etire pas sur la hauteur du texte : elle garde son
   ratio et reste calee en haut, sinon une bio longue la deformerait. */
.pb-people--bio .pb-person__media { margin-bottom: 0; }
/* Sans photo, le texte reprend toute la carte plutot que de laisser
   une colonne vide de 8rem a sa gauche. */
.pb-people--bio .pb-person--nophoto { grid-template-columns: minmax(0, 1fr); }

@media (max-width: 640px) {
  /* Une carte horizontale par ligne, photo encore reduite : deux
     colonnes de 20rem ne tiennent pas sur un telephone. */
  .pb-people.pb-people--bio { grid-template-columns: minmax(0, 1fr); }
  .pb-people--bio .pb-person { grid-template-columns: 6rem minmax(0, 1fr); }
}

/* ── 13. Bloc « Départements » (accordéon) ────────────────────────
   <details>/<summary> NATIF : clavier et lecteur d'écran gérés sans
   une ligne de JS maison.

   🔴 Piège déjà payé six fois sur ce projet : un `display` posé par une
   classe écrase le masquage NATIF (celui de l'attribut [hidden] et
   celui du contenu d'un <details> fermé, qui viennent de la feuille par
   défaut du navigateur, de spécificité plus faible). AUCUN `display`
   n'est donc posé sur .pb-dept__panel, l'enfant direct du <details> —
   la grille vit sur .pb-dept__people, un cran plus bas — et la règle
   :not([open]) ci-dessous est écrite dans la même foulée, par sécurité. */
/* --pb-hairline tombe a ~1,1:1 : ces filets sont ce qui dit « ceci est
   une liste de lignes », et ils disparaissent sur un ecran peu
   contraste. Un cran plus marque, ici seulement — le token global n'est
   pas touche. */
.pb-depts { border-top: 1.5px solid var(--border-strong); }

.pb-dept { border-bottom: 1.5px solid var(--border-strong); }
.pb-dept:not([open]) > .pb-dept__panel { display: none; }

/* 🔴 Une GRILLE a colonnes fixes, et surtout pas un flex.
   Cause reelle du defaut signale : `.pb-dept__name` etait en
   `flex: 1 1 auto` et absorbait tout l'espace libre, donc le
   `margin-left: auto` du bloc Responsable ne faisait plus rien. La
   position du compteur dependait alors de la LONGUEUR DU NOM DE LA
   RESPONSABLE — il se deplacait de plusieurs dizaines de pixels d'une
   ligne a l'autre. Un compteur ne s'aligne jamais par `margin: auto`
   sur un voisin de largeur variable : il lui faut une vraie colonne. */
.pb-dept__summary {
  display: grid;
  grid-template-columns: 2.25rem minmax(0, 1fr) minmax(0, 13rem) 1.375rem;
  align-items: center;
  column-gap: var(--s4);
  padding: var(--s5) 0;
  cursor: pointer;
  list-style: none;              /* Firefox : retire le triangle natif */
}
/* Nom et compteur empiles dans la meme colonne : le compteur cesse
   d'etre une quatrieme information de meme rang et redevient ce qu'il
   est, une legende du nom. Il n'a plus besoin de disparaitre sur
   telephone pour laisser la place aux autres. */
.pb-dept__title { display: flex; flex-direction: column; gap: 0.125rem; min-width: 0; }
.pb-dept__summary::-webkit-details-marker { display: none; }
/* Le survol doit DIRE quelque chose : il annonce ce qui va s'ouvrir. */
.pb-dept__summary:hover .pb-dept__name,
.pb-dept[open] > .pb-dept__summary .pb-dept__name { color: var(--pb-accent); }
.pb-dept__summary:hover .pb-dept__chevron,
.pb-dept[open] > .pb-dept__summary .pb-dept__chevron { color: var(--pb-accent); }
/* outline:none n'est jamais posé ici : le contour de focus du navigateur
   reste visible, c'est le seul repère de qui navigue au clavier. */

/* Pastille jaune ronde + numéro — repris de l'organigramme papier réel
   d'Interface3. Texte foncé sur jaune : 9,83:1. */
.pb-dept__num {
  flex: 0 0 auto;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 50%;
  background: var(--yellow);
  color: var(--text-on-yellow);
  font-family: var(--font-display);
  font-size: var(--text-sm);
  font-weight: 900;
  display: flex;
  align-items: center;
  justify-content: center;
}
/* Couleur reglee PAR DEPARTEMENT depuis l'admin (migration 0103).
   Liste fermee : chaque paire fond/texte est mesuree au-dessus du seuil
   AA, et aucune couleur libre ne peut entrer ici. Contrastes mesures :
   jaune 9,83:1 · vert 5,63:1 · orange 5,01:1 · violet 6,46:1 ·
   fluo 8,1:1 · sombre 11,3:1. */
.pb-dept__num--yellow { background: var(--yellow); color: var(--text-on-yellow); }
.pb-dept__num--violet { background: var(--violet); color: var(--text-on-violet); }
.pb-dept__num--green  { background: var(--green);  color: var(--text-on-green); }
.pb-dept__num--orange { background: var(--orange); color: var(--text-on-yellow); }
.pb-dept__num--fluo   { background: var(--fluo);   color: var(--text-on-yellow); }
.pb-dept__num--dark   { background: var(--black);  color: var(--text-inverse); }

/* Seule exception nécessaire : sur un bloc dont le fond est lui-même de
   la meme couleur, la pastille disparaitrait dans son propre fond. Meme
   traitement que les pastilles de la barre d'ancres (carnet, section 35).
   La bascule est toujours vers le violet, sauf sur un fond violet. */
.pb-bg--yellow .pb-dept__num--yellow,
.pb-bg--green  .pb-dept__num--green,
.pb-bg--fluo   .pb-dept__num--fluo { background: var(--violet); color: var(--text-inverse); }
.pb-bg--violet .pb-dept__num--violet { background: var(--yellow); color: var(--text-on-yellow); }
.pb-bg--dark   .pb-dept__num--dark { background: var(--yellow); color: var(--text-on-yellow); }

.pb-dept__name {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: 900;
  line-height: var(--lh-snug);
  text-transform: uppercase;
  /* Meme interlettrage que les noms des cartes de personne, quelques
     centaines de pixels plus haut sur la meme page : les petits titres
     en capitales de ce site sont tous en interlettrage POSITIF. */
  letter-spacing: 0.04em;
  color: var(--pb-text);
  min-width: 0;
}
.pb-dept__count {
  font-size: var(--text-xs);
  color: var(--pb-label);
}

/* Responsable : un intitulé en petites capitales grises + le nom en
   gras dessous. JAMAIS une pastille de couleur pleine — une version
   antérieure en avait une, verte, explicitement rejetée : un aplat crie
   aussi fort que le nom du département, qui est l'information
   principale de la ligne. */
/* Aligne a GAUCHE dans sa colonne fixe : le drapeau a droite ne sert
   plus a rien une fois la colonne posee, et il laissait le mot
   RESPONSABLE commencer a un endroit different sur chaque ligne. */
.pb-dept__lead {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  min-width: 0;
}
.pb-dept__lead-label {
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--pb-label);
}
/* Le nom monte d'un cran et l'etiquette descend : 8px d'ecart entre
   une etiquette et le nom qu'elle qualifie, ce n'etait pas assez pour
   deux natures differentes. */
.pb-dept__lead-name {
  font-size: var(--text-sm);
  font-weight: 700;
  color: var(--pb-text);
}

.pb-dept__chevron {
  width: 1.375rem;
  height: auto;
  color: var(--pb-label);
  transition: transform 0.18s ease, color 0.18s ease;
}
.pb-dept[open] > .pb-dept__summary .pb-dept__chevron { transform: scaleY(-1); }

.pb-dept__panel { padding: 0 0 var(--s6) 3.25rem; }
.pb-dept__people {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr));
  gap: var(--s4);
  list-style: none;
  margin: 0;
  padding: 0;
}
.pb-dept__person { display: flex; flex-direction: column; gap: 0.125rem; min-width: 0; }
.pb-dept__person-name { font-weight: 700; color: var(--pb-text); }
.pb-dept__person-role { font-size: var(--text-xs); color: var(--pb-label); }

@media (prefers-reduced-motion: reduce) {
  .pb-dept__chevron { transition: none; }
}

@media (max-width: 640px) {
  /* Sur un telephone, 13rem ne laissent plus qu'une seule colonne, donc
     un portrait pleine largeur (mesure : 358x477 a 390px, soit presque
     un ecran entier pour une seule tete). Deux colonnes plus serrees,
     avec un ecart reduit : le nom tient toujours, la photo redescend a
     une taille raisonnable. */
  /* Mesure : 2 colonnes a 390px (171px de photo) et 3 a 640px (187px).
     Un « repeat(2, 1fr)` fige donnerait 286px a 640px, soit plus gros
     que sur un ecran de bureau — l'inverse de ce qu'on cherche. */
  .pb-people { grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr)); gap: var(--s6) var(--s4); }
  /* 🔴 Redeclare avec DEUX classes, sinon `.pb-people--l` (0,2,0) l'emporte
     sur cette regle (0,1,0) et la taille « Grande » resterait a une seule
     colonne sur telephone — mesure : un portrait de 589px a 640px, soit
     exactement ce que le commentaire du haut de fichier declare rejete.
     Meme motif que `.pb-people--bio` juste en dessous. */
  .pb-people.pb-people--s,
  .pb-people.pb-people--l { grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr)); }

  /* Le compteur n'est plus sacrifie : range sous le nom, il ne dispute
     plus sa place a personne. La responsable descend sous les deux, dans
     la meme colonne — et surtout PAS par un `margin-left: 3.25rem` en
     dur comme avant, une valeur recopiee a la main de la largeur de la
     pastille, qui mentait en silence des que cette pastille changeait. */
  .pb-dept__summary {
    grid-template-columns: 2.25rem minmax(0, 1fr) 1.375rem;
    row-gap: var(--s3);
  }
  .pb-dept__lead { grid-column: 2 / 3; }
  .pb-dept__panel { padding-left: 0; }
}
