/*
Theme Name:   Firalis Group
Theme URI:    https://firalisgroup.com
Description:  Thème enfant de Firalis Group — tout le custom du site vit ici. Symlink depuis le hub de développement.
Author:       Firalis
Template:     twentytwentyfive
Version:      0.36.1
Text Domain:  firalis-group
*/

/* ═══════════════════════════════════════════════════════════════════
   Les variables --fi-* sont injectées par le mu-plugin firalis-core
   depuis packages/tokens/tokens.json. Ne jamais écrire une couleur ou
   un espacement en dur ici.

   Les couleurs de filiale existent en deux versions :
   --fi-company-<slug>       couleur de MARQUE, réservée à la vague
                             (WCAG 1.4.3 exempte les logotypes)
   --fi-company-<slug>-ink   variante assombrie, seule autorisée pour
                             du texte ou une pastille porteuse de sens
   ═══════════════════════════════════════════════════════════════════ */

:root {
	--fi-sec: clamp(3.5rem, 7vw, 6.5rem);

	/* Hauteur de l'enveloppe collante de l'en-tête. ui.js la MESURE et écrase cette
	   valeur au chargement et au redimensionnement — elle vaut 97px à 1440 et 92px
	   à 390, la CSS ne peut pas la connaître. Le repli est volontairement majoré :
	   sans JavaScript, un dépassement passe hors du document, alors qu'un défaut
	   laisserait une bande blanche au-dessus du fond du hero. */
	--fi-header-h: 7rem;
}

/* WordPress espace les blocs frères de 19,2px : entre deux sections pleine
   largeur, cette bande de fond quasi-blanc lit comme une couture de rendu,
   surtout entre le gris de « Quality » et le navy de « Momentum ». */
.wp-block-post-content > .alignfull,
.wp-site-blocks > .alignfull { margin-block-start: 0; }

/* ⚠️ 10/10 — Le pied de page avait échappé à la règle : c'est une partie de
   gabarit (<footer>), pas un bloc « alignfull », et il gardait ses 19,2px. Sur
   les huit pages qui finissent par une bande grise (/contact/, /what-we-offer/,
   /careers/, les cinq fiches), la couture blanche se voyait entre le gris et le
   navy. Ailleurs, la dernière bande est blanche et porte sa propre marge
   intérieure : les 19,2px s'y fondaient sans rien espacer. */
.wp-site-blocks > footer { margin-block-start: 0; }

/* ── Le fond des premières bandes ────────────────────────────────────
   L'accueil ouvre sur le shader « warp », plein cadre. Les pages intérieures
   reçoivent le même dispositif dans une autre forme : un halo pâle posé à
   DROITE et fondu avant d'atteindre le texte. Le masque vit ici et pas dans le
   JavaScript — c'est une décision de mise en page, pas de rendu.

   Le fond est glissé DANS la bande : enveloppé autour d'elle, il passait
   derrière son aplat opaque et ne se voyait plus. Il s'arrête donc aux 24 px de
   gouttière — un élément absolu se positionne sur la boîte de remplissage — et
   c'est sans conséquence : le masque diagonal l'a déjà éteint bien avant les
   bords. Voir inc/wash.php pour ce qui a été essayé et pourquoi.

   Sans JavaScript ou sans WebGL, le canvas ne se monte pas : la bande garde son
   aplat, et rien ne manque. */

.fi-washband {
	position: relative;
	/* Le canvas est en z-index 0 et le contenu en 1 : sans contexte d'empilement
	   propre, une section suivante posée plus haut dans le document passerait
	   entre les deux. */
	isolation: isolate;
}

.fi-washband > *:not(.fi-wash) {
	position: relative;
	z-index: 1;
}

.fi-wash {
	position: absolute;
	inset: 0;
	z-index: 0;
	pointer-events: none;

	/* Les mises en page « constrained » de WordPress imposent une largeur maximale
	   et des marges automatiques à TOUT enfant direct, élément absolu compris : le
	   canvas se retrouvait bridé à 1 240 px et centré au lieu de couvrir la bande.
	   Mesuré : 1 240 de fond dans une bande de 1 440. */
	max-inline-size: none !important;
	margin: 0 !important;

	/* Le fond s'efface avant d'atteindre la colonne de texte. Deux masques : le
	   premier ouvre la diagonale (rien à gauche, tout à droite), le second
	   éteint le halo vers le bas.

	   Le second est en PIXELS et non en pourcentage : le halo est l'ouverture
	   d'une page, il doit s'éteindre à la même distance du haut que la bande
	   fasse 600 px ou 930. En pourcentage, une bande haute l'étirait jusque dans
	   les tuiles de service de /what-we-offer/.

	   ⚠️ 13/09 — MAIS JAMAIS AU-DELÀ DU BAS DE LA BANDE. Une bande plus courte que
	   l'arrêt (la tête de /what-we-offer/ : 393 px à 1440, pour un halo éteint à
	   620) coupait le fond NET à son ras, encore à pleine intensité — le halo
	   s'arrêtait sur une ligne droite au-dessus des rangs de services. Chaque arrêt
	   prend donc le plus petit de sa valeur en pixels et d'une borne relative :
	   l'extinction au plus tard à 100 % de la hauteur, le plein au plus tard
	   180 px avant. Une bande assez haute garde EXACTEMENT les arrêts d'avant ;
	   seules les bandes qui étaient coupées changent. */
	-webkit-mask-image: linear-gradient(102deg, transparent 14%, #000 64%),
		linear-gradient(180deg, #000 0, #000 min(340px, calc(100% - 180px)), transparent min(620px, 100%));
	mask-image: linear-gradient(102deg, transparent 14%, #000 64%),
		linear-gradient(180deg, #000 0, #000 min(340px, calc(100% - 180px)), transparent min(620px, 100%));
	-webkit-mask-composite: source-in;
	mask-composite: intersect;
}

/* La bande qui OUVRE une page commence sous l'en-tête collant : le fond remonte
   donc de la hauteur du bandeau, sinon il est coupé net à son ras et la page
   s'ouvre sur 97 px de blanc. Même geste que le fond du hero de l'accueil, qui
   remonte de la même variable. L'en-tête reste au-dessus (z-index 50 contre 0) et
   il est translucide : le halo se devine à travers, c'est voulu.

   Les arrêts du masque suivent le décalage — réglés à 340 et 620 px depuis le
   haut de la BANDE, ils s'éteindraient sinon 97 px trop tôt.

   ⚠️ Mêmes bornes que .fi-wash (13/09) : ici 100 % est le bas de la bande —
   l'élément part de −97 px et s'arrête à son ras —, l'extinction n'y va donc
   jamais au-delà. */
.fi-wash--top {
	inset-block-start: calc(-1 * var(--fi-header-h));

	-webkit-mask-image: linear-gradient(102deg, transparent 14%, #000 64%),
		linear-gradient(180deg, #000 0, #000 min(calc(340px + var(--fi-header-h)), calc(100% - 180px)), transparent min(calc(620px + var(--fi-header-h)), 100%));
	mask-image: linear-gradient(102deg, transparent 14%, #000 64%),
		linear-gradient(180deg, #000 0, #000 min(calc(340px + var(--fi-header-h)), calc(100% - 180px)), transparent min(calc(620px + var(--fi-header-h)), 100%));
}

.fi-wash canvas {
	display: block;
	inline-size: 100%;
	block-size: 100%;
}

/* Sur un écran étroit, la forme n'a pas rétréci : le cadrage est en « cover »,
   donc l'arc occupe la même part d'une bande deux fois plus étroite et passe
   derrière le titre. On le rabat sur le haut et on le retient d'un quart. */
@media (max-width: 48em) {
	/* Mêmes bornes relatives qu'au-dessus (13/09), rampe de 120 px : les arrêts
	   sont plus serrés sur un écran étroit, 180 px de rampe y mangeraient le plein. */
	.fi-wash {
		opacity: 0.75;
		-webkit-mask-image: linear-gradient(150deg, transparent 22%, #000 72%),
			linear-gradient(180deg, #000 0, #000 min(180px, calc(100% - 120px)), transparent min(380px, 100%));
		mask-image: linear-gradient(150deg, transparent 22%, #000 72%),
			linear-gradient(180deg, #000 0, #000 min(180px, calc(100% - 120px)), transparent min(380px, 100%));
	}

	.fi-wash--top {
		-webkit-mask-image: linear-gradient(150deg, transparent 22%, #000 72%),
			linear-gradient(180deg, #000 0, #000 min(calc(180px + var(--fi-header-h)), calc(100% - 120px)), transparent min(calc(380px + var(--fi-header-h)), 100%));
		mask-image: linear-gradient(150deg, transparent 22%, #000 72%),
			linear-gradient(180deg, #000 0, #000 min(calc(180px + var(--fi-header-h)), calc(100% - 120px)), transparent min(calc(380px + var(--fi-header-h)), 100%));
	}
}

/* ── Socle ───────────────────────────────────────────────────────── */

/* Les 21 pages intérieures sont courtes : le pied s'arrêtait à 840px sur un
   viewport de 900, laissant 60px de blanc sous le navy. */
html {
	block-size: 100%;
	/* L'en-tête collant fait 97px : sans cette réserve, une ancre dépose le
	   surtitre de la section à 3px sous lui. Neutralisé en mouvement réduit
	   par le bloc dédié en fin de feuille. */
	scroll-behavior: smooth;
}

/* Les sections vivent dans « .entry-content », pas en enfant direct de
   « .wp-site-blocks » : un sélecteur enfant ne les atteignait pas et la réserve
   restait à 0. On vise donc toute bande pleine largeur porteuse d'une ancre. */
.alignfull[id],
.wp-site-blocks [id][class*="fi-"] {
	scroll-margin-block-start: 7rem;
}

body {
	min-block-size: 100dvh;
	display: flex;
	flex-direction: column;
	font-family: var(--fi-font-sans);
	color: var(--fi-color-text);
	-webkit-font-smoothing: antialiased;
	text-rendering: optimizeLegibility;
}

h1, h2, h3, h4,
.wp-block-heading {
	font-family: var(--fi-font-display);
	color: var(--fi-color-ink);
	text-wrap: balance;
}

/* La graisse et l'approche des titres viennent de theme.json, où elles sont
   calées SUR LE PAS de taille : h1 et h2 tombent sur les pas 5 et 4, assez
   grands pour supporter -0.035em et une graisse 700 ; h3 à h6 descendent vers
   le corps de lecture et gardent 600 / -0.022em.
   Cette règle déclarait « font-weight: 600 ; letter-spacing: -0.03em » pour
   tous les niveaux à la fois. Son sélecteur « .wp-block-heading » a la même
   spécificité que le « :root :where(h1) » émis par theme.json et passe après
   lui dans l'ordre des feuilles : elle gagnait donc systématiquement, et les
   valeurs de theme.json n'atteignaient aucun titre du site. Ne pas y remettre
   de graisse ni d'approche — ce sont des jetons, pas des valeurs de feuille.
   Seuls h3 et h4 gardent ici l'approche d'origine, plus serrée que le défaut. */
h3, h4 {
	letter-spacing: -0.03em;
}

/* Twenty Twenty-Five pose un contour de 3px sur « :focus » tout court. Au clic
   souris, « :focus-visible » ne s'active pas sur un bouton : la règle du parent
   passait donc, et dessinait une bordure sombre autour de l'étape cliquée — et
   du panneau, qui porte tabindex="0" pour l'accessibilité.
   On ne garde l'anneau que pour la navigation au clavier. */
.wp-site-blocks :focus:not(:focus-visible) {
	outline: none;
}

:focus-visible {
	outline: 2px solid var(--fi-color-brand);
	outline-offset: 3px;
	border-radius: 2px;
}

/* L'anneau était bleu PARTOUT, bandes sombres comprises : #0038B0 sur #0C1B2A,
   soit 1.82:1 — déjà quasi invisible au clavier. En encre il disparaissait tout
   à fait. Sur fond sombre il passe donc à l'accent clair : 8.56:1. */
.fi-statement :focus-visible,
.fi-momentum :focus-visible,
.fi-footer :focus-visible {
	outline-color: var(--fi-color-accent-on-dark);
}

/* Marge haute que WordPress ajoute à tout bloc suivant un frère : elle
   décale les colonnes d'une grille CSS. À neutraliser sur chaque grille. */
.fi-pillars > *,
.fi-footer__cols > *,
.fi-footer__col > :first-child,
.fi-statement__grid > *,
.fi-momentum__grid > *,
.fi-continuum__panel > * {
	margin-block-start: 0;
}

/* La zone de contenu absorbe la hauteur restante. */
.wp-site-blocks {
	display: flex;
	flex-direction: column;
	flex: 1;
}

.wp-site-blocks > main { flex: 1; }

/* ── Surtitre ────────────────────────────────────────────────────── */

/* ⚠️ 0.6875rem et pas 0.7 : c'est LE rang de micro-libellé du site, employé
   52 fois entre cette feuille et les six feuilles de fiche. Les quatre
   déclarations qui vivaient à 0.7rem s'en écartaient de 0,2px — assez pour
   que trois revues du 01/09 les relèvent comme deux rangs distincts, trop peu
   pour qu'on voie pourquoi. Même défaut, même correctif que sur le continuum
   le 28/08 : un seul rang, une seule valeur. */
.fi-eyebrow {
	display: flex;
	align-items: center;
	gap: var(--fi-space-xs);
	margin-block-end: var(--fi-space-m);
	font-family: var(--fi-font-mono);
	font-size: 0.6875rem;
	font-weight: 500;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var(--fi-color-brand);
}

.fi-eyebrow::before {
	content: "";
	flex: 0 0 auto;
	inline-size: 1.7rem;
	block-size: 2px;
	/* Le libellé reste en encre, le filet porte la couleur : neuf sections,
	   neuf petites amorces bleues. C'est la répétition qui tient la page. */
	background: var(--fi-color-wash);
}

.fi-eyebrow--light {
	color: var(--fi-color-accent-on-dark);
}

/* Signature du groupe. Sur une ligne, le point médian sépare ; sur deux, il
   resterait orphelin en bout de ligne — on le retire et on empile, comme sur
   la carte de visite. Le <br> ne sert qu'à ça : il ne porte aucun sens, le
   libellé se lit à l'identique d'un seul tenant. */
.fi-sig__br { display: none; }

@media (max-width: 30em) {
	.fi-sig__dot { display: none; }
	.fi-sig__br  { display: inline; }

	/* Sur deux lignes, le filet se cale sur la PREMIÈRE, pas au milieu du bloc. */
	.fi-eyebrow { align-items: flex-start; }
	.fi-eyebrow::before { margin-block-start: 0.62em; }
}

/* ── Titres de section et chapôs ─────────────────────────────────── */

.fi-lede,
.fi-hero__lede {
	max-inline-size: min(46ch, 100%);
	margin-block: 0 var(--fi-space-l);
	font-size: clamp(1rem, 0.95rem + 0.3vw, 1.12rem);
	line-height: 1.65;
	color: var(--fi-color-muted);
	text-wrap: pretty;
}

/* ── Révélation au défilement ────────────────────────────────────── */

.fi-rv {
	opacity: 0;
	transform: translateY(14px);
	transition:
		opacity 0.6s cubic-bezier(0.22, 0.61, 0.36, 1),
		transform 0.6s cubic-bezier(0.22, 0.61, 0.36, 1);
}

.fi-rv.is-in {
	opacity: 1;
	transform: none;
}

@media (prefers-reduced-motion: reduce) {
	.fi-rv {
		opacity: 1;
		transform: none;
		transition: none;
	}
}

/* Sans JavaScript, rien ne doit rester invisible. */
.no-js .fi-rv {
	opacity: 1;
	transform: none;
}

/* ── Jauge de défilement ─────────────────────────────────────────── */

.fi-progress {
	position: fixed;
	inset-block-start: 0;
	inset-inline-start: 0;
	block-size: 2px;
	inline-size: 0;
	background: linear-gradient(to right, var(--fi-color-brand), var(--fi-color-wash));
	z-index: 99;
	transition: inline-size 0.1s linear;
}

/* ═══════════════════════════════════════════════════════════════════
   EN-TÊTE
   ═══════════════════════════════════════════════════════════════════ */

/* La stickiness appartient à l'ENVELOPPE générée par WordPress : notre groupe la
   remplit exactement, et un élément collant ne peut pas bouger dans un parent qu'il
   remplit. Vérifié : sans cette règle l'en-tête défile hors de l'écran. */
.wp-site-blocks > header.wp-block-template-part {
	position: sticky;
	inset-block-start: 0;
	z-index: 50;
}

.fi-header {
	background: color-mix(in srgb, var(--fi-color-surface) 86%, transparent);
	border-block-end: 1px solid var(--fi-color-line);
}

/* Le flou est porté par un pseudo-élément, PAS par l'en-tête lui-même :
   « backdrop-filter » fait de son porteur un bloc conteneur pour les descendants
   en position:fixed. Le menu mobile de WordPress, en inset:0, se résolvait donc
   contre les 78px de l'en-tête au lieu du viewport — quatre liens sur cinq étaient
   rognés hors de la boîte. Mesuré : overlay 390×77 avec le flou, 390×844 sans. */
.fi-header::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	backdrop-filter: saturate(180%) blur(14px);
	-webkit-backdrop-filter: saturate(180%) blur(14px);
	pointer-events: none;
}

.fi-header .fi-header__inner {
	/* Aligné sur la mise en page « constrained » des sections : sans cette
	   correction la marque se posait 24px à droite du « F » du titre. */
	max-inline-size: var(--fi-container-max);
	margin-inline: auto;
	padding-block: var(--fi-space-s);
	gap: var(--fi-space-l);
}

.fi-header__right {
	gap: var(--fi-space-s);
}

/* 24×24 mesuré : sous le minimum de 44px. On agrandit la zone de touche SANS
   toucher à « display » — c'est WordPress qui décide quand le bouton apparaît, et
   forcer « display: flex » ici le rendait visible jusqu'en 1440px. */
.fi-header .wp-block-navigation__responsive-container-open {
	align-items: center;
	justify-content: center;
	inline-size: 44px;
	block-size: 44px;
}

.fi-brand {
	display: inline-flex;
	align-items: center;
	gap: var(--fi-space-2xs);
	text-decoration: none;
	color: inherit;
}

.fi-brand__logo {
	display: block;
	block-size: auto;
	max-block-size: 2.25rem;
	inline-size: auto;
}

/* Le vrai logo n'a pas d'anneau : deux vagues, 265×432, donc un format portrait.
   On fixe la HAUTEUR et on laisse la largeur suivre — figer les deux écrasait le
   dessin. « aspect-ratio » évite le saut de mise en page avant peinture du SVG. */
.fi-brand__mark {
	display: block;
	block-size: 30px;
	inline-size: auto;
	aspect-ratio: 265 / 432;
	flex: 0 0 auto;
}

/* Sur fond sombre, le rapport figure/fond s'inverse : la vague dominante devient
   la plus claire, la seconde s'efface. Le gris #9F9F9F du logo posé tel quel sur
   le navy tomberait à 1.5:1 et disparaîtrait. */
.fi-brand--light .fi-brand__mark {
	--fi-color-mark-a: var(--fi-color-on-dark-strong);
	--fi-color-mark-b: var(--fi-color-on-dark-muted);
}

.fi-brand__name {
	font-family: var(--fi-font-display);
	font-size: var(--fi-size-step-1);
	font-weight: 600;
	letter-spacing: -0.025em;
	color: var(--fi-color-ink);
}

.fi-brand--light .fi-brand__name {
	color: var(--fi-color-on-dark);
}

/* ── Navigation ──────────────────────────────────────────────────── */

.fi-nav .wp-block-navigation__container {
	gap: clamp(var(--fi-space-s), 1.6vw, var(--fi-space-l));
}

.fi-nav .wp-block-navigation-item__content {
	position: relative;
	padding-block: 0.2rem;
	font-family: var(--fi-font-display);
	font-size: var(--fi-size-step-0);
	font-weight: 500;
	color: var(--fi-color-text);
	text-decoration: none;
}

/* Le souligné se déploie de gauche à droite plutôt que d'apparaître. */
.fi-nav .wp-block-navigation-item__content::after {
	content: "";
	position: absolute;
	inset-inline: 0 100%;
	inset-block-end: 0;
	block-size: 1.5px;
	background: var(--fi-color-brand);
	transition: inset-inline-end 0.22s cubic-bezier(0.22, 0.61, 0.36, 1);
}

.fi-nav .wp-block-navigation-item__content:hover::after {
	inset-inline-end: 0;
}

/* 10/10/2026 — Rubrique courante, posée par inc/nav.php (le cœur ne marque
   jamais un lien « custom ») : le souligné du survol reste tiré. Un parent
   s'allume quand un de ses enfants est courant — « News & Events » sur /news/,
   /events/ et un article. */
.fi-nav .wp-block-navigation__container > .current-menu-item > .wp-block-navigation-item__content::after,
.fi-nav .wp-block-navigation__container > .current-menu-ancestor > .wp-block-navigation-item__content::after {
	inset-inline-end: 0;
}

/* 10/10/2026 — « News & Events » n'a pas de page d'index : son libellé est un
   <button> (inc/nav.php). Comparé à « About » au CDP, propriété par propriété :
   police, couleur, souligné et position du libellé étaient déjà identiques ; ne
   différaient que les réglages d'agent utilisateur du bouton — 6px de
   remplissage latéral, curseur, « appearance », modèle de boîte, alignement. */
.fi-nav .fi-nav__parent {
	box-sizing: content-box;
	padding-inline: 0;
	border: 0;
	background: none;
	appearance: none;
	text-align: start;
	cursor: pointer;
}

.fi-header__cta .wp-block-button__link {
	padding: 0.55rem 1.1rem;
	border-radius: var(--fi-radius-s);
	border: 1px solid color-mix(in srgb, var(--fi-color-brand) 30%, transparent);
	background: transparent;
	color: var(--fi-color-brand);
	font-family: var(--fi-font-display);
	font-size: var(--fi-size-step-0);
	font-weight: 600;
	white-space: nowrap;
	transition: background-color 0.18s ease, border-color 0.18s ease;
}

.fi-header__cta .wp-block-button__link:hover {
	border-color: var(--fi-color-brand);
	background: var(--fi-color-brand-soft);
}

/* ═══════════════════════════════════════════════════════════════════
   HERO
   ═══════════════════════════════════════════════════════════════════ */

.fi-hero {
	position: relative;
	isolation: isolate;
	overflow: clip;
	background: var(--fi-color-surface);
	padding-block: clamp(3rem, 7vw, 6.5rem) clamp(2.5rem, 5vw, 4rem);
	border-bottom: 1px solid var(--fi-color-line);
}

.fi-hero > .wp-block-group.fi-hero__content {
	position: relative;
	z-index: 2;
	max-inline-size: min(38rem, 100%);
	/* WordPress force « margin-left: auto !important » sur les enfants d'une
	   mise en page « constrained ». Le décalage vaut la demi-marge du
	   conteneur centré — pas zéro — pour rester aligné sur l'en-tête. */
	margin-inline-start: max(0px, calc((100% - var(--fi-container-max)) / 2)) !important;
	margin-inline-end: auto !important;
}

.fi-hero h1 {
	margin-block: 0 var(--fi-space-m);
	font-size: var(--fi-size-step-5);
	line-height: 1.01;
	letter-spacing: -0.045em;
}

/* Six titres de section portent une phrase en emphase. En encre sur encre,
   le dispositif s'effaçait — c'est précisément ce qui aurait rendu la page terne.
   Le texte reste lisible en encre et la couleur passe sous la ligne, en filet :
   c'est le vocabulaire du site (filet de surtitre, souligné de navigation,
   filets de section), pas un surligneur. Le décor ne porte aucun sens : la
   phrase se lit à l'identique sans lui. */
.fi-hl {
	color: var(--fi-color-ink);
	/* Filet en fond, PAS en « text-decoration » : le titre du hero est découpé
	   mot à mot par ui.js en « inline-block », et une décoration de texte ne se
	   propage jamais dans un inline atomique — elle disparaissait sur le seul
	   titre où elle comptait le plus. Un fond, lui, peint bien derrière.
	   « box-decoration-break: clone » redessine le filet sur chaque ligne. */
	background-image: linear-gradient(var(--fi-color-wash), var(--fi-color-wash));
	background-repeat: no-repeat;
	background-size: 100% 0.09em;
	background-position: 0 calc(100% - 0.08em);
	box-decoration-break: clone;
	-webkit-box-decoration-break: clone;
}

/* Entrée du titre, mot à mot. Le `pre` est indispensable : un inline-block
   avale l'espace qui le suit. */
.fi-hero h1 .fi-w {
	display: inline-block;
	white-space: pre;
	opacity: 0;
	transform: translateY(0.5em);
	animation: fi-word-in 0.7s cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
}

@keyframes fi-word-in {
	to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
	.fi-hero h1 .fi-w { animation: none; opacity: 1; transform: none; }
}

/* ── Boutons ─────────────────────────────────────────────────────── */
/* 26/10/2026 — `.fi-404` (templates/404.html) prend les mêmes boutons. */

:is(.fi-hero, .fi-heroW, .fi-heroX, .fi-cta, .fi-study, .fi-cop, .fi-404) .wp-block-buttons {
	gap: var(--fi-space-xs);
}

:is(.fi-hero, .fi-heroW, .fi-heroX, .fi-cta, .fi-study, .fi-cop, .fi-404) .wp-block-button__link {
	padding: 0.9rem 1.65rem;
	border-radius: var(--fi-radius-s);
	font-family: var(--fi-font-display);
	font-size: var(--fi-size-step-0);
	font-weight: 600;
	letter-spacing: -0.008em;
	transition:
		transform 0.18s cubic-bezier(0.22, 0.61, 0.36, 1),
		box-shadow 0.18s ease,
		background-color 0.18s ease,
		border-color 0.18s ease;
}

:is(.fi-hero, .fi-heroW, .fi-heroX, .fi-cta, .fi-study, .fi-cop, .fi-404) .wp-block-button:not(.is-style-outline) .wp-block-button__link {
	background: var(--fi-color-brand);
	border: 1px solid var(--fi-color-brand);
	color: var(--fi-color-on-dark-strong);
}

:is(.fi-hero, .fi-heroW, .fi-heroX, .fi-cta, .fi-study, .fi-cop, .fi-404) .wp-block-button:not(.is-style-outline) .wp-block-button__link:hover {
	background: var(--fi-color-brand-deep);
	border-color: var(--fi-color-brand-deep);
	transform: translateY(-1px);
	box-shadow: 0 8px 22px color-mix(in srgb, var(--fi-color-brand) 16%, transparent);
}

:is(.fi-hero, .fi-heroW, .fi-heroX, .fi-cta, .fi-study, .fi-cop, .fi-404) .is-style-outline .wp-block-button__link {
	border: 1px solid color-mix(in srgb, var(--fi-color-brand) 30%, transparent);
	background: transparent;
	color: var(--fi-color-brand);
}

:is(.fi-hero, .fi-heroW, .fi-heroX, .fi-cta, .fi-study, .fi-cop, .fi-404) .is-style-outline .wp-block-button__link:hover {
	background: var(--fi-color-brand-soft);
	transform: translateY(-1px);
}

@media (max-width: 30em) {
	:is(.fi-hero, .fi-heroW, .fi-heroX, .fi-cta, .fi-study, .fi-cop, .fi-404) .wp-block-buttons { display: grid; }
	:is(.fi-hero, .fi-heroW, .fi-heroX, .fi-cta, .fi-study, .fi-cop, .fi-404) .wp-block-button__link { display: block; text-align: center; }
}

/* ── Amorce de défilement ────────────────────────────────────────── */

.fi-scroll {
	position: relative;
	z-index: 2;
	display: inline-flex;
	align-items: center;
	gap: var(--fi-space-2xs);
	margin-block-start: var(--fi-space-l);
	font-family: var(--fi-font-mono);
	font-size: 0.66rem;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--fi-color-muted);
	text-decoration: none;
}

.fi-scroll::before {
	content: "";
	display: block;
	inline-size: 1px;
	block-size: 22px;
	background: linear-gradient(var(--fi-color-brand), transparent);
	animation: fi-scroll-cue 1.9s ease-in-out infinite;
}

@keyframes fi-scroll-cue {
	0%, 100% { transform: scaleY(0.4); transform-origin: top; }
	50%      { transform: scaleY(1);   transform-origin: top; }
}

@media (prefers-reduced-motion: reduce) {
	.fi-scroll::before { animation: none; }
}

/* ── Bandeau de relevés ──────────────────────────────────────────── */

.fi-hero .fi-hero__facts {
	position: relative;
	z-index: 2;
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(10.5rem, 100%), 1fr));
	align-items: stretch;
	gap: 0 var(--fi-space-m);
	margin-block-start: clamp(2.5rem, 5vw, 4rem);
}

/* Le filet est porté par CHAQUE cellule, pas par le conteneur : sinon la rangée
   suivante n'en a pas, et les séparateurs verticaux pendent dans le vide. */
.fi-hero__facts p {
	margin: 0;
	padding-block: var(--fi-space-m);
	border-block-start: 1px solid var(--fi-color-line);
	font-size: var(--fi-size-step--1);
	font-family: var(--fi-font-mono);
	letter-spacing: 0.11em;
	text-transform: uppercase;
	line-height: 1.4;
	color: var(--fi-color-muted);
	font-variant-numeric: tabular-nums;
}



.fi-hero__facts strong {
	display: block;
	margin-block-end: 0.35rem;
	font-family: var(--fi-font-display);
	font-size: var(--fi-size-step-3);
	font-weight: 600;
	letter-spacing: -0.035em;
	line-height: 1.05;
	text-transform: none;
	color: var(--fi-color-ink);
}

/* ── Le motif ────────────────────────────────────────────────────── */

.fi-motif-wrap {
	position: relative;
	z-index: 1;
	margin-block-start: var(--fi-space-xl);
	margin-inline: calc(-1 * var(--fi-space-m));
	block-size: clamp(180px, 42vw, 300px);
}

canvas.fi-motif {
	display: block;
	inline-size: 100%;
	block-size: 100%;
}

@media (min-width: 62em) {
	.fi-motif-wrap {
		position: absolute;
		/* Se réserve au-dessus du bandeau de relevés : le réseau passait
		   derrière les chiffres et les rendait illisibles. */
		inset-block: 0 11rem;
		inset-inline-start: 44%;
		inset-inline-end: -6%;
		margin: 0;
		block-size: auto;
		-webkit-mask-image: linear-gradient(to right, transparent 0, #000 14%);
		mask-image: linear-gradient(to right, transparent 0, #000 14%);
	}
}

/* ═══════════════════════════════════════════════════════════════════
   BANDE DES NORMES — plus posée sur l'accueil depuis le 31/08

   ⚠️ HORS DE LA PAGE D'ACCUEIL. Le client ne voulait pas d'une bande grise de
   plus entre le hero et le manifeste : le détail des normes vit désormais dans la
   fiche qui s'ouvre sous le relevé « Certifications & accreditations » du bandeau
   d'assurance — voir `.fi-assurance__note`. Les relevés disent COMBIEN, la fiche
   dit LESQUELLES, et les deux tiennent au même endroit.

   Les règles restent : `patterns/certs.php` demeure insérable sur une page
   « Quality » ou « About », et cette bande a déjà été retirée puis rétablie deux
   fois (25/08, 27/08). Si elle ne sert pas d'ici la mise en production, la retirer
   avec le pattern, le shortcode [firalis_certs] et son bloc dans ui.js.

   Une corniche, pas une section : ~55px, une réserve courte, aucun titre.
   ═══════════════════════════════════════════════════════════════════ */

.fi-certs {
	background: var(--fi-color-surface-alt);
	border-block-start: 1px solid var(--fi-color-line);
	border-block-end: 1px solid var(--fi-color-line);
}

/* Le dépliage est un <details> NATIF : l'ouverture, l'état annoncé aux lecteurs
   d'écran et le clavier sont là sans nous, comme pour l'accordéon des sociétés de
   /contact/. La feuille n'ajoute que l'apparence, et ui.js que l'animation de
   hauteur — si l'un ou l'autre manque, le panneau s'ouvre quand même.

   C'est le « dropdown » demandé par le client, mais un seul contrôle plutôt que
   cinq : à 56px de haut, cinq déclencheurs séparés ne tiendraient pas les 44px de
   cible tactile, et cinq panneaux se disputeraient la même place. */
.fi-certs__disclose {
	margin: 0;
}

/* ── le résumé : la corniche elle-même ── */

.fi-certs__sum {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 0.4rem var(--fi-space-m);
	padding-block: clamp(0.85rem, 2vw, 1.15rem);
	cursor: pointer;
	list-style: none;
	transition: color 0.2s ease;
}

/* Le triangle natif de Safari et de Chrome ne se retire pas de la même façon :
   l'un veut ::-webkit-details-marker, l'autre `list-style`. Les deux sont posés. */
.fi-certs__sum::-webkit-details-marker { display: none; }

/* L'amorce et les intitulés forment un bloc : c'est lui qui tient à gauche,
   l'invite tenant à droite. Sans ce groupement, `space-between` répartissait les
   TROIS enfants du résumé et poussait les normes au milieu de la bande. */
.fi-certs__left {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 0.4rem clamp(0.85rem, 2vw, 1.5rem);
	min-inline-size: 0;
}

/* L'amorce. Elle ne décore pas : à droite, « What they cover » n'a aucun
   antécédent sur la bande fermée — « they » ne renvoie à rien sans elle. En encre
   plutôt qu'en atténué, parce qu'elle NOMME et que les normes énumèrent. Son texte
   est déduit des natures présentes dans les jetons, jamais écrit à la main :
   « Certified » seul serait faux tant qu'ISO 17025 est là. */
.fi-certs__lead {
	flex: 0 0 auto;
	font-family: var(--fi-font-mono);
	font-size: 0.68rem;
	font-weight: 600;
	letter-spacing: 0.13em;
	text-transform: uppercase;
	color: var(--fi-color-ink);
	/* Le filet remplace un séparateur écrit : il tient la même fonction que les
	   points entre les normes, à un cran plus fort parce qu'il sépare deux
	   natures de texte et non deux items d'une même liste. */
	border-inline-end: 1px solid var(--fi-color-line-strong);
	padding-inline-end: clamp(0.85rem, 2vw, 1.5rem);
}

/* Flux INLINE et non grille flexible : le séparateur doit pouvoir suivre le
   retour à la ligne. En flex avec gouttière, il était posé en absolu au milieu
   de la gouttière — et une position absolue ne sait pas où la ligne casse : à
   390px le point de la cinquième norme se retrouvait seul en tête de ligne,
   contre la marge. Relevé en revue le 28/08. */
.fi-certs__names {
	--fi-certs-gap: clamp(1.1rem, 2.6vw, 2.25rem);
	display: block;
	line-height: 1.9;
	font-family: var(--fi-font-mono);
	font-size: 0.68rem;
	font-weight: 500;
	letter-spacing: 0.13em;
	text-transform: uppercase;
	color: var(--fi-color-muted);
}

.fi-certs__std {
	display: inline-block;
	transition: color 0.2s ease;
}

/* Le séparateur est DESSINÉ, pas écrit : un « · » posé dans le texte suivrait les
   intitulés dans le presse-papier et se ferait annoncer par un lecteur d'écran,
   qui doit entendre une liste et non une ponctuation.

   Posé en ::after du PRÉCÉDENT et non en ::before du suivant : ainsi il reste
   accroché à la fin de la ligne qu'il termine, au lieu d'ouvrir la suivante. */
.fi-certs__std:not(:last-child)::after {
	content: "";
	display: inline-block;
	inline-size: 3px;
	block-size: 3px;
	border-radius: 50%;
	background: var(--fi-color-line-strong);
	margin-inline: calc(var(--fi-certs-gap) / 2);
	vertical-align: 0.25em;
}

/* L'invite. Elle est le seul aveu que la bande s'ouvre : sans elle, cinq
   intitulés en petites capitales se lisent comme une frise décorative — le même
   piège que les étapes du continuum avant le 17/08. */
.fi-certs__cue {
	display: inline-flex;
	align-items: center;
	gap: 0.45rem;
	flex: 0 0 auto;
	font-family: var(--fi-font-mono);
	font-size: 0.68rem;
	font-weight: 500;
	letter-spacing: 0.13em;
	text-transform: uppercase;
	color: var(--fi-color-brand);
}

.fi-certs__chev {
	inline-size: 0.9rem;
	block-size: 0.9rem;
	flex: 0 0 auto;
	transition: transform 0.28s cubic-bezier(0.22, 0.61, 0.36, 1);
}

.fi-certs__disclose[open] .fi-certs__chev {
	transform: rotate(180deg);
}

/* Le survol éclaircit les intitulés, pas seulement l'invite : c'est toute la
   bande qui est le contrôle, et c'est elle qui doit répondre. */
.fi-certs__sum:hover .fi-certs__std,
.fi-certs__disclose[open] .fi-certs__std {
	color: var(--fi-color-ink);
}

.fi-certs__sum:focus-visible {
	outline: 2px solid var(--fi-color-brand);
	outline-offset: -2px;
}

/* ── le panneau ── */

/* ⚠️ LE PANNEAU EST L'ÉLÉMENT ANIMÉ : il ne porte NI réserve NI bordure.

   Deux pièges s'y sont succédé, tous deux mesurés image par image.

   1. `box-sizing` par défaut. ui.js anime `height` entre deux valeurs relevées au
      getBoundingClientRect(), qui rend la boîte de BORDURE — or `height` vise la
      boîte de CONTENU, et Twenty Twenty-Five ne pose aucune remise à zéro
      universelle. Poser height = 428px sur un panneau qui en mesurait 428 lui en
      donnait 468 : +40px à la première image de la fermeture. Quatrième
      occurrence du piège, après .fi-co__link, .fi-offer__link et .fi-heroX__link.

   2. La réserve elle-même. Corrigé le premier point, `height: 0` laissait un
      PLANCHER de 40px : en border-box une réserve ne se comprime pas. La bande
      stagnait donc à 99px pendant 92ms — l'animation était finie mais le panneau
      occupait encore sa réserve — puis `open = false` la retirait d'un coup.
      Le saut avait changé de place, pas disparu.

   La réserve vit donc dans un conteneur INTERNE, que rien n'anime. Le panneau
   garde `border-box` en garde-fou : si une réserve y revenait un jour, au moins
   la mesure resterait juste. */
.fi-certs__panel {
	box-sizing: border-box;
}

.fi-certs__panel-in {
	padding-block-end: clamp(1.5rem, 3.5vw, 2.5rem);
}

.fi-certs__rows {
	margin: 0;
	padding: 0;
	list-style: none;
	display: grid;
	gap: 0;
	border-block-start: 1px solid var(--fi-color-line);
}

/* Une rangée par norme, trois champs : ce qu'elle est, ce qu'elle couvre, qui
   l'a délivrée et sous quel numéro. Les trois autres champs des jetons — le
   titulaire, identique aux cinq — sont dits une fois en pied plutôt que répétés
   cinq fois. */
.fi-certs__row {
	display: grid;
	gap: 0.35rem var(--fi-space-m);
	padding-block: clamp(0.85rem, 2vw, 1.1rem);
	border-block-end: 1px solid var(--fi-color-line);
}

@media (min-width: 56em) {
	.fi-certs__row {
		grid-template-columns: minmax(0, 14rem) minmax(0, 1fr) minmax(0, 16rem);
		align-items: baseline;
	}
}

.fi-certs__row > p { margin: 0; }

.fi-certs__name {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 0.5rem;
	font-family: var(--fi-font-mono);
	font-size: 0.78rem;
	font-weight: 600;
	letter-spacing: 0.08em;
	color: var(--fi-color-ink);
}

/* Certification et accréditation ne sont pas synonymes — la seconde est délivrée
   par le COFRAC sur la compétence d'un laboratoire, la première par un organisme
   certificateur sur un système. Sur un site de diagnostic, confondre les deux est
   une faute. L'étiquette porte donc le mot exact des jetons. */
.fi-certs__kind {
	font-size: 0.62rem;
	font-weight: 500;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--fi-color-muted);
	border: 1px solid var(--fi-color-line-strong);
	border-radius: 2px;
	padding: 0.15rem 0.4rem;
	white-space: nowrap;
}

.fi-certs__scope {
	font-size: var(--fi-size-step-0);
	line-height: 1.5;
	color: var(--fi-color-text);
	text-wrap: pretty;
}

.fi-certs__by {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 0.3rem 0.6rem;
	font-size: 0.88rem;
	line-height: 1.5;
	color: var(--fi-color-muted);
}

/* Le numéro est ce qui rend l'affirmation VÉRIFIABLE : c'est lui qu'on recopie
   dans le registre de l'organisme. Chasse fixe, donc, et une teinte qui le
   distingue du nom de l'organisme sans le mettre en avant. */
.fi-certs__ref {
	font-family: var(--fi-font-mono);
	font-size: 0.72rem;
	letter-spacing: 0.04em;
	font-variant-numeric: tabular-nums;
	/* « line-strong » tombait à 1.54:1 sur la bande : c'est le numéro qu'on recopie
	   dans le registre de l'organisme, donc du texte porteur, donc 4.5:1 au moins.
	   « muted » tient 5.37:1 et reste second par rapport au nom de l'organisme,
	   qui est à la même teinte mais dans une plus grande taille. */
	color: var(--fi-color-muted);
	white-space: nowrap;
}

.fi-certs__foot {
	margin: var(--fi-space-m) 0 0;
	max-inline-size: 88ch;
	/* Deux phrases entières : c'est du TEXTE COURANT, pas un libellé de donnée.
	   À 0.88rem l'audit le relevait à 14.08px — sous le seuil de 16px que le
	   projet s'impose depuis le 25/08, en deçà duquel iOS zoome de lui-même. */
	font-size: var(--fi-size-step-0);
	line-height: 1.6;
	color: var(--fi-color-muted);
	text-wrap: pretty;
}

.fi-certs__foot strong {
	font-weight: 600;
	color: var(--fi-color-text);
}

/* Séparateur entre les deux phrases du pied, dessiné plutôt qu'écrit — même
   raison que celui des intitulés. */
.fi-certs__sep {
	display: inline-block;
	inline-size: 3px;
	block-size: 3px;
	border-radius: 50%;
	background: var(--fi-color-line-strong);
	margin-inline: 0.55rem;
	vertical-align: 0.2em;
}

/* Sous 40em les cinq intitulés passent sur deux lignes, et l'invite dessous.

   Ils ont d'abord DÉFILÉ à l'horizontale, pour garder la corniche sur une ligne.
   Retiré le 28/08 après mesure : à 390px la cinquième norme sortait du cadre, et
   le glissement au doigt ne la ramenait pas — du contenu invisible ET inatteignable.
   S'ajoutait un conflit de geste, une zone qui défile logée dans une cible de clic.
   Deux lignes coûtent 18px ; la norme manquante coûtait une norme. */
@media (max-width: 40em) {
	.fi-certs__names {
		inline-size: 100%;
	}

	.fi-certs__std { white-space: nowrap; }

	/* L'amorce prend sa ligne : le filet vertical qui la sépare des normes n'a
	   plus de sens quand elles passent dessous. */
	.fi-certs__lead {
		inline-size: 100%;
		border-inline-end: 0;
		padding-inline-end: 0;
	}
}

/* ═══════════════════════════════════════════════════════════════════
   BANDEAU D'ASSURANCE — cinq nombres, posés sous le hero
   La seule preuve chiffrée de l'accueil depuis le 25/08. Une bande basse,
   pas une section : elle se lit d'un coup d'œil en descendant du hero.
   ═══════════════════════════════════════════════════════════════════ */

/* Le bandeau autonome — une corniche grise entre le hero et le manifeste — a été
   dissous le 25/08. Trois fonds différents se succédaient en 350px : pâle, gris,
   navy. Ses relevés ouvrent désormais la bande sombre, qui les portait
   mieux : ils y gagnent du contraste, et le manifeste y gagne la substance qu'il
   avait perdue avec ses trois piliers.

   Remis puis re-retiré le 27/08 : le client visait le bandeau des NORMES qui fermait
   le hero, pas ces relevés. Les règles de bande restent pour
   patterns/assurance.php, qui n'est plus posé sur l'accueil mais reste insérable
   ailleurs. */
.fi-assurance {
	background: var(--fi-color-surface-alt);
	border-block-end: 1px solid var(--fi-color-line);
	padding-block: clamp(1.75rem, 4vw, 2.75rem);
}

.fi-assurance__list {
	margin: 0;
	padding: 0;
	list-style: none;
	display: grid;
	/* Les colonnes sont posées par palier, plus bas : « Trois dispositions ». */
	/* ⚠️ AUCUN row-gap, et ce n'est pas un oubli (03/09). La fiche des normes est
	   depuis M-2 une RANGÉE de cette grille, repliée à zéro tant qu'elle est
	   fermée : un `row-gap` lui donnerait de la hauteur alors qu'elle n'affiche
	   rien, et le bandeau porterait 24px de vide sous le dernier relevé. Le pas
	   vertical est donc porté par les relevés eux-mêmes, où il ne concerne que
	   les rangées qui existent. */
	gap: 0;
}

.fi-assurance__item {
	margin: 0;
	display: flex;
	flex-direction: column;
	gap: 0.4rem;
	padding-inline: clamp(0.9rem, 2.4vw, 1.75rem);
	/* Même vocabulaire que l'annuaire du hero : des bordures, pas un fond de
	   grille — le pas suit le nombre de colonnes et se réécrit à chaque reprise. */
	border-inline-start: 1px solid var(--fi-color-line);
}

/* ── Trois dispositions, aucune cellule orpheline — 14/09 ────────────
   Jusqu'au 13/09 : deux colonnes sous 56em, cinq au-delà. Deux défauts mesurés.

   ① Cinq relevés sur deux colonnes font 2 + 2 + 1 : « 2008 Founded » restait
   seul sur sa rangée de 360 à 895px, et la fiche des normes, dernier <li>,
   s'ouvrait SOUS lui — à 97-100px de son bouton, une rangée étrangère entre
   les deux.
   ② Cinq colonnes dès 56em ne laissaient que 105 à 124px au libellé entre 896
   et ~1090px : « Certifications / & / accreditations » sur trois lignes, le
   « & » seul. L'espace insécable de inc/sections.php colle désormais « & » à
   « accreditations », mais le groupe demande 134px : dans une cellule plus
   étroite il déborderait au lieu de couper. Il fallait donc des cellules plus
   larges, pas seulement une espace.

   D'où : sous 40em, un relevé par RANG (le nombre dans une colonne commune, le
   libellé dans l'autre) ; de 40 à 70em, 3 + 2 sur six pistes ; cinq colonnes
   au-delà de 70em, où le bouton mesure 138px et plus.

   La fiche suit son bouton : sous 70em, `order` la remonte juste après les
   certifications. L'ordre du DOM ne bouge pas — entre le bouton et les onglets
   de la fiche il n'y a que du texte, le parcours au clavier reste donc celui
   que l'on voit. */
@media (max-width: 69.99em) {
	.fi-assurance__list > .fi-assurance__item--note ~ .fi-assurance__item { order: 2; }
	.fi-assurance__list > .fi-assurance__note { order: 1; }
}

/* Sous 40em : un rang par relevé. Sous-grille, pour que les cinq libellés
   partent de la même verticale : la colonne des nombres prend la chasse du plus
   large (« €7.2M »), quelle qu'elle soit. Sans sous-grille, le nombre et son
   libellé s'empilent — l'état d'avant, sans casse. Les écarts sont redits : une
   sous-grille qui déclare son propre `gap` n'hérite pas de celui du parent. */
@media (max-width: 39.99em) {
	.fi-assurance__list {
		grid-template-columns: max-content minmax(0, 1fr);
		column-gap: var(--fi-space-m);
	}

	.fi-assurance__list > .fi-assurance__item,
	.fi-assurance__item--note .fi-assurance__btn {
		grid-column: 1 / -1;
		display: grid;
		grid-template-columns: subgrid;
		align-items: baseline;
		gap: 0 var(--fi-space-m);
	}

	.fi-assurance__list > .fi-assurance__item {
		padding-block: var(--fi-space-xs);
		padding-inline: 0;
		border-inline-start: 0;
		border-block-start: 1px solid var(--fi-color-line);
	}

	.fi-assurance__list > .fi-assurance__item:first-child {
		padding-block-start: 0;
		border-block-start: 0;
	}

	.fi-statement .fi-assurance__list > .fi-assurance__item {
		border-block-start-color: var(--fi-color-line-dark);
	}

	/* Le chevron se centre sur le rang : calé en haut, il flottait au-dessus
	   d'un libellé d'une seule ligne. `translate` et non `transform`, que
	   l'ouverture emploie déjà pour le retourner. */
	.fi-assurance__chev {
		inset-block-start: 50%;
		translate: 0 -50%;
	}
}

/* De 40 à 70em : 3 + 2 sur six pistes. Les deux relevés du second rang se
   partagent la largeur, aucun ne reste seul. Les sélecteurs comptent depuis la
   FIN — cinq relevés puis la fiche, six <li> : avec un autre nombre de relevés
   la règle ne s'applique pas, et tout reste en tiers plutôt que de mentir. */
@media (min-width: 40em) and (max-width: 69.99em) {
	.fi-assurance__list {
		grid-template-columns: repeat(6, minmax(0, 1fr));
	}

	.fi-assurance__list > .fi-assurance__item {
		grid-column: span 2;
	}

	.fi-assurance__list > .fi-assurance__item:nth-child(4):nth-last-child(3),
	.fi-assurance__list > .fi-assurance__item:nth-child(5):nth-last-child(2) {
		grid-column: span 3;
	}

	/* Pas de trois : le filet de tête tombe sur les relevés 1, 4, 7… */
	.fi-assurance__list > .fi-assurance__item:nth-child(3n + 1) {
		border-inline-start: 0;
		padding-inline-start: 0;
	}

	/* Le pas vertical, rendu aux relevés faute de `row-gap`. */
	.fi-assurance__list > .fi-assurance__item:nth-child(n + 4) {
		margin-block-start: var(--fi-space-m);
	}
}

.fi-assurance__n {
	font-family: var(--fi-font-display);
	font-size: var(--fi-size-step-4);
	font-weight: 600;
	letter-spacing: -0.04em;
	line-height: 1;
	color: var(--fi-color-ink);
	/* Les chiffres sont comptés par ui.js : sans chasse fixe, la largeur de la
	   cellule sautait à chaque incrément. */
	font-variant-numeric: tabular-nums;
}

.fi-assurance__k {
	font-family: var(--fi-font-mono);
	font-size: 0.72rem;
	font-weight: 500;
	letter-spacing: 0.13em;
	text-transform: uppercase;
	line-height: 1.45;
	color: var(--fi-color-muted);
	text-wrap: pretty;
}

/* Palier porté de 56 à 70em le 14/09 : voir « Trois dispositions » ci-dessus.

   ⚠️ 02/10/2026 — Le nombre de colonnes est celui des RELEVÉS, imprimé par
   [firalis_assurance] dans `--fi-facts` (docs/74 X-1). Il était écrit « 5 » : le
   retrait de la figure en euros laissait quatre nombres et une cinquième cellule
   vide à droite. Le repli reste 5, la valeur d'avant, si la variable manquait. */
@media (min-width: 70em) {
	.fi-assurance__list {
		grid-template-columns: repeat(var(--fi-facts, 5), minmax(0, 1fr));
	}

	/* Une seule rangée : le filet revient PARTOUT sauf en tête, et le pas
	   vertical n'a plus lieu d'être. Écrite sans compter les colonnes — c'est
	   la règle en `nth-child(2n + 1)` du 24/08, calée sur quatre relevés, qui a
	   cassé le jour où le client en a demandé un cinquième (03/09).

	   ⚠️ Le sélecteur descend de la liste pour reprendre la spécificité de la
	   règle de pas ci-dessus : `.fi-assurance__item` seul ne pourrait pas la
	   défaire, une classe pèse moins que classe + pseudo-classe. */
	.fi-assurance__list > .fi-assurance__item {
		border-inline-start: 1px solid var(--fi-color-line);
		padding-inline-start: clamp(0.9rem, 2.4vw, 1.75rem);
		margin-block-start: 0;
	}

	.fi-assurance__list > .fi-assurance__item:first-child {
		border-inline-start: 0;
		padding-inline-start: 0;
	}
}

/* ── Quatre relevés — 02/10/2026 ─────────────────────────────────────
   Revue client du 02/10/2026, docs/74 X-1 (décision D-2, tout financement retiré) :
   « €7.2M Bioproduction programme » quitte le bandeau, il reste QUATRE relevés —
   Companies, Services, Certifications & accreditations, Founded. Les dispositions
   ci-dessus comptent cinq relevés ; à quatre, sans ces règles, on lisait 3 + 1 de 40
   à 70em (« 2008 Founded » seul sur sa rangée, le défaut ① du 14/09) et quatre
   nombres dans cinq colonnes au-delà. Les sélecteurs portent `[data-fi-facts="4"]`,
   imprimé par [firalis_assurance] : les règles à cinq restent intactes, et un autre
   nombre retombe sur le repli en tiers plutôt que de mentir.

   — Sous 40em : rien ne change, un relevé par rang.
   — De 40 à 56em : 2 + 2. Quatre colonnes y laisseraient au libellé des
     certifications 111px à 640 et 124 à 700 (mesuré), moins que les 135 qu'exige
     « & accreditations », insécable — il déborderait au lieu de couper. À 768 il
     en resterait 140 : six pixels de marge, trop peu pour une police de repli.
   — Dès 56em : une rangée de quatre, comme au-delà de 70em. À 896px le libellé
     des certifications dispose de 146px (mesuré).
   ⚠️ 08/10/2026 — 64em ET NON PLUS 56em. Sur la bande sombre de l'accueil, les
   nombres passent à `step-5` et les libellés à `step--1` (revue client, GP-Homepage
   p. 1 — voir « Les relevés, en tête du manifeste ») : « & accreditations » demande
   désormais ~146px, ce qui ne laissait plus de marge à 896. Le 2 + 2 court donc
   jusqu'à 64em ; la rangée de quatre reprend à 1024, où le libellé a la place.

   Dans les deux cas l'ordre est rendu au DOM : `order` sortait « Founded » après la
   fiche des normes pour la coller à son bouton — à quatre, la fiche tombe d'elle-
   même sous la rangée des certifications, et le déplacement aurait isolé
   « Founded » sur une rangée à part. Le parcours clavier reste celui que l'on voit :
   entre le bouton et les onglets de la fiche, seul « Founded », un texte. */
@media (min-width: 40em) and (max-width: 69.99em) {
	.fi-assurance__list[data-fi-facts="4"] > :is(.fi-assurance__item, .fi-assurance__note) {
		order: 0;
	}
}

@media (min-width: 40em) and (max-width: 63.99em) {
	.fi-assurance__list[data-fi-facts="4"] > .fi-assurance__item {
		grid-column: span 3;
	}

	/* Filet de tête sur les relevés 1 et 3, qui ouvrent chacun leur rangée ; il
	   revient sur le 4, que la règle en `3n + 1` des cinq relevés lui retirait. */
	.fi-assurance__list[data-fi-facts="4"] > .fi-assurance__item:nth-child(odd) {
		border-inline-start: 0;
		padding-inline-start: 0;
	}

	.fi-assurance__list[data-fi-facts="4"] > .fi-assurance__item:nth-child(even) {
		border-inline-start: 1px solid var(--fi-color-line);
		padding-inline-start: clamp(0.9rem, 2.4vw, 1.75rem);
	}

	.fi-statement .fi-assurance__list[data-fi-facts="4"] > .fi-assurance__item:nth-child(even) {
		border-inline-start-color: var(--fi-color-line-dark);
	}

	.fi-assurance__list[data-fi-facts="4"] > .fi-assurance__item:nth-child(n + 3) {
		margin-block-start: var(--fi-space-m);
	}
}

@media (min-width: 64em) and (max-width: 69.99em) {
	.fi-assurance__list[data-fi-facts="4"] {
		grid-template-columns: repeat(4, minmax(0, 1fr));
	}

	.fi-assurance__list[data-fi-facts="4"] > .fi-assurance__item {
		grid-column: auto;
		border-inline-start: 1px solid var(--fi-color-line);
		padding-inline-start: clamp(0.9rem, 2.4vw, 1.75rem);
		margin-block-start: 0;
	}

	.fi-statement .fi-assurance__list[data-fi-facts="4"] > .fi-assurance__item {
		border-inline-start-color: var(--fi-color-line-dark);
	}

	.fi-assurance__list[data-fi-facts="4"] > .fi-assurance__item:first-child {
		border-inline-start: 0;
		padding-inline-start: 0;
	}
}

/* ── Les relevés, en tête du manifeste ───────────────────────────────
   Sur la bande sombre, les jetons s'inversent : les nombres passent au blanc
   plein, les libellés à l'atténué clair, et les filets au trait sombre. Un filet
   les sépare de la déclaration — ils la précèdent, ils n'en font pas partie. */
.fi-statement > .fi-eyebrow {
	margin-block-end: clamp(1.5rem, 3vw, 2rem);
}

.fi-statement .fi-assurance__list {
	margin-block-end: clamp(2.25rem, 5vw, 3.5rem);
	padding-block-end: clamp(2rem, 4vw, 3rem);
	border-block-end: 1px solid var(--fi-color-line-dark);
}

.fi-statement .fi-assurance__item {
	border-inline-start-color: var(--fi-color-line-dark);
}

/* ⚠️ 08/10/2026 — REVUE CLIENT (Chloé Schindler, GP-Homepage p. 1) : « Pour des
   chiffres clés de l'entreprise, ils sont très petits et peu mis en valeur. Il
   faudrait les agrandir. » `step-3` → `step-5` : 32 → 68px à 1440, 25,6 → 38,4px à
   390. Ils étaient tenus PLUS PETITS qu'en bande autonome pour ne pas disputer la
   primauté au titre du manifeste (50px) ; ce titre a été retiré le 03/09 (M-4), la
   raison est partie avec lui. Ils sont désormais ce que la bande a de plus grand :
   la phrase de droite dit le groupe, les chiffres le prouvent.

   Les libellés suivent d'un cran, 0.72rem → `step--1` (11,5 → 13,3px), l'interlettrage
   resserré de 0.13 à 0.1em pour que « & accreditations », insécable, garde sa place.
   Voir « Quatre relevés » plus haut : la rangée de quatre ne commence plus qu'à 64em. */
.fi-statement .fi-assurance__n {
	font-size: var(--fi-size-step-5);
	color: var(--fi-color-on-dark-strong);
}

.fi-statement .fi-assurance__k {
	font-size: var(--fi-size-step--1);
	letter-spacing: 0.1em;
	color: var(--fi-color-on-dark-muted);
}

/* Sous 360px, la colonne des libellés tombe à 140px (mesuré à 320) et « &
   accreditations », insécable, en demandait 149 : 5px de débordement horizontal.
   L'interlettrage se resserre encore, 0.1 → 0.04em, soit 136px. */
@media (max-width: 22.49em) {
	.fi-statement .fi-assurance__k { letter-spacing: 0.04em; }
}

/* Le nombre a doublé : l'écart avec son libellé suit. Pas sous 40em, où le relevé
   devient un RANG en sous-grille et où `gap` porte l'écart entre les colonnes. */
@media (min-width: 40em) {
	.fi-statement :is(.fi-assurance__item, .fi-assurance__btn) {
		gap: var(--fi-space-xs);
	}
}

/* ── Le panneau des normes, sous la rangée des relevés ───────────────
   Posé le 31/08. Il reprend le rôle de la bande grise qui suivait le hero : le
   client voulait le détail des normes, pas une bande de plus entre le hero et le
   manifeste. Le chiffre annonce, le panneau détaille, et la page perd un fond.

   ⚠️ RÉÉCRIT LE 03/09 (M-2 de la revue client). Le panneau FLOTTAIT —
   `position: absolute; z-index: 30` — et se posait par-dessus le manifeste : le
   client l'a relevé au trait rouge, « the dropdown does not hide or overlap the
   section below ». Il est désormais EN FLUX et POUSSE ce qu'il y a dessous.

   Ce qui change, et pourquoi chaque suppression est nécessaire :

   — Le panneau est le DERNIER <li> de la liste des relevés, posé sur une rangée
     pleine largeur (`grid-column: 1 / -1`). Il n'est plus enfant de la cellule
     des certifications : une cellule de 248px ne peut pas porter une fiche.
   — L'ouverture s'anime sur `grid-template-rows: 0fr → 1fr` et non plus sur
     `opacity` + `transform`. Une opacité ne pousse rien ; une rangée, si.
   — `z-index`, l'ombre d'élévation et le pseudo-élément « pont »
     `.fi-assurance__item--note::after` sont retirés : les trois n'existaient que
     pour un panneau flottant séparé de son déclencheur par 0,75rem de vide.
     `position: relative` sur la cellule part avec eux — plus rien ne s'y ancre,
     le chevron se cale sur le bouton.
   — L'ouverture au SURVOL part aussi. Mesurée en flux, elle déplace le contenu
     situé sous le curseur de 237px à 1440 et à 1024, 227px à 768, et 386px à 390
     — sans geste du visiteur. Reste le clic (ui.js), le focus clavier, et le
     survol du seul repli `.no-js`, où rien d'autre ne pourrait ouvrir la fiche. */

/* Le bouton reprend l'empilement de la cellule : c'est LUI qui porte le nombre et
   son libellé, la cellule n'est plus qu'un repère de position. Sans cela, le
   déclencheur n'aurait couvert que le texte et laissé des zones mortes autour. */
.fi-assurance__btn {
	position: relative;
	display: flex;
	flex-direction: column;
	align-items: start;
	gap: 0.4rem;
	inline-size: 100%;
	margin: 0;
	/* La réserve à droite est celle du chevron : sans elle, un libellé long lui
	   passait dessous. */
	padding: 0 1.35rem 0 0;
	border: 0;
	background: none;
	color: inherit;
	font: inherit;
	text-align: start;
	cursor: pointer;
	/* 14/09 — Plancher de cible. Empilé, le bouton faisait 51 à 86px ; en rang
	   sous 40em (voir « Trois dispositions ») il n'en mesurait plus que 43. */
	min-block-size: 2.75rem;
}

/* L'affordance doit être VISIBLE sans survol : un pointillé sous le libellé, la
   convention du terme qui cache une définition. Rien d'autre ne signalerait que
   cette cellule-ci s'ouvre et que les quatre autres non. */
.fi-assurance__item--note .fi-assurance__k {
	text-decoration: underline;
	text-decoration-style: dotted;
	text-decoration-thickness: 1px;
	text-underline-offset: 0.4em;
}

.fi-assurance__chev {
	position: absolute;
	inset-block-start: 0.4rem;
	inset-inline-end: 0;
	inline-size: 1rem;
	block-size: 1rem;
	color: var(--fi-color-muted);
	transition: transform 0.2s ease, color 0.2s ease;
}

.fi-statement .fi-assurance__chev { color: var(--fi-color-on-dark-muted); }

.fi-assurance__item--note.is-open .fi-assurance__chev,
.no-js .fi-assurance__btn:focus-visible .fi-assurance__chev {
	transform: rotate(180deg);
}

/* ── La fiche en RÉGIME SOMBRE, sur la bande du manifeste ────────────
   Tant que la fiche flottait, elle restait claire : une carte posée SUR la page,
   avec son ombre et son bord, se lit sur n'importe quel fond. Posée en flux DANS
   la bande navy (03/09, M-2), la même carte devient un rectangle blanc de 1240px
   au milieu du sombre — comparé en capture avant de trancher.

   Elle passe donc aux jetons de la bande : un fond à peine relevé sur `ink-2`,
   le filet sombre, et les deux rangs de texte clair. Aucune couleur en dur, tout
   vient du même jeu de jetons que le reste de la bande.

   ⚠️ Le régime CLAIR reste la valeur par défaut : `patterns/assurance.php`, le
   bandeau autonome, est posé sur `surface-alt` et la fiche y est encore une
   carte. C'est le contexte qui décide, pas la fiche. */
.fi-statement .fi-assurance__note-in {
	background: color-mix(in srgb, var(--fi-color-on-dark) 5%, transparent);
	color: var(--fi-color-on-dark);
	border-color: var(--fi-color-line-dark);
}

.fi-statement .fi-assurance__tabs {
	border-block-end-color: var(--fi-color-line-dark);
}

.fi-statement .fi-assurance__tab {
	color: var(--fi-color-on-dark-muted);
}

.fi-statement .fi-assurance__tab:hover {
	color: var(--fi-color-on-dark-strong);
}

.fi-statement .fi-assurance__tab.is-current {
	color: var(--fi-color-on-dark-strong);
	background: color-mix(in srgb, var(--fi-color-on-dark) 10%, transparent);
	border-color: var(--fi-color-line-dark);
}

.fi-statement .fi-assurance__row > .fi-assurance__scope {
	color: var(--fi-color-on-dark-strong);
}

.fi-statement .fi-assurance__row > .fi-assurance__by,
.fi-statement .fi-assurance__kind,
.fi-statement .fi-assurance__ref,
.fi-statement .fi-assurance__note-in > .fi-assurance__foot {
	color: var(--fi-color-on-dark-muted);
}

.fi-statement .fi-assurance__kind {
	border-color: var(--fi-color-line-dark);
}

.fi-statement .fi-assurance__note-in > .fi-assurance__foot {
	border-block-start-color: var(--fi-color-line-dark);
}

/* La rangée dépliante. Elle est en grille à UNE cellule dont on anime la hauteur
   de `0fr` à `1fr` : c'est la seule façon d'interpoler vers une hauteur `auto`
   sans la mesurer en JavaScript, et la seule qui POUSSE ce qui suit. */
.fi-assurance__note {
	grid-column: 1 / -1;
	margin: 0;
	display: grid;
	grid-template-rows: 0fr;
	transition: grid-template-rows 0.24s ease;
}

/* Le rogneur ne porte AUCUNE réserve ni bordure : à hauteur nulle, un remplissage
   resterait visible — une boîte ne descend pas sous la somme de ses marges
   intérieures. `min-block-size: 0` lève la taille minimale automatique des
   éléments de grille, sans quoi la rangée refuserait de se replier. */
.fi-assurance__note-clip {
	overflow: hidden;
	min-block-size: 0;
}

/* La fiche elle-même : c'est ici que vivent le fond, le filet et la respiration.
   La marge haute la décolle de la rangée des relevés et n'existe que dépliée,
   puisqu'elle est à l'intérieur du rognage. */
.fi-assurance__note-in {
	margin-block-start: var(--fi-space-m);
	box-sizing: border-box;
	padding: clamp(0.9rem, 2.2vw, 1.35rem);
	background: var(--fi-color-surface);
	color: var(--fi-color-text);
	border: 1px solid var(--fi-color-line);
	border-radius: var(--fi-radius-m);
	/* Sortie de l'arbre d'accessibilité tant que la fiche est repliée : une
	   hauteur nulle ne suffit pas, le contenu resterait annoncé. Le retard sur
	   `visibility` la laisse visible le temps du repli. */
	visibility: hidden;
	transition: visibility 0s linear 0.24s;
}

/* Le clavier passe par `.is-open`, posé par ui.js sur un focus VISIBLE — pas par
   `:focus-within`. Mesuré au tactile : après une tape, le bouton garde le focus,
   `:focus-within` restait vrai et la fiche refusait de se refermer à la tape
   suivante.

   ⚠️ Le lien avec le déclencheur est désormais un sélecteur de FRÈRE : depuis le
   03/09 la fiche n'est plus dans la cellule des certifications, elle est le
   dernier <li> de la même liste. */
.fi-assurance__item--note.is-open ~ .fi-assurance__note {
	grid-template-rows: 1fr;
}

.fi-assurance__item--note.is-open ~ .fi-assurance__note .fi-assurance__note-in {
	visibility: visible;
	transition-delay: 0s;
}

/* Le repli SANS ui.js, et lui seul. Le survol y reste le seul geste dont dispose
   une souris — le clic n'ouvre rien sans script — et le focus clavier y ouvre
   comme avant. Avec ui.js, ni l'un ni l'autre : le survol pousserait la page de
   237px sous le curseur (386px à 390), et le clic fait le travail.

   `:has()` remplace le `~` sur le bouton, qui n'est plus frère de la fiche. Le
   test reste `:focus-visible` et non `:focus-within` : un focus de souris ou de
   doigt n'est pas « visible », c'est ce qui empêchait le doigt d'ouvrir la fiche
   sans le vouloir. */
.no-js .fi-assurance__item--note:has(.fi-assurance__btn:focus-visible) ~ .fi-assurance__note {
	grid-template-rows: 1fr;
}

.no-js .fi-assurance__item--note:has(.fi-assurance__btn:focus-visible) ~ .fi-assurance__note .fi-assurance__note-in {
	visibility: visible;
	transition-delay: 0s;
}

@media (hover: hover) and (pointer: fine) {
	.no-js .fi-assurance__item--note:hover ~ .fi-assurance__note {
		grid-template-rows: 1fr;
	}

	.no-js .fi-assurance__item--note:hover ~ .fi-assurance__note .fi-assurance__note-in {
		visibility: visible;
		transition-delay: 0s;
	}

	.no-js .fi-assurance__item--note:hover .fi-assurance__chev {
		transform: rotate(180deg);
	}
}

@media (prefers-reduced-motion: reduce) {
	.fi-assurance__note { transition: none; }
	.fi-assurance__chev { transition: none; }
	/* Le panneau change encore, mais d'un coup — et ui.js coupe le défilement
	   automatique, donc il ne change que sur un geste du visiteur. */
	.fi-assurance__row { transition: none; transform: none; }
	.fi-assurance__row.is-current { transform: none; }
}

/* ── Les onglets : les sept intitulés sur une ligne ──────────────────
   C'est la réponse à « lesquelles » — les sept noms visibles d'un coup — et c'est
   ce que faisait déjà la bande grise. Ils ne défilent pas : seul le DÉTAIL défile
   sous eux. Sept intitulés qui apparaîtraient un par un ne diraient jamais qu'il
   y en a sept.

   ⚠️ 03/09 — SEPT depuis M-3, et la fiche s'en ressent : mesurée à 390px, elle
   passe de 312 à 386px, les sept intitulés tenant sur TROIS lignes. C'est assumé,
   pour la même raison qu'au 31/08 : un défilement horizontal cacherait quatre
   normes sur sept derrière un geste que rien n'annonce, et la fiche est maintenant
   en flux — elle pousse la page au lieu de la recouvrir, donc sa hauteur ne coûte
   plus qu'un défilement, jamais une section masquée. */
.fi-assurance__tabs {
	display: flex;
	flex-wrap: wrap;
	gap: 0.15rem;
	margin-block-end: 0.6rem;
	padding-block-end: 0.6rem;
	border-block-end: 1px solid var(--fi-color-line);
}

.fi-assurance__tab {
	margin: 0;
	/* 0.9rem de réserve verticale porte la cible à 45px : c'est un contrôle
	   TACTILE, le premier de cette fiche, et le seuil de 44px du projet s'applique.
	   Mesuré : 0.85rem donnait 43px, et l'audit le relevait aux quatre largeurs.
	   La parade habituelle — remplissage plus marge négative — ne vaut pas ici :
	   l'onglet courant porte un fond, qui trahirait la réserve empruntée. */
	padding: 0.9rem 0.4rem;
	border: 1px solid transparent;
	border-radius: var(--fi-radius-s);
	background: none;
	font-family: var(--fi-font-mono);
	font-size: 0.72rem;
	font-weight: 600;
	letter-spacing: 0.06em;
	line-height: 1.2;
	white-space: nowrap;
	color: var(--fi-color-muted);
	cursor: pointer;
	transition: color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease;
}

.fi-assurance__tab:hover {
	color: var(--fi-color-ink);
}

/* L'onglet courant est marqué par un FOND et une bordure, pas par la seule
   couleur : le repère doit tenir sans distinguer les teintes. */
.fi-assurance__tab.is-current {
	color: var(--fi-color-ink);
	background: var(--fi-color-surface-alt);
	border-color: var(--fi-color-line-strong);
}

/* ── La zone de détail : une rangée, jamais cinq ─────────────────────
   Les cinq panneaux sont EMPILÉS dans la même cellule de grille. La hauteur de la
   zone est donc celle du panneau le plus haut, et elle ne bouge plus quand on
   passe d'une norme à l'autre — un panneau qui change de hauteur ferait sauter le
   pied de la fiche à chaque défilement.

   Empilés et non retirés du DOM : `visibility: hidden` sort un panneau de l'arbre
   d'accessibilité comme le ferait `display: none`, mais il reste mesurable, donc
   la zone garde sa hauteur. */
.fi-assurance__slot {
	display: grid;
}

.fi-assurance__row {
	grid-area: 1 / 1;
	opacity: 0;
	visibility: hidden;
	transform: translateY(0.4rem);
	transition:
		opacity 0.25s ease,
		transform 0.25s ease,
		visibility 0s linear 0.25s;
}

.fi-assurance__row.is-current {
	opacity: 1;
	visibility: visible;
	transform: none;
	transition-delay: 0s;
}

.fi-assurance__row:focus-visible {
	outline: 2px solid var(--fi-color-brand);
	outline-offset: 3px;
}

.fi-assurance__row > p { margin: 0; }

/* La sélection reprend le parent : `.fi-assurance__row > p` remet les marges à
   zéro et l'emporterait sur une classe seule. */
.fi-assurance__row > .fi-assurance__scope {
	font-size: var(--fi-size-step-0);
	line-height: 1.45;
	color: var(--fi-color-ink);
	text-wrap: pretty;
}

.fi-assurance__row > .fi-assurance__by {
	margin-block-start: 0.4rem;
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 0.3rem 0.55rem;
	line-height: 1.45;
	color: var(--fi-color-muted);
}

/* Certification et accréditation ne sont pas synonymes — la seconde est délivrée
   par le COFRAC sur la compétence d'un laboratoire, la première par un organisme
   certificateur sur un système. Sur un site de diagnostic, confondre les deux est
   une faute. L'étiquette porte donc le mot exact des jetons. */
.fi-assurance__kind {
	font-size: 0.6rem;
	font-weight: 500;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--fi-color-muted);
	border: 1px solid var(--fi-color-line-strong);
	border-radius: 2px;
	padding: 0.12rem 0.35rem;
	white-space: nowrap;
}

.fi-assurance__org {
	font-size: 0.88rem;
}

/* Le numéro est ce qui rend l'affirmation VÉRIFIABLE : c'est lui qu'on recopie
   dans le registre de l'organisme. Chasse fixe, donc. */
.fi-assurance__ref {
	font-family: var(--fi-font-mono);
	font-size: 0.72rem;
	letter-spacing: 0.04em;
	font-variant-numeric: tabular-nums;
	color: var(--fi-color-muted);
	white-space: nowrap;
}

.fi-assurance__note-in > .fi-assurance__foot {
	margin: 0.85rem 0 0;
	padding-block-start: 0.75rem;
	border-block-start: 1px solid var(--fi-color-line);
	/* Deux phrases entières : c'est du TEXTE COURANT, pas un libellé de donnée.
	   À 0.82rem l'audit le relevait à 13.12px — sous le seuil de 16px que le projet
	   s'impose depuis le 25/08, en deçà duquel iOS zoome de lui-même. */
	font-size: var(--fi-size-step-0);
	line-height: 1.55;
	color: var(--fi-color-muted);
	text-wrap: pretty;
}

/* ═══════════════════════════════════════════════════════════════════
   LE MANIFESTE — bande sombre, le « pourquoi » du groupe
   ═══════════════════════════════════════════════════════════════════ */

.fi-statement {
	position: relative;
	background: var(--fi-color-ink-2);
	color: var(--fi-color-on-dark);
	padding-block: var(--fi-sec);
}

/* Même filet que le pied de page : les bandes sombres se répondent.
   Le dégradé partait de --fi-color-brand : en encre, sa première moitié
   disparaissait dans le navy. Il court désormais de l'accent clair vers rien. */
.fi-statement::before,
.fi-momentum::before {
	content: "";
	position: absolute;
	inset-block-start: 0;
	inset-inline: 0;
	block-size: 2px;
	background: linear-gradient(
		to right,
		var(--fi-color-accent-on-dark),
		color-mix(in srgb, var(--fi-color-accent-on-dark) 12%, transparent)
	);
}

.fi-statement__grid {
	display: grid;
	gap: clamp(1.5rem, 4vw, 4rem);
	align-items: start;
}

@media (min-width: 56em) {
	.fi-statement__grid { grid-template-columns: 1.08fr 0.92fr; }

	/* La phrase se cale sur le MILIEU de la photo, pas sur son bord haut. Le
	   03/09, le corps est passé de deux paragraphes à une phrase (M-6) et la
	   plaque de 77 à 426px (M-5) : alignés en tête, trois lignes de texte
	   laissaient 340px de bande vide sous elles. L'alignement en tête reste la
	   règle de la grille (`align-items: start`) — c'est cette colonne-ci, et elle
	   seule, qui y déroge. */
	.fi-statement__body { align-self: center; }
}

/* ── La plaque du manifeste ──────────────────────────────────────────
   ⚠️ RÉÉCRITE LE 03/09 (M-5). Le client demande une photo PLUS GRANDE. Prise au
   pied de la lettre, la demande produisait l'inverse.

   Jusqu'ici la plaque était dimensionnée par le RESTE : la colonne gauche était
   étirée (`align-self: stretch`), la plaque y prenait tout l'espace libre
   (`flex: 1 1 0`, image en absolu), et la hauteur de rangée était dictée par la
   colonne de DROITE. Elle ne pesait rien, elle comblait. Or la même revue vide la
   colonne gauche de son titre (M-4) et réduit la droite de deux paragraphes à une
   phrase (M-6) : la rangée s'effondrait, et la plaque avec elle. Mesuré avant
   correction : 77px de haut à 1440, 90px à 1024 — une meurtrière, pas une photo.

   Elle a donc une taille PROPRE : `aspect-ratio: 3 / 2`, le rapport natif du
   fichier (1600 × 1067), donc aucun recadrage imposé par la mise en page. La
   plaque redevient ce qui dicte la hauteur de la rangée, ce qui est légitime
   maintenant que le texte n'y prétend plus.

   ⚠️ Elle disparaissait sous 56em (`display: none`). C'était défendable tant que
   la colonne gauche portait un titre ; sans titre, le manifeste mobile ne serait
   plus que cinq relevés et une phrase. Elle est rétablie, en flux, pleine largeur,
   et posée SOUS le texte par `order` — l'ordre du DOM la place avant, et c'est là
   qu'elle doit rester pour la lecture : le texte dit la section, l'image
   l'illustre. Aucune conséquence pour un lecteur d'écran, la figure est décorative
   et son `alt` est vide.

   ⚠️ `assets/lab.jpg` est un SUBSTITUT — le laboratoire d'une AUTRE institution,
   posé le 28/08 pour montrer l'emplacement. L'agrandir de 77 à 425px le rend
   d'autant plus visible. La vraie photographie de Huningue est attendue (brief §9)
   et doit arriver avant toute mise en production. */
.fi-statement__plate {
	position: relative;
	margin: 0;
	/* Le rapport du fichier source (1600 × 1067) : la hauteur suit la largeur de
	   la colonne à chaque point d'arrêt, sans valeur fixe à maintenir. */
	aspect-ratio: 3 / 2;
	overflow: clip;
	border-radius: var(--fi-radius-s);
	/* Un filet de la famille sombre : la plaque est une ouverture DANS la
	   bande, pas un rectangle posé dessus. */
	outline: 1px solid var(--fi-color-line-dark);
	outline-offset: -1px;
}

/* L'image reste hors du flux : c'est le RAPPORT de la plaque qui décide de la
   hauteur, jamais la hauteur intrinsèque du fichier. */
.fi-statement__plate img {
	position: absolute;
	inset: 0;
	display: block;
	inline-size: 100%;
	block-size: 100%;
	object-fit: cover;
	/* Le cadrage garde la ligne de fuite de l'allée et les silhouettes ; centré,
	   la bande ne montrait que le plafond. */
	object-position: 50% 62%;
	/* Une photo de laboratoire est presque blanche : brute, elle devenait
	   l'élément le plus clair de la bande et prenait la primauté sur la
	   déclaration, qui est le message. Quatre traitements comparés côte à côte ;
	   au-delà (.78 / .7) l'image devient terne et perd ses plans. */
	filter: var(--fi-photo-tone-deep);
}

/* Le voile reprend EXACTEMENT le fond de la bande. C'est lui qui fait
   appartenir la photo à la section au lieu de l'y poser : les blancs du
   laboratoire virent vers le bleu du navy, et la plaque cesse de se lire
   comme un rectangle rapporté. */
.fi-statement__plate::after {
	content: "";
	position: absolute;
	inset: 0;
	background: var(--fi-color-ink-2);
	opacity: 0.18;
	pointer-events: none;
}

/* En colonne unique, la photo passe SOUS le texte. Le DOM la garde en tête —
   c'est la colonne « lead » — et seul l'ordre visuel change. */
@media (max-width: 55.99em) {
	.fi-statement__lead { order: 2; }

	/* Et elle est PLAFONNÉE. En pleine largeur, le rapport 3/2 donnait 480px de
	   haut à 768 : sur une bande dont tout le reste tient en 300px, la photo de
	   substitution devenait le sujet. Le recadrage est absorbé par `object-fit:
	   cover` et le cadrage à 62% de hauteur, qui gardent l'allée et les
	   silhouettes. À 390 la plaque reste sous le plafond (228px) et garde son
	   rapport natif.

	   ⚠️ `inline-size: 100%` n'est pas redondant. Un plafond de hauteur posé sur une
	   boîte dont les DEUX dimensions sont automatiques se reporte sur la largeur :
	   mesuré, la plaque rétrécissait à 576px au lieu de rester à 720 et de rogner.
	   Une largeur définie rend le rapport dérivé, et c'est bien la hauteur qui est
	   coupée. */
	.fi-statement__plate {
		inline-size: 100%;
		max-block-size: 24rem;
	}
}

.fi-statement h2 {
	margin-block: 0;
	font-size: var(--fi-size-step-4);
	line-height: 1.06;
	color: var(--fi-color-on-dark-strong);
}

/* ⚠️ 08/10/2026 — REVUE CLIENT (Chloé Schindler, GP-Homepage p. 1) : « Il faudrait
   les agrandir [les chiffres] et le texte à droite de la photo aussi. » La phrase
   passe du corps courant (16-17px, atténué) à `step-3` en caractère de titre :
   25,6px à 390, 32px à 1440, en clair. Une phrase seule à côté d'une photo de 420px
   de haut n'est pas du texte courant, c'est la déclaration de la bande — le titre
   du manifeste, retiré le 03/09 (M-4), lui avait laissé ce rôle sans la taille qui
   va avec. Interligne resserré en conséquence ; la mesure en `ch` suit la taille,
   c'est la colonne qui borne la ligne. */
.fi-statement__body p {
	margin-block: 0 var(--fi-space-m);
	max-inline-size: 30ch;
	color: var(--fi-color-on-dark);
	font-family: var(--fi-font-display);
	font-size: var(--fi-size-step-3);
	font-weight: 500;
	letter-spacing: -0.015em;
	line-height: 1.35;
	text-wrap: pretty;
}

.fi-statement__body p:last-child { margin-block-end: 0; }

/* ⚠️ SANS CONSOMMATEUR DEPUIS LE 03/09. Les trois piliers ont quitté la page
   d'accueil le 25/08 ; ils vivaient encore dans patterns/about.php, resynchronisé
   depuis (M-7). Ces règles ne sont donc plus atteintes par aucune page. Elles sont
   conservées le temps de la revue client — la bande manifeste y perd son argument
   (M-6) et le client peut vouloir le récupérer sous cette forme. Si rien ne les
   rappelle d'ici la mise en production, les retirer avec `.fi-pillar`. */
.fi-pillars {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
	gap: var(--fi-space-l);
	margin-block-start: clamp(2.4rem, 5vw, 4rem);
	padding-block-start: var(--fi-space-l);
	border-block-start: 1px solid var(--fi-color-line-dark);
}

.fi-pillar h3 {
	margin-block: 0 var(--fi-space-2xs);
	font-size: var(--fi-size-step-1);
	line-height: 1.25;
	color: var(--fi-color-on-dark-strong);
}

.fi-pillar p {
	margin: 0;
	max-inline-size: 34ch;
	color: var(--fi-color-on-dark-muted);
	font-size: var(--fi-size-step-0);
	line-height: 1.6;
}

/* ═══════════════════════════════════════════════════════════════════
   LE CONTINUUM — le temps fort

   Quatre étapes cliquables. Le panneau montre ce qui s'y passe, quelles
   sociétés y opèrent, et quelle certification la gouverne. C'est le seul
   argument qu'un concurrent mono-métier ne peut pas tenir : le rendre
   manipulable, c'est le rendre démontrable.
   ═══════════════════════════════════════════════════════════════════ */

.fi-continuum {
	background: var(--fi-color-surface);
	padding-block: var(--fi-sec);
	border-bottom: 1px solid var(--fi-color-line);
	/* La mesure de la section, partagée par le chapô et par la description du
	   panneau. Ils avaient 495px et 864px : deux textes du même rôle — de la prose
	   qui explique — à deux mesures différentes dans la même bande. Une seule
	   valeur, et ils se répondent. */
	--fi-cont-measure: min(54rem, 100%);
}

/* ⚠️ CENTRÉE puis REMISE AU FER À GAUCHE le 31/08, dans la même journée.

   Le conflit était réel : la tête tenait 640px au fer à gauche, moitié droite de
   la bande vide, sous un axe et un panneau centrés sur 1240 — deux compositions
   superposées. Il a d'abord été résolu en centrant la tête. Mauvais sens : les
   neuf autres sections de la page sont au fer à gauche, et c'est l'identité de la
   page qui devait gagner, pas la symétrie d'une section. Tout est revenu à gauche,
   et c'est l'AXE qui a été refait pour ne plus laisser de vide à droite — voir
   `grid-template-columns` de `.fi-continuum__axis`. */
.fi-continuum > .wp-block-group.fi-continuum__head {
	max-inline-size: var(--fi-cont-measure);
	margin-inline-start: max(0px, calc((100% - var(--fi-container-max)) / 2)) !important;
	margin-inline-end: auto !important;
}

/* Le chapô prend la mesure de la section, comme la description du panneau. */
.fi-continuum__head .fi-lede {
	max-inline-size: var(--fi-cont-measure);
}

.fi-continuum h2 {
	margin-block: 0 var(--fi-space-m);
	font-size: var(--fi-size-step-4);
	line-height: 1.08;
}

/* Le sélecteur d'étapes — un AXE, pas une barre de progression.

   Le 17/08, quatre pastilles sur un rail dégradé avaient été retirées : c'est le
   vocabulaire du tunnel de commande — « vous êtes à l'étape 1 sur 4 d'une tâche
   que vous accomplissez » — alors que le continuum est un index, le visiteur
   n'accomplit rien. Le client tient au filet (27/08). Il revient donc, mais
   construit de façon à dire l'inverse d'une progression. Trois règles :

   1. AUCUN remplissage derrière le point courant. C'est le seul détail qui
      sépare « index » de « tunnel » : une portion pleine suivie d'une portion
      vide EST une barre de progression, quoi qu'on écrive autour.
   2. Les quatre points ont le même poids au repos. Le courant se distingue par
      un noyau plein et un halo, pas par le fait d'exister plus que les autres.
   3. Le filet est nommé à ses deux bouts (« Sample » → « Clinical decision ») :
      un segment borné et légendé se lit comme une ÉCHELLE, et une échelle
      s'aborde par n'importe quel point.

   Le chiffre reste le sujet, composé à l'échelle d'un titre : en creux au repos,
   plein à la sélection. Aucune vague de société ici — elles sont dans le
   panneau, les répéter au-dessus ferait doublon. */
/* ⚠️ 08/10/2026 — REVUE CLIENT (Chloé Schindler, GP-Homepage, p. 1) : « On a du mal à
   associer le texte avec la bonne étape. Il faudrait aligner le texte avec le point
   d'étape. » Le panneau restait calé à gauche, sous « Discover », quelle que soit
   l'étape choisie : à « Commercialise », le texte se lisait sous la mauvaise étape.
   Il SUIT désormais l'étape active, aux deux orientations :

   — à l'horizontale (dès 64em), l'axe et le corps partagent la MÊME grille de N
     colonnes égales, une par étape, et le panneau occupe la colonne de l'étape
     active (`--fi-step-col`, tenu par ui.js). Son bord gauche tombe sur le bord
     gauche du point, donc sur la première lettre du libellé ;
   — à la verticale (sous 64em), le panneau s'insère JUSTE SOUS l'étape active,
     dans le prolongement du filet — voir le bloc vertical plus bas.

   Les variables de l'axe vivent ici et non plus sur l'axe : le corps (horizontal)
   et le panneau (vertical) en ont besoin, et ni l'un ni l'autre n'est un enfant de
   l'axe. Le DOM, les rôles ARIA et le clavier ne changent pas : la liste d'onglets
   reste la liste d'onglets, le panneau reste le panneau, après elle.

   ⚠️ 10/10/2026 — LA DESCRIPTION PASSE « EN LARGEUR » (demande de l'utilisateur,
   maquette H, variante A validée). Le panneau du 08/10, tenu dans la colonne de son
   étape (~286px à 1440), empilait titre, six prestations et « Held by » sur une
   bande étroite, et laissait les trois autres colonnes vides. À l'horizontale il
   devient une CARTE teintée sur toute la largeur, posée sur la grille même de l'axe :
   titre à gauche, prestations au milieu, « Held by » à droite, sous « Commercialise ».
   Le lien avec l'étape active, qui était la demande du 08/10, n'est pas perdu : il
   passe par un CURSEUR (un triangle) sur le bord haut de la carte, sous le point de
   l'étape active, qui glisse d'un point à l'autre. Les libellés d'étape sont rentrés
   de la marge intérieure de la carte (`--fi-card-pad`) : libellés, points et texte de
   la carte partagent les mêmes colonnes. À la verticale, l'accordéon du 08/10 reste,
   le panneau prend la même carte et son curseur pointe vers le libellé au-dessus.
   Voir « La carte du continuum » après `.fi-panel-cert`. */
.fi-continuum__interactive {
	position: relative;
	/* Nommée : l'arrêt est posé en absolu DANS l'étape, et doit franchir cette
	   réserve pour atteindre le filet. Les deux valeurs ne peuvent pas diverger. */
	--fi-axis-pad: calc(var(--fi-space-m) + 0.5rem);
	--fi-axis-gap: clamp(1rem, 2.5vw, 2rem);
	/* Le décalage de l'arrêt : le rayon du point, pour que son bord gauche tombe
	   exactement sur la première lettre du libellé. La valeur est la même pour les
	   quatre : les arrêts restent régulièrement espacés. */
	--fi-dot-x: 5.5px;
	/* 10/10/2026 — la hauteur du curseur de la carte ; sa base en vaut le double. */
	--fi-caret: 11px;
}

.fi-continuum__axis {
	position: relative;
	display: grid;
	/* ⚠️ 08/10/2026 — QUATRE colonnes ÉGALES, une par étape. Du 31/08 au 08/10 :
	   trois colonnes égales et une quatrième réduite à la chasse de son libellé,
	   pour que le filet ne finisse pas sur une colonne vide. Cette colonne n'est
	   plus vide : elle reçoit le panneau quand « Commercialise » est choisie, et
	   elle doit donc avoir la largeur des autres — c'est la même grille que celle
	   du corps, et c'est elle qui aligne le texte sur son point. Le nombre vient
	   des jetons (`--fi-steps`, imprimé par [firalis_continuum]).
	   10/10/2026 : toujours quatre colonnes égales — la carte pleine largeur reprend
	   cette grille, dédoublée, et « Held by » y tombe sous la quatrième étape. */
	grid-template-columns: repeat(var(--fi-steps, 4), minmax(0, 1fr));
	gap: var(--fi-axis-gap);
	/* ⚠️ Le rythme de la section était INVERSÉ, mesuré le 31/08 : 22px entre le
	   chapô et l'axe, 29px entre le filet et le titre du panneau. Les libellés
	   d'étape étaient donc plus près de l'intro que le panneau ne l'était de sa
	   propre commande — rien ne disait que l'un pilote l'autre.
	   L'axe s'éloigne de l'intro, le panneau se colle à l'axe : le couple
	   commande / sortie devient le plus serré de la bande. */
	margin: clamp(2.75rem, 8vw, 5rem) 0 0;
	padding: 0 0 var(--fi-axis-pad);
	list-style: none;
}

/* Le filet. Posé en ::after et non en border-block-end pour que les arrêts
   puissent s'asseoir dessus : une bordure ne se laisse pas chevaucher.

   Il court d'un arrêt EXTRÊME à l'autre, pas d'un bord à l'autre du conteneur :
   une ligne qui dépasse son dernier arrêt file vers nulle part.

   ⚠️ TRONÇONNÉ depuis le 31/08 — un segment par étape, de SON arrêt à celui de la
   suivante, et aucun segment après le dernier. Il était d'un seul tenant, posé sur
   l'axe, et sa longueur se calculait depuis la largeur des colonnes. Ce calcul est
   devenu impossible le jour où la quatrième colonne est passée en `auto` : sa
   largeur est celle de la chasse de « Diagnose », qu'aucune feuille ne connaît.

   La distance entre deux arrêts, elle, se dit sans mesure : c'est la largeur d'une
   colonne plus la gouttière, soit « 100% + gap » relativement à l'étape. C'est
   exactement la construction déjà employée en mode vertical, où la même impossibilité
   se posait sur la hauteur des rangées.

   Teinte unie d'un bout à l'autre : aucun remplissage, aucune progression. */
.fi-step:not(:last-child)::before {
	content: "";
	position: absolute;
	/* Même ancrage que l'arrêt, au demi-pixel près : la boîte descend d'une réserve
	   d'axe, puis se décale de sa demi-hauteur. Les deux tombent donc sur la même
	   ligne, quelle que soit la hauteur de l'étape. */
	inset-block-end: calc(-1 * var(--fi-axis-pad));
	inset-inline-start: var(--fi-dot-x);
	inline-size: calc(100% + var(--fi-axis-gap));
	block-size: 1px;
	transform: translateY(50%);
	background: var(--fi-color-line-strong);
}

.fi-step {
	position: relative;
	display: flex;
	/* Centré et non calé sur la ligne de base : l'étape ne portait plus qu'un seul
	   enfant depuis le retrait du chiffre (31/08), et il n'y avait plus deux
	   lignes de base à accorder. C'est la réserve ci-dessous qui a besoin d'un
	   alignement : sans elle, le libellé serait resté collé en haut de sa boîte. */
	align-items: center;
	/* La CIBLE. Le chiffre d'étape donnait sa hauteur à l'étape ; retiré, la boîte
	   tombait à 37-41px selon la largeur, et l'audit relevait les quatre étapes aux
	   quatre largeurs. La réserve est portée par la boîte elle-même et non par un
	   remplissage : l'arrêt est posé en absolu par rapport à cette boîte, et un
	   remplissage bas l'aurait décalé hors du filet. */
	min-block-size: 44px;
	margin: 0;
	padding: 0;
	border: 0;
	background: none;
	font: inherit;
	text-align: start;
	color: inherit;
}

/* L'ARRÊT. Le canon du plan de ligne : point PLEIN = le service s'y arrête
   toujours, anneau creux = il n'y passe que parfois. Les quatre arrêts sont donc
   pleins et identiques au repos — chacun dit « on peut monter ici ». Un point
   creux aurait dit l'inverse exact de ce que la section doit dire : « étape non
   atteinte ». C'est l'encodage, pas une légende, qui porte le message.

   L'étape courante ne devient pas « plus existante » : elle reçoit un ANNEAU
   supplémentaire, un repère « vous êtes ici ». La sélection est donc portée par
   une forme en plus, pas par la couleur seule (WCAG 1.4.1). */
.fi-step__tick {
	position: absolute;
	/* L'étape est un élément de grille : son bas s'arrête au-dessus de la réserve
	   de l'axe. Sans ce report, l'arrêt flottait à 2rem au-dessus du filet. */
	inset-block-end: calc(-1 * var(--fi-axis-pad));
	inset-inline-start: var(--fi-dot-x);
	inline-size: 11px;
	block-size: 11px;
	border-radius: 50%;
	/* « muted » et non « noise » : mesuré, noise tombe à 2.12:1 sur la surface, en
	   deçà du 3:1 que WCAG 1.4.11 exige d'un objet graphique porteur de sens — et
	   l'arrêt en porte un, il dit où l'on peut monter. muted tient 5.73:1. Effet
	   secondaire voulu : les arrêts pèsent plus que les chiffres en creux, ce qui
	   dit « toutes les stations sont ouvertes » avant de dire « vous lisez la 3 ». */
	background: var(--fi-color-muted);
	/* Le halo de fond découpe le filet autour de l'arrêt : sur un plan de ligne,
	   la station interrompt le trait, elle ne se pose pas dessus. */
	box-shadow: 0 0 0 4px var(--fi-color-surface);
	/* Sans lui, le ::after de l'axe — dernier enfant généré — passait AU-DESSUS
	   des arrêts : on voyait le filet leur traverser le ventre. */
	z-index: 1;
	transform: translate(-50%, 50%);
	transition: box-shadow 0.3s ease, background 0.3s ease;
}

/* Le survol PRÉFIGURE la sélection : l'arrêt prend l'encre et l'anneau que porte
   l'étape courante, en plus pâle.

   ⚠️ 03/09 — CE COMMENTAIRE DISAIT « c'est la seule chose qui dise cliquer ici
   déplace le repère, et c'est pour cela que le chapô doit encore écrire select a
   stage ». Il est devenu FAUX : la revue client (C-4) a remplacé le chapô, et
   « select a stage to see what happens there and who runs it » n'existe plus. Plus
   une ligne de la page ne dit que l'axe est un contrôle. Le survol ne suffit pas —
   il ne se voit qu'après avoir déjà visé, et un visiteur tactile ne l'a jamais.
   L'affordance est donc passée AU REPOS, en style, sans revenir sur le texte du
   client : voir le soulignement de `.fi-step__t` plus bas. */
button.fi-step:hover .fi-step__tick,
button.fi-step:focus-visible .fi-step__tick {
	background: var(--fi-color-ink);
	box-shadow:
		0 0 0 4px var(--fi-color-surface),
		0 0 0 5.5px var(--fi-color-line-strong);
}

.fi-step[aria-selected="true"] .fi-step__tick,
.fi-step[data-current] .fi-step__tick {
	background: var(--fi-color-ink);
	box-shadow: 0 0 0 4px var(--fi-color-surface), 0 0 0 5.5px var(--fi-color-ink);
}

/* Encre et non atténué : c'est une garantie commerciale, pas une légende. */

/* Le curseur n'apparaît que sur le vrai bouton : sans JavaScript les étapes sont
   des libellés inertes, et une main sur du texte mort est un mensonge. */
button.fi-step {
	cursor: pointer;
}

/* ⚠️ `.fi-step__n` — le chiffre d'étape — a été RETIRÉ le 31/08 sur demande
   client, avec ses règles de survol et de sélection. Il numérotait une chaîne qui
   n'est pas un tunnel. La position vit dans le panneau, « Stage 01 / 04 ». */

.fi-step__t {
	font-family: var(--fi-font-display);
	font-size: clamp(1rem, 0.9rem + 0.5vw, 1.35rem);
	font-weight: 600;
	letter-spacing: -0.026em;
	/* Atténué et non « line-strong » : c'est le libellé d'un BOUTON, il doit se
	   lire avant le clic. Mesuré — line-strong tombe à 1.54:1, muted tient
	   5.73:1, et l'encre de l'étape active à 18.07:1. La hiérarchie reste franche. */
	color: var(--fi-color-muted);
	transition: color 0.3s ease;
}

/* ⚠️ 03/09 — L'AFFORDANCE AU REPOS, en remplacement de la consigne « select a
   stage » que la revue client a retirée du chapô (C-4).

   C'est le geste que la section emploie déjà vingt lignes plus bas pour les noms de
   sociétés du panneau (`.fi-panel-co span`), et pour la même raison : un élément qui
   n'est cliquable qu'au survol n'est pas cliquable pour qui ne survole pas. Filet
   fort, 1px, décalé de 4 — assez pour dire « contrôle », trop peu pour peser autant
   que le libellé.

   L'étape COURANTE ne le porte pas : on ne clique pas là où l'on est déjà, et sa
   distinction — encre pleine et anneau sur l'arrêt — se lit mieux sans. Le
   soulignement prend l'encre au survol et au focus, comme les noms de sociétés. */
.fi-step__t {
	text-decoration: underline;
	text-decoration-color: var(--fi-color-line-strong);
	text-underline-offset: 6px;
	text-decoration-thickness: 1px;
	transition: color 0.3s ease, text-decoration-color 0.3s ease;
}

button.fi-step:hover .fi-step__t,
button.fi-step:focus-visible .fi-step__t {
	color: var(--fi-color-ink);
	text-decoration-color: currentColor;
}

.fi-step[aria-selected="true"] .fi-step__t,
.fi-step[data-current] .fi-step__t {
	color: var(--fi-color-ink);
}

/* ⚠️ Le préfixe `button` n'est pas décoratif : sans lui cette règle pèse 0-3-0 et
   perd contre `button.fi-step:hover .fi-step__t` (0-3-1) — survoler l'étape
   COURANTE lui rendait un soulignement, c'est-à-dire l'invitation à cliquer là où
   l'on est déjà. La variante `[data-current]` n'en a pas besoin : elle ne vit que
   dans le repli sans JavaScript, où aucune règle de survol ne s'applique. */
button.fi-step[aria-selected="true"] .fi-step__t,
.fi-step[data-current] .fi-step__t {
	text-decoration-color: transparent;
}

/* Sous 48em, un filet horizontal n'a plus de place pour porter quatre points.
   L'axe bascule à la VERTICALE — une colonne, le filet à gauche, un point par
   rangée. C'est le même objet, tourné : l'échelle reste une échelle, et chaque
   étape gagne une rangée entière comme zone tactile. ui.js annonce
   aria-orientation « vertical » à ce même point d'arrêt.

   ⚠️ 14/09 — 48em ET NON PLUS 52em. Le seuil de 52em avait été posé pour quatre
   CHIFFRES d'étape, retirés de l'axe le 31/08 ; il ne reste que les libellés.
   Mesuré en horizontal à 768 : colonnes de 180px pour des libellés de 67 à 124px,
   cibles de 44px, filet d'un arrêt à l'autre sans débord. L'axe vertical laissait
   entre 768 et 832px une section de 789px de haut, contre 605 en horizontal.

   ⚠️ 08/10/2026 — 64em ET NON PLUS 48em (revue client, GP-Homepage p. 1). Le panneau
   tient désormais dans la colonne de son étape (voir `.fi-continuum__interactive`) :
   sous 64em, une colonne sur quatre tombe sous 200px et la liste se hacherait mot à
   mot. Entre 48 et 64em l'axe redevient donc vertical — et c'est là que le panneau
   s'insère sous son étape, ce qu'aucune disposition horizontale ne sait faire.

   10/10/2026 : le seuil de 64em RESTE, pour une autre raison. Le panneau n'est
   plus dans une colonne mais dans une carte pleine largeur à trois zones ; sous
   64em, la zone des prestations tomberait sous 250px et « Warehousing,
   transportation, distribution » casserait sur deux lignes. L'accordéon garde la
   même carte, en une colonne.

   Le panneau n'est pas DÉPLACÉ dans le DOM : la liste d'onglets ne doit contenir que
   des onglets. L'axe et le corps passent en `display: contents`, leurs enfants
   deviennent les rangées d'une même grille, et `order` range l'affichage : les
   étapes jusqu'à l'active (0), le panneau (1), les étapes suivantes (2). L'ordre de
   tabulation reste celui que l'on voit — seul l'onglet actif est tabulable
   (tabulation roulante), et le panneau le suit immédiatement, à l'écran comme dans
   le DOM. Les rôles ARIA posés sur l'<ol> ne dépendent pas de sa boîte. */
@media (max-width: 63.99em) {
	.fi-continuum__interactive {
		display: grid;
		grid-template-columns: minmax(0, 1fr);
		/* 10/10/2026 : resserré (il valait clamp(1.1rem, 4vw, 1.75rem)). La carte
		   et son curseur prennent de la place sous l'étape active ; l'écart entre
		   rangées cède d'autant. C'est la VARIABLE qui change et non le seul
		   `row-gap` : les tronçons de filet se mesurent sur elle, ils restent
		   ainsi d'un point à l'autre sans dépasser. */
		--fi-axis-gap: clamp(1rem, 3.5vw, 1.5rem);
		--fi-rail-x: calc(-1.9rem + 5.5px);
		/* Le centre de l'arrêt, d'où part le segment de filet. Il valait « 0.55rem
		   + rayon », une hauteur calée sur le chiffre d'étape ; celui-ci retiré
		   (31/08), l'arrêt se centre sur la RANGÉE, dont la hauteur suit la taille
		   fluide du libellé. Mesuré avant correction : l'arrêt tombait 7px au-dessus
		   du milieu de son libellé, et l'écart changeait avec la largeur. */
		--fi-dot-y: 50%;
		row-gap: var(--fi-axis-gap);
		/* La réserve du filet, portée jusqu'ici par l'axe : elle vaut pour le
		   panneau aussi, qui s'aligne ainsi sur les libellés et non sur le rail.
		   La marge haute de l'axe passe ici pour la même raison — une boîte en
		   `display: contents` n'a ni marge ni remplissage. Double déclaration :
		   voir « Hauteur d'écran » plus bas. */
		padding-inline-start: 1.9rem;
		margin-block-start: clamp(2.75rem, 8vw, 5rem);
		margin-block-start: clamp(1.75rem, min(8vw, 8svh), 5rem);
	}

	.fi-continuum__axis,
	.fi-continuum__body {
		display: contents;
	}

	.fi-step[aria-selected="true"] ~ .fi-step,
	.fi-step[data-current] ~ .fi-step {
		order: 2;
	}

	/* Le remplissage bas (`--fi-space-xs`) est parti le 10/10/2026 : le panneau est
	   une carte, sa marge intérieure est déclarée avec elle, plus bas. */
	.fi-continuum__panel {
		order: 1;
	}

	/* 10/10/2026 — un peu d'air entre le libellé actif et la pointe du curseur.
	   Le tronçon de filet de cette étape la franchit : il court de son point
	   jusqu'au milieu de la hauteur de cible, sous le haut de la carte. */
	.fi-step[aria-selected="true"],
	.fi-step[data-current] {
		margin-block-end: 0.25rem;
	}

	/* Le filet traverse le panneau : sans lui, il s'arrêtait sous l'étape active
	   et reprenait à la suivante, et le panneau se lisait comme une coupure de la
	   chaîne. Le tronçon court du haut du panneau jusqu'au point de l'étape
	   suivante, dont le centre tombe à mi-hauteur de sa cible de 44px. */
	.fi-continuum__panel::before {
		content: "";
		position: absolute;
		inset-block-start: 0;
		inset-inline-start: var(--fi-rail-x);
		inline-size: 1px;
		block-size: calc(100% + var(--fi-axis-gap) + 22px);
		background: var(--fi-color-line-strong);
	}

	/* Après la dernière étape, il n'y a plus de point à rejoindre. */
	.fi-continuum__interactive:has(.fi-step:last-child:is([aria-selected="true"], [data-current])) .fi-continuum__panel::before {
		content: none;
	}

	/* Le filet tourne avec l'axe : le même tronçonnage, mais sur la hauteur des
	   rangées. Toutes les propriétés d'orientation sont redéclarées — le bloc
	   horizontal reste en vigueur pour ce qui n'est pas repris ici. */
	.fi-step:not(:last-child)::before {
		inset-block-end: auto;
		inset-block-start: var(--fi-dot-y);
		inset-inline-start: var(--fi-rail-x);
		inline-size: 1px;
		block-size: calc(100% + var(--fi-axis-gap));
		transform: none;
	}

	.fi-step__tick {
		inset-block-end: auto;
		inset-block-start: 50%;
		inset-inline-start: -1.9rem;
		transform: translateY(-50%);
	}

	/* La hauteur de rangée porte seule la zone tactile : pas de réserve latérale,
	   qui décalerait le point hors du filet. */
	button.fi-step {
		padding-block: 6px;
	}
}

/* ⚠️ Un bloc 52-64em portait ici `padding: 3px 4px` et `margin-inline-start: -4px`
   sur le bouton : il gagnait ses 44px de cible tactile au remplissage, et son
   retrait négatif recalait le premier CHIFFRE sur la marge. Retiré le 31/08 avec
   ce chiffre. Deux raisons, pas une :

   — la cible est désormais portée par `min-block-size: 44px` sur l'étape, à toutes
     les largeurs, sans remplissage à compenser ;
   — le retrait de 4px désaxait le filet. L'arrêt est posé à 50 % de la BOÎTE du
     bouton : élargie de 8px et décalée de 4, elle ne recouvrait plus sa colonne, et
     les réserves tombaient à 110px à gauche contre 114 à droite. Mesuré. */

/* Le filet de séparation appartient au SÉLECTEUR, pas au panneau : les deux en
   portaient un, et on lisait deux traits parallèles séparés d'un vide.

   ⚠️ 02/10/2026 — REVUE CLIENT (docs/74 H-4). LE PANNEAU NE SAUTE PLUS AU CHANGEMENT
   D'ONGLET. Les listes du client vont de 4 à 6 prestations (H-5) et passent en une
   colonne : d'une étape à l'autre, la section aurait gagné ou perdu jusqu'à deux
   lignes, et tout ce qui la suit avec. ui.js relève la hauteur de la PLUS LONGUE des
   quatre étapes, à la largeur courante, et la pose en `min-block-size` sur le
   panneau — voir son bloc « Hauteur stable ». La mesure est faite sur une copie
   invisible du panneau, jamais sur le panneau lui-même : réécrire son contenu pour
   le mesurer ferait perdre le focus à qui est posé sur un lien « Held by ».
   `space-between` cale « Held by » en BAS de cette hauteur : la signature des
   sociétés reste à la même place d'un onglet à l'autre, et c'est le vide sous la
   liste courte qui varie, pas la position du bloc. Sans JavaScript, pas de hauteur
   imposée : un seul panneau s'affiche, rien ne peut sauter.

   ⚠️ 10/10/2026 — LE PANNEAU DEVIENT UNE CARTE teintée (maquette H, variante A ;
   voir `.fi-continuum__interactive`). La hauteur stable reste, la mesure de ui.js
   aussi, à une condition : `box-sizing: border-box`. ui.js mesure la copie au bord
   de la BORDURE (getBoundingClientRect, remplissage compris) et pose le résultat en
   `min-block-size` ; en `content-box`, ce plancher s'applique au CONTENU et le
   remplissage s'ajoute une seconde fois. Mesuré avant correction : 12px de trop à
   768 et à 390 (le remplissage bas de l'époque), et ce serait 76 à 92px avec celui
   de la carte. `space-between` passe à `start` : dès 64em « Held by » est une zone
   de la carte, en haut à droite, à la même place d'un onglet à l'autre ; dans
   l'accordéon, la carte bouge avec son étape et « Held by » suit la liste. */
.fi-continuum__panel {
	box-sizing: border-box;
	position: relative;
	display: grid;
	gap: var(--fi-space-l);
	align-content: start;
	padding: var(--fi-space-m) var(--fi-space-m) var(--fi-space-l);
	border-radius: var(--fi-radius-m);
	background: var(--fi-color-surface-alt);
}

/* Le CURSEUR — 10/10/2026. Un triangle de la teinte de la carte, posé sur son bord
   haut (1px de recouvrement : aucune couture). À la verticale il pointe vers le
   libellé de l'étape, juste au-dessus ; à l'horizontale, il se place sous le point
   de l'étape active et glisse d'un point à l'autre (bloc « La carte du continuum »).
   Un pseudo-élément du PANNEAU, et non un élément de plus : ui.js réécrit le contenu
   du panneau, jamais le panneau lui-même — le curseur survit au changement
   d'onglet, et c'est ce qui lui permet de se DÉPLACER au lieu de réapparaître.
   Décoratif : rien à annoncer, l'onglet sélectionné le dit déjà. */
.fi-continuum__panel::after {
	content: "";
	position: absolute;
	z-index: 1;
	inset-block-start: calc(-1 * var(--fi-caret) + 1px);
	inset-inline-start: var(--fi-space-m);
	inline-size: calc(2 * var(--fi-caret));
	block-size: var(--fi-caret);
	background: var(--fi-color-surface-alt);
	clip-path: polygon(50% 0, 100% 100%, 0 100%);
}

/* ── Le corps ────────────────────────────────────────────────────────
   ⚠️ 13/09 — LA PHOTOGRAPHIE A ÉTÉ RETIRÉE, sur demande client. Du 31/08 au 13/09
   le corps tenait le panneau ET une vue `.fi-continuum__view`, en deux colonnes
   (`minmax(0, 1fr) minmax(0, 20rem)` dès 56em). La grille est partie avec la
   photo : gardée sans image, sa colonne de 20rem laissait un trou à droite et
   pinçait le panneau pour rien. Le panneau reprend toute la largeur, et c'est la
   mesure de la section qui borne sa description, comme le chapô.

   L'enveloppe reste pour la réserve sous le filet : elle est portée par le CORPS
   et non par le panneau — voir le commentaire de marge de `.fi-continuum__axis`,
   et sa variante des écrans bas plus bas dans cette feuille. */
.fi-continuum__body {
	margin-block-start: clamp(1.25rem, 2vw, 1.75rem);
}

/* ⚠️ Le panneau tenait DEUX colonnes (1.1fr / 0.9fr) jusqu'au 31/08 : le texte à
   gauche, les sociétés à droite. Il est passé en COLONNE UNIQUE ce jour-là, et il
   y reste après le retour au fer à gauche — pour une raison qui n'a rien à voir
   avec l'alignement : c'est la seule façon que la description et le chapô de la
   section partagent la même mesure. En deux colonnes, la description était bornée
   par sa colonne (650px) là où le chapô en faisait 864, et deux textes du même
   rôle se lisaient à deux mesures dans la même bande.

   L'ordre est celui du DOM, inchangé : titre, description, puis les sociétés. */

/* ⚠️ `.fi-panel-pos` — « Stage 01 / 04 » — a été RETIRÉ le 31/08 avec ses règles,
   sur demande client : le continuum est un index, pas un tunnel, et il était
   numéroté à deux endroits jusqu'au retrait des chiffres d'étape le matin même.
   Le libellé sélectionné sur l'axe suffit à dire où l'on est. */

/* 10/10/2026 : `step-2` dans la carte de l'accordéon (il valait `step-3`), et
   `step-3` dès 64em, où le titre a sa zone. Un titre d'étape ne laisse jamais un
   mot seul. */
.fi-continuum__panel h3 {
	margin-block: 0 var(--fi-space-s);
	font-size: var(--fi-size-step-2);
	line-height: 1.2;
	text-wrap: balance;
}

/* ⚠️ Du 08/10 au 10/10/2026, un bloc dès 64em rangeait ici le panneau dans la
   COLONNE de l'étape active (`grid-column: var(--fi-step-col)`, corps en grille
   de quatre colonnes, titre à `step-2`). Remplacé le 10/10 par la carte pleine
   largeur : voir « La carte du continuum » après `.fi-panel-cert`. Il est posé
   là-bas et non ici parce que ses règles doivent passer APRÈS celles de la liste
   et de « Held by », qu'elles réarrangent. */

/* Le contenu entre en fondu à chaque changement d'étape : ui.js réécrit le
   panneau, et une animation déclarée sur ses enfants rejoue à chaque insertion.
   Le regard suit ainsi le texte d'une colonne à l'autre au lieu de le chercher.

   10/10/2026 : l'animation descend d'un niveau — sur le titre, la liste et
   « Held by », et non plus sur `.fi-panel-txt`. Dès 64em celui-ci passe en
   `display: contents` pour que ses enfants deviennent des zones de la carte, et
   une boîte qui n'est pas rendue n'anime ni opacité ni transformation. Les trois
   zones entrent en léger décalé, de gauche à droite. */
.fi-continuum__panel .fi-panel-txt > *,
.fi-continuum__panel .fi-panel-side {
	animation: fi-panel-in 0.32s cubic-bezier(0.22, 0.61, 0.36, 1) both;
}

.fi-continuum__panel .fi-panel-txt > :not(:first-child) { animation-delay: 0.04s; }
.fi-continuum__panel .fi-panel-side { animation-delay: 0.08s; }

@keyframes fi-panel-in {
	from { opacity: 0; transform: translateY(0.4rem); }
}

@media (prefers-reduced-motion: reduce) {
	.fi-continuum__panel .fi-panel-txt > *,
	.fi-continuum__panel .fi-panel-side { animation: none; }
}

/* Les sociétés portent leur vague plutôt qu'une pastille dans une pilule : le
   groupe est « un dessin, cinq couleurs », autant le montrer là où on nomme les
   sociétés. */
.fi-panel-cos {
	display: flex;
	flex-wrap: wrap;
	gap: var(--fi-space-2xs) var(--fi-space-m);
}

/* Pastille devenue LIEN le 27/08. Le soulignement n'apparaissait alors qu'au
   survol : quatre noms soulignés sous un titre en petites capitales faisaient une
   liste de liens plutôt qu'une signature de sociétés.

   ⚠️ DÉCISION INVERSÉE LE 31/08, pour deux raisons qui ont changé depuis :
   — le panneau n'en montre plus quatre mais DEUX à la fois, la liste ne peut plus
     faire liste ;
   — la section a un but, et ce but est ce lien. C'est par lui qu'on quitte
     l'accueil vers la fiche de la société qui tient l'étape. C'était l'élément le
     plus petit, le dernier, et le seul qui ne se donnait pas pour cliquable.
   Le soulignement est donc posé AU REPOS, au filet fort pour ne pas peser autant
   que le nom, et prend la couleur de la société au survol. */
.fi-panel-co {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	font-family: var(--fi-font-display);
	font-size: var(--fi-size-step-0);
	font-weight: 600;
	color: var(--fi-color-ink);
	text-decoration: none;
	transition: color 0.2s ease;
	/* La pastille fait 26px de haut — la vague en dicte la mesure. La réserve
	   porte la zone cliquable à 44 et le retrait la reprend, si bien que rien ne
	   bouge à l'écran : seule la cible grandit. Même dispositif que les étapes. */
	padding-block: 9px;
	margin-block: -9px;
}

.fi-panel-co span {
	text-decoration: underline;
	text-decoration-color: var(--fi-color-line-strong);
	text-underline-offset: 4px;
	text-decoration-thickness: 1px;
	transition: text-decoration-color 0.2s ease;
}

.fi-panel-co:hover,
.fi-panel-co:focus-visible {
	color: var(--fi-c-ink, var(--fi-color-brand));
}

.fi-panel-co:hover span,
.fi-panel-co:focus-visible span {
	text-decoration-color: currentColor;
}

.fi-panel-co__w {
	display: block;
	block-size: 22px;
	inline-size: auto;
	aspect-ratio: 265 / 432;
	flex: 0 0 auto;
}

.fi-continuum__panel .fi-panel-txt p {
	margin: 0;
	/* 44ch tant que le panneau était en colonne de gauche : c'était la mesure d'un
	   texte au fer à gauche dans une colonne étroite. Centré sous un axe qui court
	   sur 75 % de la bande, ce bloc de 440px se lisait pincé. Il prend la mesure de
	   la SECTION, la même que le chapô — 54rem, soit 74 signes par ligne mesurés,
	   le haut de la fourchette lisible. Au-delà, une ligne centrée devient
	   impossible à rattraper d'un bout à l'autre. */
	max-inline-size: var(--fi-cont-measure);
	/* Taille explicite : sans elle, ce paragraphe héritait d'une valeur fluide et
	   tombait à 14.15px à 390 et 14.97px à 768 — mesuré. C'est du texte courant,
	   il ne descend pas sous 16px, seuil sous lequel iOS zoome de lui-même. */
	font-size: var(--fi-size-step-0);
	color: var(--fi-color-muted);
	line-height: 1.65;
}

/* ⚠️ 03/09 — REVUE CLIENT (C-3). La phrase de l'étape est devenue une LISTE de
   quatre prestations. Deux colonnes dès qu'il y a la place : en colonne unique,
   quatre lignes faisaient descendre le panneau sous la photographie sœur, qui
   donnait sa hauteur à la bande. Photo retirée le 13/09 : les deux colonnes
   restent, elles gardent la bande courte.

   ⚠️ 02/10/2026 — REVUE CLIENT (docs/74 H-4, diapo 3). UNE SEULE COLONNE, à toutes
   les largeurs. Guillaume : « 2 à 2 interfère avec le schéma de lecture et donc
   avec l'enfilade [des] mots clefs […] Une colonne de mots clefs est plus
   lisible » — la liste se lisait en Z, et à 1440 la seconde colonne venait se
   ranger sous le libellé « Develop » de l'axe, au point de s'y rattacher. La règle
   `repeat(2, minmax(0, max-content))` dès 34em est RETIRÉE ; la grille reste, pour
   son seul pas vertical. Coût : deux à trois lignes de plus par étape, absorbées
   par la hauteur stable du panneau (voir `.fi-continuum__panel` plus haut).
   10/10/2026 : la colonne unique est GARDÉE dans la carte pleine largeur, sur la
   même décision. Les prestations y commencent au milieu d'une colonne de l'axe,
   sous AUCUN point : elles ne se rattachent plus à « Develop » (voir « La carte du
   continuum »). La variante à deux colonnes de la maquette n'a pas été retenue.

   Même mesure, même taille, même couleur que le paragraphe qu'elle remplace : ce
   n'est pas un autre registre de texte, c'est le même contenu autrement découpé.

   La puce est DESSINÉE — un tiret court à la couleur de marque — et non un
   `list-style` : le marqueur natif se pose sur la ligne de base du navigateur et
   non sur celle du texte, et une puce ronde à cette taille lit comme une liste de
   courses. Le tiret reprend le trait des filets de la section. */
.fi-continuum__panel .fi-panel-list {
	margin: 0;
	padding: 0;
	list-style: none;
	max-inline-size: var(--fi-cont-measure);
	display: grid;
	gap: var(--fi-space-2xs) var(--fi-space-xl);
	font-size: var(--fi-size-step-0);
	line-height: 1.65;
	color: var(--fi-color-muted);
}

.fi-continuum__panel .fi-panel-list li {
	position: relative;
	padding-inline-start: 1.15em;
}

.fi-continuum__panel .fi-panel-list li::before {
	content: "";
	position: absolute;
	inset-inline-start: 0;
	/* Posé sur la moitié de la hauteur de ligne, pas sur la ligne de base : à
	   1.65 d'interligne, un tiret aligné en haut flotte au-dessus du mot. */
	inset-block-start: 0.82em;
	inline-size: 0.55em;
	block-size: 1px;
	background: var(--fi-color-brand);
}

/* ⚠️ `.fi-panel-xchg` — le couple « Starts from / Delivers » — a été SUPPRIMÉ le
   31/08 avec toutes ses règles : le filet, les deux cellules, la flèche entre
   elles et son repli sous 34em. Voir le commentaire de `firalis_group_exchange()`
   dans inc/sections.php : ce n'est pas son fond qui l'a fait tomber mais son coût
   graphique une fois centré. */

/* Aligné sur le surtitre : 0.66rem donnait 10,56px là où le surtitre de section
   en fait 11,2 — deux tailles pour un même rôle de micro-libellé, et la plus
   petite sous le plancher de 12px que le projet s'impose ailleurs. Une seule
   valeur, celle du surtitre. */
.fi-panel-side h4 {
	margin-block: 0 var(--fi-space-s);
	font-family: var(--fi-font-mono);
	font-size: 0.6875rem;
	font-weight: 500;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var(--fi-color-muted);
}

.fi-panel-cert {
	margin-block-start: var(--fi-space-m);
	padding-block-start: var(--fi-space-s);
	border-block-start: 1px solid var(--fi-color-line);
	font-family: var(--fi-font-mono);
	font-size: 0.74rem;
	line-height: 1.6;
	color: var(--fi-color-muted);
}

.fi-panel-cert strong { color: var(--fi-color-ink); font-weight: 500; }

/* ── La carte du continuum, dès 64em — 10/10/2026 ───────────────────────
   Demande de l'utilisateur : la description « en largeur ». Maquette H, variante A
   validée, avec ses réglages par défaut : ni chiffre d'étape (retiré le 31/08), ni
   filet rempli jusqu'à l'étape active (règle 1 de l'axe : un index, pas une
   progression), prestations en UNE colonne (02/10, H-4). Remplace le panneau du
   08/10 tenu dans la colonne de son étape (docs/75, H-4).

   La carte prend toute la largeur, sous l'axe, et reprend SA grille : quatre
   colonnes d'étape à la même gouttière, chacune coupée en deux — huit
   demi-colonnes. Deux demi-colonnes et une gouttière font exactement une colonne
   de l'axe, donc chaque zone tombe sur un repère de l'axe :
   — le titre, demi-colonnes 1 à 3, aligné sur « Discover » ;
   — les prestations, 4 à 6 : elles commencent au MILIEU de la colonne de
     « Develop », sous aucun point — elles ne se lisent plus comme la légende de
     cette étape, le défaut relevé le 02/10 ;
   — « Held by », les deux dernières, sous « Commercialise » (lignes -3 / -1 : la
     dernière étape, quel que soit leur nombre).
   L'axe prend en marge intérieure celle de la carte (`--fi-card-pad`) : libellés,
   points et texte de la carte sont sur les mêmes colonnes.

   Le lien à l'étape active passe par le CURSEUR : sous le point actif, il glisse
   d'un point à l'autre. Sa position se calcule depuis `--fi-step-col`, déjà tenue
   par ui.js et posée à 1 par le serveur — rien de neuf en JavaScript, et sans
   script il est sous « Discover », la seule étape rendue. La hauteur reste stable
   d'un onglet à l'autre (ui.js, « Hauteur stable »), d'où une carte de hauteur fixe
   dont la zone la plus longue fait la mesure.

   Ce qui glisse, c'est le NUMÉRO d'étape et non la position : `--fi-step-col` est
   déclarée en nombre (@property) et c'est elle qui porte la transition. Une
   transition sur `inset-inline-start` rejouait à chaque changement de largeur —
   le curseur courait derrière son point pendant un redimensionnement (relevé sur
   les captures, qui redimensionnent la page). Sans @property, le curseur saute
   d'un point à l'autre, sans glisser : rien d'autre ne change. */
@property --fi-step-col {
	syntax: "<number>";
	inherits: true;
	initial-value: 1;
}

@media (min-width: 64em) {
	.fi-continuum__interactive {
		--fi-card-pad: clamp(1.5rem, 2.6vw, 2.5rem);
		transition: --fi-step-col 0.42s cubic-bezier(0.22, 0.61, 0.36, 1);
	}

	.fi-continuum__axis {
		padding-inline: var(--fi-card-pad);
	}

	/* Fixe, sans la variante en svh des écrans bas : sous ~22px, la pointe du
	   curseur touche l'anneau de l'arrêt actif (11px sous le filet). Le préfixe
	   l'emporte sur cette variante, déclarée plus bas dans la feuille. */
	.fi-continuum .fi-continuum__body {
		margin-block-start: calc(var(--fi-space-l) + 2px);
	}

	.fi-continuum__panel {
		grid-template-columns: repeat(var(--fi-steps, 4), minmax(0, 1fr) minmax(0, 1fr));
		column-gap: var(--fi-axis-gap);
		row-gap: var(--fi-space-l);
		align-items: start;
		padding: clamp(1.75rem, 3vw, 2.75rem) var(--fi-card-pad) clamp(2rem, 3.4vw, 3rem);
	}

	/* Le titre et la liste deviennent des zones de la carte. */
	.fi-continuum__panel .fi-panel-txt {
		display: contents;
	}

	.fi-continuum__panel h3 {
		grid-column: 1 / span 3;
		max-inline-size: 11em;
		margin: 0;
		font-size: var(--fi-size-step-3);
		line-height: 1.12;
		letter-spacing: -0.022em;
	}

	/* La hauteur de capitale du titre et la première prestation sur une ligne. */
	.fi-continuum__panel .fi-panel-list,
	.fi-continuum__panel .fi-panel-txt p {
		grid-column: 4 / -3;
		margin-block-start: 0.2rem;
	}

	.fi-continuum__panel .fi-panel-side {
		grid-column: -3 / -1;
		margin-block-start: 0.45rem;
	}

	.fi-continuum__panel .fi-panel-cos {
		flex-direction: column;
		align-items: flex-start;
		gap: var(--fi-space-s);
	}

	/* Centre de l'étape i : marge de la carte, plus (i − 1) fois une colonne de
	   l'axe et sa gouttière, plus le décalage du point dans son étape. `100%` est
	   la largeur de la carte, celle de l'axe : elles ont la même boîte. */
	.fi-continuum__panel::after {
		inset-inline-start: calc(
			var(--fi-card-pad)
			+ (var(--fi-step-col, 1) - 1) * ((100% - 2 * var(--fi-card-pad) - (var(--fi-steps, 4) - 1) * var(--fi-axis-gap)) / var(--fi-steps, 4) + var(--fi-axis-gap))
			+ var(--fi-dot-x)
		);
		transform: translateX(-50%);
	}
}

@media (min-width: 64em) and (prefers-reduced-motion: reduce) {
	.fi-continuum__interactive { transition: none; }
}

/* ═══════════════════════════════════════════════════════════════════
   WHAT WE DO — l'offre, service par service
   Huit services pour cinq sociétés depuis le 02/10/2026 (sept avant) : ni
   séquence, ni parité, donc ni rail ni numérotation. Chaque cellule porte son
   propre filet. Plus de photographie dans la grille de l'accueil depuis la même
   date (docs/74 H-6) : les règles de `.fi-offer__view` ci-dessous restent, inertes
   sans elle, tant que l'attribut `photo` du shortcode existe.
   ═══════════════════════════════════════════════════════════════════ */

.fi-offer-section {
	background: var(--fi-color-surface-alt);
	padding-block: var(--fi-sec);
	/* Conteneur de requête de la grille des services : voir « La vue de l'offre ». */
	container: fi-offer / inline-size;
}

.fi-offer-section > .wp-block-group.fi-offer-section__head,
.fi-companies > .wp-block-group.fi-companies__head,
.fi-quality > .wp-block-group.fi-quality__head,
.fi-news > .wp-block-group.fi-news__head {
	max-inline-size: min(40rem, 100%);
	margin-inline-start: max(0px, calc((100% - var(--fi-container-max)) / 2)) !important;
	margin-inline-end: auto !important;
}

/* h1 inclus : les pages intérieures réutilisent ces têtes de section avec un
   titre de niveau 1, qui sinon n'héritait d'aucune marge basse. */
.fi-offer-section__head h2,
.fi-companies__head :is(h1, h2),
.fi-quality__head h2,
.fi-news__head h2,
.fi-form-band__aside h2,
.fi-locale__txt h2 {
	margin-block: 0 var(--fi-space-m);
	font-size: var(--fi-size-step-4);
	line-height: 1.1;
}

/* ⚠️ 08/10/2026 — REVUE CLIENT (Chloé Schindler, GP-Homepage p. 2) : « La mise à la
   ligne est différente du bloc d'au-dessus, il faut harmoniser. » Les deux têtes
   voisines de l'accueil n'avaient pas la même mesure : 54rem pour le continuum
   (« One chain, four stages, full support. » tenait sur une ligne), 40rem ici
   (« One integrated chain / of services » cassait après « chain »). La tête de
   l'offre et son chapô prennent la mesure du continuum, `--fi-cont-measure`,
   redéclarée ici avec la même valeur — les deux têtes ont désormais la même
   construction ; les deux titres prennent le même interligne et `text-wrap:
   balance`. Sur une ligne dès 768, ils cassent de la même façon quand ils cassent :
   en deux lignes de longueur voisine, jamais un mot seul en bout de titre.
   La règle commune des têtes ci-dessus ne change pas pour les autres pages. */
.fi-offer-section {
	--fi-cont-measure: min(54rem, 100%);
}

.fi-offer-section > .wp-block-group.fi-offer-section__head,
.fi-offer-section__head .fi-lede {
	max-inline-size: var(--fi-cont-measure);
}

.fi-offer-section__head h2,
.fi-continuum h2 {
	line-height: 1.08;
	text-wrap: balance;
}

.fi-offer {
	display: grid;
	/* Repli des navigateurs sans requêtes de conteneur. Partout ailleurs, les
	   paliers de « La vue de l'offre » posent des colonnes explicites aux mêmes
	   seuils. */
	grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
	gap: var(--fi-space-xl) var(--fi-space-l);
	margin: clamp(2.5rem, 5vw, 3.75rem) 0 0;
	padding: 0;
	list-style: none;
}

/* ── La vue de l'offre, dernière cellule de la grille ────────────────
   13/09, demande client : la photographie quitte la tête de la bande pour finir
   la grille des services. Posée le 31/08 à droite du chapô, elle imposait SA
   hauteur à la tête — 377px à 1440, contre 257 au texte seul — et DÉBORDAIT de
   76px le bord droit de la grille : `max-inline-size: 100%` rendait à la tête
   toute la largeur de la
   bande pendant que la marge du fer à gauche la décalait encore. La tête revient
   à la règle commune des têtes de section, 40rem au fer à gauche.

   Le contrat : la photo remplit EXACTEMENT les cellules laissées libres après le
   dernier service — une à 1440, deux à 1024, une à 768 —, ne crée jamais de rang
   vide et ne passe jamais seule sur un rang où il restait de la place, quel que
   soit le nombre de services. Trois choix le tiennent.

   ① Colonnes EXPLICITES par palier. L'étendue de la photo se déduit du nombre de
   colonnes, que `auto-fit` calculait sans jamais le livrer à une autre règle. Les
   paliers reprennent ses seuils — N × 15rem + (N − 1) × 2rem de gouttière : 32,
   49, 66rem —, les tuiles ne bougent donc pas d'un pixel. Cinq colonnes
   demanderaient 83rem, au-delà des 1240px de la bande : pas de palier.

   ② Le conteneur de requête est la BANDE, pas la liste : un élément ne peut pas
   s'interroger lui-même. La requête lit la boîte de contenu de la bande,
   gouttières globales déduites ; la liste en prend min(cette largeur, 1240px), et
   les trois seuils sont sous 1240px — bande et liste changent de palier ensemble.

   ③ L'étendue se lit sur le RANG de la photo, toujours dernier enfant de la liste
   (inc/companies.php l'ajoute après la boucle). À N colonnes, rang ≡ k (mod N),
   k = 0 lu comme N : elle démarre en colonne k et prend les N − k + 1 restantes.
   Rang ≡ 1 : le dernier rang de tuiles est plein, elle ouvre le sien en bande
   basse — la règle de base, qui sert aussi en colonne unique et sans requêtes de
   conteneur. Les paliers sont DISJOINTS : empilés, l'étendue d'un palier
   inférieur survivrait là où le suivant ne dit rien. */

/* Base, la bande basse : 16/9 comme la vue en une colonne d'avant, plafonnée pour
   qu'un dernier rang plein à 1240px ne produise pas 700px d'image. */
.fi-offer__view {
	position: relative;
	grid-column: 1 / -1;
	justify-self: stretch;
	aspect-ratio: 16 / 9;
	max-block-size: 16rem;
	margin: 0;
	overflow: clip;
	border-radius: var(--fi-radius-s);
}

/* L'image est posée en ABSOLU : hors flux, elle ne pèse rien dans le calcul des
   pistes. Dans une cellule partielle, le rang garde la hauteur de ses tuiles et
   la photo s'y étire — bord haut sur leur filet, bord bas au pied de leur ligne
   d'attribution. En flux, sa hauteur naturelle l'emportait : 640px de large à
   1024, soit 427 de haut, pour un rang de 163. */
.fi-offer__photo {
	position: absolute;
	inset: 0;
	margin: 0;
}

.fi-offer__photo img {
	display: block;
	inline-size: 100%;
	block-size: 100%;
	object-fit: cover;
	/* Le cadrage commun aux vues du substitut : il garde têtes et bustes jusque
	   dans la cellule la plus allongée, deux colonnes sur un rang de 163px à 1024. */
	object-position: 50% 62%;
	filter: var(--fi-photo-tone);
}

@container fi-offer (32rem <= inline-size < 49rem) {
	.fi-offer { grid-template-columns: repeat(2, minmax(0, 1fr)); }

	/* Rang pair : une cellule libre. Rang impair : rang plein, bande de base. */
	.fi-offer__view:nth-child(2n) {
		grid-column: span 1;
		aspect-ratio: auto;
		max-block-size: none;
	}
}

@container fi-offer (49rem <= inline-size < 66rem) {
	.fi-offer { grid-template-columns: repeat(3, minmax(0, 1fr)); }

	/* Hors rang plein, la cellule prend la hauteur du rang : ni rapport ni plafond. */
	.fi-offer__view:not(:nth-child(3n + 1)) {
		aspect-ratio: auto;
		max-block-size: none;
	}

	.fi-offer__view:nth-child(3n + 2) { grid-column: span 2; }
	.fi-offer__view:nth-child(3n) { grid-column: span 1; }
}

@container fi-offer (inline-size >= 66rem) {
	.fi-offer { grid-template-columns: repeat(4, minmax(0, 1fr)); }

	.fi-offer__view:not(:nth-child(4n + 1)) {
		aspect-ratio: auto;
		max-block-size: none;
	}

	.fi-offer__view:nth-child(4n + 2) { grid-column: span 3; }
	.fi-offer__view:nth-child(4n + 3) { grid-column: span 2; }
	.fi-offer__view:nth-child(4n) { grid-column: span 1; }
}

.fi-offer__item {
	position: relative;
	margin: 0;
	border-block-start: 1px solid var(--fi-color-line-strong);
}

/* Le filet coloré se déploie au survol : c'est la seule apparition de la
   couleur de la société dans cette section. */
.fi-offer__item::after {
	content: "";
	position: absolute;
	inset-block-start: -1px;
	inset-inline-start: 0;
	inline-size: 0;
	block-size: 2px;
	background: var(--fi-c, var(--fi-color-brand));
	transition: inline-size 0.32s cubic-bezier(0.22, 0.61, 0.36, 1);
}

.fi-offer__item:hover::after { inline-size: 100%; }

.fi-offer__link {
	display: flex;
	flex-direction: column;
	gap: var(--fi-space-2xs);
	block-size: 100%;
	padding-block: var(--fi-space-m) 0;
	text-decoration: none;
	color: inherit;
}

.fi-offer__title {
	font-family: var(--fi-font-display);
	font-size: var(--fi-size-step-1);
	font-weight: 600;
	line-height: 1.22;
	letter-spacing: -0.02em;
	color: var(--fi-color-ink);
	transition: color 0.2s ease;
}

.fi-offer__link:hover .fi-offer__title { color: var(--fi-color-brand); }

/* ── Titre, texte et attribution sur des rangées COMMUNES — 14/09 ────
   Le titre réservait deux lignes (`min-block-size: 2.44em`) pour que les
   descriptions d'un même rang partent à la même hauteur quand un titre passe
   sur deux lignes. Aucun titre ne le fait aujourd'hui, à aucune largeur : la
   réserve n'était que du blanc, 31px du titre à sa description contre 8 de la
   description à la société, et le titre se lisait détaché de son propre texte.
   En colonne unique elle ne servait même pas l'alignement.

   Sous-grille : chaque tuile occupe trois rangées de la grille des services, et
   ses trois éléments s'y posent. Une rangée prend la hauteur du plus haut titre
   DE CE RANG — une ligne quand tous tiennent sur une ligne, deux dès qu'un seul
   en demande deux, et l'alignement des descriptions est gardé sans rien
   réserver. La vue photographique occupe les mêmes trois rangées. */
@supports (grid-template-rows: subgrid) {
	.fi-offer > .fi-offer__item,
	.fi-offer > .fi-offer__view {
		grid-row: span 3;
	}

	.fi-offer__item,
	.fi-offer__link {
		display: grid;
		grid-template-rows: subgrid;
		/* L'écart de la tuile, pas celui de la grille des services (48px) : une
		   sous-grille qui ne déclare rien hériterait du second. */
		row-gap: var(--fi-space-2xs);
	}

	.fi-offer__link {
		grid-row: 1 / -1;
	}
}

/* Sans sous-grille, la réserve d'avant : l'alignement d'abord, le blanc ensuite. */
@supports not (grid-template-rows: subgrid) {
	.fi-offer__title { min-block-size: 2.44em; }
}

/* `step--1` (13.33px) était la plus petite écriture PORTEUSE D'INFORMATION de la
   page — une phrase entière, deux crans sous le texte courant du reste du site.
   Ramenée au texte courant : la hiérarchie de la tuile tient toujours, le titre
   étant à 20px, et la page n'a plus qu'un seul régime de lecture. Coût mesuré :
   une ligne de plus par tuile. `step--1` reste en usage pour ce à quoi il sert —
   les micro-libellés en capitales espacées. */
.fi-offer__blurb {
	color: var(--fi-color-muted);
	font-size: var(--fi-size-step-0);
	line-height: 1.55;
	text-wrap: pretty;
}

/* ⚠️ 03/09 — `flex` et non `inline-flex` (O-2). La ligne d'attribution prend
   maintenant TOUTE la largeur de la tuile, pour que la flèche ajoutée plus bas
   puisse être poussée au bord droit. Elle ne contenait qu'une pastille et un nom,
   tous deux au fer à gauche : rien ne bouge à l'écran. */
.fi-offer__by {
	display: flex;
	align-items: center;
	gap: 0.4rem;
	margin-block-start: auto;
	padding-block-start: var(--fi-space-s);
	font-family: var(--fi-font-mono);
	font-size: 0.68rem;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--fi-c-ink, var(--fi-color-brand));
}

.fi-offer__by::before {
	content: "";
	inline-size: 7px;
	block-size: 7px;
	border-radius: 50%;
	flex: 0 0 auto;
	background: var(--fi-c-ink, var(--fi-color-brand));
}

/* ⚠️ 03/09 — L'AFFORDANCE AU REPOS de la tuile, en remplacement de « follow it
   through to see how they run it » que la revue client a retiré du chapô (O-2).

   Sans elle, la tuile n'annonçait plus rien : au repos, un titre, une phrase et une
   attribution — le filet coloré et la mise en couleur du titre n'apparaissent qu'AU
   SURVOL, et un visiteur tactile ne les voit jamais. C'est la seule section de la
   page dont les liens ne se donnaient pas.

   La flèche est celle de l'annuaire du hero et des cartes de société — MÊME tracé,
   `M3 8h10M9 4l4 4-4 4` de firalis_group_arrow_svg(), au trait de 1.6 — reproduite
   ici en MASQUE parce que le balisage de la tuile est produit par inc/companies.php
   et qu'il n'y avait pas à y toucher pour un cue graphique. Le `#000` du tracé ne
   peint rien : un masque ne lit que l'alpha, la couleur vient de `background-color`
   et donc des jetons. Repos au filet fort, encre au survol et au focus, comme
   `.fi-heroX__go`.

   Mesuré : COÛT NUL en hauteur. La flèche fait 16px, la ligne d'attribution en fait
   17,4 (mono à 10,88px) — le glyphe tient dans la boîte de ligne existante. La ligne
   reste à 30,9px et la section à 949,8px à 1440, 1029,4 à 1024, 1534,1 à 768 et
   1997,8 à 390 : rien n'a bougé, et la contrainte « l'offre tient dans un écran »
   posée le 27/08 est intacte. */
.fi-offer__by::after {
	content: "";
	margin-inline-start: auto;
	flex: 0 0 auto;
	inline-size: 1rem;
	block-size: 1rem;
	background-color: var(--fi-color-line-strong);
	--fi-arrow-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M3 8h10M9 4l4 4-4 4' stroke='%23000' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
	-webkit-mask: var(--fi-arrow-mask) center / contain no-repeat;
	mask: var(--fi-arrow-mask) center / contain no-repeat;
	transition: background-color 0.24s ease;
}

.fi-offer__link:hover .fi-offer__by::after,
.fi-offer__link:focus-visible .fi-offer__by::after {
	background-color: var(--fi-color-ink);
}

/* ═══════════════════════════════════════════════════════════════════
   OUR COMPANIES — un dessin, cinq couleurs
   ═══════════════════════════════════════════════════════════════════ */

.fi-companies {
	background: var(--fi-color-surface);
	padding-block: var(--fi-sec);
	border-bottom: 1px solid var(--fi-color-line);
}

/* ⚠️ 14/09 — Dernière bande de la page, elle perd son filet bas. Sur /studies/,
   la bande est seule : son filet, 19px de blanc, puis le liseré du pied de page
   faisaient DEUX séparations pour une seule limite. Le pied de page porte déjà
   la sienne. Aucune autre page ne se termine sur une bande à filet (relevé sur
   les 21 pages du 14/09). */
main .entry-content > .fi-companies:last-child {
	border-block-end: 0;
}

.fi-co {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(13rem, 100%), 1fr));
	gap: var(--fi-space-s);
	margin: clamp(2.5rem, 5vw, 3.75rem) 0 0;
	padding: 0;
	list-style: none;
}

.fi-co__item {
	margin: 0;
	border: 1px solid var(--fi-color-line);
	border-radius: var(--fi-radius-m);
	background: var(--fi-color-surface);
	transition: border-color 0.22s ease, transform 0.22s ease, box-shadow 0.22s ease;
}

.fi-co__item:hover {
	transform: translateY(-3px);
	border-color: var(--fi-c, var(--fi-color-brand));
	box-shadow: 0 10px 30px color-mix(in srgb, var(--fi-color-ink) 8%, transparent);
}

/* Sans box-sizing, « block-size: 100% » puis 40px de padding font déborder le lien
   hors de sa carte : Twenty Twenty-Five ne pose pas de remise à zéro universelle. */
.fi-co__link,
.fi-offer__link {
	box-sizing: border-box;
}

.fi-co__link {
	display: flex;
	flex-direction: column;
	block-size: 100%;
	padding: var(--fi-space-m) var(--fi-space-m) var(--fi-space-s);
	text-decoration: none;
	color: inherit;
}

.fi-co__mark {
	display: block;
	block-size: 38px;
	inline-size: auto;
	aspect-ratio: 265 / 432;
	margin-block-end: var(--fi-space-s);
}

.fi-co__name {
	font-family: var(--fi-font-display);
	font-size: var(--fi-size-step-1);
	font-weight: 600;
	letter-spacing: -0.025em;
	color: var(--fi-color-ink);
}

/* Défaut ANTÉRIEUR relevé le 28/08 en auditant /studies/ : « step--1 » vaut
   13.33px, et ces phrases sont du texte courant, pas des libellés — c'est le
   même défaut que le pied du panneau des normes, corrigé le matin même. Le
   seuil que le projet s'impose est 15px. */
.fi-co__blurb {
	margin-block-start: var(--fi-space-3xs);
	color: var(--fi-color-muted);
	font-size: var(--fi-size-step-0);
	line-height: 1.55;
}

.fi-co__go {
	margin-block-start: auto;
	padding-block-start: var(--fi-space-s);
	font-family: var(--fi-font-mono);
	font-size: 0.68rem;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--fi-c-ink, var(--fi-color-brand));
}

.fi-co__go--off { color: var(--fi-color-muted); }

/* ═══════════════════════════════════════════════════════════════════
   QUALITY — un tableau, parce qu'un tableau lit comme de la rigueur
   ═══════════════════════════════════════════════════════════════════ */

/* ⚠️ CE BLOC DOIT RESTER APRÈS les règles de `.fi-offer*`. Posé plus haut dans
   la feuille, il n'avait aucun effet sur l'offre : à spécificité égale la
   dernière déclaration gagne, et `.fi-offer-section { padding-block: var(--fi-sec) }`
   la reprenait 230 lignes plus bas. Le continuum, lui, est déclaré avant — d'où
   un bloc qui semblait fonctionner à moitié. */
/* ═══════════════════════════════════════════════════════════════════
   SECTIONS « PLEINE LECTURE » — le continuum et l'offre

   Demande client du 27/08 : ces deux sections doivent tenir dans un écran,
   faute de quoi le visiteur défile À L'INTÉRIEUR d'un contenu qui se présente
   comme un bloc — un sélecteur dont le panneau sort du champ, une grille dont
   la seconde rangée est invisible au moment où on lit la première.

   Le rythme vertical du site est indexé sur la LARGEUR (`--fi-sec` est en vw) :
   il ne sait rien de la hauteur disponible, et gonfle donc exactement là où il
   faudrait qu'il cède — écran large et bas. Ces règles le réindexent sur `svh`,
   la hauteur d'écran chrome VISIBLE, la plus petite des trois : dimensionner
   dessus garantit que rien ne dépasse quand la barre d'adresse est déployée.

   Chaque propriété est déclarée DEUX FOIS : la valeur d'origine, puis la valeur
   bornée. Un navigateur sans `svh` jette la seconde comme invalide et garde la
   première — dégradation propre, aucun @supports à maintenir.

   Seuils mesurés : le continuum tient à partir de ~700px de hauteur utile,
   l'offre à partir de ~810px. Sous ces valeurs les sections défilent, ce qui
   reste préférable à des tuiles tronquées. Le mobile n'est pas concerné :
   sept services et un axe vertical n'entrent pas dans 844px, quel que soit le
   réglage — les y forcer supposerait de couper du contenu.
   ═══════════════════════════════════════════════════════════════════ */

.fi-continuum,
.fi-offer-section {
	padding-block: var(--fi-sec);
	padding-block: clamp(1.75rem, 5svh, var(--fi-sec));
}

/* Les titres cèdent sur la hauteur avant tout le reste : ce sont eux qui
   prennent le plus de place pour le moins d'information par pixel. */
.fi-continuum h2,
.fi-offer-section__head h2 {
	font-size: min(var(--fi-size-step-4), 5.2svh);
}

.fi-continuum__axis {
	margin-block-start: clamp(2.75rem, 8vw, 5rem);
	margin-block-start: clamp(1.75rem, min(8vw, 8svh), 5rem);
}

.fi-continuum__body {
	margin-block-start: clamp(1.25rem, 2vw, 1.75rem);
	margin-block-start: clamp(1rem, min(2vw, 2.6svh), 1.75rem);
}

.fi-offer {
	margin-block-start: clamp(2.5rem, 5vw, 3.75rem);
	margin-block-start: clamp(1.5rem, min(5vw, 4.5svh), 3.75rem);
	row-gap: var(--fi-space-xl);
	row-gap: clamp(1.5rem, 4svh, var(--fi-space-xl));
}

.fi-offer__link {
	padding-block-start: var(--fi-space-m);
	padding-block-start: clamp(0.9rem, 2.2svh, var(--fi-space-m));
}

.fi-offer__by {
	padding-block-start: var(--fi-space-s);
	padding-block-start: clamp(0.6rem, 1.5svh, var(--fi-space-s));
}

/* Le repli n'a de sens qu'en paysage : en portrait, `svh` vaut beaucoup et les
   bornes hautes s'appliquent d'elles-mêmes. La règle est donc universelle et
   n'a pas besoin d'être bornée en largeur. */

.fi-quality {
	background: var(--fi-color-surface-alt);
	padding-block: var(--fi-sec);
	border-bottom: 1px solid var(--fi-color-line);
}

.fi-quality__scroll { overflow-x: auto; }

.fi-qt {
	inline-size: 100%;
	border-collapse: collapse;
	margin-block-start: clamp(2.2rem, 5vw, 3rem);
	font-size: var(--fi-size-step-0);
}

.fi-qt caption {
	text-align: start;
	padding-block-end: var(--fi-space-s);
	font-family: var(--fi-font-mono);
	font-size: 0.66rem;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--fi-color-muted);
}

.fi-qt th {
	text-align: start;
	padding: 0 var(--fi-space-s) 0.7rem 0;
	border-block-end: 1px solid var(--fi-color-line-strong);
	font-family: var(--fi-font-mono);
	font-size: 0.64rem;
	font-weight: 500;
	letter-spacing: 0.11em;
	text-transform: uppercase;
	color: var(--fi-color-muted);
}

.fi-qt td {
	padding: 0.95rem var(--fi-space-s) 0.95rem 0;
	border-block-end: 1px solid var(--fi-color-line);
	vertical-align: top;
	color: var(--fi-color-muted);
}

.fi-qt td:first-child {
	font-family: var(--fi-font-display);
	font-weight: 600;
	font-size: var(--fi-size-step-0);
	letter-spacing: -0.015em;
	color: var(--fi-color-ink);
	white-space: nowrap;
}

.fi-qt td:last-child {
	padding-inline-end: 0;
	font-family: var(--fi-font-mono);
	font-size: 0.76rem;
}

.fi-qt tbody tr:hover td {
	background: color-mix(in srgb, var(--fi-color-wash) 16%, transparent);
}

/* Sous 48em un tableau à quatre colonnes ne tient pas : chaque ligne
   devient un bloc, l'en-tête disparaît. */
/* Sous 48em les colonnes ne tiennent pas. On garde le tableau intact et on
   ré-expose chaque intitulé via data-label : masquer thead retirait la ligne
   d'en-tête de l'arbre d'accessibilité et laissait quatre chaînes anonymes —
   sur la section dont l'argument est justement la vérifiabilité. */
@media (max-width: 48em) {
	.fi-qt thead {
		position: absolute;
		inline-size: 1px;
		block-size: 1px;
		overflow: hidden;
		clip-path: inset(50%);
		white-space: nowrap;
	}

	.fi-qt tr {
		display: block;
		padding-block: var(--fi-space-s);
		border-block-end: 1px solid var(--fi-color-line);
	}

	.fi-qt td {
		display: flex;
		gap: var(--fi-space-s);
		border: 0;
		padding: 0.15rem 0;
	}

	.fi-qt td::before {
		content: attr(data-label);
		flex: 0 0 6.5rem;
		font-family: var(--fi-font-mono);
		font-size: 0.64rem;
		letter-spacing: 0.11em;
		text-transform: uppercase;
		color: var(--fi-color-muted);
		padding-block-start: 0.15rem;
	}

	.fi-qt td:first-child { font-size: var(--fi-size-step-1); }
}

/* ═══════════════════════════════════════════════════════════════════
   MOMENTUM — un grand chiffre, et ce qu'il y a derrière
   ═══════════════════════════════════════════════════════════════════ */

.fi-momentum {
	position: relative;
	background: var(--fi-color-ink-2);
	color: var(--fi-color-on-dark);
	padding-block: var(--fi-sec);
	overflow: clip;
}

.fi-momentum__grid {
	display: grid;
	gap: clamp(2rem, 5vw, 4rem);
	align-items: center;
}

@media (min-width: 56em) {
	.fi-momentum__grid { grid-template-columns: 0.85fr 1.15fr; }
}

.fi-momentum__figure strong {
	display: block;
	font-family: var(--fi-font-display);
	font-size: var(--fi-size-step-6);
	font-weight: 600;
	line-height: 0.92;
	letter-spacing: -0.05em;
	color: var(--fi-color-on-dark-strong);
	font-variant-numeric: tabular-nums;
}

.fi-momentum__figure span {
	display: block;
	margin-block-start: var(--fi-space-2xs);
	font-family: var(--fi-font-mono);
	font-size: 0.6875rem;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--fi-color-accent-on-dark);
}

.fi-momentum__list { margin: 0; padding: 0; list-style: none; }

.fi-momentum__list li {
	display: grid;
	gap: 0.2rem;
	padding-block: var(--fi-space-s);
	border-block-start: 1px solid var(--fi-color-line-dark);
}

@media (min-width: 40em) {
	.fi-momentum__list li {
		grid-template-columns: 8.5rem 1fr;
		gap: var(--fi-space-m);
		align-items: baseline;
	}
}

.fi-momentum__list strong {
	font-family: var(--fi-font-display);
	font-size: var(--fi-size-step-1);
	font-weight: 600;
	letter-spacing: -0.02em;
	color: var(--fi-color-on-dark-strong);
	font-variant-numeric: tabular-nums;
}

.fi-momentum__list p {
	margin: 0;
	color: var(--fi-color-on-dark-muted);
	font-size: var(--fi-size-step-0);
	line-height: 1.6;
}

/* ═══════════════════════════════════════════════════════════════════
   NEWS — liste à filets. Une actualité de groupe se lit comme un
   communiqué, pas comme une vignette.
   ═══════════════════════════════════════════════════════════════════ */

/* Le filet de tête est nécessaire depuis le 25/08 : les sections « offre »,
   « qualité » et « élan » parties, les actualités suivent directement le
   continuum — deux bandes claires de suite, sans lui la jonction ne se voyait
   plus. Même traitement que la bande de clôture. */
/* ⚠️ LA BANDE D'ACTUALITÉS DISPARAÎT TANT QU'AUCUN ARTICLE N'EST PUBLIÉ.
   Ce n'est pas un bug : sans article, elle mesurait 464px pour 58 signes — une
   densité de 13 signes par 100px, quatre fois moins que toute autre bande de la
   page — et affichait un titre, un filet et « No news published yet. » séparés par
   deux grands vides. Une page d'accueil qui annonce une salle vide vaut moins
   qu'une page qui ne l'annonce pas.

   Elle réapparaît d'elle-même à la publication du premier article, sans rien
   toucher : c'est le bloc « aucun résultat » du cœur de WordPress qui déclenche
   la règle. Vérifié en publiant puis en supprimant un article de contrôle.

   Repli : un navigateur sans `:has()` affiche la bande vide — l'état d'avant,
   inesthétique mais pas cassé. */
.fi-news:has(.fi-news__empty) {
	display: none;
}

.fi-news {
	background: var(--fi-color-surface);
	border-block-start: 1px solid var(--fi-color-line);
	padding-block: var(--fi-sec);
	border-bottom: 1px solid var(--fi-color-line);
}

.fi-news__items {
	margin: clamp(2.2rem, 5vw, 3rem) 0 0;
	padding: 0;
	list-style: none;
	border-block-start: 1px solid var(--fi-color-line-strong);
}

.fi-news__items > li {
	margin: 0;
	border-block-end: 1px solid var(--fi-color-line);
	transition: background-color 0.2s ease;
}

.fi-news__items > li:hover {
	background: color-mix(in srgb, var(--fi-color-wash) 14%, transparent);
}

.fi-news .fi-news__item {
	display: grid;
	gap: var(--fi-space-2xs);
	padding-block: var(--fi-space-m);
}

.fi-news__item > * { margin-block-start: 0; }

/* ⚠️ 14/09 — DEUX PALIERS, ET NON PLUS UN SEUL À 48em. Les trois colonnes
   (date · texte · vignette) partaient dès 768px : 11rem + 12rem + deux gouttières
   de 2rem ne laissaient que 288px au titre, MOINS que les 342 d'un téléphone à
   390. « Amoneta's APO-Easy® genotyping kit is CE-marked under the EU IVDR »
   tombait sur trois lignes et « CE-marked » se coupait au trait d'union.

   Entre 48 et 60em, la date et la catégorie remontent donc AU-DESSUS du titre,
   comme sur téléphone, et la vignette garde sa colonne à droite : 496px de texte
   à 768. Les trois colonnes reviennent à 60em, où le texte a 480px — le même
   ordre de grandeur, avec la date de nouveau dans la marge.

   `align-items: start` et non plus `baseline` : un titre de deux ou trois lignes
   se calait sur sa DERNIÈRE ligne face à la date (mesuré 29 et 53px sous le haut
   du titre à 768), et la date flottait selon la longueur du titre. La vignette
   était déjà en `start` pour la même raison, voir plus bas. */
@media (min-width: 48em) {
	.fi-news .fi-news__item {
		grid-template-columns: minmax(0, 1fr) 12rem;
		gap: var(--fi-space-2xs) var(--fi-space-l);
		align-items: start;
	}

	/* Placée explicitement : sans cela l'auto-placement mettrait le texte dans la
	   seconde colonne du premier rang, à côté de la date. */
	.fi-news__thumb {
		grid-column: 2;
		grid-row: 1 / span 2;
	}

	/* ⚠️ 02/10 — LE TEXTE AUSSI EST PLACÉ, PAS SEULEMENT LA VIGNETTE. Un article
	   SANS image à la une (« Firalis Molecular Precision becomes Precursion »,
	   post 129) n'a pas de `.fi-news__thumb` pour occuper la colonne 2 : l'auto-
	   placement y posait alors `.fi-news__content`, à côté de la date, et le titre
	   tombait dans les 192px réservés à la vignette (mesuré à 900 sur /news/ et la
	   fiche Firalis). Méta et texte restent donc en colonne 1 quoi qu'il arrive ;
	   la colonne 2 reste vide, et le titre garde l'alignement des rangs voisins. */
	.fi-news .fi-news__meta,
	.fi-news .fi-news__content {
		grid-column: 1;
	}
}

.fi-news .fi-news__meta {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: var(--fi-space-2xs) var(--fi-space-s);
}

.fi-news__meta > * { margin-block-start: 0; }

.fi-news__date {
	color: var(--fi-color-muted);
	font-family: var(--fi-font-mono);
	font-size: 0.72rem;
	font-variant-numeric: tabular-nums;
	white-space: nowrap;
}

.fi-news__cat,
.fi-news__cat a {
	font-family: var(--fi-font-mono);
	font-size: 0.68rem;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--fi-color-brand);
	text-decoration: none;
}

/* Cible tactile. La catégorie mesurait 53 × 14px et elle est un lien : même parade
   que le titre plus bas — le remplissage agrandit la cible jusqu'à 44px, et le
   lien reste « inline », donc la ligne ne grandit pas d'un pixel. */
.fi-news__cat a {
	padding-block: 0.95rem;
}

/* La catégorie vit dans .fi-news__meta (flex) : elle ne peut pas se placer sur la
   grille parente. Elle reste donc sous la date, et la troisième colonne revient à
   la VIGNETTE, posée le 31/08 — voir plus bas. Palier porté de 48 à 60em le 14/09,
   voir la règle de `.fi-news__item` ci-dessus. */
@media (min-width: 60em) {
	.fi-news .fi-news__item {
		grid-template-columns: 11rem minmax(0, 1fr) 12rem;
		gap: var(--fi-space-l);
	}

	.fi-news .fi-news__meta { flex-direction: column; gap: var(--fi-space-3xs); }

	/* Trois colonnes nommées, et non plus laissées à l'auto-placement : le palier
	   de 48em fixe le texte en colonne 1 (voir plus haut), il faut l'en sortir ici.
	   Sans vignette, la colonne 3 reste vide. */
	.fi-news .fi-news__meta { grid-column: 1; }
	.fi-news .fi-news__content { grid-column: 2; }

	.fi-news__thumb {
		grid-column: 3;
		grid-row: 1;
	}
}

/* ── La vignette d'article ───────────────────────────────────────────
   Posée le 31/08. Les trois articles portaient une image à la une depuis leur
   import du 28/08 — la liste ne la montrait nulle part, et une salle de presse
   sans visuel se lit comme une page inachevée. Aucune image nouvelle n'a été
   fabriquée : ce sont celles des articles.

   `align-self: start` et non la ligne de base de la grille : une image est un
   élément remplacé, sa ligne de base est son bord INFÉRIEUR. Alignée comme le
   texte, elle serait descendue jusqu'à ce que son bas touche la première ligne du
   titre, et aurait poussé la rangée d'autant.

   Elle DISPARAÎT sous 48em : la grille repasse en une colonne, où la vignette
   viendrait s'intercaler entre le chapô et l'article suivant sans rien apporter —
   la liste se lit alors comme un fil, pas comme une grille de cartes. */
.fi-news__thumb {
	align-self: start;
	margin: 0;
}

.fi-news__thumb img {
	display: block;
	inline-size: 100%;
	/* Même raison que la vue du continuum : sans elle, la hauteur en attribut
	   l'emporterait sur le rapport. Ici WordPress pose aussi un style en ligne qui
	   fait le travail — la règle reste, pour ne pas dépendre de lui. */
	block-size: auto;
	/* Rapport IMPOSÉ, et non la hauteur native : les trois images à la une sont un
	   kakémono de salon, un plan produit et une photo de groupe — trois cadrages,
	   trois hauteurs, et la liste se lisait en escalier. Un seul rapport, et les
	   trois rangées redeviennent une liste.

	   ⚠️ 14/09 — 40/21 ET NON PLUS 3/2. Les images à la une sont au format de
	   partage 1200 × 630 (1,905) ou tout près : 1,905, 1,83 et 1,78 mesurés. En 3/2,
	   `cover` en coupait 21 % sur les côtés, et la bannière AD/PD 2026 perdait le
	   bord de son TEXTE — une affiche coupée se lit comme une erreur. En 40/21, le
	   format 1200 × 630 lui-même, la bannière passe entière ; la photo la plus
	   haute perd 3 % en haut et 3 % en bas, là où il n'y a que du ciel et du sol.
	   `contain` aurait tout montré, au prix de bandes vides d'une vignette à
	   l'autre : la liste reprenait l'escalier que ce rapport existe pour éviter.

	   `!important` contre le CŒUR de WordPress : le bloc post-featured-image écrit
	   `aspect-ratio: 3/2` en style en ligne, depuis l'attribut `aspectRatio` de
	   templates/home.html et de la page d'accueil en base. Les vignettes des fiches
	   (inc/news.php) n'ont pas de style en ligne et n'en ont pas besoin. */
	aspect-ratio: 40 / 21 !important;
	object-fit: cover;
	border-radius: var(--fi-radius-s);
	/* Une photographie de laboratoire est presque blanche : brute, elle prenait la
	   primauté sur le titre de l'article, qui est le message. Même traitement que
	   la plaque du manifeste. */
	filter: var(--fi-photo-tone);
	transition: filter 0.3s ease;
}

.fi-news__items > li:hover .fi-news__thumb img {
	filter: none;
}

@media (max-width: 47.99em) {
	.fi-news__thumb { display: none; }
}

.fi-news .fi-news__content { display: grid; gap: var(--fi-space-2xs); }
.fi-news__content > * { margin-block-start: 0; }

/* ⚠️ 14/09 — LA TÊTE DE PAGE ENTRAIT DANS LA LISTE. firalis-core enveloppe tout
   core/post-title rendu dans la boucle principale d'une PAGE dans `.fi-pagehead`
   (voir « TÊTE DE PAGE » plus bas) — et la boucle de requête de la bande
   d'actualités tourne À L'INTÉRIEUR de la page d'accueil. Chaque titre y portait
   donc le filet et la réserve d'une tête de page : un trait de 1px, aussi fort
   que le séparateur d'articles, et 33px du titre à son chapô contre 8 sur
   /news/, où la boucle n'est pas celle d'une page. L'extrait se lisait comme la
   ligne d'après. Neutralisé ICI, dans la liste seulement : le filtre est partagé
   par les trois sites et n'a pas à connaître une bande d'accueil. */
.fi-news__content > .fi-pagehead {
	padding-block-end: 0;
	border-block-end: 0;
}

.fi-news__title {
	margin-block: 0;
	font-size: var(--fi-size-step-1);
	line-height: 1.3;
	letter-spacing: -0.022em;
}

/* Défaut latent, apparu à la publication des premiers articles : le titre est
   la seule cible cliquable de la ligne, et à 26px de haut il est sous les 44
   exigés. Le remplissage agrandit la cible, la marge négative le reprend — le
   rythme vertical de la liste ne bouge pas d'un pixel. Le lien reste « inline »,
   donc un titre sur deux lignes garde ses deux fragments cliquables. */
/* ⚠️ 14/09 — 0.65rem et non plus 0.6 : une ligne de titre faisait 43px, pas 44.
   Le défaut était caché tant que les titres passaient sur deux ou trois lignes ;
   ils tiennent sur une seule depuis le palier de 60em. */
.fi-news__title a {
	color: var(--fi-color-ink);
	text-decoration: none;
	transition: color 0.2s ease;
	padding-block: 0.65rem;
	margin-block: -0.65rem;
}
.fi-news__items > li:hover .fi-news__title a { color: var(--fi-color-brand); }

.fi-news__excerpt {
	margin: 0;
	max-inline-size: 68ch;
	color: var(--fi-color-muted);
	font-size: var(--fi-size-step-0);
	line-height: 1.6;
	text-wrap: pretty;
}

.fi-news__excerpt p { margin: 0; }

.fi-news__all {
	margin-block-start: var(--fi-space-l);
	font-family: var(--fi-font-display);
	font-size: var(--fi-size-step-0);
	font-weight: 600;
}

/* Même parade de cible que la catégorie : 20px de haut mesurés, 44 après, sans
   que la ligne bouge — le lien reste « inline ». */
.fi-news__all a {
	padding-block: 0.75rem;
	color: var(--fi-color-brand);
	text-decoration: none;
}

.fi-news__all a::after {
	content: "→";
	display: inline-block;
	/* Une espace dans content: est absorbée par le rendu : marge explicite. */
	margin-inline-start: 0.4em;
	transition: transform 0.2s cubic-bezier(0.22, 0.61, 0.36, 1);
}

.fi-news__all a:hover { text-decoration: underline; text-underline-offset: 0.35em; }
.fi-news__all a:hover::after { transform: translateX(3px); }

.fi-news__empty {
	margin: 0;
	padding-block: var(--fi-space-l);
	color: var(--fi-color-muted);
	border-block-start: 1px solid var(--fi-color-line);
}

/* ═══════════════════════════════════════════════════════════════════
   BANDE DE CLÔTURE — le contact
   Elle portait deux panneaux à égalité, contact et carrières. Carrières est
   parti le 25/08 : le panneau restant prend toute la largeur plutôt que de
   laisser une demi-bande vide, et son texte garde une largeur de lecture.
   ═══════════════════════════════════════════════════════════════════ */

/* Fond CLAIR depuis le 25/08 : la bande d'offre a repris le gris juste au-dessus,
   et deux bandes grises de suite cassaient l'alternance claire / grise / navy qui
   tient toute la page. Le filet de tête reste : il sépare la clôture de ce qui
   précède, quelle que soit la teinte. */
.fi-cta {
	background: var(--fi-color-surface);
	border-block-start: 1px solid var(--fi-color-line);
}

/* Bandeau de clôture, simplifié le 27/08 sur demande client.

   Il portait deux panneaux — partenaires et candidats — traités à égalité, puis
   un seul depuis que « Careers » a quitté l'accueil : restaient une grille à deux
   colonnes privée de sa seconde colonne, une règle `:has(:only-child)` pour
   rattraper le vide, un sur-titre, et un lien-texte dont l'::before rendait tout
   le panneau cliquable — au prix, noté à l'époque, de la sélection du texte.

   Une page qui se termine n'a qu'une chose à demander : un titre, une ligne, un
   bouton. Le texte tient à gauche, le bouton à droite, sur la bande que le
   panneau unique laissait vide aux deux tiers. */
.fi-cta__band {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: var(--fi-space-m) var(--fi-space-xl);
	padding-block: clamp(2.6rem, 6vw, 4.5rem);
}

.fi-cta__txt {
	display: flex;
	flex-direction: column;
	gap: var(--fi-space-2xs);
	/* Largeur de lecture : étirée sur 1240px, la ligne ferait plus de 130 signes. */
	max-inline-size: min(52ch, 100%);
}

.fi-cta__txt > * { margin-block: 0; }

/* Le bouton ne s'étire pas : il garde sa largeur de contenu et reste collé au
   bord droit de la bande, quel que soit ce que le texte occupe à gauche. */
.fi-cta__actions {
	flex: 0 0 auto;
	margin-block-start: 0;
}

.fi-cta h2 {
	margin-block: 0;
	font-size: var(--fi-size-step-3);
	line-height: 1.12;
}

.fi-cta__text {
	margin: 0;
	color: var(--fi-color-muted);
	font-size: var(--fi-size-step-0);
	line-height: 1.6;
	text-wrap: pretty;
}

/* ── Cibles tactiles ─────────────────────────────────────────────────
   Mesuré : les liens du pied de page font 26px de haut et les deux verrous de
   marque 32 et 34px, contre 44 recommandés au doigt. On élargit la ZONE cliquable
   sans toucher à la taille du texte, et on retire le gouttière entre les liens
   d'autant, pour que la colonne ne s'allonge pas de la hauteur qu'on vient
   d'ajouter — le rythme visuel reste celui d'avant.

   Le seuil est la largeur et non « pointer: coarse » : un iPad en paysage fait
   1024px avec un pointeur grossier, et c'est justement le cas qu'on veut couvrir. */
@media (max-width: 64em) {
	/* 10px et non 9 : l'interlignage donne 25,6px de haut, donc 9px de réserve
	   plafonnaient à 43,6 — mesuré, et sous le seuil. */
	.fi-footer__links a,
	.fi-footer__col a {
		padding-block: 10px;
	}

	/* La gouttière entre les liens du pied se retire dans la section du pied,
	   APRÈS la règle qui la pose : écrite ici, elle perdait (voir « Le pied au
	   doigt, sous 64em »). */

	.fi-brand {
		min-block-size: 44px;
		align-items: center;
	}

	/* Entre le repli en menu burger (~600px) et 1024px, la navigation reste
	   horizontale avec des liens de 32px de haut — c'est exactement l'iPad en
	   paysage. On élargit la zone cliquable ; l'en-tête gagne 12px, que la variable
	   --fi-header-h mesurée par ui.js répercute d'elle-même sur le hero. */
	.fi-header .wp-block-navigation-item__content {
		/* 9px : la boîte du lien fait 26px, pas 32 — les 32 relevés incluaient
		   l'interlignage du conteneur. Mesuré après coup, pas déduit. */
		padding-block: 9px;
	}
}

/* ═══════════════════════════════════════════════════════════════════
   PIED DE PAGE
   ═══════════════════════════════════════════════════════════════════ */

.fi-footer {
	position: relative;
	background: var(--fi-color-ink);
	color: var(--fi-color-on-dark);
	padding-block: clamp(3rem, 6vw, 4.5rem) var(--fi-space-l);
	/* ⚠️ 14/09 — LA GOUTTIÈRE MANQUAIT. Le pied de page est une partie de gabarit
	   et non une bande « constrained » : il ne reçoit pas la classe
	   has-global-padding des sections. Son conteneur (.fi-footer__inner) est borné
	   à la largeur de contenu et centré — au-delà de 1240 px le centrage créait la
	   marge, mais en dessous le conteneur prenait toute la largeur et le texte
	   touchait le bord de l'écran (0 px à 1024, 768 et 390, contre 24 px pour le
	   reste de la page). Même variable que les sections : à 1440 le calcul redonne
	   exactement 100 px, rien n'y bouge. */
	padding-inline: var(--wp--style--root--padding-left) var(--wp--style--root--padding-right);
}

.fi-footer::before {
	content: "";
	position: absolute;
	inset-block-start: 0;
	inset-inline: 0;
	block-size: 2px;
	background: linear-gradient(
		to right,
		var(--fi-color-accent-on-dark),
		color-mix(in srgb, var(--fi-color-accent-on-dark) 12%, transparent)
	);
}

.fi-footer .fi-footer__inner {
	max-inline-size: var(--fi-container-max);
	margin-inline: auto;
}

.fi-footer__top { margin-block-end: clamp(2rem, 4vw, 3rem); }

/* 10/10 — Le même verrou que l'en-tête, à toutes les largeurs : FIRALIS / GROUP
   empilé en capitales (`stack="1"` dans parts/footer.html), vague de 34px. Le
   pied montrait encore « Firalis Group » sur une ligne, en casse courante : deux
   logos pour une même marque, sur une même page.
   La vague plus haute abaissait la ligne de base du verrou, posé dans le
   paragraphe que WordPress enroule autour du shortcode : +2px de ligne. Aligné
   en haut, comme les liens plus bas. */
.fi-footer .fi-brand { vertical-align: top; }
.fi-footer .fi-brand__mark { block-size: 34px; }

/* La signature officielle du groupe, composée comme sur la carte de visite :
   capitales espacées sous le logo, pas une phrase courante. Elle remplace un
   texte qui reprenait mot pour mot le titre du hero. */
.fi-footer__signature {
	max-inline-size: 34ch;
	margin-block: var(--fi-space-s) 0;
	color: var(--fi-color-on-dark-muted);
	font-family: var(--fi-font-mono);
	font-size: 0.72rem;
	font-weight: 500;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	line-height: 1.75;
}

.fi-footer__cols {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(12rem, 100%), 1fr));
	gap: var(--fi-space-l);
	align-items: start;
}

/* 10/10 — Sous 40em, « Companies » et « Group » côte à côte, « Contact » en
   pleine largeur dessous. Les trois listes empilées faisaient du pied une
   colonne de 1 231px à 390, près d'un écran et demi. À 320, chaque piste garde
   124px ; « All companies » et « What we offer », les libellés les plus longs,
   en demandent 101 et 100 (mesuré). */
@media (max-width: 40em) {
	.fi-footer__cols {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		column-gap: var(--fi-space-m);
	}

	.fi-footer__col:last-child { grid-column: 1 / -1; }
}

.fi-footer__title {
	margin-block: 0 var(--fi-space-s);
	font-family: var(--fi-font-mono);
	font-size: 0.66rem;
	font-weight: 500;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--fi-color-on-dark-muted);
}


.fi-footer__links {
	margin: 0;
	padding: 0;
	list-style: none;
	font-size: var(--fi-size-step-0);
	line-height: 1.6;
}

.fi-footer__links li + li { margin-block-start: var(--fi-space-2xs); }

.fi-footer__links a {
	display: inline-flex;
	align-items: center;
	gap: var(--fi-space-2xs);
	/* ⚠️ 10/10 — Sans cela, la pastille décalait les rangées d'une colonne à
	   l'autre. Une boîte « inline-flex » se pose sur la ligne de base de son
	   PREMIER élément : ici le ::before, vide, dont la base est le bord bas. Posée
	   plus bas que le texte, la boîte grandissait la ligne : 27,3px contre 25,6
	   dans « Group », et « Lodiag » finissait 7px sous « News », sur la même
	   rangée. Alignée en haut, elle ne fait plus que sa hauteur de ligne. */
	vertical-align: top;
}

/* Pastille de la société : décorative, aucun texte, aucune information — le nom
   est juste à côté.

   Elle porte le SECOND TON de la vague, pas la couleur de marque. Sur le navy du
   pied de page le rapport s'inverse, c'est la règle de docs/10-charte-graphique.md.
   Mesuré : en couleur de marque, Lodiag tombe à 2.06:1 et Amoneta à 2.95 quand
   Firalis tient 3.61 — sur cinq lignes de même rang, une pastille plus faible se
   lit comme un raté, pas comme une couleur. Au second ton les cinq se tiennent
   entre 6.42 et 8.56:1. */
.fi-footer__links a::before {
	content: "";
	inline-size: 7px;
	block-size: 7px;
	border-radius: 50%;
	background: var(--fi-c-light);
	flex: 0 0 auto;
}

/* ⚠️ Le garde-fou visait le LIEN, alors que firalis_group_company_vars() pose la
   variable sur la PUCE. Il matchait donc toujours, et la pastille n'a jamais pu
   s'afficher depuis qu'elle a été écrite — la feuille décrivait une fonctionnalité
   morte. Corrigé le 25/08 en visant la puce.
   Il sert toujours : la ligne « All companies » qui ferme la colonne n'a pas de
   couleur de société, et ne doit pas prendre de pastille. */
.fi-footer__links li:not([style*="--fi-c"]) a::before,
.fi-footer__links--plain a::before { display: none; }

/* Dernière ligne de la colonne « Companies » : l'index. C'est le seul lien du
   site vers /our-companies/ depuis que l'onglet a quitté le menu (25/08), et il
   est présent sur TOUTES les pages — ce que l'annuaire du hero n'est pas, lui
   qui ne vit que sur l'accueil. Détaché du filet et atténué : il ne fait pas
   nombre avec les cinq sociétés, il les rassemble. */
.fi-footer__links li.fi-footer__all {
	margin-block-start: var(--fi-space-s);
	padding-block-start: var(--fi-space-2xs);
	border-block-start: 1px solid var(--fi-color-line-dark);
}

.fi-footer__links .fi-footer__all a { color: var(--fi-color-on-dark-muted); }
.fi-footer__links .fi-footer__all a:hover { color: var(--fi-color-accent-on-dark); }

.fi-footer a {
	color: var(--fi-color-on-dark);
	text-decoration: none;
	text-underline-offset: 0.3em;
	transition: color 0.18s ease;
}

.fi-footer a:hover { color: var(--fi-color-accent-on-dark); text-decoration: underline; }

.fi-footer a:focus-visible {
	outline: 2px solid var(--fi-color-accent-on-dark);
	outline-offset: 3px;
}

.fi-footer__text {
	margin-block: 0 var(--fi-space-2xs);
	color: var(--fi-color-on-dark-muted);
	font-size: var(--fi-size-step-0);
	line-height: 1.6;
}

.fi-footer__bar {
	display: flex;
	flex-wrap: wrap;
	justify-content: space-between;
	gap: var(--fi-space-s) var(--fi-space-l);
	margin-block-start: clamp(2rem, 4vw, 3rem);
	padding-block-start: var(--fi-space-m);
	border-block-start: 1px solid var(--fi-color-line-dark);
}

.fi-footer__legal {
	margin: 0;
	color: var(--fi-color-on-dark-muted);
	font-size: var(--fi-size-step--1);
}

/* ── Le pied au doigt, sous 64em ─────────────────────────────────────
   ⚠️ 10/10 — Ces règles vivent ICI, après les règles de base du pied, et non
   dans « Cibles tactiles » plus haut. Le retrait de la gouttière entre les liens
   y était écrit AVANT `.fi-footer__links li + li` : même spécificité, la règle
   la plus basse gagnait et la gouttière revenait — 8px mesurés au lieu de 0,
   48px de trop à 768 et 1024. Ici l'ordre suffit, sans !important ni sélecteur
   alourdi. La réserve de 10px des liens, elle, reste là-haut : rien ne la
   conteste. */
@media (max-width: 64em) {
	.fi-footer__links li + li { margin-block-start: 0; }

	/* « Contact » prend le pas des deux autres colonnes. Ses deux lignes sont des
	   paragraphes, pas des liens de liste : sans la réserve des liens,
	   « Huningue, France » finissait 10px au-dessus de « Firalis » et de « What we
	   offer », et « Contact the group » 30px au-dessus de leur deuxième rangée, à
	   768 comme à 1024. Chaque ligne fait désormais 45,6px, comme les autres. */
	.fi-footer__text {
		margin-block-end: 0;
		padding-block: 10px;
	}

	/* Le lien était resté « inline » : sa réserve ne s'ajoutait qu'à sa boîte de
	   texte, 40px mesurés. En bloc en ligne il couvre toute la rangée, et la
	   marge négative le garde dans son paragraphe. */
	.fi-footer__text a {
		display: inline-block;
		padding-block: 10px;
		margin-block: -10px;
	}

	/* La barre légale avait échappé à la règle : 18px de haut. Même procédé,
	   47px de zone et pas un pixel de mise en page en plus. */
	.fi-footer__bar a {
		display: inline-block;
		padding-block: 13px;
		margin-block: -13px;
	}
}

/* ── Dès 70em : la marque entre dans la rangée des colonnes ──────────
   10/10 — Au-dessus des listes, le logo et sa signature tenaient seuls une
   rangée de 142px, vide sur les trois quarts de sa largeur. Sur la grille de 12
   du site, 3 + 3 + 3 + 3 : la marque prend la première colonne, les trois listes
   les suivantes. Les deux grilles portent le même écart (--fi-space-l) : chaque
   liste fait exactement trois pistes et tombe sur les lignes de la grille.
   Sous 70em, palier « bureau » du site, la marque reste au-dessus. */
@media (min-width: 70em) {
	.fi-footer .fi-footer__inner {
		display: grid;
		grid-template-columns: repeat(12, minmax(0, 1fr));
		column-gap: var(--fi-space-l);
	}

	/* En grille, les marges ne fusionnent plus : celle que WordPress pose entre
	   frères (19,2px) réapparaîtrait au-dessus des listes. La barre garde la
	   sienne. */
	.fi-footer .fi-footer__top,
	.fi-footer .fi-footer__cols { margin-block-start: 0; }

	.fi-footer .fi-footer__top {
		grid-column: 1 / span 3;
		margin-block-end: 0;
	}

	.fi-footer .fi-footer__cols {
		grid-column: 4 / -1;
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}

	.fi-footer .fi-footer__bar { grid-column: 1 / -1; }
}

/* ═══════════════════════════════════════════════════════════════════
   Correctifs issus de la review du 17/08/2026
   ═══════════════════════════════════════════════════════════════════ */

/* Conformité GCLP : sortie du tableau des certificats, l'EMA et l'OMS
   ne certifient pas et n'émettent aucune référence. */
.fi-compliance {
	margin-block-start: var(--fi-space-l);
	padding-block-start: var(--fi-space-m);
	border-block-start: 1px solid var(--fi-color-line-strong);
}

.fi-compliance h3 {
	margin-block: 0 var(--fi-space-2xs);
	font-family: var(--fi-font-mono);
	font-size: 0.66rem;
	font-weight: 500;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--fi-color-muted);
}

.fi-compliance ul { margin: 0; padding: 0; list-style: none; }

.fi-compliance li {
	color: var(--fi-color-muted);
	font-size: var(--fi-size-step-0);
	line-height: 1.6;
}

.fi-compliance strong,
.fi-qt__holder { color: var(--fi-color-ink); font-weight: 600; }
.fi-qt__holder { font-family: var(--fi-font-mono); font-size: 0.76rem; font-weight: 400; }

/* ── La page /news/ n'avait aucune règle : l'en-tête collait sous le
      menu et la pagination serait apparue sans style au 11e article. ── */

.fi-archive {
	padding-block: clamp(3rem, 7vw, 5.5rem) clamp(4rem, 9vw, 7rem);
}

.fi-archive > .wp-block-group.fi-archive__head {
	max-inline-size: min(38rem, 100%);
	margin-block-end: clamp(2rem, 5vw, 3.5rem);
	margin-inline-start: max(0px, calc((100% - var(--fi-container-max)) / 2)) !important;
	margin-inline-end: auto !important;
}

.fi-archive__head > * { margin-block-start: 0; }

.fi-archive h1 {
	margin-block: 0 var(--fi-space-m);
	font-size: var(--fi-size-step-4);
	line-height: 1.06;
}

/* La liste est le composant de l'accueil : on neutralise seulement son cadre. */
.fi-archive .fi-news {
	background: transparent;
	padding-block: 0;
	border-bottom: 0;
}

.fi-pagination {
	margin-block-start: clamp(2rem, 5vw, 3rem);
	padding-block-start: var(--fi-space-m);
	border-block-start: 1px solid var(--fi-color-line);
	gap: var(--fi-space-m);
	font-family: var(--fi-font-display);
	font-size: var(--fi-size-step-0);
	font-weight: 600;
}

.fi-pagination a { color: var(--fi-color-brand); text-decoration: none; }
.fi-pagination a:hover { text-decoration: underline; text-underline-offset: 0.35em; }
.fi-pagination .page-numbers.current { color: var(--fi-color-muted); }

/* ── L'en-tête était cassé sur toute la bande 600-767px : le menu
      déroulant de WordPress bascule à 600, la navigation en ligne a
      besoin de 768. On force le déroulant jusqu'à 48em. ── */

/* Seuil mesuré, pas deviné. Historique des mesures, parce que chaque entrée
   ajoutée le déplace :
     6 entrées, « What we do »     → tient à 800px, seuil posé à 51em (816px)
     7 entrées, « What we offer »  → tient à 915px, seuil posé à 59em (944px)
     7 entrées, « Events » (09/10/2026, « Team » passé sous « About » la
       veille) → une seule rangée à 944px, en-tête à 97px, 140px libres
       entre la marque et le menu : seuil inchangé
     6 entrées, « News & Events » (10/10/2026, News et Events réunis en
       sous-menu : un libellé plus long et un chevron de plus) → une seule
       rangée à 944px, .fi-header__inner à 73px avant comme après, 110px
       libres (141 la veille) : seuil inchangé
     5 rubriques, sélecteur de langue SORTI du menu (26/10/2026 : globe +
       code + chevron entre le menu et « Contact », filet compris) → une
       rangée dès 946px ; à 944 la barre passait sur deux rangées (rattrapée
       par le garde-fou `fi-nav-tight` de ui.js, pas sans JavaScript) :
       seuil posé à 61em (976px), 28px libres à 976
   Entre 816 et 915 la barre se cassait en DEUX rangées : l'en-tête passait de
   73 à 104px de haut, sans jamais déborder — donc invisible pour shot.sh, qui
   n'audite que le débordement horizontal. Mesuré au CDP, rangée par rangée.
   La marge (29px) absorbe les variations de rendu des polices.
   ⚠️ À remesurer si une entrée est ajoutée ou renommée.
   Les deux côtés sont déclarés, sinon l'ordre de la feuille décide. */
@media (min-width: 61em) {
	.fi-header .wp-block-navigation__responsive-container-open {
		display: none;
	}
}

@media (max-width: 60.99em) {
	.fi-header .wp-block-navigation__responsive-container:not(.has-modal-open) {
		display: none;
	}

	.fi-header .wp-block-navigation__responsive-container-open {
		display: flex;
	}
}

.fi-brand__name { white-space: nowrap; }

/* Le menu mobile ignorait la palette : noir pur sur blanc pur. */
.fi-header .wp-block-navigation__responsive-container.has-modal-open {
	background: var(--fi-color-surface);
	color: var(--fi-color-text);
}

/* 10/10/2026 — Le libellé-bouton de « News & Events » (inc/nav.php) aussi : il
   sortait en noir pur, mesuré, à côté des liens en encre. */
.fi-header .wp-block-navigation__responsive-container.has-modal-open a,
.fi-header .wp-block-navigation__responsive-container.has-modal-open .fi-nav__parent {
	color: var(--fi-color-ink);
}

/* ── Sans JavaScript le motif réservait jusqu'à 300px de vide. ── */

.no-js .fi-motif-wrap { display: none; }

/* Les études sont deux, pas cinq : deux colonnes fixes dès 40em. */
.fi-co--studies { grid-template-columns: 1fr; }

@media (min-width: 40em) {
	.fi-co--studies { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.fi-co--studies .fi-co__item:hover { border-color: var(--fi-color-brand); }
.fi-co--studies .fi-co__go { color: var(--fi-color-brand); }
.fi-co--studies .fi-co__go--off { color: var(--fi-color-muted); }

/* ── La grille des sociétés laissait une carte orpheline entre 1024
      et 1199px. Cinq cartes : 2 colonnes, puis 5 d'un coup. ── */

.fi-co { grid-template-columns: repeat(auto-fit, minmax(min(13rem, 100%), 1fr)); }

@media (min-width: 48em) and (max-width: 74.99em) {
	.fi-co { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 75em) {
	.fi-co { grid-template-columns: repeat(5, minmax(0, 1fr)); }
}

/* ── prefers-reduced-motion ne couvrait que 3 animations sur 11.
      Les transformations au survol sont précisément ce que ces
      utilisateurs suppriment. ── */

@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}
}

/* ═══════════════════════════════════════════════════════════════════
   EN-TÊTE EN CARTE — variante 5a de la maquette
   ═══════════════════════════════════════════════════════════════════ */

/* Le bandeau devient une carte flottante posée sur le contenu. L'enveloppe garde
   la stickiness (voir plus haut), la carte garde sa marge : le contenu défile
   VISIBLEMENT autour d'elle, c'est tout l'effet. */
.fi-header--card {
	background: transparent;
	border-block-end: 0;
	padding-block: var(--fi-space-xs);
	padding-inline: clamp(var(--fi-space-s), 3vw, var(--fi-space-xl));
}

/* Le flou du bandeau plein n'a plus lieu d'être : il est repris par la carte. */
.fi-header--card::after {
	display: none;
}

.fi-header--card .fi-header__inner {
	position: relative;
	padding: 0.7rem 0.8rem 0.7rem 1.25rem;
	border: 1px solid var(--fi-color-line);
	border-radius: var(--fi-radius-l);
	/* Le fond et le flou sont portés par ::before, pas par cette boîte : un
	   « backdrop-filter » ferait d'elle le bloc conteneur du menu mobile de
	   WordPress (position: fixed, inset: 0), qui se résoudrait sur les 60px de
	   la carte au lieu du viewport. Même piège que sur .fi-header, même parade. */
	background: transparent;
}

.fi-header--card .fi-header__inner::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	border-radius: inherit;
	background: color-mix(in srgb, var(--fi-color-surface) 92%, transparent);
	backdrop-filter: saturate(180%) blur(12px);
	-webkit-backdrop-filter: saturate(180%) blur(12px);
	transition: background-color 0.3s ease, backdrop-filter 0.3s ease;
	box-shadow:
		0 1px 2px color-mix(in srgb, var(--fi-color-ink) 7%, transparent),
		0 8px 24px color-mix(in srgb, var(--fi-color-ink) 7%, transparent);
	pointer-events: none;
}

/* La carte s'ouvre — mais SEULEMENT au-dessus du hero, où le shader du fond
   remonte sous elle. On doit le deviner, pas le lire : 92 % le masquait tout à
   fait, 70 % laissait apparaître la forme du drapé et donnait l'impression que
   l'en-tête bougeait. À 78 %, avec le flou porté à 18px, il ne reste qu'un souffle
   de couleur.

   La bascule est posée par ui.js et retirée dès que la bande d'ouverture passe
   sous l'en-tête. C'est nécessaire : une valeur unique ne peut pas convenir aux
   deux régimes — assez translucide pour laisser voir le shader, la carte vire au
   gris sale dès qu'elle survole une des trois bandes navy de la page (mesuré :
   78 % de surface sur #0C1B2A donne #D0D3D6).

   Le contraste est tenu dans tous les cas : le ton le plus soutenu du shader est
   un mélange à 50 % de « wash » sur la surface ; à travers 78 % de blanc, le texte
   courant reste au-dessus de 14:1 et les libellés atténués au-dessus de 5:1. */
.is-over-hero .fi-header--card .fi-header__inner::before {
	background: color-mix(in srgb, var(--fi-color-surface) 78%, transparent);
	backdrop-filter: saturate(180%) blur(18px);
	-webkit-backdrop-filter: saturate(180%) blur(18px);
}

/* ── Le verrou de marque, empilé ─────────────────────────────────── */

.fi-header--card .fi-brand__mark {
	block-size: 34px;
	inline-size: auto;
}

.fi-brand__lockup {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 1px;
	font-family: var(--fi-font-display);
	font-weight: 700;
	line-height: 1;
	color: var(--fi-color-ink);
}

.fi-brand--stack .fi-brand__name {
	font-size: 1.1875rem;
	font-weight: 700;
	letter-spacing: -0.005em;
	text-transform: uppercase;
}

.fi-brand__unit {
	font-size: 0.72rem;
	letter-spacing: 0.2em;
	text-transform: uppercase;
	color: inherit;
}

.fi-brand--light .fi-brand__lockup {
	color: var(--fi-color-on-dark);
}

/* ── L'appel à l'action passe en plein ───────────────────────────── */

.fi-header--card .fi-header__cta .wp-block-button__link {
	padding: 0.65rem 1.25rem;
	border-radius: var(--fi-radius-m);
	border-color: var(--fi-color-brand);
	background: var(--fi-color-brand);
	color: var(--fi-color-on-brand);
	font-weight: 500;
}

.fi-header--card .fi-header__cta .wp-block-button__link:hover {
	border-color: var(--fi-color-brand-deep);
	background: var(--fi-color-brand-deep);
}

@media (max-width: 47.9375em) {
	.fi-header--card .fi-header__inner {
		padding: 0.55rem 0.6rem 0.55rem 0.9rem;
	}
}

/* Sous 360px, la carte ne tient plus la marque, le bouton du menu et
   « Contact » sur une rangée. Mesuré le 09/10 à 320 : 294px de contenu pour
   262 disponibles — le bouton sortait de la carte et la page débordait de 5px.
   On resserre les deux espacements et le rembourrage latéral du bouton
   (48px rendus) : la cible de 44px du menu et la hauteur du bouton ne changent
   pas, et rien ne bouge à partir de 360. */
@media (max-width: 22.4375em) {
	.fi-header--card .fi-header__inner,
	.fi-header--card .fi-header__right {
		gap: var(--fi-space-2xs);
	}

	.fi-header--card .fi-header__cta .wp-block-button__link {
		padding-inline: var(--fi-space-xs);
	}
}

/* ═══════════════════════════════════════════════════════════════════
   HERO « WORDMARK » — variante 5a
   Le nom du groupe en très grand, un champ radial de filets derrière,
   deux cartouches épinglés en diagonale, la promesse en bas à droite.
   ═══════════════════════════════════════════════════════════════════ */

.fi-heroW {
	position: relative;
	isolation: isolate;
	overflow: clip;
	background: var(--fi-color-surface);
	padding-block: clamp(2.5rem, 5vw, 4rem) clamp(2rem, 4vw, 3rem);
	border-bottom: 1px solid var(--fi-color-line);
}

/* La mise en page « constrained » de WordPress plaque un max-width et des marges
   automatiques sur CHAQUE enfant direct : le champ de filets doit s'en extraire
   pour couvrir toute la bande. */
.fi-heroW > .fi-heroW__rings {
	position: absolute;
	inset: 0;
	z-index: 0;
	max-inline-size: none !important;
	margin: 0 !important;
	pointer-events: none;
}

.fi-heroW__rings svg {
	display: block;
	inline-size: 100%;
	block-size: 100%;
}

/* ── Le champ radial ─────────────────────────────────────────────── */

/* Aucune couleur dans le SVG : `fill="none"` y est un attribut de présentation,
   donc battu par la moindre règle CSS. Tout vient des tokens. */
.fi-rings__line {
	stroke: var(--fi-color-line);
	stroke-width: 1;
}

.fi-rings__dash {
	stroke: color-mix(in srgb, var(--fi-color-line) 75%, transparent);
	stroke-width: 1;
	stroke-dasharray: 2 10;
}

.fi-rings__dash2 {
	stroke: color-mix(in srgb, var(--fi-color-line) 55%, transparent);
	stroke-width: 1;
	stroke-dasharray: 1 7;
}

.fi-rings__hair {
	stroke: color-mix(in srgb, var(--fi-color-line) 45%, transparent);
	stroke-width: 1;
}

.fi-rings__dot {
	fill: var(--fi-color-line-strong);
}

.fi-rings__dot--live {
	fill: var(--fi-color-wash);
	r: 5;
}

/* ── Un point par société, sur le cercle extérieur ──────────────── */

/* Cinq marques régulièrement réparties sur une même orbite : c'est le modèle du
   groupe dit en une image. Le point porte la couleur pleine, le halo la même
   couleur très diluée — sans lui, six pixels de couleur sur un fond blanc ne se
   voient pas à distance de lecture.

   Aucune information n'est portée ici : les cinq sociétés sont nommées en toutes
   lettres dans l'annuaire juste dessous, et l'enveloppe du champ est aria-hidden.
   La couleur ne fait qu'y faire écho (WCAG 1.4.1). */
.fi-rings__seed {
	fill: var(--fi-c, var(--fi-color-line-strong));
}

.fi-rings__halo {
	fill: var(--fi-c, var(--fi-color-line-strong));
	opacity: 0.16;
}

/* Le rayon est un attribut de présentation, donc pilotable en CSS — et il DOIT
   l'être ici : le champ du hero « index » est cinq fois plus petit que celui du
   hero « wordmark », les rayons du SVG y donneraient des points de 2px. On les
   redimensionne dans l'espace de la viewBox, pas en pixels d'écran, pour que le
   motif reste identique à toutes les largeurs. */
.fi-heroX .fi-rings__seed { r: 23; }
.fi-heroX .fi-rings__halo { r: 52; }

/* Deux rotations lentes en sens inverse : à 3°/s, l'œil ne voit pas un mouvement,
   il voit que l'image n'est pas figée. */
.fi-rings__out,
.fi-rings__in {
	transform-box: view-box;
	transform-origin: 720px 424px;
}

.fi-rings__out { animation: fi-rings-spin 120s linear infinite; }
.fi-rings__in  { animation: fi-rings-spin 90s linear infinite reverse; }

@keyframes fi-rings-spin {
	to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
	.fi-rings__out,
	.fi-rings__in { animation: none; }
}

/* ── L'illustration centrale ─────────────────────────────────────── */

/* Elle prend l'emplacement que la maquette réservait à un PNG détouré : au centre
   du champ radial, SOUS le texte (z-index 1, les anneaux sont à 0). Le verrou
   typographique la recouvre donc en partie à gauche, comme dans la maquette.
   Décorative : alt vide côté markup, `pointer-events: none` ici — elle ne doit
   intercepter aucun clic destiné à ce qui passe au-dessus. */
.fi-heroW > .fi-heroW__art {
	position: absolute;
	/* 46% et non 50% : le centre optique de l'illustration est plus bas que son
	   centre géométrique (le socle du microscope), et 4% suffisent à dégager
	   le cartouche des certifications qui passe juste dessous. */
	inset-block-start: 46%;
	inset-inline-start: 50%;
	z-index: 1;
	inline-size: clamp(16rem, 32vw, 30rem);
	margin: 0 !important;
	max-inline-size: none !important;
	transform: translate(-50%, -50%);
	pointer-events: none;
}

.fi-heroW__art img {
	display: block;
	inline-size: 100%;
	block-size: auto;
}

/* ── La grille ───────────────────────────────────────────────────── */

.fi-heroW__grid {
	position: relative;
	z-index: 2;
	display: grid;
	gap: clamp(1.75rem, 4vw, 2.5rem);
}

/* Marge haute que WordPress ajoute à tout bloc suivant un frère. */
.fi-heroW__grid > * {
	margin-block-start: 0;
}

/* ── Le verrou typographique ─────────────────────────────────────── */

.fi-heroW__wordmark {
	margin: 0;
	display: flex;
	flex-direction: column;
	font-family: var(--fi-font-display);
	font-weight: 700;
	line-height: 0.88;
	color: var(--fi-color-ink);
	text-wrap: nowrap;
}

/* EXCEPTION ASSUMÉE à l'échelle. Le hero-wordmark n'est pas un titre : c'est une
   composition typographique où le mot, l'unité et la promesse sont dimensionnés
   les uns PAR RAPPORT AUX AUTRES pour tenir sur une ligne, pas selon un rang de
   hiérarchie. Les router sur les pas casserait l'ajustement optique sans rien
   apporter — aucun autre élément du site ne doit s'aligner sur eux.
   Les trois tailles ci-dessous et .fi-route__n sont les SEULES tailles de niveau
   titre encore écrites en dur dans cette feuille. Ne pas en ajouter d'autres. */
.fi-heroW__word {
	font-size: clamp(3rem, 0.9rem + 8.9vw, 9.25rem);
	letter-spacing: -0.045em;
	text-transform: uppercase;
}

.fi-heroW__unit {
	font-size: clamp(1.2rem, 0.35rem + 3.5vw, 3.625rem);
	letter-spacing: 0.115em;
	text-transform: uppercase;
	color: var(--fi-color-muted);
}

.fi-heroW__tag {
	margin: clamp(1.25rem, 2.5vw, 1.75rem) 0 0;
	max-inline-size: 24ch;
	font-size: var(--fi-size-step-0);
	line-height: 1.85;
	letter-spacing: 0.14em;
	color: var(--fi-color-text);
	text-wrap: pretty;
}

/* ── Les cartouches épinglés ─────────────────────────────────────── */

.fi-heroW__note {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: var(--fi-space-2xs);
	padding-inline-start: 2.5rem;
	max-inline-size: 26rem;
}

/* Le « + » de la maquette : une pastille décorative, donc en CSS et pas en markup —
   rien à lire pour un lecteur d'écran, rien à traduire pour l'éditeur. */
.fi-heroW__note::before {
	content: "+";
	position: absolute;
	inset-block-start: 0.15em;
	inset-inline-start: 0;
	display: grid;
	place-items: center;
	inline-size: 1.5rem;
	block-size: 1.5rem;
	border-radius: 50%;
	background: var(--fi-color-brand);
	color: var(--fi-color-on-brand);
	font-family: var(--fi-font-mono);
	font-size: 0.95rem;
	line-height: 1;
}

.fi-heroW__noteT {
	margin: 0;
	font-family: var(--fi-font-display);
	font-size: var(--fi-size-step-1);
	font-weight: 700;
	letter-spacing: -0.012em;
	line-height: 1.2;
	color: var(--fi-color-ink);
}

/* ── Cartouches cliquables ───────────────────────────────────────
   Le « + » annonçait une interaction qui n'existait pas. Chaque cartouche
   mène désormais à la section qui le développe.

   Le texte utile reste TOUJOURS visible : seul le libellé de destination
   se révèle. Cacher de l'information derrière un survol la rend
   inatteignable au doigt et au clavier — ici il n'y a rien à découvrir,
   seulement une destination à annoncer. */
.fi-heroW__go {
	margin: 0;
	font-family: var(--fi-font-mono);
	font-size: 0.68rem;
	font-weight: 500;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	line-height: 1.4;
}

.fi-heroW__go a {
	color: var(--fi-color-ink);
	text-decoration: none;
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
}

.fi-heroW__go a::before {
	content: "→" / "";
	font-size: 0.9rem;
	transition: transform 0.22s cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* Lien étendu : toute la surface du cartouche est cliquable, une seule cible
   pour les lecteurs d'écran. Même technique que les panneaux du bandeau de
   clôture. */
.fi-heroW__go a::after {
	content: "";
	position: absolute;
	inset: -0.75rem;
	border-radius: var(--fi-radius-m);
}

.fi-heroW__note:hover .fi-heroW__go a::before,
.fi-heroW__note:focus-within .fi-heroW__go a::before {
	transform: translateX(3px);
}

.fi-heroW__note:hover .fi-heroW__go {
	color: var(--fi-color-ink);
}

/* La pastille répond, sinon rien ne dit que le « + » était le signal. */
.fi-heroW__note:hover::before,
.fi-heroW__note:focus-within::before {
	transform: scale(1.12);
}

.fi-heroW__note::before {
	transition: transform 0.22s cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* L'anneau de focus ceint le cartouche entier, pas les huit mots du lien. */
.fi-heroW__note:has(a:focus-visible) {
	outline: 2px solid var(--fi-color-brand);
	outline-offset: 0.75rem;
	border-radius: var(--fi-radius-m);
}

.fi-heroW__note:has(a:focus-visible) .fi-heroW__go a:focus-visible {
	outline: none;
}

/* Sur un appareil sans survol, la destination ne se révèle jamais : elle est
   donc affichée en permanence. C'est le défaut, et le survol est l'exception. */
@media (hover: hover) {
	/* Opacité SEULE, jamais de « transform » ici : un élément transformé devient
	   bloc conteneur pour ses descendants en position absolue, et le lien étendu
	   se retrouvait confiné à cette ligne au lieu de couvrir le cartouche —
	   mesuré 400×44 au lieu de 440×134. Le mouvement est porté par la flèche. */
	.fi-heroW__go {
		opacity: 0;
		transition: opacity 0.22s ease;
	}

	.fi-heroW__note:hover .fi-heroW__go,
	.fi-heroW__note:focus-within .fi-heroW__go {
		opacity: 1;
	}
}

.fi-heroW__noteD {
	margin: 0;
	font-size: var(--fi-size-step-0);
	line-height: 1.55;
	color: var(--fi-color-text);
	text-wrap: pretty;
}

.fi-heroW__std {
	margin: 0;
	font-family: var(--fi-font-mono);
	font-size: var(--fi-size-step--1);
	line-height: 1.75;
	letter-spacing: 0.02em;
	color: var(--fi-color-text);
}

.fi-heroW__hold {
	margin: 0;
	font-family: var(--fi-font-mono);
	font-size: 0.66rem;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--fi-color-muted);
}

/* ── La promesse ─────────────────────────────────────────────────── */

.fi-heroW__claim {
	margin: 0;
	font-family: var(--fi-font-display);
	font-weight: 700;
	font-size: clamp(1.9rem, 0.6rem + 4.4vw, 3.875rem);
	line-height: 1;
	letter-spacing: -0.03em;
	text-transform: uppercase;
	color: var(--fi-color-ink);
}

/* ── Les appels à l'action ───────────────────────────────────────── */

/* La flèche est décorative : le « / "" » vide son texte alternatif, sinon les
   lecteurs d'écran annoncent « flèche vers la droite » après chaque libellé. */
.fi-heroW__cta .wp-block-button__link::after {
	content: "  →" / "";
	font-family: var(--fi-font-mono);
	font-weight: 400;
}

/* ── Composition large : la diagonale de la maquette ─────────────── */

@media (min-width: 64em) {
	.fi-heroW__grid {
		grid-template-columns: repeat(12, minmax(0, 1fr));
		grid-template-rows: auto 1fr auto auto;
		column-gap: var(--fi-space-m);
		row-gap: clamp(1.5rem, 3vw, 2.5rem);
		align-items: start;
		min-block-size: clamp(30rem, 66vh, 42rem);
	}

	.fi-heroW__id { grid-column: 1 / 8; grid-row: 1; }

	.fi-heroW__note--a {
		grid-column: 8 / 13;
		grid-row: 1;
		margin-block-start: clamp(3rem, 7vw, 6rem);
	}

	.fi-heroW__note--b {
		grid-column: 1 / 6;
		grid-row: 3;
		justify-self: end;
		text-align: right;
		padding-inline: 0 2.5rem;
	}

	/* Le cartouche de droite se retourne : pastille à droite, texte cadré à droite.
	   C'est ce retournement qui fait lire la diagonale. */
	.fi-heroW__note--b::before {
		inset-inline: auto 0;
	}

	.fi-heroW__note--b .fi-heroW__noteT,
	.fi-heroW__note--b .fi-heroW__std,
	.fi-heroW__note--b .fi-heroW__hold,
	.fi-heroW__note--b .fi-heroW__go {
		align-self: flex-end;
	}

	/* Cartouche retourné : la flèche pointe vers la gauche du bloc, donc elle
	   passe après le libellé. */
	.fi-heroW__note--b .fi-heroW__go a {
		flex-direction: row-reverse;
	}

	.fi-heroW__claim {
		grid-column: 7 / 13;
		grid-row: 3;
		justify-self: end;
		text-align: right;
	}

	.fi-heroW__cta {
		grid-column: 1 / 13;
		grid-row: 4;
		justify-content: center;
	}
}

/* Sous 64em la composition redevient une colonne : les filets passent en arrière-plan
   discret pour ne pas concurrencer un texte qui occupe désormais toute la largeur. */
@media (max-width: 63.9375em) {
	.fi-heroW__rings { opacity: 0.6; }

	/* En colonne, la boîte est bien plus haute que large : « contenu » dans son cadre,
	   le champ se réduirait à une pastille au milieu, qui lit comme un défaut de rendu.
	   On l'agrandit et on le recadre — quelques arcs valent mieux qu'un jeton. */
	.fi-heroW__rings svg {
		position: absolute;
		inset-block-start: 50%;
		inset-inline-start: 50%;
		inline-size: 190%;
		block-size: auto;
		transform: translate(-50%, -50%);
	}

	.fi-heroW__note { max-inline-size: 34rem; }

	/* En colonne, une illustration centrée passerait derrière le texte : elle
	   reprend sa place dans le flux, en tête de bande. */
	.fi-heroW > .fi-heroW__art {
		position: static;
		transform: none;
		inline-size: min(20rem, 72%);
		margin: 0 auto var(--fi-space-m) !important;
	}
}

/* ═══════════════════════════════════════════════════════════════════
   HERO « INDEX » — l'ouverture retenue le 24/08
   Le titre-phrase à gauche, le chapô et les appels à l'action à droite,
   l'annuaire des cinq sociétés en bande de cinq colonnes qui la ferme.
   La bande des normes qui la fermait au 24/08 est autonome depuis le
   27/08 — voir « BANDE DES NORMES » plus haut.
   Portée d'une maquette Claude Design, du sombre au clair.
   ═══════════════════════════════════════════════════════════════════ */

.fi-heroX {
	position: relative;
	isolation: isolate;
	/* Le fond doit remonter SOUS l'en-tête : c'est la bande d'ouverture, elle
	   commence au bord du document, pas sous le bandeau. On ne rogne donc plus
	   qu'à l'horizontale. « visible » avec « clip » est la seule combinaison que
	   la spécification laisse telle quelle — elle ne dégénère pas en « auto »,
	   donc aucune barre de défilement parasite. */
	overflow-x: clip;
	overflow-y: visible;
	background: var(--fi-color-surface);
	padding-block: clamp(2.5rem, 5vw, 4rem) clamp(2rem, 4vw, 3rem);
	border-bottom: 1px solid var(--fi-color-line);

	/* Colonne flexible pour RÉPARTIR la hauteur, pas seulement la réserver.
	   La hauteur minimale plus bas fait déjà tenir le hero dans l'écran, mais tout
	   le surplus s'accumulait sous l'annuaire : mesuré 79px à 1440×900 et 204px à
	   1440×1100, et zéro entre le titre et l'annuaire. On lisait une composition
	   tassée en haut avec une bande de fond morte en dessous. */
	display: flex;
	flex-direction: column;

	/* Le hero et l'en-tête remplissent EXACTEMENT l'écran du lecteur, quel qu'il
	   soit : la bande suivante commence à la ligne de flottaison. Sans règle, la
	   hauteur suivait le contenu et la coupure tombait n'importe où (à 1440×900,
	   le bandeau suivant coupé de 33px).

	   ⚠️ 10/10/2026, demande de Thibault : plus d'aperçu ni de plafond. La règle
	   du 25/08 réservait 4rem d'aperçu de la bande suivante (`--fi-hero-peek`) et
	   plafonnait à 54rem : mesuré, le hero s'arrêtait 64px avant le bas de l'écran
	   à 1440×900, 1512×860 et 1728×1000, 119px à 1920×1080, 339px à 2560×1300 —
	   il ne « prenait pas la hauteur de l'écran ». Sur un écran très haut, le
	   surplus passe entre les appels à l'action et l'annuaire (margin-top: auto
	   plus bas), là où il se lit comme de l'air.

	   « svh » et non « vh » : sur mobile, vh compte la barre d'adresse rétractée
	   et le hero dépasserait d'autant. C'est une hauteur MINIMALE : quand le
	   contenu est plus haut que l'écran (mobile, 1280×720), le contenu gagne. */
	min-block-size: calc(100svh - var(--fi-header-h));
}

/* Marge haute que WordPress ajoute à tout bloc suivant un frère. */
.fi-heroX > * { margin-block-start: 0; }

/* En colonne flexible, un enfant qui porte « margin-inline: auto » — ce que la
   mise en page « constrained » de WordPress pose sur TOUS les enfants directs —
   ne s'étire plus : les marges automatiques absorbent l'espace libre et l'élément
   se réduit à son contenu. La ligne de tête de l'annuaire, en « space-between »,
   se retrouvait ainsi recentrée avec ses deux libellés collés au milieu.
   « inline-size: 100% » lui rend la largeur de ligne ; le max-width la replafonne
   à 1240px et les marges automatiques la recentrent, comme avant. */
.fi-heroX > *:not(.fi-heroX__paper) { inline-size: 100%; }

/* L'annuaire est poussé au bas de la bande : c'est le socle de la composition, et
   le surplus de hauteur passe alors ENTRE les appels à l'action et lui, là où il
   se lit comme de l'air. Quand le contenu dépasse la hauteur minimale — écran bas,
   mobile — la marge automatique retombe à zéro et rien ne bouge. */
.fi-heroX > .fi-heroX__dirhead { margin-block-start: auto; }

/* ── Le fond ─────────────────────────────────────────────────────── */

/* Un shader WebGL « warp » de Paper Shaders, monté par js/hero-paper.js sur cette
   couche. Il tire sa rampe des jetons --fi-color-surface et --fi-color-wash : la
   couleur du fond suit la charte sans qu'aucune valeur soit écrite en JavaScript.

   La mise en page « constrained » de WordPress plaque un max-width et des marges
   automatiques sur chaque enfant direct : la couche doit s'en extraire pour couvrir
   la bande, comme la bande des normes qui la suit.

   Sans WebGL, rien ne se monte : la couche reste vide et la bande garde la surface
   unie du site. Aucun repli à écrire. */
.fi-heroX > .fi-heroX__paper {
	position: absolute;
	inset-block: calc(-1 * var(--fi-header-h)) 0;
	inset-inline: 0;
	z-index: 0;
	max-inline-size: none !important;
	margin: 0 !important;
	overflow: hidden;
	pointer-events: none;
}

.fi-heroX__paper canvas {
	display: block;
	inline-size: 100%;
	block-size: 100%;
}

/* Voile de lisibilité. Le shader est pâle, mais le titre est ce que la page a de
   plus important : on garantit son fond plutôt que d'espérer que le dégradé tombe
   au bon endroit. Il s'efface vers la droite, où il n'y a que le chapô. */
.fi-heroX__paper::after {
	content: "";
	position: absolute;
	inset: 0;
	background: linear-gradient(
		100deg,
		color-mix(in srgb, var(--fi-color-surface) 88%, transparent) 0%,
		color-mix(in srgb, var(--fi-color-surface) 62%, transparent) 42%,
		transparent 82%
	);
}

/* ── L'accroche ──────────────────────────────────────────────────── */

/* Deux colonnes : le titre tient la gauche, le chapô et les boutons la droite.
   Sur 1240px, un titre seul laissait la moitié de la page vide — et la paire
   d'appels à l'action se retrouvait sous le pli sur un portable en paysage. */
.fi-heroX__head {
	position: relative;
	z-index: 2;
	display: grid;
	grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
	gap: clamp(1.5rem, 4vw, 3.5rem);
	align-items: end;
	padding-block: clamp(1.5rem, 4vw, 3rem) clamp(2.5rem, 5vw, 4rem);
}

.fi-heroX__head > * { margin-block-start: 0; }

/* ⚠️ 03/09 — SANS CONSOMMATEUR depuis la revue client (H-1) : le surtitre
   « Biomarker sciences » est retiré du hero, et `fi-heroX` n'est employé que par
   patterns/hero-index.php. La règle est laissée en place — elle ne coûte rien et
   c'est elle qui fait du surtitre une RANGÉE de la grille, donc c'est elle qui
   garantit qu'il n'a laissé aucun écart derrière lui. À supprimer le jour où le
   surtitre est écarté pour de bon. */
.fi-heroX__head .fi-eyebrow {
	grid-column: 1 / -1;
	margin-block-end: 0;
}

.fi-heroX__title {
	margin-block: 0;
	font-size: var(--fi-size-step-5);
	line-height: 1.02;
	letter-spacing: -0.04em;
	font-weight: 700;
	color: var(--fi-color-brand);
}

/* Le chapô reprend la largeur de lecture du site, pas celle de sa colonne.
   ⚠️ 08/10/2026 — Plus de marge basse : elle le séparait des deux boutons, retirés
   à la demande du client (GP-Homepage, p. 1). Le chapô est désormais le dernier
   élément de sa colonne, et `align-items: end` pose son bas sur celui du titre.
   La règle `.fi-heroX__cta` est partie avec les boutons. */
.fi-heroX__lede {
	max-inline-size: min(44ch, 100%);
	margin-block: 0;
	font-size: clamp(1rem, 0.95rem + 0.3vw, 1.12rem);
	line-height: 1.65;
	color: var(--fi-color-muted);
	text-wrap: pretty;
}

/* ── L'annuaire des cinq sociétés ────────────────────────────────── */

.fi-heroX__dirhead {
	position: relative;
	z-index: 2;
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: var(--fi-space-s);
	margin-block: 0 var(--fi-space-xs);
	font-family: var(--fi-font-mono);
	font-size: 0.6875rem;
	font-weight: 500;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--fi-color-muted);
}

/* Les séparateurs sont des BORDURES, pas un fond de grille vu à travers un pixel
   de gouttière. La première version peignait un aplat opaque sur toute la bande :
   le shader du fond y disparaissait complètement, et c'est ce qui a fait échouer
   les premières propositions de fond. Ici, rien n'est peint que les filets. */
.fi-heroX__dir {
	position: relative;
	z-index: 2;
	margin: 0;
	padding: 0;
	list-style: none;
	display: grid;
	grid-template-columns: repeat(5, minmax(0, 1fr));
	border-block: 1px solid var(--fi-color-line);
}

.fi-heroX__co {
	margin: 0;
	background: transparent;
	border-inline-start: 1px solid var(--fi-color-line);
}

/* Première colonne : pas de filet à gauche, le conteneur n'en a pas. Le pas de 5
   suit le nombre de colonnes, et le sélecteur se réécrit à chaque reprise plus
   bas — c'est le prix à payer pour des filets qui ne peignent aucun aplat. */
.fi-heroX__co:nth-child(5n + 1) {
	border-inline-start: 0;
}

/* Au-delà de la première rangée — donc à partir d'une sixième société — le filet
   passe à l'horizontale. */
.fi-heroX__co:nth-child(n + 6) {
	border-block-start: 1px solid var(--fi-color-line);
}

.fi-heroX__link {
	position: relative;
	/* Sans lui, « block-size: 100% » se résout sur la boîte de contenu et les
	   2 × 24px de padding s'ajoutent par-dessus : le lien débordait de 48px sous
	   sa cellule, flèche comprise. Même piège que .fi-offer__link. */
	box-sizing: border-box;
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: var(--fi-space-xs);
	block-size: 100%;
	padding: clamp(1.1rem, 2vw, 1.5rem) clamp(0.9rem, 1.6vw, 1.25rem);
	text-decoration: none;
	color: inherit;
	transition: background 0.24s cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* Le rail de la société se déploie depuis le haut : c'est la seule apparition
   de sa couleur, et elle dit « cette colonne-ci ». Même dispositif que
   l'aiguillage de /contact/, retourné à l'horizontale. */
.fi-heroX__link::before {
	content: "";
	position: absolute;
	inset-block-start: 0;
	inset-inline: 0;
	block-size: 2px;
	background: var(--fi-c);
	transform: scaleX(0);
	transform-origin: left;
	transition: transform 0.24s cubic-bezier(0.22, 0.61, 0.36, 1);
}

.fi-heroX__co:hover .fi-heroX__link,
.fi-heroX__link:focus-visible {
	background: color-mix(in srgb, var(--fi-color-surface) 62%, transparent);
}

.fi-heroX__co:hover .fi-heroX__link::before,
.fi-heroX__link:focus-visible::before {
	transform: scaleX(1);
}

.fi-heroX__mark {
	display: block;
	block-size: 32px;
	inline-size: auto;
	aspect-ratio: 265 / 432;
	flex: 0 0 auto;
}

.fi-heroX__name {
	font-family: var(--fi-font-display);
	font-size: var(--fi-size-step-1);
	font-weight: 600;
	letter-spacing: -0.02em;
	line-height: 1.15;
	color: var(--fi-color-ink);
}

/* ⚠️ 02/10/2026 — 0.92rem → 0.9375rem, soit 14,72 → 15px (docs/74 H-2). La ligne de
   Firalis est passée de 40 à 93 signes avec le lot S-6 (« Innovative biomarkers for
   cardiovascular disease Dx, bioproduction, biobank & clinical trials ») : sur quatre
   lignes à cinq colonnes, ce n'est plus une étiquette mais du texte courant, et
   l'audit (tools/preview/audit.js) le relève en MAJEUR sous 15px. Un quart de pixel,
   mesuré à 1440, 1280, 1100, 1024, 768 et 390 : rangées de la bande à ±2px, flèches
   toujours alignées. Seule la ligne d'Amoneta passe à deux lignes à 768, dans une
   rangée que celle de Firalis tenait déjà sur deux. */
.fi-heroX__service {
	font-size: 0.9375rem;
	line-height: 1.5;
	color: var(--fi-color-muted);
	text-wrap: pretty;
}

/* La flèche est poussée en bas de cellule : les descriptions font une à trois
   lignes selon la société, et alignées sur le texte les flèches formaient un
   escalier. */
.fi-heroX__go {
	margin-block-start: auto;
	padding-block-start: var(--fi-space-2xs);
	color: var(--fi-color-line-strong);
	transition: color 0.24s ease;
}

.fi-heroX__go .fi-arrow {
	display: block;
	inline-size: 1.15rem;
	block-size: 1.15rem;
}

.fi-heroX__co:hover .fi-heroX__go,
.fi-heroX__link:focus-visible .fi-heroX__go {
	color: var(--fi-color-ink);
}

/* ── Reprises ────────────────────────────────────────────────────── */

/* Sous 64em, l'accroche redevient une colonne et l'annuaire passe à deux :
   cinq colonnes de 150px coupent « Innovative biomarkers for neurological
   disease Dx » en six lignes. */
@media (max-width: 64em) {
	.fi-heroX__head {
		grid-template-columns: 1fr;
		align-items: start;
	}

	.fi-heroX__dir { grid-template-columns: repeat(2, minmax(0, 1fr)); }

	/* Le pas des filets suit le nombre de colonnes : deux ici. */
	.fi-heroX__co { border-inline-start: 1px solid var(--fi-color-line); }
	.fi-heroX__co:nth-child(2n + 1) { border-inline-start: 0; }
	.fi-heroX__co:nth-child(n + 3) { border-block-start: 1px solid var(--fi-color-line); }

	/* Cinq sociétés sur deux colonnes laissent une cellule vide. La dernière ligne
	   impaire prend donc toute la largeur — et perd son filet de gauche, puisqu'elle
	   commence à la première colonne. Générique : à six sociétés la règle ne se
	   déclenche plus, à sept elle se redéclenche. */
	.fi-heroX__co:last-child:nth-child(odd) {
		grid-column: 1 / -1;
		border-inline-start: 0;
	}

	/* Le chapô est passé en pleine largeur, mais il s'arrête bien avant le bord :
	   c'est cette marge droite, sur toute la hauteur de l'accroche, qui accueille
	   le champ. Le poser plus bas le faisait passer SOUS les cellules de
	   l'annuaire, qui sont opaques — il disparaissait purement et simplement. */
}

@media (max-width: 40em) {
	.fi-heroX__dir { grid-template-columns: 1fr; }

	/* Une seule colonne : il ne reste que des filets horizontaux. */
	.fi-heroX__co { border-inline-start: 0; border-block-start: 0; }
	.fi-heroX__co:nth-child(n + 2) { border-block-start: 1px solid var(--fi-color-line); }

	/* En colonne unique, la carte redevient une rangée : le nom et le service
	   à gauche, la flèche à droite, comme l'annuaire de /contact/. */
	.fi-heroX__link {
		display: grid;
		grid-template-columns: auto 1fr auto;
		align-items: center;
		gap: var(--fi-space-s);
	}

	.fi-heroX__name { grid-column: 2; }
	.fi-heroX__service { grid-column: 2; }
	.fi-heroX__mark { grid-row: 1 / span 2; }
	.fi-heroX__go { grid-row: 1 / span 2; grid-column: 3; margin-block-start: 0; padding-block-start: 0; }
}

/* ═══════════════════════════════════════════════════════════════════
   PAGE CONTACT
   Trois bandes depuis la revue client du 08/10/2026 : tête, implantation,
   formulaire — blanc, blanc, gris.

   Retirés à la demande du client, CSS compris : les trois guichets
   (« The group answers », .fi-desks / .fi-desk) le 25/08 ; le chapô, le
   standard de tête (.fi-triage*) et la bande sombre des cinq sociétés
   (.fi-router-band, .fi-router, .fi-firm*) le 08/10. Le tri ne tient plus
   que par le menu du formulaire, qui nomme chaque société du groupe — voir
   patterns/contact.php.
   ═══════════════════════════════════════════════════════════════════ */

/* WordPress force « margin-inline: auto » sur tout enfant d'une mise en page
   « constrained ». Un bloc plus étroit que le conteneur se retrouve donc CENTRÉ,
   alors que tout le site est calé à gauche. Le décalage vaut la demi-gouttière,
   pas zéro : c'est ainsi que l'alignement retombe sur celui de l'en-tête.
   Même parade que .fi-archive__head et .fi-hero__content. */
/* « :not(.fi-wash) » : le fond de bande est un enfant direct lui aussi, et ce
   décalage le poussait à 76 px du bord gauche — un canvas qui doit couvrir la
   bande n'a rien à faire dans la grille du contenu. */
.fi-contact-head > *:not(.fi-wash) {
	margin-inline-start: max(0px, calc((100% - var(--fi-container-max)) / 2)) !important;
	margin-inline-end: auto !important;
}

/* Marge haute que WordPress ajoute à tout bloc suivant un frère : elle décale
   les colonnes d'une grille CSS, et les filets ne s'alignent plus. */
.fi-locale__grid > *,
.fi-form-band__grid > * {
	margin-block-start: 0;
}

/* ── 1. La tête de page ──────────────────────────────────────────── */

/* Même ouverture que la tête de /news/ — l'idiome des pages intérieures :
   88px au-dessus à 1440.

   08/10 — Le client a retiré le chapô et le standard de droite : la tête ne
   porte plus qu'un surtitre et le titre, sur toute la largeur. La grille
   chapô / standard est partie avec eux, et le bas de la bande est resserré à
   48px : l'implantation qui suit a sa propre réserve haute (--fi-sec), et les
   112px d'avant s'y ajoutaient — plus de 200px de blanc sous un titre d'une
   ligne.

   L'implantation est blanche elle aussi : sans la bande sombre des sociétés
   entre les deux, rien ne marquait plus la fin de la tête (audit : « même fond
   que la bande précédente et aucun filet »). D'où le filet pleine largeur, le
   même que celui qui sépare les actualités de leurs voisines (.fi-news). */
.fi-contact-head {
	background: var(--fi-color-surface);
	padding-block: clamp(3rem, 7vw, 5.5rem) clamp(var(--fi-space-l), 4vw, var(--fi-space-xl));
}

.fi-contact-head + .fi-locale {
	border-block-start: 1px solid var(--fi-color-line);
}

/* Ni taille ni interlettrage ici : un h1 de page intérieure prend l'échelle du
   thème, la même que celui de /news/.

   Et AUCUNE largeur maximale : « Get in touch with the right team » tient sur
   une ligne dans le conteneur de 1240. « text-wrap: balance », hérité de la
   règle globale des titres, ne s'active que lorsque le texte DOIT se couper :
   en dessous il équilibre les deux lignes au lieu d'en laisser une longue et
   une courte. */
.fi-contact-head__title {
	margin-block: 0;
	line-height: 1.06;
}

/* ── 2. L'implantation ───────────────────────────────────────────── */

/* Elle FERMAIT la page jusqu'au 25/08. Personne ne la lisait : après un
   formulaire, une page est finie. Elle prend la place des trois guichets,
   retirés à la demande du client. */
.fi-locale {
	background: var(--fi-color-surface);
	padding-block: var(--fi-sec);
}

.fi-locale__grid {
	display: grid;
	grid-template-columns: 1fr;
	gap: clamp(2.25rem, 5vw, 3.5rem);
	align-items: start;
}

@media (min-width: 60em) {
	/* La carte prend la colonne la plus large : c'est elle qui répond à la
	   question de la bande, les relevés ne font que la chiffrer. */
	.fi-locale__grid {
		grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
		gap: clamp(3rem, 6vw, 5rem);
	}
}

.fi-locale__grid > *,
.fi-locale__txt > * { margin-block-start: 0; }

.fi-locale__title { margin-block: 0 var(--fi-space-m); }

.fi-locale__d {
	margin: 0 0 clamp(2rem, 4vw, 2.75rem);
	max-inline-size: 42ch;
	font-size: clamp(1rem, 0.95rem + 0.3vw, 1.12rem);
	line-height: 1.65;
	color: var(--fi-color-muted);
	text-wrap: pretty;
}

/* ── les relevés ── */

.fi-place__facts {
	margin: 0;
	display: grid;
}

.fi-place__facts > div {
	display: grid;
	grid-template-columns: minmax(7rem, 10rem) 1fr;
	gap: var(--fi-space-s);
	align-items: baseline;
	padding-block: var(--fi-space-s);
	border-block-start: 1px solid var(--fi-color-line);
}

.fi-place__facts > div:last-child {
	border-block-end: 1px solid var(--fi-color-line);
}

.fi-place__facts dt {
	font-family: var(--fi-font-mono);
	font-size: 0.68rem;
	font-weight: 500;
	letter-spacing: 0.13em;
	text-transform: uppercase;
	color: var(--fi-color-muted);
}

.fi-place__facts dd {
	margin: 0;
	font-family: var(--fi-font-display);
	font-size: var(--fi-size-step-1);
	font-weight: 600;
	letter-spacing: -0.02em;
	color: var(--fi-color-ink);
	font-variant-numeric: tabular-nums;
}

@media (max-width: 30em) {
	.fi-place__facts > div { grid-template-columns: 1fr; gap: 0.25rem; }
}

/* ── les portes d'entrée ─────────────────────────────────────────────
   Sur TOUTE la largeur, sous la grille, et non empilées sous les relevés :
   à 1440 la colonne de gauche dépassait alors la carte de 170 px et la bande
   se terminait en escalier. Elles la ferment, ce qui est aussi leur rôle
   de lecture — on vient d'apprendre où c'est, on apprend par où l'on arrive.

   Elles ne portent NI distance NI durée : aucune n'a été vérifiée sur
   itinéraire, et une durée fausse sur une page de contact est une promesse
   que personne dans le groupe n'a faite. */
.fi-ways__lab {
	margin: clamp(2.5rem, 5vw, 3.75rem) 0 var(--fi-space-m);
	font-family: var(--fi-font-mono);
	font-size: 0.66rem;
	font-weight: 500;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--fi-color-muted);
}

.fi-ways {
	margin: 0;
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--fi-space-m) var(--fi-space-l);
}

/* ⚠️ 14/09 — TOUTES LES PORTES SUR UN RANG dès 40em. `auto-fit` sur 15rem
   rangeait AIR et RAIL côte à côte et laissait ROAD seul de 768 à ~990px :
   trois colonnes de 15rem et deux gouttières demandent 784px de bande. Le
   rang se construit maintenant sur le NOMBRE de portes, pas sur une largeur
   minimale : trois colonnes de 176px à 640, où « Basel-Mulhouse-Freiburg »
   se coupe encore proprement à ses traits d'union. */
@media (min-width: 40em) {
	.fi-ways {
		grid-template-columns: none;
		grid-auto-flow: column;
		grid-auto-columns: minmax(0, 1fr);
	}
}

/* Même idiome que la grille de l'offre : le filet est porté par la CELLULE,
   pas par le conteneur, pour qu'une dernière rangée incomplète reste lisible. */
.fi-way {
	display: flex;
	flex-direction: column;
	gap: var(--fi-space-3xs);
	padding-block-start: var(--fi-space-s);
	border-block-start: 1px solid var(--fi-color-line-strong);
}

.fi-way dt {
	font-family: var(--fi-font-mono);
	font-size: 0.66rem;
	font-weight: 500;
	letter-spacing: 0.13em;
	text-transform: uppercase;
	color: var(--fi-color-muted);
}

.fi-way dd {
	margin: 0;
	font-size: var(--fi-size-step-0);
	line-height: 1.5;
	color: var(--fi-color-ink);
	text-wrap: pretty;
}

/* ── la carte ───────────────────────────────────────────────────────
   Aucune carte tierce n'est encastrée : un iframe Google ou une tuile Mapbox
   transmet l'IP du visiteur à un tiers AVANT tout consentement. La géométrie
   est téléchargée une fois par tools/geo/build-place-map.js et servie depuis
   ce site — zéro requête sortante, zéro cookie, et le dessin prend les jetons
   du site plutôt que d'imposer le style d'un fournisseur.

   Le rapport du cadre est celui du viewBox, et il ne peut pas en changer : les
   étiquettes sont posées en POURCENTAGES du cadre, pas en unités du dessin, et
   un cadre d'un autre rapport les décalerait toutes d'un coup. 1000 × 702,2 =
   14,3 km d'est en ouest sur 10,0 km du sud au nord, soit 70,1 unités pour un
   kilomètre — c'est de là que sort la règle graphique. Le cadre a été aplati le
   28/08 : à 1,17 de rapport la figure faisait 745 px de haut dans sa colonne et
   la colonne de gauche finissait sur 200 px de blanc.

   Toutes les largeurs de trait sont en unités du viewBox : rendu sur 560 px, le
   dessin est réduit de 0,56, donc un trait de 2 fait 1,1 px à l'écran. C'est le
   régime des filets du site, et c'est voulu — une carte au trait épais serait
   la seule illustration grasse de la page. */

.fi-map { margin: 0; }

.fi-map__frame {
	/* Conteneur de requête des étiquettes (14/09) : ce qui décide qu'une
	   étiquette tient, c'est la largeur du CADRE, pas celle de la fenêtre. La
	   carte fait 720px à 768 et 494px à 1024, où elle passe en colonne. */
	container: fi-map / inline-size;
	position: relative;
	aspect-ratio: 1000 / 702.2;
	border: 1px solid var(--fi-color-line);
	border-radius: var(--fi-radius-m);
	overflow: hidden;
	background: var(--fi-color-surface);
}

.fi-map__svg {
	display: block;
	inline-size: 100%;
	block-size: 100%;
}

.fi-map__ground { fill: var(--fi-color-surface); }

/* Les taches urbaines — Bâle, Huningue, Saint-Louis, Weil am Rhein, les zones
   d'activité de la plaine. C'est ce qui distingue une carte d'un schéma de
   rivières : sans elles, le Rhin flotte au milieu d'une page blanche et rien ne
   dit qu'on est dans une agglomération de 800 000 habitants. Assez pâles pour
   rester un fond : elles ne portent aucune information à lire. */
.fi-map__urban {
	fill: var(--fi-color-surface-alt);
	stroke: none;
}

/* L'eau est un APLAT depuis le 28/08, plus un gros trait : la géométrie est
   maintenant celle des berges, pas un axe schématisé. --fi-color-wash tombe à
   2:1 sur fond clair, c'est un jeton DÉCORATIF — une nappe d'eau en est
   exactement l'usage prévu. */
.fi-map__water {
	fill: color-mix(in srgb, var(--fi-color-wash) 30%, transparent);
	stroke: color-mix(in srgb, var(--fi-color-wash) 62%, transparent);
	stroke-width: 1.2;
}

/* Canaux et affluents : le Grand Canal d'Alsace, le canal de Huningue, la Birs,
   le Birsig, la Wiese. Ils tiennent le réseau du dessin — sans eux le Rhin flotte
   au milieu d'une page blanche. */
.fi-map__stream {
	fill: none;
	stroke: color-mix(in srgb, var(--fi-color-wash) 72%, transparent);
	stroke-width: 2;
	stroke-linecap: round;
	stroke-linejoin: round;
}

/* Les réseaux sont un FOND, pas un sujet : ils donnent l'échelle urbaine et
   disent que le site est desservi, sans jamais accrocher l'œil avant le
   réticule. D'où des filets à la couleur des lignes de tableau du site. */
.fi-map__road {
	fill: none;
	stroke: var(--fi-color-line-strong);
	stroke-width: 2.2;
	stroke-linecap: round;
	stroke-linejoin: round;
	opacity: 0.75;
}

.fi-map__rail {
	fill: none;
	stroke: var(--fi-color-line-strong);
	stroke-width: 1.2;
	stroke-dasharray: 7 5;
	opacity: 0.7;
}

/* Les deux pistes de l'EuroAirport : le seul trait plein et large du fond, parce
   qu'une piste EST une surface — et parce que c'est la première porte d'entrée
   listée sous la carte. */
.fi-map__runway {
	fill: none;
	stroke: var(--fi-color-line-strong);
	stroke-width: 5;
	stroke-linecap: butt;
}

/* Les frontières passent PAR-DESSUS tout, y compris le Rhin dont elles épousent
   le cours au nord du point des trois frontières : c'est la convention de
   n'importe quel atlas, et c'est le sujet de cette carte. */
.fi-map__border {
	fill: none;
	stroke: var(--fi-color-muted);
	stroke-width: 1.8;
	stroke-dasharray: 9 6;
	stroke-linecap: round;
	opacity: 0.72;
}

.fi-map__town {
	fill: var(--fi-color-surface);
	stroke: var(--fi-color-muted);
	stroke-width: 2;
}

/* Les portes d'entrée : un carré, jamais un rond. La bande sous la figure les
   liste — air, rail, route — et le carré est ce qui relie la liste au dessin. */
.fi-map__gate rect {
	fill: var(--fi-color-surface);
	stroke: var(--fi-color-muted);
	stroke-width: 2;
}

/* Le point des trois frontières : un losange, seule forme du dessin qui ne soit
   ni un rond, ni un carré, ni un trait. Il ne se confond avec rien. */
.fi-map__tri path {
	fill: var(--fi-color-surface);
	stroke: var(--fi-color-ink);
	stroke-width: 2;
}

/* Huningue : un RÉTICULE, pas une pastille. Une pastille dirait « une ville de
   plus » ; le réticule dit « le point que cette carte existe pour montrer ». */
/* Le halo est NEUTRE, pas bleu : posé en wash à côté du Rhin et de ses canaux,
   il se lisait comme un plan d'eau de plus. */
.fi-map__halo { fill: color-mix(in srgb, var(--fi-color-ink) 7%, transparent); }
.fi-map__cross { fill: none; stroke: var(--fi-color-ink); stroke-width: 1.8; }
.fi-map__pip { fill: var(--fi-color-ink); }

/* La plaque des deux repères de lecture — règle et nord. Presque opaque : une
   frontière en tirets qui passe dessous les rend illisibles, et ces deux-là ne
   servent à rien si on doit les deviner. */
.fi-map__plate {
	fill: color-mix(in srgb, var(--fi-color-surface) 88%, transparent);
	stroke: none;
}

.fi-map__rule {
	fill: none;
	stroke: var(--fi-color-muted);
	stroke-width: 1.8;
}

/* Une carte sans nord est une illustration. */
.fi-map__north {
	fill: var(--fi-color-muted);
	stroke: var(--fi-color-muted);
	stroke-width: 1.8;
}

/* Les étiquettes sont en HTML, pas en <text> : un <text> s'exprime en unités du
   viewBox, donc il rétrécit AVEC la carte — 15 unités donnent 13 px à 1440 et
   7 px à 390, illisibles. Posées ici, elles prennent la typographie du site,
   restent sélectionnables et suivent les points d'arrêt de la page. */
.fi-map__zone,
.fi-map__pin {
	position: absolute;
	inset-inline-start: var(--x);
	inset-block-start: var(--y);
	pointer-events: none;
}

.fi-map__zone {
	/* Borné à 1rem du haut (14/09) : « Germany » est ancré à 2,2 % du cadre, et
	   centré sur ce point il touchait le bord — 0 à 5px d'encre mesurés. */
	inset-block-start: max(var(--y), var(--fi-space-s));
	translate: -50% -50%;
	font-family: var(--fi-font-mono);
	font-size: 0.64rem;
	font-weight: 400;
	letter-spacing: 0.26em;
	text-transform: uppercase;
	white-space: nowrap;
	color: var(--fi-color-muted);
}

.fi-map__pin {
	font-family: var(--fi-font-mono);
	font-size: 0.68rem;
	font-weight: 500;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	white-space: nowrap;
	color: var(--fi-color-muted);
}

.fi-map__pin--l { translate: -100% -50%; padding-inline-end: 1.5rem; text-align: end; }
.fi-map__pin--r { translate: 0 -50%; padding-inline-start: 1.5rem; }

/* Huningue n'est pas une ville de plus sur la carte : c'est sa raison d'être.
   Elle sort donc du régime mono des autres étiquettes et prend le titrage. */
.fi-map__pin--here {
	display: flex;
	flex-direction: column;
	align-items: flex-end;
	gap: 0.15rem;
	padding-inline-end: 2rem;
}

.fi-map__pin--here b {
	font-family: var(--fi-font-display);
	font-size: clamp(1rem, 0.8rem + 0.8vw, 1.35rem);
	font-weight: 600;
	letter-spacing: -0.02em;
	text-transform: none;
	color: var(--fi-color-ink);
}

.fi-map__pin--here i {
	font-style: normal;
	font-size: 0.62rem;
	font-weight: 500;
	letter-spacing: 0.14em;
	color: var(--fi-color-muted);
}

.fi-map__rule-t,
.fi-map__north-t {
	position: absolute;
	font-family: var(--fi-font-mono);
	font-size: 0.62rem;
	font-weight: 500;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--fi-color-muted);
	pointer-events: none;
}

/* Calées sur la règle et sur la flèche dessinées dans le SVG, en unités du
   nouveau cadre 1000 × 858,3 : la barre part de x=52 et flotte 46 unités
   au-dessus du bas, la flèche est à 46 du bord droit et occupe y=23 à 62.

   ⚠️ 14/09 — « 2 km » part APRÈS le trait gauche de la règle, et « N » descend
   sous la pointe de sa flèche. Calés sur l'origine exacte des deux dessins, le
   trait vertical de la règle passait sur le « 2 » (768 et 820) et la hampe de
   la flèche touchait le « N ». Les deux restent sur leur plaque. */
.fi-map__rule-t { inset-inline-start: calc(5.2% + 0.45rem); inset-block-end: calc(6.6% + 0.2rem); }
.fi-map__north-t { inset-inline-start: 95.4%; inset-block-start: calc(8.4% + 0.25rem); translate: -50% 0; }

/* ── Le halo des étiquettes — 14/09 ──────────────────────────────────
   Les étiquettes sont posées PAR-DESSUS le dessin : le Rhin traversait
   « Weil am Rhein », la frontière « FR · DE · CH », une pastille de ville
   tombait dans « Firalis Group » à 360, 390 et de 1024 à 1180. Un liseré de la
   couleur du fond, à 2px, écarte le trait sous chaque lettre sans masquer la
   carte autour. En `text-shadow` et non en `-webkit-text-stroke` +
   `paint-order` : un navigateur qui ignore `paint-order` sur du texte HTML
   peindrait le contour PAR-DESSUS la lettre et la rongerait. */
.fi-map__zone,
.fi-map__pin,
.fi-map__rule-t,
.fi-map__north-t {
	text-shadow:
		-2px 0 0 var(--fi-color-surface),
		2px 0 0 var(--fi-color-surface),
		0 -2px 0 var(--fi-color-surface),
		0 2px 0 var(--fi-color-surface),
		-1.5px -1.5px 0 var(--fi-color-surface),
		1.5px -1.5px 0 var(--fi-color-surface),
		-1.5px 1.5px 0 var(--fi-color-surface),
		1.5px 1.5px 0 var(--fi-color-surface);
}

/* Une étiquette ancrée près du bord gauche et écrite VERS la gauche :
   EuroAirport, à 18 % du cadre. Rapprochée de son repère (1.1rem au lieu de
   1.5), elle garde 12px d'encre au bord dans le plus grand cadre (624px à 1280). */
.fi-map__pin--edge { padding-inline-end: 1.1rem; }

/* ⚠️ 14/09 — REQUÊTES DE CONTENEUR, et non plus de fenêtre. Les étiquettes
   secondaires ne partaient que sous une FENÊTRE de 34em ; mais de 1024 à ~1250px
   la carte passe en colonne et ne mesure que 494 à 609px, et « EuroAirport »
   sortait du cadre par la gauche — encre à −18px à 1024, −11 à 1100, −3 à
   1180. Sous 38rem de cadre, l'étiquette de bord part ; son carré reste, et la
   porte est nommée dans la bande juste dessous. */
@container fi-map (inline-size < 38rem) {
	.fi-map__pin--edge { display: none; }
}

/* Sous 28rem de cadre (fenêtre de moins de ~500px) : les étiquettes secondaires
   se chevauchent ou sortent du dessin. Les repères RESTENT tous — losange des
   trois frontières, carrés des portes d'entrée, pastilles des villes voisines —
   seuls leurs noms partent. Il reste Huningue, Bâle et les trois pays : c'est
   exactement ce que la bande doit dire à cette taille. Même seuil qu'avant pour
   un téléphone ; ce qui change, c'est qu'un cadre de 494px sur grand écran est
   désormais traité comme tel. */
@container fi-map (inline-size < 28rem) {
	.fi-map__pin--minor { display: none; }
	.fi-map__zone { font-size: 0.56rem; letter-spacing: 0.18em; }
	.fi-map__pin { font-size: 0.6rem; }
	.fi-map__pin--l { padding-inline-end: 1.1rem; }
	.fi-map__pin--r { padding-inline-start: 1.1rem; }
	.fi-map__pin--here { padding-inline-end: 1.5rem; }
}

.fi-map__cap {
	margin-block-start: var(--fi-space-s);
	max-inline-size: 62ch;
	font-size: var(--fi-size-step--1);
	line-height: 1.55;
	color: var(--fi-color-muted);
	text-wrap: pretty;
}

/* Le fleuve se traçait au dévoilement : « stroke-dasharray » sur un axe unique.
   L'eau est maintenant un APLAT (les berges, pas un axe) et les affluents sont
   vingt-et-un tracés séparés — la même règle y dessinerait vingt-et-un traits
   qui se remplissent en désordre. La figure entre donc comme le reste de la
   page, par .fi-rv, et rien ne s'anime à l'intérieur du cadre. */

/* ── 3. Le formulaire ────────────────────────────────────────────── */

.fi-form-band {
	background: var(--fi-color-surface-alt);
	padding-block: var(--fi-sec);
}

/* L'ancre est un CONTRAT : l'accueil, les fiches et le retour POST/Redirect/GET
   du formulaire visent /contact/#contact-form. La réserve suit la hauteur
   MESURÉE de l'en-tête collant (--fi-header-h, posée par ui.js : 97px à 1440,
   92px à 390 ; repli 7rem sans JavaScript), plus une marge : arrivé sur
   l'ancre, le haut de la bande n'est jamais sous l'en-tête, même s'il grandit.
   Sélecteur d'identifiant et non de classe : la règle générale
   « .wp-site-blocks [id][class*="fi-"] » l'emporterait sur une classe seule, et
   la réserve suit l'ancre sur toute page qui la porte. Vérifié le 09/10 :
   bande à 113px sous un en-tête de 97 (1440). */
#contact-form {
	scroll-margin-block-start: calc(var(--fi-header-h) + var(--fi-space-s));
}

.fi-form-band__grid {
	display: grid;
	grid-template-columns: 1fr;
	gap: clamp(2rem, 4vw, 3.5rem);
}

@media (min-width: 60em) {
	.fi-form-band__grid {
		grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
		gap: clamp(3rem, 6vw, 5rem);
		align-items: start;
	}

	/* Le contexte reste à l'écran pendant qu'on remplit : c'est lui qui rappelle
	   ce que ce guichet traite, et ce qu'il ne traite pas. */
	.fi-form-band__aside {
		position: sticky;
		inset-block-start: 8rem;
	}
}

.fi-form-band__grid > * { margin-block-start: 0; }
.fi-form-band__aside > * { margin-block-start: 0; }

.fi-form-band__note {
	margin: 0;
	font-size: var(--fi-size-step-0);
	line-height: 1.65;
	color: var(--fi-color-muted);
	max-inline-size: 40ch;
}

/* L'avertissement porte le pare-feu de contenu. Il est signalé par un filet
   latéral, pas par une couleur d'alerte : ce n'est pas une erreur, c'est une
   orientation. 09/10/2026 : sur /contact/, il n'écarte plus les demandes
   produit, il invite à choisir la société ou le sujet dans le menu
   (patterns/contact.php) — toujours une orientation, même traitement. */
/* Défaut ANTÉRIEUR relevé le 25/08, corrigé le 28/08 : deux phrases entières
   en « step--1 », soit 13.33px. Ce sont du texte courant, pas un libellé, et
   le seuil que le projet s'impose est 15px. C'est la troisième occurrence du
   même écart, après le pied du panneau des normes et les phrases de la grille
   des sociétés. */
.fi-form-band__warn {
	margin-block-start: var(--fi-space-m);
	padding-inline-start: var(--fi-space-s);
	border-inline-start: 2px solid var(--fi-color-wash);
	font-size: var(--fi-size-step-0);
	line-height: 1.6;
	color: var(--fi-color-text);
	max-inline-size: 44ch;
}

.fi-form {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: var(--fi-space-m);
}

.fi-form__row {
	display: flex;
	flex-direction: column;
	gap: 0.4rem;
	margin: 0;
}

.fi-form__pair {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(12rem, 100%), 1fr));
	gap: var(--fi-space-m);
}

.fi-form label {
	font-family: var(--fi-font-mono);
	font-size: 0.68rem;
	font-weight: 500;
	letter-spacing: 0.13em;
	text-transform: uppercase;
	color: var(--fi-color-text);
}

.fi-form__opt {
	color: var(--fi-color-muted);
	letter-spacing: 0.1em;
}

.fi-form input[type="text"],
.fi-form input[type="email"],
.fi-form select,
.fi-form textarea {
	/* Les contrôles de formulaire n'héritent PAS du box-sizing du thème : sans
	   cette ligne, « 100% + 2rem de rembourrage » débordait de 285px à 1024. */
	box-sizing: border-box;
	inline-size: 100%;
	padding: 0.85rem 1rem;
	border: 1px solid var(--fi-color-line-strong);
	border-radius: var(--fi-radius-m);
	background: var(--fi-color-surface);
	font-family: var(--fi-font-sans);
	font-size: var(--fi-size-step-0);
	line-height: 1.5;
	color: var(--fi-color-text);
	transition: border-color 0.18s ease, box-shadow 0.18s ease;
}

.fi-form textarea {
	resize: vertical;
	min-block-size: 8rem;
}

.fi-form :is(input, select, textarea):focus-visible {
	outline: none;
	border-color: var(--fi-color-brand);
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--fi-color-wash) 60%, transparent);
}

/* Le champ « select » natif garde sa flèche système : la remplacer casse le
   rendu sur les navigateurs qui ne l'exposent pas de la même façon. */
.fi-form select {
	appearance: none;
	background-image: linear-gradient(45deg, transparent 50%, var(--fi-color-muted) 50%),
		linear-gradient(135deg, var(--fi-color-muted) 50%, transparent 50%);
	background-position: calc(100% - 1.15rem) 55%, calc(100% - 0.8rem) 55%;
	background-size: 6px 6px, 6px 6px;
	background-repeat: no-repeat;
	padding-inline-end: 2.5rem;
}

.fi-form__consent {
	display: grid;
	grid-template-columns: auto 1fr;
	gap: var(--fi-space-2xs);
	align-items: start;
	margin: 0;
}

/* 18×18 mesurés, pour un minimum de 24. C'est le contrôle qui décide si le
   formulaire part : le rater, c'est ne pas pouvoir envoyer son message. La
   case grandit, et l'étiquette avec elle — une case de 24px à côté d'un texte
   de 13px se lit comme une erreur de mise en page. */
.fi-form__consent input {
	inline-size: 1.5rem;
	block-size: 1.5rem;
	margin-block-start: 0.05rem;
	accent-color: var(--fi-color-brand);
}

.fi-form__consent label {
	font-family: var(--fi-font-sans);
	font-size: var(--fi-size-step-0);
	letter-spacing: 0;
	text-transform: none;
	line-height: 1.55;
	color: var(--fi-color-muted);
}

.fi-form__consent a { color: var(--fi-color-brand); }

.fi-form__submit {
	margin: var(--fi-space-2xs) 0 0;
}

.fi-form button[type="submit"] {
	display: inline-flex;
	align-items: center;
	gap: 0.6rem;
	padding: 0.95rem 1.8rem;
	border: 1px solid var(--fi-color-brand);
	border-radius: var(--fi-radius-m);
	background: var(--fi-color-brand);
	color: var(--fi-color-on-brand);
	font-family: var(--fi-font-display);
	font-size: var(--fi-size-step-0);
	font-weight: 600;
	cursor: pointer;
	transition: transform 0.18s cubic-bezier(0.22, 0.61, 0.36, 1),
		background-color 0.18s ease, box-shadow 0.18s ease;
}

.fi-form button[type="submit"]::after {
	content: "→" / "";
	font-family: var(--fi-font-mono);
	font-weight: 400;
}

.fi-form button[type="submit"]:hover {
	background: var(--fi-color-brand-deep);
	border-color: var(--fi-color-brand-deep);
	transform: translateY(-1px);
	box-shadow: 0 8px 22px color-mix(in srgb, var(--fi-color-brand) 16%, transparent);
}

/* Le piège à miel : hors écran, jamais « display: none » — certains robots
   sautent précisément les champs masqués de cette façon. */
.fi-form__trap {
	position: absolute;
	inline-size: 1px;
	block-size: 1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}

.fi-form__notice {
	margin: 0;
	padding: 0.9rem 1.1rem;
	border-radius: var(--fi-radius-m);
	border-inline-start: 3px solid;
	font-size: var(--fi-size-step-0);
	line-height: 1.55;
}

.fi-form__notice--ok {
	border-color: var(--fi-color-brand);
	background: var(--fi-color-brand-soft);
	color: var(--fi-color-ink);
}

/* Rouge réservé à l'échec réel : c'est la seule teinte sémantique du site,
   et elle ne participe pas à la palette de marque. */
.fi-form__notice--ko {
	border-color: #A8321E;
	background: #FDF1EE;
	color: #6E2113;
}


/* ═══════════════════════════════════════════════════════════════════
   FICHE D'ÉTUDE CLINIQUE
   ═══════════════════════════════════════════════════════════════════

   Onze mouvements, neuf gabarits. La contrainte tenue ici est simple et
   elle est la raison d'être de tout ce bloc : **deux bandes voisines ne
   partagent jamais leur gabarit**. La première maquette posait la même
   colonne-plus-rail cinq fois de suite — le dispositif devenait un fond
   de page et la fiche se lisait comme une plaquette.

   Le rail de notes marginales ne sert donc qu'au mouvement 04, les filets
   verticaux qu'au bandeau d'identité, les cartes qu'aux acteurs, et le
   très grand corps qu'au seul chiffre de la page.

   Les fonds alternent clair / alt / sombre sans jamais se répéter d'une
   bande à l'autre, sauf entre l'ouverture et le champ : le champ appartient
   à l'ouverture, il ne s'en détache pas.
   ═══════════════════════════════════════════════════════════════════ */

.fi-study {
	/* Deux valeurs, et deux seulement. Avant révision la page en portait
	   quatre — 79.2, 72, 57.6 et un 52/64 dissymétrique — dont deux séparées
	   de sept pixels : assez pour que le rythme se dérègle, trop peu pour
	   qu'on voie pourquoi. Les bandes ordinaires prennent la première, les
	   bandes de respiration et la bande à chiffre la seconde. */
	--fi-study-band: clamp(3rem, 5.5vw, 5.5rem);
	--fi-study-band-tight: clamp(2.25rem, 4vw, 3.75rem);
	background: var(--fi-color-surface);
}

/* WordPress pose une marge haute sur tout bloc frère : elle décale les
   bandes les unes par rapport aux autres et casse les filets de séparation. */
.fi-study > * {
	margin-block: 0;
}

.fi-study h2 {
	margin-block: 0 var(--fi-space-s);
	font-size: var(--fi-size-step-4);
	line-height: 1.07;
	letter-spacing: -0.035em;
	color: var(--fi-color-ink);
	text-wrap: balance;
}

/* Texte courant de la fiche. Plus étroit que le chapô et plus sombre que
   lui : le chapô annonce, le corps explique. */
.fi-body {
	margin-block: 0 var(--fi-space-s);
	max-inline-size: 62ch;
	font-size: var(--fi-size-step-0);
	line-height: 1.68;
	color: var(--fi-color-muted);
}

.fi-study__head {
	margin-block-end: clamp(1.75rem, 3vw, 2.75rem);
}

.fi-study__head .fi-lede {
	margin-block-end: 0;
}

/* Depuis le 17/09 la tête d'une bande peut porter DEUX paragraphes : la phrase
   d'appui, puis ce qu'elle développe. Sans écart entre les deux — le chapô sort
   à zéro, le corps n'a pas de marge haute — les deux se touchaient.
   La bande « How long does DNA keep? » d'ApoDiag en porte TROIS depuis la copie
   corrigée : la règle vaut donc aussi d'un corps au suivant, sans quoi le
   deuxième reprend sa marge basse de `--fi-space-s` et creuse un écart sous la
   tête alors que la tête a déjà le sien. */
.fi-study__head .fi-lede + .fi-body,
.fi-study__head .fi-body + .fi-body {
	margin-block: var(--fi-space-2xs) 0;
}

/* Attente de SOURCE, jamais attente de fait : un fait absent ne s'affiche
   pas du tout (voir inc/study.php). Cet ambre est la deuxième et dernière
   teinte sémantique du site, après le rouge d'échec des formulaires — elle
   ne participe pas à la palette de marque. 7.2:1. */
.fi-pending {
	display: inline-flex;
	align-items: center;
	padding: 0.15rem 0.5rem;
	border: 1px dashed #C8A75E;
	border-radius: var(--fi-radius-s);
	background: #FCF5E6;
	color: #6B4A11;
	font-family: var(--fi-font-mono);
	font-size: 0.625rem;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	white-space: nowrap;
}

/* ── La photographie de tête de bande — 10/10/2026 ───────────────────
   Deux emplacements sur les deux fiches, et deux seulement : la bande 06
   d'Alzevit (« Taking part ») et la bande 04 d'ApoDiag (« How long does DNA
   keep? »), les deux seules dont la phrase décrit un objet physique. Validé par
   l'utilisateur après audit ; le pourquoi est écrit sur [firalis_study_photo],
   inc/study.php. La grille de chacune vit avec sa bande, plus bas : « 06 · Le
   parcours » et « L'échelle de conservation ».

   ⚠️ MASQUÉE PAR DÉFAUT. La figure n'apparaît que dans une tête qui lui ouvre
   une colonne, et seulement à partir de la largeur où cette colonne existe. En
   dessous elle n'est PAS empilée : la décision du 10/10 est une bande de
   hauteur inchangée sur téléphone — mesuré, 0px d'écart à 390 et à 768. Une
   image `loading="lazy"` dans une figure en `display: none` n'est pas
   téléchargée : le téléphone ne paie pas l'image qu'il ne montre pas.

   Les règles venaient de `.fi-cop__photo` (css/company.css, retirée le
   27/10/2026 avec les fiches longues — docs/79-fiches-porte.md) : la feuille
   des fiches n'est pas chargée sur les études. Elles y ont chacune coûté
   une mesure — largeur explicite contre la taille nulle d'une image paresseuse,
   `block-size: auto` AVANT le rapport contre `height="1067"` — et valent ici
   pour les mêmes raisons. */
.fi-study__photo {
	/* 21/9 dans les deux têtes : la photo se pose à côté d'un titre et de trois
	   lignes, et un rapport plus haut la ferait descendre sous le texte — elle
	   pousserait la frise au lieu d'accompagner la phrase. Réglable par la tête,
	   comme sur les fiches : le rapport appartient à la bande. */
	--fi-photo-ar: 21 / 9;
	--fi-photo-pos: 50% 62%;
	display: none;
	margin: 0;
	inline-size: 100%;
	overflow: clip;
	border-radius: var(--fi-radius-s);
}

.fi-study__photo img {
	display: block;
	inline-size: 100%;
	block-size: auto;
	aspect-ratio: var(--fi-photo-ar);
	object-fit: cover;
	object-position: var(--fi-photo-pos);
	/* Bande claire : le traitement documentaire de référence. Brute, une photo
	   de laboratoire devient l'élément le plus clair de la bande et prend la
	   primauté sur le titre. */
	filter: var(--fi-photo-tone);
}

/* Bande sombre : la recette de la plaque du manifeste et des fiches à la valeur
   près — filet de la famille sombre, `tone-deep`, voile du fond de bande à 18 %.
   Le voile fond les bords de l'image dans le navy : la photo devient une
   OUVERTURE dans la bande, pas un rectangle posé dessus. Deux traitements du
   même substitut sur le même navy se verraient d'une page à l'autre. */
.fi-study__band--dark .fi-study__photo {
	position: relative;
	outline: 1px solid var(--fi-color-line-dark);
	outline-offset: -1px;
}

.fi-study__band--dark .fi-study__photo img {
	filter: var(--fi-photo-tone-deep);
}

.fi-study__band--dark .fi-study__photo::after {
	position: absolute;
	inset: 0;
	background: var(--fi-color-ink-2);
	opacity: 0.18;
	content: "";
	pointer-events: none;
}

/* ── 01 · Ouverture ──────────────────────────────────────────────── */

.fi-study__open {
	padding-block: clamp(3rem, 6vw, 5.5rem) 0;
}

/* WordPress force « margin-left: auto !important » sur les enfants directs
   d'une mise en page « constrained » : tout enfant plus étroit que le conteneur
   s'y retrouve CENTRÉ. Mesuré ici : le h1, large de 1048px dans un conteneur de
   1240, démarrait à 196px au lieu de 100 — 96px à droite de tout le reste de la
   page. Même piège, même parade que dans inc/hero-index.php. */
.fi-study__h1 {
	margin-block: 0 clamp(1.75rem, 3vw, 2.5rem);
	/* Le décalage vaut la DEMI-MARGE du conteneur centré, pas zéro : à zéro le
	   titre se colle au bord de la bande pleine largeur et passe 76px à gauche
	   du reste de la page. Idiome déjà employé par .fi-hero__content. */
	margin-inline-start: max(0px, calc((100% - var(--fi-container-max)) / 2)) !important;
	margin-inline-end: auto !important;
	max-inline-size: 22ch;
	font-size: var(--fi-size-step-5);
	line-height: 1.01;
	letter-spacing: -0.045em;
	color: var(--fi-color-ink);
}

/* Le chapô à gauche, l'appel à l'action à droite : l'accueil fait l'inverse
   (titre à gauche, chapô à droite). Même matériel, arrangement distinct — la
   page ne doit pas donner l'impression d'être l'accueil avec un autre texte. */
.fi-study__opengrid {
	display: grid;
	gap: clamp(1.5rem, 3vw, 3rem);
	align-items: end;
	padding-block-end: clamp(2rem, 4vw, 3.25rem);
}

@media (min-width: 56em) {
	.fi-study__opengrid {
		grid-template-columns: minmax(0, 1fr) auto;
	}
}

.fi-study__opengrid .fi-lede {
	margin-block: 0;
	max-inline-size: 52ch;
}

/* ⚠️ 17/09 — Le chapô du client tient en TROIS paragraphes. Empilés avec leurs
   marges propres, ils héritaient de deux écarts différents — 32px sous le chapô
   (`.fi-lede`), 16 sous le corps (`.fi-body`) — et la pile se lisait comme un
   bloc puis deux notes. La grille les écarte d'une seule valeur et annule les
   marges : trois temps d'un même chapô, pas un chapô et sa suite. */
.fi-study__ledestack {
	display: grid;
	gap: var(--fi-space-s);
	align-content: end;
}

.fi-study__ledestack > * {
	margin-block: 0;
	max-inline-size: 52ch;
	/* Le troisième temps finit sur trois phrases courtes — « No clinic visit. No
	   appointment. No cost. » — et à 1440 « No cost. » tombait seul sur sa ligne.
	   `pretty` récupère la dernière ligne sans toucher aux précédentes. */
	text-wrap: pretty;
}

/* Le troisième temps est une PROMESSE — « no clinic visit, no appointment, no
   cost » —, pas une explication. Il reste au corps de lecture, mais son gras
   passe en encre pleine : c'est ce qu'on retient de l'ouverture, et à la couleur
   de texte courant il se serait lu comme la fin du paragraphe précédent. */
/* ⚠️ Deux essais avant celui-ci, tous deux mesurés à 1440. `pretty` ne bouge
   rien : Chrome ne rééquilibre que les dernières lignes d'un bloc LONG, et
   celui-ci en fait trois. `balance` les ramène à deux, mais coupe « No clinic /
   visit. » au milieu d'une phrase de trois mots. La coupe juste n'est pas une
   affaire de répartition : elle est au point où la phrase change de nature — le
   constat d'un côté, les trois promesses de l'autre. Le gras passe donc en bloc,
   et la ligne tombe toujours là. */
.fi-study__ledeclaim strong {
	display: block;
	margin-block-start: 0.2rem;
	color: var(--fi-color-ink);
	font-weight: 600;
}

/* ⚠️ 17/09 — La copie corrigée d'ApoDiag met du gras DANS le chapô et dans le
   corps : « 15 months », « prove that APO-Easy® performs as specified », « two
   separate consents ». Les deux blocs sortent en « muted » ; un gras de la même
   couleur que ce qui l'entoure ne se voit qu'à la graisse, c'est-à-dire presque
   pas à 16px. L'emphase passe donc en encre pleine — même dispositif que
   `.fi-study__ledeclaim strong`, mais EN LIGNE : ici elle souligne un membre de
   phrase, elle ne détache pas une promesse. */
.fi-study :is(.fi-lede, .fi-body) strong {
	color: var(--fi-color-ink);
	font-weight: 600;
}

:is(.fi-study__gov, .fi-study__band--dark) :is(.fi-lede, .fi-body) strong {
	color: var(--fi-color-on-dark-strong);
}

/* Le surtitre de la fiche signalétique. Plus serré que les surtitres de section :
   il ne coiffe pas une bande, il étiquette le tableau qui le suit immédiatement. */
.fi-study__glance {
	margin-block: 0 var(--fi-space-xs);
}

/* Phrase d'appui : la conclusion d'un mouvement, en encre et en demi-gras, au
   corps de lecture. Employée quatre fois sur la page — jamais deux fois dans la
   même bande, sans quoi elle cesse d'appuyer quoi que ce soit. */
.fi-study__punch {
	color: var(--fi-color-ink);
	font-weight: 500;
}

.fi-studycta__actions {
	display: flex;
	flex-wrap: wrap;
	gap: var(--fi-space-xs);
	margin-block: 0;
}

.fi-studycta__out .wp-block-button__link,
.fi-studycta__out {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
}

/* ⚠️ 14/09 — Sous 30em, les boutons de bande passent en `display: block` pour
   prendre la largeur (règle commune, voir « Boutons »). Le `gap` qui écartait la
   flèche du texte cessait alors d'exister : « Take part on alzevit.com↗ » et
   « Read NCT06432192↗ », 0px mesuré. Flex centré plutôt que bloc : même largeur,
   même centrage, et l'écart revient. */
@media (max-width: 30em) {
	.fi-study .fi-studycta__out {
		display: flex;
		justify-content: center;
	}
}

/* ⚠️ 17/09 — Était en libellé monospace capitales à 11px. La copie du client
   allonge la phrase — « Enrolment takes place on the participant website, in
   French. », 60 signes contre 49 — et `audit.sh` la remonte en MAJEUR : du texte
   courant sous 15px. Il a raison, et c'est deux fois le même arbitrage que le
   28/08 sur la légende du champ : une PHRASE n'est pas un libellé, quelle que
   soit sa longueur. Elle passe donc au corps de lecture et en casse normale. Le
   monospace reste : cette ligne est de l'appareil, pas du discours. */
.fi-studycta__note {
	margin-block: var(--fi-space-2xs) 0;
	max-inline-size: 42ch;
	/* Le monospace tenait tant que la ligne était un libellé de onze pixels. Au
	   corps de lecture il devient un pavé de terminal collé sous deux boutons :
	   la phrase passe donc au sans, comme toute autre phrase de la page. */
	font-size: 0.9375rem;
	line-height: 1.5;
	color: var(--fi-color-muted);
}

/* La fiche signalétique. Seul endroit de la page à porter des filets
   VERTICAUX : ils disent « colonnes d'un registre », et ils ne réapparaissent
   nulle part ailleurs. Le fond des cellules est la surface, l'interstice est
   la ligne — la grille se lit donc en filets, pas en cases. */
/* ⚠️ Défaut mesuré à 768 : en « auto-fit », cinq entrées se rangeaient en
   quatre colonnes plus une, et les trois cellules vides de la seconde rangée
   montraient le fond du conteneur — un bloc gris de 540px, franc, au milieu de
   la fiche. Le fond servait à dessiner les filets par la gouttière ; il ne
   peut pas le faire sans supposer que la grille est pleine.

   « grid-auto-flow: column » avec des colonnes automatiques d'une fraction met
   TOUTES les entrées sur une seule rangée, quel qu'en soit le nombre : il n'y a
   plus de cellule vide possible. Les filets redeviennent des bordures, portées
   par les entrées. Sous 62em la fiche s'empile, où cinq colonnes de 144px ne
   tiendraient de toute façon pas une adresse. */
.fi-idcard {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	margin-block: 0;
	border-block: 1px solid var(--fi-color-line);
}

.fi-idcard__row {
	padding-block: var(--fi-space-s);
	border-block-start: 1px solid var(--fi-color-line);
}

.fi-idcard__row:first-child {
	border-block-start: 0;
}

@media (min-width: 62em) {
	.fi-idcard {
		grid-auto-flow: column;
		grid-auto-columns: minmax(0, 1fr);
	}

	.fi-idcard__row {
		padding-block-start: var(--fi-space-m);
		padding-block-end: var(--fi-space-m);
		padding-inline-start: var(--fi-space-m);
		padding-inline-end: var(--fi-space-s);
		border-block-start: 0;
		border-inline-start: 1px solid var(--fi-color-line);
	}

	.fi-idcard__row:first-child {
		padding-inline-start: 0;
		border-inline-start: 0;
	}
}

.fi-idcard__k {
	margin-block-end: 0.45rem;
	font-family: var(--fi-font-mono);
	font-size: 0.625rem;
	font-weight: 500;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--fi-color-muted);
}

.fi-idcard__v {
	margin: 0;
	font-size: 0.9375rem;
	line-height: 1.45;
	font-weight: 500;
	color: var(--fi-color-ink);
	/* Ce sont des valeurs courtes dans des colonnes étroites : sans
	   équilibrage, « 2 January 2024 – 25 March 2025 » laisse « 2025 » seul sur
	   sa ligne. « balance » répartit les deux lignes et coupe à l'endroit qui
	   fait sens — ici sur le tiret. Sans effet là où la valeur tient sur une
	   ligne, et sans repli à prévoir : un navigateur qui l'ignore rend
	   exactement ce qui était rendu avant. */
	text-wrap: balance;
}

/* ── 02 · Le champ ───────────────────────────────────────────────── */

.fi-study__fieldband {
	padding-block: var(--fi-study-band-tight);
	padding-inline: 0;
	background: var(--fi-color-surface);
}

/* Le seul élément de toute la page qui touche les deux bords. C'est
   littéralement le sujet : la population entière. Le contenant « constrained »
   de WordPress plafonne ses enfants à 1240px et centre leurs marges — les deux
   sont neutralisés ici, la marge en !important parce que WordPress l'y met. */
.fi-study__fieldband > .fi-field {
	max-inline-size: none;
	margin-inline: 0 !important;
	padding-inline: 0 !important;
}

.fi-field {
	margin: 0;
}

.fi-field__canvas {
	display: block;
	inline-size: 100%;
	block-size: 18.75rem;
}

/* Sans JavaScript le canvas reste vide : mieux vaut ne rien montrer qu'une
   bande grise de 300px. La légende porte l'information entière — le dessin
   illustre ce qu'elle dit, il ne le remplace jamais. */
.no-js .fi-field__canvas {
	display: none;
}

/* Le contenu de la légende doit s'aligner sur les 1240px du reste de la page,
   alors que la figure, elle, touche les deux bords. En « content-box » la
   contrainte porte sur le TEXTE et la gouttière s'ajoute autour : mesuré, le
   premier repère tombe à 100px, exactement comme le titre et le bandeau. */
.fi-field__legend {
	box-sizing: content-box;
	max-inline-size: var(--fi-container-max);
	margin-inline: auto;
	padding-block-start: var(--fi-space-s);
	/* ⚠️ 14/09 — La gouttière DU SITE, et non plus une valeur fluide propre. Le
	   `clamp(1rem, 4vw, 3rem)` d'origine tombait juste à 1440 (où le centrage fait
	   la marge) et faux partout ailleurs : légende à 16px du bord à 390, 31 à 768,
	   41 à 1024 et 48 à 1280, quand le titre et la bande sont à 24. */
	padding-inline: var(--wp--style--root--padding-left) var(--wp--style--root--padding-right);
}

/* Deux repères, et deux seulement : ce sont des LIBELLÉS. La phrase qui
   explique la figure descend dans la légende, en corps de lecture — une
   explication de soixante signes à 11px en capitales n'est pas lisible, et
   l'audit a raison de la compter comme du texte courant. */
.fi-field__keys {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem var(--fi-space-l);
	margin-block: 0 var(--fi-space-2xs);
	font-family: var(--fi-font-mono);
	font-size: 0.6875rem;
	letter-spacing: 0.09em;
	text-transform: uppercase;
	color: var(--fi-color-muted);
}

.fi-field__key {
	display: inline-flex;
	align-items: center;
	gap: 0.55rem;
}

/* Le génotype garde SA casse dans un repère en capitales : voir inc/study.php.
   ε en capitale est Ε, qui ne se distingue pas d'un E latin. */
.fi-field__geno {
	text-transform: none;
}

.fi-field__bullet {
	flex: 0 0 auto;
	inline-size: 0.5rem;
	block-size: 0.5rem;
	border-radius: 50%;
	background: var(--fi-color-line-strong);
}

.fi-field__bullet--hit {
	inline-size: 0.6875rem;
	block-size: 0.6875rem;
	background: var(--fi-color-ink);
}

.fi-field__cap {
	margin-block: 0;
	max-inline-size: 78ch;
	font-size: 0.9375rem;
	line-height: 1.6;
	color: var(--fi-color-muted);
}

.fi-field__cap + .fi-field__cap {
	margin-block-start: var(--fi-space-2xs);
}

/* ⚠️ 17/09 — Le quatrième paragraphe n'est pas la suite des trois autres : les
   trois disent ce que le dessin MONTRE, celui-ci dit d'où vient le chiffre et
   qu'il n'est pas mesuré. C'est l'appareil de note d'une figure, et il se lit
   comme tel — filet, retrait, corps plus petit. À la même taille et sans filet,
   la réserve passait pour une quatrième explication et se perdait. */
.fi-field__cap--note {
	margin-block-start: var(--fi-space-s);
	padding-block-start: var(--fi-space-2xs);
	border-block-start: 1px solid var(--fi-color-line);
	max-inline-size: 72ch;
	/* ⚠️ Ne PAS descendre sous 0.9375rem (15px). Essayé à 14 pour démarquer la
	   note des trois phrases au-dessus : `audit.sh` le remonte en MAJEUR, et il a
	   raison — c'est du texte courant, pas un libellé. Le filet et la couleur
	   suffisent à la démarquer ; c'est exactement l'arbitrage du 28/08, où quatre
	   tailles à 14.5px sont remontées au seuil. */
	font-size: 0.9375rem;
	line-height: 1.55;
}

.fi-field__cap .fi-pending {
	margin-inline-start: 0.25rem;
	transform: translateY(-1px);
}

/* ── 03 · La bascule ─────────────────────────────────────────────── */

/* Une phrase, un fond sombre, rien d'autre. Ni surtitre, ni bouton, ni
   filet de section : c'est une respiration entre le dessin et la science,
   et tout ce qu'on y ajouterait en ferait une bande de plus. */
.fi-study__turn {
	padding-block: var(--fi-study-band-tight);
	background: var(--fi-color-ink-2);
}

.fi-study__turntext {
	position: relative;
	margin-block: 0;
	/* Même piège de centrage automatique que le h1 : 34ch dans un conteneur de
	   1240px, la phrase partait au milieu de la bande. */
	margin-inline-start: max(0px, calc((100% - var(--fi-container-max)) / 2)) !important;
	margin-inline-end: auto !important;
	padding-block-start: var(--fi-space-m);
	max-inline-size: 34ch;
	font-family: var(--fi-font-display);
	font-size: var(--fi-size-step-3);
	font-weight: 600;
	line-height: 1.28;
	letter-spacing: -0.028em;
	color: var(--fi-color-on-dark-strong);
	text-wrap: balance;
}

.fi-study__turntext::before {
	content: "";
	position: absolute;
	inset-block-start: 0;
	inset-inline-start: 0;
	inline-size: 2.25rem;
	block-size: 1px;
	background: var(--fi-color-accent-on-dark);
}

/* ── 04 · Le gène ────────────────────────────────────────────────── */

.fi-study__gene {
	padding-block: var(--fi-study-band);
}

/* Colonne de lecture décalée et rail de notes. UNE SEULE FOIS dans la page :
   c'est la mise en page d'un article scientifique, elle vaut pour la section
   scientifique et elle perd tout son sens répétée. */
.fi-spread {
	display: grid;
	gap: clamp(1.5rem, 4vw, 3.5rem);
	align-items: start;
}

@media (min-width: 61.25em) {
	/* Le rail se pose contre le bord DROIT du conteneur, pas contre la colonne
	   de lecture : c'est une marge, et une marge borde la page. En largeurs
	   fixes (« 38rem 13rem ») la grille se tassait à gauche et laissait 370px
	   de vide à droite — le rail flottait au milieu de rien. */
	.fi-spread {
		grid-template-columns: minmax(0, 38rem) minmax(11rem, 15rem);
		justify-content: space-between;
	}
}

.fi-spread > * {
	margin-block: 0;
}

.fi-rail {
	padding-inline-start: var(--fi-space-s);
	border-inline-start: 1px solid var(--fi-color-line);
}

@media (max-width: 61.1875em) {
	.fi-rail {
		padding-inline-start: 0;
		padding-block-start: var(--fi-space-s);
		border-inline-start: 0;
		border-block-start: 1px solid var(--fi-color-line);
		columns: 2;
		column-gap: var(--fi-space-l);
	}
}

.fi-rail__note {
	margin-block: 0 var(--fi-space-s);
	font-family: var(--fi-font-mono);
	font-size: 0.71875rem;
	line-height: 1.6;
	color: var(--fi-color-muted);
	break-inside: avoid;
}

.fi-rail__k {
	display: block;
	margin-block-end: 0.2rem;
	font-size: 0.625rem;
	font-weight: 500;
	letter-spacing: 0.11em;
	text-transform: uppercase;
	color: var(--fi-color-ink);
}

/* Figure de la taille d'un paragraphe, posée DANS la colonne de lecture —
   pas une bande. La case suivie par l'étude passe en négatif : c'est le seul
   aplat sombre hors bande de la page, et il désigne exactement une chose. */
.fi-alleles {
	margin-block: var(--fi-space-m) var(--fi-space-l);
	max-inline-size: 34rem;
}

.fi-alleles__row {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 1px;
	background: var(--fi-color-line);
	border: 1px solid var(--fi-color-line);
}

.fi-alleles__cell {
	display: flex;
	flex-direction: column;
	gap: 0.4rem;
	padding: var(--fi-space-xs) var(--fi-space-s);
	background: var(--fi-color-surface);
}

.fi-alleles__a {
	font-family: var(--fi-font-mono);
	font-size: 1.125rem;
	color: var(--fi-color-ink);
}

.fi-alleles__e {
	font-family: var(--fi-font-mono);
	font-size: 0.625rem;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--fi-color-muted);
}

.fi-alleles__cell--key {
	background: var(--fi-color-ink-2);
}

.fi-alleles__cell--key .fi-alleles__a {
	color: var(--fi-color-on-dark-strong);
}

.fi-alleles__cell--key .fi-alleles__e {
	color: var(--fi-color-accent-on-dark);
}

/* Les trois énoncés d'allèles, un par ligne dans un seul paragraphe : c'est la
   mise en page du client, et les <br> y portent un sens — les trois se lisent en
   colonne. La lettre grecque passe en monospace et en encre pour tenir le rang
   de gauche ; sans elle, les trois lignes forment un pavé gris dans lequel on ne
   retrouve plus quel allèle fait quoi. */
.fi-study__alleleline {
	margin-block-end: var(--fi-space-m);
}

.fi-study__alleleline b {
	font-family: var(--fi-font-mono);
	font-weight: 500;
	color: var(--fi-color-ink);
}

.fi-study__alleleline strong {
	color: var(--fi-color-ink);
	font-weight: 500;
}

.fi-alleles__cap {
	display: grid;
	gap: 0.55rem;
	margin-block-start: 0.6rem;
	font-family: var(--fi-font-mono);
	font-size: 0.6875rem;
	line-height: 1.5;
	color: var(--fi-color-muted);
}

.fi-alleles__cap strong {
	color: var(--fi-color-ink);
	font-weight: 500;
}

/* ⚠️ 17/09 — Le génotype suivi sortait jusqu'ici en gras AU FIL de la légende,
   à 11px : le seul objet que toute la section désigne se lisait comme un mot
   d'une phrase de légende. Le client l'a détaché sur sa propre ligne ; il est
   donc posé seul, au corps du libellé d'allèle (18px), aligné à droite du rappel
   qui l'annonce. Sous 26em les deux s'empilent — 34ch de libellé plus un
   génotype ne tiennent pas sur 320px. */
.fi-alleles__follow {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	justify-content: space-between;
	gap: 0.35rem var(--fi-space-s);
	padding-block-start: 0.55rem;
	border-block-start: 1px solid var(--fi-color-line);
}

/* Même règle que ci-dessus : la première ligne de la légende est une phrase de
   74 signes, elle se lit au corps de lecture. Le rappel qui annonce le génotype
   suivi, lui, reste un libellé — court, monospace, capitales. */
.fi-alleles__capline {
	font-family: var(--fi-font-sans);
	font-size: 0.9375rem;
	line-height: 1.55;
}

.fi-alleles__followk {
	letter-spacing: 0.06em;
	text-transform: uppercase;
}

.fi-alleles__followv {
	font-family: var(--fi-font-mono);
	font-size: 1.125rem;
	font-weight: 500;
	line-height: 1;
	color: var(--fi-color-ink);
}

/* ── 05 · Le chiffre ─────────────────────────────────────────────── */

.fi-study__claimband {
	padding-block: var(--fi-study-band-tight);
	border-block: 1px solid var(--fi-color-line);
	background: var(--fi-color-surface-alt);
}

/* Un seul chiffre à cette échelle sur toute la page. Deux en feraient deux
   chiffres moyens, et la fiche perdrait son unique point d'appui visuel
   entre le champ et le parcours. */
.fi-claim {
	display: grid;
	gap: clamp(0.75rem, 3vw, 3rem);
	align-items: center;
}

@media (min-width: 48em) {
	.fi-claim {
		grid-template-columns: auto minmax(0, 1fr);
	}
}

.fi-claim__n {
	margin-block: 0;
	font-family: var(--fi-font-display);
	font-size: var(--fi-size-step-6);
	font-weight: 700;
	line-height: 0.84;
	letter-spacing: -0.055em;
	color: var(--fi-color-ink);
	font-variant-numeric: tabular-nums;
	white-space: nowrap;
}

.fi-claim__u {
	font-size: 0.42em;
	letter-spacing: 0;
}

/* ⚠️ 17/09 — Le sujet du chiffre, sur la copie corrigée d'ApoDiag : « 1,474 /
   healthy blood donors ». Il ne peut pas passer par `.fi-claim__u`, qui vit DANS
   `.fi-claim__n` — donc en `white-space: nowrap`, à 0.42em du corps 6 : vingt
   signes y auraient fait une ligne insécable de trois cents pixels, poussant la
   colonne du chiffre sur la moitié de la bande. Il est posé sous le nombre, au
   corps de lecture, et il en épouse la largeur plutôt que l'inverse. */
.fi-claim__fig {
	max-inline-size: max-content;
}

/* ⚠️ Mesuré à 1440 : le sujet TOUCHAIT le chiffre. `.fi-claim__n` est en
   `line-height: 0.84` — sa boîte est plus courte que ses glyphes —, et la
   virgule de « 1,474 » descend d'environ 0.08em sous le bas de cette boîte. La
   marge du libellé, elle, se compte sur SON corps à 15px : elle ne pouvait pas
   rattraper un débord exprimé dans un corps sept fois plus grand. La réserve est
   donc posée sur le chiffre, en em de son propre corps, et seulement quand un
   sujet le suit — Alzevit n'en a pas et ne doit pas gagner un blanc. */
.fi-claim__n:has(+ .fi-claim__lab) {
	padding-block-end: 0.12em;
}

.fi-claim__lab {
	margin-block: 0.35rem 0;
	font-size: 0.9375rem;
	font-weight: 600;
	line-height: 1.35;
	letter-spacing: -0.005em;
	color: var(--fi-color-ink);
	text-wrap: balance;
}

.fi-claim__t {
	margin-block: 0;
	max-inline-size: 36ch;
	font-size: clamp(1rem, 0.9rem + 0.5vw, 1.25rem);
	line-height: 1.45;
	letter-spacing: -0.01em;
	color: var(--fi-color-text);
}

/* ⚠️ 17/09 — « Not patients. Not a selected disease population. » : ce que le
   fait signifie, et non une précision de plus. Même mesure et même corps que la
   phrase du chiffre, mais en encre et en demi-gras — c'est `.fi-study__punch`,
   au corps de la bande plutôt qu'à celui du texte courant. */
.fi-claim__punch {
	margin-block: var(--fi-space-xs) 0;
	max-inline-size: 36ch;
	font-size: clamp(1rem, 0.9rem + 0.5vw, 1.25rem);
	line-height: 1.45;
	letter-spacing: -0.01em;
	font-weight: 500;
	color: var(--fi-color-ink);
}

.fi-claim__meta {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	margin-block: var(--fi-space-2xs) 0;
	font-family: var(--fi-font-mono);
	font-size: 0.6875rem;
	letter-spacing: 0.09em;
	text-transform: uppercase;
	color: var(--fi-color-muted);
}

/* ⚠️ 17/09 — Le client a sorti les 85 % de dépôts amyloïdes de la phrase du
   chiffre et leur a donné leur propre source. Deux affirmations, deux
   provenances : le second énoncé est donc SÉPARÉ, pas rallongé — même mesure,
   corps légèrement descendu, filet au-dessus. Le chiffre géant reste unique et
   ne couvre que la première. */
.fi-claim__also {
	margin-block: var(--fi-space-s) 0;
	padding-block-start: var(--fi-space-2xs);
	border-block-start: 1px solid var(--fi-color-line);
	max-inline-size: 36ch;
	font-size: 0.9375rem;
	line-height: 1.55;
	color: var(--fi-color-muted);
}

/* ── 06 · Le parcours ────────────────────────────────────────────── */

.fi-study__routeband {
	padding-block: var(--fi-study-band);
}

/* ⚠️ 10/10/2026 — La tête du parcours porte une photographie, calée sur la
   frise : le texte tient les colonnes 1-2, l'image les colonnes 3-4, son bord
   gauche sur « 03 · Kit arrives » — l'étape qu'elle doit montrer (un kit, pas un
   laboratoire : voir le pattern). La grille REPREND celle de `.fi-route` juste
   dessous : mêmes quatre pistes, même gouttière, même seuil de 64em. Les deux
   bougent ensemble ou pas du tout — une gouttière retouchée d'un seul côté
   décolle l'image de sa colonne, et c'est précisément l'alignement pour lequel
   elle est posée.

   64em, et non les 62em de la tête d'ApoDiag : sous 64em la frise n'a que deux
   colonnes, il n'y a pas de « colonnes 3-4 » où se caler, et la figure reste
   masquée. */
@media (min-width: 64em) {
	.fi-study__head--route {
		display: grid;
		grid-template-columns: repeat(4, minmax(0, 1fr));
		column-gap: clamp(var(--fi-space-m), 3vw, var(--fi-space-xl));
		align-items: start;
	}

	.fi-study__head--route > .fi-study__headtext {
		grid-column: 1 / 3;
	}

	.fi-study__head--route > .fi-study__photo {
		display: block;
		grid-column: 3 / 5;
	}
}

/* La coupure du titre « Ten minutes. / No clinic required. » — voir le pattern.
   Même mécanique que `.fi-sig__br` : le <br> ne porte aucun sens, il n'existe
   que là où il sert. Visible dès 64em, où la photo ramène la colonne de texte à
   598px à 1440 et où le titre cassait sinon au milieu du segment souligné ; et
   sous 30em, où il cassait DÉJÀ au même endroit sur deux lignes — la coupure y
   est gratuite. Masqué entre les deux : sans photo le titre tient sur une ligne
   dès 548px (mesuré), et le <br> lui en ajouterait une. */
.fi-study__br {
	display: none;
}

@media (max-width: 30em), (min-width: 64em) {
	.fi-study__br {
		display: inline;
	}
}

/* Quatre temps, filets HORIZONTAUX seulement. Pas de rail à pastilles :
   ce vocabulaire dit « étape 1 sur 4 d'une tâche que vous accomplissez »,
   ce qui est faux ici — le continuum de l'accueil s'en est débarrassé pour
   la même raison le 25/08. Le délai fait le reste : il transforme une
   séquence en calendrier. */
.fi-route {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: 0 clamp(var(--fi-space-m), 3vw, var(--fi-space-xl));
	margin-block: 0;
	padding: 0;
	list-style: none;
}

/* ⚠️ 14/09 — UNE, DEUX, QUATRE colonnes ; jamais trois. `auto-fit` sur 15rem
   rangeait les quatre étapes en 3 + 1 de 820 à ~1100px : la dernière seule
   sur sa rangée, et une séquence lue comme « trois étapes et un reste ». Même
   règle pour la direction d'étude d'ApoDiag (quatre personnes), qui avait le
   même 3 + 1 aux mêmes largeurs — voir `.fi-direction`. Quatre colonnes dès
   64em : 221px par étape à 1024, le numéro, le délai et un titre de deux mots y
   tiennent. */
@media (min-width: 36em) {
	.fi-route { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 64em) {
	.fi-route { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

.fi-route__step {
	padding-block: var(--fi-space-m);
	border-block-start: 1px solid var(--fi-color-line);
}

/* EXCEPTION ASSUMÉE, comme .fi-heroW__* : un numéro d'étape, pas un titre. Le
   passer au pas 4 le ferait grandir jusqu'à 49,6px sur grand écran alors qu'il
   doit rester calé sur la ligne de texte qu'il numérote. /contact/ a par ailleurs
   été validé par le client le 03/09 : taille fixe, et on n'y revient pas. */
.fi-route__n {
	display: block;
	font-family: var(--fi-font-display);
	font-size: 2.25rem;
	font-weight: 700;
	line-height: 1;
	letter-spacing: -0.04em;
	/* Audit du 28/08 : « line-strong » donnait 1.54:1 sur la surface, très en
	   dessous des 3:1 exigés d'un grand corps. Le numéro n'est pas un décor —
	   il porte le rang de l'étape — donc il contraste. « muted » : 5.73:1. */
	color: var(--fi-color-muted);
	font-variant-numeric: tabular-nums;
}

.fi-route__when {
	display: block;
	margin-block-start: 0.6rem;
	font-family: var(--fi-font-mono);
	font-size: 0.625rem;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--fi-color-muted);
}

.fi-route__t {
	margin-block: 0.7rem 0.45rem;
	font-size: var(--fi-size-step-1);
	font-weight: 600;
	letter-spacing: -0.02em;
	color: var(--fi-color-ink);
}

.fi-route__d {
	margin-block: 0;
	font-size: 0.9375rem;
	line-height: 1.6;
	color: var(--fi-color-muted);
}

/* Une étape peut porter DEUX lignes depuis le 17/09 : l'instruction, puis ce
   qu'elle garantit (« Nothing to print. Nothing to post. No appointment. »). La
   seconde passe en encre — c'est une promesse, et en gris elle se serait lue
   comme une précision de service. */
.fi-route__d + .fi-route__d {
	margin-block-start: 0.45rem;
	color: var(--fi-color-text);
}

/* ── 07 · Le tamis ───────────────────────────────────────────────── */

.fi-study__sieveband {
	padding-block: var(--fi-study-band);
	background: var(--fi-color-surface-alt);
}

/* Un seul tableau numéroté, pas deux colonnes « inclusion » / « exclusion » :
   le lecteur cherche SA situation, et deux colonnes l'obligent à parcourir
   les sept lignes deux fois avant de savoir. */
.fi-sieve__head {
	display: flex;
	justify-content: space-between;
	gap: var(--fi-space-s);
	margin-block: 0;
	padding-block-end: 0.7rem;
	border-block-end: 1px solid var(--fi-color-line-strong);
	font-family: var(--fi-font-mono);
	font-size: 0.6875rem;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--fi-color-muted);
}

.fi-sieve__list {
	margin-block: 0;
	padding: 0;
	list-style: none;
}

.fi-sieve__row {
	display: grid;
	grid-template-columns: 2.5rem minmax(0, 1fr) 7rem;
	gap: var(--fi-space-s);
	align-items: baseline;
	padding-block: 0.9rem;
	border-block-end: 1px solid var(--fi-color-line);
}

.fi-sieve__i {
	font-family: var(--fi-font-mono);
	font-size: 0.6875rem;
	/* 1.45:1 en « line-strong ». À 11px le minimum est 4.5:1 — « muted » : 5.73. */
	color: var(--fi-color-muted);
}

.fi-sieve__t {
	font-size: 0.96875rem;
	line-height: 1.5;
	color: var(--fi-color-text);
}

.fi-sieve__v {
	font-family: var(--fi-font-mono);
	font-size: 0.625rem;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	text-align: end;
	color: var(--fi-color-ink);
}

.fi-sieve__row--out .fi-sieve__v {
	color: var(--fi-color-muted);
}

@media (max-width: 35em) {
	.fi-sieve__row {
		grid-template-columns: 2.25rem minmax(0, 1fr);
	}

	.fi-sieve__v {
		grid-column: 2;
		margin-block-start: 0.4rem;
		text-align: start;
	}
}

/* ── 08 · La contrepartie ────────────────────────────────────────── */

.fi-study__give {
	padding-block: var(--fi-study-band);
}

.fi-study__givegrid {
	display: grid;
	gap: clamp(1.75rem, 4vw, 4.5rem);
	align-items: start;
}

@media (min-width: 56em) {
	.fi-study__givegrid {
		grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
	}
}

.fi-study__givegrid > * {
	margin-block: 0;
}

.fi-study__giveside .fi-body {
	margin-block-end: var(--fi-space-s);
}

/* ⚠️ 17/09 — Les deux polymorphismes, sortis de la phrase par le client. En
   chasse fixe et en encre pleine, au corps d'un intertitre : un identifiant
   dbSNP se recopie, et c'est ce qui décide de sa fonte — même raison que
   `.fi-assay__snp`. Pas de pastilles ici : la fiche du test, à droite, en porte
   déjà, et les mêmes deux paires de pastilles à un mètre l'une de l'autre
   diraient qu'on a répété une ligne. Ici c'est l'énoncé, là c'est la fiche. */
.fi-study__snps {
	margin-block: 0 var(--fi-space-s);
	font-family: var(--fi-font-mono);
	font-size: var(--fi-size-step-1);
	font-weight: 500;
	letter-spacing: -0.01em;
	color: var(--fi-color-ink);
}

.fi-study__giveside .fi-body:last-child {
	margin-block-end: 0;
}

/* ⚠️ 17/09 — « Instead, participants contribute to something bigger: » raccorde
   le refus (colonne de gauche) à ce qu'il produit (colonne de droite). Elle
   ferme la colonne de gauche en pointant à droite : au-dessus de 56em la flèche
   dit où regarder, en dessous la liste arrive directement sous elle et la
   flèche n'a plus rien à désigner — elle disparaît. */
.fi-study__giveconnect {
	margin-block-start: var(--fi-space-m);
	color: var(--fi-color-ink);
	font-weight: 500;
}

@media (min-width: 56em) {
	.fi-study__giveconnect::after {
		content: "→";
		margin-inline-start: 0.45rem;
		color: var(--fi-color-muted);
	}
}

.fi-outcomes {
	margin-block: 0;
	padding: 0;
	list-style: none;
	counter-reset: fi-outcome;
}

.fi-outcomes__item {
	counter-increment: fi-outcome;
	display: grid;
	grid-template-columns: 2rem minmax(0, 1fr);
	/* ⚠️ 14/09 — Écart vertical ramené à 4px. `gap: 1rem` valait aussi entre le
	   titre et sa description, plus la marge du titre : 20px, contre 16 de la
	   description au filet suivant. Chaque titre se lisait plus près du critère
	   d'après que du sien. */
	gap: var(--fi-space-3xs) var(--fi-space-s);
	padding-block: var(--fi-space-s);
	border-block-start: 1px solid var(--fi-color-line);
}

.fi-outcomes__item::before {
	content: "0" counter(fi-outcome);
	font-family: var(--fi-font-mono);
	font-size: 0.6875rem;
	line-height: 1.9;
	color: var(--fi-color-muted);
}

/* Trois enfants pour deux colonnes : sans placement explicite, la description
   repart à la ligne suivante DANS la colonne de 2rem du numéro et se casse
   lettre à lettre. Le numéro tient la colonne 1, le texte tient la colonne 2. */
.fi-outcomes__t,
.fi-outcomes__d {
	grid-column: 2;
}

.fi-outcomes__t {
	display: block;
	font-family: var(--fi-font-display);
	font-size: 1.0625rem;
	font-weight: 600;
	letter-spacing: -0.018em;
	color: var(--fi-color-ink);
}

.fi-outcomes__d {
	display: block;
	font-size: 0.9375rem;
	line-height: 1.6;
	color: var(--fi-color-muted);
}

/* ── 09 · Les acteurs ────────────────────────────────────────────── */

.fi-study__actorsband {
	padding-block: var(--fi-study-band);
	background: var(--fi-color-surface-alt);
}

/* La seule rangée de cartes bordées de la page, et le seul endroit coloré :
   les vagues sont des logotypes, exemptés de WCAG 1.4.3. Une étude n'a pas
   de couleur — dans ce système la couleur désigne une société. */
.fi-actors {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--fi-space-m);
	margin-block: 0;
	padding: 0;
	list-style: none;
}

/* ⚠️ 14/09 — Colonnes par palier, et la dernière carte d'un nombre impair prend
   la rangée. `auto-fit` sur 17rem donnait 2 + 1 de 616 à 911px : la carte de
   contact de l'étude restait seule sur une moitié de rangée. Mêmes seuils
   qu'avant (deux colonnes dès 38.5em, trois dès 57em), seul l'orphelin change.
   C'est l'idiome de l'annuaire du hero (décision du 24/08) : une dernière
   cellule impaire ferme la grille au lieu d'y laisser un trou. */
@media (min-width: 38.5em) {
	.fi-actors {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

/* La carte qui prend la rangée passe en LIGNE : empilée, elle gardait son
   contenu dans le tiers gauche d'une carte de 720px, et une moitié de carte
   vide remplaçait la moitié de rangée vide. Tête, description et pastilles
   gardent la largeur ; le courriel, le téléphone et le renvoi se rangent sur
   une ligne, le renvoi au bord droit. */
@media (min-width: 38.5em) and (max-width: 56.99em) {
	.fi-actors__item:last-child:nth-child(odd) {
		grid-column: 1 / -1;
		flex-direction: row;
		flex-wrap: wrap;
		align-items: center;
		column-gap: var(--fi-space-l);
	}

	.fi-actors__item:last-child:nth-child(odd) > :not(.fi-actors__line, .fi-actors__go) {
		flex-basis: 100%;
	}

	.fi-actors__item:last-child:nth-child(odd) .fi-actors__go {
		margin-block-start: 0;
		margin-inline-start: auto;
		padding-block-start: 0;
		align-items: center;
	}
}

@media (min-width: 57em) {
	.fi-actors {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

.fi-actors__item {
	display: flex;
	flex-direction: column;
	padding: var(--fi-space-m);
	border: 1px solid var(--fi-color-line);
	border-radius: var(--fi-radius-m);
	background: var(--fi-color-surface);
}

.fi-actors__head {
	display: flex;
	align-items: center;
	gap: 0.65rem;
	margin-block-end: var(--fi-space-xs);
}

.fi-actors__mark {
	display: block;
	block-size: 1.5rem;
	inline-size: auto;
	aspect-ratio: 265 / 432;
	flex: 0 0 auto;
}

.fi-actors__name {
	font-family: var(--fi-font-display);
	font-size: 1.0625rem;
	font-weight: 600;
	letter-spacing: -0.02em;
	color: var(--fi-color-ink);
}

.fi-actors__role {
	margin-inline-start: auto;
	font-family: var(--fi-font-mono);
	font-size: 0.625rem;
	letter-spacing: 0.11em;
	text-transform: uppercase;
	color: var(--fi-color-muted);
	text-align: end;
}

.fi-actors__d {
	margin-block: 0 var(--fi-space-xs);
	font-size: 0.9375rem;
	line-height: 1.6;
	color: var(--fi-color-muted);
}

.fi-actors__creds {
	display: flex;
	flex-wrap: wrap;
	gap: 0.4rem;
	margin-block: 0 var(--fi-space-s);
	padding: 0;
	list-style: none;
}

.fi-actors__creds li {
	padding: 0.2rem 0.55rem;
	border: 1px solid var(--fi-color-line);
	border-radius: var(--fi-radius-pill);
	font-family: var(--fi-font-mono);
	font-size: 0.625rem;
	letter-spacing: 0.09em;
	text-transform: uppercase;
	color: var(--fi-color-muted);
}

/* 44px de haut : ce sont un courriel et un téléphone, donc les deux liens de
   la page qu'on touche vraiment depuis un mobile. 30px mesurés au premier
   audit, pour un minimum de 44. */
.fi-actors__line {
	display: flex;
	align-items: center;
	min-block-size: 2.75rem;
	margin-block-end: 0.1rem;
	font-size: 0.9375rem;
	line-height: 1.5;
	color: var(--fi-color-ink);
	text-decoration: none;
	border-block-end: 1px solid transparent;
	inline-size: fit-content;
}

.fi-actors__line:hover {
	border-block-end-color: var(--fi-color-wash);
}

.fi-actors__go {
	display: inline-flex;
	align-items: flex-end;
	min-block-size: 2.75rem;
	margin-block-start: auto;
	padding-block-start: var(--fi-space-s);
	font-family: var(--fi-font-display);
	font-size: 0.84375rem;
	font-weight: 600;
	color: var(--fi-color-ink);
	text-decoration: none;
	inline-size: fit-content;
}

/* ⚠️ 14/09 — Marge explicite : l'espace de « " →" » était absorbé, le lien étant
   un conteneur flex, et la flèche touchait le dernier mot (0px mesuré). Même
   écriture que « All news → » de la liste d'actualités. */
.fi-actors__go::after {
	content: "→";
	margin-inline-start: 0.4em;
}

.fi-actors__go:hover {
	color: var(--fi-color-brand-deep);
}

.fi-actors__item--contact {
	background: var(--fi-color-brand-soft);
	border-color: transparent;
}

/* ── 10 · Gouvernance ────────────────────────────────────────────── */

/* Bandes génériques. `.fi-study__gov` désigne une bande de GOUVERNANCE ; s'en
   servir pour n'importe quelle bande sombre ferait qu'une retouche de la
   gouvernance casserait des sections sans rapport. Les deux noms partagent donc
   les règles, et le générique existe pour les pages qui en ont besoin. */
.fi-study__band {
	padding-block: var(--fi-study-band);
}

.fi-study__band--alt {
	background: var(--fi-color-surface-alt);
}

.fi-study__gov,
.fi-study__band--dark {
	padding-block: var(--fi-study-band);
	background: var(--fi-color-ink-2);
}

:is(.fi-study__gov, .fi-study__band--dark) h2 {
	color: var(--fi-color-on-dark-strong);
}

:is(.fi-study__gov, .fi-study__band--dark) .fi-eyebrow {
	color: var(--fi-color-on-dark-muted);
}

/* Défaut relevé à la capture du 28/08 : `.fi-lede` est en `muted`, réglé pour
   la surface claire. Posé sur le navy, il tombe à 1.9:1 — illisible, et
   BLOQUANT à l'audit. Les deux régimes de contraste appellent deux jetons ;
   c'est la même règle que pour `accent-on-dark` et `wash`, qui portent la même
   valeur pour deux fonds différents. */
:is(.fi-study__gov, .fi-study__band--dark) .fi-lede,
:is(.fi-study__gov, .fi-study__band--dark) .fi-body {
	color: var(--fi-color-on-dark-muted);
}

/* .fi-hl force « color: var(--fi-color-ink) » : sur le navy de la bande, le
   texte tombe à 1.2:1 et disparaît. C'est le premier emploi du surlignement
   sur fond sombre du site, d'où l'absence de variante jusqu'ici. Le filet
   passe à l'accent clair, qui est le même #99B4FF vu dans l'autre régime. */
:is(.fi-study__gov, .fi-study__band--dark) .fi-hl {
	color: var(--fi-color-on-dark-strong);
	background-image: linear-gradient(var(--fi-color-accent-on-dark), var(--fi-color-accent-on-dark));
}

/* Deux colonnes de rangs : la densité EST le propos de la bande. Une colonne
   unique de huit lignes sur fond sombre fait une page de conditions
   générales ; deux colonnes font une fiche. */
.fi-gov {
	display: grid;
	gap: 0 clamp(var(--fi-space-l), 4vw, var(--fi-space-2xl));
	margin-block: 0;
}

@media (min-width: 56em) {
	.fi-gov {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

/* ⚠️ 17/09 — La colonne de libellés passe de 9 à 10.5rem. Le client fait monter
   « ClinicalTrials.gov » de la VALEUR au LIBELLÉ, et c'est un mot de dix-huit
   signes sans espace : en capitales à 10.5px avec 0.11em d'approche il mesure
   145px, contre 144 de colonne, et rien n'y offre de point de césure. Il ne
   serait pas passé à la ligne, il serait SORTI de sa colonne. */
.fi-gov__row {
	display: grid;
	grid-template-columns: minmax(6.5rem, 10.5rem) minmax(0, 1fr);
	gap: var(--fi-space-s);
	align-items: baseline;
	padding-block: 0.8rem;
	border-block-end: 1px solid var(--fi-color-line-dark);
}

.fi-gov__k {
	margin: 0;
	font-family: var(--fi-font-mono);
	font-size: 0.65625rem;
	letter-spacing: 0.11em;
	text-transform: uppercase;
	color: var(--fi-color-on-dark-muted);
}

.fi-gov__v {
	margin: 0;
	font-size: 0.9375rem;
	line-height: 1.55;
	color: var(--fi-color-on-dark);
}

/* ⚠️ 14/09 — Sous 30em, le libellé passe AU-DESSUS de sa valeur, comme dans la
   fiche signalétique du haut de page (`.fi-idcard`, même écart de 0.45rem). La
   colonne de libellés de 6.5 à 9rem ne laissait que 152 à 182px aux valeurs à
   360 et 390 — des noms d'organismes sur quatre lignes. Même règle pour la
   fiche du test d'ApoDiag, voir `.fi-assay__row`. */
@media (max-width: 30em) {
	.fi-gov__row {
		grid-template-columns: minmax(0, 1fr);
		gap: 0.45rem;
	}
}

/* ── 11 · Clôture ────────────────────────────────────────────────── */

.fi-study__close {
	padding-block: var(--fi-study-band);
}

.fi-study__closegrid {
	display: grid;
	gap: clamp(var(--fi-space-m), 3vw, var(--fi-space-xl));
	align-items: center;
}

@media (min-width: 56em) {
	.fi-study__closegrid {
		grid-template-columns: minmax(0, 1fr) auto;
	}
}

.fi-study__closegrid > * {
	margin-block: 0;
}

.fi-study__close h2 {
	max-inline-size: 20ch;
}

.fi-study__close .fi-body {
	margin-block-end: 0;
}

/* ═══════════════════════════════════════════════════════════════════
   SOUS-MENU « STUDIES »
   ═══════════════════════════════════════════════════════════════════

   Un panneau, pas une liste de deux mots. Chaque entrée porte son nom, son
   état et une phrase ; une ligne vers l'index ferme le panneau. Le balisage
   est injecté sur le rendu du bloc de navigation du cœur — voir inc/study.php
   pour le pourquoi. Vocabulaire repris tel quel des cartes du site : filet
   d'un pixel, rayon moyen, ombre courte. Rien de neuf.
   ═══════════════════════════════════════════════════════════════════ */

/* Le chevron est un vrai bouton : il ouvre le panneau au clic, seul geste
   disponible là où le survol n'existe pas. WordPress ne dimensionne que son
   SVG — la cible mesurait 12×12, la moitié du minimum de 44. */
.fi-header .fi-nav .wp-block-navigation-submenu__toggle {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	inline-size: 26px;
	block-size: 44px;
	padding: 0;
	margin-inline-start: 0.15rem;
	color: var(--fi-color-muted);
	background: none;
	border: 0;
}

/* Le chevron du cœur fait 12px pour un trait de 1.5 : à côté d'un libellé de
   16px il pèse autant qu'un mot. Ramené à 9px, le trait suit — il est exprimé
   dans le viewBox, donc l'échelle l'amincit à 1.13 sans qu'on y touche. La
   cible, elle, ne bouge pas : 26×44 d'aire de clic autour de 9px de dessin. */
.fi-header .fi-nav .wp-block-navigation-submenu__toggle svg {
	inline-size: 9px;
	block-size: 9px;
	transition: transform 0.2s cubic-bezier(0.22, 0.61, 0.36, 1);
}

.fi-header .fi-nav .wp-block-navigation-submenu__toggle[aria-expanded="true"] svg {
	transform: rotate(180deg);
}

/* `.has-child` dans la chaîne, comme pour l'entrée : le cœur pose
   « width: 0 » sur `.wp-block-navigation .has-child
   .wp-block-navigation__submenu-container`, trois classes, plus tard dans la
   cascade. Avec `min-width: 200px` par-dessus, le panneau se figeait à 200px et
   la phrase se cassait en colonne de six mots. Mesuré : cssWidth 200px pour
   21rem demandés. Quatre classes tranchent. */
/* ⚠️ Propriétés PHYSIQUES dans ce bloc, contre la convention du reste de la
   feuille : le cœur écrit `width`, et une déclaration logique ne reprend pas
   proprement la sienne ici. Exception locale au bloc de navigation.

   Et surtout : la largeur du panneau se règle DEUX FOIS. Au repos le cœur pose
   `width: 0`. À l'OUVERTURE il pose, dans un `@media (hover: hover)` :

       .wp-block-navigation .has-child:not(.open-on-click):hover
         > .wp-block-navigation__submenu-container { width: auto; min-width: 200px }

   soit cinq classes — plus que la règle de repos. C'est elle qui figeait le
   panneau à 200px et cassait la phrase en colonne de six mots ; corriger la
   règle de repos seule ne changeait rien, et trois mesures successives ont
   renvoyé exactement la même largeur avant que la bonne règle sorte. Le second
   sélecteur ci-dessous couvre l'ouverture au CLIC, qui est le seul geste
   disponible au doigt. */
.fi-header .fi-nav .has-child .wp-block-navigation__submenu-container {
	width: 15rem;
	min-width: 0;
	max-width: calc(100vw - 2rem);
	padding: 0.35rem;
	border: 1px solid var(--fi-color-line);
	border-radius: var(--fi-radius-m);
	background: var(--fi-color-surface);
	box-shadow:
		0 2px 6px color-mix(in srgb, var(--fi-color-ink) 6%, transparent),
		0 16px 40px color-mix(in srgb, var(--fi-color-ink) 10%, transparent);
}

.fi-header .fi-nav.wp-block-navigation .has-child:hover > .wp-block-navigation__submenu-container,
.fi-header .fi-nav.wp-block-navigation .has-child .wp-block-navigation-submenu__toggle[aria-expanded="true"] ~ .wp-block-navigation__submenu-container {
	width: 15rem;
	min-width: 0;
	max-width: calc(100vw - 2rem);
}

/* Deux éléments sur une ligne : le nom, et l'état poussé au bord droit.

   Le sélecteur est long, et il l'est pour une raison mesurée : le cœur pose
   « display: flex; padding: .5em 1em » sur
   `.wp-block-navigation .has-child .wp-block-navigation__submenu-container >
    .wp-block-navigation-item > .wp-block-navigation-item__content`,
   soit quatre classes — la même spécificité qu'une version courte, mais plus
   tard dans la cascade. Résultat relevé par CDP : la grille ne prenait pas, les
   trois éléments s'alignaient en ligne et la phrase se cassait en colonne de six
   mots. On reprend la chaîne du cœur et on la préfixe : six classes, la question
   est tranchée sans « !important ». */
.fi-header .fi-nav .has-child .wp-block-navigation__submenu-container > .wp-block-navigation-item > .wp-block-navigation-item__content {
	display: grid;
	grid-template-columns: minmax(0, 1fr) auto;
	gap: 0.3rem 0.75rem;
	align-items: center;
	inline-size: 100%;
	/* Twenty Twenty-Five ne pose aucune remise à zéro universelle de
	   « box-sizing » : le remplissage s'AJOUTE à la hauteur minimale. Mesuré,
	   0.65rem de haut et de bas donnaient des rangs de 65px pour une ligne de
	   texte — deux fois l'air nécessaire, et un panneau qui flotte. Le
	   remplissage vertical part, la hauteur minimale suffit et vaut exactement
	   la cible tactile. Cinquième occurrence du piège dans ce thème. */
	min-block-size: 2.75rem;
	padding: 0 0.75rem;
	border-radius: var(--fi-radius-s);
	transition: background-color 0.14s ease;
}

.fi-header .fi-nav .has-child .wp-block-navigation__submenu-container > .wp-block-navigation-item > .wp-block-navigation-item__content:hover,
.fi-header .fi-nav .has-child .wp-block-navigation__submenu-container > .wp-block-navigation-item > .wp-block-navigation-item__content:focus-visible {
	background: var(--fi-color-surface-alt);
}

/* 10/10/2026 — L'entrée courante du panneau (inc/nav.php) garde le fond du
   survol : « News » sur /news/, « Events » sur /events/. */
.fi-header .fi-nav .has-child .wp-block-navigation__submenu-container > .current-menu-item > .wp-block-navigation-item__content {
	background: var(--fi-color-surface-alt);
}

/* Le souligné de la navigation principale se déploie sur toute la largeur du
   lien : dans un panneau, il tirerait un trait d'un bord à l'autre. */
.fi-header .fi-nav .has-child .wp-block-navigation__submenu-container .wp-block-navigation-item__content::after {
	display: none;
}

.fi-header .fi-nav .has-child .wp-block-navigation__submenu-container .wp-block-navigation-item__label,
.fi-header .fi-nav .has-child .wp-block-navigation__submenu-container > .wp-block-navigation-item > .wp-block-navigation-item__content > .wp-block-navigation-item__label {
	font-family: var(--fi-font-display);
	font-size: var(--fi-size-step-0);
	font-weight: 600;
	letter-spacing: -0.015em;
	color: var(--fi-color-ink);
}

/* L'état n'est pas un ornement : « Soon » est la seule chose qui empêche
   ApoDiag, dont le dossier n'existe pas encore, de passer pour un lien mort.
   Pas de vert : dans ce système la couleur désigne une société, et le site
   n'a que deux teintes sémantiques — le rouge d'échec des formulaires et
   l'ambre d'attente de source. L'état ouvert se signale par « wash », le
   jeton qui sert déjà partout à dire que quelque chose est vivant. */
.fi-header .fi-submenu__tag {
	justify-self: end;
	padding: 0.15rem 0.5rem;
	border: 1px solid var(--fi-color-line);
	border-radius: var(--fi-radius-pill);
	font-family: var(--fi-font-mono);
	font-size: 0.625rem;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	white-space: nowrap;
	color: var(--fi-color-muted);
}

.fi-header .fi-submenu__tag--on {
	border-color: var(--fi-color-wash);
	background: var(--fi-color-brand-soft);
	color: var(--fi-color-ink);
}


/* En panneau plein écran, le sous-menu n'est plus une carte flottante : il se
   déplie dans la liste. Retirer le cadre évite une carte dans une carte.
   ⚠️ 09/10/2026 — Seuil aligné sur celui du menu burger (58.99em, voir « On
   force le déroulant ») : à 47.9375em, entre 768 et 943px, le panneau plein
   écran montrait encore « Studies » puis « About » en cartes ombrées. Suit le
   seuil du burger : 60.99em depuis le 26/10/2026. */
@media (max-width: 60.99em) {
	.fi-header .fi-nav .has-child .wp-block-navigation__submenu-container {
		width: auto;
		max-width: none;
		padding: 0;
		border: 0;
		border-radius: 0;
		box-shadow: none;
		background: transparent;
	}
}

/* Une paire d'allèles ne se coupe pas. « ε2/ε4 » offre une occasion de retour à
   la ligne après la barre oblique, et dans un rail de 13rem elle tombe une fois
   sur deux — un génotype coupé en deux ne se lit plus comme un génotype. */
.fi-nobreak {
	white-space: nowrap;
}

/* ═══════════════════════════════════════════════════════════════════
   ÉTUDE TERMINÉE — composants propres à ApoDiag
   ═══════════════════════════════════════════════════════════════════

   Une étude close ne se lit pas comme une étude ouverte. Alzevit invite ;
   ApoDiag rend compte. D'où des dispositifs différents autour des mêmes
   jetons : une période fermée, des critères de jugement, une échelle de
   conservation, une direction nommée.
   ═══════════════════════════════════════════════════════════════════ */

/* ── Les critères de jugement ────────────────────────────────────── */

.fi-measures {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
	gap: 0 clamp(var(--fi-space-m), 3vw, var(--fi-space-xl));
	margin-block: 0;
	padding: 0;
	list-style: none;
}

.fi-measures__item {
	padding-block: var(--fi-space-m);
	border-block-start: 1px solid var(--fi-color-line);
}

/* ⚠️ 17/09 — `.fi-measures__kind` a disparu : le rang — primaire, secondaire —
   coiffait le titre en surtitre, il est descendu rejoindre l'échéance dans
   `.fi-measures__when`, dont il est indissociable. La place prend le NUMÉRO. */
.fi-measures__t {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 0.55rem;
	margin-block: 0 0.45rem;
	font-size: var(--fi-size-step-1);
	font-weight: 600;
	letter-spacing: -0.02em;
	color: var(--fi-color-ink);
}

/* Le numéro est de l'APPAREIL, pas du titre : il se lit dans la chasse fixe des
   index du site — celle du tamis d'éligibilité, quatre bandes plus haut — et non
   dans la graisse du titre qu'il précède. Le point médian sort d'une bordure
   plutôt que d'un caractère : un « · » collé au numéro dans le HTML serait lu à
   voix haute par un lecteur d'écran, et « 01 point médian APOE genotype » n'est
   pas ce qu'il y a à entendre. */
.fi-measures__n {
	padding-inline-end: 0.55rem;
	border-inline-end: 1px solid var(--fi-color-line-strong);
	font-family: var(--fi-font-mono);
	font-size: 0.8125rem;
	font-weight: 500;
	letter-spacing: 0.06em;
	color: var(--fi-color-muted);
}

/* ⚠️ 17/09 — La description était en `muted` à 15px, dans le registre d'une note
   de bas de carte : elle décrivait. Sur la copie corrigée elle pose une QUESTION,
   qui est le propos entier de la bande — « Can APO-Easy® reliably detect… ? ».
   Une question qu'on doit chercher des yeux n'en est plus une : elle remonte au
   corps de lecture et à l'encre du texte courant. */
.fi-measures__d {
	margin-block: 0;
	font-size: var(--fi-size-step-0);
	line-height: 1.6;
	color: var(--fi-color-text);
	text-wrap: pretty;
}

.fi-measures__when {
	display: inline-block;
	margin-block-start: var(--fi-space-xs);
	font-family: var(--fi-font-mono);
	font-size: 0.625rem;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--fi-color-muted);
}

/* ── L'échelle de conservation ───────────────────────────────────── */

/* ⚠️ 10/10/2026 — La tête de l'échelle porte une photographie à sa droite. La
   recette est celle de `.fi-lodc__intro` (css/company-lodiag.css) à la valeur
   près : 32rem de plancher pour le texte, au-dessus du plafond de 494,6px du
   chapô — il n'est jamais rétréci par l'image —, et `1.1fr / 1fr`. Jamais un
   facteur sous 1 : la piste ne recevrait qu'une FRACTION de l'espace libre et
   l'image décollerait du bord de bande (piège mesuré à 1024, écrit dans
   css/company.css).

   La photo reste dans la TÊTE ; l'échelle, figure de signature de la page, garde
   toute la largeur de la bande sous elle. Texte et image sont alignés en tête,
   la rangée prend la hauteur du plus haut des deux, et la marge basse de la tête
   s'applique SOUS cette rangée : l'écart entre la photo et la frise ne descend
   jamais sous celui qui sépare aujourd'hui le texte de la frise. */
@media (min-width: 62em) {
	.fi-study__head--aside {
		display: grid;
		grid-template-columns: minmax(32rem, 1.1fr) minmax(0, 1fr);
		column-gap: clamp(2rem, 4vw, 3.5rem);
		align-items: start;
	}

	.fi-study__head--aside > .fi-study__photo {
		display: block;
	}
}

/* Le dispositif de la page, comme le champ de points l'est pour Alzevit.
   Sept relevés sur deux ans, en échelle LOGARITHMIQUE — et la légende le
   dit. Les positions viennent du PHP en variable CSS ; aucun script.

   Les libellés alternent au-dessus et au-dessous du filet : les deux
   derniers relevés sont séparés de 82px à 1440, et « 12 months » posé à
   côté de « 24 months » se chevaucherait. */
.fi-tl {
	margin: 0;
}

.fi-tl__temps {
	display: flex;
	gap: var(--fi-space-s);
	margin-block: 0 var(--fi-space-m);
}

.fi-tl__temps span {
	padding: 0.2rem 0.6rem;
	border: 1px solid var(--fi-color-line-dark);
	border-radius: var(--fi-radius-pill);
	font-family: var(--fi-font-mono);
	font-size: 0.6875rem;
	letter-spacing: 0.08em;
	color: var(--fi-color-on-dark);
}

.fi-tl__axis {
	position: relative;
	margin-block: 0;
	padding: 0;
	list-style: none;
	block-size: 5.25rem;
}

.fi-tl__axis::before {
	content: "";
	position: absolute;
	inset-block-start: 2.25rem;
	inset-inline: 0;
	block-size: 1px;
	background: var(--fi-color-line-dark);
}

.fi-tl__pt {
	position: absolute;
	inset-block-start: 0;
	inset-inline-start: var(--fi-tl-x);
	inline-size: 0;
}

.fi-tl__tick {
	position: absolute;
	inset-block-start: 1.5rem;
	inline-size: 1px;
	block-size: 1.5rem;
	background: var(--fi-color-accent-on-dark);
}

.fi-tl__lab {
	position: absolute;
	inline-size: max-content;
	font-family: var(--fi-font-mono);
	font-size: 0.6875rem;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--fi-color-on-dark);
	transform: translateX(-50%);
}

/* ⚠️ 17/09 — Le rang du relevé, ajouté sur la copie corrigée du client. Il est
   en retrait — `on-dark-muted` — parce qu'il ordonne sans être l'information :
   ce qu'on lit sur l'axe, c'est « 3 MONTHS ».
   Le point médian du client est CONSERVÉ, et il n'est pas décoratif : sans lui
   « 5 3 MONTHS » et « 2 24 HOURS » font deux nombres collés, et le rang se lit
   comme un chiffre de la mesure. Le libellé le plus long de l'axe passe ainsi de
   9 à 11 signes ; le pire écart de la figure — entre les relevés 5 et 7, seuls
   voisins de même rangée à se rapprocher — reste mesuré à 19px à 768, largeur à
   laquelle l'axe bascule en liste au pixel suivant. */
.fi-tl__n {
	margin-inline-end: 0.4rem;
	color: var(--fi-color-on-dark-muted);
}

/* Un libellé centré sur le premier relevé sortirait par la gauche, et le
   dernier par la droite. Les deux extrémités s'alignent donc sur leur bord. */
.fi-tl__pt:first-child .fi-tl__lab {
	transform: none;
}

.fi-tl__pt:last-child .fi-tl__lab {
	transform: translateX(-100%);
}

.fi-tl__pt--a .fi-tl__lab {
	inset-block-start: 0.35rem;
}

.fi-tl__pt--b .fi-tl__lab {
	inset-block-start: 3.5rem;
}

.fi-tl__legend {
	margin-block-start: var(--fi-space-m);
}

/* ⚠️ 17/09 — Le relevé de la figure, sur la copie corrigée du client :
   « 7 measurements. 24 months. 2 temperatures. » Ce n'est pas une phrase, c'est
   un DÉNOMBREMENT — il se lit d'un coup d'œil et doit donc être compté, pas lu.
   D'où le corps de lecture en encre claire, au-dessus de la légende, et non un
   libellé en chasse fixe : trois nombres à 11px sous un axe de 1240px seraient
   passés pour de l'appareil de figure. */
.fi-tl__sum {
	margin-block: 0;
	max-inline-size: 62ch;
	font-size: var(--fi-size-step-0);
	font-weight: 500;
	line-height: 1.5;
	letter-spacing: -0.01em;
	color: var(--fi-color-on-dark-strong);
}

.fi-tl__cap {
	margin-block: var(--fi-space-2xs) 0;
	max-inline-size: 62ch;
	font-size: 0.9375rem;
	line-height: 1.6;
	color: var(--fi-color-on-dark-muted);
}

/* ⚠️ 17/09 — La mention d'échelle NE VIENT PAS du client : sa légende ne la
   reprend pas. Elle reste, parce que l'axe EST logarithmique et qu'une échelle
   non linéaire qui ne s'annonce pas est un mensonge graphique. Elle est démotée
   au rang d'appareil de note — filet, retrait, corps descendu —, exactement
   comme la note de fréquence du champ d'Alzevit (`.fi-field__cap--note`) : ce
   n'est pas la suite de la légende, c'est ce qui dit comment lire la figure. */
.fi-tl__cap--note {
	margin-block-start: var(--fi-space-s);
	padding-block-start: var(--fi-space-2xs);
	border-block-start: 1px solid var(--fi-color-line-dark);
	max-inline-size: 52ch;
}

/* L'échelle n'a plus d'objet en dessous d'une certaine largeur : sept libellés
   en monospace ne tiennent pas, et une figure illisible ne vaut pas mieux qu'une
   figure absente. Elle bascule en liste verticale, où le filet devient une
   colonne et les relevés se lisent dans l'ordre.

   ⚠️ 17/09 — SEUIL REMONTÉ DE 48em À 56em, après mesure. Les relevés sont
   numérotés depuis la copie corrigée du client : chaque libellé gagne deux
   signes, et les seuls voisins de même rangée à se rapprocher — les relevés 5 et
   7, que l'échelle logarithmique tasse contre le bord droit — tombaient à 14px
   l'un de l'autre à 768. À cette distance on ne lit plus deux libellés mais un
   seul, « 5 · 3 MONTHS 7 · 24 MONTHS ». À 896px l'écart remonte à 42px et la
   figure se relit. Entre les deux, la liste verticale dit la même chose sans
   rien tasser : ce n'est pas la numérotation qu'il faut retirer, c'est l'axe. */
@media (max-width: 55.9375em) {
	.fi-tl__axis {
		block-size: auto;
		padding-inline-start: var(--fi-space-m);
	}

	.fi-tl__axis::before {
		inset-block: 0.5rem;
		inset-inline: 0 auto;
		inline-size: 1px;
		block-size: auto;
	}

	.fi-tl__pt {
		position: static;
		inline-size: auto;
		display: block;
		padding-block: 0.5rem;
	}

	/* Le tiret se pose sur le filet vertical, pas 24px à sa gauche : un absolu
	   se résout sur la boîte de REMPLISSAGE de son conteneur positionné, donc
	   « -24px » le sortait du cadre et il pendait dans la marge de la page. */
	.fi-tl__tick {
		position: absolute;
		inset-block-start: auto;
		inset-inline-start: 0;
		margin-block-start: 0.45rem;
		inline-size: 0.75rem;
		block-size: 1px;
	}

	/* Les deux extrémités portent un décalage propre à l'échelle horizontale —
	   le premier libellé s'aligne à gauche, le dernier à droite. En liste
	   verticale ces deux règles n'ont plus d'objet, et celle du DERNIER point
	   l'emportait sur la remise à zéro : « 24 months » partait de toute sa
	   largeur vers la gauche et disparaissait du cadre. Sept relevés annoncés,
	   six affichés. */
	.fi-tl__lab,
	.fi-tl__pt--a .fi-tl__lab,
	.fi-tl__pt--b .fi-tl__lab,
	.fi-tl__pt:first-child .fi-tl__lab,
	.fi-tl__pt:last-child .fi-tl__lab {
		position: static;
		display: block;
		transform: none;
		inline-size: auto;
	}

	/* ⚠️ La mention d'échelle disparaît AVEC l'échelle. Une liste ne place rien,
	   elle énumère : il n'y a plus de logarithme, plus de relevés tassés, et
	   plus rien à annoncer. Laissée en place elle décrirait une figure que le
	   lecteur n'a pas sous les yeux — soit exactement le défaut qu'elle existe
	   pour éviter. */
	.fi-tl__cap--note {
		display: none;
	}
}

/* ── Les sites ───────────────────────────────────────────────────── */

.fi-sites {
	margin-block: 0;
	padding: 0;
	list-style: none;
	border-block-start: 1px solid var(--fi-color-line);
}

.fi-sites__item {
	display: grid;
	grid-template-columns: minmax(0, 1fr) auto;
	gap: 0.2rem var(--fi-space-s);
	align-items: baseline;
	padding-block: var(--fi-space-s);
	border-block-end: 1px solid var(--fi-color-line);
}

.fi-sites__city {
	font-family: var(--fi-font-display);
	font-size: var(--fi-size-step-1);
	font-weight: 600;
	letter-spacing: -0.02em;
	color: var(--fi-color-ink);
}

.fi-sites__zip {
	font-family: var(--fi-font-mono);
	font-size: 0.6875rem;
	letter-spacing: 0.1em;
	color: var(--fi-color-muted);
}

.fi-sites__org {
	grid-column: 1 / -1;
	font-size: 0.9375rem;
	color: var(--fi-color-muted);
}

/* ── Le test ─────────────────────────────────────────────────────── */

.fi-assay {
	padding: var(--fi-space-m);
	border: 1px solid var(--fi-color-line);
	border-radius: var(--fi-radius-m);
	background: var(--fi-color-surface);
}

.fi-assay__name {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 0.6rem;
	margin-block: 0 var(--fi-space-s);
	font-family: var(--fi-font-display);
	font-size: var(--fi-size-step-2);
	font-weight: 700;
	letter-spacing: -0.03em;
	color: var(--fi-color-ink);
}

.fi-assay__owner {
	font-family: var(--fi-font-mono);
	font-size: 0.625rem;
	font-weight: 500;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--fi-color-muted);
}

.fi-assay__rows {
	margin: 0;
	border-block-start: 1px solid var(--fi-color-line);
}

.fi-assay__row {
	display: grid;
	grid-template-columns: minmax(5.5rem, 7rem) minmax(0, 1fr);
	gap: var(--fi-space-s);
	align-items: baseline;
	padding-block: 0.7rem;
	border-block-end: 1px solid var(--fi-color-line);
}

/* ⚠️ 14/09 — Empilée sous 30em, comme `.fi-gov__row` : la colonne de libellés
   de 5.5 à 7rem ne laissait que 134 et 164px aux valeurs à 360 et 390. Posé
   APRÈS la règle de base, qu'il doit surcharger à spécificité égale. */
@media (max-width: 30em) {
	.fi-assay__row {
		grid-template-columns: minmax(0, 1fr);
		gap: 0.45rem;
	}
}

.fi-assay__k {
	margin: 0;
	font-family: var(--fi-font-mono);
	font-size: 0.625rem;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--fi-color-muted);
}

.fi-assay__v {
	display: flex;
	flex-wrap: wrap;
	gap: 0.4rem;
	margin: 0;
	font-size: 0.9375rem;
	line-height: 1.5;
	color: var(--fi-color-text);
}

/* Un identifiant de polymorphisme se recopie dans dbSNP : il est donné en
   chasse fixe, comme les numéros de certificat de la bande des normes. */
.fi-assay__snp {
	padding: 0.15rem 0.5rem;
	border: 1px solid var(--fi-color-line-strong);
	border-radius: var(--fi-radius-s);
	font-family: var(--fi-font-mono);
	font-size: 0.8125rem;
	color: var(--fi-color-ink);
}

/* ── La direction d'étude ────────────────────────────────────────── */

/* Colonnes posées par palier avec `.fi-route` (14/09) : une, deux, quatre. */
.fi-direction {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: 0 clamp(var(--fi-space-m), 3vw, var(--fi-space-xl));
	margin-block: 0;
	padding: 0;
	list-style: none;
}

/* Les paliers de `.fi-route`, redits ICI : posés avant cette règle de base, ils
   perdaient contre elle à spécificité égale. */
@media (min-width: 36em) {
	.fi-direction { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 64em) {
	.fi-direction { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

.fi-direction__item {
	padding-block: 0.8rem;
	border-block-end: 1px solid var(--fi-color-line-dark);
}

.fi-direction__n {
	display: block;
	font-size: 0.9375rem;
	color: var(--fi-color-on-dark);
}

.fi-direction__r {
	display: block;
	margin-block-start: 0.2rem;
	font-family: var(--fi-font-mono);
	font-size: 0.625rem;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--fi-color-on-dark-muted);
}

/* Variante claire de la bande à chiffre : ApoDiag l'emploie entre deux bandes
   qui sont déjà « alt » et sombre. Le fond change, les filets restent — c'est
   eux qui font la bande, pas la couleur. */
.fi-study__claimband--plain {
	background: var(--fi-color-surface);
}

/* Population et sites côte à côte : le tamis est un tableau, les sites une
   courte liste. Empilés, la liste passe pour la fin du tableau. */
.fi-study__popgrid {
	display: grid;
	gap: clamp(1.75rem, 4vw, 4rem);
	align-items: start;
}

@media (min-width: 56em) {
	.fi-study__popgrid {
		grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
	}
}

.fi-study__popgrid > * {
	margin-block: 0;
}

/* Intertitre de second rang, à l'intérieur d'une bande. En chasse fixe et non
   en titre : il ordonne, il n'annonce pas une nouvelle section. */
/* La marge basse vaut le remplissage bas de `.fi-sieve__head`, filet compris.
   Ce n'est pas une valeur d'agrément : dans la bande « Blood donors » les deux
   colonnes ouvrent chacune sur un libellé en chasse fixe suivi d'un filet, et
   à 16px de marge les deux filets tombaient à cinq pixels l'un de l'autre —
   assez pour qu'on lise un défaut, trop peu pour qu'on lise une intention.
   Mesuré après correction : même ligne au pixel. */
.fi-study__sub {
	margin-block: clamp(2rem, 4vw, 3rem) 0.7rem;
	font-family: var(--fi-font-mono);
	font-size: 0.6875rem;
	letter-spacing: 0.13em;
	text-transform: uppercase;
	color: var(--fi-color-muted);
}

:is(.fi-study__gov, .fi-study__band--dark) .fi-study__sub {
	color: var(--fi-color-on-dark-muted);
}

/* ── Corps d'article ─────────────────────────────────────────────────
   ⚠️ 07/09 : le site a désormais SON gabarit d'article — templates/single.html,
   créé le 04/09 pour la tâche A-3. Ce bloc lui reste nécessaire : il règle le
   corps du texte, que le gabarit ne touche pas. Son texte courant sort à 14.15px, sous le
   seuil de 15 que le projet s'impose — relevé MAJEUR dès la publication du
   premier article. On ne redessine pas le gabarit ici, on remonte ce qui se
   lit. Le reste est porté à la liste d'avant-production.
   Portée à « body.single-post » : les PAGES emploient le même conteneur, et
   leurs patterns fixent déjà leurs tailles. */
body.single-post .wp-block-post-content :is(p, li) {
	font-size: var(--fi-size-step-0);
	line-height: 1.7;
}

/* ── La mesure de lecture — 14/09 ────────────────────────────────────
   Le texte courant prenait les 760px du gabarit : 92 à 98 signes par ligne
   mesurés de 768 à 1440, pour une cible de 65 à 75. 35rem en rend 72 à ces
   largeurs. Le titre, l'image à la une et les images du texte gardent 760px :
   une photographie de reportage lue sur 560px ne montre plus personne, et le
   texte ne perd rien à être plus étroit que ce qui l'illustre. Tout part du
   même bord gauche (css/news.css), la différence ne se lit qu'à droite. */
body.single-post .fi-post .wp-block-post-content > :where(:not(.wp-block-image):not(.wp-block-gallery):not(.fi-photogrid):not(.fi-postgallery)) {
	max-inline-size: 35rem;
}

/* ── Les intertitres du texte — 14/09 ────────────────────────────────
   Ils héritaient du h2 de SECTION du thème, pas 4 : 33,8px sous un h1 de
   38,8 à 390 — deux titres que rien ne distinguait —, « Spotlight on
   APO-Easy® : A Genotyping Solution… » sur cinq lignes, et 49,6px à 1440
   au-dessus d'un corps de 16. Un intertitre d'article ordonne un texte, il
   n'ouvre pas une bande : pas 2 (20,8 à 23px).

   La réserve au-dessus était celle d'un paragraphe (19px mesurés), la même
   que dessous : l'intertitre flottait à égale distance de ce qu'il ferme et
   de ce qu'il ouvre. 48px au-dessus, 12 dessous — il appartient au texte qui
   le suit. La marge basse passe par le frère suivant, parce que l'écart de
   bloc de WordPress (1.2rem) y est posé en marge HAUTE et l'emporterait à la
   fusion des marges. */
body.single-post .fi-post .wp-block-post-content > :is(h2, h3) {
	margin-block: var(--fi-space-xl) 0;
	line-height: 1.3;
	letter-spacing: -0.015em;
	text-wrap: balance;
}

body.single-post .fi-post .wp-block-post-content > h2 { font-size: var(--fi-size-step-2); }

/* Aucun article n'a de h3 aujourd'hui. Sans cette ligne, le premier qui en
   aurait un l'afficherait au pas 3 du thème — PLUS grand que le h2 ci-dessus. */
body.single-post .fi-post .wp-block-post-content > h3 { font-size: var(--fi-size-step-1); }

body.single-post .fi-post .wp-block-post-content > :is(h2, h3) + * {
	margin-block-start: var(--fi-space-xs);
}

/* Les trois liens du gabarit d'article de Twenty Twenty-Five — auteur,
   catégorie, et les titres de « More posts » — mesurent 17 à 38px de haut, sous
   les 44 d'une cible. Même parade que pour les titres de la liste d'actualités :
   le remplissage agrandit la cible, la marge négative le reprend, le rythme ne
   bouge pas.

   ⚠️ DORT DEPUIS LE 07/09 — les deux règles qui suivent n'ont plus de cible.
   templates/single.html retire du gabarit parent l'auteur, les étiquettes et
   la liste « More posts » : plus aucun .wp-block-post-author-name__link, ni
   .wp-block-post-terms a, ni titre d'article lié sur une page d'article. La
   catégorie de la bande passe par .fi-news__cat. Conservées le temps de la
   revue client — supprimer single.html les rappellerait toutes les trois. */
body.single-post :is(.wp-block-post-author-name__link, .wp-block-post-terms a) {
	padding-block: 0.85rem;
	margin-block: -0.85rem;
}

body.single-post .wp-block-post-title a {
	padding-block: 0.3rem;
	margin-block: -0.3rem;
}

/* ═══════════════════════════════════════════════════════════════════
   TÊTE DE PAGE
   ═══════════════════════════════════════════════════════════════════
   Habillage de la structure posée par firalis-core (filtre render_block
   sur core/post-title). Le fond du problème n'était pas typographique :
   Twenty Twenty-Five rend le titre d'une page dans un bloc contraint à
   la mesure de lecture et centré dans la fenêtre — bord gauche à 340px
   à 1440, quand toutes les sections du site commencent à 100px. Une
   page portait donc DEUX bords gauches, et c'est ce décalage qui la
   faisait lire comme un gabarit générique posé sur une page qui, elle,
   a une direction.

   L'idiome ci-dessous — se caler sur le bord gauche du conteneur et
   laisser filer la droite — est celui du site, déjà employé par le
   hero, le continuum, l'offre, l'archive et les études. On ne réinvente
   pas un alignement, on rattache ces pages à celui qui existe.

   Mesuré avant d'écrire : sur les onze pages passées en revue client —
   accueil du 03/09, cinq fiches de société du 04/09, team — la
   différence est de 0,00 % de pixels. Leurs blocs de contenu sont tous
   « alignfull » et ne sont donc jamais touchés par la règle de contenu.
   ═══════════════════════════════════════════════════════════════════ */

.fi-pagehead,
main .entry-content > :where(:not(.alignfull):not(.alignwide)) {
	max-width: none;
	/* Les « !important » ne sont pas une facilité : la mise en page contrainte de
	   WordPress émet « margin-left: auto !important » sur tout enfant non aligné.
	   Sans eux la déclaration ne passe pas, et le bloc reste centré. C'est la
	   raison des huit autres occurrences de cet idiome dans cette feuille. */
	margin-inline-start: max(0px, calc((100% - var(--fi-container-max)) / 2)) !important;
	margin-inline-end: auto !important;
}

.fi-pagehead {
	padding-block-end: var(--fi-space-m);
	border-block-end: 1px solid var(--fi-color-line);
}

.fi-pagehead .wp-block-post-title {
	max-width: none;
	margin-block: 0;
}

/* Le surtitre situe la page dans la hiérarchie — il vaut le titre de la page
   parente, et une page de premier niveau n'en a tout simplement pas. Le filet
   court qui le précède est celui des surtitres de section : même objet, même
   signe, et rien de neuf à apprendre pour le lecteur. */
.fi-pagehead__up {
	display: flex;
	align-items: center;
	gap: 0.75rem;
	margin-block: 0 0.9rem;
}

.fi-pagehead__up::before {
	content: "";
	flex: none;
	inline-size: 2rem;
	block-size: 1px;
	background: var(--fi-color-wash);
}

/* ═══════════════════════════════════════════════════════════════════
   CORPS D'ARTICLE — éléments introduits par les actualités
   ═══════════════════════════════════════════════════════════════════
   Le gabarit d'article reste celui de Twenty Twenty-Five (voir la liste
   d'avant-production) : ce bloc ne le redessine pas, il habille les trois
   objets que les articles ont apportés — la ligne de source, le pavé de
   financement européen et la galerie.
   ═══════════════════════════════════════════════════════════════════ */

/* La ligne de source ferme l'article. Elle n'est pas décorative : ces textes
   sont republiés depuis le site d'une société du groupe, et le dire est la
   moindre des choses — pour le lecteur comme pour le référencement. */
body.single-post .fi-post__source {
	margin-block-start: var(--fi-space-xl);
	padding-block-start: var(--fi-space-s);
	border-block-start: 1px solid var(--fi-color-line);
	font-size: 0.9375rem;
	line-height: 1.6;
	color: var(--fi-color-muted);
}

/* Le drapeau et la mention de financement vont ENSEMBLE : c'est une obligation
   des projets HORIZON, pas une illustration. L'emblème reste petit — il
   authentifie, il n'annonce pas. */
body.single-post .fi-funding {
	display: grid;
	grid-template-columns: 5.5rem minmax(0, 1fr);
	gap: var(--fi-space-s) var(--fi-space-m);
	align-items: center;
	margin-block-start: var(--fi-space-l);
	padding: var(--fi-space-m);
	border: 1px solid var(--fi-color-line);
	border-radius: var(--fi-radius-m);
	background: var(--fi-color-surface-alt);
}

body.single-post .fi-funding figure {
	margin: 0;
}

body.single-post .fi-funding img {
	display: block;
	inline-size: 100%;
	block-size: auto;
}

body.single-post .fi-funding p {
	margin: 0;
	/* 0.875rem valait 14px : c'est une phrase entière, donc du texte courant,
	   et le seuil du projet est 15. La mention de financement est une
	   obligation contractuelle — la rendre petite serait la rendre illisible. */
	font-size: 0.9375rem;
	line-height: 1.6;
	color: var(--fi-color-muted);
}

/* ⚠️ 14/09 — Empilé sous 30em. Les 5.5rem du drapeau et la gouttière laissaient
   150px à la mention à 360 (180 à 390) : neuf lignes de trois mots pour une
   phrase obligatoire. Le drapeau garde sa taille et passe au-dessus — il
   authentifie la mention, il n'a pas à la côtoyer. */
@media (max-width: 30em) {
	body.single-post .fi-funding {
		grid-template-columns: minmax(0, 1fr);
		justify-items: start;
	}

	body.single-post .fi-funding figure {
		inline-size: 5.5rem;
	}
}

/* Deux colonnes, jamais plus : ce sont des photographies de reportage, et à
   trois par rangée on n'y distingue plus personne. */
body.single-post .fi-postgallery {
	margin-block: var(--fi-space-l);
	gap: var(--fi-space-xs);
}

body.single-post .wp-block-image img {
	inline-size: 100%;
	block-size: auto;
	border-radius: var(--fi-radius-s);
}

/* Une citation d'article n'est pas une bande de manifeste : filet à gauche,
   pas de guillemet dessiné, et l'attribution en chasse fixe. */
body.single-post .wp-block-quote {
	margin-block: var(--fi-space-l);
	padding-inline-start: var(--fi-space-m);
	border-inline-start: 2px solid var(--fi-color-wash);
	font-style: normal;
}

body.single-post .wp-block-quote p {
	font-size: var(--fi-size-step-1);
	line-height: 1.5;
	letter-spacing: -0.012em;
	color: var(--fi-color-ink);
}

body.single-post .wp-block-quote cite {
	display: block;
	margin-block-start: var(--fi-space-xs);
	font-family: var(--fi-font-mono);
	font-size: 0.6875rem;
	font-style: normal;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--fi-color-muted);
}

/* Grille de reportage. La galerie du cœur dimensionne ses figures les unes par
   rapport aux autres : cinq photographies de rapports différents s'y décalent
   en escalier, et deux d'entre elles disparaissaient sous les autres. Ici deux
   colonnes franches, un rapport imposé, et la dernière image d'un nombre impair
   occupe la largeur — elle n'est pas orpheline, elle ferme. */
body.single-post .fi-photogrid {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: var(--fi-space-xs);
	margin-block: var(--fi-space-l);
}

body.single-post .fi-photogrid figure {
	margin: 0;
}

body.single-post .fi-photogrid img {
	display: block;
	inline-size: 100%;
	block-size: 100%;
	aspect-ratio: 3 / 2;
	object-fit: cover;
	border-radius: var(--fi-radius-s);
}

body.single-post .fi-photogrid > :last-child:nth-child(odd) {
	grid-column: 1 / -1;
}

body.single-post .fi-photogrid > :last-child:nth-child(odd) img {
	aspect-ratio: 21 / 9;
}

@media (max-width: 35em) {
	body.single-post .fi-photogrid {
		grid-template-columns: minmax(0, 1fr);
	}
}

/* ⚠️ DORT DEPUIS LE 07/09. La navigation entre articles du thème parent — ses
   liens faisaient 22 à 42px de haut, sous les 44 d'une cible — est retirée par
   templates/single.html : ce sont les deux croix rouges de redlines-p05.png.
   Conservée le temps de la revue client, comme les deux règles ci-dessus. */
body.single-post .wp-block-post-navigation-link a {
	display: inline-block;
	padding-block: 0.7rem;
	margin-block: -0.7rem;
}

/* ═══════════════════════════════════════════════════════════════════
   MULTILINGUE — sélecteur de langue et menu allemand (26/10/2026)
   docs/78-multilingue.md, lot B. Le site parle anglais et allemand
   (/de/, mêmes slugs) ; le sélecteur est ENTRE le menu et « Contact »,
   hors du menu (parts/header.html, inc/header-footer.php).
   ═══════════════════════════════════════════════════════════════════ */

/* ── Le sélecteur : un globe, le code de la langue, une liste ────────────
   Revu le 26/10/2026 (planches lang-switcher, option B retenue). « EN | DE »
   en mono 12px, dernière entrée du menu, ne se voyait pas : rien ne disait
   « langue », la langue courante ne différait de l'autre que par la couleur,
   et sous le seuil du burger il finissait en bas du panneau plein écran — sous
   le pli d'un écran de 667px. Désormais : un filet sépare les rubriques des
   outils, puis un bouton globe + code + chevron qui ouvre une petite carte (la
   même que les sous-menus) où chaque langue est écrite dans SA langue, la
   courante cochée. La forme ne grandit pas avec le nombre de langues.

   Balisage du socle (firalis_language_switcher(), forme « menu ») : un
   <details> — il s'ouvre au clic, à Entrée et à Espace SANS JavaScript ; ui.js
   ajoute Échap, le clic au-dehors, la sortie au clavier et les flèches. Le code
   visible (« EN ») ouvre le nom accessible du bouton (« EN Language: English »,
   WCAG 2.5.3) ; sous 375px il n'est plus que lu (globe seul).

   Le groupe .fi-header__right espace ses enfants de --fi-space-s : le
   sélecteur l'annule à sa gauche. En barre, le filet reprend cet espace ; en
   burger (pas de filet), la case du globe TOUCHE celle du menu — deux cibles de
   44px côte à côte, 23px d'air visible entre les deux pictogrammes. */
.fi-header .fi-lang {
	display: flex;
	align-items: center;
	margin-inline-start: calc(-1 * var(--fi-space-s));
}

.fi-header .fi-lang::before {
	content: "";
	flex: none;
	inline-size: 1px;
	block-size: 1.25rem;
	margin-inline: var(--fi-space-s) var(--fi-space-3xs);
	background: var(--fi-color-line-strong);
}

.fi-lang--menu .fi-lang__menu {
	position: relative;
}

/* 44px de haut ET de large au moins : la cible tactile, sans grandir la carte
   (73px). Le code garde le registre des surtitres du site (mono, capitales
   espacées) ; le globe est à l'encre, le chevron atténué comme ceux du menu. */
.fi-lang--menu .fi-lang__toggle {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.4rem;
	box-sizing: border-box;
	min-inline-size: 44px;
	block-size: 44px;
	padding-inline: 0.6rem;
	border-radius: var(--fi-radius-m);
	font-family: var(--fi-font-mono);
	font-size: 0.8125rem;
	font-weight: 500;
	letter-spacing: 0.08em;
	line-height: 1;
	white-space: nowrap;
	color: var(--fi-color-ink);
	list-style: none;
	cursor: pointer;
	user-select: none;
	-webkit-tap-highlight-color: transparent;
	transition: background-color 0.18s ease;
}

/* Le triangle natif : ::-webkit-details-marker pour Safari, `list-style` pour
   les autres (même parade que .fi-certs__sum). */
.fi-lang--menu .fi-lang__toggle::-webkit-details-marker {
	display: none;
}

.fi-lang--menu .fi-lang__toggle:hover,
.fi-lang--menu .fi-lang__menu[open] > .fi-lang__toggle {
	background: var(--fi-color-surface-alt);
}

.fi-lang--menu .fi-lang__toggle:focus-visible {
	outline-offset: 2px;
	border-radius: var(--fi-radius-m);
}

.fi-lang__globe {
	flex: none;
	inline-size: 18px;
	block-size: 18px;
}

.fi-lang__chevron {
	flex: none;
	inline-size: 12px;
	block-size: 12px;
	color: var(--fi-color-muted);
	transition: transform 0.2s ease;
}

.fi-lang__menu[open] .fi-lang__chevron {
	transform: rotate(180deg);
}

/* La carte : celle des sous-menus du site (cadre, rayon, ombre, rangs de 44px,
   rang courant sur le fond du survol). Elle pend sous la carte de l'en-tête,
   alignée sur la droite du bouton. */
.fi-lang--menu .fi-lang__list {
	position: absolute;
	z-index: 10;
	inset-block-start: calc(100% + 0.95rem);
	inset-inline-end: 0;
	box-sizing: border-box;
	min-inline-size: 12.5rem;
	max-inline-size: calc(100vw - 2rem);
	margin: 0;
	padding: 0.35rem;
	list-style: none;
	border: 1px solid var(--fi-color-line);
	border-radius: var(--fi-radius-m);
	background: var(--fi-color-surface);
	box-shadow:
		0 2px 6px color-mix(in srgb, var(--fi-color-ink) 6%, transparent),
		0 16px 40px color-mix(in srgb, var(--fi-color-ink) 10%, transparent);
	animation: fi-lang-in 0.16s cubic-bezier(0.22, 0.61, 0.36, 1);
}

@keyframes fi-lang-in {
	from {
		opacity: 0;
		transform: translateY(-4px);
	}
}

.fi-lang--menu .fi-lang__item {
	margin: 0;
}

.fi-lang--menu .fi-lang__link {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 0.75rem;
	box-sizing: border-box;
	min-block-size: 2.75rem;
	padding: 0 0.75rem;
	border-radius: var(--fi-radius-s);
	font-family: var(--fi-font-display);
	font-size: var(--fi-size-step-0);
	font-weight: 600;
	letter-spacing: -0.015em;
	white-space: nowrap;
	color: var(--fi-color-ink);
	text-decoration: none;
	transition: background-color 0.14s ease;
}

.fi-lang--menu .fi-lang__link:hover,
.fi-lang--menu .fi-lang__link:focus-visible,
.fi-lang--menu .fi-lang__item.is-current .fi-lang__link {
	background: var(--fi-color-surface-alt);
}

.fi-lang--menu .fi-lang__link:focus-visible {
	outline-offset: -2px;
}

.fi-lang__check {
	flex: none;
	inline-size: 16px;
	block-size: 16px;
}

/* ── Sous le seuil du burger : pas de filet ─────────────────────────────
   Le filet sépare les rubriques des outils ; sans rubriques dans la barre, il
   séparerait le menu du globe. ⚠️ Trois conditions, EN PHASE avec celles qui
   font paraître le burger (« L'en-tête était cassé… », « Menu en allemand ») —
   à retoucher ensemble. */
@media (max-width: 60.99em) {
	.fi-header .fi-lang::before {
		display: none;
	}
}

@media (max-width: 73.99em) {
	:root:not(:lang(en)) .fi-header .fi-lang::before {
		display: none;
	}
}

.fi-nav-tight .fi-header .fi-lang::before {
	display: none;
}

/* ── Écran de téléphone : la carte s'ouvre sous la carte de l'en-tête ─────
   Le bouton n'est plus qu'à quelques pixels du bord : une carte alignée sur
   lui sortirait de l'écran à gauche à 320. Sous 48em, elle se pose sous la
   carte de l'en-tête (.fi-header__inner, qui est le bloc de référence), calée
   sur son bord droit, jamais plus large qu'elle. */
@media (max-width: 47.9375em) {
	.fi-header .fi-lang--menu .fi-lang__menu {
		position: static;
	}

	.fi-header .fi-lang--menu .fi-lang__list {
		inset-block-start: calc(100% + var(--fi-space-2xs));
		max-inline-size: 100%;
	}
}

/* ── Barre de téléphone : marque, menu, globe, « Contact » ───────────────
   Mesuré le 26/10/2026 (CDP, viewport réel), globe seul, anglais :
     espacements d'origine           → « Contact » sort de la carte de 5px à
                                        390, 35px à 360
     sous 26em : espacements à 0.5rem,
       « Contact » resserré           → tient de 360 à 416 (5px de marge à 360)
     sous 22.4375em : en plus, marque
       (28px, nom à 1rem) et
       rembourrages resserrés         → tient à 320, anglais et allemand
   Ce qui ne bouge JAMAIS : les cases de 44px du menu et du globe, la hauteur
   du bouton. Le globe touche la case du menu (sa marge annule l'espacement du
   groupe), « Contact » garde 0.5rem. Ces règles remplacent (e), qui ne valait
   que hors de l'anglais jusqu'à 24em (repris : une page non anglaise sans
   sélecteur — recette en brouillon — reste resserrée).
   `:has(.fi-lang)` : tant qu'une seule langue est publiée (la prod jusqu'au
   passage en « live »), le bloc ne rend rien et la barre garde ses
   espacements et sa marque d'origine. */
@media (max-width: 25.9375em) {
	.fi-header--card:has(.fi-lang) .fi-header__inner,
	.fi-header--card:has(.fi-lang) .fi-header__right,
	:root:not(:lang(en)) .fi-header--card .fi-header__inner,
	:root:not(:lang(en)) .fi-header--card .fi-header__right {
		gap: var(--fi-space-2xs);
	}

	.fi-header--card:has(.fi-lang) .fi-header__cta .wp-block-button__link,
	:root:not(:lang(en)) .fi-header--card .fi-header__cta .wp-block-button__link {
		padding-inline: var(--fi-space-xs);
	}

	.fi-header .fi-lang {
		margin-inline-start: calc(-1 * var(--fi-space-2xs));
	}
}

@media (max-width: 22.4375em) {
	.fi-header--card:has(.fi-lang) .fi-header__inner {
		padding-inline: 0.5rem 0.35rem;
	}

	.fi-header--card:has(.fi-lang) .fi-brand__mark {
		block-size: 28px;
	}

	.fi-header--card:has(.fi-lang) .fi-brand--stack .fi-brand__name {
		font-size: 1rem;
	}

	.fi-header--card:has(.fi-lang) .fi-brand--stack .fi-brand__unit {
		font-size: 0.62rem;
	}

	/* `:root` : passe devant la règle non anglaise de 26em, plus spécifique. */
	:root .fi-header--card:has(.fi-lang) .fi-header__cta .wp-block-button__link {
		padding-inline: 0.55rem;
	}
}

/* « Contact » ne passe JAMAIS sur deux lignes : la règle (c) plus bas équilibre
   les libellés de bouton hors de l'anglais (`text-wrap: balance`, qui rétablit
   le retour à la ligne malgré `white-space: nowrap`) — à 360, « Kontak/t » se
   cassait en deux. Un mot seul n'a rien à équilibrer. */
:root .fi-header--card .fi-header__cta .wp-block-button__link {
	text-wrap: nowrap;
}

/* ── Sous 30em : sans chevron ; sous 375px : le globe seul ───────────────
   Mesuré à 390 : la marque, le burger, « EN » + chevron et « Contact » ne
   tenaient pas ensemble. Sous 30em, le chevron s'en va et le bouton se
   resserre (57px : globe + code) — il reste 14px de marge à 375. Sous 375px
   (360, 320), le code passe hors écran : le bouton devient une case de 44px
   comme celle du menu, et le code reste lu (« EN Language: English »). */
@media (max-width: 29.99em) {
	.fi-header .fi-lang--menu .fi-lang__toggle {
		gap: 0.3rem;
		padding-inline: 0.5rem;
	}

	.fi-header .fi-lang--menu .fi-lang__chevron {
		display: none;
	}
}

@media (max-width: 23.4em) {
	.fi-header .fi-lang--menu .fi-lang__toggle {
		inline-size: 44px;
		padding: 0;
	}

	.fi-header .fi-lang--menu .fi-lang__code {
		position: absolute;
		inline-size: 1px;
		block-size: 1px;
		overflow: hidden;
		clip-path: inset(50%);
		white-space: nowrap;
	}
}

/* ── Menu en allemand (et toute langue plus longue que l'anglais) ────────
   Mesuré le 26/10/2026 au CDP, sélecteur compris, libellés substitués dans la
   page allemande :
     anglais (5 rubriques + « EN | DE »)        → une rangée dès 944px, 34px libres
     allemand plausible (« Unser Angebot », « Über uns », « Studien »,
       « Aktuelles & Termine », « Karriere », « Kontakt »)      → dès 1024px
     anglais allongé de 40 % (length_factor 1.35 du registre, arrondi haut)
                                                               → dès 1152px, 3px libres
   Remesuré le même jour avec le sélecteur à globe, hors du menu (barre forcée
   en ligne, rangée par rangée) :
     anglais                                    → une rangée dès 946px
     allemand réel (Leistungen, Über uns, Studien, Aktuelles & Termine,
       Karriere, Kontakt)                       → dès 991px
     anglais allongé de 40 % sur une page non anglaise, « Contact » compris
                                                → dès 1147px, 37px libres à 74em
   Le seuil du burger passe donc à 74em (1184px) hors de l'anglais : la marge de
   ~30px du seuil anglais (voir « L'en-tête était cassé… ») pour des libellés que
   le lot de traduction n'a pas encore fixés. `:not(:lang(en))` et non `:lang(de)` :
   une langue ajoutée sans code (docs/78 § 5) hérite du seuil. Garde-fou générique
   en plus : ui.js pose `fi-nav-tight` sur <html> si la barre passe malgré tout
   sur deux rangées (libellé retouché, police de repli) — mêmes effets, à toute
   largeur au-dessus du seuil anglais (61em).
   ⚠️ Le panneau plein écran garde, dans cette plage, la mise à plat des
   sous-menus de la règle « En panneau plein écran… » (60.99em) : elle est
   reprise ici, sinon « About » s'ouvrirait en carte ombrée dans le panneau. */
@media (min-width: 61em) and (max-width: 73.99em) {
	:root:not(:lang(en)) .fi-header .wp-block-navigation__responsive-container:not(.has-modal-open) {
		display: none;
	}

	:root:not(:lang(en)) .fi-header .wp-block-navigation__responsive-container-open {
		display: flex;
	}

	:root:not(:lang(en)) .fi-header .fi-nav .has-child .wp-block-navigation__submenu-container {
		width: auto;
		max-width: none;
		padding: 0;
		border: 0;
		border-radius: 0;
		box-shadow: none;
		background: transparent;
	}
}

@media (min-width: 61em) {
	.fi-nav-tight .fi-header .wp-block-navigation__responsive-container:not(.has-modal-open) {
		display: none;
	}

	.fi-nav-tight .fi-header .wp-block-navigation__responsive-container-open {
		display: flex;
	}

	.fi-nav-tight .fi-header .fi-nav .has-child .wp-block-navigation__submenu-container {
		width: auto;
		max-width: none;
		padding: 0;
		border: 0;
		border-radius: 0;
		box-shadow: none;
		background: transparent;
	}
}

/* ── Césure en allemand ──────────────────────────────────────────────────
   26/10/2026 — l'allemand compose des mots longs (« Biomarkerforschung »,
   « Qualitätsmanagementsystem ») que la colonne étroite d'une carte, d'un
   relevé ou d'un écran de 360px ne peut pas tenir : sans césure, ils dépassent
   de leur boîte ou laissent des lignes à deux mots. La césure est donc ACTIVE sur
   les pages allemandes (`lang="de-DE"`, posé par firalis-core) et seulement là —
   l'anglais ne change pas. Les titres ne coupent que les mots d'au moins douze
   lettres, en gardant cinq lettres de chaque côté : une césure de titre se voit,
   et « Leis-tungen » sous un soulignement se lisait mal à 360px (mesuré) ; un mot
   de dix lettres passe à la ligne entier.
   Les boutons, le sélecteur de langue et les étiquettes sur une ligne gardent
   leur `white-space: nowrap`, que la césure ne touche pas. */
:lang(de) body {
	-webkit-hyphens: auto;
	hyphens: auto;
	hyphenate-limit-chars: 8 3 3;
	overflow-wrap: break-word;
}

/* ⚠️ Titres (recette du lot F, 26/10/2026). La limite « 12 5 5 » laissait passer
   « Unter-nehmen. » à 360 — Chrome compte le point final dans le mot. Les titres
   ne coupent plus que les mots de SEIZE signes et plus, six de chaque côté : un
   mot courant passe entier à la ligne, un composé (« Vermarktungs-leistungen »,
   « Mutter-gesellschaft ») se coupe à une vraie frontière. Sans aucune césure
   (essayé), un composé plus long que sa colonne — « Vermarktungsleistungen » en
   h2 à 1280, « Muttergesellschaft » en h1 à 360 — était cassé SANS trait par
   `overflow-wrap` (« …leistung|en »). Les surtitres, en capitales espacées, ne
   coupent jamais. */
:lang(de) :is(h1, h2, h3, h4) {
	hyphenate-limit-chars: 16 6 6;
}

:lang(de) .fi-eyebrow {
	-webkit-hyphens: manual;
	hyphens: manual;
}

/* ── Recette multilingue du 26/10/2026 (lot F) — corrections ciblées ─────
   Toutes portent sur une page NON anglaise (`:root:not(:lang(en))`) : le rendu
   anglais ne change pas d'un pixel (comparé capture par capture). */

/* (a) Panneau du menu : un nom propre ne se coupe pas (« ApoDia|g » à côté de
   son étiquette). Les libellés du menu ne prennent ni césure ni coupure de
   secours ; dans le panneau plein écran, l'étiquette d'état (« Abgeschlossen »)
   passe SOUS le nom quand la ligne ne tient pas, au lieu d'écraser la colonne
   du nom — une rangée souple et non une grille à deux colonnes. */
:root:not(:lang(en)) .fi-header .fi-nav :is(.wp-block-navigation-item__label, .fi-submenu__tag, .fi-nav__parent) {
	-webkit-hyphens: manual;
	hyphens: manual;
	overflow-wrap: normal;
}

:root:not(:lang(en)) .fi-header .fi-nav .wp-block-navigation__responsive-container.has-modal-open .has-child .wp-block-navigation__submenu-container > .wp-block-navigation-item > .wp-block-navigation-item__content {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	column-gap: 0.75rem;
	row-gap: 0.3rem;
}

/* (c) Boutons en allemand : un libellé long passe sur deux lignes ÉQUILIBRÉES
   plutôt qu'un mot seul en bas (« An der Studie Alzevit / teilnehmen ») ; sous
   30em, où les boutons de bande prennent toute la largeur, la réserve latérale
   se resserre pour laisser une chance à une seule ligne. Les « portes »
   d'IVDias et de Lodiag et le relevé des certifications de l'accueil passent
   déjà sur deux lignes en anglais à certaines largeurs : c'est leur dessin, on
   équilibre seulement la coupure. */
:root:not(:lang(en)) :is(.wp-block-button__link, .fi-ivd__door, .fi-lodb__door, .fi-events__tab) {
	text-wrap: balance;
}

/* Ni césure ni équilibrage sur ces libellés courts : équilibrées, les deux lignes
   du relevé « Zertifizierungen & Akkreditierungen » coupaient le premier mot
   (« ZERTIFIZIERUN-/GEN », mesuré à 768). Un libellé de bouton ou d'étiquette
   passe ses mots entiers à la ligne. */
:root:not(:lang(en)) :is(.wp-block-button__link, .fi-ivd__door, .fi-lodb__door, .fi-events__tab, .fi-assurance__k, .fi-assurance__btn) {
	-webkit-hyphens: manual;
	hyphens: manual;
}

@media (max-width: 30em) {
	:root:not(:lang(en)) :is(.fi-hero, .fi-heroW, .fi-heroX, .fi-cta, .fi-study, .fi-cop, .fi-404) .wp-block-button__link {
		padding-inline: 1rem;
	}
}

/* (d) Pipeline d'Amoneta : règle retirée le 27/10/2026 avec la bande qui la
   portait — la fiche est devenue une porte d'un écran (docs/79-fiches-porte.md),
   l'escalier condensé gère l'allemand dans css/company-amoneta.css. */

/* (e) En-tête à 360 : « Kontakt » ne laissait aucun pixel de marge (une langue
   40 % plus longue débordait de 4px). Les resserrements posés ici jusqu'à 24em
   hors de l'anglais vont désormais jusqu'à 26em — hors de l'anglais comme
   avant, et dans toute langue dès que le sélecteur est dans la barre, où son
   globe a rejoint le burger : voir « Barre de téléphone » dans le bloc du
   sélecteur, plus haut. */

/* (f) Carte de /contact/ : une étiquette ne sort plus du cadre. Écrite vers la
   gauche, elle ne dépasse pas la distance de son repère au bord gauche ; vers la
   droite, celle qui le sépare du bord droit — au-delà, elle passe sur deux lignes.
   `--x` est la position du repère, en pourcentage du cadre (le bloc conteneur de
   l'étiquette). Une étiquette plus courte que la place ne change pas. */
:root:not(:lang(en)) .fi-map__pin--l {
	max-inline-size: calc(var(--x) - 0.25rem);
	white-space: normal;
}

:root:not(:lang(en)) .fi-map__pin--r {
	max-inline-size: calc(100% - var(--x) - 0.25rem);
	white-space: normal;
}

/* Un nom d'étiquette plus long que sa place se coupe en dernier recours plutôt
   que de sortir du cadre. Les noms de pays, centrés sur leur repère, restent sur
   une ligne : « DEUTSCHLAND » tient à 360 au ras de sa place (bornés, il passait
   sur deux lignes — essayé). */
:root:not(:lang(en)) .fi-map__pin {
	box-sizing: border-box; /* la borne compte la réserve du repère (1.1 à 2rem) */
	overflow-wrap: anywhere;
}

/* « DEUTSCHLAND », plus long que « GERMANY », touchait la flèche du nord dans un
   petit cadre (360) : l'interlettrage des noms de pays se resserre. */
@container fi-map (inline-size < 28rem) {
	:root:not(:lang(en)) .fi-map__zone {
		letter-spacing: 0.08em;
	}
}

/* (g) Libellé d'allèle d'Alzevit (« Protective ») dans sa cellule à 360 : coupé
   en dernier recours plutôt que débordant. */
:root:not(:lang(en)) .fi-alleles__e {
	overflow-wrap: anywhere;
}
