/* ══════════════════════════════════════════════════════════════════════════════════════════════
   TELA 7 + HUB — DIREÇÃO B, "APLICATIVO"   (aprovada pelo Lucas em 17/08/2026, `_proto/direcao-b.html`)

   Registro: app nativo QUIETO. Densidade maior que uma landing, calor maior que um dashboard — o
   assunto continua sendo luto, então a linguagem de app entra na ESTRUTURA (previsibilidade, estado,
   navegação), nunca no TOM (nada de métrica, nada de "gerencie", nada de cinza corporativo).

   🔒 TRÊS TRAVAS, e nenhuma é opinião:
   1. Tudo aqui é prefixado por `.ap-shell`. Este arquivo entra na PÁGINA INTEIRA (o funil é uma só
      página com 7 telas): um seletor solto mudaria as telas 1 a 6, que não estão em revisão.
      🔁 26/08/2026 — o prefixo ERA `#screen-7`, e virou classe quando o Lucas pediu a mesma casca
      no `/acompanhar`, que não tem tela numerada nenhuma. Trocar o id por classe é o que permite
      DOIS hosts com UM arquivo de CSS; duplicar 797 linhas é como o bloco do upsell acabou em 5
      versões divergentes. Quem quiser a casca põe `class="ap-shell"` no container e pronto.
   2. Nenhuma variável do `:root` do funil é redefinida — `--text`, `--text-dim`, `--text-dim2`,
      `--primary`, `--secondary`, `--font`, `--radius` são LIDAS pelo bloco de upsell
      (css/styles.css:694-830). Os tokens desta direção têm nome próprio (`--ap-*`) e escopo próprio.
   3. Nenhum seletor `.ups*` / `.upsm*` aqui dentro. O upsell está aprovado e é intocável; o que se
      redesenha é o que está EM VOLTA dele.
      🪤 E por isso `.ap-shell`, `.ap-corpo`, `.ap-pad` e `#genResult` NÃO declaram `font-size` nem
      `line-height`: `.ups-nome`, `.ups-off` e `.ups-conta` não declaram a sua (css/styles.css:761,
      766, 806) e HERDAM do que está em volta. Em produção o `body` não tem font-size nem
      line-height (styles.css:37-44) = 16px/normal — mexer nisso aqui engordaria o nome da cena
      dentro de uma `.ups-linha-nome` de 22px e empurraria a linha do preço, que é justamente a
      linha consertada em 16-17/08. Cada elemento `.ap-*` declara o seu tamanho.
   ══════════════════════════════════════════════════════════════════════════════════════════════ */

.ap-shell.tela-app{
  /* 🎨 paleta "brasa", a mesma já aprovada na área do cliente (acompanhar.html:43-68): marrom-carvão
     quente. Preto puro + dourado lê como "premium frio"; aqui a tela precisa parecer um abraço. */
  --ap-pp:        oklch(16% 0.012 58);   /* fundo do app */
  --ap-pp2:       oklch(21.5% 0.016 58); /* card */
  --ap-pp3:       oklch(27% 0.020 58);   /* card em destaque */
  --ap-tinta:     oklch(97% 0.008 80);   /* texto */
  --ap-tinta2:    oklch(80% 0.014 72);   /* apoio */
  --ap-tinta3:    oklch(66% 0.014 72);   /* meta (datas, contadores) */
  --ap-ouro:      oklch(83% 0.107 86);   /* dourado da marca = #E7C86B */
  --ap-ouro-esc:  oklch(21% 0.040 70);   /* texto EM CIMA do dourado */
  --ap-linha:     oklch(32% 0.018 58);
  --ap-foco:      oklch(88% 0.120 90);
  --ap-serif: Georgia, "Iowan Old Style", "Times New Roman", serif;
  --ap-r-card: 18px;
  --ap-r-btn: 999px;
  --ap-toque: 62px;                      /* altura mínima de QUALQUER coisa clicável (público 45+) */
  --ap-e: cubic-bezier(0.16, 1, 0.3, 1);

  /* a brasa vem de cima, atrás da barra: fundo chapado dava cara de slide de apresentação */
  background:
    radial-gradient(120% 46% at 50% -6%, oklch(24% 0.035 62) 0%, transparent 62%),
    var(--ap-pp);
}

/* ───────────────────────────────── barra superior ───────────────────────────────── */
.ap-shell .ap-topo{
  position:absolute; top:0; left:0; right:0; height:60px; z-index:30;
  /* 📐 09/09/2026 — o `padding-right` NAO e simetrico ao esquerdo de proposito, e o numero saiu de
     medicao: o botao da conta tem 60px e centraliza um avatar de 40px, entao sobram 10px de folga
     dentro dele. Sem padding-right nenhum, a TINTA do avatar terminava 6px depois da borda direita
     de tudo o que esta embaixo (h1, grades, rodape) — gutter de 16px a esquerda contra 10px a
     direita, identico em 360/390/430. Com 6px aqui, 6+10 fecha os mesmos 16px da coluna. Mexeu na
     largura do `.ap-conta`? este numero muda junto. */
  display:flex; align-items:center; justify-content:space-between; padding-left:16px; padding-right:6px;
  background:color-mix(in oklch, var(--ap-pp) 82%, transparent);
  backdrop-filter:blur(14px) saturate(1.2); -webkit-backdrop-filter:blur(14px) saturate(1.2);
  border-bottom:1px solid color-mix(in oklch, var(--ap-linha) 70%, transparent);
}
.ap-shell .ap-marca{display:flex; align-items:center; gap:9px}
.ap-shell .ap-marca img{width:24px; height:24px; border-radius:6px}
.ap-shell .ap-marca span{font-family:var(--ap-serif); font-size:19px; letter-spacing:.01em; color:var(--ap-tinta)}
.ap-shell .ap-conta{
  width:60px; height:60px; display:flex; align-items:center; justify-content:center;
  background:none; border:0; padding:0; cursor:pointer;
  /* 👓 16px num botao que so tem icone parece inutil, e nao e: o publico e 45+ e a regra da casa
     cobra fonte legivel em TUDO que se toca (test/e2e-tela7.mjs:153). Herdando do <button> isso
     nascia 13.3px, e a mesma heranca vale pro dia em que alguem puser uma inicial aqui dentro —
     que e exatamente o que acontece com quem entra por e-mail. */
  font-family:inherit; font-size:16px;
}
.ap-shell .ap-conta__av{
  width:40px; height:40px; border-radius:50%; display:flex; align-items:center; justify-content:center;
  font-family:var(--ap-serif); font-size:19px; line-height:1; color:var(--ap-ouro);
  background:oklch(26% 0.030 66); border:1px solid oklch(40% 0.040 74);
  transition:transform 140ms var(--ap-e);
}
/* 🧍 ícone de pessoa: `currentColor` faz ele herdar o dourado do avatar, então nada duplica cor */
.ap-shell .ap-conta__av svg{width:23px; height:23px; display:block}
/* 👤 com a foto do cliente dentro, o círculo vira retrato: `cover` porque foto de rosto vem em
   qualquer proporção e `contain` deixaria duas tarjas ao lado da cara da pessoa. O `overflow` mora
   no próprio av: sem ele o canto quadrado da imagem escapa do círculo. */
.ap-shell .ap-conta__av{overflow:hidden}
.ap-shell .ap-conta__av img,
.ap-shell .ap-folha__av img{width:100%; height:100%; object-fit:cover; display:block; border-radius:50%}
.ap-shell .ap-folha__av{overflow:hidden}
.ap-shell .ap-conta:active .ap-conta__av{transform:scale(.94)}
.ap-shell .ap-conta:focus-visible{outline:3px solid var(--ap-foco); outline-offset:-6px; border-radius:16px}

/* ───────────────────────────────── corpo rolável ─────────────────────────────────
   A rolagem continua sendo a `.screen__scroll` do funil — só reservamos o espaço das duas barras,
   que são `position:absolute` (é isso que faz o conteúdo correr POR BAIXO delas). */
.ap-shell .ap-corpo{
  display:flex; flex-direction:column;
  padding:60px 0 64px;
  overscroll-behavior:contain;
}
/* na ESPERA não existe barra de abas (decisão do Lucas, 28/07) — então o espaço dela também some */
.ap-shell.ap-esperando .ap-corpo{padding-bottom:0}
/* 🔴 17/08 — E NA TELA DE ENTREGA TAMBÉM NÃO: "o vídeo É a tela". A barra cobria 24px do
   "Baixar meu vídeo" em 360×640 (medido) e o toque caía numa aba em vez do botão. Quem esconde é o
   `js/tela7-app.js` (pintarAbas), pela MESMA regra da espera; a saída pro hub continua sendo o
   "Ver outras opções" abaixo do upsell. A classe segue o atributo `hidden` da barra, então o
   padding reservado nunca sobra sem barra nem falta com ela. */
.ap-shell.ap-sem-abas .ap-corpo{padding-bottom:0}
.ap-shell .ap-pag:not([hidden]){display:flex; flex-direction:column; flex:1 0 auto}
.ap-shell .ap-pad{display:flex; flex-direction:column; gap:16px; padding:16px 16px 26px; flex:1 0 auto}
/* curta e para cima: o bastante pra dizer "a tela trocou", curta demais pra atrasar quem já sabe
   onde está indo */
/* 🔴 `backwards`, NUNCA `both`. Com `both` o `transform:none` da keyframe final fica valendo pra
   sempre e o computado vira `matrix(1,0,0,1,0,0)` — que NÃO é `none`: a `.ap-pag` vira containing
   block de `position:fixed` e o #upsellPix (fixed, filho desta seção) passa a se medir contra a
   caixa rolável. Medido: modal 390×1843 em y=60, card do PIX em y=663 num viewport de 740 = oferta
   invendável. `backwards` dá a mesma entrada e devolve `transform:none` assim que ela acaba. */
.ap-shell .ap-pag{animation:apEntraPag 190ms var(--ap-e) backwards}
@keyframes apEntraPag{from{opacity:0; transform:translateY(8px)} to{opacity:1; transform:none}}

/* ───────────────────────────────── navegação inferior ─────────────────────────────────
   O destino atual fica dourado E ganha uma marca fina em cima: cor sozinha não passa em daltonismo. */
.ap-shell .ap-abas{
  position:absolute; left:0; right:0; bottom:0; height:64px; z-index:30; display:flex;
  background:color-mix(in oklch, var(--ap-pp) 88%, transparent);
  backdrop-filter:blur(14px); -webkit-backdrop-filter:blur(14px);
  border-top:1px solid var(--ap-linha);
}
.ap-shell .ap-aba{
  /* 📐 09/09/2026 — `min-width:0` conserta abas de larguras diferentes. `flex:1` sozinho nao
     encolhe abaixo do conteudo (min-width:auto e o padrao em flex), entao "Homenagens", que e o
     rotulo mais longo, roubava largura das outras tres: medido 105,66 / 84,78 / 84,78 / 84,78px em
     360px de tela — 20,88px de diferenca, com os centros dos icones desigualmente espacados. Em
     430px sumia sozinho, porque 1/4 da tela ja passa do rotulo; era por isso que nao aparecia em
     print de tela grande. */
  flex:1; min-width:0; min-height:var(--ap-toque); display:flex; flex-direction:column; align-items:center;
  justify-content:center; gap:5px; background:none; border:0; cursor:pointer; position:relative;
  /* 🔠 16px, nao 15px: abaixo de 15.5px a trava de acessibilidade da area do cliente acusa
     (test/e2e-tela7.mjs:153), e ela existe porque o publico e 45+ — o rotulo da aba e justamente
     o texto que a pessoa procura quando se perde. */
  color:var(--ap-tinta3); font-family:inherit; font-size:16px; font-weight:600; letter-spacing:.01em;
  padding:0 4px; transition:color 160ms var(--ap-e);
}
.ap-shell .ap-aba svg{width:25px; height:25px; fill:none; stroke:currentColor; stroke-width:1.7;
  stroke-linecap:round; stroke-linejoin:round}
.ap-shell .ap-aba.on{color:var(--ap-ouro)}
.ap-shell .ap-aba.on::before{content:""; position:absolute; top:0; width:34px; height:2px;
  border-radius:0 0 3px 3px; background:var(--ap-ouro)}
.ap-shell .ap-aba:focus-visible{outline:3px solid var(--ap-foco); outline-offset:-4px; border-radius:12px}
/* bolinha de novidade: só nasce quando um vídeo FICA pronto com a pessoa em outra aba, e some assim
   que ela entra na aba. Aviso que não some vira enfeite, e o time aprende a ignorar o canal. */
.ap-shell .ap-aba__ponto{position:absolute; top:13px; left:calc(50% + 9px); width:8px; height:8px;
  border-radius:50%; background:var(--ap-ouro); border:2px solid var(--ap-pp)}

/* ───────────────────────────────── tipos ─────────────────────────────────
   A serifada é reservada ao momento emocional (o título da entrega). Todo o resto — listas, rótulos,
   preço, navegação — é sans compacta: é o que dá "cara de app" sem esfriar o texto que importa.
   17px é o PISO de texto de corpo aqui (há teste que reprova fonte miúda). */
.ap-shell .ap-h1{font-family:var(--ap-serif); font-weight:400; font-size:27px; line-height:1.14;
  letter-spacing:-.01em; margin:0; color:var(--ap-tinta); text-wrap:balance;
  /* centrado com o card do vídeo (pedido do Lucas, 18/08 23h32) — vale pros dois estados da tela
     (esperando e pronto): é o mesmo h1, e centrado num estado + esquerda no outro leria como salto */
  text-align:center}
/* 17px e não 16: "Minhas homenagens" era o ÚNICO texto de corpo abaixo do piso desta tela — um
   título menor que o parágrafo embaixo dele (medido: 16 contra 17 nos 3 viewports) */
/* 📐 09/09/2026 — O ESPAÇAMENTO CEDEU 0,04em, e por um motivo medido: em 390px o par
   "MINHAS HOMENAGENS" + "atualizado às 15:25" ficava 5,4px maior que a coluna e as DUAS metades
   quebravam em duas linhas — um cabeçalho de 4 linhas pra dizer duas coisas curtas. Em `.12em`,
   17 letras em caixa alta gastam ~35px só de ar entre elas; `.08em` devolve ~11px, que sobra pro
   par caber inteiro. A voz de etiqueta (caixa alta, espaçada, apagada) fica igual.
   🪤 `nowrap` nos dois: sem isso o navegador prefere quebrar a quebrar — basta a hora ganhar
   um dígito (23:59) pra voltar tudo. Se um dia não couber mesmo, quem some é a palavra "atualizado",
   não o título. */
.ap-shell .ap-h2{font-size:17px; font-weight:700; letter-spacing:.08em; text-transform:uppercase;
  color:var(--ap-tinta3); margin:0; white-space:nowrap}
/* 🛒 o resumo da compra: pílula discreta, ouro, largura do conteúdo. Não compete com o
   título — só confirma, em uma linha, que ela não se perdeu no meio do caminho. */
.ap-shell .ap-entrada__resumo{display:block; width:fit-content; margin:10px auto 0;
  padding:7px 15px; border-radius:999px; border:1px solid var(--ap-ouro);
  background:oklch(24% 0.030 70); color:var(--ap-ouro); font-size:15.5px; font-weight:700;
  font-variant-numeric:tabular-nums lining-nums; text-wrap:nowrap}
.ap-shell .ap-entrada__resumo[hidden]{display:none}
.ap-shell .ap-sub{font-size:17px; line-height:1.42; color:var(--ap-tinta2); margin:0; text-wrap:pretty}
/* era `--menor` (16px) e virou só espaçamento: 17px é o PISO desta tela e a linha de apoio da folha
   da cena é texto de corpo, não legenda */
/* a data do pedido e o contato da conta são CONTEÚDO, não legenda de rodapé — daí os 17px */
.ap-shell .ap-meta{font-size:17px; color:var(--ap-tinta3); margin:0; white-space:nowrap;
  font-variant-numeric:tabular-nums lining-nums}
.ap-shell .ap-meta--forte{color:var(--ap-tinta)}
.ap-shell .ap-nota{font-size:17px; line-height:1.4; color:var(--ap-tinta3); text-align:center; margin:0;
  text-wrap:pretty}
.ap-shell .ap-nota--esq{text-align:left}
.ap-shell .ap-rodape{text-align:center; font-size:17px; line-height:1.55; color:var(--ap-tinta3); margin:0;
  text-wrap:pretty}
/* 🔤 quebra que dá dó: "e-" numa linha e "mail 💛" na outra (medido em 414×896). `text-wrap:pretty`
   resolve a linha órfã, mas o hífen do "e-mail" é ponto de quebra legítimo pro navegador — só um
   nowrap explícito segura a palavra inteira. */
.ap-shell .ap-nao-quebra{white-space:nowrap}
/* link de rodapé continua sendo LINK, mas com alvo de dedo: em linha corrida dava ~25px clicáveis */
.ap-shell .ap-rodape a{color:var(--ap-tinta2); display:inline-flex; align-items:center;
  justify-content:center; min-height:var(--ap-toque); padding:0 10px}
.ap-shell .ap-erro-txt{font-size:17px; line-height:1.4; color:var(--ap-ouro); text-align:center; margin:0}

/* ───────────────────────────────── botões ───────────────────────────────── */
.ap-shell .ap-bt{
  display:flex; align-items:center; justify-content:center; gap:9px; width:100%;
  min-height:var(--ap-toque); padding:14px 18px; border-radius:var(--ap-r-btn); border:0;
  font-family:inherit; font-size:18.5px; font-weight:700; line-height:1.15; text-align:center;
  text-decoration:none; cursor:pointer;
  transition:transform 140ms var(--ap-e), background-color 140ms var(--ap-e);
}
.ap-shell .ap-bt--ouro{background:var(--ap-ouro); color:var(--ap-ouro-esc)}
.ap-shell .ap-bt--ouro:hover{background:oklch(87% 0.107 86)}
.ap-shell .ap-bt--calmo{background:oklch(24% 0.016 58); color:var(--ap-tinta); border:1px solid var(--ap-linha)}
.ap-shell .ap-bt--calmo:hover{background:oklch(27% 0.016 58)}
.ap-shell .ap-bt:active{transform:scale(.985)}
.ap-shell .ap-bt:focus-visible{outline:3px solid var(--ap-foco); outline-offset:3px}
.ap-shell .ap-bt svg{width:21px; height:21px; flex:0 0 auto; fill:none; stroke:currentColor;
  stroke-width:2; stroke-linecap:round; stroke-linejoin:round}

/* ───────────────────────────────── selos de estado ─────────────────────────────────
   O estado é a informação nº1 do app ("onde está a minha homenagem?"), por isso ele é um selo com
   cor e forma próprias, e não uma frase perdida no meio do parágrafo. */
.ap-shell .ap-selo{display:inline-flex; align-items:center; gap:7px; padding:5px 11px 5px 9px;
  border-radius:999px; font-size:15px; font-weight:700; letter-spacing:.03em; white-space:nowrap}
.ap-shell .ap-selo i{width:8px; height:8px; border-radius:50%; background:currentColor; flex:0 0 auto}
.ap-shell .ap-selo--pronto{background:oklch(35% 0.060 86); color:oklch(92% 0.100 88)}
.ap-shell .ap-selo--producao{background:oklch(28% 0.020 58); color:var(--ap-tinta2)}
/* o ponto pulsa SÓ no "em produção": é o sinal de que tem gente trabalhando agora */
.ap-shell .ap-selo--producao i{animation:apPulsa 1.9s ease-in-out infinite}
/* 🩹 TERCEIRO ESTADO — "Estamos cuidando". Nasceu do beco do erro: o pedido que quebrou na entrega
   não pode aparecer como "Pronto" (mentira) nem como "Em produção" (o pontinho pulsando diz que
   está andando, e não está) nem sumir da lista (aí a pessoa não tem onde voltar). Dourado apagado,
   sem pulso: chama atenção sem soar alarme. */
.ap-shell .ap-selo--cuidando{background:oklch(30% 0.045 80); color:oklch(88% 0.090 88)}
@keyframes apPulsa{0%,100%{opacity:.35; transform:scale(.82)} 50%{opacity:1; transform:scale(1)}}

/* ───────────────────────────────── palco de vídeo ─────────────────────────────────
   🔴 NADA DE CORTE. O entregável é 9:16 (720×1280, medido) e as cenas são 540×960. Enquadrar 9:16
   numa caixa larga com `cover` come metade da altura — foi o que reprovou a 1ª versão do upsell em
   16/08. A caixa nítida usa `contain` e o vão dos lados é uma cópia BORRADA do próprio vídeo. */
.ap-shell .ap-palco{position:relative; width:100%; border-radius:16px; overflow:hidden;
  background:#0B0A0A; border:1px solid var(--ap-linha)}
.ap-shell .ap-palco__fundo{position:absolute; inset:0; width:100%; height:100%; object-fit:cover;
  filter:blur(22px) brightness(.40) saturate(1.1); transform:scale(1.2); pointer-events:none}
.ap-shell .ap-palco__vid{position:absolute; inset:0; width:100%; height:100%; object-fit:contain; z-index:2}
/* 🎵 O PLAYER DA MUSICA (order bump `musica`, 16/09/2026). Fica POR CIMA da capa e encostado embaixo: o entregavel e' som, e o que a pessoa reconhece na folha e' o rosto de quem ela homenageou. `width:calc(100% - 32px)` pra barra nao encostar nas bordas do palco. */
.ap-shell .ap-palco__audio{position:absolute; left:16px; right:16px; bottom:16px; width:calc(100% - 32px); z-index:3}
/* 🎵 29/10/2026 — a caixa do player da casa (`window.ETZ_Som`, js/app.js), montado FORA do palco:
   a capa morre em 2 dias (retenção do bucket) e o palco some com ela, mas o som continua lá. */
.ap-shell .ap-som-cx{display:block; width:100%; margin-top:12px}
/* 📏 A ALTURA DO PLAYER É CONTA, NÃO GOSTO. Quem pagou tem que ver o vídeo E o "Baixar meu vídeo"
   sem rolar (medido em 31/07 com `test/audit-mobile.mjs`, na ALTURA ÚTIL — medir em 844 mente).
   🔴 REVISÃO 17/08: o orçamento antigo (306px, teto 398) reservava 78px pra uma barra de abas que
   AINDA ASSIM cobria o botão, e de quebra encolhia o entregável a 224×398 — 41% menos área que os
   298×530 da produção (medido nos dois). A 1ª correção tirou a barra e chegou a 268×478 — ainda 19%
   menos área. O que faltava era acima do vídeo: com a linha de apoio no cabeçalho o topo do vídeo
   caía em 177px (medido nos 3 viewports) contra 113px da produção. Ela desceu pro pé do bloco
   (reencontro-app7.html) e o topo virou 121px, então o orçamento fora do vídeo agora é:
   60 (barra de cima) + 16 (respiro do .ap-pad) + 31 (título) + 14 (gap) + 62 (botão de baixar) +
   ~27 (respiro no pé) = 210px. Em 390×740 isso devolve exatamente os 530px de altura da produção.
   O teto de 604px é o mesmo da produção (lá o `.gen__video` trava em 340px de largura ÷ .5625).
   O `vh` vem antes do `dvh` de propósito: em navegador que não conhece `dvh` a declaração inteira
   cai, e sem a primeira o palco ficaria sem altura (mesma armadilha do #app, styles.css:52-56).
   📐 E a LARGURA é amarrada à altura (×0,5625 = 9/16), como a produção já faz no `.gen__video`
   (reencontro-app7.html:44-50). Sem isso a caixa nasce 100% (356px) pra um vídeo que ocupa 222,8px:
   sobram 66,6px de tarja borrada de cada lado sem aumentar um pixel de imagem. O `min(100%,…)` é a
   trava pra tela estreita — a caixa nunca passa da coluna. */
.ap-shell .ap-player{align-self:center;
  height:clamp(210px, calc(100vh - 210px), 604px);
  width:min(100%, calc(clamp(210px, calc(100vh - 210px), 604px) * .5625))}
.ap-shell .ap-player{height:clamp(210px, calc(100dvh - 210px), 604px);
  width:min(100%, calc(clamp(210px, calc(100dvh - 210px), 604px) * .5625))}
.ap-shell .ap-palco--item{height:330px}
/* botão de play sobre o vídeo: aparece parado, some tocando. O alvo é o vídeo INTEIRO — impossível
   errar com o dedo. Ele só existe depois que o `js/tela7-app.js` desliga o `controls` nativo. */
.ap-shell .ap-play{position:absolute; inset:0; z-index:3; display:flex; align-items:center;
  justify-content:center; background:none; border:0; padding:0; cursor:pointer}
.ap-shell .ap-play span{width:78px; height:78px; border-radius:50%; display:flex; align-items:center;
  justify-content:center; background:oklch(12% 0.01 58 / .58); border:1px solid oklch(100% 0 0 / .3);
  backdrop-filter:blur(3px); opacity:0; transform:scale(.9);
  transition:opacity 220ms, transform 220ms var(--ap-e)}
.ap-shell .ap-player.pausado .ap-play span{opacity:1; transform:scale(1)}
.ap-shell .ap-play svg{width:30px; height:30px; fill:#fff; stroke:none; margin-left:3px}
/* 🎯 os dois controles de dentro do player não tinham anel de foco próprio e caíam no `outline:auto
   1px` do navegador sobre fundo quase preto — os outros 11 pontos de foco desta tela usam 3px */
.ap-shell .ap-play:focus-visible{outline:3px solid var(--ap-foco); outline-offset:-3px;
  border-radius:16px}
.ap-shell .ap-som:focus-visible{outline:3px solid var(--ap-foco); outline-offset:2px}
/* som: controle DO PLAYER, no canto do vídeo. Alvo de 62px e fundo a .80 — em frame claro (praia,
   escadaria dourada) o translúcido mais leve não garantia o branco legível.
   🔴 17/08 — SEM RÓTULO POR EXTENSO. Medido: a pílula "Desativar som" media 167px numa caixa de
   vídeo de 222px = 75% da largura, tapando exatamente a faixa do abraço, e nunca sumia. Virou um
   alvo redondo de 62px com só o ícone; o texto continua no DOM (`.ap-som__rot`, lido por leitor de
   tela e escrito pelo tela7-app.js) e o estado passou a ser visível pelo próprio desenho: o corte
   diagonal aparece quando está mudo. O fundo a .80 continua sendo o que garante contraste do ícone
   branco em frame claro. */
.ap-shell .ap-som{position:absolute; right:10px; bottom:10px; z-index:4;
  width:var(--ap-toque); height:var(--ap-toque); padding:0; border-radius:50%;
  border:1px solid oklch(100% 0 0 / .22);
  background:oklch(12% 0.01 58 / .80); backdrop-filter:blur(4px); color:#fff; font-family:inherit;
  display:flex; align-items:center; justify-content:center; cursor:pointer}
.ap-shell .ap-som svg{width:24px; height:24px; fill:none; stroke:currentColor; stroke-width:1.9;
  stroke-linecap:round}
/* o rótulo continua existindo pra quem NÃO vê o ícone (leitor de tela): ele é o nome acessível do
   botão. Escondê-lo com `display:none` o apagaria da árvore de acessibilidade junto. */
.ap-shell .ap-som__rot{position:absolute; width:1px; height:1px; overflow:hidden;
  clip-path:inset(50%); white-space:nowrap; font-size:17px}
.ap-shell .ap-som .ap-som__off{display:none}
.ap-shell .ap-som[aria-pressed="false"] .ap-som__on{display:none}
.ap-shell .ap-som[aria-pressed="false"] .ap-som__off{display:block}

/* ───────────────────────────────── A · ESPERANDO ─────────────────────────────────
   O card tem que ter VIDA (os dois retratos, a luz entre eles, a barra andando): o que a pessoa
   mais precisa nesses minutos é da certeza de que alguém está cuidando — não de um spinner. */
#genLoading:not([hidden]){display:flex; flex-direction:column; gap:16px; flex:1 0 auto}
.ap-shell .ap-obra{background:var(--ap-pp2); border:1px solid var(--ap-linha);
  border-radius:var(--ap-r-card); padding:18px; display:flex; flex-direction:column; gap:16px;
  position:relative; overflow:hidden; color:var(--ap-tinta)}
/* respiro quente atrás dos retratos: é a "luz" da cena sendo construída */
.ap-shell .ap-obra::before{content:""; position:absolute; left:50%; top:-40px; width:280px; height:200px;
  transform:translateX(-50%); pointer-events:none;
  background:radial-gradient(50% 50% at 50% 50%, oklch(60% 0.10 78 / .22), transparent 70%);
  animation:apRespira 4.6s ease-in-out infinite}
@keyframes apRespira{0%,100%{opacity:.5} 50%{opacity:1}}
.ap-shell .ap-obra__topo{display:flex; align-items:center; justify-content:space-between; gap:10px;
  position:relative}
.ap-shell .ap-obra__nome{font-size:18px; font-weight:700}
.ap-shell .ap-par{display:flex; align-items:center; justify-content:center; position:relative}
.ap-shell .ap-par figure{width:112px; height:140px; border-radius:14px; overflow:hidden;
  border:1px solid oklch(40% 0.030 70); background:oklch(28% 0.010 58)}
.ap-shell .ap-par img{width:100%; height:100%; object-fit:cover; object-position:center top}
.ap-shell .ap-par figure:first-child{transform:rotate(-2.5deg) translateX(9px)}
.ap-shell .ap-par figure:last-child{transform:rotate(2.5deg) translateX(-9px)}
/* a fresta de luz entre os dois retratos é o produto inteiro em um símbolo: o encontro.
   🔴 Eles se APROXIMAM e nunca se encontram — o encontro é o vídeo. Prometer o abraço aqui
   roubaria o clímax do produto. */
.ap-shell .ap-luz{position:relative; z-index:2; width:16px; height:150px; flex:0 0 auto;
  background:linear-gradient(180deg, transparent, oklch(92% 0.09 88 / .85), transparent);
  filter:blur(5px); animation:apBrilha 3.2s ease-in-out infinite}
@keyframes apBrilha{0%,100%{opacity:.45; transform:scaleY(.86)} 50%{opacity:1; transform:scaleY(1)}}
.ap-shell .ap-etapas{list-style:none; display:flex; flex-direction:column; gap:11px; position:relative;
  margin:0; padding:0}
.ap-shell .ap-etapas li{display:flex; align-items:center; gap:11px; font-size:17px;
  color:var(--ap-tinta3); transition:color 300ms var(--ap-e)}
.ap-shell .ap-etapas li b{flex:0 0 auto; width:24px; height:24px; border-radius:50%;
  border:1.5px solid var(--ap-linha); display:flex; align-items:center; justify-content:center;
  font-size:13px; color:var(--ap-tinta3); transition:all 300ms var(--ap-e)}
/* 🔒 `is-feita` / `is-agora` são as classes que o `js/app.js` escreve (cenaAtualizar, :1515) —
   não renomear. O ✓ da etapa cumprida é CSS: o app.js não mexe no texto do número. */
.ap-shell .ap-etapas li.is-feita{color:var(--ap-tinta2)}
.ap-shell .ap-etapas li.is-feita b{background:oklch(38% 0.055 86); border-color:transparent;
  color:oklch(94% 0.09 88); font-size:0}
.ap-shell .ap-etapas li.is-feita b::after{content:"✓"; font-size:13px; line-height:1}
.ap-shell .ap-etapas li.is-agora{color:var(--ap-tinta); font-weight:600}
.ap-shell .ap-etapas li.is-agora b{border-color:var(--ap-ouro); color:var(--ap-ouro);
  box-shadow:0 0 0 4px oklch(60% 0.09 84 / .16)}
/* A barra é dirigida pelo SERVIDOR: `--p` (0 → 0,94) é gravado no #cena pelo app.js:1511 e a largura
   sai DELE — sem JS no meio, uma fonte só. O 8% do fallback é o ponto de partida, antes da primeira
   resposta do servidor (conferido em 17/08: com `--p` em 0,5 a barra mede exatamente 50% do trilho). */
.ap-shell .ap-barra{height:6px; border-radius:99px; background:oklch(27% 0.012 58); overflow:hidden;
  position:relative}
.ap-shell .ap-barra i{display:block; height:100%; border-radius:99px;
  width:calc(var(--p, .08) * 100%);
  background:linear-gradient(90deg, oklch(70% 0.09 80), var(--ap-ouro));
  transition:width 900ms var(--ap-e)}
.ap-shell .ap-obra__pe{display:flex; align-items:baseline; justify-content:space-between; gap:10px;
  font-size:17px; color:var(--ap-tinta3); position:relative}
/* recado da espera, logo abaixo do card */
.ap-shell .ap-fica{display:flex; gap:12px; align-items:flex-start; background:oklch(19% 0.014 58);
  border:1px solid var(--ap-linha); border-radius:var(--ap-r-card); padding:15px 16px; font-size:17px;
  color:var(--ap-tinta2); line-height:1.4}
.ap-shell .ap-fica p{margin:0}
.ap-shell .ap-fica b{color:var(--ap-tinta); font-weight:700}
.ap-shell .ap-fica__ic{font-size:20px; line-height:1.2; flex:0 0 auto}
/* ajuda na espera: discreta DE PROPÓSITO — serve a quem já está aflito, não convida a sair */
.ap-shell .ap-ajuda{margin-top:auto; align-self:center; display:inline-flex; align-items:center; gap:8px;
  min-height:var(--ap-toque); padding:0 20px; border-radius:999px; border:1px solid var(--ap-linha);
  background:oklch(19% 0.012 58); color:var(--ap-tinta2); font-size:17px; text-decoration:none}
.ap-shell .ap-ajuda:hover{color:var(--ap-tinta)}

/* ───────────────────────────────── B · PRONTO ───────────────────────────────── */
/* sem `gap` aqui de propósito: o `.ups` tem `margin-top:28px` próprio (reencontro.html) e um gap de
   flex se SOMARIA a ele, afastando o bloco aprovado do resto da tela. */
#genResult:not([hidden]){display:flex; flex-direction:column}
.ap-shell .ap-entrega{display:flex; flex-direction:column; gap:14px}
.ap-shell .ap-entrega__cab{display:flex; flex-direction:column; gap:7px}
/* a linha do endereço deixou de ser formulário: no app ela é uma LINHA (rótulo + valor + UMA ação) */
#genLinkBox:not([hidden]){display:flex; flex-direction:column; gap:11px}
.ap-shell .ap-linha{background:var(--ap-pp2); border:1px solid var(--ap-linha);
  border-radius:var(--ap-r-card); padding:15px 16px}
.ap-shell .ap-linha__rot{font-size:17px; line-height:1.35; color:var(--ap-tinta3)}
/* o valor é um <input readonly> porque o app.js escreve `.value` e chama `.select()` nele — aqui ele
   é pintado como TEXTO: sem moldura, sem cara de campo pra preencher */
.ap-shell .ap-linha__val{width:100%; border:0; background:none; padding:0; font-family:inherit;
  font-size:16.5px; line-height:1.35; color:var(--ap-tinta); text-overflow:ellipsis;
  font-variant-numeric:tabular-nums lining-nums}
.ap-shell .ap-linha__val:focus{outline:none}
/* 🔴 banner virou SÓ o botão (17/08): sem card em volta, sem rótulo, sem endereço à mostra — o
   botão é a linha inteira, discreto, pra não roubar espaço do upsell logo abaixo. */
.ap-shell .ap-linha--so-copiar{background:none; border:0; border-radius:0; padding:0}
/* input do link fica no DOM pro `.select()` do app.js, mas fora da vista (não `display:none`, senão
   `.select()` não funciona no fallback sem clipboard) */
.ap-shell .ap-oculto-visual{position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0; opacity:0; pointer-events:none}
/* mesma família da .ap-bt (pílula): três raios de botão no mesmo app pareciam três design systems */
.ap-shell .ap-copiar{width:100%; min-height:var(--ap-toque); border-radius:var(--ap-r-btn);
  border:1px solid var(--ap-linha); background:oklch(24% 0.016 58); color:var(--ap-tinta);
  font-family:inherit; font-size:17px; font-weight:700; cursor:pointer; display:flex;
  align-items:center; justify-content:center; gap:9px}
.ap-shell .ap-copiar svg{width:19px; height:19px; flex:0 0 auto; fill:none; stroke:currentColor;
  stroke-width:2; stroke-linecap:round; stroke-linejoin:round; opacity:.85}
.ap-shell .ap-copiar:focus-visible{outline:3px solid var(--ap-foco); outline-offset:3px}

/* 🔴 O UPSELL MAIS LARGO E IMPONENTE (pedido do Lucas, 17/08). O bloco `.ups.ups--cenas` tem
   `max-width:360px` no css/styles.css (produção); aqui, SÓ no escopo .ap-shell, ele quebra os 16px
   de padding do `.ap-pad` e ocupa a tela inteira — vira o elemento mais largo da tela, com presença
   de "oferta principal". Não toco no markup nem no CSS de produção: é override de largura, escopado.
   🪤 A cena grande dentro dele é `aspect-ratio:9/16` com teto de altura, então alargar o container
   NÃO estica a cena — ela continua centrada e o fundo borrado preenche a faixa mais larga. O padding
   interno próprio do bloco (16px) mantém o conteúdo longe da borda da tela. */
.ap-shell #upsell.ups.ups--cenas{
  max-width:none;
  margin-left:-16px; margin-right:-16px;
  width:calc(100% + 32px);
  padding:22px 18px;
  border-left:0; border-right:0; border-radius:0;
  /* um respiro dourado em cima e embaixo pra virar uma "faixa" de oferta, não um card espremido */
  border-top-width:1.5px; border-bottom-width:1.5px;
  background:linear-gradient(180deg, oklch(24% 0.030 78 / .55), oklch(19% 0.020 70 / .30));
}
/* em telas mais largas (tablet/desktop) não deixa a faixa esticar sem fim: limita e centraliza */
@media (min-width:520px){
  .ap-shell #upsell.ups.ups--cenas{max-width:none; width:calc(100% + 32px)}
}
/* 🔴 O PREÇO É O MAIOR DESTAQUE DO BLOCO (pedido do Lucas, 18/08). Produção usa 30px
   (css/styles.css:802) e o título do bloco tem 22px; aqui, SÓ no escopo .ap-shell, o preço passa a
   dominar o bloco — maior que título, cena e CTA. Mesma razão preço/riscado ~2,8× que ele aprovou
   na folha da cena (17/08 22h41): número grande + comparação pequena AO LADO, nunca dois números
   parecidos brigando. O chip "26% OFF" (.ups-off) fica como está: selo, não competidor.
   ⚠️ 40px + riscado + chip passam de 390px de largura ⇒ o flex-wrap do .ups__preco (styles.css:797)
   quebra o chip pra 2ª linha em telas estreitas — comportamento aceito, não bug. */
.ap-shell #upsell.ups.ups--cenas .ups__preco b{
  font-size:40px; letter-spacing:-1.2px;
  text-shadow:0 2px 18px oklch(78% 0.11 85 / .22);
}
.ap-shell #upsell.ups.ups--cenas .ups__preco s{ font-size:15px; }
/* 🔴 MINIATURAS DO ROLO SEM CORTE (pedido do Lucas, 18/08). Produção usa 4:3 (css/styles.css:777)
   pra economizar altura no card de 360px — mas os vídeos das cenas são 9:16, e `cover` num quadro
   4:3 mostra só a faixa central (~42%): o cliente escolhia cena vendo um recorte. Aqui, SÓ no
   escopo .ap-shell, a mini fica na MESMA proporção do vídeo: cover encaixa exato — vídeo inteiro,
   sem corte e sem barra, em qualquer largura de tela. Custo: o bloco cresce ~80px de altura. */
.ap-shell #upsell.ups.ups--cenas .ups-mini{ aspect-ratio:9/16; }
/* 🔴 A SAÍDA PRO HUB — GRANDE E CHAMATIVA (pedido do Lucas, 17/08). Quem não quis o upsell tem que
   ver, sem procurar, a porta pro resto do produto ("ver outras opções"). Antes era um card escuro
   discreto; agora é um botão alto, com moldura dourada e brilho — DESTACADO, mas de propósito com
   tratamento de CONTORNO (não dourado sólido): o sólido é do "APROVEITAR DESCONTO" do upsell, e a
   hierarquia comprar > explorar tem que se manter. Imponente sem competir de igual com a compra. */
.ap-shell .ap-saida{display:flex; align-items:center; justify-content:space-between; gap:14px;
  width:100%; min-height:72px; margin-top:20px; padding:14px 22px;
  border-radius:16px; border:1.5px solid var(--ap-ouro);
  background:linear-gradient(180deg, oklch(27% 0.030 78), oklch(22% 0.024 74));
  box-shadow:0 6px 22px oklch(60% 0.10 80 / .16), inset 0 1px 0 oklch(80% 0.08 85 / .12);
  color:var(--ap-ouro); font-family:inherit; font-size:20px; font-weight:800; letter-spacing:-.2px;
  /* 🪤 09/09/2026 — era `var(--ap-e-saida)`, e essa variavel NUNCA existiu neste arquivo (nem em
     nenhum outro). Valor invalido derruba a declaracao inteira em silencio: a transicao do botao
     estava MORTA desde sempre, sem erro no console e sem teste vermelho. Agora usa a curva padrao
     da casa, `--ap-e`, que e a mesma dos outros botoes. */
  text-align:left; cursor:pointer; transition:transform 140ms var(--ap-e), box-shadow 140ms ease}
.ap-shell .ap-saida__txt{display:block; line-height:1.15}
.ap-shell .ap-saida__sub{display:block; font-size:15.5px; font-weight:500; color:var(--ap-tinta2);
  margin-top:4px; text-wrap:pretty; letter-spacing:0}
/* a seta cresce e ganha um disco dourado: vira um alvo óbvio de "vai pra frente" */
.ap-shell .ap-saida svg{width:26px; height:26px; flex:0 0 auto; fill:none; stroke:var(--ap-ouro);
  stroke-width:2.4; stroke-linecap:round; stroke-linejoin:round}
.ap-shell .ap-saida:hover{box-shadow:0 8px 26px oklch(60% 0.10 80 / .24)}
.ap-shell .ap-saida:active{transform:scale(.99)}
.ap-shell .ap-saida:focus-visible{outline:3px solid var(--ap-foco); outline-offset:3px}

/* ───────────────────────────────── C · ERRO ─────────────────────────────────
   🔴 O card de erro é o ÚNICO estado da tela 7 em que a pessoa já pagou e ainda não recebeu nada.
   Ele não pode parecer um alerta de sistema (fundo vermelho, ícone de perigo): quem lê está em luto
   e acabou de gastar dinheiro. Mesma família visual do resto do app — card, vela, dourado — com a
   diferença de que aqui existe uma GARANTIA escrita e duas saídas de verdade.
   📐 O card não é `align-items:center` na garantia: lista centralizada com 2 linhas fica com o texto
   dançando no meio. Título e ações centralizam; o que se lê linha a linha alinha à esquerda. */
#genErr:not([hidden]){display:flex; flex-direction:column; align-items:center; gap:14px;
  text-align:center; background:var(--ap-pp2); border:1px solid var(--ap-linha);
  border-radius:var(--ap-r-card); padding:22px 18px}
.ap-shell .ap-erro__ic{font-size:34px; line-height:1}

/* a promessa (pagamento seguro + o vídeo chega). Fica DENTRO de uma caixa própria porque é a única
   parte deste card que o app.js não pode reescrever — é ela que impede a tela de virar só um susto. */
.ap-shell .ap-erro__garantia{list-style:none; margin:2px 0 0; padding:14px 15px; width:100%;
  display:flex; flex-direction:column; gap:12px; text-align:left;
  background:var(--ap-pp); border:1px solid var(--ap-linha); border-radius:14px}
.ap-shell .ap-erro__garantia li{display:flex; align-items:flex-start; gap:10px;
  font-size:17px; line-height:1.45; color:var(--ap-tinta2); text-wrap:pretty}
.ap-shell .ap-erro__garantia li > span:first-child{flex:0 0 auto; font-size:18px; line-height:1.35}

/* o código curto é para ser LIDO EM VOZ ALTA pro atendimento — daí tabular, espaçado e do tamanho
   do corpo. Não é etiqueta de rodapé. */
.ap-shell .ap-erro__cod{margin:0; font-size:17px; line-height:1.4; color:var(--ap-tinta3);
  display:flex; flex-wrap:wrap; align-items:baseline; justify-content:center; gap:4px 9px}
.ap-shell .ap-erro__cod b{font-size:21px; letter-spacing:.10em; color:var(--ap-ouro);
  font-variant-numeric:tabular-nums lining-nums}

/* a frase que aponta pro resto do app (o destino real são a barra de abas e o hub logo abaixo) */
.ap-shell .ap-erro__pe{margin:2px 0 0; font-size:17px; line-height:1.45; color:var(--ap-tinta3);
  text-wrap:pretty}
.ap-shell .ap-erro__pe b{color:var(--ap-tinta2); font-weight:700}

/* 📏 APARELHO ESTREITO — a ação principal tem que caber na tela. Em 360×640 (o menor do público) o
   card media 786px e o "Tentar de novo" terminava em 673px, 33px abaixo da dobra: quem já pagou
   abria a tela do erro e não via a saída. Aqui o card aperta o cinto — respiro e recheio menores,
   nunca o alvo de toque (62px) nem o corpo (17px), que são o piso do público 45+. */
@media (max-width: 380px) {
  #genErr:not([hidden]){gap:12px; padding:18px 15px}
  .ap-shell .ap-erro__ic{font-size:30px}
  .ap-shell .ap-erro__garantia{padding:12px 13px; gap:10px}
}

/* ───────────────────────────────── D · O HUB (lista) ───────────────────────────────── */
#apHub:not([hidden]){display:flex; flex-direction:column; gap:14px; margin-top:12px;
  padding-top:22px; border-top:1px solid var(--ap-linha)}
.ap-shell .ap-cabec{display:flex; align-items:baseline; justify-content:space-between; gap:12px}
.ap-shell .ap-lista{display:flex; flex-direction:column; gap:12px}
/* a linha INTEIRA é o alvo (padrão de app), então ela não tem botão dentro — o que respeita "uma
   ação por bloco" e dá um alvo de ~130px de altura */
.ap-shell .ap-item{display:flex; align-items:center; gap:14px; width:100%; text-align:left;
  padding:12px; background:var(--ap-pp2); border:1px solid var(--ap-linha);
  border-radius:var(--ap-r-card); color:var(--ap-tinta); font-family:inherit; cursor:pointer;
  transition:background 140ms var(--ap-e)}
.ap-shell .ap-item:hover{background:oklch(24% 0.016 58)}
.ap-shell .ap-item:focus-visible{outline:3px solid var(--ap-foco); outline-offset:2px}
/* 9/16 exato (62×110): uma caixa 3:4 com `cover` comeria ~25% da altura da cena */
.ap-shell .ap-item__capa{position:relative; width:62px; height:110px; border-radius:12px;
  overflow:hidden; flex:0 0 auto; background:oklch(28% 0.010 58); border:1px solid var(--ap-linha)}
.ap-shell .ap-item__capa img{width:100%; height:100%; object-fit:cover; object-position:center top;
  display:block}
/* 🖼️ a capa SEM foto — apagada pela retenção do bucket, ou pedido que nunca teve foto (crédito,
   carta). O emoji solto ficava encostado no canto em 11px; aqui ele vira um selo centrado. */
.ap-shell .ap-item__capa--selo{display:flex; align-items:center; justify-content:center;
  font-size:28px; line-height:1}
.ap-shell .ap-item__capa--selo.ap-item__capa--obra::after{content:none}
/* na capa do que está EM PRODUÇÃO a foto entra escurecida com um brilho passando: é o mesmo trabalho
   do card de espera, resumido em 62px */
.ap-shell .ap-item__capa--obra img{filter:brightness(.5) saturate(.85)}
.ap-shell .ap-item__capa--obra::after{content:""; position:absolute; inset:0;
  background:linear-gradient(105deg, transparent 30%, oklch(85% 0.09 86 / .30) 50%, transparent 70%);
  background-size:260% 100%; animation:apVarre 2.4s linear infinite}
@keyframes apVarre{from{background-position:130% 0} to{background-position:-130% 0}}
.ap-shell .ap-item__txt{flex:1; min-width:0; display:flex; flex-direction:column; align-items:flex-start;
  gap:6px}
.ap-shell .ap-item__nome{font-size:18px; font-weight:700; letter-spacing:-.01em}
/* 🎵 02/11/2026 — DESTAQUE DO ORDER BUMP (música, foto extra). O servidor marca `extra:true` pelo
   `bump_de` (api/cliente.js:431). Sem isto o bump entrava como card igual ao do vídeo e a compra
   que a pessoa pagou A MAIS não se distinguia da homenagem principal. Dourado da casa (hue 86). */
.ap-shell .ap-item--extra{border-color:oklch(80% 0.10 86 / .55);
  background:linear-gradient(180deg, oklch(80% 0.10 86 / .12), oklch(80% 0.10 86 / .03)), var(--ap-pp2);
  box-shadow:inset 3px 0 0 oklch(80% 0.11 86)}
.ap-shell .ap-item--extra:hover{background:linear-gradient(180deg, oklch(80% 0.10 86 / .18), oklch(80% 0.10 86 / .05)), oklch(24% 0.016 58)}
.ap-shell .ap-chip-extra{display:inline-block; margin-left:8px; padding:1px 8px; border-radius:999px;
  font-size:11px; font-weight:800; letter-spacing:.4px; vertical-align:middle; line-height:1.6;
  color:oklch(26% 0.04 70); background:linear-gradient(180deg, oklch(88% 0.09 86), oklch(78% 0.11 83))}
.ap-shell .ap-item__seta{flex:0 0 auto; width:22px; height:22px; fill:none; stroke:var(--ap-tinta3);
  stroke-width:2; stroke-linecap:round; stroke-linejoin:round}
/* estado vazio da lista (sem contato guardado, ou contato sem pedido) */
.ap-shell .ap-vazio{display:flex; flex-direction:column; gap:14px; align-items:center;
  text-align:center; background:var(--ap-pp2); border:1px solid var(--ap-linha);
  border-radius:var(--ap-r-card); padding:20px 18px}

/* ───────────────────────────────── aba ELENCO ─────────────────────────────────
   As pessoas dela. O rosto é o conteúdo — nome e parentesco são legenda, e por isso a foto ocupa
   o card inteiro e o texto vem embaixo, fora dela: legenda POR CIMA de foto de família fica
   ilegível em metade das fotos (fundo claro) e some na outra metade. */
.ap-shell .ap-elenco{display:grid; grid-template-columns:repeat(auto-fill, minmax(104px, 1fr)); gap:12px}
/* 🪤 sem isto o aviso de "ainda não tem ninguém" vira UM ITEM do grid e o texto sai espremido
   numa coluna de 104px. Recado ocupa a largura toda; só rosto entra na grade. */
.ap-shell .ap-elenco--recado{display:block}
.ap-shell .ap-pessoa{display:flex; flex-direction:column; gap:8px; text-align:center}
.ap-shell .ap-pessoa__foto{width:100%; aspect-ratio:1; object-fit:cover; border-radius:14px;
  background:var(--ap-pp3); border:1px solid var(--ap-linha); display:block}
.ap-shell .ap-pessoa__nome{font-size:15px; font-weight:600; color:var(--ap-tinta); line-height:1.25;
  overflow-wrap:anywhere}
.ap-shell .ap-pessoa__meta{font-size:13px; color:var(--ap-tinta3); line-height:1.2; margin-top:-4px}

/* ───────────────────────────────── aba CRIAR ─────────────────────────────────
   🔴 O catálogo é PREÇO CHEIO. O que ele oferece de verdade é conveniência, e é isso que ele diz —
   nunca contador, nunca "últimas vagas". */
.ap-shell .ap-grade{display:grid; grid-template-columns:1fr 1fr; gap:12px}
.ap-shell .ap-cena{position:relative; padding:0; border:1px solid var(--ap-linha); border-radius:16px;
  overflow:hidden; background:#0B0A0A; cursor:pointer; text-align:left; color:var(--ap-tinta);
  font-family:inherit; transition:transform 160ms var(--ap-e), border-color 160ms var(--ap-e);
  /* 📱 25/09/2026 — SEM O RETANGULO CINZA DO ANDROID por cima do card. Ele nasce em TODO toque,
     inclusive no toque que so queria rolar a pagina, e num card que e quase todo imagem ele
     parece que a cena "foi selecionada". */
  -webkit-tap-highlight-color:transparent;
  /* 📱 O DEDO DECIDE O EIXO, NAO O CARD. Sem esta linha o navegador ainda espera pra ver se vem
     um duplo-toque de zoom antes de liberar o gesto, e o comeco da rolagem vertical em cima do
     card chega atrasado. `manipulation` = clique e rolagem sim, duplo-toque-pra-zoom nao. */
  touch-action:manipulation}
/* 🖱️ 25/09/2026 — O :hover SO ONDE EXISTE MOUSE (Lucas, testando no celular: "sempre que eu
   tento scrollar clicando por cima de alguma oferta, ele seleciona aquela oferta").
   No toque nao existe "sair de cima": o navegador aplica o :hover no primeiro contato do dedo e
   ele FICA GRUDADO ate a pessoa tocar em outro lugar. Com `transform:translateY(-2px)` mais a
   borda dourada, o card fica visivelmente "escolhido" — e quem so queria rolar a lista ve a
   oferta errada acesa atras do dedo.
   `@media (hover:hover)` e o unico jeito de manter o efeito no desktop sem exporta-lo pro
   celular. Medido na bancada em 375x812 com emulacao de toque, que e o que o aparelho reporta:
   matchMedia("(hover: hover)").matches === false. */
@media (hover:hover){
  .ap-shell .ap-cena:hover{border-color:oklch(48% 0.055 82); transform:translateY(-2px)}
}
.ap-shell .ap-cena:focus-visible{outline:3px solid var(--ap-foco); outline-offset:2px}
/* 9/16 exato = zero corte, aritmética e não opinião. A cena é o produto: ela não pode ser aparada. */
/* ✝️ `img` junto de `video`: os cards de figura religiosa não têm clipe de vitrine e mostram a
   foto da figura. Mesma regra pros dois, senão o card da carta sai com outro tamanho no meio da
   grade e parece defeito. */
.ap-shell .ap-cena video,
.ap-shell .ap-cena img{width:100%; aspect-ratio:9/16; object-fit:cover; display:block}
/* 🖼️ A CAPA É O FUNDO DO CARD, e o vídeo só aparece enquanto toca — é isso que mata o pisca do
   último quadro ao sair do mouse (ver `prepararCapasDosCards`). A classe `--capa` só existe nos
   cards que REALMENTE têm `poster`: sem essa guarda, um card sem capa ficaria preto no repouso. */
.ap-shell .ap-cena--capa{background-size:cover; background-position:center top; background-repeat:no-repeat}
.ap-shell .ap-cena--capa video{opacity:0; transition:opacity 140ms linear}
.ap-shell .ap-cena--capa.tocando video{opacity:1}
@media (prefers-reduced-motion: reduce){
  .ap-shell .ap-cena--capa video{transition:none}
}
/* 📐 09/09/2026 — dois defeitos medidos em 360/390/430, os dois consertados sem tocar no tamanho
   da fonte (o piso de 15,5px de test/e2e-tela7.mjs nao permitiria encolher muito, e encolher seria
   a saida errada num publico 45+).

   1. PALAVRA ORFA. O nome tem 17px fixo num card de 156-191px de largura util, entao ele quebra em
      duas linhas com UMA palavra sozinha embaixo: 10 dos 22 cards em 360px, 9 em 390px. O pior era
      "Abraco com Jesus ✝️", que deixava a CRUZ sozinha na segunda linha. `text-wrap:balance` divide
      as duas linhas em partes parecidas em vez de encher a primeira e jogar o resto pra baixo.
      Navegador antigo simplesmente ignora a declaracao e volta ao comportamento de hoje.

   2. ROTULOS DE CARDS IRMAOS EM ALTURAS DIFERENTES. O nome e ancorado embaixo (`bottom:0`), entao
      quando um card tem nome de 1 linha e o vizinho tem 2, o topo da caixa — e junto o degrade que
      a carrega — comeca 20,39px mais alto num que no outro. Medido em 3 fileiras a 360px e 4 a
      390px. O `min-height` reserva a altura de DUAS linhas em todos, entao o degrade sempre comeca
      na mesma altura e a fileira fica reta. A conta e: 26 de padding-top + 11 de baixo + 2 linhas
      de 17px x 1,2. */
.ap-shell .ap-cena__nome{position:absolute; left:0; right:0; bottom:0; padding:26px 11px 11px;
  font-size:17px; font-weight:600; color:#fff; line-height:1.2;
  min-height:calc(26px + 11px + 2 * 17px * 1.2); text-wrap:balance;
  background:linear-gradient(180deg, transparent, oklch(8% 0.01 58 / .88));
  /* ✍️ 25/09/2026 — O NOME FICA PARADO (Lucas: "ta bugando muito os nomes das ofertas, elas
     ficam flicando... o nome das ofertas devia ser fixo e ficar parado").
     POR QUE ELE PISCAVA: o nome mora POR CIMA do video, num degrade translucido. Cada vez que o
     card troca de capa para video e de volta (opacity 140ms, e isso acontece a cada entrada e
     saida da tela enquanto a pessoa rola) o navegador repinta o texto junto, porque os dois
     estao na mesma camada. Em celular fraco esse repinte perde quadros e o texto tremula.
     `translateZ(0)` promove o nome a uma camada propria: o video troca embaixo sem obrigar o
     texto a ser redesenhado. `pointer-events:none` e o par disso — o nome nao precisa receber
     toque nenhum (quem recebe e o botao inteiro) e sem ele o degrade e mais um alvo no meio do
     card pra o navegador considerar antes de liberar a rolagem. */
  transform:translateZ(0); pointer-events:none}
/* 🪤 o card largo tem o nome em fluxo normal (`position:static`, regra logo abaixo): reservar duas
   linhas la abriria um buraco dentro de um card de 153px de altura. */
.ap-shell .ap-cena--larga .ap-cena__nome{min-height:0}
.ap-shell .ap-cena--larga{grid-column:1 / -1; display:flex; align-items:center; gap:13px; padding:10px}
/* 📐 09/09/2026 — a miniatura era `width:74px` CRAVADO e nao acompanhava a tela: medido em
   360/430/768/1440, o card largo ia de 328 -> 398 -> 418 -> 418px e a miniatura ficava em 74,0px
   nos quatro. Na MESMA grade o card normal mostrava 203px de video e o largo mostrava 74.
   O `clamp` so cresce a partir de ~352px de card, entao em 360px nada muda (fica no piso de 74) e
   o ganho aparece justamente onde havia folga sobrando.
   🪤 O teto de 92px NAO e estetico: a altura do card largo e o `aspect-ratio:9/16` da miniatura
   (74 -> 131,5px de altura; 92 -> 163,5px). Subir o teto engorda os 3 cards de "Outras homenagens"
   e empurra o rodape — se mexer aqui, meça a altura da aba de novo.
   🪤 E o app e uma COLUNA TRAVADA em 450px (--col/#app em css/styles.css:33,50-51): de 768 pra
   1440 nada muda porque nao pode mudar. Nao existe layout de tela larga pra esta tela. */
.ap-shell .ap-cena--larga video{width:clamp(74px, 21%, 92px); aspect-ratio:9/16; border-radius:10px; flex:0 0 auto}
.ap-shell .ap-cena--larga .ap-cena__cx{flex:1; min-width:0}
.ap-shell .ap-cena--larga .ap-cena__nome{position:static; display:block; padding:0; background:none;
  font-size:17.5px; font-weight:700}
/* 📐 `balance` porque em 360px o subtítulo caía com UMA palavra sozinha na 2ª linha ("Aquela
   foto rasgada volta / nítida"): o navegador reparte as linhas em vez de encher a primeira. */
.ap-shell .ap-cena__sub{display:block; margin-top:4px; font-size:17px; line-height:1.32;
  color:var(--ap-tinta3); text-wrap:balance}

/* ───────────────────────────────── aba AJUDA ───────────────────────────────── */
.ap-shell .ap-faq{background:var(--ap-pp2); border:1px solid var(--ap-linha);
  border-radius:var(--ap-r-card); overflow:hidden}
.ap-shell .ap-faq details + details{border-top:1px solid var(--ap-linha)}
.ap-shell .ap-faq summary{min-height:var(--ap-toque); display:flex; align-items:center;
  justify-content:space-between; gap:12px; padding:14px 16px; font-size:17.5px; font-weight:600;
  color:var(--ap-tinta); cursor:pointer; list-style:none}
.ap-shell .ap-faq summary::-webkit-details-marker{display:none}
.ap-shell .ap-faq summary::after{content:""; width:10px; height:10px; flex:0 0 auto;
  border-right:2px solid var(--ap-tinta3); border-bottom:2px solid var(--ap-tinta3);
  transform:rotate(45deg) translateY(-3px); transition:transform 180ms var(--ap-e)}
.ap-shell .ap-faq details[open] summary::after{transform:rotate(-135deg) translateY(-3px)}
.ap-shell .ap-faq p{padding:0 16px 16px; margin:0; font-size:17px; line-height:1.45;
  color:var(--ap-tinta2)}

/* ───────────────────────────────── folhas (sheets) ─────────────────────────────────
   Sobem de baixo: a tela continua visível atrás, então a pessoa não sente que "saiu" de lugar
   nenhum. Quem abre/fecha mexe SÓ na classe `.aberta` — nenhum `display` inline em nada disto. */
/* z-index 55 (era 40, 05/11/2026) — a folha passa a ficar acima da barra de upsell `.ups-barra`,
   que esta em 50 (css/styles.css:886) e e filha direta de `#app` (js/app.js:4547).
   ISTO E A CORRECAO TECNICA do bug que o Lucas viu: com a folha em 40 a barra ficava por cima do
   "Sua conta" e comia o toque da faixa de baixo. Verificado em producao com
   `document.elementsFromPoint` no centro da barra: a pilha passou a trazer `.ap-folha[z:55]`
   ACIMA de `.ups-barra`, e quem atende o toque virou o conteudo da folha.
   🪤 MEDIR ISTO DA ERRADO se a aba estiver em segundo plano ou se a leitura pegar a transicao de
   abertura pela metade: nos dois casos o `elementFromPoint` ainda devolve a barra e parece que o
   z-index nao pegou. Custou um commit errado (28cd34d dizia que os 55 nao resolviam; nao era
   verdade, era a medicao). Espere a transicao terminar e meca com a aba em primeiro plano.
   🪤 Mexendo aqui, fique ENTRE 51 e 59: abaixo vem a barra (50), acima vem o confete (60), o
   `.paywrap` (100), o `.cta-folha` (120) e o modal `.upsm` (9999), que devem cobrir a folha.
   Alem disto a barra RECOLHE enquanto a folha esta aberta (`#app.com-folha-aberta .ups-barra`):
   isso e escolha de PRODUTO — modal nao divide a tela com oferta — e nao necessidade tecnica.
   Coberto por test/e2e-folha-acima-da-barra.mjs. */
.ap-shell .ap-folha{position:absolute; inset:0; z-index:55; pointer-events:none}
.ap-shell .ap-folha__fundo{position:absolute; inset:0; background:oklch(8% 0.008 58 / .68);
  opacity:0; transition:opacity 240ms var(--ap-e)}
.ap-shell .ap-folha__cx{position:absolute; left:0; right:0; bottom:0; max-height:88%; overflow-y:auto;
  background:var(--ap-pp2); border:1px solid var(--ap-linha); border-bottom:0;
  border-radius:24px 24px 0 0; padding:8px 16px 22px; transform:translateY(102%);
  transition:transform 320ms var(--ap-e); display:flex; flex-direction:column; gap:15px;
  color:var(--ap-tinta)}
.ap-shell .ap-folha.aberta{pointer-events:auto}
.ap-shell .ap-folha.aberta .ap-folha__fundo{opacity:1}
.ap-shell .ap-folha.aberta .ap-folha__cx{transform:none}
/* alça: o sinal universal de "isto some pra baixo" */
.ap-shell .ap-folha__alca{width:44px; height:5px; border-radius:99px; background:oklch(38% 0.012 58);
  margin:2px auto 4px; flex:0 0 auto}
.ap-shell .ap-folha__h{font-family:var(--ap-serif); font-size:23px; font-weight:400; line-height:1.15;
  margin:0}
.ap-shell .ap-folha__linha{display:flex; align-items:center; gap:13px; padding:13px 0;
  border-bottom:1px solid var(--ap-linha)}
.ap-shell .ap-folha__av{width:52px; height:52px; border-radius:50%; flex:0 0 auto; display:flex;
  align-items:center; justify-content:center; font-family:var(--ap-serif); font-size:23px;
  line-height:1; color:var(--ap-ouro); background:oklch(26% 0.030 66);
  border:1px solid oklch(40% 0.040 74)}
.ap-shell .ap-folha__av svg{width:29px; height:29px; display:block}
/* 10px e não 6: a 6px o alvo de 60px invadia a curva do raio (24px) da folha e o ✕ lia como
   elemento quebrado sobreposto à quina (Lucas, 19/08 01h30) */
.ap-shell .ap-folha__x{position:absolute; top:10px; right:10px; width:60px; height:60px; display:flex;
  align-items:center; justify-content:center; background:none; border:0; padding:0;
  color:var(--ap-tinta2); font-size:27px; line-height:1; cursor:pointer; z-index:2}
/* os dois estados da folha da conta empilham como o resto da folha */
#apContaCom:not([hidden]),
#apContaSem:not([hidden]){display:flex; flex-direction:column; gap:15px}

/* ───────────────────────────────── entrada (sem conta) ───────────────────────────────── */
#apEntrada:not([hidden]){position:absolute; inset:0; z-index:35; background:var(--ap-pp);
  padding:26px 20px; display:flex; flex-direction:column; justify-content:center; gap:16px;
  text-align:center; overflow-y:auto}
.ap-shell .ap-entrada__ic{width:44px; height:44px; border-radius:12px; margin:0 auto}
.ap-shell .ap-form{display:flex; flex-direction:column; gap:13px}
.ap-shell .ap-campo{width:100%; min-height:var(--ap-toque); border-radius:16px;
  border:2px solid var(--ap-linha); background:oklch(23% 0.014 58); color:var(--ap-tinta);
  font-family:inherit; font-size:20px; font-weight:600; padding:0 16px; text-align:center}
.ap-shell .ap-campo::placeholder{color:oklch(56% 0.012 70); font-weight:400}
.ap-shell .ap-campo:focus{outline:none; border-color:var(--ap-ouro)}

/* ───────────────────────────────── celular baixo (espera) ─────────────────────────────────
   📏 Medido em 360×640 (a altura ÚTIL do aparelho mais barato do público): a frase que SEGURA a
   pessoa na tela — "Fica aqui com a gente" — nascia 108px abaixo do fim da tela, e ela não tem
   como saber que dá pra rolar. Aqui a espera fica compacta: retratos menores, respiros menores,
   título um ponto menor. Nada some e nenhum alvo de toque encolhe (o piso de 62px e o de 17px de
   texto continuam valendo — só os ESPAÇOS cedem).
   ⚠️ `max-height` e não `max-width`: quem aperta é a altura, e um iPhone deitado tem o mesmo
   problema numa largura grande. */
/* 📏 1º DEGRAU (17/08) — o aparelho MEDIANO também não cabia. Medido em 390×740: o `#genSuporte`
   nascia 63px abaixo da dobra (o degrau abaixo só pegava ≤700px, e 740 passava batido). A conta da
   tela: 60 (barra) + 16 + 62 (título em 2 linhas) + 16 + 404 (card) + 16 + 151 (recado) + 16 + 62
   (ajuda) = 803 num viewport de 740. Aqui cedem só os ESPAÇOS e o corpo dos retratos; nada some,
   nenhum alvo encolhe e o piso de 17px de texto continua de pé.
   🪤 Este bloco vem ANTES do de ≤700 de propósito: os dois têm a mesma especificidade, então quem
   ganha num celular baixo é o de baixo — o degrau seguinte só precisa declarar o que aperta MAIS. */
@media (max-height: 820px){
  .ap-shell.ap-esperando .ap-pad{padding-top:10px; padding-bottom:18px}
  .ap-shell.ap-esperando .ap-h1{font-size:23px}
  #genLoading:not([hidden]){gap:11px}
  .ap-shell .ap-obra{padding:15px; gap:12px}
  .ap-shell .ap-par figure{width:104px; height:128px}
  .ap-shell .ap-luz{height:134px}
  .ap-shell .ap-obra::before{top:-34px; height:170px}
  .ap-shell .ap-etapas{gap:9px}
  .ap-shell .ap-fica{padding:13px 15px; gap:11px}
}
@media (max-height: 700px){
  .ap-shell.ap-esperando .ap-pad{gap:12px; padding-top:4px; padding-bottom:12px}
  .ap-shell.ap-esperando .ap-h1{font-size:21px}
  #genLoading:not([hidden]){gap:7px}
  .ap-shell .ap-obra{padding:10px 12px; gap:7px}
  /* 🖼️ o retrato encolhe mas continua RETRATO: quem cede é a largura antes da altura. Com 96×84 a
     moldura virava paisagem e a foto vertical que a pessoa mandou entrava cortada nos dois lados. */
  .ap-shell .ap-par figure{width:82px; height:92px}
  .ap-shell .ap-luz{height:96px}
  .ap-shell .ap-obra::before{top:-30px; height:150px}
  .ap-shell .ap-etapas{gap:5px}
  /* a bolinha do número encolhe; o TEXTO da etapa continua em 17px (o piso desta tela) */
  .ap-shell .ap-etapas li b{width:21px; height:21px}
  .ap-shell .ap-fica{padding:11px 14px; gap:10px; line-height:1.3}
  .ap-shell .ap-ajuda{margin-top:4px}
}

/* ───────────────────────────────── menos movimento ───────────────────────────────── */

/* ══════════════════════════════ 🪙 PACOTES DE CRÉDITO ════════════════════════════════════════
   Desenho aprovado pelo Lucas em 09/09/2026 12h15, depois de duas reprovações. O que a segunda
   reprovação ensinou e está codificado aqui:

   1. **O DESTAQUE É DO SELECIONADO, NÃO DO PACOTE.** A folha nasce com o pacote do meio escolhido,
      e o realce inteiro (brasa, borda, preço grande, fitas acesas) VIAJA para onde a pessoa tocar.
      O selo "mais escolhido" fica cravado no de 300 o tempo todo: ele informa o que os OUTROS
      compram, não o que você escolheu — são duas informações diferentes e não podem se confundir.
   2. **O preço nunca quebra.** A versão anterior dava `padding-right` ao número quando ele crescia
      pra não bater na marca ✓, e em 390px "R$ 57,00" partia em duas linhas. Agora o número tem
      `nowrap` e DESCE um pouco no lugar de estreitar. Medido nos 3 pacotes × 4 larguras (320/375/
      390/430): 12 combinações, nenhuma quebra.
   3. **As fitas são a quantidade.** Uma fita por homenagem — a pessoa vê que são 3 sem ler.
   ══════════════════════════════════════════════════════════════════════════════════════════ */
.ap-shell .ap-cr__grade{display:flex; flex-direction:column; gap:10px; margin:2px 0 0}
.ap-shell .ap-cr__card{position:relative; display:grid; grid-template-columns:1fr auto;
  gap:3px 12px; align-items:center; padding:14px 16px; width:100%; text-align:left;
  border:1px solid var(--ap-linha); border-radius:var(--ap-r-card); background:var(--ap-pp2);
  color:var(--ap-tinta); font-family:inherit; font-size:15.5px; cursor:pointer;
  transition:transform 180ms var(--ap-e), border-color 180ms var(--ap-e),
    background 180ms var(--ap-e), box-shadow 180ms var(--ap-e)}
.ap-shell .ap-cr__card:hover{border-color:oklch(42% 0.024 58)}
.ap-shell .ap-cr__card:active{transform:scale(.99)}
.ap-shell .ap-cr__card:focus-visible{outline:3px solid var(--ap-foco); outline-offset:2px}
.ap-shell .ap-cr__card[aria-pressed="true"]{border-color:oklch(58% 0.080 84);
  background:radial-gradient(120% 80% at 50% 0%, oklch(29% 0.045 76) 0%, transparent 72%), oklch(22% 0.026 66);
  box-shadow:0 12px 30px oklch(8% 0.010 58 / .5), 0 0 0 1px oklch(58% 0.080 84) inset}
/* o card que carrega o selo precisa de ar em cima pra ele não encostar no vizinho */
.ap-shell .ap-cr__card--selo{margin-top:9px}
.ap-shell .ap-cr__selo{position:absolute; top:-9px; left:16px; padding:3px 10px; border-radius:999px;
  background:var(--ap-ouro); color:var(--ap-ouro-esc); font-size:15.5px; font-weight:800;
  letter-spacing:.06em; text-transform:uppercase}
.ap-shell .ap-cr__n{font-size:17px; font-weight:700; transition:font-size 180ms var(--ap-e)}
.ap-shell .ap-cr__card[aria-pressed="true"] .ap-cr__n{font-size:19px}
/* 🔢 sans + tabular + nowrap: Georgia tem numeral old-style (desce da linha) e a quebra de linha
   aqui foi exatamente o defeito que o Lucas pegou na tela dele. */
.ap-shell .ap-cr__p{grid-row:span 2; align-self:center; white-space:nowrap;
  font-family:system-ui,-apple-system,"Segoe UI",Roboto,Arial,sans-serif;
  font-size:21px; font-weight:800; letter-spacing:-.02em;
  font-variant-numeric:tabular-nums lining-nums;
  transition:font-size 180ms var(--ap-e), color 180ms var(--ap-e), margin-top 180ms var(--ap-e)}
.ap-shell .ap-cr__card[aria-pressed="true"] .ap-cr__p{font-size:30px; color:var(--ap-ouro);
  text-shadow:0 0 20px oklch(83% 0.107 86 / .20); margin-top:14px}
.ap-shell .ap-cr__fitas{display:flex; gap:5px; margin-top:7px}
.ap-shell .ap-cr__fita{width:30px; height:9px; border-radius:3px; background:oklch(31% 0.016 60);
  border:1px solid oklch(37% 0.018 60); transition:background 180ms var(--ap-e)}
.ap-shell .ap-cr__card[aria-pressed="true"] .ap-cr__fita{
  background:linear-gradient(180deg, oklch(88% 0.110 88), oklch(76% 0.105 84));
  border-color:oklch(70% 0.100 84); box-shadow:0 0 12px oklch(83% 0.107 86 / .35)}
/* 📐 DUAS LINHAS RESERVADAS SEMPRE, e o motivo é aritmético: só os pacotes de 3 e 5 têm
   "economia de R$ ..." pra anunciar (`crEconomia` devolve 0 no de 1 vídeo), então a linha de apoio
   deles quebra em 2 e a do pacote de 1 fica em 1 — 21px de diferença entre cards irmãos.
   🩤 Até 09/09/2026 isso passava despercebido por ACIDENTE: o "cada" sobrando no singular
   ("1 homenagem · R$ 27,00 cada") empurrava a linha pra 2 e emparelhava as alturas. Consertar a
   copy revelou o desalinho que ela escondia — 122/156/122 virou 101/156/122.
   O `line-height` é explícito porque a conta do `min-height` depende dele. */
/* 📐 LARGURA INTEIRA (`1/-1`), não a coluna da esquerda. Presa em `1/2` ela dividia espaço com
   o preço — e no card ESCOLHIDO o preço é 30px, então sobrava tão pouco que "R$ 12,33 cada"
   partia no meio e deixava "cada" sozinho numa linha. Embaixo do preço, com a largura toda, a
   frase inteira cabe numa linha só em qualquer um dos três cards. */
.ap-shell .ap-cr__cada{grid-column:1/-1; margin-top:6px; font-size:15.5px; color:var(--ap-tinta2);
  line-height:1.35; min-height:calc(2 * 15.5px * 1.35);
  font-variant-numeric:tabular-nums lining-nums}
.ap-shell .ap-cr__card[aria-pressed="true"] .ap-cr__cada{color:var(--ap-tinta2)}
/* 📐 LINHA PRÓPRIA. Emendada na mesma linha do valor unitário, a economia empurrava a quebra
   pro meio de "R$ 12,33 cada" — valor numa linha, "cada" na outra. Em bloco, cada informação
   ocupa a sua, e as 2 linhas já reservadas no `.ap-cr__cada` acomodam as duas sem mexer na altura. */
.ap-shell .ap-cr__eco{display:block; color:var(--ap-ouro); font-weight:700}
.ap-shell .ap-cr__tick{position:absolute; top:12px; right:14px; width:20px; height:20px;
  border-radius:50%; background:var(--ap-ouro); display:none; align-items:center; justify-content:center}
.ap-shell .ap-cr__card[aria-pressed="true"] .ap-cr__tick{display:flex}
.ap-shell .ap-cr__tick svg{width:12px; height:12px; stroke:var(--ap-ouro-esc); stroke-width:3; fill:none}

/* 🔘 O BOTÃO NÃO FALA EM PAGAR (Lucas, 09/09 12h12): ninguém quer apertar um botão que cobra dela.
   Ele promete o que ela LEVA — desbloquear a homenagem, aproveitar o desconto — e o valor desce
   pra segunda linha, menor, como confirmação. */
.ap-shell .ap-cr__bt{min-height:var(--ap-toque); padding:8px 18px; width:100%; border:0;
  border-radius:var(--ap-r-btn); background:var(--ap-ouro); color:var(--ap-ouro-esc);
  font-family:inherit; font-size:17px; font-weight:800; line-height:1.2; cursor:pointer;
  box-shadow:0 10px 26px oklch(83% 0.107 86 / .18)}
.ap-shell .ap-cr__bt small{display:block; margin-top:3px; font-size:15.5px; font-weight:600;
  opacity:.72; font-variant-numeric:tabular-nums lining-nums}
.ap-shell .ap-cr__bt[aria-busy="true"]{opacity:.6; pointer-events:none}

/* saldo e textos de apoio da folha */
.ap-shell .ap-cr__saldo{margin:0; color:var(--ap-tinta3)}
.ap-shell .ap-cr__intro{margin:0; text-align:left; color:var(--ap-tinta2)}

/* Hallmark · component: modal PIX · genre: atmospheric · theme: Eterniz brasa
 * states: default · hover · focus · active · disabled · loading · error · success
 * contrast: pass (40–41) · responsive: pass (320 · 375 · 414 · 768)
 * pre-emit critique: P5 H5 E5 S5 R5 V4
 *
 * 🪙 RESUMO DA RECARGA — duas colunas, uma hierarquia. Antes o preço era um <b> dentro do
 * <span> da frase; a regra global de .upsm__motivo b transformava o número em bloco e deixava
 * “São”, “R$ 27,00” e a explicação em três eixos diferentes. A classe só existe na recarga. */
.ap-shell .upsm__motivo--recarga{display:grid; grid-template-columns:minmax(0,1fr) auto;
  align-items:center; gap:12px 18px; margin:18px 0; padding:16px;
  text-align:left; background:color-mix(in oklch,var(--ap-ouro) 9%,var(--ap-pp2));
  border:1px solid color-mix(in oklch,var(--ap-ouro) 34%,var(--ap-linha))}
.ap-shell .upsm__recarga-pacote,.ap-shell .upsm__recarga-total{display:flex; flex-direction:column;
  min-width:0; gap:3px}
.ap-shell .upsm__recarga-pacote b{display:block; margin:0; color:var(--ap-tinta);
  font-size:18px; line-height:1.2; letter-spacing:-.01em}
.ap-shell .upsm__recarga-pacote small,.ap-shell .upsm__recarga-total small{
  color:var(--ap-tinta3); font-size:15.5px; line-height:1.25}
.ap-shell .upsm__recarga-total{text-align:right; align-items:flex-end}
.ap-shell .upsm__recarga-total strong{color:var(--ap-ouro); font-size:23px; line-height:1;
  font-weight:800; font-variant-numeric:tabular-nums lining-nums; white-space:nowrap}
.ap-shell .upsm__recarga-total #upsellTaxa{font-size:15.5px; line-height:1.25; color:var(--ap-tinta3)}
.ap-shell .upsm__recarga-ajuda{grid-column:1/-1; padding-top:11px;
  border-top:1px solid color-mix(in oklch,var(--ap-ouro) 18%,var(--ap-linha));
  color:var(--ap-tinta2); font-size:15.5px; line-height:1.35}
/* O X era 32px: abaixo do piso de toque. O círculo cresce sem invadir o resumo. */
.ap-shell .upsm__x{top:8px; right:8px; width:44px; height:44px}
.ap-shell .upsm__x:focus-visible,.ap-shell #upsellCopy:focus-visible,.ap-shell #upsellSupport:focus-visible{
  outline:3px solid var(--ap-foco); outline-offset:2px}
.ap-shell .upsm__x:active,.ap-shell #upsellCopy:active,.ap-shell #upsellSupport:active{
  transform:translateY(1px)}
.ap-shell #upsellCopy,.ap-shell #upsellSupport{white-space:nowrap}
.ap-shell #upsellSupport{display:flex; align-items:center; justify-content:center; text-decoration:none}
.ap-shell #upsellCopy:disabled{opacity:.55; cursor:not-allowed}
@media (hover:hover){
  .ap-shell .upsm__x:hover{background:color-mix(in oklch,var(--ap-tinta) 14%,transparent)}
}
@media (max-width:340px){
  .ap-shell .upsm__motivo--recarga{gap:10px 12px; padding:14px}
  .ap-shell .upsm__recarga-pacote b{font-size:17px}
  .ap-shell .upsm__recarga-total strong{font-size:21px}
}
@media (prefers-reduced-motion:reduce){
  .ap-shell .upsm__x,.ap-shell #upsellCopy,.ap-shell #upsellSupport{transition:none}
}
/* ══════════════════════ 🎞️ ABA CRIAR EM TRILHOS (versão H, 10/09/2026) ══════════════════════
   Resgatado do protótipo `_proto/criar-streaming.html`, que testou sete formatos e concluiu que
   só os TRILHOS prestaram. O H é: um billboard no topo (a continuação natural do que a pessoa
   acabou de comprar) e três linhas roláveis abaixo.

   🔑 OS CARDS SÃO OS MESMOS `.ap-cena` DA GRADE, movidos pra dentro dos trilhos — não são cópias.
   É isso que faz o clique, o hover e o modo-celular continuarem funcionando sem uma segunda
   implementação pra manter em dia. O CSS daqui só muda a forma deles DENTRO do rolo.

   🔴 4/5 no rolo, e não o 9/16 da grade: com 9/16 um card de 150px tem 267px de altura e só cabem
   duas linhas na tela inteira — o formato perderia o próprio motivo de existir. O 9/16 continua
   sagrado onde a cena É o produto: o billboard e a folha.
   ══════════════════════════════════════════════════════════════════════════════════════════ */
.ap-shell .ap-trilhos{display:flex; flex-direction:column; gap:22px}

/* ── billboard: a cena em tamanho de vitrine, com o texto sobre o degradê ── */
.ap-shell .ap-bb{position:relative; display:block; width:calc(100% + 32px); margin:-8px -16px 0;
  /* 🪤 `background-color:transparent`, e NÃO `background:none`: a forma curta zera TAMBÉM o
     `background-size/position/repeat`, e o billboard passou a mostrar a capa no tamanho original,
     encostada no canto — o enquadramento que `prepararCapasDosCards` monta ia embora aqui. */
  padding:0; overflow:hidden; text-align:left; color:var(--ap-tinta); border:0;
  background-color:transparent;
  font-family:inherit; cursor:pointer}
.ap-shell .ap-bb video{width:100%; aspect-ratio:4/5; object-fit:cover; display:block;
  background:oklch(11% 0.006 58);
  /* 🙂 35%, e não o centro: com o teto de altura abaixo, a janela sobre um vídeo 9:16 fica mais
     estreita, e centrada ela passava na ALTURA DO PEITO — a primeira montagem cortou a cabeça da
     senhora da escadaria, que é justamente o que a cena vende. 35% sobe o recorte pro terço de
     cima, onde os rostos moram. Conferido nas 27 capas do catálogo recortadas nesta janela
     (folha de contato de 25/09/2026): nenhuma perde o rosto. */
  object-position:center 35%;
  /* 📏 O BILLBOARD NÃO PODE COMER A TELA INTEIRA (Lucas, 25/09/2026, com print de iPhone SE
     375x667 e de Nest Hub Max 1280x800). Medido na bancada em 375x667 ANTES desta linha: o
     billboard tinha 469px e terminava a 14px da barra de abas, e o título da primeira linha de
     cenas nascia em y=597 com a barra em y=589 — ou seja, ATRÁS dela. Quem abre a aba vê UMA
     cena e não tem como descobrir que existem outras 21 embaixo; o formato em trilhos depende
     de a pessoa enxergar que a página continua.
     📐 365 = 114 de cromo em cima (barra de 60, padding de 16, o título da aba e o gap, menos a
     margem negativa do próprio billboard) + 78 da barra de abas + 173 de ESPIA. A espia não é
     gosto: 22 de gap + 81 do cabeçalho da linha (título e subtítulo, as duas linhas do caso
     pior) + 70 do card, que é a faixa de imagem que faz a pessoa entender que aquilo ROLA.
     Medido depois: billboard de 302px no SE, com 70px do primeiro card acima da barra.
     Onde a tela é alta o `aspect-ratio` continua mandando sozinho e nada muda — o teto só morde
     quando o 4/5 passaria do fim da tela.
     🪤 `svh`, e não `dvh`: o dvh cresce quando a barra do navegador some, e o billboard mudaria
     de altura no meio da rolagem. A linha com `vh` é o fallback de quem não conhece `svh` —
     o público é 45+ e ainda chega Chrome velho aqui. O piso de 300px evita que uma tela muito
     baixa (paisagem, 5s) transforme a vitrine numa tarja. */
  /* ✂️ 12/10/2026 — A RESERVA CAIU DE 365 PRA 248, e o motivo é que a porta mudou de dono.
     Em 25/09 esta tela era area do CLIENTE: quem chegava ja tinha comprado, e a espia de 173px
     existia pra ele descobrir que havia outras 21 cenas embaixo do billboard. Hoje a raiz do
     `eternizapp.com` abre aqui pra quem NUNCA comprou, e a primeira coisa que essa pessoa ve
     tem que ser a oferta inteira, nao uma tarja dela.
     📐 MEDIDO na janela do Lucas (450 de largura util, 678 de altura, 12/10 14h51): com 365 o
     billboard ficava em 313px contra os 563px naturais do 4/5 — 44% da cena cortada, com a
     senhora da escadaria perdendo metade do corpo. Com 248 da 430px: 24% de corte, e a partir
     de ~810px de altura o teto nao morde mais e a cena aparece INTEIRA.
     📐 248 = 114 de cromo em cima + 78 da barra de abas + 56 de espia. A espia encolheu, nao
     sumiu: 22 de gap + 34 do titulo da primeira linha, que e o suficiente pra aparecer texto
     cortado embaixo do billboard — e texto cortado e o sinal de "rola" que a pessoa entende.
     O que se perdeu foi a faixa de 70px do primeiro CARD; o teste disso e a rolagem, nao o
     print: ninguem para numa tela onde um titulo nasce pela metade.
     🪤 O piso de 300px fica: em paisagem ou num 5s o teto cai abaixo disso e o billboard viraria
     tarja de verdade. */
  max-height:max(300px, calc(100vh - 313px));
  max-height:max(300px, calc(100svh - 313px))}
/* o degradê não é enfeite: é o que mantém o texto legível sobre imagem em MOVIMENTO */
.ap-shell .ap-bb__cx{position:absolute; left:0; right:0; bottom:0; padding:64px 16px 18px;
  display:flex; flex-direction:column; gap:8px;
  background:linear-gradient(180deg, transparent, oklch(14% 0.012 58 / .93) 62%, var(--ap-pp))}
.ap-shell .ap-bb__pq{font-size:15.5px; line-height:1.35; color:var(--ap-tinta2)}
.ap-shell .ap-bb__pq b{color:var(--ap-ouro); font-weight:600}
.ap-shell .ap-bb__nome{font-family:var(--ap-serif); font-size:29px; line-height:1.08; font-weight:700}
.ap-shell .ap-bb__ang{font-size:17px; line-height:1.35; color:var(--ap-tinta2)}
.ap-shell .ap-bb__bt{margin-top:6px; min-height:62px; border-radius:var(--ap-r-btn);
  background:var(--ap-ouro); color:var(--ap-ouro-esc); font-size:20px; font-weight:800;
  letter-spacing:-.012em; display:flex; align-items:center; justify-content:center;
  animation:apBbHalo 2.5s ease-in-out infinite}
@keyframes apBbHalo{
  0%,100%{box-shadow:0 10px 24px -14px oklch(83% 0.107 86 / .7), 0 0 0 0 oklch(83% 0.107 86 / .38)}
  50%{box-shadow:0 16px 38px -10px oklch(83% 0.107 86 / .9), 0 0 0 9px oklch(83% 0.107 86 / 0)}}
@media (prefers-reduced-motion: reduce){
  .ap-shell .ap-bb__bt{animation:none; box-shadow:0 12px 30px -12px oklch(83% 0.107 86 / .72)}}

/* ── a linha ── o título dela É o argumento de venda, não um rótulo de categoria ── */
.ap-shell .ap-li{display:flex; flex-direction:column; gap:9px; position:relative}
/* ➡️ A SETA QUE CONVIDA (10/09/2026). Ela existe pra CONTAR que a linha continua fora da tela —
   a barra de rolagem é escondida e o público não descobre sozinho. Por isso é sempre visível, e
   não um enfeite de `:hover`: metade dele está no celular, onde hover não existe.
   📏 48px de alvo, o mínimo confortável pra dedo de 60 anos, com o ícone menor dentro. */
/* 📏 62px DE ALVO, que é o piso de toque da casa (`--ap-toque`) — a primeira versão tinha 48 e a
   varredura mostrou o preço: errar a seta por 7px cai NO CARD, que abre a compra da cena. O
   círculo desenhado continua com 46px; quem cresce é a área que o dedo acerta, invisível.
   📐 ANCORADA NO CARD, não no bloco: `top:50%` media a altura do `.ap-li` INTEIRO — título e
   subtítulo incluídos — e como esse cabeçalho tem 1 ou 2 linhas conforme a linha, cada seta
   parava numa altura diferente e nenhuma no meio do card. Medindo a partir do FUNDO, que é onde o
   rolo termina, todas caem no mesmo lugar: 4px de padding + metade da altura do card (187px). */
.ap-shell .ap-seta{position:absolute; top:auto; bottom:calc(4px + 93.5px - 31px); z-index:3;
  width:62px; height:62px; padding:0; display:flex; align-items:center; justify-content:center;
  border:0; background:none; cursor:pointer; color:var(--ap-ouro); -webkit-tap-highlight-color:transparent}
.ap-shell .ap-seta i{width:46px; height:46px; display:flex; align-items:center; justify-content:center;
  border:1px solid oklch(52% 0.06 82 / .5); border-radius:50%;
  background:oklch(12% 0.012 58 / .82); backdrop-filter:blur(3px);
  box-shadow:0 3px 12px oklch(0% 0 0 / .45); transition:transform 140ms var(--ap-e), background 140ms var(--ap-e)}
.ap-shell .ap-seta svg{width:24px; height:24px; display:block}
@media (hover:hover){
  .ap-shell .ap-seta:hover i{background:oklch(18% 0.02 58 / .92); transform:scale(1.06)}
}
.ap-shell .ap-seta:active i{transform:scale(.94)}
/* as bordas do rolo sangram 16px pra fora (margin:0 -16px), então a seta acompanha esse sangramento */
.ap-shell .ap-seta--esq{left:-4px}
.ap-shell .ap-seta--dir{right:-4px}
@media (prefers-reduced-motion: reduce){ .ap-shell .ap-seta i{transition:none} }
.ap-shell .ap-li__t{font-size:18px; font-weight:700; line-height:1.25; color:var(--ap-tinta)}
.ap-shell .ap-li__t em{font-style:normal; color:var(--ap-ouro)}
.ap-shell .ap-li__s{margin-top:-4px; font-size:15.5px; line-height:1.35; color:var(--ap-tinta3)}
/* 🎞️ 25/09/2026 — O TRILHO ARRASTA COMO STORIES (Lucas: "adicionar a função de conseguir
   arrastar os trilhos só arrastando o dedo... eu consigo só arrastar pro lado como se fosse
   arrastando stories do Instagram").
   🔴 `proximity` NO LUGAR DE `mandatory`, e essa e a troca que muda o toque inteiro: com
   `mandatory` o navegador e OBRIGADO a terminar todo gesto encaixado num card. Na pratica ele
   segura o trilho no eixo X assim que o dedo encosta — arrasto curto volta pro card de origem
   (parece travado) e o gesto diagonal, que e como se rola uma pagina de verdade, fica preso na
   horizontal em vez de descer a pagina. `proximity` so encaixa quando a pessoa PARA perto de um
   card: o arrasto livre continua livre e o alinhamento continua acontecendo.
   📱 `overscroll-behavior-x:contain` impede que o fim do trilho vire o gesto de VOLTAR do
   navegador — chegar na ultima cena e continuar arrastando saia do app.
   📱 `touch-action:pan-x pan-y pinch-zoom` diz explicitamente que os DOIS eixos valem aqui. O
   padrao (`auto`) ja deveria permitir, mas com um scroller horizontal dentro de um vertical o
   Chrome do Android decide o eixo no primeiro milimetro e erra pro lado do filho. Declarado, o
   dedo que sobe sobe e o dedo que vai pro lado vai pro lado. */
.ap-shell .ap-rolo{display:flex; gap:10px; overflow-x:auto; scroll-snap-type:x proximity;
  overscroll-behavior-x:contain; touch-action:pan-x pan-y pinch-zoom;
  scrollbar-width:none; margin:0 -16px; padding:1px 16px 4px}
.ap-shell .ap-rolo::-webkit-scrollbar{height:0}

/* ── o card dentro do rolo: mesmo elemento da grade, outra forma ── */
.ap-shell .ap-rolo .ap-cena{flex:0 0 150px; scroll-snap-align:start; border-radius:14px}
.ap-shell .ap-rolo .ap-cena video,
.ap-shell .ap-rolo .ap-cena img{aspect-ratio:4/5}

/* ✝️ A FOLHA DO NOME (js/carta-app.js) — a compra de figura religiosa por crédito.
   Fica FORA do `.ap-shell` de propósito: ela é `fixed` na janela, como um diálogo, e não uma
   camada dentro da coluna do app. Campos e botão em 48px+ porque quem compra esta oferta é gente
   mais velha, e fonte 16px no input porque abaixo disso o iOS dá zoom sozinho ao focar. */
.cta-folha{position:fixed; inset:0; z-index:120; background:rgba(16,12,8,.74);
  display:flex; align-items:center; justify-content:center; padding:18px; overflow:auto}
.cta-folha__caixa{position:relative; background:#fffdf8; color:#2a2118; border-radius:20px;
  max-width:360px; width:100%; padding:22px; margin:auto; box-shadow:0 26px 70px rgba(0,0,0,.45)}
.cta-folha__x{position:absolute; top:6px; right:10px; width:40px; height:40px; border:0;
  background:none; color:#9a8a72; font-size:26px; line-height:1; cursor:pointer}
.cta-folha__foto{width:112px; aspect-ratio:9/16; object-fit:cover; border-radius:12px; display:block}
.cta-folha__nome{font-size:19px; font-weight:700; margin:12px 0 2px}
.cta-folha__desc{font-size:13.5px; color:#7a6a55; margin:0 0 16px}
.cta-folha__rot{display:block; font-size:14.5px; font-weight:700; margin-bottom:7px}
.cta-folha__campo{width:100%; min-height:50px; padding:0 12px; border:1px solid #e3d9c6;
  border-radius:11px; font-size:16px; font-family:inherit; color:#2a2118; background:#fff;
  box-sizing:border-box}
.cta-folha__erro{min-height:18px; margin:9px 0 2px; color:#b4342a; font-size:13px}
.cta-folha__bt{width:100%; min-height:52px; border:0; border-radius:13px; background:#1e3a5f;
  color:#fff; font-size:15.5px; font-weight:700; font-family:inherit; cursor:pointer}
.cta-folha__bt[disabled]{opacity:.65}
.cta-folha__pe{font-size:12.5px; color:#9a8a72; text-align:center; margin:11px 0 0}
/* 🪤 O CARD LARGO NÃO CABE NUM ROLO, e virou um amontoado ilegível na 1ª montagem (print do
   Lucas, 10/09 13h34). Ele nasceu pra ocupar a LINHA INTEIRA da grade (`grid-column:1/-1`), com
   miniatura de 74–92px e o texto ao lado; espremido em 150px, o nome quebrava letra a letra.
   Dentro do rolo ele volta a ser o que todo card do rolo é: vídeo em cima, nome embaixo. */
.ap-shell .ap-rolo .ap-cena--larga{display:block; padding:0; gap:0; grid-column:auto}
.ap-shell .ap-rolo .ap-cena--larga video{width:100%; aspect-ratio:4/5; border-radius:0}
.ap-shell .ap-rolo .ap-cena--larga .ap-cena__cx{position:absolute; left:0; right:0; bottom:0;
  padding:24px 10px 9px; background:linear-gradient(180deg, transparent, oklch(8% 0.010 58 / .9))}
.ap-shell .ap-rolo .ap-cena--larga .ap-cena__nome{position:static; padding:0; background:none;
  font-size:16px; line-height:1.2; color:#fff}
/* 🔇 a descrição some no rolo: no card largo ela explicava o produto, aqui não cabe em 150px
   sem virar parede de texto. O argumento inteiro está na folha, a um toque. */
/* 🪤 `.ap-cena__sub`, e NÃO `.ap-cena__desc`: a classe que eu escrevi aqui em 10/09 de manhã não
   existe em lugar nenhum do repositório, então a regra nunca escondeu nada e a descrição de 17px
   continuou empilhada dentro do card de 150px. Achado da varredura de 10/09 17h. */
.ap-shell .ap-rolo .ap-cena--larga .ap-cena__sub{display:none}

/* 🖱️ ARRASTAR COM O MOUSE: no desktop não há dedo, e rolo sem barra visível parecia travado —
   o Lucas não conseguia alcançar as cenas fora da tela. O cursor avisa que dá pra puxar. */
.ap-shell .ap-rolo{cursor:grab}
.ap-shell .ap-rolo.puxando{cursor:grabbing; scroll-snap-type:none; scroll-behavior:auto}
.ap-shell .ap-rolo.puxando .ap-cena{pointer-events:none}

/* 🔁 o ECO é um card igual a qualquer outro do rolo — herda `.ap-rolo .ap-cena` inteiro. Fica
   aqui só como aviso: nada nele pode ficar diferente do original, senão a costura do loop
   aparece exatamente no ponto em que ela precisa ser invisível. */
.ap-shell .ap-rolo .ap-eco{}

@media (prefers-reduced-motion: reduce){
  .ap-shell .ap-pag,
  .ap-shell .ap-obra::before,
  .ap-shell .ap-luz,
  .ap-shell .ap-selo--producao i,
  .ap-shell .ap-item__capa--obra::after{animation:none}
  .ap-shell .ap-bt,
  .ap-shell .ap-folha__cx,
  .ap-shell .ap-folha__fundo,
  .ap-shell .ap-barra i{transition:none}
}

/* ═════════════════════════════════════════════════════════════════════════════════════════════
   FOLHA DA CENA — DIREÇÃO "PALCO"   (aprovada pelo Lucas em 17/08/2026, 23h04)

   Por que a folha antiga foi refeita, em um número: ela mostrava o vídeo em 148×265 enquanto a
   MINIATURA do card que a pessoa acabou de tocar tem 171×304 (medido nos dois em 390×740). Tocar
   no card ENCOLHIA o produto em 13% — a folha existe pra ver a cena melhor e fazia o contrário.
   Aqui o vídeo vai a 248×415: +118% de área. Em 360×640 (o celular baixo do público) vai a
   198×327, contra a miniatura de 156×277.

   ⚠️ ORDEM IMPORTA: este bloco fica no FIM do arquivo de propósito. Vários seletores daqui empatam
   em especificidade com as regras-base lá de cima e ganham por ordem — é isso que evita !important
   espalhado. Mover este bloco pra cima quebra a folha em silêncio.
   ⚠️ E o `transform` do `.ap-folha__cx` NUNCA é redeclarado aqui: ele empataria com
   `.ap-folha.aberta .ap-folha__cx{transform:none}` e a folha simplesmente não subiria.
   ═════════════════════════════════════════════════════════════════════════════════════════════ */

/* 📐 A ALTURA DO VÍDEO É CONTA, NÃO GOSTO — mesmo raciocínio do `.ap-player` (css/tela7-app.css:
   210-221). A folha tem max-height:88%, então o teto do vídeo é 88dvh menos o que os outros blocos
   ocupam. `vh` vem antes do `dvh` de propósito: em navegador que não conhece dvh a declaração
   inteira cai, e sem a primeira o palco nasceria sem altura.
   🔴 O piso de 300px não é estético: abaixo dele o vídeo da folha fica MENOR que a miniatura de
   171×304 do card (medido), e aí tocar no card encolhe o produto — que é exatamente o bug que
   esta revisão veio consertar. */
.ap-shell [data-folha-alvo="cena"] .ap-palco--cena{
  flex:0 0 auto; align-self:center;
  height:clamp(var(--cena-min,300px), calc(88vh - var(--cena-resto)), var(--cena-max,460px));
  width:min(100%, calc(clamp(var(--cena-min,300px), calc(88vh - var(--cena-resto)), var(--cena-max,460px)) * .5625));
  border-radius:var(--ap-r-card); border:1px solid oklch(38% 0.030 72)}
.ap-shell [data-folha-alvo="cena"] .ap-palco--cena{
  height:clamp(var(--cena-min,300px), calc(88dvh - var(--cena-resto)), var(--cena-max,460px));
  width:min(100%, calc(clamp(var(--cena-min,300px), calc(88dvh - var(--cena-resto)), var(--cena-max,460px)) * .5625))}

/* faixa de preço — 17/08, pedido do Lucas: "dar mais destaque para o preço" e o rótulo "menor e
   pequenininho". O que mudou, em números: preço 26px → 36px e rótulo 17px → 13px, então a razão
   entre os dois saltou de 1,5× para 2,8× — é a razão, não o tamanho isolado, que faz o olho ir
   direto ao valor. O rótulo continua ali porque é ele que desarma "isto é assinatura?", mas em
   voz baixa: cor de meta e caixa alta espaçada, que lê como etiqueta, não como frase.
   Nasce [hidden] — as homenagens sem preço somem com o bloco inteiro. */
.ap-shell [data-folha-alvo="cena"] .ap-cena2__preco{
  display:flex; flex-direction:column; align-items:center; gap:2px; width:100%;
  background:oklch(20% 0.024 64); border:1px solid oklch(42% 0.055 82);
  border-radius:var(--ap-r-card); padding:10px 16px 11px; text-align:center}
.ap-shell [data-folha-alvo="cena"] .ap-cena2__preco[hidden]{display:none}
/* 🔇 uma linha só, apagada. A 1ª tentativa foi caixa alta com letter-spacing: virou um BLOCO de
   3 linhas ao lado do número — "pequenininho" pede pouco espaço, não só fonte pequena.
   🔴 09/09/2026: os 13px violavam o piso de 15,5px desta casa, que existe porque quem lê esta
   tela lê no celular e costuma ter mais de 50 anos. Subir a fonte sozinho quebraria o `nowrap` —
   então quem encolheu foi a FRASE, no HTML: "sem assinatura" já estava dito em "pagamento único". */
.ap-shell [data-folha-alvo="cena"] .ap-cena2__preco span{
  font-size:15.5px; line-height:1.25; color:var(--ap-tinta3); white-space:nowrap; order:2}
.ap-shell [data-folha-alvo="cena"] .ap-cena2__preco b{order:1}
/* 🔢 preço NUNCA em Georgia: os algarismos old-style descem da linha e "R$ 19,90" lê torto */
.ap-shell [data-folha-alvo="cena"] .ap-cena2__preco b{
  font-family:system-ui,-apple-system,"Segoe UI",Roboto,Arial,sans-serif;
  font-size:36px; font-weight:800; line-height:1; letter-spacing:-.025em; color:var(--ap-ouro);
  font-variant-numeric:tabular-nums lining-nums; white-space:nowrap;
  text-shadow:0 0 22px oklch(83% 0.107 86 / .22)}

.ap-shell [data-folha-alvo="cena"] .ap-cena2__bt{width:100%; flex:0 0 auto}

/* ✨ BOTÃO PULSANTE (Lucas, 17/08: "efeito pulsante e brilho sem dó pra ficar bem chamativo").
   Três camadas, e cada uma resolve uma coisa diferente:
   1. 'apBotaoPulsa' — halo dourado que respira em 2,2s. É 'box-shadow' + 'scale', as duas únicas
      propriedades que o navegador anima na GPU: animar 'width'/'padding' faria a folha inteira
      recalcular layout 60×/s e engasgar no celular velho deste público.
   2. 'apBotaoBrilho' — o brilho que VARRE o botão. Ciclo de 3,4s com o clarão ocupando só ~18% dele:
      o resto é pausa. Brilho contínuo vira ruído e o olho para de ver em 10 segundos.
   3. o '<span>' com 'z-index:2' — sem ele o clarão passaria POR CIMA de "Fazer esta homenagem" e
      apagaria o texto no meio da varredura.
   ⚠️ 'overflow:hidden' + 'isolation:isolate' seguram o clarão dentro do raio de 999px; sem o
   isolation ele escapa por cima da faixa de preço em Safari. */
.ap-shell [data-folha-alvo="cena"] .ap-bt--pulsa{
  position:relative; overflow:hidden; isolation:isolate;
  animation:apBotaoPulsa 2.2s ease-in-out infinite;
  will-change:transform, box-shadow}
.ap-shell [data-folha-alvo="cena"] .ap-bt--pulsa > span{position:relative; z-index:2}
.ap-shell [data-folha-alvo="cena"] .ap-bt--pulsa::after{
  content:""; position:absolute; top:-40%; bottom:-40%; left:0; width:46%; z-index:1;
  pointer-events:none; transform:translateX(-160%) skewX(-18deg);
  background:linear-gradient(90deg, transparent, oklch(100% 0 0 / .55) 30%, oklch(100% 0 0 / 1) 50%, oklch(100% 0 0 / .55) 70%, transparent);
  animation:apBotaoBrilho 3.4s ease-in-out infinite}
@keyframes apBotaoPulsa{
  0%,100%{transform:scale(1);     box-shadow:0 8px 20px -8px oklch(83% 0.107 86 / .60), 0 0 0 0 oklch(85% 0.115 88 / .55), 0 0 26px -4px oklch(83% 0.107 86 / .45)}
  50%    {transform:scale(1.032); box-shadow:0 18px 52px -6px oklch(83% 0.107 86 / .95), 0 0 0 15px oklch(85% 0.115 88 / 0),  0 0 64px -2px oklch(83% 0.107 86 / .80)}}
@keyframes apBotaoBrilho{
  0%,58%{transform:translateX(-160%) skewX(-18deg)}
  86%,100%{transform:translateX(360%) skewX(-18deg)}}
/* 🚦 quem pediu menos movimento no sistema não leva pulso nenhum — mas continua com o halo, senão
   o botão principal fica MENOS visível justamente pra quem já tem dificuldade com a tela. */
@media (prefers-reduced-motion: reduce){
  .ap-shell [data-folha-alvo="cena"] .ap-bt--pulsa{
    animation:none; box-shadow:0 10px 30px -8px oklch(83% 0.107 86 / .7)}
  .ap-shell [data-folha-alvo="cena"] .ap-bt--pulsa::after{animation:none; opacity:0}
}
/* 🔍 nota de apoio a 17px, não 14,5: é a linha que diz que ainda dá pra desistir, e o público
   desta oferta é 45+ — é justamente ela que ninguém consegue ler pequena. */
.ap-shell [data-folha-alvo="cena"] .ap-cena2__nota{
  font-size:17px; line-height:1.35; color:var(--ap-tinta3); margin:0; text-align:center}

/* 🅱️ PALCO — o vídeo sangra até as bordas da folha: a margem negativa anula o padding lateral e o
   raio de cima casa com o raio da própria folha (24px), senão aparece um fio da cor da folha. */
.ap-shell [data-folha-alvo="cena"] .ap-cx--palco{
  /* 🔬 MEDIDO: com 210 sobravam 5px de rolagem, e a faixa de preço engordou 21px quando o número
     foi de 26px pra 36px. 236 = 215 (o real medido) + esses 21. */
  --cena-resto:236px;
  gap:0; padding:0 16px 16px}
.ap-shell [data-folha-alvo="cena"] .ap-palco--sangra{
  width:calc(100% + 32px); max-width:none; margin:0 -16px; align-self:stretch;
  border:0; border-radius:24px 24px 0 0}
/* a largura da CAIXA é a folha inteira; o vídeo nítido continua em contain no meio (9:16, sem
   corte) e as laterais são a cópia borrada de si mesmo — é ela que faz o efeito de palco. */
.ap-shell [data-folha-alvo="cena"] .ap-palco--sangra{width:calc(100% + 32px)}
.ap-shell [data-folha-alvo="cena"] .ap-palco__veu{
  position:absolute; left:0; right:0; bottom:0; height:62%; z-index:3; pointer-events:none;
  background:linear-gradient(180deg, transparent 0%, oklch(10% 0.010 58 / .55) 42%,
    oklch(9% 0.010 58 / .88) 78%, oklch(8% 0.008 58 / .96) 100%)}
.ap-shell [data-folha-alvo="cena"] .ap-palco__legenda{
  position:absolute; left:0; right:0; bottom:0; z-index:4; padding:0 18px 16px; text-align:center}
/* 🔴 o nome fica SOBRE imagem que muda (céu claro, praia): o véu acima garante o fundo, e a sombra
   é a segunda trava — sem ela "A escadaria dourada" sobre nuvem branca some. */
.ap-shell [data-folha-alvo="cena"] .ap-palco__h{
  font-size:25px; line-height:1.14; color:oklch(99% 0.006 80); margin:0;
  text-shadow:0 2px 10px oklch(6% 0.006 58 / .85), 0 1px 2px oklch(6% 0.006 58 / .9)}
.ap-shell [data-folha-alvo="cena"] .ap-palco__sub{
  font-size:17px; line-height:1.35; color:oklch(88% 0.010 76); margin:4px 0 0;
  text-shadow:0 1px 6px oklch(6% 0.006 58 / .9)}
.ap-shell [data-folha-alvo="cena"] .ap-palco__pe{
  display:flex; flex-direction:column; gap:12px; padding-top:14px}
/* ✕ POR CIMA do vídeo: precisa de disco próprio pra sobreviver a um quadro claro.
   🪟 19/08 01h30 (Lucas): o disco a 8px caía SOBRE a curva do raio (24px) e lia como elemento
   quebrado — agora ele senta a 12px, na área plana do quadro, menor e concêntrico. */
/* 👆 60px, nao 52px (26/08/2026): o alvo minimo da area do cliente e 60 (test/e2e-tela7.mjs), e
   este X e o unico jeito de sair da folha em quem nao usa gesto de voltar. O circulo de vidro do
   ::before continua com 38px — o que cresce e a AREA DE TOQUE, nao o desenho. */
.ap-shell [data-folha-alvo="cena"] .ap-folha__x--sobre{
  top:12px; right:12px; width:60px; height:60px; z-index:6;
  color:oklch(99% 0.004 80); font-size:22px}
.ap-shell [data-folha-alvo="cena"] .ap-folha__x--sobre::before{
  content:""; position:absolute; width:38px; height:38px; border-radius:50%;
  background:oklch(10% 0.008 58 / .62); border:1px solid oklch(100% 0 0 / .22);
  backdrop-filter:blur(6px); -webkit-backdrop-filter:blur(6px); z-index:-1}
/* a alça "isto desce pra baixo" morre com a folha flutuante — o sinal seria mentira */
.ap-shell [data-folha-alvo="cena"] .ap-folha__alca--sobre{display:none}

/* 🪟 A FOLHA DA HOMENAGEM FLUTUA NO MEIO (pedido do Lucas, 19/08 01h30): antes era bottom-sheet
   presa na base; agora é modal centrado — sobe 16px + fade na entrada. Só a folha da CENA:
   conta/ajuda continuam sheets (lá o conteúdo é lista, o padrão de baixo segue certo).
   ⚠️ Empate de especificidade com `.ap-folha.aberta .ap-folha__cx{transform:none}` (linha ~557):
   estas regras PRECISAM vir depois no arquivo — é a ordem que decide o vencedor. */
.ap-shell [data-folha-alvo="cena"] .ap-folha__cx{
  left:14px; right:14px; bottom:auto; top:50%; margin:0 auto; max-width:400px;
  border-bottom:1px solid var(--ap-linha); border-radius:24px;
  transform:translateY(calc(-50% + 16px)); opacity:0;
  transition:transform 320ms var(--ap-e), opacity 240ms var(--ap-e)}
.ap-shell .ap-folha[data-folha-alvo="cena"].aberta .ap-folha__cx{
  transform:translateY(-50%); opacity:1}
.ap-shell [data-folha-alvo="cena"] .ap-palco--sangra{border-radius:24px 24px 0 0}

/* ═══════════════════════ SEGUNDO HOST: a página que ROLA (`/acompanhar`) ═══════════════════════
   26/08/2026 — a casca nasceu na tela 7, que é uma `.screen` do tamanho da viewport com rolagem
   INTERNA (`.screen__scroll`). Por isso as duas barras são `position:absolute`: elas se ancoram na
   tela, que não se move.
   🪤 No `/acompanhar` quem rola é a PÁGINA. `absolute` ali gruda a barra no fim do documento — a
   navegação sumiria de vista assim que a pessoa rolasse. Só neste host as barras viram `fixed`.
   É a ÚNICA diferença entre os dois; tudo o mais (paleta, cards, folhas, tipografia) é o mesmo
   arquivo, o que é o ponto inteiro de ter trocado `#screen-7` por `.ap-shell`. */
.ap-shell--pagina{min-height:100dvh}
.ap-shell--pagina .ap-topo,
.ap-shell--pagina .ap-abas{position:fixed}
/* as barras cobrem a largura toda; o conteúdo continua na coluna de 520px do `.ac` */
.ap-shell--pagina .ap-abas{padding-bottom:env(safe-area-inset-bottom)}
/* 📏 o conteúdo precisa nascer ABAIXO da barra de cima e terminar ACIMA da de baixo, senão o
   primeiro título fica atrás do vidro fosco e o último botão fica intocável embaixo das abas.
   60px e 64px são as alturas declaradas lá em cima — mexeu numa, mexe aqui. */
/* 🪤 `body.` na frente NAO e enfeite: o `/acompanhar` declara `.pg .ac{padding:28px 18px ...}` num
   <style> inline, que vem DEPOIS deste arquivo no <head>. Especificidade empatada (2 classes) =
   ganha o ultimo, e o conteudo nascia por baixo da barra de vidro. `body` + 2 classes desempata. */
body.ap-shell--pagina .ac{padding-top:calc(60px + 22px)}
body.ap-shell--pagina:has(.ap-abas:not([hidden])) .ac{
  padding-bottom:calc(64px + 24px + env(safe-area-inset-bottom))}
