/* ===========================================================================
   POSTAL · "eu tenho medo"
   O cartão em 3D, o papel e o selo holográfico.

   REGRA ESTRUTURAL Nº 1 — leia antes de mexer em qualquer coisa aqui.
   `opacity < 1`, `filter`, `mix-blend-mode`, `overflow` OU `contain`/`container-type` em
   QUALQUER ancestral de `.postal-cartao` achata o `preserve-3d` e o cartão vira um
   retângulo chapado. E numa FACE, `container-type` (= `contain: layout`) TIRA a face do
   contexto 3D e mata o `backface-visibility` dela — a face de costas vaza espelhada e
   distorcida. (Já aconteceu: pus `container-type` na face frontal pra um `cqw` do logo, e
   o cartão inteiro pareceu bugado no verso. Use `--postal-w` pra medida relativa ao
   cartão, nunca `container-type` numa face.)
   Consequências práticas, todas já respeitadas abaixo:
     · `.postal-cartao` NUNCA entra dentro de `.reveal` (o DS anima com opacity:0);
     · o grão e o brilho do papel moram DENTRO de uma face, nunca acima do cartão;
     · a face é folha da árvore 3D — blend mode dentro dela é seguro; `contain` NÃO é.
   O `.grain` global do site é irmão (position:fixed, z-index 2) e não encosta nisso.

   TESTE de Regra nº 1: medir a face a 45°/90° NÃO basta — mede só uma face. O que pegou
   o bug do `container-type` foi olhar o VERSO (ry 180) e ver a frente vazando. Teste as
   DUAS faces, girando o cartão até cada uma ficar de costas.

   REGRA Nº 2 — a paleta do cartão.
   O verso é índigo #1f1949 sobre papel creme, com vermelho #A90010 no selo. Isso NÃO
   viola "A Regra da Cor-Conteúdo" do DESIGN.md: o cartão REPRESENTA um objeto impresso,
   e representação entra na mesma categoria da fotografia. A interface em volta (botão,
   campo, nav, CTA) continua estritamente Breu/Osso. Cor nenhuma vaza do cartão pra fora.

   E que fique dito, porque a palavra "impresso" aqui já enganou uma vez: o postal é
   100% DIGITAL. Nada vai pra gráfica, nada chega pelo correio. O papel, o carimbo e a
   tinta são desenho — a leitura de impresso é o efeito, nunca uma promessa. Copy que
   diga ou sugira que a gente imprime e entrega é bug, não licença poética.
   =========================================================================== */

/* `hidden` do HTML só vale display:none na folha do user-agent, e QUALQUER
   `display` do autor ganha dela. `.movement{display:grid}` do DS estava vencendo, e
   as seções escondidas apareciam do mesmo jeito. Aqui o atributo volta a mandar. */
.postal-page [hidden] {
  display: none !important;
}

.postal-page {
  /* Tinta e papel do objeto impresso. Deliberadamente FORA dos tokens do tema:
     um postal impresso não muda de cor quando o site vira modo claro. */
  --tinta: #1f1949;
  --tinta-60: rgba(31, 25, 73, 0.6);
  --tinta-35: rgba(31, 25, 73, 0.35);
  --papel: #f2ede1;
  --papel-sombra: #e4dcc9;
  --carmim: #a90010;

  /* A sombra do cartão POUSADO na página. Ao contrário da tinta/papel (que são do objeto
     e não mudam com o tema), esta muda: o fundo muda. Default = tema escuro, onde ela some
     contra o Breu (quem separa é a aresta creme), então o valor forte aqui é inofensivo.
     No claro ela é sobrescrita por algo suave e quente — ver o override lá embaixo. */
  --postal-sombra-contato: rgba(0, 0, 0, 0.18);
  --postal-sombra-perto: rgba(0, 0, 0, 0.5);
  --postal-sombra-longe: rgba(0, 0, 0, 0.45);

  /* A5 — 595×420pt. A razão é a do Figma, não um número redondo. Deitado aqui; no
     celular ele fica EM PÉ (ver "O A5 EM PÉ" mais abaixo). */
  --postal-a5: 1.4167;
  --postal-razao: var(--postal-a5);
  /* O cartão é a estrela da página, e o tamanho é o que sobra depois de descontar a
     topbar e o botão — ver o orçamento vertical em #cartao. `svh` e não `vh`: a barra
     do Safari no iPhone. Um valor só, pras duas pontas: o mesmo cartão não pode ter
     dois tamanhos por causa de qual link a pessoa clicou.

     O teto de 760px saiu: era ele que segurava o cartão em 35% de um desktop 1440,
     quando cabem ~52%. Agora quem manda é a altura, que é o recurso escasso. */
  --postal-w: min(96vw, calc(80svh * var(--postal-razao)));
  --postal-h: calc(var(--postal-w) / var(--postal-razao));
  --postal-espessura: 1.5px;

  /* Escrito pelo JS a cada movimento do ponteiro (0..1). O CSS só consome. */
  --px: 0.5;
  --py: 0.5;

  /* Tempos da chegada. Saída ~80% da entrada: sair é mais rápido que chegar. */
  --chegada-entrada: 420ms;
  --chegada-saida: 340ms;
  --chegada-cortina: 760ms;
}

/* ===========================================================================
   O A5 EM PÉ — a única geometria em que o postal cabe num celular.

   Um A5 DEITADO num celular EM PÉ é 29% da tela, e a esse tamanho a mensagem sai a
   7,6px e o rótulo a 3,3px (medido no iPhone 15, 393×852). O postal chega por link
   de WhatsApp: 29% da tela é o caso principal, não a exceção. Pra cobrir 90% da
   altura deitado, o cartão precisaria de 1076px de largura — 2,76× a tela. É
   geometria, não gosto.

   A razão aqui é `1 / --postal-a5`, e o `calc` é o argumento inteiro: isto NÃO é um
   aspecto inventado pro mobile. É o MESMO A5, de pé — a mesma folha que você vira na
   mão pra escrever. Um A5 deitado e um A5 em pé são o mesmo papel. Por isso o objeto
   continua sendo um só nas duas pontas, e por isso `--postal-a5` existe separado.

   E o que resolve a LEGIBILIDADE não é isto — é o piso em `rem` da tipografia (ver
   "A TIPOGRAFIA TEM PISO"). O verso é medido em `cqw` = % da largura do cartão, e a
   largura está presa na do celular: virar o cartão de pé não muda a fonte em nada.
   O que o A5 em pé compra é ALTURA, e altura é pauta: ~9,5 linhas contra ~5.
   =========================================================================== */
@media (orientation: portrait) and (max-width: 639px) {
  .postal-page {
    --postal-razao: calc(1 / var(--postal-a5));
  }
}

/* ===========================================================================
   A CHEGADA
   A cortina é IRMÃ do <main> e não pode, em hipótese nenhuma, virar ancestral do
   cartão: ela faz fade com `opacity`, e opacity num ancestral achata o preserve-3d
   (Regra nº 1, no topo deste arquivo). Pelo mesmo motivo, é proibido travar o
   scroll com `overflow: hidden` no body enquanto ela existe — body é ancestral do
   cartão, e `overflow` mata o 3D pelo mesmo caminho, em silêncio.

   Não há regra de `prefers-reduced-motion` pra esta feature, e isso é a prova de
   que o desenho está certo, não esquecimento: a sequência é fade de opacidade, que
   não é movimento vestibular, e as falas SÃO a compreensão — matá-las tiraria o
   sentido, que não é o que a preferência pede. A única coisa aqui que é movimento
   de verdade é o parallax do cartão, e ele é JS (`temMouse`/`semMovimento` em
   postal.js) — uma regra de CSS pra ele não teria efeito nenhum.
   =========================================================================== */

.postal-chegada {
  position: fixed;
  inset: 0;
  /* 11 e não 99: a topbar é 12 e fica POR CIMA. O wordmark da BRUNÊ está na tela o
     tempo todo — a anfitriã presente sem precisar dizer o nome. De quebra, o mute
     nunca fica inalcançável enquanto houver som (WCAG 1.4.2). */
  z-index: 11;
  display: grid;
  place-items: center;
  /* OPACO. Não é scrim, é cortina: ela existe pra esconder a página inteira,
     inclusive o scroll instantâneo que acontece atrás dela. */
  background: var(--bg);
  opacity: 1;
  transition: opacity var(--chegada-cortina) var(--ease);
}

.postal-chegada.is-saindo {
  opacity: 0;
}

/* A navbar fica fora da chegada. Ela desce junto com a cortina, quando a página
   inteira aparece. Gated na classe que o JS acende/apaga: sem script a cortina
   nunca sobe, e a barra segue visível desde o primeiro frame.

   A volta é LENTA e curta de propósito (1,4s, 8px): a barra tem que reaparecer
   sem chamar atenção, depois que a cena já entregou o cartão. A transição mora no
   elemento, não no estado, senão só a ida seria animada. */
.postal-page .topbar {
  transition: opacity 1.4s var(--ease), translate 1.4s var(--ease);
}

:root.postal-chegando .topbar {
  opacity: 0;
  translate: 0 -8px;
  pointer-events: none;
}

.postal-chegada__falas {
  display: grid;
  gap: var(--s3);
  justify-items: center;
  text-align: center;
  max-width: 88vw;
  padding: var(--gutter);
  /* A MEDIDA NÃO MORA AQUI, e a tentativa de pôr custou um bug: `ch` resolve contra
     a fonte DO PRÓPRIO elemento, e este container herda JetBrains Mono a 16px. Um
     `30ch` aqui virava 288px — e a fala, que é Cormorant a 40px, quebrava em duas
     linhas sem precisar. A medida vive na fala, onde a fonte dela vive. */
}

/* UM tamanho pras duas falas. O nome NÃO ganha escala de display: display faz do
   nome um title card, e title card é keynote — a anti-referência "pop star" do
   PRODUCT.md. Do mesmo tamanho, as duas linhas são um parágrafo sendo escrito, que
   é o que a copy quer ser. */
/* O logotipo manuscrito no lugar do título redigitado. Mesma arte do hero. */
.album__logo {
  display: block;
  width: min(100%, 460px);
  height: auto;
}

.postal-chegada__fala {
  /* TODAS na mesma célula do grid: as falas se revezam no mesmo ponto da tela, em
     vez de empilhar. Sem isto, uma frase saindo deixaria o buraco dela no layout e
     a seguinte entraria mais abaixo. */
  grid-area: 1 / 1;
  margin: 0;
  font-family: var(--serif);
  font-size: clamp(24px, 5.2vw, 40px);
  /* Aqui `ch` resolve contra Cormorant no tamanho real da fala — é o único lugar
     onde a medida significa o que a gente quer que signifique. */
  max-width: 30ch;
  line-height: 1.24;
  color: var(--fg);
  opacity: 0;
  transition: opacity var(--chegada-entrada) var(--ease);
  text-wrap: balance;
  /* O campo de nome aceita 40 caracteres livres. "Fernanda Beatriz de Albuquerque"
     existe, e aqui ela aparece sozinha no meio da tela. */
  overflow-wrap: anywhere;
  hyphens: none;
}

.postal-chegada__fala.is-in {
  opacity: 1;
}

/* Nada de translateY. O `.reveal` do DS usa, e este desvio é deliberado: Y é
   "chegar de algum lugar", e estas palavras não vêm de lugar nenhum — elas
   aparecem, como tinta secando. */
.postal-chegada__falas.is-saindo .postal-chegada__fala {
  opacity: 0;
  transition-duration: var(--chegada-saida);
}

.postal-chegada__pular {
  position: absolute;
  bottom: max(var(--s5), env(safe-area-inset-bottom));
  min-height: var(--tap);
  padding: 0 var(--s4);
  font-family: var(--sans);
  font-size: var(--label-size);
  letter-spacing: var(--utility-track);
  text-transform: uppercase;
  color: var(--muted);
  background: none;
  border: 0;
  cursor: pointer;
  transition: color var(--dur-micro) var(--ease);
}

.postal-chegada__pular:hover {
  color: var(--fg);
}

.postal-chegada__pular:focus-visible {
  outline: 2px solid var(--fg);
  outline-offset: 3px;
  border-radius: 100px;
}

/* ===========================================================================
   PRA QUEM RECEBEU, A SEÇÃO 02 *É* A PÁGINA

   O cartão morava dentro do `.movement`, que é o grid editorial do site
   (`rail | conteúdo`). Isso o tratava como figura dentro de um artigo: a coluna do
   rail empurrava ele 95px pra direita (ele centralizava na coluna de conteúdo, não
   na tela), a topbar cortava ele com 2px de folga, e "02 · O cartão / arraste pra
   girar" boiava no canto esquerdo feito entulho. Medido em 1440×813, nas duas pontas.

   A seção 02 não é uma seção como as outras. Ela é a hora em que o cartão aparece —
   pra quem acabou de escrever e pra quem acabou de receber. Nas duas o cartão é o
   produto, e o enquadramento é dele.

   Isto NÃO é arrancar o cartão pra um fullscreen flutuante (a "galeria" rejeitada em
   04/07). Ele continua na seção 02, no documento, com o botão embaixo e o rodapé
   depois. O que muda é só quem manda no enquadramento.

   Sem `[data-recebido]` de propósito. Isto já esteve escopado nele, e era errado por
   duas razões: dava ao remetente a versão pior da mesma tela, e fazia o mesmo cartão
   ter dois tamanhos sem nenhum motivo além de qual link a pessoa clicou.
   =========================================================================== */

/* Uma coluna só: o cartão centraliza na TELA, não na coluna de conteúdo.
   O `padding-top` da topbar entra ANTES do `align-content: center`, não depois — ela
   é sticky e come 65px do alto, e centralizar no viewport inteiro deixava 24px de
   folga em cima contra 188px embaixo. Tirando a topbar da conta, o que sobra é o ar
   de verdade, e ele divide igual entre cartão e botão. */
#cartao.movement {
  grid-template-columns: 1fr;
  column-gap: 0;
  min-height: 100svh;
  align-content: center;
  padding-block: 66px 0;
  /* SEM o `max-width: 42ch` (--measure) que o DS dá às seções de leitura: aqui a seção é
     o CARTÃO, herói de tela cheia, não uma coluna de texto. Com o cap de 42ch (~361px no
     mobile) a seção ficava mais estreita que o cartão (96vw ≈ 377px), e o cartão
     transbordava TODO pra direita (esq 16px, dir 0) — o `place-items: center` do palco não
     conserta porque a track do grid é a largura do cartão, que estoura o container à
     direita. Sem o cap, a seção é do tamanho do viewport e o cartão centra: mesmo respiro
     dos dois lados. */
  max-width: none;

  /* CLIP DO SANGRAMENTO 3D — e por que ele NÃO fere a Regra nº 1.
     O clarão (`inset:-30%` + translateX até ±70%) e a luz da frente (`inset:-25%`)
     sangram MUITO além do cartão de propósito, e quem os contém é o `overflow:hidden` da
     FACE. Só que o Safari do iPhone NÃO honra esse `overflow:hidden` quando a face está num
     contexto 3D com backface-visibility (bug conhecido do WebKit): os spans vazam, a página
     fica ~879px de largura num viewport de 375 e dá pra "arrastar pro lado" — o "cartão
     fantasma". (Reproduzido forçando `overflow:visible` nas faces: scrollWidth 375 → 879.)

     A Regra nº 1 proíbe overflow em ancestral do `.postal-cartao` porque achata o
     preserve-3d. A exceção é precisa: a `perspective` mora no `#palco` (o FILHO), então o
     contexto 3D começa ali. `#cartao` está ACIMA da perspectiva — clipar aqui recorta o
     RESULTADO já projetado, sem tocar na preservação do 3D. Verificado: com este clip a
     face ainda encolhe a 0px em 90° (perspectiva intacta) e o scroll volta a 375.

     `overflow-x: clip` e não `hidden`: `clip` convive com `overflow-y: visible` (hidden
     forçaria o Y a `auto`, criando container de rolagem e podendo cortar a sombra vertical).
     Só o eixo X, que é o único que sangra. */
  overflow-x: clip;
}

/* "02 · O cartão" é entrada de índice: serve pra quem percorre a página, não pra
   quem está olhando o postal. Quem ensina a girar é o botão logo abaixo, que diz
   "Abrir o postal" com todas as letras — a legenda no rail era redundância boiando
   longe do objeto que ela explicava. */
#cartao.movement .rail {
  display: none;
}

/* O palco não centraliza mais nada: quem centraliza é a seção, e o palco só ocupa a
   altura do cartão. Ter os dois com `align-content: center` fazia um desfazer o
   outro — o padding do palco entrava DEPOIS do centro da seção e empurrava tudo. */
#cartao.movement .postal-palco {
  min-height: 0;
  padding-block: 0;
}

/* ============ PALCO ============ */

.postal-palco {
  display: grid;
  place-items: center;
  perspective: 1600px;
  perspective-origin: 50% 45%;
  padding: clamp(20px, 5vw, 56px) 0;
  /* touch-action: o arrasto gira o cartão; o browser não pode roubar o gesto
     pra fazer scroll. `pan-y` mantém o scroll vertical da página funcionando. */
  touch-action: pan-y;
}

/* ============ O CARTÃO ============ */

.postal-cartao {
  position: relative;
  width: var(--postal-w);
  height: var(--postal-h);
  transform-style: preserve-3d;
  /* rotateY(180deg) = verso à mostra. O JS escreve --ry/--rx/--perfil por frame. */
  transform: rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg));
  cursor: grab;

  /* SEM `transition` no transform, de propósito — e é a única coisa no site que
     foge do `var(--ease)` do DS. Quem integra o giro é uma mola no JS (ver "A MOLA"
     em postal.js). Uma transição CSS é curva enlatada: não sabe que o cartão já
     estava girando quando a pessoa clicou, reinicia do zero e engole a velocidade
     que existia. Se alguém devolver um `transition: transform` aqui, ela vai brigar
     com a mola a cada frame e o giro fica borrachudo.

     Sem will-change fixo: o cartão fica parado a maior parte do tempo, e camada
     promovida à toa custa memória de GPU no celular. A mola liga e desliga sozinha. */
}

.postal-cartao.is-arrastando {
  cursor: grabbing;
  will-change: transform;
}

/* NENHUMA imagem do cartão é arrastável nem captura o ponteiro. `-webkit-user-drag: none`
   mata o drag NATIVO de imagem do browser (o "fantasma" que sai colado no cursor); sem
   isto, clicar e arrastar sobre a foto começava um drag-and-drop da imagem EM VEZ de girar
   o postal — e sequestrava o gesto, então o cartão nunca imantava numa face. As camadas de
   profundidade já tinham `pointer-events:none`; a `.postal-foto` (fallback) não tinha, e
   era ela que arrastava. O cartão inteiro é o alvo do arrasto-pra-girar; as imagens só
   desenham. Os campos (textarea/input) NÃO são imagens, então seguem interativos. */
.postal-cartao img {
  -webkit-user-drag: none;
  user-select: none;
  pointer-events: none;
}

/* ENQUANTO ARRASTA PRA GIRAR, nada na página seleciona. O arrasto do cartão ancorava e
   estendia a seleção nativa do browser — girar o postal saía "pintando" o texto do site
   em volta (nav, consentimento, botões). A classe entra no <html> no pointerdown do giro
   e sai no `solta()`, então vale SÓ durante o gesto: fora dele, os campos continuam
   selecionáveis normalmente (escrever, copiar a mensagem). `!important` porque precisa
   ganhar do `user-select: text` dos campos pela duração do arrasto. */
html.postal-arrastando,
html.postal-arrastando * {
  -webkit-user-select: none !important;
  user-select: none !important;
  -webkit-touch-callout: none;
}

/* O cartão é botão antes de ser objeto: quem usa teclado abre com Enter/Espaço. */
.postal-cartao:focus-visible {
  outline: 2px solid var(--fg);
  outline-offset: 14px;
  border-radius: 4px;
}

/* ============ AS FACES ============ */

.postal-face {
  position: absolute;
  inset: 0;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  border-radius: 3px;
  overflow: hidden; /* seguro: a face é folha da árvore 3D, não ancestral dela */

  /* A ARESTA CORTADA, e ela não é enfeite — é a única coisa que dava contorno ao
     objeto. As três sombras abaixo são pretas, e a página é Breu #1a1413: preto
     sobre quase-preto não separa nada. No tema escuro o cartão não tinha borda
     nenhuma, e nos cantos onde a foto escurece ele DISSOLVIA no fundo. Parecia uma
     imagem colada na página, não um postal pousado nela.

     A solução é física, não decorativa: a frente é impressa até a borda, mas o
     corte do papel mostra o miolo do cartão — creme. É essa aresta que pega luz num
     quarto escuro, e é ela que o olho lê como "objeto".

     Os dois se revezam sozinhos, sem media query: no tema claro a aresta creme some
     contra o papel creme e as sombras fazem o trabalho; no escuro as sombras somem
     contra o Breu e a aresta faz. Cada tema usa o recurso que ali funciona.

     `--postal-espessura` e não um px cravado: esta linha É a espessura do cartão
     vista de frente. Se um dia o cartão engordar, a aresta engorda junto. */
  box-shadow:
    0 0 0 var(--postal-espessura) var(--papel-sombra),
    0 1px 1px var(--postal-sombra-contato),
    0 18px 40px -12px var(--postal-sombra-perto),
    0 40px 90px -30px var(--postal-sombra-longe);
}

/* No tema CLARO a sombra é a única separação (a aresta creme some contra o papel creme),
   mas preto a 0.5 sobre o creme vira um borrão pesado. Tinta quente (a mesma família do
   --shadow-video/flutuante do DS) e alpha baixo: o cartão parece papel POUSADO, não colado
   com uma sombra dura embaixo. Só o claro muda; o escuro fica com o forte-porém-invisível. */
:root[data-theme="light"] .postal-page {
  --postal-sombra-contato: rgba(33, 25, 24, 0.1);
  --postal-sombra-perto: rgba(33, 25, 24, 0.14);
  --postal-sombra-longe: rgba(33, 25, 24, 0.08);
}

/* translateZ separa as faces em Z. Sem isso, duas faces coplanares brigam
   (z-fighting) e o Safari pisca entre uma e outra durante o giro. */
.postal-face--frente {
  transform: rotateY(0deg) translateZ(var(--postal-espessura));
}

.postal-face--verso {
  transform: rotateY(180deg) translateZ(var(--postal-espessura));
  background: var(--papel);
}

/* ============ FRENTE — a foto ============ */

/* `display: contents` e não um wrapper com tamanho: o <picture> existe só pra escolher
   o arquivo, e não deve entrar no layout. Sem isso o `height: 100%` da foto passaria a
   medir contra o <picture> (inline, altura de linha) em vez da face, e a frente do
   cartão ficaria com uma tira de foto no topo. O <picture> não carrega semântica, então
   tirá-lo da árvore não custa acessibilidade — quem tem `alt` é o <img>, e ele fica. */
.postal-foto-wrap {
  display: contents;
}

.postal-foto {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  /* A foto já vem com o duotone e o grão queimados do Figma. Nada de filtro aqui:
     seria tratar duas vezes. */
}

/* A foto lisa não tem mais parallax próprio: as camadas de profundidade (abaixo) a
   cobrem nas duas pontas, então uma transform aqui só moveria um elemento escondido. Ela
   fica como FALLBACK (se uma camada não carregar) e como âncora de acessibilidade — é o
   `alt` dela que descreve a capa; as camadas são `aria-hidden`. */

/* O brilho especular da frente. A primeira versão era um HOLOFOTE redondo, branco puro,
   em `screen` sobre o céu escuro — virava um blob de névoa colado no cursor, e lia como
   fake. Reflexo de verniz de verdade tem quatro qualidades que isto agora imita:
     · ALONGADO (elipse deitada, não círculo): é uma BANDA que varre, não um ponto;
     · QUENTE (branco levemente âmbar, não #fff): luz real não é branco de tela;
     · MACIO e FRACO: o pico caiu de 0.22 pra 0.11, e o raio abriu — sheen, não mancha;
     · CONSEQUÊNCIA DO ÂNGULO, não do cursor: verniz reflete no ângulo RASO e some de
       frente. `--holo` já é a distância do centro (0 de frente, 1 no canto). De frente o
       brilho quase não existe; ao levar o ponteiro pro grazing, ele acende. É isso que
       tira o "holofote no meio da tela".
   Some junto com a face quando o cartão vira de costas (backface-visibility) — verniz só
   brilha no lado impresso. Overshoot no `inset` pra a borda macia não cortar reto. */
.postal-luz-frente {
  position: absolute;
  inset: -25%;
  pointer-events: none;
  background: radial-gradient(
    88% 42% at calc(var(--px, 0.5) * 100%) calc(var(--py, 0.5) * 100%),
    rgba(255, 248, 236, 0.11),
    rgba(255, 248, 236, 0.035) 40%,
    transparent 66%
  );
  mix-blend-mode: screen;
  opacity: calc(0.12 + var(--holo, 0) * 0.5);
}

/* ============ PROFUNDIDADE POR CAMADAS (Nível 2) ============

   Dois planos reais empilhados sobre a `.postal-foto`, dentro da face — céu ao FUNDO,
   BRUNÊ na FRENTE, cada um com seu recorte (landscape no desktop, retrato no celular via
   <picture>). A DIFERENÇA de ritmo entre eles É a profundidade: a BRUNÊ desliza ~2,3×
   mais que o céu e descola dele. Transform 2D em folha da árvore 3D não toca no
   preserve-3d (Regra nº 1, testada a 45°/90°).

   O `wrap` é `display: contents` (só escolhe o arquivo; não entra no layout), como o da
   foto. As camadas SEMPRE aparecem — no desktop e no celular. Quem move é o input:
   ponteiro no desktop, giroscópio no celular ("segurar e girar o postal"). */
.postal-camada-wrap {
  display: contents;
}

.postal-camada {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
}

/* A FORÇA da profundidade — UM número pra tudo. Sobe/desce o parallax dos três planos de
   uma vez, sem tocar na proporção entre eles. 1 = como calibrado; 1.3 = 30% mais
   dramático (se no seu celular estiver sutil demais); 0.7 = mais contido. É o knob que a
   gente afina segurando o aparelho. */
.postal-page {
  --prof: 1;
}

/* O parallax só liga quando HÁ input — `data-mov` no body, escrito pelo JS quando o
   ponteiro se move (desktop) ou o giroscópio começa a mandar (celular). Sem `data-mov`
   as camadas ficam em transform identidade: recorte exato, custo zero, sem o
   sobre-recorte do `scale` pagando por um movimento que não existe.

   SEM `transition` de propósito: o giroscópio já é suavizado no JS (o lerp de `ligaTilt`),
   e o ponteiro já vem suave do sistema. Uma transição CSS por cima só somava lag — o
   efeito arrastava atrás da mão, o oposto de "responde ao aparelho". */
.postal-page[data-mov] .postal-camada {
  will-change: transform;
}

/* O céu é o plano LONGE: desliza pouco. `scale` dá a folga pro translate não abrir fresta
   da aresta da face (o fundo é opaco e preenche a face inteira). */
.postal-page[data-mov] .postal-camada--fundo {
  transform: scale(1.06)
    translate(
      calc((var(--px, 0.5) - 0.5) * 1.6% * var(--prof, 1)),
      calc((var(--py, 0.5) - 0.5) * 1.6% * var(--prof, 1))
    );
}

/* A BRUNÊ é o plano PERTO: desliza ~2,3× mais que o céu. Recorte com alpha, o céu sempre
   preenche atrás — precisa de menos scale. */
.postal-page[data-mov] .postal-camada--brune {
  transform: scale(1.03)
    translate(
      calc((var(--px, 0.5) - 0.5) * 3.6% * var(--prof, 1)),
      calc((var(--py, 0.5) - 0.5) * 3.6% * var(--prof, 1))
    );
}

/* O WORDMARK — plano MAIS PRÓXIMO, posicionado (não cobre a face). Posição exata do Figma
   (ver o HTML). Não usa `object-fit`: é um elemento colocado, com largura própria. */
.postal-camada--logo {
  position: absolute;
  left: 8.82%;
  top: 47.02%;
  width: 35.46%;
  height: auto;
  pointer-events: none;
}

/* Parallax do logo em `--postal-w` (a LARGURA DO CARTÃO), não em `%` — que resolveria
   contra a caixa pequena do próprio logo e daria um movimento gigante e inconsistente.

   Era `cqw`, e isso QUEBROU o cartão: pra ter `cqw` eu pus `container-type: inline-size`
   na `.postal-face--frente`, mas `container-type` implica `contain: layout`, que TIRA o
   elemento do contexto 3D do pai (achata/regrupa) e mata o `backface-visibility`. No
   verso, a frente vazava espelhada e distorcida — o cartão inteiro parecia bugado. O
   teste de Regra nº 1 não pegou porque mede a face do VERSO, não a da frente. Lição no
   header do arquivo. `--postal-w` dá o mesmo tamanho (4,6% da largura do cartão) SEM
   container nenhum. Plano mais próximo => desliza MAIS que a BRUNÊ, e flutua sobre ela. */
.postal-page[data-mov] .postal-camada--logo {
  will-change: transform;
  transform: translate(
    calc((var(--px, 0.5) - 0.5) * var(--postal-w) * 0.046 * var(--prof, 1)),
    calc((var(--py, 0.5) - 0.5) * var(--postal-w) * 0.046 * var(--prof, 1))
  );
}

@media (prefers-reduced-motion: reduce) {
  .postal-page[data-mov] .postal-camada--logo {
    transform: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .postal-page[data-mov] .postal-camada {
    transform: none;
    transition: none;
  }
}

/* ============ O PAPEL ============ */

/* Grão: o mesmo tile do site, em multiply, pra tinta e papel receberem a
   mesma textura. Dentro da face — nunca acima do cartão (Regra nº 1). */
.postal-papel-grao {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image: url("../ds-bundle/assets/brune-grain-tile.webp");
  background-repeat: repeat;
  background-size: 180px 180px;
  mix-blend-mode: multiply;
  opacity: 0.16;
}

/* Fibra do papel: feTurbulence numa data-URI, rasterizado UMA vez pelo browser e
   depois só repetido como imagem. É estático de propósito — filtro SVG recalculado
   por frame re-rasteriza tudo e derruba o fps no celular. Quem se mexe é a luz. */
.postal-papel-fibra {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.14;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3' seed='7'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='220' height='220' filter='url(%23f)' opacity='0.4'/%3E%3C/svg%3E");
  background-repeat: repeat;
  background-size: 220px 220px;
}

/* Brilho especular: o papel não é fosco nem espelho. Um gradiente largo e fraco
   que segue o ponteiro dá a leitura de "superfície sob uma luz" sem custo de filtro. */
.postal-papel-luz {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(
    60% 80% at calc(var(--px) * 100%) calc(var(--py) * 100%),
    rgba(255, 255, 255, 0.5),
    rgba(255, 255, 255, 0) 70%
  );
  mix-blend-mode: soft-light;
}

/* ============ O CLARÃO DO GIRO ============ */

/* Um cartão de verdade pega a luz quando vira: o clarão varre a superfície e some
   quando ela volta a encarar você. É a coisa que faz o objeto ter matéria, e o que
   faltava aqui — o giro era geometria correta e sem física nenhuma.

   Vive DENTRO de cada face (Regra nº 1: blend acima do cartão achata o preserve-3d),
   e é dirigido por `--perfil` (0 de frente, 1 de perfil), que o JS escreve por frame
   a partir do próprio ângulo. Consequência do ângulo, não animação em paralelo: um
   cartão parado a 90° fica de perfil, com o clarão que um perfil teria — não "no
   meio de uma animação que já acabou". */
.postal-clarao {
  position: absolute;
  inset: -30%;
  pointer-events: none;
  border-radius: 50%;
  background: radial-gradient(
    circle,
    rgba(255, 255, 255, 0.42) 0%,
    rgba(255, 255, 255, 0.1) 38%,
    transparent 70%
  );
  /* screen sobre o papel creme estouraria pra branco; soft-light mantém o brilho
     dentro do monocromo quieto da casa. O ganho é o mesmo, o berro não. */
  mix-blend-mode: soft-light;
  /* Sai de fora à esquerda, cruza, e sai à direita — a luz varrendo a superfície. */
  transform: translateX(calc((var(--perfil, 0) - 0.5) * 140%));
  opacity: calc(var(--perfil, 0) * 0.9);
  will-change: transform, opacity;
}

/* ============ ESPESSURA ============ */

/* Sem isso o cartão é uma folha de zero espessura e, de perfil, some por completo.
   Duas bordas bastam: o olho não checa as quatro. */
.postal-canto {
  position: absolute;
  background: linear-gradient(var(--papel-sombra), #cfc5ae);
  pointer-events: none;
}

.postal-canto--dir {
  top: 0;
  right: 0;
  width: calc(var(--postal-espessura) * 2);
  height: 100%;
  transform: rotateY(90deg);
  transform-origin: right center;
}

.postal-canto--esq {
  top: 0;
  left: 0;
  width: calc(var(--postal-espessura) * 2);
  height: 100%;
  transform: rotateY(-90deg);
  transform-origin: left center;
}

/* ============ SOMBRA NO CHÃO ============ */

/* Irmã do cartão, não ancestral — de novo a Regra nº 1. Ela se deforma junto com
   o giro pra sombra não parecer colada.

   `--perfil` encolhe a sombra conforme o cartão vira: de frente ele apresenta a
   superfície inteira ao chão e a sombra é larga; de perfil ele apresenta uma borda,
   e a sombra fecha. Sombra do mesmo tamanho em qualquer ângulo é o detalhe que
   denuncia que aquilo é um retângulo com CSS, não um objeto. */
.postal-sombra {
  position: absolute;
  left: 50%;
  bottom: -6%;
  width: 78%;
  height: 8%;
  transform: translateX(-50%) translateX(calc((var(--px) - 0.5) * -40px))
    scaleX(calc(1 - var(--perfil, 0) * 0.55));
  background: radial-gradient(50% 50%, rgba(0, 0, 0, 0.45), transparent 72%);
  filter: blur(18px);
  opacity: calc(1 - var(--perfil, 0) * 0.35);
  pointer-events: none;
  z-index: -1;
}

/* ===========================================================================
   O SELO HOLOGRÁFICO
   Pilha de camadas, de baixo pra cima:
     1. tinta   — o eclipse carmim, o desenho real
     2. holo    — faixas de matiz em color-dodge, deslocadas pelo ponteiro
     3. brilho  — clarão especular em overlay, segue o ponteiro
   As três vivem DENTRO da face. Blend mode aqui é seguro (folha da árvore 3D).

   Por que faixas de matiz e não um arco-íris de conic-gradient: foil real é
   interferência de película fina — o matiz varre um trecho do espectro e volta,
   não dá a volta completa. Arco-íris fechado é o que faz parecer adesivo de bazar.
   =========================================================================== */

.postal-selo {
  /* A silhueta do eclipse recorta as três camadas. Uma variável só, pra máscara
     nunca sair de sincronia entre a tinta, o holo e o brilho. */
  --selo-mask: url("../assets/postal/postal-selo-mask.svg");

  position: relative;
  flex: 0 0 auto;
  width: 9cqw;
  aspect-ratio: 40.8769 / 28.5947; /* a razão real do desenho, não um quadrado */
  isolation: isolate; /* prende os blends ao selo; não vazam pro papel */
}

/* O desenho real: carmim + índigo, como no Figma. */
.postal-selo__tinta {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

/* Foil de verdade é película fina: o matiz VARRE um trecho do espectro conforme o
   ângulo e volta — não dá a volta completa. Arco-íris fechado é o que faz parecer
   adesivo de bazar, e foi exatamente o que a primeira versão fez.
   Duas correções em cima disso:
     · `overlay`, não `color-dodge` — dodge sobre carmim satura na hora e estoura
       pra magenta/branco, matando o desenho embaixo;
     · faixa curta de matiz (ouro → verde → azul) e opacidade baixa, pra a marca
       continuar sendo carmim e índigo, com brilho POR CIMA, não no lugar. */
.postal-selo__holo {
  position: absolute;
  inset: 0;
  -webkit-mask: var(--selo-mask) center / contain no-repeat;
  mask: var(--selo-mask) center / contain no-repeat;
  background: repeating-linear-gradient(
    var(--holo-ang, 100deg),
    #d9a441 0%,
    #6fc4a8 9%,
    #5b7fd4 18%,
    #d9a441 27%
  );
  background-size: 180% 180%;
  background-position: calc(var(--px) * 100%) calc(var(--py) * 100%);
  mix-blend-mode: hard-light;

  /* A intensidade acompanha o ângulo, e é isso que separa foil de adesivo.
     Foil parado é quase só tinta; foil em ângulo raso é que pega fogo. `--holo`
     (0..1) é a distância do ponteiro até o centro, escrita pelo JS. Parado, a
     marca é carmim e índigo; inclinada, ela irisa. Uma opacidade fixa teria que
     escolher entre as duas — e as duas são verdade, em momentos diferentes. */
  opacity: calc(0.16 + var(--holo, 0) * 0.74);
}

.postal-selo__brilho {
  position: absolute;
  inset: 0;
  -webkit-mask: var(--selo-mask) center / contain no-repeat;
  mask: var(--selo-mask) center / contain no-repeat;
  background: radial-gradient(
    38% 38% at calc(var(--px) * 100%) calc(var(--py) * 100%),
    rgba(255, 255, 255, 0.9),
    rgba(255, 255, 255, 0.15) 45%,
    transparent 70%
  );
  mix-blend-mode: plus-lighter;
  opacity: 0.55;
}

/* ============ O VERSO IMPRESSO ============ */

/* O container mora na FACE, não no `.postal-verso`, e a diferença não é estilo: um
   elemento NÃO pode consultar o próprio container, e o `grid-template-columns` que
   precisa mudar mora no `.postal-verso`. Com o container na face, o verso vira
   consultável. A face é FOLHA da árvore 3D (o `preserve-3d` é do cartão, e ela não
   tem filhos em 3D), então a contenção que o `container-type` traz não sobe pro
   cartão — medido a 45°, não lido no `transformStyle`, que mente sobre achatamento. */
.postal-face--verso {
  container-type: inline-size;
}

.postal-verso {
  position: absolute;
  inset: 0;
  padding: 6.2% 5.5%;
  color: var(--tinta);
  display: grid;
  grid-template-columns: 1fr 1px 1fr;
  grid-template-rows: auto 1fr auto;
  gap: 0 5%;
  /* container query unit: tudo escala com o cartão, não com a viewport.
     É o que faz o postal ser o MESMO objeto no celular e no desktop. */
  container-type: inline-size;
}

.postal-cabeca {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: 2.5cqw;
}

/* A MARCA REAL, mascarada na tinta do cartão — não mais a Cormorant aproximando o
   wordmark. O texto "BRUNÊ" segue no DOM (selecionável, buscável, lido por leitor de
   tela); o que se VÊ é o `background` recortado pela forma do wordmark (mesma técnica do
   `.postal-pontilhado`). `cqw` na altura pra escalar com o cartão nas duas pontas. */
.postal-wordmark-txt {
  display: inline-block;
  flex: 0 0 auto;
  height: 3.1cqw;
  aspect-ratio: 928 / 196;
  background: var(--tinta);
  -webkit-mask: url("../brune-logo-cream.svg") left center / contain no-repeat;
  mask: url("../brune-logo-cream.svg") left center / contain no-repeat;
  /* o texto vira só acessibilidade: some visualmente, mas continua na árvore */
  color: transparent;
  font-size: 0;
  line-height: 0;
  white-space: nowrap;
}

.postal-cabeca__postal {
  font-family: var(--sans);
  font-weight: 700;
  font-size: 1.5cqw;
  letter-spacing: 0.3cqw;
  color: var(--tinta);
}

/* Os pontos feitos à mão do Figma. mask + currentColor pra herdarem a tinta,
   em vez de um <img> com a cor congelada dentro do arquivo. */
.postal-pontilhado {
  flex: 1;
  height: 1.2cqw;
  background-color: var(--tinta);
  -webkit-mask: url("../assets/postal/postal-pontilhado.svg") center / contain no-repeat;
  mask: url("../assets/postal/postal-pontilhado.svg") center / contain no-repeat;
  opacity: 0.85;
}

.postal-divisor {
  grid-row: 2 / 4;
  grid-column: 2;
  background: var(--tinta);
  opacity: 0.6;
  width: 1px;
}

/* --- coluna da mensagem --- */

.postal-mensagem {
  grid-column: 1;
  grid-row: 2;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.postal-rotulo {
  font-family: var(--sans);
  font-weight: 700;
  font-size: 1.35cqw;
  letter-spacing: 0.24cqw;
  margin-bottom: 2.5cqw;
}

.postal-rotulo::after {
  content: "•";
  color: var(--carmim);
  margin-left: 0.6cqw;
}

/* O texto escrito à mão. Pauta real: cada linha do texto cai sobre uma linha
   impressa, então o line-height e o background-size TÊM que casar. É por isso
   que os dois usam --pauta e não dois números soltos. */
/* A TIPOGRAFIA TEM PISO — e o piso é o que consertou o defeito, não o tamanho do cartão.

   `cqw` é % da largura do CARTÃO, e num celular a largura do cartão é a do celular.
   Sem piso, isto dava 7,6px de mensagem e 3,3px de rótulo num iPhone — o postal existe
   pra ser lido no celular, e não era legível lá. `max(…, 1rem)` trava em 16px: some o
   zoom no foco do Safari do iPhone (que dispara abaixo de 16px e jogaria um cartão
   fullscreen pra fora da tela) e a pessoa enxerga o que digita.

   O piso é LOCAL, na fonte. Piso em `rem` no `--postal-w` foi medido e reprovado: dava
   cartão de 704px num viewport de 375 → scroll horizontal → falha de WCAG 1.4.10.
   `transform: scale` também está proibido: congelaria a letra em 8px visuais, matando
   o zoom junto com a legibilidade.

   `--pauta` serve line-height E background-size — é o contrato que faz o texto cair NA
   linha impressa. Por isso ele ganha piso junto: pauta e letra crescem casadas, senão
   a letra de 16px escreveria por cima de uma pauta de 8px. */
.postal-linhas {
  --pauta: max(5.1cqw, 1.5rem);
  flex: 1;
  font-family: var(--serif);
  font-size: max(2.3cqw, 1rem);
  letter-spacing: 0.22cqw;
  line-height: var(--pauta);
  white-space: pre-wrap;
  overflow-wrap: break-word;
  background-image: linear-gradient(var(--pauta-tinta) 1px, transparent 1px);
  background-size: 100% var(--pauta);
  /* desce meio pixel pra linha ficar SOB a base da letra, não cortando ela */
  background-position: 0 calc(var(--pauta) - 1px);
  overflow: hidden;

  /* Agora isto é um <textarea>. Ele tem que parar de parecer um. */
  display: block;
  width: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  /* `transparent` explícito: o navegador dá fundo de campo (branco/Field) a todo
     <textarea>, e `background-image` sozinho NÃO apaga isso — o campo desenhava um
     retângulo claro por cima do papel, com a pauta boiando dentro. O papel tem que
     atravessar o campo. */
  background-color: transparent;
  color: var(--tinta);
  resize: none;
  /* `local` e NÃO o padrão `scroll`: com `scroll` a pauta fica carimbada na moldura e o
     texto desliza POR CIMA dela na primeira rolagem — as letras saem de cima das linhas
     e o papel vira mentira. `local` prende o fundo ao conteúdo. */
  background-attachment: local;
  /* O campo não tem caixa: quem diz "escreve aqui" é a pauta. O foco aparece no papel
     (ver `.postal-linhas:focus-visible`), não numa borda de formulário. */
  outline: none;
  -webkit-appearance: none;
  appearance: none;
}

/* A PAUTA É O CAMPO — e por isso ela deixou de ser decoração e virou norma.

   Com `--tinta-35` a linha dava 2,11:1 contra o papel. Enquanto era enfeite, tudo bem:
   linha decorativa não tem piso de contraste. Mas a pauta é a ÚNICA coisa que diz onde
   se escreve — ela virou o indicador do campo, e aí cai sob a 1.4.11, que exige 3:1.
   `--tinta-45` mede 2,6; `--tinta-55` mede 3,4. Fica a 55. */
.postal-page {
  --pauta-tinta: rgba(31, 25, 73, 0.55);
}

/* O foco mora no papel: um anel de sistema em volta de um <textarea> que ocupa meia
   folha desenharia um retângulo de formulário no meio do postal. A pauta escurece — é o
   mesmo objeto dizendo "é aqui", com a linguagem dele. Ainda é 3:1 contra o papel. */
.postal-linhas:focus-visible,
.postal-linhas:focus {
  --pauta-tinta: var(--tinta);
}

/* A pessoa não deve poder EDITAR um postal que já chegou, mas tem que poder LER e
   COPIAR. `readonly` faz exatamente isso; `disabled` tiraria da árvore de leitura e a
   mensagem sumiria pra quem usa leitor de tela. Só o cursor precisa deixar de mentir. */
.postal-linhas:read-only,
.postal-campo__v:read-only {
  cursor: default;
}

/* A REDE DO LADO DE QUEM LÊ — a mensagem ROLA, nunca corta.

   Enquanto se escreve, `overflow: hidden` + o guard geométrico impedem passar da pauta:
   quem escreve NÃO pode exceder a própria tela. Mas quem LÊ pode estar numa tela menor
   que a de quem escreveu (a capacidade da pauta varia com a tela: ~328 num desktop, 220
   num aparelho de 320px). Nesse caso o `overflow: hidden` cortaria o fim da mensagem em
   silêncio — o pior defeito possível aqui. O cap de 300 (postal.js) cobre as telas
   comuns; ISTO cobre o resto: em modo leitura a pauta rola, e a pessoa vê tudo.

   `overflow` aqui é seguro pela Regra nº 1: ela fala de ANCESTRAIS do `.postal-cartao`.
   Isto é descendente da face, que é folha da árvore 3D — não sobe. E o `:read-only`
   garante que só vale pra quem lê: no modo escrita continua `hidden`, senão a pessoa
   rolaria pra além da pauta e o guard geométrico perderia o sentido. */
.postal-linhas:read-only {
  overflow-y: auto;
  scrollbar-width: thin;
}

/* O ZAP VAZIO DO DESTINATÁRIO SOME. No cartão recebido os dois zaps ficam vazios (Regra
   nº 2: telefone nunca entra no link) e readonly. Um input vazio e readonly ainda mostra
   o PLACEHOLDER — o destinatário veria "ZAP (62) 90000-0000", um número falso que parece
   preenchido. Aqui a linha inteira some quando o campo é readonly e só tem placeholder.
   Só os zaps têm placeholder; DE/PARA (preenchidos, sem placeholder) nunca casam com
   `:placeholder-shown`, então nunca somem. No modo escrita os campos não são readonly,
   então quem escreve continua vendo os quatro. */
.postal-campo:has(.postal-campo__v:read-only:placeholder-shown) {
  display: none;
}

/* --- coluna do remetente --- */

.postal-remetente {
  grid-column: 3;
  grid-row: 2;
  display: flex;
  flex-direction: column;
}

/* As duas colunas moram AQUI, e os campos herdam com `subgrid`. Cada `.postal-campo`
   ser um grid próprio fazia cada rótulo medir por conta — "DE" e "REDES" davam
   larguras diferentes e cada valor começava num lugar. Com subgrid, a coluna é uma só
   pros quatro, larga o bastante pro maior rótulo. */
.postal-campos {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0;
  margin-top: 1cqw;
}

/* `min-height: var(--tap)` porque estes campos VÃO virar campos de verdade, e aí a
   linha do endereço deixa de ser desenho e vira alvo de dedo. Só de `padding: 1.9cqw`
   dava 39px num celular — reprova os 44 do DS. No desktop o campo já tem 70px e o
   `min-height` não encosta. `align-content: center` porque `min-height` sem ele
   deixaria o texto colado no alto da caixa que acabei de criar. */
/* `subgrid` e não `8cqw`: com o piso em `rem`, o rótulo parou de escalar junto com o
   cartão e "REDES" a 11px não cabia mais nos 8cqw (=27px num cartão de 377). O texto
   vazava por cima do valor — saía "REDES@eusoubrune". A medida fixa só funcionava
   enquanto TUDO era cqw. Agora a coluna mede o conteúdo, e é a MESMA pros quatro campos.

   `min-height: var(--tap)` porque estes campos VÃO virar campos de verdade, e aí a linha
   do endereço deixa de ser desenho e vira alvo de dedo. Só o `padding: 1.9cqw` dava 39px
   num celular — reprova os 44 do DS. No desktop o campo já tem 70px e o `min-height` não
   encosta. `align-content: center` porque `min-height` sem ele encostaria o texto no alto
   da caixa que o próprio `min-height` acabou de criar. */
.postal-campo {
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: subgrid;
  align-items: baseline;
  align-content: center;
  padding: 1.9cqw 0;
  min-height: var(--tap);
  border-bottom: 1px solid var(--tinta-60);
}

/* O respiro entre rótulo e valor vira padding do rótulo: com `subgrid` o `gap` vem do
   pai, e um `gap` local aqui seria ignorado sem avisar. */
.postal-campo__k {
  padding-right: 1.5cqw;
}

/* O rótulo tinha DOIS defeitos que só apareceram quando alguém mediu: saía a 3,14px
   num celular (e a 9px no desktop — `1cqw` é pequeno em qualquer tela), e a --tinta-60
   sobre o papel dá 4,18:1, que reprova o AA de texto normal (exige 4,5). Não era
   "discreto": era ilegível e fora da norma. Agora tem piso e tinta cheia (13,9:1). */
.postal-campo__k {
  font-family: var(--sans);
  font-weight: 500;
  font-size: max(1cqw, 0.6875rem);
  letter-spacing: 0.22cqw;
  color: var(--tinta);
}

/* Também é <input> agora. Mesma regra do textarea: o campo desaparece, a escrita fica.
   Quem diz "escreve aqui" é o sublinhado do `.postal-campo`, que já existia impresso. */
.postal-campo__v {
  font-family: var(--serif);
  font-size: max(1.9cqw, 1rem);
  letter-spacing: 0.3cqw;
  overflow-wrap: anywhere;
  min-width: 0;
  width: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--tinta);
  outline: none;
  -webkit-appearance: none;
  appearance: none;
}

/* O placeholder do zap é exemplo, não conteúdo: precisa ler como impressão apagada e
   não como algo que a pessoa escreveu. 4,18:1 passa no AA de texto normal? Não (4,5) —
   mas placeholder não é texto de conteúdo, e o rótulo ao lado carrega o significado. */
.postal-campo__v::placeholder {
  color: var(--tinta-35);
  opacity: 1; /* Firefox aplica opacity .54 por conta própria */
}

/* O foco vive no sublinhado que já estava impresso — o campo herda o traço do papel em
   vez de ganhar um anel de formulário por cima do postal. */
.postal-campo:focus-within {
  border-bottom-color: var(--tinta);
  border-bottom-width: 2px;
  padding-bottom: calc(1.9cqw - 1px);
}

/* Erro: carmim no próprio traço do papel. É a cor que o sistema já usa pro erro, e o
   postal já tem vermelho no selo — não entra cor nova no objeto. */
.postal-campo:has([aria-invalid="true"]) {
  border-bottom-color: var(--carmim);
  border-bottom-width: 2px;
  padding-bottom: calc(1.9cqw - 1px);
}

.postal-linhas[aria-invalid="true"] {
  --pauta-tinta: var(--carmim);
}

/* --- rodapé do cartão --- */

.postal-rodape {
  grid-column: 1 / -1;
  grid-row: 3;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  padding-top: 2cqw;
}

/* ============ O VERSO EM UMA COLUNA ============

   Container query e NÃO media query, de propósito: quem decide é a largura do OBJETO,
   não a do aparelho. A regra vale igual pra quem escreve e pra quem lê, e continua certa
   se o cartão mudar de tamanho por qualquer outro motivo.

   Duas colunas num cartão de 377px davam uma coluna de mensagem de 188px — a 16px de
   Cormorant, ~4 palavras por linha. Em uma coluna ela vai a ~335px.

   REDES/SITE saem: são assinatura da BRUNÊ, não conteúdo do postal, e num cartão em pé
   competem com o que a pessoa escreveu. O divisor sai junto — não há o que dividir.

   ESTE BLOCO MORA NO FIM DA SEÇÃO, E ISSO NÃO É ARRUMAÇÃO. `@container` não adiciona
   especificidade nenhuma: dentro dele, `.postal-remetente` continua valendo (0,1,0),
   exatamente igual à regra base. Quem decide é a ORDEM. Este bloco já esteve lá em cima,
   logo depois do `.postal-verso`, e de lá ele perdia calado pra TODA regra base definida
   abaixo — o verso virava 1 coluna, mas o remetente continuava dizendo `grid-column: 3`
   e o grid criava colunas implícitas. Ficava com cara de query que não disparou, e o
   diagnóstico custou caro. Regra nova do verso entra ANTES deste bloco, nunca depois. */
@container (max-width: 520px) {
  .postal-verso {
    grid-template-columns: 1fr;
    grid-template-rows: auto 1fr auto auto;
    gap: 0;
  }

  .postal-mensagem {
    grid-column: 1;
    grid-row: 2;
  }

  .postal-remetente {
    grid-column: 1;
    grid-row: 3;
    margin-top: 3cqw;
  }

  /* Linha 4, e não a 3 da regra base: em pé o remetente ocupa a 3, e os dois
     empilhados na mesma linha se sobreporiam. */
  .postal-rodape {
    grid-row: 4;
  }

  .postal-divisor,
  .postal-campo--assinatura {
    display: none;
  }
}

.postal-cifra {
  font-family: var(--sans);
  font-weight: 500;
  font-size: 1.1cqw;
  letter-spacing: 0.33cqw;
  color: var(--tinta);
}

/* O selo postal: o círculo carmim do Figma — agora um FOIL, não uma tinta chapada.
   Mesma física do selo holográfico da BRUNÊ (.postal-selo__holo/__brilho): faixas de
   matiz em hard-light + um brilho especular, os dois dirigidos por --px/--py/--holo (o
   ponteiro no desktop, o giroscópio no celular). Parado é quase só vermelho; inclinado,
   irisa. Vive DENTRO da face (folha da árvore 3D), então blend e isolation são seguros
   aqui — Regra nº 1 fala de ancestrais do cartão, e o selo é bisneto de uma face. */
.postal-selo-correio {
  position: relative;
  width: 6.5cqw;
  height: 6.5cqw;
  border-radius: 50%;
  background: var(--carmim);
  /* prende os blends ao selo; não vazam pro papel (igual ao .postal-selo) */
  isolation: isolate;
}

/* As faixas de matiz, agora sobre o vermelho. Faixa curta (ouro → verde → azul) e não
   arco-íris fechado, pelo mesmo motivo do selo grande: foil real é película fina, o matiz
   varre um trecho do espectro e volta. A opacidade acompanha o ângulo (--holo): quase só
   tinta parado, pega fogo no grazing. `border-radius` no lugar da máscara SVG — é círculo. */
.postal-selo-correio::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: repeating-linear-gradient(
    var(--holo-ang, 100deg),
    #d9a441 0%,
    #6fc4a8 9%,
    #5b7fd4 18%,
    #d9a441 27%
  );
  background-size: 180% 180%;
  background-position: calc(var(--px) * 100%) calc(var(--py) * 100%);
  mix-blend-mode: hard-light;
  opacity: calc(0.16 + var(--holo, 0) * 0.74);
}

/* O clarão especular que segue o ponteiro — o mesmo do .postal-selo__brilho. */
.postal-selo-correio::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: radial-gradient(
    38% 38% at calc(var(--px) * 100%) calc(var(--py) * 100%),
    rgba(255, 255, 255, 0.9),
    rgba(255, 255, 255, 0.15) 45%,
    transparent 70%
  );
  mix-blend-mode: plus-lighter;
  opacity: 0.55;
}

/* O carimbo de obliteração, batido POR CIMA do selo — é o que o correio faz pra
   o selo não ser reusado, e é o detalhe que faz o postal parecer postado.
   Fica torto de propósito: carimbo é batido à mão, e nenhum sai reto. O ângulo é
   fixo (não aleatório) pra o cartão ser sempre o mesmo objeto — dois postais com
   a mesma data têm que sair idênticos, senão vira enfeite gerado, não impressão. */
/* Ancorado pelo SELO (left), não pela borda do cartão (right): o carimbo tem uma
   relação com o selo — ele cancela o selo — e essa relação é que precisa ficar
   firme. `left: 3.2cqw` põe os anéis cruzando o selo (a obliteração lê) e deixa a
   data cair inteira no papel. Ancorado pela borda, a data escorregava pra trás do
   selo e o "1" do dia sumia — e a data é a única informação que o carimbo carrega. */
.postal-carimbo {
  position: absolute;
  left: 3.2cqw;
  bottom: -1.2cqw;
  width: 8.6cqw;
  height: 8.6cqw;
  transform: rotate(-11deg);
  color: var(--tinta);
  /* Tinta de carimbo nunca cobre por igual — 0.72 dá o encharcamento irregular
     sem precisar de mais uma textura por cima. */
  opacity: 0.72;
  overflow: visible;
}

.postal-carimbo circle {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
}

.postal-carimbo__arco,
.postal-carimbo__data {
  fill: currentColor;
  font-family: var(--sans);
  font-weight: 500;
}

.postal-carimbo__data {
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.4px;
}

/* O selo e o carimbo se sobrepõem, então precisam de um contexto de posicionamento
   próprio. `isolation` não entra aqui: nada faz blend, e criar contexto de pilha
   à toa é o tipo de coisa que morde o preserve-3d lá em cima (Regra nº 1). */
/* O padding reserva a largura que o carimbo ocupa por cima (ele é absolute e sai do
   fluxo). Sem isso o grupo mede só o selo, e o carimbo vaza pra fora da margem do
   cartão — 3.2 + 8.6 = 11.8cqw, menos os 5cqw do selo que já contam, dá 6.8. */
.postal-rodape__marcas {
  position: relative;
  display: flex;
  align-items: center;
  padding-right: 6.8cqw;
}

/* ===========================================================================
   INTERFACE EM VOLTA — daqui pra baixo é Breu/Osso, sem exceção.
   =========================================================================== */

/* ============ FORMULÁRIO ============ */

/* O `max-width: 46ch` SAIU, e não por gosto: o <form> passou a envolver o palco, então
   ele é ANCESTRAL DO CARTÃO. 46ch teria espremido o postal inteiro na medida de uma
   coluna de texto. Pelo mesmo motivo — Regra nº 1 — este seletor NUNCA pode receber
   `overflow`, `opacity` ou `filter`: qualquer um dos três achata o preserve-3d e o
   cartão vira um retângulo chapado, em silêncio. Ele é um contêiner sem opinião. */
.postal-form {
  display: contents;
}

/* Texto que só o leitor de tela ouve. Complementa o rótulo impresso ("DE" vira "DE —
   nome de quem escreve") sem sujar o papel.

   Mora DENTRO de uma face, e isso é seguro apesar do `clip-path`: a Regra nº 1 fala de
   ANCESTRAIS do `.postal-cartao`. Isto é folha — descendente da face, que já é o fim da
   árvore 3D. `clip-path` aqui não sobe.

   Nunca `display:none` nem `visibility:hidden`: os dois tiram da árvore de acessibilidade
   e o complemento não seria lido — que é a única razão dele existir. */
.postal-vh {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* A tira: o que é lei e interface, embaixo do cartão, em Breu/Osso. */
.postal-tira {
  max-width: 52ch;
  text-align: center;
  /* respiro real contra o cartão (que ainda projeta sombra abaixo de si) —
     12px lia como colado em qualquer viewport */
  margin: clamp(28px, 4.5vh, 44px) auto 0;
}

.postal-tira[hidden] {
  display: none;
}

/* A faixa de erro. Carmim porque é a cor de erro do sistema; centrada porque ela fala
   do cartão inteiro, não de um campo — quem aponta o campo é o traço vermelho no papel. */
.postal-erros {
  max-width: 52ch;
  margin: var(--s4) auto 0;
  color: var(--carmim);
  font-family: var(--sans);
  font-size: var(--label-size);
  text-align: center;
}

.postal-erros[hidden] {
  display: none;
}

/* `.postal-campo-ui`, `.postal-input`, `.postal-textarea`, `.postal-erro`, `.postal-dica`,
   `.postal-acoes` e `.postal-contador` foram REMOVIDOS daqui: vestiam o formulário da
   seção "01 · Escreva", que deixou de existir quando a escrita virou o próprio cartão.
   Eram ~70 linhas mantidas vivas por nada, e a mais perigosa delas era
   `.postal-textarea { field-sizing: content }` — se alguém reaproveitasse a classe no
   campo da pauta, o cartão cresceria conforme a pessoa escreve. A regra dos 16px que
   morava aqui virou o piso em `rem` da tipografia do verso, que é onde ela importa. */

/* consentimento — sutil, não escondido. "Sutil" aqui é TAMANHO, ESPAÇO e POSIÇÃO
   (pequeno, margens apertadas, colado acima do botão que efetiva a coleta), nunca
   contraste ruim: `--muted` compõe ~7.8:1 no tema escuro e ~6.1:1 no claro sobre o
   fundo — passa AA 4.5:1 nos dois mesmo a 12px. Rebaixar o contraste pra "discreto"
   deixaria de ser consentimento legível no ponto da coleta, que é o que a LGPD exige. */
/* CENTRADO, como a fila de botões logo abaixo. A tira era uma caixa de 44ch
   centrada com o texto encostado à esquerda dela, e os botões um grupo centrado:
   duas réguas diferentes, e o aceite nascia deslocado em relação aos botões. */
.postal-consent {
  display: flex;
  gap: var(--s2);
  align-items: center;
  justify-content: center;
  margin-bottom: var(--s3);
  font-family: var(--sans);
  font-size: 0.75rem;
  line-height: 1.45;
  color: var(--muted);
}

.postal-consent input {
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  margin-top: 1px;
  accent-color: var(--fg);
}

.postal-consent a {
  color: var(--fg);
}

/* ============ AVISO ============ */

/* Sem cor de alerta: a regra do monocromo vale aqui como no resto da interface.
   O que dá peso é a borda e o espaço, não um vermelho. */
.postal-aviso {
  max-width: 52ch;
  margin: var(--s5) auto 0;
  padding: var(--s4);
  border: 1px solid var(--line-strong);
  border-radius: 3px;
  background: var(--card);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 0.8125rem;
  line-height: 1.5;
  overflow-wrap: anywhere; /* o link do postal é longo e não pode estourar a caixa */
}

/* ============ O MUTE NA NAVBAR ============ */

/* Agrupa mute + tema. Sem isto os dois brigam pelo `justify-content: space-between`
   do `.nav` e o mute ia parar no meio da barra. */
.postal-nav__acoes {
  display: flex;
  align-items: center;
  gap: var(--s2);
}

/* Copia a régua do `.theme-toggle` — mesmo `--tap` (44px), mesma pílula, mesmo
   `--card`. Não é preguiça: os dois são o mesmo tipo de coisa (controle utilitário,
   discreto, que mora na barra), e um botão de som com régua própria ao lado do tema
   leria como enxerto. Também é o que garante os 44×44 de alvo de toque. */
.postal-mute {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  min-width: var(--tap);
  min-height: var(--tap);
  padding: 0 12px;
  border: 1px solid var(--line);
  border-radius: 100px;
  background: var(--card);
  color: var(--fg);
  font: 500 var(--utility-size) / 1 var(--sans);
  letter-spacing: var(--utility-track);
  text-transform: uppercase;
  cursor: pointer;
  transition:
    background var(--dur-micro) var(--ease),
    border-color var(--dur-micro) var(--ease);
}

.postal-mute:hover {
  background: var(--hover);
  border-color: var(--line-strong);
}

.postal-mute:active {
  /* 0.96 — abaixo de 0.95 o toque lê como exagero. */
  transform: scale(0.96);
}

.postal-mute[hidden] {
  display: none;
}

/* Os dois ícones ocupam o MESMO lugar e fazem cross-fade. Um `display:none` faria o
   ícone sumir e reaparecer — um piscar sem transição de saída. Os valores (escala
   0.25→1, blur 4px→0) são os do better-ui, não invenção. */
.postal-mute__icone {
  width: 16px;
  height: 16px;
  flex: 0 0 auto;
  grid-area: 1 / 1;
  transition:
    opacity 0.2s cubic-bezier(0.2, 0, 0, 1),
    scale 0.2s cubic-bezier(0.2, 0, 0, 1),
    filter 0.2s cubic-bezier(0.2, 0, 0, 1);
}

.postal-mute__icone--mudo {
  position: absolute;
  left: 12px;
}

/* Som ligado: o alto-falante com ondas aparece, o mudo some. */
.postal-mute[aria-pressed="false"] .postal-mute__icone--mudo,
.postal-mute[aria-pressed="true"] .postal-mute__icone--ligado {
  opacity: 0;
  scale: 0.25;
  filter: blur(4px);
}

.postal-mute[aria-pressed="false"] .postal-mute__icone--ligado,
.postal-mute[aria-pressed="true"] .postal-mute__icone--mudo {
  opacity: 1;
  scale: 1;
  filter: blur(0);
}

/* O rótulo é a leitura pra quem usa leitor de tela e a dica pra quem não entende o
   ícone. No mobile ele some, como o do tema — a barra é estreita e o aria-label
   carrega o significado. */
.postal-mute__rotulo {
  white-space: nowrap;
}

@media (max-width: 639px) {
  .postal-mute {
    width: var(--tap);
    padding: 0;
  }
  .postal-mute__rotulo {
    display: none;
  }
  .postal-mute__icone--mudo {
    left: 50%;
    translate: -50% 0;
  }

  /* GUTTER DE LEITURA no que fica abaixo do cartão. Sem isto o consentimento e o botão
     primário (`.btn--primary` é `width:100%` no celular) iam de BORDA A BORDA da tela —
     mais largos que o próprio cartão (96vw), encostando e desalinhados dele. O padding vai
     nos containers-folha; NUNCA no `.postal-final`, que envolve chamada + ações e somaria
     o gutter duas vezes nas ações (elas já são `.postal-controles`). */
  .postal-tira,
  .postal-erros,
  .postal-aviso,
  .postal-controles,
  .postal-final__chamada {
    padding-inline: var(--gutter);
  }

  /* OS DOIS BOTÕES LADO A LADO. Antes o primário tomava a linha inteira
     (`.btn--primary` é width:100% no celular) e o "ver a frente" virava um disco
     só de ícone embaixo dele. Agora dividem a linha, os dois com texto: o par de
     ações do cartão lê como um par. */
  .postal-controles {
    display: flex;
    flex-wrap: nowrap;
    gap: var(--s2);
    align-items: stretch;
  }
  .postal-controles .btn {
    flex: 1 1 0;
    width: auto;
    min-width: 0;
    padding-inline: var(--s3);
    justify-content: center;
    text-align: center;
  }
  /* o ícone de girar some: aqui é texto, como o irmão ao lado */
  .postal-virar__icone {
    display: none;
  }
  .postal-virar__txt {
    display: inline;
  }
}

/* ============ CONTROLES DO CARTÃO ============ */

.postal-controles {
  display: flex;
  gap: var(--s3);
  justify-content: center;
  flex-wrap: wrap;
  margin-top: var(--s5);
}

/* O botão de virar: ícone de girar OU texto. O ícone fica escondido por padrão — no
   desktop e no estado "Abrir o postal" (a ação principal de quem recebe) mostra o texto.
   Só no CELULAR + estado aberto ("Ver a frente") ele vira um botão circular só-ícone
   (ver o @media abaixo). A troca de forma acontece junto com o giro 3D do cartão, então
   não precisa de transição própria — o olho já está no cartão virando. */
.postal-virar__icone {
  display: none;
  width: 20px;
  height: 20px;
  flex: 0 0 auto;
}

/* ============ O FINAL (chamada + ações abaixo do cartão) ============ */

/* Irmão do palco, nunca ancestral do cartão (Regra nº 1). Some via [hidden]; quem acende
   é mostraFinal (remetente ao carimbar, destinatário ao abrir). */
.postal-final {
  margin-top: var(--s5);
}

.postal-final[hidden] {
  display: none;
}

/* A chamada pra ouvir. Cormorant itálico, a "voz emocional" do sistema — igual ao lead e
   à letra da seção 02: é convite, não informação. */
.postal-final__chamada {
  max-width: 38ch;
  margin: 0 auto var(--s4);
  text-align: center;
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(18px, 2.1vw, 22px);
  line-height: 1.6;
  color: var(--ink);
}

.postal-final__chamada[hidden] {
  display: none;
}

/* A fila de ações já é `.postal-controles` (herda o flex centrado); só encosta na chamada. */
.postal-final__acoes {
  margin-top: 0;
}

/* ============ MENU DE COMPARTILHAR (portal) ============ */

/* Filho do <body>, fixed: fora de qualquer ancestral do cartão. Mobile-first: bottom sheet
   com fundo escurecido; no desktop vira popover ancorado (o JS posiciona a folha e o fundo
   fica transparente, só pra capturar o clique-fora). */
.postal-share {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: flex-end;
  justify-content: center;
}

.postal-share[hidden] {
  display: none;
}

.postal-share__fundo {
  position: absolute;
  inset: 0;
  background: oklch(0 0 0 / 0.42);
  opacity: 0;
  transition: opacity var(--dur-move) var(--ease);
}

.postal-share[data-aberto="true"] .postal-share__fundo {
  opacity: 1;
}

.postal-share__folha {
  position: relative;
  width: min(440px, 100%);
  background: var(--bg);
  border: 1px solid var(--line-strong);
  border-radius: 22px 22px 0 0;
  /* A sombra flutuante — mesma exceção declarada do `.sacola`: um objeto pousado sobre o
     documento precisa de elevação pra não ler como parte do papel. */
  box-shadow: 0 8px 30px var(--shadow-flutuante);
  padding: var(--s3);
  padding-bottom: calc(var(--s3) + env(safe-area-inset-bottom, 0px));
  opacity: 0;
  transform: translateY(16px);
  transition:
    opacity var(--dur-move) var(--ease),
    transform var(--dur-move) var(--ease);
}

.postal-share[data-aberto="true"] .postal-share__folha {
  opacity: 1;
  transform: none;
}

/* A pega: a afordância de "isto é uma folha que sobe do rodapé e pode ser dispensada".
   Só no celular — no desktop é popover ancorado, não folha (o @media a esconde). */
.postal-share__pega {
  display: block;
  width: 34px;
  height: 4px;
  border-radius: 99px;
  background: var(--line-strong);
  margin: 2px auto var(--s3);
}

.postal-share__titulo {
  margin: 0 0 var(--s2);
  padding-inline: var(--s3);
  font-family: var(--sans);
  font-size: var(--label-xs-size);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}

.postal-share__item {
  display: flex;
  align-items: center;
  gap: var(--s3);
  width: 100%;
  min-height: var(--tap);
  padding: var(--s3);
  border: 0;
  border-radius: 12px;
  background: transparent;
  color: var(--fg);
  font-family: var(--sans);
  font-size: var(--meta-size);
  text-align: left;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition:
    background var(--dur-micro) var(--ease),
    transform var(--dur-micro) var(--ease);
}

.postal-share__item:hover {
  background: var(--hover);
}

/* Toque: um afundar de 1,5% — feedback tátil sem virar bounce. */
.postal-share__item:active {
  transform: scale(0.985);
}

/* Foco de teclado: anel POR DENTRO da linha (box-shadow inset), não um outline que
   estoura pra fora e engorda a folha. O JS foca o primeiro item ao abrir, e um outline
   grosso ali lia como erro. O fundo de hover entra junto, pra leitura redundante. */
.postal-share__item:focus-visible {
  outline: none;
  background: var(--hover);
  box-shadow: inset 0 0 0 1.5px var(--fg);
}

.postal-share__item[hidden] {
  display: none;
}

/* O par copiar/copiado — cross-fade, não toggle seco. Os dois ícones ficam no DOM o
   tempo todo, um sobre o outro (`position:absolute` nos dois, a caixa 22×22 é do par,
   não de cada svg): o que entra nasce em scale(.25)+blur+opacity 0 e assenta; o que sai
   percorre o mesmo caminho ao contrário. Antes era `hidden` cru — a moeda virava sem
   nenhum aviso de movimento, e essa é justo a categoria de ícone (estado que muda,
   like→liked) que pede a animação. */
.postal-share__icone-par {
  position: relative;
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
}

/* O ícone padrão: INLINE, discreto, acende no hover/foco. Antes era `position:absolute`
   pra TODO ícone — mas só o par copiar/copiado (a caixa `-par` acima) precisa empilhar.
   Os ícones soltos (WhatsApp, Stories) herdavam o absolute e fugiam pro canto da folha
   (`inset:0` contra o primeiro ancestral posicionado). Conserto: base estática; o absolute
   volta só DENTRO do par. */
.postal-share__icone {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  color: var(--muted);
  transition: color var(--dur-micro) var(--ease);
}

.postal-share__item:hover .postal-share__icone,
.postal-share__item:focus-visible .postal-share__icone {
  color: var(--fg);
}

.postal-share__icone-par .postal-share__icone {
  position: absolute;
  inset: 0;
  transition:
    opacity var(--dur-move) cubic-bezier(0.2, 0, 0, 1),
    transform var(--dur-move) cubic-bezier(0.2, 0, 0, 1),
    filter var(--dur-move) cubic-bezier(0.2, 0, 0, 1),
    color var(--dur-micro) var(--ease);
}

.postal-share__item [data-icone="copiado"] {
  opacity: 0;
  transform: scale(0.25);
  filter: blur(4px);
}

.postal-share__item[data-copiado="true"] [data-icone="copiar"] {
  opacity: 0;
  transform: scale(0.25);
  filter: blur(4px);
}

.postal-share__item[data-copiado="true"] [data-icone="copiado"] {
  opacity: 1;
  transform: scale(1);
  filter: blur(0);
  color: var(--fg);
}

/* Desktop: popover ancorado (o JS escreve top/left inline na folha), sem escurecer o fundo. */
@media (min-width: 640px) {
  .postal-share {
    align-items: flex-start;
    justify-content: flex-start;
  }
  .postal-share__fundo {
    background: transparent;
  }
  .postal-share__folha {
    position: absolute;
    width: min(300px, 90vw);
    border-radius: 14px;
    padding-bottom: var(--s3);
  }
  /* popover não é folha: sem pega. */
  .postal-share__pega {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .postal-share__fundo,
  .postal-share__folha,
  .postal-share__item,
  .postal-share__icone,
  .postal-share__icone-par .postal-share__icone {
    transition: none;
  }
  .postal-share__folha {
    transform: none;
  }
  .postal-share__item:active {
    transform: none;
  }
}

/* ============ CTA DE STREAMING ============ */

/* Entra 10s depois do cartão aberto. Não é modal e não rouba o foco: a pessoa
   ainda está lendo o cartão dela. */
/* À esquerda, como as seções 00/01/02 desta mesma página. Estava centrada e produzia
   três alinhamentos numa seção só — título e letra no centro, lead e botão na
   esquerda —, porque `.lead` e o flex dos botões têm caixa própria e não obedecem ao
   `text-align` do pai. Uma página, um eixo. */
.postal-cta {
  margin-top: var(--air);
  opacity: 0;
  transform: translateY(14px);
  transition:
    opacity var(--dur-settle) var(--ease),
    transform var(--dur-settle) var(--ease);
}

.postal-cta.in {
  opacity: 1;
  transform: none;
}

.postal-cta[hidden] {
  display: none;
}

/* A capa do single. O contorno de 1px é a regra do better-ui pra imagem: preto puro
   no claro, branco puro no escuro — nunca um neutro tingido, que pega a cor da
   superfície embaixo e lê como sujeira na borda. Aqui ele vira `--capa-borda`, que o
   tema troca; sem isso a capa flutuaria sem assentar no papel. */
.postal-capa {
  --capa-borda: oklch(0 0 0 / 0.1);
  display: block;
  width: min(320px, 62vw);
  height: auto;
  aspect-ratio: 1;
  border-radius: 2px;
  outline: 1px solid var(--capa-borda);
  outline-offset: -1px;
  margin-bottom: var(--s5);
}

/* O título cede pra capa. Em momento de lançamento quem lidera é a arte, não a
   tipografia — e a página já nomeou a faixa em caixa alta de display lá na seção 00;
   repetir em 5,2rem aqui é eco, não hierarquia. O precedente de ajustar a escala do
   `.album__title` por contexto é da própria loja. */
#musica .album__title {
  font-size: clamp(1.7rem, 4.4vw, 2.6rem);
}

[data-theme="dark"] .postal-capa {
  --capa-borda: oklch(1 0 0 / 0.1);
}

/* A letra. Itálico do Cormorant — "A Regra do Itálico Quente" do DESIGN.md: texto
   emocional é sempre serifado itálico. É o que separa a voz da canção da voz do site.
   O filete à esquerda marca a citação — e só funciona porque a seção é alinhada à
   esquerda; com texto centralizado ele lia como layout quebrado. */
/* O respiro embaixo não é gosto: o lead que vem depois é Cormorant itálico igual à
   letra, e colado nela lia como um quinto verso da música. O ar é o que separa a voz
   da canção da voz do site quando as duas usam a mesma tipografia. */
.postal-letra {
  margin: var(--s5) 0 var(--breath);
  padding-left: var(--s5);
  border-left: 1px solid var(--line);
  max-width: 34ch;
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(19px, 2.2vw, 24px);
  line-height: 1.7;
  color: var(--ink);
}

/* A letra agora vem inteira, em estrofes. O respiro entre elas é o que separa
   uma da outra: sem isto as sete estrofes viram um bloco só de texto corrido. */
.postal-letra p + p {
  margin-top: 1.15em;
}

/* A data de lançamento. Mono, como todo dado no sistema — o serifado itálico é a
   voz emocional, e "sai dia 20 de julho" é informação, não sentimento. */
.postal-lancamento {
  margin-top: var(--s4);
  font-family: var(--sans);
  font-size: 0.8125rem;
  letter-spacing: 0.1em;
  color: var(--muted);
}

.postal-plataformas {
  display: flex;
  gap: var(--s3);
  flex-wrap: wrap;
  margin-top: var(--s5);
}

.postal-plataformas:empty {
  margin-top: 0;
}

/* Rodapé fora do grid do `.movement`: ele não tem rail e não precisa de um. */
.postal-rodape-site {
  max-width: var(--sheet);
  margin: 0 auto;
  padding: var(--dense) var(--gutter);
  display: flex;
  align-items: center;
  gap: clamp(14px, 2.4vw, 24px);
  flex-wrap: wrap;
}

/* ============ IMPRESSÃO ============ */

/* Alguém VAI tentar imprimir o postal — é literalmente um postal. */
@media print {
  .topbar,
  .postal-form,
  .postal-controles,
  .postal-cta,
  .grain {
    display: none !important;
  }
  .postal-cartao {
    transform: none !important;
    transition: none !important;
  }
  .postal-face--frente {
    display: none;
  }
  .postal-face--verso {
    position: static;
    transform: none;
    box-shadow: none;
  }
}

/* ============ MOVIMENTO REDUZIDO ============ */

@media (prefers-reduced-motion: reduce) {
  /* O giro do cartão NÃO é tratado aqui — quem cuida dele é o `molaVai()` em
     postal.js, que pula a integração e vai direto ao alvo. Não há `transition` no
     `.postal-cartao` pra encurtar: a mola é JS. Uma regra de CSS aqui não teria
     efeito nenhum e daria a impressão falsa de que o caso está coberto.

     O clarão do giro também não precisa de regra: ele é função do ângulo, e sem
     movimento o ângulo não passa pelos valores intermediários — ele simplesmente
     não acontece. */

  /* O holográfico para de perseguir o ponteiro, mas não some: ele é o desenho
     do selo, não enfeite. Congela num ângulo bonito. O selo dos Correios idem —
     setar --px/--py nele cascateia pros ::before/::after. */
  .postal-selo__holo,
  .postal-selo__brilho,
  .postal-papel-luz,
  .postal-selo-correio {
    --px: 0.5;
    --py: 0.35;
  }
  .postal-cta {
    transition-duration: var(--dur-reduced);
  }
}

/* ============ ALTO CONTRASTE ============ */

@media (forced-colors: active) {
  /* `var(--bg)` some no alto contraste do Windows, e sem isto a cortina fica
     transparente — o cartão vazando por trás durante a sequência inteira. */
  .postal-chegada {
    background: Canvas;
  }

  /* Blend mode e gradiente somem no modo de alto contraste do Windows. O cartão
     ainda precisa ser legível como documento. */
  .postal-selo__holo,
  .postal-selo__brilho,
  .postal-papel-luz,
  .postal-papel-grao,
  .postal-selo-correio::before,
  .postal-selo-correio::after {
    display: none;
  }
  .postal-face {
    border: 1px solid CanvasText;
  }
}

/* ============ OS PASSOS ============
   O caminho inteiro antes de começar. Quem chega do Instagram não sabe que no fim
   sai um link pra mandar no WhatsApp, e ninguém entra numa estrada sem saber onde
   ela termina.

   <ol> de verdade, com contador próprio: o número é conteúdo (a ordem É a
   informação), então ele fica no `::before` do item e não numa <span> escrita à
   mão que o leitor de tela leria duas vezes junto do "1 de 5" nativo. */
.postal-passos {
  counter-reset: passo;
  list-style: none;
  margin: clamp(18px, 3vw, 26px) 0 0;
  padding: 0;
  display: grid;
  gap: 10px;
  max-width: 46ch;
}

.postal-passos li {
  counter-increment: passo;
  display: grid;
  grid-template-columns: 1.6em 1fr;
  gap: 10px;
  align-items: baseline;
  font-family: var(--sans);
  font-size: var(--meta-size);
  line-height: 1.5;
  color: var(--muted);
}

.postal-passos li::before {
  content: counter(passo, decimal-leading-zero);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.08em;
  color: var(--faint);
}
