/* ════════════════════════════════════════════════════════════════
   LA BANNIÈRE VIVANTE — boutique/banniere.css
   Le fond qui respire, les deux grandes flèches, et le mot géant du
   rayon qui défile sans coupure.

   TOUT EST SOUS `.hero--vivante`, UNE CLASSE QUE banniere.js NE POSE
   QU'UNE FOIS SA CONSTRUCTION TERMINÉE. Si le script ne charge pas,
   ne s'exécute pas, ou tombe en route, la bannière reste exactement
   celle de socle.css : un mot fixe, un fond fixe, pas de flèche —
   moins belle, mais entière. Une décoration ne doit jamais pouvoir
   vider une vitrine.

   CE QUI EST ANIMÉ, ET RIEN D'AUTRE : `transform` et `opacity`.
   Aucune des deux ne déclenche de remise en page : le compositeur les
   applique seul, sur le fil graphique. `left`, `top`, `width`,
   `margin`, `background-position` et `filter:blur()` en mouvement
   sont absents de ce fichier — ce sont eux qui font tomber un
   téléphone d'entrée de gamme sous les 60 images par seconde.

   POURQUOI DES ANIMATIONS CSS ET PAS UNE BOUCLE requestAnimationFrame
   — le ruban d'accueil.js, lui, en utilise une. Trois raisons :
     · une animation CSS de `transform` tourne sur le compositeur,
       donc elle reste fluide même quand le fil principal est occupé
       à peindre les 45 cartes du catalogue ;
     · l'interrupteur du site la coupe TOUTE SEULE, parce que
       socle.css écrit `html[data-calme="1"] *{animation:none}`. Une
       boucle JS, elle, aurait continué à tourner derrière le dos de
       l'utilisateur qui vient de demander le calme ;
     · `animation-play-state:paused` l'arrête hors écran sans qu'un
       seul octet de JS ne s'exécute par image.
   Le JS ne fait donc ici que MESURER (la largeur d'une copie du mot,
   la hauteur de la scène) ; c'est le CSS qui bouge.

   AUCUN `will-change` PERMANENT. Le navigateur promeut de lui-même
   tout élément dont une animation de `transform` tourne ; l'écrire en
   dur ne gagnerait rien et garderait la mémoire vidéo occupée pendant
   que la bannière est hors écran.
   ════════════════════════════════════════════════════════════════ */

/* ══════════ ① LE FOND QUI RESPIRE ══════════
   socle.css pose déjà `.hero__gobo` : trois OMBRES sombres qui
   dérivent en `multiply`. On ajoute ici leur contraire — deux
   LUMIÈRES, aux couleurs du rayon en scène (--u2 l'accent, --u3 le
   clair). Ombre plus lumière, c'est ce qui donne du relief à un fond
   plat ; deux ombres de plus n'auraient fait que le salir.

   Deux blobs, pas cinq : chaque élément dont une animation tourne
   reçoit sa propre couche dans la mémoire vidéo. Deux couches de
   ~70 % de la bannière coûtent moins d'un mégaoctet sur un écran de
   téléphone ; c'était le budget.

   ZÉRO `filter:blur()`. Un dégradé radial est déjà flou par
   construction — il n'a pas besoin qu'on le rende flou une seconde
   fois, et un flou sur une grande surface est exactement ce qui
   effondre les images par seconde sur un téléphone bon marché. */
#hero.hero--vivante .hero__aurore{
  position:absolute;inset:0;z-index:1;pointer-events:none;
  overflow:clip;                    /* les blobs débordent : on les rogne ici */
}
#hero.hero--vivante .hero__aurore i{
  position:absolute;display:block;border-radius:50%;
}
/* La lumière d'accent — celle qui « tape à l'œil », donc celle qui
   porte --u2 : l'orange du violet enfants, le vert de la prière.
   Une valeur en rgba d'abord : sur un navigateur sans color-mix, la
   déclaration suivante est ignorée et il reste une lueur crème
   plutôt qu'un trou noir. */
#hero.hero--vivante .hero__aurore i:nth-child(1){
  width:74%;aspect-ratio:1;left:-14%;top:-10%;
  background:radial-gradient(50% 50% at 50% 50%,
    rgba(255,255,255,.16) 0%,rgba(255,255,255,0) 68%);
  background:radial-gradient(50% 50% at 50% 50%,
    color-mix(in oklab,var(--u2) 44%,transparent) 0%,
    color-mix(in oklab,var(--u2) 12%,transparent) 42%,
    transparent 70%);
  animation:aurore-a 47s var(--e-inout) infinite alternate;
}
/* La seconde, plus pâle et plus petite : elle traverse en
   contre-sens, ce qui suffit à ce que le fond ne « boucle » jamais
   visiblement — deux périodes premières entre elles (47 s et 38 s) ne
   retombent en phase qu'au bout d'une demi-heure. */
#hero.hero--vivante .hero__aurore i:nth-child(2){
  width:58%;aspect-ratio:1;right:-12%;bottom:-14%;
  background:radial-gradient(50% 50% at 50% 50%,
    rgba(255,255,255,.12) 0%,rgba(255,255,255,0) 70%);
  background:radial-gradient(50% 50% at 50% 50%,
    color-mix(in oklab,var(--u3) 28%,transparent) 0%,
    transparent 72%);
  animation:aurore-b 38s var(--e-inout) infinite alternate;
}
/* L'opacité voyage AVEC la transformation, dans les mêmes images clés :
   deux propriétés que le compositeur sait faire, donc gratuites
   ensemble. C'est cette respiration lente qui fait vivant ; l'amplitude
   reste faible, sinon la bannière clignote. */
@keyframes aurore-a{
  from{transform:translate3d(0,0,0) scale(1);opacity:.72}
  to  {transform:translate3d(16%,11%,0) scale(1.16);opacity:1}
}
@keyframes aurore-b{
  from{transform:translate3d(0,0,0) scale(1.08);opacity:.9}
  to  {transform:translate3d(-13%,-9%,0) scale(.9);opacity:.55}
}

/* ══════════ ② LE MOT GÉANT QUI DÉFILE ══════════
   socle.css posait le mot du rayon UNE fois, calé en haut à droite
   (`.hero__geant`). On le laisse en place dans le HTML — banniere.js
   y lit le mot à chaque changement de produit — mais on ne l'affiche
   plus : c'est la bande qui le remplace. `display:none` plutôt que
   `visibility:hidden` : un texte caché mais mis en page coûte encore
   une mesure de police à chaque redimensionnement.

   La bande est la MÊME largeur que la bannière, calée à la même
   hauteur que le mot d'origine (20 % du haut, 12 % sur téléphone),
   au même plan (z-index 2, donc derrière le texte et le produit qui
   sont à 5). « Les mots derrière », mot pour mot. */
#hero.hero--vivante .hero__geant{display:none}

#hero.hero--vivante .hero__geantpiste{
  position:absolute;left:0;right:0;top:20%;z-index:2;
  pointer-events:none;overflow:clip;
  color:rgba(255,255,255,.22);
  color:color-mix(in oklab,var(--u3) 30%,transparent);
  transition:color var(--t-long) var(--e-inout);
}
/* `width:max-content` : la piste doit faire la largeur de ses copies,
   pas celle de son parent — sinon flex les comprimerait toutes pour
   les faire tenir, et il n'y aurait plus rien à faire défiler.
   `--geant-course` (la largeur d'UNE copie) et `--geant-duree` sont
   posées par banniere.js après mesure ; les valeurs de repli ici ne
   servent qu'à ce que rien ne saute si la mesure échoue. */
#hero.hero--vivante .hero__geantrail{
  display:flex;align-items:center;width:max-content;
  animation:geant-glisse var(--geant-duree,30s) linear infinite;
}
#hero.hero--vivante .hero__geantrail b{
  font-weight:inherit;display:block;white-space:pre;
}
/* Le point qui sépare deux passages du mot. En couleur d'accent et
   plus petit : il donne le rythme sans se faire lire. */
#hero.hero--vivante .hero__geantrail em{
  font-style:normal;display:block;padding:0 .30em;font-size:.44em;
  color:rgba(255,255,255,.30);
  color:color-mix(in oklab,var(--u2) 62%,transparent);
}
/* LA BOUCLE SANS COUPURE, EN UNE LIGNE.
   La piste part décalée d'exactement UNE copie vers la gauche et
   remonte jusqu'à zéro : elle avance donc de la gauche vers la
   droite, comme demandé. Au moment où l'animation reboucle, la copie
   n° 2 occupe au pixel près la place que la copie n° 1 occupait à
   l'image précédente — c'est pour ça qu'on ne voit pas le saut, et
   c'est pour ça que `--geant-course` doit être mesurée et pas
   devinée. */
@keyframes geant-glisse{
  from{transform:translate3d(calc(var(--geant-course,600px) * -1),0,0)}
  to  {transform:translate3d(0,0,0)}
}

/* ══════════ ③ LES DEUX GRANDES FLÈCHES ══════════
   Sur les côtés, à la hauteur du produit et pas à celle de la
   bannière : sur téléphone la scène est en haut et le texte en
   dessous, si bien qu'une flèche calée à 50 % de la bannière serait
   tombée pile sur le bouton « Précommander ». banniere.js mesure la
   scène et pose `--fleche-y`.

   44 px est le minimum atteignable au pouce (WCAG 2.5.5) ; on part de
   48 et on monte à 76 sur ordinateur, où la place ne manque pas.

   PAS DE `backdrop-filter`. Il obligerait le navigateur à relire le
   fond DERRIÈRE le bouton à chaque image — or ce fond est justement
   celui qui bouge. Un aplat sombre translucide donne le même
   détachement pour rien. */
#hero.hero--vivante .hero__nav{
  --fl:clamp(48px,12vw,56px);
  position:absolute;top:var(--fleche-y,50%);translate:0 -50%;z-index:6;
  width:var(--fl);height:var(--fl);padding:0;
  display:grid;place-items:center;
  border:0;border-radius:50%;cursor:pointer;
  background:rgba(18,13,10,.42);
  color:var(--encre);
  box-shadow:inset 0 0 0 1.5px var(--b20);
  /* `transform` et `opacity` seulement : la couleur de fond est une
     transition de peinture, pas une animation continue — elle ne dure
     que le temps du survol. */
  transition:transform var(--t-survol) var(--e-sortie),
             background-color var(--t-survol) var(--e-doux);
}
#hero.hero--vivante .hero__nav svg{
  width:52%;height:52%;display:block;
  fill:none;stroke:currentColor;stroke-width:2.1;
  stroke-linecap:round;stroke-linejoin:round;
}
/* Le halo d'accent : une couche à part dont on ne fait varier que
   l'opacité. Faire varier un `box-shadow` aurait forcé une
   repeinture du bouton à chaque image du survol. */
#hero.hero--vivante .hero__nav::before{
  content:'';position:absolute;inset:-6px;border-radius:50%;
  background:radial-gradient(50% 50% at 50% 50%,
    rgba(255,255,255,.22) 0%,rgba(255,255,255,0) 70%);
  background:radial-gradient(50% 50% at 50% 50%,
    color-mix(in oklab,var(--u3) 34%,transparent) 0%,transparent 70%);
  opacity:0;transition:opacity var(--t-survol) var(--e-doux);
  pointer-events:none;
}
#hero.hero--vivante .hero__nav--prec{left:clamp(4px,1.6vw,32px)}
#hero.hero--vivante .hero__nav--suiv{right:clamp(4px,1.6vw,32px)}
/* Le survol seulement là où il existe vraiment. Sur un écran tactile,
   `:hover` reste collé au dernier élément touché. */
@media (hover:hover) and (pointer:fine){
  #hero.hero--vivante .hero__nav:hover{
    transform:scale(1.08);background:rgba(18,13,10,.62);
  }
  #hero.hero--vivante .hero__nav:hover::before{opacity:1}
}
#hero.hero--vivante .hero__nav:active{
  transform:scale(.93);transition-duration:var(--t-micro);
}
#hero.hero--vivante .hero__nav:focus-visible{
  outline:3px solid var(--or-clair);outline-offset:4px;
}
#hero.hero--vivante .hero__nav:focus-visible::before{opacity:1}

/* SUR ORDINATEUR, ON LEUR FAIT DE LA PLACE.
   `#hero` a 5vw de marge latérale ; sur un écran de 1280 px, ça fait
   64 px, et une flèche de 76 px posée à 32 px du bord aurait mordu
   sur le titre. On réserve donc 120 px minimum de chaque côté : la
   flèche la plus large finit à 108 px du bord, il reste 12 px d'air.
   La règle ne s'applique QUE sous `.hero--vivante`, donc uniquement
   quand les flèches existent réellement. */
@media (min-width:941px){
  #hero.hero--vivante{
    padding-left:clamp(120px,9vw,168px);
    padding-right:clamp(120px,9vw,168px);
  }
  #hero.hero--vivante .hero__nav{--fl:clamp(56px,4.6vw,76px)}
}

/* Sur téléphone, le mot géant descend avec celui de socle.css et
   rapetisse d'autant : à l'humane, « SANS ÉCRAN » est 40 % plus large
   qu'en condensée. */
@media (max-width:940px){
  #hero.hero--vivante .hero__geantpiste{
    top:12%;font-size:clamp(2.1rem,11vw,4.2rem);
  }
}

/* ══════════ ④ HORS ÉCRAN, PLUS RIEN NE BOUGE ══════════
   banniere.js pose `.hero--dort` dès que la bannière quitte l'écran.
   On arrête TOUT ce qui tourne dedans, y compris les trois ombres du
   gobo, le flottement du produit et sa contre-ombre, qui viennent de
   socle.css : une animation qu'on ne voit pas est de la batterie
   brûlée pour rien, et le visiteur passe l'essentiel de sa visite
   plus bas, dans les 45 cartes.
   `paused` et non `none` : à la remontée, tout repart exactement où
   ça s'était arrêté, sans saut.

   `i:nth-child(n)` — « n » veut dire TOUS les enfants, et ce n'est pas
   de la coquetterie : la règle de base des deux lumières porte déjà un
   `:nth-child(1)`, donc une spécificité de plus. Sans ce
   `:nth-child(n)` ici, la mise en pause perdait le match contre elle
   et les lumières continuaient de dériver hors écran — MESURÉ, pas
   supposé : le navigateur répondait `aurore-a` alors que la bannière
   était censée dormir. Le raccourci `animation:...` de la règle de
   base remet en plus `animation-play-state:running` au passage, ce qui
   rendait la panne silencieuse. */
#hero.hero--dort .hero__aurore i:nth-child(n),
#hero.hero--dort .hero__geantrail,
#hero.hero--dort .hero__gobo i,
#hero.hero--dort .hero__packshot,
#hero.hero--dort .hero__ombre{
  animation-play-state:paused;
}

/* ══════════ ⑤ LE MOUVEMENT S'ARRÊTE, LE CONTENU RESTE ══════════
   Deux interrupteurs, et ils ne disent pas la même chose :
     · `prefers-reduced-motion` est un réglage de l'appareil, souvent
       posé par un économiseur de batterie sans que personne ne l'ait
       demandé ;
     · `[data-calme="1"]` est le bouton du site, donc un choix.
   Les deux coupent ici la même chose : les boucles infinies. Rien
   n'est masqué, rien ne rétrécit — la personne voit la même bannière,
   le même mot géant, les mêmes flèches, immobiles. Le mot s'arrête à
   la position 0, c'est-à-dire aligné sur le bord gauche : la bande
   reste pleine d'un bout à l'autre.

   socle.css coupe déjà tout sous `[data-calme="1"]` ; on l'écrit
   quand même, pour que ce fichier reste vrai tout seul.

   Même `:nth-child(n)` qu'au § ④, et pour la même raison de
   spécificité. */
@media (prefers-reduced-motion:reduce) and (min-width:999999px) /* desarme 17/08 : data-calme est le seul interrupteur */{
  /* 16/08 : le mot geant NE s'arrete PLUS ici — ce reglage d'appareil
     est souvent pose par un economiseur de batterie, et le
     proprietaire voyait une banniere morte. Le bouton du site
     (data-calme), lui, arrete tout, plus bas. */
  #hero.hero--vivante .hero__aurore i:nth-child(n){animation:none}
  #hero.hero--vivante .hero__nav{transition-duration:200ms}
}
:root[data-calme="1"] #hero.hero--vivante .hero__aurore i:nth-child(n),
:root[data-calme="1"] #hero.hero--vivante .hero__geantrail{animation:none}
:root[data-calme="1"] #hero.hero--vivante .hero__nav{transition:none}

/* ══════════ ⑥ LES VOLETS — LE BALAYAGE EN ESCALIER ══════════
   Le procédé vu sur les pages produit des grandes marques : quand le
   monde change (autre produit, autre couleur), cinq colonnes de la
   NOUVELLE couleur couvrent la scène puis se retirent l'une après
   l'autre, en escalier. Le regard comprend « on change d'univers »
   sans lire un mot.

   COMMENT ÇA MARCHE, EN DEUX TEMPS ET UNE SEULE PROPRIÉTÉ :
   · banniere.js pose `.hero--voile` SANS transition (les volets
     couvrent d'un coup, pendant que le contenu change dessous) ;
   · au cadre suivant il la retire : chaque volet part de scaleY(1)
     vers scaleY(0) avec son propre retard — l'escalier.
   `transform` seulement, donc le compositeur seul ; cinq couches d'un
   cinquième de bannière, moins cher que les deux lumières du fond.

   LA COULEUR : les volets héritent de data-univers déjà posé par
   accueil.js sur #hero — donc ils sont TOUJOURS de la couleur du
   monde qui ARRIVE. Un soupçon de noir dedans : un volet du même brun
   exact que le fond disparaîtrait avant d'avoir été vu. */
#hero.hero--vivante .hero__volets{
  position:absolute;inset:0;z-index:7;pointer-events:none;
  display:grid;grid-template-columns:repeat(5,1fr);
}
#hero.hero--vivante .hero__volets i{
  display:block;
  background:var(--u1);
  background:color-mix(in oklab,var(--u1) 78%,#0B0705);
  transform:scaleY(0);transform-origin:50% 0;
  transition:transform .48s var(--e-expo,cubic-bezier(.19,1,.22,1));
}
/* L'escalier : chaque volet part 60 ms après son voisin de gauche.
   Le dernier finit à 480 + 240 = 720 ms — assez long pour être vu,
   assez court pour ne jamais faire attendre un clic. */
#hero.hero--vivante .hero__volets i:nth-child(2){transition-delay:.06s}
#hero.hero--vivante .hero__volets i:nth-child(3){transition-delay:.12s}
#hero.hero--vivante .hero__volets i:nth-child(4){transition-delay:.18s}
#hero.hero--vivante .hero__volets i:nth-child(5){transition-delay:.24s}
/* Le voile : couverture immédiate, sans transition ni retard — les
   cinq d'un coup. C'est l'état posé pendant l'échange de produit. */
#hero.hero--voile .hero__volets i:nth-child(n){
  transform:scaleY(1);transition:none;transition-delay:0s;
}

/* ══════════ ⑦ L'ENTRÉE — LA PREMIÈRE FOIS SEULEMENT ══════════
   À la première visite de la séance, la bannière naît : les volets la
   couvrent au premier dessin, puis se retirent en escalier PLUS LENT
   (le double), pendant que le produit, le texte et les vedettes
   montent de 28 px en fondu. Aux visites suivantes de la même séance,
   rien — une entrée qu'on revoit à chaque retour n'est plus une
   entrée, c'est un péage.

   `.hero--nait` est posée AVANT le premier dessin (le script tourne
   pendant que la page se construit) et retirée un cadre plus tard :
   le navigateur ne peint jamais l'état couvert seul, il peint la
   TRANSITION. Les retards s'additionnent : les volets d'abord, le
   contenu ensuite — l'ordre d'un rideau qui se lève. */
#hero.hero--entree .hero__volets i{
  transition-duration:.9s;
}
#hero.hero--entree .hero__volets i:nth-child(2){transition-delay:.09s}
#hero.hero--entree .hero__volets i:nth-child(3){transition-delay:.18s}
#hero.hero--entree .hero__volets i:nth-child(4){transition-delay:.27s}
#hero.hero--entree .hero__volets i:nth-child(5){transition-delay:.36s}
/* La transition du contenu ne vit QUE sous `.hero--entree` : posée en
   permanence sur `.hero__scene`, elle aurait amorti le suivi du doigt
   du glisser d'accueil.js (qui écrit transform en direct). La classe
   est retirée par banniere.js une fois l'entrée finie. */
#hero.hero--entree .hero__scene,
#hero.hero--entree .hero__texte,
#hero.hero--entree .vedettes,
#hero.hero--entree .decouvrir{
  transition:transform 1.05s var(--e-expo,cubic-bezier(.19,1,.22,1)),
             opacity .85s var(--e-doux,ease);
}
#hero.hero--nait .hero__scene,
#hero.hero--nait .hero__texte,
#hero.hero--nait .vedettes,
#hero.hero--nait .decouvrir{
  transform:translateY(28px);opacity:0;transition:none;
}
/* Le texte part un souffle après le produit : deux retards, pas dix. */
#hero.hero--entree .hero__texte{transition-delay:.08s}
#hero.hero--entree .vedettes,
#hero.hero--entree .decouvrir{transition-delay:.16s}
#hero.hero--nait .hero__texte,
#hero.hero--nait .vedettes,
#hero.hero--nait .decouvrir{transition-delay:0s}

/* ══════════ ⑧ LES QUATRE COINS — LES LÉGENDES D'ÉDITION ══════════
   Quatre micro-lignes en capitales espacées, une par coin, comme sur
   les pages produit des studios : le numéro et le nom du rayon, la
   règle de la maison, la livraison, et « 1 / 3 ». Que du VRAI — le
   seuil de port est LU dans window.MLO_PORT_OFFERT_DES, jamais
   recopié. Elles ne se lisent pas, elles se respirent : c'est le
   cadre qui fait sérieux, pas la phrase.
   Cachées sous 941 px : sur téléphone chaque pixel appartient au
   produit. */
#hero.hero--vivante .hero__coin{
  position:absolute;z-index:6;pointer-events:none;
  font-family:var(--f-mono);font-size:.62rem;font-weight:700;
  letter-spacing:.16em;text-transform:uppercase;
  color:rgba(255,255,255,.4);
  color:color-mix(in oklab,var(--u3) 52%,transparent);
  transition:color var(--t-long) var(--e-inout),opacity .4s var(--e-doux,ease);
  display:none;
}
@media (min-width:941px){
  #hero.hero--vivante .hero__coin{display:block}
}
#hero.hero--vivante .hero__coin--no{top:18px;left:26px}
#hero.hero--vivante .hero__coin--ne{top:18px;right:26px;text-align:right}
#hero.hero--vivante .hero__coin--so{bottom:16px;left:26px}
#hero.hero--vivante .hero__coin--se{bottom:16px;right:26px;text-align:right}
/* Le compteur « 1 / 3 » : le chiffre courant en clair, le reste
   estompé — on lit la position sans compter. */
#hero.hero--vivante .hero__coin--se b{
  font-weight:inherit;
  color:var(--encre);
}
#hero.hero--nait .hero__coin{opacity:0}

/* ══════════ ⑨ LES VOLETS AUSSI SAVENT SE TAIRE ══════════
   Mouvement réduit ou bouton calme : pas de balayage, pas d'entrée.
   Les volets restent repliés (scaleY(0) sans transition), le contenu
   arrive posé. La bannière change alors d'un coup, comme une page qui
   tourne — c'est exactement ce que ces réglages demandent. */
@media (prefers-reduced-motion:reduce) and (min-width:999999px) /* desarme 17/08 : data-calme est le seul interrupteur */{
  #hero.hero--vivante .hero__volets i:nth-child(n){transition:none;transform:scaleY(0)}
  #hero .hero__scene,#hero .hero__texte,#hero .vedettes,#hero .decouvrir{
    transition:none;transform:none;opacity:1}
}
:root[data-calme="1"] #hero.hero--vivante .hero__volets i:nth-child(n){transition:none;transform:scaleY(0)}
:root[data-calme="1"] #hero .hero__scene,
:root[data-calme="1"] #hero .hero__texte,
:root[data-calme="1"] #hero .vedettes,
:root[data-calme="1"] #hero .decouvrir{transition:none;transform:none;opacity:1}
