/* =====================================================================
   4pbox — Landing · BASE
   Reset enxuto + tipografia + layout + componentes de uso comum.
   Depende de tokens.css.
   ===================================================================== */

*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

/* ---------------- Rolagem encaixada por dobra ----------------
   Ao soltar a rolagem perto de um ponto de encaixe, o navegador termina o
   movimento ali — a mesma curva do `scroll-behavior: smooth` (começa rápido,
   termina suave). Não precisa de biblioteca.

   ⚠️ A unidade do encaixe NÃO é a seção, e isso é medida, não gosto: nenhuma
   seção de conteúdo cabe numa dobra de notebook. "O problema" tem ~1090px
   contra 622px úteis em 1536×695 e 527px em 1280×600 — nem zerando o respiro
   caberia (cabeça + três cards + pé = 739px). Alvo mais alto que a tela faz o
   Chrome relaxar o encaixe de propósito: o spec proíbe snap que torne conteúdo
   inalcançável.

   Por isso o encaixe acontece em DOIS pontos por seção:
     1. topo da seção  → respiro + cabeça + o começo dos cards (convida a rolar)
     2. topo da grade  → os três cards inteiros, e o pé junto quando cabe
   Cada pedaço cabe numa dobra com folga, então o encaixe fica firme — e os três
   cards continuam lado a lado, que é o argumento das seções de comparação.

   ⚠️ Trocar por `mandatory` NÃO muda nada aqui: testado com roda de mouse real
   no mesmo gesto, os dois pararam no mesmo pixel. Fica `proximity` por ser o
   mais conservador. Números em QA.md §"Rolagem encaixada por dobra".

   O `scroll-margin-top` existe por causa do header grudado (72px): sem ele, o
   topo do alvo pára embaixo do header. Isso também conserta os links do menu,
   que tinham o mesmo defeito. */
html { scroll-snap-type: y proximity; }
.hero, .section {
  scroll-snap-align: start;
  scroll-margin-top: 72px;
}

/* Segundo ponto de encaixe: a grade de cards. Só a partir de 900px, que é onde
   as grades viram três colunas — empilhadas em coluna única elas passam de duas
   telas e não haveria o que encaixar. Os 96px são os 72 do header mais 24 de
   ar: encostar o card na borda do header fica apertado. */
@media (min-width: 900px) {
  .leaks, .profiles, .steps, .stats {
    scroll-snap-align: start;
    scroll-margin-top: 96px;
  }
}
/* .about entra depois: é ele quem vira duas colunas só em 1000px. */
@media (min-width: 1000px) {
  .about {
    scroll-snap-align: start;
    scroll-margin-top: 96px;
  }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; scroll-snap-type: none; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

body {
  overflow-x: hidden; /* rede de segurança contra estouro lateral */
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: 1.6;
  color: hsl(var(--foreground));
  background: hsl(var(--background));
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img, svg, video { display: block; max-width: 100%; height: auto; }

/* ---------------- Fundo vivo ----------------
   Camada fixa atrás de todo o conteúdo: três manchas de luz da paleta de
   dados, em opacidade baixíssima, derivando em mais de um minuto — mais
   grão fino para quebrar o banding do gradiente. O teste é simples: se
   alguém notar o movimento em vez do texto, está exagerado.
   Só transform anima; nada aqui recebe evento de ponteiro. */

.fundo {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
}

.fundo i {
  position: absolute;
  display: block;
  border-radius: 50%;
}

/* Split quente/frio: azul entrando pelo alto à esquerda, rosa subindo pela
   direita embaixo, violeta fazendo a transição no meio. É o esquema das
   referências de campanha — o drama vem do contraste entre as duas
   temperaturas, não da saturação de uma cor só. */
.fundo i:nth-child(1) {
  width: 58vmax; height: 58vmax;
  top: -24vmax; left: -16vmax;
  background: radial-gradient(circle, hsl(var(--chart-1) / 0.24), transparent 66%);
  animation: deriva-a 74s var(--ease-standard) infinite alternate;
}
.fundo i:nth-child(2) {
  width: 52vmax; height: 52vmax;
  top: 16vmax; right: -22vmax;
  background: radial-gradient(circle, hsl(var(--chart-4) / 0.20), transparent 66%);
  animation: deriva-b 92s var(--ease-standard) -30s infinite alternate;
}
.fundo i:nth-child(3) {
  width: 48vmax; height: 48vmax;
  bottom: -22vmax; right: -8vmax;
  background: radial-gradient(circle, hsl(var(--chart-5) / 0.22), transparent 66%);
  animation: deriva-c 110s var(--ease-standard) -60s infinite alternate;
}

/* Grão: tira o aspecto liso demais do gradiente sobre fundo escuro.
   Estático — não anima em hipótese alguma. */
.fundo::after {
  content: "";
  position: absolute;
  inset: 0;
  opacity: 0.035;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23g)'/%3E%3C/svg%3E");
}

@keyframes deriva-a {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(7vmax, 5vmax, 0) scale(1.14); }
}
@keyframes deriva-b {
  from { transform: translate3d(0, 0, 0) scale(1.06); }
  to   { transform: translate3d(-6vmax, -7vmax, 0) scale(1); }
}
@keyframes deriva-c {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(-5vmax, -4vmax, 0) scale(1.1); }
}

/* Quem pediu redução não recebe movimento nenhum — as manchas ficam onde
   estão e a página continua com a mesma cor de fundo. Os três seletores
   repetem o :nth-child de propósito: sem isso a especificidade é menor que
   a das regras acima e a animação continuaria declarada. */
@media (prefers-reduced-motion: reduce) {
  .fundo i:nth-child(1),
  .fundo i:nth-child(2),
  .fundo i:nth-child(3) { animation: none; }
}

a { color: inherit; text-decoration: none; }

:focus-visible {
  outline: 2px solid hsl(var(--ring));
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* ---------------- Tipografia ---------------- */

h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: var(--tracking-tight);
  line-height: 1.1;
  text-wrap: balance;
}

h1 { font-size: var(--fs-hero); }
h2 { font-size: var(--fs-h2); }
h3 { font-size: var(--fs-h3); font-weight: 600; line-height: 1.25; }

p { text-wrap: pretty; }

/* Quebra de linha só a partir de telas médias — em mobile o texto flui */
.br-md { display: none; }
@media (min-width: 700px) { .br-md { display: inline; } }

.lead {
  font-size: var(--fs-lead);
  line-height: 1.55;
  color: hsl(var(--muted-foreground));
  max-width: var(--measure);
}

.overline {
  font-size: var(--fs-overline);
  font-weight: 600;
  letter-spacing: var(--tracking-overline);
  text-transform: uppercase;
  color: hsl(var(--brand));
}

.muted { color: hsl(var(--muted-foreground)); }
.measure { max-width: var(--measure); }

/* Texto só para leitor de tela. Existe por causa do carrossel do hero: as
   telas do celular são decorativas (aria-hidden), mas o slide precisa dizer
   o que está mostrando para quem não enxerga. */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---------------- Layout ---------------- */

.container {
  width: 100%;
  max-width: var(--content-max);
  margin-inline: auto;
  padding-inline: var(--page-gutter);
}

.section { padding-block: var(--section-y); }

/* Faixa alternada. Translúcida de propósito: é o que deixa a camada de fundo
   aparecer sob ela. Sem isso, metade da página volta a ser chapada.

   O fundo vive num ::before, e não na própria seção, por um motivo: ele precisa
   de máscara nas bordas. Terminando em linha reta, a faixa cria um degrau
   horizontal visível na troca de dobra — discreto quando a luz de fundo era
   fraca, escancarado depois que ela ficou forte. A máscara dissolve os 120px de
   cima e de baixo, então a faixa entra e sai sem corte.
   Aplicar a máscara na SEÇÃO apagaria o texto junto; por isso o pseudo-elemento.

   isolation: isolate é obrigatório — cria um contexto de empilhamento próprio
   para que o z-index:-1 do ::before fique atrás do conteúdo DESTA seção, e não
   escape para trás da camada .fundo (que também é z-index:-1, mas global).

   A extensão do degradê é `--section-y`, e não um valor fixo: assim a faixa
   termina de entrar exatamente quando o conteúdo começa. Com os 120px fixos de
   antes, o respiro menor em notebook deixaria a overline e metade do h2 fora da
   faixa — a cabeça da seção flutuando sobre o fundo. */
.section--surface {
  position: relative;
  isolation: isolate;
}
.section--surface::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: hsl(var(--surface) / 0.88);
  -webkit-mask-image: linear-gradient(to bottom,
      transparent 0, #000 var(--section-y), #000 calc(100% - var(--section-y)), transparent 100%);
  mask-image: linear-gradient(to bottom,
      transparent 0, #000 var(--section-y), #000 calc(100% - var(--section-y)), transparent 100%);
}
.section__head { margin-bottom: var(--sp-12); }
.section__head .overline { display: block; margin-bottom: var(--sp-3); }
.section__head h2 + p { margin-top: var(--sp-4); }

.grid { display: grid; gap: var(--sp-6); }
@media (min-width: 768px) {
  .grid--3 { grid-template-columns: repeat(3, 1fr); }
  .grid--2 { grid-template-columns: repeat(2, 1fr); }
}

/* ---------------- Componentes ---------------- */

/* Card: borda antes de sombra (princípio do DS) */
.card {
  background: hsl(var(--card));
  border: 1px solid hsl(var(--border));
  border-radius: var(--radius);
  padding: var(--sp-8);
}
.card h3 { margin-bottom: var(--sp-3); }
.card p { color: hsl(var(--muted-foreground)); }

/* Botões */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  padding: 14px 24px;
  font-size: var(--fs-body);
  font-weight: 600;
  border-radius: var(--radius-md);
  border: 1px solid transparent;
  cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-standard),
              border-color var(--duration-fast) var(--ease-standard),
              transform var(--duration-fast) var(--ease-standard);
}
.btn:active { transform: translateY(1px); }

.btn--primary {
  background: hsl(var(--primary));
  color: hsl(var(--primary-foreground));
}
.btn--primary:hover { background: hsl(var(--primary-hover)); }

.btn--ghost {
  background: transparent;
  color: hsl(var(--foreground));
  border-color: hsl(var(--border-strong));
}
.btn--ghost:hover { background: hsl(var(--muted)); }

.btn__icon { width: 20px; height: 20px; flex: none; }

/* Lista com marcador tipográfico (sem bolinha padrão) */
.list-clean { list-style: none; padding: 0; display: grid; gap: var(--sp-4); }
.list-clean li { padding-left: var(--sp-6); position: relative; }
.list-clean li::before {
  content: "—";
  position: absolute;
  left: 0;
  color: hsl(var(--brand));
  font-weight: 700;
}

/* Divisor */
.rule { height: 1px; background: hsl(var(--border)); border: 0; }
