/* ==========================================================
   Gamme de produits — v2.1.0

   Architecture en deux blocs :
     .gr-products__left   arc + un <li class="gr-products__item">
                           par produit (point + image + CTA)
     .gr-products__right  trait vertical + liste des noms

   Chaque item = un point TOUJOURS visible (même sans image), une
   image estompée qui grossit sur l'actif, et un CTA qui n'apparaît
   que sur l'actif. Point et image partagent le même point d'ancrage
   sur l'arc — l'image est en plus décalée d'un écart réglable et
   ancrée par son bord DROIT, pas son centre : elle grossit vers la
   gauche sans faire bouger son point de départ sur l'arc.

   Toutes les leçons apprises en v1.x appliquées dès l'écriture :
   - transform-origin:0 0 explicite sur tout élément tourné
   - aucune règle "mode grille" non scopée avec :not(--orbit) sur
     une propriété que le mode cercle pilote dynamiquement
   - l'opacité par distance passe par une variable CSS DÉDIÉE
     (--gr-item-op), jamais directement en `opacity` inline — un
     `opacity` de feuille de style en !important bat toujours un
     style inline classique, quelle que soit la spécificité
   - la hauteur de ligne de la liste est mesurée sur l'élément réel
     rendu, jamais lue depuis une variable CSS via getComputedStyle
     (qui renvoie la chaîne brute déclarée, pas une valeur en px)
   - l'arc et les points/images partagent un centre UNIQUE, dérivé
     directement de la largeur de colonne (right:0 pour l'arc,
     right:var(--gr-radius-px) pour les items) — impossible qu'ils
     divergent
   ========================================================== */

.gr-products {
	--gr-accent: #FF0000;
	--gr-line: rgba(255, 255, 255, .25);
	--gr-idle: .45;
	--gr-dot: 8px;
	--gr-radius-px: 0px;    /* calculé en JS */
	--gr-row-h: 3.5rem;     /* hauteur d'une ligne de la liste */
}

/* ==========================================================
   Mode grille (défaut / mobile / sans JS)
   ========================================================== */

.gr-products.gr-products {
	position: relative !important;
	margin: 0 !important;
	color: #fff !important;
}

.gr-products.gr-products .gr-products__arc {
	display: none !important;
}

.gr-products.gr-products .gr-products__head {
	margin: 0 0 2rem !important;
	padding: 0 1.25rem !important;
}

.gr-products.gr-products .gr-products__title {
	margin: 0 0 .5rem !important;
	padding: 0 !important;
	color: #fff !important;
	font-size: clamp(1.5rem, 3vw, 2.25rem) !important;
	line-height: 1.15 !important;
}

.gr-products.gr-products .gr-products__subtitle {
	margin: 0 !important;
	padding: 0 !important;
	color: rgba(255, 255, 255, .65) !important;
	font-size: .9375rem !important;
	line-height: 1.5 !important;
}

.gr-products.gr-products .gr-products__stage {
	display: block !important;
	height: auto !important;
	padding: 0 1.25rem !important;
}

.gr-products.gr-products:not(.gr-products--orbit) .gr-products__left,
.gr-products.gr-products:not(.gr-products--orbit) .gr-products__right {
	position: static !important;
	width: auto !important;
	height: auto !important;
	overflow: visible !important;
}

.gr-products.gr-products .gr-products__items {
	display: grid !important;
	grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr)) !important;
	gap: 1.5rem !important;
	margin: 0 0 2.5rem !important;
	padding: 0 !important;
	list-style: none !important;
}

.gr-products.gr-products:not(.gr-products--orbit) .gr-products__item {
	position: static !important;
	opacity: 1 !important;
	transform: none !important;
	list-style: none !important;
	display: flex !important;
	flex-direction: column !important;
	align-items: center !important;
	gap: .5rem !important;
}

.gr-products.gr-products .gr-products__image {
	display: flex !important;
	align-items: center !important;
	justify-content: center !important;
	width: 100% !important;
	height: 8rem !important;
	margin: 0 !important;
	padding: .5rem !important;
	background: rgba(255, 255, 255, .04) !important;
	border: 1px solid rgba(255, 255, 255, .1) !important;
	border-radius: 4px !important;
}

.gr-products.gr-products .gr-products__image img {
	display: block !important;
	max-width: 100% !important;
	max-height: 100% !important;
	width: auto !important;
	height: auto !important;
	object-fit: contain !important;
}

.gr-products.gr-products .gr-products__cta-link {
	display: inline-flex !important;
	align-items: center !important;
	gap: .5rem !important;
	color: #fff !important;
	font-size: .8125rem !important;
	text-decoration: none !important;
}

.gr-products.gr-products .gr-products__cta-icon {
	color: var(--gr-accent) !important;
}

.gr-products.gr-products .gr-products__spine {
	display: none !important;
}

.gr-products.gr-products:not(.gr-products--orbit) .gr-products__list {
	position: static !important;
	height: auto !important;
	overflow: visible !important;
	mask-image: none !important;
	-webkit-mask-image: none !important;
}

.gr-products.gr-products:not(.gr-products--orbit) .gr-products__list-track {
	display: block !important;
	transform: none !important;
}

.gr-products.gr-products .gr-products__row {
	display: flex !important;
	align-items: center !important;
	gap: .75rem !important;
	margin: 0 !important;
	padding: 0 !important;
}

.gr-products.gr-products:not(.gr-products--orbit) .gr-products__row + .gr-products__row {
	margin-top: .5rem !important;
}

.gr-products.gr-products .gr-products__tick {
	display: none !important;
}

.gr-products.gr-products .gr-products__name {
	margin: 0 !important;
	padding: .5rem 0 !important;
	background: none !important;
	border: 0 !important;
	color: rgba(255, 255, 255, .55) !important;
	font: inherit !important;
	font-size: 1.0625rem !important;
	text-align: left !important;
	cursor: default !important;
}

.gr-products.gr-products .gr-products__name.is-active {
	color: #fff !important;
	font-weight: 600 !important;
}

/* ==========================================================
   Mode cercle — classe ajoutée par le JS une fois la géométrie
   mesurée
   ========================================================== */

.gr-products.gr-products--orbit .gr-products__stage {
	display: grid !important;
	grid-template-columns: var(--gr-arc-x) 1fr !important;
	height: var(--gr-height, 80vh) !important;
	padding: 0 !important;
}

/* ----------------------------------------------------------
   Colonne gauche
   ---------------------------------------------------------- */

.gr-products.gr-products--orbit .gr-products__left {
	position: relative !important;
	grid-column: 1 !important;
	height: 100% !important;
	overflow: hidden !important;
}

/* L'arc : son bord DROIT touche exactement la frontière entre les
   deux colonnes. */
.gr-products.gr-products--orbit .gr-products__arc {
	display: block !important;
	position: absolute !important;
	top: 50% !important;
	left: 0 !important;
	z-index: 1 !important;
	width: calc(var(--gr-radius-px) * 2) !important;
	height: calc(var(--gr-radius-px) * 2) !important;
	margin: 0 !important;
	transform: translateY(-50%) !important;
	border: 1px solid var(--gr-line) !important;
	border-radius: 50% !important;
	pointer-events: none !important;

	/*
	 * Fondu combiné (haut/bas + fondu horizontal DOUBLE) via UN SEUL
	 * masque SVG, pas via mask-composite (support peu fiable constaté
	 * sur ce projet — la valeur "intersect" était reconnue par
	 * getComputedStyle mais sans effet visible). Deux rectangles
	 * dégradés superposés, combinés avec mix-blend-mode:multiply :
	 * leurs luminances se multiplient, équivalent à une intersection.
	 *
	 * Le dégradé horizontal a DEUX zones de fondu, pas une seule
	 * (miroir de la version précédente — inversé sur demande) :
	 *  - 80% à 100% : le côté proche de la liste s'éteint en
	 *    l'approchant, comme demandé à l'origine.
	 *  - ~57% à 69% puis 69% à 100% : le côté opposé de l'arc, celui
	 *    qui dépasse le bord de sa colonne et se fait couper net par
	 *    l'overflow, disparaît avant la coupure plutôt que de laisser
	 *    un bord tranché visible.
	 * Les deux pourcentages de la première zone sont calés sur la
	 * géométrie par défaut (colonne à 55%, rayon à 72%) ; si ces deux
	 * réglages changent beaucoup, le point de coupure réel se déplace
	 * et ces valeurs peuvent avoir besoin d'être réajustées.
	 */
	mask-image: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%22100%22 height=%22100%22 viewBox=%220 0 100 100%22 preserveAspectRatio=%22none%22%3E%3Cdefs%3E%3ClinearGradient id=%22v%22 x1=%220%22 y1=%220%22 x2=%220%22 y2=%221%22%3E%3Cstop offset=%220%22 stop-color=%22%23000%22/%3E%3Cstop offset=%220.14%22 stop-color=%22%23fff%22/%3E%3Cstop offset=%220.86%22 stop-color=%22%23fff%22/%3E%3Cstop offset=%221%22 stop-color=%22%23000%22/%3E%3C/linearGradient%3E%3ClinearGradient id=%22h%22 x1=%220%22 y1=%220%22 x2=%221%22 y2=%220%22%3E%3Cstop offset=%220%22 stop-color=%22%23000%22/%3E%3Cstop offset=%220.2%22 stop-color=%22%23fff%22/%3E%3Cstop offset=%220.57%22 stop-color=%22%23fff%22/%3E%3Cstop offset=%220.69%22 stop-color=%22%23000%22/%3E%3Cstop offset=%221%22 stop-color=%22%23000%22/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width=%22100%22 height=%22100%22 fill=%22url(%23v)%22/%3E%3Crect width=%22100%22 height=%22100%22 fill=%22url(%23h)%22 style=%22mix-blend-mode:multiply%22/%3E%3C/svg%3E");
	-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%22100%22 height=%22100%22 viewBox=%220 0 100 100%22 preserveAspectRatio=%22none%22%3E%3Cdefs%3E%3ClinearGradient id=%22v%22 x1=%220%22 y1=%220%22 x2=%220%22 y2=%221%22%3E%3Cstop offset=%220%22 stop-color=%22%23000%22/%3E%3Cstop offset=%220.14%22 stop-color=%22%23fff%22/%3E%3Cstop offset=%220.86%22 stop-color=%22%23fff%22/%3E%3Cstop offset=%221%22 stop-color=%22%23000%22/%3E%3C/linearGradient%3E%3ClinearGradient id=%22h%22 x1=%220%22 y1=%220%22 x2=%221%22 y2=%220%22%3E%3Cstop offset=%220%22 stop-color=%22%23000%22/%3E%3Cstop offset=%220.2%22 stop-color=%22%23fff%22/%3E%3Cstop offset=%220.57%22 stop-color=%22%23fff%22/%3E%3Cstop offset=%220.69%22 stop-color=%22%23000%22/%3E%3Cstop offset=%221%22 stop-color=%22%23000%22/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width=%22100%22 height=%22100%22 fill=%22url(%23v)%22/%3E%3Crect width=%22100%22 height=%22100%22 fill=%22url(%23h)%22 style=%22mix-blend-mode:multiply%22/%3E%3C/svg%3E");
	mask-size: 100% 100% !important;
	-webkit-mask-size: 100% 100% !important;
	mask-repeat: no-repeat !important;
	-webkit-mask-repeat: no-repeat !important;
}

/* Les items : ancrage de rotation = le centre du MÊME cercle que
   l'arc, soit --gr-radius-px depuis le bord GAUCHE de la colonne
   (même référence que .gr-products__arc, ci-dessus). */
.gr-products.gr-products--orbit .gr-products__items {
	display: block !important;
	position: absolute !important;
	top: 50% !important;
	left: 75px !important;
	z-index: 2 !important;
	width: 0 !important;
	height: 0 !important;
	margin: 0 !important;
	padding: 0 !important;
	list-style: none !important;
}

.gr-products.gr-products--orbit .gr-products__item {
	position: absolute !important;
	top: 0 !important;
	left: 0 !important;
	margin: 0 !important;
	padding: 0 !important;
	list-style: none !important;
	/* OBLIGATOIRE : sans ça la rotation pivote autour du centre de la
	   boîte de l'élément et non du centre du cercle — bug déjà
	   rencontré et corrigé deux fois sur ce projet. */
	transform-origin: 0 0 !important;
	/* Le JS calcule cette opacité par distance à l'actif et l'écrit
	   dans --gr-item-op, JAMAIS directement dans `opacity` en style
	   inline : cette règle porte déjà `opacity` en !important, qui
	   bat toujours un style inline classique quelle que soit la
	   spécificité (bug déjà rencontré sur `transform` — voir le
	   changelog 1.2.2 de ce plugin). Passer par une variable que
	   cette règle CONSOMME évite de reproduire le même piège. */
	opacity: var(--gr-item-op, 1) !important;
	transition: transform .5s cubic-bezier(.4, 0, .2, 1), opacity .4s ease !important;
	/* le JS écrit le transform final (rotation + rayon) à chaque
	   changement d'actif */
}

.gr-products.gr-products--orbit .gr-products__item.is-hidden {
	pointer-events: none !important;
}

/* ----------------------------------------------------------
   L'image — ancrée par son bord DROIT au même point que le
   marqueur, décalée d'un écart fixe indépendant de la taille.
   Elle grandit vers la GAUCHE sur l'actif, son point d'ancrage
   ne bouge jamais.
   ---------------------------------------------------------- */

.gr-products.gr-products--orbit .gr-products__image {
	display: block !important;
	position: absolute !important;
	top: 0 !important;
	left: 0 !important;
	z-index: 2 !important;
	width: 5rem !important;
	height: 5rem !important;
	/* Uncode applique souvent max-width:100% sur les <figure> pour du
	   responsive. .gr-products__item est une boîte 0×0 (tous ses
	   enfants sont en position absolue) : max-width:100% s'y calcule
	   comme 100% de 0 = 0px, ce qui écrasait notre largeur explicite
	   tout en laissant height intacte (pas de max-height équivalent)
	   — d'où des images invisibles malgré une hauteur correcte. */
	max-width: none !important;
	max-height: none !important;
	margin: 0 !important;
	padding: 0 !important;
	background: none !important;
	border: 0 !important;
	border-radius: 0 !important;
	cursor: pointer !important;
	pointer-events: auto !important;
	transform: translate( calc( -100% - var( --gr-media-gap, 24px ) ), -50% ) rotate( var( --gr-counter-rot, 0deg ) ) !important;
	transition: width .5s ease, height .5s ease !important;
}

.gr-products.gr-products--orbit .gr-products__item.is-active .gr-products__image {
	width: var(--gr-media-size, 280px) !important;
	height: var(--gr-media-size, 280px) !important;
	/* écart propre à l'actif, plus grand pour le recentrer vers le
	   milieu du cercle — les inactifs, eux, restent proches de leur
	   point sur l'arc avec le petit écart de la règle ci-dessus. */
	transform: translate( calc( -100% - var( --gr-media-gap-active, 160px ) ), -50% ) rotate( var( --gr-counter-rot, 0deg ) ) !important;
}

.gr-products.gr-products--orbit .gr-products__image img {
	display: block !important;
	width: 100% !important;
	height: 100% !important;
	max-width: none !important;
	max-height: none !important;
	/* Uncode applique parfois un opacity:0 global à ses <img> pour son
	   propre effet d'apparition au chargement (lazy-reveal). Sans ce
	   garde-fou explicite, l'image existe dans le DOM mais reste
	   invisible en permanence si Uncode gagne cette bataille de
	   spécificité sur la balise <img> elle-même. */
	opacity: 1 !important;
	object-fit: contain !important;
	object-position: right center !important;
}

/* ----------------------------------------------------------
   Le CTA — n'apparaît que sur l'actif, sous l'image.
   ---------------------------------------------------------- */

.gr-products.gr-products--orbit .gr-products__cta-link {
	display: inline-flex !important;
	position: absolute !important;
	top: calc(var(--gr-media-size, 280px) / 2 + 14px) !important;
	right: calc(var(--gr-media-gap-active, 160px) + var(--gr-media-size, 280px) * .55) !important;
	z-index: 3 !important;
	align-items: center !important;
	gap: .625rem !important;
	margin: 0 !important;
	padding: 0 !important;
	opacity: 0 !important;
	color: #fff !important;
	font-size: .8125rem !important;
	text-decoration: none !important;
	white-space: nowrap !important;
	pointer-events: none !important;
	transition: opacity .4s ease !important;
}

.gr-products.gr-products--orbit .gr-products__item.is-active .gr-products__cta-link {
	opacity: 1 !important;
	pointer-events: auto !important;
}

.gr-products.gr-products--orbit .gr-products__cta-icon {
	display: inline-flex !important;
	align-items: center !important;
	justify-content: center !important;
	width: 1.25rem !important;
	height: 1.25rem !important;
	color: var(--gr-accent) !important;
	font-size: 1rem !important;
	line-height: 1 !important;
}

/* ----------------------------------------------------------
   Colonne droite : trait vertical + liste des noms
   ---------------------------------------------------------- */

.gr-products.gr-products--orbit .gr-products__right {
	position: relative !important;
	grid-column: 2 !important;
	height: 100% !important;
	padding: 0 0 0 2.5rem !important;
}

.gr-products.gr-products--orbit .gr-products__spine {
	display: block !important;
	position: absolute !important;
	/* même boîte que .gr-products__list : sans ça, le trait ne
	   correspond pas à l'étendue réelle des lignes visibles — les
	   deux utilisaient des systèmes de dimensionnement différents
	   (pourcentages de toute la colonne vs hauteur de ligne fixe). */
	top: 50% !important;
	left: 0 !important;
	width: 1px !important;
	height: calc(var(--gr-row-h) * (2 * var(--gr-visible-side, 2) + 1)) !important;
	margin: 0 !important;
	transform: translateY(-50%) !important;
	background: var(--gr-line) !important;
}

.gr-products.gr-products--orbit .gr-products__list {
	position: absolute !important;
	top: 50% !important;
	left: 0 !important;
	right: 1.5rem !important;
	height: calc(var(--gr-row-h) * (2 * var(--gr-visible-side, 2) + 1)) !important;
	margin: 0 !important;
	overflow: hidden !important;
	transform: translateY(-50%) !important;

	-webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 14%, #000 86%, transparent 100%);
	        mask-image: linear-gradient(to bottom, transparent 0, #000 14%, #000 86%, transparent 100%);
}

.gr-products.gr-products--orbit .gr-products__list-track {
	display: block !important;
	margin: 0 !important;
	padding: 0 !important;
	transition: transform .5s cubic-bezier(.4, 0, .2, 1) !important;
}

.gr-products.gr-products--orbit .gr-products__row {
	display: flex !important;
	align-items: center !important;
	gap: 1rem !important;
	height: var(--gr-row-h) !important;
	margin: 0 !important;
	padding: 0 !important;
}

.gr-products.gr-products--orbit .gr-products__tick {
	display: block !important;
	flex: 0 0 auto !important;
	width: 1.25rem !important;
	height: 1px !important;
	margin: 0 !important;
	background: var(--gr-line) !important;
	transition: background-color .3s ease, width .3s ease !important;
}

.gr-products.gr-products--orbit .gr-products__row.is-active .gr-products__tick {
	width: 2rem !important;
	background: #fff !important;
}

.gr-products.gr-products--orbit .gr-products__name {
	display: block !important;
	flex: 1 1 auto !important;
	margin: 0 !important;
	padding: 0 !important;
	overflow: hidden !important;
	background: none !important;
	border: 0 !important;
	color: rgba(255, 255, 255, .45) !important;
	font: inherit !important;
	font-size: 1.375rem !important;
	line-height: 1.2 !important;
	text-align: left !important;
	text-overflow: ellipsis !important;
	white-space: nowrap !important;
	cursor: pointer !important;
	transition: color .3s ease !important;
}

.gr-products.gr-products--orbit .gr-products__name.is-active {
	color: #fff !important;
	font-weight: 600 !important;
}

.gr-products.gr-products--orbit .gr-products__name:focus-visible {
	outline: 2px solid #fff !important;
	outline-offset: -2px !important;
}

@media (prefers-reduced-motion: reduce) {
	.gr-products.gr-products--orbit .gr-products__item,
	.gr-products.gr-products--orbit .gr-products__image,
	.gr-products.gr-products--orbit .gr-products__cta-link,
	.gr-products.gr-products--orbit .gr-products__list-track,
	.gr-products.gr-products--orbit .gr-products__name,
	.gr-products.gr-products--orbit .gr-products__tick {
		transition: none !important;
	}
}

/* ----------------------------------------------------------
   Écrans intermédiaires
   ---------------------------------------------------------- */

@media (min-width: 1024px) and (max-width: 1279px) {
	.gr-products.gr-products--orbit .gr-products__item.is-active .gr-products__image {
		width: calc(var(--gr-media-size, 280px) * .75) !important;
		height: calc(var(--gr-media-size, 280px) * .75) !important;
	}

	.gr-products.gr-products--orbit .gr-products__name {
		font-size: 1.125rem !important;
	}
}
