/*
Theme Name: Studio Esdée
Theme URI: http://studio-esde.local/
Description: Thème enfant de Twenty Twenty-Five pour Studio Esdée.
Author: Studio Esdée
Template: twentytwentyfive
Version: 1.11.4
Requires at least: 6.7
Requires PHP: 7.2
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: studio-esdee
*/

/* Aucun anneau de focus sur le site : on retire l'outline natif et celui des
   styles personnalisés (nav, FAQ, cartes à tabindex, boutons, liens, champs). */
*:focus,
*:focus-visible {
	outline: none;
}

.wp-block-navigation .wp-block-navigation-item__content {
	text-decoration: none;
}

/* Aucun arrondi sur les images du site (blocs image, médias, vignettes). */
img,
.wp-block-image img,
.wp-block-image,
figure.wp-block-image > a {
	border-radius: 0 !important;
}

/* Items du menu : police Stack Sans Notch et couleur corail (#FF6F59) pour les
   liens nav comme le bouton Contact. */
.site-header .wp-block-navigation .wp-block-navigation-item__content,
.site-header .wp-block-button__link {
	font-family: "Stack Sans Notch", var(--wp--preset--font-family--manrope), sans-serif;
	color: #FF3463;
	font-size: 1.0625rem;
}

/* Le bouton Contact pose sa taille via la classe preset has-small-font-size.
   On l'aligne sur les autres items en battant le preset par la specificite
   (deux classes sur le lien + contexte .site-header), sans !important. */
.site-header .wp-block-button__link.has-custom-font-size.has-text-color {
	font-size: 1.0625rem;
}

/* Le bouton Contact porte la classe de preset has-contrast-color (couleur en
   !important) : on force donc la couleur corail par-dessus. */
.site-header .wp-block-button__link.has-text-color {
	color: #FF3463 !important;
}

.wp-block-navigation .wp-block-navigation-item__content:hover,
.wp-block-navigation .current-menu-item .wp-block-navigation-item__content {
	color: var(--wp--preset--color--accent);
}

.wp-block-navigation .wp-block-navigation-item__content:focus {
	outline: none;
}

.wp-block-navigation .wp-block-navigation-item__content:focus-visible {
	outline: none;
}

header .wp-block-button__link:hover {
	background-color: var(--wp--preset--color--blanc);
	color: var(--wp--preset--color--accent);
}

header.wp-block-template-part {
	position: sticky;
	top: 0;
	z-index: 100;
	/* Glissement vertical pour le masquage au scroll vers le bas / reaffichage au
	   scroll vers le haut (classe is-hidden posee par le JS header). */
	transition: transform 0.35s ease;
}

/* Masque au scroll vers le bas : le header glisse hors de l'ecran par le haut
   (classe is-hidden posee par le JS sur le <header> sticky). */
header.wp-block-template-part.is-hidden {
	transform: translateY(-100%);
}

.site-header .nav-bar {
	width: max-content;
	max-width: 100%;
	/* Caler le bord gauche du menu sur la grille de contenu (zone "wide" centrée,
	   même bord que l'image de gauche du hero). Au-delà de wideSize, on pousse la
	   barre vers la droite de la demi-marge ; en deçà, la valeur retombe à 0 et le
	   menu reste collé au bord gauche. */
	margin-left: max(0px, (100% - var(--wp--style--global--wide-size, 1320px)) / 2) !important;
	margin-right: auto !important;
	padding: 0.5rem 0.75rem;
	border-radius: 0;
	transition: background-color 0.25s ease, box-shadow 0.25s ease;
}

.nav-logo {
	display: flex;
	align-items: center;
	margin: 0;
	width: 0;
	max-width: 0;
	overflow: hidden;
	opacity: 0;
	transition: opacity 0.25s ease, max-width 0.3s ease, margin 0.3s ease;
}

.nav-logo img {
	display: block;
	height: 34px;
	width: auto;
	max-width: none;
}

.nav-logo a {
	display: flex;
	align-items: center;
	line-height: 0;
}

/* Geometrie de l'etat "cale" du logo, partagee avec le JS (logo-parallax.ts :
   TARGET_PAD / DOCKED_HEIGHT / DOCKED_TOP_MARGIN). Les pages internes reproduisent
   exactement cette position finale en statique pour un menu identique a la home. */
:root {
	--logo-docked-pad: 24px;
	--logo-docked-height: 48px;
	--logo-docked-top: 12px;
}

/* Hors home : meme rendu que l'etat FINAL de l'animation home. Le logo n'est plus
   dans le flux de la nav-bar mais cale en haut a gauche du viewport (fixed), a la
   meme place que le logo flottant cale de la home. Le menu, lui, adopte sa
   disposition "calee" via --nav-progress: 1 (voir plus bas). */
body:not(.home) .nav-logo {
	position: fixed;
	top: var(--logo-docked-top);
	left: var(--logo-docked-pad);
	z-index: 110;
	width: auto;
	max-width: 200px;
	overflow: visible;
	opacity: 1;
	margin: 0;
}

body:not(.home) .nav-logo img {
	height: var(--logo-docked-height);
	width: auto;
}

/* Sur la home, le logo de la barre n'est jamais peint : c'est le logo du hero
   qui vient s'y caler par-dessus au scroll. Le .nav-logo reste donc de largeur 0
   en permanence ; c'est --nav-shift (pilote par le JS, en phase avec le logo)
   qui ecarte progressivement le menu pour lui menager la place. */
.home .nav-logo {
	visibility: hidden;
	width: 0;
	max-width: 0;
	opacity: 0;
	margin-right: calc(-1 * var(--wp--preset--spacing--40));
}

/* Sur la home, le menu ne se decale plus en bloc (l'ancien padding-left pilote
   par --nav-shift cassait l'alignement de la grille). A la place, chaque item se
   reagence individuellement vers sa colonne "calee" via --nav-progress (voir plus
   bas). On garde donc la nav-bar a sa pleine largeur, sans padding gauche. */
.site-header .nav-bar .wp-block-navigation {
	margin-left: 0;
}

/* Items du menu cales sur la grille 12 colonnes du hero : la barre s'etire sur
   la pleine largeur de contenu (meme wideSize que .hero-art) et la navigation
   devient une grille 12 colonnes. Chaque item est place sur sa colonne :
   Services -> 2, Projets -> 8, Contact -> 12. */
.site-header .nav-bar {
	width: 100%;
	max-width: var(--wp--style--global--wide-size, 1320px);
	margin-left: auto !important;
	margin-right: auto !important;
	/* Aucun padding horizontal : la grille du menu doit couvrir exactement la
	   meme largeur que celle du hero (.hero-art), sans retrait lateral. */
	padding-left: 0;
	padding-right: 0;
	/* La nav-bar devient un conteneur de requete : 1cqw = 1% de SA largeur. On
	   peut ainsi exprimer la largeur d'une colonne de la grille 12 sans dependre
	   du contexte de l'element qui l'utilise (un % dans une custom property serait
	   resolu sur le <li>, pas sur la nav-bar -> valeur erronee). */
	container-type: inline-size;
	/* Largeur d'une colonne de la grille 12, en unites de conteneur. Sert a
	   convertir un decalage "en colonnes" en pixels pour le reagencement des
	   items pendant l'animation du logo. */
	--col-w: calc(100cqw / 12);
	/* Progression du reagencement : les items sont figes d'emblee sur leur
	   disposition "calee" (colonnes 2/6/9/12), home comprise. Ils ne glissent plus
	   au scroll : le menu reste a la meme position. (Le JS ne pilote plus cette
	   variable ; il ne gere que --nav-shift, le decalage anti-chevauchement du logo.) */
	--nav-progress: 1;
}

/* Aucun glissement des items : la disposition est etablie d'emblee, sans
   transition, sur toutes les pages (home incluse). */
.site-header .nav-bar .wp-block-navigation__container > li {
	transition: none;
}

.site-header .nav-bar .wp-block-navigation {
	flex: 1;
	margin-left: 0 !important;
}

/* Header toujours transparent, sans flou ni voile : le menu se lit directement
   par-dessus le contenu. Il se masque au scroll vers le bas et reapparait au
   scroll vers le haut (voir header.wp-block-template-part.is-hidden). */
.site-header {
	background-color: transparent;
	/* Leger espace supplementaire au-dessus du menu (s'ajoute au padding du
	   markup) pour aerer la barre. */
	padding-top: var(--wp--preset--spacing--20);
}

.site-header .nav-bar .wp-block-navigation .wp-block-navigation__container {
	display: grid;
	grid-template-columns: repeat(12, 1fr);
	width: 100%;
	align-items: center;
	/* Pas de gap : la grille du hero (.hero-art) n'en a pas non plus. Un gap
	   decalerait chaque colonne et casserait l'alignement sur les lignes rouges. */
	gap: 0 !important;
}

/* Pas de padding sur les items : le lien colle au bord de sa colonne. */
.site-header .nav-bar .wp-block-navigation .wp-block-navigation-item__content {
	padding: 0;
}

/* Item "a venir" (Blog/Soon) : mode desactive. Grise, non cliquable, sans survol
   actif. Le pointer-events: none empeche le clic ; opacity et cursor le signalent. */
.site-header .wp-block-navigation .nav-item--soon .wp-block-navigation-item__content {
	opacity: 0.4;
	pointer-events: none;
	cursor: not-allowed;
}

/* Neutralise le changement de couleur au survol pour cet item. */
.site-header .wp-block-navigation .nav-item--soon .wp-block-navigation-item__content:hover {
	color: #FF3463;
}

/* Reagencement relatif pendant l'animation du logo.
   Chaque item est place sur sa colonne de REPOS dans la grille, puis glisse
   horizontalement vers sa colonne CALEE via --nav-progress (0 -> 1). Le decalage
   en colonnes (--shift-cols = colonne_calee - colonne_repos) est converti en
   pixels par --col-w. Le dernier item (Blog) ne bouge pas : il reste ancre sur
   la 12e colonne, donc l'espacement entre items se resserre vers la droite.

   Repos -> Cale :
     Services : 2 -> 3   (+1)
     Projets  : 6 -> 7   (+1)
     Contact  : 9 -> 10  (+1)
     Blog     : 12 -> 13 (+1)  decale d'une colonne vers la droite */
.site-header .nav-bar .wp-block-navigation .wp-block-navigation__container > li {
	transform: translateX(calc(var(--shift-cols, 0) * var(--col-w) * var(--nav-progress)));
	/* Pas de transition : --nav-progress vaut 1 d'emblee, les items ne glissent
	   plus au scroll (ils restent a la meme position). */
	transition: none;
}

.site-header .nav-bar .wp-block-navigation .wp-block-navigation__container > li:nth-child(1) {
	grid-column: 2;
	--shift-cols: 2;
}

.site-header .nav-bar .wp-block-navigation .wp-block-navigation__container > li:nth-child(2) {
	grid-column: 6;
	--shift-cols: 1;
}

.site-header .nav-bar .wp-block-navigation .wp-block-navigation__container > li:nth-child(3) {
	grid-column: 9;
	--shift-cols: 1;
}

.site-header .nav-bar .wp-block-navigation .wp-block-navigation__container > li:nth-child(4) {
	grid-column: 12;
	--shift-cols: 1;
}

.hero {
	position: relative;
	/* De combien le média déborde sous le fond rose et chevauche la section suivante. */
	--hero-overlap: 8rem;
	/* De combien l'image de gauche (back) plonge en plus dans la section suivante. */
	--back-overlap: 4rem;
	/* Le hero (zone rose visible) occupe au minimum la hauteur de l'écran.
	   On ajoute --hero-overlap car le fond rose s'arrête à cette distance du bas. */
	min-height: calc(100vh + var(--hero-overlap));
	padding-bottom: 0 !important;
	margin-bottom: calc(-1 * var(--hero-overlap));
	/* Ni isolation ni z-index : l'image de gauche (via .hero-art, z-index 1) doit
	   s'empiler dans le contexte de <main>, entre le fond de la section suivante
	   qu'elle recouvre et le contenu de celle-ci, qui reste lisible au-dessus. */
}

/* Le média (grande image) passe au-dessus de la section suivante. */
.hero-art {
	position: relative;
	z-index: 1;
}

/* Le fond rose plein s'arrête au-dessus de la zone de chevauchement. */
.hero.has-base-background-color {
	background-color: transparent;
}

.hero::after {
	content: "";
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	bottom: var(--hero-overlap);
	z-index: -2;
	background-color: var(--wp--preset--color--base);
}

.hero::before {
	content: "";
	position: absolute;
	top: 0;
	bottom: var(--hero-overlap);
	left: 50%;
	transform: translateX(-50%);
	width: min(100%, var(--wp--style--global--wide-size, 1320px));
	z-index: -1;
	background-image:
		linear-gradient(
			to bottom,
			color-mix(in srgb, var(--wp--preset--color--base) 40%, transparent) 0%,
			color-mix(in srgb, var(--wp--preset--color--base) 55%, transparent) 45%,
			transparent 100%
		),
		url("assets/images/pattern.svg");
	background-repeat: no-repeat, repeat;
	background-size: 100% 100%, calc(100% / 24) auto;
	-webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 30%, transparent 85%);
	mask-image: linear-gradient(to bottom, #000 0%, #000 30%, transparent 85%);
}

.site-scroll {
	margin-top: 0;
}

.site-header {
	padding-top: 0 !important;
}

.home .hero {
	margin-top: calc(-1 * var(--header-h, 6.5rem));
	padding-top: 0 !important;
}

.home .hero-art {
	padding-top: var(--header-h, 6.5rem);
}

.home .hero-art__front {
	/* L'image de droite est calée en absolu (top depuis le haut du .hero-art, qui
	   réserve déjà la hauteur du header via son padding-top) : pas de remontée
	   négative ici, sinon elle passerait sous le header. */
	margin-top: 0;
}

.hero-art {
	position: relative;
	display: grid;
	grid-template-columns: repeat(12, 1fr);
	align-items: start;
	margin-inline: auto;
}

.hero-art::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 50;
	pointer-events: none;
	background-image: repeating-linear-gradient(
		to right,
		red 0,
		red 1px,
		transparent 1px,
		transparent calc(100% / 12)
	);
	box-shadow: inset -1px 0 0 0 red;
	display: none;
}

.hero-art__back,
.hero-art__front {
	grid-row: 1;
	margin-right: 0;
	margin-bottom: 0;
	margin-left: 0;
}

.hero-art__back img,
.hero-art__front img {
	display: block;
	width: 100%;
	height: auto;
	object-fit: cover;
	border-radius: 0;
}

/* Filtre gris (désaturation) sur l'image de droite uniquement ;
   l'image de gauche reste en couleur. */
.hero-art__front img {
	filter: grayscale(1);
}

.hero-art__back {
	grid-column: 1 / span 5;
	margin-top: clamp(10rem, 34vh, 26rem) !important;
	/* Seule l'image de gauche plonge dans la section suivante : on annule la
	   remontée de la section (--hero-overlap) puis on déborde de --back-overlap. */
	margin-bottom: calc(-1 * (var(--hero-overlap) + var(--back-overlap))) !important;
	z-index: 2;
}

.hero-art__back img {
	aspect-ratio: 3 / 4;
	height: clamp(40rem, 50vh, 52rem);
	width: 100%;
	object-fit: cover;
}

.hero-art__front {
	position: relative;
	grid-column: 9 / span 4;
	z-index: 0;
}

.hero-art__front img {
	aspect-ratio: 1 / 1;
}

@keyframes hero-reveal-down {
	from {
		opacity: 0;
		clip-path: inset(0 0 100% 0);
	}
	to {
		opacity: 1;
		clip-path: inset(0 0 0 0);
	}
}

.hero-art__back,
.hero-art__front {
	opacity: 0;
	animation: hero-reveal-down 0.65s cubic-bezier(0.22, 1, 0.36, 1) forwards;
}

.hero-art__front {
	animation-delay: 0.08s;
}

.hero-art__back {
	animation-delay: 0.28s;
}

@media (prefers-reduced-motion: reduce) {
	.hero-art__back,
	.hero-art__front {
		opacity: 1;
		animation: none;
		clip-path: none;
	}
}

.hero-art__front::after {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: 0;
	pointer-events: none;
	background: linear-gradient(
		100deg,
		rgba(22, 32, 44, 0.42) 0%,
		rgba(22, 32, 44, 0.22) 28%,
		rgba(22, 32, 44, 0) 58%
	);
}

.hero-logo {
	position: absolute;
	z-index: 2;
	left: calc(100% / 12);
	width: calc(100% / 12 * 6);
	top: 36%;
	transform: translateY(-50%);
	/* Cliquable au repos (retour en haut). */
	pointer-events: auto;
}

.hero-logo__img {
	margin: 0;
}

.hero-logo__link {
	display: block;
	cursor: pointer;
}

.hero-logo__img img {
	display: block;
	width: 100%;
	height: auto;
}

/* Des que la transition demarre, le logo d'origine s'efface : c'est le calque
   .hero-logo-floating (ancre au viewport, hors conteneur Locomotive) qui prend
   le relais. */
.home .hero-logo.is-floating {
	opacity: 0;
	pointer-events: none;
}

/* Calque clone anime par le JS : fixe au viewport, deplace et reduit depuis son
   coin haut-gauche (translate + scale). Cache tant qu'il n'est pas actif. Le
   header etant hors du conteneur transforme par Locomotive, ce calque doit
   aussi vivre hors de lui (il est attache au <body>) pour que position: fixed
   s'ancre bien au viewport et non au conteneur. */
.hero-logo-floating {
	position: fixed;
	top: 0;
	left: 0;
	z-index: 110;
	display: none;
	transform-origin: top left;
	will-change: transform;
	cursor: pointer;
	line-height: 0;
}

.hero-logo-floating.is-active {
	display: block;
}

/* Le logo cale (.is-docked) reste constamment visible en haut a gauche, fixe au
   viewport : il ne se masque PLUS avec le menu quand on scrolle vers le bas (le
   header.ts ne lui propage plus .is-hidden). Sa cible est figee cote JS pour ne
   pas suivre la barre de menu lorsqu'elle glisse hors ecran. */
.hero-logo-floating img {
	display: block;
	width: 100%;
	height: auto;
}

/* Pas d'animation "pop" a l'arrivee : le calque (.hero-logo-floating) est deja
   amene a sa position et sa taille finales (scale 1) par le JS, en phase avec le
   scroll. Un keyframe sur l'<img> qui rapetissait puis regrossissait (0.86 ->
   1.06 -> 1) ajoutait un second mouvement apres l'arret du glissement : le logo
   semblait "bouger puis rebouger". On le supprime pour un arret net. */

.hero-baseline {
	margin: 0;
	color: var(--wp--preset--color--contrast);
}

.hero-texte {
	position: absolute;
	z-index: 3;
	left: calc(100% / 12 * 6);
	width: calc(100% / 12 * 6);
	/* Descendu sous l'image de droite pour ne pas être masqué par elle. */
	top: 78%;
	transform: translateY(-50%);
	text-align: left;
	pointer-events: none;
}

.hero-texte > * {
	pointer-events: auto;
}

.hero-titre.hero-titre {
	max-width: 22ch;
	margin: 0;
	font-size: 0.9rem;
	font-weight: 600;
}

/* Animation du titre, façon Locomotive Scroll : chaque ligne est un masque
   (clip-path) derrière lequel le mot remonte en place, avec un décalage par
   ligne via --index. L'état révélé est posé en JS (.is-revealed). La classe
   .titre-reveal est posée en JS sur tout titre animé (hero + titres de section). */

/* Harmonisation des titres de section animés : même taille et même graisse, quel
   que soit le niveau (h2/h3) ou la classe de taille d'origine. On exclut le hero,
   qui garde son style propre via .hero-titre.hero-titre (spécificité supérieure).
   Le !important sur la graisse neutralise le font-weight:800 inline de « Studio
   Esdée ». */
.titre-reveal:not(.hero-titre) {
	/* !important : les classes has-*-font-size de WordPress posent la taille en
	   !important, et « Studio Esdée » a un font-weight:800 inline. */
	font-size: var(--wp--preset--font-size--xx-large) !important;
	font-weight: 700 !important;
}

.titre-reveal .hero-line {
	display: block;
	clip-path: inset(-5% 0);
}

.titre-reveal .hero-word {
	display: inline-block;
	transform: translate3d(0, 110%, 0);
	transition: transform 0.6s cubic-bezier(0.165, 0.84, 0.44, 1);
	transition-delay: calc(var(--index) * 0.1s);
}

.titre-reveal.is-revealed .hero-word {
	transform: translate3d(0, 0, 0);
}

@media (prefers-reduced-motion: reduce) {
	.titre-reveal .hero-word {
		transform: none;
		transition: none;
	}
}

.hero-pitch.hero-pitch {
	max-width: 46ch;
	margin: var(--wp--preset--spacing--30) 0 0;
	color: var(--wp--preset--color--contrast);
	font-size: 0.72rem;
}

.hero-cta {
	margin-top: var(--wp--preset--spacing--40);
	justify-content: flex-start;
}

.hero-cta .wp-block-button__link {
	position: relative;
	background: none !important;
	color: var(--wp--preset--color--contrast) !important;
	padding: 0;
	border-radius: 0;
	text-transform: uppercase;
	letter-spacing: 0.08em;
	font-size: var(--wp--preset--font-size--small);
}

.hero-cta .wp-block-button__link::before {
	content: "↗";
	margin-right: 0.5em;
	font-size: 1.1em;
	line-height: 1;
}

.hero-cta .wp-block-button__link::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	bottom: -0.15em;
	height: 1px;
	background: currentColor;
	transform: scaleX(0);
	transform-origin: right center;
	transition: transform 0.25s ease;
}

.hero-cta .wp-block-button__link:hover,
.hero-cta .wp-block-button__link:focus {
	background: none !important;
	color: var(--wp--preset--color--contrast) !important;
}

.hero-cta .wp-block-button__link:hover::after,
.hero-cta .wp-block-button__link:focus::after {
	transform: scaleX(1);
	transform-origin: left center;
}

@media (max-width: 781px) {
	/* Sur mobile, on abandonne la composition desktop (grille 12 colonnes,
	   logo + texte en absolu, débordements négatifs) pour un flux vertical
	   simple : logo, puis image pleine largeur, puis titre / pitch / CTA. */
	.hero {
		min-height: 0;
		margin-bottom: 0;
		--hero-overlap: 0rem;
		--back-overlap: 0rem;
	}

	/* Sur mobile uniquement, on aere le bas du hero de la home (le desktop le force
	   a 0 pour le chevauchement, neutralise ici via --hero-overlap: 0). */
	.home .hero {
		padding-bottom: var(--wp--preset--spacing--60) !important;
	}

	.home .hero-art {
		padding-top: var(--header-h, 5rem);
	}

	/* La grille redevient un simple flux vertical. */
	.hero-art {
		display: flex;
		flex-direction: column;
		gap: var(--wp--preset--spacing--40);
	}

	/* Logo en haut, en flux, pleine largeur (plus d'absolu ni de débordement). */
	.hero-logo {
		position: static;
		transform: none;
		left: auto;
		top: auto;
		width: min(70%, 18rem);
		order: 1;
	}

	/* Image principale en pleine largeur, hauteur raisonnable, sans marges
	   négatives de chevauchement. */
	.hero-art__back {
		grid-column: auto;
		order: 2;
		margin-top: 0 !important;
		margin-bottom: 0 !important;
	}

	.hero-art__back img {
		aspect-ratio: 4 / 3;
		height: auto;
		max-height: 60vh;
	}

	/* Image secondaire (front) masquée sur mobile : superflue, elle se
	   superposait au reste. */
	.hero-art__front {
		display: none;
	}

	/* Texte en flux sous l'image, pleine largeur, lisible. */
	.hero-texte {
		position: static;
		transform: none;
		left: auto;
		top: auto;
		width: auto;
		order: 3;
	}

	/* On laisse les tailles de preset (x-large pour le titre, medium pour le
	   pitch) : elles rendent bien sur mobile. On retire juste la contrainte de
	   largeur héritée du desktop pour que le texte occupe toute la colonne. */
	.hero-titre.hero-titre,
	.hero-pitch.hero-pitch {
		max-width: none;
	}
}

/* Header mobile : menu inline pleine largeur, au-dessus du site, sans burger. */
@media (max-width: 781px) {
	/* La barre occupe toute la largeur, plus de bloc flottant calé à gauche. */
	.site-header .nav-bar {
		width: 100%;
		max-width: 100%;
		margin-left: 0 !important;
		margin-right: 0 !important;
		justify-content: space-between;
		gap: var(--wp--preset--spacing--20);
		padding: 0.5rem var(--wp--preset--spacing--20);
	}

	/* Pas de fond translucide isolé au scroll : on couvre toute la barre. */
	.site-header.is-scrolled .nav-bar {
		background-color: var(--wp--preset--color--base);
	}

	/* Menu mobile : on laisse le comportement responsive natif de WordPress
	   (bouton burger + overlay plein écran géré par core/navigation). On se
	   contente de styler le bouton et l'overlay aux couleurs du thème. */
	/* La nav pousse le burger à droite de la barre (sinon il est centré dans
	   l'espace du bloc navigation). */
	.site-header .nav-bar .wp-block-navigation {
		justify-content: flex-end;
		flex: 1;
	}

	.site-header .wp-block-navigation__responsive-container-open {
		display: flex;
		color: var(--wp--preset--color--contrast);
		padding: 0;
	}

	.site-header .wp-block-navigation__responsive-container-open svg,
	.site-header .wp-block-navigation__responsive-container-close svg {
		width: 1.75rem;
		height: 1.75rem;
		fill: currentColor;
	}

	/* Le bouton de fermeture (croix) est calé au pixel près sur la position du
	   bouton d'ouverture (burger) : même top/right, même taille. Ainsi l'icône
	   ne bouge pas entre l'état fermé et ouvert. Le burger est à top:8px /
	   right:44px du viewport (8px = padding-block de la nav-bar, 44px = 32px de
	   marge de contenu + 12px de padding latéral). */
	.site-header .wp-block-navigation__responsive-container-close {
		position: fixed;
		top: 8px;
		right: 44px;
		margin: 0;
		padding: 0;
		width: 28px;
		height: 28px;
		color: var(--wp--preset--color--contrast);
	}

	/* Overlay ouvert : fond rose pâle du thème, items empilés et alignés à
	   gauche, sous le bouton de fermeture (qui reste en haut à droite). */
	.site-header .wp-block-navigation__responsive-container.is-menu-open {
		background-color: var(--wp--preset--color--base);
		padding: var(--wp--preset--spacing--40);
		justify-content: flex-start;
		align-items: flex-start;
	}

	.site-header
		.wp-block-navigation__responsive-container.is-menu-open
		.wp-block-navigation__responsive-container-content {
		width: 100%;
		/* Dégage la zone du bouton de fermeture (croix en haut à droite). */
		margin-top: var(--wp--preset--spacing--60);
	}

	.site-header
		.wp-block-navigation__responsive-container.is-menu-open
		.wp-block-navigation__container {
		display: flex !important;
		flex-direction: column;
		align-items: flex-start;
		justify-content: flex-start;
		gap: var(--wp--preset--spacing--40);
		text-align: left;
		width: 100%;
	}

	/* Les <li> gardaient une largeur fixe héritée du layout desktop, ce qui les
	   faisait déborder : on les laisse prendre leur largeur naturelle et
	   s'aligner sur le bord gauche. */
	.site-header
		.wp-block-navigation__responsive-container.is-menu-open
		.wp-block-navigation__container > li {
		width: auto !important;
		max-width: 100%;
		margin: 0 !important;
		text-align: left;
		/* Neutralise le décalage horizontal en escalier hérité du desktop
		   (transform translateX par nth-child), qui faisait déborder les items. */
		transform: none !important;
	}

	.site-header
		.wp-block-navigation__responsive-container.is-menu-open
		.wp-block-navigation-item__content {
		font-size: 2.5rem;
	}
}

.reveal {
	position: relative;
	background-color: transparent !important;
}

.reveal::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -2;
	background-color: inherit;
	opacity: 0;
	transition: opacity 0.9s ease;
}

.reveal.has-base-background-color::after { background-color: var(--wp--preset--color--base); }
.reveal.has-base-deux-background-color::after { background-color: var(--wp--preset--color--base-deux); }
.reveal.has-blanc-background-color::after { background-color: var(--wp--preset--color--blanc); }
.reveal.has-accent-clair-background-color::after { background-color: var(--wp--preset--color--accent-clair); }

.reveal.is-visible::after {
	opacity: 1;
}

/* Sections à fond blanc : on ne fait PAS le fondu d'opacité du fond. Le body
   du site est rose (couleur base) ; un fond blanc translucide laisserait ce
   rose transparaître pendant l'apparition. On garde donc le fond blanc opaque
   en permanence (le contenu, lui, continue d'apparaître en fondu). */
.reveal.has-blanc-background-color::after {
	opacity: 1;
	transition: none;
}

@media (prefers-reduced-motion: reduce) {
	.reveal::after {
		opacity: 1;
		transition: none;
	}
}

.services-row {
	display: flex;
	gap: var(--wp--preset--spacing--30);
	/* Bas des cartes aligné : la carte active grandit vers le haut, le pied de
	   rangée reste sur une même ligne. */
	align-items: flex-end;
}

.service-card {
	position: relative;
	display: flex;
	flex-direction: column;
	flex: 1 1 0;
	min-width: 0;
	/* Carte au repos ~carrée. Hauteur EXPLICITE (et non auto/min-height) : c'est la
	   seule façon d'animer l'ouverture sans décroché — une seule propriété (height)
	   transitionnée, donc une seule temporalité. overflow:hidden masque le corps tant
	   que la carte est repliée ; toutes les cartes au repos ont la même hauteur. */
	height: clamp(210px, 22vw, 290px);
	overflow: hidden;
	padding: var(--wp--preset--spacing--40);
	/* Réserver en bas la place du titre (posé en absolu) pour que le corps révélé
	   ne se glisse pas derrière lui. */
	padding-bottom: calc(var(--wp--preset--spacing--40) + 3.5rem);
	/* Couleur de la carte (--card-bg) posée par nth-child ci-dessous : camaïeu
	   rose/bleu, une teinte par carte. Au repos elle remplit le fond, sans bordure.
	   Une fois active, le fond passe au blanc et c'est la bordure qui reprend cette
	   teinte. Texte sombre dans les deux états (teintes claires → lisible). */
	background-color: var(--card-bg, var(--wp--preset--color--blanc));
	border: 1px solid transparent;
	color: var(--wp--preset--color--contrast);
	cursor: pointer;
	/* Une seule courbe, rapide mais progressive (ease-out doux) pour un déroulé très
	   fluide, sans à-coup au démarrage. La hauteur porte l'ouverture. opacity/transform
	   servent à l'apparition au scroll (droite → gauche, voir plus bas). */
	transition:
		height 0.5s cubic-bezier(0.22, 1, 0.36, 1),
		background-color 0.4s ease,
		color 0.4s ease,
		border-color 0.4s ease,
		opacity 0.3s ease var(--card-delay, 0s),
		transform 0.35s cubic-bezier(0.22, 1, 0.36, 1) var(--card-delay, 0s);
}

/* Apparition au scroll : avant révélation, les cartes sont décalées vers la droite
   et transparentes. Quand .services-row reçoit .is-cards-revealed (JS), elles
   glissent en place de la droite vers la gauche, en décalé (--card-index : 0 pour
   la carte la plus à droite, qui part donc en premier) et très rapidement
   (pas de stagger de 60 ms, transition courte). */
.services-row .service-card {
	--card-delay: calc(var(--card-index, 0) * 0.06s);
	opacity: 0;
	transform: translateX(40px);
}

.services-row.is-cards-revealed .service-card {
	opacity: 1;
	transform: translateX(0);
}

@media (prefers-reduced-motion: reduce) {
	.services-row .service-card {
		opacity: 1;
		transform: none;
	}
}

/* Quatre teintes en camaïeu rose → bleu (claires, pour garder le texte lisible).
   Valeurs hex explicites pour éviter toute dépendance à color-mix. */
.service-card:nth-child(1) { --card-bg: #fce7e7; } /* rose pâle */
.service-card:nth-child(2) { --card-bg: #f8d7d7; } /* rose soutenu */
.service-card:nth-child(3) { --card-bg: #dfe3f5; } /* bleu très clair */
.service-card:nth-child(4) { --card-bg: #c7cef0; } /* bleu clair */

/* Survol : la bordure corail apparaît pour signaler que la carte est cliquable.
   Sur la carte active, la bordure prend déjà la teinte de la carte — le survol la
   passe au corail pour rester cohérent avec le point qui suit la souris. */
.service-card:hover,
.service-card:focus-visible {
	border-color: var(--wp--preset--color--accent, #ff3c34);
}

.service-card.is-active {
	/* À l'ouverture : hauteur explicite au format ~portrait 3/4 (≈ largeur × 4/3),
	   transitionnée depuis le carré du repos → déroulé fluide d'une seule traite.
	   Léger surplus de hauteur pour garantir que le corps ne touche jamais le titre. */
	height: clamp(320px, 33vw, 430px);
	/* Active : fond blanc, et la bordure 1px reprend la couleur de la carte. */
	background-color: var(--wp--preset--color--blanc);
	border-color: var(--card-bg);
	color: var(--wp--preset--color--contrast);
}

.service-card__num {
	margin: 0;
	font-weight: 700;
	font-size: 1rem;
	letter-spacing: 0.02em;
	/* Numéro dans le rose-rouge du logo (était bleu électrique). */
	color: #FF3463;
}

/* Carte active (désormais fond blanc) : le numéro reste dans le rose-rouge du
   logo, lisible sur le blanc. */
.service-card.is-active .service-card__num {
	color: #FF3463;
}

/* Le titre est cloué au pied de la carte en absolu (bottom fixe = padding), à
   distance constante du bas sur les quatre cartes. Étant hors flux, sa hauteur
   ne dépend pas du détail : les titres restent alignés en bas, carte ouverte
   comme fermée. */
.service-card__title {
	position: absolute;
	left: var(--wp--preset--spacing--40);
	right: var(--wp--preset--spacing--40);
	bottom: var(--wp--preset--spacing--40);
	margin: 0;
	width: auto;
	max-width: 100%;
	/* Un cran sous le preset x-large : titres un peu plus compacts dans les cartes. */
	font-size: clamp(1.375rem, 1.1rem + 0.9vw, 1.75rem) !important;
}

.service-card__body {
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--30);
	margin-top: var(--wp--preset--spacing--40);
	width: 300px;
	max-width: 100%;
	/* Le corps reste dans le flux mais est masqué par overflow:hidden de la carte
	   tant qu'elle est repliée (hauteur fixe). Plus de height:0 → auto (non
	   animable) : c'est la hauteur de la carte qui anime l'ouverture, le corps ne
	   fait qu'apparaître en fondu, légèrement décalé et glissant un peu vers le haut
	   pour accompagner le déroulé. Toutes les cartes au repos gardent la même
	   hauteur (hauteur de carte fixe, indépendante de la longueur du texte). */
	opacity: 0;
	transform: translateY(8px);
	/* FERMETURE : disparition rapide et SANS delay. La transition portée par l'état
	   de base (carte repliée) s'applique quand on passe actif → repos : le texte
	   s'efface presque aussitôt, avant que la carte ne rétrécisse, ce qui évite le
	   chevauchement texte / titre pendant la fermeture. */
	transition:
		opacity 0.18s ease,
		transform 0.18s ease;
}

.service-card.is-active .service-card__body {
	opacity: 1;
	transform: translateY(0);
	/* OUVERTURE : apparition douce et légèrement retardée (le texte suit le déroulé
	   de la hauteur de la carte). Cette transition n'est active que dans l'état
	   .is-active, donc seulement à l'ouverture — la fermeture garde la version
	   rapide ci-dessus. */
	transition:
		opacity 0.4s ease 0.12s,
		transform 0.5s cubic-bezier(0.22, 1, 0.36, 1) 0.08s;
}

.service-card__body p {
	margin: 0;
	/* Un peu plus petit que le preset small pour alléger le corps des cartes. */
	font-size: 0.8125rem;
	line-height: 1.55;
	/* Carte active sur fond blanc : texte sombre légèrement atténué. */
	color: var(--wp--preset--color--contrast);
}

.service-card:not(.is-active) .service-card__body {
	pointer-events: none;
}

.service-card__cta {
	margin: 0;
}

/* Même style que le CTA du hero (.hero-cta) : texte en capitales, soulignement
   1px qui se révèle de gauche à droite au survol. Carte active sur fond blanc :
   le CTA est dans le rose-rouge du logo. */
.service-card__cta a {
	position: relative;
	display: inline-block;
	padding: 0;
	color: #FF3463;
	text-transform: uppercase;
	letter-spacing: 0.08em;
	font-size: var(--wp--preset--font-size--small);
	text-decoration: none;
}

.service-card__cta a::before {
	content: "↗";
	margin-right: 0.5em;
	font-size: 1.1em;
	line-height: 1;
}

.service-card__cta a::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	bottom: -0.15em;
	height: 1px;
	background: currentColor;
	transform: scaleX(0);
	transform-origin: right center;
	transition: transform 0.25s ease;
}

.service-card__cta a:hover::after,
.service-card__cta a:focus::after {
	transform: scaleX(1);
	transform-origin: left center;
}

@media (prefers-reduced-motion: reduce) {
	.service-card,
	.service-card__body {
		transition: none;
		transform: none;
	}
}

@media (max-width: 781px) {
	.services-row {
		flex-direction: column;
	}

	.service-card {
		flex: none;
		width: 100%;
		height: auto;
		min-height: 0;
		overflow: visible;
		/* Sur mobile tout est dans le flux : on annule la réserve du titre absolu. */
		padding-bottom: var(--wp--preset--spacing--40);
		/* Chaque carte garde sa teinte camaïeu (--card-bg), texte sombre, pas de
		   bordure : même grammaire que l'état au repos en desktop. */
		background-color: var(--card-bg);
		border-color: transparent;
		color: var(--wp--preset--color--contrast);
		cursor: auto;
	}

	/* Numéro dans le rose-rouge du logo, lisible sur les teintes claires. */
	.service-card__num {
		color: #FF3463;
	}

	/* Le titre repasse dans le flux (plus d'ancrage absolu) : ordre naturel
	   numéro → titre → détail, cartes empilées et entièrement visibles. */
	.service-card__title {
		position: static;
		left: auto;
		right: auto;
		bottom: auto;
		margin-top: var(--wp--preset--spacing--40);
	}

	/* Accordéon conservé sur mobile : le corps est replié par défaut (display:none),
	   on tape la carte pour le déployer (.is-active, posé par services.ts qui attache
	   déjà le tap sur toutes les cartes). Plus de hauteur fixe ici : la carte est en
	   flux (height:auto), le corps apparaît/disparaît simplement. */
	.service-card__body {
		display: none;
		opacity: 1;
		visibility: visible;
		transform: none;
		pointer-events: auto;
		margin-top: var(--wp--preset--spacing--30);
	}

	.service-card.is-active .service-card__body {
		display: flex;
	}

	/* Carte active sur mobile : fond blanc + bordure teintée, comme en desktop, pour
	   signaler l'ouverture. */
	.service-card.is-active {
		height: auto;
		background-color: var(--wp--preset--color--blanc);
		border-color: var(--card-bg);
	}
}

/* ----------------------------------------------------------------------------
   Cartes d'information (sections « Un constat » et « Pourquoi Studio Esdée »).
   Variante statique, non cliquable, de la famille .service-card : même grammaire
   visuelle (numéro en accent, bordure fine, titre, texte) pour faire écho à la
   grille services sans en copier l'interaction. Posées dans une grille
   .info-grid (3 colonnes au repos, repli responsive).
---------------------------------------------------------------------------- */
.info-grid {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: var(--wp--preset--spacing--40);
}

.info-card {
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--30);
	padding: var(--wp--preset--spacing--40);
	background-color: var(--wp--preset--color--blanc);
	border: 1px solid color-mix(in srgb, var(--wp--preset--color--contrast) 14%, transparent);
	transition: border-color 0.3s ease, transform 0.3s ease;
}

.info-card:hover {
	border-color: var(--wp--preset--color--accent);
	transform: translateY(-3px);
}

/* Numéro façon répertoire : 01/ 02/ … en accent, au-dessus du titre. */
.info-card__num {
	margin: 0;
	font-weight: 700;
	font-size: 1rem;
	letter-spacing: 0.02em;
	color: var(--wp--preset--color--electrique);
}

.info-card__title {
	margin: 0;
}

.info-card p:not(.info-card__num) {
	margin: 0;
	color: var(--wp--preset--color--contrast);
}

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

@media (max-width: 781px) {
	.info-grid {
		grid-template-columns: 1fr;
	}
}

/* ----------------------------------------------------------------------------
   Familles de prestations (page Services, pattern services-familles).
   Réutilise la grammaire .info-grid / .info-card : chaque carte est une famille
   (numéro, titre, phrase) suivie de la liste de ses prestations. La grille passe
   à deux colonnes sur tablette puis une seule sur mobile.
---------------------------------------------------------------------------- */
.services-familles-grid {
	grid-template-columns: repeat(4, 1fr);
}

.service-famille {
	gap: var(--wp--preset--spacing--20);
}

/* La liste des prestations, posée sous la phrase d'intro : puces discrètes,
   alignées sur le ton « répertoire » des cartes. */
.service-famille__list {
	margin: var(--wp--preset--spacing--20) 0 0;
	padding: 0;
	list-style: none;
	border-top: 1px solid color-mix(in srgb, var(--wp--preset--color--contrast) 14%, transparent);
}

.service-famille__list li {
	padding: 0.5rem 0;
	font-size: 0.9rem;
	color: var(--wp--preset--color--contrast);
	border-bottom: 1px solid color-mix(in srgb, var(--wp--preset--color--contrast) 8%, transparent);
}

.service-famille__list li:last-child {
	border-bottom: none;
}

@media (max-width: 1024px) {
	.services-familles-grid {
		grid-template-columns: repeat(2, 1fr);
	}
}

@media (max-width: 600px) {
	.services-familles-grid {
		grid-template-columns: 1fr;
	}
}

/* ----------------------------------------------------------------------------
   Accordéon FAQ (section « Pourquoi Studio Esdée »).
   Chaque ligne : un titre cliquable pleine largeur (avec un + qui pivote) qui
   déploie son corps. Un seul ouvert à la fois, géré par faq.js. Le corps
   s'anime de 0 à sa hauteur réelle via grid-template-rows.
---------------------------------------------------------------------------- */
.faq {
	display: flex;
	flex-direction: column;
}

.faq__item {
	border-top: 1px solid color-mix(in srgb, var(--wp--preset--color--contrast) 14%, transparent);
}

.faq__item:last-child {
	border-bottom: 1px solid color-mix(in srgb, var(--wp--preset--color--contrast) 14%, transparent);
}

/* Le titre est le déclencheur : pleine largeur, cliquable, avec un + qui pivote. */
.faq__head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--wp--preset--spacing--30);
	margin: 0;
	padding: var(--wp--preset--spacing--40) 0;
	cursor: pointer;
	user-select: none;
	transition: color 0.25s ease;
}

.faq__head::after {
	content: "+";
	flex: none;
	font-weight: 400;
	line-height: 1;
	color: var(--wp--preset--color--accent);
	transition: transform 0.3s ease;
}

.faq__item:hover .faq__head,
.faq__item.is-open .faq__head {
	color: var(--wp--preset--color--accent);
}

.faq__item.is-open .faq__head::after {
	transform: rotate(45deg);
}

.faq__head:focus-visible {
	outline: none;
}

/* Le corps s'anime de 0 à sa hauteur réelle (hauteur « auto » animable). */
.faq__body {
	display: grid;
	grid-template-rows: 0fr;
	transition: grid-template-rows 0.3s ease;
}

.faq__body > * {
	overflow: hidden;
	min-height: 0;
	margin: 0;
	max-width: 60ch;
	color: var(--wp--preset--color--contrast);
}

.faq__item.is-open .faq__body {
	grid-template-rows: 1fr;
	padding-bottom: var(--wp--preset--spacing--40);
}

@media (prefers-reduced-motion: reduce) {
	.faq__body,
	.faq__head::after {
		transition: none;
	}
}

/* ----------------------------------------------------------------------------
   Section « Un constat » — grille en escalier (3 colonnes côte à côte).
   Inspiration : la grille « My philosophy » (capture de réf). Les trois cartes
   sont posées côte à côte, séparées par de fines lignes verticales. Chaque carte
   descend un peu plus que la précédente (effet escalier) et porte un aplat de
   couleur (placeholder image) lui aussi décalé : bas en colonne 1, haut en
   colonne 2, plus haut encore en colonne 3. Tout le texte est affiché en
   permanence — ce n'est plus un accordéon (cf. services.ts).
---------------------------------------------------------------------------- */
.constat-grid {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 0;
	/* Aligne les colonnes par le haut : le décalage vertical est porté par
	   transform (cf. .info-card), pas par la hauteur des colonnes. */
	align-items: start;
	/* Le décalage escalier étant un transform (sans hauteur réservée), la colonne
	   la plus décalée déborderait sous la grille. On réserve donc en bas l'espace
	   du décalage résiduel une fois le rattrapage fait (≈ 0.15 × le plus grand
	   offset), pour que le bas du bloc respire juste ce qu'il faut, sans le grand
	   vide d'avant. */
	padding-bottom: clamp(1rem, 2.5vw, 2.5rem);
}

.constat-grid .info-card {
	position: relative;
	width: 100%;
	gap: var(--wp--preset--spacing--30);
	/* Plus de fond ni de bordure de carte : on ne garde que la fine ligne
	   verticale entre colonnes (gérée juste après), comme sur l'inspiration. */
	background-color: transparent;
	border: 0;
	padding: 0 var(--wp--preset--spacing--40);
	cursor: default;
	transition: none;
}

/* Pas de séparateur vertical entre les colonnes (retiré à la demande). */

/* Effet escalier : chaque colonne démarre plus bas que la précédente. Le
   décalage de repos (--col-offset) sert à la fois au padding-top initial et à
   la parallaxe de rattrapage ci-dessous, pour garder la valeur au même endroit. */
.constat-grid .info-card { --col-offset: 0px; }
.constat-grid .info-card:nth-child(2) { --col-offset: clamp(1.5rem, 3.5vw, 3.5rem); }
.constat-grid .info-card:nth-child(3) { --col-offset: clamp(6rem, 14vw, 14rem); }

/* Escalier + parallaxe portés UNIQUEMENT par transform, jamais par padding/margin :
   ainsi le décalage vertical ne réserve aucune hauteur dans la grille (sinon la
   colonne 3, poussée de ~14rem, étirait la rangée et laissait un grand vide sous
   les colonnes 1 et 2 — c'était la « grande marge sous le bloc »). La grille
   calcule donc ses hauteurs comme si les colonnes étaient alignées en haut.
   - décalage de repos : +--col-offset (la colonne descend).
   - rattrapage au scroll : on remonte de --catchup × --col-offset × 0.85, donc le
     décalage net vaut --col-offset × (1 - 0.85·--catchup). */
.constat-grid .info-card {
	transform: translate3d(0, calc(var(--col-offset) * (1 - 0.85 * var(--catchup, 0))), 0);
	will-change: transform;
}

/* Les cartes ne sont plus interactives : on neutralise le hover hérité sans
   écraser le transform de parallaxe. */
.constat-grid .info-card:hover {
	border-color: color-mix(in srgb, var(--wp--preset--color--contrast) 18%, transparent);
}

@media (prefers-reduced-motion: reduce) {
	.constat-grid .info-card {
		transform: none;
	}
}

/* Placeholder image : simple aplat de couleur en format portrait, posé dans le
   flux de la carte. Sa position et sa taille varient par colonne pour reproduire
   l'escalier d'images de la capture. */
/* Le média est désormais un vrai bloc image WordPress (figure.wp-block-image)
   éditable dans le back office. La figure sert de masque (clip), l'image remonte
   de 110 % derrière elle — exactement comme le mot du hero (.hero-word). */
.constat-grid .info-card__media {
	width: 100%;
	aspect-ratio: 1 / 1;
	border-radius: 0;
	flex: none;
	margin: 0;
	position: relative;
	overflow: hidden;
	clip-path: inset(0);
	/* Fond de repli en camaïeu (rose / bleu), visible tant qu'aucune image n'est
	   posée et derrière le placeholder transparent. Dégradé doux dans la famille
	   de couleurs de la marque plutôt qu'un gris neutre. La teinte est déclinée
	   par colonne ci-dessous (rose, bleu, mixte). */
	background-image: linear-gradient(
		160deg,
		var(--media-from, var(--wp--preset--color--base-deux)) 0%,
		var(--media-to, var(--wp--preset--color--base)) 100%
	);
}

/* Camaïeu rose pour la colonne 1. */
.constat-grid .info-card:nth-child(1) .info-card__media {
	--media-from: var(--wp--preset--color--base-deux);
	--media-to: color-mix(in srgb, var(--wp--preset--color--base) 70%, var(--wp--preset--color--blanc));
}

/* Camaïeu bleu pour la colonne 2 (électrique vers bleu nuit, adouci). */
.constat-grid .info-card:nth-child(2) .info-card__media {
	--media-from: color-mix(in srgb, var(--wp--preset--color--electrique) 75%, var(--wp--preset--color--blanc));
	--media-to: color-mix(in srgb, var(--wp--preset--color--contrast) 80%, var(--wp--preset--color--electrique));
}

/* Camaïeu mixte rose -> bleu pour la colonne 3, pour faire le lien. */
.constat-grid .info-card:nth-child(3) .info-card__media {
	--media-from: var(--wp--preset--color--base-deux);
	--media-to: color-mix(in srgb, var(--wp--preset--color--electrique) 55%, var(--wp--preset--color--base));
}

.constat-grid .info-card__media img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	border-radius: 0;
	transform: translate3d(0, 110%, 0);
	transition: transform 0.6s cubic-bezier(0.165, 0.84, 0.44, 1);
	/* Stagger : chaque média part 0,12 s après le précédent (--media-index posé
	   en JS, comme --index sur les lignes de titre du hero). */
	transition-delay: calc(var(--media-index, 0) * 0.12s);
}

/* État révélé : la classe .is-media-revealed est posée sur .constat-grid par le
   JS quand la grille entre dans le viewport (cf. reveal.ts). */
.constat-grid.is-media-revealed .info-card__media img {
	transform: translate3d(0, 0, 0);
}

@media (prefers-reduced-motion: reduce) {
	.constat-grid .info-card__media img {
		transform: none;
		transition: none;
	}
}

/* Média identique dans les trois colonnes : en tête de carte (avant le texte,
   cf. markup), même taille, aligné à gauche, même marge basse. Seule la teinte
   du fond de repli reste déclinée par colonne (voir plus haut). */
.constat-grid .info-card__media {
	align-self: flex-start;
	margin-bottom: var(--wp--preset--spacing--40);
}

.constat-grid .info-card__num {
	margin: 0;
}

.constat-grid .info-card__title {
	margin: 0;
}

/* Tout le texte est affiché en permanence : on annule l'ancien pliage. */
.constat-grid .info-card p:not(.info-card__num) {
	max-width: 38ch;
	margin: 0;
	max-height: none;
	overflow: visible;
	opacity: 1;
	color: var(--wp--preset--color--contrast);
}

/* La section constat doit laisser déborder la bande d'images et passer au-dessus
   de la section services qui la suit. */
.constat-section {
	position: relative;
	/* Surtout PAS de z-index ici : un z-index positif sur la section en ferait un
	   contexte d'empilement isolé, ce qui emprisonnerait son fond (::before, -1)
	   dans une couche située AU-DESSUS de l'image du hero (.hero-art, z-index 1).
	   Le fond blanc repeindrait alors par-dessus l'image au lieu de passer dessous.
	   En restant en simple position:relative, la section ne crée pas de contexte :
	   dans le repère commun de <main>, on obtient fond (-1) < image hero (1) <
	   contenu de la section (1, via .section-numbered > *, déclaré après dans le
	   DOM donc dessiné par-dessus). L'image déborde visiblement dans les zones
	   sans texte, le contenu reste lisible. */
	overflow: visible;
}

/* Le fond blanc de la section démarre plus bas que son sommet : cette bande
   laisse voir l'image du hero qui plonge dessus, sur le rose de la page. La
   section remonte sous le hero de --hero-overlap (8rem) et l'image déborde
   encore de --back-overlap (4rem) : le fond doit donc démarrer sous la somme
   des deux pour que tout le débordement reste visible. */
.constat-section.section-numbered::before {
	top: calc(8rem + 4rem);
}

@media (max-width: 781px) {
	/* Sur mobile, l'escalier n'a plus de sens : les trois cartes s'empilent en
	   une seule colonne, sans décalage vertical ni ligne verticale. */
	.constat-grid {
		grid-template-columns: 1fr;
		gap: var(--wp--preset--spacing--50);
	}

	.constat-grid .info-card,
	.constat-grid .info-card:nth-child(2),
	.constat-grid .info-card:nth-child(3) {
		--col-offset: 0px;
		padding: 0;
		padding-top: 0;
		/* Pas de parallaxe de rattrapage en pile mobile. */
		transform: none;
	}

	/* Neutralise les remontées d'images propres à l'escalier sur mobile. */
	.constat-grid .info-card:nth-child(3) .info-card__media {
		margin-top: 0;
	}
}

.idx-intro {
	max-width: 38ch;
	margin-bottom: var(--wp--preset--spacing--50);
	color: var(--wp--preset--color--contrast);
}

.idx-list {
	border-top: 1px solid var(--wp--preset--color--contrast);
	/* La liste déborde de son container parent (contentSize 1200px) : on la
	   centre sur une largeur plus grande via des marges négatives symétriques.
	   La largeur reste bornée à la viewport moins les marges latérales de la
	   section pour ne jamais provoquer de scroll horizontal. */
	--idx-list-width: 1500px;
	width: min(var(--idx-list-width), 100vw - 2 * var(--wp--preset--spacing--40));
	margin-left: calc(50% - min(var(--idx-list-width), 100vw - 2 * var(--wp--preset--spacing--40)) / 2);
	margin-right: calc(50% - min(var(--idx-list-width), 100vw - 2 * var(--wp--preset--spacing--40)) / 2);
}

.idx-row {
	--img-h: clamp(44px, 5.5vw, 60px);
	position: relative;
	min-height: calc(var(--img-h) + 1rem);
	gap: clamp(1rem, 4vw, 3rem);
	/* WordPress ajoute un margin-top inter-bloc (block-gap) à chaque row :
	   comme le séparateur est en bas, ce margin créait un espace asymétrique
	   au-dessus du contenu. On le neutralise et on répartit l'espacement
	   symétriquement via le seul padding-block. */
	margin-block: 0;
	padding-block: 0.5rem;
	border-bottom: 1px solid var(--wp--preset--color--contrast);
	isolation: isolate;
}

.idx-row:hover {
	z-index: 3;
}

/* La miniature n'occupe plus de colonne : elle devient un média flottant qui
   affiché par-dessus le tableau au survol de la ligne, centré horizontalement
   sur le tableau et verticalement sur la ligne survolée. Masquée par défaut,
   et jamais affichée pour les placeholders. */
.idx-thumb {
	position: absolute;
	left: 50%;
	top: 50%;
	transform: translate(-50%, -50%) scale(0.85);
	height: clamp(120px, 16vw, 200px);
	width: auto;
	aspect-ratio: 3 / 2;
	margin: 0;
	border-radius: 0;
	overflow: hidden;
	z-index: 5;
	pointer-events: none;
	opacity: 0;
	transition: opacity 0.35s ease, transform 0.35s cubic-bezier(0.22, 1, 0.36, 1);
	will-change: transform, opacity;
}

.idx-thumb img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

.idx-row:hover .idx-thumb {
	opacity: 1;
	transform: translate(-50%, -50%) scale(1);
}

/* Les placeholders (aplats de couleur) ne s'affichent jamais en survol :
   filet de sécurité CSS en plus du JS. */
.idx-row:hover .idx-thumb:has(img[src$="thumb-placeholder.svg"]) {
	opacity: 0;
}

/* Projets sans média : miniature en aplat uni, une couleur de la palette par
   variante (du plus clair au plus soutenu) pour varier sans sortir de
   l'identité corail/rose. */
.idx-thumb--1 { background-color: var(--wp--preset--color--base); }
.idx-thumb--2 { background-color: var(--wp--preset--color--base-deux); }
.idx-thumb--3 { background-color: var(--wp--preset--color--accent); }
.idx-thumb--4 { background-color: color-mix(in srgb, var(--wp--preset--color--accent) 35%, var(--wp--preset--color--blanc)); }
.idx-thumb--5 { background-color: color-mix(in srgb, var(--wp--preset--color--accent) 60%, var(--wp--preset--color--blanc)); }
.idx-thumb--6 { background-color: color-mix(in srgb, var(--wp--preset--color--base-deux) 70%, var(--wp--preset--color--accent)); }

.idx-meta {
	position: relative;
	z-index: 2;
	flex: 1 1 auto;
	min-width: 0;
}

.idx-nom {
	margin: 0;
	font-size: clamp(0.95rem, 1.7vw, 1.2rem);
	line-height: 1.15;
	text-transform: uppercase;
	letter-spacing: 0.02em;
	color: var(--wp--preset--color--contrast);
	/* ancre du soulignement (::after), calé sur la largeur du texte */
	position: relative;
	/* le nom ne s'étire pas sur toute la cellule : le soulignement suit le mot */
	width: fit-content;
	max-width: 100%;
}

/* Les titres de l'index portent .titre-reveal, qui force xx-large en !important.
   On réduit d'un cran (x-large) pour les seuls titres de projet. */
.idx-nom.titre-reveal:not(.hero-titre) {
	font-size: clamp(1.1rem, 1.6vw, 1.3rem) !important;
}

.idx-nom a {
	color: var(--wp--preset--color--contrast);
	text-decoration: none;
	/* PAS de position:relative ici : l'overlay ::before doit s'ancrer sur
	   .idx-meta (grande cellule centrale), pas sur le lien (largeur du texte). */
}

/* Zone cliquable agrandie. Souci d'origine : la miniature (.idx-thumb) grossit au
   survol (scale 2.4), débordait sur le nom et captait le clic. Corrigé en deux
   temps :
   1. .idx-thumb a pointer-events:none (plus haut) : elle ne capte plus rien.
   2. le lien porte un overlay transparent ::before qui, ancré sur .idx-meta
      (ancêtre positionné le plus proche, car le lien n'est plus positionné),
      couvre toute la cellule centrale + le padding vertical de la ligne (1rem).
      Cible large et fiable, sans calcul dépendant de la longueur du nom. */
.idx-meta:has(.idx-nom a) {
	cursor: pointer;
}

.idx-nom a::before {
	content: "";
	position: absolute;
	z-index: 0;
	top: -1rem;
	bottom: -1rem;
	left: 0;
	right: 0;
}

/* Soulignement animé, ancré sur .idx-nom (largeur du texte) et au-dessus de
   l'overlay pour rester visible ; non cliquable pour ne pas gêner. */
.idx-nom::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	bottom: -0.1em;
	height: 1px;
	background: currentColor;
	transform: scaleX(0);
	transform-origin: right center;
	transition: transform 0.25s ease;
	z-index: 1;
	pointer-events: none;
}

.idx-nom a:hover {
	color: var(--wp--preset--color--contrast);
}

/* ------------------------------------------------------------------ */
/* Footer                                                             */
/* ------------------------------------------------------------------ */

.site-footer {
	position: relative;
	overflow: hidden;
}

.site-footer a {
	color: inherit;
}

/* Tout le texte du footer en Stack Sans Notch, comme les items du menu (header).
   Exception : le gros titre d'accroche (.footer-cta__titre), un H2, suit la règle
   générale des titres (Manrope ; seuls les mots en gras passent en Stack Sans
   Notch via la règle h2 strong / h2 b). */
.site-footer {
	font-family: "Stack Sans Notch", var(--wp--preset--font-family--manrope), sans-serif;
}

.footer-cta__titre.footer-cta__titre {
	font-family: var(--wp--preset--font-family--manrope), sans-serif;
}

/* Tout le texte du footer dans la même couleur : le gris foncé de la charte
   (contrast, #16202c). On uniformise les titres de colonnes et le lien CTA, qui
   étaient en bleu électrique, ainsi que contact / baseline / mentions légales,
   qui étaient en contrast atténué. Les survols (passage en corail) restent
   gérés par les règles :hover plus bas. */
.site-footer,
.footer-cta__lien a,
.footer-col__titre.footer-col__titre,
.footer-nav a,
.footer-contact,
.footer-baseline,
.footer-legal p {
	color: var(--wp--preset--color--contrast);
}

/* Typo commune avec les items du menu (header) : capitales + interlettrage.
   On reprend à l'identique text-transform/letter-spacing du bloc navigation.
   Le gros titre du CTA (.footer-cta__titre) est volontairement exclu : c'est
   un titre de phrase, qui reste en casse normale. */
.footer-cta__lien,
.footer-cta__lien a,
.footer-col__titre.footer-col__titre,
.footer-nav,
.footer-nav a,
.footer-contact,
.footer-contact a,
.footer-baseline,
.footer-legal,
.footer-legal p,
.footer-legal a {
	text-transform: uppercase;
	letter-spacing: 0.08em;
}

/* Bloc d'appel au contact */
.footer-cta {
	padding-bottom: var(--wp--preset--spacing--60);
}

.footer-cta__kicker {
	margin: 0 0 var(--wp--preset--spacing--30);
	font-size: 0.75rem;
	font-style: italic;
	letter-spacing: 0.06em;
	color: var(--wp--preset--color--accent);
}

.footer-cta__titre.footer-cta__titre {
	max-width: 20ch;
	margin: 0;
	font-size: clamp(1.75rem, 4vw, 3.25rem);
	font-weight: 800;
	line-height: 1.1;
	letter-spacing: -0.02em;
	text-wrap: balance;
}

.footer-cta__lien {
	margin: var(--wp--preset--spacing--40) 0 0;
}

.footer-cta__lien a {
	position: relative;
	display: inline-block;
	max-width: 100%;
	font-size: var(--wp--preset--font-size--large);
	font-weight: 700;
	color: var(--wp--preset--color--electrique);
	text-decoration: none;
}

.footer-cta__lien a::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	bottom: -0.1em;
	height: 2px;
	background: currentColor;
	transform: scaleX(1);
	transform-origin: left center;
	transition: transform 0.3s ease;
}

.footer-cta__lien a:hover {
	color: var(--wp--preset--color--contrast);
}

.footer-cta__lien a:hover::after {
	transform: scaleX(0);
	transform-origin: right center;
}

/* Colonnes */
.footer-cols {
	gap: var(--wp--preset--spacing--50);
	margin-top: var(--wp--preset--spacing--60);
	align-items: flex-start;
}

.footer-col {
	flex: 1 1 12rem;
}

/* Apparition au scroll : les trois colonnes montent et apparaissent en fondu,
   en décalé (la première du DOM part en premier). Le JS pose --col-index pour le
   stagger et ajoute .is-cols-revealed à .footer-cols à son entrée dans le
   viewport ; le CSS porte le mouvement. Même grammaire que les cartes services. */
.footer-cols .footer-col {
	--col-delay: calc(var(--col-index, 0) * 0.1s);
	opacity: 0;
	transform: translateY(28px);
	transition:
		opacity 0.6s ease var(--col-delay, 0s),
		transform 0.6s cubic-bezier(0.22, 1, 0.36, 1) var(--col-delay, 0s);
}

.footer-cols.is-cols-revealed .footer-col {
	opacity: 1;
	transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
	.footer-cols .footer-col {
		opacity: 1;
		transform: none;
		transition: none;
	}
}

.footer-col__titre.footer-col__titre {
	margin: 0 0 var(--wp--preset--spacing--30);
	font-size: 0.7rem;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.08em;
	color: var(--wp--preset--color--electrique);
}

.footer-nav a {
	font-size: var(--wp--preset--font-size--medium);
	text-decoration: none;
	transition: color 0.2s ease;
}

.footer-nav a:hover {
	color: var(--wp--preset--color--accent);
}

.footer-contact {
	margin: 0;
	font-size: var(--wp--preset--font-size--medium);
	line-height: 1.7;
	color: var(--wp--preset--color--contrast);
}

.footer-contact a:hover {
	color: var(--wp--preset--color--accent);
}

/* Signature géante : le logo en filigrane blanc sur le fond rose pâle. */
.footer-wordmark.footer-wordmark {
	/* Le logo vient coller le bas du footer (donc le bas de la fenêtre) : aucune
	   marge basse, et on annule le padding-bottom du footer juste en dessous.
	   Marge haute resserrée pour rapprocher le logo du contenu du footer. */
	margin: clamp(1rem, 3vw, 2.5rem) 0 0;
	pointer-events: none;
	user-select: none;
	/* Le conteneur masque le bas du logo. L'image dépasse vers le bas via une marge
	   négative ; comme les % de marge se calculent sur la LARGEUR du conteneur, le
	   crop reste proportionnel quelle que soit la taille d'écran. */
	overflow: hidden;
}

/* On supprime la réserve en bas du footer pour que le logo touche le bord. */
.site-footer {
	padding-bottom: 0 !important;
}

.footer-wordmark img {
	display: block;
	width: 100%;
	height: auto;
	/* Quantité rognée en bas : marge négative en % de la largeur du logo
	   (0 = logo entier, aucun crop). Passer à -1%, -2%… pour couper le bas. */
	margin-bottom: 0;
	/* Le logo SVG est en indigo : on le bascule en blanc pour l'effet filigrane. */
	filter: brightness(0) invert(1);
}

/* Bloc bas de page, désormais en 3e colonne du footer (à côté de « Le studio »
   et « Me joindre ») : baseline au-dessus des mentions légales, empilées et
   alignées à gauche comme les autres colonnes. */
.footer-bottom {
	gap: var(--wp--preset--spacing--20);
}

/* La baseline est la première ligne de la 3e colonne : on cale sa métrique
   (taille, hauteur de ligne, marge basse) sur celle du titre des deux autres
   colonnes (.footer-col__titre) pour que « Création… » s'aligne exactement sur
   « Le studio » / « Me joindre ». On garde sa casse normale (c'est une phrase,
   pas un libellé en capitales). */
.footer-bottom .footer-baseline {
	font-size: 0.7rem;
	line-height: 1.4;
	margin: 0 0 var(--wp--preset--spacing--30);
}

/* Tous les textes de la 3e colonne (baseline, mentions légales, copyright) dans
   une fonte réduite, plus discrète que les deux autres colonnes. La classe de
   preset has-small-font-size pose la taille en !important : on la bat donc avec
   le même !important. */
.footer-bottom p,
.footer-bottom .has-small-font-size {
	font-size: 0.7rem !important;
}

.footer-baseline {
	margin: 0 0 var(--wp--preset--spacing--30);
	color: var(--wp--preset--color--contrast);
}

.footer-legal {
	gap: var(--wp--preset--spacing--20);
}

.footer-legal p {
	margin: 0;
	color: var(--wp--preset--color--contrast);
}

.footer-legal a:hover {
	color: var(--wp--preset--color--accent);
}

@media (max-width: 781px) {
	.footer-cols {
		gap: var(--wp--preset--spacing--50) var(--wp--preset--spacing--40);
	}
	.footer-col {
		flex: 1 1 45%;
	}
}

@media (max-width: 600px) {
	.footer-col {
		flex: 1 1 100%;
	}
}

/* Le soulignement s'anime au survol de toute la zone cliquable (la cellule
   centrale), pas seulement du texte du lien. Uniquement si le titre porte un
   lien : sans <a>, pas de soulignement (rien à ouvrir). */
.idx-meta:hover .idx-nom:has(a)::after,
.idx-row:hover .idx-nom:has(a)::after {
	transform: scaleX(1);
	transform-origin: left center;
}

.idx-cat,
.idx-services {
	flex: 0 0 auto;
	margin: 0;
	text-transform: uppercase;
	letter-spacing: 0.03em;
}

/* Réduit la 3e (.idx-cat) et 4e (.idx-services) colonne. !important pour
   surclasser .has-small-font-size, le preset WP étant lui-même en !important. */
p.idx-cat,
p.idx-services {
	font-size: 0.75rem !important;
}

.idx-cat {
	width: clamp(6rem, 10vw, 9rem);
	color: var(--wp--preset--color--contrast);
}

.idx-services {
	width: clamp(8rem, 14vw, 12rem);
	color: var(--wp--preset--color--contrast);
}

.idx-annee {
	position: relative;
	z-index: 2;
	flex: 0 0 auto;
	width: clamp(5rem, 10vw, 8rem);
	margin: 0;
	text-align: left;
	font-size: 0.6875rem;
	text-transform: uppercase;
	letter-spacing: 0.03em;
	font-variant-numeric: tabular-nums;
	color: var(--wp--preset--color--contrast);
}

@media (max-width: 680px) {
	/* Tableau fluide sur une seule ligne : année · nom · catégorie · services se
	   partagent la largeur disponible, sans débordement. On abandonne les largeurs
	   fixes (clamp) du desktop au profit de bases proportionnelles, et on resserre
	   l'espacement inter-colonnes. */
	.idx-row {
		flex-wrap: nowrap;
		gap: 0.5rem;
	}

	/* Colonnes étroites et fluides : largeur de base proportionnelle, libres de se
	   réduire (min-width: 0 autorise le retrait sous la taille du contenu). */
	.idx-annee {
		flex: 0 1 18%;
		width: auto;
		min-width: 0;
		text-align: left;
	}

	/* Le nom prend l'espace restant. */
	.idx-meta {
		flex: 1 1 auto;
		min-width: 0;
	}

	.idx-cat,
	.idx-services {
		flex: 0 1 22%;
		width: auto;
		min-width: 0;
	}

	/* Textes longs : on coupe proprement plutôt que de pousser la ligne. */
	.idx-annee,
	.idx-cat,
	.idx-services,
	.idx-nom {
		overflow-wrap: anywhere;
	}
}

/* Repli sous ~440px : disposition en 2 colonnes sur 2 lignes, dans l'ordre du DOM.
     ligne 1 : année (col 1) + nom (col 2)
     ligne 2 : catégorie (col 3) + services (col 4)
   Chaque cellule occupe la moitié de la largeur (moins le demi-gap), le wrap fait
   le reste. Font réduite pour gagner en lisibilité dans ces cellules étroites. */
@media (max-width: 440px) {
	.idx-row {
		flex-wrap: wrap;
		row-gap: 0.35rem;
	}
	.idx-annee,
	.idx-meta,
	.idx-cat,
	.idx-services {
		flex: 0 0 calc(50% - 0.25rem);
		width: auto;
		min-width: 0;
		text-align: left;
	}
	/* Réduction de la taille de texte sur les cellules étroites. !important sur les
	   paragraphes pour battre le preset WP (.has-small-font-size, lui-même en
	   !important). */
	.idx-annee {
		font-size: 0.625rem;
	}
	.idx-nom {
		font-size: 1rem;
	}
	p.idx-cat,
	p.idx-services {
		font-size: 0.6875rem !important;
	}
}

/* L'aperçu au survol n'a de sens qu'avec un pointeur fin (souris). Sur tactile,
   le :hover n'existe pas (ou reste collé après un tap) et l'image recouvrirait
   le texte : on masque complètement le média sur ces appareils. La liste reste
   alors une liste de texte épurée. */
@media (hover: none), (pointer: coarse) {
	.idx-thumb {
		display: none;
	}
}

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

/* ------------------------------------------------------------------ */
/* Chiffre de section géant, en filigrane sticky (option B, 100% CSS)  */
/* ------------------------------------------------------------------ */
/* Chaque section numérotée affiche son numéro en très grand, derrière */
/* le contenu. Le chiffre est sticky : il reste centré verticalement   */
/* dans la fenêtre tant que la section défile, puis cède la place à     */
/* celui de la section suivante.                                        */

/* Le fond opaque de la section est déplacé sur ::before (z-index -1) pour
   laisser le filigrane (z-index 0) apparaître entre le fond et le contenu.
   Empilement, dans le contexte de la section : fond (-1) < filigrane (0) <
   contenu (1). Tout est interne à la section, donc insensible au transform
   Locomotive du conteneur de scroll. */
.section-numbered {
	position: relative;
	overflow: hidden; /* le filigrane géant ne déborde pas de la section */
	background-color: transparent !important;
}

.section-numbered::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background-color: var(--section-bg, var(--wp--preset--color--blanc));
}

.is-section-01 { --section-bg: var(--wp--preset--color--blanc); }
.is-section-02 { --section-bg: var(--wp--preset--color--blanc); }

/* Le contenu réel passe au-dessus du filigrane. */
.section-numbered > *:not(.section-number-bg) {
	position: relative;
	z-index: 1;
}

/* Section éditoriale de la home : elle accueille le même filigrane fixé au scroll
   que les sections numérotées. On lui pose le strict nécessaire (contexte de
   positionnement, recadrage du filigrane géant, et passage du contenu au-dessus),
   SANS le fond ::before des sections numérotées : .home-edito garde son propre
   fond défini dans l'éditeur. */
.home-edito {
	position: relative;
	overflow: hidden;
}

.home-edito > *:not(.section-number-bg) {
	position: relative;
	z-index: 1;
}

/* Filigrane géant, enfant de la section, repositionné au scroll par
   section-number.js (sa propriété top suit le centre du viewport). */
.section-number-bg {
	position: absolute;
	/* Centrage horizontal sur toute la largeur de la section (alignfull = largeur
	   du viewport) : on étale le filigrane bord à bord et on centre le texte, plutôt
	   que de dépendre d'un left:50% sensible au padding global de la section et à la
	   barre de défilement (ce qui le décalait du centre réel du viewport). Le JS ne
	   pilote plus que `top` ; le translate ne porte donc que le centrage vertical. */
	left: 0;
	right: 0;
	width: 100%;
	transform: translateY(-50%);
	z-index: 0;
	line-height: 1;
	font-size: clamp(14rem, 34vw, 40rem);
	font-weight: 800;
	letter-spacing: -0.04em;
	text-align: center;
	white-space: nowrap;
	pointer-events: none;
	user-select: none;
	opacity: 0;
	/* Transition douce : lisse le crossfade « constat » → « solution » à la
	   jonction des deux sections, sans trop traîner derrière le scroll (l'opacité
	   est mise à jour en continu par section-number.js). */
	transition: opacity 0.3s ease;
	color: var(--num-color, color-mix(in srgb, var(--section-bg, var(--wp--preset--color--blanc)) 92%, var(--wp--preset--color--contrast)));
}

/* Visible quand la section est au centre de l'écran. L'opacité exacte est
   pilotée au scroll par section-number.js (--mark-opacity) : pleine à l'arrivée,
   puis fondu progressif à la lecture pour ne pas gêner le texte. */
.section-number-bg.is-visible {
	opacity: var(--mark-opacity, 1);
}

/* Filigrane en mot (ex. « constat », « solution ») plutôt qu'en chiffre. On
   l'habille de la typo du menu (Manrope en majuscules, interlettrage large) en
   texte rose, comme une grande signature posée sur la section. Un mot étant plus
   long qu'un chiffre, on le dimensionne plus sobrement pour qu'il reste lisible
   sans saturer la section. La teinte précise est posée par section ci-dessous. */
.section-number-bg--word {
	font-size: clamp(5rem, 16vw, 16rem);
	text-transform: uppercase;
	letter-spacing: 0.08em;
}

/* « constat » : texte rose soutenu ; « solution » (section 02) : rose pâle. */
.constat-section .section-number-bg--word {
	--num-color: var(--wp--preset--color--base-deux);
}

/* Filigrane FORME : une icône SVG géante en fond, fixée au scroll comme le
   filigrane texte. La div ne porte pas de texte : on l'habille d'un carré masqué
   par un SVG, dont la couleur est portée par background-color. Le masque garde le
   dessin net à toutes les tailles et permet de le teinter (un background-image ne
   se teinte pas). La forme et la teinte sont posées par les modificateurs --rose
   / --cyber ci-dessous. */
.section-number-bg--img {
	/* Carré géant, dans la même fourchette que le filigrane mot. */
	width: clamp(16rem, 42vw, 40rem);
	aspect-ratio: 1 / 1;
	/* Centrage horizontal : la div couvre toute la largeur (left:0/right:0,
	   width:100%) côté filigrane ; ici on la recadre en carré centré. */
	margin-inline: auto;
}

/* Les deux filigranes FORME sont volontairement très clairs : un rose pâle
   fortement translucide, pour rester en arrière-plan discret derrière le contenu.
   On agit sur l'alpha de la teinte (et non sur opacity) afin de ne pas écraser le
   fondu de lecture au scroll, qui module --mark-opacity par-dessus. */
.section-number-bg--rose,
.section-number-bg--cyber {
	background-color: color-mix(in srgb, var(--wp--preset--color--base-deux) 35%, transparent);
}

/* Section « Un constat » : la rose. */
.section-number-bg--rose {
	-webkit-mask: url("assets/images/Rose.svg") no-repeat center / contain;
	mask: url("assets/images/Rose.svg") no-repeat center / contain;
}

/* Section 02 « solution » : l'arobase (Cyber.svg). */
.section-number-bg--cyber {
	-webkit-mask: url("assets/images/Cyber.svg") no-repeat center / contain;
	mask: url("assets/images/Cyber.svg") no-repeat center / contain;
}

/* Section éditoriale de la home (.home-edito) : le picto Programming, en blanc
   translucide pour un filigrane discret. */
.section-number-bg--prog {
	background-color: color-mix(in srgb, var(--wp--preset--color--blanc) 60%, transparent);
	-webkit-mask: url("assets/images/Programming.svg") no-repeat center / contain;
	mask: url("assets/images/Programming.svg") no-repeat center / contain;
}

.is-section-02 .section-number-bg--word {
	/* Filigrane « solution » : exactement la même teinte que « constat » (le rose
	   pâle « base »). « constat » est en .is-section-01, dont la règle ci-dessous
	   pose --num-color: base ; on aligne donc « solution » sur la même valeur. */
	--num-color: var(--wp--preset--color--base);
}

/* Section 01 : filigrane dans le rose du hero (« base »), couleur pleine. */
.is-section-01 .section-number-bg { --num-color: var(--wp--preset--color--base); }

/* Petit label (« Un constat », « La solution ») qui remplace l'ancien
   bloc h2+p : on garde l'esthétique d'origine. */
.section-eyebrow {
	font-weight: 700;
	letter-spacing: 0.04em;
	text-transform: uppercase;
}

@media (max-width: 781px) {
	/* Sur mobile le filigrane reste mais plus contenu, pour ne pas déborder. */
	.section-number-bg {
		font-size: clamp(9rem, 42vw, 16rem);
	}

	.section-number-bg--word {
		font-size: clamp(3.5rem, 18vw, 7rem);
	}
}

/* ------------------------------------------------------------------ */
/* Sections pleine largeur accolées                                    */
/* ------------------------------------------------------------------ */
/* Le fond global de la page est rose (« base »). Entre deux sections  */
/* pleine largeur, le block-gap (1.2rem) laisse une bande de ce rose   */
/* qui se lit comme une grande ligne. On referme l'espace dès qu'une   */
/* section pleine largeur en suit une autre, pour que les fonds soient */
/* jointifs quelles que soient leurs couleurs. Le hero garde sa marge  */
/* négative (il remonte sous le header) : ce sélecteur ne vise que les */
/* sections *suivantes*, jamais la première.                           */
.entry-content > .wp-block-group.alignfull
	+ .wp-block-group.alignfull {
	margin-top: 0;
}

/* ------------------------------------------------------------------ */
/* Largeur de contenu unifiée des sections                             */
/* ------------------------------------------------------------------ */
/* Le thème a contentSize 1200px et wideSize 1320px (theme.json). Les   */
/* sections numérotées (constat, services) ont été passées à 1320px    */
/* dans l'éditeur, mais les sections de contenu standard restent à     */
/* 1200px : leur contenu, plus étroit et centré, démarre donc ~60px    */
/* plus à droite et casse l'alignement du bord gauche d'une section à   */
/* l'autre. On réaligne tout sur la largeur « wide » (1320px), qui sert */
/* déjà de référence au hero et aux sections numérotées.                */
/* Sélecteur volontairement spécifique (plusieurs classes + :not) pour  */
/* battre la règle inline de WordPress (.wp-container-...-is-layout-xxx  */
/* > :where(...) { max-width:1200px }) sans dépendre de son hash. Les    */
/* enfants alignwide/alignfull gardent leur propre largeur. */
.entry-content > .wp-block-group.alignfull.is-layout-constrained
	> :not(.alignwide):not(.alignfull):not(.alignleft):not(.alignright) {
	max-width: var(--wp--style--global--wide-size, 1320px);
}

/* ==========================================================================
   TEST — hero front rétréci + ferré à droite du viewport
   (bloc isolé, à retirer après le test)
   ----------------------------------------------------------------------- */
.hero-art {
	/* La grille .hero-art reste centrée dans 1320px : cette marge mesure la
	   distance entre le bord droit du conteneur et le bord droit de l'écran. */
	--hero-gutter: max(0px, (100vw - var(--wp--style--global--wide-size, 1320px)) / 2);
	/* Largeur souhaitée de l'image réduite (≈ ajuster pour le test). */
	--hero-front-w: clamp(11rem, 18vw, 20rem);
}

.hero-art__front {
	/* On sort le front de la grille et on le cale tout en haut à droite du
	   viewport, avec une marge égale en haut et à droite mesurée depuis les bords
	   de la fenêtre. À droite : .hero-art étant centré dans 1320px, on retranche la
	   gouttière. En haut : .hero-art réserve la hauteur du header via son
	   padding-top, on le retranche pour que la marge parte bien du haut de la
	   fenêtre. */
	position: absolute;
	top: calc(var(--wp--preset--spacing--40) - var(--header-h, 6.5rem));
	right: calc(var(--wp--preset--spacing--40) - var(--hero-gutter));
	left: auto;
	grid-column: auto; /* annule le placement en grille (9 / span 4) */
	width: var(--hero-front-w);
	margin: 0;
	/* Remontée à spacing-40 du haut de la fenêtre = dans la bande du header sticky
	   (z-index 100) : on passe l'image au-dessus pour qu'elle reste visible. */
	z-index: 101;
}

.hero-art__front img {
	width: 100%;
	height: auto;
	/* Cette image n'est pas désaturée (contrairement à l'image de gauche). */
	filter: none;
}

/* Image de gauche (back) : on la rallonge jusqu'au bord gauche du viewport.
   margin-left négatif de la gouttière = elle déborde du conteneur centré. */
.hero-art__back {
	margin-left: calc(-1 * var(--hero-gutter)) !important;
}

@media (max-width: 781px) {
	.hero-art__front {
		/* En mobile, on garde le front dans la grille comme avant. */
		position: static;
		right: auto;
		width: auto;
		grid-column: 6 / span 7;
	}

	.hero-art__back {
		/* En mobile, pas de débordement à gauche. */
		margin-left: 0 !important;
	}
}
/* ====================== /TEST hero front ============================== */

/* ====================== Sections interet / contact =================== */
/* La structure (deux colonnes) reste celle définie dans Gutenberg. On ne
   retouche ici que les paragraphes de contenu : largeur réduite, texte plus
   petit, marge au-dessus et apparition animée façon titres. */

/* Paragraphes : 65 % de la largeur de leur colonne, texte plus petit, et une
   marge au-dessus de chacun pour les aérer.
   Les !important sont nécessaires pour battre WordPress : la classe
   has-small-font-size pose la taille en !important, et l'éditeur a posé un
   margin-top:0 inline sur les paragraphes de #contact. */
#interet .wp-block-column p,
#contact .wp-block-column p {
	max-width: 65%;
	font-size: clamp(0.7rem, 0.78vw, 0.8rem) !important;
	margin-top: var(--wp--preset--spacing--50) !important;
	line-height: 1.8;
}

/* Bloc contact (home) : interlignage resserré par rapport à la section interet,
   qui garde le 1.8 ci-dessus. */
#contact .wp-block-column p {
	line-height: 1.5;
}

/* Apparition animée : le paragraphe remonte en place derrière un masque, comme
   les titres (.titre-reveal). L'état révélé (.is-revealed) est posé en JS par
   src/para-reveal.ts à l'entrée dans le viewport. */
.para-reveal {
	display: block;
	clip-path: inset(-5% 0 -5% 0);
}

.para-reveal > .para-reveal__inner {
	display: block;
	transform: translate3d(0, 110%, 0);
	opacity: 0;
	transition:
		transform 0.6s cubic-bezier(0.165, 0.84, 0.44, 1),
		opacity 0.6s cubic-bezier(0.165, 0.84, 0.44, 1);
	transition-delay: calc(var(--index, 0) * 0.1s);
}

.para-reveal.is-revealed > .para-reveal__inner {
	transform: translate3d(0, 0, 0);
	opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
	.para-reveal > .para-reveal__inner {
		transform: none;
		opacity: 1;
		transition: none;
	}
}
/* ====================== /Sections interet / contact ================== */

/* ====================== Point curseur ============================== */
/* Petit point corail qui suit la souris, créé et déplacé par src/cursor-dot.ts.
   Fixé à l'écran, au-dessus de tout, et transparent aux événements pour ne pas
   gêner les clics. Masqué tant que la souris n'a pas bougé (is-visible). */
.cursor-dot {
	position: fixed;
	top: 0;
	left: 0;
	z-index: 100000;
	width: 10px;
	height: 10px;
	border-radius: 50%;
	background-color: var(--wp--preset--color--accent, #ff3c34);
	pointer-events: none;
	opacity: 0;
	will-change: transform;
}

.cursor-dot.is-visible {
	opacity: 1;
}

/* Au survol des images de la section « constat », le point grossit et passe en
   mode contraste : mix-blend-mode difference inverse les pixels de l'image sous
   le rond, ce qui fait surgir une couleur de contraste vive là où il passe.
   Fond clair pour maximiser l'inversion. La taille est animée par transform
   (le déplacement utilise déjà translate3d, on ajoute scale en facteur). */
.cursor-dot {
	transition: opacity 0.2s ease, width 0.3s cubic-bezier(0.165, 0.84, 0.44, 1),
		height 0.3s cubic-bezier(0.165, 0.84, 0.44, 1),
		background-color 0.3s ease;
}

.cursor-dot.is-big {
	width: 90px;
	height: 90px;
	background-color: var(--wp--preset--color--blanc, #fff);
	mix-blend-mode: difference;
}

@media (prefers-reduced-motion: reduce) {
	.cursor-dot.is-big {
		width: 60px;
		height: 60px;
	}
}
/* Titres H2 : Manrope par défaut (hérité du body). Les mots mis en exergue par
   le gras (balise <strong> ou <b> posée par l'éditeur) passent en Stack Sans
   Notch, la même typo que le menu. */
h2 strong,
h2 b {
	font-family: "Stack Sans Notch", var(--wp--preset--font-family--manrope), sans-serif;
}

/* Pré-titre : petite étiquette posée au-dessus d'un titre. Même typo que le
   menu (Stack Sans Notch), corps très petit, interlettrage légèrement aéré. */
.pretitre {
	font-family: "Stack Sans Notch", var(--wp--preset--font-family--manrope), sans-serif;
	font-size: 0.7rem;
	letter-spacing: 0.08em;
	text-align: left;
}

/* ----------------------------------------------------------------------------
   Gabarit de section commun à toutes les pages (filet de sécurité).
   Donne à chaque section pleine largeur du contenu d'une page le même rythme
   vertical que les sections de la home (padding haut/bas = spacing-70), pour que
   toute page — y compris une page future créée sans réglage manuel — hérite
   automatiquement de la « grille » du site.

   Exclusions :
   - .hero / .index-projets : composants qui gèrent déjà leur propre espacement ;
   - .section-numbered : sections home avec leur filigrane et padding propres ;
   - [style*="padding-top"] : section qui porte déjà un padding inline (celles
     qu'on a posées sur services et contact), pour ne pas le doubler.
---------------------------------------------------------------------------- */
.entry-content > .wp-block-group.alignfull:not(.hero):not(.index-projets):not(.section-numbered):not([style*="padding-top"]),
.entry-content > section.wp-block-group.alignfull:not(.hero):not(.index-projets):not(.section-numbered):not([style*="padding-top"]) {
	padding-top: var(--wp--preset--spacing--70);
	padding-bottom: var(--wp--preset--spacing--70);
}

/* ====================== Formulaire de contact ======================= */
/* Le formulaire est un bloc HTML brut (Formspree), sans classe propre : on le
   cible par son attribut action. Rien de spectaculaire ici, juste de quoi
   aligner les champs sur la typo et les couleurs du reste du site. */
form[action*="formspree"] {
	max-width: 520px;
	margin-top: var(--wp--preset--spacing--50);
}

/* Les <label> portent le texte « Votre email : » / « Votre message : ».
   On les passe en bloc pour empiler proprement libellé puis champ. */
form[action*="formspree"] label {
	display: block;
	margin-bottom: 1.25rem;
	font-size: 0.95rem;
	font-weight: 600;
	color: #16202c;
}

/* Les <br/> du markup brut servaient à espacer ; on les neutralise, c'est la
   marge des labels qui gère l'espacement maintenant. */
form[action*="formspree"] > br {
	display: none;
}

form[action*="formspree"] input,
form[action*="formspree"] textarea {
	width: 100%;
	margin-top: 0.4rem;
	padding: 0.7rem 0.85rem;
	font-family: inherit;
	font-size: 1rem;
	font-weight: 400;
	color: #16202c;
	background: #ffffff;
	border: 1px solid #f8d7d7;
	border-radius: 6px;
	transition: border-color 0.15s ease;
}

form[action*="formspree"] textarea {
	min-height: 150px;
	resize: vertical;
}

form[action*="formspree"] input:focus,
form[action*="formspree"] textarea:focus {
	border-color: #FF3C34;
}

/* Bouton repris sur le style des boutons du thème (gris -> corail au survol),
   défini ici en dur car ce <button> brut n'a pas la classe wp-block-button. */
form[action*="formspree"] button[type="submit"] {
	padding: 0.85rem 1.6rem;
	font-family: inherit;
	font-size: 1.0625rem;
	font-weight: 600;
	color: #fce7e7;
	background: #16202c;
	border: none;
	border-radius: 6px;
	cursor: pointer;
	transition: background-color 0.15s ease;
}

form[action*="formspree"] button[type="submit"]:hover {
	background: #FF3C34;
}
/* ====================== /Formulaire de contact ====================== */

/* ====================== Grille de debug ============================ */
/* Lignes de colonnes (1px), activées par body.grid-debug (ajoutée via ?grid
   dans l'URL — voir functions.php). Overlay fixé au viewport : comme les
   colonnes sont identiques sur toute la hauteur, des lignes fixées au viewport
   donnent les mêmes X qu'une grille pleine page, et restent visibles sur toutes
   les sections quand on scrolle (insensible à Locomotive Scroll).
   12 colonnes calées sur la largeur de contenu (1200px), centrées. Chaque trait
   marque un BORD de colonne, pour comparer la position des blocs au pixel près.
   Désactivé par défaut : aucun impact sans ?grid. */
.grid-debug::before {
	content: "";
	position: fixed;
	top: 0;
	bottom: 0;
	left: 50%;
	transform: translateX(-50%);
	z-index: 2147483647;
	pointer-events: none;
	/* Bande de contenu centrée (1200px, ou pleine largeur moins les marges). */
	width: min(1200px, calc(100% - 64px));
	/* Pas d'une colonne + sa gouttière. Comme largeur = 12·col + 11·gutter,
	   on a (col + gutter) = (largeur + gutter) / 12. On trace, à chaque pas, le
	   bord GAUCHE (trait 1px) puis le bord DROIT de la colonne (trait 1px), le
	   reste transparent -> on voit les deux côtés de chaque colonne. */
	background-image: repeating-linear-gradient(
		to right,
		rgba(255, 60, 52, 0.55) 0,
		rgba(255, 60, 52, 0.55) 1px,
		transparent 1px,
		transparent calc((100% - 11 * 24px) / 12),
		rgba(255, 60, 52, 0.55) calc((100% - 11 * 24px) / 12),
		rgba(255, 60, 52, 0.55) calc((100% - 11 * 24px) / 12 + 1px),
		transparent calc((100% - 11 * 24px) / 12 + 1px),
		transparent calc((100% + 24px) / 12)
	);
	/* Filet 1px sur les bords extérieurs gauche/droite de la zone de contenu. */
	border-left: 1px solid rgba(255, 60, 52, 0.55);
	border-right: 1px solid rgba(255, 60, 52, 0.55);
}
