/* ===========================================================
   REVEAL — entrada de conteúdo
   Enter: opacity 0 · blur · sobe · escala quase imperceptível
   Trigger: Layer in View (IntersectionObserver, scripts/reveal.js)
   Stagger: --i no elemento × --fx-step

   O QUE MUDOU E POR QUÊ (auditoria de agosto/2026)

   O stagger existia no HTML e não existia no CSS. Todo elemento
   carregava um --i, mas o animation-delay era 0ms fixo e o --fx-step
   valia 0ms. Resultado: a página inteira entrava de uma vez só, o que
   lê como "apareceu" em vez de "chegou". Cinema é cascata, uma coisa
   puxando a próxima. Agora o delay é calculado.
   =========================================================== */
/* --spring, --ease-in-cine e --fx-* moram em tokens.css */

/* Melhoria progressiva: o estado base é sempre visível. Se o JavaScript
   falhar ou estiver desativado, nenhum texto desaparece. */
.fx{
  opacity:1;
  filter:none;
  translate:none;
  scale:none;
}

/* O PISCA, E POR QUE ESTA REGRA EXISTE

   Sem ela a sequência era: o HTML pinta o elemento visível, o script
   roda e marca pra animar, e a animação começa do opacity 0. Ou seja,
   a pessoa via o texto, ele sumia, e voltava. Com o stagger isso ficou
   escancarado, porque um elemento com --i alto some e fica 680ms
   esperando a vez antes de reaparecer.

   A classe `js` é escrita no <html> por um script no <head>, antes de
   qualquer pintura. Então quem tem JavaScript nunca chega a ver o
   estado visível, e quem não tem continua lendo a página inteira. */
.js .fx:not(.fx--on){opacity:0;}

/* A entrada começa quando o elemento chega à tela, e cada um espera a
   sua vez na fila. O min() no --i evita que um índice alto lá no fim de
   uma lista segure o conteúdo por dois segundos. */
.fx.fx--on:not(.fx--done){
  animation-name:fx-in;
  animation-duration:var(--fx-dur);
  animation-timing-function:var(--ease-in-cine);
  animation-fill-mode:both;
  animation-delay:calc(min(var(--i,0), 8) * var(--fx-step));
}

/* Depois que a entrada termina, a animação é DESLIGADA.
   Motivo: mover um elemento no DOM remove e reinsere ele, e isso
   REINICIA qualquer animação CSS ativa. O card da foto é movido pro
   slot quando estaciona — com a animação ainda pendurada nele, ele
   sumia e reaparecia a cada travessia.
   Sem a animação, o elemento simplesmente fica no estado natural
   (opaco, sem blur, sem offset), que é exatamente o frame final. */
.fx--done{animation:none !important;}

/* A escala entra em .985 e não em .9. Escala grande em texto vira zoom
   de apresentação de slides. O que dá peso é o quase nada. */
@keyframes fx-in{
  from{opacity:0; filter:blur(var(--fx-blur)); translate:0 var(--fx-shift); scale:.985;}
  to  {opacity:1; filter:blur(0);              translate:0 0;               scale:1;}
}

/* Variante sem offset: pros ícones 3D, cuja posição vive no `transform`
   e cujo `translate` já é usado pela flutuação contínua. */
@keyframes fx-in-soft{
  from{opacity:0; filter:blur(var(--fx-blur));}
  to  {opacity:1; filter:blur(0);}
}

/* Variante sem blur: pro card de vidro. `filter` num ancestral muda a
   raiz de backdrop do `backdrop-filter` dos filhos — o vidro pararia de
   ler a página atrás dele. Fica só opacidade + offset. */
@keyframes fx-in-card{
  from{opacity:0; translate:0 var(--fx-shift);}
  to  {opacity:1; translate:0 0;}
}

/* -----------------------------------------------------------
   TÍTULO DO HERO — palavra a palavra, subindo por trás de uma
   máscara. É o gesto de cortina, e só funciona em display grande:
   em corpo de texto o mesmo efeito vira letra pulando.
   O padding-bottom existe pra descida do "g" não ser cortada.
   ----------------------------------------------------------- */
.hero__title .line{display:block;overflow:hidden;padding-bottom:.08em;}
.hero__title .fx{display:inline-block;}
.hero__title .fx.fx--on:not(.fx--done){
  animation-name:fx-in-word;
  animation-duration:1250ms;
}
@keyframes fx-in-word{
  from{opacity:0; translate:0 92%; scale:.97;}
  to  {opacity:1; translate:0 0;   scale:1;}
}

@media (prefers-reduced-motion:reduce){
  .fx,.hero__title .fx{animation:none;opacity:1;filter:none;translate:none;scale:none;}
}
