/* ==========================================================================
   FLUX — motion.css
   CAMADA DE MOVIMENTO. Carregada por último, depois de sections.css.

   Princípio da marca (manual §13 — IDENTIDADE EM MOVIMENTO): "caos
   controlado". Corte seco, entrada rápida e intencional. Aqui a densidade
   de animação é alta, mas o vocabulário continua o mesmo: nada flutua,
   nada demora. Tudo entra, assenta e para.

   Índice
     1. Tokens de movimento
     2. Barra de progresso de rolagem
     3. Ondas (divisores animados)
     4. Reveal — variantes de entrada (blur, corte, escala, direção)
     5. Reveal — texto por palavra/caractere
     6. Hover — cards com desfoque que assenta
     7. Hover — botões e links
     8. Parallax e flutuação de fundo
     9. Realces contínuos (marquee, brilho, pulso)
    10. prefers-reduced-motion
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. TOKENS DE MOVIMENTO
   -------------------------------------------------------------------------- */
:root {
  --t-blur: 900ms;
  --e-out: cubic-bezier(0.16, 1, 0.3, 1);      /* saída longa, chegada macia */
  --e-back: cubic-bezier(0.34, 1.4, 0.5, 1);   /* leve ultrapassagem */
  --reveal-blur: 14px;
  --wave-dur-1: 11s;
  --wave-dur-2: 8s;
  --wave-dur-3: 6s;
}

/* --------------------------------------------------------------------------
   2. BARRA DE PROGRESSO DE ROLAGEM
   Fio roxo no topo da página. Preenche conforme a leitura avança.
   -------------------------------------------------------------------------- */
.scroll-progress {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 90;
  height: 2px;
  width: 100%;
  transform: scaleX(0);
  transform-origin: 0 50%;
  background: linear-gradient(90deg, var(--roxo), #c48bff 60%, var(--roxo));
  pointer-events: none;
  will-change: transform;
}

/* --------------------------------------------------------------------------
   3. ONDAS — divisores animados entre seções
   Três cópias do mesmo path deslizando em velocidades diferentes criam
   profundidade sem vídeo e sem canvas. A cor vem de --wave-color, então o
   mesmo componente serve para qualquer transição de seção.
   -------------------------------------------------------------------------- */
/* A onda é sempre o último filho da seção que ela encerra, ancorada no
   rodapé dela. Fica dentro do padding inferior, então nunca encosta no
   conteúdo — e, por estar dentro da seção, os vãos entre as camadas
   mostram o fundo da própria seção, que é o que dá o efeito de "despejo".
   A cor sólida (camada 3) é a da seção SEGUINTE. */
.waves {
  --wave-color: var(--preto);
  --wave-h: clamp(48px, 6vw, 92px);

  display: block;
  position: absolute;
  bottom: -1px; /* mata a linha de sub-pixel entre a onda e a seção seguinte */
  left: 0;
  z-index: 4;
  width: 100%;
  height: var(--wave-h);
  line-height: 0;
  pointer-events: none;
}

.waves svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
  transform: translateZ(0);
  backface-visibility: hidden;
}

.waves use { fill: var(--wave-color); }

.waves__l1 use { opacity: 0.22; }
.waves__l2 use { opacity: 0.45; }
.waves__l3 use { opacity: 1; }

/* Sem will-change explícito: uma animação de transform já é promovida a
   camada própria pelo navegador. Declarar aqui só multiplicaria camadas
   (são 11 ondas × 3 faixas) sem ganho. */
.waves__l1 { animation: wave-drift-a var(--wave-dur-1) linear -2s infinite; }
.waves__l2 { animation: wave-drift-b var(--wave-dur-2) linear -2s infinite; }
.waves__l3 { animation: wave-drift-b var(--wave-dur-3) linear -2s infinite; }

/* Onda fora da tela fica parada. Animação de transform em SVG é rasterizada
   na thread principal, e 11 ondas × 3 faixas rodando sem parar travavam o
   compositor. O JS marca .is-live só na onda que está visível. */
.waves:not(.is-live) .waves__l1,
.waves:not(.is-live) .waves__l2,
.waves:not(.is-live) .waves__l3 { animation-play-state: paused; }

@keyframes wave-drift-a {
  from { transform: translate3d(85px, 0, 0); }
  to   { transform: translate3d(-90px, 0, 0); }
}

@keyframes wave-drift-b {
  from { transform: translate3d(-90px, 0, 0); }
  to   { transform: translate3d(85px, 0, 0); }
}

/* Variantes de cor, nomeadas pela seção de destino */
.waves--preto   { --wave-color: var(--preto); }
.waves--roxo    { --wave-color: var(--roxo); }
.waves--light   { --wave-color: var(--offwhite); }
.waves--lavanda { --wave-color: var(--lavanda); }

/* Onda sobre fundo escuro contínuo: sem contraste de cor, as camadas de
   trás viram energia roxa em vez de sumir. Usada no hero e nos clientes. */
.waves--energia .waves__l1 use { fill: var(--roxo); opacity: 0.34; }
.waves--energia .waves__l2 use { fill: var(--roxo); opacity: 0.16; }

/* --------------------------------------------------------------------------
   4. REVEAL — variantes de entrada
   O base.css já define o [data-reveal] padrão (sobe + fade). Aqui entram as
   variantes, escolhidas por atributo: data-reveal="blur", "left", "clip"...
   -------------------------------------------------------------------------- */

/* Desfoque que assenta — é a assinatura pedida: o bloco chega fora de foco
   e "trava" no lugar. Aplicado por padrão a todo reveal, com transição
   própria para não atrasar o fade. */
[data-reveal] {
  filter: blur(var(--reveal-blur));
  transition:
    opacity var(--t-slow) var(--e-snap),
    transform var(--t-slow) var(--e-snap),
    filter var(--t-blur) var(--e-out);
  transition-delay: var(--reveal-delay, 0ms);
}

[data-reveal].is-in { filter: blur(0); }

/* Direções */
[data-reveal="left"]  { transform: translate3d(-46px, 0, 0); }
[data-reveal="right"] { transform: translate3d(46px, 0, 0); }
[data-reveal="up"]    { transform: translate3d(0, 46px, 0); }
[data-reveal="down"]  { transform: translate3d(0, -38px, 0); }

/* Escala — cresce de dentro, bom para imagens e cards de mídia */
[data-reveal="scale"] {
  transform: scale(0.9);
  --reveal-blur: 18px;
}

/* Corte — a marca abre por uma fenda horizontal, sem fade */
[data-reveal="clip"] {
  opacity: 1;
  filter: none;
  transform: none;
  clip-path: inset(0 0 100% 0);
  transition: clip-path 940ms var(--e-out);
  transition-delay: var(--reveal-delay, 0ms);
}

[data-reveal="clip"].is-in { clip-path: inset(0 0 0 0); }

/* Giro seco — entra levemente torto e endireita */
[data-reveal="tilt"] {
  transform: perspective(900px) rotateX(14deg) translate3d(0, 40px, 0);
  transform-origin: 50% 100%;
}

/* O elemento que só hospeda máscaras não deve desfocar */
[data-reveal].reveal-mask { filter: none; }

/* Máscara de título: junta o corte com um leve giro, dá peso de "impressão" */
.mask > span {
  transition:
    transform 880ms var(--e-out),
    filter 880ms var(--e-out);
  filter: blur(6px);
}

.is-in .mask > span,
.mask.is-in > span { filter: blur(0); }

/* --------------------------------------------------------------------------
   5. REVEAL DE TEXTO — palavra a palavra
   O JS quebra o texto em <span class="word"> e cada palavra entra em
   cascata. Usado nos títulos de seção e no manifesto.
   -------------------------------------------------------------------------- */
.split { display: inline; }

.split .word {
  display: inline-block;
  transform: translate3d(0, 0.85em, 0);
  opacity: 0;
  filter: blur(10px);
  transition:
    transform 780ms var(--e-out),
    opacity 600ms var(--e-out),
    filter 780ms var(--e-out);
  transition-delay: calc(var(--w, 0) * 55ms + var(--reveal-delay, 0ms));
}

.split.is-in .word,
.is-in .split .word {
  transform: none;
  opacity: 1;
  filter: blur(0);
}

/* --------------------------------------------------------------------------
   6. HOVER — cards com desfoque que assenta
   Regra geral: ao passar o mouse, a mídia ganha nitidez e o conteúdo sobe.
   Nada de escalas grandes — a marca corta, não infla.
   -------------------------------------------------------------------------- */

/* Camada de brilho que percorre o card na diagonal */
.card,
.service,
.plan,
.case,
.founder,
.why__item,
.process__item,
.quote,
.creative { position: relative; }

.card::after,
.service::after,
.plan::after,
.quote::after,
.founder::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(
    115deg,
    transparent 30%,
    rgba(123, 0, 255, 0.16) 46%,
    rgba(233, 221, 251, 0.22) 52%,
    transparent 68%
  );
  background-size: 240% 240%;
  background-position: 100% 0;
  transition: opacity 260ms var(--e-cut), background-position 760ms var(--e-out);
}

.card:hover::after,
.service:hover::after,
.plan:hover::after,
.quote:hover::after,
.founder:hover::after {
  opacity: 1;
  background-position: 0 100%;
}

/* Elevação seca — sobe, firma a borda e acende o roxo */
.card,
.service,
.plan,
.case,
.founder,
.why__item,
.quote {
  transition:
    transform var(--t) var(--e-snap),
    border-color var(--t) var(--e-cut),
    box-shadow var(--t) var(--e-cut);
}

.card:hover,
.service:hover,
.plan:hover,
.case:hover,
.founder:hover,
.why__item:hover,
.quote:hover {
  transform: translate3d(0, -6px, 0);
  border-color: var(--roxo);
  box-shadow: 0 18px 48px -24px rgba(123, 0, 255, 0.65);
}

/* Mídia do card: chega levemente desfocada e fora de escala, foca no hover.
   É o efeito de "overlay com blur" pedido na referência. */
.creative__poster,
.founder__photo img,
.case img {
  transition:
    transform 760ms var(--e-out),
    filter 520ms var(--e-out);
}

.creative:hover .creative__poster,
.creative:focus-within .creative__poster,
.founder:hover .founder__photo img,
.case:hover img {
  transform: scale(1.06);
  filter: blur(2px) saturate(1.12);
}

/* Quando o vídeo assume, o poster sai de foco de vez */
.creative.is-playing .creative__poster { filter: blur(6px); opacity: 0; }

.creative__media {
  transition: filter 620ms var(--e-out), transform 760ms var(--e-out);
}

.creative.is-playing .creative__media {
  animation: media-focus 700ms var(--e-out) both;
}

@keyframes media-focus {
  from { filter: blur(12px); transform: scale(1.08); }
  to   { filter: blur(0);    transform: scale(1); }
}

/* Véu e metadados sobem juntos */
.creative__meta {
  transition: transform 420ms var(--e-out), opacity 320ms var(--e-cut);
}

.creative:hover .creative__meta,
.creative:focus-within .creative__meta {
  transform: translate3d(0, -4px, 0);
}

/* Código técnico entra deslizando pela direita */
.creative__code {
  transition: transform 380ms var(--e-back), opacity 260ms var(--e-cut);
}

.creative:not(:hover) .creative__code { transform: translate3d(10px, 0, 0); }

/* Entrada em cascata do grid do portfólio ao trocar de aba */
.work__item {
  animation: work-in 720ms var(--e-out) both;
  animation-delay: var(--stagger, 0ms);
}

@keyframes work-in {
  from { opacity: 0; transform: translate3d(0, 26px, 0) scale(0.97); filter: blur(12px); }
  to   { opacity: 1; transform: none; filter: blur(0); }
}

/* --------------------------------------------------------------------------
   7. HOVER — botões e links
   O .btn já tem o bloco de corte seco vindo de components.css. Aqui a seta
   ganha o deslize pedido e o botão ganha resposta magnética (via JS).
   -------------------------------------------------------------------------- */
.btn {
  transition:
    transform 220ms var(--e-out),
    color var(--t-fast) var(--e-cut),
    border-color var(--t-fast) var(--e-cut),
    background-color var(--t-fast) var(--e-cut);
}

.btn__arrow {
  transition: transform 320ms var(--e-back);
}

.btn:hover .btn__arrow,
.btn:focus-visible .btn__arrow {
  transform: translate3d(6px, 0, 0);
}

/* Botão magnético: o JS escreve --mx/--my a partir da posição do ponteiro */
.btn[data-magnetic] {
  transform: translate3d(var(--mx, 0), var(--my, 0), 0);
}

.btn[data-magnetic]:active { transform: translate3d(var(--mx, 0), var(--my, 0), 0) scale(0.97); }

/* Link com seta — a seta sai e volta por trás do texto */
.link-arrow svg,
.link-arrow .btn__arrow { transition: transform 320ms var(--e-back); }
.link-arrow:hover svg { transform: translate3d(6px, 0, 0); }

/* Sublinhado que se desenha da esquerda */
.nav__link,
.footer a,
.menu__link { position: relative; }

.nav__link::after,
.footer__col a::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -3px;
  height: 1px;
  width: 100%;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: 100% 50%;
  transition: transform 320ms var(--e-out);
}

.nav__link:hover::after,
.nav__link.is-active::after,
.footer__col a:hover::after {
  transform: scaleX(1);
  transform-origin: 0 50%;
}

/* Abas do portfólio e dos planos */
.tab,
.plans__opt {
  transition:
    transform 200ms var(--e-back),
    background-color var(--t-fast) var(--e-cut),
    border-color var(--t-fast) var(--e-cut),
    color var(--t-fast) var(--e-cut);
}

.tab:hover,
.plans__opt:hover { transform: translate3d(0, -2px, 0); }

/* Item do accordion: o ícone gira e o título desloca */
.acc__btn { transition: color var(--t-fast) var(--e-cut), padding-left 260ms var(--e-out); }
.acc__btn:hover { padding-left: 8px; }
.acc__icon { transition: transform 380ms var(--e-back); }
.acc__item[data-open="true"] .acc__icon { transform: rotate(135deg); }

/* --------------------------------------------------------------------------
   8. PARALLAX E FLUTUAÇÃO DE FUNDO
   O JS escreve --py (deslocamento) conforme a rolagem.
   -------------------------------------------------------------------------- */
[data-parallax] {
  transform: translate3d(0, var(--py, 0px), 0);
  will-change: transform;
}

/* Brilho roxo que respira atrás de seções escuras */
.section--glow::before {
  content: "";
  position: absolute;
  inset: -20% 0 auto 50%;
  z-index: -1;
  width: min(900px, 90vw);
  aspect-ratio: 1;
  translate: -50% 0;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(123, 0, 255, 0.18), transparent 62%);
  filter: blur(40px);
  animation: glow-breathe 9s ease-in-out infinite;
  pointer-events: none;
}

@keyframes glow-breathe {
  0%, 100% { opacity: 0.55; transform: scale(1); }
  50%      { opacity: 1;    transform: scale(1.14); }
}

/* --------------------------------------------------------------------------
   9. REALCES CONTÍNUOS
   -------------------------------------------------------------------------- */

/* Marquee pausa quando o ponteiro entra — deixa ler o logo */
.marquee:hover .marquee__track { animation-play-state: paused; }

/* Indicador de rolagem do hero */
.hero__scroll i { animation: scroll-hint 1.9s var(--e-snap) infinite; }

@keyframes scroll-hint {
  0%, 100% { transform: translateY(0);   opacity: 1; }
  55%      { transform: translateY(7px); opacity: 0.35; }
}

/* Pulso do selo do plano em destaque */
.plan--featured .plan__flag {
  animation: flag-pulse 2.6s var(--e-snap) infinite;
}

@keyframes flag-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(123, 0, 255, 0.5); }
  55%      { box-shadow: 0 0 0 10px rgba(123, 0, 255, 0); }
}

/* Nó ativo da órbita do Sistema FLUX */
.orbit__node.is-active { animation: node-pop 420ms var(--e-back); }

@keyframes node-pop {
  0%   { transform: scale(0.86); }
  60%  { transform: scale(1.08); }
  100% { transform: scale(1); }
}

/* Números de prova social: sobem ao contar */
.stat__value { transition: transform 520ms var(--e-out); }
.stat.is-in .stat__value { animation: stat-rise 620ms var(--e-out) both; }

@keyframes stat-rise {
  from { transform: translate3d(0, 16px, 0); filter: blur(8px); }
  to   { transform: none; filter: blur(0); }
}


/* --------------------------------------------------------------------------
   10. ACESSIBILIDADE — respeita quem pediu menos movimento
   Tudo acima é enfeite: sem movimento, o site continua completo.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  [data-reveal],
  [data-reveal].is-in { filter: none; transform: none; opacity: 1; }

  .split .word { transform: none; opacity: 1; filter: none; }
  .mask > span { filter: none; }

  .waves__l1,
  .waves__l2,
  .waves__l3 { animation: none; }

  .scroll-progress { display: none; }

  .work__item { animation: none; }

  .creative:hover .creative__poster,
  .founder:hover .founder__photo img,
  .case:hover img { transform: none; filter: none; }

  .section--glow::before,
  .hero__scroll i,
  .plan--featured .plan__flag { animation: none; }

  [data-parallax] { transform: none; }
}

/* --------------------------------------------------------------------------
   11. SEÇÃO "O PROBLEMA" — movimento com intenção

   Esta é a única seção 100% roxa do site e a que mais carrega argumento.
   Estava parada em relação ao resto, então ganhou movimento — mas só onde
   ele ajuda a ler: a lista entra na ordem do argumento, cada item responde
   ao ponteiro, e as linhas de fluxo continuam se movendo porque o assunto
   da seção é justamente fluxo contínuo.
   -------------------------------------------------------------------------- */

/* Luz que acompanha o ponteiro. O JS escreve --mx/--my em porcentagem e
   cria o .brilho; sem JS (ou sem mouse) nada disso existe.

   A luz mora num ELEMENTO PRÓPRIO, não num pseudo-elemento da seção, e
   fica atrás do conteúdo por z-index negativo — não por empurrar os
   filhos para frente. As duas coisas são cicatriz de bug:

   • `.section::after` já é a diagonal decorativa do canto. Pendurar a luz
     ali a substituía, e ainda deixava a luz recortada no polígono da
     diagonal (ou seja, nem funcionava direito).
   • `[data-brilho] > * { position: relative }` atingia TODOS os filhos,
     inclusive a onda divisória — que é `position: absolute` e, virando
     relative, saía do rodapé da seção e deixava uma faixa reta de cor no
     lugar da onda.

   Resumo: não mexer no position dos filhos e não usar ::before/::after de
   .section aqui. */
[data-brilho] { position: relative; isolation: isolate; }

.brilho {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: 0;
  transition: opacity 420ms var(--e-out);
  background: radial-gradient(
    420px circle at var(--mx, 50%) var(--my, 50%),
    rgba(244, 242, 247, 0.18),
    transparent 70%
  );
}

[data-brilho].tem-ponteiro .brilho { opacity: 1; }

/* Item da lista: entra na cascata e responde ao mouse.

   CUIDADO AO EDITAR: este elemento tem DOIS movimentos concorrentes — a
   entrada (do sistema de reveal) e o hover. Declarar um `transition`
   atalho aqui apagaria o do [data-reveal], levando junto o atraso da
   cascata (foi exatamente o que aconteceu na primeira versão: os três
   itens passaram a entrar ao mesmo tempo). Por isso a transição é
   declarada propriedade a propriedade, com o atraso da cascata só nas
   que pertencem à entrada.

   Pelo mesmo motivo o deslocamento do hover usa `padding-left` e não
   `transform`: transform é da entrada, e os dois brigariam. */
.problem__list li {
  transition-property: opacity, transform, filter, padding-left, border-color, background-color;
  transition-duration: var(--t-slow), var(--t-slow), var(--t-blur), var(--t), var(--t), var(--t);
  transition-timing-function: var(--e-snap), var(--e-snap), var(--e-out), var(--e-snap), var(--e-cut), var(--e-cut);
  transition-delay: var(--reveal-delay, 0ms), var(--reveal-delay, 0ms), var(--reveal-delay, 0ms), 0ms, 0ms, 0ms;
}

.problem__list li:hover {
  padding-left: 26px;
  border-color: var(--preto);
  background: rgba(8, 8, 11, 0.28);
}

.problem__list b {
  display: inline-block;
  transition: transform var(--t) var(--e-back), color var(--t) var(--e-cut);
}

.problem__list li:hover b {
  transform: scale(1.35);
  color: var(--offwhite);
}

/* A frase-chave do manifesto entra depois do resto, como conclusão */
.problem__manifesto strong {
  opacity: 0;
  transform: translate3d(0, 10px, 0);
  transition:
    opacity 520ms var(--e-out) 520ms,
    transform 520ms var(--e-out) 520ms;
}

.is-in .problem__manifesto strong,
.problem__manifesto.is-in strong { opacity: 1; transform: none; }

/* Depois de desenhadas, as linhas de fluxo seguem correndo devagar — é a
   ideia da seção: o fluxo não para. Movimento lento de propósito, para
   ler como respiração e não como animação chamando atenção. */
.is-in .flow path {
  animation:
    flow-draw 1s var(--e-snap) forwards,
    flow-corre 9s linear 1.1s infinite;
}

@keyframes flow-corre {
  from { stroke-dasharray: 460; stroke-dashoffset: 0; }
  to   { stroke-dasharray: 460; stroke-dashoffset: -460; }
}

@media (prefers-reduced-motion: reduce) {
  .brilho { display: none; }
  .problem__list li:hover { padding-left: 16px; }
  .problem__list li:hover b { transform: none; }
  .problem__manifesto strong { opacity: 1; transform: none; transition: none; }
  .is-in .flow path { animation: none; stroke-dashoffset: 0; }
}

/* --------------------------------------------------------------------------
   12. HERO — respiração do vídeo de fundo

   Sem trocar o arquivo, é o zoom lento que devolve sensação de movimento
   contínuo à primeira dobra. 26 segundos de ida e volta: devagar o
   bastante para não competir com a leitura do título, mas suficiente para
   a dobra não parecer uma imagem parada.

   Começa em 1.02 e não em 1: o vídeo é `object-fit: cover` e uma escala
   exata de 1 deixaria a borda aparecer no meio do percurso.
   -------------------------------------------------------------------------- */
.hero__video {
  animation: hero-respira 26s ease-in-out infinite alternate;
  will-change: transform;
}

@keyframes hero-respira {
  from { transform: scale(1.02); }
  to   { transform: scale(1.12); }
}

@media (prefers-reduced-motion: reduce) {
  .hero__video { animation: none; transform: none; }
}
