/**
 * Tamriya Shahad
 *
 * theme.json porte les couleurs, les polices, les tailles et les espacements.
 * Ce fichier ne contient que ce que son schéma ne couvre pas.
 *
 * Jetons disponibles :
 *   --wp--preset--color--*        base, contrast, primary, secondary, tertiary, accent
 *   --wp--preset--font-family--*  display, body, arabic
 *   --wp--preset--spacing--*      20 à 70
 *   --ts-or-*, --ts-rose-*        tons de marque, définis dans theme.json
 *
 * Les variantes de styles/ redéfinissent tous ces jetons. Aucune couleur ne
 * doit être écrite en dur dans ce fichier.
 */

/* ==========================================================================
   Réglages
   ========================================================================== */

:root {
	--ts-ar-interligne: 1.9;
	--ts-ar-interligne-titre: 1.45;
	--ts-gap-bloc: clamp(1.3rem, 3.4vh, 2.6rem);
	--ts-gap-ligne: clamp(0.65rem, 1.7vh, 1.2rem);
	--ts-gap-serre: clamp(0.3rem, 0.9vh, 0.6rem);

	--ts-courbe: cubic-bezier(0.22, 1, 0.36, 1);
	--ts-duree: 0.8s;
	--ts-distance: 34px;
	/* Hauteur de la barre d'en-tête une fois le logotype resserré, au
	   défilement. Les pages qui calent un élément sous l'en-tête collant
	   s'en servent. */
	--ts-entete-hauteur: 5.5rem;
	--ts-logo-compact: 4.25rem;
	--ts-voile-entete: color-mix(
		in srgb,
		var(--wp--preset--color--base) 72%,
		transparent
	);

	/* Grain très léger posé sur les fonds dégradés, pour qu'ils ne fassent
	   pas aplat numérique. */
	--ts-bruit: url("data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20width=%22140%22%20height=%22140%22%3E%3Cfilter%20id=%22g%22%3E%3CfeTurbulence%20type=%22fractalNoise%22%20baseFrequency=%220.86%22%20numOctaves=%224%22%20stitchTiles=%22stitch%22/%3E%3CfeColorMatrix%20type=%22saturate%22%20values=%220%22/%3E%3C/filter%3E%3Crect%20width=%22140%22%20height=%22140%22%20filter=%22url(%23g)%22%20opacity=%220.052%22/%3E%3C/svg%3E");

	/* Dégradé de la page de lancement, réutilisé comme fond de tout le site.
	   Ses ingrédients sont définis dans theme.json, et le mode sombre
	   (assets/modes/sombre.json) en donne la version aux clartés inversées. */
	--ts-fond-montant:
		var(--ts-bruit),
		radial-gradient(76% 46% at 50% -6% in oklab, color-mix(in srgb, var(--ts-fond-rehaut) 30%, var(--wp--preset--color--base)) 0%, transparent 62%),
		radial-gradient(78% 62% at 84% 108% in oklab, color-mix(in srgb, var(--ts-fond-rose) 46%, var(--wp--preset--color--tertiary)) 0%, transparent 74%),
		linear-gradient(174deg in oklab, color-mix(in srgb, var(--ts-fond-rehaut) 22%, var(--wp--preset--color--base)) 0%, var(--wp--preset--color--base) 22%, color-mix(in srgb, var(--ts-fond-chaleur) 5%, var(--wp--preset--color--tertiary)) 44%, color-mix(in srgb, var(--ts-fond-chaleur) 12%, var(--wp--preset--color--tertiary)) 62%, color-mix(in srgb, var(--ts-fond-chaleur) 20%, var(--wp--preset--color--tertiary)) 80%, color-mix(in srgb, var(--ts-fond-rose) 50%, var(--wp--preset--color--tertiary)) 100%);
	--ts-fond-montant-tailles: 140px 140px, cover, cover, cover;
	--ts-fond-montant-repetitions: repeat, no-repeat, no-repeat, no-repeat;

	/* Filets de la grille et aplat du récit. Tous dérivés des jetons de
	   marque : les variantes de styles/ les recolorent avec le reste. */
	--ts-filet: color-mix(
		in oklab,
		var(--wp--preset--color--contrast) 14%,
		transparent
	);
	--ts-filet-fort: color-mix(
		in oklab,
		var(--wp--preset--color--contrast) 26%,
		transparent
	);
	--ts-filet-rose: color-mix(in oklab, var(--ts-rose-texte) 26%, transparent);

	/* Boutons. Le ressort dépasse sa cible puis revient : c'est lui qui donne
	   au relâchement d'une pression son côté physique. */
	--ts-ressort: cubic-bezier(0.34, 1.56, 0.64, 1);
	--ts-bouton-hauteur: 3.25rem;

	/* Verre dépoli des commandes. Le fond suit le mode actif, puisqu'il part
	   de la couleur de base, teintée d'un soupçon de rose ; le reflet et
	   l'ombre sont des jetons de theme.json, parce qu'un reflet reste clair et
	   une ombre reste sombre dans les deux modes. */
	--ts-verre-teinte: color-mix(
		in srgb,
		var(--wp--preset--color--base) 86%,
		var(--ts-rose-decor)
	);
	--ts-verre: color-mix(in srgb, var(--ts-verre-teinte) 46%, transparent);
	--ts-verre-dense: color-mix(in srgb, var(--ts-verre-teinte) 82%, transparent);
	--ts-verre-flou: blur(16px) saturate(1.5);
	--ts-verre-ombre: 0 12px 32px -14px
		color-mix(in srgb, var(--ts-ombre) 42%, transparent);
}

/* ==========================================================================
   Fond de page
   ========================================================================== */

/* Le dégradé de la page de lancement habille tout le site. Il est fixé à
   l'écran et non à la page : chaque écran montre le même passage du crème au
   rose, comme la page de lancement, au lieu d'étirer le dégradé sur trois
   mille pixels où le rose n'apparaîtrait qu'au pied de page.
   Un pseudo-élément fixe plutôt que background-attachment: fixed, que Safari
   sur iOS ignore. */
body {
	background-color: var(--wp--preset--color--base);
}

body::before {
	content: "";
	position: fixed;
	inset: 0;
	z-index: -1;
	background-image: var(--ts-fond-montant);
	background-size: var(--ts-fond-montant-tailles);
	background-repeat: var(--ts-fond-montant-repetitions);
	pointer-events: none;
}

/* ==========================================================================
   En-tête
   ========================================================================== */

/* C'est l'enveloppe de la partie de modèle qui colle en haut de l'écran : le
   groupe qu'elle contient n'est pas plus haut qu'elle et ne glisserait pas. */
.wp-site-blocks > header.wp-block-template-part {
	position: sticky;
	inset-block-start: 0;
	z-index: 50;
}

.admin-bar .wp-site-blocks > header.wp-block-template-part {
	inset-block-start: var(--wp-admin--admin-bar--height, 32px);
}

/* Sous 600 px, la barre d'administration défile avec la page. */
@media (max-width: 600px) {
	.admin-bar .wp-site-blocks > header.wp-block-template-part {
		inset-block-start: 0;
	}
}

/* Le fond et son flou vivent sur un pseudo-élément. Posé sur l'en-tête
   lui-même, backdrop-filter en ferait le cadre des éléments fixes qu'il
   contient : le menu plein écran du téléphone serait enfermé dans la barre.
   Le fond se choisit dans Réglages, Tamriya Shahad (classes ts-fond-entete-*
   posées sur body). */
.ts-entete {
	--ts-entete-fond: var(--ts-voile-entete);
	--ts-entete-filet: var(--ts-filet);
	position: relative;
	isolation: isolate;

	&::before {
		content: "";
		position: absolute;
		inset: 0;
		z-index: -1;
		border-block-end: 1px solid var(--ts-entete-filet);
		background-color: var(--ts-entete-fond);
		-webkit-backdrop-filter: var(--ts-verre-flou);
		backdrop-filter: var(--ts-verre-flou);
	}
}

.ts-fond-entete-rose .ts-entete {
	--ts-entete-fond: color-mix(in srgb, var(--ts-pied-fond) 90%, transparent);
	--ts-entete-filet: var(--ts-filet-rose);
}

/* Capsule : la barre se détache du bord et flotte sur la page, en verre. */
.ts-fond-entete-capsule .ts-entete {
	padding-block-start: var(--wp--preset--spacing--20);

	&::before {
		content: none;
	}

	& .ts-entete__barre {
		position: relative;
		isolation: isolate;
		padding-inline: var(--wp--preset--spacing--30) var(--wp--preset--spacing--20);

		&::before {
			content: "";
			position: absolute;
			inset: 0;
			z-index: -1;
			border: 1px solid var(--ts-verre-reflet);
			border-radius: 999px;
			background-color: var(--ts-verre-dense);
			box-shadow: var(--ts-verre-ombre);
			-webkit-backdrop-filter: var(--ts-verre-flou);
			backdrop-filter: var(--ts-verre-flou);
		}
	}
}

/* Trois zones : le logo, le menu au centre, les actions. Sur téléphone, le
   bouton du menu passe à gauche et le logo au centre, comme dans la plupart
   des boutiques. */
.ts-entete .ts-entete__barre {
	display: grid;
	grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
	grid-template-areas: "logo menu actions";
	align-items: center;
	gap: var(--wp--preset--spacing--30);
	min-block-size: var(--ts-entete-hauteur);
	padding-block: 0.5rem;

	& > * {
		margin: 0;
	}
}

.ts-entete__logo {
	grid-area: logo;
	justify-self: start;
}

.ts-entete__menu {
	grid-area: menu;
	font-weight: 500;
}

.ts-entete .ts-entete__actions {
	grid-area: actions;
	justify-self: end;
	gap: 0.25rem;
}

@media (max-width: 599px) {
	:root {
		--ts-entete-hauteur: 4.75rem;
		--ts-logo-compact: 3.5rem;
	}

	.ts-entete .ts-entete__barre {
		grid-template-areas: "menu logo actions";
	}

	.ts-entete__menu {
		justify-self: start;
	}
}

/* Le logotype prend la largeur réglée dans le bloc Logo du site. */
.ts-logo-bloc .ts-logo {
	display: block;
	inline-size: var(--ts-logo-largeur, 4rem);
	block-size: auto;
}

/* En mode sombre, le logotype passe en crème uni, partout : les dégradés
   bruns de la calligraphie disparaîtraient sur le fond foncé. Ses couleurs
   sont écrites dans le SVG depuis un sélecteur d'identifiant : seul
   !important les remplace. */
:root[data-ts-mode="sombre"] .ts-logo :is(path, polygon, rect, circle, ellipse) {
	fill: var(--ts-toujours-clair) !important;
}

@media (max-width: 599px) {
	.ts-entete__logo :is(.ts-logo, img) {
		inline-size: 4.5rem;
		block-size: auto;
	}
}

/* Le logotype s'affiche en grand en haut de page, puis se resserre dès qu'on
   défile : l'en-tête collant rend la place au contenu. Le défilement pilote
   l'animation lui-même ; sans cette prise en charge, le logo reste grand. */
@supports (animation-timeline: scroll()) {
	@media (prefers-reduced-motion: no-preference) {
		.ts-entete__logo :is(.ts-logo, img) {
			animation: ts-logo-resserre linear both;
			animation-timeline: scroll(root);
			animation-range: 0 10rem;
		}
	}
}

@keyframes ts-logo-resserre {
	to {
		inline-size: var(--ts-logo-compact);
	}
}

/* Liens du menu : la couleur du texte, le rose au survol et sur la page en
   cours. */
.ts-entete__menu .wp-block-navigation-item__content {
	padding-block: 0.4rem;
	color: var(--wp--preset--color--contrast);
	transition: color 0.3s var(--ts-courbe);
}

.ts-entete__menu .wp-block-navigation-item__content:is(:hover, :focus-visible, [aria-current="page"]) {
	color: var(--ts-rose-texte);
}

@media (min-width: 600px) and (max-width: 960px) {
	.ts-entete__menu .wp-block-navigation__container {
		gap: var(--wp--preset--spacing--30);
	}
}

/* Le logo et les réseaux sociaux du menu n'apparaissent que dans le menu
   plein écran du téléphone : dans la barre de l'ordinateur, ils feraient
   doublon avec le logo et le pied de page. WordPress les place chacun dans
   un élément de liste. */
.ts-entete__menu .wp-block-navigation-item:has(> .ts-menu__logo, > .ts-menu__reseaux) {
	display: none;
}

/* Menu plein écran du téléphone. WordPress lui impose un fond blanc et un
   texte noir depuis un sélecteur à quatre classes : celui-ci en compte cinq.
   Le menu suit le mode choisi : crème en mode clair, bordeaux en mode
   sombre, éclairé d'un reflet doré et d'un reflet rose, avec une grande
   palme qui se balance doucement. En haut le logo, en bas les réseaux : les
   deux se règlent dans l'éditeur, comme les liens. Ses couleurs passent
   par les jetons --ts-menu-*, redéfinis pour le mode sombre plus bas. */
.ts-entete .wp-block-navigation.ts-entete__menu .wp-block-navigation__responsive-container.is-menu-open {
	--navigation-layout-justification-setting: stretch;
	--navigation-layout-justify: flex-start;
	--ts-menu-fond: var(--wp--preset--color--base);
	--ts-menu-reflet-or: color-mix(in srgb, var(--ts-or-decor) 30%, transparent);
	--ts-menu-reflet-rose: color-mix(in srgb, var(--ts-rose-decor) 40%, transparent);
	--ts-menu-texte: var(--wp--preset--color--contrast);
	--ts-menu-accent: var(--ts-rose-texte);
	--ts-menu-filet: var(--ts-filet);
	--ts-menu-palme: color-mix(in srgb, var(--ts-rose-decor) 24%, transparent);
	--ts-menu-icones: var(--ts-or-texte);

	overflow: hidden;
	padding: var(--wp--preset--spacing--30) var(--wp--preset--spacing--40) var(--wp--preset--spacing--40);
	background-color: var(--ts-menu-fond);
	background-image:
		radial-gradient(70% 45% at 100% 0%, var(--ts-menu-reflet-or), transparent 70%),
		radial-gradient(80% 55% at 0% 100%, var(--ts-menu-reflet-rose), transparent 72%);
	color: var(--ts-menu-texte);

	/* La palme, en filigrane, déborde du coin bas. */
	&::before {
		content: "";
		position: absolute;
		inset-block-end: -8%;
		inset-inline-end: -22%;
		inline-size: 92%;
		aspect-ratio: 41.9 / 47;
		background-color: var(--ts-menu-palme);
		-webkit-mask: url("../images/palme.svg") no-repeat center / contain;
		mask: url("../images/palme.svg") no-repeat center / contain;
		rotate: -18deg;
		transform-origin: 70% 90%;
		pointer-events: none;
	}

	& .wp-block-navigation__responsive-close,
	& .wp-block-navigation__responsive-dialog {
		position: relative;
		block-size: 100%;
	}

	& .wp-block-navigation__responsive-container-content {
		position: relative;
		z-index: 1;
		block-size: 100%;
		align-items: stretch;
		padding-block-start: 0;
	}

	& .wp-block-navigation__container {
		flex-grow: 1;
		align-items: stretch;
		gap: 0;
		inline-size: 100%;
	}

	& .wp-block-navigation-item {
		align-items: flex-start;
		border-block-end: 1px solid var(--ts-menu-filet);
	}

	& .wp-block-navigation-item__content {
		display: block;
		inline-size: 100%;
		padding-block: 1.1rem;
		color: var(--ts-menu-texte);
		font-family: var(--wp--preset--font-family--display);
		font-size: var(--wp--preset--font-size--xx-large);
		line-height: var(--wp--custom--interligne--titre);
		text-align: start;

		&::after {
			display: none;
		}

		&:is(:hover, :focus-visible, [aria-current="page"]) {
			color: var(--ts-menu-accent);
		}
	}

	/* Le logo ouvre le menu. Ses couleurs suivent le mode, comme dans
	   l'en-tête. */
	& .wp-block-navigation-item:has(> .ts-menu__logo) {
		display: block;
		margin-block-end: var(--wp--preset--spacing--40);
		border: 0;
	}

	& .ts-menu__logo .ts-logo {
		inline-size: 5.5rem;
	}

	/* Les réseaux ferment le menu, posés en bas de l'écran. */
	& .wp-block-navigation-item:has(> .ts-menu__reseaux) {
		display: block;
		margin-block-start: auto;
		padding-block-start: var(--wp--preset--spacing--50);
		border: 0;
	}

	& .wp-block-social-links.ts-menu__reseaux {
		gap: var(--wp--preset--spacing--40);

		& .wp-social-link {
			color: var(--ts-menu-icones);
			/* Taille de l'icône : WordPress la règle par font-size. */
			font-size: 1.75rem;
		}
	}
}

/* Mode sombre : le bordeaux profond de la marque et le texte crème. */
:root[data-ts-mode="sombre"] .ts-entete .wp-block-navigation.ts-entete__menu .wp-block-navigation__responsive-container.is-menu-open {
	--ts-menu-fond: var(--ts-bordeaux-fond);
	--ts-menu-reflet-or: color-mix(in srgb, var(--ts-or-decor) 40%, transparent);
	--ts-menu-reflet-rose: color-mix(in srgb, var(--ts-rose-decor) 42%, transparent);
	--ts-menu-texte: var(--ts-toujours-clair);
	--ts-menu-accent: var(--ts-or-decor);
	--ts-menu-filet: color-mix(in srgb, var(--ts-toujours-clair) 16%, transparent);
	--ts-menu-palme: color-mix(in srgb, var(--ts-toujours-clair) 10%, transparent);
	--ts-menu-icones: var(--ts-or-decor);
}

/* Les liens entrent l'un après l'autre, et la palme se balance. */
@media (prefers-reduced-motion: no-preference) {
	.ts-entete .wp-block-navigation.ts-entete__menu .wp-block-navigation__responsive-container.is-menu-open {
		&::before {
			animation: ts-palme-balance 7s ease-in-out infinite alternate;
		}

		& .wp-block-navigation-item {
			animation: ts-menu-entree 0.7s var(--ts-courbe) backwards;
		}

		& .wp-block-navigation-item:nth-child(2) { animation-delay: 0.06s; }
		& .wp-block-navigation-item:nth-child(3) { animation-delay: 0.12s; }
		& .wp-block-navigation-item:nth-child(4) { animation-delay: 0.18s; }
		& .wp-block-navigation-item:nth-child(5) { animation-delay: 0.24s; }
		& .wp-block-navigation-item:nth-child(6) { animation-delay: 0.3s; }
		& .wp-block-navigation-item:nth-child(n + 7) { animation-delay: 0.36s; }
	}
}

@keyframes ts-menu-entree {
	from {
		opacity: 0;
		translate: 0 1.25rem;
	}
}

@keyframes ts-palme-balance {
	to {
		rotate: -10deg;
	}
}

.ts-entete .wp-block-navigation .wp-block-navigation__responsive-container-close {
	z-index: 2;
	inline-size: 2.75rem;
	block-size: 2.75rem;
	background-color: color-mix(in srgb, var(--ts-menu-texte, currentColor) 12%, transparent);
	color: var(--ts-menu-texte, currentColor);
}

/* Boutons d'icône de l'en-tête : menu, compte, panier, mode. Une même
   pastille de 40 px, que le doigt atteint sans peine, et une icône de 22 px. */
.ts-entete :is(
	.wp-block-navigation__responsive-container-open,
	.wp-block-navigation__responsive-container-close,
	.wc-block-customer-account__link,
	.wc-block-mini-cart__button,
	.ts-bascule-mode
) {
	display: inline-grid;
	place-items: center;
	inline-size: 2.5rem;
	block-size: 2.5rem;
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: none;
	color: var(--wp--preset--color--contrast);
	cursor: pointer;
	transition: background-color 0.3s var(--ts-courbe), color 0.3s var(--ts-courbe);
}

.ts-entete :is(
	.wp-block-navigation__responsive-container-open,
	.wc-block-customer-account__link,
	.wc-block-mini-cart__button,
	.ts-bascule-mode
):hover {
	background-color: color-mix(in srgb, var(--ts-rose-decor) 20%, transparent);
	color: var(--ts-rose-texte);
}

.ts-entete :is(
	.wp-block-navigation__responsive-container-open,
	.wp-block-navigation__responsive-container-close,
	.wc-block-customer-account__link,
	.wc-block-mini-cart__button,
	.ts-bascule-mode
) svg {
	inline-size: 1.375rem;
	block-size: 1.375rem;
	fill: currentColor;
}

/* Sur les pages Panier et Commande, WooCommerce rend le mini-panier
   invisible mais lui laisse sa place : il sort ici de la rangée. */
.ts-entete .wc-block-mini-cart[aria-hidden="true"] {
	display: none;
}

/* Lien vedette du menu : celui qui porte la classe ts-lien-vedette, posée
   dans l'éditeur (bloc du lien, Avancé, Classes CSS additionnelles) ; l'admin
   peut la déplacer sur un autre lien. Il s'écrit plus grand, en bordeaux,
   souligné d'un filet or et rose qui s'allonge au survol, et un reflet doré
   le traverse toutes les cinq secondes. */
.ts-entete__menu .ts-lien-vedette > .wp-block-navigation-item__content {
	color: var(--ts-bordeaux);
	font-size: var(--wp--preset--font-size--large);
	font-weight: 600;

	&::after {
		block-size: 2px;
		border-radius: 2px;
		background: linear-gradient(to right in oklab, var(--ts-or-decor), var(--ts-rose-decor));
		transform: scaleX(0.45);
		transform-origin: left center;
	}

	&:is(:hover, :focus-visible)::after {
		transform: scaleX(1);
	}
}

@media (prefers-reduced-motion: no-preference) {
	.ts-entete__menu .ts-lien-vedette > .wp-block-navigation-item__content .wp-block-navigation-item__label {
		background-image: linear-gradient(100deg, var(--ts-bordeaux) 42%, var(--ts-or-reflet) 50%, var(--ts-bordeaux) 58%);
		background-size: 300% 100%;
		background-position: 100% 0;
		-webkit-background-clip: text;
		background-clip: text;
		-webkit-text-fill-color: transparent;
		animation: ts-reflet-vedette 5s ease-in-out infinite;
	}
}

/* Le reflet reste hors du mot les trois premières secondes, puis le
   traverse de gauche à droite. */
@keyframes ts-reflet-vedette {
	0%,
	60% {
		background-position: 100% 0;
	}

	100% {
		background-position: 0 0;
	}
}

/* Au-delà de 600 px, le menu s'affiche en entier : son bouton se cache. */
@media (min-width: 600px) {
	.ts-entete .wp-block-navigation__responsive-container-open:not(.always-shown) {
		display: none;
	}
}

.ts-entete .wp-block-navigation__responsive-container-close {
	inset-block-start: var(--wp--preset--spacing--30);
	inset-inline-end: var(--wp--preset--spacing--30);
}

/* Le bloc du panier écrit sa couleur en dur dans les attributs fill de son
   icône. Une règle CSS l'emporte toujours sur un attribut de présentation :
   l'icône suit ainsi la couleur de texte, donc la variante active. */
.wc-block-mini-cart__icon path {
	fill: currentColor;
}

/* Bouton clair / sombre, hors de l'en-tête (page de lancement). */
.ts-bascule-mode {
	display: inline-grid;
	place-items: center;
	inline-size: 2.5rem;
	block-size: 2.5rem;
	padding: 0;
	border: 0;
	background: none;
	color: var(--wp--preset--color--contrast);
	cursor: pointer;
}

/* L'attribut hidden perdrait contre display: inline-grid sans cette règle. */
.ts-bascule-mode[hidden] {
	display: none;
}

.ts-bascule-mode svg {
	grid-area: 1 / 1;
	inline-size: 1.375rem;
	block-size: 1.375rem;
	fill: currentColor;
}

/* La lune propose le mode sombre, le soleil propose le retour au clair. */
:root[data-ts-mode="sombre"] .ts-bascule-mode__lune,
:root:not([data-ts-mode="sombre"]) .ts-bascule-mode__soleil {
	display: none;
}

.ts-bascule-mode:focus-visible {
	outline: 2px solid var(--ts-or-texte-profond);
	outline-offset: 2px;
}

/* ==========================================================================
   Structure
   ========================================================================== */

/* Pied de page maintenu en bas quand le contenu est court.
   svh et non vh : vh ignore la barre d'adresse escamotable des mobiles. */
.wp-site-blocks {
	display: flex;
	flex-direction: column;
	min-block-size: 100svh;
}

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

.admin-bar .wp-site-blocks {
	min-block-size: calc(100svh - var(--wp-admin--admin-bar--height, 32px));
}

/* ==========================================================================
   Typographie
   ========================================================================== */

:where(h1, h2, h3, .wp-block-heading, .wp-block-site-title) {
	letter-spacing: var(--wp--custom--approche--titre);
}

/* Les lignes d'un titre s'équilibrent : jamais un mot seul sur la dernière. */
:where(h1, h2, h3, h4, .wp-block-heading) {
	text-wrap: balance;
}

/* Le filtre render_block de functions.php pose lang="ar" dir="rtl" sur les
   blocs rédigés en arabe. Les deux écritures cohabitent dans une même page
   sans bascule globale de la mise en page. */
:lang(ar) {
	font-family: var(--wp--preset--font-family--arabic);
	line-height: var(--ts-ar-interligne);
}

:lang(ar):is(h1, h2, h3, h4, h5, h6),
:lang(ar) :is(h1, h2, h3, h4, h5, h6),
:lang(ar).wp-block-heading {
	font-family: var(--wp--preset--font-family--arabic);
	line-height: var(--ts-ar-interligne-titre);
	font-weight: 400;
}

/* Sans cette règle, un prix latin dans une phrase RTL apparaît inversé. */
:lang(ar) .woocommerce-Price-amount,
:lang(ar) bdi {
	font-family: var(--wp--preset--font-family--body);
	direction: ltr;
	unicode-bidi: embed;
}

/* Or métallique sur le texte. La plage reste dans les tons foncés : les
   reflets clairs de la marque tombent sous 2:1 et seraient illisibles. */
.ts-or-metal {
	color: var(--ts-or-texte);
	background-image: linear-gradient(
		100deg,
		var(--ts-or-texte) 0%,
		var(--ts-or-texte-profond) 38%,
		var(--ts-or-texte) 72%,
		var(--ts-or-texte-profond) 100%
	);
	-webkit-background-clip: text;
	background-clip: text;
	-webkit-text-fill-color: transparent;
}

/* ==========================================================================
   Animations
   ========================================================================== */

@keyframes ts-monte {
	from { opacity: 0; transform: translateY(var(--ts-distance)); }
	to   { opacity: 1; transform: none; }
}

@keyframes ts-fondu {
	from { opacity: 0; }
	to   { opacity: 1; }
}

@keyframes ts-pose {
	from { transform: scale(1.12); }
	to   { transform: none; }
}

@keyframes ts-trait {
	from { transform: scaleX(0); }
	to   { transform: scaleX(1); }
}

@keyframes ts-souffle {
	from { transform: translate3d(0, 0, 0) scale(1); }
	to   { transform: translate3d(1.6%, -2.4%, 0) scale(1.04); }
}

/* Révélations au défilement, en CSS natif. Les navigateurs sans
   animation-timeline affichent le contenu sans animation. */
.ts-reveal {
	animation: ts-monte linear both;
	animation-timeline: view();
	animation-range: entry 4% cover 30%;
}

.ts-reveal--late { animation-range: entry 0% cover 34%; }

@supports not (animation-timeline: view()) {
	.ts-reveal { animation: none; }
}

/* Séquence appliquée aux écrans vus sans défilement. */
.ts-enter {
	opacity: 0;
	animation: ts-monte 0.95s both var(--ts-courbe);
}

.ts-enter--1 { animation-delay: 0.46s; }
.ts-enter--2 { animation-delay: 0.62s; }
.ts-enter--3 { animation-delay: 0.78s; }
.ts-enter--4 { animation-delay: 0.94s; }
.ts-enter--5 { animation-delay: 1.10s; }
.ts-enter--6 { animation-delay: 1.26s; }

/* ==========================================================================
   Écran de lancement
   ========================================================================== */

.ts-lancement {
	box-sizing: border-box;
	position: relative;
	overflow: hidden;
	isolation: isolate;
	display: flex;
	flex-direction: column;
	background-size: 140px 140px, cover, cover, cover;
	background-repeat: repeat, no-repeat, no-repeat, no-repeat;
}

/* Cinq directions de fond. Pour changer, remplacer la classe ts-fond--montant
   par une autre dans templates/coming-soon.html.

   Les étapes sont calculées pour rester perceptuellement homogènes : clarté
   de 0.966 à 0.825 et chroma de 0.015 à 0.047, soit un rapport de 3.2. Une
   version précédente montait à 12.7, ce qui ne donnait plus un dégradé mais
   deux couleurs qui se rencontrent. Interpolation en oklab, faute de quoi un
   crème et un rose se croisent par un gris terne en sRVB. */
.ts-fond--montant {
	background-image: var(--ts-fond-montant);
	background-size: var(--ts-fond-montant-tailles);
	background-repeat: var(--ts-fond-montant-repetitions);
}

.ts-fond--diagonale {
	background-image:
		var(--ts-bruit),
		radial-gradient(62% 56% at 8% -4% in oklab, color-mix(in srgb, var(--ts-fond-rehaut) 30%, var(--wp--preset--color--base)) 0%, transparent 60%),
		radial-gradient(72% 68% at 104% 106% in oklab, color-mix(in srgb, var(--ts-fond-rose) 46%, var(--wp--preset--color--tertiary)) 0%, transparent 74%),
		linear-gradient(138deg in oklab, color-mix(in srgb, var(--ts-fond-rehaut) 22%, var(--wp--preset--color--base)) 0%, var(--wp--preset--color--base) 24%, color-mix(in srgb, var(--ts-fond-chaleur) 5%, var(--wp--preset--color--tertiary)) 46%, color-mix(in srgb, var(--ts-fond-chaleur) 12%, var(--wp--preset--color--tertiary)) 64%, color-mix(in srgb, var(--ts-fond-chaleur) 20%, var(--wp--preset--color--tertiary)) 82%, color-mix(in srgb, var(--ts-fond-rose) 50%, var(--wp--preset--color--tertiary)) 100%);
	background-size: 140px 140px, cover, cover, cover;
	background-repeat: repeat, no-repeat, no-repeat, no-repeat;
}

.ts-fond--halo {
	background-image:
		var(--ts-bruit),
		radial-gradient(56% 44% at 50% 34% in oklab, color-mix(in srgb, var(--ts-fond-rehaut) 30%, var(--wp--preset--color--base)) 0%, transparent 70%),
		radial-gradient(118% 106% at 50% 42% in oklab, transparent 40%, color-mix(in srgb, var(--ts-fond-chaleur) 12%, var(--wp--preset--color--tertiary)) 72%, color-mix(in srgb, var(--ts-fond-rose) 50%, var(--wp--preset--color--tertiary)) 100%),
		linear-gradient(180deg in oklab, color-mix(in srgb, var(--ts-fond-chaleur) 5%, var(--wp--preset--color--tertiary)) 0%, var(--wp--preset--color--base) 46%, color-mix(in srgb, var(--ts-fond-chaleur) 5%, var(--wp--preset--color--tertiary)) 100%);
	background-size: 140px 140px, cover, cover, cover;
	background-repeat: repeat, no-repeat, no-repeat, no-repeat;
}

.ts-fond--horizon {
	background-image:
		var(--ts-bruit),
		radial-gradient(92% 24% at 50% 40% in oklab, color-mix(in srgb, var(--ts-fond-rehaut) 30%, var(--wp--preset--color--base)) 0%, color-mix(in srgb, var(--ts-fond-chaleur) 9%, var(--wp--preset--color--tertiary)) 52%, transparent 88%),
		radial-gradient(62% 38% at 92% 100% in oklab, color-mix(in srgb, var(--ts-fond-rose) 26%, var(--wp--preset--color--tertiary)) 0%, transparent 72%),
		linear-gradient(180deg in oklab, color-mix(in srgb, var(--ts-fond-chaleur) 5%, var(--wp--preset--color--tertiary)) 0%, color-mix(in srgb, var(--ts-fond-rehaut) 22%, var(--wp--preset--color--base)) 24%, var(--wp--preset--color--base) 40%, color-mix(in srgb, var(--ts-fond-chaleur) 12%, var(--wp--preset--color--tertiary)) 60%, color-mix(in srgb, var(--ts-fond-chaleur) 20%, var(--wp--preset--color--tertiary)) 80%, color-mix(in srgb, var(--ts-fond-rose) 50%, var(--wp--preset--color--tertiary)) 100%);
	background-size: 140px 140px, cover, cover, cover;
	background-repeat: repeat, no-repeat, no-repeat, no-repeat;
}

.ts-fond--vignette {
	background-image:
		var(--ts-bruit),
		radial-gradient(68% 56% at 50% 40% in oklab, color-mix(in srgb, var(--ts-fond-rehaut) 30%, var(--wp--preset--color--base)) 0%, transparent 66%),
		radial-gradient(102% 94% at 50% 46% in oklab, transparent 46%, color-mix(in srgb, var(--ts-fond-chaleur) 12%, var(--wp--preset--color--tertiary)) 74%, color-mix(in srgb, var(--ts-fond-rose) 50%, var(--wp--preset--color--tertiary)) 100%),
		linear-gradient(180deg in oklab, color-mix(in srgb, var(--ts-fond-chaleur) 5%, var(--wp--preset--color--tertiary)) 0%, var(--wp--preset--color--base) 44%, color-mix(in srgb, var(--ts-fond-chaleur) 5%, var(--wp--preset--color--tertiary)) 100%);
	background-size: 140px 140px, cover, cover, cover;
	background-repeat: repeat, no-repeat, no-repeat, no-repeat;
}

/* Frondaison. Palmes réparties sur une grille de 5 par 4, chaque pièce
   décalée au hasard dans sa case : la grille assure la couverture, le
   décalage évite l'aspect mécanique. Les pièces qui tombent dans la bande
   centrale reçoivent une opacité plus faible, pour que le texte reste
   lisible. Graine fixe : la composition ne change pas d'un chargement à
   l'autre. */
.ts-lancement > .ts-frondaison {
	position: absolute;
	inset: 0;
	max-inline-size: none;
	margin-inline: 0;
	z-index: -1;
	pointer-events: none;
	overflow: hidden;
}

/* L'opacité finale passe par une variable : une seule règle d'apparition
   suffit pour toutes les densités. */
.ts-palme {
	position: absolute;
	aspect-ratio: 41.9 / 47;
	background: url("../images/palme.svg") no-repeat center / contain;
	opacity: 0;
	will-change: opacity, transform, translate;
	animation-name: ts-palme-entree, ts-souffle;
	animation-fill-mode: forwards, none;
	animation-iteration-count: 1, infinite;
	animation-direction: normal, alternate;
	animation-timing-function: var(--ts-courbe), ease-in-out;
}

@keyframes ts-palme-entree {
	from { opacity: 0; transform: scale(1.06); }
	to   { opacity: var(--ts-palme-opacite); transform: none; }
}

.ts-palme--1 {
	--ts-palme-opacite: 0.12;
	inline-size: min(286px, 40.9vw);
	inset-block-start: 5.2%;
	inset-inline-start: 7.2%;
	rotate: -146deg;
	translate: calc(var(--ts-px, 0) * 20px) calc(var(--ts-py, 0) * -24px);
	animation-duration: 1.4s, 40s;
	animation-delay: 0.94s, 2.34s;
}

.ts-palme--2 {
	--ts-palme-opacite: 0.07;
	inline-size: min(142px, 20.3vw);
	inset-block-start: 6.5%;
	inset-inline-start: 36.6%;
	rotate: 52deg;
	translate: calc(var(--ts-px, 0) * -18px) calc(var(--ts-py, 0) * -25px);
	animation-duration: 1.4s, 52s;
	animation-delay: 0.72s, 2.12s;
}

.ts-palme--3 {
	--ts-palme-opacite: 0.08;
	inline-size: min(177px, 25.3vw);
	inset-block-start: 4.6%;
	inset-inline-start: 55.2%;
	rotate: 152deg;
	translate: calc(var(--ts-px, 0) * -41px) calc(var(--ts-py, 0) * 14px);
	animation-duration: 1.4s, 20s;
	animation-delay: 1.47s, 2.87s;
}

.ts-palme--4 {
	--ts-palme-opacite: 0.06;
	inline-size: min(194px, 27.7vw);
	inset-block-start: 20.0%;
	inset-inline-start: 62.7%;
	rotate: 44deg;
	translate: calc(var(--ts-px, 0) * -33px) calc(var(--ts-py, 0) * 3px);
	animation-duration: 1.4s, 52s;
	animation-delay: 1.25s, 2.65s;
}

.ts-palme--5 {
	--ts-palme-opacite: 0.15;
	inline-size: min(283px, 40.4vw);
	inset-block-start: 14.2%;
	inset-inline-start: 84.9%;
	rotate: -74deg;
	translate: calc(var(--ts-px, 0) * 22px) calc(var(--ts-py, 0) * -28px);
	animation-duration: 1.4s, 53s;
	animation-delay: 0.23s, 1.63s;
}

.ts-palme--6 {
	--ts-palme-opacite: 0.16;
	inline-size: min(229px, 32.7vw);
	inset-block-start: 41.3%;
	inset-inline-start: 5.3%;
	rotate: -10deg;
	translate: calc(var(--ts-px, 0) * 10px) calc(var(--ts-py, 0) * 10px);
	animation-duration: 1.4s, 36s;
	animation-delay: 0.49s, 1.89s;
}

.ts-palme--7 {
	--ts-palme-opacite: 0.14;
	inline-size: min(140px, 20.0vw);
	inset-block-start: 43.4%;
	inset-inline-start: 24.9%;
	rotate: 124deg;
	translate: calc(var(--ts-px, 0) * 15px) calc(var(--ts-py, 0) * 7px);
	animation-duration: 1.4s, 45s;
	animation-delay: 0.54s, 1.94s;
}

.ts-palme--8 {
	--ts-palme-opacite: 0.09;
	inline-size: min(227px, 32.4vw);
	inset-block-start: 29.5%;
	inset-inline-start: 57.7%;
	rotate: -86deg;
	translate: calc(var(--ts-px, 0) * -29px) calc(var(--ts-py, 0) * 26px);
	animation-duration: 1.4s, 43s;
	animation-delay: 0.2s, 1.6s;
}

.ts-palme--9 {
	--ts-palme-opacite: 0.14;
	inline-size: min(266px, 38.0vw);
	inset-block-start: 43.1%;
	inset-inline-start: 72.7%;
	rotate: -10deg;
	translate: calc(var(--ts-px, 0) * -4px) calc(var(--ts-py, 0) * 27px);
	animation-duration: 1.4s, 46s;
	animation-delay: 0.24s, 1.64s;
}

.ts-palme--10 {
	--ts-palme-opacite: 0.12;
	inline-size: min(298px, 42.6vw);
	inset-block-start: 32.7%;
	inset-inline-start: 83.5%;
	rotate: 170deg;
	translate: calc(var(--ts-px, 0) * 45px) calc(var(--ts-py, 0) * 3px);
	animation-duration: 1.4s, 53s;
	animation-delay: 1.49s, 2.89s;
}

.ts-palme--11 {
	--ts-palme-opacite: 0.11;
	inline-size: min(218px, 31.1vw);
	inset-block-start: 58.0%;
	inset-inline-start: 15.2%;
	rotate: 7deg;
	translate: calc(var(--ts-px, 0) * 11px) calc(var(--ts-py, 0) * 9px);
	animation-duration: 1.4s, 27s;
	animation-delay: 0.97s, 2.37s;
}

.ts-palme--12 {
	--ts-palme-opacite: 0.18;
	inline-size: min(193px, 27.6vw);
	inset-block-start: 56.6%;
	inset-inline-start: 29.9%;
	rotate: -104deg;
	translate: calc(var(--ts-px, 0) * 2px) calc(var(--ts-py, 0) * 14px);
	animation-duration: 1.4s, 48s;
	animation-delay: 0.26s, 1.66s;
}

.ts-palme--13 {
	--ts-palme-opacite: 0.09;
	inline-size: min(155px, 22.1vw);
	inset-block-start: 63.5%;
	inset-inline-start: 49.2%;
	rotate: 50deg;
	translate: calc(var(--ts-px, 0) * -13px) calc(var(--ts-py, 0) * 17px);
	animation-duration: 1.4s, 39s;
	animation-delay: 1.07s, 2.47s;
}

.ts-palme--14 {
	--ts-palme-opacite: 0.13;
	inline-size: min(141px, 20.1vw);
	inset-block-start: 56.8%;
	inset-inline-start: 68.1%;
	rotate: -80deg;
	translate: calc(var(--ts-px, 0) * 36px) calc(var(--ts-py, 0) * -7px);
	animation-duration: 1.4s, 17s;
	animation-delay: 0.8s, 2.2s;
}

.ts-palme--15 {
	--ts-palme-opacite: 0.15;
	inline-size: min(121px, 17.3vw);
	inset-block-start: 57.5%;
	inset-inline-start: 91.4%;
	rotate: -96deg;
	translate: calc(var(--ts-px, 0) * -1px) calc(var(--ts-py, 0) * 36px);
	animation-duration: 1.4s, 37s;
	animation-delay: 1.44s, 2.84s;
}

.ts-palme--16 {
	--ts-palme-opacite: 0.18;
	inline-size: min(278px, 39.7vw);
	inset-block-start: 87.8%;
	inset-inline-start: 13.0%;
	rotate: 165deg;
	translate: calc(var(--ts-px, 0) * -42px) calc(var(--ts-py, 0) * 22px);
	animation-duration: 1.4s, 52s;
	animation-delay: 0.68s, 2.08s;
}

.ts-palme--17 {
	--ts-palme-opacite: 0.12;
	inline-size: min(282px, 40.3vw);
	inset-block-start: 79.2%;
	inset-inline-start: 28.4%;
	rotate: 35deg;
	translate: calc(var(--ts-px, 0) * -40px) calc(var(--ts-py, 0) * -10px);
	animation-duration: 1.4s, 45s;
	animation-delay: 0.37s, 1.77s;
}

.ts-palme--18 {
	--ts-palme-opacite: 0.06;
	inline-size: min(120px, 17.1vw);
	inset-block-start: 78.1%;
	inset-inline-start: 47.4%;
	rotate: 120deg;
	translate: calc(var(--ts-px, 0) * -36px) calc(var(--ts-py, 0) * 10px);
	animation-duration: 1.4s, 18s;
	animation-delay: 0.24s, 1.64s;
}

.ts-palme--19 {
	--ts-palme-opacite: 0.1;
	inline-size: min(282px, 40.3vw);
	inset-block-start: 84.9%;
	inset-inline-start: 65.3%;
	rotate: -41deg;
	translate: calc(var(--ts-px, 0) * 29px) calc(var(--ts-py, 0) * 10px);
	animation-duration: 1.4s, 47s;
	animation-delay: 0.32s, 1.72s;
}

.ts-palme--20 {
	--ts-palme-opacite: 0.16;
	inline-size: min(239px, 34.1vw);
	inset-block-start: 97.9%;
	inset-inline-start: 95.6%;
	rotate: 75deg;
	translate: calc(var(--ts-px, 0) * -38px) calc(var(--ts-py, 0) * -18px);
	animation-duration: 1.4s, 23s;
	animation-delay: 1.16s, 2.56s;
}

/* Le contenu passe devant la frondaison. Celle-ci est exclue nommément :
   sans cela elle hériterait de position: relative, retomberait à zéro de
   haut, et overflow: hidden rognerait les palmes. */
.ts-lancement > *:not(.ts-frondaison) {
	position: relative;
	z-index: 1;
}

/* Rythme vertical de l'écran de lancement. Trois niveaux seulement :
   serré entre deux lignes solidaires, ligne à l'intérieur d'un groupe,
   bloc entre deux groupes. Le rythme se tient ici et nulle part ailleurs. */
.ts-lancement__contenu > * {
	margin-block: 0;
}

.ts-lancement__contenu > * + * {
	margin-block-start: var(--ts-gap-ligne);
}

/* Titre et sous-titre restent solidaires. */
.ts-lancement__contenu > p + p {
	margin-block-start: var(--ts-gap-serre);
}

/* Respiration après le logotype, et avant chaque groupe autonome. */
.ts-lancement__contenu > figure + *,
.ts-lancement__contenu > .ts-benefices,
.ts-lancement__contenu > .wp-block-social-links {
	margin-block-start: var(--ts-gap-bloc);
}

.ts-lancement__contenu {
	display: flex;
	flex-direction: column;
	justify-content: center;
	flex-grow: 1;
}

.ts-lancement .wp-block-image :is(img, svg) {
	/* Le logotype dépend de la hauteur autant que de la largeur : sur un
	   écran de lancement, c'est la hauteur qui contraint. min() retient la
	   plus petite des deux mesures, donc il se réduit sur un écran court
	   sans qu'on ait à le prévoir écran par écran. */
	display: block;
	inline-size: clamp(150px, min(58vw, 29vh), 400px);
	block-size: auto;
	margin-inline: auto;
	animation:
		ts-fondu 1.1s 0.1s both var(--ts-courbe),
		ts-pose 1.5s 0.1s both var(--ts-courbe);
}

/* Ornement de séparation : deux filets dégressifs encadrant une palme.
   Le trait est peint en fond sur une bande de 1 px centrée, avec une coupure
   au milieu où vient se loger la fronde. Celle-ci est posée en masque plutôt
   qu'en image, ce qui la rend colorable par les jetons du thème. */
.ts-lancement .wp-block-separator {
	position: relative;
	inline-size: clamp(170px, 26vw, 230px);
	block-size: 22px;
	margin-inline: auto;
	border: 0;
	opacity: 1;
	background-image: linear-gradient(
		90deg,
		transparent 0%,
		var(--ts-or-decor) 22%,
		var(--ts-or-texte) 38%,
		transparent 41%,
		transparent 59%,
		var(--ts-or-texte) 62%,
		var(--ts-or-decor) 78%,
		transparent 100%
	);
	background-size: 100% 1px;
	background-position: center;
	background-repeat: no-repeat;
}

.ts-lancement .wp-block-separator::after {
	content: "";
	position: absolute;
	inset-block-start: 50%;
	inset-inline-start: 50%;
	inline-size: 17px;
	aspect-ratio: 41.9 / 47;
	transform: translate(-50%, -50%);
	background: var(--ts-or-texte);
	-webkit-mask: url("../images/palme.svg") no-repeat center / contain;
	mask: url("../images/palme.svg") no-repeat center / contain;
}

/* Rangée de bénéfices. Grille de quatre colonnes plutôt que flex : les
   quatre pictogrammes tiennent sur une rangée quelle que soit la largeur,
   sans dépendre d'un calcul de largeurs fixes qui passait à 2 px près. */
.ts-benefices {
	display: grid;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	gap: clamp(0.5rem, 2.6vw, 1.6rem);
	max-inline-size: 30rem;
	margin-inline: auto;
}

.ts-benefice {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 0.5rem;
	min-inline-size: 0;
	text-align: center;
}

.ts-benefice img {
	inline-size: 30px;
	block-size: auto;
}

.ts-benefice span {
	font-family: var(--wp--preset--font-family--arabic);
	font-size: var(--wp--preset--font-size--x-small);
	line-height: var(--wp--custom--interligne--texte);
	color: var(--wp--preset--color--secondary);
}

.ts-lancement__pied {
	margin-block-start: auto;
	padding-block-start: var(--wp--preset--spacing--60);
	justify-content: center;
	font-size: var(--wp--preset--font-size--x-small);
	color: var(--wp--preset--color--secondary);
	opacity: 0.72;
}

.ts-lancement__pied a {
	color: inherit;
	text-decoration: none;
	border-block-end: 1px solid transparent;
	transition: border-color 0.35s var(--ts-courbe), color 0.35s;
}

.ts-lancement__pied a:hover,
.ts-lancement__pied a:focus-visible {
	color: var(--ts-or-texte);
	border-block-end-color: currentColor;
}

/* ==========================================================================
   Pied de page
   ========================================================================== */

/* Les coordonnées viennent de Réglages puis Tamriya Shahad, par l'API de
   liaisons de blocs. Le CSS ne fait que les mettre en forme. */

/* Le fond se choisit dans Réglages, Tamriya Shahad (classes ts-fond-pied-*
   posées sur body). Chaque fond redéfinit les mêmes jetons : le fond, le
   texte, l'accent des intitulés et des survols, les icônes, le filet. */
.ts-pied {
	--ts-pied-accent: var(--ts-rose-texte);
	--ts-pied-icones: var(--ts-or-texte);
	--ts-pied-filet: var(--ts-filet-rose);
	padding-block: var(--wp--preset--spacing--70) var(--wp--preset--spacing--40);
	border-block-start: 1px solid var(--ts-pied-filet);
	background-color: var(--ts-pied-fond);
	color: var(--ts-pied-texte);
}

/* Bordeaux : la couleur des boutons, en aplat. Le logotype passe en clair. */
.ts-fond-pied-bordeaux .ts-pied {
	--ts-pied-fond: var(--ts-bordeaux-fond);
	--ts-pied-texte: var(--ts-toujours-clair);
	--ts-pied-accent: var(--ts-rose-decor);
	--ts-pied-icones: var(--ts-or-decor);
	--ts-pied-filet: color-mix(in srgb, var(--ts-toujours-clair) 18%, transparent);
	--ts-logo-encre: var(--ts-toujours-clair);
	--ts-logo-legende: var(--ts-or-decor);
	border-block-start-color: transparent;
}

/* Sur le bordeaux, les dégradés dorés du logotype manquent de contraste :
   il passe en version unie, crème, comme tout logo posé sur la couleur de
   sa marque. Ses couleurs sont écrites dans le SVG depuis un sélecteur
   d'identifiant : seul !important les remplace. */
.ts-fond-pied-bordeaux .ts-pied .ts-logo :is(path, polygon, rect, circle, ellipse) {
	fill: var(--ts-toujours-clair) !important;
}

.ts-fond-pied-creme .ts-pied {
	--ts-pied-fond: var(--wp--preset--color--base);
}

.ts-pied .ts-pied__colonnes {
	gap: var(--wp--preset--spacing--50) var(--wp--preset--spacing--60);
	margin-block: 0;
}

/* À droite de la marque : les trois colonnes de liens, puis la newsletter
   dans l'espace qu'elles laissent dessous. */
.ts-pied .ts-pied__droite {
	display: grid;
	align-content: start;
	gap: var(--wp--preset--spacing--50);

	& > * {
		margin: 0;
	}
}

.ts-pied .ts-pied__liens {
	gap: var(--wp--preset--spacing--40);
	margin: 0;
}

/* Newsletter : l'invitation à gauche, le formulaire à droite, sur un filet.
   Le champ et le bouton tiennent sur une ligne, la case d'accord dessous.
   Couleurs tirées des jetons du pied : le bloc suit le fond choisi. */
.ts-pied .ts-pied__newsletter {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 26rem);
	grid-template-rows: auto 1fr;
	grid-template-areas:
		"titre formulaire"
		"texte formulaire";
	align-items: start;
	gap: 0.3rem var(--wp--preset--spacing--40);
	padding-block-start: var(--wp--preset--spacing--40);
	border-block-start: 1px solid var(--ts-pied-filet);

	& > * {
		margin: 0;
	}

	& > .fluentform {
		grid-area: formulaire;
	}
}

.ts-pied .ts-pied__newsletter-titre {
	grid-area: titre;
	color: var(--ts-pied-texte);
	font-size: var(--wp--preset--font-size--large);
}

.ts-pied .ts-pied__newsletter-texte {
	grid-area: texte;
	color: color-mix(in srgb, var(--ts-pied-texte) 80%, transparent);
	font-size: var(--wp--preset--font-size--small);
	line-height: var(--wp--custom--interligne--court);
}

.ts-pied .ts-pied__newsletter .fluentform {
	/* Hauteur commune du champ et du bouton. Les déclarations précèdent les
	   règles imbriquées : certains navigateurs ignorent celles qui suivent. */
	--ts-nl-hauteur: 3.25rem;

	color: var(--ts-pied-texte);

	& :is(form, fieldset) {
		margin: 0;
		padding: 0;
		border: 0;
	}

	/* Le bloc, aligné sur le bord droit du pied, a la largeur du champ ; le
	   bouton se pose au bout du champ, dans la même case de la grille. */
	& fieldset {
		display: grid;
		grid-template-columns: minmax(0, 1fr);
		gap: 0.8rem;
	}

	& .ff-el-group {
		margin: 0;
	}

	& .ts-newsletter__email {
		grid-column: 1;
		grid-row: 1;
	}

	& .ff_submit_btn_wrapper {
		z-index: 1;
		grid-column: 1;
		grid-row: 1;
		justify-self: end;
		display: flex;
		align-items: center;
		block-size: var(--ts-nl-hauteur);
	}

	& :is(.ts-newsletter__accord, .ff-errors-in-stack) {
		grid-column: 1 / -1;
	}

	& .ff-el-form-control {
		min-block-size: var(--ts-nl-hauteur);
		padding: 0 8rem 0 0;
		border: 0;
		border-block-end: 1.5px solid color-mix(in srgb, var(--ts-pied-texte) 50%, transparent);
		border-radius: 0;
		background: transparent;
		box-shadow: none;
		-webkit-backdrop-filter: none;
		backdrop-filter: none;
		color: var(--ts-pied-texte);
		font-size: var(--wp--preset--font-size--medium);
		transition:
			border-color 0.25s var(--ts-courbe),
			box-shadow 0.25s var(--ts-courbe);

		&::placeholder {
			color: color-mix(in srgb, var(--ts-pied-texte) 65%, transparent);
		}

		/* La saisie se voit : le filet devient plein, de la couleur du texte,
		   et s'épaissit, sans que la ligne bouge. */
		&:focus {
			border-block-end-color: var(--ts-pied-texte);
			background: transparent;
			box-shadow: 0 1px 0 var(--ts-pied-texte);
			outline: 0;
		}

		/* Le remplissage automatique du navigateur ne pose pas son fond
		   jaune ou bleu sur le pied. */
		&:-webkit-autofill {
			-webkit-text-fill-color: var(--ts-pied-texte);
			transition: background-color 600000s 0s, color 600000s 0s;
		}
	}

	/* Le bouton est un mot suivi d'une flèche, sans capsule. Au survol, il
	   prend l'accent du pied et la flèche avance. */
	& .ff_btn_style.wp-element-button {
		display: inline-flex;
		align-items: center;
		gap: 0.4rem;
		min-block-size: 0;
		margin: 0;
		padding: 0.4rem 0;
		border: 0;
		border-radius: 0;
		background: none;
		box-shadow: none;
		color: var(--ts-pied-texte);
		font-weight: 600;
		letter-spacing: 0.01em;
		transition: color 0.25s var(--ts-courbe);

		&::before {
			content: none;
		}

		&::after {
			content: "\2192";
			transition: translate 0.3s var(--ts-courbe);
		}

		&:is(:hover, :focus) {
			background: none;
			color: var(--ts-pied-accent);
		}

		&:hover::after {
			translate: 0.2rem 0;
		}

		&:active {
			transform: none;
		}
	}

	/* La case et la phrase tiennent sur une même ligne, la case centrée sur
	   le texte. Fluent Forms place la case dans une enveloppe et la phrase
	   dans un bloc : ni l'une ni l'autre ne gardent de marge. */
	& .ff_tc_label {
		display: flex;
		align-items: center;
		gap: 0.55rem;
		margin: 0;
		color: color-mix(in srgb, var(--ts-pied-texte) 75%, transparent);
		font-size: calc(var(--wp--preset--font-size--x-small) * 0.92);
		line-height: var(--wp--custom--interligne--court);
	}

	/* Fluent Forms pose 8 px de retrait au-dessus de la case (padding-top,
	   avec !important) : seul un autre !important le retire, et la case
	   retrouve le centre de la ligne. */
	& .ff-el-tc .ff_tc_label > .ff_tc_checkbox {
		display: flex;
		align-items: center;
		flex: none;
		inline-size: auto;
		margin: 0;
		padding: 0 !important;
	}

	& .ff_t_c {
		margin: 0;
		padding: 0;

		& p {
			margin: 0;
		}
	}

	/* La case d'accord devient un rond : un filet au repos, une pastille de
	   l'accent du pied, cerclée du fond, une fois cochée. */
	& .ff_gdpr_field {
		position: static;
		flex: none;
		appearance: none;
		inline-size: 1.1rem;
		block-size: 1.1rem;
		margin: 0;
		border: 1.5px solid color-mix(in srgb, var(--ts-pied-texte) 60%, transparent);
		border-radius: 50%;
		background-color: transparent;
		cursor: pointer;
		transition:
			background-color 0.2s var(--ts-courbe),
			border-color 0.2s var(--ts-courbe),
			box-shadow 0.2s var(--ts-courbe);

		&:checked {
			border-color: var(--ts-pied-accent);
			background-color: var(--ts-pied-accent);
			box-shadow: inset 0 0 0 3px var(--ts-pied-fond);
		}

		&:focus-visible {
			outline: 2px solid var(--ts-pied-texte);
			outline-offset: 2px;
		}
	}

	& .text-danger {
		color: var(--ts-pied-accent);
	}
}

/* La confirmation remplace le formulaire, dans les couleurs du pied. */
.ts-pied .ts-pied__newsletter .ff-message-success {
	padding: 0;
	border: 0;
	background: none;
	box-shadow: none;
	-webkit-backdrop-filter: none;
	backdrop-filter: none;
	color: var(--ts-pied-texte);

	&::before {
		background-color: var(--ts-pied-accent);
	}
}

.ts-pied .ts-pied__marque {
	display: grid;
	align-content: start;
	justify-items: start;
	gap: var(--wp--preset--spacing--30);

	& > * {
		margin: 0;
	}
}

.ts-pied__devise {
	max-inline-size: 30ch;
	color: color-mix(in srgb, var(--ts-pied-texte) 88%, transparent);
	font-size: var(--wp--preset--font-size--medium);
	line-height: var(--wp--custom--interligne--texte);
}

/* Réseaux sociaux : des pastilles cerclées d'un filet, l'icône à la couleur
   du texte du pied ; au survol, la pastille se remplit et l'icône passe à la
   couleur du fond. En style « logos seuls », WordPress colore chaque icône
   aux couleurs de son réseau depuis un sélecteur à trois classes : celui-ci
   en compte une de plus. */
.wp-block-social-links.is-style-logos-only.ts-pied-reseaux .wp-social-link {
	color: var(--ts-pied-texte);
	/* Taille de l'icône : WordPress la règle par font-size. */
	font-size: 1.25rem;

	& .wp-block-social-link-anchor {
		display: grid;
		place-items: center;
		inline-size: 2.75rem;
		block-size: 2.75rem;
		padding: 0;
		border: 1px solid color-mix(in srgb, var(--ts-pied-texte) 30%, transparent);
		border-radius: 50%;
		transition:
			background-color 0.3s var(--ts-courbe),
			border-color 0.3s var(--ts-courbe),
			color 0.3s var(--ts-courbe),
			transform 0.4s var(--ts-ressort);
	}

	& .wp-block-social-link-anchor:is(:hover, :focus-visible) {
		border-color: var(--ts-pied-texte);
		background-color: var(--ts-pied-texte);
		color: var(--ts-pied-fond);
		transform: translateY(-2px);
	}
}

.wp-block-social-links.ts-pied-reseaux {
	gap: var(--wp--preset--spacing--20);
}

.wp-block-social-links.is-style-logos-only.ts-lancement-reseaux .wp-social-link {
	color: var(--wp--preset--color--primary);
}

/* Les intitulés de colonne ont la voix des étiquettes du site : petites
   capitales espacées, dans l'accent du fond choisi. */
.ts-pied .ts-pied-titre {
	margin: 0 0 var(--wp--preset--spacing--30);
	color: var(--ts-pied-accent);
	font-weight: 600;
	letter-spacing: var(--wp--custom--approche--mention);
	text-transform: uppercase;
}

.ts-pied-menu {
	gap: var(--wp--preset--spacing--20);
}

.ts-pied-menu a {
	color: inherit;
	text-decoration: none;
	border-block-end: 1px solid transparent;
	transition: color 0.3s var(--ts-courbe), border-color 0.3s var(--ts-courbe);
}

.ts-pied-menu a:hover,
.ts-pied-menu a:focus-visible {
	color: var(--ts-pied-accent);
	border-block-end-color: currentColor;
}

/* Le soulignement animé de la navigation principale n'a pas sa place ici :
   les liens du pied sont déjà dans une liste. */
.ts-pied-menu .wp-block-navigation-item__content::after {
	display: none;
}

.ts-pied .ts-pied-filet {
	margin-block: var(--wp--preset--spacing--60) var(--wp--preset--spacing--40);
	border: 0;
	block-size: 1px;
	opacity: 1;
	background: var(--ts-pied-filet);
}

.ts-pied .ts-pied-bas {
	gap: var(--wp--preset--spacing--20) var(--wp--preset--spacing--30);
	margin-block-start: 0;
	color: color-mix(in srgb, currentColor 78%, transparent);

	& > * {
		margin: 0;
	}
}

/* Téléphone : la marque, puis les colonnes de liens deux par deux, pour ne
   pas allonger la page de trois écrans, puis la newsletter, son texte
   au-dessus du formulaire. */
@media (max-width: 781px) {
	.ts-pied .ts-pied__liens {
		display: grid;
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}

	.ts-pied .ts-pied__newsletter {
		grid-template-columns: minmax(0, 1fr);
		grid-template-rows: none;
		grid-template-areas:
			"titre"
			"texte"
			"formulaire";

		& > .fluentform {
			margin-block-start: var(--wp--preset--spacing--20);
		}
	}

	.ts-pied .ts-pied-bas {
		flex-direction: column;
		align-items: center;
		text-align: center;
	}
}

/* ==========================================================================
   Pages de texte (À propos, FAQ, livraison, pages légales)
   ========================================================================== */

/* Les compositions de ces pages laissent des paragraphes vides, à remplir :
   tant qu'ils le restent, ils ne creusent pas de trou dans la page. */
.wp-block-post-content > p:empty {
	display: none;
}

/* Sur une page de lecture (modèle par défaut), les titres de section sont
   plus petits que ceux de l'accueil : ils structurent un texte, ils ne
   l'annoncent pas. */
.page-template-default .wp-block-post-content {
	& > h2.wp-block-heading {
		margin-block-start: var(--wp--preset--spacing--60);
		font-size: var(--wp--preset--font-size--x-large);
	}

	& > h3.wp-block-heading {
		margin-block-start: var(--wp--preset--spacing--50);
		font-size: var(--wp--preset--font-size--large);
	}
}

/* Questions de la FAQ : une liste réglée de questions qui se déplient. Le
   triangle du navigateur cède la place à un plus qui pivote en croix. */
.wp-block-post-content .wp-block-details {
	border-block-end: 1px solid var(--ts-filet);

	& summary {
		position: relative;
		padding-block: 1.1rem;
		padding-inline-end: 2.5rem;
		cursor: pointer;
		list-style: none;
		font-weight: 600;

		&::-webkit-details-marker {
			display: none;
		}

		&::after {
			content: "+";
			position: absolute;
			inset-block-start: 50%;
			inset-inline-end: 0.25rem;
			color: var(--ts-rose-texte);
			font-size: var(--wp--preset--font-size--x-large);
			font-weight: 400;
			line-height: 1;
			translate: 0 -50%;
			transition: rotate 0.3s var(--ts-courbe);
		}

		&:hover {
			color: var(--ts-rose-texte);
		}
	}

	&[open] summary::after {
		rotate: 45deg;
	}

	& > :not(summary) {
		margin-block: 0 1.1rem;
		color: var(--wp--preset--color--secondary);
	}
}

.wp-block-post-content .wp-block-details + .wp-block-heading {
	margin-block-start: var(--wp--preset--spacing--60);
}

/* Tableaux des pages de texte, comme celui des cookies : des lignes réglées,
   l'en-tête en étiquettes. */
.wp-block-post-content .wp-block-table {
	overflow-x: auto;

	& table {
		border-collapse: collapse;
		font-size: var(--wp--preset--font-size--small);
	}

	& :is(th, td) {
		padding: 0.75rem 0.9rem;
		border: 0;
		border-block-end: 1px solid var(--ts-filet);
		text-align: start;
		vertical-align: top;
	}

	& th {
		color: var(--ts-rose-texte);
		font-size: var(--wp--preset--font-size--x-small);
		font-weight: 600;
		letter-spacing: var(--wp--custom--approche--mention);
		text-transform: uppercase;
	}

	& thead {
		border-block-end: 1px solid var(--ts-filet-fort);
	}
}

/* ==========================================================================
   Bulle WhatsApp (inc/whatsapp.php)
   ========================================================================== */

/* Une pastille au vert de WhatsApp (--ts-whatsapp), en bas à droite,
   au-dessus du contenu mais sous le tiroir du panier et le menu du
   téléphone : la couleur de la marque se reconnaît d'un coup d'œil, même
   sur le pied bordeaux. Un halo s'en échappe de temps en temps pour attirer
   l'œil. Sur ordinateur, le libellé glisse à sa gauche au survol, et une
   fois par visite, quelques secondes après l'arrivée (classe est-annoncee,
   posée par le script de inc/whatsapp.php). Le reste du temps, seule la
   pastille occupe le coin. La bulle entre une fois, un instant après la
   page. */
.ts-whatsapp {
	position: fixed;
	z-index: 60;
	inset-inline-end: max(var(--wp--preset--spacing--40), env(safe-area-inset-right));
	inset-block-end: max(var(--wp--preset--spacing--40), env(safe-area-inset-bottom));
	display: flex;
	align-items: center;
	gap: 0.75rem;
	color: var(--wp--preset--color--contrast);
	text-decoration: none;
	animation: ts-monte 0.6s 1.2s both var(--ts-courbe);
}

.ts-whatsapp__pastille {
	position: relative;
	display: grid;
	place-items: center;
	flex: none;
	inline-size: 4rem;
	block-size: 4rem;
	border-radius: 50%;
	background-color: var(--ts-whatsapp);
	box-shadow: 0 14px 30px -10px color-mix(in srgb, var(--ts-whatsapp) 70%, transparent);
	color: var(--ts-whatsapp-texte);
	transition:
		background-color 0.3s var(--ts-courbe),
		transform 0.4s var(--ts-ressort);

	& svg {
		inline-size: 2.15rem;
		block-size: 2.15rem;
		fill: currentColor;
	}

	/* Le halo : un anneau vert qui grandit et s'efface toutes les cinq
	   secondes. */
	&::after {
		content: "";
		position: absolute;
		inset: 0;
		z-index: -1;
		border-radius: inherit;
		background-color: var(--ts-whatsapp);
		opacity: 0;
		animation: ts-whatsapp-halo 5s 2.5s ease-out infinite;
	}
}

@keyframes ts-whatsapp-halo {
	0% {
		opacity: 0.5;
		transform: scale(1);
	}

	30%,
	100% {
		opacity: 0;
		transform: scale(1.6);
	}
}

/* En fin de page, la pastille se pose sous la dernière ligne du pied au
   lieu de la recouvrir : le pied s'allonge de sa hauteur. */
body:has(.ts-whatsapp) .ts-pied {
	padding-block-end: calc(4rem + var(--wp--preset--spacing--40));
}

/* Le libellé : une capsule claire, lisible sur toutes les pages. */
.ts-whatsapp__libelle {
	padding: 0.65rem 1.1rem;
	border: 1px solid var(--ts-filet);
	border-radius: 999px;
	background-color: var(--wp--preset--color--base);
	box-shadow: var(--ts-verre-ombre);
	color: var(--wp--preset--color--contrast);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	white-space: nowrap;
	opacity: 0;
	translate: 0.75rem 0;
	pointer-events: none;
	transition:
		opacity 0.35s var(--ts-courbe),
		translate 0.35s var(--ts-courbe);
}

.ts-whatsapp.est-annoncee .ts-whatsapp__libelle {
	opacity: 1;
	translate: 0 0;
}

.ts-whatsapp:is(:hover, :focus-visible) {
	& .ts-whatsapp__pastille {
		background-color: color-mix(in srgb, var(--ts-whatsapp) 86%, var(--ts-toujours-sombre));
		transform: scale(1.06);
	}

	& .ts-whatsapp__libelle {
		opacity: 1;
		translate: 0 0;
	}
}

.ts-whatsapp:focus-visible {
	outline: none;

	& .ts-whatsapp__pastille {
		outline: 2px solid var(--ts-or-texte-profond);
		outline-offset: 3px;
	}
}

/* Sur téléphone, la pastille seule : le libellé masquerait le contenu. */
@media (max-width: 781px), (hover: none) {
	.ts-whatsapp__libelle {
		display: none;
	}
}

@media (max-width: 781px) {
	.ts-whatsapp {
		inset-inline-end: max(var(--wp--preset--spacing--30), env(safe-area-inset-right));
		inset-block-end: max(var(--wp--preset--spacing--30), env(safe-area-inset-bottom));
	}

	.ts-whatsapp__pastille {
		inline-size: 3.75rem;
		block-size: 3.75rem;

		& svg {
			inline-size: 2rem;
			block-size: 2rem;
		}
	}

	/* Sur la fiche d'un produit simple, le bouton d'achat flotte en bas de
	   l'écran : la bulle se pose au-dessus de lui. WordPress pose la classe
	   du type de produit sur body. */
	body.product-type-simple:has(.ts-produit__achat form.cart) .ts-whatsapp {
		inset-block-end: calc(
			max(var(--wp--preset--spacing--30), env(safe-area-inset-bottom)) +
				var(--ts-bouton-hauteur) + 0.6rem + var(--wp--preset--spacing--30)
		);
	}
}

@media (prefers-reduced-motion: reduce) {
	.ts-whatsapp,
	.ts-whatsapp__pastille::after {
		animation: none;
	}
}

/* ==========================================================================
   Boutons
   ========================================================================== */

/* Les boutons de 2026 redeviennent des objets qu'on presse : une capsule
   franche plutôt que l'arrondi de 8 px, une réponse au doigt, et le verre
   dépoli pour les commandes posées sur le contenu. theme.json donne la
   capsule et ses couleurs ; ce fichier ajoute le mouvement.

   Au survol, un calque de la couleur --ts-bouton-survol apparaît en fondu
   sur la capsule. Le fond du bouton ne change pas, si bien qu'un bouton
   coloré depuis l'éditeur garde sa couleur. Le style choisi dans Réglages,
   Tamriya Shahad, Animation des boutons (classe ts-bouton-* sur body)
   ajoute son effet par trois variables : --ts-bouton-reflet, un éclat de
   lumière qui traverse le calque ; --ts-bouton-halo, une ombre colorée ;
   --ts-bouton-leve, une élévation. Les boutons d'icône de WooCommerce
   (fermer le tiroir du panier, fermer un avis) n'en reçoivent pas : ils
   n'ont pas de capsule. Le lien « Voir le panier » d'une alerte non plus :
   WooCommerce le dessine en lien souligné. */
:is(a, button):is(.wp-element-button, .wp-block-button__link):not(
		.is-style-outline,
		.is-style-outline > *,
		.is-style-ts-lien > *,
		.wc-block-components-drawer__close,
		.wc-block-components-notice-banner__dismiss,
		.wc-block-components-notice-banner .wc-forward
	) {
	position: relative;
	isolation: isolate;
	overflow: hidden;
	transition:
		transform 0.5s var(--ts-ressort),
		translate 0.4s var(--ts-courbe),
		box-shadow 0.4s var(--ts-courbe),
		opacity 0.25s var(--ts-courbe);

	&::before {
		content: "";
		position: absolute;
		inset: -1px;
		z-index: -1;
		background-color: var(--ts-bouton-survol);
		background-image: var(--ts-bouton-reflet, none);
		background-position: 130% 0;
		background-repeat: no-repeat;
		background-size: 250% 100%;
		opacity: 0;
		transition:
			opacity 0.35s var(--ts-courbe),
			background-position 1.1s ease-in-out;
	}

	&:is(:hover, :focus-visible) {
		box-shadow: var(--ts-bouton-halo, none);
		translate: 0 var(--ts-bouton-leve, 0);
	}

	&:is(:hover, :focus-visible)::before {
		background-position: -30% 0;
		opacity: 1;
	}

	/* La pression enfonce la capsule ; le ressort la relâche. */
	&:active {
		transform: scale(0.97);
		transition-duration: 0.12s;
	}

	&:is(:disabled, [aria-disabled="true"], .disabled) {
		opacity: 0.45;
		cursor: not-allowed;
		transform: none;

		&::before {
			content: none;
		}
	}
}

/* Les trois styles d'animation. Le reflet est une bande de lumière en
   biais, tirée du crème de la marque. */
.ts-bouton-reflet {
	--ts-bouton-reflet: linear-gradient(
		105deg,
		transparent 35%,
		color-mix(in srgb, var(--ts-toujours-clair) 45%, transparent) 50%,
		transparent 65%
	);
}

.ts-bouton-halo {
	--ts-bouton-halo: 0 14px 28px -12px color-mix(in srgb, var(--ts-rose-decor) 85%, transparent);
	--ts-bouton-leve: -2px;
}

/* Sans mouvement demandé, l'éclat et l'élévation disparaissent : seule la
   couleur change. */
@media (prefers-reduced-motion: reduce) {
	body {
		--ts-bouton-reflet: none;
		--ts-bouton-leve: 0;
	}
}

/* Un lien laissé en ligne ne découpe pas ce qui le déborde : le calque du
   survol glisserait sous la capsule voisine. Les liens-boutons sans autre
   affichage deviennent des blocs en ligne. La spécificité est nulle : tout
   affichage déjà prévu par WordPress ou WooCommerce l'emporte. */
:where(a.wp-element-button, a.wp-block-button__link) {
	display: inline-block;
	box-sizing: border-box;
}

/* Style « Lien » du bloc Bouton (functions.php) : le bouton se lit comme un
   lien souligné, sans capsule. Le filet de soulignement passe au rose au
   survol, comme les autres liens du site. */
.wp-block-buttons > .wp-block-button.is-style-ts-lien > .wp-block-button__link {
	padding: 0;
	border-radius: 0;
	background: none;
	color: var(--wp--preset--color--contrast);
	font-size: inherit;
	font-weight: 500;
	letter-spacing: 0;
	text-align: start;
	text-decoration: underline;
	text-decoration-color: var(--ts-filet-rose);
	text-decoration-thickness: 1px;
	text-underline-offset: 0.3em;
	transition:
		color 0.25s var(--ts-courbe),
		text-decoration-color 0.25s var(--ts-courbe);

	&:hover {
		color: var(--ts-rose-texte);
		text-decoration-color: currentColor;
	}
}

/* Un champ input ne porte pas de pseudo-élément : il change de fond. */
input.wp-element-button:hover {
	background-color: var(--ts-bouton-survol);
}

/* Le rose signe aussi les petits gestes : le texte qu'on sélectionne et la
   pastille qui compte les articles du panier. */
::selection {
	background-color: color-mix(in srgb, var(--ts-rose-decor) 42%, transparent);
}

.wc-block-mini-cart__badge {
	background-color: var(--ts-rose-texte);
	color: var(--wp--preset--color--base);
}

/* Dans l'en-tête, la pastille du nombre d'articles se pose sur le coin de
   la pastille du bouton, cerclée du fond, sans mordre sur l'icône.
   WooCommerce la place pour une icône de 32 px, depuis la droite physique :
   on reprend sa position en propriétés logiques. */
.ts-entete .wc-block-mini-cart__button {
	position: relative;
}

.ts-entete .wc-block-mini-cart__quantity-badge {
	position: static;
}

.ts-entete .wc-block-mini-cart__icon {
	margin: 0;
}

.ts-entete .wc-block-mini-cart__badge {
	inset-block-start: -0.2rem;
	inset-inline-start: auto;
	inset-inline-end: -0.3rem;
	min-inline-size: 1.375rem;
	block-size: 1.375rem;
	margin: 0;
	padding-inline: 0.3rem;
	border: 2px solid var(--wp--preset--color--base);
	font-size: var(--wp--preset--font-size--x-small);
	font-weight: 600;
	line-height: 1;
	transform: none;

	/* WooCommerce écrit les couleurs du badge en ligne, déduites de celles
	   de l'en-tête : seul !important les ramène aux jetons du thème. */
	background-color: var(--ts-rose-texte) !important;
	color: var(--wp--preset--color--base) !important;
}

:is(.wp-element-button, .wp-block-button__link):focus-visible {
	outline: 2px solid var(--ts-or-texte-profond);
	outline-offset: 3px;
}

/* Le bouton secondaire est une capsule de verre : on voit le fond à travers,
   flouté, avec un reflet sur l'arête haute. Le sélecteur dépasse d'une
   classe celui du style « contour » de WordPress. */
.wp-block-buttons > .wp-block-button.is-style-outline > .wp-block-button__link:not(.has-background),
.wp-element-button.is-style-outline:not(.has-background) {
	border: 1px solid var(--ts-filet-fort);
	background-color: var(--ts-verre);
	-webkit-backdrop-filter: var(--ts-verre-flou);
	backdrop-filter: var(--ts-verre-flou);
	box-shadow: inset 0 1px 0 var(--ts-verre-reflet);
	color: var(--wp--preset--color--contrast);
	transition:
		background-color 0.3s var(--ts-courbe),
		border-color 0.3s var(--ts-courbe),
		transform 0.5s var(--ts-ressort);

	&:hover {
		border-color: color-mix(
			in srgb,
			var(--wp--preset--color--contrast) 45%,
			transparent
		);
		background-color: var(--ts-verre-dense);
	}

	&:active {
		transform: scale(0.97);
		transition-duration: 0.12s;
	}
}

/* ==========================================================================
   Listes déroulantes
   ========================================================================== */

/* Une seule liste ouverte pour tout le site : formulaire de contact, tri de
   la boutique, pays et région de la commande. Chaque liste fermée garde
   l'habillage de son contexte ; ouverte, elle prend le même panneau que les
   listes enrichies des adresses (woocommerce/commun.css) : fond de base,
   filet, coins arrondis, ombre, survol bordeaux et choix en cours rosé.

   appearance: base-select laisse la liste native (clavier, lecteurs d'écran,
   mobile, formulaires de WooCommerce) et ouvre son panneau au CSS. Les
   navigateurs qui ne le connaissent pas encore (Safari, Firefox) affichent
   la liste du système : rien ne casse. */
@supports (appearance: base-select) {
	/* size="1" est une liste ordinaire : WooCommerce l'écrit sur les siennes.
	   WooCommerce, Fluent Forms et nos feuilles de contexte posent
	   appearance: none depuis des sélecteurs plus forts, pour les navigateurs
	   sans base-select. Ici, et pour cette seule propriété, !important
	   l'emporte sur eux tous sans dupliquer la règle dans chaque contexte. */
	select:not([multiple], [size]:not([size="1"])),
	select:not([multiple], [size]:not([size="1"]))::picker(select) {
		appearance: base-select !important;
	}

	/* Chaque contexte dessine déjà sa flèche : celle du navigateur ferait
	   doublon. */
	select::picker-icon {
		display: none;
	}

	/* La liste des pays compte 250 entrées : le panneau défile au-delà d'un
	   tiers d'écran environ. */
	select::picker(select) {
		max-block-size: min(22rem, 55dvh);
		margin-block: 0.4rem;
		padding: 0.35rem;
		border: 1px solid var(--ts-filet-fort);
		border-radius: var(--ts-champ-rayon, 0.9rem);
		background-color: var(--wp--preset--color--base);
		box-shadow: var(--ts-verre-ombre);
		color: var(--wp--preset--color--contrast);
		font-family: var(--wp--preset--font-family--body);
		opacity: 1;
		translate: 0 0;
		transition:
			opacity 0.2s var(--ts-courbe),
			translate 0.25s var(--ts-courbe),
			display 0.25s allow-discrete,
			overlay 0.25s allow-discrete;
	}

	/* Le panneau descend d'un rien en s'ouvrant. */
	select:not(:open)::picker(select) {
		opacity: 0;
		translate: 0 -0.4rem;
	}

	@starting-style {
		select:open::picker(select) {
			opacity: 0;
			translate: 0 -0.4rem;
		}
	}

	select option {
		gap: 0.6rem;
		padding: 0.6rem 0.85rem;
		border-radius: calc(var(--ts-champ-rayon, 0.9rem) - 0.35rem);
		font-size: var(--wp--preset--font-size--small);
		line-height: var(--wp--custom--interligne--court);
		cursor: pointer;
		transition: background-color 0.15s var(--ts-courbe);

		&::checkmark {
			color: var(--ts-rose-texte);
		}

		/* L'invite (« Choisissez un objet ») n'est pas un vrai choix. */
		&[value=""] {
			color: var(--wp--preset--color--secondary);
		}

		&:checked {
			background-color: color-mix(in srgb, var(--ts-rose-decor) 22%, transparent);
			font-weight: 600;
		}

		&:is(:hover, :focus-visible) {
			outline: none;
			background-color: var(--ts-bordeaux);
			color: var(--wp--preset--color--base);

			&::checkmark {
				color: inherit;
			}
		}
	}
}

/* ==========================================================================
   Micro-interactions
   ========================================================================== */

.wp-block-navigation-item__content {
	position: relative;
}

.wp-block-navigation-item__content::after {
	content: "";
	position: absolute;
	inset-inline: 0;
	bottom: -0.15em;
	block-size: 1px;
	background: var(--wp--preset--color--primary);
	transform: scaleX(0);
	transform-origin: right center;
	transition: transform 0.42s var(--ts-courbe);
}

.wp-block-navigation-item__content:hover::after,
.wp-block-navigation-item__content:focus-visible::after {
	transform: scaleX(1);
	transform-origin: left center;
}

/* ==========================================================================
   WooCommerce
   ========================================================================== */

/* Les grilles se règlent sur leur conteneur, pas sur la fenêtre. */
.wp-block-woocommerce-product-collection,
.wc-block-product-template {
	container-type: inline-size;
}

.wc-block-product-template .wc-block-components-product-image {
	overflow: hidden;

	& img {
		transition: transform var(--ts-duree) var(--ts-courbe);
	}
}

.wc-block-product-template li.wc-block-product:hover
	.wc-block-components-product-image img {
	transform: scale(1.06);
}

/* ==========================================================================
   Prix
   ========================================================================== */

/* Le prix est l'information qu'on cherche en premier. Le montant du jour
   s'affiche en grand, en rouge vif (--ts-prix), dans la police des titres
   (--wp--preset--font-family--prix la reprend) ; la devise le suit en plus
   petit corps. En promotion, l'ancien prix passe après, barré, petit et
   gris, et la remise se lit sur la photo (inc/prix.php). Une seule règle
   pour les cartes de toutes les grilles : accueil, boutique, produits liés,
   panier. Le bloc qui enveloppe le prix
   impose sa propre taille avec !important : elle se règle donc sur le prix
   lui-même. WooCommerce le remet en display: block depuis une feuille
   chargée après celle-ci : body donne au sélecteur le cran de plus. Les
   lignes du panier et du tiroir, qui emploient les mêmes classes, gardent
   leur propre mise en forme (woocommerce/commun.css et panier.css). */
body :is(.wc-block-product, .wc-block-grid__product, .ts-produit__prix) :is(.wc-block-components-product-price, .wc-block-grid__product-price),
body .wc-block-grid__product-price {
	display: inline-flex;
	flex-wrap: wrap;
	align-items: baseline;
	justify-content: center;
	gap: 0.15rem 0.6rem;
	color: var(--ts-prix);
	font-family: var(--wp--preset--font-family--prix);
	font-size: calc(var(--wp--preset--font-size--x-large) * 1.3);
	font-weight: 600;
	line-height: 1;
	letter-spacing: -0.01em;

	/* Chiffres alignés et à chasse proportionnelle : des chiffres elzéviriens,
	   de hauteurs inégales, faisaient lire « 1 20,00 » pour « 120,00 ». */
	& .woocommerce-Price-amount {
		font-variant-numeric: lining-nums proportional-nums;
		font-feature-settings: "lnum" 1, "tnum" 0;
	}

	/* La devise suit le montant sur la même ligne de base, en plus petit
	   corps légèrement espacé, de même graisse : « 100 DH » se lit d'un bloc. */
	& .woocommerce-Price-currencySymbol {
		margin-inline-start: 0.12em;
		font-size: 0.55em;
		font-weight: inherit;
		letter-spacing: 0.04em;
	}

	& ins {
		order: -1;
		color: inherit;
		text-decoration: none;
	}

	/* L'ancien prix reste discret : petit, gris, à peine barré. */
	& del {
		color: color-mix(in srgb, var(--wp--preset--color--secondary) 80%, transparent);
		font-family: var(--wp--preset--font-family--body);
		font-size: var(--wp--preset--font-size--small);
		font-weight: 400;
		letter-spacing: 0;
		text-decoration-thickness: 1px;

		& .woocommerce-Price-currencySymbol {
			font-size: 1em;
		}
	}
}

/* La remise d'un produit en promotion s'affiche dans une capsule claire,
   posée dans le coin haut de la photo, côté début de ligne (à gauche en
   français) : « −17 % » au lieu du mot « Promo », en rouge sur un verre
   crème. Discrète, elle signale l'offre sans faire de l'ombre au prix.
   Même dessin dans les cartes, dans l'ancienne grille du panier vide et
   sur la grande photo de la fiche, quel que soit l'alignement réglé dans le
   bloc Image du produit. */
:is(
	.wc-block-product-template .wc-block-components-product-image .wc-block-components-product-sale-badge,
	.ts-accueil__produits .wc-block-components-product-image .wc-block-components-product-sale-badge,
	body .wc-block-grid__product .wc-block-grid__product-onsale,
	.ts-galerie__promo
) {
	position: absolute;
	z-index: 3;
	inset-block-start: var(--ts-promo-retrait, 0.75rem);
	inset-inline: var(--ts-promo-retrait, 0.75rem) auto;
	display: block;
	inline-size: auto;
	block-size: auto;
	margin: 0;
	padding: var(--ts-promo-espace, 0.3rem 0.65rem);
	border: 0;
	border-radius: 999px;
	background-color: color-mix(in srgb, var(--ts-toujours-clair) 90%, transparent);
	-webkit-backdrop-filter: blur(6px);
	backdrop-filter: blur(6px);
	box-shadow: 0 6px 14px -8px color-mix(in srgb, var(--ts-ombre) 60%, transparent);
	color: var(--ts-promo);
	font-family: var(--wp--preset--font-family--body);
	font-size: var(--ts-promo-taille, var(--wp--preset--font-size--x-small));
	font-weight: 700;
	letter-spacing: 0;
	line-height: 1.2;
	text-transform: none;
	white-space: nowrap;
	transform: none;
	-webkit-mask: none;
	mask: none;
}

/* Sur la grande photo de la fiche, la capsule grandit. Les réglages passent
   par des variables, posées sur le cadre : la règle commune ci-dessus, plus
   spécifique, les lit. */
.ts-galerie__cadre {
	--ts-promo-retrait: var(--wp--preset--spacing--30);
	--ts-promo-espace: 0.45rem 0.9rem;
	--ts-promo-taille: var(--wp--preset--font-size--small);
}

.ts-galerie__promo {
	pointer-events: none;
}


/* --------------------------------------------------------------------------
   Cartes produit (inc/carte.php)
   -------------------------------------------------------------------------- */

/* Une carte se lit de haut en bas : la photo, que l'on fait défiler quand
   le produit en a plusieurs, la mention, le nom, le prix, puis le bouton
   sur toute la largeur. Pas de trait entre le nom et le prix : le rouge du
   prix suffit à le détacher. Le sélecteur commun couvre les grilles de
   l'accueil, de la boutique et des produits liés. */
body :is(.wc-block-product-template li.wc-block-product, .ts-accueil__produits .wc-block-product) {
	display: flex;
	flex-direction: column;

	& .wp-block-post-title {
		margin-block: 0.3rem 0.2rem;

		&::after {
			content: none;
		}
	}

	/* Le modèle de la boutique écrit une marge en style en ligne sur le
	   prix et sur le bouton : seul !important la remplace. */
	& .wp-block-woocommerce-product-price {
		margin-block: 0 var(--wp--preset--spacing--30) !important;
	}

	/* Le bouton descend en bas de la carte et prend toute sa largeur : les
	   boutons d'une même rangée s'alignent, quelle que soit la longueur des
	   noms. */
	& .wp-block-button.wc-block-components-product-button {
		align-items: stretch;
		margin-block-start: auto;

		& .wc-block-components-product-button__button {
			inline-size: 100%;
			justify-content: center;
			margin-block-end: 0 !important;
		}
	}
}

/* La mention : quelques mots en petites capitales, dans le rose de la
   marque, au-dessus du nom. Les grilles posent leur écart entre blocs sur
   chaque enfant de la carte : le sélecteur, plus précis, le remplace. */
body .wc-block-product .ts-carte-mention {
	margin: var(--wp--preset--spacing--30) 0 0;
	padding-inline: var(--wp--preset--spacing--20);
	color: var(--ts-rose-texte);
	font-size: var(--wp--preset--font-size--x-small);
	font-weight: 600;
	letter-spacing: var(--wp--custom--approche--mention);
	line-height: var(--wp--custom--interligne--court);
	text-transform: uppercase;
}

/* La bande des photos : chaque photo occupe toute la largeur, et la bande
   défile au doigt, photo par photo. */
.ts-carte-photos {
	display: flex;
	overflow-x: auto;
	overscroll-behavior-inline: contain;
	scroll-snap-type: x mandatory;
	scrollbar-width: none;

	&::-webkit-scrollbar {
		display: none;
	}

	& > img {
		flex: 0 0 100%;
		inline-size: 100%;
		aspect-ratio: 1;
		object-fit: cover;
		scroll-snap-align: start;
	}
}

@media (prefers-reduced-motion: no-preference) {
	.ts-carte-photos {
		scroll-behavior: smooth;
	}
}

/* Les points se posent au bas de la photo, sur un voile qui les rend
   lisibles sur n'importe quelle image. Celui de la photo affichée
   s'allonge. */
.ts-carte-points {
	position: absolute;
	z-index: 3;
	inset-block-end: 0.7rem;
	inset-inline-start: 50%;
	display: flex;
	gap: 0.35rem;
	padding: 0.35rem 0.5rem;
	border-radius: 999px;
	background-color: color-mix(in srgb, var(--ts-toujours-sombre) 35%, transparent);
	-webkit-backdrop-filter: blur(6px);
	backdrop-filter: blur(6px);
	translate: -50% 0;
}

[dir="rtl"] .ts-carte-points {
	translate: 50% 0;
}

.ts-carte-point {
	inline-size: 0.45rem;
	block-size: 0.45rem;
	padding: 0;
	border: 0;
	border-radius: 999px;
	background-color: color-mix(in srgb, var(--ts-toujours-clair) 55%, transparent);
	cursor: pointer;
	transition:
		inline-size 0.3s var(--ts-courbe),
		background-color 0.3s var(--ts-courbe);

	&[aria-current] {
		inline-size: 1.1rem;
		background-color: var(--ts-toujours-clair);
	}

	&:focus-visible {
		outline: 2px solid var(--ts-toujours-clair);
		outline-offset: 2px;
	}
}

/* Les cartes produit se lisent à gauche, sur le bord de la photo : le nom,
   son trait, le prix et le bouton partent du même retrait. WordPress centre
   le nom et le prix par la classe has-text-align-center, réglée dans
   l'éditeur : ces règles l'emportent sur elle. */
body :is(.wc-block-product-template li.wc-block-product, .ts-accueil__produits .wc-block-product, .wc-block-grid__product) {
	text-align: start;

	& :is(.wp-block-post-title, .wc-block-grid__product-title, .wp-block-woocommerce-product-price, .wc-block-grid__product-price:not(.wc-block-components-product-price), .wp-block-button.wc-block-components-product-button, .wc-block-grid__product-add-to-cart) {
		padding-inline: var(--wp--preset--spacing--20);
		text-align: start;
	}

	& .wp-block-post-title::after {
		margin-inline: 0 auto;
	}

	& :is(.wc-block-components-product-price, .wc-block-grid__product-price) {
		justify-content: flex-start;
	}

	& .wp-block-button.wc-block-components-product-button {
		align-items: flex-start;
		justify-content: flex-start;
	}
}

/* Sur la fiche, le prix est plus grand encore, aligné sur le texte. */
.ts-produit .ts-produit__prix :is(.wc-block-components-product-price, .wc-block-grid__product-price) {
	justify-content: flex-start;
	font-size: var(--wp--preset--font-size--xx-large);
}

/* ==========================================================================
   Page produit
   ========================================================================== */

/* La page est composée comme une planche de catalogue : une grille visible,
   des aplats francs, des angles droits, et pas une ombre. Le relief vient de
   l'écart entre les corps de texte et de la position des filets, jamais d'un
   flou. */
.ts-produit {
	--ts-produit-ancrage: calc(
		var(--ts-entete-hauteur) + var(--wp--preset--spacing--40)
	);

	/* Le geste d'entrée se fait discret : sur une fiche produit, une animation
	   qu'on remarque est une animation de trop. */
	--ts-distance: 12px;
}

.admin-bar .ts-produit {
	--ts-produit-ancrage: calc(
		var(--ts-entete-hauteur) + var(--wp--preset--spacing--40) +
			var(--wp-admin--admin-bar--height, 32px)
	);
}

.ts-produit .ts-enter {
	animation-duration: 0.55s;
}

.ts-produit .ts-enter--1 { animation-delay: 0.03s; }
.ts-produit .ts-enter--2 { animation-delay: 0.08s; }
.ts-produit .ts-enter--3 { animation-delay: 0.13s; }
.ts-produit .ts-enter--4 { animation-delay: 0.18s; }
.ts-produit .ts-enter--5 { animation-delay: 0.23s; }
.ts-produit .ts-enter--6 { animation-delay: 0.28s; }

/* La plage par défaut se termine à « cover 30 % », un point qu'une section
   déjà entièrement visible n'atteint jamais sur une page courte : elle
   resterait figée à mi-opacité. */
.ts-produit .ts-reveal {
	animation-range: entry 0% entry 88%;
}

.ts-produit .ts-reveal--late {
	animation-range: entry 0% entry 96%;
}

/* --------------------------------------------------------------------------
   Fil d'Ariane
   -------------------------------------------------------------------------- */

/* Même voix que le fil d'Ariane de la boutique : une étiquette en capitales,
   en or profond. Le bloc impose sa taille avec !important : elle se règle sur
   la liste qu'il contient. */
.ts-produit__fil .woocommerce-breadcrumb {
	color: var(--ts-or-texte-profond);
	font-size: var(--wp--preset--font-size--x-small);
	font-weight: 600;
	letter-spacing: var(--wp--custom--approche--mention);
	text-transform: uppercase;
}

.ts-produit__fil a {
	color: inherit;
	text-decoration: none;
	border-block-end: 1px solid transparent;
	transition: border-color 0.25s var(--ts-courbe);
}

.ts-produit__fil a:hover {
	border-block-end-color: var(--ts-bordeaux);
}

/* --------------------------------------------------------------------------
   Grille de la planche
   -------------------------------------------------------------------------- */

/* Le filet horizontal ouvre la planche, le filet vertical sépare l'objet de
   sa notice. C'est la grille qui tient la page, pas les marges. */
.ts-produit__entete {
	padding-block-start: var(--wp--preset--spacing--50);
	border-block-start: 1px solid var(--ts-filet-fort);
}

@media (min-width: 782px) {
	.ts-produit__entete > .ts-produit__resume {
		position: sticky;
		inset-block-start: var(--ts-produit-ancrage);
		align-self: start;
		padding-inline-start: var(--wp--preset--spacing--50);
		border-inline-start: 1px solid var(--ts-filet);
	}
}

/* --------------------------------------------------------------------------
   Galerie
   -------------------------------------------------------------------------- */

/* Deux présentations au choix, dans Réglages, puis Tamriya Shahad. Elles
   partagent la même piste : un conteneur qui défile avec accrochage. Le
   glissement au doigt, la molette et le clavier viennent du navigateur, et
   aucune largeur n'est mesurée en JavaScript, contrairement au diaporama
   livré par WooCommerce. */
.ts-galerie {
	/* Hauteur d'écran disponible sous l'en-tête collant : la photo principale
	   doit pouvoir se voir en entier sans défiler. */
	--ts-galerie-hauteur: calc(
		100svh - var(--ts-produit-ancrage) - var(--wp--preset--spacing--50)
	);
	--ts-galerie-format: 4 / 5;
	--ts-galerie-arrondi: 0;

	/* Lu par galerie.js : la feuille de style décide seule de la mécanique,
	   selon l'appareil et la largeur. « defilement » au doigt, « fondu » à la
	   souris, « mosaique » quand toutes les photos sont déjà à l'écran. */
	--ts-galerie-mode: defilement;
}

.ts-galerie__cadre {
	position: relative;
}

.ts-galerie__piste {
	position: relative;
	display: flex;
	overflow-x: auto;
	overflow-y: hidden;
	overscroll-behavior-inline: contain;
	scroll-snap-type: x mandatory;
	scrollbar-width: none;
}

.ts-galerie__piste::-webkit-scrollbar {
	display: none;
}

@media (prefers-reduced-motion: no-preference) {
	.ts-galerie__piste {
		scroll-behavior: smooth;
	}
}

.ts-galerie__vue {
	flex: 0 0 100%;
	margin: 0;
	scroll-snap-align: start;
	scroll-snap-stop: always;
}

/* Toutes les vues partagent le même cadre : sans cela, la piste changerait de
   hauteur à chaque glissement vers une photo de proportion différente, et la
   page sauterait sous les yeux du visiteur. */
.ts-galerie__photo,
.ts-galerie__attente {
	display: block;
	inline-size: 100%;
	aspect-ratio: var(--ts-galerie-format);
	object-fit: cover;
	border-radius: var(--ts-galerie-arrondi);
	background-color: var(--wp--preset--color--tertiary);
}

/* Flèches -------------------------------------------------------------------
   Deux pastilles de verre au milieu des bords de la photo. Elles n'apparaissent
   qu'au survol ou au clavier : au repos, rien ne recouvre la photo. Sur un
   écran tactile, le doigt glisse, et elles ne s'affichent pas du tout. */
.ts-galerie__fleche {
	position: absolute;
	z-index: 1;
	inset-block-start: 50%;
	display: grid;
	place-items: center;
	inline-size: 2.75rem;
	block-size: 2.75rem;
	padding: 0;
	border: 1px solid var(--ts-verre-reflet);
	border-radius: 50%;
	background-color: var(--ts-verre-dense);
	-webkit-backdrop-filter: var(--ts-verre-flou);
	backdrop-filter: var(--ts-verre-flou);
	box-shadow: var(--ts-verre-ombre);
	color: var(--wp--preset--color--contrast);
	cursor: pointer;
	opacity: 0;
	translate: 0 -50%;
	transition:
		opacity 0.3s var(--ts-courbe),
		transform 0.45s var(--ts-ressort);
}

.ts-galerie__fleche--precedente {
	inset-inline-start: var(--wp--preset--spacing--30);
}

.ts-galerie__fleche--suivante {
	inset-inline-end: var(--wp--preset--spacing--30);
}

.ts-galerie__fleche svg {
	inline-size: 1.25rem;
	block-size: 1.25rem;
	fill: currentColor;
}

.ts-galerie__cadre:is(:hover, :focus-within)
	.ts-galerie__fleche:not([aria-disabled="true"]),
.ts-galerie__fleche:focus-visible {
	opacity: 1;
}

.ts-galerie__fleche[aria-disabled="true"] {
	cursor: default;
}

.ts-galerie__fleche[aria-disabled="true"]:focus-visible {
	opacity: 0.35;
}

.ts-galerie__fleche:active:not([aria-disabled="true"]) {
	transform: scale(0.88);
	transition-duration: 0.12s;
}

.ts-galerie__fleche:focus-visible {
	outline: 2px solid var(--ts-or-texte-profond);
	outline-offset: 2px;
}

@media (hover: none) {
	.ts-galerie__fleche {
		display: none;
	}
}

/* Pellicule -----------------------------------------------------------------
   Une capsule de verre au pied de la photo, qui porte toutes les vues en
   pastilles rondes : on voit d'un coup d'œil combien il y en a et où l'on
   est. Rondes parce que la capsule l'est : leurs courbes sont concentriques.
   La pastille active grandit et prend un anneau d'or. */
.ts-galerie__pellicule {
	position: absolute;
	z-index: 1;
	inset-block-end: var(--wp--preset--spacing--30);
	inset-inline-start: 50%;
	display: flex;
	gap: 0.3rem;
	max-inline-size: calc(100% - 2 * var(--wp--preset--spacing--30));
	margin: 0;
	padding: 0.3rem;
	overflow-x: auto;
	border: 1px solid var(--ts-verre-reflet);
	border-radius: 999px;
	background-color: var(--ts-verre);
	-webkit-backdrop-filter: var(--ts-verre-flou);
	backdrop-filter: var(--ts-verre-flou);
	box-shadow: var(--ts-verre-ombre);
	list-style: none;
	scrollbar-width: none;
	translate: -50% 0;
}

.ts-galerie__pellicule::-webkit-scrollbar {
	display: none;
}

.ts-galerie__pellicule li {
	flex: none;
	margin: 0;
}

.ts-galerie__miniature {
	display: block;
	inline-size: 2.5rem;
	block-size: 2.5rem;
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: none;
	cursor: pointer;
	transform: scale(0.8);
	transition:
		transform 0.45s var(--ts-ressort),
		box-shadow 0.3s var(--ts-courbe);
}

.ts-galerie__miniature img {
	display: block;
	inline-size: 100%;
	block-size: 100%;
	object-fit: cover;
	border-radius: 50%;
}

.ts-galerie__miniature:hover {
	transform: scale(0.9);
}

/* L'anneau est fait de deux ombres pleines : un liseré de la couleur de fond,
   puis le rose. Il épouse ainsi le cercle sans rien ajouter au balisage. */
.ts-galerie__miniature[aria-current] {
	box-shadow:
		0 0 0 2px var(--wp--preset--color--base),
		0 0 0 3.5px var(--ts-rose-texte);
	transform: scale(1);
}

.ts-galerie__miniature:focus-visible {
	outline: 2px solid var(--ts-or-texte-profond);
	outline-offset: 3px;
}

/* Fondu ---------------------------------------------------------------------
   À la souris, les photos ne défilent pas : elles sont empilées dans la même
   case et se relaient en fondu enchaîné. La molette ou le pavé tactile qui
   passent sur la galerie font défiler la page, jamais les photos. La photo
   qui arrive se pose en partant d'un léger agrandissement. */
@media (hover: hover) and (pointer: fine) {
	.ts-galerie {
		--ts-galerie-mode: fondu;
	}

	.ts-galerie__piste {
		display: grid;
		overflow: hidden;
		scroll-snap-type: none;
	}

	.ts-galerie__vue {
		grid-area: 1 / 1;
		visibility: hidden;
		opacity: 0;
		clip-path: inset(0 round var(--ts-galerie-arrondi));
		transition:
			opacity 0.8s var(--ts-courbe),
			visibility 0s linear 0.8s;
	}

	.ts-galerie__vue[data-ts-active] {
		visibility: visible;
		opacity: 1;
		transition:
			opacity 0.8s var(--ts-courbe),
			visibility 0s;
	}

	.ts-galerie__photo {
		scale: 1.05;
		transition:
			scale 1.4s var(--ts-courbe),
			transform 1.2s var(--ts-courbe);
	}

	.ts-galerie__vue[data-ts-active] .ts-galerie__photo {
		scale: 1;
	}

	/* La photo survolée avance lentement vers l'œil, de quelques pour cent.
	   La vue la découpe à ses angles arrondis : clip-path plutôt
	   qu'overflow, que Safari laisse déborder pendant une transformation. */
	.ts-galerie__vue:hover .ts-galerie__photo {
		transform: scale(1.035);
	}
}

/* Défilé ----------------------------------------------------------------------
   Une grande photo aux angles adoucis, posée sur une ombre longue et douce
   qui la détache du dégradé, avec ses commandes en verre par-dessus. */
.ts-galerie--defile {
	--ts-galerie-arrondi: 1.25rem;
}

.ts-galerie--defile .ts-galerie__cadre {
	border-radius: var(--ts-galerie-arrondi);
	box-shadow: 0 36px 64px -36px
		color-mix(in srgb, var(--ts-ombre) 55%, transparent);
}

.ts-galerie--defile .ts-galerie__piste {
	gap: var(--wp--preset--spacing--20);
}

.ts-galerie--defile .ts-galerie__photo {
	max-block-size: var(--ts-galerie-hauteur);
}

/* Éditorial -------------------------------------------------------------------
   Sur grand écran, toutes les photos sont posées d'un coup, comme une double
   page de magazine : la première en pleine largeur, les suivantes deux par
   deux, et la notice reste collée à côté pendant qu'on les parcourt. Sur
   mobile, la mosaïque redevient le même carrousel que le défilé. */
.ts-galerie--editorial {
	--ts-galerie-arrondi: 1rem;
}

.ts-galerie--editorial .ts-galerie__piste {
	gap: var(--wp--preset--spacing--20);
}

@media (min-width: 782px) {
	.ts-galerie--editorial {
		--ts-galerie-mode: mosaique;
	}

	.ts-galerie--editorial .ts-galerie__piste {
		display: grid;
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: var(--wp--preset--spacing--30);
		overflow: visible;
		scroll-snap-type: none;
	}

	/* Toutes les vues sont posées côte à côte : aucune n'attend son tour. */
	.ts-galerie--editorial .ts-galerie__vue {
		grid-area: auto;
		visibility: visible;
		opacity: 1;
	}

	.ts-galerie--editorial .ts-galerie__photo {
		scale: 1;
	}

	/* La première photo ouvre en pleine largeur ; la dernière la rejoint
	   quand elle se retrouverait seule sur sa rangée. */
	.ts-galerie--editorial
		.ts-galerie__vue:is(:first-child, :last-child:nth-child(even)) {
		grid-column: 1 / -1;
	}

	.ts-galerie--editorial
		.ts-galerie__vue:is(:first-child, :last-child:nth-child(even))
		.ts-galerie__photo {
		aspect-ratio: 1;
	}

	/* Toutes les photos sont à l'écran : rien à piloter. */
	.ts-galerie--editorial :is(.ts-galerie__fleche, .ts-galerie__pellicule) {
		display: none;
	}
}

@media (max-width: 781px) {
	.ts-galerie__miniature {
		inline-size: 2.25rem;
		block-size: 2.25rem;
	}
}

/* --------------------------------------------------------------------------
   Notice du produit
   -------------------------------------------------------------------------- */

/* Deux corps, très éloignés : une capitale minuscule très espacée pour les
   libellés, une romaine très grande pour le nom. Rien entre les deux. */
.ts-produit__categorie {
	color: var(--ts-or-texte-profond);
	font-size: var(--wp--preset--font-size--x-small);
	font-weight: 600;
	letter-spacing: var(--wp--custom--approche--mention);
	text-transform: uppercase;
}

.ts-produit__categorie a {
	color: inherit;
	text-decoration: none;
}

.ts-produit__titre {
	font-family: var(--wp--preset--font-family--produit);
	margin-block: var(--wp--preset--spacing--30) 0;
	font-size: var(--wp--preset--font-size--xx-large);
	font-weight: var(--wp--custom--graisse--produits);
	line-height: var(--wp--custom--interligne--titre);
	letter-spacing: var(--wp--custom--approche--produit);
}

/* Le filet court sur toute la colonne : c'est une réglure, pas un ornement
   centré sous un titre. */
.ts-produit__filet.wp-block-separator {
	inline-size: 100%;
	block-size: 1px;
	margin-block: var(--wp--preset--spacing--40) 0;
	border: 0;
	border-radius: 0;
	background-color: transparent;
	background-image: linear-gradient(
		to right in oklab,
		var(--ts-or-decor) 0%,
		var(--ts-rose-decor) 32%,
		var(--ts-filet) 32%,
		var(--ts-filet) 100%
	);
}

.ts-produit__accroche {
	max-inline-size: 40ch;
	font-size: var(--wp--preset--font-size--medium);
	line-height: var(--wp--custom--interligne--texte);
}

/* Le prix occupe sa propre réglure, comme une ligne de bordereau. Sa mise
   en forme est celle de tous les prix (section Prix). */
.ts-produit .ts-produit__prix {
	margin-block-start: var(--wp--preset--spacing--50);
	padding-block: var(--wp--preset--spacing--30);
	border-block: 1px solid var(--ts-filet);
}

.ts-produit__stock {
	margin-block-start: var(--wp--preset--spacing--30);
	color: var(--ts-or-texte-profond);
	font-size: var(--wp--preset--font-size--x-small);
	letter-spacing: var(--wp--custom--approche--mention);
	text-transform: uppercase;
}

/* --------------------------------------------------------------------------
   Commande
   -------------------------------------------------------------------------- */

.ts-produit__achat form.cart {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--wp--preset--spacing--20);
	margin-block-start: var(--wp--preset--spacing--50);
}

/* Le sélecteur de quantité est une capsule de verre, de la hauteur du bouton.
   WooCommerce le peint en blanc depuis une règle en ligne à cinq classes et
   trois éléments : on reprend sa chaîne exacte en y ajoutant la classe du
   bloc. Une classe de plus suffit à l'emporter, sans recourir à !important. */
div.ts-produit__achat.wc-block-add-to-cart-form.wc-block-add-to-cart-form--stepper
	form.cart
	div.wc-block-components-quantity-selector.quantity {
	align-items: center;
	min-block-size: var(--ts-bouton-hauteur);
	margin-inline-end: 0;
	padding-inline: 0.3rem;
	border: 1px solid var(--ts-filet-fort);
	border-radius: 999px;
	background-color: var(--ts-verre);
	-webkit-backdrop-filter: var(--ts-verre-flou);
	backdrop-filter: var(--ts-verre-flou);
	box-shadow: inset 0 1px 0 var(--ts-verre-reflet);
	color: var(--wp--preset--color--contrast);
	transition: border-color 0.25s var(--ts-courbe);

	/* Le champ perd l'anneau carré de WooCommerce : c'est la capsule entière
	   qui signale la saisie en cours. */
	&:focus-within {
		border-color: var(--ts-or-texte-profond);
	}
}

.ts-produit__achat .quantity input.qty {
	inline-size: 2.5rem;
	padding-block: 0;
	border: 0;
	background: transparent;
	color: var(--wp--preset--color--contrast);
	text-align: center;
	font-family: var(--wp--preset--font-family--body);
	font-variant-numeric: lining-nums tabular-nums;
	-moz-appearance: textfield;
	appearance: textfield;
}

.ts-produit__achat .quantity input.qty::-webkit-outer-spin-button,
.ts-produit__achat .quantity input.qty::-webkit-inner-spin-button {
	-webkit-appearance: none;
	margin: 0;
}

.ts-produit__achat .wc-block-components-quantity-selector input.qty:focus {
	box-shadow: none;
}

/* Moins et plus deviennent des pastilles rondes, qui s'éclairent au survol
   et s'enfoncent à la pression. */
.ts-produit__achat
	.wc-block-components-quantity-selector
	.wc-block-components-quantity-selector__button {
	display: grid;
	place-items: center;
	inline-size: calc(var(--ts-bouton-hauteur) - 0.8rem);
	min-inline-size: 0;
	aspect-ratio: 1;
	border-radius: 50%;
	color: var(--wp--preset--color--contrast);
	font-size: var(--wp--preset--font-size--large);
	line-height: 1;
	opacity: 1;
	transition:
		background-color 0.25s var(--ts-courbe),
		transform 0.45s var(--ts-ressort);

	&:hover:not(:disabled) {
		background-color: color-mix(
			in srgb,
			var(--ts-rose-decor) 26%,
			transparent
		);
	}

	&:active:not(:disabled) {
		transform: scale(0.86);
		transition-duration: 0.12s;
	}

	&:focus {
		box-shadow: none;
	}

	&:focus-visible {
		outline: 2px solid var(--ts-or-texte-profond);
		outline-offset: 1px;
	}

	&:disabled {
		opacity: 0.3;
	}
}

/* Le bouton d'ajout reçoit la capsule et le remplissage de tous les boutons,
   plus une pastille dorée à son extrémité, où le sac est découpé à
   l'emporte-pièce. WooCommerce le passe en inline-block depuis une chaîne de
   quatre classes et deux éléments ; on la reprend avec une classe de plus. */
.woocommerce div.product .ts-produit__achat form.cart button.single_add_to_cart_button {
	display: inline-flex;
	flex: 1 1 13rem;
	align-items: center;
	justify-content: space-between;
	gap: var(--wp--preset--spacing--30);
	min-block-size: var(--ts-bouton-hauteur);
	padding-block: 0.4rem;
	padding-inline: 1.6rem 0.4rem;
	white-space: nowrap;

	/* Seul l'alpha compte dans un masque : le premier calque est le sac, le
	   second couvre la pastille, et « exclude » garde l'une sans l'autre. Le
	   sac découpé laisse voir le fond du bouton : la pastille doit donc
	   trancher sur lui. Dorée sur le bordeaux du mode clair, elle passe au
	   brun profond sur le rose du mode sombre, par ses deux jetons. */
	&::after {
		content: "";
		flex: none;
		inline-size: calc(var(--ts-bouton-hauteur) - 0.8rem);
		aspect-ratio: 1;
		border-radius: 50%;
		background-image: linear-gradient(
			135deg in oklab,
			var(--ts-pastille-a),
			var(--ts-pastille-b)
		);
		-webkit-mask:
			url("../icones/handbag-simple.svg") center / 48% no-repeat,
			linear-gradient(currentColor 0 0);
		-webkit-mask-composite: xor;
		mask:
			url("../icones/handbag-simple.svg") center / 48% no-repeat exclude,
			linear-gradient(currentColor 0 0);
		transition: transform 0.55s var(--ts-ressort);
	}

	&:is(:hover, :focus-visible)::after {
		transform: rotate(-12deg) scale(1.06);
	}
}

.ts-produit__meta {
	padding-block-start: var(--wp--preset--spacing--30);
	border-block-start: 1px solid var(--ts-filet);
	color: var(--wp--preset--color--secondary);
	font-size: var(--wp--preset--font-size--x-small);
	letter-spacing: var(--wp--custom--approche--mention);
	text-transform: uppercase;
}

/* Sans référence produit, le bloc ne rend qu'un groupe vide : sans cette
   règle, son filet traînerait seul sous le bouton. */
.ts-produit__meta:empty {
	display: none;
}

/* --------------------------------------------------------------------------
   Ornement de transition
   -------------------------------------------------------------------------- */

/* Le trait est peint en fond sur une bande de 1 px centrée, avec une coupure
   au milieu pour laisser passer la palme. Même procédé que le séparateur de
   l'écran de lancement. */
.ts-produit__ornement.wp-block-separator {
	position: relative;
	block-size: 2rem;
	margin-block: var(--wp--preset--spacing--60);
	border: 0;
	background-color: transparent;
	background-image: linear-gradient(
		to right,
		var(--ts-filet) 0%,
		var(--ts-filet) calc(50% - 1.8rem),
		transparent calc(50% - 1.8rem),
		transparent calc(50% + 1.8rem),
		var(--ts-filet) calc(50% + 1.8rem),
		var(--ts-filet) 100%
	);
	background-position: center;
	background-repeat: no-repeat;
	background-size: 100% 1px;
}

/* La palme est peinte par masque : elle prend la couleur des jetons, donc
   elle suit les variantes de styles/ sans second fichier. */
.ts-produit__ornement.wp-block-separator::after {
	content: "";
	position: absolute;
	inset: 0;
	margin: auto;
	inline-size: 1.7rem;
	block-size: 1.7rem;
	background-image: linear-gradient(
		to right in oklab,
		var(--ts-or-decor),
		var(--ts-rose-texte)
	);
	mask: url("../images/palme.svg") no-repeat center / contain;
	-webkit-mask: url("../images/palme.svg") no-repeat center / contain;
}

/* --------------------------------------------------------------------------
   Zone du récit
   -------------------------------------------------------------------------- */

.ts-produit__recit {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--wp--preset--spacing--40);
}

.ts-produit__recit-etiquette {
	margin: 0;
	color: var(--ts-bordeaux);
	font-size: var(--wp--preset--font-size--x-small);
	font-weight: 600;
	letter-spacing: var(--wp--custom--approche--mention);
	text-transform: uppercase;
}

.ts-produit__recit-etiquette::after {
	content: "";
	display: block;
	inline-size: 2rem;
	block-size: 1px;
	margin-block-start: var(--wp--preset--spacing--30);
	background-color: var(--ts-bordeaux);
}

@media (min-width: 900px) {
	.ts-produit__recit {
		grid-template-columns: 9rem minmax(0, 40rem);
		gap: var(--wp--preset--spacing--60);
		justify-content: center;
	}

	.ts-produit__recit-etiquette {
		position: sticky;
		inset-block-start: var(--ts-produit-ancrage);
		align-self: start;
	}
}

/* Les sections se numérotent toutes seules. Le compteur vit dans la gouttière
   que la grille réserve déjà à l'étiquette. */
.ts-produit__texte {
	counter-reset: ts-section;
}

.ts-produit__texte :is(h2, h3, h4) {
	position: relative;
	counter-increment: ts-section;
	margin-block: var(--wp--preset--spacing--50) var(--wp--preset--spacing--30);
	color: var(--wp--preset--color--contrast);
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--x-large);
	font-weight: var(--wp--custom--graisse--titres);
	letter-spacing: var(--wp--custom--approche--titre);
}

.ts-produit__texte > :first-child {
	margin-block-start: 0;
}

@media (min-width: 900px) {
	.ts-produit__texte :is(h2, h3, h4)::before {
		content: counter(ts-section, decimal-leading-zero);
		position: absolute;
		inset-inline-start: -3.4rem;
		inset-block-start: 0.55em;
		color: var(--ts-bordeaux);
		font-family: var(--wp--preset--font-family--body);
		font-size: var(--wp--preset--font-size--x-small);
		font-weight: 500;
		letter-spacing: var(--wp--custom--approche--mention);
	}
}

.ts-produit__texte p {
	color: var(--wp--preset--color--secondary);
	line-height: var(--wp--custom--interligne--texte);
}

/* Le premier paragraphe tient lieu de chapô, même si l'auteur n'a pas
   structuré son texte en titres. */
.ts-produit__texte > p:first-of-type {
	color: var(--wp--preset--color--contrast);
	font-size: var(--wp--preset--font-size--large);
	line-height: var(--wp--custom--interligne--texte);
}

/* --------------------------------------------------------------------------
   Suite de la collection
   -------------------------------------------------------------------------- */

.ts-produit__suite {
	margin-block-start: var(--wp--preset--spacing--70);
	padding-block-start: var(--wp--preset--spacing--60);
	border-block-start: 1px solid var(--ts-filet-rose);
}

.ts-produit__suite-titre {
	font-weight: var(--wp--custom--graisse--titres);
}

/* --------------------------------------------------------------------------
   Entrée de la fiche
   -------------------------------------------------------------------------- */

/* Une chorégraphie courte, en trois temps : la photo se dévoile comme on lève
   un rideau, le nom monte derrière sa ligne, puis la notice arrive, le bouton
   en dernier, qu'un reflet traverse. Tous les gestes suivent la même courbe
   très amortie : rien ne rebondit, tout se pose. Les états de départ ne sont
   portés que par les animations elles-mêmes : quand le visiteur demande moins
   de mouvement, elles sont coupées et tout s'affiche à sa place. */
@keyframes ts-rideau {
	from {
		clip-path: inset(100% 0 0 0 round var(--ts-galerie-arrondi));
	}

	/* La découpe finit au large, ombre comprise : quand elle est retirée, à
	   la fin, rien ne bouge. */
	to {
		clip-path: inset(-10% -10% -30% -10% round var(--ts-galerie-arrondi));
	}
}

@keyframes ts-installe {
	from { scale: 1.16; }
	to   { scale: 1; }
}

/* Le texte monte derrière une ligne fixe : la translation et la découpe ont
   la même base, la hauteur du bloc, et avancent du même pas. Les marges
   négatives laissent passer les accents et les jambages. */
@keyframes ts-surgit {
	from {
		clip-path: inset(-0.4em -0.2em 100% -0.2em);
		transform: translateY(100%);
	}

	to {
		clip-path: inset(-0.4em -0.2em -0.4em -0.2em);
		transform: none;
	}
}

/* Mise au point : le bloc sort du flou en montant d'un rien. */
@keyframes ts-net {
	from {
		opacity: 0;
		filter: blur(10px);
		transform: translateY(0.75rem);
	}

	to {
		opacity: 1;
		filter: none;
		transform: none;
	}
}

@keyframes ts-reflet {
	from { background-position: 130% 0; }
	to   { background-position: -30% 0; }
}

/* Les classes ts-enter du gabarit gardent l'ordre ; les gestes et le tempo
   sont propres à la fiche. */
.ts-produit .ts-enter {
	opacity: 1;
}

.ts-produit .ts-produit__fil {
	animation: ts-net 0.8s var(--ts-courbe) backwards;
}

.ts-produit .ts-produit__visuel.ts-enter {
	animation: none;
}

.ts-produit .ts-galerie__cadre,
.ts-produit .ts-galerie__attente {
	animation: ts-rideau 1.15s 0.1s var(--ts-courbe) backwards;
}

.ts-produit .ts-galerie__vue:first-child .ts-galerie__photo {
	animation: ts-installe 1.8s 0.1s var(--ts-courbe) backwards;
}

.ts-produit .ts-galerie__pellicule {
	animation: ts-monte 0.7s 0.95s var(--ts-courbe) backwards;
}

.ts-produit .ts-produit__categorie {
	animation: ts-net 0.8s 0.25s var(--ts-courbe) backwards;
}

.ts-produit .ts-produit__titre {
	animation: ts-surgit 1s 0.3s var(--ts-courbe) backwards;
}

.ts-produit .ts-produit__filet {
	transform-origin: left center;
	animation: ts-trait 1.1s 0.55s var(--ts-courbe) backwards;
}

.ts-produit .ts-produit__accroche {
	animation: ts-net 0.9s 0.6s var(--ts-courbe) backwards;
}

.ts-produit .ts-produit__prix {
	animation: ts-surgit 0.9s 0.75s var(--ts-courbe) backwards;
}

.ts-produit .ts-produit__stock {
	animation: ts-net 0.8s 0.85s var(--ts-courbe) backwards;
}

.ts-produit .ts-produit__achat {
	animation: ts-monte 0.8s 0.9s var(--ts-courbe) backwards;
}

.ts-produit .ts-produit__meta {
	animation: ts-net 0.8s 1s var(--ts-courbe) backwards;
}

/* Une fois le bouton posé, un reflet de lumière le traverse, une seule fois :
   le regard sait où aller, sans qu'un clignotement le harcèle ensuite. */
.woocommerce div.product .ts-produit__achat form.cart button.single_add_to_cart_button {
	background-image: linear-gradient(
		105deg,
		transparent 38%,
		color-mix(in srgb, var(--ts-verre-reflet) 55%, transparent) 50%,
		transparent 62%
	);
	background-position: 130% 0;
	background-repeat: no-repeat;
	background-size: 260% 100%;
	animation: ts-reflet 1.3s 1.9s var(--ts-courbe) backwards;
}

/* --------------------------------------------------------------------------
   Au défilement
   -------------------------------------------------------------------------- */

@keyframes ts-ornement {
	from { background-size: 0% 1px; }
	to   { background-size: 100% 1px; }
}

@keyframes ts-palme-pose {
	from {
		opacity: 0;
		transform: rotate(-24deg) scale(0.6);
	}

	to {
		opacity: 1;
		transform: none;
	}
}

/* Plus bas, chaque bloc s'anime quand il entre à l'écran, piloté par le
   défilement lui-même. Les navigateurs qui ne savent pas le faire montrent
   simplement le contenu. */
@supports (animation-timeline: view()) {
	/* Le trait de l'ornement s'étire de part et d'autre de la palme, qui se
	   pose en pivotant. */
	.ts-produit__ornement.wp-block-separator {
		animation: ts-ornement linear both;
		animation-timeline: view();
		animation-range: entry 10% cover 40%;
	}

	.ts-produit__ornement.wp-block-separator::after {
		animation: ts-palme-pose linear both;
		animation-timeline: view();
		animation-range: entry 20% cover 45%;
	}

	/* La description se lit comme elle arrive : chaque paragraphe, chaque
	   intertitre sort du flou à son tour. Le bloc entier ne bouge plus. */
	.ts-produit .ts-produit__recit.ts-reveal {
		animation: none;
	}

	.ts-produit__texte > * {
		animation: ts-net linear both;
		animation-timeline: view();
		animation-range: entry 0% entry 75%;
	}

	/* Les produits apparentés arrivent l'un après l'autre, en léger décalé. */
	.ts-produit__suite .wc-block-product {
		animation: ts-net linear both;
		animation-timeline: view();
		animation-range: entry 0% entry 70%;
	}

	.ts-produit__suite .wc-block-product:nth-child(3n + 2) {
		animation-range: entry 8% entry 80%;
	}

	.ts-produit__suite .wc-block-product:nth-child(3n) {
		animation-range: entry 16% entry 90%;
	}
}

/* --------------------------------------------------------------------------
   Ajout au panier
   -------------------------------------------------------------------------- */

/* panier.js envoie le formulaire en arrière-plan et pose l'état du bouton
   dans data-ts-etat. Pendant l'envoi, la pastille respire ; une fois
   l'article ajouté, le sac laisse place à une coche qui éclot d'un coup de
   ressort, le temps que le tiroir du panier s'ouvre. */
@keyframes ts-respire {
	from { transform: scale(0.86); }
	to   { transform: scale(1.04); }
}

@keyframes ts-eclot {
	from { transform: scale(0.3) rotate(-30deg); }
	to   { transform: none; }
}

.woocommerce div.product .ts-produit__achat form.cart button.single_add_to_cart_button {
	&[data-ts-etat="en-cours"] {
		cursor: progress;

		&::after {
			animation: ts-respire 0.6s var(--ts-courbe) infinite alternate;
		}
	}

	&[data-ts-etat="ajoute"]::after {
		-webkit-mask:
			url("../icones/check.svg") center / 52% no-repeat,
			linear-gradient(currentColor 0 0);
		-webkit-mask-composite: xor;
		mask:
			url("../icones/check.svg") center / 52% no-repeat exclude,
			linear-gradient(currentColor 0 0);
		animation: ts-eclot 0.6s var(--ts-ressort);
	}
}

/* --------------------------------------------------------------------------
   Écran étroit
   -------------------------------------------------------------------------- */

@media (max-width: 781px) {
	.ts-produit__entete {
		gap: var(--wp--preset--spacing--50);
	}

	/* Sur mobile, le bouton d'achat quitte la notice pour flotter en bas de
	   l'écran, dans un dock de verre, sous le pouce, comme les barres d'outils
	   des téléphones récents. Il y reste pendant toute la lecture de la page.
	   Le dock est réservé aux produits simples : le formulaire d'un produit à
	   variantes porte ses listes de choix, qui n'y auraient pas leur place. */
	.product-type-simple .ts-produit__achat form.cart {
		position: fixed;
		z-index: 20;
		inset-inline: var(--wp--preset--spacing--30);
		inset-block-end: max(
			var(--wp--preset--spacing--30),
			env(safe-area-inset-bottom)
		);
		flex-wrap: nowrap;
		margin: 0;
		padding: 0.3rem;
		border: 1px solid var(--ts-filet);
		border-radius: 999px;
		background-color: var(--ts-verre-dense);
		-webkit-backdrop-filter: var(--ts-verre-flou);
		backdrop-filter: var(--ts-verre-flou);
		box-shadow:
			inset 0 1px 0 var(--ts-verre-reflet),
			var(--ts-verre-ombre);
		animation: ts-monte 0.55s 0.3s both var(--ts-courbe);
	}

	/* Un ancêtre transformé deviendrait le repère du dock à la place de
	   l'écran : l'entrée animée de son bloc parent est donc coupée, et c'est
	   le dock lui-même qui monte. */
	.product-type-simple .ts-produit__achat.ts-enter {
		opacity: 1;
		animation: none;
	}

	/* Le site se termine plus haut de la hauteur du dock : en fin de page, il
	   ne masque rien du pied de page. */
	.product-type-simple .wp-site-blocks {
		padding-block-end: calc(
			var(--ts-bouton-hauteur) + 0.6rem + 2 * var(--wp--preset--spacing--30)
		);
	}

	/* Deux verres empilés se brouillent : dans le dock, le sélecteur perd le
	   sien et ne garde que ses pastilles. */
	div.ts-produit__achat.wc-block-add-to-cart-form.wc-block-add-to-cart-form--stepper
		form.cart
		div.wc-block-components-quantity-selector.quantity {
		border-color: transparent;
		background-color: transparent;
		-webkit-backdrop-filter: none;
		backdrop-filter: none;
		box-shadow: none;
	}

	.woocommerce div.product .ts-produit__achat form.cart button.single_add_to_cart_button {
		flex-basis: 0;
		padding-inline-start: 1.2rem;
		font-size: var(--wp--preset--font-size--small);
	}
}

/* Sous 400 px, la pastille du sac ferait déborder le dock : le libellé seul
   suffit. */
@media (max-width: 399px) {
	.woocommerce div.product .ts-produit__achat form.cart button.single_add_to_cart_button {
		justify-content: center;
		padding-inline-end: 1.2rem;

		&::after {
			content: none;
		}
	}
}

/* ==========================================================================
   Divers
   ========================================================================== */

.wp-block-quote {
	padding-inline-start: var(--wp--preset--spacing--40);
}

img,
video {
	max-inline-size: 100%;
	block-size: auto;
}

/* ==========================================================================
   Mouvement réduit
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
	/* Le visiteur a demandé moins de mouvement : les animations posées en
	   style en ligne ou par des sélecteurs plus précis s'arrêtent aussi. */
	*,
	*::before,
	*::after {
		animation: none !important;
		transition: none !important;
	}

	.ts-enter {
		opacity: 1;
	}

	/* Ces deux éléments naissent à opacity 0 et comptent sur leur animation
	   pour apparaître. Sans cette règle ils resteraient invisibles. */
	.ts-palme {
		opacity: var(--ts-palme-opacite);
	}
}

/* ==========================================================================
   Mobile
   ========================================================================== */

@media (max-width: 600px) {
	/* Vingt palmes saturent un écran étroit, même réduites : on n'en garde
	   qu'une sur deux. */
	.ts-palme:nth-child(even) {
		display: none;
	}

	/* Le rythme se resserre pour que tout tienne dans une hauteur d'écran. */
	.ts-lancement__contenu {
		--ts-gap-bloc: clamp(0.8rem, 2.2vh, 1.4rem);
		--ts-gap-ligne: 0.5rem;
		--ts-gap-serre: 0.25rem;
	}

	/* Les quatre pictogrammes tiennent sur une seule rangée d'un écran de
	   375 px : icônes de 24 px et écarts resserrés. */
	.ts-benefices {
		gap: 0.5rem;
	}

	.ts-benefice img {
		inline-size: 24px;
	}

	.ts-benefice span {
		font-size: var(--wp--preset--font-size--x-small);
		line-height: var(--wp--custom--interligne--court);
	}

	.ts-lancement__pied {
		padding-block-start: var(--wp--preset--spacing--30);
		font-size: var(--wp--preset--font-size--x-small);
	}

	.ts-lancement .wp-block-separator {
		block-size: 18px;
	}
}
