/* ==========================================================================
   PageHub — camada de cenário e efeitos (v3)

   Arquivo separado do styles.css de propósito: aqui é tudo enfeite. Se este
   CSS não carregar, o site continua legível e navegável — nada de estrutura
   depende do que está abaixo.

   A ideia central: o hero deixa de ser "um retângulo com uma ilustração" e
   vira um PALCO com camadas de profundidade diferentes. Céu ao fundo, horizonte
   atrás, poeira luminosa no meio, elementos recortados na frente e uma moldura
   de folhas e cristais na boca do palco. Cada camada anda numa velocidade
   diferente quando o mouse mexe e quando a página rola — é isso, e só isso,
   que dá sensação de espaço em vez de papel de parede.

   Cuidado herdado do styles.css: quase todo componente de lá já usa ::before
   ou ::after (a barra do .pilar, o escurecimento do .bt, a moldura do
   .cta-final) e quase todo card já tem transform no :hover. Por isso o clarão
   do cursor mora num <span class="brilho"> injetado pelo JS, e não num
   pseudo-elemento: pseudo aqui sobrescreveria o do outro arquivo em silêncio.

   Ordem: palco · camadas · elementos flutuantes · ilha · efeitos · extras
   ========================================================================== */

/* --- Palco ---------------------------------------------------------------
   Ocupa o hero inteiro por baixo do conteúdo. `contain` isola layout e pintura
   das camadas: sem isso, animar vinte elementos aqui obriga o navegador a
   reavaliar a página inteira a cada frame. */
.palco {
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
  contain: layout paint;
}

/* Base pintada em CSS: garante o degradê certo antes de qualquer imagem
   chegar, então o hero nunca pisca preto no primeiro carregamento. */
.palco__ceu {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(120% 80% at 50% 108%, #43167a 0%, transparent 60%),
    radial-gradient(90% 70% at 15% 8%, #2a1266 0%, transparent 65%),
    linear-gradient(180deg, #0d0524 0%, #1a0a44 46%, #2a0f57 78%, #3d1268 100%);
}

.palco__cam {
  position: absolute;
  left: 50%;
  width: 116%;              /* folga lateral: o parallax desloca a camada e sem
                               isso aparece o vazio na beirada da tela */
  max-width: none;
  /* `translate` e não `transform`: o JS escreve em transform, e usar a
     propriedade separada mantém a centralização intacta a cada frame */
  translate: -50% 0;
  will-change: transform;
}
.palco__cam--ceu {
  top: -4%;
  height: 84%;
  object-fit: cover;
  opacity: 0.9;
  mask-image: linear-gradient(180deg, #000 52%, transparent 100%);
  -webkit-mask-image: linear-gradient(180deg, #000 52%, transparent 100%);
}
.palco__cam--horizonte {
  bottom: 24%;
  opacity: 0.45;
  filter: blur(1.5px) saturate(1.15);
  mask-image: linear-gradient(180deg, #000 58%, transparent 100%);
  -webkit-mask-image: linear-gradient(180deg, #000 58%, transparent 100%);
}
/* Boca do palco: a arte vem colorida e chapada, quem transforma em primeiro
   plano escuro e fora de foco é o filtro daqui.
   `height` fixa + object-fit RECORTA a faixa em vez de escalar: sem isso a
   imagem de 2400x771 esticada em 132% da tela vira 1000px de altura e cobre o
   hero inteiro, competindo com a ilha em vez de emoldurá-la. */
.palco__cam--frente {
  bottom: -5%;
  width: 126%;
  height: 26%;
  object-fit: cover;
  object-position: 50% 42%;
  z-index: 4;
  opacity: 0.85;
  filter: blur(4px) brightness(0.3) saturate(1.3);
  mask-image: linear-gradient(180deg, transparent 0%, #000 42%);
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 42%);
}

/* Véu de leitura sobre a coluna de texto. O cenário é saturado de propósito;
   sem este degradê o corpo do texto disputa contraste com nuvem e aurora, e a
   resposta certa não é apagar a arte — é escurecer só o lado onde há leitura. */
.palco__veu {
  position: absolute;
  inset: 0;
  z-index: 3;
  background:
    linear-gradient(100deg, #0e0526f2 0%, #0e0526cf 32%, #0e05266e 54%, transparent 72%),
    linear-gradient(0deg, #0e052699 0%, transparent 36%);
}

/* Aurora em movimento por cima do céu, em `screen` para somar luz em vez de
   cobrir — o degradê do fundo continua aparecendo por baixo. */
.palco__aurora {
  position: absolute;
  inset: -25%;
  z-index: 1;
  mix-blend-mode: screen;
  opacity: 0.5;
  background:
    radial-gradient(38% 30% at 22% 28%, #7c5cff 0%, transparent 62%),
    radial-gradient(34% 28% at 78% 22%, #ff4fd8 0%, transparent 62%),
    radial-gradient(42% 34% at 55% 78%, #22e6d4 0%, transparent 62%);
  filter: blur(50px);
  animation: aurora-anda 26s var(--ease) infinite alternate;
  animation-play-state: var(--ambiente);
}
@keyframes aurora-anda {
  from { transform: translate3d(-3%, -2%, 0) scale(1); }
  to   { transform: translate3d(4%, 3%, 0) scale(1.14); }
}

/* Facho do cursor. Uma luz do tamanho de um holofote acende o pedaço do
   cenário por onde o ponteiro passa. O parallax já responde ao mouse, mas com
   deslocamento pequeno de propósito — e o resultado é que muita gente passa o
   mouse pelo hero sem perceber que ele respondeu. Aqui a resposta é óbvia.

   Mora dentro do palco (z-index -1 no hero), então a luz banha a arte e nunca
   chega perto do texto. Tamanho fixo e `transform` pelo JS: o rastro é a
   `transition` daqui, resolvida pelo compositor — nada de lerp por quadro. */
.palco__facho {
  position: absolute;
  left: 0;
  top: 0;
  z-index: 6;
  width: 720px;
  height: 720px;
  margin: -360px 0 0 -360px;
  border-radius: 50%;
  pointer-events: none;
  mix-blend-mode: screen;
  opacity: 0;
  background: radial-gradient(
    closest-side,
    #ffffff44 0%,
    #b98bff3a 30%,
    #22e6d422 56%,
    transparent 76%
  );
  /* 0.34s e não 0.55s: acima disso a luz deixa de parecer presa à mão e passa
     a parecer um segundo objeto perseguindo o ponteiro com atraso. */
  transition: transform 0.34s var(--ease), opacity 0.5s var(--ease);
}
.palco__facho.is-aceso { opacity: 1; }
@media (max-width: 980px) { .palco__facho { display: none; } }

/* Poeira luminosa em canvas, não em divs. Cem elementos com animação própria
   travam o scroll no celular; um canvas é uma superfície só. */
.palco__poeira {
  position: absolute;
  inset: 0;
  z-index: 2;
  width: 100%;
  height: 100%;
  opacity: 0.8;
}

/* Chão de luz: emenda o palco com a seção de baixo sem linha reta visível. */
.palco::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 30%;
  z-index: 5;
  background: linear-gradient(180deg, transparent 0%, #140a2e99 58%, #140a2e 100%);
}

/* --- Elementos flutuantes ------------------------------------------------
   Dois níveis de propósito: o .flut recebe o parallax do JS e o <img> dentro
   dele recebe a animação de flutuar do CSS. Se fossem o mesmo elemento, uma
   transform sobrescreveria a outra e o elemento ficaria parado ou saltando. */
.flut {
  position: absolute;
  left: var(--x, 50%);
  top: var(--y, 50%);
  z-index: var(--z, 3);
  width: var(--tam, 120px);
  pointer-events: none;
}
/* `will-change` só nas camadas do hero. Promover as vinte e seis peças da
   página inteira a camadas próprias custa memória de GPU o tempo todo, e as
   que ficam nas seções de baixo só se mexem com o scroll — o navegador dá
   conta delas sem aviso prévio. */
.palco .flut { will-change: transform; }
/* O brilho não vem na imagem: é este halo, que segue a cor da seção e pulsa.
   Vantagem sobre glow embutido no PNG — muda de cor sem regerar a arte. */
.flut::before {
  content: "";
  position: absolute;
  inset: -26%;
  border-radius: 50%;
  background: radial-gradient(closest-side, var(--c, #7c5cff), transparent 72%);
  filter: blur(18px);
  animation: brilho-pulsa var(--dur, 8s) ease-in-out infinite alternate;
  animation-play-state: var(--ambiente);
  animation-delay: var(--atraso, 0s);
}
.flut img {
  position: relative;
  display: block;
  width: 100%;
  height: auto;
  animation: flut-sobe var(--dur, 8s) ease-in-out infinite alternate;
  animation-play-state: var(--ambiente);
  animation-delay: var(--atraso, 0s);
}
@keyframes flut-sobe {
  from { transform: translateY(calc(var(--amp, 14px) * -1)) rotate(calc(var(--rot, 3deg) * -1)); }
  to   { transform: translateY(var(--amp, 14px)) rotate(var(--rot, 3deg)); }
}
@keyframes brilho-pulsa {
  from { opacity: 0.14; transform: scale(0.88); }
  to   { opacity: 0.4; transform: scale(1.12); }
}

/* Variação: em vez de subir e descer, gira devagar — para anel e orbe. */
.flut--gira img { animation: flut-orbita var(--dur, 30s) linear infinite;
  animation-play-state: var(--ambiente); }
@keyframes flut-orbita { to { transform: rotate(360deg); } }

/* Elemento pequeno e distante: menos brilho, mais desfoque, some no fundo. */
.flut--longe img { filter: blur(1.5px); opacity: 0.55; }
.flut--longe::before { opacity: 0.12; }

/* --- Ilha do hero -------------------------------------------------------- */
.ilha { position: relative; z-index: 3; }
.ilha__base {
  --amp: 12px;
  --rot: 0.8deg;
  width: 100%;
  animation: flut-sobe 9s ease-in-out infinite alternate;
  animation-play-state: var(--ambiente);
  filter: drop-shadow(0 40px 55px #08021acc);
}
/* Halo por trás da ilha, na cor da marca. */
.ilha::before {
  content: "";
  position: absolute;
  inset: 14% 4% 22%;
  border-radius: 50%;
  background: radial-gradient(closest-side, #ff4fd855, #7c5cff33 55%, transparent 75%);
  filter: blur(46px);
  z-index: -1;
  animation: brilho-pulsa 7s ease-in-out infinite alternate;
  animation-play-state: var(--ambiente);
}
/* Anel de luz correndo por baixo, no lugar da sombra projetada. Sem ele a ilha
   parece colada no fundo, não flutuando sobre o nada. */
.ilha::after {
  content: "";
  position: absolute;
  left: 14%;
  right: 14%;
  bottom: 4%;
  height: 7%;
  z-index: -1;
  border-radius: 50%;
  background: radial-gradient(closest-side, #22e6d477, transparent 72%);
  filter: blur(13px);
  animation: sombra-respira 9s ease-in-out infinite alternate;
  animation-play-state: var(--ambiente);
}
@keyframes sombra-respira {
  from { transform: scaleX(0.84); opacity: 0.4; }
  to   { transform: scaleX(1.08); opacity: 0.85; }
}

/* --- Decoração dentro das seções -----------------------------------------
   Camada própria, atrás do conteúdo e recortada na borda da seção: um
   elemento posicionado em -4% precisa ser cortado ali, e não criar barra de
   rolagem horizontal na página. O `overflow: clip` fica aqui e não no
   .section justamente para não cortar as sombras coloridas dos cards. */
.deco {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: clip;
}
.section > .wrap { position: relative; z-index: 1; }

/* ==========================================================================
   Transições entre seções
   ==========================================================================
   A v2 separava as seções com uma onda SVG: melhor que borda reta, mas ainda
   um recorte decorativo. Aqui cada emenda vira uma CENA com narrativa própria,
   e o scroll é quem a conduz.

   Como funciona: o JS escreve uma única variável `--t` em cada faixa, de 0
   (entrando pela base da tela) a 1 (saindo pelo topo). Todo o resto é CSS —
   cada camada usa `--t` dentro de um calc() para deslocar, crescer, clarear
   ou aparecer. Nada de uma propriedade animada por JS por frame: o JS escreve
   um número, o navegador resolve o desenho.

   Sem JS, `--t` cai no valor padrão e a cena fica parada num quadro composto.
   No modo calmo o JS trava em 0.5 — a cena existe, só não se move.

   Sobre `mix-blend-mode: screen`: as faixas de luz (nuvem, raio, corrente,
   portal) foram geradas sobre PRETO CHAPADO. Em screen o preto desaparece
   sozinho e sobra só a luz, com a borda macia intacta. É muito melhor que
   recorte por matte para esse tipo de arte — nuvem recortada ganha contorno
   duro e denuncia a colagem. */

/* Duas peças, com papéis distintos:

   `.tr`       é o CURSO — quanto de rolagem a cena ocupa na página.
   `.tr__palco` é o QUADRO — o que se vê na tela enquanto se atravessa o curso.

   Nas faixas comuns os dois têm a mesma altura e o `sticky` não tem para onde
   ir: o resultado é idêntico ao de antes. Nas cenas de capítulo (`.tr--cena`)
   o curso é bem maior que o quadro, e a diferença entre os dois é o tempo em
   que a cena fica PRESA ocupando a tela inteira enquanto se rola. É a
   diferença entre uma faixa que passa e um lugar em que se entra.

   O `overflow` e o `isolation` moraram no `.tr` até aqui e mudaram para o
   `.tr__palco` por obrigação: qualquer overflow diferente de `visible` num
   ancestral transforma esse ancestral no contêiner de rolagem e mata o
   `sticky` em silêncio. */
.tr {
  position: relative;
  z-index: 2;
  height: var(--alt, clamp(220px, 32vh, 400px));
  /* emenda sem costura com a seção de cima e a de baixo */
  margin-block: -1px;
}
.tr__palco {
  position: sticky;
  top: 0;
  height: var(--vis, 100%);
  overflow: clip;
  isolation: isolate;
}
.tr + .section, .section + .tr { margin-top: -1px; }

/* --- Cenas de tela cheia --------------------------------------------------
   Até aqui, três das sete emendas ocupavam a tela inteira (abertura, virada e
   chegada) e as outras quatro eram faixas de ~40vh. O argumento era ritmo:
   sete pausas obrigatórias viram pedágio.

   O argumento estava certo sobre a PAUSA e errado sobre o QUADRO. Numa faixa
   de 40vh a cena divide a tela com a seção seguinte já visível embaixo: o
   numeral fica cortado, a legenda espremida numa tira, e o que devia ser um
   lugar lê como uma tarja bonita passando. Nenhuma das quatro chegava a
   acontecer.

   Agora as sete ocupam a tela inteira — e o ritmo se resolve no CURSO, não no
   quadro. São dois patamares:

     .tr--cena   curso de 170vh — a cena PRENDE por quase uma tela de rolagem.
                 São os três marcos: descida, amanhecer, portal.
     .tr--quadro curso de 118vh — o quadro é o mesmo, mas mal encosta: entra,
                 cumpre a frase e sai. São as quatro travessias entre marcos.

   `.tr--full` é o que os dois compartilham: quadro de 100svh, câmera, barras
   de cinema e a cartela empilhada. */
.tr--cena { --alt: 170vh; }
.tr--quadro { --alt: 118vh; }
.tr--full .tr__palco { --vis: 100vh; --vis: 100svh; }
.tr--full .tr__fala span { font-size: clamp(1.3rem, 2.9vw, 2.35rem); }
/* Na tela cheia o numeral sai de trás da frase e vai para CIMA dela. Sobrepostos
   num quadro de 100vh os dois brigavam: o algarismo é grande demais para servir
   de textura atrás de um texto grande. Empilhados, viram cartela de capítulo. */
.tr--full .tr__fala { width: min(880px, 86vw); top: 58%; }
.tr--full .tr__num { font-size: clamp(180px, 25vw, 420px); top: 38%; }
/* O quadro curto atravessa em menos rolagem, então a cartela precisa nascer
   mais cedo e morrer mais tarde para caber inteira na travessia. */
.tr--quadro .tr__fala { top: 56%; }
.tr--quadro .tr__num { top: 37%; font-size: clamp(150px, 20vw, 330px); }

/* Barras de cinema. Entram com a cena e saem com ela — o quadro FECHA em
   widescreen no ponto alto e reabre depois. Só `transform` por quadro: cada
   barra tem altura fixa e é esticada a partir da própria borda. */
.tr__cinema {
  position: absolute;
  inset: 0;
  z-index: 6;
  pointer-events: none;
}
.tr__cinema::before,
.tr__cinema::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 10vh;
  background: #05010f;
  transform: scaleY(var(--f, 0));
  will-change: transform;
}
.tr__cinema::before { top: 0; transform-origin: top; }
.tr__cinema::after { bottom: 0; transform-origin: bottom; }
/* Hierarquia entre os dois patamares. Os três MARCOS fecham em widescreen de
   verdade; as quatro TRAVESSIAS só encostam nas bordas. Sete cenas com o mesmo
   letterbox viram sete vezes o mesmo gesto — e gesto repetido sete vezes deixa
   de ser gesto. */
.tr--quadro .tr__cinema::before,
.tr--quadro .tr__cinema::after { height: 6vh; }
/* No modo calmo a cena de capítulo VOLTA a ser faixa. O JS trava `--t` em 0.5
   ali, o que deixa a cena composta e parada — e uma cena parada presa na tela
   por uma tela e meia de rolagem não é "movimento reduzido", é um obstáculo.
   Quem pediu menos movimento não pediu para rolar mais. As barras de cinema
   somem pelo mesmo motivo: sem a abertura e o fechamento elas seriam só duas
   tarjas pretas permanentes. */
.modo-calmo .tr--full { --alt: clamp(320px, 46vh, 620px); }
.modo-calmo .tr--full .tr__palco { --vis: 100%; }
.modo-calmo .tr--full .tr__fala { top: 50%; }
.modo-calmo .tr--full .tr__num { top: 50%; }
.modo-calmo .tr__cinema { display: none; }

@media (max-width: 820px) {
  .tr--cena { --alt: 150vh; }
  .tr--quadro { --alt: 108vh; }
  .tr__cinema::before, .tr__cinema::after { height: 6vh; }
  /* As peças soltas somem no celular porque numa faixa de 22vh viram mancha
     por cima da cena. Numa cena de tela cheia sobra espaço de sobra, e sem
     elas o quadro fica sendo uma foto parada com uma frase em cima. */
  .tr--full .tr__peca { display: block; }
}

/* Degradê que costura a cor da seção anterior com a da próxima. */
.tr__fundo {
  position: absolute;
  inset: 0;
  z-index: 0;
  background: linear-gradient(180deg, var(--de, #140a2e) 0%, var(--para, #140a2e) 100%);
}

/* Fecho de cima. Sem ele a arte encosta na borda superior da faixa e aparece
   um corte reto atravessando a tela — exatamente a costura que a transição
   existe para esconder. O de baixo é o .tr__frente. */
.tr__palco::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  background: linear-gradient(180deg, var(--de, #140a2e) 0%, transparent var(--abre, 30%));
}

/* Grão de filme. Um ladrilho de ruído de 180px repetido por cima de tudo, em
   `overlay` e com opacidade baixíssima. É o detalhe que separa "ilustração
   colada na página" de "quadro filmado": arte gerada por modelo sai limpa
   demais, e superfície limpa demais o olho lê como impressão, não como cena.

   Estático de propósito — grão que TREMA por quadro obriga a repintar a tela
   inteira e é o efeito mais caro que existe por unidade de beleza. Aqui pinta
   uma vez, vira cache e não aparece mais no orçamento de quadro. */
.tr__palco::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 7;
  pointer-events: none;
  opacity: 0.055;
  mix-blend-mode: overlay;
  background-size: 180px 180px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23g)'/%3E%3C/svg%3E");
}

/* Camada de arte. `translate` cuida da centralização e `transform` fica livre
   para o scroll — mesma separação usada nas camadas do palco.

   REGRA DURA desta seção: por quadro só mudam `transform` e `opacity`. As
   duas são resolvidas pelo compositor, sem repintar a imagem. A primeira
   versão daqui animava também `filter: brightness(calc(--t ...))` nas faixas
   de amanhecer e anoitecer — e travou o renderizador: mudar filtro obriga a
   re-rasterizar a imagem inteira a cada quadro, e são peças de ~3800px de
   largura com máscara por cima. Clarear e escurecer virou véu de opacidade.
   Máscara, blend e tamanho ficam ESTÁTICOS: entram uma vez, viram cache. */
.tr__cam {
  position: absolute;
  left: 50%;
  bottom: var(--base, 0);
  width: var(--larg, 118%);
  max-width: none;
  translate: -50% 0;
  z-index: 1;
  transform:
    /* vetor da câmera (só nas cenas de capítulo — ver bloco "olho da cena") */
    translate3d(
      calc(var(--px, 0) * var(--olho, 0px)),
      calc(var(--py, 0) * var(--olho, 0px) * 0.42),
      0)
    translateY(calc(var(--t, 0.5) * var(--desloca, 0px)))
    scale(calc(1 + var(--t, 0.5) * var(--cresce, 0)));
  will-change: transform, opacity;
}
/* As faixas de luz: o preto do fundo some no blend. */
.tr__cam--luz { mix-blend-mode: screen; }

/* Camada colada na câmera. Só existe para produzir profundidade: anda muito
   mais que as de trás e entra desfocada, porque nada tão perto do olho está
   em foco. É a diferença entre olhar a nuvem e atravessar a nuvem.
   O desfoque é ESTÁTICO — filtro que muda por quadro obriga a re-rasterizar
   uma imagem de ~1800px a cada scroll, e foi assim que a primeira versão
   destas faixas travou o renderizador. */
.tr__perto {
  z-index: 2;
  filter: blur(7px);
  opacity: 0.42;
}
/* No celular a peça de perto cobre a faixa inteira sem acrescentar leitura de
   profundidade — sem parallax de mouse e com a faixa em 22vh, ela vira só
   mancha por cima da cena. */
@media (max-width: 820px) { .tr__perto { display: none; } }

/* --- O olho da cena -------------------------------------------------------
   As três cenas de capítulo prendem o visitante na tela por uma tela e meia de
   rolagem. Eram o único trecho da travessia em que passar o mouse não devolvia
   nada: um quadro de 100vh parado esperando o scroll continuar.

   O `cena.js` escreve `--px` e `--py` (o vetor da câmera do hero, de -1 a 1)
   no `.tr__palco` da cena que está na tela. Aqui cada camada declara o quanto
   anda com esse vetor pelo seu `--olho`. Quem está mais perto do olho anda
   mais — é a mesma regra de profundidade do palco do hero.

   O numeral e a legenda andam ao CONTRÁRIO (valor negativo): estão na frente
   de tudo, e camada da frente que acompanha o cenário mata a profundidade que
   as outras acabaram de construir.

   Vale em toda cena de tela cheia (`.tr--full`). Não valia nas faixas curtas
   porque num quadro de 22vh qualquer deslocamento de câmera lê como tremor,
   não como espaço — agora não existem mais faixas curtas. */
.tr--full .tr__cam { --olho: 26px; }
.tr--full .tr__cam--ceu { --olho: 13px; }
.tr--full .tr__perto { --olho: 96px; }
.tr--full .tr__peca { --olho: 44px; }
.tr--full .tr__peca--longe { --olho: 22px; }
.tr--full .tr__num { --olho: -34px; }
.tr--full .tr__fala { --olho: -14px; }
.tr--full .tr__leque { --olho: 40px; }
.tr--full .tr__coro { --olho: 30px; }
.tr--full .tr__astro { --olho: 18px; }
.tr--full .tr__eco { --olho: 40px; }
/* Sem ponteiro não há vetor: o custo do calc() por camada não se paga. */
@media (hover: none), (max-width: 820px) { .tr--full .tr__palco { --px: 0; --py: 0; } }

/* Véu da frente: fecha a base da faixa na cor exata da próxima seção, para a
   arte nunca encostar numa borda dura. */
.tr__frente {
  position: absolute;
  inset: 0;
  z-index: 4;
  pointer-events: none;
  background: linear-gradient(180deg, transparent var(--fecha, 55%), var(--para, #140a2e) 100%);
}

/* Vinheta: escurece as quatro bordas da faixa e ABRE conforme a cena chega ao
   meio do percurso (--f). É o que dá leitura de câmera — a imagem não aparece
   inteira de uma vez, ela abre. Sem isso a arte panorâmica encosta nas
   laterais da tela e denuncia que é um retângulo colado, não um lugar. */
.tr__vinheta {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  opacity: calc(0.9 - var(--f, 0) * 0.55);
  background: radial-gradient(
    120% 78% at 50% 50%,
    transparent 34%,
    color-mix(in srgb, var(--para, #140a2e) 88%, #000) 100%
  );
  will-change: opacity;
}

/* Facho do cursor DENTRO da cena de capítulo.
   O hero tem um holofote que segue o ponteiro (`.palco__facho`, montado pelo
   JS). As cenas não tinham nada — e são justamente os quadros em que o
   visitante fica parado mais tempo. Aqui o facho sai de graça: o centro do
   gradiente é o próprio `--px/--py` que a câmera já publica, então não há
   evento novo, elemento novo nem leitura de geometria. `background-position`
   num gradiente é repintura de uma camada só, do tamanho da tela, e o vetor
   chega com inércia — o clarão ARRASTA atrás do ponteiro em vez de grudar
   nele, que é o que separa holofote de cursor colorido.

   Fica no `::after` da vinheta porque `.tr__palco` já gastou os dois
   pseudo-elementos (fecho de cima e grão de filme). */
.tr--full .tr__vinheta::after {
  content: "";
  position: absolute;
  inset: 0;
  mix-blend-mode: screen;
  opacity: calc(var(--f, 0) * 0.5);
  background: radial-gradient(
    30% 34% at calc(50% + var(--px, 0) * 50%) calc(50% + var(--py, 0) * 50%),
    #ffffff26 0%,
    color-mix(in srgb, var(--pulse) 16%, transparent) 38%,
    transparent 72%
  );
}
@media (hover: none), (max-width: 820px) { .tr--full .tr__vinheta::after { display: none; } }

/* --- Legenda da cena ------------------------------------------------------
   Cada emenda entre seções ganhou um nome. Não é enfeite tipográfico: a linha
   diz o que a cena está preparando, e é ela que transforma sete faixas
   bonitas em uma travessia com começo, meio e fim.

   Nasce e morre pelo `--f` (0 nas pontas da faixa, 1 no meio). Aparecer e
   sumir com o scroll é de propósito: legenda que fica parada na tela vira
   ruído; legenda que só existe no ponto alto da cena vira cinema.

   `aria-hidden` vem do .tr inteiro — é narração de apoio, e repetir para o
   leitor de tela um texto que só existe entre duas seções atrapalha mais do
   que ajuda. O conteúdo de verdade está nas seções, com heading próprio. */
.tr__fala {
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: 5;
  width: min(760px, 84vw);
  margin: 0;
  translate: -50% -50%;
  text-align: center;
  pointer-events: none;
  opacity: var(--f, 0);
  transform:
    translate3d(
      calc(var(--px, 0) * var(--olho, 0px)),
      calc(var(--py, 0) * var(--olho, 0px) * 0.42),
      0)
    translateY(calc((0.5 - var(--t, 0.5)) * 30px));
  will-change: opacity, transform;
}
/* Sombra de leitura por trás da legenda.
   A vinheta da faixa ABRE conforme a cena chega ao meio — de propósito, é ela
   que dá a leitura de câmera. Mas o meio da cena é exatamente onde a legenda
   nasce, então quanto mais bonita a abertura, menos legível a frase. Numa cena
   de nuvem clara em tela cheia a linha praticamente sumia.
   Este borrão escuro resolve sem tocar na vinheta: escurece só a elipse sob o
   texto, entra e sai junto com ele (é filho do próprio .tr__fala, herda a
   opacidade) e não custa nada por quadro. */
.tr__fala::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: -1;
  width: 210%;
  height: 460%;
  translate: -50% -50%;
  /* elipse larga e baixa, não círculo: o círculo aparecia como um borrão
     redondo desenhado sobre a nuvem. Uma faixa escura larga o olho lê como
     sombra de nuvem, e não como mancha colada */
  background: radial-gradient(50% 50% at 50% 50%, #05010fbb 0%, #05010f78 42%, transparent 74%);
}
.tr--clara .tr__fala::before {
  background: radial-gradient(50% 50% at 50% 50%, #fbf8ffd6, #fbf8ff8c 42%, transparent 74%);
}
.tr__fala b {
  display: block;
  margin-bottom: 10px;
  font-family: var(--f-mono);
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--pulse);
  /* dois halos: o ciano faz a linha brilhar, o escuro a descola de qualquer
     nuvem clara que esteja atrás — sem o segundo, o rótulo some nas cenas
     de céu aberto, que são justamente as mais bonitas */
  text-shadow: 0 0 18px #22e6d4aa, 0 1px 12px #05010f, 0 0 34px #05010fcc;
}
.tr__fala span {
  display: block;
  font-family: var(--f-display);
  font-size: clamp(1.05rem, 2.1vw, 1.6rem);
  font-weight: 300;
  line-height: 1.35;
  letter-spacing: -0.01em;
  color: #f4efff;
  text-shadow: 0 2px 26px #05010fcc, 0 0 60px #05010f99;
}
/* Régua de luz que se abre sob a frase. Cresce do centro com o `--f`, junto
   com a legenda: o traço nascendo é o que fecha a leitura de "cartela de
   capítulo" e separa a narração da arte atrás. */
.tr__fala::after {
  content: "";
  display: block;
  width: min(300px, 46%);
  height: 1px;
  margin: 22px auto 0;
  background: linear-gradient(90deg, transparent, var(--pulse), transparent);
  transform: scaleX(var(--f, 0));
}

/* Na faixa clara o texto branco some. Aqui ele vira tinta. */
.tr--clara .tr__fala span { color: #251145; text-shadow: 0 2px 22px #ffffffcc; }
.tr--clara .tr__fala b { color: #7c3ad6; text-shadow: none; }
.tr--clara .tr__fala::after { background: linear-gradient(90deg, transparent, #7c3ad6, transparent); }

/* --- Numeral da cena ------------------------------------------------------
   O número do capítulo em corpo enorme, só contorno, atrás da frase. É o que
   dá ESCALA à faixa: sem ele a legenda flutua no meio de uma imagem
   panorâmica sem nada com que se medir. Vazado e não chapado de propósito —
   preenchido, competiria com a arte em vez de emoldurá-la.

   Algarismo com zero à esquerda (01…07) e não romano: em corpo de 400px, um
   "II" vazado vira duas barras verticais e um "III" vira uma grade — o olho
   lê retângulo, não número. O romano ficou só na narração, onde o tamanho é
   pequeno e a forma se resolve.

   Anda ao contrário da legenda (ela sobe, ele desce) para os dois não lerem
   como um bloco só deslizando. */
.tr__num {
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: 4;
  translate: -50% -50%;
  font-family: var(--f-display);
  font-size: clamp(160px, 28vw, 440px);
  font-weight: 800;
  line-height: 0.72;
  letter-spacing: -0.07em;
  color: transparent;
  -webkit-text-stroke: 2px #ffffff4d;
  /* o algarismo é vazado e, sobre nuvem clara, contorno branco sobre branco
     não existe: a sombra desenha a silhueta e devolve a forma ao olho */
  text-shadow: 0 2px 26px #05010f7a;
  pointer-events: none;
  user-select: none;
  opacity: calc(var(--f, 0) * 0.8);
  transform:
    translate3d(
      calc(var(--px, 0) * var(--olho, 0px)),
      calc(var(--py, 0) * var(--olho, 0px) * 0.42),
      0)
    translateY(calc((var(--t, 0.5) - 0.5) * 80px));
  will-change: opacity, transform;
}
.tr--clara .tr__num { -webkit-text-stroke-color: #25114533; }
@media (max-width: 820px) { .tr__num { font-size: clamp(120px, 38vw, 210px); } }

/* --- Peça que atravessa o quadro -----------------------------------------
   Um elemento recortado cruzando a faixa enquanto se rola. Diferença para o
   `.flut` das seções: ali a peça paira no lugar; aqui ela ENTRA por um lado e
   SAI pelo outro no curso da faixa, e é isso que faz a transição ler como
   deslocamento no espaço, não como pano de fundo trocando.

   Todo o desenho sai de `--t`, igual às camadas de arte. Cada peça declara
   para onde vai (--vx/--vy), quanto gira (--vr) e quanto cresce (--vs) no
   style inline, então cena nova não pede CSS novo.

   O halo é radial-gradient PURO, sem `filter`. Um blur aqui obrigaria a
   re-rasterizar a peça a cada mudança de escala — e a escala muda o scroll
   inteiro. Gradiente radial já tem borda macia de graça. */
.tr__peca {
  position: absolute;
  left: var(--x, 50%);
  top: var(--y, 50%);
  z-index: var(--z, 2);
  width: var(--tam, 120px);
  translate: -50% -50%;
  pointer-events: none;
  opacity: calc(var(--f, 0) * var(--op, 0.9));
  transform:
    translate3d(
      calc((var(--t, 0.5) - 0.5) * var(--vx, 0px) + var(--px, 0) * var(--olho, 0px)),
      calc((var(--t, 0.5) - 0.5) * var(--vy, -260px) + var(--py, 0) * var(--olho, 0px) * 0.42),
      0)
    rotate(calc((var(--t, 0.5) - 0.5) * var(--vr, 16deg)))
    scale(calc(1 + var(--t, 0.5) * var(--vs, 0.3)));
  will-change: transform, opacity;
}
.tr__peca::before {
  content: "";
  position: absolute;
  inset: -42%;
  border-radius: 50%;
  background: radial-gradient(
    closest-side,
    color-mix(in srgb, var(--c, #7c5cff) 50%, transparent),
    transparent 72%
  );
}
.tr__peca img { position: relative; display: block; width: 100%; height: auto; }
/* Peça de fundo: menor participação, mais atrás, fora de foco. */
.tr__peca--longe img { filter: blur(2px); opacity: 0.6; }
@media (max-width: 820px) { .tr__peca { display: none; } }

/* --- O farol ---------------------------------------------------------------
   Um ponto de luz com rastro que atravessa TODAS as sete cenas, sempre no
   mesmo sentido geral: entra pela esquerda alta na primeira e sai pelo centro
   do portal na última.

   Existe por um motivo de narrativa, não de enfeite. Sete cenas bonitas e
   independentes o visitante lê como sete papéis de parede diferentes; a mesma
   luz reaparecendo em todas transforma a sequência em UMA travessia, com
   alguém atravessando. É a peça mais barata do arquivo e a que mais muda a
   leitura do conjunto.

   Feito de gradiente puro, sem imagem: são sete instâncias, e sete PNGs a mais
   custariam mais que tudo o que este arquivo desenha junto. O núcleo é o
   `::before`, o rastro é o `::after` esticado no sentido contrário à viagem
   (`--ang`, declarado por cena).

   Ao contrário das peças, ele NÃO nasce e morre com o `--f`: entra em 15% de
   opacidade e só some de vez fora da faixa. Farol que pisca junto com a
   legenda seria mais uma peça da cena; farol que já está lá quando a cena
   abre é alguém que estava viajando antes de você chegar. */
.tr__farol {
  position: absolute;
  left: var(--x, 50%);
  top: var(--y, 50%);
  z-index: var(--z, 5);
  width: var(--tam, 13px);
  aspect-ratio: 1;
  translate: -50% -50%;
  pointer-events: none;
  opacity: calc(0.15 + var(--f, 0) * 0.85);
  transform:
    translate3d(
      calc((var(--t, 0.5) - 0.5) * var(--vx, 0px) + var(--px, 0) * var(--olho, 0px)),
      calc((var(--t, 0.5) - 0.5) * var(--vy, -300px) + var(--py, 0) * var(--olho, 0px) * 0.42),
      0);
  will-change: transform, opacity;
}
.tr--full .tr__farol { --olho: 66px; }

/* Núcleo: um ponto branco com halo na cor da cena. */
.tr__farol::before {
  content: "";
  position: absolute;
  inset: -260%;
  border-radius: 50%;
  background:
    radial-gradient(closest-side, #ffffff 0%, #ffffffcc 12%, transparent 26%),
    radial-gradient(
      closest-side,
      color-mix(in srgb, var(--c, #9ad8ff) 72%, transparent) 0%,
      color-mix(in srgb, var(--c, #9ad8ff) 26%, transparent) 34%,
      transparent 70%
    );
}
/* Rastro: uma lágrima esticada apontando para trás do movimento. A máscara
   afina a ponta — sem ela o rastro termina num corte reto e lê como risco. */
.tr__farol::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: var(--rastro, 190px);
  height: calc(var(--tam, 13px) * 1.15);
  translate: 0 -50%;
  transform-origin: 0 50%;
  transform: rotate(var(--ang, 200deg)) scaleX(calc(0.35 + var(--f, 0) * 0.65));
  border-radius: 50%;
  background: linear-gradient(
    90deg,
    color-mix(in srgb, var(--c, #9ad8ff) 62%, transparent),
    transparent 82%
  );
  filter: blur(3px);
  opacity: 0.85;
}
@media (max-width: 820px) { .tr__farol { --tam: 9px; --rastro: 110px; } }

/* --- Leque de raios -------------------------------------------------------
   Feixes saindo de um ponto, girando devagar com o scroll. Serve nas cenas em
   que existe uma FONTE de luz na arte (o sol do amanhecer, o rasgo dos
   raios): sem os feixes, a fonte é um borrão claro; com eles, é uma luz que
   vem de algum lugar.

   `repeating-conic-gradient` é caro de pintar — por isso ele é ESTÁTICO aqui,
   e só `transform`/`opacity` mudam por quadro. Pinta uma vez, vira cache. */
.tr__leque {
  position: absolute;
  left: 50%;
  bottom: var(--leque-base, -95%);
  z-index: 2;
  width: 170%;
  aspect-ratio: 1;
  translate: -50% 0;
  pointer-events: none;
  mix-blend-mode: screen;
  opacity: calc(var(--f, 0) * var(--leque-forca, 0.45));
  transform:
    translate3d(calc(var(--px, 0) * var(--olho, 0px)), 0, 0)
    rotate(calc((var(--t, 0.5) - 0.5) * var(--leque-gira, 12deg) + var(--px, 0) * 2deg));
  background: repeating-conic-gradient(
    from 180deg at 50% 50%,
    transparent 0deg 3.4deg,
    var(--leque-cor, #ffffff1c) 3.4deg 4.6deg,
    transparent 4.6deg 9.2deg
  );
  mask-image: radial-gradient(closest-side, #000 4%, #000000a0 30%, transparent 62%);
  -webkit-mask-image: radial-gradient(closest-side, #000 4%, #000000a0 30%, transparent 62%);
  will-change: transform, opacity;
}

/* --- Risco anamórfico -----------------------------------------------------
   O rastro horizontal que uma lente anamórfica deixa quando uma luz forte
   entra no quadro. Abre junto com a cena e some junto com ela. É um detalhe
   pequeno e é justamente o tipo de detalhe que faz a faixa parecer filmada em
   vez de montada. */
.tr__risco {
  position: absolute;
  left: 50%;
  top: var(--risco-y, 44%);
  z-index: 3;
  width: 150%;
  height: 2px;
  translate: -50% -50%;
  pointer-events: none;
  mix-blend-mode: screen;
  filter: blur(2px);
  background: linear-gradient(
    90deg,
    transparent 0%,
    var(--risco-cor, #8fd6ff) 32%,
    #ffffff 50%,
    var(--risco-cor, #8fd6ff) 68%,
    transparent 100%
  );
  opacity: calc(var(--f, 0) * var(--risco-forca, 0.5));
  transform: scaleX(calc(0.3 + var(--f, 0) * 0.7));
  will-change: transform, opacity;
}
@media (max-width: 820px) { .tr__risco { display: none; } }

/* --- Coro de luzes --------------------------------------------------------
   Faróis de chão SUBINDO da névoa: um ponto de luz com uma coluna vertical
   saindo dele. Nasceu para a cena do vale, que se chama "as quatro luzes" e
   até aqui não tinha nenhuma — as luzes eram só uma promessa da legenda, e o
   visitante tinha de acreditar na frase em vez de ver a coisa.

   Cada luz é um `<i>` com `--x` próprio, e não um `repeating-gradient` de um
   elemento só: quatro empresas não ficam a distâncias iguais num vale, e
   espaçamento regular é a assinatura visual de "textura gerada", não de lugar.
   Cada uma também pulsa no seu tempo (`--atraso`), o que só se consegue com
   elementos separados.

   Sobem com o scroll — no vale a câmera desce, então o que está no chão passa
   por ela para cima. É o mesmo sentido das peças daquela cena, de propósito:
   duas coisas subindo juntas lê como um movimento; uma subindo e outra descendo
   lê como dois efeitos. */
.tr__coro {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  mix-blend-mode: screen;
  opacity: calc(var(--f, 0) * var(--coro-forca, 0.9));
  transform:
    translate3d(
      calc(var(--px, 0) * var(--olho, 0px)),
      calc((0.5 - var(--t, 0.5)) * var(--coro-sobe, 190px)),
      0);
  will-change: transform, opacity;
}
.tr__coro i {
  position: absolute;
  left: var(--x, 50%);
  bottom: var(--y, 30%);
  width: var(--tam, 9px);
  aspect-ratio: 1;
  translate: -50% 0;
}
/* O núcleo: ponto branco com halo na cor da luz.
   O branco é um PONTO, não um miolo. A primeira versão dava a ele 11% do raio
   com opacidade quase cheia, e sobre o vale — que já é magenta saturado — o
   resultado era quatro luzes brancas: a cor da marca existia no arquivo e não
   chegava ao olho. Em `screen`, branco satura o canal e apaga o matiz de
   qualquer coisa que esteja embaixo, então quanto mais branco, menos cor.
   Agora o branco fecha em 7% e o halo entra saturado logo em seguida. */
.tr__coro i::before {
  content: "";
  position: absolute;
  inset: -320%;
  border-radius: 50%;
  background:
    radial-gradient(closest-side, #fff 0%, #ffffffb3 6%, transparent 13%),
    radial-gradient(
      closest-side,
      var(--c, #9ad8ff) 0%,
      color-mix(in srgb, var(--c, #9ad8ff) 62%, transparent) 22%,
      color-mix(in srgb, var(--c, #9ad8ff) 20%, transparent) 46%,
      transparent 72%
    );
  animation: coro-pulsa var(--dur, 5.5s) ease-in-out infinite alternate;
  animation-play-state: var(--ambiente);
  animation-delay: var(--atraso, 0s);
}
/* A coluna: o feixe que sai do ponto e se perde para cima. É ela que
   transforma "ponto aceso" em "farol", e a máscara é o que a faz desaparecer
   em vez de terminar num corte. */
.tr__coro i::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: 0;
  width: calc(var(--tam, 9px) * var(--largura, 2.6));
  height: var(--feixe, 190px);
  translate: -50% 0;
  border-radius: 50% 50% 0 0;
  background: linear-gradient(
    0deg,
    var(--c, #9ad8ff) 0%,
    color-mix(in srgb, var(--c, #9ad8ff) 58%, transparent) 26%,
    color-mix(in srgb, var(--c, #9ad8ff) 16%, transparent) 62%,
    transparent 100%
  );
  filter: blur(4px);
  animation: coro-pulsa var(--dur, 5.5s) ease-in-out infinite alternate;
  animation-play-state: var(--ambiente);
  animation-delay: var(--atraso, 0s);
}
@keyframes coro-pulsa {
  from { opacity: 0.5; }
  to   { opacity: 1; }
}
/* Sem o pulso, o feixe ficaria travado no quadro inicial (meia luz). Fixa num
   valor cheio: o modo calmo tira o movimento, não a luz. */
.modo-calmo .tr__coro i::before,
.modo-calmo .tr__coro i::after { opacity: 0.9; }
/* Mesma armadilha de cascata do astro: a cena escreve `--coro-forca` inline, e
   inline vence media query. Quem a media query pode vencer é a `opacity`, que
   continua saindo da folha de estilo. */
@media (max-width: 820px) {
  .tr__coro { opacity: calc(var(--f, 0) * var(--coro-forca, 0.9) * 0.72); }
}

/* --- Astro ----------------------------------------------------------------
   O corpo de luz que sobe no amanhecer e desce no anoitecer. Até aqui as duas
   cenas da virada tinham um clarão (o `.tr__luz`) e um leque de feixes, mas
   nenhuma FONTE: a luz vinha de lugar nenhum, e "amanhecer" sem sol é só a
   tela ficando mais clara.

   Gradiente puro, nada de imagem — é um disco com corona, e um PNG de 1800px
   custaria mais que tudo o que este arquivo desenha junto. Sobe pelo `--t` com
   `--astro-sobe` positivo e desce com valor negativo, então a mesma peça serve
   nas duas cenas espelhadas sem uma linha de CSS a mais. */
.tr__astro {
  position: absolute;
  left: var(--astro-x, 50%);
  bottom: var(--astro-y, -22%);
  z-index: 1;
  width: var(--astro-tam, 44%);
  aspect-ratio: 1;
  translate: -50% 0;
  pointer-events: none;
  mix-blend-mode: screen;
  opacity: calc(var(--f, 0) * var(--astro-forca, 0.85));
  transform:
    translate3d(
      calc(var(--px, 0) * var(--olho, 0px)),
      calc((0.5 - var(--t, 0.5)) * var(--astro-sobe, 300px)),
      0)
    scale(calc(0.82 + var(--t, 0.5) * var(--astro-cresce, 0.36)));
  background:
    /* Disco: borda nítida o bastante para ler como corpo, e não como borrão.
       O núcleo branco fecha em 8%, não em 15%. Em `screen` sobre um céu de
       amanhecer — que já é claro — um núcleo largo satura os três canais e o
       corpo volta branco: um sol sem cor de sol, que é o mesmo que um borrão.
       Estreitando o branco, o anel quente passa a ocupar a maior parte do
       disco e o astro lê dourado, com o branco servindo só de estouro central,
       que é o que uma fonte forte faz numa lente de verdade. */
    radial-gradient(
      closest-side,
      var(--astro-nucleo, #fffaf0) 0%,
      var(--astro-nucleo, #fffaf0) 8%,
      color-mix(in srgb, var(--astro-cor, #ffb84f) 92%, transparent) 13%,
      color-mix(in srgb, var(--astro-cor, #ffb84f) 74%, transparent) 19%,
      transparent 23%
    ),
    /* corona: o halo largo que dá a leitura de atmosfera em volta do corpo */
    radial-gradient(
      closest-side,
      color-mix(in srgb, var(--astro-cor, #ffb84f) 55%, transparent) 0%,
      color-mix(in srgb, var(--astro-cor, #ffb84f) 16%, transparent) 42%,
      transparent 76%
    );
  will-change: transform, opacity;
}
/* Reflexo de lente: o anel largo e fraco que uma fonte forte deixa fora do
   eixo. Gira devagar com o scroll — o suficiente para o olho não fixar a
   forma e ler o conjunto como luz, em vez de como dois círculos desenhados. */
.tr__astro::before {
  content: "";
  position: absolute;
  inset: -34%;
  border-radius: 50%;
  background: conic-gradient(
    from 200deg,
    transparent 0deg,
    color-mix(in srgb, var(--astro-cor, #ffb84f) 20%, transparent) 60deg,
    transparent 150deg,
    color-mix(in srgb, var(--astro-nucleo, #fffaf0) 12%, transparent) 240deg,
    transparent 330deg
  );
  mask-image: radial-gradient(closest-side, transparent 52%, #000 74%, transparent 96%);
  -webkit-mask-image: radial-gradient(closest-side, transparent 52%, #000 74%, transparent 96%);
  opacity: 0.7;
  transform: rotate(calc((var(--t, 0.5) - 0.5) * 40deg));
}
/* Numa tela estreita o corpo precisa de MAIS largura relativa, não de menos: a
   mesma porcentagem que num monitor dá um sol vira um ponto num celular.
   A regra mexe em `width`, não em `--astro-tam`, e o motivo é de cascata: cada
   cena define a variável num `style` inline, e inline vence media query. Só
   que quem tem inline aqui é a VARIÁVEL — a propriedade final continua sendo
   escrita pela folha de estilo, e aí a media query manda. */
@media (max-width: 820px) { .tr__astro { width: calc(var(--astro-tam, 44%) * 1.7); } }

/* --- Eco ------------------------------------------------------------------
   Anéis concêntricos abrindo de um ponto, como onda de choque. Serve em duas
   situações opostas e é a mesma peça nas duas: onde algo IRRADIA (o rasgo de
   luz da cena IV) e onde algo CHEGA (o portal da cena VII, onde os anéis
   abrem para fora enquanto o visitante entra).

   `repeating-radial-gradient` é caro de pintar, então ele é ESTÁTICO: pinta
   uma vez, vira cache, e por quadro só mudam `transform` e `opacity`. A
   máscara em anel apaga o centro e a beirada — sem ela, o miolo vira um alvo
   de tiro e a borda termina num corte circular duro. */
.tr__eco {
  position: absolute;
  left: var(--eco-x, 50%);
  top: var(--eco-y, 50%);
  z-index: 2;
  width: var(--eco-tam, 128%);
  aspect-ratio: 1;
  translate: -50% -50%;
  pointer-events: none;
  mix-blend-mode: screen;
  opacity: calc(var(--f, 0) * var(--eco-forca, 0.5));
  transform:
    translate3d(
      calc(var(--px, 0) * var(--olho, 0px)),
      calc(var(--py, 0) * var(--olho, 0px) * 0.42),
      0)
    scale(calc(0.5 + var(--t, 0.5) * var(--eco-cresce, 1)));
  background: repeating-radial-gradient(
    circle at 50% 50%,
    transparent 0 5.4%,
    var(--eco-cor, #ffffff22) 5.4% 5.9%,
    transparent 5.9% 11.4%
  );
  mask-image: radial-gradient(closest-side, transparent 6%, #000 32%, #00000099 58%, transparent 78%);
  -webkit-mask-image: radial-gradient(closest-side, transparent 6%, #000 32%, #00000099 58%, transparent 78%);
  will-change: transform, opacity;
}
@media (max-width: 820px) { .tr__eco { display: none; } }

/* --- T1 · A descida pelas nuvens (hero → pilares) ----------------------- */
/* Sem `--alt` próprio: é cena de capítulo, o curso vem do `.tr--cena`. */
.tr--descida .tr__cam {
  /* as duas camadas descem em velocidades diferentes e crescem: é o que
     transforma "duas nuvens paradas" em "atravessando a camada de nuvens" */
  opacity: calc(0.35 + var(--t, 0.5) * 0.6);
}

/* --- T2 · O vale das quatro luzes (pilares → ecossistema) --------------- */
/* Sem `--alt` próprio: o curso vem do `.tr--quadro`. */
/* Aqui a arte não é luz sobre preto — tem céu próprio. Então entra opaca, com
   máscara nas duas pontas em vez de blend. */
.tr--vale .tr__cam {
  mask-image: linear-gradient(180deg, transparent 0%, #000 30%, #000 80%, transparent 100%);
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 30%, #000 80%, transparent 100%);
  /* O filtro já foi `brightness(1.45)`: a arte sai do modelo com névoa escura e,
     entre a máscara nas pontas e o fecho da faixa, os feixes DELA sumiam. Só
     que clarear a arte inteira resolvia aquilo criando outro problema — sobre
     um vale magenta a 145% de brilho, `screen` satura todos os canais e QUALQUER
     luz posta por cima volta branca. As quatro luzes de marca entravam laranja,
     verde, turquesa e violeta e chegavam ao olho como quatro colunas brancas.

     Agora quem carrega o nome da cena é o `.tr__coro`, e a arte pode voltar a
     ser o que é: fundo. Escurecida, ela devolve a faixa de contraste em que
     cor lida como cor — e as quatro luzes viram o assunto do quadro, que é o
     que a legenda promete. Filtro ESTÁTICO (não segue --t), então é rasterizado
     uma vez e não custa por quadro. */
  filter: brightness(0.68) saturate(1.22) contrast(1.06);
  opacity: calc(0.7 + var(--t, 0.5) * 0.3);
}

/* --- T3 · As correntes (ecossistema → o que construímos) ---------------- */
/* Sem `--alt` próprio: o curso vem do `.tr--quadro`. */
.tr--correntes .tr__cam {
  /* corrente que anda de lado, não de cima para baixo: reforça a leitura de
     fluxo passando, e quebra a repetição do movimento vertical das outras */
  transform:
    translateX(calc((var(--t, 0.5) - 0.5) * var(--lado, 120px)))
    translate(-50%, 0)
    scale(calc(1 + var(--t, 0.5) * var(--cresce, 0)));
  left: 50%;
  translate: none;
  opacity: calc(0.4 + var(--t, 0.5) * 0.6);
}

/* --- T4 · A luz que rompe (o que construímos → processo) ---------------- */
/* Sem `--alt` próprio: o curso vem do `.tr--quadro`. */
.tr--raios .tr__cam { opacity: calc(0.25 + var(--t, 0.5) * 0.7); }

/* --- T5 · O amanhecer (processo → modelos) ------------------------------
   A peça principal. É a virada do escuro para o claro, e cai exatamente onde
   o visitante decide — a seção de modelos de trabalho. O sol sobe e a faixa
   inteira clareia conforme se rola. */
/* Sem `--alt` próprio: é cena de capítulo. */
.tr--amanhecer .tr__cam--ceu {
  mask-image: linear-gradient(180deg, transparent 0%, #000 30%);
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 30%);
}
.tr--amanhecer .tr__frente { --fecha: 74%; }

/* --- T6 · O anoitecer (modelos → perguntas) -----------------------------
   Espelho do amanhecer. A arte tem noite no topo e nuvem acesa embaixo, então
   o que costura o claro do papel com o escuro da próxima seção é o degradê da
   faixa; a arte entra por dentro, mascarada nas duas pontas. */
/* Sem `--alt` próprio: o curso vem do `.tr--quadro`. */
.tr--anoitecer .tr__cam--ceu {
  mask-image: linear-gradient(180deg, transparent 0%, #000 34%, #000 70%, transparent 100%);
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 34%, #000 70%, transparent 100%);
}
.tr--anoitecer .tr__frente { --fecha: 62%; }

/* --- Véu de luz --------------------------------------------------------
   O que clareia o amanhecer e apaga o anoitecer. É um degradê chapado cuja
   OPACIDADE segue --t — de propósito, em vez de um filtro sobre a arte:
   opacidade o compositor resolve sozinho, filtro obriga a redesenhar a
   imagem inteira a cada quadro. Mesmo efeito no olho, outra ordem de custo. */
.tr__luz {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  opacity: calc(var(--t, 0.5) * var(--forca, 0.6));
  background: var(--luz, linear-gradient(180deg, transparent 30%, #fff1de 100%));
  mix-blend-mode: var(--luz-blend, screen);
  will-change: opacity;
}

/* --- T7 · O portal (perguntas → chamada final) --------------------------
   O anel cresce e some por fora do quadro conforme se aproxima: a leitura é
   de atravessar, não de olhar. Termina bem em cima do bloco de contato. */
/* Sem `--alt` próprio: é cena de capítulo. */
.tr--portal .tr__cam--portal {
  bottom: auto;
  top: 50%;
  width: var(--larg, 60%);
  translate: -50% -50%;
  transform: scale(calc(0.55 + var(--t, 0.5) * 1.15));
  opacity: calc(0.15 + var(--t, 0.5) * 0.85);
  /* O fundo da arte é quase preto, mas não preto puro: em `screen` esse
     resíduo soma o bastante para desenhar o retângulo da imagem na tela. A
     máscara redonda apaga a moldura e deixa só o anel. Estática, entra uma
     vez e vira cache. */
  mask-image: radial-gradient(closest-side, #000 58%, transparent 96%);
  -webkit-mask-image: radial-gradient(closest-side, #000 58%, transparent 96%);
}

/* No celular a arte panorâmica precisa de MAIS largura, não de menos altura: a
   peça é um panorama de 1800px e, cortada na largura da tela, sobra o miolo
   sem contexto. O curso de cada cena vem do bloco de 820px lá em cima
   (`.tr--cena` 150vh, `.tr--quadro` 108vh) — encolher a faixa aqui, como a
   versão anterior fazia com um `.tr { --alt }` genérico, anulava aquele bloco
   por vir depois no arquivo e devolvia as sete cenas a tarjas de 340px. */
@media (max-width: 820px) {
  .tr__cam { width: 190%; }
  /* Leque de feixes é a camada mais cara da faixa (conic-gradient grande com
     máscara e blend) e a que menos se lê numa tela estreita. */
  .tr__leque { display: none; }
}

/* --- Clarão que segue o cursor -------------------------------------------
   O <span> é injetado pelo JS em todo [data-brilho]; as coordenadas chegam em
   --mx/--my. `plus-lighter` faz o clarão SOMAR luz: passa por cima do texto
   sem apagá-lo, que é o motivo de ele poder ficar acima do conteúdo sem
   mexer no z-index de nada do styles.css. */
[data-brilho] { position: relative; }
.brilho {
  position: absolute;
  inset: 0;
  z-index: 5;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  mix-blend-mode: plus-lighter;
  transition: opacity 0.45s var(--ease);
  background: radial-gradient(
    240px circle at var(--mx, 50%) var(--my, 50%),
    color-mix(in srgb, var(--c, #7c5cff) 30%, transparent),
    transparent 68%
  );
}
[data-brilho].is-perto .brilho { opacity: 1; }
/* No claro, plus-lighter estoura para branco. Lá o clarão vira sombra suave. */
.section--claro .brilho {
  mix-blend-mode: multiply;
  background: radial-gradient(240px circle at var(--mx, 50%) var(--my, 50%), #e6dcff, transparent 68%);
}

/* --- Botão magnético -----------------------------------------------------
   Especificidade acima de .btn:hover de propósito: o styles.css já define
   transform ali, e sem os dois seletores de classe o ímã não teria efeito. */
.btn[data-ima] {
  transform: translate3d(var(--ix, 0px), var(--iy, 0px), 0);
  transition: transform 0.35s var(--ease), box-shadow 0.4s var(--ease);
}
.btn[data-ima]:hover { transform: translate3d(var(--ix, 0px), calc(var(--iy, 0px) - 3px), 0); }
.btn[data-ima].is-puxando { transition: transform 0.12s linear; }

/* --- Botão de movimento (rodapé) ----------------------------------------
   Existe porque o site obedece ao sistema por padrão, e no Windows a opção
   "efeitos de animação" vem desligada em muita máquina. Sem este botão, o
   visitante recebe um site parado sem ter pedido e sem ter como reverter
   dentro do próprio site. */
.movimento {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 7px 15px;
  border-radius: 999px;
  border: 1px solid #ffffff20;
  background: #ffffff0a;
  color: var(--text-mute);
  font-family: var(--f-mono);
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  cursor: pointer;
  transition: border-color 0.3s var(--ease), color 0.3s var(--ease), background-color 0.3s var(--ease);
}
.movimento:hover { border-color: var(--pulse); color: var(--text); background: #22e6d418; }
.movimento b { color: var(--text-soft); font-weight: 600; }
.movimento:hover b { color: var(--pulse); }
.movimento__luz {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
  box-shadow: 0 0 8px currentColor;
}
.movimento[aria-pressed="true"] .movimento__luz { background: var(--pulse); box-shadow: 0 0 10px var(--pulse); }

/* Versão do topo. O rodapé era tarde demais: quem estranha o hero parado
   estranha nos primeiros três segundos, e ninguém rola oito seções para
   descobrir por quê. Aqui o rótulo é só o estado — a frase inteira vive no
   title e no aria-label, porque esta barra existe para destacar o CTA. */
.movimento--fino { padding: 6px 13px; font-size: 0.68rem; }
.movimento--fino .movimento__rot { letter-spacing: 0.08em; }
/* Parado e sem escolha registrada = provavelmente o sistema desligou a
   animação sem o visitante saber. O ponto pisca até alguém decidir, e para
   assim que a preferência é gravada. */
html:not([data-movimento]) .movimento--fino[aria-pressed="false"] .movimento__luz {
  animation: chamar-movimento 2.4s var(--ease) infinite;
}
@keyframes chamar-movimento {
  0%, 100% { opacity: 0.35; }
  50%      { opacity: 1; box-shadow: 0 0 12px var(--beam-2); }
}
@media (max-width: 820px) { .movimento--fino { display: none; } }

/* --- Barra de progresso da leitura --------------------------------------- */
.progresso {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 950;
  height: 3px;
  transform-origin: 0 50%;
  transform: scaleX(var(--p, 0));
  background: var(--brand-grad);
  box-shadow: 0 0 14px #ff4fd8aa;
  pointer-events: none;
}

/* --- Trilha de capítulos --------------------------------------------------
   A barra do topo diz quanto falta; esta diz onde se está. O rótulo fica
   escondido e só abre no hover do item ou quando o capítulo é o atual —
   um menu vertical permanente com oito nomes competiria com a leitura. */
.trilha {
  position: fixed;
  top: 50%;
  right: clamp(14px, 2vw, 30px);
  z-index: 900;
  translate: 0 -50%;
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 10px 6px;
}
.trilha__it {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
  padding: 5px 4px;
  text-decoration: none;
  color: var(--text-mute);
}
.trilha__pt {
  position: relative;
  flex: none;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #ffffff2e;
  transition: background-color 0.4s var(--ease), box-shadow 0.4s var(--ease), scale 0.4s var(--ease);
}
/* O número só existe para leitura rápida no capítulo atual; nos outros ele
   ocuparia espaço para dizer o que o ponto já diz. */
.trilha__n {
  position: absolute;
  right: 22px;
  font-family: var(--f-mono);
  font-size: 0.6rem;
  letter-spacing: 0.1em;
  opacity: 0;
  transition: opacity 0.35s var(--ease);
}
.trilha__rot {
  max-width: 0;
  overflow: hidden;
  white-space: nowrap;
  font-family: var(--f-mono);
  font-size: 0.66rem;
  letter-spacing: 0.09em;
  opacity: 0;
  transition: max-width 0.5s var(--ease), opacity 0.35s var(--ease), color 0.35s var(--ease);
}
.trilha__it:hover .trilha__rot,
.trilha__it:focus-visible .trilha__rot,
.trilha__it.is-aqui .trilha__rot { max-width: 240px; opacity: 1; }
.trilha__it:hover .trilha__pt { background: var(--pulse); scale: 1.25; }
.trilha__it:hover .trilha__rot { color: var(--text); }
.trilha__it.is-aqui { color: var(--text-soft); }
.trilha__it.is-aqui .trilha__pt {
  background: var(--pulse);
  box-shadow: 0 0 0 4px #22e6d41f, 0 0 14px #22e6d4aa;
}
/* Sobre a seção clara a trilha inverte, senão some no papel. */
.trilha.na-claro { color: var(--paper-soft); }
.trilha.na-claro .trilha__pt { background: #1a0e3826; }
.trilha.na-claro .trilha__it { color: var(--paper-soft); }
.trilha.na-claro .trilha__it.is-aqui .trilha__pt { background: #7c3ad6; box-shadow: 0 0 0 4px #7c3ad61f; }
.trilha.na-claro .trilha__it.is-aqui { color: var(--paper-ink); }
@media (max-width: 1179px) { .trilha { display: none; } }

/* --- Convite de movimento -------------------------------------------------
   Aparece uma vez só, e só para quem tem o sistema pedindo menos animação sem
   nunca ter escolhido nada no site. É a diferença entre respeitar a
   preferência do sistema e deixar o visitante sem saber que existe outra
   versão da página. */
.convite {
  position: fixed;
  left: 50%;
  bottom: clamp(16px, 3vh, 34px);
  z-index: 960;
  display: flex;
  align-items: flex-start;
  gap: 12px 14px;
  flex-wrap: wrap;
  width: min(760px, calc(100vw - 28px));
  padding: 20px 24px;
  border-radius: 20px;
  border: 1px solid #ffffff1f;
  background: #150a30f2;
  box-shadow: 0 26px 70px -22px #000, 0 0 0 1px #7c5cff1f inset;
  backdrop-filter: blur(14px);
  translate: -50% 26px;
  opacity: 0;
  transition: opacity 0.5s var(--ease), translate 0.5s var(--ease);
}
.convite.is-in { opacity: 1; translate: -50% 0; }
.convite__ico {
  flex: none;
  margin-top: 8px;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: var(--pulse);
  box-shadow: 0 0 14px var(--pulse);
}
/* Texto em linha inteira e botões numa segunda fila. Lado a lado, a explicação
   ficava numa coluna de 300px, quebrava em seis linhas e virava um bloco denso
   exatamente onde precisa ser lido de relance. */
.convite__txt {
  flex: 1 1 100%;
  margin: 0;
  font-size: 0.92rem;
  line-height: 1.55;
  color: var(--text-soft);
}
/* A primeira linha é o diagnóstico e vira título: em corpo corrido, a
   explicação de POR QUE a página está parada se perdia dentro do parágrafo —
   e é justamente essa frase que o visitante precisa ler em um segundo. */
.convite__txt b {
  display: block;
  margin-bottom: 5px;
  font-family: var(--f-display);
  font-size: 1.02rem;
  font-weight: 650;
  color: var(--text);
}
.convite button {
  flex: none;
  padding: 11px 19px;
  border-radius: 999px;
  font-family: inherit;
  font-size: 0.82rem;
  font-weight: 600;
  cursor: pointer;
  transition: filter 0.3s var(--ease), border-color 0.3s var(--ease), color 0.3s var(--ease);
}
.convite__sim { margin-left: auto; border: 0; background: var(--brand-grad); color: #fff; }
.convite__sim:hover { filter: brightness(1.12); }
.convite__nao { border: 1px solid #ffffff26; background: transparent; color: var(--text-mute); }
.convite__nao:hover { border-color: #ffffff4d; color: var(--text-soft); }

/* --- Chamada para descer -------------------------------------------------
   O hero ocupa a tela inteira e termina numa faixa de nuvem: sem esta marca,
   parte dos visitantes não percebe que a página continua — e o que vem
   depois é justamente a travessia.

   Mora na CALHA ESQUERDA, escrita de baixo para cima, e não centralizada na
   base. Centralizada, ela caía exatamente sobre a faixa de estatística — o
   hero tem mais conteúdo que altura de tela, então "bottom" do hero não é
   "base da tela vazia". Na calha não disputa espaço com nada, e o texto na
   vertical rende um detalhe editorial em vez de um remendo. */
.descer {
  position: absolute;
  left: clamp(16px, 3.2vw, 48px);
  bottom: clamp(22px, 5vh, 54px);
  z-index: 6;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  font-family: var(--f-mono);
  font-size: 0.6rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--text-mute);
  text-decoration: none;
  transition: color 0.35s var(--ease), transform 0.35s var(--ease);
}
.descer > span:first-child {
  writing-mode: vertical-rl;
  transform: rotate(180deg);   /* lê de baixo para cima, como lombada de livro */
}
.descer:hover { color: var(--pulse); transform: translateY(4px); }
.descer__risco {
  position: relative;
  width: 1px;
  height: 62px;
  overflow: hidden;
  background: #ffffff1f;
}
/* A luz corre por dentro do risco em vez de o risco inteiro piscar: com o
   traço parado o olho lê "para baixo", que é a instrução. */
.descer__risco::after {
  content: "";
  position: absolute;
  inset: -40% 0 auto 0;
  height: 40%;
  background: linear-gradient(180deg, transparent, var(--pulse));
  animation: descer-corre 2.1s var(--ease) infinite;
  animation-play-state: var(--ambiente);
}
@keyframes descer-corre {
  from { transform: translateY(0); }
  to   { transform: translateY(350%); }
}
.modo-calmo .descer__risco::after { transform: translateY(150%); }
@media (max-width: 980px) { .descer { display: none; } }

/* --- Título que sobe palavra a palavra ----------------------------------- */
.palavra {
  display: inline-block;
  opacity: 0;
  transform: translateY(var(--palavra-y, 0.45em)) rotate(var(--palavra-r, 2deg));
  transition: opacity 0.7s var(--ease), transform 0.7s var(--ease);
  transition-delay: var(--d, 0ms);
}
.palavra.is-in { opacity: 1; transform: none; }

/* --- Brilho que varre o texto em gradiente -------------------------------
   O gradiente já existe no styles.css; aqui ele ganha folga e passa a andar. */
.grad, .grad-2 {
  background-size: 220% 100%;
  animation: grad-anda 9s ease-in-out infinite alternate;
}
@keyframes grad-anda {
  from { background-position: 0% 50%; }
  to   { background-position: 100% 50%; }
}

/* --- Responsivo ----------------------------------------------------------
   No celular o palco perde as camadas caras: não existe parallax de mouse sem
   mouse, o horizonte desfocado custa pintura por frame e a moldura da frente
   come metade da tela útil. Fica o céu, a aurora e a poeira. */
/* A ilha substituiu o .hero__cena, então o empilhamento do styles.css não
   alcança mais este bloco: a regra de subir a cena para cima do texto no
   tablet precisa ser repetida aqui. */
@media (max-width: 980px) {
  .ilha { order: -1; max-width: 520px; margin-inline: auto; }
}

@media (max-width: 820px) {
  .palco__cam--horizonte { opacity: 0.3; filter: none; }
  .palco__cam--frente { display: none; }
  /* o tamanho vem por style inline (--tam), então não adianta redefinir a
     variável aqui: quem precisa mudar é a largura */
  .flut { width: calc(var(--tam, 120px) * 0.62); }
  .flut--some-mob { display: none; }
  .deco .flut { opacity: 0.45; }
}

@media (max-width: 640px) {
  .palco__poeira { opacity: 0.5; }
}

/* --- Movimento reduzido --------------------------------------------------
   O interruptor `--ambiente` do styles.css congela as animações de loop. O que
   sobra para resolver aqui é o que não é animação CSS: a poeira em canvas (o
   JS decide) e o halo dos elementos, que sem o pulso ficaria parado no quadro
   inicial — quase invisível. Fixamos num valor médio para eles continuarem
   acesos, só que quietos. */
.modo-calmo .flut::before,
.modo-calmo .ilha::before { opacity: 0.26; }
.modo-calmo .ilha::after { opacity: 0.6; }

@media print {
  .palco, .flut, .deco, .progresso, .brilho { display: none; }
}
