/* ==========================================================================
   NEXUS theme-final / 05-motion.css
   Camada transversal de movimento (CONTRATO-UI.md §6).

   Escopo deste arquivo: o que é do motor de revelação e o que é interruptor
   global. Só transform e opacity animam aqui. Nenhum hex, nenhum raio em px,
   nenhuma família de fonte: tudo vem de var(--...) de 01-tokens.css.

   ONDE VIVE CADA KEYFRAME (não duplicar aqui, por §1 e por territórios
   disjuntos; este bloco é o índice, não a definição):

     nx-drift            02-base.css      deriva do padrão de fundo global
                                          e, reaproveitada, o halo do hero
                                          (.hero::before, sections/hero.css)
     nx-marquee          04-sections.css  rail de verticais (.rail__track)
     nx-contato-beam     sections/contato.css   feixe da seção de contato
     nx-cap-pulse        sections/capacidades.css
     nx-skeleton         03-ui.css
     nx-glass-aurora     06-skin-glass.css
     nx-glass-mesh       06-skin-glass.css

   PENDÊNCIA DE PALETA (fora do meu território, só registro): em 2026-08-03
   o halo do hero (sections/hero.css, .hero::before) e o feixe de contato
   (sections/contato.css, .contato__beam ou equivalente) ainda giram
   hsl(var(--brand-h) ± N ...) em alta saturação (74-90%), ou seja, ainda são
   coloridos, não a "luz branca com opacidade baixa" que a paleta preto e
   branco pede. 03-ui.css/05-motion.css não tocam nesses arquivos (território
   alheio); quem possui sections/hero.css e sections/contato.css precisa
   trocar essas radial/linear-gradient por hsl(var(--foreground) / alfa
   baixo) ou, para o toque cromático contido de até 3% da tela, hsl(var(
   --signal) / alfa baixo), o mesmo par usado agora em .card--glow deste
   arquivo. As keyframes (só transform + opacity) e o gate por --motion já
   estão corretos; é só a cor da pintura que ficou para trás.

   Os easings e durações (--ease-out, --ease-io, --dur-fast, --dur-base,
   --dur-slow) são tokens de 01-tokens.css §"motion". Este arquivo apenas os
   aplica; nunca redeclara valor.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Motor de revelação: [data-reveal]

   O estado inicial oculto é escrito POR JS (core/motion.js), nunca aqui.
   Regra do contrato §6: página sem JS mostra todo o conteúdo. Por isso este
   arquivo NÃO tem `[data-reveal] { opacity: 0 }` em lugar nenhum. Se este
   arquivo escondesse alguma coisa, um erro de JS apagaria a página.

   O que fica no CSS é só a transição, para que o contrato de duração e easing
   seja o mesmo do resto do site e continue valendo caso o estilo inline
   escrito pelo motor seja removido. A duração é multiplicada por --motion:
   com o interruptor do estúdio em 0, a transição vira instantânea sem que
   nenhuma regra precise ser sobrescrita.
   -------------------------------------------------------------------------- */

[data-reveal] {
  transition:
    opacity calc(var(--dur-base) * var(--motion)) var(--ease-out),
    transform calc(var(--dur-base) * var(--motion)) var(--ease-out);
}

/* Enquanto o motor ainda não revelou o elemento, ele é candidato a compositar
   em camada própria. Assim que revela, o motor limpa o will-change inline;
   esta regra existe só para o intervalo entre inicializar e revelar. */
[data-reveal-init]:not([data-revealed]) {
  will-change: opacity, transform;
}

/* Revelado: nada mais para promover, e o elemento volta a ser um elemento
   comum para o compositor. */
[data-revealed] {
  will-change: auto;
}

/* --------------------------------------------------------------------------
   2. Contador numérico e marquee: pontos de acoplamento

   O contador (core/motion.js) só troca textContent, não anima em CSS. O que
   ele precisa do CSS é estabilidade de largura, para que o número subindo de
   0 até o alvo não empurre o layout a cada frame.
   -------------------------------------------------------------------------- */

[data-count] {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

/* O rail duplica os itens por JS e publica --marquee-distance e
   --marquee-duration no elemento [data-marquee]. A animação em si é
   nx-marquee, definida em 04-sections.css. Aqui só a ponte entre o que o JS
   mediu e o que a folha da seção consome, com o fallback do valor de fábrica
   caso o JS não tenha rodado. */
[data-marquee][data-marquee-ready] .rail__track {
  animation-duration: calc(var(--marquee-duration, 34s) * var(--motion));
}

[data-marquee-clone] {
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   3. Brilho que segue o cursor

   O motor publica --px e --py em porcentagem no elemento [data-pointer].
   Valor de fábrica no centro, para que o efeito nasça neutro antes do
   primeiro movimento do ponteiro e em qualquer dispositivo sem ponteiro fino.
   -------------------------------------------------------------------------- */

[data-pointer] {
  --px: 50%;
  --py: 50%;
}

/* --------------------------------------------------------------------------
   4. Interruptor do estúdio: --motion: 0

   Consulta de estilo em container, mesma técnica de 01-tokens.css (padrões de
   fundo) e de 04-sections.css (rail). html é o container implícito de body,
   então a consulta alcança body e toda a árvore abaixo dele.

   A maior parte do site já é imune por aritmética: as durações são escritas
   como calc(var(--dur-*) * var(--motion)), o que zera sozinho. Este bloco é a
   rede de segurança para qualquer regra que tenha escapado dessa disciplina,
   inclusive CSS de terceiros colado no futuro.
   -------------------------------------------------------------------------- */

@container style(--motion: 0) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0ms !important;
  }

  /* Revelado na hora, sem entrada. Vence o estilo inline do motor, que já
     chama showNow() nesse caso; aqui é a garantia de que o conteúdo aparece
     mesmo se o JS de movimento falhar depois de esconder. */
  [data-reveal] {
    opacity: 1 !important;
    transform: none !important;
  }

  .rail__track {
    animation-play-state: paused !important;
  }
}

/* --------------------------------------------------------------------------
   5. prefers-reduced-motion: reduce

   02-base.css §7 já zera duração de animação e de transição no documento
   inteiro. O que falta, e é o que este bloco resolve, é a garantia de
   visibilidade: quem pediu menos movimento não pode receber uma página em
   branco porque o motor escondeu os elementos e a revelação foi zerada.

   Efeitos desligados aqui, na ordem do contrato §6: reveal, marquee, aurora,
   parallax. O vídeo do hero é pausado por JS (partials/hero.js), porque CSS
   não pausa mídia.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  [data-reveal] {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
    will-change: auto !important;
  }

  [data-reveal-init]:not([data-revealed]) {
    will-change: auto;
  }

  .rail__track {
    animation-play-state: paused !important;
  }

  /* Fundo global e halo do hero param de derivar. As duas camadas usam
     nx-drift; matar a animação aqui mantém o gradiente estático, que é o
     estado visual correto, não a ausência do gradiente. */
  body::before,
  .hero::before {
    animation: none !important;
  }

  html {
    scroll-behavior: auto;
  }
}
