/* ═════════════════════════════════════════════════════════════════════════
   TEZZINI · Ambientes Memoráveis
   Fábrica de Sites da Fatormix · construído em 28/08/2026

   As decisões de desenho e o PORQUÊ de cada uma estão em
   _meta/ESTRATEGIA.md §4. O repertório de peças está em
   _meta/SISTEMA-VISUAL.md. Aqui ficam os comentários que só fazem sentido
   junto da regra.

   A IDEIA, EM UMA LINHA: o símbolo da marca é uma JANELA — um retângulo
   vertical com abertura interna deslocada. O site inteiro é essa janela:
   moldura, vão, batente, e a luz entrando por uma abertura. Quem dá cor à
   página é a foto do ambiente; a paleta é a moldura.
   ═════════════════════════════════════════════════════════════════════════ */

/* ── §1 · TOKENS ─────────────────────────────────────────────────────────
   Os 11 da marca vêm do Figma, com o PAPEL declarado por lá
   (INVENTARIO › Identidade visual). Só `--papel-tonal` é derivado, e o
   porquê está na ESTRATEGIA §4.4.

   ⚠️ Cada tom tem papel FIXO (AG_MOTION §6.1). Sem isso o mesmo tom acaba
   em botão, onde passa no contraste, e em texto, onde reprova. */
:root {
  /* superfícies escuras */
  --canvas:        #0E1011;   /* fundo principal */
  --superficie:    #17191B;   /* cartões e blocos */
  --elevado:       #212427;   /* hover e estados */

  /* marca · grafite */
  --grafite-800:   #3A3D40;   /* profundo */
  --grafite-700:   #4A4E52;   /* sombra e contorno */
  --grafite-500:   #6C7074;   /* ⭐ OFICIAL · Manual 2022 — a cor da marca */
  --grafite-400:   #8E9296;   /* texto secundário */
  --grafite-300:   #A3A8AD;   /* névoa e legendas */
  --grafite-100:   #D5D8DB;   /* linhas e bordas */

  --preto:         #000000;   /* ⭐ OFICIAL · Manual 2022 */
  --branco:        #FFFFFF;

  /* papéis — é por aqui que o CSS fala, nunca pelo hex */
  --papel:         var(--branco);
  --papel-tonal:   #F4F5F6;   /* derivado. ESTRATEGIA §4.4 */
  --tinta:         var(--superficie);      /* 18,9:1 sobre branco */
  --tinta-suave:   var(--grafite-700);     /*  8,0:1 sobre branco */
  --tinta-clara:   var(--branco);          /* 18,1:1 sobre canvas */
  --tinta-clara-suave: var(--grafite-300); /*  8,4:1 sobre canvas */
  --linha:         var(--grafite-100);
  --linha-escura:  var(--grafite-800);
  /* ⚠️ Não existe token de AÇÃO sobre superfície clara, e é decisão, não
     esquecimento: toda ação primária deste site mora em superfície escura
     (hero e fecho), e ali ela é branca. Ver ESTRATEGIA §0.11 — inclusive a
     medição que tirou o Grafite 500 do papel de botão. */

  /* degradês — os quatro da marca, escritos UMA vez (AG_MOTION §6.1:
     receita repetida é receita a virar token) */
  --deg-assinatura:     linear-gradient(180deg, var(--preto), var(--grafite-500));
  --deg-profundidade:   linear-gradient(160deg, var(--canvas), var(--grafite-700));
  --deg-luz:            linear-gradient(90deg, var(--grafite-700), var(--branco) 50%, var(--grafite-100));
  --deg-luz-escura:     linear-gradient(90deg, transparent, var(--grafite-500) 50%, transparent);
  --deg-nevoa:          linear-gradient(180deg, rgb(14 16 17 / 0) 30%, rgb(14 16 17 / .72));

  /* tipografia */
  --fonte-titulo: "DM Serif Display", Georgia, "Times New Roman", serif;
  --fonte-corpo:  "Jost", "Avenir Next", system-ui, -apple-system, sans-serif;

  /* escala — usar, não inventar valor solto */
  --e1: .5rem;   --e2: 1rem;    --e3: 1.5rem;
  --e4: 2.5rem;  --e5: 4rem;    --e6: 6rem;

  /* ⚠️ Sem isto, uma transição de `block-size: 0` para `auto` SALTA — o
     navegador não sabe interpolar palavra-chave. É o que faz a resposta da
     pergunta abrir deslizando em vez de aparecer de uma vez.
     Não muda nada onde não há transição de tamanho, e onde não houver
     suporte a declaração é ignorada e a abertura volta a ser instantânea. */
  interpolate-size: allow-keywords;

  --largura: 1180px;
  --raio: 2px;              /* quase reto: a marca é uma moldura, não um cartão */
  --barra: 76px;            /* altura do cabeçalho — o rodapé e o zap contam com ela */
}

/* ── §2 · FONTES ─────────────────────────────────────────────────────────
   Locais (invariante 3). Dois arquivos por família: latin e latin-ext.

   ⚠️ A DM Serif Display substituiu a Bodoni Moda em 28/08/2026, por
   REPROVAÇÃO DE LEGIBILIDADE de Ronaldo. A direção da marca não mudou —
   continua sendo a serifada display de alto contraste do wordmark
   "Tezzini" —, mudou a execução: a Bodoni é uma didone de contraste
   extremo, e sobre superfície ESCURA, que é onde ficam todos os títulos
   grandes deste site, as hastes finas somem. Texto claro sobre fundo escuro
   engrossa opticamente as grossas e apaga as finas; o defeito não aparece na
   amostra em fundo branco do especimen. Ver ESTRATEGIA §4.3. */
@font-face {
  font-family: "DM Serif Display"; font-style: normal; font-weight: 400;
  font-display: swap; src: url(../fonts/dmserif-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "DM Serif Display"; font-style: normal; font-weight: 400;
  font-display: swap; src: url(../fonts/dmserif-latin-ext.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Jost"; font-style: normal; font-weight: 300 600;
  font-display: swap; src: url(../fonts/jost-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Jost"; font-style: normal; font-weight: 300 600;
  font-display: swap; src: url(../fonts/jost-latin-ext.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ── §3 · BASE ───────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--papel);
  color: var(--tinta);
  font-family: var(--fonte-corpo);
  font-size: 1.0625rem;        /* 17px — Jost tem altura-x moderada e pede um degrau a mais */
  font-weight: 400;
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
}
img, svg, video { display: block; max-width: 100%; }
img { height: auto; }
a { color: inherit; }
h1, h2, h3 { font-family: var(--fonte-titulo); font-weight: 400; margin: 0; }

/* ⚠️ A escala é um CONJUNTO (AG_MOTION §6.1): razão ~1,5 entre os três
   maiores. Subir o h1 sem subir h2 e h3 quebra a hierarquia no meio. */
/* ⚠️ Os tamanhos caíram um degrau ao trocar a letra, e isso é regra e não
   ajuste fino: a DM Serif Display tem altura-x maior e cor mais pesada que a
   Bodoni, então o MESMO corpo em px pesa mais na página. Manter o número e
   trocar a fonte teria entregue um título maior sem ninguém ter decidido
   isso. A razão de ~1,5 entre os três maiores continua valendo. */
h1 { font-size: clamp(2.5rem, 5.8vw, 4.1rem); line-height: 1.06; letter-spacing: -.01em; }
h2 { font-size: clamp(1.85rem, 3.9vw, 2.75rem); line-height: 1.15; letter-spacing: -.005em; }
h3 { font-size: clamp(1.2rem, 2.2vw, 1.4rem); line-height: 1.25; }
p  { margin: 0 0 var(--e2); }
p:last-child { margin-bottom: 0; }

/* ⚠️ TEXTO CORRIDO É `--tinta-suave`. `--tinta` é cor de TÍTULO e de dado de
   contato, não de parágrafo.
   Isto estava certo em onze lugares e errado num só: `.dupla__texto` herdava
   o preto cheio do body, e a mesma anatomia (olho + h2 + parágrafo) aparecia
   pintada de dois jeitos conforme a seção — divergência que ninguém decidiu,
   que é o defeito que o AG_BUILD › "O sistema visual do site" descreve.
   Declarada aqui, ela passa a valer POR CONSTRUÇÃO: a próxima página nasce
   certa sem ninguém lembrar. As regras de bloco continuam existindo para
   tamanho e margem, e só sobrescrevem a cor quando a SUPERFÍCIE muda.
   Medido: 8,0:1 sobre o branco e 7,6:1 sobre o tonal; 8,4:1 sobre o canvas. */
p { color: var(--tinta-suave); }
.secao--escura p, .rodape p { color: var(--tinta-clara-suave); }

.wrap { width: 100%; max-width: var(--largura); margin-inline: auto; padding-inline: var(--e3); }

/* Rótulo acessível fora da tela. `display:none` sumiria também para o
   leitor de tela, e o botão de ícone ficaria sem nome. */
.ler-so {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}

/* Foco visível em tudo que recebe teclado. Aro em Grafite 500, que é o papel
   gráfico da cor da marca (ESTRATEGIA §0.11). */
:focus-visible { outline: 2px solid var(--grafite-500); outline-offset: 3px; border-radius: 1px; }
.secao--escura :focus-visible { outline-color: var(--grafite-100); }

/* ── §4 · SEÇÕES E SUPERFÍCIES ───────────────────────────────────────────
   Três superfícies e nada mais: clara, tonal, escura. A alternância é o
   ritmo da página, e ela está desenhada em ESTRATEGIA §2. */
.secao { padding-block: clamp(3.5rem, 9vw, var(--e6)); position: relative; }
.secao--clara  { background: var(--papel); }
.secao--tonal  { background: var(--papel-tonal); }
.secao--escura {
  background: var(--canvas); color: var(--tinta-clara);
  background-image: var(--deg-profundidade); background-blend-mode: normal;
}
.secao--escura h1, .secao--escura h2, .secao--escura h3 { color: var(--tinta-clara); }

/* O OLHO — o rótulo em caixa alta com entreletras larga. Vem direto da
   assinatura "AMBIENTES MEMORÁVEIS" do logotipo, e é a peça que amarra a
   página à marca sem repetir o logo. */
.olho {
  font-size: .72rem; font-weight: 500; letter-spacing: .22em; text-transform: uppercase;
  color: var(--grafite-500); margin: 0 0 var(--e2);
  display: flex; align-items: center; gap: .8rem;
}
.olho::after {
  content: ""; flex: 1; max-width: 4.5rem; height: 1px;
  background: var(--deg-luz-escura);
}
.secao--escura .olho { color: var(--grafite-300); }

/* Cabeça de seção: o olho, o h2 e a resposta direta. O AG_SEO §3.3 pede que
   cada seção ABRA com a resposta em uma frase — por isso `.cabeca p` é
   parágrafo de abertura, e não legenda. */
.cabeca { max-width: 46rem; margin-bottom: clamp(2rem, 5vw, var(--e5)); }
/* h1/h2/h3 nascem sem margem, e por isso o respiro entre o título e a
   resposta direta é declarado AQUI, no bloco que os junta. Sem ele os dois
   encostam, e o parágrafo parece legenda em vez de abertura. */
.cabeca h2 { margin-bottom: var(--e2); }
.cabeca p { font-size: 1.1rem; margin-bottom: 0; }
/* O DIVISOR — o degradê "Grafite · Luz" da marca: escuro nas pontas, claro
   no meio. É luz atravessando um vão, e dissolve nas laterais em vez de
   fechar a caixa (AG_MOTION §6.1: linha que encosta nas duas bordas endurece
   o bloco). */
.divisor { height: 1px; border: 0; margin: 0 0 var(--e5); background: var(--deg-luz); opacity: .45; }

/* ── §5 · O VÃO — a assinatura visual ────────────────────────────────────
   O símbolo da marca é um retângulo vertical com abertura interna
   DESLOCADA. `.vao` reproduz isso em volta da foto: uma moldura fina
   deslocada para fora, aberta do lado direito, com o BATENTE em degradê da
   marca correndo pela borda esquerda.

   ⚠️ A moldura é ::before ABSOLUTO: assim ela não gera altura, não empurra
   o layout e não precisa de `clip-path` para não sobrar no fim da seção
   (a receita do transbordo, AG_MOTION §6.1). */
.vao { position: relative; margin: 0; isolation: isolate; }
.vao img { width: 100%; }
.vao::before {
  content: ""; position: absolute; z-index: -1;
  inset: calc(var(--e2) * -1) 38% calc(var(--e2) * -1) calc(var(--e3) * -1);
  border: 1px solid var(--linha); border-right: 0;
  pointer-events: none;
}
.secao--escura .vao::before { border-color: var(--linha-escura); }
/* o batente: o filete de 2px, com o degradê Assinatura da marca */
.vao__batente {
  position: absolute; z-index: 1;
  left: calc(var(--e3) * -1); top: calc(var(--e2) * -1); bottom: calc(var(--e2) * -1);
  width: 2px; background: var(--deg-assinatura); pointer-events: none;
}
.secao--escura .vao__batente { background: linear-gradient(180deg, var(--grafite-500), var(--canvas)); }
/* legenda da foto, quando houver */
/* ⚠️ Sem este limite a moldura seria calculada sobre a largura da COLUNA, e
   o cartão de vídeo (22rem) flutuaria solto dentro de um vão largo demais. O
   `max-width` migra do cartão para o vão, e o cartão passa a preenchê-lo. */
.vao--video { max-width: 22rem; }
.vao--video .video-cartao { max-width: none; }

.vao figcaption {
  font-size: .78rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--grafite-500); margin-top: var(--e2);
}

/* ── §6 · BOTÕES ─────────────────────────────────────────────────────────
   Uma FORMA por papel (AG_MOTION §6.1): sólido = ação principal, contorno =
   secundária. Quando os dois têm borda, a diferença some. */
.botao {
  display: inline-flex; align-items: center; gap: .6rem;
  padding: .95rem 1.6rem; min-height: 48px;
  font-family: var(--fonte-corpo); font-size: .95rem; font-weight: 500;
  letter-spacing: .06em; text-transform: uppercase; text-decoration: none;
  border: 1px solid transparent; border-radius: var(--raio); cursor: pointer;
  transition: background-color .18s ease, color .18s ease, border-color .18s ease;
}
.botao .seta { width: 18px; height: 18px; flex: none; transition: transform .18s ease; }
/* ⚠️ A SETA QUE ANDA é o hover do botão preto. Preto não tem como escurecer,
   e clarear derrubaria o contraste no exato momento da mira (ESTRATEGIA
   §0.11). O deslocamento diz "vai para algum lugar", que é o que o botão faz. */
@media (hover: hover) { .botao:hover .seta { transform: translateX(4px); } }

.botao--claro { background: var(--branco); color: var(--preto); }
@media (hover: hover) { .botao--claro:hover { background: var(--grafite-100); } }
.botao--contorno { border-color: var(--grafite-500); color: var(--tinta); background: transparent; }
@media (hover: hover) { .botao--contorno:hover { background: var(--papel-tonal); border-color: var(--tinta); } }
.secao--escura .botao--contorno { color: var(--tinta-clara); border-color: var(--grafite-700); }
@media (hover: hover) {
  .secao--escura .botao--contorno:hover { background: var(--elevado); border-color: var(--grafite-500); }
}
/* Botão de cabeçalho é MENOR que o do hero: tamanho igual não é peso igual
   quando o entorno muda (AG_MOTION §6.1). */
.botao--miudo { padding: .6rem 1.05rem; min-height: 40px; font-size: .8rem; }

/* `align-items: center` porque o bloco mistura botão (48 px de altura) com
   link de texto: sem ele o item de flex ESTICA, e o traço do link desce até
   a base do botão. */
.acoes { display: flex; flex-wrap: wrap; align-items: center; gap: var(--e2) var(--e4); margin-top: var(--e3); }

/* Link de texto com seta — para "ver a página tal" dentro do corpo */
/* ⚠️ O respiro vertical não é estético, é ALVO DE TOQUE: com o traço
   colado no texto o link tinha 29 px de altura, e o dedo precisa de 44. O
   efeito colateral é bom: o filete desce e passa a separar em vez de
   sublinhar. */
.link-seta {
  display: inline-flex; align-items: center; gap: .5rem;
  font-weight: 500; font-size: .95rem; letter-spacing: .04em;
  text-decoration: none; border-bottom: 1px solid var(--grafite-500);
  padding: .7rem 0 .5rem; transition: border-color .18s ease, color .18s ease;
}
.link-seta .seta { width: 16px; height: 16px; transition: transform .18s ease; }
@media (hover: hover) {
  .link-seta:hover { border-color: var(--tinta); }
  .link-seta:hover .seta { transform: translateX(3px); }
  .secao--escura .link-seta:hover { border-color: var(--branco); }
}

/* ── §7 · CABEÇALHO ──────────────────────────────────────────────────────
   ⚠️ O vidro vai em PSEUDO-ELEMENTO, nunca no <header>: `backdrop-filter`
   cria bloco de contenção, e um `position: fixed` dentro dele passa a se
   medir pelo cabeçalho — foi assim que um drawer de tela inteira nasceu com
   140 px (AG_MOTION §6.1).

   ⚠️ E o fundo translúcido vale SEMPRE, não só depois de rolar: se
   dependesse da classe que o JS põe, a página sem JS teria texto passando
   por trás de um cabeçalho transparente. */
.topo {
  position: sticky; top: 0; z-index: 50;
  height: var(--barra); display: flex; align-items: center;
  color: var(--tinta-clara);
  border-bottom: 1px solid transparent;
  transition: border-color .25s ease;
}
.topo::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: rgb(14 16 17 / .82);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
}
.topo.esta-rolado { border-bottom-color: var(--linha-escura); }
.topo .wrap { display: flex; align-items: center; gap: var(--e2); }
/* min-height de 44 px: a marca também é alvo de toque, e o desenho dela
   tem 38. O `display:flex` centra a imagem dentro da folga. */
.topo__marca { flex: none; display: flex; align-items: center; min-height: 44px; }
.topo__marca img { width: 132px; height: 38px; }

.nav { margin-left: auto; display: flex; align-items: center; }

/* O drawer é <details>: abre e fecha SEM JavaScript (invariante 8). O JS só
   acrescenta o que o elemento não faz — véu, Esc e fechar ao seguir link. */
/* ⚠️ `.menu__conteudo` é `display: contents`, então quem vira pai da lista
   e do CTA é o próprio <details> — e <details> é `display: block`, o que
   empilhava os dois em duas linhas dentro de uma barra de altura fixa.
   Item de flex que estica não centra o filho, e bloco que devia ser linha
   quebra a barra: os dois defeitos são o mesmo descuido. */
.menu { position: relative; display: flex; align-items: center; }
.menu > summary {
  list-style: none; cursor: pointer; display: none;
  width: 44px; height: 44px; align-items: center; justify-content: center;
  color: var(--tinta-clara);
}
.menu > summary::-webkit-details-marker { display: none; }
.menu__hamburguer, .menu__x { width: 24px; height: 24px; }
.menu__x { display: none; }
.menu[open] > summary .menu__hamburguer { display: none; }
.menu[open] > summary .menu__x { display: block; }

/* ⚠️ `display: contents` no filho NÃO basta para o menu aparecer no
   desktop: um <details> fechado esconde o conteúdo pelo SLOT do navegador,
   e desde o Chrome 131 isso é `::details-content { content-visibility:
   hidden }`. Medido: `.menu__conteudo` ficava com 0×0 e a barra saía só com
   o logo — e nada acusava, porque o CSS estava "certo".
   Por isso a devolução da visibilidade é feita no pseudo-elemento, que é
   quem realmente esconde — e SÓ no desktop: no celular, esconder enquanto
   fechado é justamente o comportamento certo, e é ele que faz a gaveta
   funcionar sem uma linha de JavaScript. */
@media (min-width: 980px) {
  .menu::details-content { display: contents; content-visibility: visible; }
}
.menu__conteudo { display: contents; }
.nav__lista {
  display: flex; align-items: center; gap: clamp(.9rem, 2vw, 1.7rem);
  list-style: none; margin: 0; padding: 0;
}
.nav__lista > li > a {
  display: block; padding: .4rem 0;
  font-size: .84rem; font-weight: 400; letter-spacing: .09em; text-transform: uppercase;
  text-decoration: none; color: var(--grafite-300);
  border-bottom: 1px solid transparent;
  transition: color .18s ease, border-color .18s ease;
}
@media (hover: hover) { .nav__lista > li > a:hover { color: var(--branco); } }
.nav__lista > li > a[aria-current="page"] { color: var(--branco); border-bottom-color: var(--grafite-500); }
.topo__cta { margin-left: clamp(.9rem, 2vw, 1.7rem); }
/* ⚠️ O cabeçalho é superfície ESCURA, e `.botao--contorno` nasce com
   `color: var(--tinta)` — texto quase preto. Na barra ele ficava ilegível e
   na gaveta sumia por completo: um botão contornado e VAZIO. Nada acusa isso,
   porque a borda continua desenhada. O papel do tom muda com a superfície, e
   é isto que a regra abaixo declara. */
.topo .botao--contorno { color: var(--tinta-clara); border-color: var(--grafite-700); }
@media (hover: hover) {
  .topo .botao--contorno:hover { background: var(--elevado); border-color: var(--grafite-500); }
}

/* — celular e tablet: o mesmo HTML vira gaveta — */
@media (max-width: 979px) {
  .topo__marca img { width: 112px; height: 32px; }
  .menu > summary { display: flex; }
  /* ⚠️ O VÉU EXISTE SEMPRE, e é isso que permite animá-lo: um pseudo-elemento
     que só nasce com `[open]` aparece de uma vez, porque não há estado
     anterior de onde sair. Fechado ele é transparente e `pointer-events:
     none`, então não intercepta clique nenhum. */
  .menu::before {
    content: ""; position: fixed; inset: var(--barra) 0 0; z-index: 40;
    background: rgb(0 0 0 / 0); pointer-events: none;
    transition: background-color .24s ease;
  }
  .menu[open]::before { background: rgb(0 0 0 / .55); pointer-events: auto; }

  /* ⚠️ `content-visibility` com `allow-discrete` é o que segura a gaveta na
     tela durante a SAÍDA. Sem ele o <details> some no primeiro quadro e a
     animação de volta nunca aparece (AG_BUILD › Menu e cabeçalho).
     ⚠️ E o `transform` mora no PAINEL, não no <details>: no desktop o
     conteúdo é `display: contents` e não tem caixa para transformar. */
  .menu::details-content {
    transition: content-visibility .26s allow-discrete;
  }
  .menu__conteudo {
    display: flex; flex-direction: column; align-items: stretch; gap: var(--e1);
    position: fixed; z-index: 45;
    top: var(--barra); right: 0; bottom: 0; width: min(20rem, 84vw);
    padding: var(--e3) var(--e3) var(--e5);
    background: var(--superficie); border-left: 1px solid var(--linha-escura);
    overflow-y: auto;
    /* a gaveta entra pela direita, que é o lado de onde ela vem */
    transform: translateX(100%);
    transition: transform .26s cubic-bezier(.32, .72, 0, 1);
  }
  .menu[open] .menu__conteudo { transform: none; }
  .nav__lista { flex-direction: column; align-items: stretch; gap: 0; }
  .nav__lista > li > a {
    padding: .85rem 0; font-size: .95rem; letter-spacing: .1em;
    border-bottom: 1px solid var(--linha-escura); color: var(--grafite-100);
  }
  .nav__lista > li > a[aria-current="page"] { border-bottom-color: var(--grafite-500); }
  /* na gaveta o CTA deixa de ser o botão miúdo da barra e volta ao tamanho
     cheio: ali ele é a ação da tela, não um item ao lado do menu */
  .topo__cta { margin: var(--e3) 0 0; justify-content: center; min-height: 48px; padding: .95rem 1.4rem; font-size: .88rem; }
}

/* ── §8 · HERO ───────────────────────────────────────────────────────────
   Duas colunas: o texto e o VÃO com a foto. A foto do cliente é retrato
   (as melhores fotos têm EXIF rotacionado e são 3:4), e é isso que torna o
   vão a composição certa em vez de um corte panorâmico que jogaria fora
   metade da imagem. */
.hero { padding-block: clamp(3rem, 7vw, 5.5rem) clamp(3.5rem, 8vw, var(--e6)); }
.hero__grade { display: grid; gap: clamp(2.5rem, 6vw, var(--e5)); align-items: center; }
.hero h1 { margin-bottom: var(--e3); }
.hero__apoio {
  font-size: clamp(1.05rem, 1.6vw, 1.2rem); color: var(--tinta-clara-suave);
  max-width: 34rem;
}
@media (min-width: 900px) {
  .hero__grade { grid-template-columns: 1fr minmax(340px, 44%); gap: var(--e6); }
  .hero .vao { margin-left: var(--e2); }
}

/* ── §9 · AS TRÊS FRENTES ────────────────────────────────────────────────
   Três cartões, e o terceiro é o de destaque: motorizadas é a frente de
   maior valor e menor concorrência orgânica (ESTRATEGIA §0.1). */
.frentes { display: grid; gap: var(--e3); }
.frente {
  display: flex; flex-direction: column; gap: var(--e2);
  padding: var(--e3); background: var(--papel);
  border: 1px solid var(--linha); border-radius: var(--raio);
  text-decoration: none;
}
.frente h3 { font-size: 1.45rem; }
.frente p { font-size: .98rem; margin: 0; }
.frente__ir {
  margin-top: auto; padding-top: var(--e1);
  font-size: .8rem; letter-spacing: .14em; text-transform: uppercase; font-weight: 500;
  display: inline-flex; align-items: center; gap: .5rem; color: var(--grafite-500);
}
.frente__ir .seta { width: 16px; height: 16px; transition: transform .18s ease; }
.frente--destaque {
  background: var(--canvas); border-color: var(--canvas); color: var(--tinta-clara);
}
.frente--destaque h3 { color: var(--tinta-clara); }
.frente--destaque p { color: var(--tinta-clara-suave); }
.frente--destaque .frente__ir { color: var(--grafite-100); }
@media (hover: hover) { .frente:hover .seta { transform: translateX(4px); } }
@media (min-width: 720px) { .frentes { grid-template-columns: repeat(3, 1fr); } }

/* ── §10 · ANTES E DEPOIS — a assinatura em movimento ────────────────────
   O par está lado a lado o tempo todo, rotulado, e legível sem nada.
   Dentro do @supports (§16) o "depois" é revelado por um clip-path que
   DESCE COMO UM TECIDO conforme a seção entra na tela — que é literalmente
   o que o produto faz.

   ⚠️ Não é opacity, é recorte; e o estado inicial recortado só existe
   dentro do @supports. Sem suporte, sem JS ou com reduced-motion, as duas
   fotos estão inteiras (AGENTS, invariante 8). */
.antes-depois { display: grid; gap: var(--e3); }
.antes-depois figure { margin: 0; position: relative; }
.antes-depois img { width: 100%; border-radius: var(--raio); }
.antes-depois figcaption {
  position: absolute; left: var(--e2); top: var(--e2);
  padding: .4rem .8rem; background: rgb(14 16 17 / .72); color: var(--branco);
  font-size: .72rem; letter-spacing: .2em; text-transform: uppercase; font-weight: 500;
}
@media (min-width: 720px) { .antes-depois { grid-template-columns: 1fr 1fr; } }

/* ── §11 · AMBIENTES, DEGRAUS E DEPOIMENTOS ──────────────────────────────
   Três blocos de lista, e a diferença entre eles é o que a ordem significa.
   `.degraus` é <ol> e leva número porque É uma sequência; `.ambientes` e
   `.depoimentos` não levam, porque ali a ordem não carrega informação. */
.ambientes, .depoimentos { display: grid; gap: var(--e3); list-style: none; margin: 0; padding: 0; }
@media (min-width: 760px) {
  .ambientes { grid-template-columns: repeat(3, 1fr); }
  .depoimentos { grid-template-columns: repeat(3, 1fr); }
}
.ambiente { border-top: 1px solid var(--linha); padding-top: var(--e2); }
.secao--escura .ambiente { border-top-color: var(--linha-escura); }
.ambiente h3 { font-size: 1.35rem; margin-bottom: .4rem; }
.ambiente p { margin: 0; }

.degraus { display: grid; gap: var(--e3); list-style: none; margin: 0; padding: 0; counter-reset: degrau; }
@media (min-width: 640px) { .degraus { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .degraus { grid-template-columns: repeat(4, 1fr); } }
.degrau { counter-increment: degrau; border-top: 1px solid var(--linha); padding-top: var(--e2); }
.degrau::before {
  content: counter(degrau, decimal-leading-zero);
  display: block; font-family: var(--fonte-titulo); font-size: 1.6rem;
  color: var(--grafite-500); line-height: 1; margin-bottom: .6rem;
}
.degrau h3 { font-size: 1.2rem; margin-bottom: .4rem; }
.degrau p { font-size: .97rem; margin: 0; }

.depoimento {
  display: flex; flex-direction: column; gap: var(--e2);
  padding: var(--e3); background: var(--papel); border: 1px solid var(--linha);
}
.depoimento blockquote {
  margin: 0; font-family: var(--fonte-titulo); font-size: 1.25rem; line-height: 1.4;
}
.depoimento cite {
  font-style: normal; font-size: .78rem; letter-spacing: .16em; text-transform: uppercase;
  color: var(--grafite-500); margin-top: auto;
}
.depoimento cite span { display: block; letter-spacing: .08em; text-transform: none; color: var(--tinta-suave); margin-top: .2rem; }

/* ── §12 · VÍDEO — cartão e lightbox ─────────────────────────────────────
   ⚠️ O cartão é um LINK REAL para o .mp4. Sem JavaScript o clique abre o
   vídeo do mesmo jeito; o lightbox é melhoria progressiva, não condição
   (AGENTS, invariante 8). */
.video-cartao {
  position: relative; display: block; text-decoration: none;
  border: 1px solid var(--linha-escura); border-radius: var(--raio); overflow: hidden;
  max-width: 22rem;
}
.video-cartao img { width: 100%; }
.video-cartao::after {                 /* a névoa, para o rótulo pousar */
  content: ""; position: absolute; inset: 0; background: var(--deg-nevoa); pointer-events: none;
}
.video-cartao__rotulo {
  position: absolute; z-index: 1; left: var(--e2); right: var(--e2); bottom: var(--e2);
  display: flex; align-items: center; gap: .7rem;
  color: var(--branco); font-size: .84rem; letter-spacing: .1em; text-transform: uppercase; font-weight: 500;
}
.video-cartao__play {
  width: 40px; height: 40px; flex: none; border-radius: 50%;
  border: 1px solid rgb(255 255 255 / .6); display: grid; place-items: center;
  transition: background-color .2s ease;
}
.video-cartao__play svg { width: 14px; height: 14px; margin-left: 2px; }
.video-cartao__tempo { margin-left: auto; color: var(--grafite-100); letter-spacing: .08em; }
@media (hover: hover) {
  .video-cartao:hover .video-cartao__play { background: rgb(255 255 255 / .22); }
}

/* A transcrição da narração, visível a um clique. Existe porque muita gente
   assiste sem som — e porque o texto é do próprio cliente, o que faz dele
   fato do inventário e conteúdo citável (AG_SEO §3.5). */
.transcricao { margin-top: var(--e2); max-width: 34rem; }
.transcricao > summary {
  cursor: pointer; font-size: .82rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--grafite-500); padding: .5rem 0; list-style: none;
  display: flex; align-items: center; gap: .5rem;
}
.transcricao > summary::-webkit-details-marker { display: none; }
.transcricao > summary::before { content: "+"; font-size: 1rem; line-height: 1; }
.transcricao[open] > summary::before { content: "–"; }
.transcricao p { font-size: .97rem; }
.secao--escura .transcricao > summary { color: var(--grafite-300); }

/* O lightbox. Nasce [hidden]: é conteúdo que só existe depois do clique, e
   não conteúdo escondido esperando script (a diferença que o AG_MOTION §5
   mede). O vídeo tem preload="none": os 18 MB só saem do servidor quando
   alguém clica. */
/* ⚠️ O ESTADO ESCONDIDO CONTINUA PRESO AO ATRIBUTO `hidden`, que é o que o
   JavaScript liga e desliga. Isso importa por dois motivos: o conteúdo do
   lightbox só existe depois do clique (não é conteúdo escondido esperando
   script), e a régua de movimento sabe ler `[hidden]` como estado legítimo.
   O `display` entra na transição com `allow-discrete` para que o fundo tenha
   tempo de esmaecer na SAÍDA — sem isso ele desaparece no primeiro quadro. */
.lightbox[hidden] { display: none; opacity: 0; }
.lightbox {
  position: fixed; inset: 0; z-index: 100;
  display: grid; place-items: center; padding: var(--e3);
  background: rgb(0 0 0 / .88);
  opacity: 1;
  transition: opacity .2s ease, display .2s allow-discrete;
}
/* o primeiro quadro depois de sair do `display: none` */
@starting-style {
  .lightbox { opacity: 0; }
}
/* ⚠️ O ✕ é uma LINHA DO LAYOUT, não um absoluto deslocado para fora.
   Ele nasceu como `position: absolute; top: -3rem; right: -.5rem`, e no
   celular isso produzia dois defeitos que só apareciam lá: o botão sangrava
   8 px para FORA da tela — parte do alvo de toque inacessível — e caía
   colado ao hambúrguer do menu, dois controles parecidos lado a lado.

   Como item de flex, o espaço dele é RESERVADO em vez de emprestado da
   margem: ele não tem como sair da tela, e o vídeo encolhe o necessário para
   caber. É a mesma diferença entre reservar e torcer para caber. */
.lightbox__quadro {
  position: relative;
  display: flex; flex-direction: column; align-items: flex-end; gap: var(--e1);
  width: min(94vw, calc((100vh - 7.5rem) * 0.5625));
  max-height: calc(100vh - 3rem);
}
/* O vídeo sobe um pouco ao entrar. Animação, e não `@starting-style`, porque
   aqui quem muda de estado é o PAI: uma keyframe disparada pelo seletor do
   pai é a forma que não depende do primeiro-render do filho. */
.lightbox:not([hidden]) .lightbox__quadro {
  animation: lightbox-entra .26s cubic-bezier(.32, .72, 0, 1) both;
}
@keyframes lightbox-entra {
  from { opacity: 0; transform: translateY(10px) scale(.985); }
  to   { opacity: 1; transform: none; }
}
.lightbox video {
  width: 100%; max-height: calc(100vh - 7.5rem); aspect-ratio: 9 / 16;
  background: var(--preto); border-radius: var(--raio);
}
/* ⚠️ NO CELULAR o quadro deixa de ser centrado e passa a nascer ABAIXO da
   faixa do cabeçalho. Centrado, o ✕ caía com o topo em 58 px numa barra que
   vai até 76 — ou seja, na mesma altura do hambúrguer, e dois controles
   parecidos disputando a mesma faixa é o tipo de coisa que faz a pessoa
   fechar o menu quando queria fechar o vídeo.
   O preço é o vídeo ficar um pouco menor, e é um preço bom: o alvo de fechar
   é o que precisa estar óbvio, não o último pixel de imagem. */
@media (max-width: 599px) {
  .lightbox { align-items: start; padding-top: calc(var(--barra) + var(--e2)); }
  .lightbox__quadro { max-height: calc(100vh - var(--barra) - 4.5rem); }
  .lightbox video { max-height: calc(100vh - var(--barra) - 5.75rem); }
}

.lightbox__fechar {
  flex: none;                     /* linha própria, alinhada à direita do vídeo */
  width: 44px; height: 44px; display: grid; place-items: center;
  background: none; border: 0; color: var(--branco); cursor: pointer;
}
.lightbox__fechar svg { width: 22px; height: 22px; }

/* ── §13 · GRADE DE FOTOS ────────────────────────────────────────────────
   Galeria única, sem agrupamento inventado: as fotos não têm nome de
   projeto, e o default da casa é não inventar um (AGENTS §3.1). */
.grade-fotos { display: grid; gap: var(--e2); list-style: none; margin: 0; padding: 0; }
/* ⚠️ `aspect-ratio` + `object-fit` porque as fotos do cliente vêm em
   proporções diferentes (uma 4:3, outra 9:16, outra 3:4). Numa grade, isso
   sai ruim de um jeito que parece descuido, e não escolha. O recorte 3:4
   é o da maioria delas, então é o que menos corta. */
.grade-fotos img {
  width: 100%; aspect-ratio: 3 / 4; object-fit: cover; border-radius: var(--raio);
}
@media (min-width: 640px) { .grade-fotos { grid-template-columns: repeat(2, 1fr); gap: var(--e3); } }
@media (min-width: 1000px) { .grade-fotos { grid-template-columns: repeat(3, 1fr); } }

/* Duas colunas: texto de um lado, foto no vão do outro. É o bloco que se
   repete nas páginas de frente. */
.dupla { display: grid; gap: clamp(2rem, 5vw, var(--e5)); align-items: center; }
/* Quando as duas colunas são TEXTO, centrar vertical desalinha os dois
   títulos e a seção parece torta. Aí o alinhamento é pelo topo. */
.dupla--topo { align-items: start; }
@media (min-width: 900px) {
  .dupla { grid-template-columns: 1fr 1fr; }
  .dupla--foto-esquerda .dupla__foto { order: -1; }
  .dupla--foto-esquerda .vao::before { inset: calc(var(--e2) * -1) 38% calc(var(--e2) * -1) calc(var(--e3) * -1); }
}
.dupla__texto { max-width: 34rem; }
.dupla__texto h2 { margin-bottom: var(--e2); }

/* ── §14 · PERGUNTAS ─────────────────────────────────────────────────────
   <details> e não JavaScript: o conteúdo está no HTML e é lido por
   rastreador de IA mesmo fechado (AG_SEO §3.1). */
.perguntas { max-width: 46rem; }
.pergunta { border-bottom: 1px solid var(--linha); }
.pergunta > summary {
  cursor: pointer; list-style: none; padding: var(--e2) 2.5rem var(--e2) 0;
  position: relative; font-size: 1.08rem; font-weight: 500;
}
.pergunta > summary::-webkit-details-marker { display: none; }
.pergunta > summary::after {
  content: ""; position: absolute; right: .5rem; top: 50%;
  width: 10px; height: 10px; margin-top: -6px;
  border-right: 1px solid var(--grafite-500); border-bottom: 1px solid var(--grafite-500);
  transform: rotate(45deg); transition: transform .2s ease;
}
.pergunta[open] > summary::after { transform: rotate(-135deg); margin-top: -2px; }

/* ⚠️ A ABERTURA DESLIZA, e o conteúdo continua no HTML o tempo todo.
   Onde não há `::details-content`, o seletor inteiro é inválido e a regra é
   descartada: a pergunta volta a abrir instantânea, que é o comportamento
   nativo do <details>. Não existe caminho em que a resposta suma
   (AGENTS.md, invariante 8) — e é por isso que a animação é de ALTURA e não
   de opacidade. */
.pergunta::details-content, .transcricao::details-content {
  block-size: 0;
  overflow: hidden;
  transition: block-size .24s ease, content-visibility .24s allow-discrete;
}
.pergunta[open]::details-content, .transcricao[open]::details-content {
  block-size: auto;
}
.pergunta__resposta { padding: 0 0 var(--e2); color: var(--tinta-suave); max-width: 42rem; }

/* ── §15 · LOCAL, TRILHA, FECHO E RODAPÉ ─────────────────────────────── */
.local { font-style: normal; line-height: 1.9; }
.local strong { font-weight: 500; }
/* Telefone, e-mail e endereço são o caminho para o contato, não texto
   corrido: alvo de 44 px em qualquer lugar do site.
   ⚠️ A exceção declarada é o link "fatormix" do rodapé: dar 44 px a ele
   acrescentaria altura ao rodapé, e o AGENTS §5.2 diz o contrário — o
   crédito assina sem competir e sem margem extra. */
.local a { display: inline-block; padding: .55rem 0; text-decoration: none; border-bottom: 1px solid var(--linha); }
.secao--escura .local a { border-bottom-color: var(--grafite-700); }
@media (hover: hover) { .local a:hover { border-bottom-color: var(--grafite-500); } }

.trilha { font-size: .78rem; letter-spacing: .1em; text-transform: uppercase; color: var(--grafite-400); }
.trilha ol { list-style: none; display: flex; flex-wrap: wrap; gap: .5rem; margin: 0; padding: 0; }
.trilha li + li::before { content: "·"; margin-right: .5rem; }
/* o link da trilha é alvo de toque como qualquer outro: com o texto colado
   ele tinha 18 px de altura */
.trilha a { text-decoration: none; display: inline-block; padding: .5rem 0; }
.trilha li { display: flex; align-items: center; }
@media (hover: hover) { .trilha a:hover { color: var(--branco); } }

.fecho { text-align: center; }
.fecho .acoes { justify-content: center; }
.fecho h2 { margin-bottom: var(--e2); }
.fecho p { max-width: 34rem; margin-inline: auto; color: var(--tinta-clara-suave); }

.rodape { background: var(--canvas); color: var(--tinta-clara-suave); padding-block: var(--e5) var(--e3); font-size: .95rem; }
.rodape__grade { display: grid; gap: var(--e4); }
@media (min-width: 760px) { .rodape__grade { grid-template-columns: 1.2fr 1fr 1fr; } }
.rodape__marca { display: inline-flex; align-items: center; min-height: 44px; margin-bottom: var(--e2); }
.rodape__marca img { width: 146px; height: 42px; }
.rodape h2 {
  font-family: var(--fonte-corpo); font-size: .74rem; font-weight: 500;
  letter-spacing: .2em; text-transform: uppercase; color: var(--grafite-500);
  margin-bottom: var(--e2);
}
.rodape ul { list-style: none; margin: 0; padding: 0; }
.rodape li { margin-bottom: 0; }
.rodape a { text-decoration: none; }
/* 44 px de alvo nos links de lista e nos de contato: no celular eles são o
   caminho para o WhatsApp e para o e-mail, e não texto corrido. */
.rodape li a { display: inline-block; padding: .65rem 0; }
@media (hover: hover) { .rodape a:hover { color: var(--branco); } }
/* A área atendida faz parte da ENTIDADE, e o rodapé é onde ela aparece em
   toda página (AG_SEO §4.1). Fica separada do NAP de propósito: o endereço
   é onde a loja ESTÁ, e isto é onde ela ATENDE. */
.rodape__area {
  margin: var(--e2) 0 0; font-size: .82rem; letter-spacing: .12em;
  text-transform: uppercase; color: var(--grafite-500);
}
.rodape__sociais { display: flex; gap: var(--e2); margin-top: var(--e2); }
.rodape__sociais a { display: grid; place-items: center; width: 44px; height: 44px; border: 1px solid var(--linha-escura); }
.rodape__sociais svg { width: 20px; height: 20px; }
@media (hover: hover) { .rodape__sociais a:hover { border-color: var(--grafite-500); } }

/* ⚠️ A assinatura da casa (AGENTS §5.2): na MESMA linha do copyright, só a
   palavra "fatormix" é link, em semibold e SEM sublinhado — nem no hover,
   onde a cor clareia. A página é do cliente; o crédito assina sem competir.
   ⚠️ O `padding-right` reserva o espaço do botão flutuante: ele não pode
   cobrir o rodapé (ESTRATEGIA §0.10). */
.rodape__fim {
  margin-top: var(--e4); padding-top: var(--e3); border-top: 1px solid var(--linha-escura);
  font-size: .85rem; color: var(--grafite-400);
}
.rodape__fim p { padding-right: 5.5rem; margin: 0; color: var(--grafite-400); }
.rodape__fim a { font-weight: 600; color: var(--grafite-300); text-decoration: none; }
@media (hover: hover) { .rodape__fim a:hover { color: var(--branco); text-decoration: none; } }

/* ── §16 · O BOTÃO FLUTUANTE DE WHATSAPP ─────────────────────────────────
   Em todas as sete páginas, com a mensagem da página em que a pessoa está.
   ⚠️ Alvo de 56 px (o mínimo é 44), e ele NÃO cobre conteúdo nem o rodapé —
   quem reserva o espaço é o `.rodape__fim`. */
/* ⚠️ ESTE VERDE É A ÚNICA COR FORA DA PALETA DA MARCA, e é decisão de
   Ronaldo (28/08/2026): o botão usa o verde do WhatsApp mesmo.
   Por que a exceção se sustenta: o botão não é elemento de identidade, é um
   ATALHO para um aplicativo de terceiro, e o visitante reconhece o destino
   pela cor antes de ler qualquer coisa. Ela vive num alvo de 56 px no canto
   e não encosta em mais nada da página - não é um acento introduzido no
   sistema (ESTRATEGIA §0.6 continua valendo para o resto).
   ⚠️ O glifo branco sobre #25D366 dá 1,93:1, abaixo do piso de texto. É
   aceito porque ele é o DESENHO DA MARCA do WhatsApp, e não texto: quem
   nomeia o botão é o aria-label. O aro escuro é o que separa o verde de um
   fundo claro. */
.zap {
  position: fixed; z-index: 60; right: var(--e3); bottom: var(--e3);
  width: 56px; height: 56px; border-radius: 50%;
  display: grid; place-items: center;
  background: #25D366; color: var(--branco);
  border: 1px solid rgb(0 0 0 / .16);
  box-shadow: 0 10px 30px -12px rgb(0 0 0 / .55);
  transition: background-color .18s ease, transform .18s ease;
}
.zap svg { width: 26px; height: 26px; position: relative; }

/* ⚠️ O PULSO — o único elemento deste site que se move sozinho, e num site
   declarado SÓBRIO isso precisa de justificativa: ele não é enfeite da marca,
   é a sinalização de um canal de atendimento. É a mesma razão que já
   autorizou o verde de fora da paleta (ESTRATEGIA §0.6.1).

   Três decisões que o mantêm discreto:
   · o ciclo tem PAUSA EMBUTIDA — o halo leva 1,8 s e o resto dos 3,2 s é
     silêncio. Um pulso contínuo vira farol no canto do olho, e é isso que
     faria a página parecer barata;
   · anima `transform` e `opacity`, nunca `box-shadow`: sombra animada
     repinta a cada quadro e é o que engasga no celular da cliente;
   · no hover ele SOME. Ali o botão já responde por conta própria, e dois
     avisos ao mesmo tempo é um a mais.

   ⚠️ E não há `opacity: 0` escrito na REGRA, de propósito: o repouso vem do
   `both` no fim da keyframe. Estado inicial invisível declarado em regra é a
   assinatura do defeito que o AG_MOTION §5 reprova, e a régua não tem como
   saber que aqui seria "só" um halo. */
.zap::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  border-radius: 50%; background: #25D366; pointer-events: none;
  animation: zap-pulso 3.2s ease-out infinite both;
}
@keyframes zap-pulso {
  0%   { transform: scale(1);    opacity: .5; }
  55%  { transform: scale(1.75); opacity: 0; }
  100% { transform: scale(1.75); opacity: 0; }
}
/* sem animação o halo volta a ter o tamanho exato do botão, atrás dele —
   ou seja, desaparece sem precisar de uma segunda declaração */
@media (hover: hover) { .zap:hover::before { animation: none; } }
/* hover ESCURECE (AG_MOTION §6.1) - é o verde escuro do próprio WhatsApp */
@media (hover: hover) { .zap:hover { background: #1DA851; transform: translateY(-2px); } }
@media (max-width: 479px) { .zap { width: 48px; height: 48px; right: var(--e2); bottom: var(--e2); } }

/* ── §17 · MOVIMENTO ─────────────────────────────────────────────────────
   Nível SÓBRIO (ESTRATEGIA §0.8): piso, revelar ao rolar, elevar contido, e
   UMA assinatura. Nada de ambiente, nada de contagem, nada de canvas. */

/* Piso: quem pediu menos movimento recebe menos movimento. Não é
   acessibilidade decorativa — enxaqueca e distúrbio vestibular são
   desencadeados por deslocamento na tela. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  /* ⚠️ `*` NÃO ALCANÇA `::details-content`, e isso não é detalhe: é onde vivem
     a abertura da resposta da pergunta e a saída da gaveta do menu. Sem esta
     linha, quem liga "reduzir movimento" no sistema continuaria recebendo os
     240 ms — e nada acusaria, porque a régua confere se EXISTE um bloco de
     reduced-motion no arquivo, não se ele cobre tudo.
     Descoberto medindo, em 28/08/2026: o mesmo `*` do teste também não
     alcançava o pseudo-elemento, e por isso a medição dava 0 px de altura. */
  ::details-content {
    transition-duration: .001ms !important;
    animation-duration: .001ms !important;
  }
  html { scroll-behavior: auto; }
}

/* Revelar ao rolar — CSS puro, sem JavaScript e sem observer.
   ⚠️ O estado inicial invisível SÓ existe dentro do @supports: onde não há
   suporte, o bloco inteiro é ignorado e o conteúdo aparece. Não há fallback
   a escrever, porque não existe caminho em que o texto suma. */
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    /* ⚠️ O intervalo é medido na fase ENTRY, e não em `cover`, e isso não é
       preferência: `cover` é proporcional à ALTURA DA JANELA, então numa tela
       alta o bloco chega ao meio da tela ainda pela metade da animação — e o
       visitante vê conteúdo meio transparente parado na frente dele. Medido
       numa janela de 2600 px, e é exatamente o que acontecia.
       Na fase `entry`, o percurso é o do próprio elemento entrando: em
       qualquer tela, ele termina revelado quando termina de entrar. */
    .revela {
      animation: revela-entrada linear both;
      animation-timeline: view();
      animation-range: entry 5% entry 75%;
    }
    /* a cascata é pelo FIM, não pelo começo: os três partem juntos e chegam
       em degraus, que é o que se lê como sequência */
    .revela-2 { animation-range: entry 5% entry 85%; }
    .revela-3 { animation-range: entry 5% entry 95%; }

    /* ⭐ A ASSINATURA: o voil que fecha sobre a janela.
       O "depois" é recortado de cima para baixo conforme a seção entra na
       tela — o tecido descendo. É recorte, não opacidade: se algum dia esta
       regra não valer, a foto está inteira e nada some. */
    .cai-como-tecido {
      animation: tecido-desce linear both;
      animation-timeline: view();
      animation-range: entry 10% entry 90%;
    }
  }
}
@keyframes revela-entrada {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}
@keyframes tecido-desce {
  from { clip-path: inset(0 0 100% 0); }
  to   { clip-path: inset(0 0 0 0); }
}

/* Elevar no hover — contido, e só nos cartões. Sempre dentro de
   @media (hover: hover): em telefone o hover fica grudado depois do toque, e
   o cartão volta a subir sozinho quando a pessoa rola. */
.eleva { transition: transform .18s ease, border-color .25s ease, box-shadow .25s ease; }
@media (hover: hover) {
  .eleva:hover { transform: translateY(-2px); border-color: var(--grafite-500); }
}

/* ── §17.5 · A TEXTURA DO HERO — o caimento do tecido ────────────────────
   ⚠️ Aprovada em 28/08/2026 e estendida a TODAS as heros. Por isso ela vive
   em `.hero.secao--escura`, e não num modificador: quando um "modificador"
   se aplica a 100% dos casos, ele deixa de modificar — vira propriedade da
   peça. Mantê-lo como classe obrigaria cada página nova a lembrar de
   acrescentá-la, e a oitava página nasceria sem textura sem ninguém notar.

   ⚠️ O seletor pede `.secao--escura` de propósito: a textura é branca a
   4,5%, e só existe sobre superfície escura. Num hero claro ela seria
   invisível — ou pior, um chuvisco.

   **Por que ESTA textura e não um ruído.** Um grão genérico serviria a
   qualquer cliente, e o AG_MOTION §2.1 chama isso de decoração. Aqui as
   linhas verticais finas são o **caimento do tecido** e as **lâminas da
   persiana** — o mesmo desenho que aparece em toda foto do site, e o mesmo
   vocabulário do símbolo da marca. É o produto virando superfície.

   **Três decisões que a mantêm no registro sóbrio:**
   · 4% de branco. Ela é para ser sentida, não vista: quem reparar nela
     olhando de perto vê tecido, e quem não reparar vê um fundo menos chapado;
   · a MÁSCARA dissolve a textura para baixo, como luz que entra pelo alto e
     se perde no fundo do ambiente. Sem ela a listra encosta na borda da seção
     e vira padrão de papel de parede;
   · custo ZERO de rede: é `repeating-linear-gradient`, não imagem. Nenhuma
     requisição, nenhum KB.

   ⚠️ `pointer-events: none` e z-index abaixo do conteúdo: textura que
   intercepta clique é textura que quebra o CTA do hero. */
.hero.secao--escura::after {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background-image: repeating-linear-gradient(90deg,
    rgb(255 255 255 / .045) 0 1px, transparent 1px 9px);
  -webkit-mask-image: linear-gradient(180deg, rgb(0 0 0 / .9) 0%, transparent 78%);
          mask-image: linear-gradient(180deg, rgb(0 0 0 / .9) 0%, transparent 78%);
}
/* o conteúdo sobe acima da textura — sem isto ela pintaria por cima do h1 */
.hero.secao--escura > .wrap { position: relative; z-index: 1; }

/* ── §18 · DUAS PEÇAS MENORES ────────────────────────────────────────────
   Ficam no fim porque sobrescrevem regras de cima, e com a mesma
   especificidade a última vence (AG_MOTION §6.1: sobrescrita escrita antes
   não vale e não avisa). */

/* Os três ambientes viram COLUNA quando moram dentro de `.dupla`: três
   colunas dentro de meia largura viram três frestas. */
/* ⚠️ O ponto de corte é 900, e não 760: é em 900 que `.dupla` vira duas
   colunas e o bloco passa a morar em meia largura. Entre 760 e 900 ele ainda
   tem a largura inteira, e ali três colunas cabem bem — cortá-las antes da
   hora deixaria o tablet com três linhas de texto num vão largo e vazio. */
@media (min-width: 900px) {
  .ambientes--coluna { grid-template-columns: 1fr; }
}

/* Um respiro a mais depois de um bloco que já terminou — o link solto
   embaixo das perguntas, o "como chegar" embaixo do endereço. */
.mais-um { margin-top: var(--e4); }
