/*
 * Regles communes a toutes les compositions.
 * Engagement 5 : aucun hexadecimal, valeurs de repli comprises.
 */

:where([data-ivy-reveal]) {
	will-change: transform, opacity;
}

/*
 * Le conteneur Elementor est l'autorite de largeur par defaut. Le controle
 * Section d'ivypress peut ensuite reduire la boite du widget sans peindre son
 * fond. margin-inline:auto ne change rien a 100 %, mais centre une mesure plus
 * etroite choisie par l'editeur.
 */
.ivy-root {
	box-sizing: border-box;
	margin-inline: auto;
}

/*
 * Les compositions ne reduisent jamais leur titre ou leur texte principal
 * avec une mesure arbitraire en ch : ils occupent toute la largeur disponible
 * de leur parent. Le !important ne porte QUE sur la borne historique des
 * compositions ; le controle responsive continue de regler inline-size
 * librement.
 */
.ivy-root :is( h1, h2, [class$="__title"], [class*="__title "], [class$="__text"], [class*="__text "] ) {
	align-self: stretch;
	inline-size: 100%;
	max-inline-size: 100% !important;
	min-inline-size: 0;
	/*
	 * `break-word` et non `anywhere`. Les deux coupent un mot trop long pour
	 * sa ligne — la protection contre le debordement est identique. Ils ne
	 * different que sur la taille MIN-CONTENT, et l'ecart est brutal : mesure
	 * sur un titre de hero a 76,8 px, `anywhere` donne une largeur minimale de
	 * **50 px**, soit un caractere, la ou `break-word` garde les **378 px** du
	 * mot entier.
	 *
	 * Tout conteneur qui se dimensionne sur min-content — piste de grille
	 * `auto`, boite en shrink-to-fit, cellule de tableau — effondre donc le
	 * titre a une lettre et empile le mot verticalement. C'est le defaut
	 * mesure sur le pilote Casoria : un titre de `hero/fendu` a **438 px de
	 * large pour 650 px de haut, sept lignes**, dans une colonne qui lui en
	 * offrait 640.
	 *
	 * Les trois declarations voisines (inline-size, max-inline-size,
	 * align-self) compensaient ce defaut sans le corriger : elles ne peuvent
	 * rien quand c'est le PARENT qui se dimensionne sur son contenu.
	 */
	overflow-wrap: break-word;
	text-wrap: pretty;
}

/*
 * LE CORPS EDITORIAL EST UNE BOITE, PAS UN PARAGRAPHE. `WidgetBase::rich_text()`
 * passe le corps a wpautop : la boite `__text` recoit donc des <p>.
 *
 * UNE SEULE des deux marges a besoin de cette regle, et c'est mesure :
 * `reset.css` de Hello Elementor pose `p { margin: 0 0 0.9rem }`. Le haut vaut
 * donc DEJA zero — une garde `:first-child` a ete ecrite ici puis retiree,
 * sabotage a l'appui : elle ne changeait rien. Le bas, lui, vaut **14,4 px**,
 * et il s'ajoute a la marge que la composition a choisie pour sa boite.
 *
 * `[class$="__text"]` ne touche PAS `ivy-services__item-text` : cette classe
 * finit par `-text`, pas par `__text`. Les textes de carte restent echappes,
 * et c'est le contrat.
 */
.ivy-root :is( [class$="__text"], [class*="__text "] ) > :last-child {
	margin-block-end: 0;
}

/*
 * LE BAS DU MARQUEUR EST LA POINTE. Le runtime ancre le marqueur sur le bas de
 * sa boite (`ivy-map.js`), donc l'epingle doit s'y poser — sinon une goutte
 * pointerait a cote du lieu qu'elle designe. La regle est ici et non dans les
 * feuilles de produit : c'est le pendant CSS d'un contrat de runtime, et les
 * trois produits du rayon le partagent. Leaflet impose ses propres marges sur
 * `.leaflet-marker-icon` ; on ne touche qu'a la mise en place interne.
 */
/*
 * `.leaflet-marker-icon` A LA MEME SPECIFICITE ET SE CHARGE APRES. La feuille
 * de Leaflet pose `display: block` en 0-1-0 sur cette classe ; une regle a
 * `.ivy-map__marker` seul pesait autant et perdait a l'ordre. Mesure : le
 * `place-items` s'appliquait, le `display` non, donc l'epingle restait en haut
 * de sa boite et sa pointe tombait 12 px sous le lieu. Les deux classes
 * ensemble pesent 0-2-0 et gagnent quel que soit l'ordre de chargement.
 */
.ivy-map__marker.leaflet-marker-icon {
	display: grid;
	place-items: end center;
	/*
	 * Leaflet habille ses marqueurs par defaut. La neutralisation vivait dans
	 * la feuille de `zone-intervention`, SANS cadrage sous sa racine : elle
	 * servait donc les trois produits par accident. Elle est ici parce qu'elle
	 * vaut pour les trois par CONTRAT.
	 */
	border: 0 !important;
	background: transparent !important;
}

/* Un en-tete de section ne doit pas redecouper la largeur avant son titre. */
.ivy-root > header,
.ivy-root > [class*="__inner"] > header {
	inline-size: 100%;
	max-inline-size: 100% !important;
}

/*
 * Le pendant, pour les proprietes RECUES, de la regle de cadrage sous classe
 * racine : cadrer sous .ivy-* protege de ce qu'on emet, pas de ce qu'on recoit.
 *
 * Un reset tiers qui pose `button { white-space: nowrap }` est courant, et
 * aucune de nos feuilles ne le voit venir. Mesure du pilote Casoria en 390 px :
 * le libelle d'une question occupait 441 px dans une rangee de 330, l'icone se
 * posait a 507, et le DOCUMENT ENTIER passait a 507 px — trois pages sur cinq
 * defilaient lateralement sur mobile. Les deux pages saines etaient exactement
 * celles sans FAQ.
 *
 * Specificite 0-1-1 : gagne contre le `button` nu d'un reset quel que soit
 * l'ordre de chargement, et perd contre n'importe quelle regle de composition
 * (0-2-0 au minimum). Une composition qui veut vraiment `nowrap` sur un bouton
 * — un libelle masque en screen-reader-text, par exemple — garde donc le
 * dernier mot sans rien declarer de special.
 */
.ivy-root button {
	white-space: normal;
}

/*
 * Geometrie critique de portal. Elementor peut demander la feuille du produit
 * apres le premier rendu ; sans cette reservation dans le socle, son image
 * passe brievement dans le flux puis devient absolue, ce que Lighthouse voit
 * par intermittence comme un CLS de 0,369. Le core ne decide ici ni couleur,
 * ni clip, ni mouvement : seulement la place necessaire avant l'asset tardif.
 */
.ivy-root.ivy-hero--portal {
	position: relative;
	min-block-size: 100svh;
	overflow: hidden;
}

.ivy-hero--portal .ivy-hero__frame,
.ivy-hero--portal .ivy-hero__media {
	position: absolute;
	inset: 0;
}

.ivy-hero--portal .ivy-hero__image {
	display: block;
	inline-size: 100%;
	block-size: 100%;
	object-fit: cover;
}

/*
 * Geometrie critique de l'ouverture video. Le produit reserve son parcours
 * avant l'arrivee de sa feuille afin que la video ne saute pas du flux vers
 * son plan sticky. Le core ne peint ni le fond, ni le masque : ces choix
 * restent ceux de la composition et du theme Elementor.
 */
.ivy-root.ivy-hero--ouverture {
	--ivy-opening-stage: var( --ivy-hero-min-height, 100vh );

	position: relative;
	min-block-size: calc( max( 100svh, var( --ivy-opening-stage ) ) + 760px );
}

.ivy-hero--ouverture .ivy-hero__stage {
	position: sticky;
	top: 0;
	min-block-size: var( --ivy-opening-stage );
	overflow: hidden;
}

.ivy-hero--ouverture .ivy-hero__frame,
.ivy-hero--ouverture .ivy-hero__media {
	position: absolute;
	inset: 0;
}

.ivy-root.ivy-hero--ouverture-static {
	min-block-size: var( --ivy-opening-stage );
}

/* Les barres fixes quittent le flux avant le chargement de leur peau. Sans
 * cette seule regle structurelle, leur conteneur Elementor peut reserver une
 * page entiere puis la rendre au hero lorsque l'asset du produit arrive. */
.ivy-root:is( .ivy-navbar--pilule, .ivy-navbar--voile ) {
	position: fixed;
	inset-inline: 0;
	top: 0;
	z-index: 100;
}

/* Reservation mobile de la pilule : le burger ne doit pas traverser la
 * largeur de l'ecran pendant que la feuille du produit arrive. */
@media ( max-width: 991px ) {
	.ivy-navbar--pilule .ivy-navbar__stage {
		min-block-size: var( --ivy-navbar-h, 104px );
	}

	.ivy-navbar--pilule .ivy-navbar__inner {
		display: flex;
		align-items: center;
		min-block-size: inherit;
		padding-inline: var( --ivy-navbar-pad, clamp( 16px, 2.5vw, 40px ) );
	}

	.ivy-navbar--pilule .ivy-navbar__collapse {
		display: flex;
		align-items: center;
		margin-inline-start: auto;
	}

	.ivy-navbar--pilule .ivy-navbar__burger {
		display: inline-flex;
		inline-size: 44px;
		block-size: 44px;
	}
}

/* Les mots animes doivent etre des boites transformables sans imposer de
 * masque ou de largeur : le texte reste entier, y compris sur une ligne
 * tres longue dans l'editeur. */
.ivy-split-word,
.ivy-split-char {
	display: inline-block;
	will-change: transform, opacity;
}

.ivy-split-word {
	white-space: nowrap;
}

/* Un label peut devenir un titre semantique sans recuperer les marges UA. */
:where(.ivy-root.ivy-hero) .ivy-hero__eyebrow {
	margin-top: 0;
}

/*
 * Etat initial des elements a reveler. Applique uniquement quand le
 * runtime a pris la main (classe posee par le JS), pour qu'une page sans
 * JavaScript affiche tout son contenu au lieu de rester vide.
 */
.ivy-motion-ready :where([data-ivy-reveal]) {
	opacity: 0;
}

/*
 * Le verrou de defilement du tiroir. Le runtime pose la classe, le CSS decide
 * de ce qu'elle fait — la frontiere vaut ici comme ailleurs.
 *
 * scrollbar-gutter: stable a ete essayee ici puis retiree. Sur un navigateur
 * de bureau, poser overflow: hidden fait disparaitre la barre, la hauteur
 * defilable diminue, et le navigateur reclampe la position a la premiere
 * interaction : 24 px de derive, mesures. La propriete ne changeait RIEN a
 * cette derive — meme valeur avec et sans. Une ligne qui ne fait pas ce que
 * son commentaire annonce vaut moins que pas de ligne.
 *
 * La derive ne se produit pas la ou le tiroir vit vraiment : sous 991 px les
 * barres sont en surimpression, et la mesure y donne zero.
 */
html.ivy-locked {
	overflow: hidden;
}

@media ( prefers-reduced-motion: reduce ) {
	.ivy-root.ivy-hero--ouverture {
		min-block-size: var( --ivy-opening-stage );
	}

	.ivy-hero--ouverture .ivy-hero__stage {
		position: relative;
	}

	/*
	 * Engagement 8. Le !important est deliberе : une regle de composition
	 * plus specifique battrait sinon cette neutralisation, et le defaut
	 * serait invisible tant que personne ne teste avec le reglage actif.
	 */
	.ivy-motion-ready :where([data-ivy-reveal]) {
		opacity: 1 !important;
		transform: none !important;
		transition: none !important;
		animation: none !important;
	}

	/*
	 * Engagement 8, lu pour un effet FONCTIONNEL. Contrairement a une
	 * revelation, l'etat au defilement ne peut pas etre simplement
	 * neutralise : une barre transparente coincee au-dessus du contenu,
	 * c'est du texte illisible. Le runtime pose donc la classe quand meme,
	 * et c'est ici que tombe la seule chose qui doit tomber — la
	 * transition. Le descendant est vise aussi : ce sont les couleurs des
	 * enfants qui portent l'essentiel de la bascule.
	 */
	.ivy-motion-ready :where([data-ivy-stick]),
	.ivy-motion-ready :where([data-ivy-stick]) *,
	.ivy-motion-ready :where([data-ivy-scroll-reveal]),
	.ivy-motion-ready :where([data-ivy-scroll-reveal]) *,
	.ivy-motion-ready :where([data-ivy-disclose]),
	.ivy-motion-ready :where([data-ivy-disclose]) * {
		transition: none !important;
	}

	:where(.ivy-root) video {
		display: none !important;
	}
}

/*
 * LE DEFILEMENT DOUX — les deux seules regles qu'il exige du socle.
 *
 * Engagement 7 amende le 19 aout : Lenis est mis en file sur toutes les pages
 * publiques. Sa feuille officielle en porte cinq regles ; DEUX SONT REPRISES
 * ICI et les trois autres volontairement laissees de cote, plutot que de
 * vendre un fichier tiers qu'il faudrait ensuite modifier :
 *
 * - `html.lenis` a `height: auto` : sans elle, un theme qui pose une hauteur
 *   de 100 % sur html ou body prive le lissage de sa course.
 * - `overscroll-behavior: contain` sur les zones qui demandent a etre
 *   exclues : c'est le seul moyen de rendre un panneau defilant a lui-meme.
 *
 * LA REGLE ECARTEE, et pourquoi elle compte : la feuille officielle pose
 * `pointer-events: none` sur TOUT iframe des que le lissage est actif — et il
 * l'est en permanence chez nous. Une video YouTube, une carte embarquee ou un
 * formulaire tiers deviendraient definitivement inutilisables sur chaque page
 * du site. Le prix de son absence est connu et bien moindre : le defilement
 * n'est pas lisse quand le pointeur survole un iframe.
 */
html.lenis,
html.lenis body {
	height: auto;
}

.lenis [data-lenis-prevent] {
	overscroll-behavior: contain;
}

/* --- ECHELLE TYPOGRAPHIQUE — genere par bin/build-type-scale.php --- */
/*
 * UNE taille par role et par site pour le texte non semantique. Les
 * balises H1-H6 reprennent directement la typographie du theme et du kit
 * Elementor ; une composition ne leur impose aucun role de taille.
 */
:root {
	--ivy-font-display: calc( 2.5rem * var( --ivy-text-scale, 1 ) );
	--ivy-font-h1: calc( 2.1875rem * var( --ivy-text-scale, 1 ) );
	--ivy-font-h2: calc( 2.1875rem * var( --ivy-text-scale, 1 ) );
	--ivy-font-h3: calc( 1.5625rem * var( --ivy-text-scale, 1 ) );
	--ivy-font-h4: calc( 1.25rem * var( --ivy-text-scale, 1 ) );
	--ivy-font-h5: calc( 1.125rem * var( --ivy-text-scale, 1 ) );
	--ivy-font-h6: calc( 1rem * var( --ivy-text-scale, 1 ) );
	--ivy-font-body: calc( 1rem * var( --ivy-text-scale, 1 ) );
	--ivy-font-lead: calc( 1.25rem * var( --ivy-text-scale, 1 ) );
	--ivy-font-label: calc( 0.8125rem * var( --ivy-text-scale, 1 ) );
	--ivy-font-figure: calc( 2.5rem * var( --ivy-text-scale, 1 ) );
	--ivy-font-marquee: calc( 0.875rem * var( --ivy-text-scale, 1 ) );
	--ivy-font-step: calc( 2rem * var( --ivy-text-scale, 1 ) );
}

@media ( min-width: 768px ) {
	:root {
		--ivy-font-display: calc( 3.5rem * var( --ivy-text-scale, 1 ) );
		--ivy-font-h1: calc( 2.5rem * var( --ivy-text-scale, 1 ) );
		--ivy-font-h2: calc( 2.1875rem * var( --ivy-text-scale, 1 ) );
		--ivy-font-h3: calc( 1.5625rem * var( --ivy-text-scale, 1 ) );
		--ivy-font-h4: calc( 1.375rem * var( --ivy-text-scale, 1 ) );
		--ivy-font-h5: calc( 1.25rem * var( --ivy-text-scale, 1 ) );
		--ivy-font-h6: calc( 1.125rem * var( --ivy-text-scale, 1 ) );
		--ivy-font-body: calc( 1rem * var( --ivy-text-scale, 1 ) );
		--ivy-font-lead: calc( 1.25rem * var( --ivy-text-scale, 1 ) );
		--ivy-font-label: calc( 0.8125rem * var( --ivy-text-scale, 1 ) );
		--ivy-font-figure: calc( 3.25rem * var( --ivy-text-scale, 1 ) );
		--ivy-font-marquee: calc( 0.9375rem * var( --ivy-text-scale, 1 ) );
		--ivy-font-step: calc( 2.5rem * var( --ivy-text-scale, 1 ) );
	}
}

@media ( min-width: 1025px ) {
	:root {
		--ivy-font-display: calc( 4.5rem * var( --ivy-text-scale, 1 ) );
		--ivy-font-h1: calc( 2.8125rem * var( --ivy-text-scale, 1 ) );
		--ivy-font-h2: calc( 2.8125rem * var( --ivy-text-scale, 1 ) );
		--ivy-font-h3: calc( 1.875rem * var( --ivy-text-scale, 1 ) );
		--ivy-font-h4: calc( 1.5625rem * var( --ivy-text-scale, 1 ) );
		--ivy-font-h5: calc( 1.25rem * var( --ivy-text-scale, 1 ) );
		--ivy-font-h6: calc( 1.125rem * var( --ivy-text-scale, 1 ) );
		--ivy-font-body: calc( 1rem * var( --ivy-text-scale, 1 ) );
		--ivy-font-lead: calc( 1.25rem * var( --ivy-text-scale, 1 ) );
		--ivy-font-label: calc( 0.8125rem * var( --ivy-text-scale, 1 ) );
		--ivy-font-figure: calc( 4rem * var( --ivy-text-scale, 1 ) );
		--ivy-font-marquee: calc( 1rem * var( --ivy-text-scale, 1 ) );
		--ivy-font-step: calc( 3rem * var( --ivy-text-scale, 1 ) );
	}
}

/* Plancher du texte non gouverne par les titres du theme. */
.ivy-root {
	font-size: var( --ivy-font-body );
}

.ivy-root p,
.ivy-root li,
.ivy-root dd,
.ivy-root dt {
	font-size: var( --ivy-font-body );
}

.ivy-root :is(
	[class*='__cta'],
	[class*='__label'],
	[class*='__tab'],
	[class*='__badge'],
	[class*='__eyebrow']
) {
	font-size: var( --ivy-font-label );
}

/* --- fin de l'echelle typographique --- */

/* Une balise de titre suit le kit. Si le client choisit `p` pour un titre
 * visuel, le role du catalogue reste son repli sans concurrencer H1-H6. */
.ivy-root [class$='__title']:not(:is( h1, h2, h3, h4, h5, h6 )) {
	font-size: var( --ivy-font-h2 );
}

.ivy-root [class$='-title']:not(:is( h1, h2, h3, h4, h5, h6 )) {
	font-size: var( --ivy-font-h3 );
}

.ivy-root.ivy-hero .ivy-hero__title:not(:is( h1, h2, h3, h4, h5, h6 )) {
	font-size: var( --ivy-font-display );
}

/* Les CTA portent aussi `.elementor-button` : le kit gouverne leur marque,
 * les compositions ne gardent que leur placement et leur geste. */
.ivy-root .ivy-button {
	min-block-size: 44px;
	cursor: pointer;
}

.ivy-services .ivy-services__actions {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 12px;
	margin-block-start: clamp( 28px, 4vw, 48px );
}

.ivy-root .ivy-button--icon {
	position: relative;
	overflow: hidden;
	isolation: isolate;
	padding-inline-end: max( 3.5em, var( --ivy-button-icon-room, 3.5em ) );
}

.ivy-root .ivy-button--icon :is( .ivy-cta__cta-label, .ivy-intro__cta-label ) {
	position: relative;
	z-index: 1;
	transition: translate calc( 260ms * var( --ivy-motion, 1 ) ) cubic-bezier( .2, .8, .2, 1 );
}

.ivy-root .ivy-button--icon :is( .ivy-cta__cta-icon, .ivy-intro__cta-icon ) {
	position: absolute;
	z-index: 0;
	inset-block-start: 50%;
	inset-inline-end: .3em;
	display: grid;
	inline-size: 2.5em;
	block-size: 2.5em;
	place-items: center;
	border-radius: var( --ivy-radius-action, 999px );
	background: var( --ivy-surface, rgb( 255 255 255 ) );
	color: var( --ivy-cta_icon-color, var( --ivy-ink, rgb( 17 17 17 ) ) );
	translate: 0 -50%;
	transition: inset-inline-end calc( 260ms * var( --ivy-motion, 1 ) ) cubic-bezier( .2, .8, .2, 1 ), rotate calc( 260ms * var( --ivy-motion, 1 ) ) cubic-bezier( .2, .8, .2, 1 ), scale calc( 140ms * var( --ivy-motion, 1 ) ) ease;
}

.ivy-root .ivy-button--icon :is( .ivy-cta__cta-icon, .ivy-intro__cta-icon ) svg {
	inline-size: 1em;
	block-size: 1em;
	fill: currentColor;
}

.ivy-root .ivy-button--icon:focus-visible :is( .ivy-cta__cta-label, .ivy-intro__cta-label ) {
	translate: 2.75em 0;
}

.ivy-root .ivy-button--icon:focus-visible :is( .ivy-cta__cta-icon, .ivy-intro__cta-icon ) {
	inset-inline-end: calc( 100% - 2.8em );
	rotate: 45deg;
}

@media ( hover: hover ) {
	.ivy-root .ivy-button--icon:hover :is( .ivy-cta__cta-label, .ivy-intro__cta-label ) {
		translate: 2.75em 0;
	}

	.ivy-root .ivy-button--icon:hover :is( .ivy-cta__cta-icon, .ivy-intro__cta-icon ) {
		inset-inline-end: calc( 100% - 2.8em );
		rotate: 45deg;
	}
}

.ivy-root .ivy-button--icon:active :is( .ivy-cta__cta-icon, .ivy-intro__cta-icon ) {
	scale: .95;
}

@media ( prefers-reduced-motion: reduce ) {
	.ivy-root .ivy-button--icon :is( .ivy-cta__cta-label, .ivy-intro__cta-label ),
	.ivy-root .ivy-button--icon :is( .ivy-cta__cta-icon, .ivy-intro__cta-icon ) {
		transition: none;
	}
}
