/* ==========================================================================
   DESIGN TOKENS
   Escala de espaçamento, cor, raio e tipografia — troque os valores de marca
   (--color-brand, --font-primary) para adaptar a um novo produto.
   ========================================================================== */
:root {
  /* Brand colors — troque aqui para rebrandear o site inteiro */
  --color-brand: #514fee;
  --color-brand-hover: #302eea;
  --color-ink: #070628;
  --color-paper: #f7f7ff;

  /* Tints derivados via color-mix (sem precisar de 10 variáveis hex fixas) */
  --brand-5: color-mix(in srgb, var(--color-brand) 5%, transparent);
  --brand-10: color-mix(in srgb, var(--color-brand) 10%, transparent);
  --brand-20: color-mix(in srgb, var(--color-brand) 20%, transparent);
  --brand-70: color-mix(in srgb, var(--color-brand) 70%, transparent);
  --ink-5: color-mix(in srgb, var(--color-ink) 5%, transparent);
  --ink-10: color-mix(in srgb, var(--color-ink) 10%, transparent);
  --ink-20: color-mix(in srgb, var(--color-ink) 20%, transparent);
  --ink-40: color-mix(in srgb, var(--color-ink) 40%, transparent);
  --ink-60: color-mix(in srgb, var(--color-ink) 60%, transparent);
  --ink-70: color-mix(in srgb, var(--color-ink) 70%, transparent);

  /* Texto e superfícies semânticas */
  --text-primary: var(--color-ink);
  --text-secondary: var(--ink-70);
  --text-tertiary: var(--ink-40);
  --text-inverse: var(--color-paper);
  --bg-page: var(--color-paper);
  --bg-card: #ffffff;
  --bg-subtle: #f2f2fb;
  --bg-inverse: var(--color-ink);
  --border-subtle: var(--ink-5);
  --border-default: var(--ink-20);

  /* Tipografia */
  --font-primary: "General Sans", "Inter", -apple-system, sans-serif;
  --font-secondary: "Inter", -apple-system, sans-serif;

  --text-2xs: 0.75rem;
  --text-xs: 0.875rem;
  --text-sm: 1rem;
  --text-md: 1.125rem;
  --text-lg: 1.25rem;
  --text-xl: 1.5rem;
  --text-2xl: 2rem;
  --text-3xl: 2.5rem;
  --text-4xl: 3rem;
  --text-5xl: 4.25rem;

  /* Espaçamento (escala em rem, alinhada à referência) */
  --space-4xs: 0.375rem;
  --space-3xs: 0.5rem;
  --space-2xs: 0.75rem;
  --space-xs: 1rem;
  --space-sm: 1.5rem;
  --space-m: 2rem;
  --space-l: 3rem;
  --space-xl: 4rem;
  --space-2xl: 6rem;
  --space-3xl: 8rem;
  --space-4xl: 10rem;

  /* Raios */
  --radius-xs: 16px;
  --radius-sm: 20px;
  --radius-m: 24px;
  --radius-l: 32px;
  --radius-xl: 40px;
  --radius-round: 9999px;

  /* Layout */
  --container-max: 1280px;
  --container-gutter: 6rem;
  --nav-height: 78px;
  --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
}

@media screen and (max-width: 991px) {
  :root { --container-gutter: 2.5rem; }
}
@media screen and (max-width: 479px) {
  :root { --container-gutter: 1.25rem; }
}

/* ==========================================================================
   RESET
   ========================================================================== */
*, *::before, *::after { box-sizing: border-box; }
html { height: 100%; scroll-behavior: smooth; }
body {
  margin: 0;
  min-height: 100%;
  background: var(--bg-page);
  color: var(--text-primary);
  font-family: var(--font-primary);
  font-size: var(--text-sm);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
ul { list-style: none; margin: 0; padding: 0; }
h1, h2, h3, h4, h5, h6, p { margin: 0; }
input, textarea { font: inherit; }
svg { display: block; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

/* ==========================================================================
   LAYOUT HELPERS
   ========================================================================== */
.layout-gutter { padding-left: var(--container-gutter); padding-right: var(--container-gutter); }
.layout-container { max-width: var(--container-max); margin: 0 auto; }
.section { padding-top: var(--space-3xl); padding-bottom: var(--space-3xl); }
.section--tight { padding-top: var(--space-2xl); padding-bottom: var(--space-2xl); }
@media screen and (max-width: 767px) {
  /* 40px em cada lado (não colapsa — são paddings, não margins) soma
     exatamente 80px de espaço visível entre duas sessões `.section`
     adjacentes, pedido explícito do usuário ("o espaço de uma sessão
     pra outra deve ser de 80px apenas"). 40px não bate com nenhum token
     da escala (--space-m=32px, --space-l=48px) — valor direto aqui de
     propósito, não é engano. Cobre a maioria das transições do site
     (Sobre↔Problema↔Soluções↔Como funciona↔Planilha vs Pruxor↔
     Diferenciais↔Depoimentos↔Planos↔FAQ, todas `.section`); a hero (que
     tem padding próprio, não usa `.section`) e o CTA final
     (`.full-width-feature`, também sem `.section` — o padding dele é
     do CARD em si, ajustado à parte numa rodada anterior) ficam de fora
     dessa conta específica. */
  .section { padding-top: 40px; padding-bottom: 40px; }
}

.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  padding: 0.35em 0.9em;
  border-radius: var(--radius-round);
  background: var(--brand-10);
  color: var(--color-brand);
  font-family: var(--font-secondary);
  font-size: var(--text-xs);
  font-weight: 500;
}
/* Variante para fundo escuro/de marca — var(--brand-10) some contra esses
   fundos, então usa branco translúcido em vez de tinta de marca. */
.badge--inverse { background: rgba(255, 255, 255, 0.12); color: var(--text-inverse); }

.eyebrow {
  font-family: var(--font-secondary);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-brand);
}

/* Section header pattern: eyebrow + heading + paragraph */
.section-header {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
  max-width: 640px;
}
.section-header--center { align-items: center; text-align: center; margin-left: auto; margin-right: auto; }
.section-header__heading { font-size: var(--text-3xl); font-weight: 500; line-height: 1.15; letter-spacing: -0.01em; text-wrap: balance; }
.section-header__paragraph { font-size: var(--text-md); color: var(--text-secondary); text-wrap: balance; }
/* Fonte um pouco menor + linhas mais próximas no mobile (pedido explícito
   do usuário, rodada de ajustes mobile de 2026-08-22, olhando a sessão
   "Problema") — `.section-header__heading` é COMPARTILHADA por praticamente
   toda sessão do site (Problema, Como funciona, Planilha vs Pruxor,
   Diferenciais, Depoimentos, Planos, FAQ etc.), então o pedido explícito
   do usuário de propagar o ajuste "pra todas as sessões que usam essa
   mesma fonte" já é satisfeito de graça por editar a classe compartilhada
   aqui, em vez de uma classe específica da sessão "Problema"
   (`.problem__header`, que só controla margin-bottom). `--text-2xl`
   (32px, um degrau abaixo do `--text-3xl` de 40px) segue o mesmo padrão já
   usado pro `<h1>` da hero no mobile (ver regra de `.hero__heading` em
   ≤767px) — mesma lógica de "um degrau menor no mobile", agora estendida
   pra esse heading compartilhado. `line-height` de 1.15 pra 1.1 (mais
   apertado, mas não tanto quanto o 1.05 da hero — esse heading aqui
   frequentemente quebra em 3 linhas de frase corrida, não só 2-3 palavras
   curtas, então um pouco mais de respiro entre linhas evita que
   ascendentes/descendentes de linhas adjacentes quase se toquem). */
@media screen and (max-width: 767px) {
  .section-header__heading { font-size: var(--text-2xl); line-height: 1.1; }
}

/* Destaque de trecho dentro de um heading (mesmo padrão do site de
   referência: um <span> extra dentro do próprio h1/h2). Duas variantes
   porque a cor de marca "some" em cima de fundo da própria cor de marca
   (ex: a faixa da CTA) — nesse caso usa a variante clara. */
.text-accent { color: var(--color-brand); }
.text-accent-inverse { color: color-mix(in srgb, white 55%, var(--color-brand) 45%); }

/* ==========================================================================
   BUTTONS
   ========================================================================== */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5em;
  padding: 0.85em 1.5em;
  border-radius: var(--radius-round);
  font-family: var(--font-secondary);
  font-size: var(--text-xs);
  font-weight: 500;
  white-space: nowrap;
  transition: background-color 0.2s var(--ease-out-expo), color 0.2s var(--ease-out-expo), border-color 0.2s var(--ease-out-expo);
}
.btn--primary { background: var(--color-brand); color: var(--text-inverse); }
.btn--primary:hover { background: var(--color-brand-hover); }
.btn--secondary { background: #fff; color: var(--color-brand); border: 1px solid var(--border-default); }
.btn--secondary:hover { background: #f5f5f5; }
.btn--tertiary { background: var(--ink-5); color: var(--text-secondary); }
.btn--tertiary:hover { background: var(--ink-10); color: var(--text-primary); }
.btn--on-dark { background: #fff; color: var(--color-ink); }
/* Bug real: usava `var(--brand-10)` (roxo com só 10% de opacidade) — sobre
   o fundo escuro em que este botão sempre aparece (`.full-width-feature`),
   isso deixava o botão quase transparente/apagado, revelando o fundo
   escuro por trás e tornando o texto (`color: var(--color-ink)`, escuro)
   praticamente ilegível (bug real, reportado com print). Trocado por um
   tom opaco só um pouco mais escuro que o branco base — continua claro o
   bastante pro texto escuro manter ótimo contraste, mas dá um feedback de
   hover de verdade, sem depender de transparência sobre um fundo variável. */
.btn--on-dark:hover { background: color-mix(in srgb, var(--color-ink) 20%, white); }
.btn--outline-inverse { background: transparent; color: var(--text-inverse); border: 1px solid rgba(255, 255, 255, 0.35); }
.btn--outline-inverse:hover { background: rgba(255, 255, 255, 0.1); }
.btn svg { width: 1em; height: 1em; }

/* ==========================================================================
   HEADER / NAV
   ========================================================================== */
.site-header {
  position: sticky;
  top: 0;
  z-index: 30;
  transition: padding-top 0.4s var(--ease-out-expo);
}
/* padding (não margin) de propósito: `.site-header__bar` é o primeiro
   filho de `.site-header`, que não tem padding/borda própria — a margem
   superior do filho colapsaria com a do pai (margin collapsing) e, com
   `position: sticky`, esse colapso faz a margem "sumir" visualmente (a
   pílula continua grudada no topo mesmo com margin-top definido). Padding
   no elemento sticky não colapsa, então garante o respiro de verdade. */
.site-header.is-scrolled {
  padding-top: var(--space-sm);
}
/* backdrop-filter vive num wrapper separado: aplicado direto no .site-header
   ele criaria um containing block para descendentes position:fixed (como o
   menu mobile), prendendo-o à altura do header em vez de cobrir a tela. */
.site-header__bar {
  /* position+z-index explícitos: sem isso o botão de hambúrguer fica
     embaixo do overlay do menu mobile (que tem z-index:20) e vira
     impossível de clicar de novo para fechar o menu. */
  position: relative;
  z-index: 25;
  margin: 0 auto;
  max-width: 100%;
  background: rgba(247, 247, 255, 0.85);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border-subtle);
  border-radius: 0;
  box-shadow: none;
  transition:
    margin 0.4s var(--ease-out-expo),
    max-width 0.4s var(--ease-out-expo),
    border-radius 0.4s var(--ease-out-expo),
    box-shadow 0.4s var(--ease-out-expo),
    background-color 0.4s ease,
    border-color 0.4s ease;
}
/* Sobre a hero (topo do index, antes de rolar) a navbar fica bem mais
   transparente pra deixar o degradê aparecer por trás — pedido explícito
   do usuário. `.has-hero` é marcada via JS (initHeaderScrollState) só
   quando existe `.hero` na página — hoje só index.html tem hero escuro.
   Exclui `body.nav-mobile-open`: com o menu mobile aberto, o overlay
   claro e opaco (`.nav__list--mobile`) fica entre a barra e a hero,
   então o "fundo" que a transparência revelaria ali é o próprio overlay
   claro, não o degradê — manter o texto branco nesse caso o deixaria
   ilegível (claro sobre claro). */
body:not(.nav-mobile-open) .site-header.has-hero:not(.is-scrolled) .site-header__bar {
  background: rgba(255, 255, 255, 0.14);
  border-bottom-color: rgba(255, 255, 255, 0.16);
}
/* Ao rolar, a navbar "encolhe" pra uma pílula flutuante, inset e
   arredondada, com fundo opaco o bastante pra continuar legível sobre
   qualquer conteúdo por trás (inclusive a própria hero escura) — por
   isso não herda a transparência do estado `.has-hero`. */
.site-header.is-scrolled .site-header__bar {
  margin: 0 auto;
  max-width: min(calc(var(--container-max) + 2rem), calc(100% - 2 * var(--space-sm)));
  background: rgba(247, 247, 255, 0.88);
  border-radius: var(--radius-round);
  border-bottom-color: transparent;
  box-shadow: 0 4px 12px rgba(7, 6, 40, 0.05);
}
.nav__container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-m);
  height: var(--nav-height);
  transition: height 0.4s var(--ease-out-expo);
}
.site-header.is-scrolled .nav__container { height: calc(var(--nav-height) - 18px); }

.nav__logo { display: flex; align-items: center; }
/* Logo real (2026-08-25) — antes era só um quadradinho de cor de marca
   (`.nav__logo-mark`) + o texto "Pruxor" ao lado; agora é a imagem do
   lockup (ícone + "PRUXOR"), recortada de `assets/Imagens-logo/
   logo-sem-fundo-fonte-branca.png`/`-preto.png` (removida a tag-line
   "Sistema de gestão..." do arquivo original — não cabe/não faz sentido
   numa navbar compacta). Altura fixa, largura automática (a imagem já
   tem a proporção certa do lockup). */
.nav__logo-img { height: 40px; width: auto; display: block; }
/* Duas versões (branca/preta) ficam as duas no DOM — trocar a COR de uma
   imagem raster via CSS não é possível como era com o texto/mark antigo
   (`color`), então a troca vira mostrar/esconder uma ou outra via
   `display`, no MESMO escopo/estado já usado pro texto claro vs escuro
   do menu (ver bloco de `.nav__link` logo abaixo) — navbar transparente
   sobre a hero (não rolada, menu mobile fechado) usa a versão branca;
   qualquer outro estado (rolada = pílula clara, ou menu mobile aberto)
   usa a preta. */
.nav__logo-img--white { display: none; }
.nav__logo-img--black { display: block; }

.nav__list { display: flex; align-items: center; gap: var(--space-sm); }
.nav__link {
  font-family: var(--font-secondary);
  font-size: var(--text-xs);
  font-weight: 500;
  color: var(--text-secondary);
  padding: 0.5em 0;
  transition: color 0.15s ease;
}
.nav__link:hover { color: var(--text-primary); }
/* Texto claro enquanto a navbar flutua transparente sobre a hero escura;
   volta ao texto escuro padrão assim que vira pílula (`.is-scrolled`),
   já que a partir daí o fundo da própria pílula garante contraste.
   Restrito a `.site-header__bar` (a barra desktop) de propósito: o menu
   mobile (`.nav__list--mobile`) também tem `.nav__link` mas é um irmão
   fora da barra, com fundo sempre claro — se a regra alcançasse ele,
   o texto claro ficaria ilegível (claro sobre claro) com o menu aberto. */
body:not(.nav-mobile-open) .site-header.has-hero:not(.is-scrolled) .site-header__bar .nav__link,
body:not(.nav-mobile-open) .site-header.has-hero:not(.is-scrolled) .site-header__bar .nav__hamburger-button {
  color: var(--text-inverse);
}
body:not(.nav-mobile-open) .site-header.has-hero:not(.is-scrolled) .site-header__bar .nav__link:hover { color: rgba(255, 255, 255, 0.7); }
/* Mesmo escopo/estado da regra de texto claro acima, aplicado à troca de
   versão do logo (branca em vez de preta) — ver comentário em
   `.nav__logo-img--white/--black`. */
body:not(.nav-mobile-open) .site-header.has-hero:not(.is-scrolled) .site-header__bar .nav__logo-img--white { display: block; }
body:not(.nav-mobile-open) .site-header.has-hero:not(.is-scrolled) .site-header__bar .nav__logo-img--black { display: none; }

.nav__actions { display: flex; align-items: center; gap: var(--space-2xs); }
.nav__hamburger-button { display: none; padding: 0.4em; transition: color 0.3s ease; }
.nav__hamburger-button svg { width: 22px; height: 22px; }

/* Menu mobile: overlay de tela cheia com os mesmos links âncora do desktop.
   Página única — sem submenus, cada link rola até uma seção desta página. */
.nav__list--mobile {
  position: fixed;
  inset: 0;
  /* z-index abaixo do .site-header (30) de propósito: o cabeçalho real
     fica por cima cobrindo o topo do overlay, então o conteúdo só precisa
     de padding-top para não ficar escondido atrás dele. */
  z-index: 20;
  background: var(--bg-page);
  padding: calc(var(--nav-height) + var(--space-m)) var(--container-gutter) var(--space-m);
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  transform: translateX(100%);
  transition: transform 0.3s var(--ease-out-expo);
  overflow-y: auto;
}
body.nav-mobile-open .nav__list--mobile { transform: translateX(0); }
body.nav-mobile-open { overflow: hidden; }
.nav__list--mobile .nav__link { font-size: var(--text-md); color: var(--text-primary); padding: 0.6em 0; border-bottom: 1px solid var(--border-subtle); }
.nav__actions--mobile { display: flex; flex-direction: column; gap: var(--space-2xs); padding-top: var(--space-xs); }

@media screen and (max-width: 991px) {
  .nav__list:not(.nav__list--mobile) { display: none; }
  /* Bug real: só `.btn--secondary` ("Entrar") escondia — `.btn--primary`
     ("Solicitar demonstração") continuava visível na barra ao lado do
     hambúrguer, e a largura combinada de logo + botão + hambúrguer
     estourava a tela em telas estreitas (ex: iPhone XR, 414px),
     empurrando o hambúrguer pra fora e causando scroll horizontal na
     página inteira. Nesta faixa, o header deve mostrar só logo +
     hambúrguer — as duas ações (Entrar/Solicitar demonstração) já
     existem dentro do overlay mobile (`.nav__actions--mobile`, seletor
     diferente, não afetado por esta regra). */
  .nav__actions .btn--secondary,
  .nav__actions .btn--primary { display: none; }
  .nav__hamburger-button { display: inline-flex; }
}

/* ==========================================================================
   HERO
   Fundo em gradiente escuro (ink → marca) com duas camadas decorativas
   por cima: uma textura de grade fixa e sutil (linhas mais claras que o
   próprio gradiente, formando quadrados) e um "holofote" de pontinhos que
   só aparece dentro de um raio ao redor do mouse — ver initHeroSpotlight
   em js/main.js. As duas camadas são puramente visuais (aria-hidden) e
   não interferem no conteúdo, que fica numa camada acima (z-index).
   ========================================================================== */
.hero {
  position: relative;
  overflow: hidden;
  /* a hero "sobe" por baixo do header (margin negativa = altura da navbar,
     compensada de volta no padding) porque a navbar agora é transparente
     no topo — sem essa sobreposição, ela flutuaria sobre o fundo claro da
     página (antes da hero começar) em vez do degradê escuro, e o texto
     claro do menu ficaria ilegível (claro sobre quase-branco). */
  margin-top: calc(-1 * var(--nav-height));
  padding-top: calc(var(--space-2xl) + var(--nav-height));
  padding-bottom: var(--space-2xl);
  /* 6 paradas em vez de um platô sólido: a cor vai clareando o tempo todo,
     sem nenhum trecho "segurando" a mesma cor — é o platô (marca parada de
     40% a 80%) que criava a mudança brusca no final, porque o degradê
     ficava sem fazer nada e então precisava clarear tudo de uma vez nos
     últimos 20%. Aqui cada trecho já entrega um pouco mais de luz que o
     anterior, then acelera gradualmente perto do fim — lê como uma curva
     contínua, igual à referência, em vez de um degrau. */
  background: linear-gradient(
    180deg,
    var(--color-ink) 0%,
    var(--color-brand) 28%,
    color-mix(in srgb, var(--color-brand) 78%, white) 52%,
    color-mix(in srgb, var(--color-brand) 45%, white) 74%,
    color-mix(in srgb, var(--color-brand) 18%, white) 90%,
    var(--bg-page) 100%
  );
  color: var(--text-inverse);
}
.hero__texture {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.06) 0 1px, transparent 1px 56px),
    repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.06) 0 1px, transparent 1px 56px);
  /* a própria textura precisa sumir na faixa branca do fundo, senão as
     linhas claras aparecem por cima do branco em vez de se fundir */
  -webkit-mask-image: linear-gradient(180deg, black 0%, black 68%, transparent 96%);
  mask-image: linear-gradient(180deg, black 0%, black 68%, transparent 96%);
}
.hero__spotlight {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.4s ease;
  background-image: radial-gradient(rgba(255, 255, 255, 0.9) 1px, transparent 1px);
  background-size: 22px 22px;
  /* a máscara combina o "holofote" (círculo ao redor do mouse) com um
     fade vertical (some na faixa branca do fundo) — e o filtro SVG
     (definido no <body>, ver #hero-wave) distorce essa máscara com um
     ruído animado, pra parecer água ondulando em vez de um círculo
     estático seguindo o cursor. */
  -webkit-mask-image:
    radial-gradient(circle 240px at var(--spot-x, 50%) var(--spot-y, 50%), black 0%, transparent 100%),
    linear-gradient(180deg, black 0%, black 68%, transparent 96%);
  -webkit-mask-composite: source-in;
  mask-image:
    radial-gradient(circle 240px at var(--spot-x, 50%) var(--spot-y, 50%), black 0%, transparent 100%),
    linear-gradient(180deg, black 0%, black 68%, transparent 96%);
  mask-composite: intersect;
  filter: url(#hero-wave);
}
.hero.is-spotlight-active .hero__spotlight { opacity: 1; }

.hero__grid { position: relative; z-index: 1; display: flex; justify-content: center; }
.hero__content { display: flex; flex-direction: column; align-items: center; max-width: 60rem; text-align: center; }
.hero__eyebrow { margin-bottom: var(--space-sm); }
.breadcrumbs { font-family: var(--font-secondary); font-size: var(--text-2xs); color: rgba(247, 247, 255, 0.55); margin-bottom: var(--space-xs); }
/* text-shadow sutil em cima do texto claro da hero — o degradê de fundo
   vai clareando continuamente (ver bloco .hero acima), então dependendo
   de onde o texto cai na altura da hero, o contraste com o texto claro
   podia ficar fraco (feedback direto do usuário, com print comparando).
   A sombra escura e suave garante leitura mesmo nos trechos mais claros
   do degradê, sem precisar escurecer o degradê em si de novo. */
.hero__heading { font-size: var(--text-5xl); font-weight: 500; line-height: 1.05; letter-spacing: -0.02em; margin-bottom: var(--space-xs); color: var(--text-inverse); text-wrap: balance; text-shadow: 0 2px 20px rgba(7, 6, 40, 0.35); }
/* "no caos." (span .text-accent-inverse dentro do heading) tem contraste
   próprio reforçado além da sombra: a versão padrão dessa classe
   (usada também no CTA, sobre fundo sólido) é uma mistura com a cor de
   marca, que fica clara demais perto do trecho mais claro do degradê da
   hero — aqui fica quase branco puro, só nesse contexto. */
.hero__heading .text-accent-inverse { color: rgba(247, 247, 255, 0.92); }
.hero__paragraph { font-size: var(--text-md); color: rgba(247, 247, 255, 0.85); margin-bottom: var(--space-sm); max-width: 46rem; text-wrap: balance; text-shadow: 0 1px 16px rgba(7, 6, 40, 0.3); }
.hero__paragraph strong { color: var(--text-inverse); }
.hero__microcopy { margin-top: var(--space-2xs); font-family: var(--font-secondary); font-size: var(--text-2xs); color: var(--color-brand); text-shadow: 0 1px 12px rgba(7, 6, 40, 0.35); }

@media screen and (max-width: 991px) {
  .hero__heading { font-size: var(--text-3xl); }
}

@media screen and (max-width: 767px) {
  /* Hero ocupando 80% da altura da viewport no mobile (pedido explícito
     do usuário, rodada de ajustes mobile de 2026-08-22) — `min-height`
     (não `height`) pra garantir que ela cresça além de 80vh se o
     conteúdo algum dia precisar de mais espaço, em vez de cortar/gerar
     overflow. `display:flex` + `justify-content:center` centralizam
     `.hero__grid` (único filho em fluxo normal — `.hero__texture`/
     `.hero__spotlight` são `position:absolute`, não entram no cálculo)
     verticalmente dentro desse espaço, já descontando o padding (o
     projeto usa `box-sizing:border-box` global) — sem isso, sobraria um
     vão vazio embaixo do conteúdo em vez de centralizar. */
  .hero {
    padding-top: calc(var(--space-l) + var(--nav-height));
    padding-bottom: var(--space-l);
    min-height: 80vh;
    display: flex;
    flex-direction: column;
    justify-content: center;
  }
  .hero__heading { font-size: var(--text-2xl); }
}

/* ==========================================================================
   PROBLEM / CARDS GRID
   ========================================================================== */
.problem__header { margin-bottom: var(--space-l); }
/* Headline + subheadline centralizados no mobile — pedido explícito do
   usuário, extensão do mesmo tratamento já aplicado em Soluções/Como
   funciona/Planilha vs Pruxor/Diferenciais/FAQ (ficou de fora daquela
   primeira rodada, pedido separado depois). */
@media screen and (max-width: 767px) {
  .problem__header { text-align: center; }
}
.problem__cards { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-sm); }
.problem__closing { max-width: 640px; margin: var(--space-l) auto 0; text-align: center; }
.problem__closing-text { font-size: var(--text-md); color: var(--text-secondary); margin-bottom: var(--space-sm); text-wrap: balance; }
.card {
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-m);
  padding: var(--space-m);
  transition: transform 0.35s var(--ease-out-expo), border-color 0.35s ease, box-shadow 0.35s var(--ease-out-expo);
}
/* Zoom + lift + borda "acendendo" ao passar o mouse — mesmo tratamento em
   qualquer lugar que reusa .card (Problema, Diferenciais, Depoimentos),
   pedido explícito do usuário pra dar mais
   sensação de interatividade ao site (reforçado numa 2ª rodada por pedir
   um efeito mais perceptível — a 1ª versão, scale(1.02) sem lift, ficou
   sutil demais). Seletor duplicado (`.card.card`) de propósito:
   `[data-reveal].is-visible` também define `transform` com a mesma
   especificidade (0,2,0) e vem depois no arquivo, então sem esse reforço
   o `translateY(0)` do reveal vence e o zoom nunca aparece de verdade (só
   a borda/sombra, que são propriedades diferentes, mudavam). */
.card.card:hover {
  transform: translateY(-6px) scale(1.045);
  border-color: color-mix(in srgb, var(--color-brand) 45%, var(--border-subtle));
  box-shadow: 0 18px 32px rgba(7, 6, 40, 0.1);
}
.card__heading { font-size: var(--text-md); font-weight: 600; margin-bottom: var(--space-4xs); text-wrap: balance; }
.card__paragraph { color: var(--text-secondary); font-size: var(--text-xs); }

/* ==========================================================================
   CARD "VIVID" — variante escura com brilho de marca, usada nos cards de
   destaque (Problema, Diferenciais). Reaproveita a mesma linguagem visual
   da hero (fundo escuro, textura de grade, brilho radial na cor da marca)
   em vez de copiar as cores arco-íris do print de referência — assim o
   fundo "sintoniza" com o resto do site em vez de introduzir uma paleta
   nova. Cada card varia a posição do brilho via --glow-x/--glow-y (ver
   regras nth-child logo abaixo) pra não ficarem todos idênticos, sem sair
   da cor de marca única do produto.
   ========================================================================== */
.card--vivid {
  position: relative;
  overflow: hidden;
  background: var(--color-ink);
  border-color: rgba(255, 255, 255, 0.08);
  color: var(--text-inverse);
  --glow-x: 20%;
  --glow-y: 0%;
}
.card--vivid::before,
.card--vivid::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.card--vivid::before {
  background: radial-gradient(circle at var(--glow-x) var(--glow-y), color-mix(in srgb, var(--color-brand) 65%, transparent) 0%, transparent 62%);
  opacity: 0.85;
  transition: opacity 0.35s ease, transform 0.35s var(--ease-out-expo);
}
/* mesma textura de grade sutil da hero, só visível dentro do halo do
   brilho (mask), pra reforçar a mesma identidade visual num componente
   diferente. */
.card--vivid::after {
  background-image:
    repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.05) 0 1px, transparent 1px 26px),
    repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.05) 0 1px, transparent 1px 26px);
  -webkit-mask-image: radial-gradient(circle at var(--glow-x) var(--glow-y), black 0%, transparent 68%);
  mask-image: radial-gradient(circle at var(--glow-x) var(--glow-y), black 0%, transparent 68%);
}
/* reforçado numa 2ª rodada — o brilho/borda da 1ª versão foi apontado
   como sutil demais; aqui o anel de borda fica mais grosso e o halo por
   trás cresce mais (1.15 → 1.3) e ganha mais opacidade/alcance. Seletor
   duplicado (`.card--vivid.card--vivid`) de propósito, mesmo motivo do
   `.card.card:hover` lá em cima: sem esse reforço de especificidade
   (0,3,0, empatando e vencendo por vir depois no arquivo), o box-shadow
   genérico de `.card.card:hover` (também 0,3,0) sobrescrevia o brilho
   colorido aqui — os cards escuros ficavam só com a sombra cinza neutra
   no hover, sem o glow de marca. */
.card--vivid.card--vivid:hover {
  border-color: color-mix(in srgb, var(--color-brand) 80%, white);
  box-shadow:
    0 0 0 1.5px color-mix(in srgb, var(--color-brand) 70%, white),
    0 0 24px color-mix(in srgb, var(--color-brand) 32%, transparent),
    0 16px 30px rgba(0, 0, 0, 0.35);
}
.card--vivid:hover::before { opacity: 1; transform: scale(1.3); }
.card--vivid .card__icon,
.card--vivid .card__heading,
.card--vivid .card__paragraph,
.card--vivid .card__sparkle { position: relative; z-index: 1; }
/* .card__spotlight já é position:absolute (definido mais abaixo); só
   precisa entrar na mesma camada de z-index pra ficar acima do brilho
   (::before) e da textura (::after), sem herdar position:relative.
   `.compare` também usa (reaproveita o mesmo elemento/efeito, ver bullet
   do holofote em "Planilha vs Pruxor"). */
.card--vivid .card__spotlight, .compare .card__spotlight { z-index: 1; }
.card--vivid .card__paragraph { color: rgba(247, 247, 255, 0.7); }

/* Holofote de pontinhos que segue o mouse dentro do card — mesmíssimo
   efeito da hero (mesma máscara radial + o filtro SVG #hero-wave, já
   definido uma vez no <body> e reaproveitado aqui), só em escala menor.
   Ver initCardSpotlight em js/main.js (atualiza --spot-x/--spot-y por
   card, igual initHeroSpotlight faz pra hero). */
.card__spotlight {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.4s ease;
  background-image: radial-gradient(rgba(255, 255, 255, 0.9) 1px, transparent 1px);
  background-size: 14px 14px;
  -webkit-mask-image: radial-gradient(circle 110px at var(--spot-x, 50%) var(--spot-y, 50%), black 0%, transparent 100%);
  mask-image: radial-gradient(circle 110px at var(--spot-x, 50%) var(--spot-y, 50%), black 0%, transparent 100%);
  filter: url(#hero-wave);
}
.card--vivid.is-spotlight-active .card__spotlight,
.compare.is-spotlight-active .card__spotlight { opacity: 1; }

.card__icon {
  width: 44px;
  height: 44px;
  border-radius: 14px;
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.16);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: var(--space-xs);
  color: var(--text-inverse);
  /* animado o tempo todo (não só no hover), pedido explícito do usuário —
     flutua suavemente e o brilho ao redor pulsa, com atraso escalonado
     por card (nth-child mais abaixo) pra não baterem todos em sincronia. */
  animation: card-icon-float 3.6s ease-in-out infinite, card-icon-glow 3.6s ease-in-out infinite;
  transition: transform 0.3s var(--ease-out-expo), background-color 0.3s ease;
}
.card__icon svg { width: 20px; height: 20px; }
.card--vivid:hover .card__icon {
  background: color-mix(in srgb, var(--color-brand) 30%, rgba(255, 255, 255, 0.08));
  border-color: color-mix(in srgb, var(--color-brand) 60%, white);
}

@keyframes card-icon-float {
  0%, 100% { transform: translateY(0) scale(1); }
  50% { transform: translateY(-5px) scale(1.06); }
}
@keyframes card-icon-glow {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--color-brand) 45%, transparent); }
  50% { box-shadow: 0 0 14px 2px color-mix(in srgb, var(--color-brand) 55%, transparent); }
}

/* Sparkles decorativos (aria-hidden) — 4 pontas, com leve "piscar"
   contínuo pra reforçar a sensação de mais animação pedida pelo usuário,
   sem chamar mais atenção que o conteúdo do card. */
.card__sparkle {
  position: absolute;
  color: rgba(255, 255, 255, 0.55);
  animation: card-sparkle-twinkle 3.2s ease-in-out infinite;
}
.card__sparkle--1 { top: 18px; right: 22px; width: 15px; height: 15px; }
.card__sparkle--2 { top: 46px; right: 46px; width: 8px; height: 8px; color: color-mix(in srgb, var(--color-brand) 40%, white); animation-delay: 1.1s; }

@keyframes card-sparkle-twinkle {
  0%, 100% { opacity: 0.3; transform: scale(0.8); }
  50% { opacity: 0.9; transform: scale(1.1); }
}

/* Posição do brilho e atraso do ícone em ciclos de 4/5 via nth-child, em
   vez de regras fixas por seção — assim qualquer fileira de .card--vivid
   (Problema, Diferenciais, Pilares, Soluções, em qualquer página) ganha
   variedade automaticamente, sem precisar de uma regra nova pra cada
   card de cada seção nova. */
.card--vivid:nth-child(4n+1) { --glow-x: 15%; --glow-y: -10%; }
.card--vivid:nth-child(4n+2) { --glow-x: 100%; --glow-y: 0%; }
.card--vivid:nth-child(4n+3) { --glow-x: 0%; --glow-y: 100%; }
.card--vivid:nth-child(4n) { --glow-x: 100%; --glow-y: 100%; }

.card--vivid:nth-child(5n+1) .card__icon { animation-delay: 0s; }
.card--vivid:nth-child(5n+2) .card__icon { animation-delay: 0.4s; }
.card--vivid:nth-child(5n+3) .card__icon { animation-delay: 0.8s; }
.card--vivid:nth-child(5n+4) .card__icon { animation-delay: 1.2s; }
.card--vivid:nth-child(5n) .card__icon { animation-delay: 1.6s; }

@media (prefers-reduced-motion: reduce) {
  .card__sparkle,
  .card__icon { animation: none; }
}

@media screen and (max-width: 991px) {
  .problem__cards { grid-template-columns: repeat(2, 1fr); }
}
@media screen and (max-width: 479px) {
  .problem__cards { grid-template-columns: 1fr; }
}

/* Section divider */
.section-divider { display: flex; align-items: center; gap: var(--space-xs); padding: var(--space-l) 0; }
.section-divider__line { flex: 1; height: 1px; background: var(--border-default); }
.section-divider__mark { width: 8px; height: 8px; border-radius: 50%; background: var(--color-brand); flex: none; }

/* ==========================================================================
   SOBRE / OUTCOMES — card escuro com globo pontilhado 3D (canvas) e
   stats que contam de 0 até o valor real. Reaproveita a mesma linguagem
   visual das outras superfícies escuras do site (--color-ink, textura de
   grade da hero/card--vivid) em vez de inventar uma paleta nova — só o
   layout (badge + heading + stats em linha + globo grande à direita,
   sangrando pra fora do card) segue o print de referência do usuário.
   ========================================================================== */
.about-outcomes {
  position: relative;
  overflow: hidden;
  background: var(--color-ink);
  color: var(--text-inverse);
  border-radius: var(--radius-xl);
  padding: var(--space-2xl) var(--space-xl);
}
.about-outcomes__texture {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.05) 0 1px, transparent 1px 56px),
    repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.05) 0 1px, transparent 1px 56px);
  -webkit-mask-image: radial-gradient(circle at 20% 30%, black 0%, transparent 70%);
  mask-image: radial-gradient(circle at 20% 30%, black 0%, transparent 70%);
}
.about-outcomes__content { position: relative; z-index: 1; max-width: 46rem; }
.about-outcomes__heading { font-size: var(--text-2xl); font-weight: 500; margin: var(--space-sm) 0 var(--space-2xs); text-wrap: balance; }
.about-outcomes__paragraph { color: rgba(247, 247, 255, 0.72); font-size: var(--text-md); max-width: 42ch; }
.about-outcomes__cta { display: inline-flex; margin-top: var(--space-sm); }

/* 4 stats numa linha só, como no print de referência (lá só tinha 3, mas
   a Pruxor tem 4 números reais) — nowrap de propósito. Abaixo de 767px
   isso quebra pra grid 2x2 (ver media query mais abaixo): mesmo com o
   card empilhado e o globo embaixo, 4 colunas nowrap não cabem em telas
   de celular (confirmado via teste: overflow horizontal na página inteira
   até ~560px de largura, bug real já visto num screenshot mobile). */
.about-outcomes__stats { display: flex; flex-wrap: nowrap; gap: var(--space-m); margin-top: var(--space-xl); }
.about-outcomes__stat { display: flex; flex-direction: column; gap: 0.2em; }
.about-outcomes__stat-value { font-size: var(--text-2xl); font-weight: 500; font-variant-numeric: tabular-nums; white-space: nowrap; }
.about-outcomes__stat-label { font-family: var(--font-secondary); font-size: var(--text-2xs); color: rgba(247, 247, 255, 0.6); }

/* Globo: canvas quadrado bem maior que a área visível, ancorado pelo
   centro no canto inferior-direito do card (`right:0; bottom:0` +
   `translate(50%, 50%)` — o translate usa % do PRÓPRIO tamanho do
   elemento, não do container, então centraliza exatamente no canto
   independente da proporção largura/altura do card). Resultado: só o
   quadrante superior-esquerdo do globo (~1/4 do círculo) fica visível,
   recortado pelo `overflow: hidden` do `.about-outcomes` — pedido
   explícito do usuário comparando com o print de referência (globo bem
   maior, só 1/4 aparecendo, sangrando pra fora do card nos dois lados). */
.about-outcomes__globe {
  position: absolute;
  right: 0;
  bottom: 0;
  transform: translate(50%, 50%);
  width: 112%;
  max-width: 1020px;
  aspect-ratio: 1;
  z-index: 0;
  pointer-events: none;
}
.about-outcomes__globe-canvas { width: 100%; height: 100%; display: block; }

/* faixa "tweener" entre o desktop cheio e o empilhamento de 991px: sem
   isso o heading (que só quebra linha se precisar, via text-wrap:balance)
   cabe numa linha só bem perto da largura do globo e passa por cima dele. */
@media screen and (max-width: 1240px) {
  .about-outcomes__content { max-width: 30rem; }
  .about-outcomes__globe { width: 84%; max-width: 720px; }
}
@media screen and (max-width: 991px) {
  .about-outcomes__content { max-width: 100%; }
  .about-outcomes__globe { position: relative; right: auto; bottom: auto; transform: none; width: 60%; max-width: 320px; margin: var(--space-xl) auto 0; }
}
/* Coluna única abaixo de 767px: nowrap (regra base) estoura a largura da
   tela em qualquer viewport abaixo de ~560px, mesmo com o card já
   empilhado (globo embaixo) — confirmado via teste automatizado
   (scrollWidth da .about-outcomes__stats > clientWidth entre 320px e
   560px). Antes era um grid 2x2 (pensado pros 4 números da versão
   anterior); com a copy oficial a sessão passou a ter só 3 stats — um
   grid de 2 colunas deixaria o 3º item sozinho numa linha desalinhada,
   então virou empilhamento vertical simples (funciona bem pra qualquer
   quantidade de stats, não só 3 ou 4). */
/* Rodada de ajustes mobile (2026-08-22), 4 pedidos explícitos do usuário
   pra essa seção — todos escopados aqui em ≤767px:
   1) globo de volta a `position: absolute` (a regra de ≤991px acima o
      tinha posto em fluxo normal, `position: relative`, empurrando todo
      o conteúdo pra baixo dele) — assim ele volta a ficar POR TRÁS do
      conteúdo (`.about-outcomes__content` já tem `z-index: 1`, contra
      `z-index: 0` do globo) em vez de ocupar um espaço próprio antes do
      badge/heading.
   2) `height: 80%` (não mais `width: X%`) faz o CÍRCULO INTEIRO do globo
      ter 80% da ALTURA do card — como o card (`.about-outcomes`,
      `position: relative`) tem `height: auto` baseada no conteúdo, a %
      de altura num filho `position: absolute` resolve contra a altura
      final já calculada do conteúdo (comportamento padrão da spec pra
      elementos absolutos, não precisa de altura fixa no pai).
      `aspect-ratio: 1` (herdado da regra base) deriva a largura a partir
      dessa altura — por isso `width`/`max-width` da regra base precisam
      ser resetados aqui. **2ª rodada (mesmo dia)**: usuário pediu que só
      METADE do globo aparecesse, e que essa metade continuasse ocupando
      os mesmos 40% do card de antes — ou seja, o círculo INTEIRO dobra
      de 40% pra 80% da altura, mas metade dele fica escondida (cortada
      pelo `overflow: hidden` do card). `bottom: 0` sozinho deixaria o
      círculo inteiro (os 80%) visível; o `translateY(50%)` no
      `transform` desloca a caixa pra baixo em 50% da PRÓPRIA altura (não
      do container) — resultado: o centro do círculo passa a coincidir
      exatamente com a borda inferior do card, então só a metade de cima
      (um semicírculo, altura = metade de 80% = 40% do card, batendo com
      o pedido) fica acima da borda e visível; a metade de baixo fica
      abaixo da borda, cortada. `left: 50%` continua fazendo a
      centralização horizontal (agora combinado com o translateY no
      mesmo `transform`, via `translate(-50%, 50%)`).
   3) Padding do card: `var(--space-l) var(--space-2xs)` = exatamente
      48px/12px pedidos (tokens batem certinho com os valores, não
      precisou hardcodear px solto).
   2) Conteúdo centralizado (`text-align: center` + `margin-inline: auto`
      no parágrafo, que tem `max-width` próprio e por isso precisa de
      margin automática pra centralizar a CAIXA, não só o texto dentro
      dela) e `line-height` do heading reduzido (1.55 herdado do body,
      solto demais pra um heading de 4 linhas — outros headings do site
      já usam ~1.05-1.15, aqui ficou de fora por descuido; corrigido só
      no mobile por ora, já que não foi pedido pro desktop). */
@media screen and (max-width: 767px) {
  .about-outcomes { padding: var(--space-l) var(--space-2xs); }
  .about-outcomes__content { text-align: center; }
  .about-outcomes__heading { line-height: 1.15; }
  .about-outcomes__paragraph { margin-left: auto; margin-right: auto; }
  .about-outcomes__stats { flex-direction: column; align-items: center; gap: var(--space-sm); }
  .about-outcomes__globe {
    position: absolute;
    top: auto;
    right: auto;
    bottom: 0;
    left: 50%;
    transform: translate(-50%, 50%);
    width: auto;
    max-width: none;
    height: 80%;
    margin: 0;
  }
}

/* ==========================================================================
   FEATURE SHOWCASE — "etapas presas" (pinned steps). .feature-showcase__track
   é um elemento alto (altura = nº de etapas × 100vh, definida via JS) que só
   existe para dar espaço de rolagem; .feature-showcase__stage fica sticky
   (preso na tela) dentro dele. A cada etapa, o par imagem+texto atual some
   e o próximo aparece com crossfade — nunca os dois ao mesmo tempo, porque
   ambos ficam com position:absolute empilhados um sobre o outro (ver
   initFeatureShowcase em js/main.js, que decide qual [data-step] está ativo
   com base em quanto já se rolou dentro do track).
   ========================================================================== */
/* Cabeçalho da sessão (eyebrow + heading + parágrafo) fica DENTRO da área
   presa/sticky, pedido explícito do usuário (com print): heading e
   parágrafo em linha horizontal, nos dois extremos (space-between), e
   presos junto com o resto do conteúdo — não rola separado, tudo (header
   + módulo) cabe numa tela só. Não existia antes da copy oficial
   (2026-08-22): cada etapa tinha seu próprio h2 funcionando como um
   "título da sessão" de fachada, mas isso desaparecia ao trocar de etapa
   — agora tem um título/intro de verdade, sempre visível, independente
   de qual dos 5 módulos está ativo no momento. */
/* align-items: end (era flex-end, na versão flex) de propósito — pedido
   explícito do usuário, com anotação visual: o parágrafo da direita deve
   alinhar pela BASE com o heading da esquerda, não pelo topo dos dois. */
/* margin-bottom: var(--space-l) (2026-08-25, era --space-m) — pedido
   explícito do usuário: mais respiro entre o header e o grid
   (imagem+texto) logo abaixo. (Uma tentativa anterior no mesmo dia
   também dava um `min-height` extra à caixa da imagem pra evitar
   sobreposição em larguras estreitas, mas foi desfeita a pedido do
   usuário — ver comentário em `.feature-showcase__visual-col` abaixo. O
   pedido real era só esse espaçamento aqui.) */
/* `display: grid; grid-template-columns: 1fr 1fr` (2026-08-26, era
   `display: flex; justify-content: space-between`) — pedido explícito do
   usuário, com print anotado (2 caixas vermelhas + linha ligando as
   bordas esquerdas): a borda esquerda de `.feature-showcase__header-paragraph`
   ("Nada de sistema complicado...") e a de `.feature-showcase__content-col`
   (heading do módulo, "Controle financeiro por obra" etc., na linha de
   baixo) não batiam. Causa: com `flex` + `space-between`, a borda
   esquerda do parágrafo era "container_width − largura própria do
   parágrafo" (ele fica encostado na borda DIREITA, empurrado pelo
   space-between) — um valor que muda com a largura do próprio texto e
   não tem nenhuma relação com onde a coluna 2 do grid de baixo (`.feature-showcase__grid`,
   `1fr 1fr`) começa de verdade. Trocando o header pro MESMO
   `grid-template-columns: 1fr 1fr` + `gap: var(--space-xl)` do grid de
   baixo, as 2 linhas passam a compartilhar literalmente a mesma
   matemática de coluna — a borda esquerda de `.feature-showcase__header-paragraph`
   (que já é `text-align: left` dentro da própria coluna) cai exatamente
   em cima da borda esquerda de `.feature-showcase__content-col`, em
   QUALQUER largura de tela, sem precisar calcular nenhum valor fixo.
   `justify-content: space-between` saiu (não faz mais sentido em grid
   com colunas `1fr`, que já preenchem 100% da largura sozinhas). O
   parágrafo deixou de ficar encostado na borda DIREITA do container
   (comportamento antigo, pedido numa rodada anterior) — troca aceita de
   propósito: o pedido novo (alinhar com a coluna do módulo abaixo)
   prevalece sobre o antigo (encostar na borda direita). */
.feature-showcase__header {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: end;
  gap: var(--space-xl);
  margin-bottom: var(--space-l);
}
/* 36rem (não mais 32rem, 2026-08-22): usuário pediu o heading em só 2
   linhas (estava quebrando em 3 com o max-width antigo). 32rem era largo
   o bastante pra não colidir com o parágrafo à direita, mas estreito
   demais pro texto (~64 caracteres) caber em 2 linhas balanceadas — medi
   via Playwright em 1440px/1920px: 36rem é o menor valor que já garante
   2 linhas (557px/570px, bem equilibradas) sem encostar no parágrafo
   (que mantém seu próprio max-width: 32rem, intocado). Testado sem
   overlap em nenhuma das duas larguras [1440/1920] — mas larguras "tweener"
   entre 992px e 1220px NÃO foram testadas na época: nelas, o header
   inteiro (heading + parágrafo) não cabe lado a lado nos dois max-width
   fixos, então os 2 itens flex ENCOLHEM (flex-shrink padrão) abaixo do
   próprio max-width, e o heading quebra em 3-4 linhas em vez de 2. **`line-height:
   1.05`** (2026-08-25, era 1.15 herdado de `.section-header__heading`,
   classe compartilhada com outras sessões — não mexida ali de propósito)
   aqui, escopado só a esse heading: reduz quanto essa quebra extra
   engorda a altura do header nas larguras estreitas (pedido explícito do
   usuário, com print mostrando o espaçamento solto entre linhas). */
.feature-showcase__header-heading { max-width: 36rem; }
.feature-showcase__header-heading h2 { line-height: 1.05; }
.feature-showcase__header-paragraph {
  max-width: 32rem;
  text-align: left;
  color: var(--text-secondary);
  font-size: var(--text-sm);
  text-wrap: balance;
}

.feature-showcase__track { position: relative; }
/* flex-direction:column (não mais row) porque o stage agora tem 2 filhos
   empilhados (header + grid), não só o grid sozinho — sem isso, os dois
   ficariam lado a lado na horizontal em vez de um em cima do outro.
   min-height removido de propósito: a soma de header + grid já dá altura
   suficiente, e travar um min-height alto empurraria o conteúdo pra fora
   da viewport em telas mais baixas (pedido explícito: a sessão inteira
   tem que caber numa tela só). */
.feature-showcase__stage {
  position: sticky;
  top: var(--nav-height);
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: var(--space-m) 0;
}
.feature-showcase__grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-xl); width: 100%; }

/* align-items do grid fica no padrão (stretch) de propósito: como os filhos
   de .feature-showcase__content-col são todos position:absolute (não
   contribuem para a altura do pai), é o tamanho do visual que acaba
   definindo a altura da linha do grid — e o stretch faz o content-col
   herdar essa altura, dando aos blocos de texto absolutos uma caixa real
   para preencher. **`aspect-ratio: 16 / 9`** (2026-08-25, era
   `min-height: 400px` fixo) — o min-height era um palpite de quando a
   sessão ainda usava placeholder sem imagem real; com as telas reais
   (ver `.feature-showcase__visual-img` abaixo), essa altura arbitrária
   não batia com a proporção de nenhuma delas e sobrava "letterbox"
   (faixas vazias em cima/embaixo ou nas laterais, mesmo com
   `object-fit: contain`). 16:9 bate quase exatamente com 4 das 5 telas
   reais (Financeiro 1280x720 = 16:9 exato; Orçamentos/Obras/Estoque
   1672x941 ≈ 16:9, diferença de 0.06%) — a altura do painel passa a
   seguir a largura da coluna (definida pelo grid) na MESMA proporção da
   imagem, então ela preenche o painel sem sobra nenhuma. */
.feature-showcase__visual-col { position: relative; aspect-ratio: 16 / 9; }
/* Um `min-height` extra (mesmo só numa faixa "tweener" de largura) pra
   dar mais altura ao texto de alguns módulos foi tentado em 2026-08-25 e
   DESFEITO no mesmo dia, a pedido explícito do usuário: reintroduzia
   sobra/letterbox na imagem (visível até nos módulos que não precisavam
   de altura extra, ex: Estoque, reportado com print) — o usuário deixou
   claro que a caixa da imagem deve continuar 100% responsiva à proporção
   real da imagem (`aspect-ratio: 16/9` sozinho, sem floor nenhum) e que
   o pedido original era só sobre o ESPAÇO ENTRE O HEADER E O GRID (ver
   `.feature-showcase__header` acima), não sobre o tamanho da imagem. Não
   reintroduzir um `min-height`/floor de altura aqui sem pedido explícito
   novo — se o texto de algum módulo precisar de mais espaço numa largura
   estreita, resolver por outro caminho (ex: encurtar o texto, ou tratar
   só o texto/CTA, nunca inflando a caixa da imagem). */
.feature-showcase__visual-panel {
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: var(--radius-l);
  background: var(--bg-subtle);
  border: 10px solid rgba(0, 0, 0, 0.1);
  opacity: 0;
  transform: scale(0.97);
  transition: opacity 0.6s var(--ease-out-expo), transform 0.6s var(--ease-out-expo);
}
.feature-showcase__visual-panel.is-active { opacity: 1; transform: scale(1); }
/* Telas reais do produto (2026-08-25) — substituem o placeholder de
   texto ("Tela do financeiro" etc.) que existia enquanto não tínhamos os
   prints. `object-fit: contain` (2026-08-25, era `cover`) mostra a tela
   inteira sem cortar nenhum canto — `cover` estava recortando conteúdo
   real das 4 telas com proporção parecida (Financeiro/Orçamentos/Obras/
   Estoque, ~1280x720/1672x941); o painel tem `background: var(--bg-subtle)`
   pra preencher a sobra quando a proporção da imagem não bate exatamente
   com a do painel. `overflow: hidden` no painel garante que a imagem
   respeite o `border-radius` do card em vez de vazar pelos cantos
   arredondados. */
.feature-showcase__visual-img { width: 100%; height: 100%; display: block; object-fit: contain; }
/* Diário de obra (data-step="2") tem proporção bem mais larga que as
   outras 4 (1807x870 vs. ~1672x941/1280x720) — sozinha entre as 5, foge
   bastante do formato comum. Mantém `cover` só nessa (recorta o excesso
   nas laterais) em vez de puxar o painel inteiro pra um formato mais
   largo só por causa de 1 imagem — as outras 4 continuam com `contain`,
   mostrando o conteúdo inteiro no mesmo tamanho de painel de sempre. */
[data-step="2"] .feature-showcase__visual-img { object-fit: cover; }

.feature-showcase__content-col { position: relative; }
/* justify-content: flex-start (2026-08-26, era center) — pedido explícito
   do usuário, com print: o texto do módulo (heading "Controle financeiro
   por obra" etc.) ficava centralizado na altura da imagem, bem mais
   baixo que o parágrafo do header ("Nada de sistema complicado...") ao
   lado. Alinhando o topo do texto do módulo com o topo da imagem (em vez
   de centralizar), ele fica no mesmo "nível" visual do parágrafo do
   header acima, dando uma leitura mais consistente entre as duas linhas
   de texto da sessão. */
.feature-showcase__block {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.5s var(--ease-out-expo), transform 0.5s var(--ease-out-expo);
  pointer-events: none;
}
.feature-showcase__block.is-active { opacity: 1; transform: translateY(0); pointer-events: auto; }
/* Botões dentro do próprio bloco (não depois do track) — colocar um link
   "ver mais" depois da faixa presa (sticky) faz ele ficar visualmente
   "flutuando" sozinho, longe do conteúdo, porque o track reserva bem mais
   altura de scroll do que o conteúdo visível ocupa. */
.feature-showcase__actions { display: flex; flex-wrap: wrap; gap: var(--space-2xs); }
/* Miniatura própria por módulo, só pro fallback mobile (ver media query
   abaixo) — escondida no desktop de propósito, onde quem mostra a "tela"
   de cada módulo é o .feature-showcase__visual-panel que crossfada. */
.feature-showcase__block-visual { display: none; }

.feature-set__heading { font-size: var(--text-2xl); font-weight: 500; margin-bottom: var(--space-sm); text-wrap: balance; }
.feature-set__paragraph { color: var(--text-secondary); font-size: var(--text-sm); max-width: 52ch; margin-bottom: var(--space-sm); text-wrap: balance; }
/* Quebra manual só nos 3 headings mais longos (financeiro, diário de
   obra, orçamento SINAPI — os outros 2, "Gestão de obras" e "Controle de
   estoque", já cabem numa linha só no mobile, sem precisar de nada). Sem
   isso, `text-wrap: balance` sozinho estava produzindo uma 1ª linha
   BEM menor que a 2ª (ex: "Controle" / "financeiro por obra") — o
   usuário pediu o oposto, 1ª linha maior. `display:none` por padrão (o
   `<br>` não quebra nada em desktop/tablet, onde o layout é diferente e
   esse ponto de quebra específico não foi pedido nem testado) — só vira
   um `<br>` de verdade em ≤767px (ver bloco abaixo). */
.feature-set__heading-break { display: none; }

/* Mobile: sem "etapas presas" — os 5 blocos de texto (não só o ativo)
   empilham normalmente. Diferente da versão com 2 etapas genéricas, os 5
   módulos de agora são telas bem distintas (financeiro, diário, orçamento,
   obras, estoque) — mostrar só 1 imagem fixa no topo pra todos os 5 textos
   ficaria claramente errado (a imagem do "financeiro" continuaria lá
   embaixo do texto do "estoque"). Por isso o crossfade de imagem
   (.feature-showcase__visual-col) fica escondido no mobile, e cada bloco
   ganha sua PRÓPRIA miniatura (.feature-showcase__block-visual) logo
   acima do próprio título — imagem e texto sempre pareados certo. */
@media screen and (max-width: 991px) {
  .feature-showcase__track { height: auto !important; }
  .feature-showcase__stage { position: static; min-height: 0; display: block; padding: 0; }
  /* header horizontal (heading|parágrafo nos extremos) só faz sentido com
     largura de desktop — empilha normal no mobile, mesmo padrão dos
     outros headers de sessão. `grid-template-columns: 1fr` (não mais
     `flex-direction: column`, que não faz nada num `display: grid`
     desde que o header virou grid pra alinhar com `.feature-showcase__grid`,
     ver comentário na regra base) — 1 coluna só, heading e parágrafo
     empilham em fluxo normal. */
  .feature-showcase__header { grid-template-columns: 1fr; align-items: stretch; gap: var(--space-sm); margin-bottom: var(--space-l); }
  .feature-showcase__header-paragraph { max-width: none; }
  .feature-showcase__grid { grid-template-columns: 1fr; }
  .feature-showcase__visual-col { display: none; }
  /* Telas reais (2026-08-25, mesma troca do painel de crossfade do
     desktop) — `overflow: hidden` + `.feature-showcase__visual-img`
     (`object-fit: contain`, cover só no diário de obra) preenche a
     miniatura sem distorcer. `display: block` é OBRIGATÓRIO aqui (bug
     real, achado na verificação): a regra base de
     `.feature-showcase__block-visual` é `display: none` (só existe
     visualmente no mobile) — ao remover o antigo `display: flex` (que
     centralizava o rótulo de texto, desnecessário agora que a imagem
     preenche via width/height 100%), o override do `display: none` foi
     embora junto por descuido, deixando a miniatura invisível (e a
     imagem nunca carregava, já que um elemento sem caixa de layout não
     dispara o `loading="lazy"`). **`aspect-ratio: 16 / 9`** (2026-08-25,
     era `4 / 3.2` — mesmo motivo/mesma proporção da versão desktop, ver
     `.feature-showcase__visual-col` acima): a proporção antiga (1.25)
     era bem mais "quadrada" que as telas reais (~1.78), deixando faixas
     vazias em cima/embaixo da miniatura mesmo com `object-fit: contain`
     (bug relatado pelo usuário com print no mobile). */
  .feature-showcase__block-visual {
    display: block;
    overflow: hidden;
    aspect-ratio: 16 / 9;
    border-radius: var(--radius-l);
    background: var(--bg-subtle);
    border: 10px solid rgba(0, 0, 0, 0.1);
    margin-bottom: var(--space-m);
  }
  .feature-showcase__content-col { display: flex; flex-direction: column; gap: var(--space-2xl); }
  .feature-showcase__block {
    position: static;
    opacity: 1 !important;
    transform: none !important;
    pointer-events: auto !important;
  }
}
/* Linhas mais próximas no heading/parágrafo de cada módulo, no mobile
   (pedido explícito do usuário, rodada de ajustes mobile de 2026-08-22)
   — nenhum dos dois tinha `line-height` próprio, então herdavam o 1.55
   solto do body. `.feature-set__heading`/`__paragraph` são
   COMPARTILHADOS pelos 5 módulos (financeiro, diário de obra, orçamento
   SINAPI, gestão de obras, estoque) — o pedido do usuário de propagar
   "pra todos que seguem essa fonte" já é satisfeito de graça editando a
   classe compartilhada aqui. Heading em 1.15 (mesmo padrão já usado nos
   outros headings do site — hero 1.05, section-header 1.1-1.15,
   about-outcomes 1.15); parágrafo em 1.4 (menos apertado que um heading,
   texto corrido ainda precisa de respiro pra legibilidade, mas visivelmente
   mais compacto que o 1.55 padrão). `.feature-showcase__header` (eyebrow +
   heading + parágrafo, já empilhados desde ≤991px) centralizado no
   mobile — pedido explícito do usuário, junto com o mesmo tratamento em
   Como funciona/Planilha vs Pruxor/Diferenciais/FAQ (ver bullets
   correspondentes nas próprias sessões). */
@media screen and (max-width: 767px) {
  .feature-set__heading { line-height: 1.15; }
  .feature-set__paragraph { line-height: 1.4; }
  .feature-set__heading-break { display: inline; }
  .feature-showcase__header { text-align: center; }
  /* `.feature-showcase__header-paragraph` tem `text-align: left` explícito
     na regra base (desktop, 2ª coluna do grid do header) — texto
     explícito no próprio elemento sempre vence herança, então o
     `text-align: center` do pai acima não bastava sozinho pra centralizar
     esse parágrafo especificamente (bug real, achado na verificação). */
  .feature-showcase__header-paragraph { text-align: center; }
}

/* ==========================================================================
   COMO FUNCIONA — sessão nova (copy oficial, 2026-08-22). 3ª versão de
   layout (pedido explícito, com GIF + print de referência de outro
   site). A 2ª versão (scroll travado + crossfade, mesmo mecanismo de
   "Soluções") NUNCA bateu com o efeito pedido: o usuário voltou com um
   print mostrando os cards em fluxo normal (um visivelmente abaixo do
   outro, com gap, sem overlap) e disse que os próximos "devem vir
   aparecendo... como uma linha do tempo, não substituindo pelo próximo,
   deve vir de baixo para cima" — descrição que bate com SCROLL NORMAL
   (o próximo card sempre "vem de baixo" na rolagem comum), não com
   crossfade. Substituído por completo: `.how-it-works__track`/`__stage`/
   `__grid`/`.is-active`/`.is-past` saíram do CSS, `initHowItWorks()`
   saiu do JS (ver memoria.md). Zero mecanismo de scroll customizado
   agora — só `position: sticky` no heading, puro CSS.
   ========================================================================== */
/* Grid de 1 linha só (2 colunas: sticky-col | cards) — voltou a ser
   assim depois de um bug real. Numa tentativa anterior, "intro"
   (heading) e "cta" (botão) tinham virado 2 LINHAS separadas do grid
   ("intro cards" / "cta cards") só pra dar pra reordenar o botão pra
   depois dos cards no mobile — mas isso quebrou o sticky no desktop: o
   "range" de sticky de um item vale só dentro da altura da PRÓPRIA
   linha do grid em que ele está, e a linha 1 (só o heading) é bem mais
   curta que a coluna de cards. Resultado: o heading (sticky) e o botão
   (não-sticky, preso na posição fixa da linha 2) se descolavam um do
   outro conforme a página rolava, com o botão passando por cima do
   heading (bug real, reportado com print). Corrigido voltando a 1 linha
   só, com heading+botão dentro de UM wrapper (`.how-it-works__sticky-col`)
   que ocupa essa linha inteira — como só existe 1 linha no grid, a altura
   dela é a da coluna mais alta (os cards), e o wrapper sticky tem esse
   range inteiro pra "colar" durante o scroll, exatamente como era antes
   do bug. */
.how-it-works__layout {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-areas: "sticky cards";
  column-gap: var(--space-xl);
  align-items: start;
}
/* `position: sticky` simples — SEM JS, sem trilho alto, sem crossfade.
   O wrapper (heading + botão juntos) fica parado enquanto a coluna da
   direita (mais alta, 3 cards empilhados em fluxo normal) rola por
   baixo dele, exatamente como qualquer sidebar sticky ao lado de uma
   lista mais alta. `top` usa só `--nav-height`, igual a todo outro
   elemento sticky do site (`.feature-showcase__stage`). */
.how-it-works__sticky-col {
  grid-area: sticky;
  position: sticky;
  top: var(--nav-height);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-sm);
  max-width: 30rem;
  padding-top: var(--space-m);
}
.how-it-works__intro { max-width: none; padding: 0; }

.how-it-works__card-col { grid-area: cards; display: flex; flex-direction: column; gap: var(--space-l); }
/* Ícone à esquerda + tag "Etapa N" à direita, na mesma linha — pedido
   explícito com base no print de referência (layout do topo do card). */
.how-it-works__card-top { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: var(--space-xs); }
.how-it-works__card-top .card__icon { margin-bottom: 0; }
/* Tag "Etapa N" — reaproveita .badge/.badge--inverse (mesmo componente já
   usado em outros rótulos sobre fundo escuro, ex: eyebrow do hero) em vez
   de criar um badge novo; o sparkle dentro é o mesmo ícone decorativo de
   4 pontas já usado em .card__sparkle, só que como conteúdo real do
   rótulo, não decoração solta. */
.how-it-works__card-tag { position: relative; z-index: 1; flex: none; }
.how-it-works__card-tag svg { width: 12px; height: 12px; }
/* Parágrafo limitado a 2 linhas — pedido explícito do usuário. Só nesta
   sessão (seletor escopado): `.card__paragraph` é reaproveitado em várias
   outras sessões do site (Problema, Diferenciais, Depoimentos) que não
   pediram esse limite. */
.how-it-works__card .card__paragraph {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Empilhado (≤991px): pedido explícito do usuário pra mover o botão pra
   DEPOIS dos cards (antes ficava logo abaixo do heading, antes deles).
   `.how-it-works__sticky-col` (o wrapper sticky do desktop) vira
   `display: contents` — ele mesmo some da árvore de caixas (inclusive o
   `position: sticky`, que só faz sentido preso a uma caixa de verdade,
   deixa de se aplicar sozinho), e `.how-it-works__intro`/`.how-it-works__cta`
   passam a ser filhos DIRETOS de `.how-it-works__layout` de novo — só
   nesse ponto dá pra reordenar cada um via `grid-template-areas`
   (intro → cards → cta) sem duplicar HTML nem precisar de JS. */
@media screen and (max-width: 991px) {
  .how-it-works__layout {
    grid-template-columns: 1fr;
    grid-template-areas:
      "intro"
      "cards"
      "cta";
    gap: var(--space-l);
  }
  .how-it-works__sticky-col { display: contents; }
}
/* Headline centralizado no mobile — pedido explícito do usuário, mesmo
   tratamento aplicado em Soluções/Planilha vs Pruxor/Diferenciais/FAQ.
   `.how-it-works__cta`, uma vez "solto" pelo `display: contents` do
   wrapper (ver bloco acima), precisa de centralização própria via
   `justify-self` — `text-align:center` no intro não alcança ele, já que
   não é mais filho dele nesse breakpoint. */
@media screen and (max-width: 767px) {
  .how-it-works__intro { text-align: center; }
  .how-it-works__cta { justify-self: center; }
}

/* ==========================================================================
   PLANILHA VS PRUXOR — card escuro (mesma identidade visual do
   `.about-outcomes`/`.card--vivid`: --color-ink + textura de grade, nunca
   a cor verde do print de referência) com um header "Na planilha / VS /
   Pruxor" e uma lista de linhas comparativas, cada uma com metade
   apagada/tracejada à esquerda e metade em destaque com ícone de raio à
   direita, separadas por um traço vertical na cor de marca.
   ========================================================================== */
/* Sem isso, o header da sessão encostava direto no card escuro — mesmo
   problema já visto em "Como funciona" (h2/p têm margin:0 por reset
   global, então sem uma regra explícita o espaço é zero). Mesmo respiro
   (--space-l) usado nas outras sessões. */
.compare__intro { margin-bottom: var(--space-l); }
.compare {
  position: relative;
  overflow: hidden;
  background: var(--color-ink);
  color: var(--text-inverse);
  border-radius: var(--radius-xl);
  padding: var(--space-xl);
}
/* Mesmo brilho radial na cor de marca do `.card--vivid::before` — pedido
   explícito do usuário ("adicionar o mesmo gradiente dos cards"). Valor
   fixo de posição (não var(--glow-x)/--glow-y com ciclo por nth-child
   como em `.card--vivid`) porque aqui é uma instância única, não uma
   fileira de cards precisando de variedade. */
.compare::before {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(circle at 20% 0%, color-mix(in srgb, var(--color-brand) 65%, transparent) 0%, transparent 62%);
  opacity: 0.85;
}
.compare__texture {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.05) 0 1px, transparent 1px 56px),
    repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.05) 0 1px, transparent 1px 56px);
  -webkit-mask-image: radial-gradient(circle at 80% 0%, black 0%, transparent 70%);
  mask-image: radial-gradient(circle at 80% 0%, black 0%, transparent 70%);
}
.compare__header, .compare__row {
  display: grid;
  grid-template-columns: 1fr 48px 1.15fr;
  align-items: center;
  gap: var(--space-sm);
}
.compare__header {
  position: relative;
  z-index: 1;
  margin-bottom: var(--space-m);
}
.compare__header-label {
  font-family: var(--font-secondary);
  font-size: var(--text-xs);
  font-weight: 600;
  color: rgba(247, 247, 255, 0.5);
  text-align: center;
}
.compare__header-label--brand {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5em;
  color: var(--text-inverse);
  font-size: var(--text-sm);
}
/* Logo real (2026-08-25) — substitui o antigo `.nav__logo-mark` + texto
   "Pruxor" nos dois lugares que usam `.compare__header-label--brand`
   (cabeçalho do desktop e a divisória entre as listas no mobile). Sempre
   a versão branca — o fundo de `.compare` é escuro em qualquer estado,
   não tem equivalente ao "rolar a página" da navbar que justificaria
   trocar de versão aqui. */
.compare__brand-logo { height: 32px; width: auto; display: block; }
.compare__vs {
  justify-self: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.16);
  background: rgba(255, 255, 255, 0.04);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-secondary);
  font-size: var(--text-2xs);
  font-weight: 700;
  color: rgba(247, 247, 255, 0.7);
}

.compare__rows { position: relative; z-index: 1; display: flex; flex-direction: column; gap: var(--space-xs); }
.compare__row {
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: var(--radius-m);
  overflow: hidden;
}
.compare__cell { padding: var(--space-sm) var(--space-m); font-size: var(--text-sm); }
.compare__cell--before {
  color: rgba(247, 247, 255, 0.5);
  background-image: repeating-linear-gradient(-45deg, rgba(255, 255, 255, 0.04) 0 1px, transparent 1px 12px);
}
.compare__cell--after { display: flex; align-items: center; gap: var(--space-2xs); font-weight: 500; }
.compare__icon { width: 18px; height: 18px; flex: none; color: var(--color-brand); }
.compare__divider { justify-self: center; width: 2px; align-self: stretch; margin: var(--space-2xs) 0; background: var(--color-brand); }
/* Só existe visualmente no mobile (≤767px, ver media query mais abaixo)
   — no desktop cada `.compare__row` já mostra o par antes/depois lado a
   lado, então não há duas "listas" separadas pra dividir. */
.compare__group-divider { display: none; }
.compare__closing { margin-top: var(--space-l); }
/* O botão fica visualmente "puxado" pra direita se só centralizar no
   container inteiro — o grid 1fr/48px/1.15fr do header/linhas já não é
   simétrico de propósito (coluna da direita um pouco maior), então o
   centro real do "VS" não bate com o centro geométrico do card. Pedido
   explícito do usuário, com print, pra alinhar o botão com essa linha do
   meio. Em vez de calcular o deslocamento na mão, o wrapper reusa o
   MESMO grid (`1fr 48px 1.15fr`) + o MESMO padding horizontal do
   `.compare` — o botão fica no `grid-column: 2` (a coluna de 48px do
   "VS") com `justify-self: center`, que centraliza o item em torno do
   CENTRO da própria coluna mesmo sendo bem mais largo que ela (o
   navegador deixa o item "vazar" pros dois lados, mas sempre centrado
   nesse ponto) — didático, e continua correto se o texto do botão ou a
   proporção do grid mudar no futuro, sem precisar recalcular nada. */
.compare__closing-grid {
  display: grid;
  grid-template-columns: 1fr 48px 1.15fr;
  gap: var(--space-sm);
  padding: 0 var(--space-xl);
}
.compare__closing-btn { grid-column: 2; justify-self: center; white-space: nowrap; }

@media screen and (max-width: 767px) {
  /* Headline + subheadline centralizados — pedido explícito do usuário,
     mesmo tratamento aplicado em Soluções/Como funciona/Diferenciais/FAQ. */
  .compare__intro { text-align: center; }
  .compare { padding: var(--space-m); }
  /* "Na planilha" sozinho, centralizado, sem o "VS" na mesma linha —
     pedido explícito do usuário com print. O "VS" saiu do cabeçalho e
     foi morar na divisória entre as duas listas (ver
     `.compare__group-divider` mais abaixo), onde ele já tem mais sentido
     agora que a lista virou "planilha inteira, depois pruxor inteira"
     em vez de pareada linha a linha. **2ª rodada, mesmo dia**: usuário
     olhou o resultado (Na planilha + Pruxor empilhados no cabeçalho) e
     pediu deixar só "Na planilha" ali — o rótulo "Pruxor" já vive na
     divisória (`.compare__group-divider`, ver mais abaixo), repeti-lo
     aqui em cima virou redundante. `.compare__header-label--brand`
     ("Pruxor") escondido também; sobra só "Na planilha", centralizado
     sozinho no cabeçalho. */
  .compare__header { grid-template-columns: 1fr; }
  .compare__header .compare__vs { display: none; }
  .compare__header .compare__header-label--brand { display: none; }
  /* Pedido explícito do usuário: mostrar a lista inteira "Na planilha"
     primeiro, depois a lista inteira "Pruxor" — sem alternar entre as
     duas a cada linha (era o que acontecia antes: cada `.compare__row`
     empilhava seu próprio before+after, então rolar a página mostrava
     planilha→pruxor→planilha→pruxor repetidamente). Como cada par
     before/after vive dentro de UMA `.compare__row` (a borda arredondada
     de "linha" pareada é dela, não das células), não dá pra só reordenar
     — a linha (`.compare__row`) vira `display: contents` (some da árvore
     de caixas, mas os filhos continuam no DOM/acessibilidade) pra que as
     14 células (7 before + 7 after) passem a ser filhas DIRETAS de
     `.compare__rows` (que já é `display:flex; flex-direction:column`) e
     o `order` funcione entre elas. `order: 1` em todo `--before` e
     `order: 3` em todo `--after` (a divisória fica no meio, order: 2)
     agrupa as 7 primeiras, depois as 7 últimas — dentro de cada grupo, a
     ordem relativa original (linha 1 a 7) se mantém, já que `order`
     empatado cai de volta pra ordem de origem. Cada célula ganha a
     própria borda/cantos arredondados (antes era só a `.compare__row`
     que tinha isso, cobrindo o par inteiro) pra continuar lendo como um
     item de lista, agora sozinha. */
  .compare__row { display: contents; }
  .compare__divider { display: none; }
  .compare__cell {
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: var(--radius-m);
    overflow: hidden;
  }
  .compare__cell--before { order: 1; }
  .compare__cell--after { order: 3; }
  /* Divisória entre a lista "Na planilha" (order:1) e a lista "Pruxor"
     (order:3) — pedido explícito do usuário, olhando o resultado da
     rodada anterior: sem nenhuma linha/rótulo entre as duas listas,
     ficava difícil perceber onde uma acaba e a outra começa (o cabeçalho
     "Na planilha / VS / Pruxor" no topo do card já não é suficiente
     depois de rolar 7 itens). 2ª rodada: o "VS" saiu do cabeçalho (ver
     `.compare__header` acima) e o rótulo "Pruxor" (mesmo
     `.compare__header-label--brand`, ícone+texto, reaproveitado sem
     duplicar CSS) veio morar aqui embaixo do traço — agora esta
     divisória sozinha anuncia "acabou a lista da planilha, começa a da
     Pruxor", igual ao "Na planilha" faz lá em cima pra lista de cima.
     `aria-hidden` porque é só reforço visual — o cabeçalho já anuncia a
     comparação pra leitor de tela. Escondido por padrão (só existe
     visualmente aqui, ≤767px); no desktop cada linha já é seu próprio
     par visível lado a lado, então não faz sentido lá. */
  .compare__group-divider {
    order: 2;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-2xs);
    margin: var(--space-2xs) 0;
  }
  .compare__group-divider-vs { display: flex; align-items: center; gap: var(--space-xs); width: 100%; }
  .compare__group-divider-line { flex: 1; height: 1px; background: rgba(255, 255, 255, 0.16); }
  .compare__group-divider .compare__vs { flex: none; width: 32px; height: 32px; }
  /* Sem o "VS" nem a divisão em 2 colunas nesse breakpoint (tudo já
     empilha), não sobra nenhuma assimetria pra compensar — o botão volta
     a ser um centralizado simples. */
  .compare__closing-grid { grid-template-columns: 1fr; padding: 0; }
  .compare__closing-btn { grid-column: 1; }
}

/* ==========================================================================
   DIFERENCIAIS (comerciais) — mesmo padrão de "Problema": section-header
   + grid de 4 `.card--vivid`. Classes próprias (não `.problem__cards`)
   pra não misturar com a sessão "Problema", mesmo a receita de CSS sendo
   idêntica.
   ========================================================================== */
.value-props__header { margin-bottom: var(--space-l); }
.value-props__cards { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-sm); }
@media screen and (max-width: 991px) {
  .value-props__cards { grid-template-columns: repeat(2, 1fr); }
}
@media screen and (max-width: 767px) {
  /* Headline + subheadline centralizados — pedido explícito do usuário,
     mesmo tratamento aplicado em Soluções/Como funciona/Planilha vs
     Pruxor/FAQ. */
  .value-props__header { text-align: center; }
}
@media screen and (max-width: 479px) {
  .value-props__cards { grid-template-columns: 1fr; }
}

/* ==========================================================================
   DEPOIMENTOS — carrossel em loop contínuo, CSS puro (sem JS): a lista
   de cards é duplicada uma vez no HTML e a faixa anima
   `translateX(0 → -50%)` — 50% é exatamente a largura de UMA cópia
   (as duas são idênticas), dando um loop sem salto perceptível, mesma
   técnica de loop contínuo sem JS usada em outros carrosséis do site, só
   que horizontal e da direita pra esquerda. Cards reusam `.card--vivid`
   (mesmo padrão dark de "Problema"/"Diferenciais"), com estrutura
   interna própria (aspas + texto + rodapé com avatar).
   ========================================================================== */
.testimonials__header { margin-bottom: var(--space-l); }
/* Fica DENTRO do .layout-container normal (não full-bleed) — igual a
   todo o resto do site — só recorta com overflow:hidden e funde as
   bordas com mask-image. */
/* overflow-x/overflow-y separados (não `overflow: hidden` nos dois eixos)
   de propósito — só o eixo horizontal precisa recortar de verdade (pra
   esconder os cards saindo/entrando pelas bordas do loop). Pegadinha da
   spec do CSS Overflow Module (ver "Cuidados importantes" em
   CLAUDE.md): o eixo vertical com `overflow: hidden` cortava o
   lift+brilho do hover do `.card--vivid` em cima E embaixo (bug real,
   reportado com print). Padding vertical generoso (50px/75px) dá espaço
   pro hover não ser cortado — sem padding horizontal aqui, já que o
   corte lateral nas bordas do loop é intencional (mask-image já funde
   visualmente, ver abaixo). */
.testimonials__loop {
  position: relative;
  overflow-x: hidden;
  overflow-y: visible;
  padding: 50px 0 75px;
  -webkit-mask-image: linear-gradient(90deg, transparent 0, black 64px, black calc(100% - 64px), transparent 100%);
  mask-image: linear-gradient(90deg, transparent 0, black 64px, black calc(100% - 64px), transparent 100%);
}
/* Bug real corrigido (2026-08-26): no Safari, essa sessão demorava muito
   pra aparecer (usuário reportou com print — só o heading "Quem usa,
   aprova." renderizava por um bom tempo, os cards ficavam invisíveis) e,
   quando finalmente aparecia, o loop não continuava — parava assim que
   chegava no fim de um ciclo em vez de voltar pro início. Causa: até
   aqui, `.testimonials__loop` também tinha `data-reveal` (fade genérico
   de scroll, ver [data-reveal] no fim do arquivo), que inclui
   `filter: blur(6px)` no estado "escondido" — só que ESSE elemento
   também é quem tem `overflow-x: hidden` + `mask-image` (2 linhas acima)
   E contém `.testimonials__track`, cuja animação `infinite` nunca para.
   `filter` + `mask-image`/`overflow:hidden` + animação `infinite` num
   descendente é uma combinação com bug documentado no WebKit/Safari:
   o Safari renderiza `filter: blur()` via CPU (não GPU, diferente de
   Chrome/Firefox) — sozinho já é lento, e some com `mask-image` +
   `overflow:hidden` num ancestral de um `animation: infinite` é um
   padrão conhecido de o loop simplesmente não recomeçar depois da 1ª
   volta. `data-reveal` foi REMOVIDO de `.testimonials__loop` no HTML
   (`index.html`) — o `.testimonials__header` (título "Quem usa,
   aprova.") continua com o fade normal, só o carrossel em si não usa
   mais esse efeito de entrada, pra nunca aplicar `filter: blur()` no
   elemento que tem o mask + a animação infinita. */
.testimonials__track {
  display: flex;
  gap: var(--space-sm);
  width: max-content;
  animation: testimonials-scroll 42s linear infinite;
  /* Promove a faixa pra sua própria camada de composição desde o
     início (Safari costuma promover/rebaixar camadas dinamicamente em
     torno de filter/mask, e é exatamente nessa troca que o bug do loop
     trava) — mitigação recomendada pra esse padrão de bug no Safari. */
  transform: translateZ(0);
}
/* pausa no hover — texto de depoimento é mais longo que um rótulo de
   badge, então dar tempo de terminar de ler antes de continuar o loop é
   o comportamento esperado, não só um extra. */
.testimonials__loop:hover .testimonials__track { animation-play-state: paused; }
@keyframes testimonials-scroll {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
  .testimonials__track { animation: none; }
}
/* Pedido explícito do usuário: sem o loop automático nem o fade no
   mobile, e o scroll tem que ser VERTICAL — não horizontal. 1ª tentativa
   (mesma rodada) tinha deixado uma lista horizontal arrastável
   (`overflow-x: auto`, cards com largura fixa); usuário viu o resultado
   e pediu pra trocar pra rolagem vertical normal da página, cards
   empilhados um embaixo do outro em largura total, igual a qualquer
   outra fileira de cards do site (Problema, Diferenciais, Como
   funciona) quando empilha no mobile. `flex-direction: column` na
   faixa + `width: 100%` nos cards faz isso sem precisar de nenhum
   scroll container próprio — a seção some do fluxo horizontal e volta a
   fazer parte do scroll normal da página. A 2ª cópia dos cards
   (`aria-hidden="true"`, existia só pra dar a ilusão de loop contínuo
   sem salto) precisa sumir — sem a animação, ela só apareceria como 5
   cards repetidos no fim da lista. */
@media screen and (max-width: 767px) {
  .testimonials__loop {
    overflow: visible;
    -webkit-mask-image: none;
    mask-image: none;
  }
  .testimonials__track {
    flex-direction: column;
    width: auto;
    animation: none;
  }
  .testimonial-card { flex: none; width: 100%; }
  .testimonial-card[aria-hidden="true"] { display: none; }
}

.testimonial-card {
  flex: 0 0 380px;
  display: flex;
  flex-direction: column;
}
.testimonial-card__quote { width: 28px; height: 28px; color: var(--color-brand); margin-bottom: var(--space-sm); flex: none; position: relative; z-index: 1; }
.testimonial-card__text { color: rgba(247, 247, 255, 0.82); font-size: var(--text-sm); line-height: 1.55; margin-bottom: var(--space-m); position: relative; z-index: 1; }
.testimonial-card__footer { display: flex; align-items: center; gap: var(--space-2xs); margin-top: auto; position: relative; z-index: 1; }
.testimonial-card__avatar {
  flex: none;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-secondary);
  font-weight: 700;
  font-size: var(--text-2xs);
  color: var(--text-inverse);
  background: color-mix(in srgb, var(--color-brand) 70%, white);
}
/* variação da cor de marca por posição (mesma disciplina do `.card--vivid`
   — nunca uma paleta nova), pra os avatares não ficarem todos idênticos. */
.testimonial-card:nth-child(5n+2) .testimonial-card__avatar { background: color-mix(in srgb, var(--color-brand) 55%, white); }
.testimonial-card:nth-child(5n+3) .testimonial-card__avatar { background: var(--color-brand); }
.testimonial-card:nth-child(5n+4) .testimonial-card__avatar { background: color-mix(in srgb, var(--color-brand) 85%, white); }
.testimonial-card:nth-child(5n) .testimonial-card__avatar { background: color-mix(in srgb, var(--color-brand) 40%, white); }
.testimonial-card__meta { display: flex; flex-direction: column; gap: 0.1em; }
.testimonial-card__name { font-size: var(--text-xs); font-weight: 600; }
.testimonial-card__role { font-family: var(--font-secondary); font-size: var(--text-2xs); color: rgba(247, 247, 255, 0.55); }

/* ==========================================================================
   FULL WIDTH FEATURE (inverse band)
   ========================================================================== */
.full-width-feature {
  position: relative;
  overflow: hidden;
  background: var(--bg-inverse);
  color: var(--text-inverse);
  border-radius: var(--radius-xl);
  padding: var(--space-2xl) var(--space-xl);
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-sm);
}
/* Mesmo brilho radial + textura de grade do `.card--vivid` (pedido
   explícito do usuário, "adicionar o mesmo plano de fundo do card") —
   mesma posição fixa (20% 0%) usada em `.compare`, pra manter a
   identidade visual consistente entre as sessões escuras do site. */
.full-width-feature::before,
.full-width-feature::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.full-width-feature::before {
  background: radial-gradient(circle at 20% 0%, color-mix(in srgb, var(--color-brand) 65%, transparent) 0%, transparent 62%);
  opacity: 0.85;
}
.full-width-feature::after {
  background-image:
    repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.05) 0 1px, transparent 1px 26px),
    repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.05) 0 1px, transparent 1px 26px);
  -webkit-mask-image: radial-gradient(circle at 20% 0%, black 0%, transparent 68%);
  mask-image: radial-gradient(circle at 20% 0%, black 0%, transparent 68%);
}
.full-width-feature__heading,
.full-width-feature__paragraph,
.full-width-feature__cta-group,
.full-width-feature__secondary-cta {
  position: relative;
  z-index: 1;
}
.full-width-feature__heading { font-size: var(--text-2xl); font-weight: 500; max-width: 30ch; text-wrap: balance; }
/* max-width 62ch (não mais 56ch, 2026-08-22): usuário pediu o parágrafo em
   3 linhas em vez de 4, sem mudar o texto — medido via Playwright, 62ch é
   o menor valor que garante 3 linhas bem balanceadas (~530-560px cada,
   ~5% de diferença entre elas); qualquer valor maior renderiza idêntico,
   já que `text-wrap: balance` sempre busca a largura mínima que ainda
   cabe em 3 linhas. Card tem espaço de sobra (~1150px disponíveis), sem
   risco de estourar. */
.full-width-feature__paragraph { color: rgba(247, 247, 255, 0.7); max-width: 62ch; text-wrap: balance; }
.full-width-feature__cta-group { display: flex; flex-direction: column; align-items: center; gap: var(--space-2xs); }
.full-width-feature__microcopy { font-family: var(--font-secondary); font-size: var(--text-2xs); color: rgba(247, 247, 255, 0.6); }
.full-width-feature__secondary-cta { font-family: var(--font-secondary); font-size: var(--text-sm); color: rgba(247, 247, 255, 0.75); text-decoration: underline; text-underline-offset: 3px; }
.full-width-feature__secondary-cta:hover { color: var(--text-inverse); }
/* Mesmos 2 ajustes já feitos em `.about-outcomes` (seção "Sobre a
   Pruxor") aplicados aqui, pedido explícito do usuário comparando as
   duas sessões escuras: padding igual (`var(--space-l) var(--space-2xs)`
   = 48px/12px) e heading com `line-height` mais apertado (1.15, mesmo
   valor — o heading aqui também não tinha `line-height` próprio, herdava
   o 1.55 solto do body). */
@media screen and (max-width: 767px) {
  .full-width-feature { padding: var(--space-l) var(--space-2xs); }
  .full-width-feature__heading { line-height: 1.15; }
}

/* ==========================================================================
   FAQ ACCORDION
   ========================================================================== */
.faqs__grid { display: grid; grid-template-columns: 0.8fr 1.2fr; gap: var(--space-xl); }
.faq-item { border-bottom: 1px solid var(--border-subtle); }
.faq-item__trigger {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  padding: var(--space-sm) 0;
  text-align: left;
  font-size: var(--text-md);
  font-weight: 500;
}
.faq-item__icon { flex: none; width: 20px; height: 20px; position: relative; }
.faq-item__icon::before, .faq-item__icon::after {
  content: "";
  position: absolute;
  background: var(--color-brand);
  border-radius: 2px;
  transition: transform 0.25s var(--ease-out-expo), opacity 0.25s;
}
.faq-item__icon::before { top: 50%; left: 0; width: 100%; height: 2px; transform: translateY(-50%); }
.faq-item__icon::after { top: 0; left: 50%; width: 2px; height: 100%; transform: translateX(-50%); }
.faq-item.is-open .faq-item__icon::after { opacity: 0; transform: translateX(-50%) rotate(90deg); }
.faq-item__panel { height: 0; overflow: hidden; transition: height 0.3s var(--ease-out-expo); }
.faq-item__answer { padding-bottom: var(--space-sm); color: var(--text-secondary); font-size: var(--text-xs); max-width: 60ch; }

@media screen and (max-width: 767px) {
  .faqs__grid { grid-template-columns: 1fr; }
  /* Headline + subheadline centralizados — pedido explícito do usuário,
     mesmo tratamento aplicado em Soluções/Como funciona/Planilha vs
     Pruxor/Diferenciais. Só o intro (`.faqs__intro`, classe nova — antes
     era uma div sem classe própria) — a lista de perguntas/respostas
     continua alinhada à esquerda, não foi pedido centralizar ela. */
  .faqs__intro { text-align: center; }
}

/* ==========================================================================
   FOOTER
   ========================================================================== */
.site-footer { padding-top: var(--space-2xl); }
.footer__top { display: flex; align-items: center; justify-content: space-between; gap: var(--space-xl); padding-bottom: var(--space-xl); border-bottom: 1px solid var(--border-subtle); flex-wrap: wrap; }
.footer__brand { max-width: 280px; display: flex; flex-direction: column; gap: var(--space-2xs); }
/* Logo real (2026-08-25) — substitui o antigo `.nav__logo-mark` + texto
   "Pruxor". Fundo do rodapé é sempre claro, então sempre a versão preta
   (sem troca de estado, diferente da navbar). */
.footer__logo-img { height: 28px; width: auto; display: block; }
/* 2ª rodada, mesmo dia: usuário pediu pra trocar a logo compacta (ícone+
   "PRUXOR") + `.footer__tagline` (parágrafo à parte, "Gestão
   inteligente...") por UMA imagem só — o lockup completo de
   `assets/Imagens-logo/Logo completa.pdf` (ícone + "PRUXOR" + a tagline
   OFICIAL "Sistema de Gestão e Acompanhamento de Obras", já com o
   texto certo — diferente do PNG usado antes, esse PDF não tinha o erro
   de digitação "ACOMPANHEMTNO"). Como agora é um lockup vertical (ícone
   em cima, texto embaixo, proporção ~1.35:1 largura/altura — bem menos
   "largo" que o `logo-lockup-*` compacto usado na navbar), dimensiona
   por LARGURA (não altura) — `.footer__tagline` (parágrafo separado)
   removido do HTML, redundante com a tagline que já vem dentro da
   imagem. */
.footer__logo-img--completa { width: 200px; height: auto; }
/* Página única: o footer só linka para seções desta mesma página (âncoras),
   não para um sitemap multi-página como no site de referência. */
.footer__nav-links { display: flex; flex-wrap: wrap; gap: var(--space-m); }
.footer__nav-link { font-family: var(--font-secondary); font-size: var(--text-xs); color: var(--text-secondary); }
.footer__nav-link:hover { color: var(--text-primary); }
.footer__contact-links { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2xs); }
.footer__contact-link { font-family: var(--font-secondary); font-size: var(--text-xs); color: var(--text-secondary); }
.footer__contact-link:hover { color: var(--text-primary); }
.footer__bottom { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: var(--space-sm); padding: var(--space-sm) 0; font-family: var(--font-secondary); font-size: var(--text-2xs); color: var(--text-tertiary); }
.footer__legal-links { display: flex; align-items: center; gap: var(--space-2xs); }
.footer__legal-link { color: var(--text-tertiary); }
.footer__legal-link:hover { color: var(--text-secondary); }
.footer__divider { width: 1px; height: 12px; background: var(--border-subtle); flex: none; }

/* Todo o rodapé centralizado no mobile — pedido explícito do usuário
   (antes só `.footer__bottom`, copyright+legal links, já ficava
   centralizado por herdar `align-items: center` da regra base; o resto
   — logo, nav-links, contact-links — estava alinhado à esquerda,
   `align-items: flex-start`). `align-items: center` no `.footer__top`
   (flex column) já centraliza cada bloco filho (`.footer__brand`,
   `.footer__nav-links`, `.footer__contact-links`) como um todo, já que
   eles encolhem pro tamanho do próprio conteúdo nesse modo (em vez de
   esticar pra largura toda); `.footer__contact-links` precisa do
   próprio `align-items: center` além disso, pra centralizar os 2 links
   EMPILHADOS dentro do próprio bloco (e-mail embaixo do Instagram),não
   só o bloco inteiro dentro do rodapé. */
@media screen and (max-width: 767px) {
  .footer__top { flex-direction: column; align-items: center; text-align: center; }
  .footer__bottom { flex-direction: column; gap: var(--space-2xs); text-align: center; }
  .footer__contact-links { flex-direction: column; align-items: center; gap: var(--space-2xs); }
  .footer__contact-links .footer__divider { display: none; }
}

/* ==========================================================================
   PLANOS — sessão "Planos" do index (copy oficial, 2026-08-22): 1 grupo,
   4 planos reais, com preços mensal/anual REAIS. Toggle FUNCIONAL:
   `initBillingToggle` (js/main.js) troca o texto de qualquer elemento com
   `data-monthly`/`data-annual` e alterna `.is-annual` nos `.pricing-card`
   (mostra/esconde parcelamento e economia).
   ========================================================================== */
.billing-toggle {
  display: flex;
  width: fit-content;
  margin: var(--space-m) auto 0;
  padding: 4px;
  background: var(--bg-subtle);
  border-radius: var(--radius-round);
  gap: 4px;
}
.billing-toggle__option {
  padding: 0.55em 1.3em;
  border-radius: var(--radius-round);
  font-family: var(--font-secondary);
  font-size: var(--text-xs);
  font-weight: 500;
  color: var(--text-secondary);
  transition: background-color 0.2s ease, color 0.2s ease;
}
.billing-toggle__option.is-active { background: #fff; color: var(--text-primary); box-shadow: 0 1px 3px var(--ink-10); }
.billing-toggle__hint { margin-top: var(--space-2xs); text-align: center; font-family: var(--font-secondary); font-size: var(--text-2xs); color: var(--text-tertiary); }
/* margin-bottom no header (colapsa com o margin-top do .billing-toggle,
   fica valendo o maior dos dois) — aplicando a lição já registrada em
   CLAUDE.md desde o início, não só depois que o usuário reportar. */
.planos__header { margin-bottom: var(--space-l); }

/* margin-top colapsa com o margin-bottom do irmão anterior (.billing-toggle__hint,
   sem margin próprio, então esse valor é quem define o respiro ali). */
.pricing-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-sm); align-items: stretch; margin-top: var(--space-l); }
.pricing-card {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-m);
  padding: var(--space-m);
}
.pricing-card--featured { border-color: var(--color-brand); box-shadow: 0 0 0 1px var(--color-brand); }
.pricing-card--featured .pricing-card__name,
.pricing-card--featured .pricing-card__amount { color: var(--color-brand); }
.pricing-card__badge {
  position: absolute;
  top: 0;
  left: var(--space-m);
  transform: translateY(-50%);
  background: var(--color-brand);
  color: var(--text-inverse);
  font-family: var(--font-secondary);
  font-size: var(--text-2xs);
  font-weight: 600;
  padding: 0.3em 0.9em;
  border-radius: var(--radius-round);
}
.pricing-card__name { font-size: var(--text-md); font-weight: 600; }
.pricing-card__desc { color: var(--text-secondary); font-size: var(--text-xs); margin-top: 0.3em; min-height: 2.6em; }
.pricing-card__price { margin-top: var(--space-sm); }
.pricing-card__amount { font-size: var(--text-2xl); font-weight: 500; }
.pricing-card__period { color: var(--text-tertiary); font-size: var(--text-xs); margin-left: 0.2em; }
/* Parcelamento/economia escondidos por padrão, só aparecem com
   .is-annual (alternado por initBillingToggle em js/main.js). */
.pricing-card__installment { display: none; color: var(--text-tertiary); font-size: var(--text-2xs); margin-top: 0.3em; }
.pricing-card__savings { display: none; font-family: var(--font-secondary); font-size: var(--text-2xs); font-weight: 600; color: var(--color-brand); margin-top: 0.3em; }
.pricing-card.is-annual .pricing-card__installment,
.pricing-card.is-annual .pricing-card__savings { display: block; }
.pricing-card__features { display: flex; flex-direction: column; gap: 0.65em; margin-top: var(--space-sm); margin-bottom: var(--space-m); flex: 1; }
.pricing-card__features li { display: flex; align-items: flex-start; gap: 0.5em; font-size: var(--text-xs); }
.pricing-card__features svg { width: 16px; height: 16px; flex: none; margin-top: 3px; color: var(--color-brand); }
.pricing-card__cta { justify-content: center; margin-top: auto; }

.planos__strip {
  max-width: 56ch;
  margin: var(--space-l) auto 0;
  text-align: center;
  font-size: var(--text-sm);
  color: var(--text-secondary);
  text-wrap: balance;
}
.planos__implementation {
  max-width: 52ch;
  margin: var(--space-sm) auto 0;
  text-align: center;
  font-family: var(--font-secondary);
  font-size: var(--text-2xs);
  color: var(--text-tertiary);
  text-wrap: balance;
}

/* Bug real (achado testando ~1024px, iPad Pro): o botão "Começar teste
   grátis" de cada `.pricing-card__cta` usa `.btn`, que tem `white-space:
   nowrap` — isso trava a largura mínima de cada card em ~249px
   (min-content, floor do texto sem quebrar). 4 cards + 3 gaps
   (~var(--space-sm)) somam ~1068px de largura mínima pro grid de 4
   colunas, mas o `.layout-container` só chega nesse tamanho a partir de
   ~1260px de viewport (1260 − 2×96px de gutter ≈ 1068px) — abaixo disso
   e acima do breakpoint antigo de 991px, sobrava uma "zona morta" onde a
   4ª coluna ("Pruxor Elite") estourava a largura da página inteira
   (overflow horizontal real, não só um corte visual). Breakpoint subido
   de 991px pra 1260px pra fechar essa zona morta por completo — mesma
   lógica da "faixa tweener" já usada em `.about-outcomes` (1240px) pro
   mesmo tipo de problema (largura mínima de conteúdo não cabendo antes
   do container atingir o tamanho máximo). `.problem__cards`/
   `.value-props__cards` usam o mesmo `repeat(4, 1fr)` mas não têm esse
   problema — não têm CTA com texto sem quebra dentro do card. */
@media screen and (max-width: 1260px) {
  .pricing-grid { grid-template-columns: repeat(2, 1fr); }
}
@media screen and (max-width: 767px) {
  .pricing-grid { grid-template-columns: 1fr; }
}

/* ==========================================================================
   SCROLL REVEAL
   ========================================================================== */
[data-reveal] {
  opacity: 0;
  transform: translateY(18px);
  filter: blur(6px);
  transition: opacity 0.7s var(--ease-out-expo), transform 0.7s var(--ease-out-expo), filter 0.7s var(--ease-out-expo);
}
[data-reveal].is-visible {
  opacity: 1;
  transform: translateY(0);
  filter: blur(0);
}
