/* ══════════════════════════════════════════════════════════════════════════════
   TRANSITIONS — sobriété assumée
   ══════════════════════════════════════════════════════════════════════════════

   CE QUI N'ALLAIT PAS
   ───────────────────
   L'ouverture d'un onglet jouait « fadeIn .45s » avec un déplacement de 14 px
   ET un zoom (scale .985). Trois défauts se cumulaient :

     · 450 ms, c'est LONG. Au-delà de ~250 ms, une transition cesse d'être
       perçue comme une réponse et devient une attente ;
     · 14 px de déplacement, c'est beaucoup pour un panneau plein écran :
       le contenu semble « tomber » à sa place ;
     · le zoom faisait respirer toute la page, et se cumulait au saut de
       défilement remis à zéro au même instant. D'où l'impression d'à-coup.

   LE PRINCIPE RETENU
   ──────────────────
   Une transition professionnelle ne se remarque pas : elle masque une
   rupture, elle ne l'annonce pas. Donc — court, discret, dirigé par
   l'opacité, sans zoom, sans rebond.

     · 200 ms pour l'entrée d'un panneau ou d'une page ;
     · 130 ms pour la sortie, toujours plus rapide que l'entrée : on ne fait
       pas attendre quelqu'un qui a déjà décidé de partir ;
     · 5 px de déplacement, juste de quoi suggérer une arrivée ;
     · une courbe qui démarre vite et s'arrête en douceur.

   ACCESSIBILITÉ
   ─────────────
   « prefers-reduced-motion » supprime tout mouvement. Ce n'est pas une
   politesse : les animations déclenchent nausées et migraines chez les
   personnes sujettes au mal des transports, et perturbent la lecture des
   élèves relevant du TDAH — public direct de cette plateforme.

   ⚠️ AUCUN « transform » SUR <body>.
      Un transform crée un bloc conteneur pour les enfants en
      « position: fixed » : boutons flottants et fenêtres modales se
      décaleraient pendant toute l'animation. L'opacité, elle, ne crée pas
      de bloc conteneur — c'est pourquoi la sortie de page ne joue que
      là-dessus.
   ══════════════════════════════════════════════════════════════════════════════ */

:root {
  --t-sortie: 130ms;
  --t-entree: 200ms;
  --t-reponse: 90ms;
  --t-courbe: cubic-bezier(.2, .8, .3, 1);
}

/* ── Arrivée sur une page ────────────────────────────────────────────────
   Portée par une animation CSS, sans JavaScript : si un script échoue, la
   page reste visible. Une page dont l'apparition dépendrait du JS serait
   une page blanche au premier pépin. */
@keyframes page-entree {
  from { opacity: 0; }
  to   { opacity: 1; }
}
body {
  animation: page-entree var(--t-entree) var(--t-courbe) both;
}

/* ── Départ vers une autre page ──────────────────────────────────────────
   Posée par js/transitions.js juste avant la navigation. Sans elle, le
   passage d'une page à l'autre est un à-coup blanc. */
body.pl-quitte {
  opacity: 0;
  transition: opacity var(--t-sortie) ease-in;
}

/* ── Ouverture d'un panneau d'onglet ─────────────────────────────────────
   Remplace « fadeIn .45s » avec zoom. Le sélecteur reprend la spécificité
   d'origine et neutralise l'ancienne animation. */
@keyframes onglet-entree {
  from { opacity: 0; transform: translateY(5px); }
  to   { opacity: 1; transform: none; }
}
.tab-content.active {
  animation: onglet-entree var(--t-entree) var(--t-courbe) both;
}

/* Marge respirée lors du « scrollIntoView » déclenché par switchTab.
   Sans elle, le panneau vient se coller au bord supérieur de la fenêtre :
   on ne voit plus ce qui précède, et rien ne dit d'où l'on arrive. */
.tab-content {
  scroll-margin-top: 24px;
}

/* ── Réponse au clic ─────────────────────────────────────────────────────
   Un enfoncement de 1,5 % : invisible consciemment, mais l'absence de tout
   retour donne l'impression que le clic n'a pas été pris en compte — c'est
   ce qui pousse à cliquer deux fois. */
.dashboard-card,
.gradient-btn,
.btn-primary {
  transition: transform var(--t-reponse) var(--t-courbe),
              box-shadow var(--t-entree) var(--t-courbe),
              opacity var(--t-reponse) linear;
}
.dashboard-card:active,
.gradient-btn:active,
.btn-primary:active {
  transform: scale(.985);
}

/* Une carte qui vient d'être cliquée et ouvre une page : on la laisse
   marquée le temps du fondu, pour que le regard sache d'où l'on part. */
.dashboard-card.pl-choisie {
  transform: scale(.985);
  opacity: .75;
}

/* ── Mouvement réduit : on coupe tout ────────────────────────────────────
   0.01 ms plutôt que « none » : les animations continuent d'émettre leur
   événement « animationend », donc rien de ce qui en dépend ne se bloque. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  body.pl-quitte { opacity: 1; }
}
