/* ============================================================
   ORYN — v2.css
   Camada da arquitetura nova (hub + páginas de frente).
   Depende de style.css: usa os MESMOS tokens, a mesma escala de 5
   degraus de fonte e os mesmos utilitários de entrada. Nada aqui
   redeclara cor, espaço ou tipo — se precisar de um valor novo, ele
   nasce como token lá, não como número solto aqui.
   ============================================================ */

/* ---------- 0. CORREÇÃO: .visually-hidden -------------------
   🐛 A classe era usada 5× no mockup que está no ar e NUNCA foi
   declarada em lugar nenhum. Consequência visível: os rótulos de
   apoio a leitor de tela estavam sendo PINTADOS — "Etapa 1 de 4: "
   aparecia dentro do título de cada passo do processo, e o <h2>
   "Depoimentos" idem.

   Classe que só existe no HTML não dá erro em nenhum lugar: não vai
   ao console, não quebra layout, não aparece em auditoria de
   contraste. Só aparece lendo a página — que é justamente o que
   ninguém faz depois da vigésima passada.

   `clip-path: inset(50%)` em vez do `clip: rect()` antigo: o clip
   legado é propriedade descontinuada e alguns leitores já ignoram.
   `white-space: nowrap` impede que o texto escondido force largura
   de rolagem no pai. */
.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden; white-space: nowrap;
  clip-path: inset(50%);
}

/* ---------- 0b. WORDMARK REAL DA ORYN ----------------------
   O logotipo do Instagram (@somosoryn) é um WORDMARK: "O R Y N" em
   caixa alta, geométrica de peso leve, tracking largo, mais uma linha
   descritora miúda embaixo.

   Não usamos a imagem do perfil: são 150×150 com artefato de JPEG —
   num cabeçalho de 22px já entrega borda suja, e em tela retina piora.
   Como o logotipo É tipografia, reproduzi-lo em fonte viva sai fiel,
   nítido em qualquer corpo e some do peso da página.

   A fonte certa é **Jost 300**, não Rajdhani. Comparado lado a lado com
   o logo real: o "O" da Jost é círculo perfeito, o "R" tem perna reta
   diagonal e o "N" é geométrico — as três coisas batem. Rajdhani é
   CONDENSADA: o "O" sai ovalado e o "N" ganha cantos. Era o que estava
   no site (`--f-disp`) e é o erro que esta regra corrige.
   (Jost é uma revival de Futura, e o logo é claramente Futura-based —
   por isso o encaixe não é coincidência.) */
.marca {
  font-family: var(--f-body);
  font-weight: 300;
  letter-spacing: .30em;
  /* o tracking empurra um vão fantasma depois da última letra; o
     padding-left negativo devolve o alinhamento óptico à margem */
  margin-right: -.30em;
  gap: 0;
}
/* O ponto dourado não existe no logotipo — foi invenção do mockup.
   Some do HTML; a regra fica como rede para qualquer cópia esquecida. */
.marca .ponto { display: none; }

/* ---------- 1. FUNDO 3D ------------------------------------
   O <canvas> é preenchido por js/malha.js. Fica atrás de tudo,
   não recebe clique e não entra na árvore de acessibilidade.

   REGRA DE CONTRASTE: este fundo é ORNAMENTO e não pode custar
   legibilidade. Duas travas:
     · alpha máximo de traço fica em .30 (o JS lê --alfa do HTML);
     · máscara radial apaga o centro-esquerda, que é justamente onde
       o texto assenta em todas as seções.
   A auditoria de contraste é feita sobre o DOM pintado COM o canvas
   ligado — medir só o token seria medir o que não está na tela. */
.malha {
  position: absolute;
  inset: 0;
  z-index: var(--z-bg);
  pointer-events: none;
  overflow: hidden;
  --malha-cor: var(--ouro);
}
.malha-cv { position: absolute; inset: 0; width: 100%; height: 100%; }

/* A máscara é o que permite o fundo existir sob texto. Sem ela, a
   malha cruza a coluna de leitura e cada linha do parágrafo passa
   por cima de um traço claro — o contraste médio continua bom e a
   leitura fica ruim mesmo assim, que é o pior dos casos: reprova no
   olho e passa no medidor. */
/* As paradas destes gradientes foram AJUSTADAS POR MEDIÇÃO, não por olho.
   Com o corte anterior (`at 82%`, transparente em 72%) a máscara ainda
   deixava passar ~33% da malha na borda direita do h1 — e como o traço
   dourado se ACUMULA onde as linhas se cruzam, aquele resto bastava para
   derrubar "Ideias que" (que é dourado) para 2,85:1, abaixo do piso 3.

   Alpha de traço não soma linearmente: um pixel onde seis arestas se
   cruzam a .30 chega perto do ouro puro. É por isso que estimar pelo
   `data-alfa` engana e a única leitura válida é amostrar o pixel. */
.malha--dir  { -webkit-mask-image: radial-gradient(100% 84% at 88% 50%, #000 10%, transparent 58%);
                       mask-image: radial-gradient(100% 84% at 88% 50%, #000 10%, transparent 58%); }
.malha--esq  { -webkit-mask-image: radial-gradient(100% 84% at 12% 50%, #000 10%, transparent 58%);
                       mask-image: radial-gradient(100% 84% at 12% 50%, #000 10%, transparent 58%); }
.malha--larga{ -webkit-mask-image: linear-gradient(180deg, transparent, #000 22%, #000 74%, transparent);
                       mask-image: linear-gradient(180deg, transparent, #000 22%, #000 74%, transparent); }

/* Canto inferior direito. Nasceu de uma falha medida: dentro do cartão
   da porta, a máscara vertical deixava o objeto cruzar a coluna do
   parágrafo e o contraste caía para 3,08:1 (piso 4,5). Aqui o objeto
   sangra pelo canto, abaixo do texto e ao lado do botão — a única área
   do cartão que nenhuma linha de leitura ocupa. */
.malha--canto{ -webkit-mask-image: radial-gradient(62% 48% at 96% 96%, #000 6%, transparent 62%);
                       mask-image: radial-gradient(62% 48% at 96% 96%, #000 6%, transparent 62%); }

/* o conteúdo sempre acima do fundo */
.sec > .env, .hero > .env { position: relative; z-index: var(--z-conteudo); }

/* No hero há DUAS camadas de fundo. A malha fica entre o vídeo e o
   texto: acima do showreel (z-index 0, com o véu já calibrado nele)
   e abaixo da coluna de leitura (z-index 2). Pôr a malha dentro de
   .hero-fundo faria o véu do vídeo apagá-la junto. */
.malha--hero { z-index: 1; }

/* Cinco passos, não quatro: o processo do hub precisa cobrir as duas
   frentes, e "produzir e validar" não existia na versão de agência. */
.proc-grade--5 { grid-template-columns: repeat(5, 1fr); }
@media (max-width: 1100px) { .proc-grade--5 { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 860px)  { .proc-grade--5 { grid-template-columns: 1fr 1fr; } }
@media (max-width: 520px)  { .proc-grade--5 { grid-template-columns: 1fr; } }

/* ---------- 1b. MENU ---------------------------------------
   Antes: dois links soltos numa barra de 1440px, rótulos diferentes em
   cada página, e nenhum sinal de onde o visitante está. Com o site
   virando hub de DUAS frentes, o menu passou a ser o lugar onde essa
   estrutura aparece — então ele é o mesmo nas três páginas e marca a
   frente ativa. */

/* Espaçamento menor: com 3 itens + CTA, o gap de 48px empurrava o botão
   para fora do respiro da direita em telas de 1280. */
.menu { gap: var(--s-6); }

.menu a:not(.btn) {
  font-size: var(--fs-micro);
  letter-spacing: var(--tr-wide);
  white-space: nowrap;
}

/* Estado ATIVO — o `main.js` escreve `aria-current="true"` na âncora de
   seção; a navegação entre páginas usa o valor semântico `page`. Os dois
   precisam acender, senão a marcação correta é a que não funciona. */
.menu a:not(.btn)[aria-current="page"] { color: var(--tx-1); }
.menu a:not(.btn)[aria-current="page"]::after { width: 100%; }

/* A frente ativa ganha um ponto dourado antes do rótulo: o sublinhado
   sozinho lê como hover, e hover é estado de passagem, não de lugar. */
.menu a:not(.btn)[aria-current="page"]::before {
  content: ''; display: inline-block;
  width: 4px; height: 4px; margin-right: var(--s-2);
  background: var(--ouro); vertical-align: middle;
}

/* --- gaveta mobile: agrupada, não uma lista chapada --- */
.gaveta-rot {
  font-size: var(--fs-micro); letter-spacing: var(--tr-wide);
  text-transform: uppercase; color: var(--tx-3);
  line-height: var(--lh-ui); margin-top: var(--s-6); margin-bottom: var(--s-2);
}
.gaveta-rot:first-child { margin-top: 0; }
.gaveta a:not(.btn)[aria-current="page"] { color: var(--ouro); }
.gaveta a:not(.btn)[aria-current="page"] .num { color: var(--tx-3); }

/* 🐛 ARMADILHA DO FLEX CENTRADO — medida, não suposta.
   A gaveta era `justify-content:center` sem rolagem. Em 360×640 o
   conteúdo passou a medir 707px: sobra 67px que o `center` joga METADE
   para fora do topo e metade para fora da base, e o navegador **não
   deixa rolar até lá** (é o clássico do overflow em container centrado).
   Resultado: "Chamar no WhatsApp" — o CTA do menu mobile — inalcançável.
   Foi o que eu mesmo causei ao agrupar a gaveta com dois rótulos.

   `safe center` resolveria, mas degrada para `center` justamente nos
   navegadores que não o suportam, ou seja, falha onde importa. A dupla
   `flex-start` + margens automáticas no primeiro e no último filho faz
   o mesmo com suporte universal: centraliza quando cabe, e as margens
   colapsam para 0 quando não cabe, deixando tudo alcançável na rolagem. */
.gaveta {
  justify-content: flex-start;
  overflow-y: auto;
  overscroll-behavior: contain;
}
.gaveta > :first-child { margin-top: auto; }
.gaveta > :last-child  { margin-bottom: auto; }

/* Tela curta: o corpo do item cede antes do conteúdo. Seis links em
   44px de Rajdhani não cabem em 640px de altura, e cortar item de menu
   é pior do que reduzi-lo. */
@media (max-height: 720px) {
  .gaveta { padding-block: var(--s-9) var(--s-7); gap: 0; }
  .gaveta a:not(.btn) { font-size: clamp(1.1875rem, 5.4vw, 1.625rem); padding-block: var(--s-3); }
  .gaveta-rot { margin-top: var(--s-4); }
  .gaveta .btn { margin-top: var(--s-5); }
}

/* ---------- 1c. BOTÃO DE WHATSAPP --------------------------
   Era um círculo de 56px com ícone de 26. Agora 64px (o piso de alvo
   tocável confortável é 48; 64 é o que um CTA flutuante merece) e o
   ícone sobe para 30.

   Em ponteiro fino ele ABRE numa pílula com rótulo. O ícone do WhatsApp
   sozinho diz "canal", não diz "fale com a gente" — e é o único elemento
   da tela que persegue o visitante, então precisa justificar a presença
   com palavra. Em toque continua círculo: não há hover, e a pílula
   comeria a largura útil. */
.zap {
  width: auto; height: 64px; border-radius: 999px;
  display: flex; align-items: center; justify-content: center;
  padding-inline: 17px;                    /* 30 do ícone + 34 = 64: círculo exato */
  /* respeita a faixa do iPhone; sem isto o botão encosta na barra de gestos */
  bottom: max(clamp(16px, 3vw, 28px), env(safe-area-inset-bottom, 0px));
}
.zap .ico { width: 30px; height: 30px; flex: none; }

.zap-txt {
  max-width: 0; opacity: 0; overflow: hidden; white-space: nowrap;
  margin-left: 0;
  font-family: var(--f-body); font-size: var(--fs-micro); font-weight: 600;
  letter-spacing: .04em; line-height: var(--lh-ui);
  transition: max-width .45s var(--e-expo), opacity .28s var(--e-expo),
              margin-left .45s var(--e-expo);
}
@media (hover: hover) and (pointer: fine) {
  .zap:hover .zap-txt, .zap:focus-visible .zap-txt {
    max-width: 200px; opacity: 1; margin-left: 11px;
  }
  /* a pílula cresce para a esquerda; sem `scale` no hover o movimento
     lateral já basta e o botão não "pula" sob o cursor */
  .zap:hover, .zap:focus-visible { transform: translateY(-2px); }
}

/* Chamada de atenção: DOIS pulsos e para. Anel infinito ao lado do
   conteúdo é ruído permanente — o objetivo é ser notado uma vez. */
.zap::after {
  content: ''; position: absolute; inset: 0; border-radius: inherit;
  border: 1px solid var(--ouro); pointer-events: none;
  opacity: 0;
}
.zap[data-visivel="true"]::after { animation: zap-pulso 2.1s var(--e-expo) 2; }
@keyframes zap-pulso {
  0%   { opacity: .55; transform: scale(1); }
  70%  { opacity: 0;   transform: scale(1.45); }
  100% { opacity: 0;   transform: scale(1.45); }
}

@media (prefers-reduced-motion: reduce) {
  .zap::after { animation: none !important; opacity: 0; }
  .zap-txt { transition: none; }
}

/* ---------- 1d. PREVIEW DO CASE: ENTRADA RÁPIDA ------------
   O fade era de .55s. Mesmo com o vídeo já tocando, meio segundo de
   crossfade LÊ como atraso — o olho registra "demorou", não "entrou
   suave". .18s é o limiar onde a transição ainda existe (não é um
   corte seco) e já não se percebe espera.

   A saída fica mais lenta que a entrada de propósito: sair devagar
   parece elegante, entrar devagar parece lento. */
.case-preview { transition: opacity .18s var(--e-out); }
.case:not([data-tocando]) .case-preview { transition: opacity .34s var(--e-out); }

/* o empurrãozinho de escala da foto acompanha a mesma pressa */
.case[data-tocando] .case-img { transition: transform .22s var(--e-out); }

/* ---------- 1e. FORMA ORGÂNICA -----------------------------
   Pedido do Onil: "sem esses quadrados e retângulos, mais orgânico".
   Isso REVOGA a decisão anterior desta folha (`--r-0: 0px`, "a marca é
   angular: raio zero é decisão, não esquecimento"). Era uma decisão
   nossa; a régua agora é a do cliente. Fica registrado para ninguém
   "corrigir" isto de volta achando que foi descuido.

   O arredondamento NÃO é uniforme, e a diferença é o que separa
   "orgânico" de "tudo com border-radius":
   · controle (botão, chip, filtro) → **pílula total**. É o que a mão
     espera tocar;
   · superfície de conteúdo (cartão de dor, porta, serviço) → raio
     médio. Arredondar pouco parece defeito, arredondar muito vira
     balão;
   · FOTO de portfólio → continua reta. A grade sangra de borda a borda
     e é o gesto mais forte da página; cantinho redondo em foto
     full-bleed a transforma em "card de blog". */
:root {
  --r-suave: 18px;
  --r-medio: 12px;
  --r-pill:  999px;
}

.btn            { border-radius: var(--r-pill); }
.btn--linha     { border-radius: var(--r-pill); }
.filtro button  { border-radius: var(--r-pill); }
.porta-itens span,
.tag            { border-radius: var(--r-pill); }
.pend           { border-radius: var(--r-pill); }

.porta, .dor, .svc, .campo--arq { border-radius: var(--r-suave); }
.aviso-gate     { border-radius: 0 var(--r-medio) var(--r-medio) 0; }
.lb-cx          { border-radius: var(--r-medio); }

/* o quadrinho do ícone vira círculo — é o elemento mais "peça de
   máquina" da folha e o que mais lucra em virar orgânico */
.svc .ico-cx        { border-radius: 50%; }
.svc .ico-cx::before{ border-radius: 50%; }

/* O preenchimento do botão de linha era um retângulo subindo; num
   contorno de pílula ele vazava pelos cantos. */
.btn--linha::before { border-radius: inherit; }

/* A porta tem `overflow:hidden` e o fundo 3D dentro: sem herdar o raio,
   o canvas desenha quadrado por cima do canto arredondado. */
.porta .malha, .porta .malha-cv { border-radius: inherit; }

@media (max-width: 860px) {
  /* raio menor em tela estreita: o mesmo 18px come proporcionalmente
     muito mais do cartão e a caixa começa a parecer uma pastilha */
  :root { --r-suave: 14px; }
}

/* ---------- 1f. COSTURA ENTRE SEÇÕES -----------------------
   Pedido: "mais fluidez". A página emendava seção com seção por um
   `border-top` de 1px cheio, de ponta a ponta — uma régua. Régua separa;
   o pedido era o contrário.

   Trocado por dois elementos que se somam:
   · um FIO que nasce e morre em transparente, com um ponto de ouro no
     meio. Ele marca a emenda sem cortar a página em fatias;
   · um HALO baixíssimo logo abaixo, que faz a cor da seção nova subir
     por dentro da anterior em vez de começar numa linha dura.
   Os dois são pseudo-elementos: zero markup, zero peso. */
.sec + .sec { border-top: 0; }

.sec + .sec::before {
  content: ''; position: absolute; z-index: 1;
  left: 0; right: 0; top: 0; height: 1px; pointer-events: none;
  background: linear-gradient(90deg,
    transparent 0%, var(--linha) 14%,
    var(--ouro-esc) 50%,
    var(--linha) 86%, transparent 100%);
  opacity: .7;
}

.sec + .sec::after {
  content: ''; position: absolute; z-index: 0;
  left: 0; right: 0; top: 0; height: 190px; pointer-events: none;
  background: radial-gradient(60% 100% at 50% 0%, var(--ouro-veu) 0%, transparent 72%);
}

/* A faixa clara e o cartão têm cor própria; o halo dourado sobre elas
   suja em vez de emendar. */
.sec--carta + .sec::after, .sec + .sec--carta::after { display: none; }

/* ---------- 1g. ENTRADA MAIS FLUIDA ------------------------
   O reveal entrava só por deslocamento (16px) — movimento de bloco,
   duro. Uma escala mínima junto (0.985 → 1) muda a leitura de "o
   elemento pulou para o lugar" para "o elemento assentou". 1,5% é
   proposital: acima de 3% vira zoom e o olho percebe o truque.
   `scale` e `translate` são propriedades separadas (não `transform`),
   então convivem sem uma sobrescrever a outra. */
.js .rev        { scale: .985; transition-property: opacity, translate, scale; }
.js .rev.mostra { scale: 1; }

.js .escada > *        { scale: .99; transition-property: opacity, translate, scale; }
.js .escada.mostra > * { scale: 1; }

@media (prefers-reduced-motion: reduce) {
  .js .rev, .js .escada > * { scale: 1; }
}

/* ---------- 1h. PARALLAX DENTRO DO CARD --------------------
   A imagem passa a ser MAIOR que o card e a deslizar dentro dele
   conforme a página rola. Sem a folga de 18% ela não teria para onde
   ir: a borda apareceria no primeiro pixel de deslocamento.

   `inset:0` já fixou top/right/bottom/left, então mudar só `height`
   não adianta — o `bottom:0` continuaria mandando. Por isso o
   `bottom:auto` explícito, que é o tipo de coisa que se descobre
   olhando por que nada mudou.

   ⚠️ O deslocamento é aplicado pelo JS na propriedade `translate`,
   NUNCA em `transform`. O hover do card já usa `transform: scale()`,
   e escrever transform pelo script apagaria a escala — as duas
   propriedades são independentes justamente para conviverem. */
.case-img, .case-preview, .case-vazio {
  height: 118%;
  top: -9%;
  bottom: auto;
}

/* o `will-change` entra e sai pelo JS, só nos cards em cena: deixá-lo
   fixo em 14 cards promove 14 camadas de composição para sempre */

@media (prefers-reduced-motion: reduce) {
  .case-img, .case-preview, .case-vazio {
    height: 100%; top: 0; bottom: 0; translate: none !important;
  }
}

/* ---------- 1i. INCLINAÇÃO 3D DO CARD ----------------------
   O card gira em perspectiva seguindo o cursor. Serve à tese do site
   — quem vende 3D não pode ter portfólio chapado — e é o único ponto
   onde a foto vira objeto em vez de retângulo.

   POR QUE CABE SEM COLIDIR: o `.case` não usava `transform` (a escala
   de hover e a da cortina moram na `.case-img`) e a `translate` está
   ocupada pelo parallax da foto. Sobrou exatamente o `transform` do
   card. Esse mapeamento é frágil de propósito lembrar:
     .case      → transform  (inclinação)
     .case-img  → transform  (escala de hover/cortina)
     .case-img  → translate  (parallax)
   Escrever qualquer um dos três no lugar errado apaga outro. */
.case-grade { perspective: 1500px; }

.case {
  transform: rotateX(0deg) rotateY(0deg);
  transition: transform .55s var(--e-expo);
}
/* enquanto o cursor está dentro, transição LONGA vira atraso: o card
   perseguiria o mouse com meio segundo de sobra. Curta e linear aqui;
   a volta ao repouso é que merece a curva. */
.case[data-inclina] { transition: transform .1s linear; }

/* Brilho que segue o cursor — é ele que faz a inclinação parecer
   superfície e não recorte girando.
   ⚠️ A máscara corta o brilho ANTES do terço inferior: é onde vive o
   título do case, e clarear o fundo ali derrubaria o contraste do
   texto branco. Efeito nenhum vale uma falha de leitura. */
.case::after {
  content: ''; position: absolute; inset: 0; z-index: 3;
  pointer-events: none; opacity: 0;
  transition: opacity .4s var(--e-out);
  background: radial-gradient(38% 52% at var(--gx, 50%) var(--gy, 50%),
              rgba(255,255,255,.13) 0%, transparent 68%);
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 44%, transparent 78%);
          mask-image: linear-gradient(180deg, #000 0%, #000 44%, transparent 78%);
}
.case[data-inclina]::after { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .case { transform: none !important; transition: none; }
  .case::after { display: none; }
}
/* toque não tem cursor para seguir: a inclinação sairia de um único
   ponto de contato e ficaria aleatória */
@media (hover: none) {
  .case { transform: none !important; }
  .case::after { display: none; }
}

/* ---------- 2. HERO DO HUB --------------------------------- */
.hero--hub h1 { max-width: 20ch; }
.hero--hub .lead { max-width: 54ch; }
.hero-linha {
  display: flex; align-items: center; gap: var(--s-4);
  font-size: var(--fs-micro); letter-spacing: var(--tr-wide);
  text-transform: uppercase; color: var(--ouro);
  font-family: var(--f-disp); font-weight: 500;
  margin-bottom: var(--s-6);
}
.hero-linha::before { content: ''; width: 42px; height: 1px; background: var(--ouro); flex: none; }

/* ---------- 3. AS DUAS PORTAS ------------------------------
   O elemento mais importante do site: é ele que impede a leitura de
   "agência de um lado, impressora do outro". Peso IGUAL entre as
   duas — mesma largura, mesmo tipo, mesma altura mínima. Qualquer
   assimetria aqui vira hierarquia, e hierarquia aqui é erro. */
.portas { display: grid; grid-template-columns: 1fr 1fr; gap: 2px; margin-top: var(--s-8); }

.porta {
  position: relative;
  display: flex; flex-direction: column;
  min-height: 460px;
  padding: var(--s-8) var(--s-7) var(--s-7);
  background: var(--bg-1);
  border: var(--borda);
  overflow: hidden;
  transition: background var(--d-mid) var(--e-out), border-color var(--d-mid) var(--e-out);
}
.porta:hover, .porta:focus-within { background: var(--bg-2); border-color: var(--ouro-esc); }

/* 🐛 `:not(.malha)` NÃO é firula. Sem ele, `.porta > *` (0,1,0) vence
   `.malha` (0,1,0) por vir depois na folha e reescreve o `position`
   do fundo de absolute para relative. Com `inset:0` sem efeito e sem
   conteúdo, o <div> colapsa para ALTURA ZERO — o canvas nasce no
   tamanho padrão de 300×150, `medir()` devolve false e a seção fica
   sem fundo, calada, sem nada no console.

   É a SEXTA vez que esta folha é mordida pelo mesmo padrão (as cinco
   anteriores estão no handoff: .menu a, .proc p, .gaveta a, a media
   query de altura e o display do .case-play). A regra da casa existe
   por isso: seletor de contexto nunca captura elemento genérico sem
   excluir o componente. */
.porta > *:not(.malha) { position: relative; z-index: var(--z-conteudo); }
.porta > .malha { z-index: 0; }

.porta-num {
  font-family: var(--f-disp); font-size: var(--fs-label);
  letter-spacing: var(--tr-wide); color: var(--ouro);
  line-height: var(--lh-ui);
}
.porta h2 {
  font-size: var(--fs-h3); margin-top: var(--s-5);
  letter-spacing: var(--tr-mid); color: var(--tx-1);
}
.porta p { font-size: var(--fs-sm); color: var(--tx-2); margin-top: var(--s-4); max-width: 38ch; }

.porta-itens { margin-top: var(--s-6); display: flex; flex-wrap: wrap; gap: var(--s-2); }
.porta-itens span {
  font-size: var(--fs-micro); letter-spacing: var(--tr-tight);
  color: var(--tx-2); padding: 5px var(--s-3);
  border: 1px solid var(--linha); line-height: var(--lh-ui);
}
/* o link do rodapé do cartão empurrado para baixo: as duas portas
   terminam na mesma linha mesmo com quantidade de texto diferente */
.porta .btn { margin-top: auto; align-self: flex-start; }

/* toda a área do cartão clicável, sem aninhar <a> dentro de <a> */
.porta-alvo::after { content: ''; position: absolute; inset: 0; z-index: 3; }

/* ---------- 4. COSTURA (diferencial integrado) ------------- */
.costura { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s-7); margin-top: var(--s-8); }
.costura article { padding-top: var(--s-5); border-top: 1px solid var(--ouro-esc); }
.costura h3 {
  font-family: var(--f-body); font-size: var(--fs-label); font-weight: 600;
  letter-spacing: var(--tr-wide); text-transform: uppercase; color: var(--tx-1);
  margin-bottom: var(--s-3);
}
.costura p { font-size: var(--fs-sm); color: var(--tx-2); }

/* ---------- 5. JORNADA (fita de etapas) -------------------- */
.jornada {
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(150px, 1fr);
  gap: 0; margin-top: var(--s-8); border-top: 1px solid var(--linha);
  overflow-x: auto; scrollbar-width: thin;
}
.jornada article { padding: var(--s-6) var(--s-4) 0 0; position: relative; }
.jornada article::before {
  content: ''; position: absolute; top: -1px; left: 0; width: 10px; height: 3px; background: var(--ouro);
}
.jornada .etapa-num {
  font-family: var(--f-disp); font-size: var(--fs-micro); letter-spacing: var(--tr-wide);
  color: var(--ouro); line-height: var(--lh-ui);
}
.jornada h3 {
  font-family: var(--f-body); font-size: var(--fs-label); font-weight: 600;
  letter-spacing: var(--tr-mid); text-transform: uppercase;
  color: var(--tx-1); margin: var(--s-3) 0 var(--s-2);
}
/* tx-2, não tx-3. Medido: com a hélice atrás (véu de 14% de ouro), o
   #888888 caía para 4,11:1 — abaixo do piso 4,5. Dava para apagar o
   fundo, mas essas linhas descrevem as SETE ETAPAS do processo: é
   conteúdo, não legenda de apoio, e 13px em cinza fraco já era o texto
   mais difícil da página antes de existir fundo nenhum. Subir a cor
   conserta o contraste e melhora a leitura de quem nunca vai reparar
   que existe uma hélice ali. */
.jornada p { font-size: var(--fs-micro); color: var(--tx-2); }

/* ---------- 6. DOR → SOLUÇÃO ------------------------------
   O coração da página industrial. A DOR vem primeiro e em corpo de
   leitura; a solução vem depois, menor e dourada. A ordem não é
   estética: o comprador não procura "impressão 3D", procura o
   problema dele. Inverter isso devolve a página a um catálogo. */
.dor-grade { display: grid; grid-template-columns: repeat(2, 1fr); gap: 2px; margin-top: var(--s-8); }
.dor {
  padding: var(--s-7) var(--s-6);
  background: var(--bg-1); border: var(--borda);
  transition: background var(--d-mid) var(--e-out);
}
.dor:hover { background: var(--bg-2); }
.dor-fala {
  font-family: var(--f-body); font-size: var(--fs-body);
  color: var(--tx-1); line-height: 1.45; max-width: 34ch;
}
.dor-fala::before { content: '“'; color: var(--ouro); margin-right: 2px; }
.dor-fala::after  { content: '”'; color: var(--ouro); margin-left: 2px; }
.dor-resp { margin-top: var(--s-5); padding-top: var(--s-5); border-top: 1px solid var(--linha); }
.dor-resp .rot {
  display: block; font-size: var(--fs-micro); letter-spacing: var(--tr-wide);
  text-transform: uppercase; color: var(--ouro); margin-bottom: var(--s-2);
  font-family: var(--f-disp); font-weight: 500; line-height: var(--lh-ui);
}
.dor-resp p { font-size: var(--fs-sm); color: var(--tx-2); }

/* ---------- 7. CASE NARRADO (sem foto) --------------------
   Enquanto não há imagem de 3D, o case se sustenta na narrativa.
   O bloco assume isso: não é card com placeholder de foto, é ficha
   de projeto. Quando a foto chegar, entra como <img> no topo sem
   mexer em mais nada. */
.caso { border-top: 1px solid var(--linha); padding-block: var(--s-7); }
.caso:last-child { border-bottom: 1px solid var(--linha); }
.caso-cx { display: grid; grid-template-columns: 1fr 2fr; gap: var(--s-7); align-items: start; }
.caso-etq {
  font-size: var(--fs-micro); letter-spacing: var(--tr-wide); text-transform: uppercase;
  color: var(--ouro); font-family: var(--f-disp); font-weight: 500; line-height: var(--lh-ui);
}
.caso h3 { color: var(--tx-1); margin-top: var(--s-3); }
.caso-linhas { display: grid; gap: var(--s-5); }
.caso-linha { display: grid; grid-template-columns: 92px 1fr; gap: var(--s-5); align-items: baseline; }
.caso-linha dt {
  font-size: var(--fs-micro); letter-spacing: var(--tr-wide); text-transform: uppercase;
  color: var(--tx-3); line-height: var(--lh-ui);
}
.caso-linha dd { font-size: var(--fs-sm); color: var(--tx-2); }
.caso-linha dd strong { color: var(--tx-1); font-weight: 500; }

/* ---------- 8. FICHA TÉCNICA ------------------------------
   Sem esta tabela a página não converte: engenheiro e comprador não
   pedem orçamento sem material, tolerância e prazo. Os valores estão
   como GATE — marcados na tela, de propósito, para o Onil e o Marcelo
   preencherem. Placeholder VISÍVEL é honesto; placeholder disfarçado
   de dado é o erro que já cometemos e não se repete. */
.ficha { margin-top: var(--s-8); border-top: 1px solid var(--linha); }
.ficha-linha {
  display: grid; grid-template-columns: 1fr 1.6fr; gap: var(--s-5);
  padding-block: var(--s-5); border-bottom: 1px solid var(--linha-fc);
}
.ficha-linha dt {
  font-size: var(--fs-micro); letter-spacing: var(--tr-wide); text-transform: uppercase;
  color: var(--tx-2); line-height: var(--lh-ui);
}
.ficha-linha dd { font-size: var(--fs-sm); color: var(--tx-2); }
.pend {
  display: inline-block; font-size: var(--fs-micro); letter-spacing: var(--tr-tight);
  color: var(--ouro); border: 1px dashed var(--ouro-esc);
  padding: 3px var(--s-3); line-height: var(--lh-ui);
}
.aviso-gate {
  margin-top: var(--s-6); padding: var(--s-5) var(--s-6);
  border-left: 2px solid var(--ouro); background: var(--ouro-veu);
  font-size: var(--fs-micro); color: var(--tx-2);
}

/* ---------- 9. FILTRO DE CASES ---------------------------- */
.filtro { display: flex; flex-wrap: wrap; gap: var(--s-2); margin-bottom: var(--s-7); }
.filtro button {
  background: none; border: 1px solid var(--linha); color: var(--tx-2);
  font-size: var(--fs-micro); letter-spacing: var(--tr-wide); text-transform: uppercase;
  padding: var(--s-2) var(--s-4); cursor: pointer; line-height: var(--lh-ui);
  transition: color var(--d-fast) var(--e-out), border-color var(--d-fast) var(--e-out);
}
.filtro button:hover { color: var(--tx-1); border-color: var(--ouro-esc); }
.filtro button[aria-pressed="true"] { color: var(--ouro); border-color: var(--ouro); }
.case[hidden] { display: none; }

/* ---------- 10. FAQ --------------------------------------- */
.faq { margin-top: var(--s-8); max-width: 62rem; }
.faq details { border-top: 1px solid var(--linha); }
.faq details:last-child { border-bottom: 1px solid var(--linha); }
.faq summary {
  cursor: pointer; list-style: none; padding-block: var(--s-5);
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-5);
  color: var(--tx-1); font-size: var(--fs-sm);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: ''; flex: none; width: 11px; height: 11px;
  border-right: 1px solid var(--ouro); border-bottom: 1px solid var(--ouro);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform var(--d-mid) var(--e-out);
}
.faq details[open] summary::after { transform: rotate(-135deg) translate(-2px, -2px); }
.faq details p { font-size: var(--fs-sm); color: var(--tx-2); padding-bottom: var(--s-6); max-width: 62ch; }
.faq summary:focus-visible { outline: 2px solid var(--ouro); outline-offset: 3px; }

/* ---------- 11. MIGALHAS ---------------------------------- */
.migalha {
  font-size: var(--fs-micro); color: var(--tx-3); letter-spacing: var(--tr-tight);
  padding-top: var(--s-9); line-height: var(--lh-ui);
}
.migalha a:hover { color: var(--ouro); }
.migalha span { color: var(--linha); margin-inline: var(--s-2); }

/* ---------- 12. CAMPO DE ARQUIVO -------------------------- */
.campo--arq { border: 1px dashed var(--linha); padding: var(--s-5); }
.campo--arq > label {
  position: static; font-size: var(--fs-micro); letter-spacing: var(--tr-wide);
  text-transform: uppercase; color: var(--tx-2); display: block; margin-bottom: var(--s-3);
}
.campo--arq input[type="file"] { font-size: var(--fs-micro); color: var(--tx-3); border: 0; padding: 0; }
.campo--arq .dica { font-size: var(--fs-micro); color: var(--tx-3); margin-top: var(--s-3); }

.campo select {
  width: 100%; background: transparent; color: var(--tx-1);
  border: 0; border-bottom: 1px solid var(--linha);
  padding: var(--s-4) 0; font-size: var(--fs-body);
}
.campo select:focus { border-bottom-color: var(--ouro); outline: none; }
.campo select option { background: var(--bg-2); color: var(--tx-1); }
.campo > .rot-fixo {
  display: block; font-size: var(--fs-micro); letter-spacing: var(--tr-wide);
  text-transform: uppercase; color: var(--tx-2); margin-bottom: var(--s-2);
  line-height: var(--lh-ui);
}

/* ---------- 13. RESPONSIVO -------------------------------- */
@media (max-width: 1100px) {
  .costura { grid-template-columns: 1fr; gap: var(--s-6); }
  .caso-cx { grid-template-columns: 1fr; gap: var(--s-5); }
}
@media (max-width: 860px) {
  .portas    { grid-template-columns: 1fr; }
  .porta     { min-height: 0; padding: var(--s-7) var(--s-6); }
  .dor-grade { grid-template-columns: 1fr; }
  .ficha-linha { grid-template-columns: 1fr; gap: var(--s-2); }
  .caso-linha  { grid-template-columns: 1fr; gap: var(--s-1); }
  /* a fita de jornada vira rolagem horizontal com pista visível —
     esconder etapa seria esconder o argumento da seção */
  .jornada { grid-auto-columns: minmax(132px, 60%); padding-bottom: var(--s-4); }
}

/* ---------- 14. MOVIMENTO REDUZIDO ------------------------ */
@media (prefers-reduced-motion: reduce) {
  /* o canvas continua na tela: o JS desenha UM quadro e não entra em
     laço. Some só o que pisca, nunca o que informa. */
  .faq details[open] summary::after,
  .faq summary::after { transition: none; }
}
