/* =========================================================================
   ORVETA — orveta.fr
   Direction artistique : « la ligne de partage »
   Voir documentation/01-direction-artistique.md
   ========================================================================= */

/* ---------- Polices (auto-hébergées, latin) ------------------------------ */

/* TROIS familles, chacune avec un rôle et une raison.

   ARCHIVO — les surtitres, la navigation, le texte courant. Validée par le
   client, jamais remise en question.

   PLAYFAIR DISPLAY (SIL OFL) — les titres. Elle succède à Bodoni Moda, qui
   n'aura tenu qu'une version : son délié mesurait **0,0021 em** contre
   0,0177 à Playfair, soit huit fois plus fin, et le client l'a vu — « certains
   traits sur les mots sont trop fins ». Playfair garde le fort contraste qui
   fait la présence de luxe (5,6:1) sans que les déliés se dissolvent sur le
   fond carbone.

   FRAUNCES (SIL OFL) — RÉSERVÉE aux titres de conversion finale
   (« .final-titre »), à la demande explicite du client qui l'y voulait
   revenir. Sa chaleur y tranche avec la rigueur de Playfair : le bloc qui
   demande d'écrire ne parle pas de la même voix que ceux qui exposent. */
@font-face {
	font-family: "Playfair Display";
	src: url("../polices/playfair.woff2") format("woff2");
	font-weight: 400 700;
	font-style: normal;
	font-display: swap;
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
	font-family: "Playfair Display";
	src: url("../polices/playfair-italique.woff2") format("woff2");
	font-weight: 400 700;
	font-style: italic;
	font-display: swap;
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
	font-family: "Fraunces";
	src: url("../polices/fraunces.woff2") format("woff2");
	font-weight: 400 700;
	font-style: normal;
	font-display: swap;
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
	font-family: "Fraunces";
	src: url("../polices/fraunces-italique.woff2") format("woff2");
	font-weight: 400 700;
	font-style: italic;
	font-display: swap;
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
	font-family: "Archivo";
	src: url("../polices/archivo.woff2") format("woff2");
	font-weight: 100 900;
	font-stretch: 62% 125%;
	font-style: normal;
	font-display: swap;
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ---------- Jetons -------------------------------------------------------- */

:root {
	/* couleurs — DA « Carbone & Rubis », validée le 30 août 2026.
	   Le site vit en noir charbon chaud ; les chapitres « clairs »
	   (approche, final) sont ses respirations. Deux rouges : le rubis
	   clair porte le texte sur carbone, le vermillon porte le texte
	   sur clair — le rouge profond #C9261F ne porte jamais de texte. */
	--carbone: #141210;
	--carbone-2: #1C1916;
	--ivoire: #EFE9DC;
	--ivoire-douce: #B5AC9D;
	--clair: #F2EDE3;
	--encre: #191510;
	--encre-douce: #5B5342;
	--rubis: #F0655A;
	--vermillon: #B3261E;
	--filet: rgba(239, 233, 220, 0.18);
	--filet-sur-clair: rgba(25, 21, 16, 0.16);

	/* typographies */
	/* Ni Playfair ni Fraunces ne descendent sous 400 : toute graisse inférieure
	   y serait écrasée en silence. Les règles de titre disent donc 400. */
	--police-titre: "Playfair Display", Georgia, "Times New Roman", serif;
	/* réservée aux titres de conversion finale — voir le bloc @font-face */
	--police-final: "Fraunces", Georgia, "Times New Roman", serif;
	--police-texte: "Archivo", system-ui, "Segoe UI", sans-serif;

	/* échelle */
	--t-affiche: clamp(3.2rem, 9.5vw, 10.5rem); /* plafond relevé le 30/08 : le
	   wordmark restait à 136 px dès 1440 px et se perdait sur un 2560. Le
	   jeton ne sert qu'au hero ; rien ne bouge sous 1432 px. */
	--t-chapitre: clamp(2.1rem, 5.5vw, 4.4rem);
	--t-projet: clamp(1.7rem, 4vw, 3rem);
	--t-corps: 1.0625rem;
	--t-contexte: 0.9375rem;
	--t-label: 0.72rem;

	/* mouvement : une seule courbe */
	--courbe: cubic-bezier(0.19, 1, 0.22, 1);
	--d-court: 0.6s;
	--d-rideau: 0.8s;

	/* rythme */
	--marge-section: clamp(5rem, 14vh, 10rem);
	--gouttiere: clamp(1.25rem, 5vw, 4rem);
}

/* ---------- Socle --------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html {
	scroll-behavior: smooth;
	scroll-padding-top: 5.5rem;
	-webkit-text-size-adjust: 100%;
}

body {
	margin: 0;
	background: var(--carbone);
	color: var(--ivoire);
	font-family: var(--police-texte);
	font-size: var(--t-corps);
	line-height: 1.7;
	font-optical-sizing: auto;
	-webkit-font-smoothing: antialiased;
	overflow-x: clip;
}

h1, h2, h3, p, ul, ol, figure { margin: 0; }
ul[class], ol[class] { padding: 0; list-style: none; }
button { font: inherit; color: inherit; background: none; border: none; padding: 0; cursor: pointer; }
a { color: inherit; }
svg { display: block; }

::selection { background: var(--rubis); color: var(--carbone); }

:focus-visible {
	outline: 2px solid var(--rubis);
	outline-offset: 3px;
	border-radius: 1px;
}
.chapitre-clair :focus-visible { outline-color: var(--vermillon); }

.acces-rapide {
	position: fixed;
	top: -100%;
	left: 1rem;
	z-index: 100;
	padding: 0.7em 1.2em;
	background: var(--ivoire);
	color: var(--carbone);
	text-decoration: none;
	font-size: var(--t-contexte);
	transition: top 0.2s;
}
.acces-rapide:focus { top: 1rem; }

.visuellement-cache {
	position: absolute !important;
	width: 1px; height: 1px;
	margin: -1px; padding: 0;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

/* ---------- Petits systèmes ----------------------------------------------- */

.interieur {
	max-width: 76rem;
	margin-inline: auto;
	padding-inline: var(--gouttiere);
}

/* le label technique : un trait vertical, des capitales espacées */
.label {
	display: inline-flex;
	align-items: baseline;
	flex-wrap: wrap;
	gap: 0.35em 0.9em;
	font-size: var(--t-label);
	font-weight: 560;
	font-stretch: 118%;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var(--ivoire-douce);
	font-variant-numeric: tabular-nums;
}
.label::before {
	content: "";
	width: 1px;
	height: 1.15em;
	background: var(--rubis);
	flex: none;
	align-self: center;
}
.chapitre-clair .label { color: var(--encre-douce); }
.chapitre-clair .label::before { background: var(--vermillon); }
/* LE TRAIT RESTE ACCROCHÉ À LA PREMIÈRE LIGNE quand un label sans enfant se
   replie : avec « wrap », le texte trop long passait entier à la ligne et
   laissait le trait seul au-dessus (banc, 390 et 320). Le décalage recentre
   le trait sur la première ligne, comme le faisait « center » : à 1440, où
   tout tient sur une ligne, rien ne bouge. */
.label:not(:has(> *)) { flex-wrap: nowrap; }
.label:not(:has(> *))::before { align-self: flex-start; margin-block-start: calc((1lh - 1.15em) / 2); }

/* le lien : soulignement qui balaie */
.lien {
	text-decoration: none;
	background-image: linear-gradient(currentColor, currentColor), linear-gradient(var(--rubis), var(--rubis));
	background-size: 100% 1px, 0 1px;
	background-position: left 100%, left 100%;
	background-repeat: no-repeat;
	transition: background-size var(--d-court) var(--courbe), color var(--d-court) var(--courbe);
	padding-bottom: 0.15em;
}
.lien:hover, .lien:focus-visible {
	background-size: 0 1px, 100% 1px;
	color: var(--rubis);
}
.chapitre-clair .lien:hover, .chapitre-clair .lien:focus-visible { color: var(--vermillon); }
.chapitre-clair .lien {
	background-image: linear-gradient(currentColor, currentColor), linear-gradient(var(--vermillon), var(--vermillon));
}

/* le bouton : remplissage depuis la ligne de gauche */
.bouton {
	position: relative;
	display: inline-flex;
	align-items: center;
	gap: 0.8em;
	padding: 1em 1.6em;
	border: 1px solid var(--ivoire);
	border-radius: 2px;
	font-size: 0.9375rem;
	font-weight: 540;
	letter-spacing: 0.05em;
	text-decoration: none;
	color: var(--ivoire);
	overflow: hidden;
	transition: color var(--d-court) var(--courbe), border-color var(--d-court) var(--courbe), transform var(--d-court) var(--courbe);
}
.bouton::before {
	content: "";
	position: absolute;
	inset: 0;
	background: var(--ivoire);
	transform: scaleX(0);
	transform-origin: left center;
	transition: transform var(--d-court) var(--courbe);
	z-index: 0;
}
.bouton > * { position: relative; z-index: 1; }
.bouton .fleche { transition: transform var(--d-court) var(--courbe); }
.bouton:hover, .bouton:focus-visible { color: var(--carbone); transform: translateY(-2px); }
.bouton:hover::before, .bouton:focus-visible::before { transform: scaleX(1); }
.bouton:hover .fleche, .bouton:focus-visible .fleche { transform: translateX(0.35em); }
.bouton:active { transform: translateY(1px); }
.diagnostic-reponses button:active { transform: translateY(1px); }

.chapitre-clair .bouton { border-color: var(--encre); color: var(--encre); }
.chapitre-clair .bouton::before { background: var(--encre); }
.chapitre-clair .bouton:hover, .chapitre-clair .bouton:focus-visible { color: var(--clair); }

/* LE NIVEAU PRINCIPAL : l'état de survol, figé dès le repos. Aucune couleur
   nouvelle (carbone / ivoire 15,45:1, clair / encre 15,57:1). La variante
   claire vient APRÈS « .chapitre-clair .bouton » : à poids égal, l'ordre
   tranche — avant, le texte encre disparaîtrait sur l'aplat encre. */
.bouton-principal { color: var(--carbone); }
.bouton-principal::before { transform: scaleX(1); }
.chapitre-clair .bouton-principal { color: var(--clair); }
/* L'ACCUEIL PORTE DÉJÀ LE FORMULAIRE : au pied, le bouton reprend le contour
   — un seul principal par écran, même au passage contact → pied (banc :
   « Préparer le courriel » et le bouton du pied visibles ensemble, à 1440
   comme à 390). Le HTML du pied reste identique sur les six pages. */
body:has(#formulaire) .pied-conclusion .bouton-principal { color: var(--ivoire); }
body:has(#formulaire) .pied-conclusion .bouton-principal::before { transform: scaleX(0); }
body:has(#formulaire) .pied-conclusion .bouton-principal:hover,
body:has(#formulaire) .pied-conclusion .bouton-principal:focus-visible { color: var(--carbone); }
body:has(#formulaire) .pied-conclusion .bouton-principal:hover::before,
body:has(#formulaire) .pied-conclusion .bouton-principal:focus-visible::before { transform: scaleX(1); }

/* LA LIGNE DE PARTAGE MARQUE LA SECTION — piste B, validée le 30 août 2026.
   Avant : un trait horizontal rouge de 6 rem suspendu sous le titre. Il
   empruntait son vocabulaire ailleurs (l'identité du site est une ligne
   VERTICALE) et ne structurait rien : le « soulignement d'accent » que tous
   les gabarits posent sous leurs titres.
   Après : la verticale du concept descend dans la marge le long de tout
   l'en-tête, en dégradé qui s'éteint. Une seule verticale à la fois — le
   petit tiret du label s'efface au profit d'elle. */
.section-entete {
	position: relative;
}
.section-entete::before {
	content: "";
	position: absolute;
	left: -1rem;          /* reste dans la gouttière, min. 1,25 rem */
	top: 0.45rem;
	bottom: 0.2rem;
	width: 1px;
	background: linear-gradient(var(--rubis), rgba(240, 101, 90, 0));
}
.chapitre-clair .section-entete::before {
	background: linear-gradient(var(--vermillon), rgba(179, 38, 30, 0));
}
.section-entete .label::before { display: none; }
@media (max-width: 40em) { .section-entete::before { left: -0.7rem; } }

/* en-tête récurrent de section */
.section-entete { margin-bottom: clamp(2.5rem, 6vh, 4.5rem); }
.section-entete .label { margin-bottom: 1.4rem; }
.titre-chapitre {
	font-family: var(--police-titre);
	font-weight: 400;
	font-size: var(--t-chapitre);
	line-height: 1.05;
	letter-spacing: -0.01em;
	max-width: 18ch;
	text-wrap: balance;
}
.titre-chapitre em {
	font-style: italic;
	font-weight: 400;
	color: var(--rubis);
}
.chapitre-clair .titre-chapitre em { color: var(--vermillon); }

.texte-conduit {
	max-width: 58ch;
	color: var(--ivoire-douce);
}
.chapitre-clair .texte-conduit { color: var(--encre-douce); }

section { padding-block: var(--marge-section); }

/* ---------- Révélations au défilement : RETIRÉES ---------------------------
   Le 1er septembre 2026, à la demande du client : « il faut que les textes
   soient affichés dès l'arrivée sur la page ». Plus rien n'est caché en
   attendant le défilement — le texte est là à la première peinture, sur
   toutes les pages.

   Les attributs `data-revele` restent dans le HTML : ils ne coûtent rien, ils
   nomment encore l'intention de chaque bloc, et le jour où une animation
   d'entrée reviendra, elle saura où se poser. Ne PAS les retirer du balisage
   sans raison. */

/* ---------- En-tête / navigation ------------------------------------------ */

.entete {
	position: fixed;
	inset: 0 0 auto 0;
	z-index: 50;
	transition:
		background-color 0.4s var(--courbe),
		box-shadow 0.4s var(--courbe),
		padding 0.4s var(--courbe);
	/* pixels ENTIERS (18 px / 10 px) : entre l’état haut et l’état compact, la
	   marque gardait une position fractionnaire différente — l’arrondi
	   sous-pixel basculait et le O paraissait aligné dans un état, pas dans
	   l’autre. C’était la vraie cause du défaut signalé. */
	padding-block: 1.125rem;
}
.entete.est-compacte {
	background: rgba(20, 18, 16, 0.94);
	box-shadow: 0 1px 0 var(--filet);
	padding-block: 0.625rem;
}
/* SANS JAVASCRIPT, l'en-tête ne devient jamais compact : fixe et
   transparent, il passait sur le texte à chaque écran (banc, --sans-js,
   1440). Il reste en haut de page. Sous 56 em, la règle « static » plus
   bas garde la main. */
html:not(.js-actif) .entete { position: absolute; }
/* LE FLOU EST PORTÉ PAR UN PSEUDO-ÉLÉMENT, JAMAIS PAR L'EN-TÊTE (rc65).
   Un « backdrop-filter » posé sur .entete en faisait le bloc conteneur de
   ses descendants fixes : le panneau du menu mobile (« position: fixed;
   inset: 0 ») restait enfermé dans les 64 px de l'en-tête compact — deux
   liens hors écran, deux illisibles. Or l'en-tête est compact dès le
   chargement sur les études de cas : le menu y était cassé d'emblée.
   Un pseudo-élément floute le même fond sans rien contenir. */
@supports (backdrop-filter: blur(4px)) {
	.entete.est-compacte { background: transparent; }
	.entete::before {
		content: "";
		position: absolute;
		inset: 0;
		z-index: -1;
		background: rgba(20, 18, 16, 0.86);
		backdrop-filter: blur(8px);
		opacity: 0;
		transition: opacity 0.4s var(--courbe);
		pointer-events: none;
	}
	.entete.est-compacte::before { opacity: 1; }
}

.entete-interieur {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 2rem;
}

/* LE LOGOTYPE — en-tête et pied. Il était en Archivo, ce qui obligeait le
   symbole à imiter un O presque circulaire à trait quasi constant : à 16 px
   cela ne faisait pas une marque, cela faisait une puce. Il passe à la police
   de titre le 1er septembre 2026, à la demande du client, et le symbole peut
   enfin être l'ovale modulé qu'il est ailleurs. Une seule marque sur tout le
   site, en trois poids optiques — comme le ferait une vraie fonte. */
.marque {
	display: inline-flex;
	align-items: center;
	gap: 0.28em;
	text-decoration: none;
	font-weight: 620;
	font-stretch: 118%;
	font-size: 0.98rem;
	letter-spacing: 0.16em;
	line-height: 1;
}
/* le symbole tient la hauteur du O de Playfair (0,7357 em) et déborde de
   0,0129 em sous la ligne de base, comme le fait la panse d'un O */
.marque { align-items: baseline; }
.marque svg {
	/* Calé sur le O réel d’ARCHIVO 620 À LARGEUR 118 % — celle du logotype.
	   Première tentative fausse : le O avait été mesuré à la largeur par
	   défaut, d’où un symbole 22 % trop étroit au milieu de lettres élargies,
	   qui se lisait comme une puce. Mesures : hauteur 0,7086 em · facteur de
	   largeur 1,2143 → rapport l/h 1,19, le O est PLUS LARGE QUE HAUT ·
	   débord 0,01 em. Le décalage passe par « top », jamais par « transform »,
	   laissé libre aux animations. */
	/* EXACTEMENT la hauteur d’encre du O d’Archivo 620, mesurée : 0,71 em.
	   Le symbole ne dépasse plus les lettres — il EST une lettre. */
/* En-tête SEULEMENT : le symbole y monte à 0,79 em, au-dessus de la hauteur
	   d’encre des lettres (0,71). À 15,68 px de corps, la marque a besoin de
	   cette présence — c’est la compensation optique des petits lockups. Le
	   pied, à 24 px, garde 0,71 em : il n’en a pas besoin. Proportion 1,19
	   inchangée, donc même dessin, seulement plus grand. */
	/* MESURÉ au calibre 220 px (rc16) : à 0,79 em le O dépassait les
	   capitales de 0,096 em. Retour à la hauteur du O DE LA POLICE : sommet
	   au niveau des capitales, pied sur la ligne de base. */
	width: 0.8432em;
	height: 0.7086em;
	position: relative;
	/* MESURÉ (rc17) : à 0,012 em le bas du O tombait 0,156 px AU-DESSUS de la
	   ligne de base, au lieu de la dépasser de 0,17 px comme le fait la panse
	   d’un O. 0,033 em le pose exactement à son débord naturel. */
	top: 0.033em;
	flex: none;
}
.marque .o-droite { fill: var(--rubis); }

.nav-liens {
	display: flex;
	gap: clamp(1.4rem, 3vw, 2.6rem);
	font-size: 0.875rem;
	font-weight: 480;
	letter-spacing: 0.04em;
}
.nav-liens a[aria-current] { color: var(--rubis); }
.nav-bouton {
	display: none;
	position: relative;
	z-index: 60;
	font-size: var(--t-label);
	font-weight: 560;
	font-stretch: 118%;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	padding: 0.6em 0.2em;
}

/* voile mobile */
.voile-nav {
	display: none;
}

@media (max-width: 56em) {
	.nav-bouton { display: inline-flex; }
	.nav-liens { display: none; }

	/* SANS JAVASCRIPT, « MENU » N'OUVRE RIEN et les cinq liens sont à 0 × 0
	   (banc, 390 et 320) : ils reprennent sa place, et l'en-tête, devenu plus
	   haut, cesse d'être fixe. Ne couvre pas « orveta.js introuvable » :
	   js-actif est posée par le script en ligne du <head>. */
	html:not(.js-actif) .nav-bouton { display: none; }
	html:not(.js-actif) .entete { position: static; }
	html:not(.js-actif) .nav-liens {
		display: flex;
		flex-wrap: wrap;
		justify-content: flex-end;
		gap: 0.625rem 0.9rem;
		font-size: 0.8125rem;
	}
	/* leur prise de 45 px (plus bas) suppose une seule rangée : empilés, chacun
	   volait le quart bas du lien du dessus (banc, --sans-js, 390 et 320).
	   Bornée à mi-chemin du voisin, elle atteint 24 px sans recouvrement. */
	html:not(.js-actif) .nav-liens .lien::after { inset: -0.3125rem -0.45rem; }

	.voile-nav {
		display: grid;
		position: fixed;
		inset: 0;
		z-index: 55;
		background: var(--clair);
		color: var(--encre);
		place-content: center;
		gap: 1rem;
		text-align: center;
		opacity: 0;
		visibility: hidden;
		transition: opacity var(--d-court) var(--courbe), visibility 0s linear var(--d-court);
	}
	.nav-est-ouverte .voile-nav {
		opacity: 1;
		visibility: visible;
		transition-delay: 0s;
	}
	.nav-est-ouverte { overflow: hidden; }
	.nav-est-ouverte .nav-bouton { color: var(--encre); }

	.voile-nav a {
		font-family: var(--police-titre);
		font-size: clamp(1.9rem, 8vw, 2.8rem);
		font-weight: 400;
		text-decoration: none;
		padding: 0.35em 0.5em;
		opacity: 0;
		transform: translateY(16px);
		transition: opacity var(--d-court) var(--courbe), transform var(--d-court) var(--courbe);
	}
	.nav-est-ouverte .voile-nav a { opacity: 1; transform: none; }
	.nav-est-ouverte .voile-nav a:nth-child(1) { transition-delay: 0.09s; }
	.nav-est-ouverte .voile-nav a:nth-child(2) { transition-delay: 0.18s; }
	.nav-est-ouverte .voile-nav a:nth-child(3) { transition-delay: 0.27s; }
	.nav-est-ouverte .voile-nav a:nth-child(4) { transition-delay: 0.36s; }
	.nav-est-ouverte .voile-nav a:nth-child(5) { transition-delay: 0.45s; }
	.voile-nav a:hover, .voile-nav a:focus-visible { color: var(--vermillon); }
	.voile-nav a[aria-current] { color: var(--vermillon); }
	/* le panneau est clair : l'anneau rubis n'y atteignait que 2,68:1 (rc65) */
	.voile-nav :focus-visible { outline-color: var(--vermillon); }
	/* « Fermer » est au-dessus du panneau clair mais hors de lui : la règle
	   du dessus ne l'atteint pas (rubis 2,68:1, vermillon 5,60:1). */
	.nav-est-ouverte .nav-bouton:focus-visible { outline-color: var(--vermillon); }
}

/* ---------- Hero ----------------------------------------------------------- */

.hero {
	min-height: 100svh;
	display: grid;
	place-items: center;
	position: relative;
	padding-block: 6rem 8rem;
	text-align: center;
	/* LES LETTRES RESTENT DANS LE HERO (rc65). En quittant le hero, le
	   logotype s'écarte : à 320 px la dernière lettre partait de 68 px et
	   débordait l'écran de 12 px — même mécanisme que la dérive des
	   réalisations, trouvé seulement une fois celle-ci contenue. « clip » ne
	   crée pas de conteneur de défilement et laisse l'axe vertical libre. */
	overflow-x: clip;
}

/* le hero vit : au défilement il se lève et s'efface (variables posées en JS) */
.hero .interieur {
	transform: translateY(calc(var(--hero-y, 0) * 1px));
	opacity: var(--hero-o, 1);
}

.hero-titre { font-weight: 400; }

.hero-marque {
	display: flex;
	justify-content: center;
	align-items: baseline;
	font-family: var(--police-titre);
	font-size: var(--t-affiche);
	line-height: 1;
	letter-spacing: 0.045em;
	color: var(--ivoire);
}
.hero-marque .lettre {
	display: inline-block;
	vertical-align: bottom;
	/* pas d'`overflow: hidden` : il rendait la lettre INVISIBLE tant que
	   l'animation n'avait pas tourné. Voir la note de la séquence d'ouverture. */
}
.hero-marque .lettre-int { display: inline-block; }
.hero-marque svg {
	/* le O se comporte comme une lettre : la hauteur des capitales, posé
	   sur leur ligne — pas un badge qui flotte */
	/* Calé sur le O réel de Playfair Display 400, mesuré par rastérisation :
	   hauteur 0,7357 em · rapport l/h 0,8641 · débord 0,0129 em. */
	width: 0.6357em;
	height: 0.7357em;
	margin-right: 0.05em;
	align-self: baseline;
	position: relative;
	top: 0.0129em;
	/* le cercle suit le curseur (position intégrée image par image en JS) */
	transform: translate(calc(var(--vise-x, 0) * 1px), calc(var(--vise-y, 0) * 1px));
	/* AUCUNE TRANSITION (rc27) : le O est conduit par le moteur, comme les
	   lettres. Une transition par-dessus ferait diverger le dessin du corps
	   qui heurte le R — le R serait poussé par un O qui n'est pas là. */
	will-change: transform;
}
.hero-marque .o-gauche { fill: var(--ivoire); }
.hero-marque .o-droite { fill: var(--rubis); }

.hero-slogan {
	display: block;
	margin-top: 2.2rem;
	font-family: var(--police-titre);
	font-weight: 400;
	font-size: clamp(1.25rem, 2.6vw, 1.85rem);
	line-height: 1.35;
	letter-spacing: 0.005em;
}
.hero-slogan em { font-style: italic; color: var(--rubis); }

.hero-sous {
	margin-top: 1.4rem;
	margin-inline: auto;
	max-width: 44ch;
	font-size: var(--t-contexte);
	color: var(--ivoire-douce);
}

.hero-actions {
	margin-top: 3rem;
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	align-items: center;
	gap: 1.4rem 2.2rem;
}
.lien-discret {
	font-size: var(--t-contexte);
	color: var(--ivoire-douce);
}
.chapitre-clair .lien-discret { color: var(--encre-douce); }

.hero-ligne {
	position: absolute;
	bottom: 0;
	left: 50%;
	width: 1px;
	height: clamp(3.5rem, 9vh, 6rem);
	background: linear-gradient(var(--ivoire), rgba(239, 233, 220, 0));
	transform-origin: top center;
}

/* séquence d'ouverture — uniquement quand le script est là.
   RÈGLE D'ARCHITECTURE : l'état de repos d'un élément est son état FINAL, et
   les états de départ vivent dans les `from{}` des animations.

   CORRECTION DU 1er SEPTEMBRE 2026 — la note qui tenait ici affirmait que si
   les animations ne s'exécutaient pas, « tout est simplement visible ».
   C'EST FAUX, et c'était mesurable : quand l'horloge d'animation est gelée
   (`playState` dit « running » mais `currentTime` reste à 0 — constaté),
   `fill-mode: both` maintient le `from{}` POUR TOUJOURS. Le hero devenait
   alors entièrement vide : lettres à `translateY(112%)` sous un masque
   `overflow: hidden`, O à `opacity: 0`, slogan coupé par son rideau.

   RÈGLE RENFORCÉE : aucun texte, aucune marque ne démarre invisible. Les
   entrées du hero n'animent plus que la POSITION, sur une amplitude qui ne
   sort d'aucun masque. Horloge gelée = tout est lisible, seulement pas encore
   posé. C'est la seule forme de la règle qui tienne debout. */
.js-actif .hero-marque .lettre-int {
	animation: lever-lettre 0.8s var(--courbe) both;
	animation-delay: calc(0.05s + var(--l-index, 0) * 0.04s);
}
/* le O ne s'anime plus à l'arrivée : il est le pivot fixe autour duquel les
   lettres se posent — et il ne peut donc jamais manquer au mot. */
/* RÈGLE (1er septembre 2026) : les DURÉES restent longues — le geste doit
   être ample — mais les DÉLAIS sont réduits au minimum. Un mouvement lent
   n’est pas une attente : tout se met en marche avant 0,45 s et tout est
   posé à 1,15 s, au lieu de 2,15 s. Le client ne doit jamais attendre un
   texte ; il peut le regarder se poser. */
/* pendant le hero, la moitié « après » du O dérive imperceptiblement */
.js-actif .hero-marque .o-droite {
	transform-origin: 50% 50%;
	animation: deriver 11s ease-in-out 3s infinite alternate;
}
/* le slogan monte, il ne se dévoile plus derrière un rideau : c'est le plus
   grand texte du site, il ne doit dépendre d'aucune horloge pour être lu. */
.js-actif .hero-slogan {
	animation: lever var(--d-rideau) var(--courbe) 0.1s both;
}
.js-actif .hero-sous,
.js-actif .hero-actions {
	animation: lever var(--d-court) var(--courbe) 0.25s both;
}
.js-actif .hero-actions { animation-delay: 0.35s; }
.js-actif .hero-ligne {
	transform-origin: top center;
	animation: tracer-bas 0.7s var(--courbe) 0.45s both;
}

@keyframes lever-lettre { from { transform: translateY(0.26em); } to { transform: translateY(0); } }
/* 1,5° et non 5° : au-delà, la rotation refermait le jeu de la ligne de
   partage en bas et l'ouvrait démesurément en haut — l'asymétrie que le
   client avait repérée. La dérive doit rester imperceptible. */
@keyframes deriver { from { transform: rotate(0deg); } to { transform: rotate(1.5deg); } }
@keyframes lever { from { transform: translateY(14px); } to { transform: none; } }
@keyframes tracer-bas { from { transform: scaleY(0); } to { transform: scaleY(1); } }

/* ---------- Le constat ----------------------------------------------------- */

.constat-grille {
	display: grid;
	grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
	gap: clamp(2.5rem, 6vw, 5rem);
	align-items: center;
}

.constat-question {
	font-family: var(--police-titre);
	font-weight: 400;
	font-size: var(--t-chapitre);
	line-height: 1.12;
	letter-spacing: -0.01em;
	max-width: 16ch;
}
.constat-question .q2 {
	display: block;
	font-style: italic;
	font-weight: 400;
	color: var(--rubis);
	margin-top: 0.2em;
}
.constat-texte { margin-top: 2rem; }
.constat-actions {
	margin-top: 2.4rem;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 1.2rem 2.2rem;
}

/* le spécimen : une page vieillissante que la ligne répare */
.specimen {
	position: relative;
	aspect-ratio: 4 / 5;
	max-width: 26rem;
	margin-left: auto;
	border: 1px solid var(--filet);
	background: var(--carbone-2);
	overflow: hidden;
	container-type: inline-size;
	cursor: pointer;
}
.specimen-face {
	position: absolute;
	inset: 0;
	padding: clamp(1rem, 8cqw, 2rem);
	display: flex;
	flex-direction: column;
	gap: 0.7rem;
}

.specimen .barre {
	height: 0.55rem;
	background: var(--s-encre, #9A958B);
	opacity: 0.8;
}
.specimen-avant { --s-encre: #8E8A80; background: #DDD9CF; }
.specimen-avant .barre { border-radius: 99px; }
.specimen-avant .b-nav { display: flex; gap: 4cqw; margin-bottom: 6cqw; }
.specimen-avant .b-nav .barre { flex: 1; height: 0.4rem; }
.specimen-avant .b-titre { width: 55%; height: 1rem; transform: rotate(-0.5deg); }
.specimen-avant .b-t2 { width: 80%; }
.specimen-avant .b-t3 { width: 72%; margin-left: 6%; transform: rotate(0.4deg); }
.specimen-avant .b-t4 { width: 64%; }
.specimen-avant .b-image {
	flex: 1;
	background: repeating-linear-gradient(-45deg, #C9C4B8 0 6px, #D6D2C7 6px 12px);
	display: grid;
	place-items: center;
}
.specimen-avant .b-image span {
	font-size: 0.62rem;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: #6F6A5F;
	background: #DDD9CF;
	padding: 0.3em 0.8em;
}
.specimen-avant .b-pied { width: 40%; height: 0.4rem; margin-top: auto; }

.specimen-apres {
	background: var(--carbone);
	clip-path: inset(0 100% 0 0);
}
.specimen-apres .a-label {
	font-size: 0.58rem;
	font-weight: 560;
	font-stretch: 118%;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var(--ivoire-douce);
	border-left: 1px solid var(--rubis);
	padding-left: 0.8em;
}
.specimen-apres .a-titre {
	font-family: var(--police-titre);
	font-size: clamp(1.1rem, 9cqw, 1.7rem);
	line-height: 1.1;
	margin-top: 0.4rem;
}
.specimen-apres .barre { height: 0.45rem; background: var(--ivoire); opacity: 0.16; }
.specimen-apres .a-t1 { width: 86%; }
.specimen-apres .a-t2 { width: 74%; }
.specimen-apres .a-colonne {
	flex: 1;
	margin-top: 0.5rem;
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 0.7rem;
}
.specimen-apres .a-carte {
	border: 1px solid var(--filet);
	padding: 0.7rem;
	display: flex;
	flex-direction: column;
	gap: 0.45rem;
}
.specimen-apres .a-carte i {
	font-style: normal;
	font-size: 0.6rem;
	letter-spacing: 0.14em;
	color: var(--rubis);
	font-variant-numeric: tabular-nums;
}
.specimen-apres .a-carte .barre { height: 0.35rem; }
.specimen-apres .a-pied { width: 34%; height: 0.35rem; margin-top: auto; background: var(--rubis); opacity: 1; }

.specimen-ligne {
	position: absolute;
	top: 0;
	bottom: 0;
	left: 0;
	width: 2px;
	background: var(--rubis);
	transform: translateX(-2px);
}
.specimen-legende {
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0.6rem;
	display: flex;
	justify-content: space-between;
	padding-inline: 0.8rem;
	font-size: 0.58rem;
	font-weight: 560;
	font-stretch: 118%;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--ivoire-douce);
	pointer-events: none;
}

.js-actif .specimen.est-joue .specimen-apres {
	clip-path: inset(0);
	transition: clip-path 1.6s var(--courbe) 0.3s;
}
.js-actif .specimen.est-joue .specimen-ligne {
	transform: translateX(100cqw);
	transition: transform 1.6s var(--courbe) 0.3s;
}
.specimen-note {
	margin-top: 0.9rem;
	max-width: 26rem;
	margin-left: auto;
	font-size: 0.8125rem;
	color: var(--ivoire-douce);
	text-align: right;
}

/* ---------- La transformation (comparateur) -------------------------------- */

.transformation { background: var(--carbone-2); }

.comparateur { --pos: 50%; }
.comparateur-scene {
	position: relative;
	aspect-ratio: 16 / 10;
	border: 1px solid var(--filet);
	background: var(--carbone);
	overflow: hidden;
	container-type: inline-size;
}
.comparateur-scene:has(.comparateur-curseur:focus-visible) {
	outline: 2px solid var(--rubis);
	outline-offset: 4px;
}

.panneau { position: absolute; inset: 0; overflow: hidden; }
.panneau-apres { clip-path: inset(0 0 0 var(--pos)); }

.comparateur-ligne {
	position: absolute;
	top: 0;
	bottom: 0;
	left: var(--pos);
	width: 2px;
	margin-left: -1px;
	background: var(--rubis);
	pointer-events: none;
}
.comparateur-poignee {
	position: absolute;
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
	width: 2.9rem;
	height: 2.9rem;
	border-radius: 50%;
	background: var(--rubis);
	color: var(--carbone);
	display: grid;
	place-items: center;
	font-size: 0.9rem;
	letter-spacing: 0.12em;
	text-indent: 0.12em;
}

.comparateur-curseur {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	margin: 0;
	opacity: 0;
	cursor: ew-resize;
	touch-action: pan-y;
	-webkit-appearance: none;
	appearance: none;
}

.comparateur-legende {
	margin-top: 1rem;
	display: flex;
	justify-content: space-between;
	gap: 1rem;
	font-size: var(--t-label);
	font-weight: 560;
	font-stretch: 118%;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--ivoire-douce);
}
.comparateur-legende .apres { color: var(--rubis); }

/* les maquettes : primitives communes */
.maquette {
	position: absolute;
	inset: 0;
	padding: clamp(0.9rem, 4cqw, 2.4rem);
	display: flex;
	flex-direction: column;
	gap: clamp(0.5rem, 1.6cqw, 1rem);
	background: var(--m-fond, var(--carbone));
	color: var(--m-encre, var(--ivoire));
	font-size: clamp(0.55rem, 1.7cqw, 0.85rem);
	line-height: 1.4;
}
.m-nav {
	display: flex;
	align-items: center;
	gap: 1.5em;
	padding-bottom: 0.8em;
	font-size: 0.85em;
}
.m-nom { font-weight: 640; letter-spacing: 0.08em; margin-right: auto; }
.m-note {
	display: inline-block;
	width: fit-content;
	font-size: 0.78em;
	letter-spacing: 0.08em;
	padding: 0.35em 0.8em;
	border: 1px solid currentColor;
	border-radius: 99px;
	opacity: 0.85;
}
.m-chiffre { font-variant-numeric: tabular-nums; }

/* — l'avant : gabarit 2013 — */
.maquette-avant {
	--m-fond: #E3E1DA;
	--m-encre: #57554E;
	font-family: Arial, Helvetica, sans-serif;
}
.maquette-avant .m-nav { border-bottom: 1px solid #C6C3BA; flex-wrap: wrap; row-gap: 0.3em; }
.maquette-avant .m-nav span:not(.m-nom) { opacity: 0.75; }
.maquette-avant .m-h1 {
	font-size: 0.72em;
	font-weight: 700;
	color: #7A776E;
}
.maquette-avant .m-cyan { color: #00AEF4; }
.maquette-avant .m-image {
	flex: 1;
	min-height: 0;
	background: repeating-linear-gradient(-45deg, #CFCCC2 0 7px, #DAD7CE 7px 14px);
	border: 1px solid #C6C3BA;
	display: grid;
	place-items: center;
	text-align: center;
	padding: 1em;
}
.maquette-avant .m-image .m-note { background: #E3E1DA; }
.maquette-avant .m-pied {
	display: flex;
	flex-wrap: wrap;
	gap: 0.6em;
	align-items: center;
	font-size: 0.85em;
}

/* — l'après : la refonte, dans sa propre identité — */
.maquette-apres {
	--m-fond: #FBFAF7;
	--m-encre: #1A1B1E;
	font-family: Georgia, "Times New Roman", serif;
}
.maquette-apres .m-nav {
	font-family: var(--police-texte);
	border-bottom: 1px solid var(--m-lien, var(--rubis));
}
.maquette-apres .m-h1 {
	font-size: clamp(1rem, 6cqw, 2.4rem);
	line-height: 1.08;
	font-weight: 500;
	text-align: center;
	margin-inline: auto;
	padding-block: 0.4em;
}
.maquette-apres .m-h1 em { font-style: italic; color: var(--m-lien, var(--rubis)); }
.maquette .m-texte {
	display: grid;
	gap: 0.7em;
	margin-block: auto;
}
.maquette .m-texte i {
	display: block;
	height: 0.5em;
	background: currentColor;
	opacity: 0.14;
	margin-inline: auto;
}
.maquette-apres .m-portes {
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	gap: 0.6em;
	margin-top: auto;
	font-family: var(--police-texte);
}
.maquette-apres .m-porte {
	border: 1px solid rgba(26, 27, 30, 0.18);
	padding: 0.7em 0.6em;
	display: flex;
	flex-direction: column;
	gap: 0.4em;
	font-size: 0.82em;
}
.maquette-apres .m-porte i {
	font-style: normal;
	color: var(--m-lien, var(--rubis));
	font-variant-numeric: tabular-nums;
	letter-spacing: 0.1em;
	font-size: 0.85em;
}
.maquette-apres .m-pied {
	display: flex;
	flex-wrap: wrap;
	gap: 0.6em;
	align-items: center;
	justify-content: space-between;
	font-family: var(--police-texte);
	font-size: 0.85em;
}
.maquette-apres .m-pied .m-note {
	border-color: var(--m-lien, var(--rubis));
	color: var(--m-lien, var(--rubis));
	opacity: 1;
}

/* ---------- Les réalisations ------------------------------------------------ */

.realisations .section-entete { max-width: 46rem; }

.projet-numero {
	font-size: var(--t-label);
	font-weight: 560;
	font-stretch: 118%;
	letter-spacing: 0.18em;
	color: var(--rubis);
	font-variant-numeric: tabular-nums;
}
.projet-secteur {
	font-family: var(--police-titre);
	font-weight: 420;
	font-size: var(--t-projet);
	line-height: 1.08;
	margin-top: 0.6rem;
	max-width: 14ch;
}
.projet-code {
	margin-top: 0.9rem;
	font-size: var(--t-label);
	font-weight: 540;
	font-stretch: 118%;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--ivoire-douce);
}
.projet-intention {
	margin-top: 1.6rem;
	color: var(--ivoire-douce);
	max-width: 44ch;
}
.projet-faits {
	margin-top: 1.8rem;
	display: grid;
	gap: 0.65rem;
	font-size: var(--t-contexte);
}
.projet-faits li {
	position: relative;
	padding-left: 2em;
}
.projet-faits li::before {
	content: "";
	position: absolute;
	left: 0;
	top: 0.78em;
	width: 1.1em;
	height: 1px;
	background: var(--rubis);
}
/* le statut d'une réalisation — toujours dit, jamais laissé deviner */
.statut {
	display: inline-flex;
	align-items: center;
	gap: 0.7em;
	width: fit-content;
	font-size: var(--t-label);
	font-weight: 560;
	font-stretch: 114%;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--ivoire-douce);
	border: 1px dashed var(--filet);
	border-radius: 99px;
	padding: 0.5em 1.1em;
	font-variant-numeric: tabular-nums;
}
.statut::before {
	content: "";
	width: 0.5em;
	height: 0.5em;
	border-radius: 50%;
	background: var(--rubis);
}
.chapitre-clair .statut { color: var(--encre-douce); border-color: var(--filet-sur-clair); }
.chapitre-clair .statut::before { background: var(--vermillon); }

/* identités propres aux trois refontes */
/* « Froid & chaud » : les jetons du thème de la maquette (theme.json) —
   brume, encre, givre profond, soleil profond. Jusqu'en rc65, cette classe
   portait la palette d'une AUTRE entreprise : l'étude en mélangeait deux. */
.maquette-froid-chaud {
	--m-fond: #F5F8F8;
	--m-encre: #101E26;
	--m-lien: #0E6E6A;
	font-family: var(--police-texte);
}
.maquette-froid-chaud .m-h1 { font-family: var(--police-texte); font-weight: 640; }
.maquette-froid-chaud .m-froid { color: #0E6E6A; }
.maquette-froid-chaud .m-chaud { color: #8A5A08; }
.maquette-froid-chaud .m-pilules { display: flex; gap: 0.6em; flex-wrap: wrap; font-family: var(--police-texte); }
.maquette-froid-chaud .m-pilules .m-note { border-radius: 99px; }

.maquette-palais {
	--m-fond: #0E0F12;
	--m-encre: #F4F1EA;
	--m-lien: #D4B369;
	font-family: Georgia, serif;
}
.maquette-palais .m-nav { border-bottom-color: #B5934C; }
.maquette-palais .m-filet-or { width: 3.5em; height: 1px; background: #B5934C; }
.maquette-palais .m-porte { border-color: rgba(244, 241, 234, 0.22); }
.maquette-palais .m-porte i { color: #D4B369; }
.maquette-palais .m-pied .m-note { border-color: #D4B369; color: #D4B369; }

.maquette-encre-mini {
	--m-fond: #FBFAF7;
	--m-encre: #1A1B1E;
	--m-lien: #0B6E97;
}

/* avant génériques par projet.
   « Froid & chaud » : ce que l'ÉCRAN montrait au relevé du site public
   (17 et 19 septembre 2026) — texte courant #666666, titres et prix du
   carrousel en jaune #F4BC70 sur blanc (1,7:1). Jusqu'en rc65, ce schéma
   peignait les valeurs d'usine d'un kit de constructeur (bandeau bleu,
   boutons verts) qu'aucun élément affiché n'employait. */
.maquette-avant-froid-chaud {
	--m-fond: #FFFFFF;
	--m-encre: #666666;
	font-family: Roboto, Arial, sans-serif;
}
.maquette-avant-froid-chaud .m-bandeau {
	flex: 1;
	min-height: 0;
	background: #FFFFFF;
	color: #F4BC70;
	display: flex;
	flex-direction: column;
	justify-content: center;
	gap: 0.6em;
	padding: 1.2em;
}
.maquette-avant-froid-chaud .m-bandeau strong { font-size: 1.3em; line-height: 1.2; }
/* un repère neutre à la place d'un menu : un schéma anonyme ne recopie pas
   les entrées du site d'origine (décision du 18 septembre 2026) */
.maquette .m-repere { flex: none; width: 9em; height: 0.5em; background: currentColor; opacity: 0.28; }
/* même repère à la place du libellé d'une porte (décision du 19 septembre
   2026) : le numéro reste, la rubrique réelle disparaît. Borné à la porte,
   dont la largeur tombe sous 9 em dans les vignettes. */
.maquette .m-porte .m-repere { display: block; width: 70%; }

/* « Palais » : ce que l'ÉCRAN montrait au relevé du 23 août 2026 — texte
   blanc #FFFFFF sur la photographie nocturne d'un palais de justice, l'or
   #B5934C pour le nom. Le fond d'origine est une photo : #101320 n'en est
   qu'un aplat sombre neutre. Avant la relecture de la rc66, ce schéma
   peignait une page claire, l'inverse du site relevé. */
.maquette-avant-palais {
	--m-fond: #101320;
	--m-encre: #FFFFFF;
	font-family: Arial, sans-serif;
}
.maquette-avant-palais .m-or { color: #B5934C; }
.maquette-avant-palais .m-bloc {
	flex: 1;
	min-height: 0;
	border: 1px solid rgba(255, 255, 255, 0.18);
	background: rgba(0, 0, 0, 0.45);
	padding: 1em;
	display: flex;
	flex-direction: column;
	gap: 0.5em;
}

/* ---------- L'approche (chapitre clair) -------------------------------------- */

.chapitre-clair {
	background: var(--clair);
	color: var(--encre);
}
.chapitre-clair ::selection { background: var(--vermillon); color: var(--clair); }

.principes { margin-top: clamp(2rem, 6vh, 4rem); }
.principe {
	border-top: 1px solid var(--filet-sur-clair);
	padding-block: clamp(2.2rem, 6vh, 3.8rem);
	display: grid;
	grid-template-columns: minmax(0, 4fr) minmax(0, 7fr);
	gap: 1.5rem clamp(2rem, 5vw, 4.5rem);
	align-items: start;
}
.principe-numero {
	font-size: var(--t-label);
	font-weight: 560;
	font-stretch: 118%;
	letter-spacing: 0.18em;
	color: var(--vermillon);
	font-variant-numeric: tabular-nums;
	margin-bottom: 1rem;
}
.principe-titre {
	font-family: var(--police-titre);
	font-weight: 400;
	font-size: clamp(1.5rem, 3vw, 2.2rem);
	line-height: 1.15;
	max-width: 16ch;
}
.principe-texte { color: var(--encre-douce); max-width: 52ch; }
.principe-texte strong { color: var(--encre); font-weight: 540; }

/* ---------- Le diagnostic ---------------------------------------------------- */

.diagnostic-grille {
	display: grid;
	grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
	gap: clamp(2.5rem, 6vw, 5rem);
	align-items: start;
}

.diagnostic-boitier {
	border: 1px solid var(--filet);
	background: var(--carbone);
	padding: clamp(1.6rem, 4vw, 2.8rem);
	position: relative;
}
.diagnostic-progres {
	position: absolute;
	top: -1px;
	left: 0;
	right: 0;
	height: 2px;
	background: var(--filet);
}
.diagnostic-progres span {
	display: block;
	height: 100%;
	background: var(--rubis);
	transform: scaleX(var(--progres, 0));
	transform-origin: left center;
	transition: transform var(--d-court) var(--courbe);
}

.diagnostic-repere {
	font-size: var(--t-label);
	font-weight: 560;
	font-stretch: 118%;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var(--ivoire-douce);
	font-variant-numeric: tabular-nums;
	min-height: 1.2em;
}
.diagnostic-question {
	font-family: var(--police-titre);
	font-weight: 400;
	font-size: clamp(1.35rem, 2.6vw, 1.8rem);
	line-height: 1.25;
	margin-top: 1.1rem;
	min-height: 3.4em;
	text-wrap: balance;
}
.diagnostic-reponses {
	margin-top: 1.8rem;
	display: flex;
	flex-wrap: wrap;
	gap: 0.8rem;
}
.diagnostic-reponses button {
	border: 1px solid var(--ivoire);
	border-radius: 2px;
	padding: 0.75em 1.5em;
	font-size: var(--t-contexte);
	font-weight: 520;
	letter-spacing: 0.03em;
	transition: background-color var(--d-court) var(--courbe), color var(--d-court) var(--courbe), border-color var(--d-court) var(--courbe);
}
/* LE SURVOL EST RÉSERVÉ AUX POINTEURS QUI SURVOLENT (rc65). Au doigt,
   « :hover » reste accroché au dernier bouton touché : la question
   suivante arrivait avec une réponse déjà remplie, comme présélectionnée. */
.diagnostic-reponses button:focus-visible {
	background: var(--ivoire);
	color: var(--carbone);
}
@media (hover: hover) {
	.diagnostic-reponses button:hover {
		background: var(--ivoire);
		color: var(--carbone);
	}
}

.diagnostic-conclusion .diagnostic-question { min-height: 0; }
/* la lecture reçoit le focus pour être lue (rc65) : ce n'est pas un
   contrôle, elle ne porte pas l'anneau des éléments actionnables */
.diagnostic-question[tabindex="-1"]:focus { outline: none; }
.diagnostic-conclusion .bouton { margin-top: 1.8rem; }
.diagnostic-refaire {
	margin-top: 1.4rem;
	font-size: 0.8125rem;
	color: var(--ivoire-douce);
}
.diagnostic-note {
	margin-top: 1.4rem;
	font-size: 0.8125rem;
	color: var(--ivoire-douce);
}
/* sans script, le bouton de départ ne mène nulle part : le <noscript> et ses
   quatre questions prennent le relais. La RANGÉE entière, sinon sa marge de
   1,8 rem laisse 28 px de vide (banc, --sans-js). */
html:not(.js-actif) [data-etape="depart"] .diagnostic-reponses { display: none; }

[hidden] { display: none !important; }

/* ---------- La philosophie ---------------------------------------------------- */

.philosophie { padding-block: 0; }
/* La phrase s'allume au défilement, et c'est la HAUTEUR DE LA PISTE qui règle
   sa vitesse — pas une durée. La scène est collante sur 100vh : seul le
   surplus fait défiler la phrase. À 150vh il ne restait que 50vh utiles, soit
   deux crans de molette pour toute la phrase ; le client l'a dit ainsi. À
   300vh il reste 200vh utiles — environ un cran de molette par mot. */
.philosophie-piste { height: 300vh; }
.philosophie-scene {
	position: sticky;
	top: 0;
	height: 100vh;
	height: 100svh;
	display: grid;
	place-items: center;
	padding-inline: var(--gouttiere);
}
.philosophie-phrase {
	font-family: var(--police-titre);
	font-weight: 400;
	font-size: clamp(1.9rem, 5vw, 4rem);
	line-height: 1.22;
	letter-spacing: -0.005em;
	max-width: 22ch;
	text-align: center;
	text-wrap: balance;
}
.philosophie-phrase em { font-style: italic; color: var(--rubis); }

/* ---------- Conversion finale -------------------------------------------------- */

.final { padding-block: clamp(7rem, 20vh, 12rem); }
.final .interieur { text-align: center; }
/* Fraunces, à la demande du client : le bloc qui demande d’écrire garde la
   voix chaleureuse d’origine, quand tout le reste passe à Playfair. */
.final-titre {
	font-family: var(--police-final);
	font-weight: 400;
	font-size: clamp(2rem, 5.5vw, 4.2rem);
	line-height: 1.15;
	letter-spacing: -0.01em;
	max-width: 22ch;
	margin-inline: auto;
	text-wrap: balance;
}
.final-titre em { font-style: italic; color: var(--vermillon); }
.final-actions {
	margin-top: 3rem;
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	align-items: center;
	gap: 1.4rem 2.4rem;
}
.final-adresse {
	margin-top: 2.6rem;
	font-size: var(--t-contexte);
	color: var(--encre-douce);
}

/* ---------- Le voile de page (chargement et transitions) -------------------------- */

/* Sans script, le voile n'existe pas : le contenu est immédiatement là.
   L'arrivée est décidée dans l'en-tête de chaque page (avant la première
   peinture) ; orveta.js ne fait que lever le voile et jouer les départs. */
.voile-page { display: none; }
.js-actif .voile-page {
	display: grid;
	place-items: center;
	position: fixed;
	inset: 0;
	z-index: 90;
	background: var(--carbone);
	transform: translateY(103%);
	visibility: hidden;
	/* le voile est un décor : quoi qu'il arrive, il ne bloque jamais rien */
	pointer-events: none;
}
.voile-coeur { display: grid; justify-items: center; }

/* ---------- L'OUVERTURE DU O ---------------------------------------------
   Le symbole d'Orveta EST deux parenthèses : « .o-gauche » ivoire et
   « .o-droite » rubis, réunies elles font le O. Le voile ne fait que jouer
   ce que le dessin contient déjà. La moitié RUBIS s'écarte vers la droite ;
   le nom paraît dans son sillage, lettre après lettre, à l'instant précis
   où elle passe devant chacune ; puis elle revient refermer le O. La
   composition finale est donc le LOGOTYPE — pas un mot entre parenthèses.

   Deux longueurs, et une seule est devinée :
     — « --o-l » et « --o-h » sont celles du lockup (cf. .marque) ;
     — « --course » est la largeur rendue de « RVETA », MESURÉE une fois au
       navigateur (Archivo 620 / largeur 118 % / interlettre 0,06 em). Elle
       est constante en em, la police étant fixe. La course de la moitié
       rubis vaut exactement cette largeur : elle balaie le mot, ni plus ni
       moins. Et la composition part centrée sur le O seul, décalée d'une
       demi-course, qu'elle rend pendant l'ouverture — le mot fini est donc
       centré, le symbole ne l'est plus.

   Rien que « transform » et « opacity ». Aucune mesure en JavaScript, aucune
   animation de mise en page. Deux SVG distincts et non un seul à deux
   chemins : une moitié qui s'éloigne de plusieurs em sortirait du viewBox
   et serait rognée. */
.voile-mot {
	position: relative;
	display: flex;
	align-items: baseline;
	margin: 0;
	font-family: var(--police-texte);
	font-weight: 620;
	font-stretch: 118%;
	font-size: clamp(1.75rem, 7.4vw, 4.6rem);
	line-height: 1;
	color: var(--ivoire);
	/* LE SYMBOLE EST PLUS GRAND QUE LES LETTRES (rc56). Dans le lockup de
	   l'en-tête il tient exactement la hauteur d'encre des capitales
	   (0,7086 em) : c'est ce qu'il faut à 16 px, où il doit se faire
	   oublier. Ici il est le sujet — il ouvre le mot et le referme. On le
	   grossit donc de 16 %, et il dépasse franchement les capitales.
	   Ces deux valeurs sont LOCALES au voile : le lockup de l'en-tête et
	   du pied garde les siennes, intactes. */
	--o-l: 0.978em;
	--o-h: 0.822em;
	/* MESURÉ au navigateur, police chargée : du bord droit du symbole au bord
	   droit du A il y a 4,3497 em. On y ajoute la largeur du symbole (0,8432)
	   pour que la moitié rubis DÉGAGE le A au lieu de s'arrêter dessus — à
	   pleine ouverture la composition se lit « ( RVETA ) », la parenthèse
	   rubis fermant le mot, avant de revenir refermer le O. */
	--course: 5.33em;
}
.voile-o {
	position: relative;
	flex: none;
	width: var(--o-l);
	height: var(--o-h);
	/* Le débord sous la ligne de base suit la taille : 0,033 em pour un
	   symbole à hauteur de capitales, un rien de plus maintenant qu'il les
	   dépasse — la panse d'un O plus gros descend plus bas. Le reste de sa
	   croissance se fait vers le HAUT, où il y a la place. */
	top: 0.042em;
}
.voile-o svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.voile-coeur .o-gauche { fill: var(--ivoire); }
.voile-coeur .o-droite { fill: var(--rubis); }
.voile-lettres {
	/* les lettres passent DEVANT la moitié rubis : elle glisse derrière le
	   mot au lieu de le barrer, à l'aller comme au retour */
	position: relative;
	z-index: 1;
	letter-spacing: 0.06em;
	/* l'interlettre du dernier A compterait dans la largeur du mot, et la
	   moitié rubis irait une lettre trop loin */
	margin-right: -0.06em;
	white-space: nowrap;
}
/* AU REPOS, LE VOILE MONTRE LE LOGOTYPE ENTIER. Les lettres sont opaques et
   la moitié rubis est en place : un environnement qui ne joue pas les
   animations affiche ORVETA, jamais un arc seul ni un mot amputé. Les états
   de départ vivent dans les « from{} », comme partout ailleurs. */
.voile-l { display: inline-block; opacity: 1; }

/* ---------- arrivée : la partition, LA SEULE ------------------------------
   Elle joue à l'identique partout où le voile paraît — première visite,
   page intérieure, passage d'une page à l'autre. Il n'y a plus de version
   resserrée : deux définitions d'un même geste finissent par diverger, et
   c'est ce qui était arrivé (le passage n'avait jamais reçu l'onde).

   0,00–0,22   le O s'installe
   0,22–0,42   micro-pause : l'œil lit le symbole
   0,42–1,09   la moitié rubis s'écarte, les lettres paraissent dans son
               sillage (0,48 · 0,60 · 0,71 · 0,83 · 0,93)
   1,09–1,29   apesanteur
   1,29–1,68   la moitié rubis revient, le O se referme
   1,70–2,375  l'onde de validation : le O donne l'impulsion, puis R, V,
               E, T, A sautent à 75 ms d'intervalle
   → levée à 2,40 s                                                       */
.voile-entree .voile-page {
	transform: translateY(0);
	visibility: visible;
}
.voile-entree .voile-coeur { animation: voile-poser 0.22s var(--courbe) both; }
.voile-entree .voile-mot { animation: voile-recentrer 1.26s linear 0.42s both; }
.voile-entree .voile-o svg:last-child { animation: voile-ouvrir 1.26s linear 0.42s both; }
.voile-entree .voile-l { animation: voile-lettre 0.78s var(--courbe) both; }
.voile-entree .voile-l:nth-child(1) { animation-delay: 0.48s; }
.voile-entree .voile-l:nth-child(2) { animation-delay: 0.60s; }
.voile-entree .voile-l:nth-child(3) { animation-delay: 0.71s; }
.voile-entree .voile-l:nth-child(4) { animation-delay: 0.83s; }
.voile-entree .voile-l:nth-child(5) { animation-delay: 0.93s; }

/* LA VALIDATION (rc56) — le O referme, puis l'onde le traverse.
   Le saut est une SECONDE animation, posée après celle de l'apparition :
   deux animations sur « transform » se disputent l'élément, et la
   dernière l'emporte pendant tout son remplissage. D'où « forwards » et
   non « both » — sans remplissage arrière, elle laisse l'apparition
   travailler jusqu'à son heure, puis prend la main et rend la lettre à sa
   place exacte. C'est la seule combinaison qui n'écrase rien. */
.voile-entree .voile-o { animation: voile-saut 0.30s var(--courbe) 1.70s forwards; }
.voile-entree .voile-l { animation-name: voile-lettre, voile-saut; }
.voile-entree .voile-l:nth-child(1) { animation-duration: 0.78s, 0.30s; animation-delay: 0.48s, 1.775s; animation-fill-mode: both, forwards; }
.voile-entree .voile-l:nth-child(2) { animation-duration: 0.78s, 0.30s; animation-delay: 0.60s, 1.850s; animation-fill-mode: both, forwards; }
.voile-entree .voile-l:nth-child(3) { animation-duration: 0.78s, 0.30s; animation-delay: 0.71s, 1.925s; animation-fill-mode: both, forwards; }
.voile-entree .voile-l:nth-child(4) { animation-duration: 0.78s, 0.30s; animation-delay: 0.83s, 2.000s; animation-fill-mode: both, forwards; }
.voile-entree .voile-l:nth-child(5) { animation-duration: 0.78s, 0.30s; animation-delay: 0.93s, 2.075s; animation-fill-mode: both, forwards; }
.voile-entree .voile-l { animation-timing-function: var(--courbe), var(--courbe); }


@keyframes voile-poser {
	from { opacity: 0; transform: scale(0.965); }
	to { opacity: 1; transform: none; }
}
/* La course et le retour sont UNE SEULE animation : deux animations sur la
   même propriété se recouvrent, la dernière l'emporte pendant tout son
   remplissage et effacerait la première. Les courbes sont donc posées PAR
   PALIER — chacune vaut pour l'intervalle qui COMMENCE à son palier. */
@keyframes voile-ouvrir {
	0% { transform: translateX(0); animation-timing-function: cubic-bezier(0.45, 0, 0.15, 1); }
	53% { transform: translateX(var(--course)); animation-timing-function: linear; }
	69% { transform: translateX(var(--course)); animation-timing-function: cubic-bezier(0.5, 0, 0.2, 1); }
	100% { transform: translateX(0); }
}
@keyframes voile-recentrer {
	0% { transform: translateX(calc(50% - var(--o-l) / 2)); animation-timing-function: cubic-bezier(0.45, 0, 0.15, 1); }
	53% { transform: translateX(0); }
	100% { transform: translateX(0); }
}
/* La lettre paraît là où la moitié rubis vient de passer — elle est POSÉE,
   pas allumée : un rien de retard horizontal, puis une apesanteur minuscule
   (0,04 em, un pixel et demi au corps courant) avant de se poser. Une seule
   animation par lettre, pour la même raison que ci-dessus. */
/* LE SAUT. Un treizième d'em, et un écrasement d'un pour cent à la
   retombée : de quoi sentir le poids sans tomber dans le dessin animé.
   La lettre revient EXACTEMENT à sa place — le mot ne bouge pas. */
@keyframes voile-saut {
	0% { transform: translateY(0) scaleY(1); }
	38% { transform: translateY(-0.13em) scaleY(1.02); }
	72% { transform: translateY(0.012em) scaleY(0.99); }
	100% { transform: translateY(0) scaleY(1); }
}
@keyframes voile-lettre {
	0% { opacity: 0; transform: translate(-0.16em, 0); }
	30% { opacity: 1; transform: translate(0, 0); }
	62% { transform: translate(0, -0.04em) rotate(var(--pivot, -0.4deg)); }
	100% { opacity: 1; transform: translate(0, 0) rotate(0); }
}
/* une lettre sur deux penche dans l’autre sens : l’apesanteur ne doit
   pas ressembler à une vague. */
.voile-l:nth-child(even) { --pivot: 0.4deg; }

/* la page est prête : le cercle s'ouvre, le voile se lève */
.voile-fini .voile-page {
	transform: translateY(-103%);
	visibility: hidden;
	transition: transform 0.8s var(--courbe), visibility 0s linear 0.8s;
}

/* LE FILET (rc65). Seul orveta.js lève le voile. S'il ne s'exécute jamais —
   fichier introuvable après une purge de cache, bloqué, en erreur —, le
   rideau restait posé sur toute la page, sans limite. Il se lève désormais
   seul à 7 s : au-delà de toute partition normale (levée à 2,4 s ; plafond
   du script ≈ 3 s après son exécution, elle-même ≈ 1,7 s en 4G lente), si
   bien qu'il ne coupe jamais un geste en cours. Borné par :not(.voile-fini)
   et :not(.voile-sortie) : il n'écrase ni la levée, ni le départ. */
.voile-entree:not(.voile-fini):not(.voile-sortie) .voile-page {
	animation: voile-filet 0.8s var(--courbe) 7s forwards;
}
@keyframes voile-filet {
	to { transform: translateY(-103%); visibility: hidden; }
}
.voile-fini .voile-coeur {
	opacity: 0;
	transform: scale(1.16);
	transition: opacity 0.6s var(--courbe), transform 0.8s var(--courbe);
}

/* départ vers une autre page : le voile monte depuis le bas */
.voile-sortie .voile-page {
	transform: translateY(0);
	visibility: visible;
	transition: transform 0.5s var(--courbe);
}


/* ---------- Bandeau des pages intérieures ------------------------------------------ */

.bandeau-page {
	padding-top: calc(clamp(4rem, 10vh, 6rem) + 4rem);
	padding-bottom: clamp(2rem, 5vh, 3.5rem);
}
.bandeau-page .label { margin-bottom: 1.3rem; }
.titre-page {
	font-family: var(--police-titre);
	font-weight: 400;
	font-size: clamp(2.4rem, 6.5vw, 5.2rem);
	line-height: 1.04;
	letter-spacing: -0.01em;
	max-width: 16ch;
	text-wrap: balance;
}
.titre-page em { font-style: italic; font-weight: 400; color: var(--rubis); }
.bandeau-page .texte-conduit { margin-top: 1.8rem; }
.bandeau-page .etude-chips { margin-top: 1.8rem; }

/* ---------- Liste des réalisations -------------------------------------------------- */

.liste-projets { border-top: 1px solid var(--filet); }
.rangee-projet {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 23rem);
	align-items: center;
	gap: 1.4rem clamp(1.5rem, 4vw, 3.5rem);
	padding-block: clamp(1.8rem, 5vh, 2.8rem);
	border-bottom: 1px solid var(--filet);
	text-decoration: none;
	transition: background-color var(--d-court) var(--courbe);
}
/* la colonne de texte porte tout le récit ; l'aperçu tient l'autre moitié */
.rangee-savoir { display: grid; justify-items: start; gap: 0.75rem; }
.rangee-pied { display: flex; align-items: center; gap: 1.2rem; flex-wrap: wrap; }
.rangee-projet:hover, .rangee-projet:focus-visible { background: var(--carbone-2); }
.rangee-numero {
	font-size: var(--t-label);
	font-weight: 560;
	font-stretch: 118%;
	letter-spacing: 0.18em;
	color: var(--rubis);
	font-variant-numeric: tabular-nums;
	white-space: nowrap;
}
.rangee-titre {
	font-family: var(--police-titre);
	font-weight: 420;
	font-size: clamp(1.5rem, 3.4vw, 2.5rem);
	line-height: 1.1;
}
.rangee-code {
	display: block;
	margin-top: 0.5rem;
	font-family: var(--police-texte);
	font-size: var(--t-label);
	font-weight: 540;
	font-stretch: 118%;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--ivoire-douce);
}
.rangee-recit {
	display: block;
	margin-top: 0.6rem;
	font-family: var(--police-texte);
	font-size: var(--t-contexte);
	font-weight: 400;
	font-stretch: 100%;
	letter-spacing: 0;
	text-transform: none;
	line-height: 1.55;
	color: var(--ivoire-douce);
	max-width: 54ch;
}
/* l'aperçu : ce n'est pas une capture, c'est la maquette réelle du projet,
   à l'échelle d'une vignette. La promesse « trois identités » cesse d'être
   une affirmation : on les voit. */
.apercu-projet {
	position: relative;
	aspect-ratio: 16 / 10;
	border: 1px solid var(--filet);
	overflow: hidden;
	container-type: inline-size;
	transition: transform var(--d-court) var(--courbe), border-color var(--d-court) var(--courbe);
}
.rangee-projet:hover .apercu-projet,
.rangee-projet:focus-visible .apercu-projet {
	transform: translateY(-3px);
	border-color: var(--rubis);
}

.rangee-fleche {
	font-size: 1.4rem;
	color: var(--ivoire-douce);
	transition: transform var(--d-court) var(--courbe), color var(--d-court) var(--courbe);
}
.rangee-projet:hover .rangee-fleche, .rangee-projet:focus-visible .rangee-fleche {
	transform: translateX(0.35em);
	color: var(--rubis);
}
.liste-projets-suite { margin-top: clamp(2rem, 6vh, 3.5rem); }

/* ---------- Étude de cas (page d'une réalisation) ------------------------------------ */

.etude-chips { display: flex; flex-wrap: wrap; gap: 0.6rem; }

.etude-section {
	border-top: 1px solid var(--filet);
	padding-block: clamp(2.5rem, 7vh, 4.5rem);
	display: grid;
	grid-template-columns: minmax(0, 4fr) minmax(0, 8fr);
	gap: 1.6rem clamp(2rem, 5vw, 4.5rem);
	align-items: start;
}
.etude-section > h2 {
	font-family: var(--police-titre);
	font-weight: 400;
	font-size: clamp(1.5rem, 3vw, 2.2rem);
	line-height: 1.15;
	max-width: 14ch;
}
/* la liste de faits échappait à la borne du paragraphe voisin : jusqu'à
   102 caractères par ligne dès 768 px */
.etude-section .projet-faits { margin-top: 0; max-width: 60ch; }
.etude-corps > p + p { margin-top: 0.9rem; }
.etude-corps .texte-conduit { max-width: 60ch; }

.etude-comparateur { padding-block: clamp(2.5rem, 7vh, 4.5rem); border-top: 1px solid var(--filet); }
.etude-comparateur > .label { margin-bottom: 1.6rem; }

.etude-suite {
	border-top: 1px solid var(--filet);
	padding-block: clamp(2.5rem, 6vh, 4rem);
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 1.2rem 2rem;
}

/* ---------- Les avant-goûts de la page d'accueil ------------------------------------- */

.grille-regles {
	display: grid;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	gap: clamp(1.4rem, 3vw, 2.5rem);
	margin-block: clamp(2rem, 6vh, 3.5rem);
}
.regle-carte { border-top: 1px solid var(--filet-sur-clair); padding-top: 1.2rem; }
.regle-carte .principe-numero { margin-bottom: 0.7rem; }
.regle-carte p {
	font-family: var(--police-titre);
	font-size: clamp(1.15rem, 2vw, 1.45rem);
	line-height: 1.2;
}

.teaser-diagnostic-lignes {
	font-family: var(--police-titre);
	font-weight: 400;
	font-size: clamp(1.6rem, 4vw, 2.8rem);
	line-height: 1.3;
	margin-block: 1.8rem 2.4rem;
}
.teaser-diagnostic-lignes em { font-style: italic; color: var(--rubis); }

/* ---------- Le formulaire de contact --------------------------------------------------- */

.formulaire { display: grid; gap: 1.5rem; max-width: 40rem; }
.champ { display: grid; gap: 0.55rem; }
.champ label {
	font-size: var(--t-label);
	font-weight: 560;
	font-stretch: 118%;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--ivoire-douce);
}
.champ input, .champ textarea {
	font: inherit;
	font-size: 1rem;
	color: var(--ivoire);
	background: var(--carbone-2);
	border: 1px solid var(--filet);
	border-radius: 2px;
	padding: 0.9em 1em;
	transition: border-color var(--d-court) var(--courbe);
}
/* sans règle, le gris du navigateur (#757575) tombe à 3,80:1 sur le champ ;
   le jeton secondaire donne 7,79:1, en retrait de la saisie (14,47:1).
   Firefox, lui, retire de l'opacité. */
.champ input::placeholder, .champ textarea::placeholder {
	color: var(--ivoire-douce);
	opacity: 1;
}
/* le focus garde l'anneau commun du site (rc65) : réduit à la bordure
   rubis de 1 px, il était identique à l'état d'erreur */
.champ input:focus-visible, .champ textarea:focus-visible {
	border-color: var(--rubis);
}
.champ textarea { min-height: 9.5rem; resize: vertical; }
/* la note de réassurance était à 13 px, sous le message d'état voisin :
   rendue au jeton des textes secondaires (15 px) */
.formulaire-note { font-size: var(--t-contexte); color: var(--ivoire-douce); max-width: 52ch; }
.formulaire .bouton { justify-self: start; }

/* SANS SCRIPT, LE FORMULAIRE DÉMENTIRAIT SA NOTE : sans action ni method,
   l'envoi natif recopie nom, site et message dans l'adresse, donc dans les
   journaux du serveur (banc, --sans-js : /?nom=…&message=…). On retire les
   champs, pas la promesse ni la cible : le <noscript> premier enfant du
   formulaire reste seul affiché, et « Parler de mon projet » (/#formulaire)
   tombe sur ce repli par courriel au lieu d'un bloc masqué. */
html:not(.js-actif) .formulaire > :not(noscript) { display: none; }

/* ---------- Pied de page signature ------------------------------------------------------ */

.pied-signature {
	border-top: 1px solid var(--filet);
	padding-block: clamp(4.5rem, 12vh, 8rem) 2rem;
}
/* le pied occupe toute la largeur de l'écran, avec de larges gouttières —
   pas le conteneur éditorial de 76 rem */
.pied-cadre {
	padding-inline: clamp(1.5rem, 5vw, 5.5rem);
	/* PLEINE LARGEUR (rc15, demande client) : les blocs du pied vont de
	   gauche à droite, seules les gouttières bordent. Les colonnes de la
	   grille grandissent avec l'écran au lieu de s'écarter. */
	max-width: none;
}

/* les liens du pied : pas de soulignement, une élévation au survol */
.lien-pied {
	display: inline-block;
	text-decoration: none;
	color: var(--ivoire-douce);
	transition: transform var(--d-court) var(--courbe), color var(--d-court) var(--courbe);
}
.lien-pied:hover, .lien-pied:focus-visible {
	color: var(--ivoire);
	transform: translateY(-2px);
}

/* 1 — la grande conclusion */
.pied-conclusion {
	display: flex;
	flex-wrap: wrap;
	align-items: flex-end;
	justify-content: space-between;
	gap: 2rem clamp(2rem, 5vw, 4rem);
	margin-bottom: clamp(3.5rem, 9vh, 6rem);
}
.pied-conclusion-texte {
	font-family: var(--police-titre);
	font-weight: 400;
	font-size: clamp(2.2rem, 5vw, 5.4rem);
	line-height: 1.1;
	letter-spacing: -0.01em;
}
.pied-conclusion-texte em { font-style: italic; color: var(--rubis); }

/* 2, 3, 4 — identité · navigation · contact */
.pied-grille {
	display: grid;
	grid-template-columns: minmax(0, 6fr) minmax(0, 3fr) minmax(0, 3fr);
	gap: 2.5rem clamp(2rem, 5vw, 4.5rem);
	align-items: start;
	border-top: 1px solid var(--filet);
	padding-block: clamp(2.5rem, 6vh, 3.5rem);
	font-size: var(--t-contexte);
}
/* la colonne contact se pose sur la marge droite, en regard du CTA */
.pied-contact { justify-self: end; }
.pied-marque {
	display: inline-flex;
	align-items: center;
	gap: 0.28em;
	text-decoration: none;
	transition: transform var(--d-court) var(--courbe);
	font-weight: 620;
	font-stretch: 118%;
	letter-spacing: 0.16em;
	font-size: 1.5rem;
	line-height: 1;
	color: var(--ivoire);
}
.pied-marque { align-items: baseline; }
.pied-marque:hover, .pied-marque:focus-visible { transform: translateY(-2px); }
/* même optique que la marque d'en-tête : la hauteur du O de la police */
/* le pied a son propre corps (1,5 rem) : mesuré, 0,033 em y donnait 0,78 px
   de débord au lieu de 0,26. Calé séparément — un décalage optique se règle
   PAR LOCKUP, pas par une valeur unique reportée. */
.pied-o { width: 0.8432em; height: 0.7086em; flex: none; position: relative; top: 0.0115em; }
.pied-o .o-gauche { fill: var(--ivoire); }
.pied-o .o-droite { fill: var(--rubis); }
.pied-texte { color: var(--ivoire-douce); margin-top: 1.2rem; max-width: 36ch; }
.pied-liens-colonne { display: grid; gap: 0.6rem; margin-top: 1.1rem; justify-items: start; }
.pied-contact-titre {
	font-family: var(--police-titre);
	font-weight: 400;
	font-size: clamp(1.4rem, 2.6vw, 2rem);
	line-height: 1.15;
	margin-bottom: 1.1rem;
}
.pied-contact-titre em { font-style: italic; color: var(--rubis); }

/* 5 — la ligne légale, discrète */
.pied-bas {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 0.8rem 2rem;
	border-top: 1px solid var(--filet);
	padding-top: 1.6rem;
	font-size: 0.8125rem;
	color: var(--ivoire-douce);
}
.pied-bas-liens { display: flex; flex-wrap: wrap; gap: 1.4rem; }

/* le cercle du pied ne se « révèle » plus : il est là, comme le reste. */

/* ---------- Page introuvable (404) ------------------------------------------------ */

.page-absente {
	padding-top: calc(clamp(4rem, 10vh, 6rem) + 4rem);
	padding-bottom: clamp(4rem, 10vh, 7rem);
	min-height: 72vh;
}
.absente-code {
	display: flex;
	align-items: center;
	gap: 0.08em;
	font-family: var(--police-titre);
	font-size: clamp(5rem, 16vw, 10rem);
	line-height: 1;
	color: var(--ivoire);
	margin-bottom: 1.2rem;
}
.absente-code { align-items: baseline; }
.absente-code svg { width: 0.6357em; height: 0.7357em; flex: none; position: relative; top: 0.0129em; }
.absente-code .o-gauche { fill: var(--ivoire); }
.absente-code .o-droite { fill: var(--rubis); }

/* ---------- Pages intérieures (mentions légales) --------------------------------- */

.page-simple { padding-top: clamp(8rem, 18vh, 11rem); min-height: 70vh; }
.page-simple .titre-chapitre { margin-bottom: 2.5rem; }
.page-simple h2 {
	font-family: var(--police-titre);
	font-weight: 420;
	font-size: 1.45rem;
	margin: 2.6rem 0 0.8rem;
}
.page-simple p { max-width: 62ch; margin-bottom: 0.8rem; }
.page-simple .a-completer {
	background: var(--carbone-2);
	border: 1px dashed var(--filet);
	padding: 0.1em 0.5em;
	font-size: 0.9em;
}

/* au-delà de 1600 px, le conteneur sort de son îlot : à 2560 il couvrait
   30 % de l'écran, il en couvre 54 %. Les textes restent bornés par leurs
   mesures en ch, la lisibilité ne bouge pas. */
@media (min-width: 100rem) {
	.interieur { max-width: 86rem; }
}

/* ---------- Responsive ------------------------------------------------------------ */

@media (max-width: 56em) {
	html { scroll-padding-top: 4.5rem; }

	.constat-grille { grid-template-columns: 1fr; }
	.specimen { margin-left: 0; }
	.specimen-note { margin-left: 0; text-align: left; }

	.rangee-projet { grid-template-columns: 1fr; row-gap: 1.2rem; }

	.etude-section { grid-template-columns: 1fr; }
	.grille-regles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
	.pied-grille { grid-template-columns: 1fr; }
	.pied-conclusion { flex-direction: column; align-items: flex-start; }

	.principe { grid-template-columns: 1fr; }
	.principe-titre { max-width: none; }

	.diagnostic-grille { grid-template-columns: 1fr; }

	.comparateur-scene { aspect-ratio: 4 / 5; }
	.maquette-apres .m-portes { grid-template-columns: repeat(2, 1fr); }
	.maquette .m-nav span:nth-child(n+5):not(.m-nom) { display: none; }
}

@media (max-width: 40em) {
	.hero-marque { letter-spacing: 0.03em; }
	.diagnostic-reponses button { flex: 1 1 auto; text-align: center; }
	.grille-regles { grid-template-columns: 1fr; }
	.rangee-titre { font-size: 1.35rem; }
	.etude-suite { flex-direction: column; align-items: flex-start; }
}

/* ---------- Mouvement réduit ------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
	html { scroll-behavior: auto; }

	.js-actif .hero-marque .lettre-int,
	.js-actif .hero-marque svg,
	.js-actif .hero-marque .o-droite,
	.js-actif .hero-slogan,
	.js-actif .hero-sous,
	.js-actif .hero-actions,
	.js-actif .hero-ligne {
		animation: none;
		opacity: 1;
		transform: none;
		clip-path: none;
	}
	.js-actif .specimen .specimen-apres,
	.js-actif .specimen .specimen-ligne,
	.bouton,
	.bouton .fleche,
	.lien,
	.lien-pied,
	.rangee-projet,
	.rangee-fleche {
		transition: none !important;
		transform: none !important;
	}
	/* LE REMPLISSAGE GARDE SON ÉTAT DE REPOS (rc65). Il figurait dans la
	   liste « transform: none » ci-dessus : forcé à pleine largeur, de la
	   couleur du texte, il effaçait le libellé — le CTA du hero, le bouton
	   d'envoi et ceux du pied devenaient des pavés vides. Seule sa
	   transition est coupée : au repos il est replié (posé sur le principal),
	   au survol il couvre. */
	.bouton::before { transition: none !important; }
	.ph-mot, .ph-image, .ph-l { opacity: 1 !important; transform: none !important; }
	.philosophie-piste { height: auto; }
	.philosophie-scene { position: static; height: auto; padding-block: var(--marge-section); }
	.voile-nav, .voile-nav a { transition: none !important; }

	/* pas de voile : la navigation est directe, le contenu immédiat */
	.js-actif .voile-page { display: none; }
	.hero .interieur { transform: none; opacity: 1; }
	.hero-marque svg { transition: none; }
}

/* =========================================================================
   PHASE 2 — la ligne de partage poussée plus loin
   Un seul geste, décliné : le cercle devient composition, la ligne devient
   fil conducteur. Rien ici n'invente de couleur ni de mécanisme : tout
   réemploie les jetons et le système de révélation existants.
   ========================================================================= */

/* ---------- 1. Le cercle du pied devient composition --------------------- */
/* Il ne s'agit plus d'un logotype posé mais d'un très grand cercle rogné par
   le bord — la signature occupe l'espace au lieu de s'y ranger. */

.pied-signature { position: relative; overflow: hidden; }
.pied-cadre { position: relative; z-index: 1; }

.pied-filigrane {
	position: absolute;
	right: -9%;
	bottom: -44%;
	width: clamp(30rem, 56vw, 64rem);
	height: auto;
	z-index: 0;
	pointer-events: none;
}
/* l'opacité vit sur les tracés, pas sur l'élément : le système de révélation
   pilote l'opacité de l'élément, les deux ne doivent pas se contredire */
/* extrémité arrondie ICI SEULEMENT : à cette échelle, le bout plat du trait
   laissait un moignon rectangulaire visible dans le cadrage. La géométrie
   du wordmark, elle, n'est pas touchée. */
.pied-filigrane .o-gauche { fill: var(--ivoire); fill-opacity: 0.10; }
.pied-filigrane .o-droite { fill: var(--rubis); fill-opacity: 0.10; }

@media (max-width: 56em) {
	.pied-filigrane { right: -38%; bottom: -34%; width: clamp(22rem, 110vw, 34rem); }
}

/* ---------- 2. La ligne balaie la rangée au survol ------------------------ */
/* Le concept du site appliqué au portfolio : survoler une réalisation, c'est
   voir la ligne de partage la traverser. Transform seul — aucun décalage. */

.rangee-projet { position: relative; }
.rangee-projet::after {
	content: "";
	position: absolute;
	left: 0;
	top: 0;
	bottom: 0;
	width: 2px;
	background: var(--rubis);
	transform: scaleY(0);
	transform-origin: top center;
	transition: transform var(--d-court) var(--courbe);
}
.rangee-projet:hover::after,
.rangee-projet:focus-visible::after { transform: scaleY(1); }

/* ---------- 3. La ligne du hero ne s'arrête plus net ---------------------- */
/* Elle sort du hero et réapparaît en tête du constat : le trait relie
   physiquement « ORVETA » à la question qui suit. Statique — l'état de repos
   est l'état final, comme partout ailleurs sur ce site. */

.constat { position: relative; }
.constat::before {
	content: "";
	position: absolute;
	top: 0;
	left: 50%;
	width: 1px;
	height: clamp(2.5rem, 7vh, 4.5rem);
	background: linear-gradient(var(--rubis), rgba(240, 101, 90, 0));
}

/* ---------- 4. Le voile est mené par la ligne ----------------------------- */
/* Le mécanisme du voile n'est pas touché — il porte trop de garde-fous. On
   lui pose simplement un filet sur chacun de ses deux bords : c'est le
   déplacement du voile lui-même qui fait courir la ligne devant lui, sans
   la moindre animation supplémentaire à synchroniser. */

.voile-page::before,
.voile-page::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	height: 2px;
	background: var(--rubis);
}
.voile-page::before { top: 0; }
.voile-page::after { bottom: 0; }

@media (prefers-reduced-motion: reduce) {
	.rangee-projet::after { transition: none !important; }
	.pied-filigrane { display: none; }
}

/* =========================================================================
   FINITION — ce qui manquait encore
   ========================================================================= */

/* ---------- Zones tactiles ------------------------------------------------ */
/* Mesuré le 30 août 2026 : 10 cibles sous 44 px sur la page contact (liens
   du pied à 26 px, wordmark à 16 px, bouton de menu à 33 px). Les liens en
   ligne dans une phrase sont laissés tels quels — WCAG 2.5.8 les excepte, et
   les agrandir casserait l'interligne du texte courant. */

.marque {
	padding-block: 0.9rem;
	margin-block: -0.9rem; /* la zone grandit, la mise en page ne bouge pas */
}
/* pas de « display » ici : la règle desktop qui masque le bouton doit rester
   maîtresse. On n'ajoute que la hauteur de la zone tactile. */
.nav-bouton { min-height: 44px; align-items: center; }
.pied-liens-colonne { gap: 0; }
/* les liens du pied n'ont pas de soulignement : le remplissage vertical y
   agrandit la zone sans rien décaler */
.lien-pied { padding-block: 0.7rem; }

/* les liens de navigation, eux, portent un soulignement animé calé sur le
   bas de leur boîte : un remplissage l'éloignerait du texte. On étend donc
   la zone tactile par un pseudo-élément, qui ne déplace rien. */
.nav-liens a { position: relative; }
.nav-liens a::before {
	content: "";
	position: absolute;
	inset: -0.85rem 0;
}

/* ---------- La preuve mobile des études de cas ---------------------------- */
/* Le responsive n'est pas une adaptation technique à mentionner : c'est un
   travail à MONTRER. Chaque étude expose donc la même refonte au format
   téléphone — la maquette n'est pas redessinée, elle se recompose, ce qui
   est précisément la démonstration. */

.preuve-mobile {
	border-top: 1px solid var(--filet);
	padding-block: clamp(2.5rem, 7vh, 4.5rem);
	display: grid;
	grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
	gap: clamp(2rem, 5vw, 4.5rem);
	align-items: center;
}
.preuve-mobile-texte .label { margin-bottom: 1.4rem; }
.preuve-mobile-texte h2 {
	font-family: var(--police-titre);
	font-weight: 400;
	font-size: clamp(1.5rem, 3vw, 2.2rem);
	line-height: 1.15;
	max-width: 18ch;
	margin-bottom: 1.4rem;
}

/* le cadre : un téléphone suggéré, pas dessiné en détail */
.cadre-mobile {
	justify-self: center;
	width: min(17rem, 100%);
	aspect-ratio: 9 / 18;
	border: 1px solid var(--filet);
	border-radius: 1.6rem;
	padding: 0.5rem;
	background: var(--carbone-2);
}
.cadre-mobile-ecran {
	position: relative;
	height: 100%;
	border-radius: 1.1rem;
	overflow: hidden;
	container-type: inline-size;
}

/* les maquettes se recomposent dans le cadre étroit — ce sont des requêtes
   de CONTENEUR, pas de fenêtre : la démonstration tient quelle que soit la
   taille de l'écran qui la regarde */
@container (max-width: 420px) {
	.maquette { padding: 0.9rem 0.8rem; gap: 0.55rem; font-size: 0.62rem; }
	.maquette .m-nav { gap: 0.7em; flex-wrap: wrap; row-gap: 0.2em; }
	.maquette .m-nav span:nth-child(n+4):not(.m-nom) { display: none; }
	.maquette-apres .m-h1 { font-size: 1.15rem; padding-block: 0.3em; }
	.maquette-apres .m-portes { grid-template-columns: repeat(2, 1fr); gap: 0.45em; }
	.maquette-apres .m-porte { padding: 0.5em 0.45em; }
	.maquette .m-texte { gap: 0.5em; }
	.maquette-apres .m-pied { gap: 0.4em; font-size: 0.78em; }
	.maquette-froid-chaud .m-pilules { gap: 0.4em; }
}
/* aperçus les plus étroits (écran de 320 px) : les portes numérotées de 02 et
   03 rognaient leur trait du bas de 0,6 et 1,7 px (banc, rc66) ; un peu
   moins de marge intérieure, et tout rentre */
@container (max-width: 300px) {
	.maquette-apres .m-porte { padding-block: 0.35em; gap: 0.3em; }
}
/* « Encre et pierre » : sur téléphone, la maquette EMPILE ses quatre entrées
   sur une colonne (jusqu'à 781 px) — le cadre dit la même chose. Banc : tout
   tient dans l'écran du cadre à 1440, 390 et 320, 14 px libres en bas. */
.cadre-mobile .maquette-encre-mini .m-portes { grid-template-columns: 1fr; }

@media (max-width: 56em) {
	.preuve-mobile { grid-template-columns: 1fr; }
	.cadre-mobile { width: min(15rem, 70%); }
}

/* ---------- États du formulaire ------------------------------------------- */
/* « Aucun état ne doit sembler oublié » : un champ obligatoire laissé vide
   à l'envoi, et le retour d'action quand la messagerie s'ouvre.
   L'état est porté par une CLASSE posée par le script, pas par
   `:user-invalid` : ce pseudo-sélecteur ne s'est pas déclenché dans le
   moteur de recette, et on ne livre pas un état qu'on ne peut pas éprouver.
   Le champ n'est jamais marqué avant une tentative d'envoi. */

.champ.est-invalide input,
.champ.est-invalide textarea { border-color: var(--rubis); }

.champ-erreur {
	font-size: 0.8125rem;
	color: var(--rubis);
	display: none;
}
.champ.est-invalide .champ-erreur { display: block; }

/* LA ZONE D'ÉTAT EST TOUJOURS RENDUE, VIDE AU REPOS (rc65). Elle passait
   de « display: none » à visible au moment même où elle devait être
   annoncée — ce qui ne garantit pas l'annonce. Le texte est écrit par le
   script au moment de l'action. */
.formulaire-etat {
	font-size: var(--t-contexte);
	color: var(--ivoire);
}
/* vide, elle sort du flux : rendue pour les lecteurs d'écran, elle ne
   crée pas pour autant une rangée vide dans la grille du formulaire */
.formulaire-etat:empty { position: absolute; }
.formulaire-etat:not(:empty) {
	border-left: 1px solid var(--rubis);
	padding-left: 0.9em;
}
.chapitre-clair .formulaire-etat:not(:empty) { border-left-color: var(--vermillon); }
/* LE REPLI (rc65). Ouvrir une messagerie ne se vérifie pas : sur un poste
   sans messagerie configurée, rien ne s'ouvre. Le courriel préparé reste
   donc lisible et copiable dans la page. */
.formulaire-repli { display: none; }
.formulaire.est-envoye .formulaire-repli { display: grid; gap: 0.6rem; }
.formulaire-repli label {
	font-size: var(--t-label);
	font-weight: 560;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--ivoire-douce);
}
.chapitre-clair .formulaire-repli label { color: var(--encre-douce); }
.formulaire-repli textarea {
	font: inherit;
	font-size: 0.9375rem;
	color: var(--ivoire);
	background: var(--carbone-2);
	border: 1px solid var(--filet);
	border-radius: 2px;
	padding: 0.9em 1em;
	min-height: 8rem;
	resize: vertical;
}
.formulaire-repli .lien { justify-self: start; }

/* =========================================================================
   LA TRAVERSÉE (1.1.0) — le site devient une expérience one-page.
   Concept : visiter orveta.fr, c'est traverser la ligne de partage.
   Voir documentation/08-traversee.md — chaque signature ci-dessous découle
   du vocabulaire de la maison, aucune n'est empruntée aux références.
   ========================================================================= */

/* ---- les jalons : le numéro de chapitre dans le surtitre ---------------- */
.jalon {
	color: var(--rubis);
	margin-right: 0.65em;
	font-variant-numeric: tabular-nums;
}
.chapitre-clair .jalon { color: var(--vermillon); }

/* ---- le bouton-guide ----------------------------------------------------
   Le O de partage à la place de la flèche ; au survol ses deux moitiés
   s'écartent — la ligne s'ouvre, l'invitation à traverser. */
.bouton-guide .guide-o {
	width: 1.05em;
	height: 0.9em;
	position: relative;
	top: 0.08em;
	flex: none;
	overflow: visible;
}
.bouton-guide .guide-o .o-droite { fill: var(--rubis); }
.bouton-guide .guide-o path { transition: transform var(--d-court) var(--courbe); }
.bouton-guide:hover .guide-o .o-gauche,
.bouton-guide:focus-visible .guide-o .o-gauche { transform: translateX(-7px); }
.bouton-guide:hover .guide-o .o-droite,
.bouton-guide:focus-visible .guide-o .o-droite { transform: translateX(7px); }

/* ---- le hero-portail ----------------------------------------------------
   Au défilement, les deux moitiés du O s'écartent : on entre dans le site
   en passant PAR la ligne de partage. Transform pur — au repos, O entier. */
.hero-marque .moitie-g,
.hero-marque .moitie-d { transition: transform 0.15s linear; }
.hero-marque .moitie-g { transform: translateX(calc(var(--ecart, 0) * -9px)); }
.hero-marque .moitie-d { transform: translateX(calc(var(--ecart, 0) * 9px)); }

/* ---- la litanie ---------------------------------------------------------
   Les trois temps réels de la méthode, séparés par la verticale du concept.
   Un battement typographique — un seul passage, pas une boucle. */
.litanie {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	margin-top: clamp(2.4rem, 7vh, 4.5rem);
	font-family: var(--police-titre);
	font-weight: 400;
	font-size: clamp(1.9rem, 5.2vw, 4rem);
	line-height: 1.1;
	letter-spacing: -0.01em;
	color: var(--encre);
}
.litanie span { position: relative; padding-right: clamp(1.1rem, 3vw, 2.2rem); }
.litanie span + span { padding-left: clamp(1.1rem, 3vw, 2.2rem); }
.litanie span + span::before {
	content: "";
	position: absolute;
	left: 0;
	top: 0.02em;
	bottom: 0.02em;
	width: 1px;
	background: var(--vermillon);
}
.litanie .accent { font-style: italic; color: var(--vermillon); }

/* ---- l'approche fusionnée ---------------------------------------------- */
.approche-methode {
	margin-top: clamp(3rem, 9vh, 5.5rem);
	border-top: 1px solid var(--filet-sur-clair);
	padding-top: clamp(2.4rem, 7vh, 4rem);
}
.approche-methode-titre { margin-top: 1.1rem; font-size: clamp(1.7rem, 3.4vw, 2.6rem); }

/* ---- le diagnostic fusionné --------------------------------------------- */
.diagnostic .diagnostic-grille { margin-top: clamp(2.4rem, 7vh, 4rem); }

/* ---- le dernier acte : conversion + contact ------------------------------
   Le formulaire garde son fond nuit — c'est voulu : sur le chapitre clair,
   il est l'endroit où l'on repasse de notre côté de la ligne. Seuls les
   textes posés directement sur le clair changent d'encre. */
.final-conduit { max-width: 52ch; margin-inline: auto; margin-top: 1.6rem; }
.final .contact-grille {
	text-align: left;
	margin-top: clamp(2.8rem, 8vh, 5rem);
}
.chapitre-clair .champ label { color: var(--encre-douce); }
.chapitre-clair .formulaire-note { color: var(--encre-douce); }
.chapitre-clair .formulaire-etat { color: var(--encre); }
.chapitre-clair .champ-erreur { color: var(--vermillon); }

/* ---- la navigation suit la traversée ------------------------------------ */
.nav-liens .lien[aria-current] { color: var(--rubis); }

@media (max-width: 40em) {
	.litanie { font-size: 1.6rem; }
}

@media (prefers-reduced-motion: reduce) {
	.hero-marque .moitie-g,
	.hero-marque .moitie-d { transform: none; transition: none; }
	.bouton-guide .guide-o path { transition: none; }
}

/* =========================================================================
   LA TRAVERSÉE, ACTE II (1.1.0-rc2) — le scroll devient le langage.
   Le fil vertical de la rc1 a été refusé (« impression de système
   d'interface externe ») : la progression rejoint l'EN-TÊTE, minimale et
   contextuelle — un filet qui s'emplit, un compteur de chapitre.
   ========================================================================= */

/* ---- la progression contextuelle --------------------------------------- */
.js-actif .entete::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	height: 1px;
	background: linear-gradient(90deg, var(--ivoire-douce), var(--rubis));
	transform: scaleX(var(--traversee, 0));
	transform-origin: left center;
	pointer-events: none;
}
/* Le compteur de chapitre, affiné (rc15) : il FOND en place au lieu de
   basculer, et le nom est séparé des chiffres par la verticale du concept —
   plus de tiret. Toujours décoratif (aria-hidden), jamais indispensable. */
.jalon-courant {
	font-weight: 560;
	font-stretch: 112%;
	letter-spacing: 0.26em;
	font-size: 0.62rem;
	text-transform: uppercase;
	color: var(--ivoire-douce);
	font-variant-numeric: tabular-nums;
	margin-left: clamp(1rem, 3vw, 2.6rem);
	margin-right: auto;
	display: inline-flex;
	align-items: center;
	opacity: 0;
	transform: translateY(4px);
	transition: opacity 0.5s var(--courbe), transform 0.5s var(--courbe);
}
.jalon-courant.est-visible { opacity: 1; transform: none; }
.jalon-courant [data-chapitre-numero] { color: var(--rubis); }
.jalon-nom { position: relative; padding-left: 1.05em; }
.jalon-nom::before {
	content: "";
	position: absolute;
	left: 0.35em;
	top: -0.15em;
	bottom: -0.15em;
	width: 1px;
	background: var(--rubis);
}
@media (max-width: 64em) { .jalon-courant { display: none; } }

/* ---- l'en-tête : PERMANENT (rc14) ---------------------------------------
   L'en-tête directionnel de la rc2 a été retiré à la demande du client :
   le menu, le fil, ses encoches et sa pointe accompagnent le visiteur
   jusqu'en bas de la page. La transition ne sert plus qu'aux états
   compacts. */
.js-actif .entete {
	transition:
		transform 0.35s var(--courbe),
		background-color 0.4s var(--courbe),
		box-shadow 0.4s var(--courbe),
		padding 0.4s var(--courbe);
}

/* ---- les dérives d'entrée des projets -----------------------------------
   Trois rangées, trois chemins d'arrivée — « aucun modèle réutilisé »,
   dit par le mouvement lui-même. Transform pur, --derive vaut 0 par
   défaut : sans moteur, tout est à sa place. */
[data-derive] { transition: transform 0.22s linear; }
[data-derive="droite"] { transform: translateX(calc(var(--derive, 0) * 46px)); }
[data-derive="bas"] { transform: translateY(calc(var(--derive, 0) * 46px)); }
[data-derive="gauche"] { transform: translateX(calc(var(--derive, 0) * -46px)); }

/* ---- la pastille « Ouvrir » ---------------------------------------------
   Elle suit le curseur avec un léger retard au-dessus des rangées de
   projet : toute la rangée s'ouvre, et la pastille le dit. */
.curseur-ouvrir {
	position: fixed;
	top: 14px;
	left: 18px;
	z-index: 90;
	pointer-events: none;
	background: var(--ivoire);
	color: var(--encre);
	font-weight: 620;
	font-stretch: 118%;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	font-size: 0.66rem;
	padding: 0.55em 0.95em;
	border-radius: 999px;
	opacity: 0;
	scale: 0.85;
	transition: opacity 0.25s var(--courbe), scale 0.25s var(--courbe);
	will-change: transform;
}
.curseur-ouvrir.est-visible { opacity: 1; scale: 1; }

/* ---- la grande pause avant le dernier acte ------------------------------ */
.final { padding-top: clamp(8rem, 26vh, 15rem); }

@media (prefers-reduced-motion: reduce) {
	.js-actif .entete::after { display: none; }
	.entete.est-retiree { transform: none; }
	[data-derive] { transform: none !important; transition: none; }
	.curseur-ouvrir { display: none; }
}

/* =========================================================================
   LA TRAVERSÉE, ACTE III (1.1.0-rc3) — les seuils de chapitre et le fil
   narratif. Voir documentation/08-traversee.md, acte III.
   ========================================================================= */

/* ---- les seuils ---------------------------------------------------------
   Chaque chapitre s'ouvre par LE geste fondateur du site : la verticale qui
   descend (le vocabulaire du hero), accompagnée du numéro fantôme. Le trait
   se dessine au défilement (--seuil 1→0), le numéro se pose. Au repos tout
   est là : sans moteur, le seuil est simplement complet. */
.seuil {
	position: relative;
	display: grid;
	justify-items: center;
	padding-top: clamp(1.2rem, 4vh, 2.6rem);
	pointer-events: none;
}
.seuil-trait {
	width: 1px;
	height: clamp(4rem, 12vh, 7rem);
	background: linear-gradient(var(--filet), var(--ivoire-douce));
	transform: scaleY(calc(1 - var(--seuil, 0)));
	transform-origin: top center;
	transition: transform 0.25s linear;
	display: grid;
	justify-items: center;
	align-content: end;
}
.seuil-numero {
	margin-top: 0.9rem;
	font-family: var(--police-titre);
	font-weight: 400;
	font-size: clamp(2.6rem, 7vw, 5rem);
	line-height: 1;
	color: var(--ivoire);
	opacity: 0.16;
	font-variant-numeric: tabular-nums;
	transform: translateY(calc(var(--seuil, 0) * 18px));
	transition: transform 0.25s linear;
}
.chapitre-clair .seuil-trait { background: linear-gradient(var(--filet-sur-clair), var(--encre-douce)); }
.chapitre-clair .seuil-numero { color: var(--encre); opacity: 0.14; }

/* cinq nuances — « chaque transition a sa personnalité » */
.seuil-fort .seuil-trait { height: clamp(5rem, 16vh, 9rem); }
.seuil-spectaculaire .seuil-trait { height: clamp(5rem, 16vh, 9rem); }
.seuil-spectaculaire .seuil-o { width: 15px; height: 18px; margin-bottom: -9px; }
.seuil-spectaculaire .seuil-o .o-gauche { fill: var(--ivoire); }
.seuil-spectaculaire .seuil-o .o-droite { fill: var(--rubis); }
.seuil-editorial .seuil-trait { height: clamp(2.6rem, 7vh, 4rem); }
.seuil-editorial .seuil-numero { font-size: clamp(2rem, 4.6vw, 3.2rem); }
.seuil-droite { justify-items: end; padding-right: clamp(1.5rem, 12vw, 12rem); }
.seuil-epure .seuil-trait { height: clamp(2.2rem, 6vh, 3.4rem); }
.seuil-epure .seuil-numero { font-size: clamp(1.7rem, 3.6vw, 2.6rem); opacity: 0.22; }

/* ---- le fil narratif ----------------------------------------------------
   Le compteur dit désormais le chapitre par son nom, et six encoches posées
   sur le filet de progression dessinent la carte du voyage : accomplies en
   rubis, la courante plus marquée. Créées par le moteur — aucune sans JS. */
.jalon-nom { color: var(--ivoire); letter-spacing: 0.24em; }
/* LE JALON EST LE SYMBOLE. Six barres de 1 × 3 px disaient bien où l'on en
   était, mais elles auraient pu appartenir à n'importe quel site. Un jalon
   porte maintenant le O d'Orveta réduit à son essentiel : deux moitiés et
   la ligne de partage. Trois états, qui racontent la traversée —

     devant soi   le O est OUVERT, les deux moitiés écartées, en filet ;
     ici          il prend ses couleurs, encore ouvert : on y est ;
     derrière soi il s'est REFERMÉ — ivoire et rubis, le logotype exact.

   La traversée assemble donc le O six fois. Rien que « transform » et la
   couleur ; le dessin ne coûte aucun élément de plus qu'avant (deux
   moitiés au lieu d'une barre) et reste posé par le moteur. */
.jalons-fil { position: absolute; left: 0; right: 0; bottom: -1px; height: 3px; pointer-events: none; }
.jalons-fil i {
	position: absolute;
	top: 50%;
	width: 6px;
	height: 6px;
	margin: -3px 0 0 -3px;
}
.jalons-fil i span {
	position: absolute;
	top: 0;
	height: 100%;
	width: 50%;
	background: var(--filet);
	transition: transform var(--d-court) var(--courbe),
		background-color var(--d-court) var(--courbe);
}
/* « --ferme » va de 0 (grand ouvert) à 1 (refermé). Le moteur le pose sur
   le SEUL jalon courant, à la mesure de ce qui a été parcouru de son
   chapitre : le O se referme donc à mesure qu'on le traverse, et le jalon
   devient une jauge sans cesser d'être un symbole. Refermé, il reste un
   cheveu entre les deux moitiés — c'est LA LIGNE DE PARTAGE, le concept
   même du site ; sans elle le jalon redeviendrait un simple point. */
.jalons-fil i span:first-child {
	left: 0;
	border-radius: 3px 0 0 3px;
	transform: translateX(calc(-1.25px + var(--ferme, 0) * 0.75px));
}
.jalons-fil i span:last-child {
	right: 0;
	border-radius: 0 3px 3px 0;
	transform: translateX(calc(1.25px - var(--ferme, 0) * 0.75px));
}
/* ici : le O prend ses couleurs et commence à se refermer */
.jalons-fil i.est-courant span:first-child { background: var(--ivoire-douce); }
.jalons-fil i.est-courant span:last-child { background: var(--rubis); }
/* franchi : il est refermé, et porte les couleurs pleines du logotype */
.jalons-fil i.est-accompli { --ferme: 1; }
.jalons-fil i.est-accompli span:first-child { background: var(--ivoire); }
.jalons-fil i.est-accompli span:last-child { background: var(--rubis); }
/* la pointe du fil, elle, garde sa mesure : c'est le seul repère qui
   BOUGE, les jalons sont fixes. On l'affine d'un cheveu pour qu'elle ne
   concurrence pas les symboles qu'elle traverse. */
.js-actif .fil-pointe { width: 2px; height: 2px; margin-left: -1px; }

@media (max-width: 48em) { .jalon-nom { display: none; } }

@media (prefers-reduced-motion: reduce) {
	.seuil-trait, .seuil-numero { transform: none !important; transition: none; }
	/* les jalons RESTENT : ils disent où l'on en est, ce n'est pas une
	   animation mais une information. Seule la transition s'éteint. */
	.jalons-fil i span { transition: none; }
}

/* =========================================================================
   L'IDENTITÉ DU SCROLL (1.1.0-rc4) — intervention ciblée : deux gestes.
   ========================================================================= */

/* ---- le O au seuil 02 : la transformation commence ----------------------
   Au seuil du chapitre 02, les deux moitiés du O arrivent écartées et se
   REFERMENT à mesure que le trait se dessine — le geste inverse du
   hero-portail (où l'on entre en ouvrant la ligne). Le récit du scroll :
   on ouvre le O pour entrer, il se referme quand la transformation
   commence, il se tient entier au seuil du travail réel (03), il revient
   au pied. Au repos : O entier, toujours. */
.seuil-fort .seuil-o {
	width: 15px;
	height: 18px;
	margin-bottom: -9px;
	overflow: visible;
}
.seuil-fort .seuil-o .o-gauche { fill: var(--ivoire); }
.seuil-fort .seuil-o .o-droite { fill: var(--rubis); }
.seuil-fort .seuil-o .moitie-g,
.seuil-fort .seuil-o .moitie-d { transition: transform 0.25s linear; }
.seuil-fort .seuil-o .moitie-g { transform: translateX(calc(var(--seuil, 0) * -8px)); }
.seuil-fort .seuil-o .moitie-d { transform: translateX(calc(var(--seuil, 0) * 8px)); }

/* ---- la pointe du fil ---------------------------------------------------
   La tête du fil de progression : un point rubis qui avance sur le filet
   de l'en-tête. Le fil ne fait plus que s'emplir — il se TIRE.

   AUCUNE TRANSITION SUR « left » (rc52). Elle valait 150 ms, et la ligne
   n'en avait aucune : la pointe accusait donc un retard proportionnel à
   la vitesse du geste et ne rejoignait le bout qu'à l'arrêt du
   défilement — « le point se balade ». Les deux lisent maintenant la même
   variable, déjà lissée par le moteur, et sans transition ni l'un ni
   l'autre : la pointe est au bout de la ligne à chaque image. */
.js-actif .fil-pointe {
	position: absolute;
	bottom: -1px;
	left: calc(var(--traversee, 0) * 100%);
	width: 3px;
	height: 3px;
	margin-left: -2px;
	border-radius: 50%;
	background: var(--rubis);
	transition: opacity 0.3s var(--courbe);
	pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
	.seuil-fort .seuil-o .moitie-g,
	.seuil-fort .seuil-o .moitie-d { transform: none; transition: none; }
	.js-actif .fil-pointe { display: none; }
}

/* =========================================================================
   LA GRAMMAIRE DES DÉRIVES (1.1.0-rc5) — le même mot, décliné.
   Les dérives montent sur les RANGÉES (chorégraphie hiérarchisée : l'aperçu
   est l'événement principal, le numéro l'accompagne, le reste est immobile)
   et gagnent deux directions : « pose » (les règles, les actes, la
   conclusion du pied se posent à leur tour) et « encre » (la seconde ligne
   du constat s'intensifie — le langage de la philosophie, repos lisible,
   jamais invisible). Toujours : var à 0 par défaut = état final.
   ========================================================================= */

/* LA DÉRIVE RESTE DANS SA SECTION (rc65). L'aperçu 01 entre de 46 px par la
   droite : sur téléphone il occupait toute la largeur utile et la
   débordait de 27 px. Le navigateur élargissait alors le viewport — page
   qui glisse au doigt, bouton « MENU » rogné, en-tête hors cadre après une
   ancre, et « vh » faussé pour le moteur. « overflow-x: clip » sur body ne
   protège pas : il est reporté sur le viewport. Posé sur la SECTION (et non
   sur la liste, qui rognerait l'aperçu 03), « clip » ne crée aucun
   conteneur de défilement et ne touche aucune scène collante. */
.realisations { overflow-x: clip; }

/* la chorégraphie des rangées : principal + secondaire, rien d'autre */
.rangee-projet[data-derive] { transform: none; }
.rangee-projet .apercu-projet,
.rangee-projet .rangee-numero { transition: transform 0.22s linear; }
.rangee-projet[data-derive="droite"] .apercu-projet { transform: translateX(calc(var(--derive, 0) * 46px)); }
.rangee-projet[data-derive="bas"] .apercu-projet { transform: translateY(calc(var(--derive, 0) * 46px)); }
.rangee-projet[data-derive="gauche"] .apercu-projet { transform: translateX(calc(var(--derive, 0) * -46px)); }
.rangee-projet[data-derive] .rangee-numero {
	display: inline-block;
	transform: translateY(calc(var(--derive, 0) * 14px));
}

/* la pose : l'élément se pose à son tour, doucement */
[data-derive="pose"] { transform: translateY(calc(var(--derive, 0) * 22px)); }

/* l'encre : la seconde ligne du constat s'intensifie à l'approche.
   Repos : pleine encre (var 0). Sous l'écran : 0,55 — le seuil de la
   philosophie, validé lisible. Jamais moins. */
[data-derive="encre"] {
	transform: none;
	opacity: calc(1 - var(--derive, 0) * 0.45);
	transition: opacity 0.22s linear;
}

@media (prefers-reduced-motion: reduce) {
	.rangee-projet[data-derive] .apercu-projet,
	.rangee-projet[data-derive] .rangee-numero,
	[data-derive="pose"] { transform: none !important; transition: none; }
	[data-derive="encre"] { opacity: 1; transition: none; }
}

/* =========================================================================
   LA LIGNE DES CINQ ACTES (1.1.0-rc6) — § 51 du cahier des charges.
   La verticale du concept longe les cinq actes et S'EMPLIT à mesure que le
   lecteur les traverse — la méthode se parcourt comme le site : acte par
   acte. Défaut à 1 : sans moteur, la ligne est simplement complète.
   ========================================================================= */
.actes-suivis {
	position: relative;
	padding-left: clamp(1.4rem, 3vw, 2.2rem);
}
.actes-suivis::before {
	content: "";
	position: absolute;
	left: 0;
	top: 0.3em;
	bottom: 0.3em;
	width: 1px;
	background: var(--filet-sur-clair);
}
.actes-suivis::after {
	content: "";
	position: absolute;
	left: 0;
	top: 0.3em;
	bottom: 0.3em;
	width: 1px;
	background: linear-gradient(var(--encre-douce), var(--vermillon));
	transform: scaleY(var(--avancee, 1));
	transform-origin: top center;
	transition: transform 0.22s linear;
}
@media (prefers-reduced-motion: reduce) {
	.actes-suivis::after { transform: none; transition: none; }
}

/* =========================================================================
   LES TRAITS FRANCHISSENT LES FRONTIÈRES (1.1.0-rc7)
   Trouvé au parcours réel, position par position : les frontières de
   chapitres étaient des coupes franches que RIEN ne traversait — le trait
   de chaque seuil naissait APRÈS la frontière. C'est cela qui faisait
   « bloc, bloc, bloc ». Le remède est le § 78 du cahier du client, au mot :
   « une ligne du chapitre 01 peut devenir le séparateur du 02 ».
   Chaque trait reçoit un PROLONGEMENT qui remonte dans le chapitre
   précédent, en fondu — la verticale arrive de l'autre côté, traverse la
   frontière, et se pose. Composition pure : aucun mouvement, aucun layout.
   ========================================================================= */

/* la ligne du hero franchit déjà sa frontière : elle descend DANS le constat */
.hero-ligne {
	height: clamp(6rem, 16vh, 9.5rem);
	bottom: calc(-1 * clamp(2.6rem, 7vh, 4.2rem));
}

/* le prolongement : la moitié amont du trait, née dans le chapitre d'avant */
.seuil-trait { position: relative; }
.seuil-trait::before {
	content: "";
	position: absolute;
	bottom: 100%;
	left: 0;
	width: 1px;
	height: calc(var(--marge-section) + clamp(2.4rem, 7vh, 4.6rem));
	background: linear-gradient(rgba(181, 172, 157, 0), var(--ivoire-douce));
}
/* le chapitre 05 arrive APRÈS le chapitre clair : son amont est à l'encre */
.seuil-droite .seuil-trait::before {
	background: linear-gradient(rgba(91, 83, 66, 0), var(--encre-douce));
}

/* =========================================================================
   LA RETRAITE DE CHAPITRE (1.1.0-rc8) — ajout unique.
   Quand le visiteur dépasse un chapitre, son contenu se retire de la
   scène (jamais du DOM) ; il revient tel quel, à sa place, quand on
   remonte. Opacité nulle à retraite complète (le plancher restait perceptible).
   Les seuils (hors du .interieur), le fil, les lignes et le hero ne sont
   pas concernés. La philosophie non plus : sa scène collante sort déjà
   d'elle-même, et un transform sur son parent casserait le sticky.
   ========================================================================= */
.js-actif [data-jalon] > .interieur {
	/* À retraite complète, opacité NULLE — le plancher de 0,04 restait
	   perceptible sur les grands titres (retour client, capture à l'appui).
	   Sans danger : c'est un contenu DÉPASSÉ, réversible au premier cran de
	   remontée, jamais concerné à l'arrivée ni sous mouvement réduit. */
	opacity: calc(1 - var(--sortie, 0));
	transform: translateY(calc(var(--sortie, 0) * -26px));
	transition: opacity 0.22s linear, transform 0.22s linear;
}

/* ---- la retraite épargne ce qu'on UTILISE -------------------------------
   Mesuré sur rc65 : l'élément focalisé se retirait lui-même (0,44 à 0,68
   d'opacité, texte et anneau à 2,51:1) ; le bouton d'envoi tombait à 0,47 au
   tiers haut ; la lecture du diagnostic et son CTA s'affichaient à 0,675
   (1440) et 0,783 (390). Un outil qu'on manipule n'est pas un contenu
   dépassé. Ailleurs et sans focus, la lecture ne change pas ; les seuils,
   hors du .interieur, gardent leur geste. */
.js-actif [data-jalon] > .interieur:has(:focus-visible),
.js-actif #diagnostic > .interieur,
.js-actif #contact > .interieur {
	opacity: 1;
	transform: none;
}

@media (prefers-reduced-motion: reduce) {
	.js-actif [data-jalon] > .interieur {
		opacity: 1 !important;
		transform: none !important;
		transition: none;
	}
}

/* ---- la philosophie entre dans la retraite (1.1.0-rc12) -----------------
   La retraite s'applique à la PHRASE, jamais à son parent : la scène est
   collante, et c'est elle qui porte le positionnement. */
.js-actif [data-retraite] .philosophie-phrase {
	opacity: calc(1 - var(--sortie, 0));
	transform: translateY(calc(var(--sortie, 0) * -26px));
	transition: opacity 0.22s linear, transform 0.22s linear;
}
@media (prefers-reduced-motion: reduce) {
	.js-actif [data-retraite] .philosophie-phrase {
		opacity: 1 !important;
		transform: none !important;
		transition: none;
	}
}


/* =========================================================================
   LES SIX PASSAGES DU COMPTEUR (1.1.0-rc16)
   À chaque changement de chapitre, le texte du compteur change avec SON
   animation — six passages, six gestes, tous brefs (0,45 s), tous sur la
   courbe maison. Planchers d'opacité ≥ 0,15 et transforms courts : une
   horloge d'animation gelée laisse toujours un compteur lisible.
   ========================================================================= */
.jalon-courant[data-anim="1"].est-change { animation: passage-pose 0.45s var(--courbe); }
.jalon-courant[data-anim="2"].est-change { animation: passage-glisse 0.45s var(--courbe); }
.jalon-courant[data-anim="3"].est-change { animation: passage-rideau 0.45s var(--courbe); }
.jalon-courant[data-anim="4"].est-change { animation: passage-descente 0.45s var(--courbe); }
.jalon-courant[data-anim="5"].est-change { animation: passage-ouverture 0.45s var(--courbe); }
.jalon-courant[data-anim="6"].est-change { animation: passage-fondu 0.7s var(--courbe); }

@keyframes passage-pose { from { opacity: 0.3; transform: translateY(6px); } }
@keyframes passage-glisse { from { opacity: 0.3; transform: translateX(-10px); } }
@keyframes passage-rideau { from { opacity: 0.6; clip-path: inset(0 60% 0 0); } to { clip-path: inset(0 0 0 0); } }
@keyframes passage-descente { from { opacity: 0.3; transform: translateY(-6px); } }
@keyframes passage-ouverture { from { opacity: 0.3; transform: scaleX(1.08); transform-origin: left center; } }
@keyframes passage-fondu { from { opacity: 0.15; } }

@media (prefers-reduced-motion: reduce) {
	.jalon-courant.est-change { animation: none !important; }
}


/* =========================================================================
   LE MENU, LE CHAMP ET L'ÉCLATEMENT (1.1.0-rc18)
   ========================================================================= */

/* ---- le menu : plus des boutons soulignés ------------------------------
   Le trait permanent sous chaque lien faisait « boutons de gabarit ». Les
   liens redeviennent du TEXTE ; c'est la verticale du concept — un filet
   d'un pixel devant le mot — qui marque le survol et la page courante.
   Le soulignement ne sert plus qu'au focus clavier. */
.nav-liens .lien {
	background-image: none;
	padding-bottom: 0;
	padding-left: 0.85em;
	position: relative;
	color: var(--ivoire-douce);
	transition: color var(--d-court) var(--courbe);
}
.nav-liens .lien::before {
	content: "";
	position: absolute;
	left: 0.1em;
	top: 0.12em;
	bottom: 0.12em;
	width: 1px;
	background: var(--rubis);
	transform: scaleY(0);
	transform-origin: center bottom;
	transition: transform var(--d-court) var(--courbe);
}
/* LA ZONE DE TOUCHER, PAS LE DESSIN : 15 px de haut portés à 45 (tablette
   tactile), sans fond ni bordure, sans déplacer le texte. Liens à 41,6 px
   l'un de l'autre à 1440, 27 px au plus serré (900) : 10 px de chaque côté
   laissent 21,6 et 7 px libres (banc). Sans JavaScript sur téléphone, la
   prise est bornée dans le bloc du menu. */
.nav-liens .lien::after {
	content: "";
	position: absolute;
	inset: -15px -10px;
}
.nav-liens .lien:hover,
.nav-liens .lien:focus-visible { color: var(--ivoire); }
.nav-liens .lien:hover::before,
.nav-liens .lien:focus-visible::before { transform: scaleY(1); }
.nav-liens .lien[aria-current] { color: var(--ivoire); }
.nav-liens .lien[aria-current]::before { transform: scaleY(1); }

/* même prise pour les liens d'action ISOLÉS (22 à 32 px de haut mesurés),
   jamais pour un lien pris dans une phrase : sa zone chevaucherait les
   lignes voisines. */
.constat-actions .lien,
.transformation .interieur > p > .lien,
.etude-suite .lien,
.specimen-note .lien,
.diagnostic-refaire .lien { position: relative; }
.constat-actions .lien::after,
.transformation .interieur > p > .lien::after,
.etude-suite .lien::after,
.specimen-note .lien::after,
.diagnostic-refaire .lien::after {
	content: "";
	position: absolute;
	inset: -11px 0;
}
/* empilés sur téléphone à 1,2 rem, les deux liens d'une fin d'étude se
   recouvraient à 11 px (banc, 390 et 320). Hauts de 31 px, 9 px suffisent :
   49 px chacun, sans contact. */
.etude-suite .lien::after { inset: -9px 0; }

/* ---- le champ du wordmark ---------------------------------------------
   Le O suit le curseur et entraîne les lettres derrière lui. Le cadre est
   borné en JS (saturation à ±1) : rien ne sort jamais de sa boîte. */
.hero-marque .lettre {
	transform:
		translate(calc(var(--suit-x, 0) * 1px), calc(var(--suit-y, 0) * 1px))
		rotate(calc(var(--suit-r, 0) * 1deg));
	/* le pivot est au PIED de la lettre : poussée en haut, elle bascule sur
	   son empattement au lieu de tourner comme un bouton */
	transform-origin: 50% 92%;
	/* AUCUNE TRANSITION (rc22). La position est intégrée image par image en
	   JS ; une transition par-dessus n'ajouterait que du retard — c'était
	   exactement ce qu'on prenait pour de la masse. */
	will-change: transform;
}

/* ---- l'éclatement à la sortie du hero ----------------------------------
   Chaque lettre se disperse sur SA trajectoire — le mot se défait comme il
   s'était construit. Le O, lui, s'ouvre déjà par le portail. */
/* La trajectoire vient de --l-index, déjà porté par le HTML (1→5) : des
   « nth-child » visaient les mauvais éléments — le SVG et le O accessible
   occupent les deux premiers rangs, et la dernière lettre ne bougeait pas.
   Dispersion PUREMENT HORIZONTALE : le mot s’ouvre depuis son centre,
   exactement comme la ligne de partage ouvre le O. Rien de diagonal, rien
   de gratuit. */
.hero-marque .lettre { --vol-x: calc((var(--l-index, 3) - 3) * 34); }
/* À LA SORTIE (rc19) : la souris LÂCHE PRISE. Le terme de poussée est
   multiplié par (1 − éclat) : à mi-chemin il ne pèse plus que la moitié, à
   la fin plus rien. Le mot n'obéit plus qu'à son ouverture. */
.hero .interieur .hero-marque .lettre {
	transform:
		translate(
			calc(var(--suit-x, 0) * (1 - var(--eclat, 0)) * 1px),
			calc(var(--suit-y, 0) * (1 - var(--eclat, 0)) * 1px))
		rotate(calc(var(--suit-r, 0) * (1 - var(--eclat, 0)) * 1deg))
		translateX(calc(var(--eclat, 0) * var(--vol-x, 0) * 1px));
}
/* le O suit le même sort : il se détache de la souris et part À GAUCHE,
   hors du territoire du R — l'ouverture du mot, vue depuis son pivot */
.hero .interieur .hero-marque svg {
	transform:
		translate(
			calc(var(--vise-x, 0) * (1 - var(--eclat, 0)) * 1px),
			calc(var(--vise-y, 0) * (1 - var(--eclat, 0)) * 1px))
		translateX(calc(var(--eclat, 0) * -74px));
}
/* le bloc du dessous s'ouvre à son tour : les trois lignes s'écartent
   verticalement pendant que le mot s'ouvre horizontalement */
/* Ces trois-là portent DÉJÀ l’animation d’ouverture du hero, qui occupe leur
   « transform » — un transform de plus y était purement ignoré (mesuré : ils
   ne bougeaient pas d’un pixel). Leur ouverture passe donc par la propriété
   « translate », indépendante et composée avec l’animation. */
.hero-slogan { translate: 0 calc(var(--eclat, 0) * -22px); transition: translate 0.2s linear; }
.hero-sous { translate: 0 calc(var(--eclat, 0) * 20px); transition: translate 0.2s linear; }
.hero-actions { translate: 0 calc(var(--eclat, 0) * 46px); transition: translate 0.2s linear; }

@media (prefers-reduced-motion: reduce) {
	.hero-marque .lettre,
	.hero-slogan, .hero-sous, .hero-actions { translate: none !important; transition: none; }
	/* la physique des lettres est déjà éteinte en JS (le module entier
	   s'arrête sur cette même requête média) ; on le redit ici pour que
	   même des variables laissées derrière ne déplacent rien. */
	.hero-marque .lettre { --suit-x: 0; --suit-y: 0; --suit-r: 0; transform: none !important; }
	.nav-liens .lien::before { transition: none; }
}

/* =========================================================================
   L'APPROCHE OPTIQUE DU LOGOTYPE (1.1.0-rc28)
   -------------------------------------------------------------------------
   Playfair Display laisse entre ses lettres des vides TRÈS inégaux. Mesurés
   sur ORVETA, d'encre à encre : O→R 10,1 · R→V 2,3 · V→E 8,1 · E→T 13,5 ·
   T→A 6,0 px (à 651 px de large). Un facteur SIX entre la paire la plus
   serrée et la plus large.

   Conséquence sur la physique : le R n'a que deux pixels et demi à parcourir
   avant de toucher le V — la passe est invisible, on croit le V parti sans
   contact — tandis que le E en a près de quinze avant d'atteindre le T.

   Ces cinq décalages égalisent les vides à CINQ pixels. Cinq, et pas huit :
   sous la règle du contact, la portée de la chaîne vaut la course du O
   (30 px) moins le cumul des vides. À 8 px il ne restait que 6 px au E,
   alors qu il lui en faut 8 pour toucher le T — la chaîne mourait là. À 5 px
   le cumul tombe à 25 et les cinq lettres se touchent : 25 · 20 · 15 · 10 · 5.
   Le mot y perd 15 px de large, soit 2,3 %. C est un crénage optique, pas un
   redessin ; pour revenir en arrière, il suffit de supprimer ce bloc.
   ========================================================================= */
/* Les rangs comptent À PARTIR DE 2 : le mot contient un <svg> puis le O
   accessible avant les cinq lettres, et « nth-of-type » compte tous les span. */
.hero-marque .lettre:nth-of-type(2) { margin-left: 0.015em; }  /* R */
.hero-marque .lettre:nth-of-type(3) { margin-left: 0.063em; }  /* V */
.hero-marque .lettre:nth-of-type(4) { margin-left: 0.016em; }  /* E */
.hero-marque .lettre:nth-of-type(5) { margin-left: -0.029em; } /* T */
.hero-marque .lettre:nth-of-type(6) { margin-left: 0.033em; }  /* A */


/* =========================================================================
   LA MATIÈRE DU HERO (rc45) — ajout unique, couche strictement décorative.
   Un canevas posé derrière tout le contenu du hero. Il ne porte AUCUNE
   information : sans script il reste transparent et le hero est celui
   d'avant, au pixel. L'opacité maîtresse est ici — c'est LE réglage à
   toucher si la matière paraît trop présente (ordre de réduction : opacité,
   puis amplitude et influence souris dans orveta.js, module 4 bis).
   ========================================================================= */
.hero-matiere {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	pointer-events: none;
	opacity: 0;
	transition: opacity 2.2s var(--courbe);
	/* le réglage maître de toute la matière */
	--matiere-opacite: 0.42;
}
/* la classe « nee » est posée par le script après la première image :
   la matière monte en 2,2 s — jamais d'apparition brutale */
.hero-matiere.nee { opacity: var(--matiere-opacite); }
@media (max-width: 1023px) { .hero-matiere { --matiere-opacite: 0.36; } }
@media (max-width: 767px) { .hero-matiere { --matiere-opacite: 0.32; } }
@media (prefers-reduced-motion: reduce) {
	/* fond STATIQUE : une seule image est dessinée, et pas de fondu */
	.hero-matiere { transition: none; }
}
/* =========================================================================
   LE MANIFESTE — « LE CHAOS QUI RÉVÈLE L'IMAGE » (rc48).
   Remplace la matière typographique de rc47, dont les formes (O, A, G,
   apostrophe) devaient précisément DISPARAÎTRE : au repos, plus une seule
   lettre décorative à l'écran.

   La phrase est découpée en trois par le module 9 :
     — segment A « Nous ne créons pas simplement des sites. Nous créons »,
       révélé mot à mot ;
     — « l'image », le point de bascule, en rubis ;
     — segment C « que votre entreprise mérite de montrer. », dont CHAQUE
       glyphe part garé sur les côtés, en apparent désordre, et rejoint sa
       place au moment de la bascule.

   LA CLÉ DU DISPOSITIF : les lettres qui volent SONT les lettres de la
   phrase, à leur place dans le flux. Ce n'est pas une copie qui rejoint un
   texte caché — c'est le texte lui-même, décalé par un `transform`. D'où
   trois propriétés gratuites : la destination est exacte par construction,
   elle se recalcule seule à tout changement de largeur, et rien ne bouge
   dans la mise en page.

   Les groupes sont `inline-block` : sans eux, chaque glyphe serait une
   occasion de coupure et « entreprise » pourrait se briser en deux lignes.
   Les coupures ne tombent donc qu'entre les mots, comme dans un texte.

   AU REPOS — sans script, en mouvement réduit, ou si le module ne tourne
   pas — la phrase est ENTIÈRE et lisible, « l'image » en rubis, chaque
   lettre à sa place. Les états de départ sont posés par le module, jamais
   par la feuille : la règle de tout le projet.
   ========================================================================= */
.philosophie-scene { overflow: hidden; }
.philosophie-phrase { position: relative; }
.ph-mot, .ph-image, .ph-groupe { display: inline-block; }
.ph-l {
	display: inline-block;
	/* la lettre garée reste dans le plan du texte : aucune ombre, aucun
	   filtre, rien qui coûte une couche de composition par glyphe */
	white-space: pre;
}
.ph-mot, .ph-image { opacity: 1; }
/* la lettre n'est pas là tant qu'elle n'est pas tombée : son état de repos
   est l'absence, et l'étirement se mesure depuis son pied. */
.ph-l { opacity: 0; transform-origin: 50% 100%; }


/* =========================================================================
   LE PORTAIL (rc58) — « ce que fait un site », en huit scènes.

   LE PRINCIPE MÉCANIQUE, INCHANGÉ DEPUIS rc53 : la piste est haute, la
   scène est COLLANTE, et l'on traduit la progression verticale en une
   translation du rail. Trois conséquences gratuites : la molette, le pavé
   tactile, le doigt et l'inertie du système fonctionnent tous sans qu'on
   écoute un seul « wheel » ni « touchmove » ; le parcours est réversible
   par construction ; et un défilement très rapide ne peut rien casser,
   puisqu'il n'y a pas d'état à rattraper — seulement une position à lire.

   CE QUI CHANGE EN rc58 : le contenu et son rôle. Le bloc ne montre plus
   une réalisation ; il DÉMONTRE, sans arguments, ce qu'un site bien conçu
   fait — attirer, présenter, organiser, faire interagir, convaincre,
   convertir, mettre en contact, créer une relation.

   TOUTE L'ANIMATION EST PILOTÉE PAR LE DÉFILEMENT, sans une seule
   « @keyframes ». Ce n'est pas une coquetterie :
     · le défilement EST la ligne de temps — avancer d'un cheveu avance la
       scène d'un cheveu, revenir en arrière la rembobine exactement ;
     · une scène immobile ne coûte RIEN (aucune image n'est recalculée
       tant qu'aucune variable ne change) ;
     · il n'existe aucune boucle à raccorder, donc aucun saut de raccord ;
     · s'arrêter au milieu d'une scène est un état parfaitement valide.

   Quatre nombres publiés par le moteur SUR CHAQUE SCÈNE :
     --u  0→1  la traversée du champ (0,5 = la scène est au centre)
     --e  0→1  l'entrée — la scène se construit
     --m  0→1  le moment principal — ce qu'elle a à montrer
     --o  0→1  la sortie — elle passe le relais à la suivante
     --joue 0/1 assez proche pour mériter d'être composée
   ========================================================================= */
.portail {
	/* LE BLOC NE SE DÉFILE PLUS, IL SE JOUE. Le parcours a sa propre
	   horloge (module 9 ter) : chaque scène est un petit film qui tourne
	   en boucle, et le rail avance de lui-même pour découvrir la suivante.
	   La hauteur est donc celle d'UN écran, pas de huit. */
	--portail-clair: #F7EEDA;   /* l'ivoire d'arrivée */
	/* LA HAUTEUR BORNE LA LARGEUR. La carte tire sa hauteur de sa largeur
	   (16/10) : sans le troisième terme, une bande de 74 vh se faisait
	   traverser par des cartes plus hautes qu'elle, rognées en haut et en
	   bas. 112 vh de large = 70 vh de haut, la bande en contient 74.
	   Le plafond est une VARIABLE : trois scènes redéclarent leur largeur,
	   et un plafond posé sur la seule déclaration de base les laissait
	   rogner exactement comme avant. */
	--sc-plafond: 120vh;
	/* PLUS GRANDES, PARCE QUE PLUS RIEN N'ATTEND À CÔTÉ. Il fallait jadis
	   tenir TROIS cartes de front : la suivante patientait, allumée, dans
	   la marge. Elle ne paraît plus avant son tour — seules la scène jouée
	   et celle qui vient de l'être cohabitent. La carte peut donc prendre
	   la place que réclame un geste d'interface, sans rien sacrifier du
	   déplacement. */
	/* LA MESURE QUI COMMANDE TOUT : trois cartes doivent tenir de front
	   dans la fenêtre — celle qui part, celle qui joue, celle qui attend.
	   À 46 vw, la carte active est centrée et laisse de chaque côté une
	   marge plus large que l'écart : les deux voisines entrent dans le
	   cadre, et le pas latéral a enfin des témoins. */
	/* PLUS GRANDS, ET MUETS. Aucune légende ne vient expliquer les scènes :
	   chacune doit se comprendre seule, ce qui suppose qu'on la VOIE — une
	   vignette ne montre pas un geste d'interface. */
	--sc-large: min(72vw, 52rem, var(--sc-plafond));
	--sc-ecart: clamp(3.5rem, 9vw, 11rem);
	/* le seuil n'a plus de progression à suivre : il est simplement là */
	--tension: 1;
	--voyage: 0;
	--sortie: 0;

	/* la matière des interfaces fictives : une surface un rien plus claire
	   que le carbone, un filet, et des barres qui tiennent lieu de texte.
	   AUCUNE MARQUE, AUCUNE COPIE — voir le commentaire du HTML. */
	--ec-fond: #1B1714;
	--ec-fond-2: #221D19;
	--ec-trait: rgba(239, 233, 220, 0.10);
	--ec-barre: rgba(239, 233, 220, 0.26);
	--ec-barre-forte: rgba(239, 233, 220, 0.44);
	position: relative;
	padding-block: clamp(3rem, 9vh, 7rem);
	/* L'ARRIVÉE. Le site est en carbone du début à la fin ; ici, et ici
	   seulement, la lumière se lève. Ce n'est pas un effet : c'est le
	   chapitre où l'on explique ce que le redesign met en place, et il
	   doit se reconnaître avant d'être lu. Une seule couleur qui monte en
	   1,2 s — pas un flash, pas un blanc : un ivoire chaud. */
	background-color: var(--carbone);
	transition: background-color 1.2s var(--courbe);
}
.portail.eclat {
	background-color: var(--portail-clair);
	/* sur l'ivoire, les filets d'ivoire ne diraient plus rien : l'encre
	   prend le relais, et les écrans sombres se posent avec une ombre. */
	--filet: rgba(25, 21, 16, 0.20);
}
.portail.eclat .portail-o .o-gauche { fill: var(--encre); }
/* LES HUIT SCÈNES SONT DES ÉCRANS, ET TOUS PORTENT LEUR OMBRE. L'ombre
   excluait « .ec-nu » du temps où deux scènes dessinaient à même la
   section ; elles ont maintenant le même cadre que les autres, et sans
   ombre elles flotteraient sur l'ivoire quand les six voisines se posent. */
.portail.eclat .ec { box-shadow: 0 26px 64px -26px rgba(20, 18, 16, 0.5); }

.portail-piste { height: 200vh; }
.portail-scene {
	position: sticky;
	top: 0;
	height: 100vh;
	height: 100svh;
	/* TOUT LE DÉPLACEMENT EST CONTENU ICI : jamais de barre horizontale
	   sur le document, quelle que soit la longueur du rail */
	overflow: hidden;
	/* PAS DE CENTRAGE ICI. Le rail est maintenant une grille de trois
	   rangées, bien plus haute que la fenêtre : un « align-items: center »
	   posait son origine de mise en page à moitié au-dessus du cadre, et
	   les huit stations, mesurées depuis le rail, héritaient toutes du même
	   décalage. Le centrage vertical est l'affaire du moteur, station par
	   station — la fenêtre, elle, commence à zéro. */
	display: block;
}

/* ---- le seuil : il se tend, puis laisse passer ------------------------ */
.portail-seuil {
	position: absolute;
	left: 50%;
	top: 0;
	display: grid;
	justify-items: center;
	transform: translateX(-50%);
	/* ON LE FRANCHIT, DONC IL RECULE. */
	opacity: calc((1 - var(--sortie, 0)) * (1 - min(1, var(--voyage, 0) / 0.22)));
	pointer-events: none;
	z-index: 3;
}
.portail-trait {
	display: block;
	width: 1px;
	height: calc(2rem + var(--tension, 0) * clamp(3rem, 9vh, 6rem));
	background: linear-gradient(180deg, transparent, var(--filet));
}
.portail-o { width: 15px; height: 18px; margin-top: -1px; }
.portail-o .o-gauche { fill: var(--ivoire); transform: translateX(calc(var(--tension, 0) * -3px)); }
.portail-o .o-droite { fill: var(--rubis); transform: translateX(calc(var(--tension, 0) * 3px)); }

/* ---- le rail : la caméra se déplace le long de la composition -------- */
.portail-rail {
	/* UN PLAN, PLUS UNE LIGNE. Le parcours descendait de huit vignettes
	   alignées : tout se jouait dans un couloir, et la bande ne pouvait
	   pas grandir vers le bas. Les scènes sont maintenant posées sur une
	   grille de trois colonnes, et la caméra suit un serpentin —
	   deux pas à droite, un cran plus bas, deux pas à gauche, un cran plus
	   bas. Le motif se reconnaît dès la troisième scène. */
	display: grid;
	grid-template-columns: repeat(3, var(--sc-large));
	justify-items: start;
	align-items: center;
	gap: clamp(5rem, 14vh, 9rem) var(--sc-ecart);
	/* LA PREMIÈRE SCÈNE COMMENCE AU BORD GAUCHE, pas au centre. C'est ce
	   décadrage qui dit qu'il y a une suite : le premier film se joue à
	   gauche, le reste attend dans la marge droite, à moitié visible.
	   Puis le rail glisse, et le motif se répète — jouer, découvrir. */
	padding: var(--gouttiere);
	opacity: var(--fondu, 1);
	will-change: transform;
	transform: translate3d(calc(var(--x, 0) * -1px), calc(var(--y, 0) * -1px), 0);
}

/* ON LIT LE BLOC COMME UNE PAGE. Le parcours suivait un serpentin : la
   deuxième rangée revenait de droite à gauche. C'est élégant sur un plan,
   illisible pour un visiteur — on ne sait plus dans quel sens l'histoire
   avance. Chaque rangée part maintenant de la gauche et finit à droite,
   comme une ligne de texte, et le retour à la ligne se fait à vue. */
.sc-01 { grid-area: 1 / 1; }
.sc-02 { grid-area: 1 / 2; }
.sc-03 { grid-area: 1 / 3; }
.sc-04 { grid-area: 2 / 1; }
.sc-05 { grid-area: 2 / 2; }
.sc-06 { grid-area: 2 / 3; }
.sc-07 { grid-area: 3 / 1; }
.sc-08 { grid-area: 3 / 2; }
.sc {
	/* le jeton d'en-tête est lisible par les curseurs, qui sont enfants de
	   la scène et non de l'écran. */
	--ec-tete: calc(clamp(16px, 2.2vw, 22px) + 0.75rem);
	/* UNE UNITÉ QUI SUIT LA CARTE. Les pourcentages d'un « translate » se
	   mesurent sur l'élément TRANSFORMÉ, pas sur son parent : un curseur
	   de 13 px à qui l'on demandait « 190 % » parcourait vingt-cinq
	   pixels et n'atteignait jamais sa cible. Un pour cent de la largeur
	   de carte, exprimé en longueur, ne peut pas faire cette erreur. */
	--U: calc(var(--sc-large) / 100);
	flex: none;
	width: var(--sc-large);
	position: relative;
	/* la profondeur : chaque scène contre-glisse un rien, si bien que les
	   plans ne défilent pas tous à la même vitesse. MICRO-parallaxe. */
	transform: translate3d(calc(var(--x, 0) * var(--prof, 0.03) * 1px), calc(var(--y, 0) * var(--prof, 0.03) * 1px), 0);
}
.sc-01 { --prof: 0.055; }
.sc-02 { --prof: 0.030; }
.sc-03 { --prof: 0.045; }
.sc-04 { --prof: 0.028; }
.sc-05 { --prof: 0.048; }
/* PLUS AUCUNE EXCEPTION DE TAILLE. Trois scènes portaient leur propre
   largeur, héritée d'une époque où chacune tenait une composition
   différente : à l'écran, une carte plus petite se lit comme un moment
   moins important, et celle du CTA était la plus petite de toutes. */
.sc-06 { --prof: 0.022; }
.sc-07 { --prof: 0.040; }
.sc-08 { --prof: 0.018; }

/* la scène entière respire : elle monte en présence en arrivant et se
   retire en partant. C'est ce qui relie les huit — aucune ne « coupe ». */
.sc > * {
	/* LA PRÉSENCE EST DÉSORMAIS SÉPARÉE DE LA PROGRESSION. Une scène
	   s'effaçait à la fin de son propre tour : on ne voyait jamais deux
	   images ensemble, et le déplacement latéral n'avait donc aucun
	   témoin. Elle reste maintenant en place pendant tout le tour de la
	   suivante, et ne s'en va que lorsque la troisième prend sa place.
	   C'est le moteur qui publie « --pres », sur sa propre horloge. */
	opacity: var(--pres, 1);
}

/* ---- l'écran fictif : la matière commune aux huit scènes -------------- */
.ec {
	--ec-pad: clamp(1rem, 2.4vw, 1.9rem);
	--ec-tete: calc(clamp(16px, 2.2vw, 22px) + 0.75rem);
	position: relative;
	border-radius: 14px;
	background: linear-gradient(170deg, var(--ec-fond-2), var(--ec-fond));
	border: 1px solid var(--ec-trait);
	padding: var(--ec-pad);
	padding-top: calc(var(--ec-pad) + var(--ec-tete));
	aspect-ratio: 16 / 10;
	overflow: hidden;
	/* elle se pose : un rien de recul à l'arrivée, jamais un zoom */
	/* ELLE VIENT DE LA DROITE ET S'EN VA PAR LA GAUCHE. Une scène qui se
	   contentait de paraître et de disparaître ne disait pas le sens du
	   parcours ; ce glissement, lu en même temps que celui du rail, fait
	   la différence entre huit images posées et une marche.

	   ET CE QUI EST JOUÉ RECULE. Une scène finie gardait toute sa
	   présence pendant le tour de la suivante : deux images pleines se
	   disputaient le regard, et l'on ne savait plus laquelle raconte. Elle
	   reste maintenant lisible — la trace de ce qui vient d'être dit — mais
	   d'un demi-pas en arrière : un peu plus petite, un peu plus pâle. */
	transform: translate3d(calc((1 - var(--e, 0)) * 34px - var(--o, 0) * 30px - var(--recul, 0) * 16px), 0, 0)
	           scale(calc(0.972 + 0.028 * var(--e, 0) - 0.022 * var(--o, 0) - 0.055 * var(--recul, 0)));
}
.ec-nu { background: none; border-color: transparent; padding-top: var(--ec-pad); }
.sc-06 .ec-nu {
	background: linear-gradient(170deg, var(--ec-fond-2), var(--ec-fond));
	border-color: var(--ec-trait);
}

/* les barres qui tiennent lieu de texte, et les boutons ---------------- */
.ba {
	display: block;
	height: clamp(7px, 1.1vw, 10px);
	border-radius: 99px;
	background: var(--ec-barre);
}
.ba-c { width: 62%; }
.bt {
	display: inline-flex;
	align-items: center;
	gap: 0.5em;
	padding: 0.62em 1.15em;
	border-radius: 99px;
	background: var(--rubis);
	color: #2A0F0C;
	font: 600 clamp(0.62rem, 1.05vw, 0.84rem)/1 var(--police-texte);
	letter-spacing: 0.04em;
	white-space: nowrap;
}
.fl {
	width: 0.85em; height: 0.85em;
	border-top: 2px solid currentColor;
	border-right: 2px solid currentColor;
	transform: rotate(45deg) scale(0.8);
	border-radius: 1px;
}
/* le curseur : un disque discret, jamais une flèche de système ---------- */
.cu {
	position: absolute;
	width: 13px; height: 13px;
	border-radius: 50%;
	border: 1.5px solid var(--ivoire);
	background: rgba(239, 233, 220, 0.12);
	pointer-events: none;
	z-index: 4;
	opacity: 0;
}

/* =========================== 01 · ATTIRER ==============================
   Presque rien, puis une page. L'ordre d'apparition EST le propos : une
   première impression se construit, elle ne tombe pas d'un bloc. */
.sc-01 {
	--n1: clamp(0, (var(--e) - 0.02) * 5, 1);   /* la barre de navigation */
	--n2: clamp(0, (var(--e) - 0.14) * 5, 1);   /* la marque et l'appel */
	--a3: clamp(0, (var(--e) - 0.26) * 4, 1);   /* la première ligne du titre */
	--a4: clamp(0, (var(--e) - 0.38) * 4, 1);   /* la seconde */
	--a5: clamp(0, (var(--e) - 0.48) * 4, 1);   /* le visuel */
	--a6: clamp(0, (var(--e) - 0.62) * 4, 1);   /* l'appel */
	/* LE SURVOL PRÉCÈDE LA PRESSION. Déclarées sur le bouton, ces deux
	   valeurs n'atteignaient pas le curseur, qui n'en est pas un
	   descendant mais un voisin : sa réaction au clic ne se produisait
	   jamais. Elles appartiennent à la SCÈNE — c'est elle qui joue. */
	--tap: clamp(0, (var(--m) - 0.42) * 5, 1);
	--enf: clamp(0, (var(--m) - 0.66) * 14, 1);
}
.ec-nav {
	--a1: 1;
	--a2: 1;
	position: absolute;
	top: var(--ec-pad);
	left: var(--ec-pad);
	right: var(--ec-pad);
	z-index: 3;
}
.mq {
	width: clamp(16px, 2.2vw, 22px);
	height: clamp(16px, 2.2vw, 22px);
	border-radius: 50%;
	/* la marque fictive est une forme, jamais un nom : deux moitiés, comme
	   partout ici — mais elle n'appartient à personne. */
	background: linear-gradient(90deg, var(--ivoire) 0 50%, var(--rubis) 50% 100%);
	opacity: var(--a2);
	transform: scale(calc(0.6 + 0.4 * var(--a2)));
}
.nav-l { width: clamp(22px, 3.4vw, 40px); height: 5px; border-radius: 99px; background: var(--ec-barre); }
/* LE BOUTON DU SITE, TOUJOURS LÀ, TOUJOURS AU MÊME ENDROIT. Il était un
   contour vide : un détail de décor. Rempli de rubis et répété à
   l'identique sur les huit écrans, il devient ce que la refonte met en
   place — le seul point rouge de l'interface, celui vers lequel tout
   converge. C'est la démonstration, sans un mot. */
.nav-p {
	margin-left: auto;
	width: clamp(44px, 6vw, 68px); height: clamp(16px, 2.2vw, 22px);
	border-radius: 99px;
	background: var(--rubis);
	opacity: var(--a2);
}
.ec-nav {
	display: flex;
	align-items: center;
	gap: clamp(0.6rem, 1.6vw, 1.3rem);
	padding-bottom: clamp(0.7rem, 1.6vw, 1.2rem);
	border-bottom: 1px solid var(--ec-trait);
	opacity: var(--a1);
	transform: translateY(calc((1 - var(--a1)) * -10px));
}
/* la scène 01 est la seule où l'en-tête se CONSTRUIT : c'est son propos. */
.sc-01 .ec-nav { --a1: var(--n1); --a2: var(--n2); }
.sc-01 .ec-corps {
	display: grid;
	grid-template-columns: 1.05fr 0.95fr;
	gap: clamp(1rem, 3vw, 2.4rem);
	align-items: center;
	height: 100%;
}
.sc-01 .ec-dit { display: grid; gap: clamp(0.5rem, 1.2vw, 0.9rem); align-content: center; }
.sc-01 .ba-1, .sc-01 .ba-2 { height: clamp(13px, 2.1vw, 20px); }
.sc-01 .ba-1 { width: 100%; background: var(--ec-barre-forte); opacity: var(--a3); transform: translateY(calc((1 - var(--a3)) * 14px)); }
.sc-01 .ba-2 { width: 72%; background: var(--ec-barre-forte); opacity: var(--a4); transform: translateY(calc((1 - var(--a4)) * 14px)); }
.sc-01 .ba-3 { width: 84%; margin-top: 0.3rem; opacity: calc(var(--a4) * 0.8); }
.sc-01 .bt {
	position: relative;
	justify-self: start;
	margin-top: clamp(0.5rem, 1.4vw, 1rem);
	opacity: var(--a6);
	/* §8 — le bouton RÉPOND, très légèrement, quand le curseur l'atteint.
	   Pas d'effet publicitaire : deux pour cent d'échelle et un souffle. */
	transform: translateY(calc((1 - var(--a6)) * 12px)) scale(calc(1 + 0.03 * var(--tap, 0)));
	box-shadow: 0 0 0 calc(var(--tap, 0) * 6px) rgba(240, 101, 90, 0.10);
	/* LE SURVOL PRÉCÈDE LA PRESSION, ET LA PRESSION SE VOIT. Un bouton qui
	   grossit sous un curseur immobile ne raconte rien ; ici il s'éclaire
	   à l'approche (--tap), puis s'enfonce d'un cheveu au contact (--enf).
	   C'est ce creux d'un pour cent qui fait lire « on a cliqué ». */
}
.sc-01 .bt {
	transform: translateY(calc((1 - var(--a6)) * 12px))
	           scale(calc(1 + 0.03 * var(--tap, 0) - 0.05 * var(--enf) * (1 - var(--enf)) * 4));
}
.sc-01 .bt .fl { transform: rotate(45deg) scale(0.8) translateX(calc(var(--tap, 0) * 3px)); }
.sc-01 .ec-vue { position: relative; height: 78%; opacity: var(--a5); }
.sc-01 .fo { position: absolute; border-radius: 10px; }
.sc-01 .fo-a {
	inset: 0 18% 22% 0;
	background: linear-gradient(150deg, rgba(239, 233, 220, 0.13), rgba(239, 233, 220, 0.04));
	border: 1px solid var(--ec-trait);
	transform: translate(calc((1 - var(--a5)) * 18px), calc((1 - var(--a5)) * 12px));
}
.sc-01 .fo-b {
	inset: 30% 0 0 34%;
	background: linear-gradient(150deg, rgba(240, 101, 90, 0.30), rgba(240, 101, 90, 0.08));
	transform: translate(calc((1 - var(--a5)) * -14px), calc((1 - var(--a5)) * 16px));
}
.sc-01 .fo-c {
	width: 26%; aspect-ratio: 1; right: 8%; top: 12%;
	border: 1px solid rgba(240, 101, 90, 0.45);
	border-radius: 50%;
	transform: scale(calc(0.7 + 0.3 * var(--a5)));
}
/* le curseur entre par la droite et vient toucher l'appel */
.sc-01 .cu-01 {
	/* IL EST DANS LE BOUTON. Placé dans la scène, sa cible dépendait de
	   deux pourcentages accordés à la main : ils tombaient à vingt-six
	   pixels au-dessus du bouton, et le curseur visait le vide. Enfant du
	   bouton, il ne peut plus le manquer, à aucune taille d'écran.
	   Il ARRIVE (0,18), il TOUCHE (0,42), il APPUIE (0,66), il RESTE. */
	left: auto;
	right: calc(1.15em + 0.425em - 6.5px);
	top: calc(50% - 6.5px);
	--vol: clamp(0, (var(--m) - 0.18) * 2.6, 1);
	opacity: clamp(0, (var(--m) - 0.18) * 5, 1);
	transform: translate(calc((1 - var(--vol)) * 44 * var(--U)), calc((1 - var(--vol)) * 17 * var(--U)))
	           scale(calc(1 - 0.28 * var(--enf, 0) * (1 - var(--enf, 0)) * 4));
	background: rgba(240, 101, 90, calc(0.12 + 0.5 * var(--enf, 0)));
	border-color: rgba(239, 233, 220, calc(0.55 + 0.45 * var(--tap, 0)));
}

/* =========================== 02 · PRÉSENTER ============================
   Ce qu'une interface sait faire. UNE chose à la fois : le carrousel
   glisse d'abord, les cartes répondent ensuite. */
/* LA CAUSE AVANT L'EFFET. Le carrousel partait seul et le curseur
   arrivait après : on voyait une machine, pas une interface. Désormais le
   curseur entre (0,02), balaye (0,12), et la piste SUIT son geste avec un
   retard d'un dixième — c'est ce retard qui se lit comme une traction. */
.sc-02 {
	--ent: clamp(0, (var(--m) - 0.02) * 6, 1);
	--bal: clamp(0, (var(--m) - 0.12) * 2.6, 1);
	--car: clamp(0, (var(--m) - 0.16) * 2.4, 1);
}
.sc-02 .ec { display: grid; grid-template-rows: 1.5fr auto; gap: clamp(0.8rem, 2vw, 1.5rem); }
.sc-02 .ca { position: relative; overflow: hidden; border-radius: 10px; }
.sc-02 .ca-piste {
	display: flex;
	height: 100%;
	width: 300%;
	transform: translate3d(calc(var(--car) * -66.666%), 0, 0);
}
.sc-02 .ca-vue {
	width: 33.333%;
	height: 100%;
	position: relative;
	display: grid;
	align-content: end;
	gap: 8px;
	padding: clamp(0.7rem, 1.8vw, 1.2rem);
	border-right: 1px solid var(--carbone);
}
.sc-02 .cv-1 { background: linear-gradient(140deg, rgba(239, 233, 220, 0.16), rgba(239, 233, 220, 0.03)); }
.sc-02 .cv-2 { background: linear-gradient(140deg, rgba(240, 101, 90, 0.30), rgba(240, 101, 90, 0.05)); }
.sc-02 .cv-3 { background: linear-gradient(140deg, rgba(239, 233, 220, 0.10), rgba(240, 101, 90, 0.14)); }
.sc-02 .ca-vue i { display: block; height: 7px; border-radius: 99px; background: rgba(20, 18, 16, 0.35); }
.sc-02 .ca-vue i:first-child { width: 46%; }
.sc-02 .ca-vue i:last-child { width: 28%; }
.sc-02 .ca-pts {
	position: absolute;
	right: clamp(0.7rem, 1.8vw, 1.2rem);
	top: clamp(0.7rem, 1.8vw, 1.2rem);
	display: flex; gap: 6px;
}
.sc-02 .ca-pts i { width: 6px; height: 6px; border-radius: 50%; background: rgba(239, 233, 220, 0.30); }
/* le point actif suit le carrousel — la commande dit la vérité */
.sc-02 .ca-pts i:nth-child(1) { background: rgba(239, 233, 220, calc(0.30 + 0.65 * (1 - clamp(0, var(--car) * 2, 1)))); }
.sc-02 .ca-pts i:nth-child(2) { background: rgba(239, 233, 220, calc(0.30 + 0.65 * min(var(--car) * 2, 2 - var(--car) * 2))); }
.sc-02 .ca-pts i:nth-child(3) { background: rgba(239, 233, 220, calc(0.30 + 0.65 * clamp(0, var(--car) * 2 - 1, 1))); }
.sc-02 .ec-cartes { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(0.6rem, 1.6vw, 1.1rem); }
.sc-02 .kt {
	display: grid; gap: 7px;
	padding: clamp(0.55rem, 1.3vw, 0.85rem);
	border-radius: 9px;
	border: 1px solid var(--ec-trait);
	background: rgba(239, 233, 220, calc(0.02 + 0.05 * var(--lev, 0)));
	transform: translateY(calc(var(--lev, 0) * -7px));
}
.sc-02 .kt-vue { height: clamp(26px, 4.5vw, 44px); border-radius: 6px; background: rgba(239, 233, 220, 0.07); }
/* §12 — les micro-interactions se SUCCÈDENT : une carte, puis l'autre.
   Simultanées, elles feraient un feu d'artifice illisible. */
.sc-02 .kt-1 { --lev: clamp(0, (var(--m) - 0.52) * 7, 1); }
.sc-02 .kt-2 { --lev: clamp(0, (var(--m) - 0.64) * 7, 1); }
.sc-02 .kt-3 { --lev: clamp(0, (var(--m) - 0.76) * 7, 1); }
.sc-02 .kt-2 { border-color: rgba(240, 101, 90, calc(0.10 + 0.45 * var(--lev, 0))); }
.sc-02 .cu-02 {
	/* sa course entière : il entre par la droite au niveau du carrousel,
	   le tire vers la gauche, puis DESCEND sur les cartes et les désigne
	   l'une après l'autre. Une seule main, un seul geste continu. */
	left: 20%; top: calc(28% + var(--ec-tete));
	--bas: clamp(0, (var(--m) - 0.44) * 3.4, 1);
	--k2: clamp(0, (var(--m) - 0.60) * 5, 1);
	--k3: clamp(0, (var(--m) - 0.72) * 5, 1);
	opacity: var(--ent);
	/* il entre par la droite (48 U), tire, puis DESCEND sur la rangée de
	   cartes (30 U ≈ la moitié de la hauteur) et passe de l'une à l'autre
	   d'un tiers de carte. Tout est en unités de carte : le geste est le
	   même sur un écran de portable et sur un moniteur. */
	transform: translate(
		calc((1 - var(--bal)) * 48 * var(--U) + (var(--k2) + var(--k3)) * 30 * var(--U)),
		calc(var(--bas) * 30 * var(--U)));
}

/* =========================== 03 · ORGANISER ============================
   Des blocs épars se rangent — c'est le geste même de la conception —
   puis une ligne de lecture descend et allume chacun à son passage.
   Rien n'est écrit : on VOIT que l'interface conduit le regard. */
.sc-03 { --ran: clamp(0, (var(--e) - 0.16) * 1.9, 1); --lec: clamp(0, (var(--m) - 0.18) * 1.45, 1); }
.sc-03 .ec { display: grid; align-content: center; }
.sc-03 .og { display: grid; gap: clamp(0.55rem, 1.5vw, 1rem); }
.sc-03 .og-b, .sc-03 .og-s {
	height: clamp(11px, 1.8vw, 17px);
	border-radius: 99px;
	background: var(--ec-barre);
	/* du désordre à l'ordre : décalage, inclinaison et largeur convergent
	   tous vers zéro. La largeur finale est celle de la hiérarchie. */
	transform: translateX(calc((1 - var(--ran)) * var(--dx, 0) * 1px))
	           rotate(calc((1 - var(--ran)) * var(--dr, 0) * 1deg));
}
.sc-03 .ob-1 { --dx: -74; --dr: -1.6; width: calc(52% + var(--ran) * 12%); height: clamp(15px, 2.5vw, 24px); background: var(--ec-barre-forte); }
.sc-03 .ob-2 { --dx: 96; --dr: 1.2; width: calc(92% - var(--ran) * 4%); }
.sc-03 .ob-3 { --dx: -58; --dr: 1.8; width: calc(70% + var(--ran) * 6%); }
.sc-03 .ob-4 { --dx: 68; --dr: -1.1; width: calc(30% + var(--ran) * 4%); background: var(--rubis); }
.sc-03 .og-trio { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(0.5rem, 1.4vw, 0.9rem); margin-block: 0.35rem; }
.sc-03 .og-s { --dr: 0; height: clamp(38px, 6vw, 62px); border-radius: 9px; }
.sc-03 .og-s:nth-child(1) { --dx: -46; }
.sc-03 .og-s:nth-child(2) { --dx: 8; }
.sc-03 .og-s:nth-child(3) { --dx: 52; }
/* la ligne de lecture : elle descend, et ce qu'elle touche s'éclaire */
.sc-03 .og-ligne {
	position: absolute;
	left: 0; right: 0;
	top: calc(12% + var(--lec) * 74%);
	height: 1px;
	background: linear-gradient(90deg, transparent, var(--rubis), transparent);
	opacity: calc(var(--lec) * (1 - var(--lec)) * 3.4);
	box-shadow: 0 0 18px rgba(240, 101, 90, 0.35);
}
/* chaque bloc s'allume quand la ligne est à sa hauteur : un pic étroit,
   centré sur sa position dans la descente. Pas de « filter » — une
   opacité coûte moins cher et ne crée pas de calque par bloc. */
.sc-03 .og > * {
	/* l'écart d'allumage était trop faible pour se voir : à 0,5 de base,
	   la ligne de lecture passait sans rien révéler. Le contraste fait
	   ici tout le sens — c'est LUI qu'on regarde, pas la ligne. */
	--lum: max(0, min(1 - (var(--lec) - var(--pos, 0)) * 7, 1 - (var(--pos, 0) - var(--lec)) * 7));
	opacity: calc(0.28 + 0.72 * var(--lum));
}
/* et le regard s'arrête sur l'action : le dernier bloc, rubis, garde sa
   pleine présence une fois la ligne passée, et s'entoure d'un halo. */
.sc-03 .ob-4 {
	--fini: clamp(0, (var(--lec) - 0.88) * 8, 1);
	opacity: calc(0.28 + 0.72 * max(var(--lum), var(--fini)));
	box-shadow: 0 0 0 calc(var(--fini) * 5px) rgba(240, 101, 90, 0.10);
}
/* le curseur vient s'y poser : la hiérarchie a conduit quelque part */
.sc-03 .cu-03 {
	left: 24%; bottom: calc(16.3% - var(--ec-tete) / 2);
	--ven: clamp(0, (var(--m) - 0.72) * 3.4, 1);
	opacity: clamp(0, (var(--m) - 0.72) * 5, 1);
	transform: translate(calc((1 - var(--ven)) * 36 * var(--U)), calc((1 - var(--ven)) * 14 * var(--U)));
}
.sc-03 .ob-1 { --pos: 0.10; }
.sc-03 .ob-2 { --pos: 0.30; }
.sc-03 .og-trio { --pos: 0.54; }
.sc-03 .ob-3 { --pos: 0.76; }
.sc-03 .ob-4 { --pos: 0.92; }

/* =========================== 04 · INTERAGIR ============================
   Le curseur arrive, survole, clique — et l'interface RÉPOND. C'est là
   qu'un site cesse d'être une affiche. */
.sc-04 {
	--app: clamp(0, (var(--m) - 0.05) * 3.2, 1);   /* l'approche */
	--sur: clamp(0, (var(--m) - 0.34) * 6, 1);     /* le survol */
	--cli: clamp(0, (var(--m) - 0.50) * 9, 1);     /* le clic */
	--ouv: clamp(0, (var(--m) - 0.58) * 2.6, 1);   /* le volet s'ouvre */
}
.sc-04 .ec { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(0.9rem, 2.4vw, 1.8rem); align-items: center; }
.sc-04 .ix { display: contents; }
.sc-04 .ix-carte {
	position: relative;
	display: grid; gap: 9px;
	padding: clamp(0.7rem, 1.8vw, 1.2rem);
	border-radius: 11px;
	border: 1px solid rgba(240, 101, 90, calc(0.08 + 0.42 * var(--sur)));
	background: rgba(239, 233, 220, calc(0.03 + 0.05 * var(--sur)));
	transform: translateY(calc(var(--sur) * -9px)) scale(calc(1 - 0.02 * var(--cli) * (1 - var(--cli))* 4));
	overflow: hidden;
}
.sc-04 .ix-vue { height: clamp(48px, 8vw, 92px); border-radius: 7px; background: rgba(239, 233, 220, 0.08); }
.sc-04 .ix-onde {
	position: absolute;
	left: 50%; top: 58%;
	width: 14px; height: 14px;
	margin: -7px 0 0 -7px;
	border-radius: 50%;
	/* UN ANNEAU, pas un disque. Le disque plein tachait la carte et
	   ressemblait à une pastille de système ; l'anneau dit le clic et
	   laisse voir ce qu'il y a dessous. */
	border: 1.5px solid rgba(240, 101, 90, 0.55);
	transform: scale(calc(var(--cli) * 14));
	opacity: calc((1 - var(--cli)) * var(--cli) * 2.6);
}
.sc-04 .ix-volet {
	display: grid; gap: 9px;
	padding: clamp(0.7rem, 1.8vw, 1.2rem);
	border-radius: 11px;
	border: 1px solid var(--ec-trait);
	background: var(--ec-fond-2);
	/* il ne « pop » pas : il se déplie depuis le clic */
	/* il naît du clic : même origine, même instant. Un volet qui « pope »
	   à côté serait un second événement — ici c'est le même. */
	transform: translateX(calc((1 - var(--ouv)) * -30px)) scale(calc(0.86 + 0.14 * var(--ouv)), calc(0.5 + 0.5 * var(--ouv)));
	transform-origin: left center;
	opacity: calc(var(--ouv) * var(--ouv));
}
.sc-04 .ix-volet .ba:last-child { background: var(--rubis); opacity: calc(0.4 + 0.6 * var(--ouv)); }
.sc-04 .cu-04 {
	left: 26%; top: calc(52% + var(--ec-tete) / 2);
	opacity: var(--app);
	/* il ne repart pas : la main reste sur ce qu'elle a ouvert. */
	transform: translate(calc((1 - var(--app)) * -28 * var(--U)), calc((1 - var(--app)) * 15 * var(--U)))
	           scale(calc(1 - 0.3 * var(--cli) * (1 - var(--cli)) * 4));
	background: rgba(240, 101, 90, calc(0.12 + 0.5 * var(--cli) * (1 - var(--cli)) * 4));
}

/* =========================== 05 · CONVAINCRE ===========================
   Quatre éléments — information, preuve, service, confiance — et des
   liens qui se tracent vers un même point. Le schéma n'est jamais écrit :
   il se ressent, parce que tout y converge. */
.sc-05 {
	--pos-b: clamp(0, (var(--e) - 0.24) * 2.4, 1);
	--fil: clamp(0, (var(--m) - 0.10) * 1.8, 1);
	--con: clamp(0, (var(--m) - 0.46) * 1.9, 1);
}
.sc-05 .cv { position: relative; height: 100%; }
.sc-05 .cv-b {
	position: absolute;
	width: 27%; height: 21%;
	border-radius: 9px;
	border: 1px solid var(--ec-trait);
	background: rgba(239, 233, 220, 0.045);
	opacity: var(--pos-b);
	/* ils arrivent des quatre coins, puis se rapprochent du centre */
	transform: translate(calc((1 - var(--pos-b)) * var(--ax, 0) * 1px + var(--con) * var(--cx, 0) * 1px),
	                     calc((1 - var(--pos-b)) * var(--ay, 0) * 1px + var(--con) * var(--cy, 0) * 1px))
	           scale(calc(1 - 0.10 * var(--con)));
}
.sc-05 .cb-1 { left: 4%;  top: 10%; --ax: -40; --ay: -26; --cx: 26; --cy: 20; }
.sc-05 .cb-2 { right: 4%; top: 10%; --ax: 40;  --ay: -26; --cx: -26; --cy: 20; }
.sc-05 .cb-3 { left: 4%;  bottom: 10%; --ax: -40; --ay: 26; --cx: 26; --cy: -20; }
.sc-05 .cb-4 { right: 4%; bottom: 10%; --ax: 40;  --ay: 26; --cx: -26; --cy: -20; }
.sc-05 .cv-fils { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.sc-05 .cv-fils path {
	fill: none;
	stroke: var(--rubis);
	stroke-width: 1.6;
	stroke-linecap: round;
	/* le dessin est étiré sur la boîte (preserveAspectRatio="none") : sans
	   ceci, l'épaisseur du trait se déformerait avec lui. */
	vector-effect: non-scaling-stroke;
	stroke-dasharray: 1;
	stroke-dashoffset: calc(1 - var(--fil));
	opacity: calc(0.20 + 0.55 * var(--fil));
}
.sc-05 .cv-cta {
	position: absolute;
	left: 50%; top: 50%;
	width: clamp(46px, 7vw, 74px);
	aspect-ratio: 1;
	margin: 0;
	display: grid; place-items: center;
	border-radius: 50%;
	background: var(--rubis);
	color: #2A0F0C;
	transform: translate(-50%, -50%) scale(calc(0.55 + 0.45 * var(--con)));
	opacity: calc(0.35 + 0.65 * var(--con));
	box-shadow: 0 0 0 calc(var(--con) * 10px) rgba(240, 101, 90, 0.09);
}
.sc-05 .cv-cta .fl { width: 0.7em; height: 0.7em; font-size: clamp(1rem, 1.8vw, 1.5rem); }
/* LA CONVERGENCE APPELLE UNE DÉCISION. Sans main, la scène montrait un
   schéma ; avec elle, elle montre un visiteur convaincu qui agit — et
   elle enchaîne sur la scène suivante, qui est l'appel seul. */
.sc-05 .cu-05 {
	/* enfant du rond d'appel : il se pose dessus par construction */
	left: 60%; top: 62%;
	--ven: clamp(0, (var(--m) - 0.62) * 3, 1);
	--pos: clamp(0, (var(--m) - 0.86) * 12, 1);
	opacity: clamp(0, (var(--m) - 0.62) * 5, 1);
	transform: translate(calc((1 - var(--ven)) * 30 * var(--U)), calc((1 - var(--ven)) * 20 * var(--U)))
	           scale(calc(1 - 0.3 * var(--pos) * (1 - var(--pos)) * 4));
	background: rgba(240, 101, 90, calc(0.12 + 0.5 * var(--pos) * (1 - var(--pos)) * 4));
}

/* =========================== 06 · CONVERTIR ============================
   Tout se retire. Il ne reste que l'appel. C'est la scène la plus vide
   du parcours — et c'est pour cela qu'elle fonctionne. */
.sc-06 {
	--eff: clamp(0, (var(--e) - 0.20) * 1.7, 1);   /* le reste s'efface */
	--viv: clamp(0, (var(--m) - 0.30) * 2.4, 1);   /* le bouton prend vie */
}
.sc-06 .ec-nu {
	display: grid;
	place-items: center;
	aspect-ratio: 16 / 10;
	position: relative;
	padding: var(--ec-pad);
	padding-top: calc(var(--ec-pad) + var(--ec-tete));
}
.sc-06 .nu-b {
	position: absolute;
	height: clamp(9px, 1.5vw, 14px);
	border-radius: 99px;
	background: var(--ec-barre);
	opacity: calc((1 - var(--eff)) * 0.9);
	transform: translateY(calc(var(--eff) * var(--fy, 0) * 1px));
}
.sc-06 .nb-1 { width: 46%; top: 16%; left: 12%; --fy: -34; }
.sc-06 .nb-2 { width: 30%; top: 30%; left: 12%; --fy: -22; }
.sc-06 .nb-3 { width: 38%; bottom: 26%; right: 12%; --fy: 26; }
.sc-06 .nb-4 { width: 22%; bottom: 16%; right: 12%; --fy: 38; }
.sc-06 .bt-grand {
	position: relative;
	font-size: clamp(0.78rem, 1.5vw, 1.05rem);
	padding: 0.85em 1.7em;
	transform: scale(calc(0.86 + 0.14 * var(--eff) + 0.05 * var(--viv)));
	box-shadow: 0 0 0 calc(var(--viv) * 14px) rgba(240, 101, 90, 0.08),
	            0 calc(var(--viv) * 16px) calc(var(--viv) * 40px) rgba(240, 101, 90, 0.14);
}
.sc-06 .bt-grand .fl { transform: rotate(45deg) scale(0.8) translateX(calc(var(--viv) * 4px)); }
.sc-06 .cu-06 {
	left: auto;
	right: calc(1.15em + 0.425em - 6.5px);
	top: calc(50% - 6.5px);
	/* il arrive, et il APPUIE : c'est la scène de la conversion, le geste
	   doit s'y produire, pas seulement s'y approcher. */
	--app6: clamp(0, (var(--m) - 0.72) * 11, 1);
	opacity: clamp(0, (var(--m) - 0.16) * 5, 1);
	transform: translate(calc((1 - var(--viv)) * 30 * var(--U)), calc((1 - var(--viv)) * 19 * var(--U)))
	           scale(calc(1 - 0.3 * var(--app6) * (1 - var(--app6)) * 4));
	background: rgba(240, 101, 90, calc(0.12 + 0.5 * var(--app6) * (1 - var(--app6)) * 4));
}
.sc-06 .bt-grand {
	transform: scale(calc(0.86 + 0.14 * var(--eff) + 0.05 * var(--viv)
	                      - 0.06 * clamp(0, (var(--m) - 0.72) * 11, 1) * (1 - clamp(0, (var(--m) - 0.72) * 11, 1)) * 4));
}

/* =========================== 07 · CONTACT ==============================
   Le site devient une page de contact. Les champs se remplissent, le
   bouton s'allume, l'envoi se valide — sans pancarte « merci ». */
.sc-07 {
	--f1: clamp(0, (var(--m) - 0.06) * 8, 1);
	--f2: clamp(0, (var(--m) - 0.17) * 8, 1);
	--f3: clamp(0, (var(--m) - 0.28) * 8, 1);
	--f4: clamp(0, (var(--m) - 0.39) * 5, 1);
	--act: clamp(0, (var(--m) - 0.56) * 7, 1);    /* le bouton s'active */
	--env: clamp(0, (var(--m) - 0.66) * 5, 1);    /* la jauge d'envoi */
	--val: clamp(0, (var(--m) - 0.82) * 6, 1);    /* la validation */
}
.sc-07 .ec { display: grid; overflow: hidden; }
.sc-07 .fm {
	display: grid;
	grid-template-rows: repeat(3, minmax(0, 1fr)) minmax(0, 1.45fr) auto;
	gap: calc(1.9 * var(--U));
	height: 100%;
	min-height: 0;
}
.sc-07 .fm-c {
	display: grid;
	grid-template-rows: auto minmax(0, 1fr);
	min-height: 0;
	gap: calc(1 * var(--U));
	opacity: calc(0.35 + 0.65 * var(--e));
	transform: translateY(calc((1 - var(--e)) * 12px));
}
.sc-07 .fm-e {
	font: 500 calc(1.85 * var(--U))/1 var(--police-texte);
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--ivoire-douce);
}
.sc-07 .fm-p {
	display: grid;
	gap: calc(1.1 * var(--U));
	align-content: center;
	padding: calc(1.3 * var(--U)) calc(1.8 * var(--U));
	border-radius: 8px;
	border: 1px solid rgba(239, 233, 220, calc(0.10 + 0.28 * var(--rem, 0)));
	background: rgba(239, 233, 220, 0.025);
	min-height: 0;
}
.sc-07 .fm-p i {
	display: block;
	height: calc(1.2 * var(--U));
	border-radius: 99px;
	background: var(--ec-barre-forte);
	/* le champ se REMPLIT : la barre pousse depuis la gauche */
	transform: scaleX(var(--rem, 0));
	transform-origin: left center;
}
.sc-07 .fc-1 { --rem: var(--f1); }
.sc-07 .fc-2 { --rem: var(--f2); }
.sc-07 .fc-3 { --rem: var(--f3); }
.sc-07 .fc-4 { --rem: var(--f4); }
.sc-07 .fc-h .fm-p { min-height: 0; }
.sc-07 .fc-h .fm-p i:nth-child(2) { transform: scaleX(clamp(0, (var(--f4) - 0.3) * 1.6, 1)); }
.sc-07 .fc-h .fm-p i:nth-child(3) { transform: scaleX(calc(clamp(0, (var(--f4) - 0.6) * 2.2, 1) * 0.55)); }
.sc-07 .fm-bt {
	position: relative;
	justify-self: start;
	margin-top: calc(0.6 * var(--U));
	display: grid;
	place-items: center;
	min-width: calc(26 * var(--U));
	padding: calc(1.9 * var(--U)) calc(3.4 * var(--U));
	border-radius: 99px;
	overflow: hidden;
	/* muet tant que le formulaire n'est pas rempli, vif ensuite. Le
	   dégradé se fait par SUPERPOSITION et non par color-mix() : celui-ci
	   est trop récent, et s'il échoue le bouton perd son fond. */
	background: rgba(239, 233, 220, 0.09);
	font: 600 calc(2.1 * var(--U))/1 var(--police-texte);
	letter-spacing: 0.04em;
	transform: scale(calc(1 + 0.03 * var(--act) - 0.04 * var(--val)));
}
.sc-07 .fm-bt::before {
	content: "";
	position: absolute;
	inset: 0;
	background: var(--rubis);
	opacity: var(--act);
}
/* les deux libellés se relaient : clair sur fond muet, sombre sur rubis */
.sc-07 .fm-mot { position: relative; display: grid; opacity: calc(1 - var(--val)); }
.sc-07 .mo { grid-area: 1 / 1; }
.sc-07 .mo-a { color: var(--ivoire-douce); opacity: calc(1 - var(--act)); }
.sc-07 .mo-b { color: #2A0F0C; opacity: var(--act); }
.sc-07 .fm-jauge {
	position: absolute;
	left: 0; bottom: 0;
	height: 2px;
	width: 100%;
	background: #2A0F0C;
	transform: scaleX(var(--env));
	transform-origin: left center;
	opacity: calc((1 - var(--val)) * 0.55);
}
/* la validation : pas de pancarte, un trait qui se coche */
.sc-07 .fm-ok {
	position: absolute;
	z-index: 1;
	width: 0.85em; height: 0.5em;
	border-left: 2px solid #2A0F0C;
	border-bottom: 2px solid #2A0F0C;
	border-radius: 1px;
	transform: rotate(-45deg) scale(var(--val));
	opacity: var(--val);
}
.sc-07 .cu-07 {
	/* IL SUIT LE FORMULAIRE. Il apparaissait au moment de l'envoi, comme
	   si les champs s'étaient remplis seuls : ils se remplissent parce
	   qu'on les remplit. Le curseur descend donc champ par champ, puis
	   vient sur le bouton et appuie. */
	left: 26%; top: calc(16% + var(--ec-tete) / 2);
	opacity: clamp(0, (var(--m) - 0.02) * 7, 1);
	transform: translate(
		calc((1 - clamp(0, (var(--m) - 0.02) * 4, 1)) * 30 * var(--U) + var(--act) * 0.4 * var(--U)),
		calc((var(--f2) + var(--f3) + var(--f4)) * 8.5 * var(--U) + var(--act) * 16.8 * var(--U)))
		scale(calc(1 - 0.3 * var(--env) * (1 - var(--env)) * 4));
	background: rgba(240, 101, 90, calc(0.12 + 0.5 * var(--env) * (1 - var(--env)) * 4));
}

/* =========================== 08 · CONNEXION ============================
   LE DÉNOUEMENT, EN QUATRE TEMPS ET SANS UN MOT :

     les champs du formulaire perdent leur matière et se rangent
     → ils deviennent les lignes d'un contrat
     → une signature se trace
     → la feuille se retire, et deux personnes se serrent la main.

   Le dessin précédent montrait deux mains seules, flottant dans le vide.
   Des mains sans corps ne racontent pas un accord : elles racontent une
   icône. Deux silhouettes entières, elles, donnent l'échelle, la scène et
   les rôles — l'agence et le client, debout, à égalité.

   UNE RÈGLE TIENT TOUT LE DESSIN : un trait de la couleur de ce qu'il
   recouvre n'existe pas. Le bras et la main de la personne ivoire passent
   DEVANT la personne rubis, avec un liseré du fond qui les en détache.
   Sans ce liseré, les deux mains fusionnent et la prise retombe en tache.
   C'est aussi la DA du site : les deux moitiés de la ligne de partage,
   enfin jointes. */
.sc-08 {
	--p-fond: var(--ec-fond);
	--p-encre: var(--ivoire);
	--vid:     clamp(0, (var(--e) - 0.04) * 3.4, 1);  /* la matière s'en va */
	--feuille: clamp(0, (var(--e) - 0.16) * 1.9, 1);  /* les champs deviennent le contrat */
	--page:    clamp(0, (var(--e) - 0.16) * 1.9, 1);  /* la feuille paraît */
	--signe:   clamp(0, (var(--e) - 0.66) * 2.6, 1);  /* on signe */
	--gens:    clamp(0, (var(--m) - 0.02) * 2.0, 1);  /* ils se lèvent */
	--tend:    clamp(0, (var(--m) - 0.22) * 2.2, 1);  /* le bras se tend */
	--serre:   clamp(0, (var(--m) - 0.40) * 2.6, 1);  /* ils se serrent la main */
	/* LA SECOUSSE, SANS HORLOGE NI IMAGE-CLÉ. Quatre seuils rapprochés
	   composent une onde montante-descendante : une poignée de main qui
	   ne bouge pas est une poignée de main figée, et c'est le geste — pas
	   le contact — qui dit que l'accord est conclu. */
	--d1: clamp(0, (var(--m) - 0.60) * 13, 1);
	--d2: clamp(0, (var(--m) - 0.68) * 13, 1);
	--d3: clamp(0, (var(--m) - 0.76) * 13, 1);
	--d4: clamp(0, (var(--m) - 0.84) * 13, 1);
	--osc: calc(var(--d1) - var(--d2) - var(--d3) + var(--d4));
}
/* le même format que les sept autres : un « 16/9 » la raccourcissait de
   quarante pixels, et une carte plus courte se lit comme un moment plus
   petit — or c'est la conclusion. */
.sc-08 .ec-nu {
	display: grid;
	place-items: end center;
	aspect-ratio: 16 / 10;
	padding: 0;
	background: linear-gradient(170deg, var(--ec-fond-2), var(--ec-fond));
	border-color: var(--ec-trait);
}
.sc-08 .cx { position: relative; width: 100%; aspect-ratio: 420 / 230; }
.sc-08 .cx-scene { width: 100%; height: 100%; overflow: visible; }

/* ---- les champs de la scène 07, qui se rangent en contrat ------------- */
.sc-08 .cx-b {
	/* sans « fill-box », l'origine serait celle de la boîte du SVG entier
	   et chaque barre pivoterait autour d'un point qui n'est pas le sien */
	transform-box: fill-box;
	transform-origin: center;
	fill: rgba(239, 233, 220, calc(0.26 * (1 - var(--vid))));
	stroke: rgba(239, 233, 220, calc(0.12 + 0.26 * var(--vid) * (1 - var(--feuille))));
	stroke-width: 1.5;
	opacity: calc(1 - var(--gens));
	transform: translateY(calc(var(--feuille) * var(--by, 0) * 1px))
	           scale(calc(1 - var(--feuille) * var(--bs, 0)), calc(1 - var(--feuille) * 0.52));
}
/* chaque champ vise la ligne qu'il va devenir */
.sc-08 .xb-1 { --by: 13;  --bs: 0.683; }
.sc-08 .xb-2 { --by: -11; --bs: 0.683; }
.sc-08 .xb-3 { --by: -35; --bs: 0.683; }
.sc-08 .xb-4 { --by: -59; --bs: 0.810; }

/* ---- la feuille, et la signature -------------------------------------- */
.sc-08 .cx-feuille {
	transform-box: fill-box;
	transform-origin: center;
	opacity: calc(var(--page) * (1 - 0.45 * var(--gens)));
	/* elle ne disparaît pas : elle se retire, vers le haut et de côté,
	   comme un document qu'on met de côté une fois signé. */
	transform: translateY(calc(var(--gens) * -46px)) scale(calc(1 - var(--gens) * 0.26));
}
.sc-08 .fe-page {
	fill: rgba(239, 233, 220, 0.08);
	stroke: rgba(239, 233, 220, 0.45);
	stroke-width: 1.5;
}
.sc-08 .fe-signe {
	fill: none;
	stroke: var(--rubis);
	stroke-width: 3;
	stroke-linecap: round;
	stroke-linejoin: round;
	/* elle S'ÉCRIT : le tracé se tire d'un bout à l'autre. Une signature
	   qui paraît d'un coup est un tampon, pas une main qui signe. */
	stroke-dasharray: 1;
	stroke-dashoffset: calc(1 - var(--signe));
}

/* ---- les deux bustes -------------------------------------------------
   Coupés par le bas de la carte, tête posée sur un cou court, palier
   d'épaules franc. Rien d'autre : ni mains détaillées, ni doigts — à
   cette échelle, un doigt de dix unités n'est pas un doigt, c'est un
   grain de bruit. */
.sc-08 .pers {
	transform-box: fill-box;
	transform-origin: center bottom;
	opacity: var(--gens);
	transform: translateY(calc((1 - var(--gens)) * 40px));
}
.sc-08 .pe-corps { stroke: none; }
.sc-08 .pe-tete {
	stroke: var(--p-fond);
	stroke-width: 4;
	paint-order: stroke;
}
/* L'AVANT-BRAS EST UN TRACÉ, DONC IL SE TEND. Il se dessine de l'épaule
   vers la main — le geste va dans ce sens, et un bras qui paraît d'un
   bloc ne se tend pas. */
.sc-08 .pe-bras {
	fill: none;
	stroke-width: 9;
	stroke-linecap: round;
	stroke-dasharray: 1;
	stroke-dashoffset: calc(1 - var(--tend));
}
.sc-08 .pers-g .pe-tete, .sc-08 .pers-g .pe-corps { fill: var(--p-encre); }
.sc-08 .pers-d .pe-tete, .sc-08 .pers-d .pe-corps { fill: var(--rubis); }
.sc-08 .pers-g .pe-bras { stroke: var(--p-encre); }
.sc-08 .pers-d .pe-bras { stroke: var(--rubis); }

/* ---- la prise ---------------------------------------------------------
   Deux mains, et c'est tout. Celle de devant recouvre l'autre d'un tiers
   et porte le liseré du fond qui l'en détache : c'est ce recouvrement,
   et lui seul, qui dit qu'elles se tiennent. */
.sc-08 .cx-prise {
	transform-box: fill-box;
	transform-origin: center;
	opacity: clamp(0, (var(--serre) - 0.08) * 4, 1);
	/* la secousse : deux degrés et trois pixels. Au-delà, deux personnes
	   ne se saluent plus, elles s'agitent. */
	transform: rotate(calc(var(--osc) * -2deg)) translateY(calc(var(--osc) * -3px));
}
.sc-08 .pr-main {
	transform-box: fill-box;
	transform-origin: center;
	stroke: none;
	transform: scale(calc(0.55 + 0.45 * var(--serre)));
}
.sc-08 .pr-d { fill: var(--rubis); }
.sc-08 .pr-g { fill: var(--p-encre); }

/* ---- petits écrans : le principe tient, la densité baisse -------------
   Le récit ne change pas — huit scènes, même ordre, même fin. Ce sont les
   compositions qui se resserrent, et la course qui raccourcit. */
@media (max-width: 48em) {
	.portail {
		--portail-course: 640vh;
		--sc-large: min(86vw, 32rem);
		--sc-ecart: clamp(2rem, 7vw, 4rem);
	}
	.sc { --prof: 0 !important; }
	.ec { aspect-ratio: 4 / 3; }
	.sc-01 .ec-corps { grid-template-columns: 1fr; gap: clamp(0.8rem, 3vw, 1.4rem); }
	.sc-01 .ec-vue { height: clamp(90px, 26vw, 150px); }
	.sc-04 .ec { grid-template-columns: 1fr; }
	.sc-02 .ec-cartes { grid-template-columns: repeat(3, 1fr); }
	.sc-08 .ec-nu { aspect-ratio: 4 / 3; }
}

/* ---- mouvement réduit : le parcours redevient une planche -------------
   Le moteur ne démarre pas (voir le module 9 ter). Sans lui, aucune
   variable n'est publiée : les scènes doivent donc être lisibles À L'ÉTAT
   D'ARRIVÉE, sans une seule animation. On force les progressions à 1 et
   l'on empile. Rien ne disparaît, rien ne bouge. */
@media (prefers-reduced-motion: reduce) {
	.portail-piste { height: auto; }
	.portail-scene {
		position: static;
		height: auto;
		display: block;
		padding-block: var(--marge-section);
	}
	.portail-seuil, .portail-horizon, .cu { display: none; }
	.sc { --u: 0.5; --e: 1; --m: 1; --o: 0; grid-area: auto !important; }
	.sc > * { opacity: 1; }
	.portail-rail {
		display: grid;
		grid-template-columns: 1fr;
		gap: clamp(2.5rem, 7vh, 4rem);
		padding-inline: var(--gouttiere);
		transform: none;
		max-width: 64rem;
		margin-inline: auto;
		will-change: auto;
	}
	/* LES SCÈNES PRENNENT LA LARGEUR DE LA PLANCHE (rc65). « width: auto »
	   dans une grille héritée en « justify-items: start » les rétractait à
	   leur contenu : 83 à 302 px, étiquettes superposées. */
	.portail-rail { justify-items: stretch; }
	.sc {
		width: 100%;
		max-width: 40rem;
		justify-self: center;
		transform: none;
		--u: 0.5; --e: 1; --m: 1; --o: 0;
	}
	.sc > * { opacity: 1; }
	.ec { transform: none; }
	.sc-02 .ca-piste { transform: translate3d(-66.666%, 0, 0); }
	.sc-03 .og-ligne { display: none; }
	/* sans la ligne de lecture, le pic d éclairage vaut zéro partout et les
	   blocs resteraient à mi-opacité : on les rend pleins. */
	.sc-03 .og > * { opacity: 1; }
}
