/* ================================================================
   ReaLink - MOTION SYSTEM (css)
   File nuovo, autonomo. Va caricato DOPO css/style.css.
   Non ridefinisce colori, font o componenti: solo movimento.

   Tutte le classi hanno prefisso "rl-" per non entrare in conflitto
   con il sistema gia presente in style.css / main.js
   (.reveal, .stagger, .pop-in, .card-tilt, .scene-3d, [data-parallax],
   [data-count], [data-fill] restano intatti e continuano a funzionare).

   REGOLA DI SICUREZZA
   Gli stati iniziali "nascosti" sono attivi SOLO sotto .rl-js, classe
   che js/motion.js aggiunge a <html>. Se il JS non parte, o va in
   errore prima di partire, i contenuti restano visibili e leggibili.

   INDICE
   00. Token di movimento
   01. Gate .rl-js + reduced motion
   02. Smooth scroll (stato del documento)
   03. Reveal allo scroll (up / left / right / scale / fade) + stagger
   04. Parallax a strati
   05. Pseudo 3D (prospettiva, raddrizzamento mockup, tilt)
   06. Numeri che salgono
   07. Testo a comparsa per i titoli
   08. Sticky storytelling
   09. Utility
   10. Mobile
   ================================================================ */

/* ================================================================
   00. TOKEN DI MOVIMENTO
   Solo tempi, curve e distanze. Nessun colore nuovo.
   ================================================================ */
:root {
  /* Curve. Coerenti con --t-base di style.css (.22,.61,.36,1) */
  --rl-ease:        cubic-bezier(.22, .61, .36, 1);   /* uscita morbida, uso generale */
  --rl-ease-soft:   cubic-bezier(.16, 1, .3, 1);      /* uscita molto lunga, per i sigilli */
  --rl-ease-in-out: cubic-bezier(.65, 0, .35, 1);     /* andata e ritorno */

  /* Durate */
  --rl-dur-fast: 380ms;
  --rl-dur:      680ms;
  --rl-dur-slow: 980ms;

  /* Distanze di partenza dei reveal */
  --rl-dist-y: 34px;   /* comparsa dal basso */
  --rl-dist-x: 46px;   /* comparsa laterale */
  --rl-scale:  .94;    /* comparsa in scala */

  /* Passo dello sfalsamento (stagger) tra elementi di un gruppo */
  --rl-stagger-step: 90ms;

  /* Prospettiva di default delle scene pseudo 3D */
  --rl-perspective: 1400px;

  /* Altezza di default di una sezione sticky storytelling */
  --rl-sticky-length: 300vh;
  --rl-sticky-top: 0px;
}

/* ================================================================
   01. GATE .rl-js + .rl-armed
   .rl-js   viene messo su <html> da js/motion.js: da quel momento
            valgono gli stati iniziali (elementi nascosti).
   .rl-armed viene messo subito dopo, ma solo dopo un ricalcolo di
            stile forzato. Serve a questo: gli stati iniziali entrano
            in vigore SENZA transizione (nessuna dissolvenza al
            contrario dei contenuti gia dipinti), e solo da li in poi
            le transizioni sono attive per l'entrata vera.
   Senza JS nessuna regola di questo file nasconde nulla.
   ================================================================ */

/* Nessuno stato iniziale fuori da .rl-js: e voluto. */

/* ================================================================
   02. SMOOTH SCROLL - stato del documento
   .rl-smooth viene messo su <html> da motion.js solo quando lo
   smooth scroll a inerzia e realmente attivo (desktop, puntatore
   fine, motion non ridotto). In quel caso lo scroll nativo "smooth"
   di style.css va spento, altrimenti le due animazioni si combattono:
   gli anchor interni li gestisce motion.js con la stessa inerzia.
   ================================================================ */
html.rl-smooth { scroll-behavior: auto; }

/* Durante il trascinamento inerziale evitiamo che il testo venga
   selezionato per sbaglio dal gesto del trackpad. */
html.rl-smooth.rl-scrolling body { -webkit-user-select: none; user-select: none; }

/* ================================================================
   03. REVEAL ALLO SCROLL
   Uso: <div class="rl-reveal">  oppure  data-rl-reveal="left"
   Varianti: up (default) | left | right | scale | fade
   Modificatori: .rl-reveal-slow, .rl-reveal-fast
   Lo stato finale e la classe .rl-in, aggiunta da motion.js quando
   l'elemento entra nel viewport (IntersectionObserver).
   ================================================================ */

/* Stato iniziale comune a tutte le varianti. Il transform e uno solo,
   parametrico: le varianti cambiano solo le variabili di partenza.
   Qui nessuna transizione: lo stato iniziale deve arrivare secco. */
.rl-js .rl-reveal,
.rl-js [data-rl-reveal] {
  opacity: 0;
  transform:
    translate3d(var(--rl-from-x, 0px), var(--rl-from-y, var(--rl-dist-y)), 0)
    scale(var(--rl-from-s, 1));
  transition: none;
  will-change: transform, opacity;
}

/* Transizioni attive solo dopo l'armamento (vedi punto 01). */
.rl-js.rl-armed .rl-reveal,
.rl-js.rl-armed [data-rl-reveal] {
  transition:
    opacity   var(--rl-dur) var(--rl-ease) var(--rl-delay, 0ms),
    transform var(--rl-dur) var(--rl-ease) var(--rl-delay, 0ms);
}

/* Stato finale: elemento al suo posto naturale. */
.rl-js .rl-reveal.rl-in,
.rl-js [data-rl-reveal].rl-in {
  opacity: 1;
  transform: none;
}

/* Variante: dal basso (default esplicito) */
.rl-js .rl-reveal-up,
.rl-js [data-rl-reveal="up"] { --rl-from-x: 0px; --rl-from-y: var(--rl-dist-y); --rl-from-s: 1; }

/* Variante: da sinistra */
.rl-js .rl-reveal-left,
.rl-js [data-rl-reveal="left"] { --rl-from-x: calc(var(--rl-dist-x) * -1); --rl-from-y: 0px; --rl-from-s: 1; }

/* Variante: da destra */
.rl-js .rl-reveal-right,
.rl-js [data-rl-reveal="right"] { --rl-from-x: var(--rl-dist-x); --rl-from-y: 0px; --rl-from-s: 1; }

/* Variante: in scala. Ottima per i due sigilli delle garanzie. */
.rl-js .rl-reveal-scale,
.rl-js [data-rl-reveal="scale"] {
  --rl-from-x: 0px;
  --rl-from-y: 14px;
  --rl-from-s: var(--rl-scale);
  /* Curva piu lunga: la variabile viene letta dalla transizione,
     cosi non serve alzare la specificita del selettore. */
  --rl-ease: var(--rl-ease-soft);
}

/* Variante: solo dissolvenza, nessuno spostamento. */
.rl-js .rl-reveal-fade,
.rl-js [data-rl-reveal="fade"] { --rl-from-x: 0px; --rl-from-y: 0px; --rl-from-s: 1; }

/* Modificatori di durata */
.rl-js .rl-reveal-slow { --rl-dur: var(--rl-dur-slow); }
.rl-js .rl-reveal-fast { --rl-dur: var(--rl-dur-fast); }

/* --- Stagger di gruppo -----------------------------------------
   Uso: <ul class="rl-stagger"> con figli .rl-reveal.
   motion.js assegna a ogni figlio --rl-i (0,1,2,...) e da li deriva
   il ritardo. Il passo si regola con data-rl-stagger="120" (ms)
   oppure ridefinendo --rl-stagger-step sul contenitore.
   ---------------------------------------------------------------- */
.rl-js .rl-stagger > * { --rl-delay: calc(var(--rl-i, 0) * var(--rl-stagger-step)); }

/* Stagger anche su elementi sparsi (non figli diretti): stessa logica,
   motion.js applica --rl-i a tutto cio che ha [data-rl-stagger-item]. */
.rl-js [data-rl-stagger-item] { --rl-delay: calc(var(--rl-i, 0) * var(--rl-stagger-step)); }

/* Pulizia: quando l'animazione e finita motion.js aggiunge .rl-done
   e liberiamo il compositor. Importante con molte card in pagina. */
.rl-js .rl-done { will-change: auto; }

/* ================================================================
   04. PARALLAX A STRATI
   Uso: <img data-rl-parallax="0.2">
        valori tipici 0.05 - 0.35, negativo = si muove al contrario.
   Opzionali: data-rl-parallax-axis="x|y" (default y)
              data-rl-parallax-max="120" (clamp in px)
   motion.js scrive solo --rl-px / --rl-py: mai top/left.
   ================================================================ */
.rl-js [data-rl-parallax] {
  transform: translate3d(var(--rl-px, 0px), var(--rl-py, 0px), 0);
  will-change: transform;
  backface-visibility: hidden;
}

/* Contenitore consigliato per lo strato: taglia lo sbordamento del
   movimento senza creare scroll orizzontale. */
.rl-parallax-frame {
  position: relative;
  overflow: clip;
}

/* Strato che deve poter uscire dai bordi mentre si muove: si tiene
   piu grande della cornice cosi non scopre mai il fondo. */
.rl-parallax-layer {
  position: absolute;
  inset: -12% -2%;
  width: auto;
  height: auto;
  pointer-events: none;
}

/* ================================================================
   05. PSEUDO 3D
   Nessuna libreria 3D: solo transform CSS.

   .rl-scene       contenitore in prospettiva
   .rl-3d          figlio che conserva la profondita dei suoi figli
   [data-rl-3d]    elemento che ruota allo scroll (motion.js scrive
                   --rl-rx / --rl-ry / --rl-rz / --rl-tz / --rl-t3-y)

   Esempio mockup che si raddrizza entrando nel viewport:
   <div class="rl-scene">
     <img class="rl-device" data-rl-3d="rx:16; ry:-10; tz:-160; y:40">
   </div>
   I valori dell'attributo sono la POSIZIONE DI PARTENZA: mentre
   l'elemento entra, tutto tende a zero e il mockup si raddrizza.
   ================================================================ */

/* Contenitore in prospettiva. Regolabile con --rl-perspective. */
.rl-scene {
  perspective: var(--rl-perspective);
  perspective-origin: var(--rl-perspective-x, 50%) var(--rl-perspective-y, 50%);
}

/* Profondita conservata per gli strati interni. */
.rl-3d { transform-style: preserve-3d; }

/* Elemento pilotato dallo scroll. Senza JS tutte le variabili valgono
   zero: l'elemento e dritto, fermo e perfettamente leggibile. */
.rl-js [data-rl-3d] {
  transform:
    translate3d(0, var(--rl-t3-y, 0px), var(--rl-tz, 0px))
    rotateX(var(--rl-rx, 0deg))
    rotateY(var(--rl-ry, 0deg))
    rotateZ(var(--rl-rz, 0deg))
    scale(var(--rl-3d-s, 1));
  opacity: var(--rl-3d-o, 1);
  will-change: transform, opacity;
  transform-origin: 50% 60%;
}

/* Mockup di dispositivo: ombra coerente con --shadow-lg del sito e
   angoli morbidi. Solo presentazione, nessun colore nuovo. */
.rl-device {
  display: block;
  max-width: 100%;
  border-radius: var(--radius-lg, 14px);
  box-shadow: var(--shadow-lg);
  transform-origin: 50% 70%;
}

/* Tilt statico di posa, utile per "presentare" un mockup fermo.
   Si combina con [data-rl-3d] perche agisce sul wrapper, non sul figlio. */
.rl-pose-left  { transform: rotateY(9deg)  rotateX(3deg); }
.rl-pose-right { transform: rotateY(-9deg) rotateX(3deg); }

/* Strato in profondita dentro una .rl-3d (badge, chip, riflesso). */
.rl-depth-1 { transform: translateZ(40px); }
.rl-depth-2 { transform: translateZ(80px); }
.rl-depth-3 { transform: translateZ(120px); }

/* ================================================================
   06. NUMERI CHE SALGONO
   Uso: <span class="rl-count" data-rl-count="720.000">720.000</span>
        <span class="rl-count" data-rl-count="58,9" data-rl-suffix=" mln">58,9 mln</span>
   Il testo scritto nell'HTML resta il valore finale: senza JS si legge
   comunque il numero giusto.
   ================================================================ */
.rl-count {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  display: inline-block;   /* evita il salto di riga mentre le cifre crescono */
}

/* Micro accento mentre il numero sale. Nessun colore nuovo: usa
   currentColor, quindi eredita il blu o l'arancio del contesto. */
.rl-count.rl-counting { text-shadow: 0 0 18px currentColor; opacity: .96; }
.rl-count { transition: text-shadow 420ms var(--rl-ease), opacity 420ms var(--rl-ease); }

/* ================================================================
   07. TESTO A COMPARSA (titoli)
   Uso: <h2 data-rl-text>Il titolo approvato dal cliente</h2>
   motion.js spezza il testo in parole, le raggruppa per riga reale e
   fa entrare le righe sfalsate. Il markup interno (span evidenziati,
   <br>, <em>) viene conservato.
   Senza JS: nessuno span, nessuna regola attiva, titolo visibile.
   ================================================================ */

/* Parola: maschera che nasconde la parte che sale da sotto.
   padding/margin compensano il taglio di accenti e discendenti. */
.rl-js .rl-word {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
  padding-bottom: .14em;
  margin-bottom: -.14em;
}

/* Corpo della parola: e questo che trasla. Il ritardo dipende dalla
   RIGA (--rl-line), non dalla parola: cosi le righe entrano compatte. */
.rl-js .rl-word-inner {
  display: inline-block;
  transform: translate3d(0, 105%, 0);
  opacity: 0;
  transition: none;
  will-change: transform, opacity;
}
.rl-js.rl-armed .rl-word-inner {
  transition:
    transform var(--rl-dur) var(--rl-ease-soft) var(--rl-line-delay, 0ms),
    opacity   var(--rl-dur) var(--rl-ease)      var(--rl-line-delay, 0ms);
}

/* Ritardo per riga. Passo regolabile con data-rl-text-step="110". */
.rl-js [data-rl-text] .rl-word {
  --rl-line-delay: calc(var(--rl-line, 0) * var(--rl-text-step, 110ms));
}

/* Stato finale */
.rl-js [data-rl-text].rl-in .rl-word-inner {
  transform: none;
  opacity: 1;
}

/* Se motion.js non riesce a spezzare il testo, non lo nasconde mai:
   non esiste nessuna regola che metta opacity 0 sull'elemento intero. */

/* ================================================================
   08. STICKY STORYTELLING
   Struttura:
   <section class="rl-sticky" data-rl-sticky style="--rl-sticky-length: 320vh">
     <div class="rl-sticky-stage">        <- resta fissa
        <div class="rl-sticky-step is-active">...</div>
        <div class="rl-sticky-step">...</div>
     </div>
   </section>
   motion.js scrive --rl-progress (0 -> 1) sulla sezione e mette
   .is-active sullo step corrispondente.
   Niente pin GSAP: usiamo position sticky, cosi non entra in
   conflitto con il pin gia attivo in js/diff-pin.js.
   ================================================================ */
.rl-sticky {
  position: relative;
  min-height: var(--rl-sticky-length);
}

.rl-sticky-stage {
  position: sticky;
  top: var(--rl-sticky-top);
  height: 100vh;
  height: 100svh;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: clip;
}

/* Gli step si sovrappongono nello stesso punto: passa avanti quello attivo. */
.rl-sticky-steps {
  position: relative;
  width: 100%;
}
/* Anche qui la transizione parte solo ad armamento avvenuto. */
.rl-js.rl-armed .rl-sticky-step {
  transition:
    opacity   var(--rl-dur-fast) var(--rl-ease),
    transform var(--rl-dur-fast) var(--rl-ease),
    filter    var(--rl-dur-fast) var(--rl-ease);
}

/* Step sovrapposti (uno alla volta).
   Senza JS NON si sovrappongono: restano in colonna, uno sotto
   l'altro, perfettamente leggibili. La sovrapposizione la attiva
   solo .rl-js, cioe solo quando qualcuno li accende a turno. */
.rl-sticky-steps.rl-overlap > .rl-sticky-step { position: relative; }

.rl-js .rl-sticky-steps.rl-overlap > .rl-sticky-step {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transform: translate3d(0, 18px, 0);
  pointer-events: none;
}
/* Il primo step resta nel flusso: e lui a dare l'altezza al blocco. */
.rl-js .rl-sticky-steps.rl-overlap > .rl-sticky-step:first-child {
  position: relative;
}
.rl-js .rl-sticky-steps.rl-overlap > .rl-sticky-step.is-active {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}

/* Step affiancati o in colonna (tutti visibili, si accende l'attivo) */
.rl-js .rl-sticky-steps:not(.rl-overlap) > .rl-sticky-step { opacity: .38; }
.rl-js .rl-sticky-steps:not(.rl-overlap) > .rl-sticky-step.is-active { opacity: 1; }

/* Barra di avanzamento opzionale, legata a --rl-progress.
   Il colore lo decide il contesto: currentColor. */
.rl-sticky-progress {
  position: absolute;
  left: 0;
  bottom: 0;
  height: 2px;
  width: 100%;
  background: var(--color-line, #e8e7e3);
  overflow: hidden;
}
.rl-sticky-progress::after {
  content: "";
  display: block;
  height: 100%;
  width: 100%;
  background: currentColor;
  transform: scaleX(var(--rl-progress, 0));
  transform-origin: 0 50%;
}

/* ================================================================
   09. UTILITY
   ================================================================ */

/* Elemento che deve stare sopra agli strati parallax. */
.rl-above { position: relative; z-index: 2; }

/* Focus sempre visibile, anche dentro le scene animate.
   Non tocca lo stile di focus gia definito in style.css: lo rafforza
   solo sugli elementi del motion system. */
.rl-js [data-rl-3d] :focus-visible,
.rl-js .rl-sticky :focus-visible,
.rl-js .rl-reveal :focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 3px;
  border-radius: 3px;
}

/* Un elemento che riceve focus mentre e ancora "chiuso" viene
   mostrato subito: la tastiera non deve mai finire nel vuoto. */
.rl-js .rl-reveal:focus-within,
.rl-js [data-rl-reveal]:focus-within {
  opacity: 1;
  transform: none;
}

/* ================================================================
   10. MOBILE
   Sotto i 720px il sito gia disattiva le scene 3D pesanti in
   style.css. Qui facciamo lo stesso per il motion system:
   restano solo dissolvenza e piccolo scorrimento verticale.
   ================================================================ */
@media (max-width: 720px) {
  :root {
    --rl-dist-y: 20px;
    --rl-dist-x: 20px;
    --rl-scale: .97;
    --rl-stagger-step: 60ms;
    --rl-dur: 520ms;
    --rl-dur-slow: 640ms;
  }

  /* Niente parallax su mobile: costa e produce scroll orizzontale. */
  .rl-js [data-rl-parallax] { transform: none !important; }

  /* Niente rotazioni 3D: i mockup restano dritti e nitidi. */
  .rl-js [data-rl-3d] {
    transform: none !important;
    opacity: 1 !important;
    will-change: auto;
  }
  .rl-scene { perspective: none; }
  .rl-pose-left, .rl-pose-right { transform: none; }
  .rl-depth-1, .rl-depth-2, .rl-depth-3 { transform: none; }

  /* Le varianti laterali diventano verticali: niente uscite di schermo. */
  .rl-js .rl-reveal-left,  .rl-js [data-rl-reveal="left"],
  .rl-js .rl-reveal-right, .rl-js [data-rl-reveal="right"] {
    --rl-from-x: 0px;
    --rl-from-y: var(--rl-dist-y);
  }

  /* Sticky storytelling: su mobile diventa flusso normale, si legge
     tutto scorrendo senza sezioni che bloccano il pollice. */
  .rl-sticky { min-height: 0; }
  .rl-sticky-stage {
    position: static;
    height: auto;
    display: block;
    overflow: visible;
  }
  .rl-sticky-steps.rl-overlap > .rl-sticky-step,
  .rl-js .rl-sticky-steps.rl-overlap > .rl-sticky-step {
    position: relative;
    inset: auto;
    opacity: 1;
    transform: none;
    pointer-events: auto;
    margin-bottom: var(--space-6, 32px);
  }
  .rl-js .rl-sticky-steps:not(.rl-overlap) > .rl-sticky-step { opacity: 1; }
}

/* Sotto i 600px: solo dissolvenza, zero spostamenti.
   Priorita alla leggibilita e alla velocita. */
@media (max-width: 600px) {
  .rl-js .rl-reveal,
  .rl-js [data-rl-reveal] {
    --rl-from-x: 0px;
    --rl-from-y: 12px;
    --rl-from-s: 1;
  }
  .rl-js .rl-word-inner { transform: translate3d(0, 60%, 0); }
}

/* ================================================================
   PREFERS-REDUCED-MOTION
   Tutto fermo, tutto visibile. Vale su ogni breakpoint e vince su
   tutte le regole sopra.
   ================================================================ */
@media (prefers-reduced-motion: reduce) {
  html.rl-smooth { scroll-behavior: auto; }

  .rl-js .rl-reveal,
  .rl-js [data-rl-reveal],
  .rl-js .rl-reveal.rl-in,
  .rl-js [data-rl-reveal].rl-in {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
    will-change: auto !important;
  }

  .rl-js [data-rl-parallax],
  .rl-js [data-rl-3d] {
    transform: none !important;
    opacity: 1 !important;
    transition: none !important;
    will-change: auto !important;
  }

  .rl-js .rl-word,
  .rl-js .rl-word-inner {
    transform: none !important;
    opacity: 1 !important;
    transition: none !important;
    overflow: visible;
    will-change: auto !important;
  }

  .rl-count { transition: none !important; text-shadow: none !important; }

  .rl-sticky { min-height: 0; }
  .rl-sticky-stage { position: static; height: auto; display: block; overflow: visible; }
  .rl-sticky-steps.rl-overlap > .rl-sticky-step,
  .rl-js .rl-sticky-steps.rl-overlap > .rl-sticky-step {
    position: relative;
    inset: auto;
    opacity: 1 !important;
    transform: none !important;
    pointer-events: auto;
    margin-bottom: var(--space-6, 32px);
  }
  .rl-js .rl-sticky-steps:not(.rl-overlap) > .rl-sticky-step { opacity: 1 !important; }
  .rl-sticky-progress::after { transform: none; }
  .rl-sticky-step { transition: none !important; }
}
