/* ==========================================================================
   Animations — Keyframes, Scroll animations, Transitions
   ========================================================================== */

/*
 * -------------------------------------------------------------------------
 *  INTRODUCTION POUR LE DÉBUTANT — CSS Animations vs CSS Transitions
 * -------------------------------------------------------------------------
 *
 *  En CSS, il y a DEUX façons d'animer des éléments :
 *
 *  1. LES TRANSITIONS (transition)
 *     → Réagissent à un CHANGEMENT D'ÉTAT (hover, ajout d'une classe, focus…).
 *     → Elles vont d'un état A à un état B, une seule fois, quand la propriété change.
 *     → Syntaxe : transition: propriété durée courbe-de-vitesse;
 *     → Exemple : quand on ajoute la classe .is-visible, l'opacité passe de 0 à 1.
 *
 *  2. LES ANIMATIONS (@keyframes + animation)
 *     → Jouent de manière AUTONOME, sans avoir besoin d'un changement d'état.
 *     → Peuvent boucler à l'infini (infinite) et avoir plusieurs étapes (0%, 25%, 50%…).
 *     → Syntaxe : animation: nom durée courbe-de-vitesse nombre-de-répétitions;
 *
 *  QUAND UTILISER QUOI ?
 *     • Transition → pour un hover, un focus, un changement de classe simple (A → B).
 *     • Animation  → pour un mouvement continu, un effet de boucle, ou un effet
 *                    avec plus de deux étapes intermédiaires.
 * -------------------------------------------------------------------------
 */


/* ---------- Morphing Photo Border Radius ---------- */

/*
 * @keyframes — Définir les étapes d'une animation
 * ------------------------------------------------
 * La règle @keyframes permet de décrire les étapes d'une animation en CSS.
 * On lui donne un NOM (ici "morphing") puis on définit l'état de l'élément
 * à différents pourcentages du temps total de l'animation :
 *   - 0%   = début de l'animation
 *   - 25%  = quart du chemin
 *   - 50%  = milieu
 *   - 75%  = trois-quarts
 *   - 100% = fin de l'animation
 *
 * ASTUCE : quand 0% et 100% sont identiques, l'animation boucle de manière
 * fluide — il n'y a pas de "saut" visible au moment où elle recommence.
 *
 * BORDER-RADIUS MORPHING — Comment ça marche ?
 * -----------------------------------------------
 * Normalement, border-radius prend une seule valeur (ex: 50% = cercle).
 * Mais on peut donner 8 valeurs séparées par un slash "/" :
 *
 *   border-radius: haut-gauche haut-droit bas-droit bas-gauche
 *                / haut-gauche haut-droit bas-droit bas-gauche ;
 *
 * Les 4 valeurs AVANT le "/" contrôlent les rayons horizontaux.
 * Les 4 valeurs APRÈS le "/" contrôlent les rayons verticaux.
 *
 * En faisant varier ces 8 valeurs d'une étape à l'autre, on crée des formes
 * organiques (comme un "blob") qui se déforment en douceur. C'est ce qui
 * donne l'effet de photo avec des bords qui "respirent".
 */
@keyframes morphing {
  0%   { border-radius: 30% 70% 70% 30% / 30% 30% 70% 70%; }
  25%  { border-radius: 58% 42% 75% 25% / 76% 46% 54% 24%; }
  50%  { border-radius: 50% 50% 33% 67% / 55% 27% 73% 45%; }
  75%  { border-radius: 33% 67% 58% 42% / 63% 68% 32% 37%; }
  100% { border-radius: 30% 70% 70% 30% / 30% 30% 70% 70%; }
}

/*
 * La propriété raccourcie "animation" — Syntaxe
 * ------------------------------------------------
 * animation: nom durée courbe-de-vitesse nombre-de-répétitions;
 *
 * Ici, on applique DEUX animations en même temps, séparées par une virgule :
 *
 *   1. morphing 8s ease-in-out infinite
 *      → Nom : morphing (défini au-dessus)
 *      → Durée : 8 secondes pour un cycle complet
 *      → ease-in-out : démarre doucement, accélère au milieu, ralentit à la fin
 *      → infinite : boucle sans jamais s'arrêter
 *
 *   2. glowPulse 3s ease-in-out infinite
 *      → Nom : glowPulse (défini plus bas)
 *      → Durée : 3 secondes
 *      → Même principe de boucle infinie
 *
 * On peut empiler autant d'animations qu'on veut avec des virgules.
 */
.hero__photo-wrapper {
  animation: morphing 8s ease-in-out infinite, glowPulse 3s ease-in-out infinite;
}

/* ---------- Glow Pulse ---------- */

/*
 * BOX-SHADOW pour créer un effet de lueur (glow)
 * ------------------------------------------------
 * box-shadow accepte plusieurs ombres séparées par des virgules.
 * Chaque ombre suit cette syntaxe :
 *
 *   box-shadow: décalage-X décalage-Y flou rayon-extension couleur;
 *
 * Ici, décalage-X et décalage-Y sont à 0 (l'ombre est centrée autour de
 * l'élément). Seul le "flou" (3ᵉ valeur) varie : 30px, 60px, 80px, 120px…
 *
 * En superposant plusieurs ombres avec des tailles de flou croissantes,
 * on obtient un halo lumineux réaliste — comme un néon qui brille.
 *
 * var(--accent-glow) est une variable CSS définie ailleurs (dans variables.css).
 * Cela permet de changer la couleur du glow à un seul endroit.
 *
 * L'animation alterne entre 2 et 3 ombres pour simuler une "pulsation" :
 *   - À 0% et 100% : 2 ombres (lueur discrète)
 *   - À 50% : 3 ombres (lueur intense, ajout d'une couche à 120px de flou)
 */
@keyframes glowPulse {
  0%, 100% { box-shadow: 0 0 30px var(--accent-glow), 0 0 60px var(--accent-glow); }
  50%      { box-shadow: 0 0 40px var(--accent-glow), 0 0 80px var(--accent-glow), 0 0 120px var(--accent-glow); }
}


/* ---------- Scroll Animations — Fade In ---------- */

/*
 * ANIMATIONS DE DÉFILEMENT — opacity et transform
 * ------------------------------------------------
 * Ces classes définissent l'état INITIAL (avant que l'élément soit visible).
 * L'élément commence invisible (opacity: 0) et légèrement décalé (transform).
 *
 * opacity : contrôle la transparence.
 *   → 0 = totalement invisible
 *   → 1 = totalement visible
 *
 * transform : déplace/déforme l'élément SANS affecter le flux de la page.
 *   → translateY(20px)  = décalé de 20px vers le BAS (axe Y, vertical)
 *   → translateX(-20px) = décalé de 20px vers la GAUCHE (axe X, horizontal)
 *   → translateX(20px)  = décalé de 20px vers la DROITE
 *
 * DIFFÉRENCE ENTRE translate, translateX et translateY :
 *   → translate(x, y)  = déplace sur les DEUX axes en même temps
 *   → translateX(valeur) = déplace UNIQUEMENT sur l'axe horizontal
 *   → translateY(valeur) = déplace UNIQUEMENT sur l'axe vertical
 *
 * TRANSITION : quand les propriétés opacity ou transform changent (grâce à
 * l'ajout de la classe .is-visible), le navigateur anime le passage de
 * l'ancienne valeur à la nouvelle en 600ms avec une courbe "ease".
 *
 * 600ms = 0,6 seconde — durée du fondu.
 * "ease" = courbe d'accélération par défaut (début lent, accélération, fin lente).
 *
 * NOTE : On utilise ici des TRANSITIONS (pas des @keyframes) car on a un
 * simple changement d'état A → B déclenché par JavaScript.
 */
.fade-in-up {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 600ms ease, transform 600ms ease;
}

.fade-in-left {
  opacity: 0;
  transform: translateX(-20px);
  transition: opacity 600ms ease, transform 600ms ease;
}

.fade-in-right {
  opacity: 0;
  transform: translateX(20px);
  transition: opacity 600ms ease, transform 600ms ease;
}

/*
 * LA CLASSE .is-visible — Ajoutée par l'IntersectionObserver (JavaScript)
 * -----------------------------------------------------------------------
 * En JavaScript, l'IntersectionObserver surveille quand un élément entre dans
 * la zone visible de l'écran (le "viewport"). Dès qu'un élément avec la classe
 * .fade-in-up, .fade-in-left ou .fade-in-right entre dans le viewport,
 * le script JS lui ajoute la classe .is-visible.
 *
 * Quand .is-visible est ajoutée :
 *   → opacity passe de 0 à 1 (l'élément apparaît)
 *   → transform passe de translateY(20px) / translateX(…) à translate(0, 0)
 *     (l'élément revient à sa position normale)
 *
 * Comme on a défini une transition (plus haut), ce changement est ANIMÉ
 * automatiquement — le navigateur interpole entre les deux états en 600ms.
 *
 * translate(0, 0) remet l'élément à sa position d'origine sur les deux axes.
 */
.fade-in-up.is-visible,
.fade-in-left.is-visible,
.fade-in-right.is-visible {
  opacity: 1;
  transform: translate(0, 0);
}

/* ---------- Stagger Delay Utilities ---------- */

/*
 * CLASSES UTILITAIRES DE DÉLAI — Effet "en cascade" (stagger)
 * ------------------------------------------------------------
 * Quand plusieurs éléments apparaissent en même temps (par exemple, une liste
 * de cartes), on veut souvent qu'ils n'apparaissent pas TOUS d'un coup, mais
 * un par un, avec un léger décalage. C'est l'effet "stagger" (échelonnement).
 *
 * transition-delay : retarde le DÉBUT de la transition.
 *   → delay-1 : attend 100ms avant de commencer la transition
 *   → delay-2 : attend 200ms
 *   → delay-3 : attend 300ms
 *   → delay-4 : attend 400ms
 *
 * UTILISATION EN HTML :
 *   <div class="fade-in-up delay-1">Premier élément (apparaît en premier)</div>
 *   <div class="fade-in-up delay-2">Deuxième élément (100ms plus tard)</div>
 *   <div class="fade-in-up delay-3">Troisième élément (200ms plus tard)</div>
 *
 * Résultat : les éléments apparaissent les uns après les autres, ce qui donne
 * un effet visuel élégant et professionnel.
 */
.delay-1 { transition-delay: 100ms; }
.delay-2 { transition-delay: 200ms; }
.delay-3 { transition-delay: 300ms; }
.delay-4 { transition-delay: 400ms; }

/* ---------- Preloader Animation ---------- */

/*
 * ANIMATION DU PRÉCHARGEUR (Preloader)
 * --------------------------------------
 * Le preloader est l'écran de chargement affiché pendant que la page se charge.
 * Son logo pulse doucement pour indiquer à l'utilisateur que quelque chose
 * se passe (retour visuel = bonne UX).
 *
 * Cette animation combine :
 *   → opacity : alterne entre 0.5 (semi-transparent) et 1 (plein)
 *   → scale : alterne entre 0.95 (légèrement rétréci) et 1 (taille normale)
 *
 * scale() fait partie des fonctions de transform. Contrairement à changer
 * width/height, scale() est optimisé par le GPU du navigateur — c'est plus
 * performant et plus fluide.
 *
 * Durée : 1.5 secondes par cycle, boucle infinie.
 */
@keyframes preloaderPulse {
  0%, 100% { opacity: 0.5; transform: scale(0.95); }
  50%      { opacity: 1;   transform: scale(1); }
}

.preloader__logo {
  animation: preloaderPulse 1.5s ease-in-out infinite;
}

/*
 * animation: none — Arrêter une animation
 * -----------------------------------------
 * Quand le preloader est masqué (classe .is-hidden ajoutée par JS après le
 * chargement de la page), on STOPPE l'animation avec "animation: none".
 *
 * Pourquoi ? Même si l'élément est caché visuellement (display: none ou
 * opacity: 0), une animation CSS continue de tourner en arrière-plan et
 * consomme des ressources CPU/GPU. "animation: none" libère ces ressources.
 */
.preloader.is-hidden .preloader__logo {
  animation: none;
}

/* ---------- Reduced Motion ---------- */

/*
 * @media (prefers-reduced-motion: reduce) — ACCESSIBILITÉ (WCAG)
 * ----------------------------------------------------------------
 * Certaines personnes sont sensibles aux mouvements sur écran (troubles
 * vestibulaires, épilepsie, migraines, etc.). Leur système d'exploitation
 * propose un réglage "Réduire les animations" :
 *   → Windows : Paramètres > Accessibilité > Effets visuels > Effets d'animation
 *   → macOS : Préférences Système > Accessibilité > Affichage > Réduire les animations
 *   → iOS/Android : réglages similaires dans Accessibilité
 *
 * La media query @media (prefers-reduced-motion: reduce) détecte ce réglage.
 * Quand il est activé, on DÉSACTIVE toutes les animations et transitions
 * pour respecter le choix de l'utilisateur.
 *
 * C'est une exigence WCAG 2.1 (critère 2.3.3) — les sites web accessibles
 * DOIVENT respecter cette préférence.
 *
 * POURQUOI !important EST JUSTIFIÉ ICI :
 * ----------------------------------------
 * En général, !important est déconseillé car il casse la cascade CSS et
 * rend le code difficile à maintenir. MAIS ici, c'est l'un des rares cas
 * où !important est LÉGITIME :
 *
 *   → On veut GARANTIR que les animations sont désactivées, peu importe
 *     la spécificité des autres règles CSS du site.
 *   → C'est une question d'accessibilité et de santé — la sécurité de
 *     l'utilisateur prime sur l'esthétique.
 *   → Les !important dans les media queries d'accessibilité sont une
 *     pratique recommandée par la communauté CSS.
 *
 * animation-duration: 0.01ms (et non 0ms) :
 *   → On utilise 0.01ms au lieu de 0ms pour que les événements JavaScript
 *     "animationend" et "transitionend" se déclenchent quand même.
 *     Avec 0ms, certains navigateurs ne déclenchent pas ces événements,
 *     ce qui peut casser la logique JS qui dépend de la fin d'une animation.
 *
 * animation-iteration-count: 1 :
 *   → Force les animations à ne jouer qu'une seule fois (pas de boucle).
 *
 * scroll-behavior: auto :
 *   → Désactive le défilement fluide (smooth scrolling) pour que les sauts
 *     de page soient instantanés — moins de mouvement = plus de confort.
 */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  /*
   * On rend directement visibles les éléments qui devaient apparaître au scroll.
   * Sans cela, ils resteraient invisibles (opacity: 0) pour les utilisateurs
   * qui ont désactivé les animations — ils ne verraient jamais le contenu !
   *
   * transition: none supprime aussi la transition pour ces éléments,
   * en complément du sélecteur universel * ci-dessus (double sécurité).
   */
  .fade-in-up,
  .fade-in-left,
  .fade-in-right {
    opacity: 1;
    transform: none;
    transition: none;
  }

  /*
   * On remet les délais à 0 pour que rien ne reste "bloqué" en attente.
   * !important garantit que ces délais sont bien écrasés, même si une
   * règle plus spécifique avait défini un transition-delay.
   */
  .delay-1,
  .delay-2,
  .delay-3,
  .delay-4 {
    transition-delay: 0ms !important;
  }

  /*
   * On stoppe l'animation de morphing et on donne un border-radius: 50%
   * pour que la photo reste un cercle parfait (forme statique propre).
   */
  .hero__photo-wrapper {
    animation: none;
    border-radius: 50%;
  }

  /*
   * On masque le canvas de fond animé (particules, etc.) car il génère
   * du mouvement continu qui pourrait gêner l'utilisateur.
   */
  #hero-canvas {
    display: none;
  }
}
