/* style.css - identidade visual do site. Mobile-first, uso com uma mao. */

:root {
  --verde:      var(--rb-verde-500);
  --verde-700:  var(--rb-verde-700);
  --verde-900:  var(--rb-verde-900);
  --amarelo:    var(--rb-amarelo);
  --vermelho:   var(--rb-vermelho);
  --creme:      var(--rb-creme);
  /* os dois eram um SEGUNDO valor, quase igual ao do identidade-ribamar.css
     e divergente dele: #12210A vs #12200C, #4F5749 vs #5C6B52. Duas tintas e
     dois cinzas no mesmo ecossistema. Agora sao alias, e o valor mora num
     lugar so. O cinza continua em #4F5749 (7,02:1 sobre creme, AAA): quem
     subiu foi o token compartilhado, que estava em 5,33:1 - trocar o
     consumidor teria rebaixado todo o corpo de texto deste produto. */
  --tinta: var(--rb-tinta);
  --cinza: var(--rb-tinta-fraca);

  --transicao: 220ms cubic-bezier(0.22, 1, 0.36, 1);
  --toque-min: 52px; /* alvo AAA de area de toque (era 48px) - publico mais velho, uso na rua */
  --largura-conteudo: 460px;

  /* Poppins e a unica familia do site: redonda, familiar, leitura imediata -
     e o que funciona melhor pro publico. --fonte-display e --fonte-corpo
     apontam pra mesma fonte hoje, mas ficam separadas pra manter a intencao
     semantica (titulo vs. corpo) se um dia precisar divergir. */
  --fonte-display: "Poppins", -apple-system, "Segoe UI", sans-serif;
  --fonte-corpo: "Poppins", -apple-system, "Segoe UI", sans-serif;

  /* escala de espacamento - todo padding/margin do site usa um desses
     degraus. Espacamento inconsistente e o que mais denuncia acabamento
     apressado. */
  --esp-1: 4px;
  --esp-2: 8px;
  --esp-3: 12px;
  --esp-4: 16px;
  --esp-6: 24px;
  --esp-8: 32px;
  --esp-12: 48px;
  --esp-16: 64px;
  --esp-24: 96px;

  /* sombras em 3 camadas - uma sombra so fica plastica, tres da profundidade
     real. -cima-md e a mesma curva de -lg com o Y invertido, pra elementos
     fixos na base (ex.: rodape sticky).
     ESCOPO: so sobreposicao real - toast, rodape fixo, overlay. O que o
     dedo "pega" (palco, chip, botao da etapa, card de modelo) usa a sombra
     DURA da secao "relevo duro" mais abaixo.
     A tinta e 18,32,12 = --rb-tinta, a mesma tinta do texto: sombra difusa
     e o texto escurecendo o que esta atras. Nao confundir com
     --sombra-tinta (18,43,1), que e a tinta da sombra dura da marca. */
  --sombra-md: 0 2px 4px rgba(18, 32, 12, .05), 0 6px 12px rgba(18, 32, 12, .06), 0 12px 24px rgba(18, 32, 12, .05);
  --sombra-lg: 0 4px 8px rgba(18, 32, 12, .05), 0 12px 24px rgba(18, 32, 12, .07), 0 24px 48px rgba(18, 32, 12, .06);
  --sombra-cima-md: 0 -2px 4px rgba(18, 32, 12, .05), 0 -6px 12px rgba(18, 32, 12, .06), 0 -12px 24px rgba(18, 32, 12, .05);

  --ease-capa: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-crossfade: cubic-bezier(0.4, 0, 0.2, 1);
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--creme);
  color: var(--tinta);
  font-family: var(--fonte-corpo);
  font-weight: 600; /* 500 fica fino demais em texto pequeno sob luz forte - AAA de legibilidade pede 600 abaixo de 17px */
  -webkit-tap-highlight-color: transparent;
}

body {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
}

h1, h2, h3 {
  font-family: var(--fonte-display);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: -0.01em; /* Poppins e larga, nao aguenta o tracking apertado que a Anton aguentava */
  line-height: 1.18;
  color: var(--verde-900);
  margin: 0 0 var(--esp-2);
}

p { margin: 0 0 var(--esp-3); color: var(--cinza); font-weight: 600; line-height: 1.65; }

main { flex: 1; display: flex; flex-direction: column; }

.tela {
  width: 100%;
  max-width: var(--largura-conteudo);
  margin: 0 auto;
  padding: var(--esp-4) var(--esp-4) var(--esp-8);
  display: flex;
  flex-direction: column;
}
.tela[hidden] { display: none; }

/* a capa e uma experiencia full-bleed (sticky + scroll proprio) - nao cabe
   na coluna estreita com padding que todo o resto do app usa */
.tela--capa {
  max-width: none;
  padding: 0;
}

.tela__topo {
  display: flex;
  align-items: center;
  gap: var(--esp-3);
  margin-bottom: var(--esp-4);
}
.tela__topo h2 { margin: 0; font-size: 20px; } /* ~10% menor: Poppins ocupa mais largura que a Anton no mesmo corpo */

/* ---------- botoes ---------- */

.btn {
  min-height: var(--toque-min);
  padding: var(--esp-3) var(--esp-4);
  border-radius: 12px;
  border: none;
  font-family: var(--fonte-corpo);
  font-weight: 700;
  font-size: 16px;
  cursor: pointer;
  transition: transform var(--transicao), box-shadow var(--transicao), opacity var(--transicao);
  -webkit-tap-highlight-color: transparent;
}
.btn:disabled { opacity: 0.45; cursor: not-allowed; }

/* ---------- relevo duro - a assinatura da marca ----------
   Blur 0, spread 0, offset por TAMANHO do elemento, y = round(1,3x). Fixa a
   direcao da luz: sempre do mesmo canto, em todo elemento do sistema.
   Degraus: 3px 4px (pequeno, ou grande pressionado) - 4px 5px (medio) -
   7px 9px (bloco grande) - 10px 13px (bloco grande levantado).
   O que se move no hover/active e o ELEMENTO, nao a sombra: ela fica
   praticamente parada na pagina (varia ~1px). Aumentar so o box-shadow da
   outro efeito - parece a sombra crescendo, nao o objeto levantando. */

.btn--primario {
  background: var(--verde-700);
  color: var(--creme);
  box-shadow: 4px 5px 0 rgba(var(--sombra-tinta), var(--sombra-alfa));
}
.btn--primario:active:not(:disabled) {
  transform: translate(3px, 4px);
  box-shadow: 3px 4px 0 rgba(var(--sombra-tinta), var(--sombra-alfa));
}
@media (hover: hover) {
  .btn--primario:hover:not(:disabled) {
    transform: translate(-2px, -3px);
    box-shadow: 7px 9px 0 rgba(var(--sombra-tinta), var(--sombra-alfa));
  }
}

.btn--secundario {
  background: transparent;
  color: var(--verde-700);
  border: 2px solid var(--verde-700);
}
/* sem sombra dura (botao de contorno nao esta na lista), mas o movimento
   segue o mesmo vetor do resto do sistema: -2px,-3px */
.btn--secundario:hover:not(:disabled) { transform: translate(-2px, -3px); }

.btn--texto {
  background: none;
  color: var(--cinza);
  text-decoration: underline;
  min-height: auto;
  padding: var(--esp-2);
}

.btn--grande { width: 100%; font-size: 17px; padding: var(--esp-3) var(--esp-4); }

/* ---------- foco visivel ----------
   Anel verde-700: 6,13:1 sobre creme e 6,57:1 sobre branco - os dois fundos
   de praticamente todo interativo deste produto. O amarelo da marca daria
   1,31:1 sobre creme e sumiria; fica reservado ao que assenta sobre o
   verde-900 da capa (6,57:1). A cor do anel se escolhe pelo que esta
   ADJACENTE, nunca por ser cor de marca. */
.btn:focus-visible,
.btn-voltar:focus-visible,
.card-modelo:focus-visible,
.toggle-formato__opcao:focus-visible,
.campo-texto:focus-visible,
.dropzone:focus-visible {
  outline: 3px solid var(--verde-700);
  outline-offset: 3px;
}

/* sobre o verde-900 da capa o verde-700 daria 1,4:1 - la o anel e amarelo */
.capa__progresso-item:focus-visible,
.capa__pular:focus-visible {
  outline: 3px solid var(--amarelo);
  outline-offset: 3px;
}
/* nas etapas 2/3 o palco vira creme e o "pular" troca de anel junto com a
   variante de cor que o JS ja alterna */
.capa__pular--sobre-creme:focus-visible {
  outline-color: var(--verde-700);
}

.btn-voltar {
  width: var(--toque-min);
  height: var(--toque-min);
  border-radius: 50%;
  border: none;
  background: rgba(24, 144, 56, 0.08);
  color: var(--verde-700);
  font-size: 20px;
  cursor: pointer;
  flex: none;
  transition: background var(--transicao);
}
.btn-voltar:hover { background: rgba(24, 144, 56, 0.16); }

/* ---------- landing (capa) ---------- */

/* abertura editorial em 3 etapas, dirigida por rolagem. Tecnica: position
   sticky + IntersectionObserver (nao animation-timeline, nem scroll listener
   - ve js/app.js pro raciocinio completo). Estrutura obrigatoria:
     .capa > .palco (sticky, 100dvh) + tres .gatilho (100dvh cada, invisiveis)
   Cada .gatilho da altura de rolagem; o observer aplica etapa-1/2/3 no
   .palco conforme o gatilho correspondente cruza 50% de interseccao. Como
   tudo e transition (nao keyframes), rolar de volta reverte sozinho. */

/* visualmente oculto mas presente pra leitor de tela - avisa que a capa rola
   antes que a pessoa dependa so da percepcao visual da animacao */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.capa { position: relative; }

.palco {
  position: sticky;
  top: 0;
  height: 100dvh;
  overflow: hidden;
  /* creme FIXO. O verde da etapa 1 vem do .capa__fundo, que ja cobre
     inset:0, ja e verde-900 e ja faz fade de opacity - transicionar
     background-color aqui repintava a viewport inteira a cada frame por
     700ms (em DPR 3 sao ~12 MB de re-textura por frame, ~42 frames, duas
     vezes por percurso). Trocado por uma unica transicao de opacity que ja
     existia. Estados inicial e final identicos; o meio da transicao clareia
     um pouco antes, porque agora e um fade em vez de dois empilhados. */
  background: var(--creme);
  padding-top: env(safe-area-inset-top);
  padding-bottom: env(safe-area-inset-bottom);
  /* borda perimetral fina - mesma linguagem das artes geradas (gerar_card.py) */
  box-shadow: inset 0 0 0 5px var(--amarelo);
}

/* ---------- capa etapa 1: cenario (so CSS, sem imagem nova) ----------
   Vocabulario das artes do designer, medido de
   card-campomaior-stories-alpha.png e card-geral-feed-alpha.png em
   15/08/2026. Saiu o vocabulario da marca anterior: as 4 estrelas de
   clip-path, o anel radial de 220% e as tres faixas diagonais.
   TUDO aqui e estatico e mora dentro do .capa__fundo, que ja e promovido
   (will-change:opacity): rasteriza uma vez, fica em cache como textura
   propria e nao repinta durante a transicao de etapa. Nenhum elemento novo
   tem transition, animation, filter ou will-change. */

.capa__fundo {
  position: absolute;
  inset: 0;
  overflow: hidden;
  /* GRADIENTE DIAGONAL. Direcao e extremos medidos por ajuste linear sobre
     os pixels verdes de fundo das duas artes: clareia a 26 graus (direita e
     um pouco pra baixo) = 116deg em CSS, de verde-700 no topo-esquerda a
     verde-500 na base-direita. Medido topo-esq #006E3B, topo-dir #189438,
     base-dir #289D36. Verde-900 NAO aparece no fundo de nenhuma das duas
     artes - ele fica so no .capa__veu, que e quem sustenta o contraste do
     texto claro da base. */
  background-image: linear-gradient(116deg, var(--verde-700) 0%, var(--verde) 100%);
  transition: opacity 700ms var(--ease-capa);
  /* promove a camada ANTES da transicao (nao no momento dela) - o fundo tem
     varios gradientes/clip-path/mask empilhados, caro pra rasterizar de
     novo a cada frame se nao ficar cacheado como textura propria */
  will-change: opacity;
}
/* RESIDUO, nao desaparecimento. Ate 15/08/2026 era opacity:0 e as etapas 2
   e 3 - as mais longas e as unicas com leitura de verdade - ficavam creme
   puro, sem identidade. Em .08 o creme ganha temperatura e o leque continua
   sugerido. Custo medido: o corpo de texto cai de 7,02 pra 6,30:1, sai do
   AAA e fica folgado em AA. NAO SUBIR sem medir - em .12 cai pra 5,96:1. */
.palco.etapa-2 .capa__fundo,
.palco.etapa-3 .capa__fundo {
  opacity: .08;
}

/* TRAMA DE PONTOS. Dois achados da medicao mudaram a regra:
   1) nas artes os pontos sao MAIS ESCUROS que o fundo (fundo #06783B,
      ponto #006E3A), nao mais claros como estavam aqui;
   2) o periodo e 2,50% da largura (27px em 1080), o que da ~10px numa
      viewport de 393px - era 15px.
   A mascara que desvanecia a trama pro canto inferior esquerdo SAIU: medi a
   amplitude da trama faixa a faixa nas artes e ela esta presente em toda a
   altura, do topo a base (o unico vao e onde fica o buraco da foto). Mascara
   nenhuma tambem economiza um passe de composicao. */
.capa__fundo::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: radial-gradient(rgba(4, 83, 43, .22) 1.8px, transparent 2px);
  background-size: 10px 10px;
}

/* LEQUE DE RAIOS. Nas artes nao e explosao radial: e folha de palmeira
   estilizada - corpo em cunha solido mais espiculas finas na borda externa -
   e sao folhas SOBREPOSTAS em tons diferentes, ancoradas fora do quadro no
   canto superior direito. Duas camadas dao a leitura.
   repeating-conic-gradient desenha as espiculas; os dois periodos (4.3deg e
   6.1deg) nao sao multiplos um do outro, entao as camadas nunca alinham e o
   angulo le como desigual, que e o que as artes fazem.
   O recorte da cunha e clip-path, NAO mask: clip-path e recorte geometrico
   e nao acrescenta passe de composicao. */
.capa__leque {
  position: absolute;
  top: -26%;
  right: -30%;
  width: 116%;
  aspect-ratio: 1;
  background: repeating-conic-gradient(from 152deg at 100% 0,
    rgba(100, 182, 104, .55) 0deg 0.9deg,
    transparent 0.9deg 4.3deg);
  clip-path: polygon(100% 0, 4% 30%, 62% 100%);
}
/* folha de tras, mais escura e mais estreita */
.capa__leque::before {
  content: "";
  position: absolute;
  inset: 0;
  background: repeating-conic-gradient(from 168deg at 100% 0,
    rgba(4, 83, 43, .45) 0deg 1.2deg,
    transparent 1.2deg 6.1deg);
  clip-path: polygon(100% 0, 26% 6%, 100% 62%);
}

/* SWEEP DIAGONAL - banda angulada cortando a base, um tom acima do fundo.
   Nas artes ela e translucida e passa POR CIMA da foto; aqui fica dentro do
   .capa__fundo, atras da foto, porque a foto tem precedencia. Como a
   silhueta e so 33% opaca, ela aparece de sobra pelas bordas. */
.capa__sweep {
  position: absolute;
  left: -10%;
  right: -10%;
  bottom: 0;
  height: 42%;
  background: var(--verde);
  opacity: .5;
  clip-path: polygon(0 38%, 100% 0, 100% 100%, 0 100%);
}

/* espiar do creme da etapa 2 nos ultimos 40px - sugere que ha mais conteudo
   abaixo antes mesmo do primeiro scroll. Fica por cima do veu (depois dele
   no DOM) senao a propria escurecida do veu apagaria a cor creme. Some
   junto com o resto do fundo verde ao entrar na etapa 2 (ja fica sobre
   creme de verdade la, perderia o sentido). */
.capa__espiar {
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 40px;
  background: var(--creme);
  border-radius: 28px 28px 0 0;
  box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.12);
  transition: opacity 700ms var(--ease-capa);
}
.palco.etapa-2 .capa__espiar,
.palco.etapa-3 .capa__espiar {
  opacity: 0;
}

/* ---------- entrada animada da etapa 1 (so no carregamento) ---------- */
/* keyframes com fill-mode:both, disparadas so quando .fotos-prontas entra no
   palco - troca entre etapas continua sendo transition (ve regras acima),
   nunca anima as MESMAS propriedades dos MESMOS elementos que a transition
   de etapa ja controla (por isso o candidato e o logo tem wrapper/estado
   dedicado onde precisa). Duracao total ~1.1s: ultimo elemento (indicador de
   rolagem + tracinhos) comeca aos 900ms e termina por volta de 1300ms - e
   esse numero que js/app.js usa pra saber quando a entrada "terminou" e
   liberar o timer da etapa 1. */

@keyframes capaEntradaFade {
  from { opacity: 0; }
  to { opacity: 1; }
}
@keyframes capaEntradaCandidato {
  from { opacity: 0; transform: translateY(30px) scale(0.96); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes capaEntradaSelo {
  from { opacity: 0; transform: scale(0.9); }
  to { opacity: 1; transform: scale(1); }
}
@keyframes capaEntradaSubida {
  from { opacity: 0; transform: translateY(22px); }
  to { opacity: 1; transform: translateY(0); }
}
@keyframes capaEntradaLinha {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}
/* o cenario nao tem entrada animada: ele e estatico e ja esta pintado
   quando a entrada dos outros elementos comeca. Menos uma animacao no
   carregamento, que e onde a capa mais engasgava. */
.palco.fotos-prontas .capa__selo {
  opacity: 0;
  animation: capaEntradaSelo 500ms var(--ease-capa) 420ms both;
}
.palco.fotos-prontas .capa__marca {
  opacity: 0;
  animation: capaEntradaSubida 600ms var(--ease-capa) 500ms both;
}
.palco.fotos-prontas .capa__linha {
  transform-origin: center;
  animation: capaEntradaLinha 500ms var(--ease-capa) 600ms both;
}
.palco.fotos-prontas .capa__promessa {
  opacity: 0;
  animation: capaEntradaFade 500ms var(--ease-capa) 660ms both;
}
.gatilho { height: 100dvh; }

/* atalho pra quem ja conhece o produto - a maioria chega pelo link do
   WhatsApp querendo montar a arte, nao assistir a apresentacao. Com o
   convite a rolagem mais forte, precisa ficar ainda mais discreto - sem
   fundo solido, so contorno fino - pra nao competir. Funciona desde o
   primeiro frame, independente da entrada animada/avanco automatico. */
.capa__pular {
  position: fixed;
  top: calc(var(--esp-4) + env(safe-area-inset-top));
  right: var(--esp-4);
  z-index: 20;
  padding: var(--esp-2) var(--esp-4);
  border-radius: 999px;
  border: 1px solid;
  background: transparent;
  color: var(--creme);
  font-family: var(--fonte-corpo);
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
  /* SEM opacity. Ele era discreto por TRANSPARENCIA, e transparencia corroi
     forma e texto ao mesmo tempo: com opacity .75 o texto ficava em 3,61:1
     na etapa 1 e a BORDA - que desenha a pilula - em 1,96:1, caindo pra
     1,33:1 na etapa 2. Agora e discreto por FORMA: contorno fino, sem
     preenchimento. Pilula solida resolveria, mas competiria com o CTA. */
  border-color: rgba(246, 248, 240, 0.9);
  transition: opacity 700ms var(--ease-capa), border-color 700ms var(--ease-capa), color 700ms var(--ease-capa);
}
/* creme-sobre-creme e invisivel: nas etapas 2/3 (fundo creme) o botao
   precisa da variante escura - alternado via JS junto com a classe de etapa
   (o botao fica fora do .palco, nao da pra fazer isso so com seletor CSS) */
.capa__pular--sobre-creme {
  /* verde-900, nao verde-700: sobre creme da 8,61:1 em vez de 6,13:1.
     Borda em .72 porque .55 dava so 2,74:1 contra o residuo do cenario. */
  border-color: rgba(4, 83, 43, 0.72);
  color: var(--verde-900);
}
.capa__pular--oculto { opacity: 0; pointer-events: none; }

/* container das duas fotos: SO ele se move/escala. As imagens dentro nunca
   recebem ajuste de posicao individual - os dois PNGs ja vem padronizados
   (1080x1500, mesma escala, cabeca no mesmo ponto), entao qualquer offset
   diferente entre elas quebraria o alinhamento no cross-fade. */
/* placeholder visivel enquanto as fotos ainda nao terminaram de decodificar
   (prepararFotosCapa() no app.js) - mesma area/posicao do candidato, some
   assim que .fotos-prontas entra no palco */
.capa__candidato-skeleton {
  position: absolute;
  left: 50%;
  bottom: 0;
  height: 84dvh;
  aspect-ratio: 720 / 1000;
  transform: translateX(-50%);
  border-radius: 12px;
  transition: opacity 260ms ease;
}
.palco.fotos-prontas .capa__candidato-skeleton {
  opacity: 0;
  pointer-events: none;
}

/* dedicado so a entrada (fade+translateY+scale) - ve comentario no HTML.
   Escondido ate fotos-prontas; a partir dai a ANIMACAO cuida de revelar
   (fill-mode:both leva o opacity:1/transform final e mantem). */
.capa__candidato-entrada {
  width: 100%;
  height: 100%;
  opacity: 0;
}
.palco.fotos-prontas .capa__candidato-entrada {
  animation: capaEntradaCandidato 900ms var(--ease-capa) 160ms both;
}

.capa__candidato {
  position: absolute;
  left: 50%;
  bottom: 0;
  height: 84dvh;
  aspect-ratio: 720 / 1000;
  transform: translateX(-50%) scale(1);
  transform-origin: bottom center;
  /* SEM filter. Havia um saturate(0.6) aqui, e filter diferente de none
     forca uma superficie de renderizacao propria pra subarvore inteira - as
     duas fotos e o wrapper de gesto tinham que ser compostos num buffer
     intermediario, filtrados e compostos de novo, sobre o maior elemento da
     tela. A dessaturacao passou a ser gravada no proprio arquivo da foto de
     etapa 1 (ribamar-bandeira-capa), com a matriz exata do feColorMatrix
     saturate em sRGB. Funciona porque a etapa 1 mostra exclusivamente
     .capa__foto--fechado e as etapas 2/3 mostram --aponta, que ja era
     saturada: a troca de saturacao E o cross-fade. De quebra ficou melhor -
     antes a saturacao pulava de golpe no instante da classe enquanto o fade
     rodava 520ms.
     Opacidade nao mora aqui - quem cuida da revelacao inicial e o
     .capa__candidato-entrada, junto com a entrada animada. */
  transition: transform 700ms var(--ease-capa);
  will-change: transform;
}
.palco.etapa-2 .capa__candidato,
.palco.etapa-3 .capa__candidato {
  /* tunado visualmente (ve historico de testes) pra nao cobrir o texto dos
     passos em 360-390px: em telas estreitas, 52%/34vw (os numeros "ideais")
     colidiam com o bloco de passos - a mao apontando cobria "Compartilhe".
     translateY sobe a figura pra a mao ficar na altura do passo 2 (meio). */
  transform: translateX(calc(-50% + 40vw)) translateY(-10dvh) scale(0.5);
}

/* micro-movimento SEPARADO do shrink/slide grande (durada e curva
   diferentes) - por isso mora num wrapper interno proprio. E isso que faz a
   troca de foto ler como um gesto, nao como duas fotos so alternando. */
.capa__candidato-gesto {
  position: absolute;
  inset: 0;
  /* sem will-change: sao 520ms e o navegador promove sozinho ao comecar.
     Com ele, esta camada e as duas fotos ficavam promovidas o tempo todo -
     quatro camadas aninhadas sobre a MESMA regiao (~13 MB cada em DPR 3),
     soltas so no encerrarCapa(), que roda quando a pessoa ja saiu da capa. */
  transition: transform 520ms var(--ease-crossfade);
}
.palco.etapa-2 .capa__candidato-gesto,
.palco.etapa-3 .capa__candidato-gesto {
  transform: scale(1.015) translateX(-4px);
}

.capa__foto {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  /* idem .capa__candidato-gesto: 520ms nao justifica promocao permanente,
     e esta regra casa DUAS imagens */
  transition: opacity 520ms var(--ease-crossfade);
}
.capa__foto--fechado { opacity: 1; }
.capa__foto--aponta { opacity: 0; }
.palco.etapa-2 .capa__foto--fechado,
.palco.etapa-3 .capa__foto--fechado { opacity: 0; }
.palco.etapa-2 .capa__foto--aponta,
.palco.etapa-3 .capa__foto--aponta { opacity: 1; }

/* veu com 5 paradas (em vez de 2) pra transicao ficar imperceptivel, e
   opaco o bastante ate ~45% da altura pra cobrir o bloco diagonal/meio-tom
   do .capa__fundo atras do texto (selo/nome/cargo) - e o que garante o
   contraste AAA do texto claro/amarelo sem depender da cor exata que esta
   por baixo. */
.capa__veu {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to top,
    var(--verde-900) 0%,
    var(--verde-900) 30%,
    rgba(0, 102, 51, 0.85) 45%,
    rgba(0, 102, 51, 0.5) 62%,
    rgba(0, 102, 51, 0.18) 80%,
    transparent 100%
  );
  transition: opacity 700ms var(--ease-capa);
}
.palco.etapa-2 .capa__veu,
.palco.etapa-3 .capa__veu { opacity: 0; }

/* O LOCKUP NO CANTO - etapas 2/3, onde o fundo ja e creme com o residuo
   .08 e ele assenta em terreno claro SEM placa nenhuma. O problema que
   existia aqui era so a colisao com o #btn-pular-capa, que e fixed e so
   some na etapa 3: em 393px o lockup vai ate x=246 e o botao comeca em
   x=176. O top:60px resolve - as duas bandas verticais nao se cruzam
   (botao y 16..52, lockup y 60..104,7), e a sobreposicao horizontal deixa
   de importar. O deslocamento do notch se cancela: o botao e fixed
   (viewport) e o lockup e absolute no palco, que comeca no padding de
   safe-area do body.
   Mesma curva e mesma duracao do .capa__intro que ele substitui, entao a
   soma das duas opacidades e 1 em todo instante: nunca ha um quadro sem
   nenhum lockup na tela.
   ARQUIVO E TAMANHO DIFERENTES da instancia do h1, de proposito. Aqui o
   lockup e ASSINATURA, nao cabecalho: 180px contra os 256 da placa, uma
   diferenca de 1,42x. E usa a versao SEM SLOGAN (logo-1500-assinatura,
   proporcao 5,252), porque com o arquivo do slogan nao existe saida - o
   slogan tem piso em 226px de largura (4,10px de x-height) e qualquer
   tamanho que produza hierarquia visivel o joga abaixo do piso, virando
   ruido. Assinatura de canto nao repete a frase: o <h1> ja a leva no alt.
   A folga de 8px contra o #btn-pular-capa nao muda com a largura - ela e
   vertical (botao y 16..52, canto y 60..94,3) e o top:60px esta fixo. */
.capa__logo-canto {
  position: absolute;
  top: 60px;
  left: 20px;
  width: 180px;
  height: auto;
  opacity: 0;
  pointer-events: none;
  transition: opacity 700ms var(--ease-capa);
}
.palco.etapa-2 .capa__logo-canto,
.palco.etapa-3 .capa__logo-canto {
  opacity: 1;
}

/* A PLACA CLARA E O CABECALHO DA ETAPA 1.
   Antes havia DOIS cabecalhos: o lockup dizia "Dr Ribamar Bandeira /
   DEPUTADO FEDERAL" e logo abaixo um <h1> repetia o mesmo nome com
   "Deputado Federal 2026". Era por isso que nada encontrava lugar na
   composicao - havia um a mais. O bloco de texto saiu e o lockup ocupou o
   lugar dele, centralizado, sobre o veu.
   POR QUE A PLACA: medido, o slogan da 5,63:1 sobre creme e 1,53:1 sobre o
   verde-900 do veu - some por completo. "Dr" e "DEPUTADO FEDERAL" ficam em
   3,18:1 no creme contra 2,70:1 no verde. A placa e o terreno, nao
   decoracao. O laranja do "BANDEIRA" e o unico que vai melhor no verde
   (3,94 contra 2,19) - e a logica de um lockup pra fundo claro.
   CONTIDA, nao faixa: envolve o lockup mais respiro e para ali. Faixa
   atravessando a tela cortava o verde que e a identidade da primeira tela.
   RETA, nao inclinada: as diagonais do vocabulario sao gestos de fundo;
   placa inclinada sob lockup horizontal le como erro de montagem, e
   inclinar o lockup junto destruiria o slogan.
   SEM SOMBRA, nem dura nem difusa: relevo duro pressupoe terreno
   consistente e isto flutua sobre foto; difusa sobre verde-900 seria
   invisivel. A placa ja se define por 8,61:1 de creme contra o veu.
   Raio 16px: o mesmo do .dropzone, .editor__canvas-wrap e
   .resultado__preview - nao inventa um nono valor.
   O lockup vive DENTRO do .capa__intro, entao some nas etapas 2/3 junto com
   ele. E o inverso de onde estava, e e deliberado: a exigencia legal e o
   numero na PRIMEIRA tela; nas 2/3 a tela e sobre os passos e o CTA. */
.capa__marca {
  /* 288px = 256 de lockup + 16 de respiro de cada lado. Era 258/226.
     O ganho que interessa e o slogan: sobe de 4,10 pra 4,64px de x-height,
     +13%. Parei em 288 e nao em 312 por LARGURA RELATIVA, nao por folga:
     312 e 86,7% de uma tela de 360 e volta a ler como faixa atravessando -
     exatamente o que a placa contida existe pra evitar - e deixaria 4px de
     margem no iPhone SE. Em 288 sao 80%, com 36px de respiro em 360px.
     min(...,100%) porque px fixo estoura: 288 nao cabe nos 280px do Fold
     externo. Com min() a placa encolhe junto (232px la, lockup em 200) e
     nada transborda. O slogan cai pra ~3,6px nesse aparelho, e naquele
     tamanho de tela ele ja nao era lido de qualquer forma. */
  width: min(288px, 100%);
  margin: 0 auto;
  padding: var(--esp-3) var(--esp-4);
  background: var(--creme);
  border-radius: 16px;
}
.capa__logo {
  display: block;
  /* 100% do content box da placa - 256px nos 288 dela. Nao e px fixo pra
     acompanhar o min() do pai quando a tela e mais estreita que a placa. */
  width: 100%;
  height: auto;
}

.capa__intro {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 18%;
  padding: 0 var(--esp-6);
  text-align: center;
  transition: transform 700ms var(--ease-capa), opacity 700ms var(--ease-capa);
}
.palco.etapa-2 .capa__intro,
.palco.etapa-3 .capa__intro {
  transform: translateY(-28px);
  opacity: 0;
  pointer-events: none;
}
.capa__selo {
  display: inline-block;
  background: var(--amarelo);
  color: var(--tinta); /* nao --verde: verde-sobre-amarelo da so 4.93:1, abaixo do alvo AAA */
  font-family: var(--fonte-corpo);
  font-weight: 700;
  font-size: 14px;
  letter-spacing: 0.1em;
  padding: var(--esp-2) 15px;
  border-radius: 999px;
  margin: 0 0 var(--esp-3);
}
/* coracao do proprio logotipo, como acento. So aqui: ele da 3,24:1 sobre o
   amarelo do selo e 4,16:1 sobre creme, mas apenas 2,07:1 sobre o verde-900
   do veu e 1,47:1 sobre verde-700 - fundo claro e a unica opcao. Nao entrou
   nos tres passos (o ordinal 1/2/3 carrega informacao que o coracao nao
   carrega, e tres ocorrencias viram padrao de fundo em vez de acento) nem
   na tela de resultado (glifo vermelho ao lado de "sua arte esta pronta",
   num produto onde vermelho e erro, cria duvida no pico do fluxo).
   38x31 e a resolucao nativa e o maximo disponivel em qualquer arte da
   campanha - a 16px e downscale, sem serrilhado. */
.capa__selo-coracao {
  width: 16px;
  height: auto;
  vertical-align: -2px;
  margin-right: var(--esp-1);
}


.capa__linha {
  width: 120px;
  height: 4px;
  background: var(--amarelo);
  border-radius: 2px;
  margin: var(--esp-3) auto 0;
}
/* a linha de promessa, no lugar que era do cargo. NAO e titulo: e apoio.
   Saiu o "Deputado Federal 2026" - o cargo ja esta dentro do lockup, e
   repeti-lo traria de volta metade do duplo cabecalho. O ano continua no
   rodape legal e nas metas. O que faltava na etapa 1 nao era identidade,
   era proposito: nenhuma frase dizia o que a pagina e, e isso so aparecia
   depois de rolar. A frase ja existia no <title> e nas metas.
   Hierarquia: 13px/600 contra os 14px/700 do selo, creme a 82% em vez de
   creme cheio - um degrau abaixo em tamanho, peso e presenca. 6,35:1 sobre
   o veu. */
.capa__promessa {
  font-size: 13px;
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: 0.04em;
  color: rgba(246, 248, 240, .82);
  margin: var(--esp-2) 0 0;
}

/* convite a rolagem: precisa ser forte o bastante pra pegar na visao
   periferica (amplitude 8px, opacidade oscilando, nao so um "quase parado")
   - a capa e a primeira coisa que a pessoa ve, se ela nao entender que rola,
   nunca chega nas etapas 2/3. Some no primeiro cancelamento (a pessoa ja
   demonstrou que sabe rolar) via .capa--cancelada no palco. */
.capa__role {
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(var(--esp-6) + env(safe-area-inset-bottom));
  margin: 0;
  text-align: center;
  color: var(--creme);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.08em;
  opacity: 0;
  animation: capaEntradaFade 400ms var(--ease-capa) 900ms both, capaRoleFlutua 1.8s ease-in-out 1300ms infinite;
}
.palco.etapa-2 .capa__role,
.palco.etapa-3 .capa__role,
.palco.capa--cancelada .capa__role {
  animation: none;
  opacity: 0;
  transition: opacity 700ms var(--ease-capa);
}
.palco.capa--enfase .capa__role {
  animation: capaEntradaFade 400ms var(--ease-capa) 900ms both, capaRoleFlutuaEnfase 1.8s ease-in-out 2;
}
@keyframes capaRoleFlutua {
  0%, 100% { transform: translateY(0); opacity: 0.6; }
  50% { transform: translateY(-8px); opacity: 1; }
}
@keyframes capaRoleFlutuaEnfase {
  0%, 100% { transform: translateY(0); opacity: 0.6; }
  50% { transform: translateY(-14px); opacity: 1; }
}
/* seta desenhada em CSS (chevron), 85% creme - nao e mais um glifo de texto */
.capa__seta {
  display: block;
  width: 15px;
  height: 15px;
  margin: var(--esp-2) auto 0;
  border-right: 3px solid rgba(246, 248, 240, 0.85);
  border-bottom: 3px solid rgba(246, 248, 240, 0.85);
  transform: rotate(45deg);
}

/* indicador tipo "stories": 3 tracinhos 22x3px, 6px de folga, area de toque
   expandida pra 52px via ::after (invisivel, nao mexe no layout visual) */
.capa__progresso {
  position: absolute;
  left: var(--esp-4);
  bottom: calc(var(--esp-4) + env(safe-area-inset-bottom));
  display: flex;
  gap: 6px;
  opacity: 0;
  animation: capaEntradaFade 400ms var(--ease-capa) 900ms both;
}
.palco.etapa-2 .capa__progresso,
.palco.etapa-3 .capa__progresso {
  opacity: 0;
  transition: opacity 700ms var(--ease-capa);
}
.capa__progresso-item {
  position: relative;
  width: 22px;
  height: 3px;
  padding: 0;
  border: none;
  border-radius: 2px;
  background: rgba(246, 248, 240, 0.3);
  cursor: pointer;
}
.capa__progresso-item::after {
  content: "";
  position: absolute;
  inset: -24.5px -15px; /* 22x3 + isso = 52x52 de area de toque, centrada no tracinho visivel */
}
.capa__progresso-preenchimento {
  position: absolute;
  inset: 0;
  width: 0%;
  border-radius: 2px;
  background: var(--amarelo);
}

.capa__passos {
  position: absolute;
  left: var(--esp-6);
  width: min(240px, 62vw); /* para curto do candidato encolhido - ve .capa__candidato */
  top: 50%;
  transform: translateY(-50%);
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--esp-4);
}
.capa__passos li {
  display: flex;
  align-items: flex-start;
  gap: var(--esp-3);
  opacity: 0;
  transform: translateY(24px);
  transition: transform 700ms var(--ease-capa), opacity 700ms var(--ease-capa);
}
.palco.etapa-2 .capa__passos li,
.palco.etapa-3 .capa__passos li {
  opacity: 1;
  transform: translateY(0);
}
.palco.etapa-3 .capa__passos li {
  opacity: 0.35;
  transform: translateY(-20px);
}
.capa__passo-num {
  flex: none;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--amarelo);
  color: var(--tinta); /* nao --verde: verde-sobre-amarelo da so 4.93:1, abaixo do alvo AAA */
  font-weight: 800;
  font-size: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.capa__passos strong {
  display: block;
  font-size: 18px;
  font-weight: 700;
  color: var(--tinta);
}
.capa__passos p {
  font-size: 15px;
  font-weight: 600;
  color: var(--cinza);
  margin: var(--esp-1) 0 0;
}

.capa__cta {
  position: absolute;
  left: var(--esp-6);
  right: var(--esp-6);
  bottom: calc(var(--esp-8) + env(safe-area-inset-bottom));
  opacity: 0;
  transform: translateY(22px);
  transition: transform 700ms var(--ease-capa), opacity 700ms var(--ease-capa);
  pointer-events: none;
}
.palco.etapa-3 .capa__cta {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}
.capa__btn-comecar {
  width: 100%;
  height: 60px;
  min-height: 60px;
  font-size: 18px;
  /* difusa, nao dura - e o LIMITE da regra de relevo, nao excecao. Relevo
     duro pressupoe terreno consistente: cartao e chip sobre coluna creme.
     Aqui o botao flutua sobre foto recortada, e a sombra dura virava uma
     tira quase preta de 4x60px no meio das pernas da foto. */
  box-shadow: var(--sombra-md);
}
/* .privacidade era usada no HTML e NUNCA definida no CSS: o
   justify-content abaixo nao fazia nada sem display:flex, o <p> caia como
   bloco a esquerda e o escudo pousava na linha de base, sem folga. */
.privacidade {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--esp-2);
  font-size: 15px;
}
.privacidade svg { flex: none; }

.capa__privacidade {
  margin: var(--esp-3) 0 0;
}

@media (prefers-reduced-motion: reduce) {
  .capa, .capa * {
    transition-duration: 0.01ms !important;
  }
  /* sem entrada, tudo aparece direto no estado final - e sem avanco
     automatico (js/app.js confere prefers-reduced-motion antes de agendar
     qualquer timer/scrollTo, isso aqui so cobre o lado CSS) */
  .capa__candidato-entrada,
  .capa__selo,
  .capa__marca,
  .capa__linha,
  .capa__promessa,
  .capa__progresso {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }
  /* .capa__role fica FORA da lista acima. Com opacity:1!important ele nunca
     sumia: as regras que o escondem (.palco.etapa-2/-3 e .capa--cancelada)
     nao tem !important e perdiam, entao quem pediu menos movimento ficava
     com "role para conhecer" preso na tela nas etapas 2 e 3. Aqui a
     animacao morre - que e o que reduced-motion pede - e a opacidade volta
     a ser decidida pelas regras de etapa, que tem especificidade (0,2,0)
     contra os (0,1,0) daqui. */
  .capa__role {
    animation: none !important;
    opacity: 1;
    transform: none !important;
  }
}

/* ---------- escolha ---------- */

.rotulo-secao { font-size: 14px; margin-top: var(--esp-4); }

.lista-modelos {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.card-modelo {
  display: flex;
  align-items: center;
  gap: var(--esp-3);
  text-align: left;
  padding: var(--esp-3);
  border-radius: 14px;
  /* .70 = #4D9872, 3,47:1 sobre #fff e 3,24:1 sobre creme. Era .15 (1,26:1),
     invisivel: a borda nao participava da leitura do estado e sobrava so o
     radio pra distinguir escolhido de nao escolhido. */
  border: 2px solid rgba(0, 108, 54, 0.7);
  background: #fff;
  cursor: pointer;
  transition: border-color var(--transicao), background var(--transicao),
    transform var(--transicao), box-shadow var(--transicao);
  min-height: var(--toque-min);
  box-shadow: 4px 5px 0 rgba(var(--sombra-tinta), var(--sombra-alfa));
}
.card-modelo:active {
  transform: translate(3px, 4px);
  box-shadow: 3px 4px 0 rgba(var(--sombra-tinta), var(--sombra-alfa));
}
@media (hover: hover) {
  .card-modelo:hover {
    transform: translate(-2px, -3px);
    box-shadow: 7px 9px 0 rgba(var(--sombra-tinta), var(--sombra-alfa));
  }
}
/* a borda de 2px em verde-700 ja existia aqui e continua sendo o sinal
   principal (6,57:1 contra o #fff do card). O que nao comunicava nada era o
   FUNDO, a 1,08:1 - fundo claro sobre fundo claro nao vira sinal em
   nenhuma opacidade util, entao quem passa a marcar a selecao junto com a
   borda e o degrau de relevo: o card escolhido sobe de 4px 5px pra 7px 9px
   e fica visivelmente mais alto que os outros da lista. */
.card-modelo.selecionado {
  border-color: var(--verde-700);
  background: rgba(24, 144, 56, 0.06);
  box-shadow: 7px 9px 0 rgba(var(--sombra-tinta), var(--sombra-alfa));
}

/* indicador de radio: circulo vazado que preenche de verde com um check
   branco (desenhado so com bordas giradas, sem SVG nem icone extra) */
.card-modelo__radio {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 2px solid rgba(0, 108, 54, 0.3);
  flex: none;
  position: relative;
  transition: border-color var(--transicao), background var(--transicao);
}
.card-modelo__radio::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  width: 10px;
  height: 6px;
  border-left: 2px solid var(--creme);
  border-bottom: 2px solid var(--creme);
  transform: translateY(-1px) rotate(-45deg) scale(0);
  transition: transform var(--transicao);
}
.card-modelo.selecionado .card-modelo__radio {
  border-color: var(--verde-700);
  background: var(--verde-700);
}
.card-modelo.selecionado .card-modelo__radio::after {
  transform: translateY(-1px) rotate(-45deg) scale(1);
}

.card-modelo__texto {
  flex: 1;
  font-family: var(--fonte-corpo);
  font-weight: 700;
  font-size: 16px;
  color: var(--tinta);
}

/* a miniatura reflete a PROPORCAO real do formato escolhido no toggle, nao
   so a arte - e assim que a pessoa entende visualmente a diferenca entre
   feed (quadrado), stories (vertical) e perfil (redondo). O src e a
   proporcao sao atualizados via JS (atualizarMiniaturas) toda vez que o
   toggle muda. */
.card-modelo__miniatura {
  height: 110px;
  width: 110px;
  border-radius: 8px;
  object-fit: cover;
  background: var(--creme);
  flex: none;
  transition: width var(--transicao), border-radius var(--transicao);
}
.card-modelo__miniatura[data-formato="stories"] { width: 62px; }
.card-modelo__miniatura[data-formato="perfil"] { border-radius: 50%; }

.contexto-formato {
  font-size: 14px;
  font-weight: 600;
  color: var(--cinza);
  text-align: center;
  margin: var(--esp-2) 0 0;
}

.toggle-formato {
  display: flex;
  gap: var(--esp-2);
  margin-top: var(--esp-2);
}
.toggle-formato__opcao {
  flex: 1;
  min-height: 56px;
  border-radius: 12px;
  /* mesma subida de .15 pra .70 do .card-modelo, mesma razao */
  border: 2px solid rgba(0, 108, 54, 0.7);
  background: #fff;
  font-family: var(--fonte-corpo);
  font-size: 16px; /* faltava - sem isso o botao caia no tamanho padrao do navegador, abaixo de 14px */
  font-weight: 600;
  color: var(--cinza);
  cursor: pointer;
  transition: border-color var(--transicao), color var(--transicao),
    background var(--transicao), transform var(--transicao), box-shadow var(--transicao);
  box-shadow: 3px 4px 0 rgba(var(--sombra-tinta), var(--sombra-alfa));
}
.toggle-formato__opcao:active:not(:disabled) {
  transform: translate(3px, 4px);
  box-shadow: 3px 4px 0 rgba(var(--sombra-tinta), var(--sombra-alfa));
}
@media (hover: hover) {
  .toggle-formato__opcao:hover:not(:disabled) {
    transform: translate(-2px, -3px);
    box-shadow: 4px 5px 0 rgba(var(--sombra-tinta), var(--sombra-alfa));
  }
}
.toggle-formato__opcao span {
  opacity: 0.75;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  margin-left: var(--esp-1);
}
/* selecionado sobe um degrau de relevo, alem de inverter o preenchimento */
.toggle-formato__opcao.selecionado {
  border-color: var(--verde-700);
  background: var(--verde-700);
  color: var(--creme);
  box-shadow: 4px 5px 0 rgba(var(--sombra-tinta), var(--sombra-alfa));
}
.toggle-formato__opcao.selecionado span { opacity: 0.85; }
.toggle-formato__opcao:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

/* fixo na base da VIEWPORT. Duas coisas precisam trabalhar JUNTAS aqui:
   - margin-top:auto empurra o wrapper pro fim de .tela quando o conteudo e
     curto (sticky sozinho NAO faz isso - sticky so gruda durante o scroll,
     nao pula pro fim de um container com sobra de espaco. Foi exatamente
     essa a causa do "vazio enorme": eu tirei o auto e sobrou so o sticky).
   - position:sticky;bottom:0 mantem o wrapper visivel quando a lista de
     modelos cresce mais que a viewport e a pagina rola.
   Fundo creme fica no WRAPPER, nao no botao (que continua verde normal
   dentro dele) - senao apagaria o .btn--primario. */
.rodape-fixo {
  position: sticky;
  bottom: 0;
  margin-top: auto;
  margin-left: calc(-1 * var(--esp-4));
  margin-right: calc(-1 * var(--esp-4));
  margin-bottom: calc(-1 * var(--esp-8));
  padding: var(--esp-3) var(--esp-4) calc(var(--esp-3) + env(safe-area-inset-bottom));
  background: var(--creme);
  border-top: 1px solid rgba(0, 108, 54, 0.12);
  box-shadow: var(--sombra-cima-md);
  z-index: 5;
}
.rodape-fixo .btn { min-height: 56px; }

/* ---------- upload ---------- */

/* tres estados, tres aparencias. Antes hover, foco e arraste-ativo tinham a
   MESMA regra - o teclado nao sabia onde estava e o arraste nao confirmava
   que a solta valia. Agora:
     repouso  tracejado .70, sem fundo
     hover    tracejado verde-700 solido, fundo 4%
     foco     o de cima + anel verde-700 (regra de foco, mais acima)
     arraste  borda SOLIDA - deixa de ser tracejada, que e o convite -, mais
              fundo 10%: a moldura "fecha" quando o arquivo pode ser solto */
.dropzone {
  border: 2px dashed rgba(0, 108, 54, 0.7);
  border-radius: 16px;
  padding: var(--esp-8) var(--esp-4);
  text-align: center;
  color: var(--cinza);
  cursor: pointer;
  transition: border-color var(--transicao), background var(--transicao),
    border-style var(--transicao);
}
.dropzone svg { color: var(--verde-700); margin-bottom: var(--esp-2); }
.dropzone:hover { border-color: var(--verde-700); background: rgba(24, 144, 56, 0.04); }
.dropzone--ativa {
  border-style: solid;
  border-color: var(--verde-700);
  background: rgba(24, 144, 56, 0.10);
}

/* a quebra de linha so faz sentido em telas largas ("arraste" e coisa de
   mouse); no mobile o texto flui numa linha so - classe existia no HTML mas
   nunca tinha sido definida aqui, a quebra aparecia sempre */
.so-desktop { display: none; }
@media (min-width: 640px) {
  .so-desktop { display: initial; }
}

.btn--mobile { margin-top: var(--esp-3); }
@media (pointer: fine) {
  .btn--mobile { display: none; } /* "tirar foto agora" so faz sentido em dispositivo com camera/touch */
}

.erro {
  margin-top: var(--esp-3);
  padding: var(--esp-3);
  border-radius: 10px;
  background: rgba(219, 4, 11, 0.08);
  color: #AD0309; /* --vermelho (#DB040B) escurecido pra 7.02:1 sobre creme (AAA) - --vermelho em si fica no valor de marca pra uso decorativo */
  font-size: 14px;
  font-weight: 600;
}

/* ---------- @ do instagram ---------- */

.campo-texto {
  width: 100%;
  min-height: var(--toque-min);
  padding: var(--esp-3) var(--esp-4);
  border-radius: 12px;
  border: 2px solid rgba(0, 108, 54, 0.7);
  background: #fff;
  color: var(--tinta);
  font-family: var(--fonte-corpo);
  font-size: 16px;
  margin-bottom: var(--esp-4);
  transition: border-color var(--transicao);
}
/* sem outline:none - o anel vem da regra de foco la em cima. A borda
   verde-700 continua como reforco, nunca como unico sinal. */
.campo-texto:focus { border-color: var(--verde-700); }

/* ---------- editor ---------- */

/* o palco da moldura e o bloco grande da tela: degrau 3 (7px 9px). Nao tem
   hover/active proprio - quem manipula e o canvas por gesto, o palco em si
   fica parado. */
.editor__canvas-wrap {
  position: relative;
  width: 100%;
  border-radius: 16px;
  overflow: hidden;
  background: #ddd;
  box-shadow: 7px 9px 0 rgba(var(--sombra-tinta), var(--sombra-alfa));
}
#canvas-editor { display: block; width: 100%; touch-action: none; }

.editor__dica {
  font-size: 14px;
  text-align: center;
  margin: var(--esp-3) 0 0;
}

.editor__acoes {
  margin-top: auto;
  padding-top: var(--esp-4);
  display: flex;
  gap: 10px;
}
.editor__acoes .btn--secundario { flex: none; }
.editor__acoes .btn--primario { flex: 1; }

/* ---------- resultado ---------- */

/* e a MESMA peca do .editor__canvas-wrap, uma etapa depois: mesmo degrau 3.
   Duas telas mostrando a mesma moldura com relevos diferentes e incoerencia
   visivel. */
.resultado__preview {
  width: 100%;
  border-radius: 16px;
  display: block;
  margin: 0 auto var(--esp-4);
  box-shadow: 7px 9px 0 rgba(var(--sombra-tinta), var(--sombra-alfa));
  background: rgba(24, 144, 56, 0.06);
  /* toque longo precisa continuar oferecendo "Adicionar as Fotos"/"Salvar
     Imagem" no iOS - explicito pra garantir, mesmo sem nenhuma regra global
     desativando hoje */
  -webkit-touch-callout: default;
  -webkit-user-select: auto;
  user-select: auto;
}

.dica-perfil {
  font-size: 14px;
  text-align: center;
  color: var(--verde-700);
  background: rgba(24, 144, 56, 0.06);
  border-radius: 10px;
  padding: var(--esp-2) var(--esp-3);
  margin: calc(-1 * var(--esp-2)) 0 var(--esp-4);
}

.resultado__acoes {
  display: flex;
  flex-direction: column;
  gap: 10px;
  align-items: stretch;
}
.resultado__acoes .btn--texto { align-self: center; }

/* hierarquia padrao: baixar primeiro. No iOS com Web Share disponivel, o
   download nunca grava na galeria (vira arquivo no app Arquivos) - so o
   Web Share oferece "Salvar Imagem", entao a ordem visual (nao so a cor)
   inverte pra guiar quem so olha o botao de cima. */
#btn-baixar { order: 1; }
#btn-compartilhar { order: 2; }
#btn-outra { order: 3; }
.resultado__acoes--compartilhar-primario #btn-compartilhar { order: 1; }
.resultado__acoes--compartilhar-primario #btn-baixar { order: 2; }

.dica-ios {
  font-size: 14px;
  color: var(--cinza);
  text-align: center;
  margin: calc(-1 * var(--esp-2)) 0 0;
}
.dica-ios__segurar {
  display: block;
  margin-top: var(--esp-1);
}

/* ---------- skeleton shimmer ---------- */

.skeleton {
  background: linear-gradient(100deg, rgba(24, 144, 56, 0.08) 30%, rgba(24, 144, 56, 0.16) 50%, rgba(24, 144, 56, 0.08) 70%);
  background-size: 300% 100%;
  animation: brilho 1.3s ease-in-out infinite;
}
.skeleton--absoluta { position: absolute; inset: 0; }
@keyframes brilho {
  0% { background-position: 150% 0; }
  100% { background-position: -150% 0; }
}

/* ---------- toast de erro ---------- */

.toast {
  position: fixed;
  left: 50%;
  bottom: calc(20px + env(safe-area-inset-bottom));
  transform: translateX(-50%);
  max-width: calc(100% - 40px);
  background: var(--tinta);
  color: var(--creme);
  padding: var(--esp-3) var(--esp-4);
  border-radius: 10px;
  font-size: 14px;
  text-align: center;
  z-index: 100;
  box-shadow: var(--sombra-lg);
  /* o toast e fixo na base e pode cair sobre o rodape legal, onde o fundo
     dele (--tinta) da so 1,84:1 contra o verde-900 do slab e a silhueta
     some. Como e toast de ERRO, sumir e falha funcional. O anel creme
     garante a borda sobre qualquer fundo do produto - creme, verde-900 ou
     a foto do editor. */
  border: 1px solid rgba(246, 248, 240, .55);
}

/* ---------- rodape legal ----------
   Replicado valor por valor de .rbl-footer / .rbl-legal / .rbl-nota do
   index.html da landing (15/08/2026). E a assinatura legal da campanha e a
   unica peca que o eleitor ve igual nos quatro produtos - divergencia aqui
   nao le como decisao de layout, le como peca de origem diferente.

   OS LITERAIS SAO DE PROPOSITO. 26/20/22 de padding, 640px de largura,
   12px, 11px, 1.65, 6px, 12px, 18px: nada disso sai da escala --esp-* e
   nada disso deve sair. Este bloco precisa ser igual ao dos outros
   produtos, nao coerente com a escala deste. Escala interna aqui seria
   justamente o erro.

   Adaptado so nos tres pontos em que este produto difere da landing:
   a) o slab e full-bleed e a largura do texto foi para um wrapper interno,
      porque .rodape aqui era uma coluna de 460px centrada;
   b) font-weight:400 explicito - a landing herda 400 do navegador, aqui
      html,body e p declaram 600, entao sem isto o bloco renderiza mais
      pesado que o dela (e por isto o Poppins 400 voltou ao <link>);
   c) a safe area: o body deste produto tem padding de env(safe-area-inset-*)
      e a landing nao. Sem cancelar isso sobraria uma faixa creme sob o slab
      no iPhone - e nas laterais em paisagem. A margem negativa puxa o slab
      para dentro do inset e o padding devolve o respiro por dentro. */

.rodape {
  background: var(--verde-900);
  color: var(--creme);
  font-family: var(--fonte-corpo);
  text-align: center;
  margin:
    0
    calc(-1 * env(safe-area-inset-right))
    calc(-1 * env(safe-area-inset-bottom))
    calc(-1 * env(safe-area-inset-left));
  padding:
    26px
    calc(20px + env(safe-area-inset-right))
    calc(22px + env(safe-area-inset-bottom))
    calc(20px + env(safe-area-inset-left));
}

/* tricolor de fechamento - 4px, no maximo 180px, centralizado, tres tercos
   exatos via flex:1. Decorativo (aria-hidden): a informacao legal esta no
   texto abaixo. Verde e vermelho ficam em 2,23:1 e 1,97:1 contra o slab -
   abaixo de 3:1 e igual a landing, aceitavel porque a faixa nao carrega
   informacao nenhuma. Se um dia carregar, as cores mudam. */
.rodape__tricolor {
  display: flex;
  height: 4px;
  max-width: 180px;
  margin: 0 auto 18px;
  border-radius: 2px;
  overflow: hidden;
}
.rodape__tricolor i { flex: 1; }
.rodape__tricolor i:nth-child(1) { background: var(--verde); }
.rodape__tricolor i:nth-child(2) { background: var(--amarelo); }
.rodape__tricolor i:nth-child(3) { background: var(--vermelho); }

.rodape__legal {
  max-width: 640px;
  margin: 0 auto;
  font-size: 12px;
  line-height: 1.65;
  color: rgba(246, 248, 240, .82); /* 6,33:1 sobre o slab */
}
/* a landing nao precisa desta regra: la o p herda peso e cor do navegador.
   Aqui o seletor de elemento p declara font-weight:600, color:var(--cinza)
   e line-height:1.65, e seletor de elemento ganha de heranca - entao os
   tres precisam ser derrubados explicitamente, um por um. */
.rodape__legal p {
  margin: 0 0 6px;
  color: inherit;
  font-weight: 400;
  line-height: inherit;
}
.rodape__legal strong {
  color: var(--amarelo); /* 6,57:1 sobre o slab */
  font-weight: 700;
}
/* DIVERGENCIA DELIBERADA DA LANDING - uma so, e para o lado do que funciona.
   La a nota e `.rbl-nota` (0,1,0) e perde para `.rbl-legal p` (0,1,1): o
   `margin-top:12px` dela e declaracao MORTA, nunca aplica, e a nota cola
   nas linhas de cima com os mesmos 6px das outras. O `color` de .72 aplica
   porque `.rbl-legal p` nao declara cor.
   Aqui a regra acima precisou declarar `color`, o que mataria tambem o .72.
   Entao o seletor sobe para (0,2,0) e as duas intencoes voltam a valer.
   Resultado: a nota fica 12px afastada e em .72, que e o que a landing quis
   e nao conseguiu. Copiar o comportamento morto seria herdar defeito - o
   que a secao 9a manda nao fazer. Reverter e trocar este seletor de volta
   para `.rodape__nota`. */
.rodape__legal .rodape__nota {
  font-size: 11px;
  color: rgba(246, 248, 240, .72); /* 5,29:1 sobre o slab */
  margin-top: 12px;
}

/* quando existir link neste rodape, o anel de foco tem que ser AMARELO: o
   verde-700 padrao do produto da 1,4:1 contra o slab e desaparece. O
   amarelo da 6,57:1. Nao ha link aqui hoje - a regra fica escrita para
   quem adicionar o primeiro.
.rodape a:focus-visible { outline: 3px solid var(--amarelo); outline-offset: 3px; }
*/

/* o relevo duro tambem respeita reduced-motion: a sombra fica (e forma, nao
   movimento), o deslocamento do elemento e que some */
@media (prefers-reduced-motion: reduce) {
  .btn, .card-modelo, .toggle-formato__opcao { transition: none; }
  .btn--primario:hover:not(:disabled),
  .btn--primario:active:not(:disabled),
  .card-modelo:hover,
  .card-modelo:active,
  .toggle-formato__opcao:hover:not(:disabled),
  .toggle-formato__opcao:active:not(:disabled) {
    transform: none;
  }
}

