/* ARTEN — as cinco seções */

/* ====================================================================
   NAV / TopBar
   Checklist §2: "logo + pill WhatsApp, sem menu de navegação"
   (attention ratio 1:1). O monograma AE saiu — é de produto/embalagem.
   ==================================================================== */
.nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: var(--layer-nav);
  padding-block: var(--space-4);
  /* difference no NAV inteiro: inverte por pixel contra o que passa por
     baixo — o wordmark nunca mais colide com título claro nem some no
     CTA branco. Todo o conteúdo do nav é monocromático branco; o blend
     faz o resto (no filho não funcionava: o stacking context do fixed
     isolava o blend do fundo da página). */
  mix-blend-mode: difference;
  color: #fff;
}
/* sob o difference o nav é sempre branco; o blend cuida do fundo claro */
.nav.is-escuro { color: #fff; }

/* Sobre o escuro o próprio fundo segura o nav. Sobre o claro o filete cai
   em cima de foto e de nome de peça — no 390 a marca encosta no rodapé do
   card. Um respiro de superfície, com a borda dissolvida. */
.nav::before {
  content: '';
  position: absolute;
  inset: 0 0 -30px 0;
  z-index: -1;
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(
    to bottom,
    color-mix(in srgb, var(--surface) 94%, transparent) 0%,
    color-mix(in srgb, var(--surface) 60%, transparent) 55%,
    transparent 100%);
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 56%, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 0%, #000 56%, transparent 100%);
  transition: opacity var(--duration-hover) var(--ease-editorial);
}
/* o véu ficava visível no meio da transição, brilhando branco sobre as
   seções escuras vizinhas do CTA — e sobre o CTA (branco) ele é
   redundante. A legibilidade quem segura é a troca de cor acima. */
.nav.is-escuro::before { opacity: 0; }

.nav__interno {
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
}
/* o alvo do wordmark era 78x18: alto demais pra mira, ainda mais no
   toque. O padding-block sobe pra 44px sem mexer no desenho (a barra do
   nav já é mais alta que isso). */
.marca {
  display: flex;
  align-items: center;
  min-height: 44px;
  text-decoration: none;
  color: inherit;
}
.marca .wordmark {
  font-size: var(--text-subtitle);
  line-height: 1;
  text-indent: var(--tracking-wordmark);   /* compensa o espaço da última letra */
}

/* CTA primário. Preto sobre claro, branco sobre escuro (checklist §2).
   Única exceção de raio no sistema. */
.nav__wpp {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-pill);
  background: #fff;
  color: #000;
  font-size: var(--text-label);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  transition: opacity var(--duration-hover) var(--ease-editorial);
}
.nav__wpp:hover { opacity: .78; }

/* ====================================================================
   1 · HERO — espetáculo
   ==================================================================== */
/* svh, não vh: o trilho tem que medir o mesmo que o palco. Com vh o trilho
   segue a viewport grande do celular e o sticky solta antes da hora. */
.hero__trilho { height: 240svh; }

.hero__palco {
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: hidden;
  background: var(--surface-inverse);
}

.hero__quadro {
  position: absolute;
  inset: 0;
  margin: 0;
  will-change: transform, opacity;
}
.hero__quadro img {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: 50% 38%;
}
.hero__quadro[data-quadro="1"] { opacity: 0; }

.hero__véu {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to top,
      color-mix(in srgb, var(--ink) 80%, transparent) 0%,
      color-mix(in srgb, var(--ink) 25%, transparent) 34%,
      transparent 62%),
    linear-gradient(to bottom,
      color-mix(in srgb, var(--ink) 45%, transparent) 0%,
      color-mix(in srgb, var(--ink) 15%, transparent) 12%,
      transparent 26%);
  pointer-events: none;
}

.hero__copy {
  position: absolute;
  left: var(--gutter);
  right: var(--gutter);
  bottom: clamp(5.5rem, 14vh, 10.5rem);
  color: var(--text-inverse);
}
.hero__linha {
  font-family: var(--font-display);
  font-size: var(--text-display-xl);
  line-height: var(--leading-display);
  letter-spacing: -0.02em;
  margin: 0;
  max-width: 18ch;
  will-change: transform, opacity;
}
/* Os três beats ocupam a MESMA célula do grid: o container mede pelo mais
   alto, e trocar de beat não muda a altura nem empurra o CTA. */
.hero__beats { display: grid; }
.hero__beats > .hero__linha { grid-area: 1 / 1; }

.hero__linha[data-linha="1"],
.hero__linha[data-linha="2"] { opacity: 0; }
.hero__linha[data-linha="2"] { font-style: italic; }

/* CTA único, perto da headline, presente desde o primeiro viewport
   (pesquisa de heros de captação). Não entra e sai com os beats: fica. */
.hero__cta {
  display: inline-flex;
  align-items: center;
  margin-top: var(--space-6);
  padding: 0.875rem var(--space-8);
  background: var(--action-inverse);
  color: var(--action);
  text-decoration: none;
  font-size: var(--text-caption);
  letter-spacing: 0.06em;
  border-radius: var(--radius-pill);   /* exceção única do raio: pill WhatsApp */
  transition: background var(--duration-hover) var(--ease-editorial),
              color var(--duration-hover) var(--ease-editorial);
}
.hero__cta:hover { background: var(--cru); }

/* Filete camelo como barra de progresso do hero (checklist §2).
   Único uso permitido do camelo: filete, nunca texto, nunca área. */
.hero__progresso {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: var(--rule-camelo);
  background: color-mix(in srgb, var(--paper) 18%, transparent);
  pointer-events: none;
}
.hero__progresso span {
  display: block;
  height: 100%;
  background: var(--camelo);
  transform: scaleX(0);
  transform-origin: left center;
}

.hero__rodape {
  position: absolute;
  left: var(--gutter);
  right: var(--gutter);
  bottom: var(--space-8);
  display: flex;
  align-items: center;
  justify-content: space-between;
  color: var(--text-muted-inverse);
}
.hero__desce {
  display: flex; align-items: center; gap: var(--space-3);
  font-size: var(--text-label); letter-spacing: var(--tracking-label); text-transform: uppercase;
}
.hero__desce-traco {
  width: 44px; height: 1px; background: currentColor;
  transform-origin: left; opacity: .6;
  animation: desce 2.6s var(--ease-suave) infinite;
}
@keyframes desce {
  0%, 100% { transform: scaleX(.35); opacity: .35; }
  50%      { transform: scaleX(1);   opacity: .8; }
}

/* ---- HERO SEM MOTION -----------------------------------------------
   O segundo quadro e a segunda linha só existiam dentro do scrub. Com o
   movimento desligado eles ficavam em opacity: 0 pra sempre — conteúdo
   perdido, não conteúdo contido. Aqui o hero deixa de ser câmera e vira
   layout: as duas fotos e as duas linhas, em fluxo, sem depender de scroll. */
:root.sem-motion .hero__trilho { height: auto; }

:root.sem-motion .hero__palco {
  position: relative;
  height: auto;
  overflow: visible;
  display: grid;
  grid-template-columns: 1fr;
  padding-bottom: var(--space-12);
}
:root.sem-motion .hero__quadro,
:root.sem-motion .hero__quadro[data-quadro="1"] {
  position: relative;
  inset: auto;
  opacity: 1;
  height: min(58svh, 520px);
  transform: none;
}
/* O véu não veste mais a foto inteira — só segura o nav no alto. */
:root.sem-motion .hero__véu {
  inset: 0 0 auto 0;
  height: 132px;
  background: linear-gradient(to bottom,
    color-mix(in srgb, var(--ink) 55%, transparent) 0%,
    color-mix(in srgb, var(--ink) 15%, transparent) 56%,
    transparent 100%);
}

:root.sem-motion .hero__copy {
  position: static;
  padding: var(--space-12) var(--gutter) 0;
}
/* Sem motion os beats saem do empilhamento e viram três parágrafos em fluxo:
   quem pediu movimento reduzido lê os três, não um só. Em display-xl os três
   empilhados ocupariam três telas — aqui eles caem um degrau na escala. */
:root.sem-motion .hero__beats { display: block; }
:root.sem-motion .hero__linha { font-size: var(--text-display); max-width: 24ch; }
:root.sem-motion .hero__linha[data-linha="1"],
:root.sem-motion .hero__linha[data-linha="2"] {
  opacity: 1;
  transform: none;
  margin-top: var(--space-2);
}
:root.sem-motion .hero__progresso { display: none; }
:root.sem-motion .hero__rodape {
  position: static;
  padding: var(--space-8) var(--gutter) 0;
}
:root.sem-motion .hero__desce-traco { animation: none; opacity: .5; }

/* Espaço pra isso: as fotos ficam lado a lado. */
@media (min-width: 720px) {
  :root.sem-motion .hero__palco { grid-template-columns: 1fr 1fr; }
  :root.sem-motion .hero__copy,
  :root.sem-motion .hero__rodape { grid-column: 1 / -1; }
}

/* Rede de segurança: mesmo sem JS nenhum, quem pediu movimento reduzido
   continua vendo os dois quadros e os três beats. */
@media (prefers-reduced-motion: reduce) {
  .hero__trilho { height: auto; }
  .hero__palco { position: relative; height: auto; overflow: visible; }
  .hero__quadro,
  .hero__quadro[data-quadro="1"] { position: relative; inset: auto; opacity: 1; height: 58svh; }
  .hero__véu { inset: 0 0 auto 0; height: 132px;
    background: linear-gradient(to bottom,
      color-mix(in srgb, var(--ink) 55%, transparent) 0%,
      color-mix(in srgb, var(--ink) 15%, transparent) 56%,
      transparent 100%); }
  .hero__copy,
  .hero__rodape { position: static; padding: var(--space-8) var(--gutter) 0; }
  .hero__beats { display: block; }
  .hero__linha[data-linha="1"],
  .hero__linha[data-linha="2"] { opacity: 1; margin-top: var(--space-2); }
  .hero__progresso { display: none; }
}

/* ====================================================================
   01 · A MALHA — dois movimentos modelados nas referências que o
   Fernando mandou (ver REFERENCIAS-SECAO-02.md): a frase que entra em
   foco (fmrg.studio, item 1a) e as três peças que reagem ao cursor
   (centremarsea.com, item 2b). Estrutura aqui — caixa, grade,
   tipografia, cor; a mecânica (sticky, blur por palavra, paralaxe e
   imantação em translate) mora em lp-extras.css.
   ==================================================================== */
.malha { background: var(--surface-inverse); color: var(--text-inverse); }
.malha .numero { color: var(--text-muted-inverse); }

/* Movimento 1 — a frase presa na tela. A caixa que a prende no lugar
   (position: sticky, altura do trilho) é mecânica: lp-extras.css. */
/* top livre do nav fixo: medido em 52px de altura nos dois breakpoints;
   --space-16 + --space-2 dá uma folga de ~20px abaixo dele. */
.malha__numero {
  position: absolute;
  left: var(--gutter);
  top: calc(var(--space-16) + var(--space-2));
}
.malha__frase {
  max-width: 22ch;
  margin: 0;
  text-align: center;
  font-family: var(--font-display);
  font-size: clamp(2rem, 6vw, 4.4rem);   /* teto de 4.4rem — mesmo valor do fmrg.studio */
  line-height: var(--leading-display);
  letter-spacing: var(--tracking-display);
  color: var(--paper);
}
.malha__palavra { display: inline-block; }

/* --------------------------------------------------------------------
   A cena da 01 — P&B embaixo, cor por cima revelada por máscara.
   Mecanismo lido do serotoninn.com (REFERENCIAS-SEROTONINN.md §2.1):
   lá são três camadas da mesma foto, a de cor mascarada por um WebP
   com alfa. Aqui a máscara é um radial-gradient cujo centro (--mx/--my)
   o js/malha.js escreve a partir do ponteiro.

   REDE DE SEGURANÇA (regra da casa): a camada P&B está sempre em
   opacidade cheia e não depende de script nenhum. A camada de cor só
   ACRESCENTA. Sem JS, com o rAF congelado, em touch ou com motion
   reduzido, --mx/--my ficam no repouso declarado aqui e a seção segue
   exatamente legível — perde o furo de cor, não perde conteúdo.
   -------------------------------------------------------------------- */
.malha__cena {
  position: absolute;
  inset: 0;
  overflow: hidden;
  z-index: 0;
  pointer-events: none;
}
.malha__cena-pb,
.malha__cena-cor {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
/* Quatro fatias verticais do mesmo modelo, lado a lado — cada camada
   (P&B embaixo, cor por cima) repete o mesmo conjunto de 4 fotos, então
   o efeito de furo/inundação continua acontecendo por cima do conjunto
   inteiro em vez de uma foto só. */
.malha__fatias {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  height: 100%;
}
.malha__fatias img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-left: 2px solid var(--hairline-color, color-mix(in srgb, var(--ink) 35%, transparent));
}
.malha__fatias img:first-child { border-left: none; }
/* A ORDEM DAS CAMADAS é o que faz o efeito ler, e custou uma tentativa:
   o véu tem que ficar ENTRE o P&B e a cor. Com o véu por cima das duas,
   ele escurece também o furo e não sobra contraste nenhum — foi o que
   aconteceu na primeira versão. Assim: o P&B fica rebaixado e apagado,
   o véu segura a legibilidade da frase, e a cor fura por cima dos dois. */
.malha__cena-pb {
  z-index: 0;
  filter: grayscale(1) contrast(1.05) brightness(0.5);
}

.malha__cena::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: color-mix(in srgb, var(--ink) 52%, transparent);
}

.malha__cena-cor {
  --mx: 50%;
  --my: 44%;
  /* o raio e o stop viram variáveis: o furo do cursor é o repouso (30vmin),
     e depois que a frase foca a INUNDAÇÃO cresce o furo até engolir a tela
     (serotoninn §1.4: máscara 30%→440% dirigida por scroll, ease linear).
     Sem JS, os fallbacks das var() deixam a seção exatamente como era. */
  --furo: 30;
  --duro: 40;
  z-index: 2;
  filter: saturate(1.12);
  -webkit-mask-image: radial-gradient(circle calc(var(--furo) * 1vmin) at var(--mx) var(--my),
                        #000 0 calc(var(--duro) * 1%), transparent 80%);
          mask-image: radial-gradient(circle calc(var(--furo) * 1vmin) at var(--mx) var(--my),
                        #000 0 calc(var(--duro) * 1%), transparent 80%);
}
/* a cena cresce 0.7→1 junto com o foco da frase (fmrg §2.3: mídia nunca
   aparece, cresce; opacity fixa). Repouso = 1: sem JS, full-bleed como era. */
.malha__cena { scale: 1; will-change: scale; transform-origin: 50% 50%; }

/* Bordas da cena com fade pro fundo da seção (pedido do Fernando, 05/08):
   a foto derrete no preto em vez de terminar em corte seco — no celular a
   faixa de 56svh deixava duas arestas duras contra o fundo. ::before (o
   ::after é o véu) acima das três camadas: o fade cobre P&B, véu e cor. */
.malha__cena::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  background:
    linear-gradient(to bottom, var(--ink), transparent 12%),
    linear-gradient(to top, var(--ink), transparent 12%),
    linear-gradient(to right, var(--ink), transparent 7%),
    linear-gradient(to left, var(--ink), transparent 7%);
  /* some conforme a inundação completa; fallback 0 mantém visível sem JS */
  opacity: calc(1 - var(--engole, 0));
}

/* Touch: sem cursor não existe furo de cor pra furar o breu, e o P&B a
   brightness(0.5) + véu de 52% somava ~24% de brilho — no celular a foto
   lia como tela preta (bug relatado pelo Fernando, 05/08). Aqui o P&B
   sobe e o véu afina (~53% efetivo: visível, ainda escuro o bastante pro
   clima); o text-shadow devolve à frase o contraste que o véu perdeu.
   Gate em hover:none, igual ao da faixa: desktop estreito não muda. */
@media (hover: none) {
  .malha__cena-pb { filter: grayscale(1) contrast(1.05) brightness(0.78); }
  .malha__cena::after { background: color-mix(in srgb, var(--ink) 32%, transparent); }
  .malha__frase { text-shadow: 0 2px 28px rgb(0 0 0 / .6), 0 0 3px rgb(0 0 0 / .4); }
}

/* A frase e o número ficam acima da cena. */
.malha__numero { z-index: 3; }
.malha__frase { position: relative; z-index: 3; }

/* Celular: a cena full-bleed cortava a foto (paisagem) pra uma fatia de
   26% da largura — o casal saía do quadro. Como faixa horizontal
   centrada, o recorte mostra ~45% da largura e os dois ficam inteiros.
   O letterbox vira intenção, não acidente. */
/* hover: none no seletor: a faixa é remédio de CELULAR. Sem essa trava,
   uma janela de desktop estreita (<810px) também virava faixa e matava
   o full-bleed com cursor. */
@media (max-width: 809.98px) and (hover: none) {
  /* --engole (0→1, escrito por js/malha.js junto com a inundação): a
     faixa cresce de 56svh até a tela cheia na saída — sem ele a seção
     saía com um vão preto entre a foto e o manifesto. */
  .malha__cena {
    inset: auto 0; top: 50%;
    height: calc(56svh + var(--engole, 0) * 44svh);
    translate: 0 -50%;
  }
  /* O 2x2 pesava (pedido do Fernando, 11/08): quatro recortes quase
     quadrados numa faixa de 56svh cortavam as cabeças da fileira de
     baixo, e o filete cruzando o meio desenhava um X duro sobre a
     frase. No celular ficam DUAS fatias lado a lado — cada uma no
     retrato que a foto pede, sem cruz no meio. As quatro continuam no
     desktop, onde a faixa é larga. */
  .malha__fatias {
    grid-template-columns: repeat(2, 1fr);
  }
  .malha__fatias img:nth-child(n + 3) { display: none; }
  /* divisória marcada entre as duas fatias (pedido do Enzo, 18/08):
     sem ela as duas peças emendavam uma na outra no celular */
  .malha__fatias img { border-left: 3px solid color-mix(in srgb, var(--ink) 45%, transparent); }
  .malha__fatias img:first-child { border-left: none; }
}

/* Movimento 2 — as três peças. As fotos são flat-lay (packshot), não
   corpo vestido: 1/1 em vez do 3/4 do .peca-card, senão o cover corta
   dentro da manga — o fundo cinza/branco do packshot dá folga de sobra
   pro corte quadrado sem tocar a peça. */
.malha__pecas { padding-block: var(--section-y); }
.malha__grade {
  list-style: none; margin: 0; padding: 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-6) var(--space-4);
}
.malha__peca-foto {
  aspect-ratio: 1 / 1;
  overflow: hidden;
  background: var(--cru);
}
.malha__peca-foto img { width: 100%; height: 100%; object-fit: cover; }
/* Reusa .peca-card__pe (mesmo padrão de rodapé da grade da Tiragem),
   só troca o hairline escuro por um claro — a seção é invertida. */
.malha__peca .peca-card__pe { border-top: var(--hairline) solid #ffffff1f; }
.malha__peca .peca-card__nome { color: var(--paper); }
.malha__peca .peca-card__cor { color: var(--text-muted-inverse); }

@media (max-width: 767.98px) {
  .malha__grade { grid-template-columns: 1fr; gap: var(--space-8); }
}

/* ====================================================================
   3 · A PEÇA — contenção
   ==================================================================== */
/* --surface-alt (cru), não --surface (paper): testado contra o branco
   puro e o suéter creme perdia a borda — a sombra virava mancha solta em
   vez de ancorar a peça. O cru dá o degrau de valor que a foto/render
   precisa pra separar do fundo. Ver nota de migração no tokens.css. */
.peca { padding-block: var(--section-y); background: var(--surface-alt); }

.peca__grade {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-16);
  align-items: center;
}
@media (min-width: 900px) {
  .peca__grade { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: var(--space-24); }
}

.peca__texto { display: flex; flex-direction: column; gap: var(--space-6); align-items: flex-start; }
.peca__titulo { font-size: var(--text-display); line-height: var(--leading-display); }
/* Era camelo — reprova AA como texto. A ênfase agora é o itálico, que é
   condimento tipográfico e não custa contraste. */
.peca__titulo em { font-style: italic; color: var(--text); }
.peca__sub { color: var(--text-muted); max-width: 34ch; }

/* Swatch de produto: círculo permitido pelo checklist §2 — o --radius: 0
   vale pra container de UI (card, painel, botão, campo), não pra amostra. */
.swatches { display: flex; gap: var(--space-3); margin-top: var(--space-2); }
.swatch {
  position: relative;
  width: 30px; height: 30px;
  border-radius: 50%;
  background: var(--cor, var(--cru));
  box-shadow: inset 0 0 0 1px var(--hairline-color);
  transition: transform var(--duration-fast) var(--ease-editorial),
              box-shadow var(--duration-fast) var(--ease-editorial);
}
.swatch:hover { transform: scale(1.08); }
.swatch.is-ativo {
  box-shadow: inset 0 0 0 1px var(--hairline-color),
              0 0 0 1px var(--surface),
              0 0 0 2px var(--ink);
}

/* 5ª vaga trancada — o verde fechado está RESERVADO no manual.
   Aparece, mas não se clica, e o motivo está escrito embaixo. */
.swatch--trancada { cursor: not-allowed; opacity: .4; }
.swatch--trancada:hover { transform: none; }
.swatch--trancada::after {
  content: '';
  position: absolute;
  inset: -2px;
  border-radius: 50%;
  background: linear-gradient(
    to bottom right,
    transparent calc(50% - 0.75px),
    var(--ink) calc(50% - 0.75px),
    var(--ink) calc(50% + 0.75px),
    transparent calc(50% + 0.75px));
}

.peca__cor-nome { font-size: var(--text-caption); color: var(--text-muted); margin-top: calc(var(--space-3) * -1); }
.swatches__nota {
  font-size: var(--text-caption);
  color: var(--text-muted);
  margin-top: calc(var(--space-4) * -1);
}

.peca__palco {
  position: relative;
  aspect-ratio: 1 / 1;
  width: 100%;
  max-height: 74vh;
  margin-inline: auto;
}
#peca-canvas { display: block; width: 100%; height: 100%; cursor: grab; touch-action: pan-y; }
#peca-canvas.is-arrastando { cursor: grabbing; }
.peca__palco.sem-webgl #peca-canvas { display: none; }

.peca__fallback { margin: 0; height: 100%; }
.peca__fallback img { width: 100%; height: 100%; object-fit: cover; }

/* hotspots e ficha — Ponto. Resolvido o conflito que o Trama sinalizou:
   a ficha era de vidro, o checklist §2 manda painel CRU SÓLIDO. */
.hotspot {
  position: absolute;
  width: 34px; height: 34px;
  margin: -17px 0 0 -17px;
  display: grid; place-items: center;
  transition: opacity var(--duration-hover) var(--ease-editorial);
}
/* Ponto CAMELO — checklist §2. É um dos poucos usos legítimos do acento:
   detalhe de 7px, não texto e não área. A regra "camelo nunca texto" é de
   acessibilidade (AA ~2.8:1) e não se aplica aqui; quem carrega o sentido
   é o aria-label do botão, não a cor. */
.hotspot span {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--camelo);
  box-shadow: 0 0 0 0 color-mix(in srgb, var(--camelo) 30%, transparent);
  transition: box-shadow var(--duration-hover) var(--ease-editorial),
              transform var(--duration-fast) var(--ease-editorial);
}
.hotspot:hover span, .hotspot:focus-visible span {
  box-shadow: 0 0 0 9px color-mix(in srgb, var(--camelo) 18%, transparent);
  transform: scale(1.15);
}

.ficha {
  position: absolute;
  left: 50%; bottom: var(--space-6);
  transform: translateX(-50%);
  width: min(360px, calc(100% - var(--space-16)));
  padding: var(--space-6);
  /* CRU SÓLIDO, opaco, sem blur nenhum: a ficha é papel apoiado na peça,
     não vidro por cima dela. O filete camelo é o que a separa do fundo —
     borda, que é uso canônico do acento. */
  background: var(--cru);
  border-top: var(--rule-camelo) solid var(--camelo);
  box-shadow: 0 18px 44px -28px color-mix(in srgb, var(--ink) 35%, transparent);
  z-index: var(--layer-ficha);
}
.ficha__fechar {
  position: absolute; top: var(--space-2); right: var(--space-3);
  font-size: 20px; line-height: 1; color: var(--text-muted);
}
.ficha__onde { margin-bottom: var(--space-2); color: var(--text-muted); }
.ficha__texto { font-size: var(--text-caption); color: var(--text); }

/* ====================================================================
   4 · TIRAGEM — espetáculo na entrada, grade estática
   "coleção" é léxico banido (checklist §3): a palavra da casa é tiragem.
   ==================================================================== */
.tiragem { padding-block: var(--section-y); background: var(--surface-alt); }

.tiragem__cabeca {
  display: flex; flex-direction: column; gap: var(--space-4);
  align-items: flex-start;
  margin-bottom: var(--space-16);
}
.tiragem__titulo { font-size: var(--text-display); line-height: var(--leading-display); }

.grade {
  list-style: none; margin: 0; padding: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-6) var(--space-4);
}
@media (min-width: 860px) { .grade { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.peca-card a { text-decoration: none; color: inherit; display: block; }
.peca-card__fotos {
  position: relative;
  aspect-ratio: 3 / 4;
  overflow: hidden;
  background: var(--cru);
  border-radius: var(--radius);
}
.peca-card__fotos img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
}
.peca-card__b {
  opacity: 0;
  transform: scale(1.04);
  transition: opacity var(--duration-hover) var(--ease-tecido),
              transform var(--duration-reveal) var(--ease-tecido);
}
.peca-card a:hover .peca-card__b,
.peca-card a:focus-visible .peca-card__b { opacity: 1; transform: scale(1); }

.peca-card__pe {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: var(--space-3);
  padding-top: var(--space-3);
  border-top: var(--rule-hairline);
  margin-top: var(--space-3);
}
.peca-card__nome { font-family: var(--font-display); font-size: var(--text-card-title); }
.peca-card__cor { font-size: var(--text-label); color: var(--text-muted); letter-spacing: .04em; }

/* ====================================================================
   5 · CAPTAÇÃO — fricção zero
   Hierarquia do checklist §2: WhatsApp é o CTA PRIMÁRIO (um por tela);
   a lista de espera é secundária, visivelmente menor.
   ==================================================================== */
.captacao { padding-block: var(--section-y); background: var(--surface); }
.captacao__interno {
  display: flex; flex-direction: column; align-items: center;
  text-align: center; gap: var(--space-6);
}
.captacao__titulo { font-size: var(--text-display); line-height: var(--leading-display); }

/* Bloco de escassez: afirmação, não alarme. Sem countdown, sem "corre". */
.escassez {
  font-size: var(--text-subtitle);
  color: var(--text-muted);
  margin-top: calc(var(--space-2) * -1);
}

/* CTA primário */
.botao-primario {
  display: inline-flex; align-items: center; gap: var(--space-2);
  padding: var(--space-4) var(--space-8);
  border-radius: var(--radius-pill);
  background: #fff;
  color: #000;
  font-size: var(--text-body);
  text-decoration: none;
  margin-top: var(--space-2);
  transition: opacity var(--duration-hover) var(--ease-editorial);
}
.botao-primario:hover { opacity: .78; }

/* Secundário: sem caixa, sem preenchimento, degrau claro abaixo do primário */
.waitlist {
  display: flex; flex-direction: column; align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-8);
  width: min(26rem, 100%);
}
.waitlist__rotulo { color: var(--text-muted); }

.waitlist__form {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-4);
  width: 100%;
}
.waitlist__form input {
  flex: 1 1 12rem;
  padding: var(--space-3) 0;
  min-height: 44px;
  background: none;
  border-bottom: var(--rule-hairline);
  transition: border-color var(--duration-fast) var(--ease-editorial);
}
.waitlist__form input::placeholder { color: var(--text-muted); }
.waitlist__form input:focus { border-bottom-color: var(--text); }
/* mata o outline só no foco por clique; teclado mantém o anel (a11y) */
.waitlist__form input:focus:not(:focus-visible) { outline: none; }
/* Campo inválido marcado pelo filete camelo — uso sancionado do acento.
   A mensagem em si fica em ink, porque camelo como texto reprova AA. */
.waitlist__form input[aria-invalid="true"] {
  border-bottom: var(--rule-camelo) solid var(--accent);
}
.waitlist__form button {
  flex: 0 0 auto;
  font-size: var(--text-caption);
  color: var(--text);
  padding-bottom: 2px;
  border-bottom: 1px solid var(--text);
  transition: opacity var(--duration-fast) var(--ease-editorial);
}
.waitlist__form button:hover { opacity: .6; }
.waitlist__form button:disabled { opacity: .4; cursor: default; }

.waitlist__erro, .waitlist__ok { flex: 1 0 100%; font-size: var(--text-caption); text-align: left; }
.waitlist__erro { color: var(--text); }
.waitlist__ok { color: var(--text-muted); }

@media (max-width: 560px) {
  .waitlist__form { flex-direction: column; align-items: stretch; }
  .waitlist__form button { align-self: flex-start; }
  .waitlist__erro, .waitlist__ok { text-align: left; }
}

/* ====================================================================
   RODAPÉ
   ==================================================================== */
.rodape { padding-block: var(--space-8); border-top: var(--rule-hairline); background: var(--surface); }
.rodape__interno { display: flex; justify-content: space-between; align-items: center; gap: var(--space-4); }
.rodape .wordmark { font-size: var(--text-subtitle); text-indent: var(--tracking-wordmark); }
.rodape .label-caps { color: var(--text-muted); }

/* ====================================================================
   CÓPIAS DAS REFERÊNCIAS — ver SPEC-01-HERO.md
   ==================================================================== */

/* --- A · cursor-objeto (serotoninn) ---------------------------------
   O cursor nativo some só dentro do bloco. Fora, o site é site. */
[data-cursor] { cursor: none; }
[data-cursor] a,
[data-cursor] button { cursor: none; }

.cursor-arten {
  position: fixed;
  top: 0; left: 0;
  z-index: 400;
  width: 76px; height: 76px;
  margin: -38px 0 0 -38px;
  display: grid;
  place-items: center;
  gap: 2px;
  pointer-events: none;
  opacity: 0;
  color: var(--paper);
  will-change: transform;
}
.cursor-arten svg { width: 40px; height: 30px; }
.cursor-arten__txt {
  font-size: 10px;
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
}

/* --- B · trilha-fantasma (centremarsea) ------------------------------
   Um clone a cada 100px, no máximo 4 vivas, fade de 300ms. */
.fantasma {
  position: fixed;
  z-index: 390;
  width: 92px;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  margin: -62px 0 0 -34px;
  pointer-events: none;
  opacity: 0;
  transform: scale(0.92);
  transition: opacity 300ms var(--ease-editorial),
              transform 300ms var(--ease-editorial);
}
.fantasma.is-visivel { opacity: 0.5; transform: scale(1); }

/* O magnetismo escreve em translate no <img>; o GSAP escreve em transform
   na <figure>. Propriedades distintas, elementos distintos: não colidem.
   O scale dá folga: com 5,5% de deslocamento, 1.14 garante que a borda da
   foto nunca aparece — full-bleed continua full-bleed. */
.hero__quadro img { will-change: translate; scale: 1.14; }
@media (hover: none), (prefers-reduced-motion: reduce) {
  .hero__quadro img { scale: 1; }
}

/* --- C · loader (milledollars) ---------------------------------------
   Loop indeterminado, sem porcentagem. Sai por evento real. */
.carregando {
  position: fixed;
  inset: 0;
  z-index: 500;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--tracking-wordmark);
  background: var(--ink);
  color: var(--paper);
  font-family: var(--font-display);
  font-size: clamp(2rem, 6vw, 4rem);
  letter-spacing: var(--tracking-wordmark);
  text-indent: var(--tracking-wordmark);
  /* rede de segurança CSS pura (regra da casa, portada da variante):
     se o JS inteiro falhar, a cortina some sozinha aos 3s — animation
     não depende de rAF nem de load real, só do tempo passar */
  animation: carregando-fim .01ms linear 3s forwards;
}
@keyframes carregando-fim { to { opacity: 0; visibility: hidden; pointer-events: none; } }
.carregando__letra {
  display: inline-block;
  opacity: 0.22;
  animation: respira 1.6s ease-in-out infinite;
}
.carregando__letra:nth-child(2) { animation-delay: 0.12s; }
.carregando__letra:nth-child(3) { animation-delay: 0.24s; }
.carregando__letra:nth-child(4) { animation-delay: 0.36s; }
.carregando__letra:nth-child(5) { animation-delay: 0.48s; }

@keyframes respira {
  0%, 100% { opacity: 0.22; }
  50%      { opacity: 1; }
}

/* Enquanto não está pronto, a página não pisca por baixo do loader. */
html:not(.is-ready) body { overflow: hidden; animation: destravar-scroll .01ms linear 3.2s forwards; }
@keyframes destravar-scroll { to { overflow: auto; } }

@media (prefers-reduced-motion: reduce) {
  .carregando { display: none; }
  .cursor-arten, .fantasma { display: none; }
}
@media (hover: none) {
  [data-cursor], [data-cursor] a, [data-cursor] button { cursor: auto; }
  .cursor-arten, .fantasma { display: none; }
}
