/*
 * Modelo "alto padrão" — FASE 1: reset próprio, tokens e esqueleto.
 *
 * Esta folha é a ÚNICA do modelo: ela não carrega o `estilo.css` de 2016 (5.886 linhas de float
 * e altura fixa), nem o `temas.css` que repinta aquele markup por cima, nem o font-awesome
 * (26 KB de CSS + 141 KB de fonte). Começar do zero é o que permite a folha inteira ficar dentro
 * da meta de 60 KB.
 *
 * A Fase 2 traz o desenho: escala tipográfica, as fontes próprias (Newsreader / Instrument Sans /
 * IBM Plex Mono em woff2 variável), a escala de cor calculada em OKLab a partir da marca da conta
 * e os componentes desenhados. O que está aqui é o mínimo para o modelo responder de pé.
 *
 * Multi-tenant: nenhuma cor de marca aparece escrita. Tudo sai de `--primary`/`--secondary`, que o
 * Layout põe no `<html>` a partir da conta. Uma imobiliária com marca amarela não pode receber
 * texto branco sobre amarelo — a decisão por luminância entra na Fase 2.
 */

/* A ordem manda mais que a especificidade: `paginas` vem depois de `componentes` porque
   repinta marcação herdada, e `utilidades` no fim para poder vencer as duas. */
@layer reset, tokens, base, componentes, paginas, utilidades;

/* ------------------------------------------------------------------ reset */
@layer reset {
  *, *::before, *::after { box-sizing: border-box; }
  html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
  body { margin: 0; }
  h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd { margin: 0; }
  ul[class], ol[class] { list-style: none; margin: 0; padding: 0; }
  img, picture, video, canvas, svg { display: block; max-width: 100%; }
  input, button, textarea, select { font: inherit; color: inherit; }
  button { cursor: pointer; }
  a { color: inherit; }
  fieldset { margin: 0; padding: 0; border: 0; }
  legend { padding: 0; }
  /* Quem pediu menos movimento recebe menos movimento — não é opcional. */
  @media (prefers-reduced-motion: reduce) {
    *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important;
      transition-duration: 0.01ms !important; scroll-behavior: auto !important; }
  }
}

/* ----------------------------------------------------------------- tokens */
@layer tokens {
  :root {
    /* Cor da marca: a ESCALA vem calculada da conta (EscalaDeCor, em OKLab), injetada no <html>
       como --ap-marca-50..950 + as decisões derivadas. Os fallbacks abaixo são o vermelho da Vini,
       para a folha nunca ficar sem cor se a API não mandar a escala.
       `--ap-marca-fundo` é o preenchimento de botão (primeiro degrau que passa AA com a tinta
       escolhida) e `--ap-marca-texto` é o degrau para texto em corpo — que NÃO é o mesmo: o 600 do
       vermelho da Vini passa o WCAG (5,21) e fica um ponto abaixo de confortável para ler, então
       o texto usa o 700. Ver docs/site-novo/DECISOES_DESIGN.md. */
    --ap-marca: var(--ap-marca-600, var(--primary, #dc1921));
    --ap-marca-escura: var(--ap-marca-700, var(--secondary, #ba1319));
    --ap-marca-fundo: var(--ap-marca-600, #d50619);
    --ap-marca-tinta: #fff;          /* tinta sobre o preenchimento, escolhida por medição */
    --ap-marca-texto: var(--ap-marca-700, #ad0011);
    --ap-marca-fraca: var(--ap-marca-100, #ffe4e0);
    --ap-marca-fio: var(--ap-marca-200, #ffc6bf);

    /* Papel e tinta quentes, em H = 75 (OKLCH). A geometria decidiu, não o gosto: o vermelho da
       marca está em H = 26,9°, e um neutro a H = 35 fica a 8° dele — sairia rosado, lendo como
       tinta desbotada da marca. Um cinza a H = 250 fica a 43° do complemento exato, que é onde o
       contraste simultâneo maximiza tensão: vibra ao lado de tijolo. H = 60–80 é longe dos dois.
       E croma 0 não serve: é a única cor que NÃO pode existir numa fotografia, então lê como
       chrome de sistema; pior, ao lado de céu e mar ele deriva perceptualmente para o
       quente-amarelado SEM ninguém ter escolhido — e derivar sem intenção é o que se lê como
       encardido. Croma pequeno e deliberado faz a família ler como estável. */
    --ap-papel: #fdfaf6;
    --ap-papel-2: #f3efed;
    --ap-tinta: #211c18;
    /* Piso de leitura MEDIDO: o cinza de legenda a #76706C passa o WCAG AA (4,66) e reprova o
       limiar de leitura confortável (Lc 70,7 < 75). É a armadilha do "cinza discreto" para m²,
       referência e condomínio. Nada que o cliente precise ler desce abaixo deste valor. */
    --ap-tinta-fraca: #5c5753;
    /* DUAS linhas, de propósito. A decorativa separa bloco e pode ser sutil; a de campo é o
       LIMITE DE UM COMPONENTE DE INTERFACE e o WCAG 1.4.11 exige 3:1 contra o fundo — abaixo
       disso a pessoa não vê onde o campo começa. `#e3dfdc` dá 1,27 sobre o papel; `#968d86` dá
       3,12. Medido por scripts/verificar-contraste.mjs, que falha o processo se cair. */
    --ap-linha: #e6e4e0;
    --ap-linha-campo: #968d86;

    /* Topo cinemático escuro, na mesma temperatura do corpo (quente). Medido: branco por cima dá
       Lc -107 e 18,8:1 — os três candidatos de temperatura empatam na medida, então a escolha é de
       coerência com o papel. */
    --ap-escuro: #16100c;
    --ap-escuro-tinta: #f7f5f3;
    /* Scrim: degradê sobre a foto para o texto ter contraste garantido. É contraste tipográfico,
       não tratamento de imagem — `filter: saturate()/contrast()` na foto lê como 2017 e some do
       arquivo o que deveria estar nele (medido: nos três sites de referência o `filter` computado
       de TODA imagem é `none`). */
    /* MEDIDO 24/09/2026: o gradiente estava de cabeça para baixo. Ele escurecia o RODAPÉ da
       foto (0,92 embaixo, 0,25 em cima) enquanto o `h1` fica em y=137 — no topo, ou seja, sobre
       a faixa mais clara. Por isso o título branco caía numa cortina clara e numa janela
       estourada, e o botão, que nunca teve problema, ficava sobre a parte escura. */
    --ap-scrim: linear-gradient(to bottom, rgb(22 16 12 / 0.88) 0%, rgb(22 16 12 / 0.55) 55%, rgb(22 16 12 / 0.25) 100%);

    /* Tipografia: serifada editorial de display + grotesca neutra + mono só para número. É a
       gramática do topo do mercado, verificada arquivo por arquivo (Inigo usa Big Caslon + Söhne;
       Knight Frank, Tiempos Headline + Suisse Int'l; Aucoot, Copernicus + Maison Neue). Newsreader
       é a alternativa OFL honesta para esse papel — e tem eixo óptico, que nenhuma delas expõe na
       web. Os fallbacks têm métrica casada via @font-face mais abaixo, para o texto não pular
       quando a fonte chega (CLS). */
    --ap-fonte-titulo: 'Newsreader', 'Newsreader fallback', ui-serif, Georgia, serif;
    --ap-fonte-texto: 'Instrument Sans', 'Instrument Sans fallback', system-ui, -apple-system, sans-serif;
    --ap-fonte-numero: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

    /* Escala fluida: o mesmo valor serve de 390px a 1440px, sem media query por tamanho. */
    --ap-t-xl: clamp(2.25rem, 1.4rem + 3.6vw, 4.5rem);
    --ap-t-lg: clamp(1.5rem, 1.15rem + 1.5vw, 2.25rem);
    --ap-t-md: clamp(1.125rem, 1rem + 0.5vw, 1.375rem);
    --ap-t-base: clamp(1rem, 0.97rem + 0.15vw, 1.0625rem);
    --ap-t-sm: 0.875rem;
    --ap-t-xs: 0.75rem;

    /**
     * Raio ZERO como padrão — e UM raio reservado para o CTA.
     *
     * É a decisão do `DECISOES_DESIGN.md`, com a medição junto: em themodernhouse.com o
     * `border-radius` computado é `0px` em **todos** os ~400 elementos. O modelo novo estava
     * herdando `--tn-raio` dos temas "moderno"/"compacto" e saía com 12px em **100 elementos**
     * (mais 75 pílulas, 2 de 8px e 1 de 50%): quatro raios diferentes, 178 cantos arredondados.
     * Canto arredondado em tudo é o que faz a página ler como painel de sistema, não como
     * editorial — e some justamente o contraste que faria o botão principal parecer uma decisão.
     *
     * A pílula dos chips (999px) fica: vem da barra segmentada e é deliberada.
     */
    --ap-raio: 0px;
    --ap-raio-cta: 0.75rem;
    --ap-gutter: 1rem;   /* respiro lateral no celular */
    --ap-largura: 1200px;
    /* Altura do logotipo TRAVADA aqui: a queixa do dono sobre o site atual foi "esse logo tá
       ficando grande demais". No clássico a imagem sai no tamanho natural do arquivo que a
       imobiliária subiu, então cada conta tem um logo de um tamanho. */
    --ap-logo-h: 2.25rem;
  }
  @media (min-width: 600px) { :root { --ap-gutter: 1.5rem; } }
}

/* ------------------------------------------------------------------- base */
@layer base {
  body {
    background: var(--ap-papel);
    color: var(--ap-tinta);
    font-family: var(--ap-fonte-texto);
    font-size: var(--ap-t-base);
    line-height: 1.6;
    /* Nenhuma página pode rolar de lado: é o defeito que escondia o agendador de visita.
       `clip` e não `hidden`: `hidden` transforma o elemento em CONTAINER DE ROLAGEM, o que
       (a) permite rolar por script mesmo sem barra e (b) quebra a busca de posição das animações
       guiadas por rolagem em CSS, que é como a Fase 2 vai fazer movimento sem um byte de JS.
       `clip` corta igual e não cria container. */
    overflow-x: clip;
  }
  h1, h2, h3, h4 { font-family: var(--ap-fonte-titulo); font-weight: 600; line-height: 1.15; text-wrap: balance; }
  h1 { font-size: var(--ap-t-xl); }
  h2 { font-size: var(--ap-t-lg); }
  h3 { font-size: var(--ap-t-md); }
  p { text-wrap: pretty; }
  a { text-decoration-thickness: 1px; text-underline-offset: 0.15em; }
  :where(a, button, input, select, textarea, summary):focus-visible {
    outline: 2px solid var(--ap-marca); outline-offset: 2px; border-radius: 2px;
  }
  main { display: block; }
}

/* ------------------------------------------------------------ componentes */
@layer componentes {
  .ap-topo-in, .ap-hero-in, .ap-rodape-in {
    max-width: var(--ap-largura); margin-inline: auto; padding-inline: var(--ap-gutter);
  }

  /* --- cabeçalho --- */
  .ap-topo { background: var(--ap-papel); border-bottom: 1px solid var(--ap-linha); }
  .ap-topo-in { display: flex; align-items: center; gap: 1rem; min-height: 4rem; }
  .ap-marca { display: flex; align-items: center; text-decoration: none; }
  /**
   * A caixa do logo é RESERVADA pelo CSS, e a imagem desenha dentro dela.
   *
   * Antes: `height` fixo + `width: auto`, com `width`/`height` chutados na marcação (200×56 no
   * topo, 180×50 no rodapé). O arquivo real da Vini é 408×160 — proporção 2,55 contra 3,57
   * declarada —, então antes de carregar o navegador reservava 128,6px e depois reduzia para
   * 91,8px: **36,6px de deslocamento no cabeçalho, em todas as páginas, acima da dobra**.
   *
   * E não há como "corrigir os números": o logo é de cada conta, e a API manda só a URL. Com
   * `aspect-ratio` + `object-fit: contain` a largura fica conhecida desde o primeiro paint e
   * qualquer proporção de arquivo cabe dentro sem distorcer — logo estreito sobra espaço à
   * direita, que é infinitamente melhor que a página pular.
   */
  .ap-logo { block-size: var(--ap-logo-h); inline-size: auto; aspect-ratio: 3 / 1;
    max-inline-size: 11rem; object-fit: contain; object-position: left center; }
  .ap-marca-texto { font-family: var(--ap-fonte-titulo); font-size: var(--ap-t-md); font-weight: 600; }
  /**
   * Toda lista da casca perde o marcador — não só a da gaveta.
   *
   * O reset é `ul[class] { list-style: none }`, de propósito (lista de conteúdo editorial mantém
   * o marcador). Quando a gaveta foi corrigida, as outras nove `<ul>` sem atributo `class` ficaram
   * para trás, e o menu do desktop e as quatro colunas do rodapé saíam com bolinha em cada link —
   * nenhum site de referência tem marcador em menu. Alcançar pelo ancestral resolve as nove de
   * uma vez e não depende de ninguém lembrar de pôr `class` numa lista nova.
   */
  .ap-topo ul, .ap-rodape ul { list-style: none; margin: 0; padding: 0; }

  .ap-menu { display: none; margin-inline-start: auto; }
  .ap-menu > ul { display: flex; gap: 1.25rem; }
  .ap-menu a { text-decoration: none; font-size: var(--ap-t-sm); padding-block: 0.75rem; display: inline-block; }
  .ap-menu a:hover { color: var(--ap-marca); }
  /**
   * O submenu do DESKTOP — que nunca abria.
   *
   * `.ap-submenu` tinha uma única regra em todo o projeto: `display: none`. Não havia `:hover`,
   * `:focus-within` nem script, e `.ap-menu-com-sub` (a classe posta no `<li>` justamente para ser
   * o gancho) não tinha regra nenhuma. Como a gaveta some acima de 960px, `.ap-menu` é a única
   * navegação do desktop — e **19 dos 24 links do site ficavam inalcançáveis** ali: Apartamentos,
   * Casas, Locação, Edifícios, Favoritos, Construtoras, Avalie seu imóvel, Simulador, Minha Casa
   * Minha Vida, Trabalhe conosco e mais. Fora o rastreamento perdido: link interno é o que leva o
   * buscador às páginas de dentro, e a home é quem tem força para isso.
   *
   * `:focus-within` junto de `:hover` resolve o teclado sem uma linha de script — a mesma
   * filosofia do `<details>` da gaveta.
   */
  .ap-menu-com-sub { position: relative; }
  .ap-submenu { display: none; position: absolute; inset-inline-start: 0; inset-block-start: 100%;
    z-index: 40; min-inline-size: 13rem; padding-block: 0.35rem;
    background: var(--ap-papel); border: 1px solid var(--ap-linha);
    box-shadow: 0 14px 28px rgb(22 16 12 / 0.1); }
  .ap-menu-com-sub:hover > .ap-submenu,
  .ap-menu-com-sub:focus-within > .ap-submenu { display: block; }
  .ap-submenu a { display: block; padding: 0.5rem 0.9rem; min-block-size: 40px; }
  .ap-submenu a:hover { background: var(--ap-papel-2); color: var(--ap-marca-texto); }
  .ap-topo-acoes { display: none; align-items: center; gap: 0.75rem; }
  .ap-topo-cliente, .ap-topo-tel { font-size: var(--ap-t-sm); text-decoration: none; }
  .ap-gaveta { margin-inline-start: auto; }
  .ap-gaveta > summary { list-style: none; display: grid; place-items: center;
    /* 44px: alvo de toque de verdade (WCAG 2.2 pede 24px no mínimo). */
    inline-size: 44px; block-size: 44px; border-radius: var(--ap-raio); }
  .ap-gaveta > summary::-webkit-details-marker { display: none; }
  /* O conteúdo da gaveta FECHADA não pode ser desenhado.
     Medido em 24/09/2026: com o `<details>` fechado, este menu era renderizado com **1.810px de
     altura**, espremido em 44px de largura, pintado por cima da página. O navegador esconde o
     conteúdo de um `<details>` fechado sozinho — mas parou de fazer isso aqui porque o `<summary>`
     recebeu `display: grid` (para centrar o ícone), e trocar o `display` do resumo desarma a regra
     do próprio navegador. Esta linha devolve a garantia, sem depender do comportamento padrão. */
  .ap-gaveta:not([open]) .ap-gaveta-menu { display: none; }

  /**
   * O menu aberto no celular.
   *
   * O que estava errado (24/09/2026): a folha tinha só `padding` aqui, e o menu abria como lista
   * crua — com os marcadores • e ○ do navegador e o recuo de 40px de cada `<ul>` somando dois
   * níveis. A causa é o reset: `ul[class] { list-style: none }` só alcança lista COM atributo
   * `class`, e as `<ul>` de dentro deste menu não têm nenhum. O seletor por atributo é proposital
   * no reset (não mexer em lista de conteúdo editorial), então quem precisa zerar é o componente.
   *
   * Além de zerar, o menu ganha o que faltava para parecer um painel: fundo do papel, regra entre
   * os itens e a largura inteira da tela. Item de menu tem 44px de alvo — é o mínimo de toque.
   */
  /**
   * ...e o menu aberto é um PAINEL, não um filho do flex.
   *
   * A outra metade do defeito: `.ap-topo-in` é `display: flex`, e o `<details>` é um item flex com
   * a largura do próprio botão — 44px. O `<nav>` aberto herdava essa caixa e escorria numa coluna
   * estreita no meio da tela, que foi exatamente o que apareceu na captura. Tirar o painel do
   * fluxo resolve as duas coisas de uma vez: ele ganha a largura da tela e deixa de empurrar a
   * página para baixo ao abrir.
   *
   * `max-block-size` + rolagem própria: com submenu, o menu é mais alto que a tela do celular, e
   * sem isso os últimos itens ficam inalcançáveis. `100dvh` (e não `vh`) porque a barra do
   * navegador no celular entra e sai da conta.
   */
  .ap-topo { position: relative; }
  .ap-gaveta-menu { position: absolute; inset-inline: 0; inset-block-start: 100%;
    z-index: 40; background: var(--ap-papel);
    border-block-start: 1px solid var(--ap-linha);
    box-shadow: 0 14px 28px rgb(22 16 12 / 0.1);
    padding: 0.25rem var(--ap-gutter) 1rem;
    max-block-size: calc(100dvh - 4rem); overflow-y: auto; overscroll-behavior: contain; }
  .ap-gaveta-menu ul { list-style: none; margin: 0; padding: 0; }
  .ap-gaveta-menu li { border-block-start: 1px solid var(--ap-linha); }
  .ap-gaveta-menu li:first-child { border-block-start: 0; }
  .ap-gaveta-menu a { display: flex; align-items: center; min-block-size: 44px;
    padding: 0.55rem 0; text-decoration: none; font-weight: 500; }
  .ap-gaveta-menu a:hover, .ap-gaveta-menu a:focus-visible { color: var(--ap-marca-texto); }
  /* Submenu: recuo pequeno e deliberado, um degrau de peso abaixo — o recuo diz "isto pertence
     ao de cima" melhor que qualquer marcador. */
  .ap-gaveta-menu ul ul { padding-inline-start: 0.9rem; }
  .ap-gaveta-menu ul ul li { border-block-start: 0; }
  .ap-gaveta-menu ul ul a { min-block-size: 40px; padding-block: 0.35rem;
    font-size: var(--ap-t-sm); font-weight: 400; color: var(--ap-tinta-fraca); }
  @media (min-width: 960px) {
    .ap-menu, .ap-topo-acoes { display: flex; }
    .ap-gaveta { display: none; }
  }

  /* --- topo da home --- */
  .ap-hero { position: relative; background: var(--ap-escuro); color: var(--ap-escuro-tinta); isolation: isolate; }
  /* A foto é <img> (o LCP precisa estar na marcação) posicionada por cima do fundo.
     Quem reserva a altura do topo é o `padding` de `.ap-hero-in`, NÃO a imagem — ela está fora
     do fluxo, então não desloca nada e não precisa de `width`/`height`. O comentário anterior
     dizia o contrário e sustentava um par de atributos chutados (1920×1080 num arquivo 800×800). */
  .ap-hero-foto { position: absolute; inset: 0; inline-size: 100%; block-size: 100%;
    object-fit: cover; z-index: -2; }
  /* Scrim: degradê por cima da foto. É contraste TIPOGRÁFICO, não tratamento de imagem — baixar a
     opacidade da foto inteira apaga o imóvel junto com o excesso de luz. O degradê escurece onde o
     texto está e deixa a foto respirar no resto. */
  .ap-hero::after { content: ''; position: absolute; inset: 0; background: var(--ap-scrim); z-index: -1; }
  .ap-hero-in { padding-block: clamp(3rem, 8vh, 6rem); }
  .ap-hero-titulo { max-width: 22ch; }
  .ap-hero-sub { margin-top: 0.75rem; max-width: 46ch; color: color-mix(in srgb, var(--ap-escuro-tinta) 80%, transparent); }

  /* --- busca --- */
  .ap-busca { margin-top: 1.5rem; display: grid; gap: 0.75rem; }
  .ap-busca-linha { display: flex; gap: 0.5rem; }
  .ap-chip { position: relative; }
  .ap-chip input { position: absolute; opacity: 0; inset: 0; }
  .ap-chip span { display: inline-flex; align-items: center; min-height: 44px; padding-inline: 1rem;
    border: 1px solid color-mix(in srgb, currentColor 35%, transparent);
    border-radius: 999px; font-size: var(--ap-t-sm); }
  .ap-chip input:checked + span { background: var(--ap-marca); border-color: var(--ap-marca); color: #fff; }
  .ap-chip input:focus-visible + span { outline: 2px solid currentColor; outline-offset: 2px; }
  .ap-busca-campos { display: grid; gap: 0.6rem; }
  .ap-campo { display: grid; gap: 0.25rem; margin: 0; }
  .ap-campo > label { font-size: var(--ap-t-xs); text-transform: uppercase; letter-spacing: 0.06em;
    color: color-mix(in srgb, currentColor 70%, transparent); }
  .ap-campo select, .ap-campo input {
    /* 16px: abaixo disso o iPhone dá zoom no campo ao tocar. */
    font-size: 1rem; min-height: 44px; padding: 0 0.75rem; width: 100%;
    background: #fff; color: var(--ap-tinta); border: 1px solid var(--ap-linha-campo); border-radius: var(--ap-raio);
  }
  @media (min-width: 760px) {
    .ap-busca-campos { grid-template-columns: repeat(3, minmax(0, 1fr)) auto; align-items: end; }
  }

  /* --- botões --- */
  .ap-btn { display: inline-flex; align-items: center; justify-content: center; gap: 0.4rem;
    min-height: 44px; padding-inline: 1.1rem; border: 1px solid transparent; border-radius: var(--ap-raio);
    font-size: var(--ap-t-sm); font-weight: 600; text-decoration: none; white-space: nowrap; }
  /* O ÚNICO raio do modelo, e é o que faz o botão principal ler como decisão. */
  .ap-btn-marca { background: var(--ap-marca); color: #fff; border-radius: var(--ap-raio-cta); }
  .ap-btn-marca:hover { background: var(--ap-marca-escura); }
  .ap-btn-linha { background: transparent; border-color: var(--ap-linha-campo); color: var(--ap-tinta); }
  .ap-ico { flex: none; }

  /* --- card de imóvel --- */
  .ap-card { background: #fff; border: 1px solid var(--ap-linha); border-radius: var(--ap-raio);
    overflow: hidden; display: flex; flex-direction: column; min-width: 0; }
  .ap-card-foto { position: relative; display: block; }
  /* Proporção FIXA + cover: foto 380×253 pintada em 380×400 era o defeito do clássico —
     imóvel distorcido, com quase metade do quadro fora. */
  .ap-card-foto img { aspect-ratio: 3 / 2; inline-size: 100%; block-size: auto; object-fit: cover; }
  .ap-card-selos { position: absolute; inset-block-start: 0.5rem; inset-inline-start: 0.5rem;
    display: flex; flex-wrap: wrap; gap: 0.25rem; }
  .ap-selo { background: rgb(0 0 0 / 0.72); color: #fff; font-size: var(--ap-t-xs);
    padding: 0.15rem 0.5rem; border-radius: 999px; }
  .ap-selo-marca { background: var(--ap-marca); }
  .ap-selo-atencao { background: #92400e; }
  .ap-card-corpo { padding: 0.9rem; display: grid; gap: 0.35rem;
    /* `min-inline-size: 0` nos itens: em grid/flex o padrão é `auto`, que impede o filho de
       encolher abaixo do conteúdo — é o que deixa um título longo empurrar a coluna para fora
       do cartão. Cinto de segurança para qualquer texto comprido que apareça no cadastro. */
    grid-template-columns: minmax(0, 1fr); }
  /* Preço em monoespaçada: é o que alinha a coluna de valores e deixa comparar de relance. */
  .ap-card-preco { font-family: var(--ap-fonte-numero); font-size: var(--ap-t-md); }
  .ap-card-preco s { color: var(--ap-tinta-fraca); font-size: var(--ap-t-sm); }
  .ap-card-titulo { font-size: var(--ap-t-base); font-weight: 600; }
  .ap-card-titulo a { text-decoration: none; }
  /* Tipo em tinta, cidade na cor da marca — a mesma divisão do logotipo da casa.
     A cor usada é `--ap-marca-texto` (o degrau medido para texto sobre papel), nunca
     `--ap-marca` cru: o 600 do vermelho da Vini passa raspando no WCAG e este título é
     texto pequeno. Ver a nota dos tokens. */
  .ap-card-t-tipo { color: var(--ap-tinta); }
  .ap-card-t-cidade { color: var(--ap-marca-texto); }
  .ap-card-local { font-size: var(--ap-t-sm); color: var(--ap-tinta-fraca); }
  .ap-card-specs { display: flex; flex-wrap: wrap; gap: 0.75rem; font-size: var(--ap-t-sm);
    color: var(--ap-tinta-fraca); }
  .ap-card-specs b { font-family: var(--ap-fonte-numero); color: var(--ap-tinta); }
  .ap-card-acoes { display: flex; gap: 0.5rem; margin-top: 0.35rem; }
  /**
   * O WhatsApp do CARD não é o CTA da página.
   *
   * Medido na home: 31 elementos com fundo vermelho e 87 com texto vermelho, 119 no total — e
   * 22 deles eram o botão preenchido de cada cartão. Vermelho em tudo deixa de significar
   * "aja aqui" e vira textura; some justamente o contraste que faria o botão do topo, o do
   * simulador e o do rodapé parecerem decisões.
   *
   * O link continua igual em função e contrato (`data-track="contato_whatsapp"` intacto — a
   * medição de interesse depende dele). Muda só o peso: contorno em vez de preenchimento, como
   * o "Ver o imóvel" ao lado.
   */
  .ap-card-acoes .ap-btn-marca {
    background: transparent; color: var(--ap-marca-texto);
    border: 1px solid var(--ap-linha); font-weight: 500; border-radius: 0;
  }
  .ap-card-acoes .ap-btn-marca:hover { border-color: var(--ap-marca-fundo); }
  .ap-card-acoes .ap-btn { flex: 1; }
  .ap-card-ref { font-size: var(--ap-t-xs); color: var(--ap-tinta-fraca);
    font-family: var(--ap-fonte-numero); }

  /* --- rodapé --- */
  .ap-rodape { background: var(--ap-escuro); color: var(--ap-escuro-tinta); margin-top: 3rem; }
  .ap-rodape-in { display: grid; gap: 2rem; padding-block: 2.5rem; }
  .ap-rodape-titulo { font-size: var(--ap-t-sm); text-transform: uppercase; letter-spacing: 0.08em;
    font-family: var(--ap-fonte-texto); font-weight: 700; margin-bottom: 0.6rem; }
  .ap-rodape-col a, .ap-rodape-dados a, .ap-rodape-sociais a { font-size: var(--ap-t-sm);
    text-decoration: none; display: inline-block; padding-block: 0.3rem; }
  .ap-rodape-col a:hover, .ap-rodape-sociais a:hover { text-decoration: underline; }
  .ap-rodape-dados { display: grid; gap: 0.15rem; font-size: var(--ap-t-sm);
    color: color-mix(in srgb, var(--ap-escuro-tinta) 78%, transparent); margin-top: 0.75rem; }
  .ap-rodape-sociais { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: 0.5rem; }
  .ap-rodape-news input { inline-size: 100%; min-height: 44px; font-size: 1rem; padding: 0 0.75rem;
    border: 1px solid color-mix(in srgb, var(--ap-escuro-tinta) 30%, transparent);
    border-radius: var(--ap-raio); background: transparent; color: inherit; margin-block: 0.5rem; }
  .ap-rodape-nota { border-top: 1px solid color-mix(in srgb, var(--ap-escuro-tinta) 15%, transparent); }
  .ap-rodape-nota > * { max-width: var(--ap-largura); margin-inline: auto; padding-inline: var(--ap-gutter);
    font-size: var(--ap-t-xs); color: color-mix(in srgb, var(--ap-escuro-tinta) 65%, transparent); }
  .ap-rodape-nota p { padding-block: 0.5rem; }
  @media (min-width: 760px) {
    .ap-rodape-in { grid-template-columns: 1.4fr 1fr 1fr 1fr; }
  }
  @media (min-width: 1100px) {
    .ap-rodape-in { grid-template-columns: 1.4fr 1fr 1fr 1fr 1.2fr; }
  }
}

/* -------------------------------------------------------------- utilidades */
@layer utilidades {
  /* Texto só para leitor de tela. `clip-path` em vez de `position: absolute` solto: elemento
     absoluto com texto longo dentro de tabela larga ALARGA a página no celular. */
  .sr-only {
    position: absolute; inline-size: 1px; block-size: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
  }
}


/* ---------------------------------------------- grade, tabela, FAQ, vazio, trilha */
@layer componentes {
  /* Grade de cards por CONTAINER QUERY, não por largura de tela: o mesmo card serve na home (largo)
     e na coluna da ficha (estreito) sem uma regra por breakpoint. É também a maior alavanca sobre o
     orçamento de 60 KB de CSS. */
  .ap-grade { container-type: inline-size; display: grid; gap: 1rem;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 16rem), 1fr)); }

  /* Tabela de dados: número em monoespaçada, alinhado à direita, e a ROLAGEM DENTRO DA CAIXA.
     `tabindex` + `role=region`: rolagem que só o mouse alcança é barreira de teclado. */
  .ap-tabela-rolagem { overflow-x: auto; max-inline-size: 100%; border: 1px solid var(--ap-linha);
    border-radius: var(--ap-raio); background: #fff; }
  .ap-tabela-rolagem:focus-visible { outline: 2px solid var(--ap-marca-fundo); outline-offset: 2px; }
  .ap-tabela { inline-size: 100%; border-collapse: collapse; font-size: var(--ap-t-sm); }
  .ap-tabela th, .ap-tabela td { padding: 0.65rem 0.8rem; text-align: left; border-bottom: 1px solid var(--ap-linha); }
  .ap-tabela th { font-family: var(--ap-fonte-texto); font-size: var(--ap-t-xs); text-transform: uppercase;
    letter-spacing: 0.06em; color: var(--ap-tinta-fraca); white-space: nowrap; }
  .ap-tabela td + td, .ap-tabela th + th { text-align: right; font-family: var(--ap-fonte-numero);
    font-variant-numeric: tabular-nums; }
  .ap-tabela tbody tr:last-child td { border-bottom: 0; }

  /* FAQ em <details> nativo: abre sem JavaScript, e o texto está sempre no HTML — marcar pergunta
     frequente no schema sem o texto visível viola a diretriz do Google. */
  .ap-faq { display: grid; gap: 0.5rem; }
  .ap-faq details { border: 1px solid var(--ap-linha); border-radius: var(--ap-raio); background: #fff; }
  .ap-faq summary { cursor: pointer; padding: 0.85rem 1rem; font-weight: 600; min-height: 44px;
    display: flex; align-items: center; gap: 0.5rem; list-style: none; }
  .ap-faq summary::-webkit-details-marker { display: none; }
  .ap-faq summary::after { content: '+'; margin-inline-start: auto; font-family: var(--ap-fonte-numero);
    color: var(--ap-marca-texto); }
  .ap-faq details[open] summary::after { content: '–'; }
  .ap-faq details > :not(summary) { padding: 0 1rem 1rem; margin: 0; color: var(--ap-tinta-fraca); }

  /* Estado vazio e de erro: nunca dizem "não temos" — oferecem o caminho seguinte. */
  .ap-vazio { display: grid; justify-items: start; gap: 0.4rem; padding: 1.5rem;
    border: 1px dashed var(--ap-linha-campo); border-radius: var(--ap-raio); background: var(--ap-papel-2); }
  .ap-vazio p { margin: 0; font-size: var(--ap-t-sm); color: var(--ap-tinta-fraca); }
  .ap-vazio p b { color: var(--ap-tinta); font-size: var(--ap-t-base); }
  .ap-vazio .ap-btn { margin-top: 0.6rem; }

  /* Trilha: onde o visitante está. Sem `>` de texto — o separador é ícone, que herda a cor. */
  .ap-trilha { display: flex; flex-wrap: wrap; align-items: center; gap: 0.35rem;
    font-size: var(--ap-t-sm); color: var(--ap-tinta-fraca); padding-block: 0.75rem; }
  .ap-trilha a { text-decoration: none; }
  .ap-trilha a:hover { text-decoration: underline; }
  .ap-trilha svg { color: var(--ap-linha-campo); flex: none; }
  .ap-trilha [aria-current] { color: var(--ap-tinta); font-weight: 600; }

  /* Seção de conteúdo: contida com margem, NÃO sangrando a tela. Medido nos sites de referência:
     em 1440px o topo do The Modern House ocupa ~64% da largura, com margem generosa — a margem
     entra no enquadramento junto com a foto. Full-bleed fica só no topo e nas quebras. */
  /**
   * Ritmo em DOIS degraus — a home era uma pilha.
   *
   * Medido: as 17 seções saíam com `padding: 40px` idêntico, e a sequência de alturas contava o
   * resto — cinco grades de cartão quase iguais seguidas. Sem respiro diferente, nada indica o
   * que é capítulo e o que é continuação, e a página lê como lista de blocos.
   *
   * O degrau maior vai nas seções que ABREM assunto (vitrine, guia, preços, sobre, simulador);
   * as demais ficam no respiro normal e leem como parte do bloco anterior.
   */
  .ap-secao { max-width: var(--ap-largura); margin-inline: auto;
    padding: var(--ap-ritmo, 2.5rem) var(--ap-gutter); }
  .ap-secao[data-bloco="vitrine"], .ap-secao[data-bloco="guia-tipos"],
  .ap-secao[data-bloco="precos-bairro"], .ap-secao[data-bloco="sobre"],
  .ap-secao[data-bloco="categorias"], .ap-simulador {
    --ap-ritmo: clamp(3.5rem, 7vw, 5.5rem);
  }
  .ap-secao-cab { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between;
    gap: 0.5rem; margin-bottom: 1.25rem; }
  /* `inline-flex` + `nowrap`: sem isto a seta cai sozinha na segunda linha em todas as oito
     seções que têm "Ver todos", e seta órfã lê como erro de renderização. */
  .ap-secao-cab a { display: inline-flex; align-items: center; gap: 0.35rem; white-space: nowrap;
    font-size: var(--ap-t-sm); text-decoration: none; color: var(--ap-marca-texto); }
  /* Rótulo de seção: sans em caixa alta travada, pequeno. Dois registros só — serifada grande e
     sans miúda em caixa alta — é a hierarquia inteira dos sites de referência. */
  .ap-rotulo { font-size: var(--ap-t-xs); text-transform: uppercase; letter-spacing: 0.1em;
    font-weight: 700; color: var(--ap-marca-texto); margin-bottom: 0.3rem; }

  .ap-btn:disabled, .ap-btn[aria-disabled='true'] { opacity: 0.5; cursor: not-allowed; }
}

/* ------------------------------------------------------------ corpo da home */
@layer componentes {
  /* Resposta direta: o parágrafo de fatos que um buscador de IA cita e o Google usa em resposta
     destacada. Tipografia maior que o corpo e medida curta — é para ser lido, não pulado. */
  .ap-resposta p { font-size: var(--ap-t-md); line-height: 1.55; max-width: 58ch;
    color: var(--ap-tinta); border-left: 2px solid var(--ap-marca-fundo); padding-left: 1rem; }

  /* A UMA assimetria deliberada: o primeiro destaque ocupa duas colunas e duas linhas. Não é bento
     de seis células — bento serve conteúdo heterogêneo, e aqui são todas fotos de prédio. */
  @container (min-width: 44rem) {
    .ap-grade-destaque > :first-child { grid-column: span 2; grid-row: span 2; }
    .ap-grade-destaque > :first-child .ap-card-foto img { aspect-ratio: 4 / 3; }
    .ap-grade-destaque > :first-child .ap-card-preco { font-size: var(--ap-t-lg); }
  }

  /* Bairros: foto em 3:2 com o nome sobre scrim. Proporção fixa porque é o que torna
     CLS ≤ 0,05 alcançável — cada proporção nova é outra chance de divergir do declarado. */
  .ap-bairros { display: grid; gap: 0.75rem;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 13rem), 1fr)); }
  .ap-bairros a { position: relative; display: block; border-radius: var(--ap-raio);
    overflow: hidden; text-decoration: none; isolation: isolate; }
  .ap-bairros img { aspect-ratio: 3 / 2; inline-size: 100%; block-size: auto; object-fit: cover; }
  .ap-bairros a::after { content: ''; position: absolute; inset: 0; background: var(--ap-scrim); }
  .ap-bairros span { position: absolute; inset-block-end: 0.6rem; inset-inline-start: 0.75rem;
    z-index: 1; color: var(--ap-escuro-tinta); font-family: var(--ap-fonte-titulo);
    font-size: var(--ap-t-md); font-weight: 600; }

  /* Atalhos de busca: hub de link interno. A contagem em monoespaçada diz se vale clicar. */
  .ap-chips { display: flex; flex-wrap: wrap; gap: 0.5rem; }
  .ap-chips a { display: inline-flex; align-items: center; gap: 0.4rem; min-height: 40px;
    padding-inline: 0.9rem; border: 1px solid var(--ap-linha); border-radius: 999px;
    background: #fff; font-size: var(--ap-t-sm); text-decoration: none; }
  .ap-chips a:hover { border-color: var(--ap-marca-fundo); color: var(--ap-marca-texto); }
  .ap-chips b { font-family: var(--ap-fonte-numero); font-size: var(--ap-t-xs);
    color: var(--ap-tinta-fraca); }

  /* Institucional em duas colunas, com o texto em medida de leitura (não a largura da tela). */
  .ap-sobre { display: grid; gap: 2rem; }
  .ap-sobre-texto { max-width: 58ch; margin-top: 0.75rem; color: var(--ap-tinta-fraca); }
  .ap-diferenciais { display: grid; gap: 1.25rem; }
  .ap-diferenciais h3 { font-size: var(--ap-t-base); font-weight: 600; }
  .ap-diferenciais p { font-size: var(--ap-t-sm); color: var(--ap-tinta-fraca); margin-top: 0.2rem; }
  @media (min-width: 860px) {
    .ap-sobre { grid-template-columns: 1.2fr 1fr; align-items: start; }
    .ap-diferenciais { gap: 1.5rem; }
  }

  /* Depoimento: aspa serifada grande, nome e data. Sem estrela e sem avatar redondo — nome com
     data é prova; cinco estrelinhas com avatar genérico é enfeite de template. */
  .ap-depoimentos { display: grid; gap: 1rem;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr)); }
  .ap-depoimentos li { padding: 1.25rem; background: #fff; border: 1px solid var(--ap-linha);
    border-radius: var(--ap-raio); }
  .ap-depoimentos blockquote { margin: 0; font-family: var(--ap-fonte-titulo);
    font-size: var(--ap-t-md); line-height: 1.4; }
  .ap-depoimentos blockquote::before { content: '“'; color: var(--ap-marca-fundo);
    font-size: 1.6em; line-height: 0; vertical-align: -0.25em; margin-inline-end: 0.1em; }
  .ap-depoimento-quem { margin-top: 0.75rem; font-size: var(--ap-t-sm); color: var(--ap-tinta-fraca); }
  .ap-depoimento-quem b { color: var(--ap-tinta); }
}

/* ------------------------------------------------- as tres perguntas do topo */
@layer componentes {
  /* Uma pergunta por vez, lendo como FRASE e não como formulário. A referência é a barra
     segmentada do Airbnb: o primeiro passo é escolha entre opções, nunca campo em branco.
     Funciona sem JavaScript — cada grupo é um `<fieldset>` com radios reais. */
  .ap-perguntas { margin-top: 1.5rem; display: grid; gap: 1rem; max-width: 54rem; }
  /**
   * A legenda é RÓTULO, não título.
   *
   * Em Newsreader 22px havia **quatro vozes serifadas na primeira dobra** — o `h1` de 72px e as
   * três legendas — contra a regra da própria casa ("dois registros e nada no meio"). Em caixa
   * alta miúda ela some como voz e continua funcionando como pergunta, e o topo devolve altura:
   * no celular o botão "Ver imóveis" estava ABAIXO da dobra, ou seja, o único caminho para o
   * estoque exigia rolar na tela que traz 70% do tráfego.
   */
  .ap-pergunta > legend { font-family: var(--ap-fonte-texto); font-size: var(--ap-t-xs);
    text-transform: uppercase; letter-spacing: 0.1em; font-weight: 700;
    color: color-mix(in srgb, currentColor 80%, transparent);
    margin-bottom: 0.45rem; }

  /* Três colunas no desktop: as perguntas leem como UMA frase, que era a promessa do desenho —
     empilhadas, ocupavam 60% do topo. */
  @media (min-width: 60rem) {
    .ap-perguntas { grid-template-columns: repeat(3, minmax(0, auto)); align-items: start;
      gap: 1.25rem 2rem; max-width: none; }
    .ap-perguntas-acao { grid-column: 1 / -1; }
  }
  /* No celular, chips mais justos: são até 8 tipos, e cada fileira a mais empurra o botão. */
  @media (max-width: 30rem) {
    .ap-opcoes { gap: 0.35rem; }
    .ap-opcoes span { min-height: 40px; padding-inline: 0.75rem; }
    .ap-hero-in { padding-block: clamp(2rem, 5vh, 6rem); }
  }
  .ap-opcoes { display: flex; flex-wrap: wrap; gap: 0.5rem; }
  /* O chip inteiro é o alvo: o WCAG 2.2 pede que caiba um quadrado sólido de 24×24 alinhado aos
     eixos DENTRO do alvo — canto muito arredondado pode reprovar um alvo que "mede" 24. Daqui
     saem 44px de altura, com folga. */
  .ap-opcoes label { position: relative; }
  .ap-opcoes input { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
  .ap-opcoes span { display: inline-flex; align-items: center; gap: 0.4rem; min-height: 44px;
    padding-inline: 1rem; border-radius: 999px; font-size: var(--ap-t-sm);
    border: 1px solid color-mix(in srgb, currentColor 35%, transparent); cursor: pointer; }
  .ap-opcoes input:checked + span { background: var(--ap-marca-fundo);
    border-color: var(--ap-marca-fundo); color: var(--ap-marca-tinta); font-weight: 600; }
  .ap-opcoes input:focus-visible + span { outline: 2px solid currentColor; outline-offset: 2px; }
  .ap-opcoes span small { font-family: var(--ap-fonte-numero); font-size: 0.75em; opacity: 0.75; }
  .ap-perguntas-acao { display: flex; flex-wrap: wrap; gap: 0.75rem; align-items: center; }
  .ap-perguntas-nota { font-size: var(--ap-t-xs);
    color: color-mix(in srgb, currentColor 65%, transparent); margin: 0; }
}

/* --------------------------------------------- como se paga e simulador */
@layer componentes {
  .ap-pagamento { display: grid; gap: 0.75rem;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr)); }
  .ap-pagamento a { display: grid; gap: 0.35rem; padding: 1.1rem; background: #fff;
    border: 1px solid var(--ap-linha); border-radius: var(--ap-raio); text-decoration: none;
    block-size: 100%; align-content: start; }
  .ap-pagamento a:hover { border-color: var(--ap-marca-fundo); }
  .ap-pagamento svg { color: var(--ap-marca-texto); }
  .ap-pagamento h3 { font-size: var(--ap-t-base); font-weight: 600; }
  .ap-pagamento p { font-size: var(--ap-t-sm); color: var(--ap-tinta-fraca); }
  /* A contagem fica na base do cartão, em monoespaçada: é número, e número se compara em coluna.
     `margin-block-start: auto` empurra para baixo, então cartões de texto curto e longo alinham
     a contagem na mesma linha — sem isso a grade parece torta. */
  .ap-pagamento-n { margin-block-start: auto; padding-block-start: 0.5rem;
    font-family: var(--ap-fonte-numero); font-size: var(--ap-t-xs);
    color: var(--ap-marca-texto); text-transform: uppercase; letter-spacing: 0.04em; }
  .ap-pagamento-n b { font-size: var(--ap-t-sm); }
  /* Sem estoque: o mesmo lugar, em tom neutro — é convite, não oferta. */
  .ap-pagamento-sob { color: var(--ap-tinta-fraca); }

  /* O simulador é a única faixa escura do corpo: contraste de superfície marca que ali se
     decide algo, sem precisar de cor de acento nova. */
  /* A faixa escura é uma QUEBRA, não um banner: sangra a cor de ponta a ponta e mantém o texto
     na mesma coluna do resto. Contida em 1200px com raio, ela lia como caixa promocional. */
  .ap-simulador { background: var(--ap-escuro); color: var(--ap-escuro-tinta); margin-top: 1rem;
    max-width: none; border-radius: 0;
    padding-inline: max(var(--ap-gutter), calc((100% - var(--ap-largura)) / 2)); }
  .ap-simulador .ap-rotulo { color: color-mix(in srgb, var(--ap-escuro-tinta) 70%, transparent); }
  .ap-simulador-texto { max-width: 56ch; margin-block: 0.6rem 1.1rem;
    color: color-mix(in srgb, var(--ap-escuro-tinta) 82%, transparent); }
}

/* ------------------------------------------------- a equipe e a nota do Google */
@layer componentes {
  /* Foto redonda e grande o bastante para reconhecer uma pessoa. Proporção 1:1 travada: foto de
     perfil vem em tamanho qualquer, e sem isso a fila de rostos fica desalinhada. */
  .ap-equipe { display: grid; gap: 1rem;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 8.5rem), 1fr)); }
  .ap-equipe li { display: grid; justify-items: center; gap: 0.15rem; text-align: center; }
  .ap-equipe img { aspect-ratio: 1; inline-size: 6.5rem; block-size: auto; object-fit: cover;
    border-radius: 50%; background: var(--ap-papel-2); margin-bottom: 0.4rem; }
  .ap-equipe b { font-size: var(--ap-t-sm); }
  .ap-equipe-creci { font-family: var(--ap-fonte-numero); font-size: var(--ap-t-xs);
    color: var(--ap-tinta-fraca); }
  .ap-equipe-n { font-family: var(--ap-fonte-numero); font-size: var(--ap-t-xs);
    color: var(--ap-marca-texto); }

  .ap-avaliacao { background: var(--ap-papel-2); }
  .ap-avaliacao-in { display: grid; gap: 1.25rem; align-items: center; }
  .ap-avaliacao-nota { display: flex; align-items: center; gap: 0.6rem; }
  .ap-avaliacao-nota b { font-family: var(--ap-fonte-numero); font-size: var(--ap-t-xl);
    line-height: 1; }
  .ap-estrelas { display: inline-flex; gap: 0.1rem; }
  .ap-estrelas .cheia { color: var(--ap-marca-fundo); }
  .ap-estrelas .vazia { color: var(--ap-linha-campo); }
  .ap-avaliacao-texto { margin-block: 0.4rem 1rem; color: var(--ap-tinta-fraca);
    font-size: var(--ap-t-sm); max-width: 48ch; }
  .ap-avaliacao-texto b { font-family: var(--ap-fonte-numero); color: var(--ap-tinta); }
  @media (min-width: 680px) {
    .ap-avaliacao-in { grid-template-columns: auto 1fr; gap: 2.5rem; }
  }
}

/* ------------------------------------- o guia: tipos, tabela de preço e NAP */
/**
 * Os blocos de conteúdo que o site legado tem e esta home não tinha (24/09/2026).
 * A regra de desenho é a mesma do resto: dois registros de tipografia, número sempre em
 * monoespaçada, e nada de cor nova só para dar destaque.
 */
@layer componentes {
  /* O parágrafo de abertura do guia: medida de leitura curta, corpo um degrau acima do texto
     comum. É ele que um buscador de IA cita, então precisa ser lido como frase, não como legenda. */
  .ap-guia-abre { max-width: 62ch; font-size: var(--ap-t-md); line-height: 1.55;
    color: var(--ap-tinta); margin-block: 0 1.5rem; }
  .ap-guia-abre b { font-weight: 600; }

  .ap-guia-tipos { display: grid; gap: 0.75rem; list-style: none; padding: 0; margin: 0;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr)); }
  .ap-guia-tipos a { display: grid; gap: 0.25rem; align-content: start; block-size: 100%;
    padding: 1rem 1.1rem; background: #fff; border: 1px solid var(--ap-linha);
    border-radius: var(--ap-raio); text-decoration: none; color: inherit; }
  .ap-guia-tipos a:hover { border-color: var(--ap-marca-fundo); }
  .ap-guia-tipos h3 { font-family: var(--ap-fonte-titulo); font-size: var(--ap-t-md);
    font-weight: 500; margin: 0; }
  .ap-guia-n { font-family: var(--ap-fonte-numero); font-size: var(--ap-t-xs); margin: 0;
    color: var(--ap-marca-texto); }
  .ap-guia-faixa { font-size: var(--ap-t-sm); color: var(--ap-tinta-fraca); margin: 0; }

  .ap-guia-resumo { max-width: 68ch; margin-block: 1.25rem 0; font-size: var(--ap-t-base);
    line-height: 1.6; color: var(--ap-tinta-fraca); }
  .ap-guia-resumo b { color: var(--ap-tinta); font-weight: 600; }

  /**
   * A tabela.
   *
   * `overflow-x` com `tabindex="0"` e `role="region"`: uma área que rola precisa ser alcançável
   * pelo teclado, senão quem não usa mouse não chega nas colunas da direita — é falha de
   * acessibilidade, não detalhe. O rótulo vem do `aria-label` no HTML.
   *
   * `position: sticky` na primeira coluna mantém o nome do bairro visível enquanto se rola de
   * lado no celular: sem isso a pessoa vê quatro valores e não sabe de qual bairro são.
   */
  .ap-tabela-rolagem { overflow-x: auto; -webkit-overflow-scrolling: touch;
    border: 1px solid var(--ap-linha); border-radius: var(--ap-raio); background: #fff; }
  .ap-tabela-rolagem:focus-visible { outline: 2px solid var(--ap-marca-fundo); outline-offset: 2px; }
  .ap-tabela { inline-size: 100%; border-collapse: collapse; font-size: var(--ap-t-sm); }
  .ap-tabela caption { text-align: start; padding: 0.9rem 1rem 0.5rem;
    font-size: var(--ap-t-sm); color: var(--ap-tinta-fraca); }
  .ap-tabela-data { display: block; font-size: var(--ap-t-xs); margin-block-start: 0.2rem; }
  .ap-tabela th, .ap-tabela td { padding: 0.65rem 0.9rem; text-align: end;
    border-block-start: 1px solid var(--ap-linha); white-space: nowrap; }
  .ap-tabela thead th { font-size: var(--ap-t-xs); text-transform: uppercase;
    letter-spacing: 0.05em; color: var(--ap-tinta-fraca); font-weight: 600; }
  .ap-tabela td { font-family: var(--ap-fonte-numero); }
  .ap-tabela th[scope="row"] { text-align: start; font-weight: 500; position: sticky;
    inset-inline-start: 0; background: #fff; }
  .ap-tabela th[scope="row"] a { color: inherit; text-decoration: none;
    border-block-end: 1px solid var(--ap-marca-fio); }
  .ap-tabela th[scope="row"] a:hover { color: var(--ap-marca-texto); }
  .ap-tabela-vazio { color: var(--ap-tinta-fraca); }
  .ap-tabela tbody tr:hover td, .ap-tabela tbody tr:hover th { background: var(--ap-papel-2); }

  /**
   * NAP: nome, endereço e telefone.
   *
   * `<dl>` em duas colunas no desktop e empilhado no celular. O rótulo em caixa alta miúda é o
   * mesmo registro do `.ap-rotulo` das seções — não é um estilo novo, é o que já existe.
   */
  .ap-nap { margin-block: 1.5rem 0; display: grid; gap: 0.1rem 1.5rem;
    border-block-start: 1px solid var(--ap-linha); padding-block-start: 1.25rem; }
  .ap-nap dt { font-size: var(--ap-t-xs); text-transform: uppercase; letter-spacing: 0.06em;
    color: var(--ap-tinta-fraca); margin-block-start: 0.7rem; }
  .ap-nap dd { margin: 0; font-size: var(--ap-t-sm); line-height: 1.5; }
  .ap-nap dd a { color: var(--ap-marca-texto); }
  @media (min-width: 40rem) {
    /* Rótulo e valor lado a lado: lê-se como ficha, que é o que é. */
    .ap-nap { grid-template-columns: max-content 1fr; align-items: baseline; }
    .ap-nap dt { margin-block-start: 0.45rem; }
    .ap-nap dd { margin-block-start: 0.45rem; }
  }

  /* Grupos de atalho por eixo (tipo, forma de pagamento, bairro). */
  .ap-buscas-grupo { margin-block-end: 1.25rem; }
  .ap-buscas-grupo h3, .ap-buscas-titulo { font-family: var(--ap-fonte-texto);
    font-size: var(--ap-t-xs); text-transform: uppercase; letter-spacing: 0.06em;
    font-weight: 600; color: var(--ap-tinta-fraca); margin-block: 0 0.6rem; }
  .ap-buscas-titulo { margin-block-start: 1.25rem; }
}

/* ------------------------------------------- categorias com foto (home) */
@layer componentes {
  /**
   * Grade de cartões com foto. `auto-fit` + `minmax` em vez de media query por tamanho: o número
   * de colunas sai da largura disponível, o que faz a mesma regra servir de 390px a 1440px.
   *
   * O texto fica SOBRE a foto com um scrim (o mesmo do topo): sem o degradê, o nome da categoria
   * sobre uma foto clara some, e foto de imóvel não se escolhe pela luminosidade do céu.
   */
  .ap-categorias { display: grid; gap: 0.75rem; list-style: none; padding: 0; margin: 0;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr)); }
  .ap-categoria { position: relative; display: block; overflow: hidden; text-decoration: none;
    border-radius: var(--ap-raio); background: var(--ap-papel-2); color: #fff;
    aspect-ratio: 3 / 2; isolation: isolate; }
  .ap-categoria-foto { position: absolute; inset: 0; display: block; }
  .ap-categoria-foto img { inline-size: 100%; block-size: 100%; object-fit: cover; }
  /* Scrim: garante contraste do texto sem tocar na fotografia (ver a nota dos tokens). */
  .ap-categoria::after { content: ''; position: absolute; inset: 0; z-index: 1;
    background: var(--ap-scrim); }
  /* Sem foto (ou foto morta do servidor antigo): o cartão vira campo de cor da marca, nunca
     um retângulo cinza quebrado. */
  /* Sem foto (ou foto morta) — a classe vem do servidor, porque `:empty` deixou de valer quando
     o selo de marca passou a morar dentro desta mesma caixa. */
  .ap-categoria-foto.sem-foto {
    background: linear-gradient(160deg, var(--ap-marca-fundo), var(--ap-escuro)); }
  .ap-categoria-texto { position: relative; z-index: 2; display: grid; gap: 0.15rem;
    block-size: 100%; align-content: end; padding: 1rem; }
  .ap-categoria-texto b { font-family: var(--ap-fonte-titulo); font-size: var(--ap-t-md);
    font-weight: 500; line-height: 1.2; }
  .ap-categoria-texto small { font-size: var(--ap-t-sm); line-height: 1.35;
    color: rgb(255 255 255 / 0.88); }
  .ap-categoria-n { font-family: var(--ap-fonte-numero); font-size: var(--ap-t-xs);
    color: rgb(255 255 255 / 0.95); margin-block-start: 0.35rem; }
  /* O movimento é da IMAGEM, não do cartão: cartão que cresce empurra os vizinhos. */
  .ap-categoria img { transition: transform 0.4s ease; }
  .ap-categoria:hover img { transform: scale(1.04); }
  .ap-categoria:focus-visible { outline: 2px solid var(--ap-marca-fundo); outline-offset: 3px; }
}

@layer componentes {
  /* Selos de programa (MCMV, CAIXA) no alto do cartão de categoria. Pastilha branca porque as duas
     marcas são coloridas e desenhadas para fundo claro — sobre foto elas sumiriam. */
  .ap-categoria-marcas { position: absolute; z-index: 2; inset-block-start: 0.6rem;
    inset-inline-start: 0.6rem; display: flex; gap: 0.35rem; }
  .ap-categoria-marcas img { block-size: 1.5rem; inline-size: auto; padding: 0.25rem 0.4rem;
    background: #fff; border-radius: 0.375rem; object-fit: contain; }
}

@layer componentes {
  /* Bairro com foto morta: campo de cor da marca em vez do nome invisível sobre papel. */
  .ap-bairros a.sem-foto {
    background: linear-gradient(160deg, var(--ap-marca-fundo), var(--ap-escuro));
  }
}
