/*
 * Movimento da Valoar.
 *
 * A pergunta que decidiu tudo aqui: que gesto pertence a ESTA marca?
 *
 * A direção aprovada é "catálogo de peça técnica", e o mundo dessa marca é o de
 * quem constrói sistema — tela real, número tabular, rótulo em mono, contagem de
 * projeto, ponto vivo no estado "no ar". O verbo desse mundo é MEDIR. Instrumento
 * mede, conta, preenche e trava na posição. Ele não flutua, não desfoca e não
 * deriva.
 *
 * Isso virou um filtro, e o filtro cortou coisa que estava na lista:
 *
 *   FORA · marquee de segmentos. Fileira infinita rolando é o gesto mais
 *          repetido da web hoje, e a própria base de UX diz que animação infinita
 *          serve para indicador de carregamento, não para decoração.
 *   FORA · holofote seguindo o cursor no card. É gradiente radial atrás do
 *          ponteiro: literalmente o "SaaS roxo com gradiente" que o prompt mestre
 *          proíbe como visual que denuncia layout de IA.
 *
 * DENTRO, porque medem:
 *
 *   · contador nos quatro números — é uma medição sendo tomada, e os números já
 *     nasceram em `tabular-nums` justamente para mudar sem empurrar o layout
 *   · leitura de progresso da rolagem no topo — é um instrumento, não um enfeite
 *   · entrada que TRAVA em vez de flutuar: aproximação rápida e parada seca
 *
 * A OUSADIA, e ela fica num lugar só
 * ----------------------------------
 * O H1. A Amberly Sans Black é o ativo tipográfico mais característico da marca e
 * hoje ele só aparece com fade, igual a todo o resto. A revelação por máscara,
 * subindo de baixo, faz o peso da fonte CHEGAR — e peso chegando é o que uma
 * black de display faz melhor do que qualquer outra coisa.
 *
 * Sem dividir o texto em elementos por caractere: a máscara é uma propriedade do
 * bloco, então o DOM continua com um nó de texto e o leitor de tela continua lendo
 * uma frase.
 *
 * BASE TÉCNICA
 * ------------
 * Animação dirigida por rolagem em CSS (`animation-timeline`), com o
 * IntersectionObserver como degradação. Não é preciosismo: a versão em CSS roda
 * fora da thread principal, então rolar a página não disputa tempo com nada e o
 * custo de INP é zero. Uma biblioteca de scroll faria o mesmo efeito pagando
 * dezenas de kilobytes e uma callback por quadro.
 *
 * Nada aqui esconde nada sem `.vlr-anima` no `<html>`, e essa classe é escrita
 * pelo `movimento.js`. Sem JS, a página aparece inteira.
 *
 * Projeto Gerado pelo Prompt Mestre do Desenvolvedor e Vibe Coder Dante Testa — www.dantetesta.com.br
 */

/* --------------------------------------------------------------------------
 * Curvas
 *
 * `--vlr-trava` é a curva da casa para entrada: sai rápido, chega e para seco,
 * com um respiro mínimo de acomodação. É o que separa "peça encaixando" de
 * "elemento deslizando", e é a diferença entre o site parecer instrumento e
 * parecer apresentação de slide.
 * ----------------------------------------------------------------------- */

:root {
	--vlr-trava: cubic-bezier(0.16, 0.9, 0.24, 1);
	--vlr-entrada: 1.05s;
}

/* --------------------------------------------------------------------------
 * A chegada
 *
 * O primeiro segundo do site, e era o que faltava: tudo aparecia pronto, de uma
 * vez, e página que se monta inteira no primeiro quadro parece exportada.
 *
 * A sequência é a da leitura, não a do DOM — quem é a empresa, o que ela diz, o
 * que sustenta, o que fazer, e por último a prova visual:
 *
 *   sobrelinha → título → apoio → ações → tela
 *
 * O passo é de 80ms e o último elemento entra antes dos 500ms. Acima disso a
 * chegada deixa de ser boas-vindas e vira espera, e o §22 é explícito: o usuário
 * chega ao conteúdo rápido.
 *
 * NÃO depende de JavaScript. É `animation` com `both`, então o navegador aplica
 * o estado inicial no primeiro quadro pintado e resolve sozinho — sem
 * interruptor, sem risco de conteúdo preso invisível se um script falhar. O
 * único portão é `prefers-reduced-motion`, mais abaixo.
 * ----------------------------------------------------------------------- */

@keyframes vlr-chega {
	from {
		opacity: 0;
		transform: translate3d(0, 14px, 0);
	}
}

@keyframes vlr-chega-tela {
	from {
		opacity: 0;
		transform: translate3d(0, 22px, 0) scale(0.985);
	}
}

[data-entra] {
	animation: vlr-chega 0.8s var(--vlr-trava) both;
	animation-delay: calc(var(--i, 0) * 130ms);
}

/*
 * A composição visual chega por último e com um passo a mais de percurso: ela é
 * a prova, e prova que chega junto com a promessa não é lida como prova.
 */
[data-entra-tela] {
	animation: vlr-chega-tela 1.05s var(--vlr-trava) both;
	animation-delay: calc(var(--i, 4) * 130ms);
}

/* --------------------------------------------------------------------------
 * Entrada dos blocos
 * ----------------------------------------------------------------------- */

@keyframes vlr-entra {
	from {
		opacity: 0;
		transform: translate3d(0, 26px, 0) scale(0.988);
	}
}

@keyframes vlr-entra-item {
	from {
		opacity: 0;
		transform: translate3d(0, 20px, 0);
	}
}

/*
 * Caminho 1: degradação por IntersectionObserver.
 *
 * Vale onde `animation-timeline` não existe. O bloco `@supports` mais abaixo
 * desliga tudo isto quando o navegador sabe fazer melhor.
 */
.vlr-anima [data-anima] {
	opacity: 0;
	transform: translate3d(0, 26px, 0) scale(0.988);
	transition:
		opacity var(--vlr-entrada) var(--vlr-trava),
		transform var(--vlr-entrada) var(--vlr-trava);
}

.vlr-anima [data-anima="dentro"] {
	opacity: 1;
	transform: none;
}

.vlr-anima [data-anima-lista] > * {
	opacity: 0;
	transform: translate3d(0, 20px, 0);
	transition:
		opacity var(--vlr-entrada) var(--vlr-trava),
		transform var(--vlr-entrada) var(--vlr-trava);
}

.vlr-anima [data-anima-lista][data-anima="dentro"] > * {
	opacity: 1;
	transform: none;
}

.vlr-anima [data-anima-lista][data-anima="dentro"] > :nth-child(1) { transition-delay: 0ms; }
.vlr-anima [data-anima-lista][data-anima="dentro"] > :nth-child(2) { transition-delay: 70ms; }
.vlr-anima [data-anima-lista][data-anima="dentro"] > :nth-child(3) { transition-delay: 140ms; }
.vlr-anima [data-anima-lista][data-anima="dentro"] > :nth-child(4) { transition-delay: 210ms; }
.vlr-anima [data-anima-lista][data-anima="dentro"] > :nth-child(5) { transition-delay: 280ms; }
.vlr-anima [data-anima-lista][data-anima="dentro"] > :nth-child(6) { transition-delay: 350ms; }
.vlr-anima [data-anima-lista][data-anima="dentro"] > :nth-child(n + 7) { transition-delay: 420ms; }

/*
 * Caminho 2: dirigido pela rolagem, no compositor.
 *
 * `animation-range: entry 8% cover 34%` quer dizer: começa quando o bloco entrou
 * 8% na tela e termina quando cobriu 34% dela. Amarrar ao progresso, e não a um
 * gatilho de tempo, é o que faz a entrada acompanhar o dedo de quem rola em vez
 * de acontecer no ritmo dela mesma.
 *
 * `animation-fill-mode: both` com `from` sozinho no keyframe: o estado final é o
 * natural do elemento, então nada precisa ser reafirmado.
 */
@supports (animation-timeline: view()) {
	.vlr-anima [data-anima],
	.vlr-anima [data-anima="dentro"] {
		opacity: 1;
		transform: none;
		transition: none;
		animation: vlr-entra linear both;
		animation-timeline: view();
		animation-range: entry 4% cover 52%;
	}

	/*
	 * A escada usa a mesma linha do tempo do PAI, e é isso que a torna barata: um
	 * cronômetro por grade, não um por card. Cada filho entra num trecho
	 * deslocado da mesma faixa.
	 */
	.vlr-anima [data-anima-lista] > *,
	.vlr-anima [data-anima-lista][data-anima="dentro"] > * {
		opacity: 1;
		transform: none;
		transition: none;
		transition-delay: 0ms;
		animation: vlr-entra-item linear both;
		animation-timeline: view();
		animation-range: entry 2% cover 38%;
	}

	.vlr-anima [data-anima-lista] > :nth-child(2) { animation-range: entry 7% cover 43%; }
	.vlr-anima [data-anima-lista] > :nth-child(3) { animation-range: entry 12% cover 48%; }
	.vlr-anima [data-anima-lista] > :nth-child(4) { animation-range: entry 17% cover 53%; }
	.vlr-anima [data-anima-lista] > :nth-child(5) { animation-range: entry 22% cover 58%; }
	.vlr-anima [data-anima-lista] > :nth-child(n + 6) { animation-range: entry 27% cover 63%; }

	/* O pai da escada não anima junto: dois movimentos sobrepostos no mesmo
	   pixel viram borrão, e a escada é a informação. */
	.vlr-anima [data-anima-lista] {
		animation: none;
	}
}

/* --------------------------------------------------------------------------
 * A assinatura: o título chega por máscara
 *
 * Só H1, e só uma vez por página. Se aparecer em h2 vira maneirismo, e
 * maneirismo repetido é o que faz um recurso parecer template.
 *
 * `mask-image` com gradiente que sobe: o texto é descoberto de baixo para cima
 * enquanto sobe alguns pixels. Numa black de display isso lê como peso
 * assentando; num peso normal seria só mais um fade.
 * ----------------------------------------------------------------------- */

@keyframes vlr-titulo {
	from {
		opacity: 0;
		transform: translate3d(0, 0.14em, 0);
		mask-position: 0 100%;
	}

	to {
		opacity: 1;
		transform: none;
		mask-position: 0 0%;
	}
}

/*
 * POR TEMPO, e não por rolagem. Isto começou errado e vale registrar.
 *
 * A primeira versão amarrou a máscara a `animation-timeline: view()`, como o
 * resto. Só que TODO H1 do site está acima da dobra — é o título da página. Uma
 * animação dirigida por rolagem que já nasce no fim do próprio percurso nunca
 * toca: o navegador pinta o estado final no primeiro quadro e pronto.
 *
 * O resultado é que a assinatura do site, o único gesto onde a ousadia foi
 * gasta, não acontecia em nenhuma página. Medido, não suposto: o H1 da Home
 * reportava `animationName: vlr-titulo` com o percurso já cumprido.
 *
 * Rolagem serve para o que ENTRA na tela. O título já está lá quando a página
 * abre, então ele pertence à chegada — e é por isso que o atraso sai do mesmo
 * `--i` da sequência.
 *
 * Não depende de JS pelo mesmo motivo da chegada: `animation` com `both` resolve
 * sozinha, e sem CSS de animação o título simplesmente aparece.
 */
[data-anima-titulo] {
	mask-image: linear-gradient(to bottom, #000 50%, transparent 50%);
	mask-size: 100% 200%;
	mask-repeat: no-repeat;
	animation: vlr-titulo 1.25s var(--vlr-trava) both;
	animation-delay: calc(var(--i, 1) * 130ms);
}

/* --------------------------------------------------------------------------
 * Leitura de progresso
 *
 * Um filete de 2px no topo, na cor da marca, que preenche conforme a página
 * anda. É instrumento: diz onde você está num documento longo. Zero JS —
 * `animation-timeline: scroll()` lê a barra de rolagem do documento direto no
 * compositor.
 *
 * Fica escondido onde `animation-timeline` não existe: barra de progresso
 * congelada em 0% é pior do que barra nenhuma, porque parece defeito.
 * ----------------------------------------------------------------------- */

.vlr-progresso {
	display: none;
}

@supports (animation-timeline: scroll()) {
	@keyframes vlr-progresso {
		from { transform: scaleX(0); }
		to   { transform: scaleX(1); }
	}

	.vlr-progresso {
		display: block;
		position: fixed;
		inset: 0 0 auto;
		z-index: 90;
		block-size: 2px;
		background: var(--vlr-roxo);
		transform-origin: 0 50%;
		animation: vlr-progresso linear both;
		animation-timeline: scroll();
	}
}

/* --------------------------------------------------------------------------
 * Profundidade nas telas do hero
 *
 * As duas telas sobrepostas andam em velocidades diferentes, e só elas: o §35
 * chama a tela de prova de que o produto existe, e dar profundidade a ela é dar
 * profundidade à prova. Texto NUNCA recebe parallax — atrapalha a leitura e é
 * a origem clássica do enjoo de rolagem.
 *
 * O deslocamento é pequeno de propósito. Acima de uns 10% as duas camadas
 * dessincronizam de um jeito que o olho lê como defeito, não como profundidade.
 * ----------------------------------------------------------------------- */

@supports (animation-timeline: view()) {
	@keyframes vlr-fundo {
		from { transform: translate3d(0, 4%, 0); }
		to   { transform: translate3d(0, -6%, 0); }
	}

	@keyframes vlr-frente {
		from { transform: translate3d(0, -3%, 0); }
		to   { transform: translate3d(0, 5%, 0); }
	}

	.vlr-anima .vlr-topo-pagina__tela--0,
	.vlr-anima .vlr-hero__tela--0 {
		animation: vlr-fundo linear both;
		animation-timeline: view();
		animation-range: cover;
		will-change: transform;
	}

	.vlr-anima .vlr-topo-pagina__tela--1,
	.vlr-anima .vlr-hero__tela--1 {
		animation: vlr-frente linear both;
		animation-timeline: view();
		animation-range: cover;
		will-change: transform;
	}
}

/* --------------------------------------------------------------------------
 * A seta do botão
 *
 * Nenhum botão do site tinha ícone, então o gesto mais óbvio de interface — a
 * seta que avança quando o ponteiro chega — não existia justamente nos CTAs
 * principais. O hover trocava o fundo e subia um pixel, e um pixel ninguém vê.
 *
 * A REGRA, e ela é semântica e não decorativa: a seta aparece em `a.vlr-btn` e
 * não em `button.vlr-btn`. Link LEVA a algum lugar, e a seta diz para onde;
 * botão FAZ alguma coisa, e apontar uma direção que não existe seria mentir
 * sobre o que vai acontecer. É por isso que "Enviar" e "Aceitar proposta" não
 * ganham seta, e "Ver os projetos" ganha.
 *
 * Zero marcação nova: sai de `::after`, então nenhum template precisou mudar.
 * ----------------------------------------------------------------------- */

a.vlr-btn::after {
	content: "→";
	display: inline-block;
	font-family: var(--vlr-dado);
	font-weight: 500;
	/* `1ch` de margem negativa aproxima a seta do rótulo: em mono ela vem com
	   folga própria, e sem isso o botão fica com um vão estranho no fim. */
	margin-inline-start: -2px;
	transition: transform var(--vlr-rapido) var(--vlr-trava);
}

a.vlr-btn:hover::after,
a.vlr-btn:focus-visible::after {
	transform: translateX(4px);
}

/*
 * O botão que abre link externo não recebe seta para a direita: ele não avança
 * na mesma página, sai dela. O WhatsApp é o caso, e a distinção importa porque
 * a seta prometeu continuidade.
 */
a.vlr-btn[target="_blank"]::after {
	content: "↗";
}

/*
 * O CTA da pílula do cabeçalho fica sem seta: ele já é o botão mais apertado do
 * site, e a seta ali empurra o rótulo para a segunda linha em telas médias.
 *
 * As pílulas de serviço do hero não entram nesta lista porque não são `.vlr-btn`
 * — elas já têm seta própria, escrita na folha da home, e a regra acima nunca as
 * alcançou.
 */
.vlr-topo a.vlr-btn::after {
	content: none;
}

/* --------------------------------------------------------------------------
 * Sublinhado que cresce
 *
 * Link em texto corrido tinha sublinhado fixo e mais nada. Um traço que cresce
 * da esquerda no hover custa nada e transforma o link em algo que responde.
 *
 * `text-decoration` não anima, então o traço é um pseudo-elemento. Só em link
 * dentro de prosa: em navegação e em card o alvo já é a caixa inteira, e um
 * segundo sinal ali seria ruído.
 * ----------------------------------------------------------------------- */

.vlr-prosa a:not(.vlr-btn),
.vlr-resultado__resumo a,
.vlr-404__zap a,
.vlr-rodape-proposta a {
	position: relative;
	text-decoration: none;
	background-image: linear-gradient(currentcolor, currentcolor);
	background-size: 0% 1px;
	background-position: 0 calc(100% - 1px);
	background-repeat: no-repeat;
	transition: background-size var(--vlr-medio) var(--vlr-trava);
	/* O traço estático fica até o hover assumir: link sem sublinhado nenhum
	   deixa de ser identificável, e cor sozinha não pode carregar essa
	   informação. */
	text-decoration: underline;
	text-decoration-color: rgb(from currentcolor r g b / 35%);
	text-underline-offset: 3px;
}

.vlr-prosa a:not(.vlr-btn):hover,
.vlr-resultado__resumo a:hover,
.vlr-404__zap a:hover,
.vlr-rodape-proposta a:hover {
	background-size: 100% 1px;
	text-decoration-color: transparent;
}

/* --------------------------------------------------------------------------
 * Costura entre seções
 *
 * As bandas clara e de superfície se encontravam numa linha reta e dura: duas
 * cores chapadas, corte seco, e a página lida como pilha de blocos em vez de um
 * documento só.
 *
 * A emenda ganha um degradê de 96px que dissolve a troca. Não é gradiente
 * decorativo — é a junta entre dois planos, e ela existe para o olho não
 * registrar um corte onde o conteúdo continua.
 *
 * `::before` no elemento de superfície, com `pointer-events: none` para não
 * atrapalhar clique em nada que encoste na borda.
 * ----------------------------------------------------------------------- */

.vlr-superficie {
	position: relative;
}

.vlr-superficie::before {
	content: "";
	position: absolute;
	inset: 0 0 auto;
	block-size: 96px;
	background: linear-gradient(to bottom, var(--vlr-papel), transparent);
	pointer-events: none;
}

/*
 * A banda que vem logo depois de outra superfície não recebe a costura: duas
 * emendas coladas viram uma faixa clara no meio do cinza, que é o contrário do
 * que a costura existe para fazer.
 */
.vlr-superficie + .vlr-superficie::before {
	content: none;
}

/* --------------------------------------------------------------------------
 * Hover com peso
 *
 * Cartão que levanta 2px é gesto que ninguém percebe. Levantar 4px E trocar o
 * degrau de sombra é o que faz a peça sair da mesa: são duas informações
 * concordando, e é assim que profundidade se lê.
 *
 * A imagem dentro do card cresce 3% num contêiner que corta. Movimento dentro da
 * moldura, com a moldura parada, é o gesto de vitrine — e a vitrine aqui é
 * sempre uma tela real.
 * ----------------------------------------------------------------------- */

.vlr-card,
.vlr-caso-card,
.vlr-atalho,
.vlr-capacidade,
.vlr-modelo,
.vlr-lado-cartao {
	transition:
		transform var(--vlr-rapido) var(--vlr-trava),
		border-color var(--vlr-rapido) var(--vlr-trava),
		box-shadow var(--vlr-medio) var(--vlr-trava);
}

.vlr-card:hover,
.vlr-caso-card:hover,
.vlr-caso-card:focus-within,
.vlr-atalho:hover,
.vlr-atalho:focus-visible {
	transform: translate3d(0, -4px, 0);
	box-shadow: var(--vlr-sombra-2);
}

.vlr-card__tela img,
.vlr-caso-card__img,
.vlr-frente__prova img {
	transition: transform 0.5s var(--vlr-trava);
}

.vlr-card:hover .vlr-card__tela img,
.vlr-caso-card:hover .vlr-caso-card__img,
.vlr-frente__prova:hover img {
	transform: scale(1.03);
}

/* --------------------------------------------------------------------------
 * Menos movimento
 *
 * Quem pede recebe a página pronta, e não a página congelada: as animações são
 * canceladas e o estado final é o natural do elemento. O `movimento.js` já sai
 * antes de escrever a classe nesse caso; isto aqui é o cinto.
 * ----------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
 * Celular
 *
 * Não é a versão de desktop encolhida. Três coisas mudam, e cada uma por um
 * motivo diferente:
 *
 * 1. O PARALLAX SAI. Ele depende de duas camadas com percursos diferentes, e
 *    numa tela estreita as telas já viraram uma só — sobra o custo de compositor
 *    sem o efeito que ele paga. Em aparelho de médio porte isso é frame perdido
 *    em troca de nada.
 *
 * 2. A ESCADA ENCURTA. Numa coluna única os cards entram um embaixo do outro, e
 *    o atraso que no desktop percorre a linha aqui vira fila de espera: o sexto
 *    card chegaria meio segundo depois de o dedo já ter passado por ele.
 *
 * 3. O PERCURSO DIMINUI. 26px numa tela de 390px é proporcionalmente o triplo do
 *    que é numa de 1280px. O mesmo número em telas diferentes não é o mesmo
 *    gesto.
 * ----------------------------------------------------------------------- */

@media (max-width: 62rem) {
	.vlr-anima .vlr-topo-pagina__tela--0,
	.vlr-anima .vlr-topo-pagina__tela--1,
	.vlr-anima .vlr-hero__tela--0,
	.vlr-anima .vlr-hero__tela--1 {
		animation: none;
		transform: none;
		will-change: auto;
	}

	@keyframes vlr-entra {
		from {
			opacity: 0;
			transform: translate3d(0, 16px, 0);
		}
	}

	@keyframes vlr-entra-item {
		from {
			opacity: 0;
			transform: translate3d(0, 12px, 0);
		}
	}

	.vlr-anima [data-anima-lista][data-anima="dentro"] > :nth-child(2) { transition-delay: 45ms; }
	.vlr-anima [data-anima-lista][data-anima="dentro"] > :nth-child(3) { transition-delay: 90ms; }
	.vlr-anima [data-anima-lista][data-anima="dentro"] > :nth-child(n + 4) { transition-delay: 135ms; }

	.vlr-superficie::before {
		block-size: 56px;
	}
}

@supports (animation-timeline: view()) {
	@media (max-width: 62rem) {
		.vlr-anima [data-anima-lista] > :nth-child(2),
		.vlr-anima [data-anima-lista] > :nth-child(3),
		.vlr-anima [data-anima-lista] > :nth-child(4),
		.vlr-anima [data-anima-lista] > :nth-child(5),
		.vlr-anima [data-anima-lista] > :nth-child(n + 6) {
			animation-range: entry 2% cover 38%;
		}
	}
}

/* --------------------------------------------------------------------------
 * Menos movimento
 *
 * Quem pede recebe a página pronta, e não a página congelada: as animações são
 * canceladas e o estado final é o natural do elemento. O `movimento.js` já sai
 * antes de escrever a classe nesse caso; isto aqui é o cinto.
 *
 * A chegada entra nesta lista mesmo não dependendo de JS: ela é a única
 * animação do site que roda sem interruptor, então é a única que precisaria ser
 * desligada por aqui de qualquer jeito.
 * ----------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
	[data-entra],
	[data-entra-tela],
	.vlr-anima [data-anima],
	.vlr-anima [data-anima="dentro"],
	.vlr-anima [data-anima-lista] > *,
	.vlr-anima [data-anima-lista][data-anima="dentro"] > *,
	[data-anima-titulo],
	.vlr-anima .vlr-topo-pagina__tela--0,
	.vlr-anima .vlr-topo-pagina__tela--1,
	.vlr-anima .vlr-hero__tela--0,
	.vlr-anima .vlr-hero__tela--1 {
		opacity: 1;
		transform: none;
		transition: none;
		transition-delay: 0ms;
		animation: none;
		mask-image: none;
		will-change: auto;
	}

	.vlr-progresso {
		display: none;
	}
}

/* Impressão nunca sai pela metade. */
@media print {
	.vlr-anima [data-anima],
	.vlr-anima [data-anima-lista] > *,
	[data-anima-titulo] {
		opacity: 1 !important;
		transform: none !important;
		animation: none !important;
		mask-image: none !important;
	}

	.vlr-progresso {
		display: none !important;
	}
}
