/* =============================================================================
   Clippit — couche cinétique
   =============================================================================
   Troisième et dernière couche. L'empilement est strict :

     clippit.css     la charte, seule source des couleurs et de la typographie
     mouvement.css   le vocabulaire du site de référence
     cinetique.css   ce fichier, qui pousse le mouvement plus loin

   Chaque couche se retire sans casser celles du dessous. Retirez ce fichier et
   son script, vous retrouvez la deuxième proposition à l'identique.

   Ce qui s'y ajoute : une ouverture orchestrée au chargement, un titre animé
   lettre à lettre, une barre de progression de lecture, un bandeau de logos
   piloté par le défilement, une inclinaison des cartes au pointeur, et un
   empilement épinglé pour l'espace client.

   La règle qui a guidé les arbitrages : plus il y a de mouvement, plus il faut
   qu'il s'arrête proprement. Rien ici ne tourne en boucle sans fin, rien ne
   retient un contenu, et le bloc « mouvement réduit » en fin de fichier ramène
   la page à un état parfaitement statique.
   ============================================================================= */

/* -----------------------------------------------------------------------------
   Ouverture au chargement
   -----------------------------------------------------------------------------
   Un rideau bleu couvre l'écran, le trombone s'y inscrit, puis le rideau se
   retire vers le haut et le hero se met en place derrière.

   Deux garde-fous. Le rideau n'existe que si le script l'a inséré : sans
   JavaScript, il n'y a rien à retirer et la page s'affiche directement. Et il
   se retire de lui-même au bout de 2,2 s même si une image tarde, ce qui évite
   le pire défaut de ce procédé, une page qui reste blanche parce qu'une
   ressource n'est pas venue.

   La séquence dure moins de deux secondes et ne se produit qu'une fois : le
   critère WCAG 2.2.2, qui vise le mouvement automatique de plus de cinq
   secondes, ne s'applique pas. Elle reste interruptible d'un clic ou d'une
   touche. */
.rideau {
    position: fixed;
    inset: 0;
    z-index: 300;
    display: grid;
    place-items: center;
    background: var(--bleu-950);
    /* `visibility` a une transition discrète, elle bascule d'un coup à la fin :
       le rideau cesse d'intercepter le pointeur au bon moment. */
    transition: clip-path 760ms cubic-bezier(0.76, 0, 0.24, 1), visibility 0s linear 760ms;
    clip-path: inset(0 0 0 0);
}
.rideau[data-parti='true'] {
    clip-path: inset(0 0 100% 0);
    visibility: hidden;
}
/* La marque clonée est un `<picture>`, et `picture { display: contents }` dans
   le système de base l'efface de l'arbre de mise en page : une largeur posée
   dessus n'aurait aucun effet. C'est donc l'image qu'il faut dimensionner. */
.rideau__marque img,
img.rideau__marque {
    width: min(180px, 34vw);
    height: auto;
    animation: marque-entre 900ms cubic-bezier(0.2, 0.8, 0.2, 1) both;
}
.rideau__trait {
    position: absolute;
    bottom: 18%;
    left: 50%;
    width: min(220px, 40vw);
    height: 2px;
    translate: -50% 0;
    background: rgba(255, 255, 255, 0.16);
    border-radius: 2px;
    overflow: clip;
}
.rideau__trait > span {
    display: block;
    height: 100%;
    background: var(--vert);
    transform-origin: left;
    animation: rideau-charge 1100ms cubic-bezier(0.4, 0, 0.2, 1) both;
}
@keyframes marque-entre {
    from { opacity: 0; transform: translateY(18px) scale(0.86); }
    to { opacity: 1; transform: none; }
}
@keyframes rideau-charge {
    from { transform: scaleX(0); }
    to { transform: scaleX(1); }
}

/* Le hero se met en place derrière le rideau, une fois celui-ci parti. La
   classe est posée par le script : sans lui, rien n'est masqué. */
.ouverture-prete .hero__annonce,
.ouverture-prete .hero__texte,
.ouverture-prete .hero__actions,
.ouverture-prete .hero__preuves,
.ouverture-prete .hero__visuel {
    animation: hero-entre 700ms cubic-bezier(0.2, 0.8, 0.2, 1) both;
}
.ouverture-prete .hero__annonce { animation-delay: 60ms; }
.ouverture-prete .hero__texte { animation-delay: 220ms; }
.ouverture-prete .hero__actions { animation-delay: 300ms; }
.ouverture-prete .hero__preuves { animation-delay: 380ms; }
.ouverture-prete .hero__visuel { animation-delay: 140ms; }
@keyframes hero-entre {
    from { opacity: 0; transform: translateY(24px); }
    to { opacity: 1; transform: none; }
}

/* -----------------------------------------------------------------------------
   Titre du hero, lettre à lettre
   -----------------------------------------------------------------------------
   La couche précédente animait les titres mot à mot au défilement. Le titre du
   hero, lui, est visible d'emblée : il est donc animé au chargement, dans le
   temps, et lettre à lettre.

   Le script découpe en lettres et pose l'index de chacune dans `--i`, ce qui
   permet de calculer le décalage en CSS plutôt que d'écrire un style en ligne
   par lettre. */
.ouverture-prete .hero__titre .lettre > span {
    animation: lettre-monte 620ms cubic-bezier(0.2, 0.9, 0.2, 1) both;
    /* Plafonné à la douzième lettre : au-delà, la dernière arriverait trop tard
       pour que le titre se lise comme un ensemble. */
    animation-delay: calc(120ms + min(var(--i), 12) * 34ms);
}
@keyframes lettre-monte {
    from { transform: translateY(100%) rotate(4deg); opacity: 0; }
    to { transform: none; opacity: 1; }
}
/* Le découpage en lettres remplace celui en mots pour ce titre : la révélation
   au défilement de la couche précédente n'a plus à s'y appliquer. */
/* Le groupe de mot est insécable : la ligne ne peut se couper qu'entre les
   mots, jamais entre deux lettres. */
.hero__titre .mot-bloc {
    display: inline-block;
    white-space: nowrap;
}
/* Le rideau de chaque lettre ne doit couper qu'en bas, là d'où la lettre monte.
   La hauteur de ligne des titres, resserrée à 1.02, est plus basse que la boîte
   du dessin de Montserrat : les accents des capitales (À, Ô, É) montent au-delà,
   les jambages descendent en dessous et le dessin dépasse la largeur d'avance
   sur les côtés. Un masquage rectangulaire les rognerait net, d'où le
   `clip-path` ouvert en haut et sur les côtés, qui ne touche pas à la mise en
   page. La valeur du bas est négative elle aussi, pour les jambages. */
.hero__titre .lettre {
    display: inline-block;
    clip-path: inset(-0.6em -0.4em -0.1em);
    vertical-align: bottom;
}
.hero__titre .lettre > span { display: inline-block; }

/* -----------------------------------------------------------------------------
   Barre de progression de lecture
   -----------------------------------------------------------------------------
   Purement indicative, et entièrement en CSS. Elle dit où l'on en est dans une
   page longue, ce qui compte d'autant plus ici que la frise épinglée fausse la
   perception donnée par la barre de défilement du navigateur. */
.progression {
    position: fixed;
    inset: 0 0 auto;
    z-index: 150;
    height: 3px;
    background: transparent;
    pointer-events: none;
}
.progression > span {
    display: block;
    height: 100%;
    background: linear-gradient(90deg, var(--vert), color-mix(in srgb, var(--vert) 40%, #fff));
    transform-origin: left;
    transform: scaleX(0);
}
@supports (animation-timeline: scroll()) {
    .progression > span {
        animation: progresse linear both;
        animation-timeline: scroll(root block);
    }
}
@keyframes progresse {
    from { transform: scaleX(0); }
    to { transform: scaleX(1); }
}

/* -----------------------------------------------------------------------------
   Bandeau de logos défilant
   -----------------------------------------------------------------------------
   Le classique du site d'agence, à une différence près : il n'avance pas tout
   seul. La bande est liée à la position de défilement, donc elle glisse quand
   on parcourt la page et s'arrête quand on s'arrête.

   Ce choix n'est pas qu'esthétique. Un bandeau qui tourne en boucle est un
   mouvement automatique permanent, que le critère WCAG 2.2.2 oblige à pouvoir
   mettre en pause. L'accrocher au défilement évite d'ajouter un bouton de
   pause à un élément purement décoratif.

   La bande est dupliquée pour que le raccord soit invisible ; la copie est
   masquée aux technologies d'assistance. */
.bande { overflow: clip; }
.bande__piste {
    display: flex;
    width: max-content;
    gap: var(--e-4);
}
@supports (animation-timeline: view()) {
    .bande__piste {
        animation: bande-glisse linear both;
        animation-timeline: view();
        animation-range: cover 0% cover 100%;
    }
}
@keyframes bande-glisse {
    /* La piste contient deux exemplaires de la liste : la décaler de la moitié
       de sa largeur la ramène exactement sur elle-même. */
    from { transform: translateX(0); }
    to { transform: translateX(-50%); }
}

/* -----------------------------------------------------------------------------
   Inclinaison des cartes au pointeur
   -----------------------------------------------------------------------------
   Le script écrit `--rx` et `--ry` d'après la position du pointeur dans la
   carte. Sans lui, les deux valeurs valent zéro et la carte est plate.

   `transform-style: preserve-3d` n'est pas utilisé : l'inclinaison reste une
   rotation de surface, sans profondeur, ce qui évite de rendre le texte flou
   sur les écrans à faible densité. */
.incline {
    --rx: 0deg;
    --ry: 0deg;
    transform: perspective(900px) rotateX(var(--rx)) rotateY(var(--ry));
    transition: transform 260ms var(--courbe);
}
/* Le survol de `.bloc` remonte déjà la carte dans la couche précédente ; les
   deux transformations doivent être combinées, sinon la dernière écrase
   l'autre. */
.bloc.incline:hover {
    transform: perspective(900px) rotateX(var(--rx)) rotateY(var(--ry)) translateY(-4px);
}

/* -----------------------------------------------------------------------------
   Empilement épinglé de l'espace client
   -----------------------------------------------------------------------------
   Les trois raccourcis se superposent en se collant les uns aux autres pendant
   le défilement, chacun venant recouvrir légèrement le précédent.

   Contrairement à la frise horizontale, cet effet ne coûte pas de hauteur
   supplémentaire artificielle : les cartes occupent la place qu'elles
   occuperaient de toute façon, elles se collent simplement en chemin. Le
   contenu reste donc entièrement accessible même si l'épinglage n'a pas lieu.

   Ces cartes sont des liens, donc focalisables. `top` tient compte du bandeau
   fixe, sans quoi une carte atteinte au clavier se collerait dessous. */
@media (min-width: 901px) {
    @supports (animation-timeline: view()) {
        .empile { display: block; }
        .empile > .bloc {
            position: sticky;
            top: calc(var(--hauteur-entete) + var(--e-5));
            margin-bottom: var(--e-5);
        }
        .empile > .bloc:nth-child(1) { top: calc(var(--hauteur-entete) + var(--e-5)); }
        .empile > .bloc:nth-child(2) { top: calc(var(--hauteur-entete) + var(--e-5) + 26px); }
        .empile > .bloc:nth-child(3) { top: calc(var(--hauteur-entete) + var(--e-5) + 52px); }
        /* Le fond doit être opaque : une carte translucide laisserait voir
           celle qu'elle recouvre. */
        .empile > .bloc { background: var(--blanc); }
    }
}

/* -----------------------------------------------------------------------------
   Mouvement réduit
   -----------------------------------------------------------------------------
   Le script n'insère ni rideau, ni curseur, ni découpage en lettres quand le
   réglage est actif ; ces règles couvrent le cas où il change en cours de
   session. */
@media (prefers-reduced-motion: reduce) {
    .rideau { display: none !important; }
    .progression > span { animation: none !important; transform: scaleX(0) !important; }
    .bande__piste { animation: none !important; transform: none !important; }
    .incline, .bloc.incline:hover { transform: none !important; transition: none !important; }
    .ouverture-prete .hero__annonce,
    .ouverture-prete .hero__texte,
    .ouverture-prete .hero__actions,
    .ouverture-prete .hero__preuves,
    .ouverture-prete .hero__visuel,
    .ouverture-prete .hero__titre .lettre > span {
        animation: none !important;
        opacity: 1 !important;
        transform: none !important;
    }
    .empile > .bloc { position: static !important; }
}

/* -----------------------------------------------------------------------------
   Bandeau de logos : mise en page de repli
   -----------------------------------------------------------------------------
   Deux situations où la piste ne glisse pas, et où elle ne peut donc pas rester
   une seule ligne plus large que son cadre.

   Sur téléphone, la piste mesure 1447 px pour un cadre de 342 px. La
   translation de la moitié de sa largeur, soit 723 px, fait traverser le cadre
   à chaque logo plus de deux fois pendant le passage de la bande à l'écran. Un
   coup de pouce couvre cette distance en une fraction de seconde : le résultat
   ne se lit pas comme un glissement mais comme un clignotement.

   En mouvement réduit, la translation est supprimée mais la piste restait large
   de 723 px : sur un écran étroit, cinq des sept logos étaient simplement
   découpés par le cadre et invisibles.

   Dans les deux cas la bande redevient ce qu'elle est au fond, une liste de
   logos, et se répartit sur plusieurs lignes. */
@media (max-width: 700px), (prefers-reduced-motion: reduce) {
    .bande__piste {
        flex-wrap: wrap;
        justify-content: center;
        width: auto;
        animation: none;
        transform: none;
    }
    /* La copie n'existe que pour rendre le raccord de la boucle invisible. */
    .bande__piste > [aria-hidden='true'] { display: none; }
    /* Les tuiles se partagent la ligne au lieu d'être dimensionnées par
       l'image : sans cela leurs largeurs suivaient les proportions des sept
       fichiers, de 57 à 120 px, et la bande paraissait décousue. */
    .bande__piste img { flex: 1 1 120px; width: auto; max-width: 220px; }
}

@media print {
    .rideau, .progression { display: none !important; }
    .bande__piste { transform: none !important; flex-wrap: wrap; width: auto !important; }
    .empile > .bloc { position: static !important; }
    .incline { transform: none !important; }
}
