/* Roosevelt Amazon Expedition · a camada de MOVIMENTO
   ---------------------------------------------------------------------------
   As duas referências que o cliente aprovou foram abertas no Chrome de verdade
   e tiveram o `transform` amostrado ao longo da rolagem, de 450 em 450px. O que
   está aqui é o que elas FAZEM, medido, e não a impressão que dão.

   > Medir isso no painel embutido não funciona: sem composição de quadro o
   > `requestAnimationFrame` não dispara, o Framer nunca atualiza, e todo
   > `transform` sai `none`. A leitura foi feita por fora.

   | efeito                                   | de onde        | onde entra aqui |
   |------------------------------------------|----------------|-----------------|
   | pino + fita horizontal por rolagem       | cabanamountain | a jornada de 7 dias |
   | cartão entra em escala .70 subindo 530px | cabanamountain | matriz, pacotes |
   | zoom-out de parallax 1.20 → 1.00         | bellavista     | hero, fotos grandes |
   | colunas convergindo de ±150px            | bellavista     | 1914, aves |
   | fita infinita de texto                   | bellavista     | espécies |
   | escada de atraso em lista                | as duas        | ficha, rodapé, links |
   | máscara de linha revelando título        | cabanamountain | todo display |

   TUDO AQUI MORRE COM `prefers-reduced-motion`. Não é cortesia: `movimento.
   reduzido.estrategia` do token diz `so_fade`, e `video_vira_poster` diz true.
   --------------------------------------------------------------------------- */

@layer kng-projeto {

/* ═══ 1 · MÁSCARA DE LINHA ═════════════════════════════════════════════════
   O título não aparece: ele SOBE de dentro de uma fresta. Cada linha é uma
   caixa que corta, e o texto dentro dela translada de 110% para 0.

   `110%` e não `100%`: descendente de letra (g, j, p, q) e o `letter-spacing`
   fazem a caixa da linha ser menor que a tinta, e em 100% sobra um fio da
   perna do "g" visível antes da hora. */

.masc { display: block; overflow: hidden; padding-block-end: .08em; margin-block-end: -.08em; }
.masc > span { display: block; transform: translateY(110%); }
.js .masc > span {
  transition: transform 900ms cubic-bezier(0.16, 1, 0.3, 1);
}
.js .dentro .masc > span,
.js .masc.dentro > span { transform: none; }
.js .masc:nth-of-type(2) > span { transition-delay: 90ms; }
.js .masc:nth-of-type(3) > span { transition-delay: 180ms; }

/* ═══ 2 · PARALLAX DE ZOOM-OUT ═════════════════════════════════════════════
   Medido na bellavista: a imagem entra em 1.20 e desce para 1.00 conforme sai
   da tela. É o oposto do zoom-in de apresentação, e por isso funciona: o
   movimento acompanha a leitura em vez de disputar com ela.

   `--p` é o progresso de 0 a 1, escrito pelo JS. */

.parallax { overflow: hidden; }
.parallax > img, .parallax > video {
  transform: scale(calc(1.18 - 0.18 * var(--p, 0)))
             translateY(calc(-3% * var(--p, 0)));
  transform-origin: center 40%;
  will-change: transform;
}

/* ═══ 3 · CONVERGÊNCIA ═════════════════════════════════════════════════════
   Medido na bellavista: dois blocos entram de +150px e −150px e se encontram
   no zero. Ela usa em par de imagem; aqui vale também para foto e texto. */

.js .converge-e { transform: translateX(calc(-110px * (1 - var(--p, 0)))); opacity: var(--p, 0); }
.js .converge-d { transform: translateX(calc( 110px * (1 - var(--p, 0)))); opacity: var(--p, 0); }
.converge-e, .converge-d { will-change: transform, opacity; }

/* ═══ 4 · CARTÃO QUE SOBE EM ESCALA ════════════════════════════════════════
   Medido na cabanamountain, quadro a quadro:
     scale .70 · y +530   →   .78 · +364   →   .88 · +165   →   .98 · −35   →  1 · −70
   Ou seja: o cartão nasce pequeno e bem abaixo, e chega passando um pouco do
   lugar. Reproduzido pela curva, não pelos números soltos. */

.js .sobe { transform: translateY(calc(120px * (1 - var(--p, 0))))
                       scale(calc(0.86 + 0.14 * var(--p, 0)));
            opacity: calc(0.15 + 0.85 * var(--p, 0));
            will-change: transform, opacity; }

/* ═══ 5 · FITA INFINITA ════════════════════════════════════════════════════
   O conteúdo é duplicado no HTML e a fita anda −50%: ao chegar lá, o segundo
   par está exatamente onde o primeiro estava, e o salto não se vê.
   A duplicata leva `aria-hidden`, senão o leitor de tela lê tudo duas vezes. */

.fita { overflow: hidden; -webkit-mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);
        mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent); }
.fita__trilho { display: flex; inline-size: max-content; animation: correr 46s linear infinite; }
.fita__trilho > * { flex: none; }
.fita:hover .fita__trilho { animation-play-state: paused; }
@keyframes correr { from { transform: translate3d(0,0,0); } to { transform: translate3d(-50%,0,0); } }

/* ═══ 6 · O PINO E A FITA HORIZONTAL ═══════════════════════════════════════
   O efeito-assinatura da cabanamountain, e o mais caro de acertar.

   Medido lá: a seção mede 1661px, o palco gruda em `top:0` com 800px, e a fita
   anda de x0 até x−1878 enquanto a página rola ~3200px. O curso vertical é
   `altura da seção − altura do palco`.

   Aqui a régua é a mesma e o cálculo é honesto: o curso vertical é declarado em
   `--voltas` (em telas), e o horizontal é medido no DOM. Assim a fita sempre
   termina exatamente no fim do pino, com qualquer número de cartões. */

/* O TÍTULO ENTRA NO PALCO, e essa é a correção que faltava.
   A primeira versão punha o cabeçalho FORA do pino: título numa faixa verde
   chapada de meia tela, e só depois o pino começava. Medido no print, a seção
   gastava ~460px de cor lisa antes do primeiro cartão, e os cartões apareciam
   pequenos porque sobrava pouca altura para eles.

   Agora o título é a coluna esquerda do próprio palco e fica parado enquanto
   os dias passam ao lado. Ganha três coisas: some o campo morto, o cartão
   cresce para a altura do palco inteiro, e o título permanece à vista durante
   a rolagem presa, que é o que dá sentido ao pino em vez de só prendê-lo. */
.jornada { position: relative; }
.jornada__pista { block-size: calc(var(--voltas, 3) * 100svh); }
.jornada__palco {
  position: sticky; inset-block-start: 0;
  block-size: 100svh; overflow: hidden;
  display: grid; grid-template-columns: minmax(0, 32%) minmax(0, 1fr);
  align-items: center; column-gap: clamp(20px, 3vw, 40px);
}
.jornada__cabeca { padding: 0 0 0 var(--margem); position: relative; z-index: 1; }
/* O RIO CORRE ATRAS DA SEMANA. A coluna do titulo tem 32% da tela e tres
   linhas de texto: em monitor grande sobrava um campo de verde liso maior que
   os proprios cartoes. O mapa preenche com o assunto da secao, e nao com cor.
   Fica no palco, que e quem gruda, entao ele acompanha o pino. */
.jornada__mapa { position: absolute; z-index: 0; pointer-events: none;
  inset-block-start: -26%; inset-inline-start: -8%;
  inline-size: min(46%, 540px); aspect-ratio: 520 / 1536;
  rotate: -5deg; opacity: .6;
  -webkit-mask-image: radial-gradient(122% 72% at 32% 48%, #000 30%, transparent 84%);
          mask-image: radial-gradient(122% 72% at 32% 48%, #000 30%, transparent 84%); }
@media (max-width: 900px) { .jornada__mapa { display: none; } }
/* A janela é o que mede o curso da fita. Sem ela o cálculo usaria a largura do
   palco inteiro, e a fita pararia com um cartão ainda escondido atrás da
   coluna do título. */
/* O CORTE DA ESQUERDA VIRA DEGRADÊ.
   `overflow: hidden` cortava o cartão que sai numa linha reta contra o verde,
   no meio de uma fotografia e no meio de uma frase. Linha reta ali não lê
   como moldura: lê como falha de carregamento.

   SÓ À ESQUERDA. À direita quem corta é a borda da tela, e esse corte é
   honesto: a tela acaba ali para tudo o que existe na página.

   O DEGRADÊ NASCE DA ROLAGEM, e essa é a parte que importa. A primeira versão
   tinha largura fixa, e por isso PRECISAVA ser curta: com o palco parado no
   início, o primeiro dia nasce encostado na borda da janela, e um véu largo e
   fixo o entregava meio dissolvido antes de alguém rolar. A saída foi empurrar
   a fita com um `padding` do mesmo tamanho, o que custava tela e limitava o
   véu a 92px.

   Agora `--fade` cresce de zero até o máximo nos primeiros 10% do pino, com
   `--q`, que o JS já escreve por quadro no palco e a janela herda. Parado, não
   há máscara nenhuma e o primeiro dia aparece inteiro; assim que a fita anda,
   o véu abre. Sem `padding`, e com quase o triplo de curso.

   As quatro paradas fazem uma curva de entrada em vez de rampa reta: dois
   terços do véu ficam abaixo de 55% de tinta, e é isso que faz o desaparecer
   parecer longo em vez de linear. */
.jornada__janela { overflow: hidden; block-size: 100%; display: flex; align-items: center;
  --fade-cheio: clamp(110px, 17vw, 300px);
  --fade: calc(var(--fade-cheio) * min(1, var(--q, 0) * 10));
  -webkit-mask-image: linear-gradient(to right,
      transparent 0,
      rgb(0 0 0 / .10) calc(var(--fade) * .34),
      rgb(0 0 0 / .52) calc(var(--fade) * .70),
      #000 var(--fade));
          mask-image: linear-gradient(to right,
      transparent 0,
      rgb(0 0 0 / .10) calc(var(--fade) * .34),
      rgb(0 0 0 / .52) calc(var(--fade) * .70),
      #000 var(--fade));
}
.jornada__fita {
  display: flex; gap: clamp(14px, 1.6vw, 24px);
  transform: translate3d(calc(-1px * var(--x, 0)), 0, 0);
  will-change: transform;
}

/* SEM PINO NO TELEFONE, e isso não é simplificação.
   Pino sequestra a rolagem: o dedo empurra a página e ela anda de lado. Em
   tela grande, com mouse, isso lê como recurso; no telefone lê como travamento,
   e briga com o gesto de voltar do navegador. A mesma fita vira rolagem
   horizontal com encaixe, que é gesto nativo do aparelho. */
@media (max-width: 900px), (prefers-reduced-motion: reduce) {
  .jornada__pista { block-size: auto; }
  .jornada__palco { position: static; block-size: auto; display: block; overflow: visible; }
  .jornada__cabeca { padding: 0 var(--margem) clamp(24px, 4vw, 40px); }
  .jornada__janela { overflow: visible; block-size: auto; display: block;
    -webkit-mask-image: none; mask-image: none; }
  .jornada__fita {
    transform: none !important;
    overflow-x: auto; scroll-snap-type: x mandatory;
    scroll-padding-inline: var(--margem);
    padding-inline: var(--margem); padding-block-end: var(--esp-md);
    scrollbar-width: none;
  }
  .jornada__fita::-webkit-scrollbar { display: none; }
  /* OS SETE DIAS ESTAVAM ENCOLHENDO PARA CABER, e não rolando.
     Item de flex encolhe por padrão, e como a fita virou caixa de largura
     fixa com `overflow-x`, cada cartão desabou para ~54px: sete colunas de
     uma letra, com a foto virando tira. `flex-shrink: 0` é a linha que
     faltava, e sem ela a rolagem horizontal nunca teria o que rolar. */
  .jornada__fita > * { scroll-snap-align: start; flex: 0 0 auto; }
}

/* ═══ 7 · CONTADOR ═════════════════════════════════════════════════════════
   O número sobe de 0 até o valor quando a faixa entra. `tabular-nums` trava a
   largura do dígito: sem isso a linha inteira dança a cada troca de algarismo. */

.conta { font-variant-numeric: tabular-nums; }

/* ═══ 8 · ESCADA ═══════════════════════════════════════════════════════════ */

.js .escada > * { opacity: 0; transform: translateY(18px);
  transition: opacity 620ms var(--curva-entrada), transform 620ms var(--curva-entrada); }
.js .escada.dentro > * { opacity: 1; transform: none; }
.js .escada.dentro > :nth-child(1) { transition-delay: 0ms; }
.js .escada.dentro > :nth-child(2) { transition-delay: 70ms; }
.js .escada.dentro > :nth-child(3) { transition-delay: 140ms; }
.js .escada.dentro > :nth-child(4) { transition-delay: 210ms; }
.js .escada.dentro > :nth-child(5) { transition-delay: 280ms; }
.js .escada.dentro > :nth-child(6) { transition-delay: 350ms; }
.js .escada.dentro > :nth-child(n+7) { transition-delay: 420ms; }

/* ═══ 9 · A TRAVA ══════════════════════════════════════════════════════════
   `movimento.reduzido` do token: estratégia `so_fade`, e vídeo vira pôster.
   Tudo que translada, escala, corre ou gruda para aqui. */

@media (prefers-reduced-motion: reduce) {
  .masc > span,
  .js .masc > span { transform: none !important; transition: none !important; }
  .parallax > img, .parallax > video { transform: none !important; }
  .js .converge-e, .js .converge-d,
  .js .sobe { transform: none !important; opacity: 1 !important; }
  .fita__trilho { animation: none !important; }
  .fita { -webkit-mask-image: none; mask-image: none; }
  .js .escada > * { opacity: 1 !important; transform: none !important; }
  .hero__filme { display: none !important; }
}


/* ═══ 10 · A ASSINATURA SE DESENHA ═════════════════════════════════════════
   O símbolo da marca aparece sendo traçado, e depois se preenche.

   COMO, E POR QUE SEM BIBLIOTECA
   O truque todo é `pathLength="1"`: ele normaliza QUALQUER path para o
   comprimento 1, então `stroke-dasharray: 1` mais `stroke-dashoffset` de 1 a 0
   desenha o traço inteiro sem ninguém precisar medir nada. Sem esse atributo
   seria preciso chamar `getTotalLength()` em cada path, e aí entraria JS, e com
   JS entraria a tentação da biblioteca.

   O anime.js foi cogitado, tem `svg.createDrawable` feito exatamente para isto,
   e está instalado em `motores/web/package.json`. Ficou de fora com número na
   mão: ele custa ~17 KB comprimido, e o que ele daria a mais aqui é controle de
   easing por path, que este desenho não usa. O arquivo do símbolo inteiro pesa
   2,2 KB comprimido. Pagar oito vezes o desenho em runtime para animá-lo seria
   inverter a conta.

   Se um dia o gesto precisar de easing diferente por traço, de reversão, ou de
   ser conduzido pela rolagem, a troca é local e aí a biblioteca se paga.

   DE ONDE VEIO O ARQUIVO, e isto é um achado do kit
   `simbolo-traco.svg` sai do `simbolo-preto.svg`, e NÃO do `simbolo-circulo`,
   porque o `circulo` não é vetor: ele carrega 73 `<image>` raster recortadas
   por clipPath. Sete dos 23 arquivos do kit são assim, inclusive a assinatura
   principal. Traço não se tira de raster. Ver a nota em `acervo.md`.

   O QUE DESENHA, E O QUE NÃO
   O ARO desenha, e desenha bem. O RETRATO não: as peças dele são formas
   grandes recortadas por `clipPath`, então o contorno de cada uma cai quase
   todo fora do recorte, e o que sobra na tela são fragmentos soltos. Traço de
   verdade no retrato exigiria redesenhá-lo como linha, que é trabalho de
   marca, na janela do DNA, e não aqui.

   Então o gesto é o que o arquivo permite bem: o aro se traça, e o retrato
   sobe preenchendo atrás dele. Fica limpo, e não finge.

   O TEMPO
   76 paths, 14ms de escada entre eles, 1.100ms de traço: ~2,2s até fechar. É longo
   para transição de interface, e o teto de 300ms do `landing-page.md` §8 não se
   aplica aqui — a ficha `21-texto-animado--tres-mecanismos` do banco separa
   justamente isso: §8 vale para interface que responde, e não para um gesto de
   assinatura que acontece uma vez. */

.assina { display: block; inline-size: 100%; block-size: auto; overflow: visible;
  color: var(--acento-sobre-claro); }

/* == O SELO: O TRACO DESENHA, A MASSA REVELA ============================
   Duas camadas no mesmo arquivo, e as duas foram um achado de medicao.

   ONDE ESTAVA O DESENHO. O `simbolo-preto.svg` foi convertido de um jeito em
   que a forma NAO esta nos caminhos que pintam: 73 dos 76 sao retangulos
   minusculos, e quem tem a geometria sao os 74 `clipPath`. O maior deles tem
   4.506 pontos: e o contorno do retrato inteiro. Foi por isso que a primeira
   tentativa de "riscar o outline" so conseguiu riscar o aro, e o resto virou
   rabisco de contornos internos.

   Agora os quatro recortes mais pesados, mais o aro, viram uma camada
   VISIVEL e tracada, e e ela que se desenha. So depois a massa preenchida
   revela por baixo dela, com mascara subindo.

   A ORDEM E O ASSUNTO: primeiro a linha, como quem esboca; depois a agua,
   depois a barba, depois o chapeu. O rio revela o homem. */

/* -- a linha -- */
.assina__risco path {
  fill: none; stroke: currentColor; stroke-width: 1.5;
  stroke-linecap: round; stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
.js .assina__risco path {
  stroke-dasharray: 1; stroke-dashoffset: 1;
  transition: stroke-dashoffset 1500ms cubic-bezier(0.33, 0.02, 0.28, 1),
              opacity 900ms linear 1900ms;
}
.js .assina__risco path:nth-child(2) { transition-delay: 90ms, 1900ms; }
.js .assina__risco path:nth-child(3) { transition-delay: 180ms, 1900ms; }
.js .assina__risco path:nth-child(4) { transition-delay: 270ms, 1900ms; }
.js .assina__risco path:nth-child(5) { transition-delay: 360ms, 1900ms; }
.js .assina.dentro .assina__risco path { stroke-dashoffset: 0; opacity: .34; }

/* -- o mesmo gesto, aplicado a LETRA --
   O wordmark nao tem o defeito do simbolo: e vetor de verdade, 27 caminhos,
   um por letra. Entao o risco dele sai em ORDEM DE LEITURA, e o `--i` que o
   gerador escreve em cada caminho e o lugar da letra nessa ordem. A marca se
   escreve da esquerda para a direita, linha por linha, em vez de piscar
   inteira de uma vez.

   46ms por letra, e nao os 90ms do simbolo: sao 27 letras contra 5 caminhos.
   A 90ms a varredura levaria 2,3s e a ultima letra comecaria depois de a
   primeira ja ter enchido de tinta. A 46ms da 1,2s, que e o tempo de correr
   os olhos pelas duas linhas.

   A letra comeca junto com o simbolo, e nao depois dele: quem espera a
   varredura terminar e so a cortina, para as duas pecas encherem no mesmo
   gesto. */
.js .assina__risco path[style*="--i"] {
  transition-delay: calc(var(--i, 0) * 46ms), 1900ms;
}
/* Contorno de letra e mais fino que contorno de retrato. `stroke-width: 1.5`
   com `non-scaling-stroke` e 1,5px de tela: no simbolo, que ocupa 190px de
   lado, e um traco; nas letras de "AMAZON EXPEDITION", que tem 17px de altura
   no rodape, fecharia a contraforma do A e do O e o risco viraria borrao. */
.assinatura--letras .assina__risco path { stroke-width: .8; }

/* -- a massa --
   A CORTINA E QUEM SE MOVE, e a borda dela e um gradiente.
   Antes era `clip-path: inset` no grupo: borda dura, e o navegador refazendo
   os 74 recortes do arquivo a cada quadro. Deu preenchimento rapido e
   travado, que foi o defeito relatado.

   Agora quem anda e UM retangulo dentro de uma `<mask>` do proprio SVG. Ele
   corre por `transform`, na thread de composicao, sem repintar nada, e a
   borda macia de 0,45H faz o preenchimento chegar como mare e nao como
   persiana.

   O percurso e 2H, com H sendo a altura do viewBox: parado, o simbolo cai no
   terco transparente do retangulo; em -2H, no terco opaco.

   3,2s, e nao 1,6s: e o gesto que fecha a marca, e nada na dobra esta
   esperando por ele. */
.assina__massa path:not([fill="none"]) { fill: currentColor; }
.assina__massa path[stroke]:not([stroke="none"]) { stroke: currentColor; }
.js .assina__cortina {
  transform: translateY(0);
  /* Curva quase reta, e nao a curva de entrada da casa. Instrumentado, a
     de entrada punha 40% do percurso nos primeiros 15% do tempo: o rosto
     inteiro enchia num pulo de 700ms no meio de uma animacao de 3s. */
  transition: transform 3400ms cubic-bezier(0.42, 0.03, 0.58, 1) 1000ms;
  will-change: transform;
}
.js .assina.dentro .assina__cortina { transform: translateY(calc(var(--percurso, 396.8px) * -1)); }

/* NA PRIMEIRA PASSADA QUEM MANDA E A TRANSICAO, e ela tambem precisa das duas
   pecas enchendo juntas. O atraso padrao de 1000ms serve ao hero, que so tem o
   simbolo; no lockup a cortina so pode subir depois da ULTIMA letra, que chega
   a 1200ms de varredura mais 1500ms de traco. Mesmo atraso e mesma duracao nas
   duas, para o preenchimento ser um gesto so. */
.js .rodape__lockup .assina__cortina {
  transition: transform 2600ms cubic-bezier(0.42, 0.03, 0.58, 1) 2800ms;
}

@media (prefers-reduced-motion: reduce) {
  /* `movimento.reduzido.estrategia` e `so_fade`: a marca aparece inteira. */
  .js .assina__cortina { transform: translateY(calc(var(--percurso, 396.8px) * -1)); transition: none !important; }
  .js .assina__risco path { stroke-dashoffset: 0 !important; opacity: .34;
    transition: none !important; }
}

/* == O MESMO GESTO, EM LACO, NO RODAPE ==================================
   O hero desenha uma vez e para: e a chegada, e repetir ali seria pedir
   atencao de quem esta lendo o titulo. O rodape e o contrario: a pagina
   acabou, nada disputa, e a marca pode se refazer.

   AS DUAS PECAS ENCHEM JUNTAS. A versao anterior punha a palavra num segundo
   tempo, depois do simbolo: ficava bonito e ficava LONGO, quase seis segundos
   ate o lockup existir por inteiro, num lugar onde ninguem esta esperando.
   Agora o que se escalona e so o traco das letras, que e o gesto de escrita;
   o preenchimento sobe nas duas ao mesmo tempo, e o ciclo cai de 16s para 14s.

   E A SAIDA E A ENTRADA DE TRAS PARA A FRENTE, nao um fade. Apagar por
   opacidade era o gesto errado: a marca inteira perdia forca de uma vez, como
   quem baixa um controle deslizante. Agora a mare desce por onde subiu e o
   traco se recolhe por onde correu, e a peca desmonta na ordem em que foi
   montada.

     0%  a  8%   o traco corre. As letras entram escalonadas, ate 17%
    18%  a 40%   a cortina sobe nas duas pecas, e a tinta chega
    40%  a 62%   parado, o lockup inteiro: 3,1 segundos de descanso
    62%  a 80%   a cortina DESCE, e a tinta escorre por onde entrou
    76%  a 88%   o traco se recolhe, tambem escalonado
    88%  a 100%  vazio, e recomeca

   UM SO JOGO DE QUADROS PARA AS DUAS PECAS, e isso e possivel porque o
   percurso da cortina e uma variavel escrita dentro de cada SVG: 396,7px no
   simbolo e 92,3px na palavra. O mesmo `@keyframes` resolve diferente em cada
   uma. O que a palavra tem de proprio e so o `animation-delay` por letra.

   Nota de custo: sao dois `transform` e um `stroke-dashoffset` em laco
   eterno. O `stroke-dashoffset` repinta o caminho, e por isso o laco so roda
   com o rodape na tela, pelo mesmo observador do resto da pagina. */
.assinatura--laco { --pausa: 14s; }
.js .assinatura--laco.rodando .assina__risco path {
  animation: laco-risco var(--pausa) linear infinite;
  transition: none;
}
.js .assinatura--laco.rodando .assina__cortina {
  animation: laco-cortina var(--pausa) linear infinite;
  transition: none;
}
/* A ESCRITA E O QUE SE ESCALONA, e so ela.
   `--i` e a posicao da letra na ordem de leitura, escrita pelo gerador. No
   laco isso vira `animation-delay`, que desloca a fase e a mantem deslocada em
   toda volta: a marca se escreve e depois se recolhe na mesma ordem, de graca.
   A cortina NAO leva atraso nenhum, e e por isso que as duas pecas enchem
   juntas mesmo com as letras entrando uma a uma. */
.js .assinatura--laco.rodando .assina__risco path[style*="--i"] {
  animation-delay: calc(var(--i, 0) * 46ms);
  /* `backwards`, e nao o padrao. Durante o atraso, uma animacao sem
     preenchimento deixa o elemento no estilo normal dele, que aqui e
     `stroke-dashoffset: 0`, ou seja LETRA DESENHADA. Medido no quadro zero do
     laco: 26 das 27 letras apareciam prontas e iam sumindo uma a uma conforme
     o atraso vencia, que e o gesto ao contrario. Com `backwards` elas ja
     entram no valor do primeiro quadro, apagadas. */
  animation-fill-mode: backwards;
}

/* A CURVA MORA NO QUADRO, E NAO NA DECLARACAO.
   `animation: ... linear` valeria para o ciclo inteiro, e ciclo inteiro e a
   coisa errada para dar curva: entre 40% e 62% nada se move, e uma curva
   esticada por 14s chega achatada nos 2s em que ha movimento.
   `animation-timing-function` dentro do quadro vale para o TRECHO que comeca
   ali, entao cada gesto ganha a curva dele, e a volta usa a espelhada. */
@keyframes laco-risco {
  0%   { stroke-dashoffset: 1; animation-timing-function: cubic-bezier(0.33, 0.02, 0.28, 1); }
  8%   { stroke-dashoffset: 0; }
  76%  { stroke-dashoffset: 0; animation-timing-function: cubic-bezier(0.72, 0, 0.67, 0.98); }
  88%  { stroke-dashoffset: 1; }
  100% { stroke-dashoffset: 1; }
}
/* A CORTINA SOBE E DEPOIS DESCE PELO MESMO CAMINHO.
   Parada em zero, a peca cai no terco transparente do gradiente; em
   `-percurso`, no terco opaco. Subir e encher, descer e esvaziar, e como a
   borda do gradiente e macia, a tinta escorre em vez de piscar. */
@keyframes laco-cortina {
  0%, 18% { transform: translateY(0); animation-timing-function: cubic-bezier(0.42, 0.03, 0.58, 1); }
  40%     { transform: translateY(calc(var(--percurso, 396.8px) * -1)); }
  62%     { transform: translateY(calc(var(--percurso, 396.8px) * -1)); animation-timing-function: cubic-bezier(0.42, 0.03, 0.58, 1); }
  80%     { transform: translateY(0); }
  100%    { transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  .js .assinatura--laco.rodando .assina__risco path,
  .js .assinatura--laco.rodando .assina__cortina { animation: none; }
}

/* Sobre fundo escuro a assinatura muda de tinta, e o fundo claro é o padrão. */
.sobre-escuro .assina { color: var(--acento-sobre-escuro); }

.assinatura { display: grid; place-items: center; margin-block-end: clamp(28px, 4vw, 48px); }
.assinatura { min-block-size: clamp(120px, 15vw, 190px); }
.assinatura .assina, .assinatura > img { inline-size: clamp(120px, 15vw, 190px); block-size: auto; }
/* Enquanto o vetor nao chegou, o selo estatico ocupa o lugar e some sem salto. */
.assinatura > img { opacity: .9; transition: opacity var(--tempo-curta) linear; }
.assinatura.trocada > img { display: none; }

@media (prefers-reduced-motion: reduce) {
  /* `movimento.reduzido.estrategia` e `so_fade`: a marca aparece inteira. */
  .js .assina { -webkit-mask-image: none; mask-image: none;
    transition: none !important; }
}


/* ═══ 11 · O TRAÇO QUE SE DESENHA ═════════════════════════════════
   Mesmo mecanismo da assinatura, aplicado aos sinais e ao mapa: `pathLength`
   igual a 1 faz o traço inteiro caber num dash de comprimento 1, e aí a
   animação é uma propriedade só, sem uma linha de medição em JS.

   NOS SINAIS o desenho é declarado no `<use>` de propósito: `stroke-dasharray`
   e `stroke-dashoffset` são propriedades herdadas em SVG, e herdar é a única
   porta que atravessa o shadow root de um `<use>`. */
.js .sinal { stroke-dasharray: 1; stroke-dashoffset: 1;
  transition: stroke-dashoffset 1000ms cubic-bezier(0.22, 0.61, 0.36, 1) 140ms; }
.js .dentro .sinal { stroke-dashoffset: 0; }
/* O SINAL DO BOTAO FLUTUANTE NAO SE DESENHA, ele so esta la.
   `movimento.css` carrega depois de `site.css`, e as duas regras tem a mesma
   especificidade: a daqui vencia e os dois icones ficavam invisiveis dentro
   dos botoes. Botao nao e secao que entra; ele aparece pronto. */
.js .flutua__b .sinal { stroke-dasharray: none; stroke-dashoffset: 0; }
/* Na célula o traço é preso à rolagem, porque a célula já carrega `--p` e o
   sinal herda a variável: o bicho se desenha enquanto a foto sobe. */
.js .celula .sinal { transition: none; stroke-dashoffset: calc(1 - var(--p, 0)); }

/* O MAPA LEVA 2,2s PARA FECHAR A MARGEM. É uma linha longa e uma só: correr
   rápido nela dá chicote, e é o gesto mais lento da página de propósito. */
/* OS DOIS RIOS DA MARCA SE DESENHAM; O RESTO DA CARTA ENTRA POR OPACIDADE.
   60 caminhos de afluente correndo `dash` ao mesmo tempo é trabalho por
   quadro sem ganho nenhum: ninguém acompanha 60 linhas se desenhando. O que
   se acompanha é UM rio, do começo ao fim, e por isso só ele e o Guariba
   levam `pathLength`.

   2,6s de curso, que é o gesto mais lento da página. O rio tem 490 km e o
   desenho pode levar o tempo dele. */
.js .m-roosevelt path, .js .m-guariba path {
  stroke-dasharray: 1; stroke-dashoffset: 1;
  transition: stroke-dashoffset 2600ms cubic-bezier(0.16, 0.84, 0.32, 1) 200ms; }
.js .mapa-osm.dentro .m-roosevelt path,
.js .mapa-osm.dentro .m-guariba path { stroke-dashoffset: 0; }
.js .m-guariba path { transition-delay: 700ms; }
.js .m-agua, .js .m-rede { opacity: 0; transition: opacity 1400ms linear 300ms; }
.js .mapa-osm.dentro .m-agua, .js .mapa-osm.dentro .m-rede { opacity: 1; }

/* ═══ 12 · A ÁGUA QUE SOBE ══════════════════════════════════════
   As três cartas do calendário enchem até o nível do período quando a faixa
   entra. `block-size` não roda na thread de composição, e isso aqui é
   aceitável: são três elementos, uma vez, sem nada mais correndo no quadro.

   A escada de 90ms por carta faz a leitura ir de alto para seco, na ordem em
   que elas estão escritas. */
.periodo__agua { block-size: 0;
  transition: block-size 1200ms cubic-bezier(0.16, 0.84, 0.32, 1) 240ms; }
.escada.dentro .periodo:nth-child(2) .periodo__agua { transition-delay: 330ms; }
.escada.dentro .periodo:nth-child(3) .periodo__agua { transition-delay: 420ms; }
.escada.dentro .periodo__agua { block-size: calc(var(--n, 0) * 1%); }
/* Sem JS a carta já nasce cheia: nível de água é informação, não enfeite. */
html:not(.js) .periodo__agua { block-size: calc(var(--n, 0) * 1%); }

/* ═══ 13 · O FIO DE PROGRESSO ══════════════════════════════════
   Dois pixels na base do cabeçalho, medindo quanto da página já passou. A
   home tem ~15.300px de altura: sem essa régua, rolagem longa vira rolagem
   sem fim à vista. Nasce do mesmo `--rolagem` que o JS já calcula por quadro,
   e por isso não custa um listener a mais. */
.topo::after { content: ""; position: absolute; inset-block-end: 0; inset-inline-start: 0;
  block-size: 2px; inline-size: calc(100% * var(--rolagem, 0));
  background: var(--acento-sobre-escuro); opacity: 0;
  transition: opacity var(--tempo-curta) linear; }
.topo.colado::after { opacity: .95; }

@media (prefers-reduced-motion: reduce) {
  .js .sinal, .js .celula .sinal,
  .js .m-roosevelt path, .js .m-guariba path { stroke-dashoffset: 0 !important; }
  .js .m-agua, .js .m-rede { opacity: 1 !important; }
  .periodo__agua { block-size: calc(var(--n, 0) * 1%) !important; transition: none !important; }
  .origem__copia { rotate: -1.2deg !important; }
}

} /* @layer kng-projeto */
