/**
 * Gutenberg New Gen - Les effets d'apparition.
 *
 * Portage des effets d'entree de WS Booster (assets/css/ws-effets-entree.css)
 * vers Gutenberg. Meme contrat, memes images cles ; seuls les noms changent,
 * passes en anglais pour rester coherents avec le reste du code.
 *
 * ---------------------------------------------------------------------------
 * LE CONTRAT, EN TROIS ELEMENTS
 *
 *   data-gng-effect="up"      sur le CONTENEUR : quel effet jouer.
 *   class="gng-fx__p"         sur chaque MORCEAU a animer, ENFANT DIRECT du
 *                             conteneur. L'enfant direct n'est pas un detail :
 *                             c'est ce qui permet d'imbriquer une cascade dans
 *                             une autre sans que la premiere rejoue les
 *                             morceaux de la seconde.
 *   --gng-fx-index: 0, 1, 2   sur chaque morceau : son rang dans la cascade.
 *
 * Reglages, poses sur le conteneur :
 *   --gng-fx-duration    duree d'un morceau              (defaut .8s)
 *   --gng-fx-stagger     retard d'un morceau au suivant  (defaut .12s)
 *   --gng-fx-band        couleur de la bande             (defaut #f97316)
 *   --gng-fx-band-delay  attente avant que la bande parte (defaut 1s)
 *
 * ---------------------------------------------------------------------------
 * LE CONTENU EST VISIBLE PAR DEFAUT
 *
 * Rien n'est masque tant que `gng-fx-js` n'est pas pose par le script
 * d'affichage. Si celui-ci ne se charge jamais - fichier bloque, erreur
 * ailleurs dans la page - le contenu reste lisible. Masquer par defaut et
 * compter sur un script pour reveler, c'est la garantie qu'un jour une page
 * s'affichera vide. Le script pose ensuite `gng-fx-visible` a l'arrivee a
 * l'ecran, et c'est LUI qui lance l'animation.
 */

/* ====================================================================
   ETAT DE DEPART
   La bande qui balaie est ecartee : pour elle, le contenu est deja en place
   des le debut, c'est la bande qui le cache.
   ==================================================================== */
.gng-fx-js[data-gng-effect]:not([data-gng-effect=""]):not([data-gng-effect="sweep"]) > .gng-fx__p {
    opacity: 0;
}

/* ====================================================================
   LA CASCADE
   Le retard de chaque morceau se calcule sur son rang.
   ==================================================================== */
.gng-fx-visible[data-gng-effect]:not([data-gng-effect=""]) > .gng-fx__p {
    animation-duration: var(--gng-fx-duration, .8s);
    animation-delay: calc(var(--gng-fx-index, 0) * var(--gng-fx-stagger, .12s));
    animation-timing-function: cubic-bezier(.22, .68, .3, 1);
    animation-fill-mode: both;
}

.gng-fx-visible[data-gng-effect="fade"]  > .gng-fx__p { animation-name: gng-fx-fade; }
.gng-fx-visible[data-gng-effect="up"]    > .gng-fx__p { animation-name: gng-fx-up; }
.gng-fx-visible[data-gng-effect="down"]  > .gng-fx__p { animation-name: gng-fx-down; }
.gng-fx-visible[data-gng-effect="left"]  > .gng-fx__p { animation-name: gng-fx-left; }
.gng-fx-visible[data-gng-effect="right"] > .gng-fx__p { animation-name: gng-fx-right; }
.gng-fx-visible[data-gng-effect="zoom"]  > .gng-fx__p { animation-name: gng-fx-zoom; }
.gng-fx-visible[data-gng-effect="mask"]  > .gng-fx__p { animation-name: gng-fx-mask; }

/* ====================================================================
   LES DEUX EFFETS A BANDE

   La bande est un pseudo-element : aucun element ajoute au contenu, donc rien
   qui puisse gener la lecture, la selection ou un lecteur d'ecran.

   `position: relative` lui donne son repere. `display: inline-block` n'est
   necessaire que pour un morceau en ligne : sans lui, une bande posee sur un
   element en ligne se comporte mal des que le texte passe a la ligne. Sur un
   morceau deja en bloc, la valeur est ignoree.
   ==================================================================== */
[data-gng-effect="sweep"] > .gng-fx__p,
[data-gng-effect="reveal"] > .gng-fx__p {
    position: relative;
    display: inline-block;
}

[data-gng-effect="sweep"] > .gng-fx__p::after,
[data-gng-effect="reveal"] > .gng-fx__p::after {
    content: "";
    position: absolute;
    background: var(--gng-fx-band, #f97316);
    pointer-events: none;
    z-index: 3;
}

/* LA BANDE QUI COUVRE, ATTEND, PUIS PART.
 *
 * Elle deborde legerement : une bande calee au pixel pres laisse depasser les
 * jambages des lettres et trahit le texte cache.
 *
 * SES TROIS ETATS, DANS CET ORDRE PRECIS.
 *
 * 1. Par defaut, elle se retire toute seule au bout de quatre secondes. C'est
 *    le FILET DE SECURITE : si le script ne se charge jamais, le contenu finit
 *    par apparaitre au lieu de rester cache pour toujours.
 * 2. Des que le script prend la main, on annule ce retrait automatique - sinon
 *    la bande partirait avant meme que le contenu soit arrive a l'ecran.
 * 3. A l'arrivee a l'ecran, elle joue pour de bon.
 *
 * L'ordre des trois regles est ce qui les departage : elles visent le meme
 * pseudo-element, la derniere applicable l'emporte. */
[data-gng-effect="sweep"] > .gng-fx__p::after {
    inset: -.08em -.06em;
    transform: scaleX(1);
    transform-origin: right center;
    animation: gng-fx-sweep var(--gng-fx-duration, .8s) cubic-bezier(.65, .05, 0, 1) 4s both;
}

.gng-fx-js[data-gng-effect="sweep"] > .gng-fx__p::after {
    animation: none;
}

.gng-fx-visible[data-gng-effect="sweep"] > .gng-fx__p::after {
    animation: gng-fx-sweep var(--gng-fx-duration, .8s) cubic-bezier(.65, .05, 0, 1) both;
    /* L'attente s'ajoute au decalage : chaque morceau patiente, puis part. */
    animation-delay: calc(var(--gng-fx-band-delay, 1s) + var(--gng-fx-index, 0) * var(--gng-fx-stagger, .12s));
}

/* LA BANDE QUI ARRIVE PUIS REPART.
   Elle grandit par la gauche en recouvrant le morceau a mesure qu'il se
   revele, puis se retire par la droite en le laissant en place. On ne voit
   donc pas le contenu apparaitre : on voit une bande passer, et le contenu
   est la derriere. */
[data-gng-effect="reveal"] > .gng-fx__p::after {
    inset: 0;
    transform: scaleX(0);
    transform-origin: left center;
}

.gng-fx-visible[data-gng-effect="reveal"] > .gng-fx__p {
    animation-name: gng-fx-reveal;
}

.gng-fx-visible[data-gng-effect="reveal"] > .gng-fx__p::after {
    /* Un peu plus longue que le rideau : la bande doit finir de se retirer
       APRES que le contenu soit entierement decouvert. */
    animation: gng-fx-band calc(var(--gng-fx-duration, .8s) * 1.15) cubic-bezier(.65, .05, 0, 1) both;
    animation-delay: calc(var(--gng-fx-index, 0) * var(--gng-fx-stagger, .12s));
}

/* ====================================================================
   LES IMAGES CLES
   ==================================================================== */
/* POURQUOI `translate` ET `scale`, ET SURTOUT PAS `transform`.
 *
 * `transform` est une propriete UNIQUE : qui l'ecrit efface tout ce qu'un
 * autre y avait mis. Or un bloc peut deja en porter un, pose par le theme ou
 * par un autre script. Une animation d'entree ecrite en `transform` y serait
 * ecrasee : il ne resterait que le fondu, et le mouvement paraitrait a moitie
 * casse.
 *
 * `translate` et `scale` sont des proprietes distinctes, qui se COMPOSENT
 * avec `transform` au lieu de le remplacer. */
@keyframes gng-fx-fade  { from { opacity: 0; }                     to { opacity: 1; } }
@keyframes gng-fx-up    { from { opacity: 0; translate: 0 .5em; }  to { opacity: 1; translate: none; } }
@keyframes gng-fx-down  { from { opacity: 0; translate: 0 -.5em; } to { opacity: 1; translate: none; } }
@keyframes gng-fx-left  { from { opacity: 0; translate: -.7em 0; } to { opacity: 1; translate: none; } }
@keyframes gng-fx-right { from { opacity: 0; translate: .7em 0; }  to { opacity: 1; translate: none; } }
@keyframes gng-fx-zoom  { from { opacity: 0; scale: .86; }         to { opacity: 1; scale: none; } }

/* DEVOILE PAR LE BAS.
   Le decoupage remplace le recadrage : il n'exige aucun element interieur a
   animer, donc l'effet marche sur n'importe quel morceau - un paragraphe comme
   une colonne entiere. Le debordement de 40 % evite de rogner une ombre ou une
   decoration qui depasserait. */
@keyframes gng-fx-mask {
    from { opacity: 1; clip-path: inset(0 -40% 100% -40%); translate: 0 .35em; }
    to   { opacity: 1; clip-path: inset(-40% -40% -40% -40%); translate: none; }
}

/* L'opacite est REPETEE dans les etapes : la regle de depart met les morceaux
   a zero pour les autres effets, et une propriete absente des etapes garderait
   cette valeur. Sans ces deux `opacity: 1`, le contenu resterait invisible. */
@keyframes gng-fx-reveal {
    from { clip-path: inset(-40% 100% -40% -40%); opacity: 1; }
    to   { clip-path: inset(-40% -40% -40% -40%); opacity: 1; }
}

@keyframes gng-fx-sweep {
    from { transform: scaleX(1); transform-origin: right center; }
    to   { transform: scaleX(0); transform-origin: right center; }
}

/* Le basculement du point d'ancrage se fait a l'instant ou la bande est pleine
   largeur : a ce moment precis l'ancrage ne change rien a l'image, le passage
   est donc invisible. C'est ce qui evite le saut qu'on obtient en faisant
   grandir et retrecir en meme temps. */
@keyframes gng-fx-band {
    0%    { transform: scaleX(0); transform-origin: left center; }
    47.9% { transform: scaleX(1); transform-origin: left center; }
    48%   { transform: scaleX(1); transform-origin: right center; }
    100%  { transform: scaleX(0); transform-origin: right center; }
}

/* ====================================================================
   MOUVEMENT REDUIT
   Le visiteur qui a demande moins d'animations voit le resultat, pas le
   trajet. Le contenu reste entierement lisible.
   ==================================================================== */
@media (prefers-reduced-motion: reduce) {
    .gng-fx-js[data-gng-effect] > .gng-fx__p,
    .gng-fx-visible[data-gng-effect] > .gng-fx__p {
        opacity: 1 !important;
        clip-path: none !important;
        translate: none !important;
        scale: none !important;
        animation: none !important;
    }
    [data-gng-effect] > .gng-fx__p::after {
        display: none !important;
    }
}
