/* hero.module — tokens uniquement. Le socle commun est dans css/patterns.css.

   ⚠️ Ce fichier était VIDE (0 octet) depuis le commit ce615eb : le CSS du hero
   avait été déplacé dans patterns.css, mais SEULES les primitives partagées y
   sont arrivées. `.hero__inner`, `.hero__copy`, `.hero__media`, `.hero__stats`
   n'avaient donc AUCUN style nulle part — le hero tombait en flux vertical nu.
   C'est une des causes des « formes et blocs manquants » signalés le 2026-08-07.

   Rythme repris de la maquette solution (11507:1340) : titre à 150px du haut de
   bande, lede à +210, boutons à +97, média à +152. */

.hero__inner { display: grid; gap: var(--space-6); }
/* Colonne de texte bornée : à 1338px de contenu, une H1 pleine largeur donnerait
   des lignes de 100+ caractères. Figma cadre le titre du hero sur 748/1338. */
.hero__copy { max-width: 46ch; }

/* Hero CENTRÉ — la disposition de la maquette (11507:1340). Titre, lede, boutons
   et média partagent l'axe de page.
   Les bornes sont des PROPORTIONS du contenu, relevées au node et non choisies :
   titre 748/1338 = 56 %, lede 770/1338 = 58 %, média 1142/1338 = 85 %. Une borne
   en `ch` ne marcherait pas ici — elle dépend de la fonte et étranglait tout le
   bloc (le lede tombait à 300px de large). La borne va sur chaque élément, jamais
   sur `.hero__copy` : sinon elle contraint aussi le kicker et les boutons. */
.hero--center { text-align: center; }
.hero--center .hero__copy { max-width: none; }
.hero--center .sec__title { max-width: 56%; margin-inline: auto; }
.hero--center .sec__lede { max-width: 58%; margin-inline: auto; }
.hero--center .actions { justify-content: center; }
.hero--center .media--hero, .hero--center .hero__media { width: 85%; margin-inline: auto; }
@media (max-width: 767px) {
  .hero--center .sec__title, .hero--center .sec__lede { max-width: none; }
  .hero--center .media--hero { width: 100%; }
}
.hero__copy .sec__title { margin-bottom: var(--space-5); }
.hero__tagline { margin: 0 0 var(--space-4); color: var(--ema-primary); }

/* Variante deux colonnes (visuel à côté du texte). Sans visuel, le hero reste
   sur une colonne : c'est ce qui permet de livrer avant les 18 illustrations. */
.hero--split { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: center; }
.hero--split .hero__copy { max-width: none; }
.hero--media-left .hero__copy { order: 2; }

/* Visuel pleine largeur sous le texte (disposition de la maquette solution :
   le média y fait 1142 de large pour 1338 de contenu, centré). */
.hero__media { margin: var(--space-7) 0 0; }
.hero__media img { display: block; width: 100%; border-radius: var(--radius-lg); }
.hero--split .hero__media { margin-top: 0; }

/* Chiffres du hero (Home, Insights) : jamais des cartes bordées — le chiffre
   porte lui-même le rythme. */
.hero__stats { display: flex; flex-wrap: wrap; gap: var(--space-7);
  margin: var(--space-7) 0 0; }
.hero__stat dt { color: var(--on-ink-muted); margin: 0 0 var(--space-1); }
.hero__stat dd { margin: 0; color: var(--ema-primary); }

@media (max-width: 991px) {
  .hero--split { grid-template-columns: minmax(0, 1fr); }
  .hero--media-left .hero__copy { order: 0; }
  .hero__stats { gap: var(--space-5); }
}

/* Photo d'ambiance sous le hero (visuel « below ») : plafonnée à 60 % de la hauteur
   d'écran et recadrée, sinon une photo 4:3 pousse la première preuve hors du premier
   écran (recette partenaires 25/08 : 900 px de photo avant le mur de logos). */
.hero--center .hero__media img, .hero--center .media--hero img { max-block-size: 52vh; object-fit: contain; object-position: center; }


/* ===== TUILES CHEVAUCHANTES (27/08, Figma accueil) ============================================
   Deux grandes tuiles sous le titre centré ; elles DESCENDENT sur la bande suivante (marge
   négative + z-index), la bande suivante s'écarte d'autant. La bande qui porte le hero ne rogne
   plus (overflow visible) — nécessaire au chevauchement. */
.hero--overlap { padding-bottom: 0; }

/* 03/09 (Gaspard, généralisé depuis pourquoi-vs-bi) — L'ÉCRAN CHEVAUCHANT (`**Écran**` du deck) :
   le hero épuré se termine sur UNE grande capture qui déborde sur la bande suivante — le
   downstream (padding compensé de la bande d'après) est déjà porté par les règles hero--overlap
   ci-dessous, communes avec les tuiles. La capture est une carte : coins arrondis, ombre portée,
   jamais collée aux bords (max 62rem). */
.hero__ecran { position: relative; z-index: 1; margin: var(--space-7) auto calc(-1 * var(--space-9));
  /* 03/09 (Gaspard : consolidation-dashboard et tableau-construire « trop grandes ») : 62rem → 46rem. */
  max-width: min(100%, 33rem); border-radius: var(--radius-xl); overflow: hidden; box-shadow: var(--shadow-raised); } /* 04/09 (Gaspard, 4e rappel taille) : 40 → 33rem */
.hero__ecran img { display: block; width: 100%; height: auto; }
@media (max-width: 767px) { .hero__ecran { margin-bottom: calc(-1 * var(--space-7)); border-radius: var(--radius-lg); } }
.hero__tiles { position: relative; z-index: 3; display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--space-6);
  margin: var(--space-8) 0 calc(-1 * var(--space-10)); text-align: left; }
.hero__tile { position: relative; overflow: hidden; border-radius: var(--radius-lg); min-height: 20rem; box-shadow: var(--shadow-card); margin: 0; }
.hero__tile--photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.hero__tile--illu { background: var(--color-paper-0); display: grid; place-items: center; padding: var(--space-6); }
.hero__tile--illu img { object-fit: contain; }
.hero__tile--claim { background: var(--ema-primary); color: var(--on-primary); display: grid; grid-template-columns: minmax(0, 6fr) minmax(0, 5fr); }
.hero__tile-copy { position: relative; z-index: 2; display: flex; flex-direction: column; gap: var(--space-5); padding: var(--space-7); }
.hero__tile-claim { margin: 0; font-weight: var(--weight-bold); text-wrap: balance; color: var(--on-primary); }
.hero__tile-btn, .on-dark .hero__tile-btn { align-self: flex-start; background: var(--color-paper-0); color: var(--color-ink-900); border-color: var(--color-paper-0); }
.hero__tile-arc { position: absolute; left: 42%; top: 10%; width: 26%; color: var(--color-paper-0); opacity: .9; z-index: 1; pointer-events: none; }
.hero__tile-arc svg { width: 100%; height: auto; display: block; }
.hero__tile-screen { position: absolute; right: calc(-1 * var(--space-8)); top: var(--space-8); width: 58%; height: auto; border-radius: var(--radius-md);
  box-shadow: var(--shadow-raised); z-index: 2; }
.dnd-section:has(.hero--overlap), .band:has(.hero--overlap) { overflow: visible; }
/* 28/08 : la compensation du chevauchement ne vise que la PREMIÈRE section qui suit — et seulement si
   le hero ferme sa bande. Avant, tous les `.sec` de la bande suivante prenaient +80 px (écarts géants
   sur l'accueil) et, quand une bande de logos suivait le hero dans la MÊME bande, les tuiles la recouvraient. */
/* 09/09 (recette dnd, home) — MIROIR EXACT des deux règles .band ci-dessous, côté drag & drop :
   • bande suivante : seulement si le hero overlap FERME sa bande — garde : aucune rangée suivante
     ne porte de .sec (la rangée band-decor, un <span>, ne compte pas). ⚠️ pas de :has() DANS un
     :has() : c'est invalide, et le parsing tolérant vide la garde (recette du 09/09 : +128 px à
     tort sur la bande 2 de la home). La compensation ne vise que la PREMIÈRE rangée de la bande
     suivante — comme `> .sec:first-child` côté aperçu : au-delà, c'est la densité
     `.dnd-row + .dnd-row .sec { padding-top: 0 }` qui règne (recette : +128 px sur en-chiffres).
   • même bande : la section qui suit le hero dans SA bande (rangée dnd adjacente) prend la même
     compensation que `.hero--overlap:not(:last-child) + .sec` — sans elle, la frise de logos de la
     home collait au hero (la densité .dnd-row + .dnd-row mettait son padding-top à 0). */
/* 11/09 (recette FR des trois `pourquoi-*`) — TROISIÈME condition, invisible jusqu'ici : côté aperçu
   le DÉCOR d'une bande est un <span> posé en PREMIER enfant (209 bandes sur 209 vérifiées), si bien
   que `> .sec:first-child` ne matche JAMAIS dans une bande décorée — donc pas de compensation. Côté
   dnd le compositeur range la rangée décor en DERNIER : `.dnd-row:first-child .sec` matchait toujours
   et la bande suivante prenait +128 px à tort (DOM identique, 40 % de pixels d'écart). La garde
   reproduit la condition de l'aperçu : pas de compensation si la bande suivante porte un décor. */
.dnd-section:has(.hero--overlap):not(:has(.dnd-row ~ .dnd-row .sec:not(.hero))) + .dnd-section:not(:has([class*="decor--"])):not(:has(.rings-band)) .dnd-row:first-child .sec, .band:has(.hero--overlap:last-child) + .band > .sec:first-child { padding-top: calc(var(--section-py) + var(--space-10)); }
.dnd-section:has(> .row-fluid .sec) .dnd-row:has(.hero--overlap) + .dnd-row .sec,
.dnd-section.ema-sec .dnd-row:has(.hero--overlap) + .dnd-row .sec,
.hero--overlap:not(:last-child) + .sec { padding-top: calc(var(--section-py) + var(--space-7)); }
@media (max-width: 991px) {
  .hero__tiles { grid-template-columns: minmax(0, 1fr); margin-bottom: calc(-1 * var(--space-8)); }
  .hero__tile--claim { grid-template-columns: minmax(0, 1fr); }
  .hero__tile-screen { position: static; width: 100%; margin: 0 var(--space-7) var(--space-7); width: calc(100% - 2 * var(--space-7)); }
  .dnd-section:has(.hero--overlap):not(:has(.dnd-row ~ .dnd-row .sec:not(.hero))) + .dnd-section:not(:has([class*="decor--"])):not(:has(.rings-band)) .dnd-row:first-child .sec, .band:has(.hero--overlap:last-child) + .band > .sec:first-child, .dnd-section:has(> .row-fluid .sec) .dnd-row:has(.hero--overlap) + .dnd-row .sec, .dnd-section.ema-sec .dnd-row:has(.hero--overlap) + .dnd-row .sec, .hero--overlap:not(:last-child) + .sec { padding-top: calc(var(--section-py) + var(--space-8)); }
}

/* 02/09 (Gaspard : alléger le mobile) — sous 768 px, la deuxième tuile du hero (illustration) s'efface :
   la photo suffit, et l'accueil perd 330 px avant le premier titre de section. */
@media (max-width: 767px) { .hero__tile--illu { display: none; } }

/* ---- MOTION « du chaos à la décision » (.mo, partial svg/motion-chaos-decision.html) — concept A du lot
   conception 02/09, posé dans la 2e tuile du hero de l'accueil (« Tuile motion : chaos-decision »).
   Boucle de 10 s : 0-30 % les fragments s'agitent · 30-52 % ils convergent dans la plaque · 52-62 % la plaque
   pulse et s'efface · 60-85 % le tableau de bord se construit · 85-100 % la coche. Tokens seulement. ---- */
.hero__tile--motion { background: var(--color-paper-0); display: grid; place-items: center; padding: var(--space-4); }
.mo { width: 100%; height: 100%; display: block; }
.mo__chip { transform: translate(var(--x), var(--y)) rotate(var(--r)); transform-origin: 35px 22px;
  animation: mo-chip 10s cubic-bezier(.4,0,.2,1) infinite both; animation-delay: var(--d); }
.mo__chip rect:first-child { fill: var(--color-paper-100); }
.mo__chip .mo__bar { fill: var(--color-green-300); }
.mo__chip--sky rect:first-child { fill: var(--color-label-sky-soft); }
.mo__chip--sky .mo__bar { fill: var(--color-label-sky); }
.mo__chip--teal rect:first-child { fill: var(--color-mint-100); }
.mo__chip--teal .mo__bar { fill: var(--ema-secondary-teal); }
@keyframes mo-chip {
  0%   { transform: translate(var(--x), var(--y)) rotate(var(--r)); opacity: 1; }
  8%   { transform: translate(calc(var(--x) + 6px), calc(var(--y) - 5px)) rotate(calc(var(--r) * -1)); }
  16%  { transform: translate(calc(var(--x) - 5px), calc(var(--y) + 6px)) rotate(var(--r)); }
  24%  { transform: translate(calc(var(--x) + 4px), calc(var(--y) + 3px)) rotate(calc(var(--r) * -1)); }
  30%  { transform: translate(var(--x), var(--y)) rotate(var(--r)); opacity: 1; }
  50%  { transform: translate(245px, 193px) rotate(0deg) scale(.35); opacity: .9; }
  53%, 100% { transform: translate(245px, 193px) rotate(0deg) scale(.2); opacity: 0; }
}
.mo__core rect { fill: var(--color-green-900); }
.mo__core-ring { fill: none; stroke: var(--ema-primary); stroke-width: 6; opacity: .35; }
.mo__core-mark { fill: none; stroke: var(--ema-primary); stroke-width: 7; stroke-linecap: round; }
.mo__core-dot { fill: var(--color-paper-0); }
.mo__core { transform-origin: 280px 215px; animation: mo-core 10s cubic-bezier(.4,0,.2,1) infinite both; }
@keyframes mo-core {
  0%, 26% { transform: scale(.92); opacity: .75; }
  34%     { transform: scale(1); opacity: 1; }
  50%     { transform: scale(1.06); opacity: 1; }
  56%     { transform: scale(1); opacity: 1; }
  64%, 100% { transform: scale(.9) translate(0, -60px); opacity: 0; }
}
.mo__dash { transform-origin: 300px 285px; animation: mo-dash 10s cubic-bezier(.2,.7,.2,1) infinite both; }
.mo__dash-card { fill: var(--color-paper-0); stroke: var(--line-glass); stroke-width: 1.5; }
.mo__dash-line { fill: var(--color-green-900); }
.mo__dash-line--2 { fill: var(--color-green-300); }
.mo__dash-bar { fill: var(--color-label-sky); transform-origin: 50% 360px; transform: scaleY(var(--h)); animation: mo-bar 10s cubic-bezier(.2,.7,.2,1) infinite both; }
.mo__dash-bar--hi { fill: var(--ema-primary); }
.mo__dash-curve { fill: none; stroke: var(--color-green-900); stroke-width: 4; stroke-linecap: round; stroke-dasharray: 1; stroke-dashoffset: 1;
  animation: mo-curve 10s cubic-bezier(.2,.7,.2,1) infinite both; }
@keyframes mo-dash { 0%, 58% { transform: translate(0, 40px) scale(.94); opacity: 0; } 68%, 100% { transform: none; opacity: 1; } }
@keyframes mo-bar { 0%, 64% { transform: scaleY(0); } 82%, 100% { transform: scaleY(var(--h)); } }
@keyframes mo-curve { 0%, 72% { stroke-dashoffset: 1; } 90%, 100% { stroke-dashoffset: 0; } }
.mo__check circle { fill: var(--ema-primary); }
.mo__check path { fill: none; stroke: var(--on-primary); stroke-width: 5; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 1; stroke-dashoffset: 1; }
.mo__check { transform-origin: 430px 196px; animation: mo-check 10s cubic-bezier(.2,.7,.2,1) infinite both; }
.mo__check path { animation: mo-tick 10s ease-out infinite both; }
@keyframes mo-check { 0%, 84% { transform: scale(0); opacity: 0; } 90%, 100% { transform: scale(1); opacity: 1; } }
@keyframes mo-tick { 0%, 88% { stroke-dashoffset: 1; } 96%, 100% { stroke-dashoffset: 0; } }
@media (prefers-reduced-motion: reduce) {
  .mo__chip, .mo__core, .mo__dash, .mo__dash-bar, .mo__dash-curve, .mo__check, .mo__check path { animation: none; }
  .mo__chip, .mo__core { display: none; }
  .mo__dash { transform: none; opacity: 1; } .mo__dash-bar { transform: scaleY(var(--h)); } .mo__dash-curve { stroke-dashoffset: 0; }
  .mo__check { transform: none; opacity: 1; } .mo__check path { stroke-dashoffset: 0; }
}
@media (max-width: 767px) { .hero__tile--motion { display: none; } }

/* ---- HERO SCÈNE (03/09, Gaspard : premiercs.com) — sous le titre, une scène sombre arrondie où l'écran
   produit monte plein cadre pendant le défilement ; un voile vert profond monte du bas sur la seconde
   moitié pour appeler la suite. Le conteneur fait 170 vh, la scène y reste collée (sticky). Moteur CSS
   (view-timeline) quand le navigateur le sait, sinon ema.js pose --p (0 → 1). Mobile : scène statique. ---- */
.hero__scene { position: relative; z-index: 3; height: 170vh; margin: var(--space-8) 0 calc(-1 * var(--space-10)); view-timeline-name: --hscene; view-timeline-axis: block; }
/* 03/09 (Gaspard : « pour le fond, fais en sorte qu'il soit fondu exactement — pas surchargé —
   avec le fond de l'accueil, avec l'arc visible ; peut-être un léger glassmorphism sans bordure
   visible ou un blur léger ») — la scène n'est plus une boîte opaque posée SUR la bande : un verre
   sombre translucide (encre à ~72 %) + blur léger. L'arc de la bande reste lisible au travers,
   aucune bordure, l'ombre passe en douce. */
.hero__scene-stage { position: sticky; top: calc(var(--sticky-top, 0px) + var(--space-5)); height: 78vh; min-height: 30rem; overflow: hidden;
  border-radius: var(--radius-xl); background: var(--surface-glass-dark);
  -webkit-backdrop-filter: blur(var(--blur-glass)); backdrop-filter: blur(var(--blur-glass));
  box-shadow: var(--shadow-card); isolation: isolate; }
.hero__scene-arc { position: absolute; right: -6%; top: -18%; width: 34%; color: var(--ema-primary); opacity: .55; pointer-events: none; }
.hero__scene-arc svg { width: 100%; height: auto; display: block; }
.hero__scene-screen { position: absolute; left: 50%; bottom: 0; width: min(86%, 1100px); height: auto; translate: -50% 0; border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  box-shadow: var(--shadow-raised); transform: translateY(14%) scale(.94); transform-origin: 50% 100%; }
/* 03/09 — variant MOTION : le bandeau vectoriel (3,38:1) n'est pas l'écran 4:3 qui « monte » ;
   il se CENTRE dans la scène, plein cadre en largeur, sans carte ni ombre (ses éléments portent
   les leurs), et l'ancrage de l'animation de défilement passe au centre. */
.hero__scene-screen--motion { bottom: auto; top: 50%; translate: -50% -50%; width: min(92%, 1240px);
  border-radius: 0; box-shadow: none; overflow: visible; background: none;
  transform: translateY(6%) scale(.96); transform-origin: 50% 50%; }
.hero__scene-photo { position: absolute; left: var(--space-6); top: var(--space-6); width: min(26%, 18rem); aspect-ratio: 4 / 3; margin: 0; overflow: hidden;
  border-radius: var(--radius-lg); box-shadow: var(--shadow-raised); transform: translateY(0); }
.hero__scene-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.hero__scene-veil { position: absolute; inset: 0; background: linear-gradient(to top, var(--color-green-900) 0%, transparent 55%); opacity: 0; pointer-events: none; }
@supports (animation-timeline: view()) {
  .hero__scene-screen, .hero__scene-veil, .hero__scene-photo { animation-timeline: --hscene; animation-range: contain 0% contain 100%; animation-fill-mode: both; animation-timing-function: linear; animation-duration: 1s; }
  .hero__scene-screen { animation-name: hscene-screen; }
  .hero__scene-veil { animation-name: hscene-veil; }
  .hero__scene-photo { animation-name: hscene-photo; }
}
@keyframes hscene-screen { 0% { transform: translateY(14%) scale(.94); } 45% { transform: translateY(0) scale(1); } 100% { transform: translateY(-4%) scale(1.02); } }
@keyframes hscene-veil { 0%, 50% { opacity: 0; } 100% { opacity: 1; } }
@keyframes hscene-photo { 0% { transform: translateY(0); } 100% { transform: translateY(-40px); } }
.no-sda .hero__scene-screen { transform: translateY(calc(14% - var(--p, 0) * 18%)) scale(calc(.94 + var(--p, 0) * .08)); }
.no-sda .hero__scene-veil { opacity: calc(max(0, var(--p, 0) - .5) * 2); }
.no-sda .hero__scene-photo { transform: translateY(calc(-40px * var(--p, 0))); }
.band:has(.hero__scene) { overflow: visible; }
@media (prefers-reduced-motion: reduce), (max-width: 767px) {
  .hero__scene { height: auto; margin-bottom: calc(-1 * var(--space-8)); }
  .hero__scene-stage { position: relative; top: auto; height: auto; aspect-ratio: auto; min-height: 0; max-width: 100%; padding-top: var(--space-6); }
  .hero__scene-screen { position: static; display: block; margin: 0 auto; translate: none; }
  .hero__inner:has(.hero__scene) { grid-template-columns: minmax(0, 1fr); }
  .hero__scene { max-width: 100%; }
  .hero__scene-screen, .hero__scene-veil, .hero__scene-photo, .no-sda .hero__scene-screen, .no-sda .hero__scene-veil, .no-sda .hero__scene-photo { animation: none; transform: none; opacity: 1; }
  .hero__scene-veil, .no-sda .hero__scene-veil { opacity: 0; }
  .hero__scene-photo { display: none; }
}


/* ==================== SCÈNE MOTION (.mopf) — 03/09, 3e passe ====================
   (Gaspard : « ça s'anime trop vite, avant qu'on ait eu le temps de lire et scroller — les
   parties basses s'animent sans qu'on le voie ; c'est en second temps que cela doit s'animer.
   Améliore le rythme, l'ordre — la roue dentée s'affiche trop tôt. »)
   L'ENTRÉE n'est plus au chargement : chaque calque s'anime QUAND IL DEVIENT VISIBLE
   (IntersectionObserver dans ema.js pose .is-in par calque). Les deux temps tombent d'eux-mêmes :
   le haut du bandeau entre avec le hero, le bas (donut, panneau IA, barres) attend qu'on
   descende. À l'intérieur d'un même temps, la cascade est portée par --mi ; la roue dentée
   (pastille connecteurs) ferme la marche de son groupe. Le PARALLAXE de profondeur au
   défilement (transform) et le FLOTTEMENT (translate) restent. Sans JS : tout visible.
   Sous mouvement réduit : statique. */
.mopf-svg { display: block; width: 100%; height: auto; overflow: visible; }
.mopf-l { transform-box: fill-box; transform-origin: center; }
/* 08/09 — CORRECTIF SAFARI (bug vu en prod, reproduit sous WebKit 18) : l'IntersectionObserver
   y mesure les éléments INTERNES d'un SVG sans appliquer la transformation viewBox. Le viewBox
   du bandeau étant recadré sur x≈1509, les rects fantômes des calques tombent hors écran :
   .is-in n'arrivait jamais et TOUT restait à opacity 0 (bandeau invisible). La chorégraphie
   d'entrée (états cachés + animations .is-in) n'existe donc que là où le moteur est moderne —
   @supports (animation-timeline: view()) : Chrome 115+, Safari 26+. Ailleurs (Safari ≤ 25,
   Firefox sans scroll-driven animations) : bandeau complet, statique, affiché d'emblée — ces
   moteurs n'appliquent de toute façon pas translate/scale/rotate aux éléments SVG. */
@supports (animation-timeline: view()) {
  .mopf-l { opacity: 0; }
  html:not(.js) .mopf-l { opacity: 1; }
  .mopf-l.is-in { animation: mopf-in .8s cubic-bezier(.2, .7, .2, 1) both, mopf-float var(--fl, 9s) ease-in-out infinite;
    animation-delay: calc(var(--mi, 0) * .16s), calc(1.4s + var(--mi, 0) * .4s); }
  .mopf-l--fond.is-in { animation: mopf-in .8s ease both; }
}
.mopf-l--fond { --mi: 0; }
.mopf-l--report { --mi: 1; --fl: 11s; --amp: -4px; }
.mopf-l--chip1 { --mi: 2; --fl: 8.4s; --amp: -7px; }
.mopf-l--chip2 { --mi: 3; --fl: 9.8s; --amp: -7px; }
.mopf-l--perf { --mi: 1; --fl: 9.4s; --amp: -5px; }
.mopf-l--analytics { --mi: 2; --fl: 10.2s; --amp: -5px; }
.mopf-l--ia { --mi: 3; --fl: 7.6s; --amp: -9px; }
/* la roue dentée ferme la marche de son groupe */
.mopf-l--connecteurs { --mi: 5; --fl: 7s; --amp: -10px; }
@keyframes mopf-in { from { opacity: 0; translate: 0 var(--space-5); } to { opacity: 1; translate: 0 0; } }
@keyframes mopf-float { 0%, 100% { translate: 0 0; } 50% { translate: 0 var(--amp, -6px); } }

/* Les éléments INTERNES attendent l'arrivée de LEUR calque, puis se déploient.
   (08/09 — même gabarit que les calques : états cachés et animations .is-in réservés aux
   moteurs à animation-timeline, voir le correctif Safari ci-dessus.) */
.mopf-e, .mopf-bar, .mopf-donut { transform-box: fill-box; }
.mopf-e { transform-origin: center; }
.mopf-bar { transform-origin: 50% 100%; }
.mopf-donut { transform-origin: center; }
@supports (animation-timeline: view()) {
  .mopf-e { opacity: 0; }
  .mopf-l.is-in .mopf-e { animation: mopf-pop .5s ease both; animation-delay: calc(.7s + var(--k, 0) * .14s); }
  .mopf-bar { transform: scaleY(0); }
  .mopf-l.is-in .mopf-bar { animation: mopf-grow .9s cubic-bezier(.2, .7, .2, 1) both; animation-delay: calc(.6s + var(--b, 0) * .12s); }
  .mopf-donut { opacity: 0; }
  .mopf-l.is-in .mopf-donut { animation: mopf-turn 1.2s cubic-bezier(.2, .7, .2, 1) both; animation-delay: .6s; }
  html:not(.js) .mopf-e, html:not(.js) .mopf-donut { opacity: 1; }
  html:not(.js) .mopf-bar { transform: none; }
}
.mopf-e--0 { --k: 0; } .mopf-e--1 { --k: 1; } .mopf-e--2 { --k: 2; } .mopf-e--3 { --k: 3; }
@keyframes mopf-pop { from { opacity: 0; scale: .85; } to { opacity: 1; scale: 1; } }
.mopf-bar--0 { --b: 0; } .mopf-bar--1 { --b: 1; } .mopf-bar--2 { --b: 2; }
.mopf-bar--3 { --b: 3; } .mopf-bar--4 { --b: 4; } .mopf-bar--5 { --b: 5; }
@keyframes mopf-grow { from { transform: scaleY(0); } to { transform: scaleY(1); } }
@keyframes mopf-turn { from { opacity: 0; rotate: -28deg; scale: .9; } to { opacity: 1; rotate: 0deg; scale: 1; } }

/* Le PARALLAXE de profondeur au défilement (là où le navigateur le sait). */
@supports (animation-timeline: view()) {
  .mopf-svg { view-timeline-name: --mopf; view-timeline-axis: block; }
  .mopf-l.is-in { animation-name: mopf-in, mopf-float, mopf-para;
    animation-duration: .8s, var(--fl, 9s), 1s;
    animation-timeline: auto, auto, --mopf;
    animation-range: normal, normal, cover 0% cover 100%;
    animation-delay: calc(var(--mi, 0) * .16s), calc(1.4s + var(--mi, 0) * .4s), 0s;
    animation-timing-function: cubic-bezier(.2, .7, .2, 1), ease-in-out, linear;
    animation-fill-mode: both, none, both;
    animation-iteration-count: 1, infinite, 1; }
  .mopf-l--report { --px: 10px; }
  .mopf-l--perf { --px: 18px; }
  .mopf-l--analytics { --px: 22px; }
  .mopf-l--ia { --px: 34px; }
  .mopf-l--connecteurs { --px: 46px; }
  .mopf-l--chip1 { --px: 40px; }
  .mopf-l--chip2 { --px: 44px; }
  .mopf-l--fond { --px: 0px; }
}
@keyframes mopf-para {
  from { transform: translateY(var(--px, 0px)); }
  to { transform: translateY(calc(-1 * var(--px, 0px))); } }

@media (prefers-reduced-motion: reduce) {
  .mopf-l, .mopf-e, .mopf-bar, .mopf-donut { animation: none; opacity: 1; translate: none; transform: none; rotate: none; scale: none; }
  .mopf-l.is-in, .mopf-l.is-in .mopf-e, .mopf-l.is-in .mopf-bar, .mopf-l.is-in .mopf-donut { animation: none; }
}

/* 03/09 (Gaspard) — SCÈNE PURE (variant motion) : pas de photo, pas d'arc, pas de délimitation.
   Le bandeau vectoriel anime ses propres éléments, rien d'autre autour. */
.hero__scene--pure .hero__scene-stage { background: none; -webkit-backdrop-filter: none; backdrop-filter: none;
  box-shadow: none; border-radius: 0; overflow: visible;
  /* 03/09 (Gaspard : « elle est mise trop basse ») — la scène pure n'est plus la boîte épinglée
     de 78 vh : hauteur au contenu, bandeau posé en haut du flux, pas d'animation au défilement. */
  position: static; height: auto; min-height: 0; display: block; padding-block: var(--space-4) 0; }
.hero__scene--pure { height: auto; min-height: 0; }
/* 03/09 (Gaspard, capture : le bandeau passait sous le pli) — le hero à scène pure se COMPRESSE
   pour composer UNE vue : texte resserré, bandeau juste sous les boutons, largement visible au
   chargement. */
.hero:has(.hero__scene--pure) { padding-top: var(--space-8); }
.hero:has(.hero__scene--pure) .hero__scene { margin-top: var(--space-2); }
.hero__scene--pure .hero__scene-screen--motion { position: static; translate: none; transform: none;
  /* 03/09 (Gaspard : « l'image est un peu trop grande ») : 96 % → 78 %, plafonnée à 980 px. */
  width: min(78%, 980px); margin-inline: auto; animation: none; }
