/* ==========================================================================
   Tramóia — Estilos da página
   Mundo escuro texturizado. Os tokens ficam em tokens.css e as primitivas
   reutilizáveis em base.css.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Textura e luz atmosférica
   O campo escuro nunca é chapado: tem grão fino por cima e um halo quente
   que entra por trás do conteúdo. É o que separa este mundo de um dark mode.
   -------------------------------------------------------------------------- */

.grain {
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  opacity: 0.32;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
}

/* O halo. Fica atrás de tudo e não recebe evento.
   --gy, --gs e --go são escritos pelo JS conforme o bloco atravessa a tela.
   Os defaults valem quando o script não roda ou o movimento está reduzido:
   nesse caso o halo existe parado, em vez de sumir. */
.glow {
  position: absolute;
  border-radius: 50%;
  pointer-events: none;
  z-index: 0;
  filter: blur(90px);
  opacity: var(--go, 1);
  /* Promove a camada uma vez: o blur é rasterizado no início e o scroll
     mexe só em transform e opacidade, que não repintam. */
  will-change: transform, opacity;
}

@media (max-width: 700px) {
  /* Camada borrada grande é cara em celular. Menos raio, mesmo efeito. */
  .glow { filter: blur(64px); }
}

/* --------------------------------------------------------------------------
   Header
   Mínimo e transparente, flutuando sobre o campo escuro.
   -------------------------------------------------------------------------- */

/* Três colunas com as laterais em 1fr: o menu do meio fica centrado na tela,
   e não no espaço que sobra entre a marca e o botão. Sem isto, marca e botão
   de larguras diferentes empurram o menu para um dos lados. */
.site-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  /* Acima do painel de menu (70): com o menu aberto, marca e botão de ação
     continuam visíveis e clicáveis, e o "Menu" vira o "Fechar". */
  z-index: 80;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--sp-4);
  height: var(--header-h);
  padding: 0 var(--pad-x);
  transition: background-color var(--dur-hover) var(--ease),
              border-color var(--dur-hover) var(--ease);
  border-bottom: 1px solid transparent;
}

.site-header__mark { justify-self: start; }

.site-header__actions {
  justify-self: end;
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}

/* O rótulo curto só entra em cena abaixo de 600px. Esta linha precisa vir
   ANTES das media queries: mesma especificidade, e a última declaração vence. */
.btn-action__short { display: none; }

/* O botão encolhe junto com a tela. Na referência ele ocupa cerca de um quarto
   da largura; "Falar no WhatsApp" é bem mais longo que "Start a project", então
   sem encolher ele passaria de metade da barra.
   Escopado a ".site-header__actions": ".btn-action" sozinho tem a mesma
   especificidade de ".btn-action--lg"/"--sm", então um seletor genérico aqui
   vazava pra esses botões em outras seções (CTA do fechamento, cards de
   preço) e apertava ícone contra texto neles também. */
@media (max-width: 900px) {
  .site-header__actions .btn-action {
    font-size: 14px;
    padding: 4px 38px 4px 12px;
  }
  .site-header__actions .btn-action:hover { padding: 4px 12px 4px 38px; }
  .site-header__actions .btn-action__icon { right: 4px; width: 26px; height: 26px; }
  .site-header__actions .btn-action__icon svg { width: 12px; height: 12px; }
  .site-header__actions .btn-action:hover .btn-action__icon { right: calc(100% - 30px); }
}

/* Abaixo disto o rótulo inteiro não cabe junto com marca e "Menu" numa linha
   só, então encurta. A ação continua visível, que é o que importa. */
@media (max-width: 600px) {
  .site-header__actions .btn-action { font-size: 13px; padding-left: 11px; }
  .site-header__actions .btn-action:hover { padding: 4px 11px 4px 38px; }
  .btn-action__full  { display: none; }
  .btn-action__short { display: inline; }
}

/* Só ganha fundo depois que a página rola: sobre o hero ele flutua limpo. */
.site-header.is-stuck {
  background: rgba(8, 8, 7, 0.72);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom-color: var(--line-soft);
}

/* A mesma marca do hero, no corpo da barra. Sem text-transform e sem tracking:
   a alternância de caixa é o desenho, e espacejar esta fonte a desmonta. */
.site-header__mark {
  font-family: var(--font-brand);
  font-size: clamp(19px, 1.5vw, 25px);
  font-weight: 400;
  line-height: 1;
  letter-spacing: 0;
  color: var(--ink);
}

.nav-links {
  justify-self: center;
  display: flex;
  align-items: center;
  gap: clamp(14px, 1.5vw, 22px);
}

.nav-links__item {
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: var(--tr-body);
  color: var(--ink-3);
  transition: color var(--dur-hover) var(--ease);
}

.nav-links__item:hover { color: var(--ink); }

/* Texto puro, sem contorno: na referência "Menu" tem o mesmo peso de um link,
   e é ele que vira "Fechar" com o painel aberto. */
.nav-burger {
  display: none;
  align-items: center;
  font-family: var(--font-sans);
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: var(--tr-body);
  color: var(--ink);
  padding: 8px 2px;
}

@media (max-width: 900px) {
  .nav-links { display: none; }
  .nav-burger { display: inline-flex; }

  /* Com o menu do meio escondido, a coluna central do grid continuaria
     ocupando gap e fatia de 1fr, empurrando marca e ações para o centro.
     Sem o menu no meio, duas pontas bastam. */
  .site-header {
    display: flex;
    justify-content: space-between;
  }
}

/* --------------------------------------------------------------------------
   Menu overlay (mobile)
   -------------------------------------------------------------------------- */

/* O véu que escurece a página atrás. O hero continua legível por baixo dele,
   só que apagado: é o que dá a leitura de folha sobreposta em vez de tela nova. */
.nav-scrim {
  position: fixed;
  inset: 0;
  z-index: 65;
  background: rgba(8, 8, 7, 0.86);
  opacity: 0;
  visibility: hidden;
  transition: opacity .45s var(--ease), visibility 0s linear .45s;
}

.nav-scrim.is-open {
  opacity: 1;
  visibility: visible;
  transition: opacity .45s var(--ease), visibility 0s;
}

/* A folha do menu. Altura própria, não tela cheia, e desce do topo.
   Fica ABAIXO do header (80) e ACIMA do véu (65): com ela aberta a marca e o
   botão de ação continuam à vista, e o próprio "Menu" vira "Fechar".

   A visibilidade é por transform e visibility, nunca por display: display não
   transiciona, e sem isto não existe animação de entrada. */
.nav-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 70;
  background: var(--bg);
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  padding: calc(var(--header-h) + clamp(32px, 7vh, 72px)) var(--pad-x) clamp(24px, 4vh, 48px);
  max-height: 100svh;
  overflow-y: auto;
  overscroll-behavior: contain;
  transform: translateY(-100%);
  visibility: hidden;
  transition: transform .55s var(--ease-out), visibility 0s linear .55s;
}

.nav-overlay.is-open {
  transform: translateY(0);
  visibility: visible;
  transition: transform .55s var(--ease-out), visibility 0s;
}

/* Cada link é uma faixa de largura inteira com filete pontilhado embaixo.
   O alvo de toque é a faixa toda, não só as letras. */
.nav-overlay__link {
  display: block;
  padding: clamp(10px, 1.7vh, 18px) 0;
  border-bottom: 1px dotted var(--line);
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(34px, 9vw, 64px);
  line-height: 1.05;
  letter-spacing: var(--tr-head);
  color: var(--ink);
  transition: color var(--dur-hover) var(--ease);
}

.nav-overlay__link:hover { color: var(--muted); }

body.is-nav-open { overflow: hidden; }

/* --------------------------------------------------------------------------
   1. Hero
   Arranjo da referência pinada, decidido pelo Lucas em 09/08/2026:
   a marca ocupa a base da tela em caixa alta e largura quase total, e o texto
   que vende fica centrado no espaço acima dela, em corpo pequeno.
   Isso reverte os requisitos 1 e 2 do briefing, de propósito.
   -------------------------------------------------------------------------- */

.hero {
  position: relative;
  isolation: isolate;
  /* O halo é maior que a viewport de propósito; sem isto ele empurra a
     página na horizontal e cria barra de rolagem lateral. */
  overflow: hidden;
  padding: 0 var(--pad-x);
}

/* Duas faixas: a de cima cresce e centra o texto, a de baixo tem a altura da
   marca. Grid em vez de flex para que a ordem visual não dependa de order. */
.hero__stage {
  min-height: 100svh;
  display: grid;
  grid-template-rows: 1fr auto;
  position: relative;
  /* Vira contêiner de consulta para que a marca possa se dimensionar pela
     largura REAL disponível. Um valor fixo em vw nunca fecha nas duas pontas,
     porque --pad-x é clamp: 18px fixos no estreito, 30px fixos no largo. */
  container-type: inline-size;
}

/* A foto (assets/hero-bg.jpg) como pano de fundo, embaixo da trama animada.
   Meio dessaturada (não preto e branco total) pra deixar a cor original
   meio lavada em vez de sumir, e escurecida com contraste mais baixo pra
   sustentar leitura do texto por cima sem ficar chapada. Mesma sangria de
   --pad-x negativo do .hero__dotmatrix logo abaixo, pelo mesmo motivo. */
.hero__photo {
  position: absolute;
  inset: 0 calc(var(--pad-x) * -1);
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
  background-image: url("../assets/hero-bg.jpg");
  background-size: cover;
  background-position: 50% 30%;
  filter: grayscale(0.5) brightness(0.45) contrast(0.85);
}

/* Trama animada (ruído simplex 3D, ver js/dot-matrix.js), por cima da foto.
   Ocupa a tela inteira: sangra pelas laterais com margem negativa de
   --pad-x porque .hero__stage já nasce inset pelo padding do .hero, e "toda
   a tela" pede ir até a borda real da viewport, não até a borda do padding.
   O .hero { overflow: hidden } existente contém a sangria sem gerar scroll
   lateral. Substituiu o .hero__glow (halo radial) removido em 11/08/2026. */
.hero__dotmatrix {
  position: absolute;
  inset: 0 calc(var(--pad-x) * -1);
  z-index: 1;
  pointer-events: none;
  overflow: hidden;
}

/* Esmaece foto + trama nos últimos ~15% da tela, pra entrar sem corte seco
   na seção seguinte (Manifesto) — mesma ideia do .closing::after. Fica só
   nessa faixa final: esmaecer mais alto competiria com o wordmark, que já
   assenta bem na base da tela. */
.hero__stage::after {
  content: "";
  position: absolute;
  inset: 0 calc(var(--pad-x) * -1);
  z-index: 2;
  pointer-events: none;
  background: linear-gradient(
    180deg,
    transparent 0%,
    transparent 85%,
    color-mix(in srgb, var(--bg) 85%, transparent) 100%
  );
}

.hero__dotmatrix canvas {
  display: block;
  width: 100%;
  height: 100%;
}

/* O bloco central. Medida curta de propósito: é ela que força a quebra em
   três linhas e dá a silhueta da referência. */
.hero__center {
  grid-row: 1;
  align-self: center;
  justify-self: center;
  position: relative;
  z-index: 3;
  max-width: 30ch;
  padding-top: var(--header-h);
  text-align: center;
}

.hero__title {
  font-size: clamp(18px, 1.55vw, 25px);
  font-weight: 500;
  line-height: 1.28;
  letter-spacing: var(--tr-sub);
  color: var(--ink);
  text-wrap: balance;
}

/* A virada da headline: muda a cor, para continuar perceptível antes da
   leitura mesmo com a frase em corpo pequeno. */
.hero__turn {
  font-style: normal;
  color: var(--muted);
}

/* O caminho de preço, que os dois botões carregavam antes. Discreto de
   propósito: sem ele, a triagem de quem não pode pagar sai da primeira tela. */
.hero__price {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: clamp(28px, 4.5vh, 52px);
  padding-bottom: 5px;
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  border-bottom: 1px solid var(--line);
  transition: color var(--dur-hover) var(--ease),
              border-color var(--dur-hover) var(--ease);
}

.hero__price:hover {
  color: var(--ink);
  border-color: var(--ink);
}

/* A marca, assentada na base da tela e quase encostando nas bordas.
   A entrelinha curta é o que traz a base das maiúsculas para perto do rodapé;
   nowrap garante que ela nunca quebre em duas linhas. */
.hero__wordmark {
  grid-row: 2;
  position: relative;
  z-index: 3;
  margin: 0;
  /* Em em, não em px: a Dirtyline assenta mais baixo na caixa que a fonte
     anterior, e a sobra abaixo da linha cresce junto com o corpo. Em px, o
     texto encostaria certo numa largura e vazaria em todas as outras. */
  padding-bottom: max(6px, 0.13em);
  font-family: var(--font-brand);
  font-weight: 400;
  font-size: var(--fs-wordmark);
  line-height: 0.8;
  /* Sem text-transform: a alternância de caixa de "trAmóia.dEsign" é
     conteúdo, não estilo, e maiusculizar por CSS a destruiria. */
  letter-spacing: 0;
  white-space: nowrap;
  /* 80% de tinta, não 80% de opacidade do elemento: a marca leva data-reveal,
     e o GSAP anima opacity nesse atributo via style inline (js/main.js), que
     sempre vence qualquer opacity declarado aqui em stylesheet. O alfa na
     cor não conflita com isso. */
  color: rgba(232, 232, 227, 0.8);
  color: color-mix(in srgb, var(--ink) 80%, transparent);
}

/* O caminho exato: 100cqw é a largura útil do stage, e dividida pela largura
   do texto em ems dá o corpo que preenche a linha inteira em qualquer tela. */
@supports (container-type: inline-size) {
  .hero__wordmark { font-size: calc(100cqw / var(--wordmark-k)); }
}

/* --------------------------------------------------------------------------
   Cabeçalhos de seção
   -------------------------------------------------------------------------- */

.section__head { margin-bottom: var(--sec-sm); }

.section__title {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--fs-h2-sm);
  line-height: var(--lh-head);
  letter-spacing: var(--tr-head);
}

.section__note {
  margin-top: var(--sp-2);
  font-size: var(--fs-body);
  color: var(--muted);
}

.head-split {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--sp-4);
}

/* --------------------------------------------------------------------------
   2. Manifesto
   -------------------------------------------------------------------------- */

.manifesto { position: relative; isolation: isolate; overflow: hidden; }

.manifesto__glow {
  width: min(90vw, 900px);
  height: 480px;
  right: -10%;
  top: -20%;
  transform: translateY(var(--gy, 0px)) scale(var(--gs, 1));
  background: radial-gradient(closest-side, var(--glow-edge), transparent 70%);
}

/* Duas colunas com vão largo, como na referência: a estreita carrega fio,
   rótulo e título; a larga carrega a declaração em medida curta. */
.manifesto__grid {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: minmax(0, 0.42fr) minmax(0, 1fr);
  gap: clamp(32px, 7vw, 140px);
  align-items: start;
}

/* Sem isto os filhos herdam min-width:auto e recusam encolher abaixo do
   conteúdo, estourando a página na horizontal em telas estreitas. */
.manifesto__grid > * { min-width: 0; }

@media (max-width: 860px) {
  .manifesto__grid { grid-template-columns: 1fr; gap: var(--sp-5); }
}

/* O manifesto abre sem fio entre seções: quem marca a abertura é a linha
   sobre o título, dentro da coluna. */
.manifesto::before { display: none; }

/* O fio da coluna, na largura dela e não do texto. */
.manifesto__aside::before {
  content: "";
  display: block;
  height: 1px;
  background-image: var(--rule-dot);
  margin-bottom: var(--sp-4);
}

.manifesto__title {
  max-width: 34ch;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(23px, 2.3vw, 38px);
  line-height: 1.12;
  letter-spacing: var(--tr-head);
  color: var(--ink);
}

/* A declaração para a 80% da coluna: com a página inteira agora na largura do
   hero, a coluna larga sozinha deixaria a linha comprida demais para ler. */
.manifesto__statement { max-width: 80%; }

@media (max-width: 860px) {
  /* Em coluna única, 80% viraria uma sobra estranha à direita. */
  .manifesto__statement { max-width: 100%; }
}

.manifesto__statement p {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(24px, 2.85vw, 47px);
  line-height: 1.16;
  letter-spacing: var(--tr-head);
  color: var(--ink-2);
  /* Impede palavra órfã na última linha. O corpo menor resolve nesta largura;
     isto mantém resolvido nas outras, sem depender de sorte de medida. */
  text-wrap: pretty;
}

/* O respiro entre os dois blocos é a linha em branco da referência. */
.manifesto__statement p + p { margin-top: 1.05em; }

.manifesto__statement .serif-em { color: var(--ink); }

/* A frase final recua para cinza, como o fecho da referência. Cor sólida,
   não gradiente no texto: mesmo efeito, sem o truque. */
.manifesto__trail { color: var(--muted); }

.serif-em {
  font-style: normal;
  color: var(--ink);
}

/* --------------------------------------------------------------------------
   2b. A distância
   Seção alta com palco preso: a altura extra é a pista de rolagem que move a
   animação. --p vai de 0 a 1 conforme o palco atravessa, escrito pelo JS.
   O default é 1, o estado resolvido: sem JS ou com movimento reduzido, a
   composição nasce fechada em vez de ficar quebrada.
   -------------------------------------------------------------------------- */

.converge {
  --p: 1;
  height: 190vh;
  /* clip, não hidden: as metades da frase saem 34vw para cada lado e precisam
     ser cortadas, mas 'hidden' criaria um contêiner de rolagem próprio e
     quebraria o position:sticky do palco. 'clip' corta sem criar contêiner. */
  overflow-x: clip;
  padding-left: var(--pad-x);
  padding-right: var(--pad-x);
  padding-top: 0;
  padding-bottom: 0;
}

/* A frase fica no centro exato da tela e o parágrafo é preso na base. Por isso
   o parágrafo sai do fluxo: em fluxo normal ele empurraria a frase para cima
   e ela deixaria de estar no meio. */
.converge__stage {
  position: sticky;
  top: 0;
  height: 100svh;
  display: grid;
  place-items: center;
}

/* A imagem cresce enquanto as metades se aproximam. Fica atrás do texto:
   no início ela ocupa o vão, no fim o texto passa por cima dela. */
.converge__media {
  position: absolute;
  z-index: 1;
  margin: 0;
  width: clamp(150px, 17vw, 290px);
  aspect-ratio: 4 / 5;
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--card);
  display: flex;
  align-items: center;
  justify-content: center;
  transform: scale(calc(0.52 + var(--p) * 0.48));
  will-change: transform;
}

.converge__media img { width: 100%; height: 100%; object-fit: cover; }

/* Véu sobre a imagem: com foto real por baixo, o texto pesado passa por cima
   e precisa de piso de contraste garantido, não de sorte de enquadramento. */
.converge__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(8, 8, 7, 0.35);
}

/* Uma linha só, centrada. O vão entre as metades encolhe até virar um espaço
   de palavra: é o gap que faz a animação inteira, não dois transforms. */
.converge__line {
  position: relative;
  z-index: 2;
  display: flex;
  justify-content: center;
  align-items: baseline;
  flex-wrap: nowrap;
  white-space: nowrap;
  gap: 0.3em;
  /* Mesma família do wordmark. Tracking em zero: esta fonte já traz o
     espacejamento no desenho e apertar fecha as formas. */
  font-family: var(--font-brand);
  font-weight: 400;
  font-size: clamp(30px, 6.4vw, 108px);
  line-height: 0.95;
  letter-spacing: 0;
  /* Sem text-transform: a alternância de caixa é o que escolhe entre caixa
     alta reta e cursiva nesta fonte, então ela é conteúdo, não estilo. */
  color: var(--ink);
}

/* Cada metade anda para o seu lado, e a linha guarda sempre a largura fechada.
   Animar o `gap` não servia: a linha crescia, estourava a área do grid, e
   conteúdo que estoura é ancorado na borda inicial, então tudo ia para a
   direita e a metade esquerda ficava parada na margem. Com transform o
   movimento é simétrico por construção, e ainda sai de graça no compositor,
   enquanto `gap` forçava recálculo de layout a cada quadro. */
.converge__half {
  display: inline-block;
  will-change: transform;
}

.converge__half:first-child { transform: translateX(calc((var(--p) - 1) * 34vw)); }
.converge__half:last-child  { transform: translateX(calc((1 - var(--p)) * 34vw)); }

.converge__body {
  position: absolute;
  z-index: 2;
  bottom: clamp(28px, 6vh, 76px);
  left: 50%;
  transform: translateX(-50%);
  width: min(46ch, 100%);
  text-align: center;
  /* Mesmo tratamento da nota de seção ("Todos no ar. Pode clicar e conferir"):
     corpo de leitura em cinza, para não competir com a frase grande. */
  font-size: var(--fs-body);
  line-height: var(--lh-read);
  color: var(--muted);
}

/* No estreito a frase não cabe numa linha: as metades empilham e o vão vira
   vertical, mas o movimento de encontro permanece. */
@media (max-width: 720px) {
  .converge { height: 170vh; }
  .converge__line {
    flex-direction: column;
    align-items: center;
    gap: 0.05em;
    text-align: center;
  }
  /* Empilhadas, mas ainda entrando de lados opostos: o encontro continua sendo
     horizontal, que é o que a frase precisa. */
  .converge__half:first-child { transform: translateX(calc((var(--p) - 1) * 62vw)); }
  .converge__half:last-child  { transform: translateX(calc((1 - var(--p)) * 62vw)); }
  .converge__media { width: clamp(130px, 42vw, 200px); }
}

@media (prefers-reduced-motion: reduce) {
  /* Sem pista de rolagem: a seção vira uma tela só, já resolvida. */
  .converge { height: auto; padding-top: var(--sec-lg); padding-bottom: var(--sec-lg); }
  .converge__stage { position: static; height: auto; }
}

/* --------------------------------------------------------------------------
   3. Portfólio
   A única seção de superfície clara da página. A inversão é o destaque: num
   campo todo escuro, virar a folha vale mais que qualquer borda ou caixa.
   -------------------------------------------------------------------------- */

.works-section {
  background: var(--ink);
  color: var(--bg);
}

/* A troca de cor já separa da seção anterior; um fio ali seria redundante. */
.works-section::before { display: none; }

/* Título à esquerda da página, projetos começando onde ele termina. */
.works {
  display: grid;
  /* auto: a coluna mede exatamente o título, que não quebra. Um valor em fr
     seria um número mágico a recalibrar a cada mudança de corpo ou de texto. */
  grid-template-columns: auto minmax(0, 1fr);
  gap: clamp(28px, 4vw, 72px);
  align-items: start;
}

.works > * { min-width: 0; }

.works__title {
  font-family: var(--font-display);
  font-weight: 600;
  white-space: nowrap;
  font-size: var(--fs-h2-sm);
  line-height: 1;
  letter-spacing: var(--tr-head);
  color: var(--bg);
}

.works__note {
  margin-top: var(--sp-2);
  font-size: var(--fs-body);
  line-height: var(--lh-read);
  color: var(--line-2);
}

.works__list {
  display: flex;
  flex-direction: column;
}

/* A primeira linha começa colada no topo: sem isto o respiro dela empurraria
   imagem e texto para baixo, e o título ficaria desalinhado. */
.works__list li:first-child .work { padding-top: 0; }

/* Fio entre linhas, nunca antes da primeira. */
.works__list li + li {
  background-image: var(--rule-dot-dark);
  background-repeat: no-repeat;
  background-size: 100% 1px;
  background-position: 0 0;
}

/* A linha inteira é o link: o alvo é a faixa toda, não um texto dentro dela. */
.work {
  display: grid;
  grid-template-columns: minmax(0, 1.34fr) minmax(0, 0.7fr);
  gap: clamp(20px, 3vw, 56px);
  align-items: start;
  padding: clamp(24px, 3.4vw, 48px) 0;
  color: inherit;
}

.work > * { min-width: 0; }

.work__shot {
  position: relative;
  aspect-ratio: 16 / 10;
  background: var(--surface);
  border-radius: var(--radius);
  overflow: hidden;
}

/* O invólucro é 36% mais alto que a moldura e nasce 18% acima dela. É essa
   sobra que o parallax consome: deslocar até 18% da altura nunca descobre
   borda (AMPLITUDE em main.js é 0.16, com folga de 2%). Efeito mais forte
   a pedido — aumentado junto com a AMPLITUDE, os dois sempre andam juntos.
   Ele carrega o deslocamento; a imagem carrega a escala do hover. Duas camadas
   porque um transform só não acumula os dois sem brigar na transição. */
.work__par {
  position: absolute;
  inset: -18% 0;
  transform: translate3d(0, var(--py, 0px), 0);
  will-change: transform;
}

.work__shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--dur-card) var(--ease);
}

.work:hover .work__shot img { transform: scale(1.03); }

.work__info {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--sp-2);
}

/* A numeração abre o bloco e tem peso próprio: o número corrente em tinta
   cheia, o total recuado, para o olho ler primeiro em que projeto está. */
.work__count {
  font-size: 15px;
  letter-spacing: 0.12em;
  color: var(--bg);
}

.work__count .de { color: var(--line-2); }

.work__name {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(24px, 2.2vw, 36px);
  line-height: 1.05;
  letter-spacing: var(--tr-head);
  color: var(--bg);
}

.work__desc {
  font-size: var(--fs-body);
  line-height: var(--lh-read);
  color: var(--line-2);
  max-width: 40ch;
}

/* Onde a referência põe a métrica. Aqui não existe métrica de cliente para
   mostrar, e a tag é real: é ela que faz o portfólio provar o cardápio. */
.work__tag {
  margin-top: var(--sp-3);
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--bg);
  /* Mesma forma do botão de ação: canto curto de 6px com contorno, e não
     pílula. É o vocabulário de controle do sistema. */
  border: 1px solid rgba(8, 8, 7, 0.28);
  border-radius: var(--radius-btn);
  padding: 8px 14px;
}

.work__live {
  margin-top: var(--sp-2);
  color: var(--line-2);
  transition: color var(--dur-hover) var(--ease);
}

.work__live .arrow {
  display: inline-block;
  transition: transform var(--dur-hover) var(--ease);
}

.work:hover .work__live { color: var(--bg); }
.work:hover .work__live .arrow { transform: translate(3px, -3px); }

/* O anel de foco padrão é bege e sumiria nesta superfície. */
.works-section :focus-visible {
  outline: 2px solid var(--bg);
  outline-offset: 6px;
}

@media (max-width: 860px) {
  .works { grid-template-columns: 1fr; gap: var(--sp-5); }
  .works__title { white-space: normal; }
  .works__list li:first-child .work { padding-top: 0; }
  .work { grid-template-columns: 1fr; gap: var(--sp-4); }
  .work__desc { max-width: none; }
}

/* --------------------------------------------------------------------------
   4. Serviços e preços
   Um produto por linha, não card. O preço fica na mesma coluna nas três,
   que é o que permite comparar de relance.
   -------------------------------------------------------------------------- */

.precos {
  container-type: inline-size;
  overflow-x: clip;
}

.precos__title {
  font-family: var(--font-brand);
  font-weight: 400;
  font-size: var(--fs-precos, 8vw);
  line-height: 0.9;
  letter-spacing: 0;
  white-space: nowrap;
  color: var(--ink);
}

@supports (container-type: inline-size) {
  .precos__title { font-size: calc(100cqw / var(--precos-k, 16.48)); }
}

/* As linhas não usam a largura toda: encostam à direita, contra o título que
   sangra de margem a margem. A assimetria é o que dá a leitura de bloco. */
.plans {
  margin-top: clamp(48px, 6vw, 96px);
  width: min(100%, 82%);
  margin-left: auto;
  /* As trilhas vivem aqui, não em cada linha. Com o grid por linha, as colunas
     auto mediam o próprio conteúdo e cada produto alinhava num lugar. */
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr) auto;
  gap: 0 clamp(14px, 1.6vw, 28px);
}

.plan {
  display: grid;
  /* subgrid: a linha ocupa as quatro trilhas da lista em vez de criar as suas,
     e é isso que mantém nome, preço, descrição e botão alinhados entre os três
     produtos. */
  grid-column: 1 / -1;
  grid-template-columns: subgrid;
  align-items: start;
  padding: clamp(26px, 3vw, 44px) 0;
}

.plan > * { min-width: 0; }

/* Fio entre produtos, nunca antes do primeiro. */
.plans li + li {
  background-image: var(--rule-dot);
  background-repeat: no-repeat;
  background-size: 100% 1px;
  background-position: 0 0;
}

.plan__name {
  white-space: nowrap;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(22px, 2vw, 32px);
  line-height: 1.05;
  letter-spacing: var(--tr-head);
  color: var(--ink);
}

.plan__term {
  display: block;
  margin-top: var(--sp-2);
  color: var(--muted);
}

/* nowrap e coluna própria: sem isto "R$" e o número quebram em duas linhas,
   e o preço é o momento de maior risco da página. */
.plan__price {
  white-space: nowrap;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(22px, 2vw, 32px);
  line-height: 1.05;
  letter-spacing: var(--tr-head);
  color: var(--ink);
}

.plan__desc {
  font-size: var(--fs-body);
  line-height: var(--lh-read);
  color: var(--muted);
}

.plan__list {
  margin-top: var(--sp-3);
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: var(--fs-label);
  color: var(--ink-3);
}

.plan__list li { display: flex; gap: 10px; }
.plan__list li::before { content: "·"; color: var(--muted); }

.plan__cta { align-self: start; }

.plans-foot {
  width: min(100%, 82%);
  margin-left: auto;
  margin-top: clamp(40px, 5vw, 72px);
  padding-top: clamp(28px, 3vw, 44px);
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  background-image: var(--rule-dot);
  background-repeat: no-repeat;
  background-size: 100% 1px;
  background-position: 0 0;
}

.plans-foot p {
  font-size: var(--fs-label);
  line-height: var(--lh-read);
  color: var(--muted);
}

@media (max-width: 1200px) {
  /* Sem espaço para nome inteiro numa linha, deixa quebrar em vez de estourar. */
  .plan__name { white-space: normal; }
}

@media (max-width: 1000px) {
  .plans, .plans-foot { width: 100%; }
  /* Abaixo disto as quatro colunas espremem o preço e a lista. Vira duas. */
  .plan {
    grid-template-columns: minmax(0, 1fr) auto;
    gap: var(--sp-3) var(--sp-4);
  }
  .plan__id { grid-column: 1; }
  .plan__price { grid-column: 2; text-align: right; }
  .plan__detail { grid-column: 1 / -1; }
  .plan__cta { grid-column: 1 / -1; justify-self: start; }
}

@media (max-width: 860px) {
  .precos__title { white-space: normal; }
}

/* --------------------------------------------------------------------------
   5. Processo
   Título em escala de página, e cada etapa ocupando uma faixa inteira: meta,
   texto e imagem sangrando até a borda direita.
   -------------------------------------------------------------------------- */

.processo {
  /* A imagem sangra até a borda; o padding lateral do lado direito sai daqui
     e volta como margem negativa na lista. */
  container-type: inline-size;
  overflow-x: clip;
}

/* Mesma técnica do wordmark: o corpo vem da largura útil, não de uma fração
   da viewport, então a linha fecha em qualquer tela. --processo-k é a largura
   do texto em ems, medida no elemento renderizado. */
.processo__title {
  font-family: var(--font-brand);
  font-weight: 400;
  font-size: var(--fs-processo, 9vw);
  line-height: 0.9;
  letter-spacing: 0;
  white-space: nowrap;
  color: var(--ink);
  margin-bottom: clamp(48px, 7vw, 120px);
}

@supports (container-type: inline-size) {
  .processo__title { font-size: calc(100cqw / var(--processo-k, 13.85)); }
}

/* Uma etapa por coluna: as quatro lado a lado, lidas da esquerda para a
   direita como a sequência que são. */
.steps {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  /* Cinco trilhas de linha: número, ícone, título, texto e a linha do cliente.
     Cada etapa as herda por subgrid, e é isso que alinha as quatro pelo topo
     de cada parte, mesmo quando uma delas quebra em duas linhas. */
  grid-template-rows: repeat(5, auto);
  column-gap: clamp(20px, 2.6vw, 52px);
}

.step {
  grid-row: 1 / -1;
  display: grid;
  grid-template-rows: subgrid;
  align-items: start;
  justify-items: start;
  row-gap: var(--sp-3);
  padding: clamp(24px, 3vw, 44px) 0;
}

/* Fio entre colunas, nunca antes da primeira. Metade do vão de padding e
   metade de margem negativa: o conteúdo segue alinhado à trilha e o fio cai
   no meio do vão, e não colado na coluna anterior. */
.steps .step + .step {
  padding-left: calc(clamp(20px, 2.6vw, 52px) / 2);
  margin-left: calc(clamp(20px, 2.6vw, 52px) / -2);
  background-image: var(--rule-dot-v);
  background-repeat: no-repeat;
  background-size: 1px 100%;
  background-position: 0 0;
}

.step > * { min-width: 0; }

.step__n { color: var(--muted); }

/* O ícone entra por máscara, não por <img>: assim herda a cor do texto e
   continua legível se a superfície inverter. Os arquivos originais vinham com
   gradiente, que foi trocado por currentColor. */
.step__icon {
  width: clamp(68px, 7vw, 116px);
  height: clamp(68px, 7vw, 116px);
  background: var(--ink-3);
  -webkit-mask: center / contain no-repeat;
  mask: center / contain no-repeat;
}

.step__icon[data-icon="35"] { -webkit-mask-image: url(../assets/icones/35.svg); mask-image: url(../assets/icones/35.svg); }
.step__icon[data-icon="1"]  { -webkit-mask-image: url(../assets/icones/1.svg);  mask-image: url(../assets/icones/1.svg); }
.step__icon[data-icon="59"] { -webkit-mask-image: url(../assets/icones/59.svg); mask-image: url(../assets/icones/59.svg); }
.step__icon[data-icon="70"] { -webkit-mask-image: url(../assets/icones/70.svg); mask-image: url(../assets/icones/70.svg); }

.step__title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(24px, 2.2vw, 36px);
  line-height: 1.05;
  letter-spacing: var(--tr-head);
  color: var(--ink);
}

.step__text {
  font-size: var(--fs-body);
  line-height: var(--lh-read);
  color: var(--muted);
}

/* O que o cliente faz na etapa. É o que diferencia esta seção. */
.step__you {
  padding-top: var(--sp-2);
  display: inline-flex;
  gap: 10px;
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink);
}

@media (max-width: 1100px) {
  /* Com duas colunas o subgrid de linhas colidiria, então cada etapa volta a
     ser uma pilha independente. */
  .steps {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-rows: none;
  }
  .step {
    grid-row: auto;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
  }
  /* Com duas colunas o fio some da terceira, que abre linha nova. */
  .steps .step:nth-child(odd) {
    padding-left: 0;
    margin-left: 0;
    background-image: none;
  }
}

@media (max-width: 640px) {
  .steps { grid-template-columns: 1fr; gap: 0; }
  .steps .step + .step {
    padding-left: 0;
    margin-left: 0;
    background-image: var(--rule-dot);
    background-size: 100% 1px;
  }
}

@media (max-width: 900px) {
  .processo__title { white-space: normal; }
}

/* --------------------------------------------------------------------------
   6. Sobre e prova social
   Três colunas: depoimentos, texto e retrato. A do meio é a mais larga.
   -------------------------------------------------------------------------- */

/* Sobre e FAQ dividem uma faixa de superfície um degrau acima do campo. É o
   mesmo --card que os cards usavam, então nenhuma cor nova entrou. */
.sobre,
.faq { background: var(--card); }

/* A troca de cor já separa da seção anterior; o fio ali seria redundante.
   Entre sobre e FAQ, que compartilham o fundo, ele continua fazendo falta. */
.sobre::before { display: none; }

.sobre__grid {
  display: grid;
  grid-template-columns: minmax(0, 0.72fr) minmax(0, 1.7fr) minmax(0, 0.6fr);
  gap: clamp(28px, 3.6vw, 72px);
  align-items: start;
}

.sobre__grid > * { min-width: 0; }

/* --- Carrossel de depoimentos --- */

.depo { display: flex; flex-direction: column; }

/* A barra é o progresso: o preenchimento cresce a cada depoimento. */
.depo__bar {
  height: 1px;
  background: var(--line);
  margin-bottom: var(--sp-4);
}

.depo__fill {
  display: block;
  height: 100%;
  background: var(--ink);
  transition: width var(--dur-hover) var(--ease);
}

.depo__nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  margin-bottom: var(--sp-5);
}

.depo__setas { display: flex; gap: var(--sp-2); }

.depo__seta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  color: var(--ink);
  transition: color var(--dur-hover) var(--ease),
              transform var(--dur-hover) var(--ease);
}

.depo__seta svg { width: 20px; height: 14px; display: block; }
.depo__seta:hover { color: var(--cta); }
.depo__seta[data-depo-prev]:hover { transform: translateX(-2px); }
.depo__seta[data-depo-next]:hover { transform: translateX(2px); }

.depo__count { color: var(--muted); }

.depo__label {
  color: var(--muted);
  margin-bottom: var(--sp-4);
}

/* O palco tem a altura do depoimento mais alto: sem isto a página pula de
   altura a cada troca. As peças se sobrepõem em grid. */
.depo__palco { display: grid; }

.depo__item {
  grid-area: 1 / 1;
  margin: 0;
  opacity: 0;
  visibility: hidden;
  transform: translateY(8px);
  transition: opacity var(--dur-hover) var(--ease),
              transform var(--dur-hover) var(--ease),
              visibility 0s linear var(--dur-hover);
}

.depo__item.is-on {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity var(--dur-hover) var(--ease),
              transform var(--dur-hover) var(--ease),
              visibility 0s;
}

.depo__texto {
  font-size: clamp(17px, 1.5vw, 22px);
  line-height: 1.4;
  letter-spacing: var(--tr-sub);
  color: var(--ink);
}

.depo__pessoa {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin-top: var(--sp-4);
}

.depo__avatar {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
}

.depo__quem {
  color: var(--muted);
}

/* --- Coluna do meio --- */

.sobre__title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(28px, 3vw, 48px);
  line-height: 1.05;
  letter-spacing: var(--tr-head);
  color: var(--ink);
  max-width: 20ch;
}

.sobre__bio { margin-top: clamp(28px, 3vw, 48px); }

.sobre__bio p {
  font-size: var(--fs-body);
  line-height: var(--lh-read);
  color: var(--muted);
  max-width: 66ch;
}

.sobre__bio p + p { margin-top: var(--sp-3); }

.sobre__logos { margin-top: clamp(32px, 3.4vw, 56px); }
.sobre__logos .mono { color: var(--muted); }

.chips {
  margin-top: var(--sp-3);
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
}

/* Empresas onde ele trabalhou, nunca clientes: o rótulo acima diz isso. */
.chip {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
  border: 1px solid var(--line);
  border-radius: var(--radius-btn);
  padding: 9px 15px;
}

/* --- Retrato --- */

.sobre__foto {
  margin: 0;
  aspect-ratio: 4 / 5;
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--card);
}

/* Fotografia colorida quebraria o monocromo da página. O filtro a traz para a
   mesma família quente: cinza puro, um grão de sépia para o quente do campo,
   e contraste levemente aberto para não achatar no fundo escuro. */
.sobre__foto img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: grayscale(1) sepia(0.22) contrast(1.06) brightness(0.94);
}

@media (max-width: 1100px) {
  .sobre__grid { grid-template-columns: minmax(0, 1fr) minmax(0, 0.7fr); }
  .sobre__main { grid-column: 1; grid-row: 1; }
  .depo { grid-column: 1; grid-row: 2; }
  .sobre__foto { grid-column: 2; grid-row: 1 / span 2; }
}

@media (max-width: 700px) {
  .sobre__grid { grid-template-columns: 1fr; }
  .sobre__main,
  .depo,
  .sobre__foto { grid-column: 1; grid-row: auto; }
  .sobre__foto { max-width: 320px; }
}

/* --------------------------------------------------------------------------
   7. FAQ
   Cada pergunta é uma faixa inteira que inverte no hover: o alvo é a barra
   toda, não o texto, e a inversão é o mesmo recurso de destaque do resto do
   sistema. A coluna da esquerda fica reservada.
   -------------------------------------------------------------------------- */

.faq__grid {
  display: grid;
  grid-template-columns: minmax(0, 0.55fr) minmax(0, 1fr);
  gap: clamp(28px, 4vw, 72px);
}

.faq__grid > * { min-width: 0; }

/* O título ocupa a coluna da esquerda, ao lado das perguntas e não acima. */
.faq__title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(26px, 2.6vw, 42px);
  line-height: 1.08;
  letter-spacing: var(--tr-head);
  color: var(--ink);
}

.faq__list { border-top: 0; }

.faq__item {
  background-image: var(--rule-dot);
  background-repeat: no-repeat;
  background-size: 100% 1px;
  background-position: 0 100%;
}

.faq__q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  padding: clamp(10px, 1vw, 14px) clamp(14px, 1.4vw, 22px);
  font-size: clamp(16px, 1.45vw, 21px);
  font-weight: 500;
  letter-spacing: var(--tr-body);
  color: var(--ink);
  list-style: none;
  cursor: pointer;
  transition: background-color var(--dur-hover) var(--ease),
              color var(--dur-hover) var(--ease);
}

.faq__q::-webkit-details-marker { display: none; }

/* A barra inteira inverte. Aberta, permanece invertida: o estado ligado e o
   estado sob o cursor são o mesmo desenho, então não há dúvida de qual está
   ativa. */
.faq__q:hover,
.faq__item[open] .faq__q {
  background: var(--ink);
  color: var(--bg);
}

.faq__text { flex: 1; }

/* O ponto à direita: contorno em repouso, cheio quando a barra inverte. */
.faq__dot {
  flex-shrink: 0;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  border: 1px solid var(--muted);
  transition: background-color var(--dur-hover) var(--ease),
              border-color var(--dur-hover) var(--ease);
}

.faq__q:hover .faq__dot,
.faq__item[open] .faq__dot {
  background: var(--bg);
  border-color: var(--bg);
}

.faq__a {
  padding: var(--sp-2) clamp(14px, 1.4vw, 22px) var(--sp-5);
  max-width: 90ch;
}

.faq__p {
  font-size: var(--fs-body);
  line-height: var(--lh-read);
  color: var(--muted);
}

.faq__p + .rate-table,
.rate-table + .faq__p { margin-top: var(--sp-3); }

.rate-table {
  display: flex;
  flex-direction: column;
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.04em;
}

.rate-table__row {
  display: flex;
  justify-content: space-between;
  gap: var(--sp-2);
  padding: var(--sp-2) 0;
  border-bottom: 1px solid var(--line-soft);
  color: var(--muted);
}

.rate-table__row span:last-child { color: var(--ink); }

@media (max-width: 860px) {
  .faq__grid { grid-template-columns: 1fr; gap: var(--sp-5); }
}

/* --------------------------------------------------------------------------
   8 + 9. Fechamento e rodapé (bloco único)
   -------------------------------------------------------------------------- */

.site-footer {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  padding: var(--sec-top) var(--pad-x) var(--sp-5);
}

/* Mesmo fio das seções: pontilhado e parando na margem lateral. */
.site-footer::before {
  content: "";
  position: absolute;
  top: 0;
  left: var(--pad-x);
  right: var(--pad-x);
  height: 1px;
  background-image: var(--rule-dot);
  z-index: 2;
}

/* O halo do fechamento espelha o do hero: a página abre e fecha na mesma luz. */
.footer__glow {
  width: min(120vw, 1400px);
  height: min(60vh, 620px);
  left: 50%;
  top: -10%;
  transform: translateX(-50%) translateY(var(--gy, 0px)) scale(var(--gs, 1));
  background: radial-gradient(closest-side, var(--glow-warm), transparent 72%);
}

/* Fundo fotográfico reativado em 12/08/2026 com uma foto em resolução alta
   o bastante (closing-bg.jpg, 2400x1600) — a versão anterior (lucas.jpg,
   660x900px) tinha sido desativada por ficar visivelmente mais suave que o
   resto do site esticada numa seção larga. overflow:hidden + margem
   negativa de --pad-x sangram a foto e a trama até a borda real da tela, e
   a padding devolve o respiro pro conteúdo, que é filho normal do flex.
   A margem negativa de --sec-top no topo faz o mesmo verticalmente: sem
   ela, o padding-top do .site-footer (--sec-top, até 224px) sobrava como
   uma faixa lisa da cor de fundo entre o fio pontilhado do rodapé e o
   início da foto — chapada porque não é coberta por nada, ao contrário do
   resto da seção. O valor puxado pra cima volta como min-height extra, não
   como padding-top: o align-items:center do flex ignora padding ao
   centralizar, então somar ali (como na primeira tentativa) deixava o
   conteúdo preso na posição de antes, agora com um vão vazio enorme acima
   dele. Em min-height o espaço extra entra no que o flex de fato reparte
   igual pra cima e pra baixo do conteúdo. */
.closing {
  position: relative;
  z-index: 2;
  overflow: hidden;
  margin: calc(var(--sec-top) * -1) calc(var(--pad-x) * -1) 0;
  padding: clamp(72px, 11vw, 160px) var(--pad-x) clamp(56px, 8vw, 120px);
  min-height: calc(min(88vh, 780px) + var(--sec-top));
  display: flex;
  align-items: center;
  justify-content: center;
  border-bottom: 1px solid var(--line-soft);
}

/* Mesmo tratamento de imagem do .hero__photo — meio dessaturada e escura,
   pro fechamento combinar com a abertura em vez de introduzir um mundo
   visual novo. inset:0 já basta aqui (sem o calc(--pad-x * -1) do hero):
   a sangria já aconteceu na margem negativa do .closing acima, então a
   caixa de padding dele — a referência do inset:0 — já é a largura cheia. */
.closing__photo {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image: url("../assets/closing-bg.jpg");
  background-size: cover;
  background-position: 50% 35%;
  filter: grayscale(0.5) brightness(0.45) contrast(0.85);
}

/* Trama parada de propósito (data-dotmatrix-static no HTML): o fechamento
   não precisa do mesmo movimento contínuo do hero, só do mesmo tratamento
   gráfico por cima da foto. */
.closing__dotmatrix {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  overflow: hidden;
}

.closing__dotmatrix canvas {
  display: block;
  width: 100%;
  height: 100%;
}

/* Esmaece foto + trama na base da seção pra entrar sem corte seco no
   --bg chapado do .foot-grid logo abaixo. */
.closing::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background: linear-gradient(
    180deg,
    transparent 0%,
    transparent 55%,
    color-mix(in srgb, var(--bg) 88%, transparent) 100%
  );
}

.closing__content {
  position: relative;
  z-index: 3;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-4);
  max-width: 68rem;
  margin-inline: auto;
  text-align: center;
}

@media (max-width: 640px) {
  .closing { min-height: calc(min(72vh, 620px) + var(--sec-top)); }
  .closing__photo { background-position: 62% 14%; }
}

/* Mesma tipografia do wordmark do hero, com a mesma alternância de caixa
   que os outros títulos em Dirtyline usam (consTruo, primEiro): a quebra
   fica no HTML porque a frase precisa fechar em exatas duas linhas, sem
   depender de medir a largura renderizada. Tamanho aumentado a pedido em
   duas rodadas a partir dos 88px/46rem medidos originalmente, sempre na
   mesma proporção entre fonte e largura do .closing__content (agora 130px
   em 68rem), pra linha mais larga ("o quE mostrAr.") continuar cabendo em
   duas linhas e a seção dentro de 100vh numa tela comum de desktop.
   Conferir depois do F5 e ajustar se tiver quebrado em três linhas ou
   estourado o vh. */
.closing__title {
  margin: 0;
  font-family: var(--font-brand);
  font-weight: 400;
  font-size: clamp(48px, 9.5vw, 130px);
  line-height: 0.86;
  letter-spacing: 0;
  color: var(--ink);
}

.closing__lead {
  margin: 0;
  font-size: var(--fs-sub);
  font-weight: 500;
  letter-spacing: var(--tr-sub);
  color: var(--ink);
  white-space: nowrap;
}

/* Gap extra além do gap uniforme do flex, só antes do CTA: separa o bloco
   de texto (título + lead) do botão sem alterar a respiração entre título
   e lead. */
.closing__content .btn-action--lg {
  margin-top: var(--sp-5);
}

.foot-grid {
  position: relative;
  z-index: 2;
  padding-top: var(--sp-6);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr));
  gap: var(--sp-5);
}

.foot-mark {
  margin-bottom: var(--sp-1);
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink);
}

.foot-line {
  margin-bottom: 6px;
  font-size: var(--fs-label);
  color: var(--muted);
}

.foot-mail {
  font-size: var(--fs-label);
  color: var(--ink);
  border-bottom: 1px solid var(--line-2);
  transition: border-color var(--dur-hover) var(--ease);
}
.foot-mail:hover { border-color: var(--ink); }

.foot-nav {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  font-size: var(--fs-label);
}

.foot-nav a {
  color: var(--muted);
  transition: color var(--dur-hover) var(--ease);
}
.foot-nav a:hover { color: var(--ink); }

.foot-contact {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1);
}

.foot-base {
  position: relative;
  z-index: 2;
  margin-top: var(--sp-6);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--line-soft);
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--sp-2);
}

/* Mesma regra do precos__title e do processo__title: nowrap só se sustenta
   enquanto sobra largura. Abaixo disso, quebra normal em vez de espremer
   a fonte a um tamanho ilegível. */
@media (max-width: 640px) {
  .closing__lead { white-space: normal; }
}

/* --------------------------------------------------------------------------
   Assinatura pintável (rodapé)
   O wordmark do hero de novo, no mesmo tamanho cheio de tela (mesma técnica
   cqw + --wordmark-k, textos idênticos), mas revelado pelo cursor em vez de
   estático — o componente js/brush-reveal.js gera os spans ghost/paint por
   caractere dentro de .foot-signoff__text.
   -------------------------------------------------------------------------- */
.foot-signoff {
  container-type: inline-size;
  margin-top: var(--sp-7);
}

.foot-signoff__text {
  margin: 0;
  padding-bottom: max(6px, 0.13em);
  font-family: var(--font-brand);
  font-weight: 400;
  font-size: var(--fs-wordmark);
  line-height: 0.8;
  letter-spacing: 0;
  text-align: center;
  white-space: nowrap;
  cursor: crosshair;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}

@supports (container-type: inline-size) {
  .foot-signoff__text { font-size: calc(100cqw / var(--wordmark-k)); }
}
