/* public/sites/site.css
   Folha dos sites publicados. Vive em public/ (estático, servido por URL) em
   vez de importada como módulo: é a mesma folha que a página pública carrega
   via <link> (app/%5Fsites/[host]/layout.tsx) e que o iframe do canvas do
   editor carrega via canvas.styles (components/sites/EditorCanvas.tsx) — uma
   origem só, alcançável dos dois jeitos.
   TODO seletor vive sob .site-root — sem isso as classes vazam pro dashboard,
   que compartilha o mesmo documento no preview. Nenhuma cor literal: tudo
   deriva dos tokens que themeToCssVars injeta. */

.site-root {
  /* Escala tipográfica derivada de --site-escala (0.9 | 1 | 1.15).
     Ancorada em 16px literal, NÃO em 1rem: o dashboard roda html/body a
     14px (app/globals.css, densidade de UI compacta) e a página pública
     nasce dentro do mesmo <html> (app/layout.tsx envolve app/%5Fsites).
     1rem aqui já não é 16px — é 14px — e a escala inteira saía 12.5% menor
     que o pretendido (compacto batia 10.7px, ilegível). rem é relativo à
     RAIZ do documento, então setar font-size em .site-root não ajudaria:
     só um valor em px quebra a dependência do 14px do app interno. */
  --s-base: calc(16px * var(--site-escala, 1));
  --s-display-1: calc(var(--s-base) * 2.75);
  --s-display-2: calc(var(--s-base) * 1.9);
  --s-display-3: calc(var(--s-base) * 1.25);
  --s-corpo: calc(var(--s-base) * 1.05);
  --s-mini: calc(var(--s-base) * 0.85);

  /* Ritmo: boutique respira. Seção tem o dobro do padding de um site comum. */
  --s-secao-y: calc(var(--s-base) * 5);
  --s-gap: calc(var(--s-base) * 1.5);
  --s-largura: 1120px;

  /* Cantos generosos — a assinatura mais visível da direção. */
  --s-raio: 20px;
  --s-raio-sm: 14px;

  /* Superfície secundária: a cor primária diluída, sem precisar de um token
     novo. color-mix mantém a coerência com qualquer paleta escolhida. */
  --s-superficie: color-mix(in srgb, var(--site-primaria) 7%, var(--site-fundo));
  --s-borda: color-mix(in srgb, var(--site-primaria) 16%, var(--site-fundo));

  /* Superfície de campo/card. `.site-bloco` redefine logo abaixo, ancorando
     em `--s-bloco-fundo` para acompanhar a alternância par/ímpar das faixas —
     e é essa versão que vale numa página de blocos.

     Este valor aqui é o que sustenta a página de CANVAS, que não tem
     `.site-bloco` em lugar nenhum: sem ele, `background: var(--s-card-fundo)`
     nos campos do formulário resolvia para nada, a declaração virava inválida
     e o fundo caía no `transparent` inicial — campo sem caixa visível em toda
     LP feita no GrapesJS. */
  --s-card-fundo: color-mix(in srgb, var(--site-primaria) 12%, var(--site-fundo));

  background: var(--site-fundo);
  color: var(--site-texto);
  font-family: var(--site-fonte-corpo), system-ui, sans-serif;
  font-size: var(--s-corpo);
  line-height: 1.75;
  -webkit-font-smoothing: antialiased;
}

.site-root h1,
.site-root h2,
.site-root h3 {
  font-family: var(--site-fonte-display), Georgia, serif;
  font-weight: 500;
  line-height: 1.15;
  letter-spacing: -0.01em;
  margin: 0 0 calc(var(--s-base) * 0.75);
  text-wrap: balance;
}

.site-root h1 { font-size: var(--s-display-1); }
.site-root h2 { font-size: var(--s-display-2); }
.site-root h3 { font-size: var(--s-display-3); }

.site-root p { margin: 0 0 var(--s-base); }
.site-root img { max-width: 100%; height: auto; display: block; }

/* Mesma contenção da regra do `img` acima, para as duas caixas que a folha
   deixava de fora. O bloco `video` do núcleo do GrapesJS grava
   `#id{width:615px;height:350px}` SEM media query (o dono diagrama no device
   Desktop), e nada nesta folha continha isso: num celular de 360px o vídeo
   estourava a viewport e dava scroll horizontal na LP INTEIRA — não só no
   vídeo. A superfície primária destas páginas é o celular (tráfego de
   anúncio), então isso é dano na tela que mais importa.

   `max-width` resolve sem depender de especificidade: ele limita o valor
   computado de QUALQUER `width`, venha de onde vier — inclusive do
   `#id{width:615px}` (1,0,0), que nenhum seletor desta folha venceria.

   Sem `height:auto` de propósito, ao contrário do `img`: iframe não tem
   proporção intrínseca, então `auto` cairia nos 150px de default do navegador.
   O vídeo do bloco nativo fica com a altura fixa que o dono escolheu, contido
   na largura — desproporcional, mas dentro da tela. Nosso `ab-embed` casa este
   seletor mas não sofre isso: ele carrega `aspect-ratio:16/9` inline no próprio
   iframe, então a altura acompanha a largura sozinha.

   Especificidade igual à do `img` — (0,1,1), sem o `:where()` da regra de cor
   de link lá embaixo. O `:where()` existe para o TEMA (uma opinião de
   aparência) perder para marcação com opinião própria; contenção de layout não
   é opinião de aparência, e afrouxar aqui devolveria o scroll horizontal a
   qualquer HTML colado com uma classe. Quem precisa escapar escapa como o
   `.site-hero-img` já escapa da regra do `img`: com um seletor mais específico
   dentro desta mesma folha. */
.site-root iframe,
.site-root video { max-width: 100%; }

/* Medida de leitura (62ch) só faz sentido pra prosa correndo a largura do
   bloco. Precisa de mais especificidade que `.site-bloco > *` (que também
   cabe num <p>, via seletor universal) — sem isso o parágrafo perdia a
   medida e corria os 1120px inteiros do container (I1 da revisão). */
.site-root .site-bloco p { max-width: 62ch; }

/* Cada bloco é uma faixa de largura total; o conteúdo é que fica contido.
   O padding horizontal da seção já entrega essa coluna centralizada — os
   filhos não precisam de margin:auto próprio. Isso importa porque um
   filho estreito (ex.: <address> de 42ch) com margin:auto centraliza a
   PRÓPRIA caixa, não o conteúdo dentro da coluna: ao lado de um <h2> quase
   full-width (também com margin:auto, mas quase sem sobra pra centralizar)
   as duas bordas esquerdas caem em pontos diferentes e o título parece
   desalinhado do corpo (C2 da revisão). Com width:100% + padding fazendo a
   centralização, todo filho — não importa a própria largura — compartilha
   a mesma borda esquerda. */
.site-root .site-bloco {
  --s-bloco-fundo: var(--site-fundo);
  /* Superfície do card, derivada do fundo REAL da seção onde ele está —
     não de --site-fundo direto. Card usava var(--site-fundo) fixo, que é
     branco nas 6 paletas; numa seção ímpar (sem tingimento, background =
     --site-fundo) o card ficava branco sobre branco, só a borda salvando.
     Ancorar em --s-bloco-fundo (que a regra nth-of-type(even) abaixo
     reatribui) faz o card sempre ficar um degrau MAIS tingido que o que
     está atrás dele, em qualquer paridade — sem herdar índice par/ímpar em
     nenhum outro lugar da folha. */
  --s-card-fundo: color-mix(in srgb, var(--site-primaria) 12%, var(--s-bloco-fundo));
  padding-top: var(--s-secao-y);
  padding-bottom: var(--s-secao-y);
  padding-left: max(calc(var(--s-base) * 1.5), calc((100% - var(--s-largura)) / 2));
  padding-right: max(calc(var(--s-base) * 1.5), calc((100% - var(--s-largura)) / 2));
}

.site-root .site-bloco > * {
  max-width: var(--s-largura);
  width: 100%;
}

/* Alternância de superfície dá ritmo sem precisar de decoração. */
.site-root .site-bloco:nth-of-type(even) {
  --s-bloco-fundo: var(--s-superficie);
  background: var(--s-bloco-fundo);
}

.site-root .site-cta {
  display: inline-block;
  padding: calc(var(--s-base) * 0.85) calc(var(--s-base) * 2.25);
  border-radius: 999px;
  background: var(--site-primaria);
  color: var(--site-texto-sobre-primaria);
  font-family: var(--site-fonte-corpo), system-ui, sans-serif;
  font-size: var(--s-corpo);
  font-weight: 500;
  text-decoration: none;
  transition: filter 120ms ease;
}

.site-root .site-cta:hover { filter: brightness(0.92); }

/* `:where()` zera a especificidade do `.site-root`, então esta regra pesa o
   mesmo que um `a` solto (0,0,1) em vez de (0,1,1). Isso é deliberado e é o
   ponto todo: o tema COLORE o link que ninguém estilizou, e PERDE para
   qualquer marcação que tenha opinião própria — uma classe `.btn` do HTML
   colado no canvas, por exemplo, já vence com (0,1,0).

   A tentativa anterior fazia o contrário e por isso falhou: acrescentava
   `.site-root .site-canvas a { color: inherit }`, que com (0,2,1) vencia o
   `.btn { color:#fff }` do dono e forçava a herança — o CTA verde continuava
   com a cor errada, só que agora herdada em vez de rosa. Consertar competindo
   com outra declaração não resolve; o certo é a regra do tema parar de
   competir.

   Consequência boa de graça: o link de privacidade do formulário (um `<a>`
   sem classe dentro de `.site-formulario`) continua pegando a cor do tema por
   esta mesma regra, sem precisar de exceção nenhuma. */
:where(.site-root) a { color: var(--site-primaria); }

/* Hero: a foto conduz. Sem foto, a superfície tingida segura a composição. */
.site-root .site-hero {
  position: relative;
  padding: 0;
  min-height: min(78vh, 640px);
  display: grid;
  align-items: center;
  overflow: hidden;
  border-radius: 0 0 var(--s-raio) var(--s-raio);
  background: var(--s-superficie);
}

.site-root .site-hero-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  max-width: none;
}

.site-root .site-hero-conteudo {
  position: relative;
  width: 100%;
  max-width: var(--s-largura);
  margin: 0 auto;
  padding: var(--s-secao-y) calc(var(--s-base) * 1.5);
}

/* Com foto de fundo, o texto precisa de uma camada própria pra continuar
   legível sobre qualquer imagem que a clínica subir. */
.site-root .site-hero:has(.site-hero-img) .site-hero-conteudo {
  background: color-mix(in srgb, var(--site-fundo) 88%, transparent);
  border-radius: var(--s-raio);
  max-width: 46rem;
  /* Horizontal auto (não um valor fixo nos 4 lados): ancora o card no MESMO
     eixo central que toda outra seção usa. Com margem fixa, width:100%
     ainda tenta preencher o container inteiro até o max-width entrar, e o
     card acaba colado na borda ESQUERDA da viewport enquanto o resto do
     site fica centralizado — o mesmo site parecia composto ou desalinhado
     só por causa de ter foto ou não (I4 da revisão). */
  margin: calc(var(--s-base) * 2) auto;
  padding: calc(var(--s-base) * 2.5);
}

.site-root .site-hero p { font-size: calc(var(--s-corpo) * 1.15); }

/* Sobre: foto ao lado do texto quando existe; sem foto, o texto ocupa a
   coluna inteira (:has evita a grade de 2 colunas colapsar pela metade). */
.site-root .site-sobre-grid:has(.site-sobre-img) {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: center;
  gap: var(--s-gap);
}

.site-root .site-sobre-img {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border-radius: var(--s-raio);
}

.site-root .site-depoimentos blockquote {
  margin: 0 0 var(--s-gap);
  padding: calc(var(--s-base) * 1.75);
  background: var(--s-card-fundo);
  border: 1px solid var(--s-borda);
  border-radius: var(--s-raio);
}

.site-root .site-depoimentos blockquote p { font-size: calc(var(--s-corpo) * 1.05); margin-bottom: calc(var(--s-base) * 0.5); }
.site-root .site-depoimentos cite { font-style: normal; font-size: var(--s-mini); opacity: 0.72; }

.site-root .site-faq details {
  border-bottom: 1px solid var(--s-borda);
  padding: calc(var(--s-base) * 1.1) 0;
}

.site-root .site-faq summary {
  cursor: pointer;
  font-family: var(--site-fonte-display), Georgia, serif;
  font-size: var(--s-display-3);
  list-style: none;
}

.site-root .site-faq summary::-webkit-details-marker { display: none; }
.site-root .site-faq summary::after { content: '+'; float: right; opacity: 0.5; }
.site-root .site-faq details[open] summary::after { content: '–'; }
.site-root .site-faq details p { margin: calc(var(--s-base) * 0.6) 0 0; }

.site-root .site-galeria-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--s-gap);
}

.site-root .site-galeria-grid img {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border-radius: var(--s-raio-sm);
}

.site-root .site-rodape {
  padding-top: calc(var(--s-base) * 2.5);
  padding-bottom: calc(var(--s-base) * 2.5);
  font-size: var(--s-mini);
  opacity: 0.72;
  border-top: 1px solid var(--s-borda);
  background: none;
}

.site-root .site-lista-proc,
.site-root .site-lista-equipe {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: var(--s-gap);
}

.site-root .site-lista-proc { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.site-root .site-lista-equipe { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }

.site-root .site-lista-proc li {
  background: var(--s-card-fundo);
  border: 1px solid var(--s-borda);
  border-radius: var(--s-raio);
  padding: calc(var(--s-base) * 1.6);
  display: flex;
  flex-direction: column;
  gap: calc(var(--s-base) * 0.4);
}

.site-root .site-lista-proc h3 { margin: 0; font-size: var(--s-display-3); }
.site-root .site-lista-proc p { margin: 0; font-size: var(--s-mini); opacity: 0.8; }

.site-root .site-lista-proc strong {
  /* margin-top:auto (não flex:1 no <p>): procedimento sem descricao nao tem
     <p> nenhum, e ai o preco subia pro topo enquanto o card vizinho
     empurrava o dele pro rodape — a linha inteira lia desalinhada. */
  margin-top: auto;
  font-family: var(--site-fonte-display), Georgia, serif;
  font-size: calc(var(--s-base) * 1.4);
  font-weight: 500;
  color: var(--site-primaria);
}

.site-root .site-lista-equipe li { text-align: center; }

.site-root .site-lista-equipe img {
  width: 100%;
  max-width: 200px;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: 50%;
  margin: 0 auto calc(var(--s-base) * 0.75);
}

.site-root .site-lista-equipe h3 { margin: 0 0 calc(var(--s-base) * 0.25); font-size: var(--s-display-3); }
.site-root .site-lista-equipe p { margin: 0 auto; font-size: var(--s-mini); opacity: 0.8; max-width: 30ch; }

.site-root .site-contato address {
  font-style: normal;
  font-size: calc(var(--s-corpo) * 1.1);
  max-width: 42ch;
}

.site-root .site-agendar { text-align: center; }

/* Formulário de contato. Nome/WhatsApp/e-mail (e cada pergunta extra) são um
   <label> seguido de um <input> soltos no fluxo, sem wrapper — por isso a
   correção é só display:block no label e margem no input: sem isso os dois
   são inline por padrão do navegador, correm na mesma linha, e um valor
   longo (ex.: "E-mail") quebra no meio da palavra por falta de espaço. */
.site-root .site-formulario form {
  /* Fixo em px, como --s-largura logo acima: cap absoluto pra não esticar
     num container largo, mas width:100% (herdado de `.site-bloco > *`) já
     preenche qualquer coluna mais estreita que isso. */
  max-width: 480px;
}

/* `--form-fonte-campo`, `--form-gap-label`, `--form-padding-campo` e
   `--form-gap-campo` vêm do campo `tamanho` do bloco `formulario`
   (lib/sites/blocks.ts, via `varsAparenciaFormulario`,
   lib/sites/formularioAparencia.ts) — o substituto honesto da alça de
   redimensionar vertical que EditorCanvas.tsx desliga no marcador: a altura
   do <form> é a soma do conteúdo, então "menos altura" só é de verdade
   quando o que compõe essa soma — padding do campo, os dois gaps verticais,
   a letra — encolhe junto (o cabeçalho entra nessa soma também, na regra
   logo depois do <input>). `tamanho: 'normal'` (o default) não grava
   nenhuma das quatro vars, e cada fallback abaixo reproduz o valor de HOJE,
   então uma página sem o campo configurado renderiza bit a bit igual à
   folha de antes desta seção existir. */
.site-root .site-formulario label {
  display: block;
  margin: 0 0 var(--form-gap-label, calc(var(--s-base) * 0.35));
  font-weight: 500;
  font-size: var(--form-fonte-campo, var(--s-corpo));
}

.site-root .site-formulario input:not([type="checkbox"]) {
  display: block;
  width: 100%;
  box-sizing: border-box;
  margin: 0 0 var(--form-gap-campo, calc(var(--s-base) * 1.1));
  padding: var(--form-padding-campo, calc(var(--s-base) * 0.65) calc(var(--s-base) * 0.85));
  border: 1px solid var(--s-borda);
  /* Fallback = var(--s-raio-sm), o valor de sempre: página que nunca
     configurou `arredondamento` (campo do bloco `formulario`, ver
     lib/sites/blocks.ts) renderiza com o raio de hoje, bit a bit. */
  border-radius: var(--form-raio-campo, var(--s-raio-sm));
  /* --s-card-fundo, não --site-fundo: mesma lógica do card de
     `.site-lista-proc li` — sempre um degrau mais tingido que a seção onde
     o campo está, então o campo continua visível numa seção ímpar (fundo =
     --site-fundo) e numa par (fundo = --s-superficie) igualmente. */
  background: var(--s-card-fundo);
  color: var(--site-texto);
  font-family: var(--site-fonte-corpo), system-ui, sans-serif;
  font-size: var(--form-fonte-campo, var(--s-corpo));
}

/* Cabeçalho do formulário (o <h2> do título e o <p> logo abaixo — descrição
   no estado aberto, mensagem de sucesso no estado enviado). Também escala
   com o campo `tamanho`, e é ele que resolve a altura de verdade numa LP de
   canvas: o formulário é montado DENTRO do modelo, então quem manda no <h2>
   é o `.lp h2` do modelo (clamp(1.8rem, 3.8vw, 2.8rem), ver
   lib/sites/modelosCanvas.ts) — manchete de seção em cima de campos
   pequenos. Escalar só o campo deixava o título do tamanho de antes.

   SEM FALLBACK, de propósito, e é a única regra desta folha assim. As outras
   vars de `tamanho` têm um "valor de hoje" fixo que o fallback reproduz; o
   título não tem: numa página de blocos vale `--s-display-2` (regra
   `.site-root h2` lá em cima), numa LP de canvas vale o clamp do modelo, e
   cada modelo pode declarar o seu. Qualquer fallback fixo aqui atropelaria o
   modelo até em `tamanho: 'normal'`, que é justamente o que não pode mudar.

   Por isso — e é a outra coisa que só esta regra tem — ela é condicionada ao
   atributo `[data-form-cabecalho]`, que `aparenciaFormulario`
   (lib/sites/formularioAparencia.ts) escreve no MESMO `if` que emite as duas
   vars. Em `tamanho: 'normal'` nem a var nem o atributo existem, a regra não
   casa e o título fica com o que a cascata já dava.

   O atributo é obrigatório, não enfeite: omitir só a var e deixar a regra
   sempre ligada NÃO devolve o elemento para a cascata. Pela spec de Custom
   Properties (§ Invalid At Computed-Value Time) a declaração continua
   VENCENDO a cascata e o valor computado vira `unset` — que em propriedade
   herdada é `inherit`, ou seja o font-size do PAI (~16,8px na <section>), não
   o `.lp h2` do modelo nem o `--s-display-2` daqui. Era isso que rebaixava o
   título a texto de corpo em toda LP publicada que nunca configurou `tamanho`.

   O seletor testa a PRESENÇA do atributo, nunca o valor: quem decide que
   tamanho mexe no cabeçalho é o TypeScript. Repetir essa decisão aqui criaria
   uma segunda fonte de verdade que diverge calada.

   Especificidade: (0,3,1) — duas classes + o atributo + o tipo. Precisa bater
   o `.lp h2` do modelo, que é (0,1,1), e bate com folga.

   Combinador filho (`>`) no <p> não é estilo, é necessidade: a descrição é
   filha direta da <section>, enquanto `.site-formulario-privacidade` e
   `.site-formulario-erro` (também <p>) vivem dentro do <form>. Sem o `>`
   este seletor venceria as regras de font-size delas (0,2,0) e o aviso de
   privacidade e a mensagem de erro perderiam o `--s-mini`. */
.site-root .site-formulario[data-form-cabecalho] > h2 {
  font-size: var(--form-fonte-titulo);
}

.site-root .site-formulario[data-form-cabecalho] > p {
  font-size: var(--form-fonte-descricao);
}

/* Consentimento: aqui o par não pode empilhar como os outros — o checkbox
   precisa ficar ao lado do próprio texto. Duas classes bate a regra de
   `label` acima (uma classe) na especificidade, então vence sem
   !important. */
.site-root .site-formulario-consent {
  display: flex;
  align-items: flex-start;
  gap: calc(var(--s-base) * 0.5);
  margin: 0 0 calc(var(--s-base) * 1);
  font-size: var(--s-mini);
  cursor: pointer;
}

.site-root .site-formulario-consent input[type="checkbox"] {
  flex-shrink: 0;
  margin-top: 0.2em;
  accent-color: var(--site-primaria);
}

.site-root .site-formulario-privacidade {
  font-size: var(--s-mini);
  opacity: 0.72;
  margin: 0 0 calc(var(--s-base) * 1.25);
}

/* Sem token de erro no tema — theme.ts só define fundo/texto/primária/
   texto-sobre-primária (ver lib/sites/theme.ts). Vermelho de aviso é
   convenção universal pra estado de erro e não deveria variar com a
   paleta escolhida mesmo que existisse um token pra isso, então fica de
   propósito fora do sistema `--site-*`/`--s-*` desta folha. */
.site-root .site-formulario-erro {
  margin: 0 0 calc(var(--s-base) * 1);
  color: #b42318;
  font-size: var(--s-mini);
  font-weight: 500;
}

/* ── Aparência configurável (bloco `formulario`) ─────────────────────────────
   As vars abaixo (mais `--form-raio-campo`, já embutida na regra do
   `input`, e o sexteto de `tamanho` — `--form-fonte-campo`,
   `--form-padding-campo`, `--form-gap-label`, `--form-gap-campo`,
   `--form-fonte-titulo`, `--form-fonte-descricao` — embutido nas regras de
   `label`/`input`/cabeçalho logo acima) vêm do `style` inline que
   FormularioBloco.tsx (e o gêmeo estático em EditorCanvas.tsx) grava na
   `section` — só quando o campo correspondente sai do default do registry
   (ver `varsAparenciaFormulario`, lib/sites/formularioAparencia.ts). Toda
   regra usa fallback pro valor de HOJE — MENOS as duas do cabeçalho, que são
   sem fallback de propósito porque o "valor de hoje" delas depende do modelo
   de LP (o motivo está por extenso na própria regra) — então uma página sem
   nenhum campo configurado bate exatamente igual ao CSS de antes desta seção
   existir. Ver
   docs/superpowers/specs/2026-08-19-formulario-aparencia-design.md. */

.site-root .site-formulario .site-cta {
  border-radius: var(--form-raio-botao, 999px);
  /* Cor de fundo (--form-botao-fundo) e a cor do texto que combina com ela
     (--form-botao-texto, calculada por luminância em lib/sites/contraste.ts
     — NUNCA um campo configurável) chegam juntas ou não chegam: a clínica
     não escolhe uma sem a outra, é o que impede o par ilegível. */
  background: var(--form-botao-fundo, var(--site-primaria));
  color: var(--form-botao-texto, var(--site-texto-sobre-primaria));
  width: var(--form-botao-largura, auto);
}

/* Alinhamento afeta título, descrição/mensagem de sucesso e botão — os três
   elementos que não são campo de preenchimento. Herda por `text-align` a
   partir da seção, e os quatro seletores abaixo devolvem explicitamente pra
   esquerda o que NÃO deve seguir o alinhamento: rótulo dos campos, aviso de
   privacidade, mensagem de erro e o texto do consentimento — sem isso a
   herança de `text-align` centralizaria o TEXTO deles também (o `<input>`
   em si não se move, mas o texto do `<label>` sim), o que a spec não pede. */
.site-root .site-formulario {
  text-align: var(--form-alinhamento, left);
}

.site-root .site-formulario label,
.site-root .site-formulario-privacidade,
.site-root .site-formulario-erro,
.site-root .site-formulario-consent {
  text-align: left;
}

/* ── Variantes ──────────────────────────────────────────────────────────────
   Cada variante é um arranjo curado que a clínica escolhe no painel. Elas só
   recompõem os tokens --s-* que a folha já define; nenhuma toca em cor, que é
   o que mantém de pé a garantia do theme.ts de que a clínica não consegue
   produzir texto ilegível.

   A variante que já existia antes desta seção é o DEFAULT de cada bloco, e não
   tem regra aqui — ela é o que as regras acima já fazem. Snapshot publicado
   sem o campo cai nela. */

/* Hero, split: texto e foto lado a lado. Ao contrário do hero com foto de
   fundo, aqui a imagem é conteúdo, não pano de fundo — então sai do
   position:absolute e vira uma coluna da grade. */
.site-root .site-hero--split {
  min-height: 0;
  border-radius: 0;
  background: var(--site-fundo);
  padding: var(--s-secao-y) max(calc(var(--s-base) * 1.5), calc((100% - var(--s-largura)) / 2));
}

/* A grade só existe quando existe foto — mesmo gate que `.site-sobre-grid`
   usa, e pelo mesmo motivo. A foto do hero é opcional e independente da
   variante: a clínica pode escolher "texto e foto lado a lado" sem nunca ter
   subido uma, ou com uma URL que o guard de host reprovou. Sem este `:has`, a
   grade de duas colunas fica valendo com um único filho, o texto encosta à
   esquerda e metade do hero fica em branco — parece layout quebrado, não
   variante funcionando sem foto. */
.site-root .site-hero--split:has(.site-hero-img) {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: center;
  gap: var(--s-gap);
}

.site-root .site-hero--split .site-hero-img {
  position: static;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 5;
  border-radius: var(--s-raio);
  /* order:2 em vez de trocar a ordem no JSX: o texto tem que vir primeiro no
     DOM para leitor de tela e para o empilhamento no mobile — quem lê a página
     linearmente quer o título antes da foto. */
  order: 2;
}

/* Mesma forma com :has da regra base, senão ela vence por especificidade e o
   card translúcido do hero de foto reaparece aqui — ver Step 2. */
.site-root .site-hero--split:has(.site-hero-img) .site-hero-conteudo,
.site-root .site-hero--split .site-hero-conteudo {
  background: none;
  border-radius: 0;
  max-width: none;
  margin: 0;
  padding: 0;
}

/* Hero, faixa: título de página interna. O template institucional põe um hero
   em cada uma das 4 páginas, e repetir a foto de 78vh em todas é exatamente o
   que faz o site parecer template. O componente não renderiza <Image> nesta
   variante, então não há regra de imagem aqui. */
.site-root .site-hero--faixa {
  min-height: 0;
  display: block;
  border-radius: 0;
  background: var(--s-superficie);
  padding: calc(var(--s-base) * 3.5) max(calc(var(--s-base) * 1.5), calc((100% - var(--s-largura)) / 2));
}

.site-root .site-hero--faixa .site-hero-conteudo {
  background: none;
  border-radius: 0;
  max-width: var(--s-largura);
  margin: 0 auto;
  padding: 0;
}

.site-root .site-hero--faixa h1 { font-size: var(--s-display-2); }

/* Sobre, foto à direita. A grade base já é de duas colunas quando há foto; só
   a ordem muda. */
.site-root .site-sobre--foto-direita .site-sobre-img { order: 2; }

/* Galeria, mosaico: a primeira foto ocupa quatro células. Grade de 4 colunas
   fixas (não auto-fit) porque o span de 2 só é previsível com contagem
   conhecida — com auto-fit, o número de colunas muda com a largura e a foto
   grande às vezes ficaria sozinha numa linha. */
.site-root .site-galeria--mosaico .site-galeria-grid {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}

.site-root .site-galeria--mosaico .site-galeria-grid img:first-child {
  grid-column: span 2;
  grid-row: span 2;
  /* A regra base fixa aspect-ratio 4/5 em toda foto da galeria. Aqui a
     primeira ocupa uma área de 2×2 células, e manter a proporção faria ela
     estourar a altura das duas linhas vizinhas. */
  aspect-ratio: auto;
  height: 100%;
}

/* Depoimentos em colunas. O invólucro .site-depoimentos-lista existe no
   componente justamente para ser o container da grade; no empilhado ele é
   inerte. */
.site-root .site-depoimentos--colunas .site-depoimentos-lista {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--s-gap);
  align-items: start;
}

/* A margem inferior do blockquote é o espaçamento do empilhado; na grade quem
   espaça é o `gap`, e a margem viraria um degrau a mais no fim de cada card. */
.site-root .site-depoimentos--colunas blockquote { margin-bottom: 0; }

@media (max-width: 720px) {
  .site-root {
    --s-display-1: calc(var(--s-base) * 2);
    --s-display-2: calc(var(--s-base) * 1.5);
    --s-secao-y: calc(var(--s-base) * 3);
    --s-largura: 100%;
  }

  .site-root .site-hero { min-height: min(68vh, 520px); }

  .site-root .site-sobre-grid:has(.site-sobre-img) { grid-template-columns: 1fr; }

  .site-root .site-hero:has(.site-hero-img) .site-hero-conteudo {
    /* width:auto substitui o width:100% herdado da regra base do
       .site-hero-conteudo: com box-sizing:border-box + margem fixa nos 4
       lados, width:100% + margin estoura o container em 2×margin (o
       .site-hero tem overflow:hidden, então não gera scroll — só corta o
       canto direito do card, silenciosamente, a partir de 390px — I3 da
       revisão). width:auto deixa o navegador descontar a margem do espaço
       disponível, como qualquer bloco normal faria. */
    width: auto;
    margin: var(--s-base);
    padding: calc(var(--s-base) * 1.5);
  }

  /* As duas irmãs abaixo existem porque as regras de `.site-hero` desta media
     query são ANTERIORES às variantes no arquivo e têm a MESMA especificidade
     que elas — media query não soma nada. Sem elas, tudo que `--split` e
     `--faixa` zeram lá em cima volta a valer no celular, e só no celular.
     Foi a varredura que faltou quando a grade do split foi corrigida: das três
     regras mobile que alcançam `.site-hero`, só aquela tinha sido tratada. */

  /* Sem isto a "faixa curta de título" sai com 520px de altura num celular de
     844px, com ~400px de vazio embaixo — porque ela declara display:block, e
     aí o align-items:center da base nem centraliza o conteúdo. É exatamente o
     efeito que a variante existe para evitar. */
  .site-root .site-hero--split,
  .site-root .site-hero--faixa { min-height: 0; }

  /* Mesma forma com :has da regra logo acima, senão ela ganha por ordem e o
     texto do split herda a margem do CARD do hero de foto — card que no split
     não existe. O efeito é a borda esquerda do <h1> não bater com a da foto
     logo abaixo: a mesma classe de desalinhamento que o comentário da regra
     de `.site-bloco > *` registra ter custado um achado de revisão. */
  .site-root .site-hero--split:has(.site-hero-img) .site-hero-conteudo {
    width: 100%;
    margin: 0;
    padding: 0;
  }

  /* Split vira empilhado: duas colunas de meia tela não cabem num celular, e
     a foto ficaria estreita demais para valer a pena.
     O `:has` aqui não é decoração: quem liga a grade é
     `.site-hero--split:has(.site-hero-img)` (0,3,0), e um override sem ele
     valeria 0,2,0 — perderia por especificidade e o split continuaria em duas
     colunas no celular, apesar de estar dentro da media query. */
  .site-root .site-hero--split:has(.site-hero-img) {
    grid-template-columns: 1fr;
    gap: var(--s-base);
  }

  .site-root .site-hero--split .site-hero-img { aspect-ratio: 16 / 10; }

  /* Mosaico de 4 colunas fica com fotos de ~80px num celular. Duas colunas
     mantêm o efeito (a primeira ainda ocupa o dobro) num tamanho legível. */
  .site-root .site-galeria--mosaico .site-galeria-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* Não há regra de prefers-reduced-motion aqui de propósito: app/globals.css
   já aplica, sob a mesma media query, `* { transition-duration: 0.01ms
   !important }` — universal, com !important, portanto também vence dentro
   de .site-root. Uma segunda regra aqui (a transição do .site-cta) nunca
   chegaria a rodar; era código morto que só parecia documentar uma decisão
   que já era tomada em outro lugar. */
