/* ============================================================
   LES BANNIERES ANIMEES DES PRODUITS — GENERE par
   outils/bannieres/generer.py, ne pas modifier a la main.

   La direction est celle de la video promo : fond tramé, lumiere bleu
   electrique, titres qui sortent du flou, carte ZeusMarket en 3D,
   notification, ondes, pastilles, curseur. Un cycle de 10 s, le meme
   pour tous les produits ; les variantes disent le produit.
   ============================================================ */

.zb-defs { position: absolute; width: 0; height: 0; overflow: hidden; }

.zb {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  container-type: inline-size;
  contain: layout paint;
  isolation: isolate;
  background: #03050B;
  color: #F4F7FF;
  font-family: 'Poppins', var(--ff-heading, system-ui), sans-serif;
  line-height: 1;
  -webkit-user-select: none;
  user-select: none;
  --cy: 10s;
  --i0: 2.2s;
  --bleu: #4DA3FF;
}

.zb2 > * { position: absolute; pointer-events: none; }

/* ---- le decor ---- */

.zb2-fond {
  inset: 0;
  background:
    radial-gradient(64cqw 30cqw at 50% 112%, rgba(30, 104, 255, .85), rgba(14, 58, 170, .38) 42%, transparent 74%),
    radial-gradient(100cqw 46cqw at 50% 128%, rgba(20, 70, 210, .4), transparent 70%),
    linear-gradient(180deg, #02040A 0%, #050913 60%, #071228 100%);
}

.zb2-points {
  inset: -1.5cqw;
  background-image: radial-gradient(circle, rgba(130, 165, 235, .22) 0 .085cqw, transparent .13cqw);
  background-size: 1.15cqw 1.15cqw;
  -webkit-mask-image: radial-gradient(90% 85% at 50% 35%, transparent 25%, #000 80%);
  mask-image: radial-gradient(90% 85% at 50% 35%, transparent 25%, #000 80%);
}

.zb2-lueur {
  left: 18%;
  right: 18%;
  bottom: -14cqw;
  height: 28cqw;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(60, 140, 255, .55), transparent);
}

/* ---- le titre : deux lignes, blanc puis bleu, lettre a lettre ---- */

.zb2-t {
  z-index: 3;
  left: 0;
  right: 0;
  top: 3.4cqw;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .7cqw;
  font-weight: 600;
  font-size: 3.9cqw;
  letter-spacing: -.01em;
  text-align: center;
  white-space: nowrap;
}

.zb2-t1 { color: #F4F7FF; }
.zb2-t2 { color: var(--bleu); text-shadow: 0 0 2.4cqw rgba(77, 163, 255, .45); }
.zb2-t i { display: inline-block; font-style: normal; white-space: pre; }

/* ---- la scene : entree > flottement > inclinaison ---- */

.zb2-scene { left: 50%; top: 19.5cqw; width: 33cqw; height: 20.8cqw; margin-left: -16.5cqw; perspective: 120cqw; }
.zb2-entree, .zb2-flotte, .zb2-incl { position: absolute; inset: 0; transform-style: preserve-3d; }
.zb2-incl { transform: rotateX(9deg) rotateY(var(--ry, -12deg)); }

/* ---- la carte ZeusMarket ---- */

.zb2-carte {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  --encre: #5EAEFF;
  --discret: #7E8AA3;
  --lvl: #4DA3FF;
}

.zb2-face, .zb2-verso {
  position: absolute;
  inset: 0;
  border-radius: 1.7cqw;
  overflow: hidden;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  border: max(1px, .1cqw) solid rgba(255, 255, 255, .09);
  box-shadow:
    0 2.4cqw 5cqw -1cqw rgba(0, 0, 0, .85),
    0 0 4.5cqw -1.5cqw rgba(40, 120, 255, .55),
    inset 0 .1cqw 0 rgba(255, 255, 255, .08);
  background:
    linear-gradient(115deg, transparent 38%, rgba(255, 255, 255, .07) 52%, transparent 66%),
    repeating-linear-gradient(115deg, rgba(255, 255, 255, .022) 0 .12cqw, transparent .12cqw .4cqw),
    linear-gradient(135deg, #18202D 0%, #0A0E16 48%, #141B27 100%);
}

.zb2-verso { transform: rotateY(180deg); }

.zb2-marque {
  position: absolute;
  left: 6.5%;
  top: 9%;
  font-size: 1.45cqw;
  font-weight: 500;
  color: var(--encre);
}

.zb2-emb { position: absolute; left: 29%; top: 17%; width: 42%; height: 66%; }
.zb2-z1 { fill: url(#zb2-gz-bleu); }
.zb2-z2 { fill: url(#zb2-gz-bleu-f); }
.zb2-z3 { fill: rgba(255, 255, 255, .08); }
.zb2-emb--trait { left: 33%; top: 22%; width: 34%; height: 56%; fill: none; stroke: url(#zb2-gz-bleu); stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }

.zb2-n {
  position: absolute;
  left: 6.5%;
  bottom: 9%;
  font-size: 1.05cqw;
  font-weight: 500;
  letter-spacing: .18em;
  color: var(--discret);
}

.zb2-lvl {
  position: absolute;
  right: 6.5%;
  bottom: 6.5%;
  font-size: 2.9cqw;
  font-weight: 700;
  font-style: italic;
  color: var(--lvl);
}

.zb2-reflet {
  position: absolute;
  top: -30%;
  bottom: -30%;
  left: 0;
  width: 32%;
  background: linear-gradient(100deg, transparent, rgba(255, 255, 255, .18) 45%, rgba(255, 255, 255, .28) 50%, rgba(255, 255, 255, .18) 55%, transparent);
  transform: translateX(-140%) rotate(10deg);
}

.zb2-badge {
  position: absolute;
  right: 6%;
  top: 8%;
  width: 3.2cqw;
  height: 3.2cqw;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: rgba(77, 163, 255, .14);
  border: max(1px, .1cqw) solid rgba(77, 163, 255, .45);
}
.zb2-badge svg { width: 58%; height: 58%; fill: none; stroke: var(--lvl); stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.zb2-carte--blanc .zb2-badge { background: rgba(29, 79, 168, .1); border-color: rgba(29, 79, 168, .35); }

.zb2-holo {
  position: absolute;
  right: 16%;
  top: 8%;
  padding: .35cqw .8cqw;
  border-radius: .5cqw;
  font-size: .95cqw;
  font-weight: 700;
  letter-spacing: .12em;
  color: #0A1020;
  background: linear-gradient(110deg, #A5F3FC, #C4B5FD 35%, #93C5FD 60%, #FBCFE8 85%);
  background-size: 220% 100%;
  animation: zb2-holo calc(var(--cy) / 2) linear infinite;
}

/* Les finitions : le niveau se lit sur la carte. */
.zb2-carte--blanc { --encre: #1D4FA8; --discret: #5B667A; --lvl: #1F2A3D; }
.zb2-carte--blanc .zb2-face, .zb2-carte--blanc .zb2-verso {
  border-color: rgba(255, 255, 255, .6);
  background:
    linear-gradient(115deg, transparent 38%, rgba(255, 255, 255, .7) 52%, transparent 66%),
    repeating-linear-gradient(115deg, rgba(0, 0, 0, .025) 0 .12cqw, transparent .12cqw .4cqw),
    linear-gradient(135deg, #FDFEFF 0%, #DCE2EB 50%, #F1F4F8 100%);
}
.zb2-carte--blanc .zb2-z1 { fill: url(#zb2-gz-encre); }
.zb2-carte--blanc .zb2-z2 { fill: url(#zb2-gz-encre-f); }

.zb2-carte--graphite, .zb2-carte--acier { --encre: #C9D3E3; --discret: #9AA6BA; --lvl: #E7ECF4; }
.zb2-carte--graphite .zb2-face, .zb2-carte--graphite .zb2-verso,
.zb2-carte--acier .zb2-face, .zb2-carte--acier .zb2-verso {
  background:
    linear-gradient(115deg, transparent 38%, rgba(255, 255, 255, .12) 52%, transparent 66%),
    repeating-linear-gradient(115deg, rgba(255, 255, 255, .03) 0 .12cqw, transparent .12cqw .4cqw),
    linear-gradient(135deg, #3E4450 0%, #23272F 50%, #383E49 100%);
}
.zb2-carte--graphite .zb2-z1 { fill: url(#zb2-gz-argent); }
.zb2-carte--graphite .zb2-z2 { fill: url(#zb2-gz-argent-f); }
.zb2-carte--acier { --lvl: #7CC0FF; --encre: #8EC8FF; }

.zb2-carte--nitro { --encre: #8EC8FF; }
.zb2-carte--nitro .zb2-face {
  background:
    linear-gradient(115deg, transparent 38%, rgba(255, 255, 255, .08) 52%, transparent 66%),
    radial-gradient(70% 90% at 80% 10%, rgba(80, 120, 255, .35), transparent 70%),
    linear-gradient(135deg, #18203F 0%, #0B0F22 55%, #1A1F3E 100%);
}

/* Le verso d'une cle. */
.zb2-verso-l { position: absolute; left: 6.5%; top: 34%; display: flex; align-items: center; gap: .8cqw; font-size: 1.7cqw; font-weight: 600; color: #F4F7FF; }
.zb2-verso-l svg { width: 2.2cqw; height: 2.2cqw; fill: none; stroke: var(--bleu); stroke-width: 2; stroke-linecap: round; }
.zb2-code {
  position: absolute; left: 6.5%; top: 52%;
  padding: .7cqw 1.2cqw; border-radius: .7cqw;
  font-size: 1.9cqw; font-weight: 600; letter-spacing: .08em; color: #CFE6FF;
  background: rgba(77, 163, 255, .12); border: max(1px, .1cqw) solid rgba(77, 163, 255, .35);
}

.zb2-carte--blanc .zb2-verso-l { color: var(--lvl); }
.zb2-carte--blanc .zb2-verso-l svg { stroke: var(--encre); }
.zb2-carte--blanc .zb2-code { color: var(--encre); background: rgba(29, 79, 168, .08); border-color: rgba(29, 79, 168, .3); }

/* ---- trois mois : trois cartes en eventail ---- */

.zb2-pale--g { transform: translateX(-23%) translateZ(-3cqw) rotate(-12deg); }
.zb2-pale--d { transform: translateX(23%) translateZ(-3cqw) rotate(12deg); }
.zb2-pale--g .zb2-face, .zb2-pale--d .zb2-face { filter: brightness(.72); }
.zb2-pale--g .zb2-reflet, .zb2-pale--d .zb2-reflet { display: none; }

.zb2-scene--pile .zb2-pale--a, .zb2-scene--gamme .zb2-pale--a { transform: translateZ(1cqw); }
.zb2-scene--gamme { width: 27cqw; height: 17cqw; margin-left: -13.5cqw; top: 22cqw; }
.zb2-scene--gamme .zb2-pale--g { transform: translateX(-62%) translateZ(-2cqw) rotate(-7deg); }
.zb2-scene--gamme .zb2-pale--d { transform: translateX(62%) translateZ(-2cqw) rotate(7deg); }
.zb2-scene--gamme .zb2-pale--g .zb2-face, .zb2-scene--gamme .zb2-pale--d .zb2-face { filter: none; }

/* ---- le telephone (livraison par lien) ---- */

.zb2-scene--tel { top: 23.2cqw; }
.zb2-tel {
  position: absolute;
  left: 50%;
  top: -10cqw;
  width: 13cqw;
  height: 26cqw;
  margin-left: -6.5cqw;
  border-radius: 2.3cqw;
  background: linear-gradient(160deg, #1A2130, #070A12 60%);
  border: max(1px, .14cqw) solid rgba(255, 255, 255, .12);
  box-shadow: 0 0 5cqw -1cqw rgba(40, 120, 255, .45);
  transform: translateZ(-5cqw);
}
.zb2-tel i { position: absolute; left: 50%; top: 1.2cqw; width: 4.2cqw; height: 1.2cqw; margin-left: -2.1cqw; border-radius: 99cqw; background: #000; }
.zb2-scene--tel .zb2-carte { transform: translateZ(1cqw); }

/* ---- les ondes ---- */

.zb2-ondes { left: 50%; top: 32.5cqw; width: 0; height: 0; }
.zb2-ondes i {
  position: absolute;
  left: -24cqw;
  top: -24cqw;
  width: 48cqw;
  height: 48cqw;
  border-radius: 50%;
  border: max(1px, .12cqw) solid rgba(77, 163, 255, .5);
  box-shadow: inset 0 0 3cqw rgba(77, 163, 255, .15);
}

/* ---- la notification ---- */

.zb2-toast {
  left: 63cqw;
  top: 17cqw;
  display: flex;
  align-items: center;
  gap: 1cqw;
  padding: 1cqw 1.5cqw 1cqw 1cqw;
  border-radius: 1.4cqw;
  background: rgba(16, 22, 36, .82);
  border: max(1px, .1cqw) solid rgba(255, 255, 255, .1);
  box-shadow: 0 1.5cqw 3cqw -1cqw rgba(0, 0, 0, .7), 0 0 3cqw -1cqw rgba(77, 163, 255, .45);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}
.zb2-toast-ic { width: 3cqw; height: 3cqw; border-radius: .8cqw; background: #0B1220; display: grid; place-items: center; border: max(1px, .08cqw) solid rgba(77, 163, 255, .35); }
.zb2-toast-ic svg { width: 70%; height: 70%; }
.zb2-toast-txt { display: flex; flex-direction: column; gap: .35cqw; white-space: nowrap; }
.zb2-toast-txt em { font-style: normal; font-size: 1.3cqw; color: #8A97B2; }
.zb2-toast-txt b { font-size: 1.65cqw; font-weight: 600; color: #F4F7FF; }

/* ---- les pastilles ---- */

.zb2-pills {
  left: 0;
  right: 0;
  top: 46.6cqw;
  display: flex;
  justify-content: center;
  gap: 1.2cqw;
}
.zb2-pill {
  display: inline-flex;
  align-items: center;
  gap: .7cqw;
  padding: 1cqw 1.9cqw 1cqw 1.4cqw;
  border-radius: 99cqw;
  font-size: 1.75cqw;
  color: #DCE5F7;
  background: rgba(255, 255, 255, .06);
  border: max(1px, .1cqw) solid rgba(255, 255, 255, .12);
  white-space: nowrap;
}
.zb2-pill b { font-weight: 500; }
.zb2-pill svg { width: 2.1cqw; height: 2.1cqw; fill: none; stroke: var(--bleu); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

/* ---- le curseur : il vit dans sa cible (pastille ou repere de carte) ---- */

.zb2-pill { position: relative; }
.zb2-vise { left: 50%; width: 0; height: 0; }

.zb2-curseur {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 2.8cqw;
  height: 2.8cqw;
  margin: -.3cqw 0 0 -.5cqw;
  fill: #4DA3FF;
  stroke: #E9F3FF;
  stroke-width: 1.2;
  stroke-linejoin: round;
  filter: drop-shadow(0 .4cqw .8cqw rgba(0, 0, 0, .6));
  opacity: 0;
  transform-origin: 20% 10%;
  pointer-events: none;
}
.zb2-clic {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 6cqw;
  height: 6cqw;
  margin: -3cqw 0 0 -3cqw;
  border-radius: 50%;
  border: max(1px, .15cqw) solid rgba(160, 205, 255, .8);
  opacity: 0;
  pointer-events: none;
}

.zb2-etincelles i {
  position: absolute;
  width: 1.2cqw;
  height: 1.2cqw;
  background: radial-gradient(circle, #FFFFFF 0 20%, rgba(120, 180, 255, .8) 35%, transparent 70%);
  border-radius: 50%;
}
.zb2-etincelles { inset: 0; }
.zb2-etincelles i:nth-child(1) { left: 30%; top: 38%; animation: zb2-scint calc(var(--cy) / 4) infinite both; }
.zb2-etincelles i:nth-child(2) { left: 70%; top: 34%; animation: zb2-scint calc(var(--cy) / 3) -1s infinite both; }
.zb2-etincelles i:nth-child(3) { left: 66%; top: 70%; animation: zb2-scint calc(var(--cy) / 4) -1.6s infinite both; }
.zb2-etincelles i:nth-child(4) { left: 34%; top: 72%; animation: zb2-scint calc(var(--cy) / 2) -.5s infinite both; }

/* ---- profondeur : l'ombre de contact sous la carte ---- */

.zb2-ombre {
  position: absolute;
  left: 10%;
  right: 10%;
  bottom: -13%;
  height: 24%;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(0, 3, 12, .72), rgba(0, 3, 12, .3) 55%, transparent);
}

/* ---- la pastille visee s'allume : un calque, pour n'animer que l'opacite ---- */

.zb2-pill--cible { isolation: isolate; }
.zb2-pill--cible::after {
  content: '';
  position: absolute;
  inset: max(-1px, -.1cqw);
  z-index: -1;
  border-radius: inherit;
  border: max(1px, .1cqw) solid rgba(77, 163, 255, .9);
  background: rgba(77, 163, 255, .16);
  box-shadow: 0 0 2cqw rgba(77, 163, 255, .55);
  opacity: 0;
}

/* ---- l'ecran du telephone s'eclaire a la notification ---- */

.zb2-tel::after {
  content: '';
  position: absolute;
  inset: 12% 8% 34%;
  border-radius: 1.6cqw;
  background: radial-gradient(closest-side, rgba(77, 163, 255, .42), rgba(77, 163, 255, .08) 70%, transparent);
  opacity: 0;
}

/* ============================================================
   LE MOUVEMENT (troisieme passe, 2026-10-02)

   UNE INTRODUCTION, PUIS UNE BOUCLE SANS COUTURE. Avant, tout repartait
   dans le flou a 8,6 s et l'ecran restait noir pres d'une seconde : une
   coupure a chaque tour. Desormais :
     0 -> 2,2 s   introduction, jouee UNE fois : les lettres sortent du
                  flou, la carte arrive en 3D, l'eventail s'ouvre, les
                  pastilles montent ;
     2,2 s ->     la boucle de 10 s (--i0 la decale) : la carte ne quitte
                  plus la scene. Seuls les temps forts reviennent :
        +1,0 s    le curseur entre
        +2,1 s    il clique ; la pastille s'allume
        +2,4 s    la carte repond : ondes, lueur, reflet ; la notification
                  (ou la cle qui se retourne, ou l'eventail qui s'ouvre)
        +7,2 s    tout redescend, plus doucement que ca n'est monte
        +10 s     l'etat de repos, identique au depart.
   Tout ce qui tourne en continu a une periode qui divise 10 s (5 s, 2,5 s,
   10/3 s) : n'importe quelle fenetre de 10 s boucle parfaitement, d'ou des
   GIF et des MP4 sans saut.

   LES PROPRIETES INDIVIDUELLES (translate, rotate, scale) portent la
   boucle, transform porte la pose et l'introduction : les deux se
   composent au lieu de s'ecraser. Rien d'autre n'est anime que
   transform, opacity et, a l'introduction seulement, filter.
   ============================================================ */

@container (min-width: 301px) {
  /* -- l'introduction, une fois -- */
  .zb2-t i { animation: zb2-lettre-in .8s cubic-bezier(.2, .7, .2, 1) calc(.1s + var(--c) * 28ms) both; }
  .zb2-t2 i { animation-delay: calc(.38s + var(--c) * 28ms); }
  .zb2-entree { animation: zb2-entree-in 1.2s cubic-bezier(.16, 1, .3, 1) .2s both; }
  .zb2-tel { animation: zb2-tel-in 1s cubic-bezier(.16, 1, .3, 1) .35s both; }
  .zb2-pill { animation: zb2-pill-in .7s cubic-bezier(.16, 1, .3, 1) calc(.95s + var(--p) * .12s) both; }
  .zb2-scene--pile .zb2-pale--g { animation: zb2-eventail-in-g 1s cubic-bezier(.16, 1, .3, 1) .75s both, zb2-souffle-g var(--cy) var(--i0) infinite both; }
  .zb2-scene--pile .zb2-pale--d { animation: zb2-eventail-in-d 1s cubic-bezier(.16, 1, .3, 1) .75s both, zb2-souffle-d var(--cy) var(--i0) infinite both; }
  .zb2-scene--gamme .zb2-pale--g { animation: zb2-gamme-in-g 1s cubic-bezier(.16, 1, .3, 1) .75s both; }
  .zb2-scene--gamme .zb2-pale--d { animation: zb2-gamme-in-d 1s cubic-bezier(.16, 1, .3, 1) .75s both; }

  /* -- l'ambiance, en continu -- */
  .zb2-flotte { animation: zb2-flotte calc(var(--cy) / 2) infinite both; }
  .zb2-ombre { animation: zb2-ombre calc(var(--cy) / 2) infinite both; }
  .zb2-incl { animation: zb2-balance var(--cy) infinite both; }
  .zb2-points { animation: zb2-parallaxe var(--cy) infinite both; }
  .zb2-lueur { animation: zb2-lueur var(--cy) var(--i0) infinite both; }

  /* -- les temps forts de la boucle -- */
  .zb2-curseur { animation: zb2-curseur var(--cy) var(--i0) infinite both; }
  .zb2-clic { animation: zb2-clic var(--cy) var(--i0) infinite both; }
  .zb2-pill--cible::after { animation: zb2-actif var(--cy) var(--i0) infinite both; }
  .zb2-pills .zb2-pill--cible { animation-name: zb2-pill-in, zb2-appui; animation-duration: .7s, var(--cy); animation-timing-function: cubic-bezier(.16, 1, .3, 1), linear; animation-delay: calc(.95s + var(--p) * .12s), var(--i0); animation-iteration-count: 1, infinite; animation-fill-mode: both, both; }
  .zb2-ondes i { animation: zb2-onde var(--cy) var(--i0) infinite both; }
  .zb2-ondes i:nth-child(2) { animation-delay: calc(var(--i0) + .28s); }
  .zb2-ondes i:nth-child(3) { animation-delay: calc(var(--i0) + .56s); }
  .zb2-reflet { animation: zb2-reflet var(--cy) var(--i0) infinite both; }
  .zb2-toast { animation: zb2-toast var(--cy) var(--i0) infinite both; }
  .zb2-tel::after { animation: zb2-ecran var(--cy) var(--i0) infinite both; }
  .zb2-retourne { animation: zb2-retourne var(--cy) var(--i0) infinite both; }
  .zb2-scene--pile .zb2-pale--a { animation: zb2-avance var(--cy) var(--i0) infinite both; }
  .zb2-scene--pile .zb2-pale--a.zb2-retourne { animation: zb2-retourne var(--cy) var(--i0) infinite both, zb2-avance var(--cy) var(--i0) infinite both; }
  .zb2-choisie { animation: zb2-choisie var(--cy) var(--i0) infinite both; }
}

/* ---- l'introduction ---- */
@keyframes zb2-lettre-in {
  from { opacity: 0; filter: blur(.7cqw); transform: translateY(.35em); }
  to { opacity: 1; filter: none; transform: none; }
}
@keyframes zb2-entree-in {
  from { opacity: 0; filter: blur(1cqw); transform: translateY(16%) scale(.86) rotateX(28deg); }
  45% { opacity: 1; }
  to { opacity: 1; filter: none; transform: none; }
}
@keyframes zb2-tel-in {
  from { opacity: 0; transform: translateZ(-5cqw) translateY(12%); }
  to { opacity: 1; transform: translateZ(-5cqw); }
}
@keyframes zb2-pill-in {
  from { opacity: 0; transform: translateY(1cqw) scale(.96); }
  to { opacity: 1; transform: none; }
}
@keyframes zb2-eventail-in-g { from { transform: translateZ(-3cqw); } to { transform: translateX(-23%) translateZ(-3cqw) rotate(-12deg); } }
@keyframes zb2-eventail-in-d { from { transform: translateZ(-3cqw); } to { transform: translateX(23%) translateZ(-3cqw) rotate(12deg); } }
@keyframes zb2-gamme-in-g { from { transform: translateZ(-2cqw); } to { transform: translateX(-62%) translateZ(-2cqw) rotate(-7deg); } }
@keyframes zb2-gamme-in-d { from { transform: translateZ(-2cqw); } to { transform: translateX(62%) translateZ(-2cqw) rotate(7deg); } }

/* ---- l'ambiance : des courbes en S douces, jamais lineaires ---- */
@keyframes zb2-flotte {
  0%, 100% { translate: 0 0; rotate: 0deg; animation-timing-function: cubic-bezier(.37, 0, .63, 1); }
  50% { translate: 0 -2.4%; rotate: .5deg; animation-timing-function: cubic-bezier(.37, 0, .63, 1); }
}
/* l'ombre suit la carte a l'envers : la carte monte, l'ombre se resserre */
@keyframes zb2-ombre {
  0%, 100% { scale: 1; opacity: 1; animation-timing-function: cubic-bezier(.37, 0, .63, 1); }
  50% { scale: .88 .82; opacity: .62; animation-timing-function: cubic-bezier(.37, 0, .63, 1); }
}
@keyframes zb2-balance {
  0%, 100% { rotate: y 0deg; animation-timing-function: cubic-bezier(.37, 0, .63, 1); }
  50% { rotate: y 3.5deg; animation-timing-function: cubic-bezier(.37, 0, .63, 1); }
}
/* la trame glisse a contre-sens de la carte : un soupcon de parallaxe */
@keyframes zb2-parallaxe {
  0%, 100% { translate: 0 0; animation-timing-function: cubic-bezier(.37, 0, .63, 1); }
  50% { translate: -.7cqw .35cqw; animation-timing-function: cubic-bezier(.37, 0, .63, 1); }
}
@keyframes zb2-lueur {
  0%, 22% { opacity: .78; scale: 1; animation-timing-function: cubic-bezier(.16, 1, .3, 1); }
  27% { opacity: 1; scale: 1.08; animation-timing-function: cubic-bezier(.33, 0, .2, 1); }
  60% { opacity: .86; scale: 1.02; animation-timing-function: cubic-bezier(.37, 0, .63, 1); }
  100% { opacity: .78; scale: 1; }
}

/* ---- les temps forts ---- */
/* Le trajet est RELATIF a la cible : il arrive d'en bas a droite en
   decelerant, appuie, et repart plus court qu'il n'est venu. */
@keyframes zb2-curseur {
  0%, 10% { opacity: 0; translate: 16cqw 9cqw; scale: 1; animation-timing-function: cubic-bezier(.22, .61, .36, 1); }
  13% { opacity: 1; animation-timing-function: cubic-bezier(.22, .61, .36, 1); }
  21% { translate: 0 0; scale: 1; animation-timing-function: cubic-bezier(.4, 0, .6, 1); }
  22.2% { scale: .8; animation-timing-function: cubic-bezier(.16, 1, .3, 1); }
  24% { scale: 1; opacity: 1; translate: 0 0; animation-timing-function: cubic-bezier(.4, 0, 1, 1); }
  31% { opacity: 0; translate: 6cqw 4cqw; }
  100% { opacity: 0; translate: 6cqw 4cqw; }
}
@keyframes zb2-clic {
  0%, 22% { opacity: 0; scale: .3; animation-timing-function: cubic-bezier(.16, 1, .3, 1); }
  22.6% { opacity: .9; animation-timing-function: cubic-bezier(.16, 1, .3, 1); }
  29%, 100% { opacity: 0; scale: 1.6; }
}
@keyframes zb2-actif {
  0%, 22.4% { opacity: 0; animation-timing-function: cubic-bezier(.16, 1, .3, 1); }
  25.5%, 72% { opacity: 1; animation-timing-function: cubic-bezier(.4, 0, .2, 1); }
  77%, 100% { opacity: 0; }
}
@keyframes zb2-appui {
  0%, 22.2% { scale: 1; animation-timing-function: cubic-bezier(.4, 0, .6, 1); }
  23.2% { scale: .95; animation-timing-function: cubic-bezier(.16, 1, .3, 1); }
  26.5%, 100% { scale: 1; }
}
@keyframes zb2-onde {
  0%, 24% { opacity: 0; scale: .42; animation-timing-function: cubic-bezier(.16, 1, .3, 1); }
  25% { opacity: .6; animation-timing-function: cubic-bezier(.22, 1, .36, 1); }
  46%, 100% { opacity: 0; scale: 1.18; }
}
/* un seul passage de lumiere par tour ; le retour se fait hors de la carte */
@keyframes zb2-reflet {
  0%, 25% { transform: translateX(-140%) rotate(10deg); animation-timing-function: cubic-bezier(.45, 0, .2, 1); }
  35%, 100% { transform: translateX(380%) rotate(10deg); }
}
/* la sortie est plus courte et plus discrete que l'entree */
@keyframes zb2-toast {
  0%, 29.5% { opacity: 0; transform: translateX(2.4cqw) scale(.96); animation-timing-function: cubic-bezier(.16, 1, .3, 1); }
  34% { opacity: 1; transform: none; }
  72% { opacity: 1; transform: none; animation-timing-function: cubic-bezier(.4, 0, 1, 1); }
  75%, 100% { opacity: 0; transform: translateY(-.7cqw); }
}
@keyframes zb2-ecran {
  0%, 29.5% { opacity: 0; animation-timing-function: cubic-bezier(.16, 1, .3, 1); }
  33% { opacity: 1; animation-timing-function: cubic-bezier(.37, 0, .63, 1); }
  62%, 100% { opacity: 0; }
}
/* 0 -> 180 -> 360 : le dernier etat EST le premier */
@keyframes zb2-retourne {
  0%, 24% { transform: rotateY(0); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  33%, 66% { transform: rotateY(180deg); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  75%, 100% { transform: rotateY(360deg); }
}
/* trois mois : l'eventail respire au clic */
@keyframes zb2-souffle-g {
  0%, 23% { rotate: 0deg; translate: 0 0; animation-timing-function: cubic-bezier(.16, 1, .3, 1); }
  29%, 70% { rotate: -3deg; translate: -2% 0; animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  80%, 100% { rotate: 0deg; translate: 0 0; }
}
@keyframes zb2-souffle-d {
  0%, 23% { rotate: 0deg; translate: 0 0; animation-timing-function: cubic-bezier(.16, 1, .3, 1); }
  29%, 70% { rotate: 3deg; translate: 2% 0; animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  80%, 100% { rotate: 0deg; translate: 0 0; }
}
@keyframes zb2-avance {
  0%, 23% { translate: 0 0; animation-timing-function: cubic-bezier(.16, 1, .3, 1); }
  29%, 70% { translate: 0 -3%; animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  80%, 100% { translate: 0 0; }
}
/* le groupe : la carte choisie sort du rang */
@keyframes zb2-choisie {
  0%, 23% { translate: 0 0; scale: 1; animation-timing-function: cubic-bezier(.16, 1, .3, 1); }
  29%, 70% { translate: 0 -8%; scale: 1.05; animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  80%, 100% { translate: 0 0; scale: 1; }
}
@keyframes zb2-holo { to { background-position: -220% 0; } }
@keyframes zb2-scint {
  0%, 100% { opacity: 0; scale: .4; animation-timing-function: cubic-bezier(.37, 0, .63, 1); }
  50% { opacity: 1; scale: 1; animation-timing-function: cubic-bezier(.37, 0, .63, 1); }
}

/* Hors de l'ecran : tout s'arrete (custom.js pose la classe). */
.zb--pause, .zb--pause *, .zb--pause *::after { animation-play-state: paused !important; }

/* Moins de mouvement : l'etat complet, fige. */
@media (prefers-reduced-motion: reduce) {
  .zb, .zb *, .zb *::after { animation: none !important; transition: none !important; }
  .zb2-curseur, .zb2-clic { display: none; }
}

/* Fiche au telephone (301 a 560 px) : la sequence entiere, mais les
   textes secondaires grossissent — a 358 px les pastilles tombaient a 6 px. */
@container (min-width: 301px) and (max-width: 560px) {
  .zb2-t { font-size: 4.9cqw; top: 3cqw; }
  .zb2-pills { top: 45.8cqw; gap: 1.6cqw; }
  .zb2-pill { font-size: 2.6cqw; padding: 1.3cqw 2.4cqw 1.3cqw 1.8cqw; gap: 1cqw; }
  .zb2-pill svg { width: 3cqw; height: 3cqw; }
  .zb2-toast { left: 60cqw; top: 15cqw; padding: 1.4cqw 2cqw 1.4cqw 1.4cqw; gap: 1.4cqw; }
  .zb2-toast-ic { width: 4.4cqw; height: 4.4cqw; }
  .zb2-toast-txt em { font-size: 1.7cqw; }
  .zb2-toast-txt b { font-size: 2.1cqw; }
  .zb2-scene { width: 37cqw; height: 23.3cqw; margin-left: -18.5cqw; }
  .zb2-scene--tel { top: 21cqw; }
  .zb2-tel { top: -8cqw; }
  .zb2-marque { font-size: 1.9cqw; }
  .zb2-n { font-size: 1.5cqw; }
  .zb2-lvl { font-size: 3.4cqw; }
}

/* ============================================================
   VIGNETTES (catalogue a 88 px, fenetre de groupe) : la carte seule.

   A PLAT. En 3D (perspective + rotateX/Y), Chromium peint le calque de la
   carte en basse definition a ces tailles : « LVL 3 » sortait baveux meme
   sur un ecran x3. A plat, la meme carte est nette au pixel. La profondeur
   vient de la lumiere : l'ombre de contact, la lueur, le reflet.

   Un mouvement de liste : la carte flotte, l'ombre et la lueur suivent, et
   une fois par tour un reflet la traverse — decale d'une vignette a l'autre
   (--zi), pour que jamais toute la liste ne brille ensemble. Au survol de
   la ligne, la carte se souleve (transition : elle se reprend si la souris
   repart). Uniquement translate/rotate/scale/opacity : le compositeur fait
   tout, quinze vignettes tiennent 60 i/s (CPU x4).
   ============================================================ */
@container (max-width: 300px) {
  .zb2-t, .zb2-pills, .zb2-toast, .zb2-curseur, .zb2-clic, .zb2-ondes, .zb2-tel, .zb2-etincelles, .zb2-points { display: none; }
  .zb2-scene { top: 9.5cqw; width: 64cqw; height: 40.3cqw; margin-left: -32cqw; perspective: none; }
  .zb2-scene--gamme { top: 14cqw; width: 42cqw; height: 26.5cqw; margin-left: -21cqw; }
  .zb2-entree, .zb2-flotte, .zb2-incl, .zb2-carte { transform-style: flat; }
  .zb2-incl { transform: rotate(calc(var(--ry, -12deg) / -6)); }
  .zb2-scene--tel .zb2-carte, .zb2-scene--pile .zb2-pale--a, .zb2-scene--gamme .zb2-pale--a { transform: none; }
  .zb2-pale--g { transform: translateX(-17%) rotate(-9deg); }
  .zb2-pale--d { transform: translateX(17%) rotate(9deg); }
  .zb2-scene--gamme .zb2-pale--g { transform: translateX(-58%) rotate(-7deg); }
  .zb2-scene--gamme .zb2-pale--d { transform: translateX(58%) rotate(7deg); }
  .zb2-marque { font-size: 3.2cqw; }
  .zb2-n { font-size: 2.6cqw; letter-spacing: .1em; }
  .zb2-lvl { font-size: 6cqw; }
  .zb2-holo { font-size: 2.2cqw; padding: .6cqw 1.4cqw; animation: none; }
  .zb2-badge { width: 6.6cqw; height: 6.6cqw; }
  .zb2-code { font-size: 3.6cqw; }
  .zb2-verso-l { font-size: 3.2cqw; }
  .zb2-face, .zb2-verso { border-radius: 3.4cqw; }
  .zb2-ombre { bottom: -16%; height: 26%; }

  .zb2-flotte { animation: zb2-flotte-v calc(var(--cy) / 2) infinite both; }
  .zb2-ombre { animation: zb2-ombre calc(var(--cy) / 2) infinite both; }
  .zb2-lueur { animation: zb2-lueur-v calc(var(--cy) / 2) infinite both; }
  .zb2-reflet { animation: zb2-reflet-v var(--cy) calc(var(--zi, 0) * -2.1s) infinite both; }

  .zb2-entree { transition: translate .45s cubic-bezier(.16, 1, .3, 1), scale .45s cubic-bezier(.16, 1, .3, 1); }
  .group:hover .zb2-entree { translate: 0 -4%; scale: 1.05; }
  .group:hover .zb2-reflet { animation: zb2-passe .9s cubic-bezier(.45, 0, .2, 1) both; }
}
/* vignettes : translation seule ; tourner le calque le reechantillonnerait */
@keyframes zb2-flotte-v {
  0%, 100% { translate: 0 0; animation-timing-function: cubic-bezier(.37, 0, .63, 1); }
  50% { translate: 0 -3%; animation-timing-function: cubic-bezier(.37, 0, .63, 1); }
}
/* la lueur des vignettes respire avec la carte (meme periode, meme phase) */
@keyframes zb2-lueur-v {
  0%, 100% { opacity: .72; animation-timing-function: cubic-bezier(.37, 0, .63, 1); }
  50% { opacity: 1; animation-timing-function: cubic-bezier(.37, 0, .63, 1); }
}
@keyframes zb2-reflet-v {
  0%, 62% { transform: translateX(-140%) rotate(10deg); animation-timing-function: cubic-bezier(.45, 0, .2, 1); }
  74%, 100% { transform: translateX(380%) rotate(10deg); }
}
@keyframes zb2-passe { from { transform: translateX(-140%) rotate(10deg); } to { transform: translateX(380%) rotate(10deg); } }

/* Fiche : le reflet suit sa boucle ; le survol n'y change rien. */
@container (min-width: 301px) {
  .group:hover .zb2-reflet { animation: zb2-reflet var(--cy) var(--i0) infinite both; }
}

/* ============================================================
   LES EFFETS (quatrieme passe, 2026-10-02) — « surprends-moi »

   Zeus, c'est la foudre. Au clic, un eclair frappe la carte : il se
   trace en 120 ms, scintille, l'ecran flashe, la scene encaisse, la
   carte plie puis rebondit, une gerbe d'etincelles retombe, une onde
   court sur le sol. Autour, le decor d'une agence SaaS :
     - un sol en grille, en perspective, qui defile vers nous, balaye
       par une bande de lumiere ;
     - deux aurores (le bleu de la boutique, le violet du site) ;
     - un faisceau qui fait le tour de la carte ;
     - un reflet holographique qui ondule sur la carte ;
     - un tableau de bord de verre : le compteur de boosts monte de 0 au
       pack, l'anneau se remplit, LVL 1-2-3 s'allument a leurs seuils.
   Periodes : 2,5 s, 5 s, 10 s — la boucle reste sans couture.
   ============================================================ */

/* ---- le decor ---- */

.zb2-aurore { inset: 0; }
.zb2-aurore i {
  position: absolute;
  border-radius: 50%;
}
.zb2-aurore i:nth-child(1) {
  left: -14cqw; top: -6cqw; width: 62cqw; height: 34cqw;
  background: radial-gradient(closest-side, rgba(56, 120, 255, .30), rgba(56, 120, 255, .08) 60%, transparent);
}
.zb2-aurore i:nth-child(2) {
  right: -16cqw; top: 4cqw; width: 58cqw; height: 32cqw;
  background: radial-gradient(closest-side, rgba(139, 92, 246, .22), rgba(139, 92, 246, .06) 60%, transparent);
}

.zb2-sol {
  left: -12cqw;
  right: -12cqw;
  top: 37cqw;
  bottom: 0;
  overflow: hidden;
  perspective: 26cqw;
  perspective-origin: 50% 0;
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 30%, #000 70%, transparent);
  mask-image: linear-gradient(180deg, transparent 0, #000 30%, #000 70%, transparent);
}
.zb2-sol-plan {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 18cqw;
  transform-origin: 50% 0;
  transform: rotateX(66deg);
  overflow: hidden;
}
.zb2-sol-grille {
  position: absolute;
  left: 0;
  right: 0;
  top: -4cqw;
  bottom: 0;
  background-image:
    linear-gradient(rgba(77, 163, 255, .26) .14cqw, transparent .14cqw),
    linear-gradient(90deg, rgba(77, 163, 255, .26) .14cqw, transparent .14cqw);
  background-size: 4cqw 4cqw;
  background-position: 50% 0;
}
.zb2-sol-onde {
  position: absolute;
  left: 50%;
  top: 2cqw;
  width: 60cqw;
  height: 60cqw;
  margin-left: -30cqw;
  margin-top: -30cqw;
  border-radius: 50%;
  border: .5cqw solid rgba(120, 190, 255, .85);
  box-shadow: 0 0 3cqw rgba(77, 163, 255, .8), inset 0 0 3cqw rgba(77, 163, 255, .5);
  opacity: 0;
}

/* ---- la carte : faisceau de bord et reflet holographique ---- */

.zb2-face { isolation: isolate; }
.zb2-carte { --rc: 1.7cqw; --anneau: max(1px, .2cqw); }
.zb2-bord {
  position: absolute;
  inset: calc(var(--anneau) * -1);
  border-radius: calc(var(--rc) + var(--anneau));
  overflow: hidden;
  transform: translateZ(-.05cqw);
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  pointer-events: none;
}
.zb2-bord b {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 160%;
  aspect-ratio: 1;
  translate: -50% -50%;
  background: conic-gradient(from 0deg, transparent 0 62%, rgba(77, 163, 255, .15) 72%, #4DA3FF 86%, #F2F8FF 93%, rgba(139, 92, 246, .9) 97%, transparent 100%);
}
.zb2-holo-f {
  position: absolute;
  top: -10%;
  bottom: -10%;
  left: -60%;
  width: 220%;
  background: linear-gradient(105deg,
    transparent 36%,
    rgba(77, 163, 255, .10) 42%,
    rgba(160, 135, 255, .15) 47%,
    rgba(130, 225, 255, .11) 52%,
    transparent 60%);
  pointer-events: none;
}
.zb2-carte--blanc .zb2-holo-f { opacity: .7; }

/* ---- la foudre ---- */

.zb2-foudre {
  position: absolute;
  left: calc(50% + 7cqw);
  bottom: 96%;
  width: 22cqw;
  height: 26cqw;
  overflow: visible;
  pointer-events: none;
}
.zb2-foudre path {
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 1 1;
  stroke-dashoffset: 1;
  opacity: 0;
}
.zb2-f-halo { stroke: rgba(77, 163, 255, .42); stroke-width: 1.9; }
.zb2-f-coeur { stroke: #F4F9FF; stroke-width: .42; }
.zb2-f-branche { stroke: #BFE0FF; stroke-width: .26; }

.zb2-eclair {
  inset: 0;
  background: radial-gradient(70cqw 44cqw at 62% 33%, rgba(225, 240, 255, .42), rgba(77, 163, 255, .16) 42%, transparent 72%);
  opacity: 0;
}

.zb2-gerbe { position: absolute; left: calc(50% + 12cqw); top: .6cqw; width: 0; height: 0; pointer-events: none; }
.zb2-gerbe i {
  position: absolute;
  left: -.3cqw;
  top: -.3cqw;
  width: calc(.6cqw * var(--s, 1));
  height: calc(.6cqw * var(--s, 1));
  border-radius: 50%;
  background: #EAF4FF;
  box-shadow: 0 0 .8cqw .15cqw rgba(77, 163, 255, .95);
  opacity: 0;
}

/* ---- le tableau de bord ---- */

@property --zn { syntax: '<integer>'; inherits: true; initial-value: 0; }
@property --zf { syntax: '<number>'; inherits: true; initial-value: 0; }

.zb2-hud {
  left: 3.4cqw;
  top: 3.4cqw;
  padding: 1.1cqw 1.7cqw 1.1cqw 1.1cqw;
  border-radius: 1.6cqw;
  background: linear-gradient(160deg, rgba(24, 32, 54, .82), rgba(9, 13, 25, .86));
  border: max(1px, .1cqw) solid rgba(255, 255, 255, .09);
  box-shadow: 0 1.6cqw 3.2cqw -1cqw rgba(0, 0, 0, .75), 0 0 3cqw -1.2cqw rgba(77, 163, 255, .45), inset 0 .1cqw 0 rgba(255, 255, 255, .07);
}
.zb2-hud-vie { display: flex; align-items: center; gap: 1.2cqw; }
.zb2-hud-boite { position: relative; width: 7.2cqw; height: 7.2cqw; flex: none; }
.zb2-hud-anneau { position: absolute; inset: 0; width: 100%; height: 100%; rotate: -90deg; overflow: visible; }
.zb2-hud-anneau circle { fill: none; stroke-width: 3.4; }
.zb2-hud-piste { stroke: rgba(255, 255, 255, .08); }
.zb2-hud-plein {
  stroke: #4DA3FF;
  stroke-linecap: round;
  stroke-dasharray: 1 1;
  stroke-dashoffset: calc(1 - var(--zf) / 20);
  filter: drop-shadow(0 0 .5cqw rgba(77, 163, 255, .9));
}
.zb2-hud-n {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: 2.7cqw;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: #F4F7FF;
  counter-reset: zbn var(--zn);
}
.zb2-hud-n::after { content: counter(zbn); }
.zb2-hud-txt { display: flex; flex-direction: column; gap: .7cqw; }
.zb2-hud-txt b { font-size: 1.35cqw; font-weight: 600; letter-spacing: .16em; color: #9AA6BE; }
.zb2-hud-niv { display: flex; align-items: center; gap: .45cqw; }
.zb2-hud-niv em { font-style: normal; font-size: 1.2cqw; font-weight: 600; letter-spacing: .08em; color: #7E8AA3; margin-right: .2cqw; }
.zb2-hud-niv i {
  --on: clamp(0, var(--zf) - var(--seuil) + 1, 1);
  display: grid;
  place-items: center;
  width: 2.5cqw;
  height: 2.5cqw;
  border-radius: .7cqw;
  font-style: normal;
  font-size: 1.25cqw;
  font-weight: 700;
  color: color-mix(in srgb, #F4F9FF calc(var(--on) * 100%), #5B6680);
  background: rgba(77, 163, 255, calc(.05 + .45 * var(--on)));
  border: max(1px, .08cqw) solid rgba(77, 163, 255, calc(.12 + .7 * var(--on)));
  box-shadow: 0 0 calc(var(--on) * 1.3cqw) rgba(77, 163, 255, .75);
  scale: calc(1 + .12 * var(--on) * (1 - var(--on)) * 4);
}

/* ---- le mouvement des effets ---- */

@container (min-width: 301px) {
  .zb2-aurore i:nth-child(1) { animation: zb2-aurore-1 var(--cy) infinite both; }
  .zb2-aurore i:nth-child(2) { animation: zb2-aurore-2 var(--cy) infinite both; }
  .zb2-sol { animation: zb2-sol-in 1.3s cubic-bezier(.16, 1, .3, 1) .1s both; }
  .zb2-sol-grille { animation: zb2-defile calc(var(--cy) / 4) linear infinite both; }
  .zb2-sol-onde { animation: zb2-onde-sol var(--cy) var(--i0) infinite both; }
  .zb2-scene { animation: zb2-secousse var(--cy) var(--i0) infinite both; }
  .zb2-flotte { animation: zb2-flotte calc(var(--cy) / 2) infinite both, zb2-coup var(--cy) var(--i0) infinite both; }
  .zb2-f-halo, .zb2-f-coeur { animation: zb2-trace var(--cy) var(--i0) infinite both; }
  .zb2-f-branche { animation: zb2-trace var(--cy) calc(var(--i0) + .07s) infinite both; }
  .zb2-eclair { animation: zb2-flash var(--cy) var(--i0) infinite both; }
  .zb2-t2 { animation: zb2-titre-eclat var(--cy) var(--i0) infinite both; }
  .zb2-gerbe i { animation: zb2-etincelle var(--cy) var(--i0) infinite both; }
  .zb2-hud { animation: zb2-hud-in .8s cubic-bezier(.16, 1, .3, 1) 1.05s both; }
  .zb2-hud-vie { animation: zb2-compte var(--cy) var(--i0) infinite both, zb2-vie var(--cy) var(--i0) infinite both; }
}
.zb2-bord b { animation: zb2-tour calc(var(--cy) / 2) linear infinite both; }
/* une seule carte porte le faisceau et le reflet irise : celle de devant */
.zb2-pale--g .zb2-bord, .zb2-pale--d .zb2-bord, .zb2-pale--g .zb2-holo-f, .zb2-pale--d .zb2-holo-f { display: none; }
.zb2-holo-f { animation: zb2-irise calc(var(--cy) / 2) infinite both; }

@keyframes zb2-aurore-1 {
  0%, 100% { translate: 0 0; scale: 1; animation-timing-function: cubic-bezier(.37, 0, .63, 1); }
  50% { translate: 9cqw 2.5cqw; scale: 1.18; animation-timing-function: cubic-bezier(.37, 0, .63, 1); }
}
@keyframes zb2-aurore-2 {
  0%, 100% { translate: 0 0; scale: 1.1; animation-timing-function: cubic-bezier(.37, 0, .63, 1); }
  50% { translate: -8cqw -2cqw; scale: .92; animation-timing-function: cubic-bezier(.37, 0, .63, 1); }
}
@keyframes zb2-sol-in { from { opacity: 0; translate: 0 2.5cqw; } to { opacity: 1; translate: 0 0; } }
@keyframes zb2-defile { from { translate: 0 0; } to { translate: 0 4cqw; } }
@keyframes zb2-onde-sol {
  0%, 22.8% { opacity: 0; scale: .12; }
  23.4% { opacity: .95; animation-timing-function: cubic-bezier(.16, 1, .3, 1); }
  42%, 100% { opacity: 0; scale: 1.7; }
}
/* l'impact : la scene tremble trois fois, de moins en moins */
@keyframes zb2-secousse {
  0%, 22.8% { translate: 0 0; }
  23.3% { translate: -.4cqw .22cqw; }
  23.8% { translate: .32cqw -.16cqw; }
  24.3% { translate: -.18cqw .1cqw; }
  24.9%, 100% { translate: 0 0; }
}
/* la carte plie sous le choc puis rebondit (le seul ressort de la scene) */
@keyframes zb2-coup {
  0%, 22.6% { scale: 1; animation-timing-function: cubic-bezier(.4, 0, .6, 1); }
  23.3% { scale: .955; animation-timing-function: cubic-bezier(.34, 1.56, .64, 1); }
  28%, 100% { scale: 1; }
}
/* l'eclair se trace en 120 ms, scintille deux fois, s'eteint */
@keyframes zb2-trace {
  0%, 22% { stroke-dashoffset: 1; opacity: 0; }
  22.1% { opacity: 1; animation-timing-function: cubic-bezier(.3, 0, .2, 1); }
  23.3% { stroke-dashoffset: 0; opacity: 1; }
  24% { opacity: .3; }
  24.6% { opacity: 1; }
  25.4% { opacity: .55; }
  26% { opacity: 1; animation-timing-function: cubic-bezier(.4, 0, 1, 1); }
  29%, 100% { stroke-dashoffset: 0; opacity: 0; }
}
@keyframes zb2-titre-eclat {
  0%, 22.9% { filter: brightness(1); }
  23.4% { filter: brightness(1.9); animation-timing-function: cubic-bezier(.16, 1, .3, 1); }
  33%, 100% { filter: brightness(1); }
}
@keyframes zb2-flash {
  0%, 22.8% { opacity: 0; }
  23.2% { opacity: 1; }
  24% { opacity: .25; }
  24.6% { opacity: .8; animation-timing-function: cubic-bezier(.16, 1, .3, 1); }
  31%, 100% { opacity: 0; }
}
/* les etincelles jaillissent, puis retombent (une parabole en deux temps) */
@keyframes zb2-etincelle {
  0%, 23% { opacity: 0; translate: 0 0; scale: 1; }
  23.3% { opacity: 1; animation-timing-function: cubic-bezier(.16, 1, .3, 1); }
  29% { opacity: 1; translate: var(--x) var(--y); scale: .85; animation-timing-function: cubic-bezier(.55, 0, 1, .45); }
  35%, 100% { opacity: 0; translate: var(--x) calc(var(--y) + 4cqw); scale: .3; }
}
@keyframes zb2-hud-in {
  from { opacity: 0; transform: translateY(-1cqw); }
  to { opacity: 1; transform: none; }
}
/* le compteur monte avec l'impact, tient, puis repart a zero A L'ABRI
   d'un fondu (84 -> 84,6 %, invisible) */
@keyframes zb2-compte {
  0%, 24% { --zn: 0; --zf: 0; animation-timing-function: linear; }
  40%, 84% { --zn: var(--max); --zf: var(--max); animation-timing-function: linear; }
  84.6%, 100% { --zn: 0; --zf: 0; }
}
@keyframes zb2-vie {
  0%, 81.5% { opacity: 1; animation-timing-function: cubic-bezier(.4, 0, 1, 1); }
  83.8%, 85.2% { opacity: 0; animation-timing-function: cubic-bezier(.16, 1, .3, 1); }
  89%, 100% { opacity: 1; }
}
@keyframes zb2-tour { from { rotate: 0turn; } to { rotate: 1turn; } }
@keyframes zb2-irise {
  0%, 100% { translate: -24% 0; animation-timing-function: cubic-bezier(.37, 0, .63, 1); }
  50% { translate: 24% 0; animation-timing-function: cubic-bezier(.37, 0, .63, 1); }
}

/* Fiche au telephone : le tableau de bord grossit, les etincelles aussi. */
@container (min-width: 301px) and (max-width: 560px) {
  .zb2-hud { left: 2.8cqw; top: 2.8cqw; padding: 1.2cqw; border-radius: 50%; }
  .zb2-hud-txt { display: none; }
  .zb2-hud-boite { width: 9.4cqw; height: 9.4cqw; }
  .zb2-hud-n { font-size: 3.5cqw; }
  .zb2-gerbe i { width: calc(.85cqw * var(--s, 1)); height: calc(.85cqw * var(--s, 1)); }
}

/* Vignettes : ni sol, ni aurores, ni tableau de bord, ni etincelles. Le
   faisceau, le reflet irise et une mini-frappe, decalee d'une vignette a
   l'autre comme le reflet : jamais deux eclairs ensemble dans la liste. */
@container (max-width: 300px) {
  .zb2-aurore, .zb2-sol, .zb2-hud, .zb2-gerbe, .zb2-f-branche { display: none; }
  .zb2-carte { --rc: 3.4cqw; --anneau: max(1px, .6cqw); }
  /* le faisceau des vignettes est un liseré fige, place autrement sur
     chaque carte (--zi) ; il ne tourne qu'au survol de la ligne. Quinze
     faisceaux en rotation coutaient 12 images/s a CPU x4. */
  .zb2-bord b { animation: none; rotate: calc(var(--zi, 0) * 97deg); }
  .group:hover .zb2-bord b { animation: zb2-tour 1.6s linear infinite both; }
  .zb2-foudre { left: calc(50% + 6.5cqw); width: 11cqw; height: 13cqw; bottom: 94%; }
  .zb2-f-coeur { stroke-width: 2.4; }
  .zb2-f-halo { stroke-width: 6; stroke: rgba(77, 163, 255, .5); }
  .zb2-flotte { animation: zb2-flotte-v calc(var(--cy) / 2) infinite both, zb2-coup var(--cy) calc(var(--zi, 0) * -2.1s) infinite both; }
  .zb2-f-coeur, .zb2-f-halo { animation: zb2-trace var(--cy) calc(var(--zi, 0) * -2.1s) infinite both; }
  .zb2-eclair { animation: zb2-flash var(--cy) calc(var(--zi, 0) * -2.1s) infinite both; }
}

/* Moins de mouvement : le tableau de bord montre le pack, rien ne frappe. */
@media (prefers-reduced-motion: reduce) {
  .zb2-hud-vie { --zn: var(--max); --zf: var(--max); }
  /* les ondes, sans leur animation, restaient un grand anneau fige */
  .zb2-ondes, .zb2-gerbe, .zb2-foudre, .zb2-eclair { display: none; }
}