/* =====================================================================
   MOMA HAIR — Landing Page · estilos (mobile-first)
   Reskin visual sobre design.md — ver o próprio arquivo para a spec completa.
   Paleta da marca preservada: laranja · preto · creme (tokens em :root).
   ===================================================================== */
:root {
  /* Marca — inalterados */
  --laranja:      #F47800;
  --preto:        #090909;
  --creme:        #FFF7F0;
  --branco:       #FFFFFF;
  --dourado:      #C9A24B;

  /* componentes RGB p/ alpha sem introduzir hex novo */
  --laranja-rgb:  244,120,0;
  --preto-rgb:    9,9,9;
  --dourado-rgb:  201,162,75;
  --wa-rgb:       37,211,102;
  --creme-rgb:    255,247,240;
  --branco-rgb:   255,255,255;

  /* Tinta (texto) */
  --ink-1:        #241F1B;   /* títulos e corpo forte */
  --ink-2:        #5C5651;   /* texto de apoio — 6.82:1 sobre creme */
  --ink-invert:   #FFF7F0;   /* tinta sobre superfície escura */
  --ink-invert-2: #B9AFA6;   /* apoio sobre superfície escura */

  /* Laranja — dois papéis separados */
  --laranja-surface: #F47800; /* fundo de botão/banda. Tinta obrigatória: --preto */
  --laranja-hover:   #D96700; /* SÓ hover de fundo. Nunca texto. */
  --laranja-ink:     #A64C00; /* laranja para TEXTO/LINK sobre creme — 5.42:1 */
  --dourado-ink:     #7A5E22; /* dourado para TEXTO sobre creme — 5.74:1 */

  /* Superfícies */
  --surface-2:    #F3E7DC;
  --surface-dark: #090909;

  /* Alpha sobre foto */
  --veil-1: rgba(9,9,9,.58); /* era .28 — ver comentário em .hero::after (:260) */
  --veil-2: rgba(9,9,9,.72);
  --veil-3: rgba(9,9,9,.94);
  --linha:  rgba(9,9,9,.10);

  /* Acento funcional */
  --wa: #25D366;             /* WhatsApp. Tinta obrigatória: --preto (10.04:1) */

  /* Tipografia — escala modular 1.25, base 16px */
  --fs-100: .8rem;
  --fs-200: 1rem;
  --fs-300: 1.25rem;
  --fs-400: 1.5625rem;
  --fs-500: clamp(1.9531rem, 1.55rem + 2vw,   2.4414rem);
  --fs-600: clamp(2.4414rem, 1.75rem + 3.4vw, 3.0518rem);
  --font-h: "Playfair Display", Georgia, serif;
  --font-b: "Poppins", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  /* Espaçamento */
  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:24px;
  --sp-6:32px; --sp-7:48px; --sp-8:64px; --sp-9:96px;
  --gutter:    clamp(20px, 5vw, 40px);
  --section-y: clamp(56px, 10vw, 112px);

  /* Raio */
  --r-sm: 10px;
  --r-md: 16px;
  --r-lg: 24px;
  --r-full: 999px;

  /* Elevação — 2 drops empilhados, 4 níveis com significado */
  --e-0: none;
  --e-1: 0 1px 2px rgba(9,9,9,.05), 0 2px 8px rgba(9,9,9,.04);
  --e-2: 0 2px 6px rgba(9,9,9,.06), 0 12px 28px -10px rgba(9,9,9,.20);
  --e-3: 0 4px 12px rgba(9,9,9,.10), 0 24px 56px -16px rgba(9,9,9,.34);
  --e-cta: 0 6px 20px -6px rgba(244,120,0,.45);

  /* Container */
  --maxw:      1120px;
  --maxw-wide: 1280px;
  --maxw-prose:  62ch;

  --ease: cubic-bezier(.22,.61,.36,1);
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  font-family: var(--font-b);
  color: var(--ink-1);
  background: var(--creme);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}
body.no-scroll { overflow: hidden; }
h1, h2, h3 { font-family: var(--font-h); font-weight: 600; line-height: 1.12; margin: 0 0 .4em; color: var(--ink-1); }
p { margin: 0 0 1em; }
img { max-width: 100%; display: block; }
a { color: inherit; }
svg { flex: none; }

/* ---------- Container de seção (§3) ---------- */
.section {
  width: min(100% - 2 * var(--gutter), var(--maxw));
  margin-inline: auto;
  padding-block: var(--section-y);
  padding-inline: 0;
}
.section p, .section li { max-width: var(--maxw-prose); }
.section-title {
  font-size: var(--fs-500);
  text-align: left;
  letter-spacing: -.02em;
  margin-block-end: var(--sp-3);
}
.section-sub {
  color: var(--ink-2);
  font-size: var(--fs-200);
  max-width: 52ch;
  margin-block-end: var(--sp-6);
}
.eyebrow {
  display: block;
  font-size: var(--fs-100);
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--dourado-ink);
  margin-block-end: var(--sp-2);
}
.center { text-align: center; margin-top: var(--sp-6); }

/* ---------- Botões ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5em;
  font-family: var(--font-b); font-weight: 600; font-size: var(--fs-200);
  padding: 14px 28px; border-radius: var(--r-full); border: 2px solid transparent;
  cursor: pointer; text-decoration: none; line-height: 1; min-height: 44px;
  transition: transform .14s ease-out, background-color .2s ease, color .2s ease, border-color .2s ease;
}
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(0) scale(.98); }
.btn:focus-visible { outline: 2px solid var(--laranja); outline-offset: 2px; }
.btn.big { padding: 17px 38px; font-size: var(--fs-300); }
.btn.sm { padding: 10px 18px; font-size: var(--fs-200); min-height: 40px; }

/* --laranja-surface como objeto gráfico (borda do próprio botão) mede 2.63:1
   sobre --creme, abaixo do 3:1 do WCAG 1.4.11 (o texto interno já passa,
   7.14:1) — filete --linha por dentro, sem mexer em cor (design.md §5.1a). */
.btn-primary { background: var(--laranja-surface); color: var(--preto); box-shadow: var(--e-cta), 0 0 0 1px var(--linha) inset; }
.btn-primary:hover { background: var(--laranja-hover); color: var(--preto); }

.btn-outline { background: transparent; color: var(--laranja-ink); border-color: var(--laranja-ink); }
.btn-outline:hover { background: var(--laranja-surface); color: var(--preto); border-color: var(--laranja-surface); }

.btn-ghost { background: transparent; color: var(--ink-1); border-color: var(--linha); }
.btn-ghost:hover { background: rgba(var(--preto-rgb), .05); border-color: var(--ink-2); }

.btn-whatsapp { background: var(--wa); color: var(--preto); box-shadow: var(--e-2); width: 100%; }
.btn-whatsapp:hover { filter: brightness(.94); }

/* ---------- Header ---------- */
.site-header {
  position: sticky; top: 0; z-index: 40;
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--sp-3) var(--gutter);
  background: rgba(var(--creme-rgb), .94);
  border-bottom: 1px solid var(--linha);
}
.brand { display: flex; align-items: center; }
.logo { height: 28px; width: auto; }
.logo-text { font-family: var(--font-h); font-weight: 600; letter-spacing: .04em; font-size: var(--fs-300); color: var(--ink-1); }
.logo-text b { color: var(--laranja-ink); font-weight: 600; }
.header-cta {
  background: var(--laranja-surface); color: var(--preto); text-decoration: none;
  padding: 9px 20px; border-radius: var(--r-full); font-weight: 600; font-size: var(--fs-200);
  min-height: 40px; display: inline-flex; align-items: center;
  transition: transform .14s ease-out, background-color .2s ease;
}
.header-cta:hover { background: var(--laranja-hover); transform: translateY(-1px); }
.header-cta:focus-visible { outline: 2px solid var(--laranja); outline-offset: 2px; }

/* =====================================================================
   HERO — mobile: a foto é a dobra. Banda escura, foto em camada de
   fundo, texto ancorado na base sobre véu. §5.1
   ===================================================================== */
.hero {
  position: relative; overflow: hidden;
  min-height: clamp(560px, 92svh, 760px);   /* svh: não conta a barra de URL do celular */
  /* flex, não grid: filho position:absolute (.hero-photo, ::after) fica de
     fora do layout flex/grid e usa o padding-box inteiro como containing
     block — mas num grid container um item abspos SEM grid-row/column
     explícitos herda o alinhamento da track implícita (aqui, align-items:end),
     ficando do tamanho do conteúdo e wa colado no fim em vez de esticar.
     Isso quase passou despercebido: a foto do hero ficava pequena, flutuando
     perto da base, com barras pretas nas bordas. */
  display: flex; flex-direction: column; justify-content: flex-end;
  background: var(--surface-dark);
  padding: var(--sp-7) var(--gutter) var(--sp-7);
  color: var(--ink-invert);
}
/* SEM position:relative aqui de propósito — correção de bug da própria
   spec (design.md §5.1 pede position:relative no .hero-inner). .hero-photo
   é filha de .hero-inner (irmã de .hero-text), então position:relative
   no .hero-inner a transformaria em containing block: como .hero-inner
   só tem a altura do CONTEÚDO do texto (não a altura cheia do .hero), a
   foto (position:absolute;inset:0) ficava pequena e colada perto da base,
   com barras pretas nas quatro bordas — só visível testando no browser.
   SEM z-index aqui também, e de propósito (ver bloco grande abaixo): já foi
   z-index:2, e isso é o bug do véu — não reintroduzir. */
.hero-inner { max-width: none; text-align: left; }
/* ---------------------------------------------------------------------
   Por que .hero-inner e .hero-photo NÃO têm z-index, e por que
   .hero-text tem z-index:2 (não 1, não empatado com o véu):

   .hero-inner é flex item de .hero (:193 display:flex) — pela spec do
   Flexbox §4.3, um flex item com z-index != auto cria stacking context
   PRÓPRIO mesmo com position:static. .hero-photo (position:absolute)
   também cria stacking context com qualquer z-index explícito, seja
   qual for. Nenhum ancestral entre eles e a raiz (.hero é position:
   relative mas z-index:auto — isso NÃO cria stacking context) intercepta
   essas stacking contexts, então elas "escapam" e competem, junto com o
   véu (.hero::after, z-index:1, mesmo problema), no nível da raiz.

   O bug original: .hero-inner tinha z-index:2. Como .hero-photo (foto)
   e .hero-text (texto) viviam DENTRO da stacking context do hero-inner,
   os dois eram pintados como UM BLOCO SÓ, acima do véu (2 > 1) — o véu
   nunca aparecia sobre nada, nem sobre a foto nem atrás do texto.

   A correção: tirar o z-index de .hero-inner E de .hero-photo. Sem
   z-index próprio, cada elemento deixa de ser uma stacking context
   atômica e passa a competir INDIVIDUALMENTE com o véu no nível
   flattened: foto (sem z-index, grupo "auto/0") < véu (z-index:1) <
   .hero-text (z-index:2, abaixo). Isso também resolve o sintoma-irmão:
   .car-dots/.car-pause (z-index:3, dentro de .hero-photo > .carousel)
   deixam de ficar presos dentro da stacking context da foto e escapam
   também — ficando acima do véu (3 > 1), legíveis contra o fundo escuro,
   como já eram desenhados para ficar.

   Armadilha: se .hero-text ficasse em z-index:1 (empatado com o véu),
   o véu vence o empate por ser o ÚLTIMO filho de .hero no DOM (::after)
   — cobriria o texto. Por isso .hero-text precisa ficar ACIMA do véu
   (z-index:2), não empatado. */
.hero-text { position: relative; z-index: 2; display: flex; flex-direction: column; align-items: flex-start; }

.hero-photo { position: absolute; inset: 0; margin: 0; max-width: none; }
.hero-photo .carousel { height: 100%; border-radius: 0; box-shadow: none; }
.hero-photo .slides { height: 100%; aspect-ratio: auto; }
.hero-photo .slide img { object-position: 50% 26%; }

/* o ÚNICO gradiente da página fora do carrossel.
   Stops e --veil-1 ajustados a partir da spec original do design.md §5.1
   (que usava --veil-1:.28 nos stops 26%/62%): medido em browser (Playwright,
   screenshot real + amostra de pixel atrás do texto, texto oculto via
   visibility:hidden para não colidir com o glifo) que a versão original
   reprovava o critério de 4.5:1 do próprio design.md — em 360×640 (a dobra
   mais curta, onde o texto ocupa fração maior da altura do .hero e cai
   mais cedo na faixa clara do "vale") o h1 media 2.25:1 e o sub 3.73:1.
   Vale mais escuro (.28→.58) e mais cedo/estreito (26%→20%, 62%→45%)
   resolve nas duas viewports com margem: h1 ≥5.4:1, sub ≥5.2:1, micro
   ≥7.5:1 em 390×844 e 360×640. --veil-2/--veil-3 ficam como estavam —
   --veil-2 é reusado em `.cta-final-micro` e no véu do desktop (:392),
   mexer nele vazaria pra lá. */
.hero::after {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(180deg,
    var(--veil-2) 0%, var(--veil-1) 20%, var(--veil-2) 45%, var(--veil-3) 100%);
}

/* .badge só é usada dentro do hero (superfície escura) — por isso já
   nasce no tom dourado (§2.9: "dourado só sobre superfície escura").
   .badge.soft é a variante para superfície clara (usada em .about).
   Fundo em rgba(preto,.65), não mais rgba(dourado,.22): o badge é o
   primeiro bloco de texto do hero, logo abaixo do topo do véu (:260) —
   mesmo já com o vale mais escuro (--veil-1 .58), sobre cabelo loiro
   claro naquela altura o tint dourado a .22 media ~2:1 (medido em
   browser, reprova o critério de 4.5:1). .22 só funcionava assumindo
   fundo já escuro; um pill escuro sólido (mesmo padrão do .car-pause,
   rgba(preto,.55)) garante o contraste do texto dourado independente do
   que está atrás — medido 6.0:1–7.9:1 em 390×844 e 360×640, nas 4 fotos
   do carrossel. */
.badge {
  display: inline-block; background: rgba(var(--preto-rgb), .65); color: var(--dourado);
  font-weight: 600; font-size: var(--fs-100); letter-spacing: .02em;
  padding: 7px 16px; border-radius: var(--r-full); margin-block-end: var(--sp-4);
}
.badge.soft { background: rgba(var(--dourado-rgb), .16); color: var(--dourado-ink); }

.hero h1 { font-size: var(--fs-600); letter-spacing: -.02em; margin-block-end: .3em; color: var(--ink-invert); }
#hero-sub { font-size: var(--fs-300); color: var(--ink-invert-2); max-width: 26ch; margin: 0 0 var(--sp-5); }
.hero-micro { font-size: var(--fs-100); font-weight: 600; color: var(--ink-invert-2); margin: var(--sp-3) 0 0; }

/* No mobile, .hero-micro era o penúltimo filho de .hero-text (.rating vinha
   depois dele, com margin-top:sp-4). Como .rating saiu do fluxo (foi pra
   dentro de .hero-photo — ver comentário grande logo abaixo), .hero-micro
   virou o ÚLTIMO filho — e por causa do justify-content:flex-end de .hero
   (:196), o ÚLTIMO filho de .hero-text é sempre o que fecha rente ao
   padding-box de .hero. Sem este margin-bottom, .hero-micro passa a
   ocupar exatamente o offset que .rating (agora position:absolute, bottom
   :var(--sp-7) — mesmo valor) também mira, e as duas caixas desenham uma
   por cima da outra: bug real, visto em produção pelo dono em 390px antes
   deste comentário existir. O valor abre de novo o espaço que .rating
   costumava tomar (cartão de ~26–50px + os 16px do antigo margin-top) —
   generoso o bastante pra cobrir o texto do selo quebrando em 2 linhas nos
   360px mais estreitos, sem depender de medir a altura exata do .rating
   (impossível em CSS puro depois que ele saiu do fluxo). Só entre 900 e o
   fim do intervalo mobile: em ≥900 .rating vira cartão sobre a foto (outro
   bloco de layout inteiro), .hero-micro não precisa mais dessa reserva. */
@media (max-width: 899px) {
  .hero-micro { margin-bottom: var(--sp-7); }
}

/* .rating é filho de .hero-photo no HTML (index.html), não de .hero-text —
   dependência estrutural: em ≥900px (Direção A, abaixo) o selo é cartão
   flutuante position:absolute com .hero-photo como containing block
   (design.md §5.1a/§5.6). Isso vale desde o mobile: .hero-photo já é
   position:absolute aqui embaixo (:245), então já É containing block válido
   sem precisar de position:relative extra. left/bottom abaixo mira a MESMA
   borda inferior-esquerda que .rating tinha como último filho de .hero-text
   (que fechava rente ao padding-box de .hero via justify-content:flex-end,
   :196) — mas só bate com a posição antiga de verdade com a reserva de
   .hero-micro logo acima: sem ela, os dois elementos (agora em subárvores
   DOM diferentes, sem flexbox comum entre si) miram o MESMO offset e se
   sobrepõem — não tem cálculo de `bottom` que sozinho resolva isso, porque
   não existe mais uma pilha flex compartilhada entre .hero-micro e .rating
   depois da mudança de pai. Sem o position:absolute o selo cairia dentro do
   fluxo de .hero-photo (que agora tem .carousel ocupando 100% da altura) e
   vazaria pra fora da dobra. z-index:2 é novo aqui: como filho direto de
   .hero-text, .rating já herdava o z-index:2 do pai (:243) pra ficar acima
   do véu — como filho de .hero-photo (sem z-index próprio) ele precisa da
   própria declaração.
   margin:0 é novo por um motivo diferente: .rating é um <p>, e o UA
   stylesheet dá a todo <p> margin:1em 0 por padrão. Enquanto .rating vivia
   em fluxo dentro de .hero-text, esse padrão era sobrescrito por um
   `margin` explícito (a versão antiga desta regra tinha
   `margin: var(--sp-4) 0 0`). Sem reset, num elemento position:absolute o
   margin-bottom do UA (1em = 12.8px no --fs-100 daqui) soma ao `bottom`
   abaixo e desloca o cartão ~13px pra cima do valor pretendido — medido em
   Playwright, não estimado. */
.rating {
  position: absolute; left: var(--gutter); bottom: var(--sp-7); z-index: 2;
  display: inline-flex; align-items: center; gap: var(--sp-2); margin: 0;
  font-size: var(--fs-100); color: var(--ink-invert-2);
}
.rating[hidden] { display: none; } /* obrigatório: .rating é inline-flex, vence [hidden] sem esta regra */
.rating .stars { color: var(--dourado); letter-spacing: .08em; font-size: var(--fs-200); }
.rating .rating-txt { color: var(--ink-invert-2); }

/* ---------- Carrossel do hero (3D flip intacto — style original preservado) ---------- */
.carousel { position: relative; border-radius: var(--r-lg); overflow: hidden; }
.slides {
  list-style: none; margin: 0; padding: 0;
  position: relative; aspect-ratio: 900 / 1125;  /* guarda de CLS fora do contexto do hero */
  perspective: 1500px;
}
.slide {
  position: absolute; inset: 0;
  opacity: 0; z-index: 0;
  transform-origin: left center;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}
.slide.is-on { opacity: 1; z-index: 1; }

.slide.is-turning {
  opacity: 1; z-index: 2; will-change: transform;
  animation: pageTurn 820ms cubic-bezier(.45,.05,.55,.95) forwards;
}
@keyframes pageTurn {
  from { transform: rotateY(0deg); }
  to   { transform: rotateY(-180deg); }
}

/* sombra que corre pela folha — iluminação do efeito 3D, não decoração (§2.8) */
.slide::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  border-radius: inherit; opacity: 0;
  background: linear-gradient(100deg, rgba(var(--preto-rgb),.55) 0%, rgba(var(--preto-rgb),.18) 45%, rgba(var(--preto-rgb),0) 75%);
}
.slide.is-turning::after { animation: pageShade 820ms ease-in forwards; }
@keyframes pageShade {
  from { opacity: 0; }
  60%  { opacity: .9; }
  to   { opacity: 1; }
}
.slide img { width: 100%; height: 100%; object-fit: cover; display: block; }

@media (prefers-reduced-motion: reduce) {
  .slide.is-turning { animation: none; opacity: 0; }
  .slide.is-turning::after { animation: none; opacity: 0; }
}

/* bolinhas — alinhadas à esquerda, na mesma linha do texto (§5.1).
   gap maior (--sp-5=24px, passo de 32px) + ::before assimétrico: alvo de
   toque de 32×44 sem sobrepor o vizinho. Com o gap antigo (--sp-2=8px,
   passo 16px) e inset:-18px em todos os lados, a área de toque de um dot
   cobria o CENTRO do dot ao lado — clique no dot 1 ativava o dot 2. */
.car-dots {
  position: absolute; left: var(--gutter); bottom: var(--sp-5);
  display: flex; gap: var(--sp-5); z-index: 3;
}
.car-dot {
  position: relative;
  width: 8px; height: 8px; padding: 0; border: 0; border-radius: var(--r-full); cursor: pointer;
  background: rgba(var(--branco-rgb), .55);
  transform-origin: center; transition: background-color .25s ease;
}
.car-dot::before { /* área de toque ampliada — 8px visual, 32×44 de alvo, sem sobrepor o vizinho */
  content: ""; position: absolute; inset: -18px -12px;
}
/* .scaleX é estado, não movimento: fica fora do no-preference para que o
   dot ativo continue visualmente distinto (não só por cor) com reduced
   motion — só a TRANSIÇÃO até lá é que é opcional. */
.car-dot[aria-current="true"] { background: var(--branco); transform: scaleX(2.75); }
@media (prefers-reduced-motion: no-preference) {
  .car-dot { transition: background-color .25s ease, transform .25s ease; }
}
.car-dot:focus-visible { outline: 2px solid var(--ink-invert); outline-offset: 3px; }

/* pausar/retomar — quiz.js:362,366 escrevem os glifos ❚❚/▶ como TEXTO
   (innerHTML), não SVG; o botão está estilado para esse texto. */
.car-pause {
  position: absolute; top: var(--sp-4); right: var(--sp-4); z-index: 3;
  width: 30px; height: 30px; border-radius: 50%; border: 0; cursor: pointer;
  background: rgba(var(--preto-rgb), .55); color: var(--ink-invert);
  font-size: var(--fs-100); line-height: 1;
  display: grid; place-items: center; opacity: 0; transition: opacity .2s ease;
}
.car-pause::before { content: ""; position: absolute; inset: -7px; } /* alvo de toque ≥44px */
.carousel:hover .car-pause,
.car-pause:focus-visible { opacity: 1; }
.car-pause:focus-visible { outline: 2px solid var(--ink-invert); outline-offset: 2px; }

/* ---------- Desktop hero — Direção A "Creme editorial" (design.md §5.1a) ----------
   Decisão do dono (esta tarefa): o tratamento claro passa a valer de 900px, não
   de 1200px como a leitura original da §5.1a fixava — abaixo de 1200 o hero
   caía de volta no fundo escuro, e é exatamente isso que gerou a queixa (janela
   não maximizada / notebook menor continuava vendo o tratamento escuro). A
   ressalva da spec (coluna de foto em 4:5 sobra pouco pro h1 entre 900–1199px,
   quebra em 4+ linhas) é real — resolvida abaixo com um degrau de tipografia só
   nessa sub-faixa (bloco @media 900–1199 logo depois deste), não com um segundo
   tratamento de layout. Sem faixa órfã: <900 cai no tratamento base (mobile:
   foto de fundo + véu + texto ancorado embaixo, bloco ".hero{...}" acima); ≥900
   cai aqui — as duas partições nascem do mesmo valor (900px), não existe
   largura sem tratamento definido. */
@media (min-width: 900px) {
  .hero { background: var(--creme); color: var(--ink-1); min-height: auto; padding-block: var(--section-y); }
  .hero-inner {
    display: grid; grid-template-columns: 1fr .82fr; gap: var(--sp-9); align-items: center;
    width: min(100% - 2 * var(--gutter), var(--maxw-wide)); margin-inline: auto;
  }
  /* sobrescreve o position:absolute do tratamento mobile (regra base de
     .hero-photo) — aqui a foto é item de grid, não camada de fundo atrás do
     texto. aspect-ratio trava perto do nativo 4:5 da foto-fonte: mostra a
     foto inteira. Também é o containing block do .rating (cartão flutuante,
     ver regra .rating logo abaixo) — não tirar o position:relative daqui. */
  .hero-photo { position: relative; height: auto; width: 100%; aspect-ratio: 4/5; margin: 0; }
  .hero-photo .carousel { border-radius: var(--r-lg); box-shadow: var(--e-3); }
  .hero-photo .slide img { object-position: 50% 50%; }
  .hero::after { content: none; } /* sem foto-fundo atrás do texto, sem véu pra escurecer */

  /* .car-dots perdeu o scrim que vinha do véu removido acima (::after) — sem
     ele fica ilegível sobre foto clara. Uma faixa de gradiente na base do
     cartão foi a primeira tentativa e escurecia justo o comprimento do
     cabelo — o que esta direção existe pra mostrar inteiro. Pill escura só
     atrás dos dots (mesmo padrão já usado no .car-pause do próprio
     carrossel) resolve a legibilidade tocando uma fração dos pixels da foto,
     sem elemento novo na pilha 3D — .car-dots já é z-index:3, já pintava
     acima do .slide.is-turning antes desta tarefa (comportamento herdado,
     não alterado aqui).
     Movida pro TOPO (base é left/bottom, :347): .rating agora mora dentro
     de .hero-photo também, ancorado no canto inferior-esquerdo (regra logo
     abaixo) — as duas na mesma linha de baixo colidem. A primeira tentativa
     foi só trocar de lado (dots embaixo-à-direita, rating embaixo-à-
     esquerda), mas medido em Playwright em toda a faixa ≥900px isso ainda
     sobrepõe de verdade entre 900 e 1200px (cartão da foto mais estreito
     ali — 290 a 425px — não sobra espaço pros dois lados da MESMA linha
     quando o texto do selo é "4,4 · 69 avaliações no Google": até 124px de
     invasão horizontal, 12px vertical, medidos, não estimados). Só resolve
     de vez tirando os dots da linha de baixo: sobem pro topo, ao lado do
     .car-pause (mesmo padrão de canto, :371) — aí as duas âncoras (topo/
     controles vs. base/selo) nunca disputam largura, em nenhuma largura
     ≥900px, veja o texto do selo longo que for. */
  .hero-photo .car-dots {
    left: var(--sp-4); right: auto; top: var(--sp-4); bottom: auto;
    padding: 6px 10px; border-radius: var(--r-full);
    background: rgba(var(--preto-rgb), .55);
  }

  /* h1/#hero-sub/.hero-micro têm `color` explícito herdado do tratamento
     escuro (--ink-invert/--ink-invert-2 ≈ --creme, invisível sobre --creme)
     — o color:var(--ink-1) do .hero acima só resolve herança, não alcança
     quem já tem color próprio. */
  .hero h1 { color: var(--ink-1); }
  #hero-sub, .hero-micro { color: var(--ink-2); }
  /* .badge no hero nasceu pill escura pro tratamento mobile (foto de fundo).
     Sobre creme reusa o mesmo par já auditado de .badge.soft (§5.6) — não
     duplica outro token pra eyebrow. */
  .hero .badge { background: rgba(var(--dourado-rgb), .16); color: var(--dourado-ink); }

  /* .rating vira cartão flutuante no canto inferior-esquerdo da foto — spec
     literal (design.md §5.1a/§5.6), possível agora porque .rating é filho de
     .hero-photo no HTML (index.html) e .hero-photo é position:relative
     logo acima (containing block). Cor inalterada: dourado sobre --preto já
     media 8.30:1 antes desta tarefa (tratamento mobile, regra base de
     .rating) — mesmo par, agora dentro de um cartão com borda em vez de
     solto sobre o véu. Borda --creme de 3px é o que garante o cartão se
     destacar mesmo quando o canto inferior-esquerdo da foto do carrossel for
     escuro (checar nas 4 fotos, não só na 1). */
  .rating {
    left: var(--sp-5); bottom: var(--sp-5);
    background: var(--preto); color: var(--ink-invert-2);
    padding: var(--sp-3) var(--sp-4); border-radius: var(--r-md);
    border: 3px solid var(--creme); box-shadow: var(--e-2);
  }
}

/* h1 na sub-faixa 900–1199px: a coluna de texto (1fr de ~1.82 unidades do
   grid acima) mede bem menos que a foto de 4:5 ao lado — testado no
   navegador (não no papel): --fs-600 já está no teto do próprio clamp
   (3.05rem/48.8px, atingido desde ~612px de viewport, portanto CONSTANTE daí
   pra frente) e nessa largura de coluna quebra "Sua transformação começa
   aqui" em 4 linhas, o h1 sozinho passando a dominar o bloco de texto. Um
   degrau de tipografia pra baixo (--fs-500, teto 2.44rem/39px) resolve sem
   tocar no grid nem no h1 do resto da faixa ≥900: 2–3 linhas, hierarquia com
   sub/CTA continua clara. Em 1200px a coluna ganha respiro (maxw-wide passa
   a caber por inteiro) e --fs-600 volta a caber sem quebra — por isso o
   teto aqui é exatamente 1199px, mesma partição do bloco de 1200 que já
   existia pra proof/gallery. */
@media (min-width: 900px) and (max-width: 1199px) {
  .hero h1 { font-size: var(--fs-500); }
}

/* =====================================================================
   PROOF / GALERIA — grid assimétrico com foto-herói (§5.4)
   ===================================================================== */
.gallery { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--sp-3); }
.ph {
  aspect-ratio: 1/1; border-radius: var(--r-md); background: var(--surface-2);
  box-shadow: var(--e-0); overflow: hidden; margin: 0;
}
.ph img { width: 100%; height: 100%; object-fit: cover; }
.ph:first-child {
  grid-column: span 2; aspect-ratio: 4/5; border-radius: var(--r-lg); box-shadow: var(--e-2);
}
@media (hover: hover) and (pointer: fine) {
  .ph img { transition: transform .32s ease-out; }
  .ph:hover img { transform: scale(1.04); }
}
@media (min-width: 1200px) {
  /* única seção que usa --maxw-wide (§5.4): foto quer largura, texto não */
  .proof { width: min(100% - 2 * var(--gutter), var(--maxw-wide)); }
  .gallery { grid-template-columns: repeat(4, 1fr); }
  .ph:first-child { grid-column: span 2; grid-row: span 2; aspect-ratio: 1/1; }
}

/* =====================================================================
   SERVICES — lista no mobile, cartão com régua no desktop (§5.5)
   ===================================================================== */
.cards { display: flex; flex-direction: column; margin-top: var(--sp-2); }
.card {
  display: flex; align-items: flex-start; gap: var(--sp-4);
  padding: var(--sp-5) 0; border-bottom: 1px solid var(--linha);
}
.cards .card:last-child { border-bottom: 0; }
.card-ic {
  width: 44px; height: 44px; flex: none; border-radius: var(--r-sm);
  background: rgba(var(--laranja-rgb), .10); color: var(--laranja-ink);
  display: grid; place-items: center;
}
.card-ic svg { width: 24px; height: 24px; }
.card h3 { font-size: var(--fs-300); margin-bottom: .2em; }
.card p { color: var(--ink-2); margin: 0; font-size: var(--fs-200); }

@media (min-width: 900px) {
  .cards { flex-direction: row; gap: var(--sp-4); counter-reset: card; }
  .card {
    flex: 1; flex-direction: column; align-items: flex-start; gap: var(--sp-3);
    padding: var(--sp-5); border: 1px solid var(--linha); border-radius: var(--r-md);
    border-top: 2px solid transparent; position: relative;
    transition: border-color .2s ease;
  }
  .card::before {
    counter-increment: card; content: "0" counter(card);
    font-size: var(--fs-100); font-weight: 600; letter-spacing: .1em;
    color: var(--dourado-ink); order: -1; margin-bottom: var(--sp-1);
  }
  .card:hover, .card:focus-within { border-top-color: var(--laranja-surface); }
}

/* =====================================================================
   ABOUT — assimetria original mantida + segundo plano sobreposto (§5.6)
   ===================================================================== */
.about { display: grid; gap: var(--sp-7); align-items: center; }
.about-photo-wrap { position: relative; }
.about-photo {
  aspect-ratio: 4/5; border-radius: var(--r-lg); background: var(--surface-2); overflow: hidden; margin: 0;
  box-shadow: var(--e-2);
}
.about-photo img { width: 100%; height: 100%; object-fit: cover; }

/* cartão da equipe — foto já é P&B na origem, sem filtro (§2.10).
   Proporção 4/3 (não 3/4): a fonte é paisagem 900×720 com as 6 pessoas
   ocupando quase toda a largura; um recorte 3/4 cortaria ~2 pessoas de
   fora, o que anula o motivo da foto existir. 4/3 preserva 100% da
   largura e recorta só ~6% da altura (sobra de fundo). */
.about-team {
  position: absolute; left: 0; bottom: 0; margin: 0;
  width: 44%; aspect-ratio: 4/3;
  border-radius: var(--r-md); overflow: hidden;
  box-shadow: var(--e-3); border: 4px solid var(--creme);
  transform: translate(-10%, 14%);
}
.about-team img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 38%; }

.about-text .badge.soft { margin-block-end: var(--sp-3); }
.ticks { list-style: none; padding: 0; margin: 0 0 var(--sp-6); }
.ticks li { display: flex; align-items: flex-start; gap: var(--sp-3); margin-bottom: var(--sp-3); color: var(--ink-1); }
.ticks li:last-child { margin-bottom: 0; }
.tick-ic {
  width: 20px; height: 20px; flex: none; margin-top: 2px; padding: 3px; border-radius: 50%;
  background: var(--laranja-surface); color: var(--preto);
}

@media (min-width: 900px) {
  .about { grid-template-columns: 1fr 1.1fr; }
  .about-photo { aspect-ratio: 3/4; }
  .about-team { width: 38%; transform: translate(-18%, 14%); }
}

/* =====================================================================
   LOCAL — cartão único da página, foto + dados (§5.2)
   ===================================================================== */
.local-card {
  background: var(--branco); border-radius: var(--r-lg); box-shadow: var(--e-2);
  overflow: hidden; display: grid;
}
.local-photo { margin: 0; aspect-ratio: 4/5; }
.local-photo img { width: 100%; height: 100%; object-fit: cover; object-position: 75% 45%; }
.local-info { padding: var(--sp-6) var(--gutter); }
.local-info .section-title { margin-block-end: var(--sp-4); }
.local-line {
  display: flex; align-items: flex-start; gap: var(--sp-3);
  font-size: var(--fs-200); color: var(--ink-1); margin: 0 0 var(--sp-3);
}
.local-ic { width: 20px; height: 20px; flex: none; margin-top: 2px; color: var(--laranja-ink); }
.local-line span { max-width: 28ch; }
.local-actions { display: flex; flex-direction: column; gap: var(--sp-3); margin-top: var(--sp-5); }
.local-actions .btn { gap: var(--sp-2); }
.local-actions svg { width: 18px; height: 18px; }

@media (min-width: 600px) {
  .local-actions { flex-direction: row; }
}
@media (min-width: 900px) {
  .local-card { grid-template-columns: 1fr 1fr; }
  .local-photo { aspect-ratio: 1/1; }
  .local-info { padding: var(--sp-8); display: flex; flex-direction: column; justify-content: center; }
}

/* =====================================================================
   CTA FINAL — banda full-bleed sem wrapper novo (§3, §5.7)
   ===================================================================== */
.cta-final {
  width: auto; max-width: none; padding-inline: var(--gutter);
  background: var(--laranja-surface); color: var(--preto); text-align: center;
}
.cta-final > h2, .cta-final > .cta-final-micro, .cta-final > .btn { max-width: var(--maxw-prose); margin-inline: auto; }
.cta-final h2 { font-size: var(--fs-500); color: var(--preto); margin-bottom: var(--sp-3); }
.cta-final-micro { font-size: var(--fs-200); color: var(--veil-2); max-width: var(--maxw-prose); margin: 0 auto var(--sp-6); }
.cta-final .btn-primary { background: var(--preto); color: var(--creme); box-shadow: var(--e-3); }
.cta-final .btn-primary:hover { background: var(--ink-1); color: var(--creme); }

/* =====================================================================
   FOOTER
   ===================================================================== */
.site-footer {
  padding: var(--sp-7) var(--gutter) calc(90px + env(safe-area-inset-bottom));
  color: var(--ink-invert-2); background: var(--surface-dark);
}
.site-footer p { margin: 0 0 var(--sp-3); }
.site-footer .footer-voice {
  font-family: var(--font-h); font-weight: 600; font-size: var(--fs-300); color: var(--ink-invert);
}
.site-footer .footer-voice .accent { color: var(--laranja); }
.site-footer a { color: var(--ink-invert); text-decoration: none; font-weight: 600; display: inline-flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-200); }
.site-footer a:hover { color: var(--laranja); }
.footer-ic { width: 18px; height: 18px; }
.footer-meta { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; font-size: var(--fs-200); }

/* ---------- FAB ---------- */
.fab {
  position: fixed; right: var(--sp-4); bottom: calc(var(--sp-4) + env(safe-area-inset-bottom)); z-index: 45;
  width: 58px; height: 58px; border-radius: 50%; border: none; cursor: pointer;
  background: var(--wa); color: var(--preto); box-shadow: var(--e-2);
  display: grid; place-items: center;
  transition: transform .16s ease-out;
}
.fab:hover { transform: scale(1.06); }
.fab:active { transform: scale(.98); }
.fab:focus-visible { outline: 2px solid var(--preto); outline-offset: 3px; }
.fab::before {
  content: ""; position: absolute; inset: -6px; border-radius: inherit;
  background: var(--wa); opacity: 0; pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
  .fab { animation: fabIn .26s ease-out; }
  .fab::before { animation: fabPulse .9s ease-out 1; animation-fill-mode: forwards; }
  @keyframes fabIn { from { opacity: 0; transform: scale(.8); } to { opacity: 1; transform: scale(1); } }
  @keyframes fabPulse { from { opacity: .5; transform: scale(1); } to { opacity: 0; transform: scale(1.5); } }
}

/* =====================================================================
   QUIZ MODAL — bottom-sheet (§5.10)
   ===================================================================== */
#quiz-modal {
  position: fixed; inset: 0; z-index: 60; display: none;
  align-items: flex-end; justify-content: center;
}
#quiz-modal.open { display: flex; }
#quiz-modal::before { /* backdrop no pseudo-elemento: clique-fora continua acertando o próprio #quiz-modal */
  content: ""; position: absolute; inset: 0; z-index: 0;
  background: rgba(var(--preto-rgb), .62);
}
.quiz-card {
  position: relative; z-index: 1; width: 100%; max-width: 520px; background: var(--branco);
  border-radius: var(--r-lg) var(--r-lg) 0 0; padding: var(--sp-6) var(--sp-5) var(--sp-7);
  box-shadow: var(--e-3); max-height: 92svh; overflow-y: auto;
}
.quiz-card::before { /* handle do bottom-sheet */
  content: ""; display: block; width: 36px; height: 4px; border-radius: var(--r-full);
  background: rgba(var(--preto-rgb), .14); margin: 0 auto var(--sp-4);
}
@media (prefers-reduced-motion: no-preference) {
  #quiz-modal.open::before { animation: backdropIn .2s ease; }
  .quiz-modal.open .quiz-card { animation: sheetIn .26s cubic-bezier(.2,.8,.2,1); }
  @keyframes backdropIn { from { opacity: 0; } to { opacity: 1; } }
  @keyframes sheetIn { from { opacity: 0; transform: translateY(24px); } to { opacity: 1; transform: none; } }
}
.quiz-close {
  position: absolute; top: var(--sp-3); right: var(--sp-4); width: 36px; height: 36px; border-radius: 50%;
  border: none; background: rgba(var(--preto-rgb), .06); color: var(--ink-1); cursor: pointer;
  display: grid; place-items: center; z-index: 3; transition: background-color .15s ease;
}
.quiz-close:hover { background: rgba(var(--preto-rgb), .12); }
.quiz-close:focus-visible { outline: 2px solid var(--laranja); outline-offset: 2px; }
.quiz-close svg { width: 18px; height: 18px; }

/* cabeçalho fixo — progresso + fechar não rolam com as opções */
.quiz-progress {
  position: sticky; top: 0; z-index: 2; background: var(--branco);
  margin: calc(var(--sp-6) * -1) calc(var(--sp-5) * -1) var(--sp-5);
  padding: var(--sp-5) var(--sp-5) var(--sp-4);
  border-radius: var(--r-lg) var(--r-lg) 0 0;
}
.quiz-progress-top { display: flex; justify-content: center; margin-bottom: var(--sp-3); }
.quiz-step-label {
  font-size: var(--fs-100); font-weight: 600; letter-spacing: .14em; text-transform: uppercase;
  color: var(--dourado-ink);
}
.quiz-track { height: 6px; border-radius: var(--r-full); background: rgba(var(--preto-rgb), .08); overflow: hidden; }
/* Exceção de contrato: quiz.js:128 escreve `style="width:X%"` inline no
   fill — a barra TEM que responder a width. Não trocar por transform:
   scaleX() sem tocar o JS, senão a barra nunca anda (ver briefing). */
.quiz-track-fill {
  display: block; height: 100%; border-radius: inherit;
  background: var(--laranja-surface);
  transition: width .32s cubic-bezier(.2,.8,.2,1);
}

.quiz-q { font-size: var(--fs-400); text-align: center; margin-bottom: .25em; }
.quiz-hint { text-align: center; color: var(--ink-2); font-size: var(--fs-200); margin-bottom: var(--sp-6); }

.quiz-group-label {
  font-size: var(--fs-100); font-weight: 600; letter-spacing: .12em; text-transform: uppercase;
  color: var(--ink-2); margin: 0 0 var(--sp-2) 2px;
}
.quiz-options + .quiz-group-label { margin-top: var(--sp-5); }
.quiz-options.grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3); margin-bottom: var(--sp-2); }

/* Correção CSS-only do "buraco": quiz.js sempre gera `.quiz-options.grid`
   (2 colunas), mesmo quando o passo tem 3 opções (unhas, sobrancelha,
   período). Sem tocar o JS, :has() detecta exatamente 3 filhos e vira
   3 colunas — degrada com segurança em navegador sem :has() (2+vazio,
   comportamento de hoje, não é regressão). */
.quiz-options.grid:has(> .opt:nth-child(3):last-child) {
  grid-template-columns: repeat(3, 1fr);
}
.quiz-options.grid:has(> .opt:nth-child(3):last-child) .opt {
  flex-direction: column; align-items: center; text-align: center;
  min-height: 0; padding: var(--sp-3) var(--sp-2); gap: var(--sp-2);
}
.quiz-options.grid:has(> .opt:nth-child(3):last-child) .opt-label { font-size: var(--fs-100); }

.opt {
  position: relative;
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-3);
  min-height: 108px; text-align: left;
  background: var(--branco); border: 1px solid var(--linha); border-radius: var(--r-md);
  padding: var(--sp-4) var(--sp-3) var(--sp-3);
  font-family: var(--font-b); font-size: var(--fs-200); font-weight: 600; line-height: 1.3;
  color: var(--ink-1); cursor: pointer;
  transition: border-color .15s ease, transform .15s ease;
}
/* elevação de :hover (--e-0 -> --e-1) vive numa camada à parte: o
   box-shadow em si nunca é transicionado (só a opacity da camada) */
.opt::before {
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  box-shadow: var(--e-1); opacity: 0; pointer-events: none;
}
.opt:hover::before { opacity: 1; }
@media (prefers-reduced-motion: no-preference) {
  .opt::before { transition: opacity .15s ease-out; }
}
.opt::after { /* anel de seleção — feedback de clique, não decoração */
  content: ""; position: absolute; inset: -1px; border-radius: inherit;
  outline: 2px solid var(--laranja); outline-offset: -2px; opacity: 0; pointer-events: none;
}
.opt.sel::after { opacity: 1; }
@media (prefers-reduced-motion: no-preference) {
  .opt::after { transition: opacity .15s ease-out, transform .15s ease-out; transform: scale(.96); }
  .opt.sel::after { transform: scale(1); }
}
.opt-ic-wrap {
  width: 38px; height: 38px; flex: none; border-radius: var(--r-sm);
  display: grid; place-items: center;
  background: rgba(var(--laranja-rgb), .10); color: var(--laranja-ink);
  transition: background-color .15s ease, color .15s ease;
}
.opt-ic { width: 21px; height: 21px; display: block; }
.opt-emoji { font-size: var(--fs-300); line-height: 1; }
.opt-label { display: block; }

.opt:hover { border-color: rgba(var(--laranja-rgb), .55); transform: translateY(-1px); }
.opt:focus-visible { outline: 2px solid var(--laranja); outline-offset: 2px; }
.opt.sel { border-color: var(--laranja-surface); background: rgba(var(--laranja-rgb), .07); }
.opt.sel .opt-ic-wrap { background: var(--laranja-surface); color: var(--preto); }

.quiz-next { width: 100%; margin-top: var(--sp-4); min-height: 48px; }
.quiz-next:disabled { opacity: .45; cursor: not-allowed; box-shadow: none; }

.quiz-back {
  display: block; margin: var(--sp-5) auto 0; background: none; border: none; color: var(--ink-2);
  font-family: var(--font-b); font-size: var(--fs-200); cursor: pointer; text-decoration: underline;
  min-height: 44px; padding: var(--sp-2);
}

/* tela final */
.quiz-check {
  width: 60px; height: 60px; margin: 0 auto var(--sp-4); border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(var(--wa-rgb), .12); color: var(--wa);
}
@media (prefers-reduced-motion: no-preference) {
  .quiz-check { animation: fabIn .35s ease-out; }
}
.quiz-check-ic { width: 30px; height: 30px; display: block; }
.quiz-resumo {
  background: var(--surface-2); border-radius: var(--r-md); padding: var(--sp-4) var(--sp-5); text-align: center;
  color: var(--ink-1); font-weight: 600; margin: var(--sp-1) 0 var(--sp-6);
}
.quiz-reassure { text-align: center; color: var(--ink-2); font-size: var(--fs-100); margin-top: var(--sp-4); }

/* ---------- Consent ---------- */
.consent {
  position: fixed; left: var(--sp-3); right: var(--sp-3); bottom: var(--sp-3); z-index: 70;
  /* --e-3 no máximo em 4 componentes (checklist design.md) — o consent é o
     candidato menos importante (aviso utilitário, não elemento de marca/
     conversão) para descer um degrau: --e-2 no lugar de --e-3. */
  background: var(--branco); border-radius: var(--r-lg); box-shadow: var(--e-2);
  /* Parecer de Portão 2, achado #2 (menor, não bloqueia): em fs-200 (1rem)
     + padding-inline sp-5 o texto quebra em mais linhas e o banner cresce o
     bastante (163px em 360px) pra nascer sobre o CTA da tela final. Mobile
     (base) fica mais compacto — --fs-200 mantido, não mexe em legibilidade —
     e ≥600px (mais largura) recupera o padding/gap de antes, no média query
     abaixo. */
  padding: var(--sp-3) var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-2);
  border: 1px solid var(--linha);
}
.consent p { margin: 0; font-size: var(--fs-200); color: var(--ink-1); max-width: none; }
.consent a { color: var(--laranja-ink); }
.consent-actions { display: flex; gap: var(--sp-3); justify-content: flex-end; }

@media (min-width: 600px) {
  .consent {
    left: var(--sp-5); right: auto; bottom: var(--sp-5); max-width: 480px;
    padding: var(--sp-4) var(--sp-5); gap: var(--sp-3);
  }
}

/* Parecer de Portão 2, achado #1 (bloqueante): .consent (z-index 70, fixed)
   fica por cima do #quiz-modal (z-index 60) e cobre/intercepta clique do
   card enquanto o modal é bottom-sheet (<900px — #quiz-modal{align-items:
   center} só liga em min-width:900px, ver abaixo). Nessa faixa (600–899px)
   o .consent é max-width:480px ancorado em left:24px (:747-750), ocupando
   24→504px, enquanto o card (max-width:520px, :588, sempre centralizado)
   ocupa 124→644px em 768px — sobreposição real. O banner de 480px não cabe
   na faixa de 124px disponível ao lado do card nessa largura (mesmo no
   topo da faixa, 899px, o gutter pelo mesmo cálculo do achado #2 abaixo é
   de 157,5px — indistinguível dos 158px aceitos como viáveis em 900px,
   sem faixa órfã entre um valor e outro): a saída é esconder o consent
   enquanto o modal está aberto e
   devolvê-lo ao fechar (comportamento inalterado — não decidir não faz o
   banner sumir, só abrir o modal faz).
   Regra em DUAS partes, sem faixa órfã entre elas (Parecer de Portão 3): a
   base abaixo esconde sem limite superior de largura; só o
   @media(min-width:900px) seguinte reexibe — as duas regras são
   complementares no MESMO valor (900px: tudo <900 cai na base, tudo >=900
   cai no media query), então não existe, por construção, nenhuma largura —
   inteira ou fracionária, qualquer precisão — em que nem uma nem outra
   regra vale (não é caso de medir caso a caso; é a definição de partição
   do eixo real em 900). Verificado com viewport aninhada (iframe) nos
   inteiros 899/900 — o Chromium arredonda a largura de layout do iframe
   pro inteiro de CSS px mais próximo, então não dá pra observar uma largura
   fracionária de verdade nesse harness; a garantia de não ter faixa órfã é
   estrutural (a partição acima), não uma medição de caso extremo. */
#quiz-modal.open ~ .consent { display: none; }

/* Achado #2 (decisão do dono, ver .zerow/backlog.md): em ≥900px o consent
   NÃO se esconde — fica visível e clicável, só migra pro canto esquerdo com
   largura estreita o bastante pra nunca entrar na faixa horizontal do
   .quiz-card. Motivo de reposicionar em vez de tentar caber acima/abaixo do
   card: o card é sempre centralizado (#quiz-modal{justify-content:center},
   :580) com max-width:520px (.quiz-card, :588) e pode chegar a
   max-height:88svh (:828) — em tela baixa (1366×620, passo "horário" do
   quiz, o mais alto) mede ~37px de respiro acima e abaixo do card,
   insuficiente pra qualquer banner. Já a
   faixa horizontal FORA do card ((100vw-520px)/2 de cada lado) é livre em
   TODA a altura da tela, card alto ou baixo — por isso a largura do consent
   abaixo é derivada dessa mesma conta (520px é a constante de .quiz-card,
   :588 — se um mudar, o outro precisa mudar junto), com min() limitando o
   teto pra não virar um cartão gigante em tela larga. Medido nos 6
   breakpoints do parecer (900/1024/1280/1366/1440/1920, inclusive alturas
   curtas 1280×650 e 1366×620): 0/9 pontos amostrados sobre o consent
   pertencem ao .quiz-card, botão "Aceitar" sempre 100% clicável. */
@media (min-width: 900px) {
  #quiz-modal.open ~ .consent {
    display: flex;
    left: var(--sp-4); right: auto; bottom: var(--sp-4); top: auto;
    max-width: min(240px, calc((100vw - 520px) / 2 - var(--sp-4) - var(--sp-4)));
    padding: var(--sp-3); gap: var(--sp-2);
  }
  /* botões empilhados: nos 158px do breakpoint mais apertado (900px exatos,
     medido em Chromium headless com scrollbar overlay — S≈0 no calc()
     acima). Com scrollbar clássica (Chrome real do dono, S=15-17px), o
     valor resolvido é maior, não menor: a diferença entre 100vw (usado no
     calc(), :802) e a largura que a media query mede (sem a barra) é
     unidirecional e vale S/2 — sobreposição exigiria S>32px, bem acima dos
     15-17px do Windows —, dando ~165,5px nesse ambiente. Em qualquer um
     dos dois casos "Aceitar" + "Agora não" lado a lado não cabem.
     Empilhado funciona em qualquer largura da faixa >=900px, então não há
     um 2º breakpoint aqui dentro pra manter sincronizado. */
  #quiz-modal.open ~ .consent .consent-actions { flex-direction: column; align-items: stretch; }
}

/* Dependências estruturais que este bloco cria (nenhuma delas visível só
   lendo o CSS — mover o HTML sem saber disso quebra em silêncio):
   1) `#quiz-modal` precisa continuar irmão direto de `.consent` no body.
      `.consent` é sempre appendChild(document.body) DEPOIS de #quiz-modal
      já presente no HTML estático (index.html:230 vs quiz.js:428) — o
      combinador de irmão geral (~) depende dessa ordem. Meter o modal
      dentro de um wrapper novo, ou o consent antes dele, desliga as duas
      regras acima sem erro nenhum no console.
   2) A classe `.open` em #quiz-modal (adicionada/removida só pelo JS,
      quiz.js) é o único sinal que este CSS lê pra saber se o modal está
      aberto. Qualquer forma alternativa de abrir o modal que não passe por
      essa classe (ex.: outro atributo, outro seletor de estado) não aciona
      nem o esconde-no-mobile nem o reposiciona-no-desktop. */

/* =====================================================================
   Breakpoints adicionais (§3)
   ===================================================================== */
@media (min-width: 900px) {
  /* #quiz-modal (ID, base) teria mais especificidade que .quiz-modal
     (classe) e ganharia mesmo vindo depois — por isso o override
     também usa o ID */
  #quiz-modal { align-items: center; }
  .quiz-card { border-radius: var(--r-lg); max-height: 88svh; }
  .quiz-progress { border-radius: var(--r-lg) var(--r-lg) 0 0; }
}

/* reduz movimento — kill-switch global.
   Nenhum estado inicial "escondido" deste arquivo vive fora de um
   @media (prefers-reduced-motion:no-preference): toda animação acima
   tem seu `animation` declarado dentro desse media, então removê-la
   aqui não deixa nada invisível — o layout já nasce no estado final. */
@media (prefers-reduced-motion: reduce) {
  /* scroll-behavior precisa de !important: html{scroll-behavior:smooth} (:85)
     tem especificidade 0,0,1, maior que este seletor universal (0,0,0) — sem
     !important o smooth de :85 vence e o kill-switch de reduced-motion não
     desliga o scroll suave. */
  * { animation: none !important; transition: none !important; scroll-behavior: auto !important; }
}
