:root {
  --red: #db1c1e;
  --red-footer: #dc1c22;
  --red-app-icon: #d10b18;
  --yellow: #ffaf2e;
  --yellow-strong: #ffb012;
  --bg: #f7f8f9;
  --ink: #1a1a1a;
  --muted: #878787;
  --muted-light: #b3b2b3;
  --line: #dcdbdc;
  --rating: #eaaa1e;
  --verde-frete: #00c044;
  --verde-frete-escuro: #6fc40f;
  --verde-frete-fundo: #cfebd5;
  --verde-frete-borda: #00c043;
  --verde-frete-barra: #01cd55;
  --laranja: #ff8000;
  --rosa-claro: #ffdde0;
  /* Cinza de texto secundario do Figma do grupo (#818181, ligeiramente mais
     escuro que o --muted #878787 do individual). */
  --cinza-medio: #818181;
  --preto-texto: #1e1e1e;
  /* Cinza do card esgotado: fundo do card, moldura do logo e trilho da barra.
     Tons proximos do --bg para o card apagar sem virar um bloco escuro no
     meio da grade. */
  --cinza-esgotado: #ededee;
  --cinza-esgotado-fundo: #e2e2e3;
  --cinza-esgotado-trilho: #d8d8d9;
  --font: "Poppins", system-ui, -apple-system, "Segoe UI", sans-serif;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
}

img { max-width: 100%; display: block; }
button, input { font: inherit; }

.page {
  /* 100dvh (dynamic viewport height) com fallback: no mobile o 100vh conta a
     barra de endereco recolhida, e o rodape "colado no fundo" ficava abaixo da
     area visivel ate o usuario rolar. Navegador sem dvh usa a 1a linha. */
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* Topo ------------------------------------------------------------------ */

.topo {
  width: 100%;
  background: var(--red);
  box-shadow: 0 4px 4px -1px rgba(0, 0, 0, .25);
  padding: 8px 20px;
  display: flex;
  justify-content: flex-start;
  z-index: 1;
}

.topo__logo {
  height: 30px;
  width: auto;
}

/* Conteudo / hero --------------------------------------------------------- */

.conteudo {
  width: 100%;
  max-width: 1024px;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.hero {
  width: 100%;
  background: var(--red);
  padding: 10px 24px 16px;
  text-align: center;
}

.hero__badge {
  display: inline-block;
  background: var(--yellow);
  color: var(--red);
  font-weight: 600;
  font-size: 13px;
  padding: 1px 14px;
  border-radius: 999px;
  margin-bottom: 12px;
}

.hero__titulo {
    display: flex;
    flex-direction: column;
    margin: 0 auto;
    line-height: 1;
    max-width: fit-content;
}

.hero__titulo-linha {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  color: #fff;
  font-weight: 700;
  font-size: 30px;
}

.hero__flor {
  position: relative;
  width: 43px;
  height: 41px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.hero__flor img { width: 100%; height: 100%; }

.hero__flor-simbolo {
  position: absolute;
  color: #fff;
  font-weight: 800;
  font-size: 20px;
}

.hero__cupom {
  display: block;
  color: #8c1112;
  font-weight: 800;
  font-size: 58px;
  line-height: 1;
  margin-top: -14px;
}

.hero__agora {
  color: #fff;
  font-weight: 700;
  font-size: 15px;
  line-height: 1;
  margin-bottom: 10px;
  white-space: nowrap;
}

.hero_subtitulo{
  align-self: flex-end;
  top: -24px;
  left: -10px;
  position: relative;

}

.hero--frete {
  padding-bottom: 28px;
}

/* Titulo do hero p/ tipo_campanha = preco_exclusivo: "Promô" branco + "Especial"
   grande em amarelo, sem o icone-flor/"agora mesmo" do titulo padrao (node 31:23). */
.hero__titulo-preco-exclusivo {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin: 0 auto;
  line-height: 1;
}

.hero__promo {
  color: #fff;
  font-weight: 700;
  font-size: 26px;
}

.hero__especial {
  color: var(--yellow);
  font-weight: 800;
  font-size: 46px;
  margin-top: -4px;
}

/* Ticket de desconto ------------------------------------------------------ */

.ticket {
  position: relative;
  width: 220px;
  margin:-5px auto -74px;
}

.ticket__fundo {
  width: 100%;
  filter: drop-shadow(0 6px 8px rgba(0, 0, 0, .18));
}

.ticket__conteudo {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--red);
}

/* Reais: coluna "R$ / OFF" a esquerda + valor grande a direita */
.ticket__layout-reais {
  display: flex;
  align-items: center;
  gap: 8px;
}

.ticket__coluna-prefixo {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  line-height: 1;
}

.ticket__prefixo {
  font-weight: 600;
  font-size: 30px;
}

/* Percentual / frete gratis: valor numa linha, rotulo abaixo, ambos a esquerda */
.ticket__layout-percentual {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

.ticket__valor-grande {
  font-weight: 800;
  font-size: 40px;
  line-height: 1;
  letter-spacing: -1px;
  white-space: nowrap;
  position: relative;
    top: -3px;
}

.ticket__rotulo {
  font-weight: 500;
  font-size: 15px;
  letter-spacing: -0.3px;
  margin-top: -2px;
}

/* Frete gratis: sem balao (o Figma nao usa o ticket-vector pra esse estado),
   "Entrega" pequeno em branco em cima de "Gratis" grande em amarelo, direto
   no fundo vermelho do hero. Ativado junto com o modificador .ticket--frete,
   que esconde o .ticket__fundo (ver preencherTicket em js/app.js). */
.ticket__layout-frete {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  line-height: 1;
}

.ticket__rotulo-frete {
  color: #fff;
  font-weight: 700;
  font-size: 23px;
}

.ticket__valor-frete {
  color: var(--yellow);
  font-weight: 800;
  font-size: 62px;
  letter-spacing: -1px;
  margin-top: -8px;
}

.ticket--frete {
  width: auto;
  margin: 4px auto 4px;
}

.ticket--frete .ticket__fundo {
  display: none;
}

.ticket--frete .ticket__conteudo {
  position: relative;
  inset: auto;
}

/* Card do produto (tipo_campanha = preco_exclusivo) ------------------------ */

/* Substitui o .ticket para esse tipo de campanha. Fica dividido em duas pecas
   de proposito (node 31:2 do Figma):
     .produto-foto-wrap — ultimo filho do .hero: SO a foto fica contra o
       fundo vermelho, entao o vermelho termina exatamente na base da foto
       (nao no fim do card inteiro).
     .produto-corpo — secao seguinte, IRMA do .hero (fora dele): encosta
       direto na foto (mesma largura, sem margem entre os dois — ver
       .hero--preco-exclusivo abaixo) e ja fica sobre o fundo da pagina.
   Se as duas fossem um card so dentro do .hero, a altura do .hero cresceria
   junto com o corpo (nome/preco/parceiro) e o vermelho vazaria muito alem da
   foto — foi exatamente esse bug que motivou a divisao. */
.hero--preco-exclusivo {
  padding-bottom: 0;
}

.produto-foto-wrap {
  position: relative;
  width: calc(100% - 36px);
  max-width: 366px;
  height: 130px;
  margin: 4px auto 0;
  background: var(--bg);
  border-radius: 18px 18px 0 0;
  overflow: hidden;
}

.produto-foto {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.produto-badge {
  position: absolute;
  top: 10px;
  right: 10px;
  display: flex;
  align-items: center;
  gap: 4px;
  background: var(--laranja);
  color: #fff;
  font-weight: 700;
  font-size: 12px;
  padding: 4px 10px;
  border-radius: 5px;
}

.produto-badge-icone {
  width: 12px;
  height: 12px;
}

/* Duas camadas atras do conteudo (amarelo + branco por cima, deixando so uma
   lasca amarela visivel nas laterais, por baixo da foto) — mesma tecnica de
   .form-card/.card-oferta--frete (ver "Pegadinha de CSS conhecida" no
   CLAUDE.md deste repo). z-index:0 aqui cria o contexto de empilhamento que
   os pseudo-elementos precisam. */
.produto-corpo {
  position: relative;
  z-index: 0;
  width: calc(100% - 36px);
  max-width: 366px;
  margin: 0 auto 20px;
  padding: 14px 16px 16px;
  border-radius: 0 0 18px 18px;
  display: flex;
flex-direction: column;
    align-items: center;
}

.produto-corpo::before {
  content: '';
  position: absolute;
  inset: 0 0 -4px;
  background: var(--yellow);
  border-radius: inherit;
  z-index: -1;
}

.produto-corpo::after {
  content: '';
  position: absolute;
  inset: 0;
  background: #fff;
  border-radius: inherit;
  box-shadow: 0 7px 8px rgba(0, 0, 0, .15);
  z-index: -1;
}

.produto-corpo__cabecalho {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 12px;
}

.produto-corpo__categoria {
  flex-shrink: 0;
  background: var(--rosa-claro);
  color: var(--red);
  font-weight: 600;
  font-size: 10px;
  padding: 3px 10px;
  border-radius: 4px;
}

.produto-corpo__nome {
  font-weight: 700;
  font-size: 16px;
  color: var(--ink);
  letter-spacing: .1px;
}

.produto-corpo__preco {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 18px;
  background: rgba(255, 175, 46, .33);
  border: 1px solid var(--yellow);
  border-radius: 8px;
  padding: 8px 16px;
}

.produto-corpo__preco-de,
.produto-corpo__preco-por {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  line-height: 1.15;
}

.produto-corpo__preco-rotulo {
  font-weight: 500;
  font-size: 13px;
}

.produto-corpo__preco-de .produto-corpo__preco-rotulo { color: var(--red); }
.produto-corpo__preco-por .produto-corpo__preco-rotulo { color: var(--verde-frete-escuro); font-weight: 600; }

.produto-corpo__preco-valor-de {
  color: var(--red);
  font-weight: 500;
  font-size: 17px;
  text-decoration: line-through;
}

.produto-corpo__preco-valor-por {
  color: var(--verde-frete-escuro);
  font-weight: 600;
  font-size: 23px;
  letter-spacing: .2px;
}

.produto-corpo__estabelecimento-slot {
  width: 100%;
  margin-top: 12px;
}

/* card-estabelecimento nesse contexto (dentro do produto-corpo, GD-1732) ocupa
   a largura do corpo do card, em vez do max-width:280px + margin-bottom
   pensados pra ele flutuando solto na pagina (fluxo de cupom). */
.produto-corpo__estabelecimento-slot .card-estabelecimento {
  width: 100%;
  max-width: none;
  margin-bottom: 0;
}

/* Texto "exclusivo" -------------------------------------------------------- */

.exclusivo {
  color: var(--red);
  font-weight: 600;
  font-size: 15px;
  text-align: center;
  margin: 72px 24px 20px;
  line-height: 1.3;
}

/* Card "oferta" -------------------------------------------------------------- */

/* Wrapper em torno do card-estabelecimento. Por padrao (reais/percentual) e
   transparente e o card-estabelecimento aparece como card solto, igual sempre
   foi. No estado frete gratis ganha o modificador --frete: passa a ser o
   card grande com borda verde-amarela (mesma tecnica de duas camadas do
   .form-card) que engloba o titulo "Peca agora...", o selo "Taxa Gratis" e o
   card-estabelecimento nele dentro (ver node 208:36/37 do Figma). */
.card-oferta {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.card-oferta--frete {
  position: relative;
  z-index: 0;
  width: calc(100% - 36px);
  max-width: 384px;
  border-radius: 18px;
  padding: 20px 16px 18px;
  margin-bottom: 16px;
}

.card-oferta--frete::before {
  content: '';
  position: absolute;
  inset: -6px 0 0;
  background: var(--yellow);
  border-radius: inherit;
  z-index: -1;
}

.card-oferta--frete::after {
  content: '';
  position: absolute;
  inset: 0;
  background: #fff;
  border-radius: inherit;
  box-shadow: 0 6px 8px rgba(0, 0, 0, .12);
  z-index: -1;
}

.card-oferta--frete .card-estabelecimento {
  margin-bottom: 0;
  width: 100%;
  max-width: none;
}

.oferta-frete {
  text-align: center;
  margin-bottom: 16px;
}

.oferta-frete__titulo {
  color: var(--red);
  font-weight: 700;
  font-size: 15px;
  line-height: 1.3;
  margin: 0 0 14px;
}

.badge-frete {
  width: 168px;
  height: 48px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: var(--verde-frete-fundo);
  border: 1px solid var(--verde-frete-borda);
  border-radius: 8px;
}

.badge-frete__rotulo {
  color: var(--verde-frete-escuro);
  font-weight: 600;
  font-size: 11px;
  letter-spacing: .1px;
}

.badge-frete__valor {
  color: var(--verde-frete-escuro);
  font-weight: 700;
  font-size: 28px;
  line-height: 1.15;
  letter-spacing: .3px;
}

/* Card do estabelecimento --------------------------------------------------- */

.card-estabelecimento {
    width: calc(100% - 36px);
    max-width: 280px;
    max-height: 90px;
    background: #fff;
    border-radius: 14px;
    box-shadow: 0 4px 8px rgba(0, 0, 0, .12);
    padding: 10px;
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 15px;
}

.card-estabelecimento__logo {
  width: 52px;
  height: 52px;
  border-radius: 10px;
  overflow: hidden;
  flex-shrink: 0;
  background: var(--bg);
}

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

.card-estabelecimento__info {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.card-estabelecimento__nome {
  font-weight: 500;
  font-size: 14px;
  color: var(--ink);
}

.card-estabelecimento__selo {
  align-self: flex-start;
  background: #95dd43;
  color: #fff;
  font-weight: 700;
  font-size: 9px;
  padding: 2px 8px;
  border-radius: 6px;
  white-space: nowrap;
}

.card-estabelecimento__linha-detalhe {
  color: var(--muted);
  font-size: 10px;
}

.card-estabelecimento__avaliacao {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  gap: 4px;
  font-size: 7px;
}

.card-estabelecimento__estrela {
  width: 10px;
  height: 10px;
}

.card-estabelecimento__avaliacao span:nth-child(2) {
  color: var(--rating);
  font-weight: 600;
}

.card-estabelecimento__qtde-avaliacoes {
  color: var(--muted);
}

/* Barra de progresso -------------------------------------------------------- */

.progresso {
  width: calc(100% - 36px);
  max-width: 384px;
  background: #fff;
  border-radius: 14px;
  box-shadow: 0 4px 8px rgba(0, 0, 0, .12);
  padding: 14px 18px;
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 12px;
}

.progresso__icone {
  position: relative;
  width: 42px;
  height: 42px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.progresso__icone-fundo,
.progresso__icone-vetor {
  position: absolute;
  width: 100%;
  height: 100%;
}

.progresso__icone-vetor {
  width: 60%;
  height: 60%;
}

.progresso__icone-simbolo {
  position: relative;
  color: var(--red);
  font-weight: 800;
  font-size: 15px;
}

.progresso__icone-frete {
  position: absolute;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background: var(--verde-frete-barra);
  display: flex;
  align-items: center;
  justify-content: center;
}

.progresso__icone-frete img {
  width: 55%;
  height: 55%;
}

.progresso--frete .progresso__titulo {
  color: var(--verde-frete);
}

.progresso--frete .progresso__barra-preenchida {
  background: var(--verde-frete-barra);
}

.progresso__icone-preco-exclusivo {
  position: absolute;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background: var(--laranja);
  display: flex;
  align-items: center;
  justify-content: center;
}

.progresso__icone-preco-exclusivo img {
  width: 55%;
  height: 55%;
}

.progresso--preco-exclusivo .progresso__titulo {
  color: var(--laranja);
}

.progresso--preco-exclusivo .progresso__barra-preenchida {
  background: var(--laranja);
}

.progresso__corpo {
  flex: 1;
}

.progresso__cabecalho {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 6px;
}

.progresso__titulo {
  color: var(--red);
  font-weight: 600;
  font-size: 14px;
}

.progresso__percentual {
  color: var(--muted);
  font-size: 10px;
}

.progresso__barra {
  background: #eee;
  border-radius: 6px;
  height: 11px;
  overflow: hidden;
}

.progresso__barra-preenchida {
  background: var(--red);
  height: 100%;
  border-radius: 6px;
  width: 0%;
  transition: width .4s ease;
}

/* Card do formulario ---------------------------------------------------------- */

/* No Figma, o card e formado por duas camadas: um retangulo amarelo atras e o
   card branco na frente (mesma largura/base, so 4px mais baixo no topo) — o
   branco cobre o amarelo quase todo, sobrando so uma lasca no topo.
   Reproduzido com dois pseudo-elementos em vez do background do proprio
   .form-card: o background do elemento pinta sempre ANTES de seus filhos
   (mesmo os de z-index negativo), entao colocar o branco ali faria o
   ::before amarelo aparecer por cima dele, cobrindo o card todo. */
.form-card {
  /* z-index:0 cria um contexto de empilhamento proprio: sem isso, ::before
     e ::after (z-index negativo) escapam para fora do card em vez de ficar
     entre o retangulo amarelo e o conteudo real. */
  position: relative;
  z-index: 0;
  width: calc(100% - 36px);
  max-width: 384px;
  border-radius: 22px;
  padding: 22px 20px;
  margin-bottom: 40px;
  text-align: center;
}

.form-card::before {
  content: '';
  position: absolute;
  inset: -4px 0 0;
  background: var(--yellow);
  border-radius: inherit;
  z-index: -1;
}

.form-card::after {
  content: '';
  position: absolute;
  inset: 0;
  background: #fff;
  border-radius: inherit;
  box-shadow: 0 6px 8px rgba(0, 0, 0, .12);
  z-index: -1;
}

/* Frete gratis: a lasca do card do telefone e vermelha no Figma, nao amarela */
.form-card--frete::before {
  background: var(--red);
}

.form-estado p { margin: 0; color: var(--muted); font-size: 14px; }
.form-estado strong { color: var(--red); }
.is-oculto { display: none; }

.form-resgate.is-oculto { display: none; }

.form-resgate__titulo {
  color: var(--red-footer);
  font-weight: 600;
  font-size: 16px;
  margin: 0 0 16px;
  line-height: 1.3;
}

.form-resgate__label {
  display: block;
  text-align: left;
  font-weight: 600;
  font-size: 12px;
  color: var(--ink);
  margin-bottom: 6px;
}

.form-resgate__input {
  width: 100%;
  height: 39px;
  border: 1px solid var(--line);
  background: var(--bg);
  border-radius: 6px;
  padding: 0 14px;
  font-size: 15px;
  color: var(--ink);
}

.form-resgate__input::placeholder { color: var(--muted-light); }

.form-resgate__input.is-invalido { border-color: var(--red); }

.form-resgate__mensagem {
  color: var(--red);
  font-size: 12px;
  font-weight: 600;
  margin: 8px 0 0;
  text-align: left;
}

.form-resgate__botao {
  width: 100%;
  height: 39px;
  margin-top: 12px;
  background: var(--red);
  color: #fff;
  border: none;
  border-radius: 6px;
  font-weight: 500;
  font-size: 15px;
  cursor: pointer;
}

.form-resgate__botao:disabled {
  opacity: .6;
  cursor: default;
}

.form-resgate__botao:not(:disabled):hover {
  background: var(--red-footer);
}

/* CTA que substitui o botao de resgate no aviso de 'ja resgatou': quem ja
   resgatou tem o cupom na conta e so precisa abrir o app, entao o aviso vem com
   o mesmo deep link do #form-resultado-cta — e no lugar do .form-resgate__botao
   (ver o submit em js/app.js), pra nao sobrar dois botoes no card. Mesmo
   vermelho do botao que ele substitui: ali ele e a unica acao. Reafirma
   .is-oculto porque declara o proprio `display` (link e inline por padrao) e vem
   DEPOIS da regra generica — mesma pegadinha do .form-resultado__botao abaixo. */
.form-resgate__cta.is-oculto { display: none; }

.form-resgate__cta {
  display: block;
  width: 100%;
  height: 39px;
  line-height: 39px;
  margin-top: 12px;
  background: var(--red);
  color: #fff;
  border-radius: 6px;
  font-weight: 500;
  font-size: 15px;
  text-align: center;
  text-decoration: none;
}

.form-resgate__cta:hover { background: var(--red-footer); }

/* CTA do resultado 'voucher' (node 338:60 do Figma) — mesmo visual do botao de
   resgate, mas e um <a> (deep link), entao precisa do proprio display (um link
   e inline por padrao) e da reafirmacao de .is-oculto (a classe generica vem
   ANTES no arquivo — mesma pegadinha do .cta-secundaria acima). */
.form-resultado__botao.is-oculto { display: none; }

.form-resultado__botao {
  display: block;
  width: 271px;
  max-width: 100%;
  height: 39px;
  line-height: 39px;
  margin: 20px auto 0;
  background: var(--red);
  color: #fff;
  border: none;
  border-radius: 6px;
  font-weight: 500;
  font-size: 15px;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
}

.form-resultado__botao:hover {
  background: var(--red-footer);
}

/* Rodape ------------------------------------------------------------------ */

.rodape {
  /* Rodape sempre no fundo: como ultimo filho do .page (flex column), o auto
     absorve a sobra vertical e o encosta na base quando o conteudo e curto —
     e nao faz nada quando o conteudo passa da viewport, entao a pagina longa
     continua idêntica.

     Feito aqui, e nao com `flex: 1` no .conteudo, de proposito: esticar o main
     mudaria a distribuicao interna dele (ele tem align-items/justify proprios)
     e mexeria no layout individual, que precisa ficar intacto. */
  margin-top: auto;
  width: 100%;
  background: var(--red-footer);
  border-radius: 24px 24px 0 0;
  padding: 26px 24px 22px;
  text-align: center;
  box-shadow: 0 -4px 8px rgba(0, 0, 0, .1);
}

.rodape__hashtag {
  color: #fff;
  font-weight: 700;
  font-size: 13px;
  margin: 0 0 14px;
}

.rodape__hashtag--medium { font-weight: 500; }
.rodape__hashtag--destaque { color: var(--yellow-strong); font-weight: 700; }

.rodape__botoes {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 10px;
  margin-bottom: 14px;
}

.rodape__botao-app img { height: 38px; width: auto; }

.rodape__botao-social {
  width: 38px;
  height: 38px;
  border-radius: 8px;
  background: var(--yellow-strong);
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 3px rgba(0, 0, 0, .25);
}

.rodape__botao-social img {
  width: 22px;
  height: 22px;
}



.rodape__copyright {
  color: #fff;
  font-size: 9px;
  font-weight: 400;
  margin: 0;
  opacity: .9;
}

/* Responsivo --------------------------------------------------------------- */

@media (min-width: 480px) {
  .hero__cupom { font-size: 64px; }
}

@media (min-width: 1024px) {
  .hero {
    border-radius: 0 0 10px 10px;
  }
}

/* ==========================================================================
   CAMPANHA DE GRUPO (<base>/grupos?campanha=<slug>)
   Layout do arquivo Figma "Resgate DeliveryGame" (8fMTOtzRe9y9UBxzYsbka7),
   frame de 402px adaptado para fluxo responsivo — mesma abordagem do
   individual. Bloco isolado de proposito: nenhuma regra daqui usa seletor do
   fluxo individual, entao mexer aqui nao pode alterar a pagina de hoje.
   ========================================================================== */

/* .is-oculto e declarado LA EM CIMA, com a mesma especificidade (uma classe)
   das regras deste bloco. Como aqui vem depois no arquivo, um display:flex/grid
   daqui venceria o display:none e o elemento nunca esconderia. Reafirma o
   esconde com dois seletores de classe (mesmo motivo de .form-resgate.is-oculto). */
.grupo.is-oculto,
.grupo-cabecalho.is-oculto,
.grupo-entrada.is-oculto,
.grupo-resgates-especiais.is-oculto,
.grupo-premios.is-oculto,
.grupo-final.is-oculto,
.grupo-modal.is-oculto,
.premio-fisico.is-oculto { display: none; }

.grupo {
  width: 100%;
  max-width: 1024px;
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* Cabecalho branco (node 1:219) ------------------------------------------- */

/* No Figma o frame do cabecalho tem 163px e comeca em y=-50, ou seja: 113px
   visiveis, com o avatar de 72px a 20px do topo visivel. */
.grupo-cabecalho {
  width: 100%;
  background: #fff;
  border-radius: 0 0 27px 27px;
  box-shadow: 0 4px 4px rgba(0, 0, 0, .25);
  padding: 20px 24px 21px;
  display: flex;
  align-items: center;
  gap: 16px;
  z-index: 1;
}

.grupo-cabecalho__avatar {
  width: 72px;
  height: 72px;
  flex-shrink: 0;
}

.grupo-cabecalho__nome {
  color: var(--red);
  font-weight: 500;
  font-size: 20px;
  min-width: 0;
}

/* Tela de entrada: hero + telefone (node 1:2) ----------------------------- */

.grupo-entrada {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* Retangulo vermelho de y=0 a y=236 com raio 26. Os cantos de cima ficam
   escondidos atras da faixa .topo (mesma cor), entao so os de baixo arredondam. */
.grupo-hero {
  width: 100%;
  background: var(--red);
  border-radius: 0 0 26px 26px;
  padding: 25px 24px 30px;
}

.grupo-hero__titulo {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  max-width: fit-content;
  margin: 0 auto;
}

.grupo-hero__linha {
  margin: 0;
  display: flex;
  align-items: center;
  gap: 15px;
}

.grupo-hero__fique-on {
  color: #fff;
  font-weight: 700;
  font-size: 34px;
  line-height: 1;
}

/* Mesma flor-percentual.svg do individual (.hero__flor), aqui em 51px e com o
   "%" em 28px, como no node 1:69/1:70. */
.grupo-hero__flor {
  position: relative;
  width: 51px;
  height: 51px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.grupo-hero__flor img { width: 100%; height: 100%; }

.grupo-hero__flor-simbolo {
  position: absolute;
  color: #fff;
  font-weight: 800;
  font-size: 28px;
}

/* "Resgate" sobe por cima do "Fique ON!" (no Figma os dois textos se sobrepoem:
   topos em y=87 e y=99 com corpos de 34px e 73px). */
.grupo-hero__resgate {
  margin: -8px 0 0;
  color: #8c1112;
  font-weight: 800;
  font-size: 62px;
  line-height: 1;
  letter-spacing: -1px;
}

.grupo-hero__premio {
  margin: -6px 0 0;
  align-self: flex-end;
  color: #fff;
  font-weight: 700;
  font-size: 18px;
  line-height: 1;
}

.grupo-entrada__form {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* Card do telefone: duas camadas (amarelo atras + branco na frente, sobrando
   uma lasca de 3px no topo). Mesma tecnica do .form-card do individual — e a
   mesma pegadinha: os pseudo-elementos tem z-index negativo, entao o card
   PRECISA de position:relative + z-index:0 para criar contexto de empilhamento
   (ver "Pegadinha de CSS conhecida" no CLAUDE.md). */
.grupo-formulario {
  position: relative;
  z-index: 0;
  width: calc(100% - 36px);
  max-width: 366px;
  border-radius: 23px;
  padding: 26px 20px 32px;
  margin-top: 49px;
  text-align: center;
}

.grupo-formulario::before {
  content: '';
  position: absolute;
  inset: -3px 0 0;
  background: var(--yellow);
  border-radius: inherit;
  z-index: -1;
}

.grupo-formulario::after {
  content: '';
  position: absolute;
  inset: 0;
  background: #fff;
  border-radius: inherit;
  box-shadow: 0 7px 7.8px rgba(0, 0, 0, .15);
  z-index: -1;
}

.grupo-formulario__titulo {
  color: var(--red-footer);
  font-weight: 600;
  font-size: 17px;
  line-height: 1.2;
  margin: 0 0 22px;
}

/* Label e input tem 271px no Figma (mais estreitos que os 326px internos do
   card) e ficam centralizados; a label alinha com a borda esquerda do input. */
.grupo-formulario__label {
  display: block;
  max-width: 271px;
  margin: 0 auto 6px;
  text-align: left;
  font-weight: 600;
  font-size: 12px;
  color: var(--ink);
}

.grupo-formulario__input {
  display: block;
  width: 100%;
  max-width: 271px;
  height: 39px;
  margin: 0 auto;
  border: 1px solid var(--line);
  background: var(--bg);
  border-radius: 6px;
  padding: 0 14px;
  font-size: 15px;
  color: var(--ink);
}

.grupo-formulario__input::placeholder { color: var(--muted-light); }

.grupo-formulario__input.is-invalido { border-color: var(--red); }

.grupo-formulario__mensagem {
  max-width: 271px;
  margin: 8px auto 0;
  color: var(--red);
  font-weight: 600;
  font-size: 12px;
  text-align: left;
}

.grupo-avancar {
  width: calc(100% - 36px);
  max-width: 271px;
  height: 39px;
  margin: 35px 0 40px;
  background: var(--red);
  color: #fff;
  border: none;
  border-radius: 6px;
  font-weight: 500;
  font-size: 15px;
  cursor: pointer;
}

.grupo-avancar:disabled { opacity: .6; cursor: default; }
.grupo-avancar:not(:disabled):hover { background: var(--red-footer); }

/* Lista de resgates especiais (GD-1787) --------------------------------------------- */

/* Tela sem Figma: reaproveita os tokens e as medidas da grade (mesmo padding
   lateral de 21px, mesmo titulo vermelho) para nao introduzir um terceiro
   dialeto visual no fluxo de grupo. O botao e o mesmo .grupo-avancar da tela
   de entrada.

   Uma linha por resgate especial, e nao um contador so: o usuario precisa reconhecer
   DE QUAL pedido veio cada resgate (estabelecimento + data) — e o que torna
   verificavel a promessa "cada pedido no periodo vale um premio". */
.grupo-resgates-especiais {
  width: 100%;
  margin: 0 auto;
  padding: 0 21px 28px;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.grupo-resgates-especiais__titulo {
  color: var(--red-footer);
  font-weight: 700;
  font-size: 36px;
  line-height: 1.05;
  text-align: center;
  margin: 24px 0 12px;
}

.grupo-resgates-especiais__texto {
  max-width: 360px;
  margin: 0 0 20px;
  color: #555;
  font-size: 14px;
  line-height: 1.4;
  text-align: center;
}

/* A lista cresce com o numero de pedidos do usuario e nao pode empurrar o
   "Escolher um prêmio" para fora da tela — quem tem 8 resgates nao veria o botao
   que e o proximo passo. Cada linha custa 75px (65 + 10 de gap), entao o teto
   corta no MEIO da quarta: meia linha visivel e o que sinaliza que ha mais, sem
   depender de o usuario notar a barra de rolagem.

   min() com 40vh porque px fixo sozinho quebra em tela baixa (celular em
   paisagem): la o teto vira 40% da altura, e o botao continua visivel.

   overscroll-behavior: contain para o fim da lista nao virar rolagem da pagina —
   o gesto continua onde comecou. */
.grupo-resgates-especiais__lista {
  width: 100%;
  max-width: 360px;
  max-height: min(255px, 40vh);
  overflow-y: auto;
  overscroll-behavior: contain;
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* O flex mora no botao porque a linha inteira e o alvo do clique. */
.grupo-resgate-especial { list-style: none; }

.grupo-resgate-especial__botao {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border: 1px solid #e6e6e6;
  border-radius: 10px;
  background: #fff;
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: border-color .15s, box-shadow .15s;
}

.grupo-resgate-especial__botao:hover,
.grupo-resgate-especial__botao:focus-visible {
  border-color: var(--red);
  box-shadow: 0 2px 10px rgba(0, 0, 0, .08);
}


/* Quadrado, e nao circulo: logo de loja e retangular e o recorte redondo come
   nome e simbolo na borda. contain para nao distorcer logo largo. */
.grupo-resgate-especial__logo {
  flex: none;
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  border-radius: 10px;
  overflow: hidden;
  background: #f4f4f4;
}

.grupo-resgate-especial__imagem {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.grupo-resgate-especial__dados {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.grupo-resgate-especial__estabelecimento {
  color: #222;
  font-weight: 600;
  font-size: 14px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.grupo-resgate-especial__pedido {
  color: #777;
  font-size: 12px;
}

/* Aparencia de botao; o clicavel e a linha (button aninhado seria invalido). */
.grupo-resgate-especial__cta {
  flex: none;
  padding: 8px 14px;
  border-radius: 999px;
  background: var(--red);
  color: #fff;
  font-weight: 700;
  font-size: 13px;
  line-height: 1;
  white-space: nowrap;
}

/* Resgate especial ja gasto continua na lista, apagado: sumir com a linha faria a
   contagem "3 pedidos, 3 premios" nao fechar com o que a pessoa ve. */
/* Grade de premios (node 1:105) ------------------------------------------- */

/* 402px de frame com 21px de margem: 360px de conteudo = 2 x 174 + 12 de gap.
   O row-gap de 32px e a distancia entre a barra de um card e o card de baixo. */
.grupo-premios {
  width: 100%;
  margin: 0 auto;
  padding: 0 21px;
}

.grupo-premios__titulo {
  color: var(--red-footer);
  font-weight: 700;
  font-size: 36px;
  line-height: 1.05;
  text-align: center;
  margin: 24px 0 23px;
}

.grupo-premios__aviso {
  color: var(--red);
  font-weight: 600;
  font-size: 13px;
  text-align: center;
  margin: 0 0 16px;
}

/* minmax(0, 1fr) e nao 1fr: o piso de `1fr` e min-content, entao a coluna com o
   conteudo indivisivel mais largo (nome de premio com palavra comprida) crescia e
   a outra encolhia — as duas colunas saiam com larguras diferentes. */
.grupo-grade {
  list-style: none;
  margin: 0 0 40px;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 32px 12px;
}

/* O <li> empilha card + barra; o card leva flex:1 para que dois cards da mesma
   linha fiquem da mesma altura (rotulos tem 1, 2 ou 3 linhas) e as barras
   continuem alinhadas — o Figma resolve isso com altura fixa de 213px. */
.grupo-card {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

/* min-width: 0 porque <button> nao encolhe abaixo do proprio min-content: sem
   isso um nome de premio comprido estica o card para fora da coluna. */
.grupo-card__botao {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  background: #fff;
  border: none;
  border-radius: 15px;
  box-shadow: 0 4px 4px rgba(0, 0, 0, .25);
  padding: 13px 19px 16px;
  font: inherit;
  color: inherit;
  text-align: center;
  cursor: pointer;
}

.grupo-card__foto {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 1;
  border-radius: 10px;
  overflow: hidden;
  background: var(--bg);
}

.grupo-card__imagem {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.grupo-card__premio {
  display: block;
  overflow-wrap: anywhere;
  margin-top: 14px;
  font-weight: 500;
  font-size: 16px;
  line-height: 1.15;
  color: var(--ink);
}

/* Nome do estabelecimento: o Figma nao mostra esse texto no card (as camadas
   dele estao todas nomeadas "Pizzaria", mas o conteudo renderizado e so o
   "75%" da barra). Sem ele, num grupo com varias lojas, o unico jeito de saber
   de quem e o premio seria reconhecer o logo. */
.grupo-card__estabelecimento {
  display: block;
  overflow-wrap: anywhere;
  margin-top: 6px;
  font-size: 10px;
  line-height: 1.2;
  color: var(--muted);
}

/* Estado esgotado (encerrada=true ou resgates_restantes=0). O Figma nao desenha
   esse estado — o tratamento cinza + selo e decisao daqui. */
.grupo-card__esgotado {
  position: absolute;
  top: 8px;
  right: 8px;
  display: none;
  background: var(--muted);
  color: #fff;
  font-weight: 700;
  font-size: 10px;
  padding: 2px 8px;
  border-radius: 4px;
}

/* Esgotado (100% resgatado, ou campanha encerrada): o CARD INTEIRO fica cinza e
   nao clicavel — fundo, logo, textos e barra. Antes so o logo perdia a cor e o
   card seguia branco igual aos disponiveis, o que nao lia como desabilitado. */
.grupo-card--esgotado .grupo-card__esgotado { display: block; }

.grupo-card--esgotado .grupo-card__botao,
.grupo-card--esgotado .grupo-card__progresso {
  background: var(--cinza-esgotado);
  box-shadow: none;
  cursor: default;
}

.grupo-card--esgotado .grupo-card__foto { background: var(--cinza-esgotado-fundo); }
.grupo-card--esgotado .grupo-card__imagem { filter: grayscale(1); opacity: .45; }
.grupo-card--esgotado .grupo-card__premio,
.grupo-card--esgotado .grupo-card__estabelecimento,
.grupo-card--esgotado .grupo-card__progresso-titulo,
.grupo-card--esgotado .grupo-card__progresso-percentual { color: var(--muted); }

/* A barra vazia (0% restante) continua visivel: o trilho um tom mais escuro
   deixa claro que e "sem cupom", em vez de sumir e parecer falha de render. */
.grupo-card--esgotado .grupo-card__barra { background: var(--cinza-esgotado-trilho); }
.grupo-card--esgotado .grupo-card__barra-preenchida { background: var(--muted-light); }

/* Nada de hover de item clicavel quando esta desabilitado. */
.grupo-card--esgotado .grupo-card__botao:hover { background: var(--cinza-esgotado); }

/* Barra "Cupons Restantes": card separado, logo abaixo do card do premio
   (node 7:351), 54px de altura no Figma. */
.grupo-card__progresso {
  margin-top: 8px;
  background: #fff;
  border-radius: 13px;
  box-shadow: 0 7px 7.8px rgba(0, 0, 0, .15);
  padding: 10px 8px 11px;
}

.grupo-card__progresso-cabecalho {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 4px;
  margin-bottom: 8px;
}

/* Sem `white-space: nowrap`: com a coluna limitada a minmax(0, 1fr) o texto que
   nao cabe vazaria para fora do card branco em telas estreitas; quebrar em duas
   linhas e o menor dos males. */
.grupo-card__progresso-titulo {
  color: var(--red);
  font-weight: 500;
  font-size: 13px;
}

.grupo-card__progresso-percentual {
  color: var(--cinza-medio);
  font-size: 9px;
}

.grupo-card__barra {
  background: #eee;
  border-radius: 6px;
  height: 11px;
  overflow: hidden;
}

.grupo-card__barra-preenchida {
  background: var(--red);
  height: 100%;
  border-radius: 6px;
  width: 0;
  transition: width .4s ease;
}

/* Modal de confirmacao (node 7:342) --------------------------------------- */

.grupo-modal {
  position: fixed;
  inset: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  /* No Figma (node 4:340) a grade fica esmaecida atras do modal. */
  background: rgba(247, 248, 249, .75);
  backdrop-filter: blur(3px);
}

.grupo-modal__caixa {
  width: 100%;
  max-width: 340px;
  background: #fff;
  border-radius: 13px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, .18);
  padding: 19px 18px 20px;
  text-align: center;
}

.grupo-modal__titulo {
  margin: 0 0 12px;
  color: var(--red);
  font-weight: 700;
  font-size: 20px;
  line-height: 1.15;
}

/* Linha "cupom — Estabelecimento" do modal de troca: identifica o premio entre o
   titulo e a explicacao. Mais escura e mais pesada que o .grupo-modal__texto de
   proposito — e o dado da tela, nao o texto de apoio. */
.grupo-modal__premio {
  margin: 0 0 10px;
  color: var(--preto-texto);
  font-weight: 600;
  font-size: 14px;
}

.grupo-modal__texto {
  margin: 0 0 16px;
  color: var(--cinza-medio);
  font-weight: 200;
  font-size: 13px;
  /* A confirmacao da troca tem duas frases em linhas separadas, e o JS as escreve
     com \n via textContent (em vez de innerHTML, que aqui receberia dado vindo do
     servidor). Sem isto as duas sairiam coladas na mesma linha. */
  white-space: pre-line;
}

.grupo-modal__acoes {
  display: flex;
  justify-content: center;
  gap: 11px;
}

.grupo-modal__botao {
  width: 103px;
  height: 32px;
  border-radius: 4px;
  font-weight: 600;
  font-size: 16px;
  cursor: pointer;
}

.grupo-modal__botao:disabled { opacity: .6; cursor: default; }

.grupo-modal__botao--nao {
  background: #eee;
  border: 1px solid rgba(0, 0, 0, .17);
  color: var(--cinza-medio);
}

.grupo-modal__botao--sim {
  background: var(--red-footer);
  border: none;
  color: #fff;
}

/* Modal de troca de resgate (GD-1809): so as diferencas do modal de
   confirmacao. Nao precisa reafirmar o .is-oculto — ele usa a classe
   .grupo-modal, ja coberta pelo bloco de is-oculto la de cima. */

.grupo-modal__acoes--empilhado {
  flex-direction: column;
  align-items: center;
}

/* "Usar meu premio"/"Trocar meu premio" nao cabem nos 103px do Sim/Nao. */
.grupo-modal__botao--largo {
  width: 100%;
  max-width: 220px;
}

/* Box do premio que a pessoa ja tem, grudado no topo da grade (GD-1809).
   Fundo branco e sombra como o .grupo-modal__caixa, mas dentro do fluxo da
   pagina: a grade fica visivel atras/abaixo dele. */
.grupo-premio-atual {
  position: sticky;
  top: 0;
  z-index: 5;
  background: #fff;
  border-radius: 13px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, .18);
  padding: 16px 18px 18px;
  margin-bottom: 18px;
  text-align: center;
}

/* Reafirma o esconde com dois seletores: o .is-oculto e declarado no meio do
   arquivo e perderia para o `display: block` implicito deste bloco. */
.grupo-premio-atual.is-oculto { display: none; }

.grupo-premio-atual__titulo {
  margin: 0 0 10px;
  color: var(--red);
  font-weight: 700;
  font-size: 18px;
  line-height: 1.15;
}

.grupo-premio-atual__texto {
  margin: 0 0 14px;
  color: var(--cinza-medio);
  font-weight: 200;
  font-size: 13px;
}

/* Card bloqueado porque a pessoa ja tem premio (GD-1809): usa o cinza do
   .grupo-card--esgotado, mas CONTINUA clicavel — o clique abre a explicacao, em
   vez de nao fazer nada. Por isso desfaz o `cursor: default` que o esgotado
   aplica no botao. */
.grupo-card--bloqueado .grupo-card__botao { cursor: pointer; }

/* Confirmacao da TROCA (GD-1809): "Trocar prêmio" em cima e "Voltar" embaixo.
   column-reverse, e nao reordenar o HTML: no modal a acao primaria e o segundo
   botao do DOM (Nao, Sim — a ordem do Figma no modo lado a lado, que continua em
   producao no fluxo normal de resgate). Inverter o HTML resolveria aqui e mexeria
   la. O foco ja abre no primario (modalSim.focus), entao o teclado nao depende
   dessa ordem visual. */
.grupo-modal__acoes--empilhado-inverso {
  flex-direction: column-reverse;
}

/* O "Usar cupom" e uma <a> (deep link), entao nao herda o centro que o <button>
   da de graca. */
a.grupo-modal__botao {
  display: flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
}

/* Telas de sucesso / "ja resgatou" (nodes 7:491 e 7:505) ------------------ */

/* As duas telas tem a mesma estrutura: arte no topo (o retangulo vermelho
   girado + foto/ilustracao, exportado do Figma como uma imagem so — mesmo caso
   "flatten" do botao-abrir-app.png descrito no CLAUDE.md), titulo, paragrafo e
   uma moeda no rodape. Trocam so a arte e os textos, via JS.
   As moedas tambem vem prontas do Figma JA giradas (13.8deg / -30.83deg /
   -16.51deg) e ja cortadas na borda do frame, entao aqui nao ha transform:
   basta encostar cada uma na borda certa. */
.grupo-final {
  width: 100%;
  margin: 0 auto;
  background: #fff;
  overflow: hidden;
  /* Coluna que ocupa a altura sobrando dentro do .page: e o que permite a moeda
     do rodape encostar no fim da pagina (margin-top: auto nela) em vez de ficar
     logo depois do texto, deixando vazio embaixo em tela alta. */
  display: flex;
  flex-direction: column;
  flex: 1;
}

/* As telas finais sao brancas de ponta a ponta no Figma, e nao uma coluna
   branca sobre o cinza do body. Modificador aplicado no .page pelo JS so nessas
   duas telas (o fluxo individual nunca recebe essa classe). */
.page--final { background: #fff; }

/* A arte tem 402x480 no Figma; o aspect-ratio mantem as moedas (posicionadas em
   % da altura) no mesmo lugar em qualquer largura. */
.grupo-final__hero {
  position: relative;
  width: 100%;
  aspect-ratio: 402 / 480;
}

.grupo-final__arte {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.grupo-final__moeda { position: absolute; }

/* O `left` negativo sangra a moeda pra fora da borda esquerda do frame, como no
   Figma. O z-index tira ela de baixo do titulo (.grupo-final__titulo tambem
   cria contexto proprio pra escapar da moeda lateral, mais abaixo). */
.grupo-final__moeda--topo {
  left: -30px;
  top: 8.54%;
  width: 37.06%;
  z-index: 10;
}

/* 74x123 em (328, 345) */
.grupo-final__moeda--lateral {
  right: 0;
  top: 71.87%;
  width: 18.41%;
}

.grupo-final__texto {
  padding: 0 24px;
}

/* O titulo comeca 12px acima do fim da arte no Figma (y=468 contra y=480). Essa
   margem negativa o sobrepoe a `.grupo-final__moeda--lateral`, que e
   position:absolute (renderiza acima de conteudo estatico, mesmo vindo antes
   no DOM) — sem position:relative + z-index aqui, o texto ficava atras da
   moeda. */
.grupo-final__titulo {
  margin: -12px 0 0;
  color: var(--preto-texto);
  font-weight: 700;
  font-size: 40px;
  line-height: 1.2;
  position: relative;
  z-index: 50;
}

/* O Figma usa Inter Regular 23px aqui; mantido em Poppins (a familia do resto
   do site, ja carregada) em 20px, que ocupa a mesma largura visual. */
.grupo-final__descricao {
  margin: 24px 0 0;
  color: var(--preto-texto);
  font-weight: 500;
  font-size: 20px;
  line-height: 1.25;
}

/* 211x102 em (150, 750): cortada na base do frame, encosta no fim da pagina.
   margin-top: auto empurra para o fundo (o `flex: 1` do .grupo-final da a folga);
   o 48px viria a menos que isso, entao fica como distancia MINIMA do texto. */
/* Arte propria da campanha: composicao de tela cheia, entao os enfeites do
   layout padrao saem de cena e a arte aparece inteira em vez de cortada no
   402/480 do hero. Dois seletores de classe para vencer as regras de cima. */
.grupo-final--arte-propria .grupo-final__moeda,
.grupo-final--arte-propria .grupo-final__moeda-rodape { display: none; }

.grupo-final--arte-propria .grupo-final__hero { aspect-ratio: auto; }

.grupo-final--arte-propria .grupo-final__arte {
  height: auto;
  object-fit: contain;
}

.grupo-final__moeda-rodape {
  width: 52.49%;
  margin: 48px 0 0 37.31%;
  margin-top: auto;
  padding-top: 48px;
  flex: none;
}

/* Responsivo do grupo ----------------------------------------------------- */

/* Mobile e tablet: conteudo de ponta a ponta, sem faixa do fundo (--bg #f7f8f9,
   quase branco) sobrando nas laterais. O frame do Figma tem 402px, mas prender a
   largura nele deixava a coluna no meio de uma moldura clara em qualquer tela
   maior que isso. O cap volta no desktop, ai de proposito (abaixo).

   `body.lp-grupo` e posto pelo JS somente na rota /grupos: o fluxo individual
   nunca recebe a classe e continua com o layout de antes. */
@media (min-width: 1024px) {
  /* Desktop: vista centrada com altura maxima, em vez de uma pagina esticada com
     o conteudo de 402px perdido no topo de uma tela de 1400px. */
  body.lp-grupo {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    min-height: 100dvh;
    background: var(--bg);
  }

  body.lp-grupo .page {
    width: 402px;
    max-height: 860px;
    /* zera o min-height:100dvh do .page: aqui quem manda e o max-height */
    min-height: 0;
    border-radius: 28px;
    overflow: hidden auto;
    box-shadow: 0 18px 50px rgba(0, 0, 0, .18);
    background: #fff;
  }

  /* Dentro da vista centrada o conteudo volta a largura do frame. */
  body.lp-grupo .grupo-premios,
  body.lp-grupo .grupo-resgates-especiais,
  body.lp-grupo .grupo-final {
    max-width: 402px;
  }

  /* O cabecalho arredondado embaixo encostaria na borda arredondada do cartao. */
  body.lp-grupo .grupo-cabecalho {
    border-radius: 0;
  }
}

/* O frame do Figma tem 402px; so a partir dai cabe o "Resgate" em 73px com as
   margens de 45px do design. */
@media (min-width: 420px) {
  .grupo-hero {
    padding-left: 45px;
    padding-right: 45px;
  }

  .grupo-hero__resgate { font-size: 73px; }
}

/* ==========================================================================
   PREMIO FISICO (GD-1761 follow-up)
   Roleta de um resultado ja sorteado no servidor — cores reaproveitadas
   do sistema existente, sem paleta nova: o dourado das moedas (--yellow-strong)
   vira o fundo da roleta e uma das duas cores do disco (o motivo moeda=premio
   ja existia no site), alternada com --laranja (ja usado no hover do
   .cta-secundaria) pra dar contraste real entre fatias — --yellow ficava
   proximo demais de --yellow-strong e as fatias somem visualmente;
   --cinza-esgotado e a mesma familia usada pro card de cupom esgotado em
   outro lugar do site, aqui reaproveitada pra "não ganhou" — mesma ideia
   visual (nada a reivindicar agora), sem tratar como erro.
   ========================================================================== */

/* .cta-secundaria declara o proprio `display`, entao precisa da mesma reafirmacao
   de .grupo.is-oculto acima (mesma especificidade de uma classe, vindo depois
   no arquivo — sem isso o botao nao esconderia nunca). Pego ao vivo no
   navegador: o botao ficava visivel na tela de "ja resgatou", que nunca chama
   configurarCtaPremioFisico() e por isso NUNCA deveria mostra-lo. */
.cta-secundaria.is-oculto { display: none; }

/* Usada em <button> (roleta) e <a> (baixar o app) — a segunda precisa
   perder o sublinhado padrao do link. */
.cta-secundaria {
  display: inline-block;
  margin-top: 16px;
  padding: 10px 22px;
  background: var(--yellow-strong);
  color: var(--preto-texto);
  border: none;
  border-radius: 999px;
  font-weight: 600;
  font-size: 15px;
  text-decoration: none;
  cursor: pointer;
}

.cta-secundaria:hover { background: var(--laranja); color: #fff; }

/* Especificidade acima de .form-estado p (classe+elemento): sem isso, aquela
   regra generica (cor/tamanho do texto de estado) venceria pela ordem no
   arquivo, mesmo com especificidade igual — mesmo cuidado do bloco do grupo
   acima, so que aqui o conflito e num seletor de outro fluxo (individual). */
.form-estado p.cta-secundaria__nota,
.grupo-final__texto p.cta-secundaria__nota {
  margin: 16px 0 0;
  color: var(--muted);
  font-size: 13px;
}

.premio-fisico.is-oculto { display: none; }

.premio-fisico {
  width: 100%;
  max-width: 402px;
  margin: 0 auto;
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 40px 24px 24px;
  position: relative;
  overflow: hidden;
  text-align: center;
}

.premio-fisico__moeda { position: absolute; width: 37%; }
.premio-fisico__moeda--topo { left: 0; top: 0; }

/* "X" pra voltar ao inicio. Absoluto no canto direito pra nao ocupar linha no
   flex-column (o layout do Figma nao previa nada acima da pilula) e com
   z-index: 2, nao 1: a caixa do botao encosta ~4px na quina superior direita
   da pilula do .premio-fisico__eyebrow (medido no navegador de 320px a 402px),
   e a pilula vem DEPOIS no DOM — com o mesmo z-index dela, era a pilula que
   pintava por cima do "x". O 2 tambem resolve a moeda do topo, que e absoluta
   e passaria por cima do botao (mesmo motivo do z-index da propria pilula).

   Nasce com .is-oculto e so aparece depois da revelacao (ver revelar() em
   js/app.js). De proposito NAO declara `display` aqui: com isso o
   .is-oculto { display: none } declarado antes no arquivo continua valendo,
   sem precisar da reafirmacao com dois seletores que os outros blocos usam. */
.premio-fisico__fechar {
  position: absolute;
  top: 12px;
  right: 12px;
  z-index: 2;
  width: 32px;
  height: 32px;
  padding: 0;
  border: none;
  border-radius: 999px;
  background: #fff;
  box-shadow: 0 2px 10px rgba(0, 0, 0, .10);
  color: var(--preto-texto);
  /* O glifo "x" (&times;) desenha pequeno na fonte do corpo; 22px com
     line-height: 1 deixa ele visualmente centrado na caixa de 32px. */
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
}

.premio-fisico__fechar:hover { background: var(--laranja); color: #fff; }

/* A moeda do rodape sai do posicionamento absoluto do topo: aqui ela e
   empurrada pro fim da tela pelo flex (mesmo truque de .grupo-final__moeda-rodape). */
.premio-fisico__moeda--rodape {
  position: static;
  width: 52%;
  margin-top: auto;
  padding-top: 32px;
}

/* Pilula branca: a .premio-fisico__moeda--topo e absoluta e passa por tras
   deste texto, que sem fundo ficava ilegivel sobre a moeda. Encolhe ate o
   conteudo sozinho — o pai e flex-column com align-items: center, entao o
   bloco nao estica (nao precisa de inline-block).

   O respiro ate o ticket passou a ser da .premio-fisico__identificacao, que
   entra logo abaixo — aqui sobra so a distancia curta ate o nome. */
.premio-fisico__eyebrow {
  color: var(--red);
  font-weight: 600;
  /* 13px e nao os 14px de antes: com o padding da pilula, a frase a 14px
     estoura os 354px uteis da secao, quebra em duas linhas e a pilula estica
     pra largura toda em vez de abracar o texto. */
  font-size: 13px;
  margin: 0 0 10px;
  z-index: 1;
  max-width: 100%;
  background: #fff;
  border-radius: 999px;
  padding: 8px 16px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, .10);
  /* Cabe em uma linha ate ~378px de viewport; abaixo disso (Galaxy S 360,
     iPhone SE 375) a frase quebra e a pilula estica pra largura toda. O
     balance divide as duas linhas por igual em vez de deixar "roleta" sozinha
     embaixo. Navegador sem suporte so ignora e cai na quebra normal. */
  text-wrap: balance;
}

/* Identificacao de quem ganhou: nome, telefone e horario, cada linha um degrau
   menor/mais claro que a de cima. Reafirma o esconde com dois seletores de
   classe porque declara `display` e .is-oculto vem antes no arquivo (mesma
   pegadinha de .grupo-*.is-oculto). */
.premio-fisico__identificacao.is-oculto { display: none; }

.premio-fisico__identificacao {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  margin: 0 0 24px;
  z-index: 1;
}

.premio-fisico__nome-usuario {
  margin: 0;
  color: var(--preto-texto);
  font-weight: 700;
  font-size: 18px;
  line-height: 1.2;
}

.premio-fisico__telefone {
  margin: 0;
  color: var(--muted);
  font-size: 13px;
}

.premio-fisico__horario {
  margin: 0;
  color: var(--muted-light);
  font-size: 12px;
}

.premio-ticket {
  position: relative;
  width: 240px;
  height: 240px;
  border-radius: 20px;
  overflow: hidden;
  box-shadow: 0 10px 24px rgba(0, 0, 0, .15);
  background: #fff;
  z-index: 1;
}

.premio-ticket__revelado {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 20px;
  gap: 6px;
}

.premio-ticket__foto {
  width: 96px;
  height: 96px;
  object-fit: cover;
  border-radius: 16px;
  margin-bottom: 4px;
}

.premio-ticket__moeda-vazia {
  width: 72px;
  filter: grayscale(1) opacity(.55);
  margin-bottom: 4px;
}

.premio-ticket__resultado {
  margin: 0;
  color: var(--muted);
  font-weight: 600;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: .04em;
}

.premio-ticket__nome {
  margin: 0;
  color: var(--preto-texto);
  font-weight: 700;
  font-size: 21px;
  line-height: 1.2;
}

/* A roleta cobre o ticket inteiro por cima do resultado — um toque dispara
   o giro (rotacao do disco, no JS); ao terminar, some com uma transicao
   curta, revelando o que ja estava escrito por baixo. O fundo deste
   container e o mesmo tom usado numa das fatias do disco (--yellow-strong):
   o disco e um circulo inscrito no card quadrado, entao os 4 cantos que
   sobram ficam desse fundo — por ser a mesma cor de fatia, o canto nao
   destoa do disco. */
.premio-ticket__roleta {
  position: absolute;
  inset: 0;
  overflow: hidden;
  cursor: pointer;
  touch-action: manipulation;
  background: var(--yellow-strong);
  transition: opacity .35s ease;
}

/* Disco: `from -22.5deg` desloca a origem do conic-gradient meio segmento
   (metade de 360/8) pra tras, entao o centro da fatia 0 cai exatamente no
   topo (0deg) — e um giro de qualquer numero inteiro de voltas (360deg * N)
   sempre devolve essa mesma fatia (o trofeu) pro topo, sob o marcador, sem
   nenhuma conta de angulo alem disso. */
.premio-ticket__roleta-disco {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: conic-gradient(
    from -22.5deg,
    var(--yellow-strong) 0deg 45deg,
    var(--laranja) 45deg 90deg,
    var(--yellow-strong) 90deg 135deg,
    var(--laranja) 135deg 180deg,
    var(--yellow-strong) 180deg 225deg,
    var(--laranja) 225deg 270deg,
    var(--yellow-strong) 270deg 315deg,
    var(--laranja) 315deg 360deg
  );
  will-change: transform;
  transition: transform 2.2s cubic-bezier(.12, .85, .18, 1);
}

/* Cada item e centralizado no meio do disco (top/left/margin) e so entao
   deslocado: rotate(N) leva ao angulo da fatia, translateY(-raio) empurra
   pra fora ao longo desse raio, e o rotate(-N) final desfaz a rotacao do
   proprio glifo — sem ele, o emoji ficaria "deitado" de lado nas fatias
   das laterais. */
.premio-ticket__roleta-item {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 28px;
  height: 28px;
  margin: -14px 0 0 -14px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 20px;
}

/* Marcador fixo (nao gira com o disco) apontando pra baixo, no 12h — o
   triangulo classico via bordas transparentes dos dois lados. */
.premio-ticket__roleta-marcador {
  position: absolute;
  top: 2px;
  left: 50%;
  width: 0;
  height: 0;
  margin-left: -8px;
  border-left: 8px solid transparent;
  border-right: 8px solid transparent;
  border-top: 12px solid var(--preto-texto);
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, .25));
}

.premio-ticket__roleta.is-revelado {
  opacity: 0;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .premio-ticket__roleta,
  .premio-ticket__roleta-disco { transition: none; }
}

.premio-fisico__instrucao {
  margin: 20px 0 0;
  color: var(--muted);
  font-size: 13px;
  z-index: 1;
}

.premio-fisico__botao-revelar {
  margin-top: 10px;
  background: none;
  border: none;
  color: var(--red-footer);
  font-weight: 600;
  font-size: 13px;
  text-decoration: underline;
  cursor: pointer;
  z-index: 1;
}

/* ==========================================================================
   Filtro de cidade da grade de grupo (GD-1828)
   ========================================================================== */

.grupo-cidades {
  margin: 0 0 20px;
}

/* Rola na horizontal em vez de quebrar linha: com muitas cidades o bloco empurraria
   a grade para fora da primeira dobra. O padding vertical e para o contorno de foco
   nao ser cortado pelo overflow. */
.grupo-cidades__lista {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  padding: 3px 0;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}

.grupo-cidades__lista::-webkit-scrollbar {
  display: none;
}

.grupo-cidade {
  flex: 0 0 auto;
  border: 1px solid var(--line);
  background: #fff;
  color: var(--ink);
  font-family: inherit;
  font-weight: 600;
  font-size: 13px;
  line-height: 1;
  padding: 9px 14px;
  border-radius: 999px;
  cursor: pointer;
  white-space: nowrap;
}

.grupo-cidade[aria-pressed="true"] {
  background: var(--red);
  border-color: var(--red);
  color: #fff;
}

/* Dois seletores: `.is-oculto` vem antes no arquivo, entao qualquer `display` que
   este bloco ganhe depois o venceria em silencio (pegadinha do CLAUDE.md). */
.grupo-cidades.is-oculto {
  display: none;
}