/*
	Camada de movimento.

	O que este arquivo resolve: no site da Pictore, movimento é requisito, não
	acabamento. O visitante deve ter a sensação de assistir a algo enquanto
	navega — não de folhear blocos.

	Medido no site de referência (freshlab.com.br): a home tem 68 gatilhos de
	animação, e o movimento se divide em dois tipos que fazem coisas
	diferentes. Os dois estão aqui.

	1. AMARRADO À ROLAGEM (`data-mov` de escala, deriva, parallax, traço).
	   O elemento acompanha a posição da rolagem, quadro a quadro. É o que dá
	   a sensação de animação contínua: a página responde ao gesto o tempo
	   todo. Lá, uma máscara de limão escala por 21 posições de rolagem e uma
	   faixa de 23.400 px desliza na horizontal.

	2. DE ENTRADA (`data-mov="entra"`). Dispara uma vez, quando o elemento
	   aparece. É o que faz a página nunca estar parada, porque sempre há algo
	   entrando.

	Tudo em `animation-timeline` nativo — roda no compositor, fora da fila do
	JavaScript. Onde o navegador não suporta, `movimento.js` entrega as
	entradas por IntersectionObserver e os amarrados ficam no estado final,
	legíveis. Nada aqui é necessário para ler a página.
*/

@media (prefers-reduced-motion: no-preference) {
	@supports (animation-timeline: view()) {

		/* ---------- 1. amarrados à rolagem ---------- */

		/*
			A curva que se desenha. O traço se completa conforme o bloco
			atravessa a tela — a tese da marca virada em código: a curva não
			emoldura, ela conduz o olho de uma seção para a seguinte.
		*/
		[data-mov="traco"] .pic-curva__traco {
			stroke-dasharray: var(--pic-traco-tamanho, 900);
			stroke-dashoffset: var(--pic-traco-tamanho, 900);
			animation: pic-desenha linear both;
			animation-timeline: view();
			animation-range: entry 10% cover 55%;
		}

		/*
			Máscara que abre. A imagem é revelada pela abertura da curva, que
			cresce com a rolagem. É o equivalente direto da máscara de limão
			da referência — só que na forma da Pictore.
		*/
		[data-mov="mascara"] {
			animation: pic-abre linear both;
			animation-timeline: view();
			animation-range: entry 0% cover 70%;
		}

		/*
			Deriva horizontal. Uma faixa larga desliza enquanto a seção passa.
			Serve a logos de cliente, a uma linha de palavras, a um mosaico.
		*/
		[data-mov="deriva"] {
			animation: pic-deriva-x linear both;
			animation-timeline: view();
			animation-range: entry 0% exit 100%;
		}

		/*
			Parallax interno: quem anda é a imagem DENTRO do recorte, não o
			elemento. É o que permite usar parallax em grade sem abrir buraco
			entre as peças.
		*/
		[data-mov-interno="parallax"] > * ,
		[data-mov-interno="parallax"] img {
			animation: pic-parallax linear both;
			animation-timeline: view();
			animation-range: entry 0% exit 100%;
		}

		/* Parallax: o elemento anda em ritmo diferente do resto da página. */
		[data-mov="parallax"] {
			animation: pic-parallax linear both;
			animation-timeline: view();
			animation-range: entry 0% exit 100%;
		}

		/* Painel que entra pela lateral e assenta. */
		[data-mov="painel"] {
			animation: pic-painel linear both;
			animation-timeline: view();
			animation-range: entry 0% cover 45%;
		}

		/*
			Título em contorno que se preenche. Reservado a dois ou três
			momentos do site inteiro — é o recurso que perde força se repetir.
		*/
		[data-mov="preenche"] {
			background: var(--pic-grad-destaque);
			background-clip: text;
			-webkit-background-clip: text;
			color: transparent;
			background-size: var(--pic-preenche, 0%) 100%;
			background-repeat: no-repeat;
			-webkit-text-stroke: 1px var(--pic-borda);
			animation: pic-preenche linear both;
			animation-timeline: view();
			animation-range: entry 20% cover 60%;
		}

		/* ---------- 2. entradas ---------- */

		[data-mov="entra"] {
			animation: pic-entra-baixo cubic-bezier(0.16, 1, 0.3, 1) both;
			animation-timeline: view();
			animation-range: entry 0% entry 90%;
		}

		[data-mov="entra"][data-de="lado"] {
			animation-name: pic-entra-lado;
		}

		[data-mov="entra"][data-de="escala"] {
			animation-name: pic-entra-escala;
		}

		/*
			Escalonamento: filhos entram em cascata, não em bloco. É o detalhe
			que separa "a seção apareceu" de "a seção se montou".
		*/
		[data-mov-cascata] > * {
			animation: pic-entra-baixo cubic-bezier(0.16, 1, 0.3, 1) both;
			animation-timeline: view();
			animation-range: entry 0% entry 85%;
		}
	}
}

/* ---------- os quadros ---------- */

@keyframes pic-desenha {
	to {
		stroke-dashoffset: 0;
	}
}

@keyframes pic-abre {
	from {
		clip-path: inset(0 0 var(--pic-abre-de, 82%) 0);
	}

	to {
		clip-path: inset(0 0 0 0);
	}
}

@keyframes pic-deriva-x {
	from {
		transform: translate3d(var(--pic-deriva-de, 0%), 0, 0);
	}

	to {
		transform: translate3d(var(--pic-deriva-ate, -22%), 0, 0);
	}
}

@keyframes pic-parallax {
	from {
		transform: translate3d(0, var(--pic-parallax-de, 12%), 0);
	}

	to {
		transform: translate3d(0, var(--pic-parallax-ate, -12%), 0);
	}
}

@keyframes pic-painel {
	from {
		transform: translate3d(var(--pic-painel-de, -18%), 0, 0);
		opacity: 0.4;
	}

	to {
		transform: translate3d(0, 0, 0);
		opacity: 1;
	}
}

@keyframes pic-preenche {
	from {
		background-size: 0% 100%;
	}

	to {
		background-size: 100% 100%;
	}
}

@keyframes pic-entra-baixo {
	from {
		opacity: 0;
		transform: translate3d(0, 2.2rem, 0);
	}

	to {
		opacity: 1;
		transform: none;
	}
}

@keyframes pic-entra-lado {
	from {
		opacity: 0;
		transform: translate3d(-2.5rem, 0, 0);
	}

	to {
		opacity: 1;
		transform: none;
	}
}

@keyframes pic-entra-escala {
	from {
		opacity: 0;
		transform: scale(0.92);
	}

	to {
		opacity: 1;
		transform: none;
	}
}

/*
	Reserva, para navegador sem animation-timeline. O JavaScript marca o
	elemento quando ele aparece e a entrada acontece uma vez — sem amarração
	à rolagem, que não dá para emular barato. Os efeitos amarrados ficam no
	estado final, legíveis: nenhum conteúdo depende deles.
*/
@media (prefers-reduced-motion: no-preference) {
	.pic-sem-linha-do-tempo [data-mov="entra"],
	.pic-sem-linha-do-tempo [data-mov-cascata] > * {
		opacity: 0;
		transform: translate3d(0, 2.2rem, 0);
		transition: opacity 0.7s cubic-bezier(0.16, 1, 0.3, 1),
			transform 0.7s cubic-bezier(0.16, 1, 0.3, 1);
	}

	.pic-sem-linha-do-tempo [data-mov="entra"].e-visivel,
	.pic-sem-linha-do-tempo [data-mov-cascata] > .e-visivel {
		opacity: 1;
		transform: none;
	}
}

/* ======================================================================
   3. A LINGUAGEM DA ABERTURA, DISPONÍVEL PARA O SITE INTEIRO

   A abertura da Home estabeleceu três coisas que não são dela: são do site.
   Repetir o código em cada seção seria garantir que divergissem, então elas
   moram aqui, declaradas por atributo como o resto do vocabulário.

   1. LUZ (`data-luz`) — o facho difuso que atravessa uma superfície. Elipse
      com `closest-side`, que morre antes da própria borda: é isso que
      diferencia luz de retângulo claro passando. Inclinada, porque luz
      inclinada lê como luz.
   2. RELEVO (`data-relevo`) — a superfície cede sob o ponteiro: o lado onde o
      cursor está vai ao fundo. Os ângulos chegam em `--pic-rx` / `--pic-ry`,
      escritos pelo `movimento.js`; o CSS decide quando aplicar, pelo `:hover`.
   3. PONTEIRO (`data-ponteiro`) — a seção publica a posição do cursor em
      `--pic-px` / `--pic-py` (-1 a 1) e cada camada dentro dela anda o quanto
      quiser. É o que dá profundidade sem mover nada por JavaScript.
   ====================================================================== */

/* ---------- luz ---------- */

/*
	A luz precisa de um elemento próprio, e não de um pseudo do componente:
	`::before` e `::after` já costumam estar ocupados, e a luz tem de poder
	entrar em qualquer peça sem disputar.

	Quem recebe `data-luz` ganha `position: relative` aqui mesmo: a luz é
	absoluta dentro dele, e depender de cada componente lembrar disso é
	garantir que um dia um esqueça.
*/
[data-luz] {
	position: relative;
}

.pic-luz {
	position: absolute;
	inset: 0;
	overflow: hidden;
	border-radius: inherit;
	pointer-events: none;
	z-index: 2;
}

.pic-luz::before {
	content: "";
	position: absolute;
	top: -55%;
	bottom: -55%;
	left: -58%;
	width: 58%;
	opacity: 0;
	mix-blend-mode: screen;
	transform: translate3d(0, -7%, 0) rotate(var(--pic-luz-angulo, -15deg));
	background: radial-gradient(
		closest-side,
		rgba(216, 234, 255, 0.3),
		rgba(178, 204, 245, 0.12) 52%,
		rgba(0, 0, 0, 0) 78%
	);
}

@media (prefers-reduced-motion: no-preference) {
	/*
		Luz que passa sozinha, de vez em quando.

		Os seletores casam por PALAVRA (`~=`) e não por valor inteiro, então
		uma peça pode declarar `data-luz="passa toque"` e ter os dois: a
		passagem lenta que acontece sem ninguém pedir, e a passagem curta que
		responde ao ponteiro. Sem isso era preciso escolher entre a seção
		respirar sozinha e a seção responder — e a linguagem do site pede as
		duas coisas.
	*/
	[data-luz~="passa"] .pic-luz::before {
		animation: pic-luz-passa var(--pic-luz-ciclo, 19s) linear infinite;
		animation-delay: var(--pic-luz-atraso, 0s);
	}

	/*
		Luz ao toque: dispara a cada vez que o ponteiro entra, porque a regra
		só casa enquanto o `:hover` vale — sair e voltar recomeça a animação.
	*/
	[data-luz~="toque"]:hover .pic-luz::before,
	[data-luz~="toque"]:focus-visible .pic-luz::before {
		animation: pic-luz-passa 1.1s ease-out;
	}
}

@keyframes pic-luz-passa {
	0% {
		opacity: 0;
		transform: translate3d(0, -7%, 0) rotate(var(--pic-luz-angulo, -15deg));
	}

	1.5% {
		opacity: 0.4;
	}

	4% {
		opacity: 1;
	}

	6.5% {
		opacity: 0.4;
	}

	8%,
	100% {
		opacity: 0;
		transform: translate3d(390%, 7%, 0) rotate(var(--pic-luz-angulo, -15deg));
	}
}

/*
	No toque o ciclo é curto, então a passagem tem de ocupar quase todo ele —
	os mesmos quadros percentuais valem, só que em 1,1 s em vez de 19 s. Por
	isso a variante de toque usa outra curva de quadros.
*/
@media (prefers-reduced-motion: no-preference) {
	[data-luz~="toque"]:hover .pic-luz::before,
	[data-luz~="toque"]:focus-visible .pic-luz::before {
		animation-name: pic-luz-toque;
	}
}

/*
	Sobre superfície clara a luz precisa de menos força: `screen` satura
	quase de imediato, e o botão ciano vira um estouro branco. Mesma luz,
	menos ganho.
*/
.pic-botao--primario .pic-luz {
	opacity: 0.38;
}

@keyframes pic-luz-toque {
	0% {
		opacity: 0;
		transform: translate3d(0, -7%, 0) rotate(var(--pic-luz-angulo, -15deg));
	}

	18% {
		opacity: 1;
	}

	82% {
		opacity: 1;
	}

	100% {
		opacity: 0;
		transform: translate3d(390%, 7%, 0) rotate(var(--pic-luz-angulo, -15deg));
	}
}

/* ---------- relevo ---------- */

/*
	Perspectiva na PEÇA e transformação na FACE, nunca `preserve-3d` no
	contêiner: cada peça é um espaço 3D fechado em si, e o recorte de quem
	está em volta continua valendo.
*/
[data-relevo] {
	perspective: var(--pic-relevo-perspectiva, 900px);
}

.pic-face {
	transform: none;
	transition: transform 0.36s cubic-bezier(0.22, 1, 0.36, 1),
		box-shadow 0.36s ease;
}

@media (hover: hover) and (pointer: fine) {
	@media (prefers-reduced-motion: no-preference) {
		[data-relevo]:hover .pic-face,
		[data-relevo]:focus-within .pic-face {
			transform: rotateX(var(--pic-rx, 0deg)) rotateY(var(--pic-ry, 0deg))
				scale(var(--pic-relevo-escala, 1.015));
		}
	}
}

/* ---------- parar o que ninguém está vendo ---------- */

/*
	`movimento.js` marca com `pic-parado` a seção que saiu da tela, e é aqui
	que isso vira alguma coisa. Sem esta regra o atributo `data-pausa-fora`
	escrevia uma classe que ninguém lia — e animação infinita fora da tela é
	bateria queimada sem ninguém olhar. Numa página longa quase tudo está fora
	da tela quase o tempo todo.

	`!important` porque declaração de `animation` em atalho REDEFINE
	`animation-play-state` para `running`: qualquer regra de animação escrita
	depois desta venceria a pausa sem isso, e a pausa tem de ganhar sempre.
*/
.pic-parado,
.pic-parado *,
.pic-parado *::before,
.pic-parado *::after {
	animation-play-state: paused !important;
}

/* ---------- contagem por aparição ---------- */

/*
	Número que conta de 0 até o alvo quando APARECE na tela. Sem biblioteca e
	sem JavaScript de animação: uma ficha registrada como `<integer>` interpola
	no relógio, e `counter()` imprime o valor. Do JavaScript vem só o gatilho —
	uma classe, escrita por `IntersectionObserver`.

	**Por que não é mais amarrado à rolagem.** Era, e o cliente achou o defeito
	na raiz: rolagem incompleta revela um número FALSO. Quem parava no meio do
	percurso ficava com "+12 clientes atendidos" parado na tela, e ali ficava.
	Animação de relógio não tem esse estado: uma vez começada, ela sempre chega
	ao fim, com a página parada ou não, e em segundo plano também — animação de
	CSS corre no `document.timeline`, que não depende de quadro sendo
	desenhado.

	**O respiro.** Entre aparecer e começar a contar há 0,35 s de pausa. Ela
	existe porque o número quase sempre aparece junto com o resto do bloco:
	sem a pausa, a contagem acontece enquanto a peça ainda está chegando, e
	ninguém vê acontecer. A curva é de saída: sobe rápido e assenta no alvo,
	que é como um número procurado se comporta.

	A TROCA entre o número real e o contador acontece dentro da MESMA consulta
	que liga a animação, e agora também sob a MESMA classe do gatilho — e isso
	não é organização, é correção. Numa primeira versão a troca dependia só de
	uma classe de capacidade, e com `prefers-reduced-motion` a animação não
	rodava enquanto o contador ficava à vista: `--pic-n` parado em 0, e o
	visitante lia "+0 mil seguidores". Aqui, se a contagem não pode rodar — por
	preferência do visitante, por falta de suporte ou porque o gatilho nunca
	chegou —, quem aparece é o valor real e estático. Nunca um contador em
	zero.

	As duas capacidades testadas: `calc()` dentro de `counter-reset` (é ele que
	separa o milhar) e `round()`.
*/
/*
	`inherits: true`, e isto é o defeito mais caro do arquivo — o número ficava
	parado em "+0" na tela para todo mundo.

	Quem imprime o valor é `counter-reset` no `::before`, e pseudo-elemento
	herda do elemento que o origina. Com `inherits: false` a ficha animada
	simplesmente não chegava lá: o elemento marcava 20, o `::before` marcava o
	valor inicial, 0, e o visitante lia "+0 clientes atendidos". Medido nos
	dois lados antes de mexer, porque a ficha estava CERTA no elemento — olhar
	só ali dizia que estava tudo bem.

	Número errado na tela é pior que número sem efeito nenhum.
*/
@property --pic-n {
	syntax: "<integer>";
	initial-value: 0;
	inherits: true;
}

/* Preenche com zeros para "2.400" não virar "2.4" no meio da contagem. */
@counter-style pic-tres {
	system: numeric;
	symbols: "0" "1" "2" "3" "4" "5" "6" "7" "8" "9";
	pad: 3 "0";
}

.pic-conta-viva {
	display: none;
}

@media (prefers-reduced-motion: no-preference) {
	@supports (counter-reset: pic calc(1)) and (width: round(down, 3px, 2px)) {
		/*
			DUAS CLASSES, e cada uma responde por uma coisa.

			`pic-conta-pronta`, na raiz, diz que o gatilho existe — e é ela que
			autoriza a TROCA do número real pelo contador. A troca acontece no
			carregamento, e não no disparo: se esperasse o disparo, o visitante
			veria "+600" virar "+0" no instante em que a contagem começa, que é
			de novo um número falso na tela, só que por um quadro.

			`pic-conta-roda`, no número, diz que aquele número apareceu — e é
			ela que larga a animação.
		*/
		.pic-conta-pronta [data-conta] .pic-conta-real {
			display: none;
		}

		.pic-conta-pronta [data-conta] .pic-conta-viva {
			display: inline;
		}

		/*
			1,5 s para o percurso e 0,35 s de respiro antes de largar. `both`
			mantém o zero durante o respiro e o alvo depois do fim — em nenhum
			momento a ficha fica sem valor.
		*/
		.pic-conta-pronta [data-conta].pic-conta-roda .pic-conta-viva {
			animation: pic-conta 1.5s cubic-bezier(0.16, 1, 0.3, 1) 0.35s both;
		}

		[data-conta] .pic-conta-viva::before {
			counter-reset: pic-mil calc(round(down, var(--pic-n) / 1000, 1)) pic-res
				calc(var(--pic-n) - round(down, var(--pic-n) / 1000, 1) * 1000);
		}

		[data-conta="simples"] .pic-conta-viva::before {
			content: var(--pic-conta-prefixo, "+") counter(pic-res);
		}

		[data-conta="milhar"] .pic-conta-viva::before {
			content: var(--pic-conta-prefixo, "+") counter(pic-mil) "."
				counter(pic-res, pic-tres);
		}
	}
}

@keyframes pic-conta {
	from {
		--pic-n: 0;
	}

	to {
		--pic-n: var(--pic-alvo, 0);
	}
}

/* ---------- os sinais se organizam ---------- */

/*
	Peça que chega torta e fora de lugar e ASSENTA conforme a seção sobe. Não
	é entrada genérica: serve onde o assunto é justamente organização — o
	movimento diz o que o texto afirma.

	**Sem desfoque, por decisão do cliente.** A entrada tinha `blur(3px)` que
	ia a zero junto com o resto. O problema é que a animação é conduzida pela
	ROLAGEM, e não pelo relógio: quem para de rolar no meio do caminho fica com
	a peça parada e meio desfocada na tela — e peça desfocada parada não lê
	como entrada, lê como defeito de renderização. Posição e opacidade não têm
	esse risco: torta e clara ainda parece movimento; borrada parece erro.

	E sai de graça: `filter` obriga o navegador a rasterizar a camada de novo a
	cada passo da rolagem. É a mesma conta que tirou o desfoque da chuva de
	código, onde ele custava 5 fps medidos.

	**Sem giro, por pedido do design.** A peça chegava torcida alguns graus,
	cada uma com o seu ângulo. O site inteiro é construído em prumo — o painel,
	a grade, as cenas dos momentos —, e quatro peças tortas na tela contrariam
	esse prumo justamente enquanto o olho procura o alinhamento. O
	deslocamento sozinho dá a mesma leitura de "chegou e assentou" sem brigar
	com o sistema.

	**E o alvo é o GRUPO, não cada peça.** Quando cada cartão tinha o seu
	`data-mov`, cada um ganhava também a SUA linha do tempo: numa grade de duas
	fileiras, a de baixo entra depois da de cima, e as colunas nunca se
	alinhavam enquanto a animação corria — medidos 3 px de diferença numa
	coluna e 8 px na outra. Não se lia como quatro peças chegando; lia-se como
	grade torta. No contêiner, tudo anda junto e fica alinhado em todos os
	quadros, e de quebra são quatro animações a menos.

	Por isso o deslocamento padrão é só VERTICAL. Um bloco entrando de lado
	briga com a coluna de texto parada logo acima dele, que é a referência de
	alinhamento da página inteira.
*/
@media (prefers-reduced-motion: no-preference) {
	@supports (animation-timeline: view()) {
		[data-mov="assenta"] {
			animation: pic-assenta linear both;
			animation-timeline: view();
			animation-range: entry 5% cover 50%;
		}
	}
}

@keyframes pic-assenta {
	from {
		opacity: 0.25;
		transform: translate3d(var(--pic-assenta-x, 0), var(--pic-assenta-y, 2.2rem), 0);
	}

	to {
		opacity: 1;
		transform: none;
	}
}

/* ---------- revelação por máscara ---------- */

/*
	A imagem é descoberta por uma máscara que abre com a rolagem, da borda
	para dentro. É a mesma tese da curva: a forma da marca revelando, em vez de
	emoldurando.
*/
@media (prefers-reduced-motion: no-preference) {
	@supports (animation-timeline: view()) {
		[data-mov="revela"] {
			animation: pic-revela linear both;
			animation-timeline: view();
			animation-range: entry 0% cover 42%;
		}
	}
}

@keyframes pic-revela {
	from {
		clip-path: inset(0 var(--pic-revela-de, 78%) 0 0 round var(--pic-revela-raio, 4px));
	}

	to {
		clip-path: inset(0 0 0 0 round var(--pic-revela-raio, 4px));
	}
}

/* ---------- acender na altura da leitura (28/09/2026) ---------- */

/*
	`data-mov="acende"` — o bloco chega apagado e acende quando alcança a
	altura da leitura, pouco abaixo do meio da tela. Só opacidade: nem
	deslocamento nem desfoque, porque quem para de rolar no meio fica com um
	texto meio aceso, e meio aceso ainda lê — torto ou borrado, não.

	`data-acende-palavras` — o mesmo, palavra por palavra, numa frase só. Cada
	`.pic-palavra` tem em `--pic-pi` a posição dela na frase (0 a 1) e recebe
	a sua fatia da passagem do bloco. A linha do tempo é a do BLOCO, nomeada:
	as palavras de uma mesma linha teriam, cada uma na própria `view()`, o
	mesmo progresso, e a frase acenderia linha a linha em vez de palavra a
	palavra.

	Estado de repouso aceso nos dois: sem suporte ou com movimento reduzido,
	o texto está inteiro. Reserva no Firefox: `rolagem.js`.
*/
@media (prefers-reduced-motion: no-preference) {
	@supports (animation-timeline: view()) {
		[data-mov="acende"] {
			animation: pic-acende linear both;
			animation-timeline: view();
			animation-range: entry 100% cover 45%;
		}

		[data-acende-palavras] {
			view-timeline: --pic-frase block;
		}

		[data-acende-palavras] .pic-palavra {
			animation: pic-acende-palavra linear both;
			animation-timeline: --pic-frase;
			animation-range: cover calc(18% + var(--pic-pi, 0) * 34%) cover calc(24% + var(--pic-pi, 0) * 34%);
		}
	}
}

@keyframes pic-acende {
	from {
		opacity: 0.22;
	}

	to {
		opacity: 1;
	}
}

@keyframes pic-acende-palavra {
	from {
		opacity: 0.16;
	}

	to {
		opacity: 1;
	}
}
