/*
 * La barre du haut vit DANS LE FLUX du document : premier enfant de <body>,
 * donc l'en-tête se place naturellement en dessous, sans marge posée en JS,
 * sans hauteur mesurée, sans rien à synchroniser. Tout le reste en découle —
 * voir l'en-tête de class-render.php pour le raisonnement complet.
 *
 * "relative" et non "static" : le rendu en flux est identique, mais la barre
 * reste un repère de positionnement valide pour ce qu'elle contient en absolu
 * (la croix de fermeture sur mobile). En "static", cette croix se positionne
 * par rapport à la page entière.
 */
.fleet-topbar {
	position: relative;
	z-index: 9990;
	height: var(--fleet-topbar-height, 44px);
	background-color: var(--fleet-topbar-bg, #0693e3);
	color: var(--fleet-topbar-text, #fff);
	font-size: var(--fleet-topbar-font-size, 14px);
	font-family: var(--fleet-topbar-font-family, inherit);
	display: flex;
	align-items: center;
	/* Indispensable au repli : c'est ce qui masque le contenu pendant que la
	   hauteur descend à 0, et ce qui clippe le glissement de .__inner. */
	overflow: hidden;
	box-sizing: border-box;
	transition: height 0.45s ease-in-out, opacity 0.35s ease;
}

/*
 * Réglage "Flottante" (admin) : la seule chose qui change est la façon dont la
 * barre suit le scroll. Elle continue d'occuper sa place dans le flux, donc
 * l'apparition, la poussée du contenu et la fermeture sont rigoureusement
 * identiques qu'elle soit flottante ou non — c'est tout l'intérêt de sticky
 * plutôt que fixed ici : fixed sort du flux et obligerait à recréer la place
 * occupée à la main.
 *
 * Prérequis mesuré sur la flotte : aucun ancêtre ne doit être un conteneur de
 * défilement immobile. Une règle `html{overflow-x:hidden}` sous 767px le
 * provoquait ; elle est neutralisée en `clip` à la volée, uniquement quand ce
 * mode est actif — voir Render::sticky_enabler_css() pour la démonstration.
 */
.fleet-topbar--floating {
	position: sticky;
	top: 0;
}

/*
 * La position "bas" ne peut pas être dans le flux : la barre est rendue en
 * haut du DOM (wp_body_open), un bloc normal se retrouverait donc en haut de
 * page. Elle reste en fixed — et c'est le seul cas où il faut recréer la place
 * occupée par une marge sur <body> (voir frontend.js).
 */
.fleet-topbar--bottom {
	position: fixed;
	left: 0;
	right: 0;
	bottom: 0;
	z-index: 99990;
}

/*
 * Grille à 3 colonnes pour un centrage réel du texte, peu importe ce qu'il y a
 * à droite (countdown/bouton/croix, une combinaison des trois, ou rien).
 * .fleet-topbar__spacer est un clone invisible (inert) du même contenu que
 * .fleet-topbar__actions — les deux colonnes "auto" sont donc forcément de
 * largeur identique (même contenu = même taille intrinsèque), ce qui centre
 * .fleet-topbar__content sans avoir à mesurer quoi que ce soit en JS. Le
 * texte central est en minmax(0,1fr) (pas "auto") pour prendre tout l'espace
 * restant — son propre contenu est en position absolue donc ne contribue à
 * aucune taille intrinsèque, un "auto" s'effondrerait à 0.
 */
.fleet-topbar__inner {
	width: 100%;
	max-width: 1400px;
	margin: 0 auto;
	padding: 0 40px;
	display: grid;
	grid-template-columns: auto minmax(0, 1fr) auto;
	align-items: center;
	gap: 16px;
	position: relative;
	box-sizing: border-box;
}

.fleet-topbar__spacer {
	visibility: hidden;
	display: flex;
	align-items: center;
	gap: 16px;
	justify-self: start;
}

.fleet-topbar__actions {
	display: flex;
	align-items: center;
	gap: 16px;
	justify-self: end;
}

.fleet-topbar__content {
	min-width: 0;
	overflow: hidden;
	text-align: center;
}

.fleet-topbar__static {
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	display: inline-block;
	max-width: 100%;
}

.fleet-topbar__static strong { font-weight: 700; }

/*
 * Mode "texte fixe" à 3 zones (gauche/centre/droite) — seulement rendu quand
 * gauche et/ou droite sont renseignés côté admin (voir class-render.php) ;
 * sinon on garde le simple span centré d'avant, inchangé. Même technique de
 * centrage que .fleet-topbar__inner (1fr auto 1fr) : le centre reste
 * visuellement centré sur toute la barre quelle que soit la largeur de
 * gauche/droite, sans avoir à les mesurer.
 */
.fleet-topbar__static-group {
	display: grid;
	grid-template-columns: 1fr auto 1fr;
	align-items: center;
	width: 100%;
	gap: 12px;
}

.fleet-topbar__static--left { justify-self: start; text-align: left; }
.fleet-topbar__static--center { justify-self: center; text-align: center; }
.fleet-topbar__static--right { justify-self: end; text-align: right; }

/*
 * En dessous de 900px (tablette comprise, ex. iPad mini 768px — testé et confirmé
 * tronqué par Mitch, 2026-09-21), 3 textes côte à côte n'ont plus la place de
 * respirer : gauche/droite se tronquent au lieu de rester lisibles. On ne garde
 * que le centre, comme sur mobile plus étroit. Breakpoint DÉLIBÉRÉMENT séparé de
 * celui plus bas (600px, voir plus loin) qui gère le repli countdown/bouton/croix
 * — ce sont deux problèmes différents, pas de raison de les coupler.
 */
@media screen and (max-width: 900px) {
	.fleet-topbar__static--left,
	.fleet-topbar__static--right {
		display: none;
	}

	.fleet-topbar__static-group {
		grid-template-columns: 1fr;
	}
}

/*
 * Lisibilité sur fond image. Deux traitements différents selon la nature du
 * texte :
 * - Le texte central (statique/défilement/rotation) : un halo (text-shadow
 *   empilé) plutôt qu'un fond en boîte — un pavé rectangulaire autour d'une
 *   phrase entière est moche (essayé, rejeté). Le halo suit le texte partout
 *   où il va, y compris en plein défilement, sans jamais dessiner de bord.
 * - Les unités du countdown (j/h/m/s) : un petit badge reste adapté, elles
 *   sont déjà courtes (1 caractère), pas de "pavé" possible à cette taille.
 * Posé uniquement quand une image de fond est réglée (voir
 * fleet-topbar--has-bg-image dans class-render.php) — jamais sur un fond de
 * couleur unie où ce n'est pas nécessaire.
 */
.fleet-topbar--has-bg-image .fleet-topbar__static,
.fleet-topbar--has-bg-image .fleet-topbar__msg,
.fleet-topbar--has-bg-image .fleet-topbar__rotate-text,
.fleet-topbar--has-bg-image .fleet-topbar__countdown-label {
	text-shadow: 0 2px 4px var(--fleet-topbar-text-shadow-color, rgba(0, 0, 0, 0.8));
}

/* Couleur pensée pour du texte clair sur fond sombre — sur un fond clair
   avec du texte foncé, la couleur/opacité par défaut ne conviennent pas,
   d'où le réglage admin (text_shadow_enabled) plutôt qu'un choix figé. */
.fleet-topbar--text-shadow-off .fleet-topbar__static,
.fleet-topbar--text-shadow-off .fleet-topbar__msg,
.fleet-topbar--text-shadow-off .fleet-topbar__rotate-text,
.fleet-topbar--text-shadow-off .fleet-topbar__countdown-label {
	text-shadow: none !important;
}

/*
 * Icônes {icon:nom} (voir Coupon::apply_icons). Dimensionnées en `em` pour
 * suivre font_size sans qu'on ait à le recalculer : la barre tourne de 14 à
 * 18px selon les presets. Les attributs width/height du HTML ne servent qu'à
 * réserver le ratio avant chargement — c'est le CSS qui décide de la taille.
 */
.fleet-topbar__icon {
	/* Shoptimizer pose `img { display: block }` globalement : sans ce rappel,
	   l'icône passe en bloc et jette le texte à la ligne suivante, dans un
	   conteneur qui fait 1.4em de haut en overflow:hidden — l'image apparaît
	   seule et la phrase est coupée. Mesuré sur melvat, pas déduit. */
	display: inline-block;
	height: 1.05em;
	width: auto;
	vertical-align: -0.15em;
	/* Ne jamais rétrécir : c'est le texte qui absorbe la contrainte de place,
	   une icône écrasée est illisible (même logique que le libellé du
	   countdown). */
	flex-shrink: 0;
}

/* Pas de halo sur les icônes, contrairement au texte : une Noto Emoji porte
   déjà ses propres contours foncés et se détache seule sur n'importe quel
   fond. Le drop-shadow ajouté par symétrie avec le texte ne faisait que
   l'encrasser (constaté par Mitch sur le preset Noël, 2026-09-24). */

.fleet-topbar--has-bg-image .fleet-topbar__countdown em {
	background: rgba(0, 0, 0, 0.35);
	padding: 0.15em 0.5em;
	border-radius: 4px;
}

/* Défilement continu : contenu dupliqué, translateX(-50%) en boucle */
.fleet-topbar__marquee {
	overflow: hidden;
	width: 100%;
}

.fleet-topbar__marquee-track {
	display: inline-flex;
	white-space: nowrap;
	animation: fleet-topbar-marquee-ltr var(--fleet-topbar-marquee-duration, 20s) linear infinite;
	will-change: transform;
}

.fleet-topbar__marquee--rtl .fleet-topbar__marquee-track {
	animation-name: fleet-topbar-marquee-rtl;
}

.fleet-topbar__marquee-track span {
	white-space: nowrap;
}

.fleet-topbar__sep {
	margin: 0 1.5em;
	opacity: 0.6;
}

/* "ltr" (Gauche -> Droite) = le texte visible se déplace vers la droite. */
@keyframes fleet-topbar-marquee-ltr {
	from { transform: translateX(-50%); }
	to   { transform: translateX(0); }
}

/* "rtl" (Droite -> Gauche) = le texte visible se déplace vers la gauche. */
@keyframes fleet-topbar-marquee-rtl {
	from { transform: translateX(0); }
	to   { transform: translateX(-50%); }
}

/*
 * Rotation : un seul message à la fois. Le JS ne réutilise jamais un élément
 * existant — à chaque cycle il en crée un nouveau (le précédent est retiré),
 * ce qui déclenche naturellement l'animation d'entrée à l'insertion. Rien à
 * repositionner, rien à "réinitialiser" : pas d'état intermédiaire possible.
 */
.fleet-topbar__rotate {
	position: relative;
	height: 1.4em;
	overflow: hidden;
}

.fleet-topbar__rotate-item {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	white-space: nowrap;
}

.fleet-topbar__rotate-item.is-entering {
	animation: fleet-topbar-rotate-enter var(--fleet-topbar-rotate-duration, 0.5s) ease-in-out;
}

/*
 * L'élément sortant reste en vie le temps de son animation de sortie (au lieu
 * d'être retiré instantanément) — voir initRotate() dans frontend.js, qui le
 * retire sur l'événement "animationend" plutôt qu'un délai dupliqué en dur.
 * forwards : reste dans son état final (translaté + transparent) le temps que
 * le JS le retire, pas de retour visuel à l'état de départ.
 */
.fleet-topbar__rotate-item.is-leaving {
	animation: fleet-topbar-rotate-leave var(--fleet-topbar-rotate-duration, 0.5s) ease-in-out forwards;
}

/* Le sortant continue le même mouvement que l'entrant (effet "tapis roulant") : il part du côté opposé à celui d'où arrive le suivant. */
.fleet-topbar__rotate--right .fleet-topbar__rotate-item.is-entering { --rotate-from: translateX(100%); }
.fleet-topbar__rotate--right .fleet-topbar__rotate-item.is-leaving  { --rotate-to: translateX(-100%); }
.fleet-topbar__rotate--left .fleet-topbar__rotate-item.is-entering { --rotate-from: translateX(-100%); }
.fleet-topbar__rotate--left .fleet-topbar__rotate-item.is-leaving  { --rotate-to: translateX(100%); }
.fleet-topbar__rotate--up .fleet-topbar__rotate-item.is-entering { --rotate-from: translateY(100%); }
.fleet-topbar__rotate--up .fleet-topbar__rotate-item.is-leaving  { --rotate-to: translateY(-100%); }
.fleet-topbar__rotate--down .fleet-topbar__rotate-item.is-entering { --rotate-from: translateY(-100%); }
.fleet-topbar__rotate--down .fleet-topbar__rotate-item.is-leaving  { --rotate-to: translateY(100%); }

@keyframes fleet-topbar-rotate-enter {
	from { transform: var(--rotate-from, translateX(100%)); opacity: 0; }
	to   { transform: translate(0, 0); opacity: 1; }
}

@keyframes fleet-topbar-rotate-leave {
	from { transform: translate(0, 0); opacity: 1; }
	to   { transform: var(--rotate-to, translateX(-100%)); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
	.fleet-topbar__marquee-track { animation: none; }
	.fleet-topbar__rotate-item.is-entering { animation: none; }
	.fleet-topbar__rotate-item.is-leaving { animation: none; }
}

/*
 * Libellé + chiffres, toujours SUR LA MÊME LIGNE (demande explicite : à côté,
 * jamais au-dessus ni en dessous). D'où `flex-wrap` laissé à sa valeur par
 * défaut (nowrap) ici, alors que .fleet-topbar__actions passe en `wrap` sur
 * mobile : ce groupe compte comme un seul élément pour elle, il peut donc
 * descendre d'une ligne entier, mais jamais se couper en deux.
 */
.fleet-topbar__countdown-group {
	display: flex;
	align-items: center;
	gap: 8px;
	/* Pas de flex-shrink:0 ici, contrairement aux chiffres plus bas : c'est le
	   libellé qui absorbe la contrainte de place, jamais le compte à rebours. */
	min-width: 0;
}

/*
 * Le libellé est volontairement HORS de .fleet-topbar__countdown : la règle
 * `.fleet-topbar__countdown span` plus bas habille tous les <span> de ce bloc
 * en pastille (fond, padding, gras) pour les chiffres, et l'emporterait sur une
 * classe simple posée à l'intérieur. Le placer à côté supprime le conflit au
 * lieu d'avoir à le défaire.
 *
 * Il rétrécit avant le countdown (`min-width: 0`) : sur un écran étroit, mieux
 * vaut rogner le libellé que faire passer les chiffres à la ligne — ce qui
 * reviendrait à le mettre au-dessus, justement ce qu'on ne veut pas.
 *
 * `max-width` est une borne volontairement simple et directe : ce champ est
 * prévu pour un texte court ("Offre valable encore", un code promo). Une
 * contrainte posée ici agit toujours, sans dépendre de la façon dont elle se
 * propage dans la grille au-dessus.
 *
 * PAS d'`overflow: hidden` ni de `text-overflow: ellipsis` ici, malgré la
 * tentation : `overflow` ne découpe pas que le texte, il découpe TOUT ce qui
 * est peint dans l'élément — le halo de lisibilité compris. Et comme la boîte
 * colle au texte, le dégradé se retrouvait tranché au ras du bord et dessinait
 * un rectangle à arêtes vives autour du libellé, là où le même halo épouse
 * joliment les lettres partout ailleurs. Diagnostiqué le 2026-09-24 : l'ombre
 * était rigoureusement identique aux deux endroits, seul `overflow` différait.
 */
.fleet-topbar__countdown-label {
	max-width: 22em;
	min-width: 0;
	white-space: nowrap;
	line-height: 1.2;
}

.fleet-topbar__countdown {
	display: flex;
	align-items: baseline;
	gap: 4px;
	font-variant-numeric: tabular-nums;
	flex-shrink: 0;
}

.fleet-topbar__countdown span {
	background: var(--fleet-topbar-cd-bg, #000);
	color: var(--fleet-topbar-cd-text, #fff);
	border-radius: 3px;
	padding: 2px 6px;
	font-weight: 700;
	min-width: 1.8em;
	text-align: center;
}

.fleet-topbar__countdown em {
	font-style: normal;
	font-size: 0.75em;
	opacity: 0.85;
	margin-right: 4px;
}

.fleet-topbar__button {
	flex-shrink: 0;
	background: var(--fleet-topbar-btn-bg, #000);
	color: var(--fleet-topbar-btn-text, #fff);
	border: none;
	border-radius: var(--fleet-topbar-btn-radius, 4px);
	padding: 9px 20px;
	font-size: 1.05em;
	font-weight: 600;
	cursor: pointer;
	text-decoration: none;
	white-space: nowrap;
	line-height: 1.4;
}

.fleet-topbar__button--bordered {
	border: 2px solid var(--fleet-topbar-btn-border-color, #fff);
}

.fleet-topbar__button--shadow {
	box-shadow: 0 4px 8px -2px rgba(0, 0, 0, 0.35);
}

/* Plat au repos, prend du relief au survol, s'enfonce au clic — pas une élévation figée en permanence. */
.fleet-topbar__button--3d {
	transition: box-shadow 0.1s ease-in-out, transform 0.1s ease-in-out;
}

.fleet-topbar__button--3d:hover {
	box-shadow: 0 5px 0 var(--fleet-topbar-btn-3d-color, #000);
	transform: translateY(-2px);
}

.fleet-topbar__button--3d:active {
	box-shadow: 0 1px 0 var(--fleet-topbar-btn-3d-color, #000);
	transform: translateY(2px);
}

.fleet-topbar__button--3d.fleet-topbar__button--shadow:hover {
	box-shadow: 0 5px 0 var(--fleet-topbar-btn-3d-color, #000), 0 8px 20px -2px rgba(0, 0, 0, 0.4);
}

.fleet-topbar__close {
	flex-shrink: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 24px;
	height: 24px;
	background: rgba(0, 0, 0, 0.4);
	border: none;
	border-radius: 50%;
	color: var(--fleet-topbar-close, #fff);
	font-size: 16px;
	line-height: 1;
	cursor: pointer;
	padding: 0;
	opacity: 0.9;
}

.fleet-topbar__close:hover { opacity: 1; }

/* Affichage desktop/mobile */
@media screen and (max-width: 782px) {
	.fleet-topbar--hide-mobile { display: none !important; }
	.fleet-topbar__inner { padding: 0 12px; gap: 8px; }
	.fleet-topbar__close--hide-mobile { display: none; }
}

@media screen and (min-width: 783px) {
	.fleet-topbar--hide-desktop { display: none !important; }
	.fleet-topbar__close--hide-desktop { display: none; }
}

/*
 * En dessous de 600px, la grille à 3 colonnes n'est plus fiable : si
 * countdown + bouton + croix sont volumineux, les deux colonnes "auto"
 * (spacer invisible + actions) peuvent réclamer plus de place que l'écran
 * n'en a, et la colonne centrale (minmax(0,1fr)) s'effondre à 0 — le texte
 * disparaît complètement alors que le fond continue de s'afficher (il est
 * sur .fleet-topbar, pas sur cette grille). On bascule donc en simple
 * empilement vertical : plus robuste qu'un centrage par colonnes miroirs à
 * cette largeur, et la hauteur devient auto pour ne jamais rien couper.
 */
@media screen and (max-width: 600px) {
	.fleet-topbar {
		height: auto;
		min-height: var(--fleet-topbar-height, 44px);
		font-size: calc(var(--fleet-topbar-font-size, 14px) * 0.92);
		padding: 8px 0;
	}

	.fleet-topbar__inner {
		display: flex;
		flex-direction: column;
		justify-content: center;
		padding: 0 12px;
		gap: 6px;
	}

	/*
	 * .fleet-topbar__actions--empty (posée côté PHP, voir class-render.php) :
	 * ni countdown ni bouton visibles, la croix a été sortie du flux
	 * (position:absolute, voir plus bas) — ce bloc n'a donc plus aucun contenu
	 * en flux, mais resterait un élément flex à part entière, autour duquel le
	 * "gap" de la colonne s'applique quand même : quelques pixels de décalage
	 * du texte par rapport au vrai centre. display:contents le fait disparaître
	 * de la mise en page (ses enfants remontent d'un cran) au lieu de
	 * compenser le symptôme avec une marge négative calée à la main sur la
	 * valeur du gap — qui redeviendrait fausse au moindre changement de gap.
	 * La croix, elle, est en absolu : elle se positionne par rapport à
	 * .fleet-topbar__inner et ne dépend pas de ce conteneur.
	 */
	.fleet-topbar__actions--empty {
		display: contents;
	}

	/* Plus besoin du clone invisible : le centrage se fait par ligne (text-align/justify-content), pas par colonnes miroirs. */
	.fleet-topbar__spacer {
		display: none;
	}

	.fleet-topbar__content {
		width: 100%;
	}

	/* Gauche/droite déjà masqués dès 900px (voir plus haut) — rien à refaire ici. */

	.fleet-topbar__actions {
		justify-content: center;
		flex-wrap: wrap;
		width: 100%;
		gap: 8px;
	}

	/* Sortie du flux pour ne jamais forcer une ligne supplémentaire ni pousser le reste. */
	.fleet-topbar__close {
		position: absolute;
		/* Centrage vertical réel, quelle que soit la hauteur de la barre (1
		   ligne, 2 lignes...) — plus de chiffre en dur (top:4px) calé pour
		   une seule hauteur et faux dès que le contenu change. */
		top: 50%;
		right: 6px;
		transform: translateY(-50%);
	}

	/*
	 * Rotation : une seule ligne (essai à 2 lignes rejeté — incohérent avec
	 * une hauteur de conteneur fixe selon que le message tienne ou non sur
	 * une ligne). Coupure propre avec "…" plutôt qu'un texte tronqué net au
	 * milieu d'un mot. min-width:0 nécessaire : un enfant flex ne peut sinon
	 * jamais rétrécir sous sa taille de contenu, la troncature ne se
	 * déclencherait jamais.
	 */
	.fleet-topbar__rotate-text {
		display: block;
		min-width: 0;
		max-width: 100%;
		overflow: hidden;
		text-overflow: ellipsis;
		white-space: nowrap;
	}

	/* Texte du contenu un peu plus petit que le reste de la barre — pas juste le facteur global 0.92, pour laisser plus de messages tenir sur une ligne avant troncature. Desktop non affecté. */
	.fleet-topbar__rotate-text,
	.fleet-topbar__msg,
	.fleet-topbar__static {
		font-size: 0.85em;
	}

	/* Countdown : trop grand hérité du seul facteur global de la barre, surtout combiné au bouton agrandi — réduction dédiée, plus marquée, uniquement ici. */
	.fleet-topbar__countdown {
		font-size: 0.78em;
		gap: 3px;
	}

	/* Même réduction pour le libellé, qui est à côté et non dedans : sans ça il
	   resterait nettement plus gros que les chiffres qu'il annonce. */
	.fleet-topbar__countdown-label {
		font-size: 0.78em;
	}

	.fleet-topbar__countdown-group {
		gap: 6px;
	}

	.fleet-topbar__countdown span {
		padding: 1px 4px;
		min-width: 1.5em;
	}
}

/*
 * ===================================================================
 * État replié — un SEUL état pour deux usages
 * ===================================================================
 * C'est à la fois l'état d'attente avant apparition (posé par PHP dès le
 * rendu, voir $pending dans class-render.php) et l'état de fermeture (posé
 * par le JS au clic sur la croix). Les deux sont le même fait : la barre
 * n'occupe aucune place. D'où une seule règle, jouée dans un sens ou dans
 * l'autre, au lieu de deux jeux de classes concurrents.
 *
 * Deux propriétés de cette approche, qui expliquent pourquoi c'est celle-ci :
 *  - hauteur nulle = aucune place réservée. Pendant l'attente, la page est
 *    exactement comme si la barre n'existait pas : pas de bandeau vide, pas
 *    de trou à combler.
 *  - c'est du CSS pur, appliqué dès la première peinture. Le JS est chargé en
 *    différé (defer, en pied de page) : tout état initial qui dépendrait de
 *    lui serait faux pendant quelques dizaines de millisecondes. Ici il n'y a
 *    rien à rattraper, l'état de départ est déjà le bon.
 *
 * Placé APRÈS le bloc mobile exprès : il doit neutraliser son height:auto,
 * son min-height et son padding vertical. C'est l'ordre du fichier qui s'en
 * charge — pas une pile de !important.
 */
.fleet-topbar--collapsed {
	height: 0;
	min-height: 0;
	padding-top: 0;
	padding-bottom: 0;
	opacity: 0;
	pointer-events: none;
}

/*
 * Effet "slide" : en plus du repli de la barre, son contenu remonte hors
 * champ (clippé par overflow:hidden). L'apparition lit donc comme un vrai
 * glissement vers le bas, et pas comme un simple déroulé. L'effet "fade" n'a
 * rien à ajouter : l'opacité de l'état replié suffit. L'effet "aucun" non
 * plus — le JS neutralise la transition le temps de l'ouverture pour qu'elle
 * soit réellement instantanée (voir expandBar() dans frontend.js).
 */
.fleet-topbar--entry-slide .fleet-topbar__inner {
	transition: transform 0.45s ease-in-out;
}

.fleet-topbar--entry-slide.fleet-topbar--collapsed .fleet-topbar__inner {
	transform: translateY(-100%);
}

.fleet-topbar--bottom.fleet-topbar--entry-slide.fleet-topbar--collapsed .fleet-topbar__inner {
	transform: translateY(100%);
}

@media (prefers-reduced-motion: reduce) {
	.fleet-topbar,
	.fleet-topbar__inner {
		transition: none;
	}
}

/*
 * Uniquement pour la barre du bas, qui est en fixed et ne peut donc pas
 * pousser le contenu elle-même : la marge est posée en JS, animée ici pour
 * rester synchrone avec le repli/dépli de la barre. La barre du haut n'a
 * jamais besoin de ça — elle est dans le flux.
 */
body {
	transition: margin-bottom 0.45s ease-in-out;
}

/* ============================================================
   Bandeau promo de la fiche produit
   Rendu par Product_Promo, inséré dans le résumé produit à la
   position 24 (après les avis, avant l'ajout au panier).
   Les variables --wcsb-* sont émises par le gestionnaire de
   couleurs de Shop Builder ; les valeurs de repli permettent au
   bandeau de rester lisible s'il est absent.
   ============================================================ */
.fleet-topbar-product-promo {
	display: inline-block;
	width: fit-content;
	max-width: 100%;
	margin: 15px 0 5px;
	padding: 6px 10px;
	border-radius: 8px;
	/* --fleet-topbar-promo-* ne sont posées sur l'élément que si la carte
	   choisit des couleurs personnalisées ; sinon on retombe sur la teinte
	   du site. Les 75 % d'opacité s'appliquent dans les deux cas : c'est ce
	   qui donne au bandeau sa légèreté sur la fiche produit. */
	background-color: color-mix(in srgb, var(--fleet-topbar-promo-bg, var(--wcsb-button-primary-bg, var(--wcsb-primary-color, #2271b1))) 75%, transparent);
	color: var(--fleet-topbar-promo-text, var(--wcsb-button-primary-text, #ffffff));
	font-size: 12px;
	line-height: 1.35;
}

.fleet-topbar-product-promo span,
.fleet-topbar-product-promo .amount {
	color: inherit;
}

.fleet-topbar-product-promo strong {
	font-weight: 600;
	color: inherit;
}

/* Les icônes {icon:…} fonctionnent ici aussi : même moteur de
   placeholders que la barre, donc même règle d'alignement. */
.fleet-topbar-product-promo .fleet-topbar__icon {
	vertical-align: -0.15em;
}
