/* ============================================================================
   BIBLIOTHEQUE UI JABS  -  motion.css
   Depend de : theme.css

   Le mouvement est le premier marqueur d'un travail soigne. Il ne s'agit pas
   d'animer davantage, mais d'animer AU BON MOMENT : a l'arrivee d'un bloc dans
   le champ de vision, pendant une transition de page, sous le doigt.

   Trois regles tenues partout dans ce fichier :
   1. Rien ne bouge sans raison. Une animation qui ne renseigne pas sur un
      changement d'etat est un cout de lecture.
   2. Le contenu est lisible AVANT l'animation. On anime l'opacite et la
      position, jamais l'existence : un bloc non anime reste visible.
   3. prefers-reduced-motion coupe tout, sans casser la mise en page.

   Les variantes reposent sur les animations pilotees par le defilement
   (animation-timeline), natives et sans JavaScript. Le repli @supports rend
   le contenu visible et immobile, jamais invisible.
   ========================================================================= */

/* ---------------------------------------------------------------------------
   SOCLE : reveler a l'entree dans le champ de vision
   `animation-timeline: view()` lie la progression de l'animation a la position
   du bloc dans la fenetre. Aucun JavaScript, aucun observateur.
   ------------------------------------------------------------------------ */
@keyframes mv-apparait { from { opacity: 0; transform: translateY(28px); } to { opacity: 1; transform: none; } }
@keyframes mv-fond     { from { opacity: 0; } to { opacity: 1; } }
@keyframes mv-glisse-g { from { opacity: 0; transform: translateX(-40px); } to { opacity: 1; transform: none; } }
@keyframes mv-glisse-d { from { opacity: 0; transform: translateX(40px); } to { opacity: 1; transform: none; } }
@keyframes mv-echelle  { from { opacity: 0; transform: scale(.94); } to { opacity: 1; transform: none; } }
@keyframes mv-flou     { from { opacity: 0; filter: blur(10px); } to { opacity: 1; filter: none; } }

/* ===========================================================================
   FAMILLE A  -  REVELATION AU DEFILEMENT
   ======================================================================== */

/* @v MOV-A1
@nom Revelation simple
@usage Le bloc monte et se revele en entrant dans le champ. C'est le mouvement de base d'une page editoriale : discret, applique une fois, jamais rejoue.
@large
@html
<div class="mv-scene" data-mv-scene>
  <p class="mv-indice">Faites defiler la zone ci-dessous</p>
  <div class="mv-piste">
    <div class="mv-bloc mv-reveler"><strong>Premier bloc</strong><span>Il monte de 28 px et se revele</span></div>
    <div class="mv-bloc mv-reveler"><strong>Deuxieme bloc</strong><span>Chacun se declenche a son entree</span></div>
    <div class="mv-bloc mv-reveler"><strong>Troisieme bloc</strong><span>Le mouvement ne se rejoue pas</span></div>
    <div class="mv-bloc mv-reveler"><strong>Quatrieme bloc</strong><span>Coupe par prefers-reduced-motion</span></div>
  </div>
</div>
@tw animate-[mv-apparait] [animation-timeline:view()] [animation-range:entry_0%_cover_35%]
@end */
.mv-reveler {
  animation: mv-apparait linear both;
  animation-timeline: view();
  animation-range: entry 0% cover 32%;
}
/* Sans animations pilotees par le defilement, le contenu reste simplement
   visible : jamais d'opacite 0 figee. */
@supports not (animation-timeline: view()) {
  .mv-reveler { animation: none; opacity: 1; transform: none; }
}
/* @endv */

/* @v MOV-A2
@nom Revelation en cascade
@usage Une liste dont les elements arrivent l'un apres l'autre. Le decalage se regle par le point de depart de chaque element, pas par un delai : ainsi le rythme suit la vitesse de defilement.
@large
@html
<div class="mv-scene" data-mv-scene>
  <p class="mv-indice">Faites defiler</p>
  <div class="mv-piste">
    <div class="mv-grille">
      <div class="mv-carte mv-reveler" style="--i:0"><b>01</b>Etude thermique</div>
      <div class="mv-carte mv-reveler" style="--i:1"><b>02</b>Devis et aides</div>
      <div class="mv-carte mv-reveler" style="--i:2"><b>03</b>Pose</div>
      <div class="mv-carte mv-reveler" style="--i:3"><b>04</b>Mise en service</div>
      <div class="mv-carte mv-reveler" style="--i:4"><b>05</b>Entretien</div>
      <div class="mv-carte mv-reveler" style="--i:5"><b>06</b>Garantie 5 ans</div>
    </div>
  </div>
</div>
@tw [animation-range:entry_calc(var(--i)*6%)_cover_35%]
@end */
.mv-grille { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: var(--sp-3); }
.mv-grille .mv-reveler { animation-range: entry calc(var(--i, 0) * 7%) cover 40%; }
.mv-carte {
  padding: var(--sp-4);
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  background: var(--c-surface);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semi);
}
.mv-carte b { display: block; margin-bottom: 6px; font-family: var(--font-mono); font-size: 11px; color: var(--c-primary); }
/* @endv */

/* @v MOV-A3
@nom Directions de revelation
@usage Cinq entrees pour cinq intentions. La direction porte un sens : ce qui vient de la gauche prolonge le texte, ce qui monte est une nouveaute, ce qui se defloute arrive de loin.
@large
@html
<div class="mv-scene" data-mv-scene>
  <p class="mv-indice">Faites defiler</p>
  <div class="mv-piste">
    <div class="mv-bloc mv-glisse-g"><strong>Depuis la gauche</strong><span>mv-glisse-g</span></div>
    <div class="mv-bloc mv-glisse-d"><strong>Depuis la droite</strong><span>mv-glisse-d</span></div>
    <div class="mv-bloc mv-echelle"><strong>Par l'echelle</strong><span>mv-echelle</span></div>
    <div class="mv-bloc mv-flou"><strong>Par le flou</strong><span>mv-flou</span></div>
    <div class="mv-bloc mv-fondu"><strong>Fondu seul</strong><span>mv-fondu, le plus sobre</span></div>
  </div>
</div>
@tw animate-[mv-glisse-g] / [mv-echelle] / [mv-flou] avec la meme timeline
@end */
.mv-glisse-g, .mv-glisse-d, .mv-echelle, .mv-flou, .mv-fondu {
  animation: linear both;
  animation-timeline: view();
  animation-range: entry 0% cover 34%;
}
.mv-glisse-g { animation-name: mv-glisse-g; }
.mv-glisse-d { animation-name: mv-glisse-d; }
.mv-echelle  { animation-name: mv-echelle; }
.mv-flou     { animation-name: mv-flou; }
.mv-fondu    { animation-name: mv-fond; }
@supports not (animation-timeline: view()) {
  .mv-glisse-g, .mv-glisse-d, .mv-echelle, .mv-flou, .mv-fondu {
    animation: none; opacity: 1; transform: none; filter: none;
  }
}
/* @endv */

/* @v MOV-A4
@nom Barre de progression de lecture
@usage En tete d'un article long. Elle suit le defilement du document, sans JavaScript, grace a scroll() plutot que view().
@large
@html
<div class="mv-scene" data-mv-scene>
  <div class="mv-piste mv-piste--article">
    <div class="mv-progres"><i></i></div>
    <h4>La renovation energetique en 2026</h4>
    <p>Le remplacement d'une chaudiere fioul par une pompe a chaleur reste l'operation la plus subventionnee. Le montant de MaPrimeRenov depend du revenu fiscal de reference et de la zone climatique.</p>
    <p>Les certificats d'economie d'energie s'ajoutent a cette aide et sont verses par le fournisseur d'energie, generalement sous forme de deduction directe sur le devis.</p>
    <p>La TVA a taux reduit de 5,5 % s'applique aux travaux d'amelioration de la performance energetique, a condition que l'attestation soit signee avant le debut du chantier.</p>
    <p>Le delai moyen constate entre la premiere visite et la mise en service se situe entre trois et six semaines selon la disponibilite du materiel.</p>
  </div>
</div>
@tw [animation-timeline:scroll(nearest)] sur une barre en position sticky
@end */
.mv-progres {
  position: sticky;
  top: 0;
  z-index: 2;
  height: 3px;
  background: var(--c-surface-3);
  border-radius: var(--r-full);
  overflow: hidden;
  margin-bottom: var(--sp-4);
}
.mv-progres i {
  display: block;
  height: 100%;
  width: 100%;
  transform-origin: 0 50%;
  background: linear-gradient(90deg, var(--c-primary), var(--c-accent));
  animation: mv-remplir linear both;
  animation-timeline: scroll(nearest);
}
@keyframes mv-remplir { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@supports not (animation-timeline: scroll()) { .mv-progres i { animation: none; transform: scaleX(.4); } }
.mv-piste--article h4 { margin: 0 0 var(--sp-3); font-size: 22px; font-weight: 800; letter-spacing: -.02em; }
.mv-piste--article p { margin: 0 0 var(--sp-4); font-size: var(--fs-md); line-height: 1.7; color: var(--c-text-soft); max-width: 62ch; }
/* @endv */

/* ===========================================================================
   FAMILLE B  -  DEFILEMENT MIS EN SCENE
   ======================================================================== */

/* @v MOV-B1
@nom Parallaxe
@usage Le fond avance moins vite que le contenu. A doser : au-dela de 15 % de decalage, l'effet se remarque plus que le contenu qu'il sert.
@large
@html
<div class="mv-scene" data-mv-scene>
  <p class="mv-indice">Faites defiler</p>
  <div class="mv-piste">
    <div class="mv-para">
      <div class="mv-para__fond"></div>
      <div class="mv-para__texte"><strong>1 240 installations</strong><span>depuis 2009 en Ile-de-France</span></div>
    </div>
    <p class="mv-note">Le fond se deplace de 14 % pendant que le bloc traverse le champ.</p>
  </div>
</div>
@tw [animation-timeline:view()] sur un pseudo-element de fond
@end */
.mv-para { position: relative; height: 260px; border-radius: var(--r-lg); overflow: hidden; display: grid; place-items: center; }
.mv-para__fond {
  position: absolute;
  inset: -14% 0;
  background:
    radial-gradient(circle at 25% 30%, #4a6fa5 0 22%, transparent 55%),
    radial-gradient(circle at 75% 60%, #a8643c 0 20%, transparent 52%),
    linear-gradient(150deg, #223047, #4a5b73 60%, #6b5a48);
  animation: mv-parallaxe linear both;
  animation-timeline: view();
}
@keyframes mv-parallaxe { from { transform: translateY(-7%); } to { transform: translateY(7%); } }
@supports not (animation-timeline: view()) { .mv-para__fond { animation: none; inset: 0; } }
.mv-para__texte { position: relative; text-align: center; color: #fff; text-shadow: 0 2px 14px rgba(0,0,0,.45); }
.mv-para__texte strong { display: block; font-size: 44px; font-weight: 800; letter-spacing: -.03em; }
.mv-para__texte span { font-size: var(--fs-md); opacity: .88; }
/* @endv */

/* @v MOV-B2
@nom Sections empilees
@usage Chaque section se colle en haut pendant que la suivante monte par-dessus. Sert a raconter une progression sans que l'utilisateur perde le fil.
@large
@html
<div class="mv-scene mv-scene--haute" data-mv-scene>
  <p class="mv-indice">Faites defiler</p>
  <div class="mv-piste mv-empile">
    <section style="--t:#1f3a5f"><b>01</b><strong>Visite technique</strong><p>Releve sur place, etude thermique offerte.</p></section>
    <section style="--t:#2f6b4f"><b>02</b><strong>Devis et aides</strong><p>Aides deduites, dossier monte par nos soins.</p></section>
    <section style="--t:#7a4b2a"><b>03</b><strong>Pose</strong><p>Par nos equipes salariees, en 1 a 3 jours.</p></section>
    <section style="--t:#4a2f5e"><b>04</b><strong>Mise en service</strong><p>Reglages, prise en main et garantie 5 ans.</p></section>
  </div>
</div>
@tw sticky top-0 avec un fond opaque par section
@end */
.mv-empile section {
  position: sticky;
  top: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 210px;
  padding: var(--sp-8);
  border-radius: var(--r-lg);
  background: var(--t);
  color: #fff;
  box-shadow: 0 -8px 30px rgba(0,0,0,.18);
}
.mv-empile section + section { margin-top: var(--sp-4); }
.mv-empile b { font-family: var(--font-mono); font-size: 12px; opacity: .6; }
.mv-empile strong { font-size: 28px; font-weight: 800; letter-spacing: -.025em; margin: 6px 0 4px; }
.mv-empile p { margin: 0; font-size: var(--fs-md); opacity: .82; max-width: 46ch; }
/* @endv */

/* @v MOV-B3
@nom Defilement horizontal
@usage Une section qui se parcourt de gauche a droite pendant que la page descend. Efficace pour une frise ou un portfolio ; a n'utiliser qu'une fois par page.
@large
@html
<div class="mv-scene mv-scene--haute" data-mv-scene>
  <p class="mv-indice">Faites defiler</p>
  <div class="mv-piste">
    <div class="mv-horiz">
      <div class="mv-horiz__colle">
        <div class="mv-horiz__rail">
          <article style="--t:#22384f"><b>2009</b><span>Creation de l'atelier</span></article>
          <article style="--t:#2f5a45"><b>2015</b><span>Certification RGE QualiPAC</span></article>
          <article style="--t:#6b4a2a"><b>2019</b><span>Deuxieme equipe de pose</span></article>
          <article style="--t:#4a3560"><b>2023</b><span>1 000e installation</span></article>
          <article style="--t:#5e3040"><b>2026</b><span>Ouverture du depot de Bondy</span></article>
        </div>
      </div>
    </div>
  </div>
</div>
@tw sticky + translateX pilote par animation-timeline:view()
@end */
.mv-horiz { height: 900px; }
.mv-horiz__colle { position: sticky; top: 0; height: 260px; overflow: hidden; border-radius: var(--r-lg); display: flex; align-items: center; }
.mv-horiz__rail {
  display: flex;
  gap: var(--sp-4);
  padding: 0 var(--sp-4);
  animation: mv-defile linear both;
  animation-timeline: view();
  animation-range: contain 0% contain 100%;
}
@keyframes mv-defile { from { transform: translateX(4%); } to { transform: translateX(-46%); } }
@supports not (animation-timeline: view()) {
  .mv-horiz__rail { animation: none; overflow-x: auto; }
  .mv-horiz { height: auto; }
  .mv-horiz__colle { position: static; height: auto; }
}
.mv-horiz__rail article {
  flex: none;
  width: 260px;
  height: 200px;
  padding: var(--sp-5);
  border-radius: var(--r-lg);
  background: var(--t);
  color: #fff;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}
.mv-horiz__rail b { font-size: 34px; font-weight: 800; letter-spacing: -.03em; }
.mv-horiz__rail span { font-size: var(--fs-sm); opacity: .82; margin-top: 4px; }
/* @endv */

/* @v MOV-B4
@nom Bandeau defilant
@usage Logos de partenaires, mots-cles, certifications. Le contenu est duplique pour que la boucle soit invisible, et l'animation se met en pause au survol.
@large
@html
<div class="mv-bandeau">
  <div class="mv-bandeau__rail">
    <span>RGE QualiPAC</span><i>&bull;</i><span>QualiBois</span><i>&bull;</i><span>Garantie 5 ans</span><i>&bull;</i>
    <span>Devis sous 24 h</span><i>&bull;</i><span>1 240 installations</span><i>&bull;</i><span>Equipes salariees</span><i>&bull;</i>
    <span aria-hidden="true">RGE QualiPAC</span><i aria-hidden="true">&bull;</i><span aria-hidden="true">QualiBois</span><i aria-hidden="true">&bull;</i>
    <span aria-hidden="true">Garantie 5 ans</span><i aria-hidden="true">&bull;</i><span aria-hidden="true">Devis sous 24 h</span><i aria-hidden="true">&bull;</i>
    <span aria-hidden="true">1 240 installations</span><i aria-hidden="true">&bull;</i><span aria-hidden="true">Equipes salariees</span><i aria-hidden="true">&bull;</i>
  </div>
</div>
@tw animate-[marquee_28s_linear_infinite] hover:[animation-play-state:paused]
@end */
.mv-bandeau {
  width: 100%;
  padding: var(--sp-4) 0;
  border-top: 1px solid var(--c-border);
  border-bottom: 1px solid var(--c-border);
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.mv-bandeau__rail {
  display: flex;
  align-items: center;
  gap: var(--sp-5);
  width: max-content;
  animation: mv-bandeau 32s linear infinite;
}
.mv-bandeau:hover .mv-bandeau__rail { animation-play-state: paused; }
@keyframes mv-bandeau { to { transform: translateX(-50%); } }
.mv-bandeau span { font-size: var(--fs-lg); font-weight: var(--fw-semi); white-space: nowrap; color: var(--c-text); }
.mv-bandeau i { color: var(--c-primary); font-style: normal; }
/* @endv */

/* ===========================================================================
   FAMILLE C  -  MOUVEMENTS D'INTERFACE
   ======================================================================== */

/* @v MOV-C1
@nom Transition entre pages
@usage La View Transitions API fait glisser une page vers la suivante au lieu du clignotement blanc. Deux lignes de CSS suffisent, et les navigateurs qui l'ignorent affichent la navigation habituelle.
@large
@html
<div class="mv-code">
  <pre><code>/* Dans le CSS du site, une seule fois */
@view-transition { navigation: auto; }

/* Regler la duree et la courbe */
::view-transition-old(root) { animation: 180ms ease-out both mv-sortie; }
::view-transition-new(root) { animation: 260ms cubic-bezier(.2,0,0,1) both mv-entree; }

@keyframes mv-sortie { to   { opacity: 0; transform: translateY(-8px); } }
@keyframes mv-entree { from { opacity: 0; transform: translateY(12px); } }

/* Un element partage entre les deux pages garde son identite :
   la vignette d'une liste devient l'image de la fiche, sans coupure. */
.vignette-103 { view-transition-name: photo-103; }</code></pre>
  <p class="mv-note">Aucun JavaScript, aucune bibliotheque. C'est ce qui remplace aujourd'hui les transitions de page qui demandaient un routeur complet.</p>
</div>
@tw @view-transition { navigation: auto } + ::view-transition-old/new
@end */
.mv-code pre { margin: 0; padding: var(--sp-4); border-radius: var(--r-md); background: #12151b; color: #d5dde8; font-family: var(--font-mono); font-size: 12px; line-height: 1.7; overflow-x: auto; }
.mv-note { margin: var(--sp-3) 0 0; font-size: var(--fs-sm); color: var(--c-text-muted); line-height: 1.55; max-width: 70ch; }
/* @endv */

/* @v MOV-C2
@nom Compteur qui s'incremente
@usage Un chiffre de preuve qui monte a l'arrivee dans le champ. Le nombre final est ecrit dans le balisage : si le script ne s'execute pas, la valeur reste juste.
@large
@html
<div class="mv-chiffres">
  <div><strong data-mv-compte="1240">1 240</strong><span>installations depuis 2009</span></div>
  <div><strong data-mv-compte="4.8" data-mv-dec="1">4,8</strong><span>note moyenne sur 312 avis</span></div>
  <div><strong data-mv-compte="98">98</strong><span>pour cent de chantiers dans les delais</span></div>
</div>
@tw JS : IntersectionObserver + requestAnimationFrame (voir js/motion.js)
@end */
.mv-chiffres { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: var(--sp-5); width: 100%; text-align: center; }
.mv-chiffres strong { display: block; font-size: 46px; font-weight: 800; letter-spacing: -.035em; color: var(--c-text); font-variant-numeric: tabular-nums; line-height: 1; }
.mv-chiffres span { display: block; margin-top: 8px; font-size: var(--fs-sm); color: var(--c-text-muted); line-height: 1.45; }
/* @endv */

/* @v MOV-C3
@nom Texte revele mot par mot
@usage Une phrase d'ouverture qui se construit. Chaque mot reste un mot dans le balisage : la selection, la recherche et les lecteurs d'ecran ne voient aucune difference.
@large
@html
<p class="mv-mots">
  <span>Nous</span> <span>posons</span> <span>des</span> <span>pompes</span> <span>a</span> <span>chaleur</span>
  <span>depuis</span> <span>2009,</span> <span>avec</span> <span>nos</span> <span>propres</span> <span>equipes.</span>
</p>
@tw [&>span]:animate-[mv-apparait] [&>span]:[animation-timeline:view()] avec un range decale
@end */
.mv-mots {
  margin: 0;
  font-size: clamp(22px, 3.4vw, 34px);
  font-weight: 700;
  line-height: 1.35;
  letter-spacing: -.02em;
  max-width: 22ch;
}
.mv-mots span {
  display: inline-block;
  animation: mv-mot linear both;
  animation-timeline: view();
  animation-range: entry 10% cover 30%;
}
@keyframes mv-mot { from { opacity: 0; transform: translateY(.4em) rotate(2deg); } to { opacity: 1; transform: none; } }
.mv-mots span:nth-child(n+4) { animation-range: entry 14% cover 34%; }
.mv-mots span:nth-child(n+8) { animation-range: entry 18% cover 38%; }
@supports not (animation-timeline: view()) { .mv-mots span { animation: none; opacity: 1; transform: none; } }
/* @endv */

/* @v MOV-C4
@nom Bouton magnetique
@usage Le bouton suit legerement le curseur avant le clic. Reserve a l'action principale d'une banniere : applique partout, l'effet devient un tic.
@html
<div class="demo-row" style="padding:30px 0">
  <button class="btn btn--plein btn--xl mv-aimant" data-mv-aimant>Demander un devis</button>
  <button class="btn btn--secondaire btn--xl mv-aimant" data-mv-aimant>Nous appeler</button>
</div>
@tw JS : translate calcule depuis la position du curseur (voir js/motion.js)
@end */
.mv-aimant { transition: transform 320ms cubic-bezier(.2,0,0,1), background-color var(--t-fast); will-change: transform; }
/* @endv */

/* @v MOV-C5
@nom Curseur suiveur
@usage Un rond qui suit le curseur et grossit sur les elements cliquables. Signature d'agence, a n'employer que sur un site vitrine, jamais dans un outil de travail.
@large
@html
<div class="mv-curseur-zone" data-mv-curseur>
  <div class="mv-curseur" aria-hidden="true"></div>
  <p>Deplacez le curseur dans cette zone.</p>
  <div class="demo-row">
    <a href="#" class="btn btn--secondaire" data-mv-cible>Un lien</a>
    <a href="#" class="btn btn--secondaire" data-mv-cible>Un autre</a>
  </div>
</div>
@tw JS : position en pointer-events-none, scale au survol des cibles
@end */
.mv-curseur-zone {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--sp-4);
  width: 100%;
  min-height: 220px;
  border: 1px dashed var(--c-border-strong);
  border-radius: var(--r-lg);
  background: var(--c-surface);
  overflow: hidden;
}
.mv-curseur-zone p { margin: 0; font-size: var(--fs-sm); color: var(--c-text-muted); }
.mv-curseur {
  position: absolute;
  top: 0; left: 0;
  width: 26px; height: 26px;
  margin: -13px 0 0 -13px;
  border: 1.5px solid var(--c-primary);
  border-radius: 50%;
  pointer-events: none;
  opacity: 0;
  transition: transform 160ms cubic-bezier(.2,0,0,1), opacity 200ms, background-color 200ms;
  z-index: 5;
}
.mv-curseur-zone.is-actif .mv-curseur { opacity: 1; }
.mv-curseur.is-cible { transform: scale(2.1); background: color-mix(in srgb, var(--c-primary) 14%, transparent); }
/* Sur un ecran tactile, il n'y a pas de curseur a suivre. */
@media (hover: none) { .mv-curseur { display: none; } }
/* @endv */

/* @v MOV-C6
@nom Chiffres qui roulent
@usage Un montant qui change en direct : compteur de dossiers, total d'un panier. Seul le chiffre modifie bouge, ce qui evite de faire clignoter toute la ligne.
@html
<div class="mv-roue" data-mv-roue>
  <span>4</span><span>2</span><span>8</span><span>0</span><em>,00 EUR</em>
</div>
@tw chaque chiffre est une colonne de 0 a 9 translatee verticalement
@end */
.mv-roue { display: inline-flex; align-items: baseline; font-size: 40px; font-weight: 800; letter-spacing: -.03em; font-variant-numeric: tabular-nums; color: var(--c-text); }
.mv-roue span {
  display: inline-block;
  height: 1em;
  overflow: hidden;
  line-height: 1;
}
.mv-roue span::before {
  content: "0\A 1\A 2\A 3\A 4\A 5\A 6\A 7\A 8\A 9";
  display: block;
  white-space: pre;
  transform: translateY(calc(var(--n, 0) * -1em));
  transition: transform 620ms cubic-bezier(.2,0,0,1);
}
.mv-roue em { font-style: normal; font-size: .55em; font-weight: var(--fw-semi); color: var(--c-text-muted); margin-left: 2px; }
/* @endv */

/* ---------------------------------------------------------------------------
   SCENE DE DEMONSTRATION (catalogue uniquement)
   Une zone de defilement autonome, pour montrer un effet de scroll sans
   dependre du defilement de la page.
   ------------------------------------------------------------------------ */
.mv-scene { width: 100%; }
.mv-indice {
  margin: 0 0 6px;
  font-size: var(--fs-xs);
  font-weight: var(--fw-semi);
  color: var(--c-text-muted);
}
.mv-indice::before { content: "\2193 \00a0"; }
.mv-piste {
  height: 300px;
  overflow-y: auto;
  padding: 40px var(--sp-4) 180px;
  border: 1px solid var(--c-border);
  border-radius: var(--r-lg);
  background: var(--c-surface);
  scroll-behavior: smooth;
}
.mv-scene--haute .mv-piste { height: 340px; }
.mv-piste > * + * { margin-top: var(--sp-4); }
.mv-bloc {
  padding: var(--sp-5);
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  background: var(--c-surface-2);
}
.mv-bloc strong { display: block; font-size: var(--fs-lg); font-weight: var(--fw-bold); }
.mv-bloc span { font-size: var(--fs-sm); color: var(--c-text-muted); }
