/* =============================================================================
   Clippit — couche de mouvement
   =============================================================================
   Cette feuille ne change aucune couleur, aucune police, aucune taille. Elle ne
   fait qu'ajouter du mouvement par-dessus le système de design de `clippit.css`,
   qui reste la seule source de la charte. On peut la retirer entièrement : la
   page redevient la première proposition, intacte.

   Le vocabulaire est repris du site donné en référence, qui utilise Lenis pour
   le défilement inertiel et GSAP ScrollTrigger pour une frise horizontale
   épinglée. Ici, tout ce qui peut l'être est écrit en CSS natif, par
   `animation-timeline`. Il n'y a donc ni GSAP ni ScrollTrigger : environ 90 Ko
   de bibliothèques en moins, et surtout aucun travail JavaScript pendant le
   défilement, ce qui est exactement ce que mesure l'INP.

   Trois règles tenues partout :

   1. Aucune animation ne conditionne l'accès à un contenu. Retirez le CSS, ou
      activez « réduire les animations », et toute la page reste lisible et
      parcourable. Les états masqués sont enfermés dans des `@supports`.
   2. Rien ne bouge tout seul en boucle. Les formes flottantes sont pilotées par
      la position de défilement, pas par une minuterie : elles ne bougent que si
      l'utilisateur bouge. Le critère WCAG 2.2.2, qui impose de pouvoir arrêter
      un mouvement automatique de plus de cinq secondes, ne s'applique donc pas.
   3. Le bloc « mouvement réduit » est en fin de fichier et neutralise tout.
   ============================================================================= */

/* Posée par le script quand le défilement inertiel prend la main. Le lissage du
   navigateur et le nôtre se combattraient : chaque `scrollTo` relancerait une
   animation native écrasée par la frame suivante, et la page n'avancerait plus
   que de quelques pixels par seconde. */
.inertie { scroll-behavior: auto; }

/* -----------------------------------------------------------------------------
   Révélation d'un titre mot à mot
   -----------------------------------------------------------------------------
   Les mots sont découpés par le script, qui pose des `<span class="mot">`. Sans
   JavaScript, `.mots` reste un titre ordinaire : le sélecteur ne mord que sur
   des `.mot` qui n'existent pas encore.

   Chaque mot monte derrière une ligne de masquage. `overflow: clip` sur le
   conteneur du mot fait le rideau, sans le `overflow: hidden` qui créerait un
   conteneur de défilement et casserait les chronologies. */
@supports (animation-timeline: view()) {
    .mots .mot {
        display: inline-block;
        /* Le rideau ne doit couper qu'en bas. Le dessin des lettres sort de leur
           boîte de trois côtés : les accents des capitales (À, Ô, É) montent
           au-dessus de la hauteur de ligne du titre, resserrée à 1.02, et le
           dessin dépasse la largeur d'avance sur les côtés, en italique surtout.
           `clip-path` masque une seule arête, et sans toucher à la mise en page :
           un `overflow: clip` sur une boîte élargie par du remplissage ferait
           déborder la page de quelques pixels sur les petits écrans.
           La valeur du bas est négative elle aussi, pour les jambages. */
        clip-path: inset(-0.6em -0.4em -0.12em);
        vertical-align: bottom;
    }
    .mots .mot > span {
        display: inline-block;
        animation: mot-monte linear both;
        animation-timeline: view();
        animation-range: entry 10% cover 22%;
    }
    /* Décalage entre les mots. Il est plafonné : au-delà du sixième, l'attente
       devient plus longue que la lecture. Le décalage se fait en décalant la
       plage, pas par un délai : un délai n'a aucun sens sur une chronologie de
       défilement, où la progression ne dépend pas du temps. */
    .mots .mot:nth-child(2) > span { animation-range: entry 13% cover 25%; }
    .mots .mot:nth-child(3) > span { animation-range: entry 16% cover 28%; }
    .mots .mot:nth-child(4) > span { animation-range: entry 19% cover 31%; }
    .mots .mot:nth-child(5) > span { animation-range: entry 22% cover 34%; }
    .mots .mot:nth-child(n+6) > span { animation-range: entry 25% cover 37%; }
}
@keyframes mot-monte {
    from { transform: translateY(105%) rotate(2deg); opacity: 0; }
    to { transform: none; opacity: 1; }
}

/* -----------------------------------------------------------------------------
   Parallaxe du hero
   -----------------------------------------------------------------------------
   Le texte et le visuel se décalent à des vitesses différentes pendant que le
   hero sort de l'écran. `scroll()` et non `view()` : la référence est la
   position de défilement du document, le hero étant en haut de page. */
@supports (animation-timeline: scroll()) {
    .hero__grille > div:first-child {
        animation: hero-texte linear both;
        animation-timeline: scroll(root block);
        animation-range: 0 90vh;
    }
    .hero__visuel {
        animation: hero-visuel linear both;
        animation-timeline: scroll(root block);
        animation-range: 0 90vh;
    }
}
@keyframes hero-texte {
    from { transform: none; opacity: 1; }
    to { transform: translateY(-38px); opacity: 0.15; }
}
@keyframes hero-visuel {
    from { transform: none; }
    to { transform: translateY(84px) scale(1.06); }
}

/* -----------------------------------------------------------------------------
   Formes flottantes
   -----------------------------------------------------------------------------
   L'équivalent des `.movable-div` de la référence, qui y dérivent en continu
   sur une minuterie. Ici elles sont accrochées au défilement : elles ne bougent
   que quand la page bouge. C'est plus sobre, et cela évite un mouvement
   perpétuel qu'il faudrait pouvoir mettre en pause.

   Purement décoratives, elles sont posées en `::before`/`::after` et donc
   absentes de l'arbre d'accessibilité. */
.formes {
    position: relative;
    isolation: isolate;
    /* Les formes débordent volontairement de la section pour que leur halo
       n'ait pas de bord franc. Il faut donc les découper ici : `overflow-x:
       clip` posé sur `body` ne suffit pas, Chromium ne propageant pas `clip` au
       viewport comme il propage `hidden`. Sans cette ligne, la page gagne deux
       cents pixels de défilement horizontal. */
    overflow: clip;
}
.formes::before,
.formes::after {
    content: '';
    position: absolute;
    z-index: -1;
    border-radius: 50%;
    pointer-events: none;
    filter: blur(50px);
}
.formes::before {
    inset: -8% auto auto -6%;
    width: 34vw;
    max-width: 460px;
    aspect-ratio: 1;
    background: radial-gradient(circle, color-mix(in srgb, var(--vert) 26%, transparent), transparent 68%);
}
.formes::after {
    inset: auto -10% -14% auto;
    width: 40vw;
    max-width: 540px;
    aspect-ratio: 1;
    background: radial-gradient(circle, color-mix(in srgb, var(--bleu) 78%, #fff 22%), transparent 66%);
    opacity: 0.5;
}
@supports (animation-timeline: view()) {
    .formes::before {
        animation: derive-a linear both;
        animation-timeline: view();
    }
    .formes::after {
        animation: derive-b linear both;
        animation-timeline: view();
    }
}
@keyframes derive-a {
    from { transform: translate3d(-40px, 60px, 0) scale(0.85); }
    to { transform: translate3d(70px, -70px, 0) scale(1.1); }
}
@keyframes derive-b {
    from { transform: translate3d(60px, 80px, 0) scale(1.12); }
    to { transform: translate3d(-50px, -60px, 0) scale(0.9); }
}

/* -----------------------------------------------------------------------------
   Frise horizontale épinglée
   -----------------------------------------------------------------------------
   L'effet central du site de référence, qui l'obtient avec GSAP : `pin` sur le
   conteneur et `xPercent` sur les diapositives, en `scrub`. Ici, `position:
   sticky` fait l'épinglage et `animation-timeline: view()` fait le défilement
   horizontal, sans une ligne de JavaScript.

   Le mécanisme : la section est plus haute que l'écran, son contenu y est collé,
   et la piste se translate à mesure que la section traverse la fenêtre. La
   hauteur de la section détermine la longueur du parcours.

   Repli par défaut, hors `@supports` : une liste verticale ordinaire. C'est
   aussi ce que voient les écrans étroits et les utilisateurs en mouvement
   réduit. */
.frise { padding-block: var(--e-9); }
.frise__entete { margin-bottom: var(--e-7); }
.frise__indice { display: none; }
.frise__jauge { display: none; }

.frise__piste {
    display: grid;
    gap: var(--e-4);
    width: min(100% - 2 * var(--e-5), var(--largeur));
    margin-inline: auto;
    /* Le numéro de chaque étape vient de `.etape::before` dans le système de
       base ; la piste doit donc réinitialiser son compteur, ce que faisait
       `.etapes` avant d'être remplacée ici. */
    counter-reset: etape;
}

@media (min-width: 901px) {
    @supports (animation-timeline: view()) {
        .frise {
            /* Longueur du parcours. Quatre étapes tiennent en trois écrans de
               défilement supplémentaires, ce qui donne une progression lisible
               sans donner l'impression que la page est bloquée. */
            height: 340vh;
            padding-block: 0;
            /* La chronologie est déclarée ici, sur la section, et non sur la
               piste. La piste est à l'intérieur du conteneur collé : elle ne
               bouge pas par rapport à la fenêtre, sa propre chronologie `view()`
               resterait donc figée. C'est la section, haute de 340vh, qui
               traverse réellement l'écran. */
            view-timeline: --frise block;
        }
        .frise__colle {
            position: sticky;
            top: 0;
            display: flex;
            flex-direction: column;
            justify-content: center;
            height: 100vh;
            overflow: clip;
        }
        .frise__entete { margin-bottom: var(--e-6); }
        .frise__indice {
            display: inline-flex;
            align-items: center;
            gap: var(--e-2);
            font-size: var(--t-xs);
            font-weight: 700;
            letter-spacing: 0.08em;
            text-transform: uppercase;
            color: var(--vert);
        }
        .frise__indice svg { width: 18px; height: 18px; }
        /* L'indice n'a plus de raison d'être une fois la séquence entamée. */
        .frise__indice {
            animation: indice-sort linear both;
            animation-timeline: --frise;
            animation-range: contain 0% contain 12%;
        }

        .frise__jauge {
            display: block;
            width: min(240px, 40%);
            height: 3px;
            margin-top: var(--e-5);
            background: rgba(255, 255, 255, 0.18);
            border-radius: var(--r-pilule);
            overflow: clip;
        }
        .frise__jauge > span {
            display: block;
            height: 100%;
            background: var(--vert);
            border-radius: inherit;
            transform-origin: left;
            animation: jauge linear both;
            animation-timeline: --frise;
            animation-range: contain 0% contain 100%;
        }

        /* Les panneaux gagnent la présence d'une carte : sans cela ils flottent
           dans un écran vide, et la séquence n'a pas de matière à faire défiler. */
        .frise .etape {
            display: flex;
            flex-direction: column;
            min-height: 40vh;
            padding: var(--e-6);
            border-top: 0;
            border: 1px solid rgba(255, 255, 255, 0.14);
            border-radius: var(--r-lg);
            background: rgba(255, 255, 255, 0.045);
            backdrop-filter: blur(6px);
        }
        .frise .etape::before {
            font-size: var(--t-2xl);
            margin-bottom: var(--e-4);
        }
        .frise .etape h3 { font-size: var(--t-lg); margin-bottom: var(--e-3); }
        .frise .etape p { font-size: var(--t-base); }

        /* Les mots du titre sont dans le conteneur collé : leur propre
           chronologie `view()` se figerait à mi-course, exactement comme celle
           de la piste. Ils prennent donc eux aussi la chronologie de la
           section, sur la portion qui précède l'épinglage. */
        .frise__colle .mots .mot > span {
            animation-timeline: --frise;
            animation-range: entry 45% entry 95%;
        }
        .frise__colle .mots .mot:nth-child(2) > span { animation-range: entry 52% entry 100%; }
        .frise__colle .mots .mot:nth-child(3) > span { animation-range: entry 59% contain 3%; }
        .frise__colle .mots .mot:nth-child(n+4) > span { animation-range: entry 66% contain 6%; }

        .frise__piste {
            display: flex;
            flex-wrap: nowrap;
            gap: var(--e-5);
            width: max-content;
            /* Le premier panneau démarre aligné sur la grille de la page, pas
               collé au bord de l'écran. */
            padding-inline: max(var(--e-5), (100vw - var(--largeur)) / 2);
            animation: frise-avance linear both;
            animation-timeline: --frise;
            /* `contain` couvre exactement la durée pendant laquelle la section
               recouvre la fenêtre, c'est-à-dire la durée de l'épinglage. */
            animation-range: contain 0% contain 100%;
        }
        .frise .etape {
            /* Assez large pour que le parcours horizontal soit substantiel :
               deux panneaux et demi visibles à la fois, et une piste qui fait
               près de deux fenêtres de large. */
            flex: 0 0 clamp(300px, 42vw, 560px);
        }
    }
}

@keyframes indice-sort {
    from { opacity: 1; transform: none; }
    to { opacity: 0; transform: translateX(10px); }
}
@keyframes jauge {
    from { transform: scaleX(0.06); }
    to { transform: scaleX(1); }
}
@keyframes frise-avance {
    from { transform: translateX(0); }
    /* La piste fait quatre panneaux ; on la décale de sa propre largeur moins
       une fenêtre, pour que le dernier panneau s'arrête au bord droit au lieu
       de sortir de l'écran. */
    to { transform: translateX(calc(-1 * (100% - 100vw))); }
}

/* -----------------------------------------------------------------------------
   Compteurs chiffrés
   -----------------------------------------------------------------------------
   Les chiffres montent quand la section entre dans l'écran. Entièrement en CSS,
   par une propriété enregistrée que l'on peut interpoler, puis rendue en texte
   par `counter()`. Aucun JavaScript, et aucun risque de laisser un compteur figé
   sur zéro si un script échoue : le chiffre réel est dans le balisage, la
   propriété ne fait que l'animer.

   Le contenu généré par CSS est exposé aux technologies d'assistance : dans
   l'arbre d'accessibilité, le compteur et le nombre du balisage se lisaient donc
   l'un derrière l'autre, « 3 » puis « 0 ». La partie animée est maintenant un
   élément à part, marqué `aria-hidden`, et le nombre réel vit dans un élément
   qui n'est visible que si l'animation n'a pas lieu. */
@property --compte {
    syntax: '<integer>';
    initial-value: 0;
    inherits: false;
}

@supports (animation-timeline: view()) {
    /* `--compte` est déclaré non héritable : l'animation doit donc porter sur
       l'élément même dont le `::after` lit le compteur. `--cible`, lui, est un
       custom property ordinaire, il descend depuis le parent. */
    .chiffre__anime {
        counter-reset: valeur var(--compte);
        animation: compte linear both;
        animation-timeline: view();
        animation-range: entry 20% cover 40%;
    }
    .chiffre__anime::after { content: counter(valeur); }
    /* Le nombre du balisage laisse la place au compteur animé, tout en restant
       la valeur lue par les technologies d'assistance. */
    .chiffre__brut {
        position: absolute;
        width: 1px; height: 1px;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }
    .chiffre__valeur[data-compte='3'] { --cible: 3; }
    .chiffre__valeur[data-compte='7'] { --cible: 7; }
    /* Les quatre indicateurs des sections « opportunité » et « usages » : ils
       étaient du texte statique à côté de chiffres qui comptaient. */
    .mesures__valeur[data-compte='46'] { --cible: 46; }
    .mesures__valeur[data-compte='52'] { --cible: 52; }
    .mesures__valeur[data-compte='78'] { --cible: 78; }
    .mesures__valeur[data-compte='88'] { --cible: 88; }
}
@keyframes compte {
    from { --compte: 0; }
    to { --compte: var(--cible); }
}

/* -----------------------------------------------------------------------------
   Micro-interactions
   -----------------------------------------------------------------------------
   Celles qui déplacent quelque chose sont réservées aux pointeurs qui savent
   survoler : sur un écran tactile, l'état de survol reste collé après l'appui,
   et un bouton qui reste soulevé se lit comme un défaut d'affichage. */
.btn { transition: transform var(--duree) var(--courbe), background-color var(--duree), color var(--duree), border-color var(--duree); }
.btn svg { transition: transform var(--duree) var(--courbe); }
.bloc__icone { transition: transform var(--duree) var(--courbe), background-color var(--duree); }

@media (hover: hover) {
    /* La flèche des boutons avance au survol, et le bouton lui-même se soulève. */
    .btn:hover { transform: translateY(-2px); }
    .btn:hover svg { transform: translateX(4px); }
    /* L'icône d'un bloc pivote légèrement au survol de la carte. */
    .bloc:hover .bloc__icone { transform: rotate(-6deg) scale(1.08); }
}

/* Soulignement qui se déploie depuis la gauche sous les liens de navigation. */
.nav__lien { position: relative; }
.nav__lien::after {
    content: '';
    position: absolute;
    left: var(--e-3);
    right: var(--e-3);
    bottom: 6px;
    height: 2px;
    background: var(--vert);
    border-radius: 2px;
    transform: scaleX(0);
    transform-origin: left;
    transition: transform var(--duree) var(--courbe);
}
.nav__lien:hover::after,
.nav__lien:focus-visible::after { transform: scaleX(1); }

/* Les tuiles de logos se soulèvent une à une. */
.partenaires img { transition: transform var(--duree) var(--courbe), box-shadow var(--duree); }
@media (hover: hover) {
    .partenaires img:hover { transform: translateY(-4px); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.28); }
}

/* -----------------------------------------------------------------------------
   Mouvement réduit
   -----------------------------------------------------------------------------
   Tout est neutralisé, y compris la frise, qui redevient une liste verticale.
   `animation: none` est indispensable en plus des propriétés remises à plat :
   une animation liée au défilement continue sinon de piloter la propriété et
   écrase la valeur posée ici. */
@media (prefers-reduced-motion: reduce) {
    .mots .mot,
    .mots .mot > span,
    .hero__grille > div:first-child,
    .hero__visuel,
    .formes::before,
    .formes::after,
    .frise__piste,
    .frise__indice,
    .frise__jauge > span,
    .chiffre__anime {
        animation: none !important;
        transform: none !important;
        opacity: 1 !important;
    }
    .chiffre__anime { display: none; }
    .chiffre__brut { position: static; width: auto; height: auto; clip-path: none; }
    .frise { height: auto !important; padding-block: var(--e-9) !important; }
    .frise__colle { position: static !important; height: auto !important; display: block !important; }
    .frise__piste {
        display: grid !important;
        width: min(100% - 2 * var(--e-5), var(--largeur)) !important;
        padding-inline: 0 !important;
    }
    .frise .etape { flex: none !important; }
    .frise__indice, .frise__jauge { display: none !important; }
    .btn:hover, .bloc:hover .bloc__icone, .partenaires img:hover { transform: none; }
    .nav__lien::after { transition: none; }
}

/* -----------------------------------------------------------------------------
   Impression
   -------------------------------------------------------------------------- */
@media print {
    .frise { height: auto !important; }
    .frise__colle { position: static !important; height: auto !important; }
    .frise__piste { display: grid !important; width: auto !important; padding-inline: 0 !important; transform: none !important; }
    .frise__indice, .frise__jauge, .formes::before, .formes::after { display: none !important; }
    .chiffre__anime { display: none; }
    .chiffre__brut { position: static; width: auto; height: auto; clip-path: none; }
}
