/* animations.css — Sistema di ingresso e scroll-reveal.
   PORTATO DA agriravagnolo (2026-08-06), dove funziona, con i selettori di
   questo sito. Le tre differenze che contano rispetto alla versione precedente:

   1. ANIMATION, NON TRANSITION. Una transizione CSS non parte sul primo
      rendering di un elemento — non esiste uno stato «prima» da cui
      interpolare — e su una pagina con molti CSS bloccanti quel caso si
      verificava sempre: il contenuto compariva già a posto. Un'animazione con
      `both` parte comunque.

   2. L'HERO NON PASSA DAL MOTORE JS. È above-the-fold, e il JS gira dopo il
      parse: qualunque `opacity:0` pilotato da lì o dà un flash (visibile →
      nascosto → riappare) o si consuma durante il «paint holding» di Chrome,
      che continua a mostrare la pagina VECCHIA finché la nuova non è pronta.
      Questo foglio invece è render-blocking: l'animazione dell'hero è già
      attiva al primo paint, quindi la vedi sempre, anche cambiando pagina.

   3. FAIL-VISIBLE. Il pre-stato `opacity:0` del motore vive dietro
      `html.js-reveal`, classe che il JS aggiunge solo se IntersectionObserver
      esiste e reduced-motion è spento. Senza JS, con JS in errore o con
      reduced-motion attivo, non è mai nascosto niente.

   L'attributo `data-ar-reveal` viene RIMOSSO a fine animazione: l'elemento
   torna nudo e nessun `animation: … both` residuo sovrascrive le transizioni
   di hover delle card. */

:root {
  --ar-dur: .65s;                          /* durata base dell'ingresso */
  --ar-dur-quick: .28s;                    /* re-render: solo dissolvenza */
  --ar-hero-dur: 1.25s;                    /* scala dell'immagine hero */
  --ar-ease: cubic-bezier(.22,.61,.36,1);
  --ar-shift: 30px;                        /* spostamento di default */
  --ar-stagger: 65ms;                      /* passo fra elementi di un gruppo */
}

/* ============================================================
   Motore di reveal allo scroll — pilotato da static/js/animations.js
   ============================================================ */
html.js-reveal [data-ar-reveal] { opacity: 0; }
html.js-reveal [data-ar-reveal].is-revealing {
  animation: ar-reveal var(--ar-dur) var(--ar-ease) both;
  animation-delay: calc(var(--ar-i, 0) * var(--ar-stagger));
}
@keyframes ar-reveal {
  from { opacity: 0; transform: translate3d(0, var(--ar-shift), 0); }
  to   { opacity: 1; transform: none; }
}

/* Ruolo gerarchico — scritto dal JS come VALORE di data-ar-reveal. Nessun
   keyframe nuovo: `ar-reveal` legge già var(--ar-shift), quindi basta
   ridefinirla e la stessa animazione cambia ampiezza.

   Il criterio è la PERCEZIONE, non la simmetria: il titolo è l'elemento più
   grande e più guardato, quindi è il PIÙ mosso e il più lento — apre la fascia
   e si deve vedere che la apre. Le CTA restano brevi: su un elemento piccolo
   un movimento ampio legge come un sussulto. */
html.js-reveal [data-ar-reveal="head"]  { --ar-shift: 46px; }
html.js-reveal [data-ar-reveal="media"] { --ar-shift: 26px; }
html.js-reveal [data-ar-reveal="cta"]   { --ar-shift: 14px; }
html.js-reveal [data-ar-reveal="head"].is-revealing {
  animation-duration: calc(var(--ar-dur) * 1.2);
}

/* Ri-disegno di una griglia già dipinta (il binder che sostituisce il fallback
   statico, un filtro, un pager). I nodi sono NUOVI, quindi il motore li
   rivelerebbe in cascata piena: far sfilare venti card a ogni interazione è un
   ostacolo, non un piacere. Dissolvenza secca, nessun ritardo. */
html.js-reveal [data-ar-reveal="quick"].is-revealing {
  animation: ar-fade var(--ar-dur-quick) var(--ar-ease) both;
  animation-delay: 0s;
}
@keyframes ar-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* Ridondanza voluta: il gate primario è in JS (js-reveal non viene nemmeno
   aggiunta). Questo copre chi attiva reduced-motion a pagina già caricata,
   prima che il listener 'change' rimuova la classe. */
@media (prefers-reduced-motion: reduce) {
  html.js-reveal [data-ar-reveal],
  html.js-reveal [data-ar-reveal].is-revealing {
    opacity: 1;
    animation: none;
  }
}

/* ============================================================
   HERO — animazione d'ingresso, CSS PURA (non passa dal motore)
   ============================================================
   `.hero` e `.sub-hero` restano nella lista di esclusione del JS. Fail-visible
   grazie a `both` su una base `opacity: 1`: se il motore CSS fosse disattivato
   l'elemento resta visibile.

   L'IMMAGINE SCALA MA NON SFUMA, ed è deliberato: la misura LCP di Google
   ignora gli elementi a `opacity: 0` — un fade sposterebbe in avanti l'istante
   misurato, e l'hero è quasi sempre L'elemento LCP — mentre non squalifica
   quelli trasformati. La scala dà lo stesso «assestamento» senza costare
   posizionamento. Per lo stesso motivo il titolo ha ritardo ZERO. */
@media (prefers-reduced-motion: no-preference) {
  .hero .hero__bg,
  .sub-hero .sub-hero__bg {
    animation: ar-hero-img var(--ar-hero-dur) var(--ar-ease) both;
  }

  .hero__headline,
  .sub-hero__title,
  .hero__subtitle,
  .hero__tagline,
  .hero__cta-box,
  .sub-hero .btn-pill {
    animation: ar-reveal var(--ar-dur) var(--ar-ease) both;
  }

  /* Il titolo: il più mosso e il più lento. Ritardo zero — sulle pagine
     interne l'h1 è spesso l'elemento LCP, e ogni ms di ritardo è un ms di LCP. */
  .hero__headline,
  .sub-hero__title {
    --ar-shift: 46px;
    animation-delay: 0s;
    animation-duration: calc(var(--ar-dur) * 1.2);
  }
  .hero__subtitle,
  .hero__tagline                  { animation-delay: 90ms; }
  .hero__cta-box,
  .sub-hero .btn-pill             { --ar-shift: 14px; animation-delay: 180ms; }
}
@keyframes ar-hero-img {
  from { transform: scale(1.08); }
  to   { transform: none; }
}

/* ===== Skeleton placeholder (anti-flash: shell senza dati finti) =====
   Usato dai contenitori [data-news-list] in attesa che il binder backend_sites
   inietti gli articoli reali. Box + righe grigie; shimmer solo se reduced-motion OFF. */
.skeleton-box,
.skeleton-line {
  position: relative;
  overflow: hidden;
  background: #e9ede9;
  border-radius: 8px;
}
.skeleton-line {
  display: block;
  height: 0.85em;
  margin: 0.6em 0;
}
.skeleton-line--title { height: 1.25em; width: 80%; }
.skeleton-line--short { width: 45%; }
.is-skeleton { pointer-events: none; }

@media (prefers-reduced-motion: no-preference) {
  .skeleton-box::after,
  .skeleton-line::after {
    content: "";
    position: absolute;
    inset: 0;
    transform: translateX(-100%);
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.65), transparent);
    animation: skeleton-shimmer 1.4s ease-in-out infinite;
  }
  @keyframes skeleton-shimmer {
    100% { transform: translateX(100%); }
  }
}
