/*
 * app/assets/animations.css — v1.0 (2026-05-18)
 * Quiz CQC 2026 — Accademia del Conducente
 * ============================================================
 * Libreria animazioni in-app. Estende app.css / quiz.css.
 * DEVE essere caricato DOPO app.css.
 *
 * Principi:
 *   - Solo `transform` e `opacity` (accelerate dalla GPU su WebView iOS).
 *   - Niente animazioni su width/height/top/left (causano scatti).
 *   - Tutto rispetta prefers-reduced-motion (vedi blocco finale).
 *   - Le classi si AGGIUNGONO ai componenti esistenti: nessuna
 *     modifica strutturale all'HTML richiesta.
 * ============================================================
 */

/* ============================================================
   0. TOKEN DI TIMING — coerenti con quelli già in uso
   ============================================================ */
:root {
  --ease-out:    cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --ease-soft:   cubic-bezier(0.4, 0, 0.2, 1);
  --t-fast:   0.18s;
  --t-base:   0.32s;
  --t-slow:   0.5s;
}

/* ============================================================
   1. TRANSIZIONI DI PAGINA / NAVIGAZIONE
   ------------------------------------------------------------
   Da applicare al primo contenitore della pagina (.app-shell,
   .quiz-page, .landing, .risultato-page).
   La classe `page-enter` parte automaticamente al load.
   Le classi direzionali servono per le transizioni tra schermate
   gestite via JS (vedi ANIMAZIONI-GUIDA.md).
   ============================================================ */

/* entrata standard di una pagina (fade + lieve salita) */
.page-enter {
  animation: pageEnter var(--t-base) var(--ease-out) both;
}
@keyframes pageEnter {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* transizioni direzionali (navigazione avanti/indietro) */
.page-in-right  { animation: pageInRight  var(--t-base) var(--ease-out) both; }
.page-out-left  { animation: pageOutLeft  var(--t-base) var(--ease-out) both; }
.page-in-left   { animation: pageInLeft   var(--t-base) var(--ease-out) both; }
.page-out-right { animation: pageOutRight var(--t-base) var(--ease-out) both; }

@keyframes pageInRight  { from{opacity:0;transform:translateX(28px)}  to{opacity:1;transform:translateX(0)} }
@keyframes pageOutLeft  { from{opacity:1;transform:translateX(0)}     to{opacity:0;transform:translateX(-28px)} }
@keyframes pageInLeft   { from{opacity:0;transform:translateX(-28px)} to{opacity:1;transform:translateX(0)} }
@keyframes pageOutRight { from{opacity:1;transform:translateX(0)}     to{opacity:0;transform:translateX(28px)} }

/* transizione di una nuova DOMANDA del quiz (sostituisce fade-up
   secco con un movimento più morbido e direzionale) */
.q-swap-in  { animation: qSwapIn  var(--t-base) var(--ease-out) both; }
.q-swap-out { animation: qSwapOut var(--t-fast) var(--ease-soft) both; }
@keyframes qSwapIn {
  from { opacity: 0; transform: translateX(24px); }
  to   { opacity: 1; transform: translateX(0); }
}
@keyframes qSwapOut {
  from { opacity: 1; transform: translateX(0); }
  to   { opacity: 0; transform: translateX(-24px); }
}

/* ============================================================
   2. ENTRATA STAGGERED DI LISTE
   ------------------------------------------------------------
   Aggiungi `.stagger` al contenitore (.cap-grid, .kpi-grid,
   .risultato-body, lista sessioni…). I figli entrano in cascata.
   Funziona fino a 12 elementi; oltre, ripartono da capo (ok).
   ============================================================ */
.stagger > * {
  animation: itemRise var(--t-base) var(--ease-out) both;
}
@keyframes itemRise {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: translateY(0); }
}
.stagger > *:nth-child(1)  { animation-delay: 0.03s; }
.stagger > *:nth-child(2)  { animation-delay: 0.07s; }
.stagger > *:nth-child(3)  { animation-delay: 0.11s; }
.stagger > *:nth-child(4)  { animation-delay: 0.15s; }
.stagger > *:nth-child(5)  { animation-delay: 0.19s; }
.stagger > *:nth-child(6)  { animation-delay: 0.23s; }
.stagger > *:nth-child(7)  { animation-delay: 0.27s; }
.stagger > *:nth-child(8)  { animation-delay: 0.31s; }
.stagger > *:nth-child(9)  { animation-delay: 0.35s; }
.stagger > *:nth-child(10) { animation-delay: 0.39s; }
.stagger > *:nth-child(11) { animation-delay: 0.43s; }
.stagger > *:nth-child(12) { animation-delay: 0.47s; }

/* ============================================================
   3. FEEDBACK QUIZ — risposta corretta / errata
   ------------------------------------------------------------
   Le classi .is-selected-correct / .is-selected-wrong /
   .is-correct-highlight ESISTONO GIÀ in quiz.css: qui aggiungo
   SOLO il movimento, agganciandomi a quelle stesse classi.
   Nessuna modifica al JS necessaria per questo blocco.
   ============================================================ */

/* risposta giusta: piccolo "pop" elastico */
.quiz-answer.is-selected-correct {
  animation: answerPop var(--t-slow) var(--ease-spring) both;
}
@keyframes answerPop {
  0%   { transform: scale(1); }
  40%  { transform: scale(1.045); }
  100% { transform: scale(1); }
}

/* risposta sbagliata: shake orizzontale secco */
.quiz-answer.is-selected-wrong {
  animation: answerShake 0.42s var(--ease-out) both;
}
@keyframes answerShake {
  0%, 100% { transform: translateX(0); }
  18%      { transform: translateX(-8px); }
  36%      { transform: translateX(7px); }
  54%      { transform: translateX(-5px); }
  72%      { transform: translateX(3px); }
  88%      { transform: translateX(-1px); }
}

/* la risposta corretta evidenziata "dopo l'errore": entra in dolcezza */
.quiz-answer.is-correct-highlight {
  animation: highlightFade var(--t-base) var(--ease-out) 0.12s both;
}
@keyframes highlightFade {
  from { opacity: 0.4; }
  to   { opacity: 0.85; }
}

/* il box di feedback (esito + soluzione) sale da sotto */
.quiz-feedback {
  animation: feedbackRise var(--t-base) var(--ease-spring) both;
}
@keyframes feedbackRise {
  from { opacity: 0; transform: translateY(16px) scale(0.98); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

/* icona dentro la risposta scelta: micro "pulse" che attira l'occhio */
.quiz-answer.is-selected-correct .quiz-answer__icon,
.quiz-answer.is-selected-wrong   .quiz-answer__icon {
  animation: iconPulse 0.45s var(--ease-spring) 0.05s both;
}
@keyframes iconPulse {
  0%   { transform: scale(0.4); opacity: 0; }
  60%  { transform: scale(1.2); opacity: 1; }
  100% { transform: scale(1); }
}

/* la barra di avanzamento ESISTE già con transition su width;
   qui aggiungo un lampo di luce quando avanza */
.quiz-progress__bar-fill.is-advancing::before {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(255, 255, 255, 0.55);
  animation: barFlash 0.5s var(--ease-out) both;
}
@keyframes barFlash {
  from { opacity: 0.6; }
  to   { opacity: 0; }
}

/* ============================================================
   4. LOADER / SPINNER / SKELETON
   ------------------------------------------------------------
   `spin` e `skeleton-pulse` esistono già. Qui aggiungo varianti
   più ricche per i diversi contesti di caricamento.
   ============================================================ */

/* --- spinner a tre puntini (azioni brevi: invio risposta) --- */
.dot-loader {
  display: inline-flex;
  gap: 6px;
  align-items: center;
  vertical-align: middle;
}
.dot-loader span {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: currentColor;
  animation: dotBounce 1.1s var(--ease-out) infinite;
}
.dot-loader span:nth-child(2) { animation-delay: 0.15s; }
.dot-loader span:nth-child(3) { animation-delay: 0.30s; }
@keyframes dotBounce {
  0%, 80%, 100% { transform: scale(0.5); opacity: 0.4; }
  40%           { transform: scale(1);   opacity: 1; }
}

/* --- barra indeterminata (caricamento sessione/statistiche) --- */
.bar-loader {
  width: 100%;
  height: 6px;
  border-radius: var(--r-pill);
  background: var(--border-soft);
  overflow: hidden;
}
.bar-loader::before {
  content: "";
  display: block;
  height: 100%;
  width: 40%;
  border-radius: var(--r-pill);
  background: var(--teal);
  animation: barIndeterminate 1.15s var(--ease-soft) infinite;
}
@keyframes barIndeterminate {
  from { transform: translateX(-110%); }
  to   { transform: translateX(330%); }
}

/* --- skeleton con SHIMMER (sostituisce/affianca skeleton-pulse) ---
   Più moderno del pulse: un riflesso scorre sull'elemento.
   Usa .skeleton-shine al posto/oltre a .skeleton */
.skeleton-shine {
  position: relative;
  overflow: hidden;
  background: var(--surface-alt);
  border-radius: var(--r-sm);
  display: block;
}
.skeleton-shine::after {
  content: "";
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(
    90deg,
    transparent,
    rgba(255, 255, 255, 0.65),
    transparent
  );
  animation: shimmer 1.4s var(--ease-soft) infinite;
}
@keyframes shimmer {
  to { transform: translateX(100%); }
}

/* --- pulsazione del logo nello splash (index.html) --- */
.splash__logo {
  animation: splashPulse 1.6s var(--ease-soft) infinite alternate !important;
}
@keyframes splashPulse {
  from { transform: scale(1);    box-shadow: 0 8px 0 rgba(0,0,0,0.2); }
  to   { transform: scale(1.06); box-shadow: 0 12px 0 rgba(0,0,0,0.25); }
}

/* ============================================================
   5. MICRO-INTERAZIONI
   ============================================================ */

/* --- pressione generica su elementi tappabili ---
   Aggiungi `.tappable`: dà un feedback tattile di scala al tocco.
   (I bottoni Duolingo-style hanno già il loro :active; questa
    classe serve per card/elementi che NON ce l'hanno.) */
.tappable {
  transition: transform var(--t-fast) var(--ease-out);
  -webkit-tap-highlight-color: transparent;
}
.tappable:active { transform: scale(0.97); }

/* --- entrata di un badge / contatore (es. cestino ripasso) ---
   Aggiungi `.badge-bump` via JS ogni volta che il numero cambia.
   Ricorda di rimuoverla e riaggiungerla per ri-triggerare
   (vedi snippet nella guida). */
.badge-bump { animation: badgeBump 0.42s var(--ease-spring); }
@keyframes badgeBump {
  0%   { transform: scale(0.3); }
  55%  { transform: scale(1.28); }
  100% { transform: scale(1); }
}

/* --- comparsa di un badge da zero (peek-badge "spiegazione consultata") --- */
.badge-appear { animation: badgeAppear var(--t-base) var(--ease-spring) both; }
@keyframes badgeAppear {
  from { opacity: 0; transform: scale(0) translateY(4px); }
  to   { opacity: 1; transform: scale(1) translateY(0); }
}

/* --- toggle / switch (es. font DSA): knob già animato in app.js?
   Questo è per uno switch generico con .switch-knob --- */
.switch-knob {
  transition: transform 0.26s var(--ease-spring);
}

/* --- pulsazione "richiamo" su un bottone importante ---
   Es. il bottone "Continua" della home, o "Conferma".
   Aggiungi `.pulse-cta`: un alone che pulsa con calma. */
.pulse-cta { position: relative; }
.pulse-cta::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: 0 0 0 0 var(--teal);
  animation: ctaPulse 2.2s var(--ease-out) infinite;
  pointer-events: none;
}
@keyframes ctaPulse {
  0%   { box-shadow: 0 0 0 0 rgba(20, 184, 166, 0.45); }
  70%  { box-shadow: 0 0 0 14px rgba(20, 184, 166, 0); }
  100% { box-shadow: 0 0 0 0 rgba(20, 184, 166, 0); }
}

/* --- "check" che si disegna (es. capitolo/modulo completato) ---
   Applica a un <path> SVG; aggiungi `.draw-check` per triggerare. */
.draw-check {
  stroke-dasharray: 28;
  stroke-dashoffset: 28;
  animation: drawCheck var(--t-base) var(--ease-out) 0.05s forwards;
}
@keyframes drawCheck {
  to { stroke-dashoffset: 0; }
}

/* --- conteggio numerico che "sale" (KPI / statistiche) ---
   Effetto visivo di comparsa; il conteggio vero va fatto in JS
   (snippet `animaNumero` nella guida). Questa classe dà solo
   l'entrata del valore. */
.kpi__value.count-in,
.risultato-stat__value.count-in {
  animation: countIn var(--t-slow) var(--ease-spring) both;
}
@keyframes countIn {
  from { opacity: 0; transform: translateY(8px) scale(0.9); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

/* --- riga di statistiche / KPI che entra alla comparsa --- */
.reveal {
  animation: reveal var(--t-base) var(--ease-out) both;
}
@keyframes reveal {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* --- "shake" di errore per input (es. PIN errato al login) ---
   Aggiungi `.input-error-shake` all'input; rimuovi/riaggiungi
   per ri-triggerare. */
.input-error-shake { animation: answerShake 0.42s var(--ease-out) both; }

/* --- coriandoli/celebrazione leggera sull'esito positivo ---
   Tre "scintille" che salgono dalla emoji del risultato.
   Applica `.celebrate` al contenitore .risultato-hero--success. */
.celebrate { position: relative; overflow: hidden; }
.celebrate::before,
.celebrate::after {
  content: "";
  position: absolute;
  top: 40%;
  width: 8px; height: 8px;
  border-radius: 2px;
  opacity: 0;
}
.celebrate::before {
  left: 28%;
  background: var(--yellow);
  animation: sparkUp 1.1s var(--ease-out) 0.3s;
}
.celebrate::after {
  right: 28%;
  background: #fff;
  animation: sparkUp 1.1s var(--ease-out) 0.5s;
}
@keyframes sparkUp {
  0%   { opacity: 0; transform: translateY(0) scale(0.5) rotate(0); }
  30%  { opacity: 1; }
  100% { opacity: 0; transform: translateY(-90px) scale(1) rotate(160deg); }
}

/* --- transizione fluida del bottom-nav attivo --- */
.bottom-nav__item svg {
  transition: transform var(--t-fast) var(--ease-spring);
}
.bottom-nav__item.is-active svg {
  transform: translateY(-2px) scale(1.08);
}

/* --- highlight di una card appena toccata (es. capitolo scelto) ---
   Aggiungi `.just-picked` prima di navigare via. */
.just-picked { animation: justPicked var(--t-base) var(--ease-out) both; }
@keyframes justPicked {
  0%   { transform: scale(1); }
  45%  { transform: scale(0.96); }
  100% { transform: scale(1); }
}

/* ============================================================
   6. ACCESSIBILITÀ — rispetta le impostazioni di sistema
   ------------------------------------------------------------
   Se l'utente ha "Riduci movimento" attivo (iOS: Impostazioni >
   Accessibilità > Movimento), tutte le animazioni vengono
   praticamente azzerate ma i contenuti restano visibili.
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  /* gli elementi che entrano con opacity:0 devono restare visibili */
  .page-enter, .stagger > *, .quiz-feedback,
  .reveal, .badge-appear, .count-in,
  .kpi__value.count-in, .risultato-stat__value.count-in {
    opacity: 1 !important;
    transform: none !important;
  }
}
