/* site/css/site.css — o sistema visual do one-pager, fora do HTML.
 * PORQUÊ EXTERNO: todo CSS deste repo é inline, e isso já custou caro uma vez. A lição
 * está escrita em scripts/dashboards/README.md § "Por que assim (não repetir o erro)":
 * enquanto os controles eram injetados arquivo-por-arquivo, sempre sobrava alguém de fora
 * e cada rodada era retrabalho. Fonte única resolve. Aqui vale o mesmo, mais o orçamento:
 * site/index.html tem teto de 25 KB brotli (check-budget.sh) e a calculadora sozinha tem
 * 628 linhas de <style> inline.
 *
 * REGRA DURA: este arquivo NÃO pode conter um único valor literal de cor, fonte, espaço ou
 * duração. Só var(--token). Nada de #0B0908, nada de rgba(...), nada de "Bodoni Moda", nada
 * de 500ms escritos à mão — tudo isso vive em site/tokens/tokens.css, que é gerado e selado
 * por sha256. O gate V-05b (scripts/site/verify.sh) falha se aparecer.
 *
 * O gate roda sobre uma cópia deste arquivo SEM COMENTÁRIOS — a função `sem_comentarios`
 * do verify.sh remove os blocos de comentário CSS em memória, preservando as quebras de
 * linha para que o número de linha reportado seja o do arquivo original, e nunca reescreve
 * o arquivo de origem. Consequência prática e deliberada:
 * este cabeçalho pode nomear à vontade o que está proibido, inclusive citar um hexadecimal
 * de referência (o Premium Light do /form é #F4EEE3) sem se auto-invalidar. Comentário é
 * documentação; quem se adapta é o gate, não a redação.
 *
 * O QUE FICOU DELIBERADAMENTE DE FORA — `scroll-behavior: smooth`.
 * A calculadora tem essa diretiva (calculadora/index.html:69-71) e ela NÃO foi trazida.
 * Três razões, todas registradas: (1) colide com o pin/scrub do ScrollTrigger, que é a
 * base da coreografia da §4; (2) o DS v2.0 proíbe "bounce, elástico, rotação, parallax
 * pesado" e inércia de scroll é da mesma família estética; (3) o público desta página é
 * dona de clínica no telemóvel, entre pacientes — scroll sequestrado é a queixa nº1 de
 * site cinematográfico e um risco de acessibilidade. Se alguém sentir falta um dia, o
 * caminho é ScrollSmoother com smoothTouch: 0 e desligado sob movimento reduzido, nunca
 * esta diretiva.
 *
 * ORDEM DE CARGA: /tokens/tokens.css → <style> crítico do <head> → este arquivo.
 * O <style> crítico do index.html declara as regras @font-face (descritores não aceitam
 * var() nem calc(), é limitação da especificação) e repete o reset e a base, porque a
 * primeira dobra não pode esperar por este arquivo para saber a cor do fundo. As
 * repetições abaixo são idênticas às de lá — mesmos tokens, mesmos valores.
 */

:root {
  /* ── Lacunas nomeadas ────────────────────────────────────────────────────────
     Nada aqui é padrão local inventado, e nada aqui pode ser acrescentado ao
     tokens.css — aquele arquivo é gerado e selado por sha256; editá-lo à mão faz
     check-tokens.mjs sair 1. O procedimento correto está em SYNC.md § Lacunas: o
     que falta no DS vive com NOME LOCAL aqui, registrado, até a próxima ida ao
     Claude Design promovê-lo a token.

     O DS não expõe token para a intensidade do grão: a classe .sn-grain vem do
     base.css do DS, que não foi transportado por ser folha de estilo e não tabela
     de valores (SYNC.md § Fronteira do transporte, item 4). */
  --grao-opacidade: .055;

  /* color-scheme não é token — é propriedade com efeito próprio, e por isso o
     surfaces.css do DS a deixou de fora do transporte. SYNC.md § Fronteira, item 4
     nomeia este arquivo como o destino dela. Sem isto, a barra de rolagem e os
     controlos nativos renderizam claros sobre a base escura. */
  color-scheme: dark;
}

/* ══ Reset e base ═══════════════════════════════════════════════════════════════
   Copiados de calculadora/index.html:63-87, menos o scroll-behavior (acima) e menos
   o display:flex de card único, que é layout de calculadora e não de one-pager. */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

body {
  /* O par 100vh/100dvh é lição real de barra de endereço em telemóvel, não
     preciosismo: o segundo sobrepõe o primeiro onde é suportado. Unidade de
     viewport não é valor de design — é primitiva de layout — e por isso não é
     token, aqui nem no DS. */
  min-height: 100vh;
  min-height: 100dvh;
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  color: var(--text-primary);
  background: var(--surface-base);
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img, svg, canvas { display: block; max-width: 100%; }

/* `hidden` com !important, e o !important NÃO é preguiça — é obrigatório aqui.
   O atributo `hidden` do HTML vale `display:none` com a especificidade de uma folha de
   estilo do agente do usuário, que qualquer regra de autor derruba. Este arquivo declara
   `display: grid` em itens que também nascem `hidden` (as métricas pendentes da §2, o
   retrato da §7): sem o !important, a regra de layout ganharia por vir depois e uma célula
   sem valor confirmado apareceria vazia na faixa de dado — que é exatamente a falha de
   honestidade que a §2 existe para impedir. */
[hidden] { display: none !important; }

::selection { background: var(--ember-600); color: var(--text-primary); }

:focus-visible {
  outline: var(--border-width-thick) solid var(--text-premium);
  outline-offset: var(--space-1);
}

/* ══ Sistema tipográfico ════════════════════════════════════════════════════════
   Display para manchete, corpo para texto corrido, mono para TODO número e rótulo.
   O eixo de largura do Archivo é doutrina do DS (88–118) e chega por token; como
   font-stretch é percentagem e os tokens de largura são unitários, a conversão é
   por calc — que é permitido em propriedade, ao contrário do descritor. */
h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: var(--weight-regular);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tightest);
  text-wrap: balance;
}
h2 { font-size: var(--text-display); }
h3 { font-size: var(--text-h3); }

p { max-width: var(--measure); }

.overline {
  font-family: var(--font-data);
  font-size: var(--text-2xs);
  font-weight: var(--weight-regular);
  letter-spacing: var(--tracking-overline);
  text-transform: uppercase;
  color: var(--text-accent);
}

/* Todo número exibido passa por aqui. Sem tabular-nums, uma faixa de dado dança
   quando o valor muda de largura. */
.dado {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  font-stretch: calc(var(--width-normal) * 1%);
  letter-spacing: var(--tracking-normal);
}

/* ══ Textura da marca — grão e halos ════════════════════════════════════════════
   O grão é ruído gerado por filtro dentro de um SVG embutido: zero requisição,
   zero binário no repo, e o `stitchTiles` faz o ladrilho fechar sem costura. A
   frequência e o número de oitavas ficam literais dentro do data URI porque um
   data URI é uma string opaca — var() não é interpolado ali dentro. É a mesma
   fronteira do @font-face: onde a especificação não deixa a variável entrar, o
   valor fica literal e o motivo fica escrito.

   REGRA DURA, DESCOBERTA POR MEDIÇÃO — o grão nunca fica atrás de texto.
   Ele é um ELEMENTO próprio, aplicado a caixas que não contêm texto (a moldura do
   herói, o palco da §4), e nunca um pseudo-elemento de uma secção que envolve
   texto. A razão é o gate V-A11Y: o axe, motor do pa11y, desiste de calcular
   contraste quando encontra imagem — ou pseudo-elemento com imagem — atrás do
   texto, e devolve "Element's background color could not be determined due to a
   pseudo element". Isso NÃO é violação de razão de contraste; é `incomplete`. Mas
   o pa11y reporta `incomplete` como erro, e o gate fica vermelho.

   Medido nesta sessão, no estado exato deste plano: com o grão como ::after de
   .heroi e de #arquitetura, o pa11y devolvia 20 erros e o axe cru devolvia
   0 violations / 20 incomplete. Removendo só o grão de #arquitetura, as 14 da §4
   desapareceram. Nenhuma cor precisou de mudar — a razão real sempre passou.

   ONDE O GRÃO ENTRA: sobre fotografia, que é para o que ele existe no DS — a moldura
   do herói. Sobre o palco da §4 ele foi testado e retirado: numa caixa sem foto por
   baixo, uma camada de ruído a 5,5% desenha a própria borda e o palco passa a ler-se
   como um painel que ninguém desenhou. O diagrama é a textura da §4. */
.sn-grao,
.heroi__grao {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: var(--grao-opacidade);
  background-repeat: repeat;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='grao'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23grao)'/%3E%3C/svg%3E");
}

.sn-halo-ember { background-image: var(--halo-ember); }
.sn-halo-gold { background-image: var(--halo-gold); }

/* ══ Doutrina de movimento do DS — fade + 16px + 500ms ══════════════════════════
   Os três valores vêm de token: --motion-shift (= --space-4), --motion-dur
   (= --duration-scroll-reveal) e --motion-ease (= --ease-reveal).

   O ESTADO ESCONDIDO SÓ EXISTE QUANDO HÁ JAVASCRIPT. É o Pattern 1 (fallback-first)
   aplicado ao CSS: sem o marcador data-js na raiz — porque o script não carregou,
   falhou ou está desligado —, .revelar não esconde coisa nenhuma e o documento
   aparece inteiro. Esconder por CSS e revelar por JS é a forma mais comum de um
   site cinematográfico ficar em branco para quem tem JS desligado; aqui o padrão
   é o inverso, de propósito. O marcador é posto pelo boot.js (plano 07-08), que
   também é quem aplica a classe. */
[data-js] .revelar {
  opacity: 0;
  transform: translateY(var(--motion-shift));
  transition: opacity var(--motion-dur) var(--motion-ease),
              transform var(--motion-dur) var(--motion-ease);
}
[data-js] .revelar[data-revelado] {
  opacity: 1;
  transform: none;
}

/* ══ §2 · Faixa de dado ═════════════════════════════════════════════════════════
   O primeiro dos dois blocos de cor cheia da página (o segundo é a §8). O token é
   escrito como --toffee-700 e não como o alias --surface-accent, que aponta para o
   mesmo valor: 07-CONTEXT § Specifics 2 nomeia a cor, e nomear a cor no CSS mantém
   a linha do documento e a linha do código legíveis lado a lado.

   Sem grão e sem halo: esta caixa envolve texto, e qualquer imagem de fundo na cadeia
   faz o axe desistir de calcular contraste (ver § Textura da marca). O bloco cheio já
   é o efeito — não precisa de textura por cima.

   Contraste medido sobre --toffee-700: --text-primary dá 10,6:1 e --text-accent dá
   6,5:1. Os dois passam WCAG AA em qualquer tamanho, o que é o que permite o rótulo
   ficar pequeno sem virar violação. */
.dados {
  padding: var(--space-16) var(--space-6);
  background: var(--toffee-700);
}

/* `auto-fit` + minmax é o que faz a grade aceitar 2, 3 ou 4 itens sem uma linha de CSS
   nova quando os dois valores pendentes forem confirmados (bloqueio humano 2). O mínimo
   é --space-40 (160px): abaixo disso a coluna colapsa sozinha para uma só, que é o
   comportamento certo no telemóvel — a âncora de D-17 em Martian Mono é larga, e duas
   colunas apertadas partiriam o número ao meio. */
.dados__grade {
  width: 100%;
  max-width: var(--container-xl);
  margin-inline: auto;
  list-style: none;
  display: grid;
  gap: var(--space-10) var(--space-8);
  grid-template-columns: repeat(auto-fit, minmax(var(--space-40), 1fr));
}

.dados__item {
  display: grid;
  gap: var(--space-2);
  align-content: start;
}

/* O número herda de .dado (Martian Mono + tabular-nums + font-stretch por token) e aqui
   só ganha escala e cor. tabular-nums importa mesmo com número fixo: é o que garante que
   o dia em que o valor mudar de 7 para 8 a coluna não dança. */
.dados__valor {
  font-size: var(--text-data-lg);
  font-weight: var(--weight-regular);
  font-variant-numeric: tabular-nums;
  line-height: var(--leading-tight);
  color: var(--text-primary);
}

.dados__rotulo {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  letter-spacing: var(--tracking-normal);
  color: var(--text-accent);
}

/* ══ §3 · A virada ══════════════════════════════════════════════════════════════
   Fundo sólido, pelo mesmo motivo da §4: a seção envolve texto. */
.virada {
  padding: var(--space-24) var(--space-6);
  background: var(--surface-base);
}

.virada__conteudo {
  width: 100%;
  max-width: var(--container-lg);
  margin-inline: auto;
}

/* A manchete repete a mecânica do herói — Bodoni com uma palavra em itálico ember — de
   propósito: são as duas únicas frases da página com esse tratamento, e é isso que liga
   «Previsibilidade não é sorte» a «o problema quase nunca é só tráfego» como se fossem
   a mesma voz dizendo a mesma coisa de dois ângulos. */
.virada__manchete {
  font-size: var(--text-display);
  max-width: var(--container-md);
}
.virada__manchete em {
  font-style: italic;
  color: var(--text-hot);
}

.sintomas {
  list-style: none;
  margin-top: var(--space-12);
  max-width: var(--container-md);
  display: grid;
  gap: var(--space-6);
}

.sintoma {
  padding-top: var(--space-4);
  border-top: var(--rule-hairline) solid var(--border-subtle);
  font-size: var(--text-lg);
  line-height: var(--leading-relaxed);
  color: var(--text-secondary);
}

.virada__fecho {
  margin-top: var(--space-12);
  font-family: var(--font-display);
  font-size: var(--text-h2);
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-tight);
  color: var(--text-primary);
}

/* ══ §4 · Momento Arquitetura — o estado BASE ═══════════════════════════════════
   O que 100% dos visitantes veem nos primeiros ~800ms, e o que quem não tem WebGL
   vê sempre. Nada aqui depende de JavaScript. */
/* Fundo SÓLIDO, sem gradiente e sem pseudo-elemento com imagem: esta secção envolve
   texto, e qualquer imagem de fundo na cadeia faz o axe desistir de calcular o
   contraste (ver § Textura da marca). O --grad-fade-dark do DS entra na página quando
   houver uma secção sem texto para o receber. */
#arquitetura {
  position: relative;
  isolation: isolate;
  padding: var(--space-24) var(--space-6);
  background: var(--surface-base);
}

/* Uma coluna por omissão (o telemóvel é o caso base), duas a partir de 64rem — o mesmo
   ponto de corte do herói, pela mesma razão: custom property não é permitida na condição
   de uma media query, logo o valor é literal e o motivo fica escrito. */
.arquitetura__grade {
  width: 100%;
  max-width: var(--container-xl);
  margin-inline: auto;
  display: grid;
  gap: var(--space-12);
  align-items: center;
  grid-template-columns: 1fr;
}

@media (min-width: 64rem) {
  .arquitetura__grade {
    grid-template-columns: 1fr 1fr;
    gap: var(--space-16);
  }

  /* A coluna de texto acompanha o palco enquanto ele está pinado.
     MEDIDO no plano 07-08, em 1440x900: com o palco pinado por três telas, a célula da
     grelha passa a ter 3600px de altura, e a coluna de texto — que tem ~600px — fica
     centrada nela e sai da viewport ao fim da primeira tela. Consequência: os rótulos 1 e 5
     acendiam com o texto fora do ecrã, e o visitante via as camadas a montar-se ao lado de
     um vazio. Colada, ela fica ao lado do diagrama durante as três telas, que é a
     coreografia que 07-CONTEXT § Specifics 4 descreve: cada camada acende COM o seu rótulo.

     Depende da classe que o scroll.js põe, e não de uma media query sozinha, por duas
     razões: sem JavaScript não há pin nenhum, logo colar não faria sentido e `align-self`
     mudaria a composição aprovada do estado base; e a classe entra ANTES de o ScrollTrigger
     medir, o que evita medir um layout que ainda vai mudar. */
  #arquitetura.arquitetura--pinado .arquitetura__texto {
    position: sticky;
    top: var(--space-24);
    align-self: start;
  }
}

/* O palco: ocupa a viewport e comporta, sobrepostos na mesma célula de grelha, o
   SVG e o canvas. É este elemento que o ScrollTrigger vai pinar no plano 07-08 —
   e é por isso que ele não anima: anima-se o conteúdo dentro do palco, nunca o
   elemento pinado. */
#arquitetura-palco {
  position: relative;
  height: 100dvh;
  display: grid;
  place-items: center;
  isolation: isolate;
}

#arquitetura-fallback,
#arquitetura-canvas {
  grid-area: 1 / 1;
  width: 100%;
  height: 100%;
  max-width: var(--container-sm);
  transition: opacity var(--duration-slow) var(--ease-smooth);
}

/* A troca é só CSS. Quem alterna o atributo é o boot.js (plano 07-08), depois de a
   cascata de detecção devolver true; enquanto o atributo não for "webgl", o SVG é
   o que está no ar. */
#arquitetura-fallback { opacity: 1; }
#arquitetura-canvas { opacity: 0; }
#arquitetura[data-modo="webgl"] #arquitetura-fallback { opacity: 0; }
#arquitetura[data-modo="webgl"] #arquitetura-canvas { opacity: 1; }

/* As lajes. Nenhum fill ou stroke é escrito no markup: a cor entra por classe,
   daqui, por token — o que mantém o SVG inline dentro da regra do V-05b e faz o
   diagrama herdar automaticamente qualquer re-sincronização do Design System. */
#arquitetura-fallback .laje-topo {
  fill: var(--toffee-700);
  stroke: var(--border-accent);
  stroke-width: var(--rule-hairline);
}
#arquitetura-fallback .laje-esq { fill: var(--surface-tertiary); }
#arquitetura-fallback .laje-dir { fill: var(--surface-primary); }

/* O eixo ember: a mesma linha que, no canvas, vai receber o pulso do fecho. */
#arquitetura-fallback .eixo {
  fill: none;
  stroke: var(--ember-500);
  stroke-width: var(--border-width-thick);
  stroke-linecap: round;
}
#arquitetura-fallback .no {
  fill: var(--ember-400);
  stroke: var(--surface-base);
  stroke-width: var(--border-width);
}

.arquitetura__texto { max-width: var(--container-sm); }

.arquitetura__intro {
  margin-top: var(--space-6);
  font-size: var(--text-lg);
  line-height: var(--leading-relaxed);
  color: var(--text-secondary);
}

/* Os cinco rótulos. A numeração é do contador do CSS e não do markup: o número é
   apresentação da ordem, não conteúdo — e assim ele já nasce em Martian Mono
   tabular, como o DS exige de todo número exibido. */
.camadas {
  counter-reset: camada;
  list-style: none;
  margin-top: var(--space-10);
  display: grid;
  gap: var(--space-6);
}

.rotulo {
  counter-increment: camada;
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: var(--space-4);
  padding-top: var(--space-4);
  border-top: var(--rule-hairline) solid var(--border-subtle);
}
.rotulo::before {
  content: counter(camada, decimal-leading-zero);
  grid-row: 1 / 3;
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-xs);
  color: var(--text-premium);
}
.rotulo__nome {
  font-family: var(--font-data);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-wide);
  color: var(--text-primary);
}
.rotulo__linha {
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: var(--leading-relaxed);
  color: var(--text-secondary);
}

.arquitetura__fecho {
  margin-top: var(--space-12);
  font-family: var(--font-display);
  font-size: var(--text-h2);
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-tight);
  color: var(--text-primary);
}

/* ══ §5 · Prova ═════════════════════════════════════════════════════════════════
   A seção está `hidden` na Onda 1 e o CSS abaixo não pinta nada hoje. Ele existe
   escrito por antecipação, e por um motivo concreto: o contrato do card está
   documentado no HTML para o plano 07-13, e um contrato de markup sem o CSS
   correspondente convida quem chega depois a inventar classes novas — que é como
   `data-case=` deixaria de casar com o gate. Marcação e folha de estilo nascem
   juntas, mesmo que a seção só apareça na Onda 2. */
.prova {
  padding: var(--space-24) var(--space-6);
  background: var(--surface-base);
}

.prova__conteudo {
  width: 100%;
  max-width: var(--container-xl);
  margin-inline: auto;
}

.prova__manchete { font-size: var(--text-display); }

.prova__intro {
  margin-top: var(--space-6);
  font-size: var(--text-lg);
  line-height: var(--leading-relaxed);
  color: var(--text-secondary);
}

.cases {
  list-style: none;
  margin-top: var(--space-16);
  display: grid;
  gap: var(--space-8);
  grid-template-columns: repeat(auto-fit, minmax(var(--container-sm), 1fr));
}

.case {
  padding: var(--space-8);
  background: var(--surface-primary);
  border: var(--border-width) solid var(--border-subtle);
  border-radius: var(--radius-lg);
}

/* O número é a peça — por isso a escala de dado e não a de texto. */
.case__numero {
  font-size: var(--text-data-md);
  font-variant-numeric: tabular-nums;
  line-height: var(--leading-snug);
  color: var(--text-premium);
}

.case__cliente {
  margin-top: var(--space-4);
  font-size: var(--text-h4);
  color: var(--text-primary);
}

/* O tempo de relação persuade tanto quanto o resultado: prova retenção. */
.case__tempo {
  margin-top: var(--space-2);
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide);
  color: var(--text-muted);
}

/* ══ §6 · Como trabalhamos ══════════════════════════════════════════════════════
   Duas colunas a partir do mesmo ponto de corte do herói e da §4 (64rem, literal
   porque custom property não é permitida na condição de uma media query). O fecho
   atravessa as duas colunas: é a frase que fecha a seção, não a legenda de uma
   delas. */
.boutique {
  padding: var(--space-24) var(--space-6);
  background: var(--surface-base);
}

.boutique__grade {
  width: 100%;
  max-width: var(--container-xl);
  margin-inline: auto;
  display: grid;
  gap: var(--space-12);
  grid-template-columns: 1fr;
  align-items: start;
}

.boutique__manchete { font-size: var(--text-display); }

.boutique__intro {
  margin-top: var(--space-6);
  font-size: var(--text-lg);
  line-height: var(--leading-relaxed);
  color: var(--text-secondary);
}

.boutique__lista {
  list-style: none;
  display: grid;
  gap: var(--space-8);
}

.ponto {
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: var(--space-4);
  align-items: start;
  padding-top: var(--space-4);
  border-top: var(--rule-hairline) solid var(--border-subtle);
  font-size: var(--text-base);
  line-height: var(--leading-relaxed);
  color: var(--text-secondary);
}

/* O ícone vem do sprite same-origin (D-14: zero CDN) e herda a cor por
   currentColor — nenhum valor de cor existe no icons.svg. A altura de linha do
   primeiro parágrafo empurra o texto uns pixels abaixo do topo da caixa; o
   deslocamento alinha a marca com a primeira linha em vez de com a borda. */
.ico {
  width: var(--space-5);
  height: var(--space-5);
  margin-top: var(--space-1);
  color: var(--text-premium);
  flex: none;
}

.boutique__fecho {
  font-family: var(--font-display);
  font-size: var(--text-h2);
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-tight);
  color: var(--text-primary);
}

@media (min-width: 64rem) {
  .boutique__grade {
    grid-template-columns: 1fr 1fr;
    gap: var(--space-16);
  }
  .boutique__fecho {
    grid-column: 1 / -1;
    margin-top: var(--space-8);
  }
}

/* ══ §7 · O arquiteto ═══════════════════════════════════════════════════════════
   Uma coluna na Onda 1 — é o que a `<figure>` oculta produz naturalmente, sem
   nenhuma regra condicional: um item de grade que não existe não deixa buraco.
   Quando o retrato entrar (07-13), a regra de duas colunas lá em baixo passa a
   valer sozinha, sem mexer em mais nada. */
.arquiteto {
  padding: var(--space-24) var(--space-6);
  background: var(--surface-base);
}

.arquiteto__grade {
  width: 100%;
  max-width: var(--container-xl);
  margin-inline: auto;
  display: grid;
  gap: var(--space-12);
  grid-template-columns: 1fr;
  align-items: center;
}

/* A moldura do retrato, pronta para a Onda 2. Mesmo desenho da moldura do herói —
   borda fina, canto do DS, sombra — para que o rosto chegue com a mesma gramática
   visual do resto e não pareça uma foto colada por cima da página. */
.arquiteto__retrato {
  position: relative;
  overflow: hidden;
  max-width: var(--container-sm);
  aspect-ratio: 1 / 1;
  border: var(--border-width) solid var(--border-subtle);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
}
.arquiteto__retrato img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

.arquiteto__texto { max-width: var(--container-sm); }

.arquiteto__manchete { font-size: var(--text-display); }

.arquiteto__corpo {
  margin-top: var(--space-6);
  font-size: var(--text-lg);
  line-height: var(--leading-relaxed);
  color: var(--text-secondary);
}

@media (min-width: 64rem) {
  .arquiteto__grade { grid-template-columns: 1fr 1fr; gap: var(--space-16); }
  .fecho__bloco { padding: var(--space-20) var(--space-16); }
}

/* ══ §8 · CTA de fecho ══════════════════════════════════════════════════════════
   A seção fica na base escura; o BLOCO dentro dela é que é a cor cheia. A divisão
   não é estética — está escrita por extenso no comentário da §8 do index.html:
   texto claro sobre --ember-500 dá 3,8:1, o que passa WCAG AA só para texto grande.
   Consequência desenhada, e não contornada com truque de font-weight: dentro do
   bloco só entra tipo genuinamente grande (--text-display na manchete, --text-h2 no
   lead, que começa em 24px = 18pt) e o botão, que carrega fundo próprio. A nota fina
   vive fora do bloco, sobre a base, onde texto normal tem 5:1. */
.fecho {
  padding: var(--space-24) var(--space-6);
  background: var(--surface-base);
  display: grid;
  justify-items: start;
  max-width: var(--container-xl);
  margin-inline: auto;
}

.fecho__overline { max-width: var(--measure); }

.fecho__bloco {
  width: 100%;
  padding: var(--space-12) var(--space-8);
  background: var(--ember-500);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
}

.fecho__manchete {
  font-size: var(--text-display);
  max-width: var(--container-md);
  color: var(--text-primary);
}

/* --text-h2 e não --text-lg, e o motivo é medido, não estético: a escala começa em
   1,5rem = 24px = 18pt, que é exatamente o limiar de «texto grande» do WCAG — o que
   leva o requisito de contraste sobre o bloco ember de 4,5:1 para 3:1, e os 3,82:1
   reais passam. Diminuir esta linha uma escala reprova o gate V-A11Y.
   Se um dia a auditoria acusar isto na fronteira (raiz do documento com fonte menor
   que 16px, por exemplo), há duas saídas conhecidas e nenhuma delas é truque de
   font-weight: tirar o parágrafo de dentro do bloco, ou trocar o bloco para
   --ember-600, que passa em 5,8:1 com texto de qualquer tamanho. */
.fecho__lead {
  margin-top: var(--space-8);
  max-width: var(--container-md);
  font-size: var(--text-h2);
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-tight);
  color: var(--text-primary);
}

/* As duas negativas fecham o que o diagnóstico NÃO é — coladas ao parágrafo anterior
   porque são a mesma respiração, não um segundo argumento. */
.fecho__lead--limite { margin-top: var(--space-4); }

/* O botão invertido. Sobre o bloco ember, o --ember-600 do botão do herói ficaria
   quase invisível — dois tons vizinhos da mesma família. O escuro da base resolve
   as duas coisas de uma vez: separa do fundo por diferença de luminância e leva o
   texto para 17:1. */
.cta--inverso {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-12);
  background: var(--surface-base);
  color: var(--text-primary);
}
.cta--inverso:hover {
  background: var(--surface-secondary);
  box-shadow: var(--shadow-lg);
}
.cta--inverso:focus-visible {
  background: var(--surface-secondary);
  outline: var(--border-width-thick) solid var(--text-premium);
  outline-offset: var(--space-1);
}

.ico--cta {
  margin-top: var(--space-0);
  color: inherit;
}

.fecho__nota {
  margin-top: var(--space-6);
  max-width: var(--measure);
  font-size: var(--text-sm);
  line-height: var(--leading-relaxed);
  color: var(--text-muted);
}

/* Sublinhado sempre presente: a cor sozinha não pode ser o único indicador de que
   algo é um link (WCAG 1.4.1). */
.fecho__nota a,
.rodape__links a {
  color: var(--text-premium);
  text-decoration: underline;
  text-underline-offset: var(--space-1);
}
.fecho__nota a:hover,
.rodape__links a:hover { color: var(--text-hot); }

/* ══ Rodapé ═════════════════════════════════════════════════════════════════════
   Sem colunas de links, sem endereço, sem rede social: o único canal desta página é
   o /form. O que existe aqui é o nome, o link exigido pela LGPD e o ano. */
.rodape {
  padding: var(--space-12) var(--space-6);
  border-top: var(--rule-hairline) solid var(--border-subtle);
  background: var(--surface-base);
}

.rodape__grade {
  width: 100%;
  max-width: var(--container-xl);
  margin-inline: auto;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4) var(--space-8);
}

.rodape__marca {
  font-family: var(--font-data);
  font-size: var(--text-sm);
  letter-spacing: var(--tracking-wordmark);
  text-transform: uppercase;
  color: var(--text-primary);
}

.rodape__links { font-size: var(--text-sm); }

/* Linha de registro do controlador (razão social + CNPJ, e o canal do encarregado só na
   política). É identificação legal, não contato — por isso vive com o peso visual do ano,
   e não com o da marca. Deixa a página inicial declarar quem é a empresa que trata o dado
   pessoal recolhido pelo /form, sem abrir um canal fora do funil. */
.rodape__ano,
.rodape__registro {
  font-size: var(--text-xs);
  color: var(--text-muted);
}

.rodape__registro a {
  color: var(--text-premium);
  text-decoration: underline;
  text-underline-offset: var(--space-1);
}
.rodape__registro a:hover { color: var(--text-hot); }

/* ══ Movimento reduzido ═════════════════════════════════════════════════════════
   O tokens.css já zera as oito durações sob esta preferência, o que sozinho
   bastaria para o tempo. O que ele não pode fazer é anular um ESTADO: .revelar
   começa em opacity 0 com deslocamento, e com duração zero isso viraria um salto
   em vez de uma transição. Aqui o estado é anulado por completo — o conteúdo
   simplesmente está lá. Movimento reduzido é requisito de acessibilidade de
   SITE-03, não um extra. */
@media (prefers-reduced-motion: reduce) {
  [data-js] .revelar {
    opacity: 1;
    transform: none;
    transition: none;
  }
  #arquitetura-fallback,
  #arquitetura-canvas,
  .cta {
    transition: none;
  }
}
