/*
 * Pixelacademia — animations au défilement.
 *
 * Ces effets s'appliquent depuis l'éditeur : on sélectionne un bloc, puis
 * Styles › une des variations « Animation… ». Aucune classe à taper.
 *
 * PRINCIPE : le défilement pilote l'animation nativement, par
 * `animation-timeline: view()`. C'est une propriété CSS standard, calculée
 * hors du fil principal par le navigateur : elle ne coûte rien au JavaScript,
 * ne déclenche aucun recalcul de mise en page, et reste fluide sur un
 * téléphone. Là où elle n'est pas encore prise en charge, un observateur
 * d'intersection de vingt lignes prend le relais (assets/animations.e7456edf.js).
 *
 * RÈGLES QUE CE FICHIER S'IMPOSE :
 *
 * 1. Rien d'autre que `transform` et `opacity` n'est animé. Ce sont les deux
 *    seules propriétés que le navigateur compose sans repasser par la mise en
 *    page ni le dessin — tout le reste fait chuter la fluidité.
 * 2. Aucun décalage de mise en page : les blocs gardent leur place et leur
 *    taille avant comme après. Le Cumulative Layout Shift reste à zéro.
 * 3. Le contenu n'est jamais retiré du document. Un texte animé est présent
 *    dans le HTML servi, donc lu par les moteurs de recherche comme par un
 *    lecteur d'écran, animation ou pas.
 * 4. Sans JavaScript, tout s'affiche normalement : la classe de repli n'est
 *    posée que par le script, jamais dans le balisage.
 * 5. `prefers-reduced-motion` coupe tout. Ce n'est pas une option : les
 *    animations au défilement déclenchent des malaises vestibulaires chez une
 *    partie du public, et le RGAA l'exige.
 */

/* ------------------------------------------------------------------
   Réglages
   ------------------------------------------------------------------ */

:root {
  /* Distance parcourue par les blocs qui montent. Volontairement courte :
     au-delà, l'effet se remarque plus que le contenu. */
  --pa-anim-lift: 1.75rem;
  --pa-anim-duration: .7s;
  --pa-anim-ease: cubic-bezier(.22, .61, .36, 1);
}

@keyframes pa-anim-fade { from { opacity: 0; } to { opacity: 1; } }

@keyframes pa-anim-rise {
  from { opacity: 0; transform: translate3d(0, var(--pa-anim-lift), 0); }
  to   { opacity: 1; transform: none; }
}

@keyframes pa-anim-side {
  from { opacity: 0; transform: translate3d(calc(var(--pa-anim-lift) * -1.4), 0, 0); }
  to   { opacity: 1; transform: none; }
}

/* Apparition rapide : le geste de la montée, en plus court et plus serré. Pour
   une rangée de logos ou une grille de portraits — des vignettes, où l'attente
   se remarquerait plus que l'effet. */
@keyframes pa-anim-pop {
  from { opacity: 0; transform: translate3d(0, 1.1rem, 0) scale(.97); }
  to   { opacity: 1; transform: none; }
}

/* Ken Burns : l'image respire pendant toute sa traversée de l'écran. */
@keyframes pa-anim-zoom {
  from { transform: scale(1.14); }
  to   { transform: scale(1); }
}

/* Parallaxe : la couche de fond monte moins vite que la page. Le débord
   vertical est assuré par la règle .is-style-anim-parallax plus bas, sans quoi
   le déplacement découvrirait le bas de l'élément. */
@keyframes pa-anim-parallax {
  from { transform: translate3d(0, -8%, 0); }
  to   { transform: translate3d(0, 8%, 0); }
}

/* Révélation par masque : le bloc se découvre du bas vers le haut. */
@keyframes pa-anim-reveal {
  from { clip-path: inset(0 0 100% 0); opacity: 0; }
  to   { clip-path: inset(0 0 0 0);    opacity: 1; }
}

/* ------------------------------------------------------------------
   Le chemin natif : le défilement pilote l'animation
   ------------------------------------------------------------------ */

@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {

    .is-style-anim-fade,
    .is-style-anim-rise,
    .is-style-anim-side,
    .is-style-anim-reveal,
    .is-style-anim-stagger > * {
      animation: var(--pa-anim-name, pa-anim-rise) linear both;
      animation-timeline: view();
      /* L'animation se joue pendant l'entrée du bloc dans l'écran et se
         termine bien avant qu'il soit centré : passé ce point, on lit. */
      animation-range: entry 5% cover 28%;
    }

    .is-style-anim-fade   { --pa-anim-name: pa-anim-fade; }
    .is-style-anim-rise   { --pa-anim-name: pa-anim-rise; }
    .is-style-anim-side   { --pa-anim-name: pa-anim-side; }
    .is-style-anim-reveal { --pa-anim-name: pa-anim-reveal; }

    /* Cascade : chaque enfant démarre un peu après le précédent. La plage est
       décalée plutôt que retardée par un `animation-delay`, qui n'a pas de
       sens sur une timeline de défilement.

       ⚠️ LA PLAGE SE TERMINE DANS `entry`, ET C'EST TOUT LE SUJET. Elle
       finissait auparavant dans `cover` — jusqu'à `cover 52%` pour les
       derniers enfants — et le client a signalé le 2026-08-21 que des rangées
       entières de cartes restaient « trop sombres » sur les trois pages
       métier : « Spectacle vivant et événements », « Entraînements virtuels »,
       « Visites scénarisées », « Formation et santé », « Culture et musées ».
       Ce n'était pas une couleur mais une animation inachevée.

       Le calcul. La plage `cover` couvre toute la traversée de l'écran, soit
       hauteur de fenêtre + hauteur de l'élément. Sur une carte de 390 px dans
       une fenêtre de 790, `cover 52%` tombe quand le haut de la carte est à
       176 px du haut de l'écran : la carte n'atteint son opacité pleine que
       lorsqu'elle est presque en haut de la fenêtre. Un lecteur qui cadre la
       grille pour la lire garde donc la **deuxième rangée** à mi-opacité, en
       permanence — sur un fond bleu nuit, cela se lit comme du gris sale. Les
       enfants 1 à 3, qui finissaient plus tôt, ne posaient pas le problème :
       d'où des rangées claires et des rangées sombres sur la même grille.

       La plage `entry`, elle, se termine à l'instant précis où l'élément est
       entièrement entré dans l'écran. Finir à 83 % d'`entry`, c'est finir
       juste avant : la carte est pleinement lisible dès qu'on la voit en
       entier, où qu'elle soit ensuite. Ne pas ramener `cover` ici.

       Cela ne vaut que pour des éléments plus petits que la fenêtre — ce que
       sont les cartes d'une cascade. La règle générale au-dessus garde
       `cover`, car elle vise des sections entières, qui la dépassent souvent
       et pour lesquelles `entry 100%` arriverait, lui, trop tard. */
    .is-style-anim-stagger > * {
      --pa-anim-name: pa-anim-rise;
      animation-range: entry 5% entry 55%;
    }
    .is-style-anim-stagger > :nth-child(2) { animation-range: entry 12% entry 62%; }
    .is-style-anim-stagger > :nth-child(3) { animation-range: entry 19% entry 69%; }
    .is-style-anim-stagger > :nth-child(4) { animation-range: entry 26% entry 76%; }
    .is-style-anim-stagger > :nth-child(n+5) { animation-range: entry 33% entry 83%; }

    /* « Apparition rapide » n'est délibérément pas ici : elle ne passe **pas**
       par la timeline de défilement, même quand le navigateur la gère. Voir la
       section du repli, plus bas, qui la traite pour tous les navigateurs.

       La raison est ce que le client a constaté le 2026-08-20 : lié au
       défilement, l'effet se termine pendant que le bloc est encore au bord
       bas de l'écran, et il ne se joue pas du tout si l'on arrive sur la page
       avec la section déjà visible. Une rangée de logos qui doit « apparaître
       rapidement » a besoin d'un temps à elle, pas d'un temps emprunté à la
       molette. */

    /* Ken Burns et parallaxe se jouent sur toute la traversée, pas seulement
       à l'entrée : c'est ce qui les rend continus. */
    .is-style-anim-zoom img,
    .is-style-anim-zoom .wp-block-cover__image-background {
      animation: pa-anim-zoom linear both;
      animation-timeline: view();
      animation-range: cover 0% cover 100%;
    }

    .is-style-anim-parallax > img,
    .is-style-anim-parallax > picture > img,
    .is-style-anim-parallax .wp-block-image img,
    .is-style-anim-parallax .wp-block-cover__image-background {
      animation: pa-anim-parallax linear both;
      animation-timeline: view();
      animation-range: cover 0% cover 100%;
    }
  }
}

/* La couche parallaxée doit déborder de son cadre : elle se déplace de ±8 %,
   et sans débord elle laisserait une bande vide. Cette règle vaut pour les
   deux chemins, natif comme repli. */
.is-style-anim-parallax { overflow: hidden; }
.is-style-anim-parallax > img,
.is-style-anim-parallax > picture > img,
.is-style-anim-parallax .wp-block-image img,
.is-style-anim-parallax .wp-block-cover__image-background {
  height: 118%;
  object-fit: cover;
}

/* ------------------------------------------------------------------
   L'observateur d'intersection : le repli, et l'apparition rapide

   Deux classes posées par assets/animations.e7456edf.js, à ne pas confondre :

     - `pa-anim-js` n'est posée que si le navigateur **ne sait pas** animer au
       défilement. Elle ouvre les règles de repli de tous les autres effets ;
     - `pa-anim-quick-js` est posée dans tous les cas, et n'ouvre que celles de
       l'apparition rapide — le seul effet du thème qui se joue au temps.

   Sans JavaScript, aucune des deux n'existe : le contenu s'affiche tel quel.
   C'est la seule façon honnête de faire, on n'anime pas en cachant.
   ------------------------------------------------------------------ */

@media (prefers-reduced-motion: no-preference) {
  .pa-anim-js .is-style-anim-fade,
  .pa-anim-js .is-style-anim-rise,
  .pa-anim-js .is-style-anim-side,
  .pa-anim-js .is-style-anim-reveal,
  .pa-anim-js .is-style-anim-stagger > * {
    opacity: 0;
    transition:
      opacity var(--pa-anim-duration) var(--pa-anim-ease),
      transform var(--pa-anim-duration) var(--pa-anim-ease),
      clip-path var(--pa-anim-duration) var(--pa-anim-ease);
  }

  .pa-anim-js .is-style-anim-rise,
  .pa-anim-js .is-style-anim-stagger > * { transform: translate3d(0, var(--pa-anim-lift), 0); }
  .pa-anim-js .is-style-anim-side        { transform: translate3d(calc(var(--pa-anim-lift) * -1.4), 0, 0); }
  .pa-anim-js .is-style-anim-reveal      { clip-path: inset(0 0 100% 0); }

  .pa-anim-js .is-style-anim-fade.is-in,
  .pa-anim-js .is-style-anim-rise.is-in,
  .pa-anim-js .is-style-anim-side.is-in,
  .pa-anim-js .is-style-anim-reveal.is-in,
  .pa-anim-js .is-style-anim-stagger.is-in > * {
    opacity: 1;
    transform: none;
    clip-path: inset(0 0 0 0);
  }

  /* La cascade, côté repli : un retard court, plafonné, pour ne pas faire
     attendre le bas d'une longue liste. */
  .pa-anim-js .is-style-anim-stagger.is-in > :nth-child(2) { transition-delay: .09s; }
  .pa-anim-js .is-style-anim-stagger.is-in > :nth-child(3) { transition-delay: .18s; }
  .pa-anim-js .is-style-anim-stagger.is-in > :nth-child(4) { transition-delay: .27s; }
  .pa-anim-js .is-style-anim-stagger.is-in > :nth-child(n+5) { transition-delay: .36s; }

  /* APPARITION RAPIDE — pour tous les navigateurs, y compris ceux qui savent
     animer au défilement.

     C'est le seul effet du thème qui se joue au temps et non au défilement, et
     c'est ce que le client demandait le 2026-08-20 : la rangée doit **se voir**
     apparaître. L'observateur d'intersection pose `is-in` quand le conteneur
     entre à l'écran — ou dès le chargement s'il y est déjà — et les enfants se
     posent alors l'un après l'autre, 130 ms d'écart.

     Les durées ont été rallongées le 2026-08-20 : à 0,45 s et 80 ms d'écart,
     le client trouvait l'effet trop rapide pour se voir. Une rangée de six
     logos met désormais un peu plus d'une seconde et demie à se poser.

     L'état masqué est une déclaration sèche, et l'apparition une **animation**
     jouée sur `is-in` : surtout pas une transition depuis cet état. Une
     transition se déclencherait aussi à l'aller, au moment où le script pose sa
     classe — la rangée s'effacerait sous les yeux du visiteur avant de revenir.
     Une animation ne part que lorsqu'on la déclare, et `both` lui fait tenir sa
     dernière image.

     Le déplacement est franc — 1,1 rem — parce qu'à un demi-centimètre le
     mouvement passait inaperçu : c'est précisément ce que le client a signalé. */
  .pa-anim-quick-js .is-style-anim-quick > * { opacity: 0; }

  .pa-anim-quick-js .is-style-anim-quick.is-in > * {
    animation: pa-anim-pop .75s var(--pa-anim-ease) both;
  }

  .pa-anim-quick-js .is-style-anim-quick.is-in > :nth-child(2) { animation-delay: .13s; }
  .pa-anim-quick-js .is-style-anim-quick.is-in > :nth-child(3) { animation-delay: .26s; }
  .pa-anim-quick-js .is-style-anim-quick.is-in > :nth-child(4) { animation-delay: .39s; }
  .pa-anim-quick-js .is-style-anim-quick.is-in > :nth-child(5) { animation-delay: .52s; }
  .pa-anim-quick-js .is-style-anim-quick.is-in > :nth-child(6) { animation-delay: .65s; }
  .pa-anim-quick-js .is-style-anim-quick.is-in > :nth-child(7) { animation-delay: .78s; }
  .pa-anim-quick-js .is-style-anim-quick.is-in > :nth-child(8) { animation-delay: .91s; }
  /* Au-delà de huit — les douze portraits de la page Formateurs — le retard est
     plafonné : la fin d'une grille ne doit pas se faire attendre. */
  .pa-anim-quick-js .is-style-anim-quick.is-in > :nth-child(n+9) { animation-delay: 1s; }
}

/* ------------------------------------------------------------------
   TEINTE QUI CIRCULE — cartes du catalogue

   Demande du client du 2026-08-20 : que la page des formations soit moins
   statique, chaque carte changeant lentement de couleur, « de manière
   subtile ».

   Deux voiles superposés sur le fond de la carte, dont seule l'opacité est
   animée — la règle du fichier tient : ni couleur ni fond ne sont animés
   directement, ce qui coûterait un redessin à chaque image. Les voiles se
   relaient sur trois temps : or, bleu, puis rien du tout, où la carte revient
   à son fond de charte. La cadence est longue (24 s) et les opacités basses :
   à l'arrêt sur image on ne voit rien, c'est en revenant sur la page qu'on
   remarque que la grille a bougé.

   Chaque carte part à un moment différent du cycle (retards négatifs, donc
   déjà en cours au chargement) : la grille respire, elle ne clignote pas
   d'un seul bloc.
   ------------------------------------------------------------------ */

@keyframes pa-teinte-or {
  0%, 100% { opacity: .55; }
  30%      { opacity: 0; }
  70%      { opacity: 0; }
}

@keyframes pa-teinte-bleue {
  0%, 100% { opacity: 0; }
  30%      { opacity: .55; }
  70%      { opacity: 0; }
}

@media (prefers-reduced-motion: no-preference) {
  .pa-grid-anime > .pa-card {
    position: relative;
    isolation: isolate;
  }

  /* Les deux voiles sont posés derrière le texte de la carte mais devant son
     fond : `z-index: -1` dans le contexte d'empilement créé juste au-dessus. */
  .pa-grid-anime > .pa-card::before,
  .pa-grid-anime > .pa-card::after {
    content: "";
    position: absolute;
    /* Débord d'un pixel : le voile recouvre la bordure de la carte, qu'il peut
       ainsi teinter à son tour. C'est le contour qui rend le changement
       lisible — un aplat de 20 % sur un fond bleu nuit, seul, ne se voit pas
       à moins de comparer deux captures. */
    inset: -1px;
    z-index: -1;
    border: 1px solid transparent;
    border-radius: inherit;
    pointer-events: none;
    animation: 9s ease-in-out infinite;
  }

  /* Les alpha ont été relevés après essai à l'écran : à 0,10, la teinte ne se
     voyait pas du tout sur le bleu nuit des cartes, et une animation qu'on ne
     voit pas ne vaut pas la peine d'être jouée. À 0,22, le coin haut de la
     carte se réchauffe juste assez pour qu'on le remarque en revenant sur la
     page — sans jamais devenir une carte dorée. */
  .pa-grid-anime > .pa-card::before {
    background: linear-gradient(155deg, rgba(111, 220, 239, .30) 0%, rgba(111, 220, 239, .07) 58%, rgba(111, 220, 239, .02) 100%);
    border-color: rgba(111, 220, 239, .45);
    animation-name: pa-teinte-or;
  }

  .pa-grid-anime > .pa-card::after {
    background: linear-gradient(155deg, rgba(120, 170, 255, .28) 0%, rgba(120, 170, 255, .07) 58%, rgba(120, 170, 255, .02) 100%);
    border-color: rgba(120, 170, 255, .42);
    animation-name: pa-teinte-bleue;
  }

  /* Décalages : cinq départs différents, répartis sur le cycle. Ils sont
     négatifs pour que chaque carte soit déjà quelque part dans sa boucle à
     l'arrivée sur la page, et non toutes au même point. */
  .pa-grid-anime > .pa-card:nth-child(5n+2)::before,
  .pa-grid-anime > .pa-card:nth-child(5n+2)::after { animation-delay: -1.8s; }
  .pa-grid-anime > .pa-card:nth-child(5n+3)::before,
  .pa-grid-anime > .pa-card:nth-child(5n+3)::after { animation-delay: -3.6s; }
  .pa-grid-anime > .pa-card:nth-child(5n+4)::before,
  .pa-grid-anime > .pa-card:nth-child(5n+4)::after { animation-delay: -5.4s; }
  .pa-grid-anime > .pa-card:nth-child(5n+5)::before,
  .pa-grid-anime > .pa-card:nth-child(5n+5)::after { animation-delay: -7.2s; }
}

/* ------------------------------------------------------------------
   Coupure générale

   Dernière règle du fichier, donc la plus forte à spécificité égale.

   Les voiles des cartes du catalogue n'y figurent pas, et n'en ont pas
   besoin : ils naissent à l'intérieur du `@media (prefers-reduced-motion:
   no-preference)` ci-dessus, donc sans `content` — ils n'existent pas du tout
   pour qui a demandé moins d'animations.
   ------------------------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
  .is-style-anim-fade,
  .is-style-anim-rise,
  .is-style-anim-side,
  .is-style-anim-reveal,
  .is-style-anim-zoom img,
  .is-style-anim-stagger > *,
  .is-style-anim-quick > *,
  .is-style-anim-parallax > img,
  .is-style-anim-parallax > picture > img,
  .is-style-anim-parallax .wp-block-image img,
  .is-style-anim-parallax .wp-block-cover__image-background {
    animation: none !important;
    transition: none !important;
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
  }
}
