/* Design system do Evento Alinutri.
 *
 * Identidade institucional real da Alinutri — ver docs/IDENTIDADE_E_CONTEUDO_EVENTO.md
 * para a origem de cada cor, do logo e da tipografia, e para a divergencia
 * documentada entre o vermelho do livro de marca e o vermelho em producao.
 *
 * Tema CLARO, coerente com o site institucional (alinutri.ind.br), que e
 * 100% claro — e mais legivel que tema escuro num estande iluminado de feira.
 */

/* Tipografia oficial da marca, self-hosted: a CSP da aplicacao e
   default-src 'self' (ver App\Core\Bootstrap), entao carregar do Google
   Fonts seria bloqueado — e adicionaria dependencia externa num evento onde
   a rede pode ser instavel. Arquivo variavel (200-800), subset latin, que ja
   cobre todos os acentos do portugues (U+0000-00FF). Licenca OFL em
   public/assets/fonts/OFL.txt. */
@font-face {
    font-family: "Plus Jakarta Sans";
    src: url("../fonts/plus-jakarta-sans-latin.woff2") format("woff2");
    font-weight: 200 800;
    font-style: normal;
    font-display: swap;
}

:root {
    /* Institucionais (5-marca/CORES.png) */
    --cor-cinza: #4d4d4d;
    --cor-rose: #f0e2e2;

    /* VERMELHO INSTITUCIONAL / BASE — o valor do site em producao e o do proprio
     * arquivo SVG do logo. E o vermelho de TUDO que e compartilhado: cabecalho,
     * alertas, foco de campo, e o painel do operador, que carrega esta folha e
     * consome este token em quatro pontos.
     *
     * NAO trocar este valor para aplicar uma decisao de campanha da experiencia.
     * Foi o que aconteceu no Lote B: `--cor-vermelho` virou `#c72626` e levou
     * junto o painel do operador — inclusive o botao de confirmar entrega —, que
     * nao estava no escopo. A decisao de cor da experiencia mora em
     * `--cor-acao-evento`, logo abaixo. */
    --cor-vermelho: #a6342e;

    /* VERMELHO DE ACAO DA EXPERIENCIA — decisao de campanha, so do participante.
     *
     * O livro de marca (5-marca/CORES.png) registra `#c72626` como "Vermelho
     * Vivo", e a outra aplicacao Alinutri (mapa-clientes) ja o usa como cor de
     * acao. A campanha adotou o mesmo valor para os CTAs desta experiencia.
     *
     * Fica num token PROPRIO, e nao no institucional, porque o alcance e
     * diferente: o painel do operador tem revisao visual propria (Lote E) e
     * continua no vermelho institucional ate la. Um token semantico e o que
     * permite as duas coisas conviverem sem duplicar valor nem escopar por
     * `:not(.pagina--admin)`.
     *
     * Contraste medido: branco sobre `#c72626` = 5,62:1, AA para o corpo de
     * 1,1-1,25rem em 600 que o CTA usa. O hover continua em `#801c15`
     * (10,02:1), mais escuro que o repouso, como manda a leitura de estado. */
    --cor-acao-evento: #c72626;
    --cor-vermelho-medio: #801c15;
    --cor-vermelho-profundo: #630a0f;
    --cor-marrom: #3d2624;

    /* Auxiliares (5-marca/CORES.png) — usadas com parcimonia, em estado/feedback */
    --cor-verde: #2c8f43;
    --cor-mostarda: #d98431;
    --cor-azul: #3399cc;

    /* Tons DERIVADOS do Verde Capim e do Cinza institucional, para fundo e
       moldura dos jogos que têm identidade própria. Não são cores novas de
       marca: são o mesmo matiz clareado ou escurecido para servir de superfície
       — um fundo chapado no verde puro apagaria as peças que ficam por cima. */
    --cor-verde-profundo: #1e6a31;
    --cor-verde-claro: #e8f3ea;
    --cor-chumbo: #2b2b2b;

    /* Sinal de PERIGO no catcher (item prejudicial, anel de erro).
       CONVERGIU com `--cor-vermelho` quando o vermelho de ação passou a ser o do
       livro de marca — os dois valem `#c72626` hoje. Os tokens continuam
       separados porque significam coisas diferentes: um é "aja aqui", o outro é
       "desvie disto". Se a calibragem do catcher pedir outro tom (Lote C), muda
       este sem mexer em nenhum CTA da aplicação. */
    --cor-vermelho-vivo: #c72626;

    /* Superficies e texto */
    --cor-fundo: #ffffff;
    --cor-fundo-suave: #faf7f7;
    --cor-superficie: #ffffff;
    --cor-texto: #2f2f2f;
    --cor-texto-suave: #6b6b6b;

    /* DUAS bordas, porque a norma trata dois casos diferentes.
     *
     * `--cor-borda` (1,38:1 sobre branco) e SEPARADOR: a linha entre duas
     * informacoes dentro de um card, a moldura de uma superficie. Nao identifica
     * componente nenhum e nao precisa de 3:1 — exigir isso encheria a tela de
     * traços pesados.
     *
     * `--cor-borda-forte` e FRONTEIRA DE COMPONENTE: a borda de um campo de
     * formulario, ou a do card que E o alvo de toque. Num card branco, sobre
     * fundo branco, e a unica coisa que diz onde tocar e ate onde vai; a WCAG
     * 1.4.11 pede 3:1 justamente para isso. Medido: **3,85:1** sobre branco e
     * **3,61:1** sobre o creme da pagina — contra 1,38:1 e 1,30:1 da borda
     * clara. O matiz e o mesmo, escurecido — nao e cor nova. */
    --cor-borda: #e3d9d9;
    --cor-borda-forte: #8c7f7f;

    --raio: 0.875rem;
    --raio-grande: 1.25rem;
    --sombra: 0 8px 24px rgba(77, 38, 36, 0.1);

    /* DUAS larguras, porque sao dois problemas diferentes.
     *
     * `--largura-conteudo` e largura de LEITURA: formulario, instrucoes,
     * resultado. Esticar um formulario para 1200px nao melhora nada — piora:
     * o rotulo fica longe do campo e a linha de texto passa do confortavel.
     * Fica em 620px (~72 caracteres na tipografia da interface).
     *
     * `--largura-palco` e largura de ESCOLHA: uma tela cuja unica funcao e
     * exibir tres ou quatro cards lado a lado. Medido antes desta mudanca, a
     * experiencia inteira usava 700px em 1920x1080 — 36,5% da largura, com
     * 602px de margem morta de cada lado, e os cards em 2+1 com um quadrante
     * vazio. O numero nao e arbitrario: 4 cards de 276px + 3 vaos de 20px +
     * 32px de respiro fecham em 1180px, e 1200 e o degrau redondo acima disso.
     * Acima de 1200 o card so engorda sem ganhar conteudo. */
    --largura-conteudo: 620px;
    --largura-palco: 1200px;
}

* {
    box-sizing: border-box;
}

/* O atributo `hidden` esconde via folha de estilo do navegador, que QUALQUER
   regra de `display` do autor sobrescreve — e .botao-principal define
   `display: block`. Sem isto, o botão "Tentar de novo" da camada de estado
   aparecia por cima da contagem "3, 2, 1" (visto em produção), convidando a um
   toque que reiniciaria a preparação no meio dela. */
[hidden] {
    display: none !important;
}

html {
    -webkit-text-size-adjust: 100%;
}

/* Rede de segurança contra rolagem horizontal — trazida do mapa-clientes, a
   outra aplicação Alinutri, onde já cumpre esse papel.
   Medido, nenhuma tela desta aplicação rola na horizontal hoje. Isto não
   conserta nada: impede que um estouro futuro (um texto longo, uma peça de
   herói, um jogo novo) vire uma tela que desliza de lado sob o dedo numa
   estação de feira, onde ninguém vai reportar o defeito — só vai desistir. */
html,
body {
    overflow-x: hidden;
}

body {
    margin: 0;
    min-height: 100vh;
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
    background: var(--cor-fundo-suave);
    color: var(--cor-texto);
    font-family: "Plus Jakarta Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    font-size: 1rem;
    line-height: 1.5;
    -webkit-tap-highlight-color: transparent;
}

/* Grafismo institucional de fundo -------------------------------------------
   Recorte de 5-marca/BG_10.jpg (arcos finos, tinta neutra), 32 KB.
   Fica ancorado nos cantos e atras de tudo (z-index negativo,
   pointer-events:none): da presenca de marca sem competir com nenhum controle
   e sem custar toque nenhum. Em tela baixa some, para nao roubar area util.

   O ARQUIVO PRECISA TER ALFA. Ate a v2 ele era 100% opaco e 89% branco: o que
   aparecia na tela nao era grafismo sobre a pagina, eram dois RETANGULOS
   BRANCOS de borda dura sobre o creme — visivel na borda esquerda das telas de
   jogo. O desenho e o mesmo; o que mudou foi desfazer a composicao sobre branco
   que o recorte trouxe, para o grafismo TINGIR a pagina em vez de COBRI-LA.
   `tests/Views/AssetsDeMarcaTest` trava essa regressao a partir de agora.

   A tinta e neutra, nao rose: medido no arquivo de origem, saturacao media de
   3,85/255 entre os pixels com cobertura. O tom rose vinha do papel do
   documento de marca, nao do traco. */
body::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background-image:
        url("../backgrounds/grafismo-linhas.webp"),
        url("../backgrounds/grafismo-linhas.webp");
    background-repeat: no-repeat, no-repeat;
    background-position: left -60px top -40px, right -60px bottom -40px;
    background-size: 200px auto, 200px auto;
    opacity: 0.9;
}

@media (max-width: 520px), (max-height: 560px) {
    body::before {
        background-size: 130px auto, 130px auto;
        opacity: 0.7;
    }
}

h1 {
    font-size: clamp(1.5rem, 3.5vw, 2.25rem);
    font-weight: 800;
    line-height: 1.2;
    margin: 0 0 0.5rem;
    color: var(--cor-marrom);
}

.subtitulo {
    font-size: clamp(1rem, 2vw, 1.15rem);
    color: var(--cor-texto-suave);
    margin: 0 0 1.5rem;
}

/* Cabecalho de marca ---------------------------------------------------------
   O logo oficial (SVG vetorial) nunca e substituido por texto e nunca tem a
   proporcao alterada: largura fixa + height:auto preservam o aspect ratio. */

.cabecalho-marca {
    display: flex;
    align-items: center;
    justify-content: center;
    /* O cromo custava 117,7px de altura em toda tela de 1024px para cima —
       padding de 20px em cima e embaixo de um logo renderizado a 74px. Reduzido
       a 96px: e a mesma marca, no mesmo lugar, com 22px a mais de area util em
       cada tela. Nada aqui encolhe a marca abaixo do que se le a um metro. */
    padding: 0.875rem 1rem;
    background: var(--cor-superficie);
    /* Assinatura de marca, e o cabeçalho é compartilhado com o painel: fica no
       vermelho institucional, que é também a cor do arquivo do logo a 15px dele.
       Enquanto o token institucional valeu `#c72626`, os dois vermelhos ficavam
       lado a lado a 1,18:1 de diferença — mesma luminância, matiz visivelmente
       diferente, no primeiro elemento de toda tela. */
    border-bottom: 3px solid var(--cor-vermelho);
}

/* O logo permanece CENTRADO. Alinha-lo a esquerda foi considerado e recusado
   por composicao: o palco da escolha e centrado, e um logo encostado na borda
   esquerda com os cards centrados abaixo desalinha a tela inteira. O ganho de
   area util veio da altura, que e o eixo escasso — a largura sobrava. */
.cabecalho-marca__logo {
    /* Proporcao travada (`height: auto`), como manda a regra de uso do logo. */
    width: clamp(116px, 12vw, 156px);
    height: auto;
    display: block;
}

.pagina {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 1.5rem 1rem 2.5rem;
    width: 100%;
}

.conteudo {
    width: 100%;
    max-width: var(--largura-conteudo);
    text-align: center;
}

/* A tela de ESCOLHA usa o palco; as demais continuam em largura de leitura.
   Nem toda tela vira full-width porque uma delas precisou de espaco. */
.pagina--escolha .conteudo {
    max-width: var(--largura-palco);
}

.rodape-marca {
    padding: 1rem;
    text-align: center;
    font-size: 0.8rem;
    color: var(--cor-texto-suave);
}

/* O rodapé custava 51,2px em TODA tela — inclusive em 844x390, onde isso é
   13,1% da altura para repetir em texto o que o logo já diz no topo. Em
   paisagem de pouca altura ele encolhe; a assinatura continua lá. */
@media (orientation: landscape) and (max-height: 40rem) {
    .rodape-marca {
        padding: 0.375rem 1rem;
        font-size: 0.7rem;
    }
}

/* Faixa de contexto por perfil ------------------------------------------------
   Mensagem institucional contextualizada pelo perfil informado no cadastro
   (App\Content\ConteudoPorPerfil) — nunca altera a mecanica nem a
   distribuicao balanceada dos jogos, so o conteudo exibido. */

.faixa-perfil {
    background: var(--cor-rose);
    border-left: 4px solid var(--cor-vermelho);
    border-radius: var(--raio);
    padding: 0.9rem 1.1rem;
    margin-bottom: 1.5rem;
    text-align: left;
    font-size: 0.95rem;
    color: var(--cor-marrom);
}

.faixa-perfil--abaixo {
    margin-top: 1.5rem;
    margin-bottom: 0;
}

/* Card ----------------------------------------------------------------------- */

.card {
    background: var(--cor-superficie);
    border: 1px solid var(--cor-borda);
    border-radius: var(--raio-grande);
    padding: 1.5rem;
    box-shadow: var(--sombra);
}

/* Formulario ------------------------------------------------------------------ */

.formulario-participacao {
    text-align: left;
    display: flex;
    flex-direction: column;
    gap: 1.25rem;
}

.campo {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}

.campo-linha {
    display: flex;
    gap: 1rem;
}

.campo-linha .campo {
    flex: 1;
}

.campo--uf {
    flex: 0 0 6rem;
}

/* `.campo` é COMPARTILHADO: o login do painel do operador o usa também. O que
   vale aqui é o estado institucional; o que a experiência do participante
   decidiu no Lote B fica logo abaixo, escopado em `.formulario-participacao`.
   Sem essa separação, cada ajuste de forma do formulário de leads chega ao
   painel sem passar por decisão nenhuma — foi o que aconteceu com o peso do
   rótulo e com a borda do campo. */
.campo label {
    font-size: 0.95rem;
    font-weight: 700;
    color: var(--cor-marrom);
}

.campo input,
.campo select {
    width: 100%;
    min-height: 3.25rem;
    font-family: inherit;
    font-size: 1.05rem;
    padding: 0.7rem 1rem;
    border-radius: var(--raio);
    border: 2px solid var(--cor-borda);
    background: var(--cor-fundo);
    color: var(--cor-texto);
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.campo input::placeholder {
    color: #a89b9b;
}

.campo input:hover,
.campo select:hover {
    border-color: #c9b8b8;
}

/* O FORMULÁRIO DO PARTICIPANTE, e só ele, recebe a fronteira de 3:1.
 *
 * Foi decisão do Lote B: campo branco dentro de card branco, onde a borda é a
 * única coisa que diz onde tocar, media 1,38:1 — abaixo do 3:1 da WCAG 1.4.11.
 * `--cor-borda-forte` mede 3,85:1 sobre branco.
 *
 * Escopado em `.formulario-participacao` porque `.campo` é compartilhado com o
 * login do painel, e o painel tem revisão visual própria (Lote E). Aplicada na
 * regra genérica, esta correção mudou a borda e o contraste dos campos do
 * operador sem que ninguém tivesse decidido isso. */
.formulario-participacao .campo input,
.formulario-participacao .campo select {
    border-color: var(--cor-borda-forte);
}

.formulario-participacao .campo input:hover,
.formulario-participacao .campo select:hover {
    border-color: var(--cor-marrom);
}

.formulario-participacao .campo label {
    font-weight: 600;
}

.campo input:focus,
.campo select:focus {
    outline: 3px solid var(--cor-vermelho);
    outline-offset: 1px;
    border-color: var(--cor-vermelho);
}

.campo select {
    /* Aparencia consistente entre navegadores/plataformas. */
    appearance: none;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='%234d4d4d'><path d='M5.5 7.5l4.5 4.5 4.5-4.5z'/></svg>");
    background-repeat: no-repeat;
    background-position: right 1rem center;
    background-size: 1.1rem;
    padding-right: 2.75rem;
}

/* O popup de opcoes e desenhado pelo navegador/SO — define fundo/texto
   explicitos para garantir contraste em qualquer plataforma. */
.campo select option {
    background: #ffffff;
    color: #111827;
}

.campo select option:checked {
    background: var(--cor-rose);
    color: #111827;
}

.campo select option:disabled {
    color: #6b7280;
}

.campo-uf {
    text-transform: uppercase;
}

.erro-campo {
    margin: 0;
    color: var(--cor-vermelho-medio);
    font-size: 0.9rem;
    font-weight: 600;
}

.alerta {
    padding: 0.9rem 1.2rem;
    border-radius: var(--raio);
    margin-bottom: 1rem;
    font-size: 0.98rem;
    text-align: left;
}

.alerta--erro {
    background: #fdf0ef;
    border: 1px solid var(--cor-vermelho);
    color: var(--cor-vermelho-medio);
}

.campo-consentimento {
    flex-direction: row;
}

/* Consentimento POR CANAL. E um <fieldset>, e nao um <div> como os demais
   campos, porque as duas caixas sao uma pergunta so ("como podemos falar com
   voce?") — o agrupamento e semantico e chega ao leitor de tela pela <legend>.
   Isso cobra tres correcoes que um <div> nao cobraria:

   1. flex-direction volta a COLUNA. `.campo-consentimento` acima impoe `row`,
      que serve a um unico rotulo; herdada aqui, punha as duas autorizacoes
      lado a lado, cada uma espremida em quatro linhas.
   2. `min-width: 0`. Fieldset tem `min-inline-size: min-content` embutido no
      navegador e por isso NAO encolhe: em 320 px o bloco estourava a viewport
      e fazia a pagina inteira rolar na horizontal.
   3. Borda, padding e margem zerados. Sao do agente do usuario, e o retangulo
      cinza que produzem nao existe em nenhum outro campo deste formulario. */
.campo-consentimento--canais {
    flex-direction: column;
    min-width: 0;
    border: 0;
    margin: 0;
    padding: 0;
}

/* <legend> tambem carrega estilo proprio do navegador (cor e posicao sobre a
   borda). Alinhada aos demais rotulos, ela le como o titulo do grupo que e. */
.campo-consentimento__legenda {
    padding: 0;
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--cor-marrom);
}

/* `.campo .rotulo-checkbox`, e não `.rotulo-checkbox`, por ESPECIFICIDADE.
 *
 * O rótulo de consentimento é um `<label>` dentro de `.campo`, e `.campo label`
 * (0,1,1) vence `.rotulo-checkbox` (0,1,0). O `font-weight: 400` declarado aqui
 * nunca chegou a valer: medido, "Aceito que meus dados sejam usados para
 * participar desta experiência do evento" renderizava em **600** — uma frase
 * corrida em semibold, acima do Medium que `5-marca/FONTE.png` recomenda para
 * texto corrido. O rótulo curto de um campo é etiqueta e pode ter peso; uma
 * frase de consentimento é leitura. */
.campo .rotulo-checkbox {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    min-height: 2.75rem;
    padding: 0.25rem 0;
    font-size: 0.95rem;
    font-weight: 400;
    color: var(--cor-texto);
    cursor: pointer;
}

/* O texto e um unico bloco dentro do label: o asterisco vive DENTRO dele, nao
   como item flex irmao — separado, ele viraria uma coluna propria e poderia
   parar em qualquer lugar. */
.rotulo-checkbox__texto {
    flex: 1;
}

/* Nota de pre-requisito ao lado do rotulo de um canal ("preencha o campo de
   e-mail acima"). Menor e mais discreta que o rotulo, mas NAO cinza-claro: ela
   diz por que o envio pode ser recusado, e informacao acionavel precisa passar
   no mesmo contraste do resto do formulario. */
.rotulo-checkbox__nota {
    font-size: 0.85em;
    color: var(--cor-texto-suave);
}

/* Marcador de campo obrigatorio.
   O asterisco vinha precedido de espaco comum ("evento. *"), que e uma
   oportunidade de quebra de linha: quando o texto ocupava quase exatamente as
   linhas disponiveis, o asterisco descia sozinho para a linha seguinte (visto
   em producao). O &nbsp; no markup gruda o asterisco na ultima palavra, e o
   nowrap aqui protege caso alguem troque o &nbsp; por espaco comum um dia.
   E decorativo (aria-hidden): quem usa leitor de tela recebe a obrigatoriedade
   do proprio `required` do input, nao de um caractere solto. */
.campo-obrigatorio {
    white-space: nowrap;
}

/* CONTROLE 1 — três blocos empilhados, não lado a lado.
 *
 * `.campo-consentimento` acima impõe `row`, que servia quando o bloco era um
 * rótulo e um link soltos. O Controle 1 passou a ter rótulo + explicação do
 * que a participação envolve + os dois links de documento: em linha, a
 * explicação virava uma coluna estreita ao lado da frase que ela explica, e em
 * tela de celular cada uma ficava com meia dúzia de caracteres por linha.
 *
 * O Controle 2 tem o seu próprio modificador (--relacionamento, abaixo) pelo
 * mesmo motivo e com o mesmo efeito: são dois blocos com conteúdos diferentes,
 * e nenhum dos dois cabe na linha única que o padrão impõe. */
.campo-consentimento--principal {
    flex-direction: column;
    gap: 0.4rem;
}

/* A EXPLICAÇÃO NÃO É LETRA MIÚDA.
 *
 * Ela diz o que a participação envolve — tratamento dos dados para operar a
 * experiência e uma única mensagem de WhatsApp — e é a parte que a pessoa
 * precisa ler para o aceite significar alguma coisa. Um degrau de tamanho
 * abaixo do rótulo a separa visualmente sem escondê-la; abaixo de 0,9rem, numa
 * TV em pé e com fila atrás, ninguém lê.
 *
 * O recuo alinha o texto ao rótulo do checkbox (1,6rem de caixa + 0,75rem de
 * gap), para o bloco inteiro ler como uma coisa só. */
.campo-consentimento__explicacao {
    margin: 0;
    padding-left: 2.35rem;
    font-size: 0.9rem;
    line-height: 1.5;
    color: var(--cor-texto);
}

/* Os dois documentos, na mesma linha quando cabem. Alvo de toque confortável
   sem precisar de botão: numa tela sensível ao toque, dois links colados são
   dois erros de toque. */
.campo-consentimento__documentos {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem 0.75rem;
    margin: 0;
    padding-left: 2.35rem;
    font-size: 0.9rem;
}

.campo-consentimento__documentos a {
    min-height: 2.2rem;
    display: inline-flex;
    align-items: center;
    color: var(--cor-vermelho-medio);
    text-decoration: underline;
}

/* CONTROLE 2 — o <details> vai ABAIXO do rótulo, não ao lado dele.
 *
 * Mesma armadilha que o Controle 1 já tinha caído: `.campo-consentimento`
 * impõe `row`, e este bloco tem DOIS filhos (o rótulo e o <details>). Em
 * produção isso rendeu "Prefiro apenas um canal" espremido numa coluna à
 * direita da frase de marketing, com três palavras em três linhas — lido como
 * um elemento solto, e não como o detalhamento da caixa que ele detalha.
 *
 * `min-width: 0` porque o item flex não encolhe abaixo do próprio min-content
 * por padrão: sem isso, uma tela de 320 px volta a rolar na horizontal. */
.campo-consentimento--relacionamento {
    flex-direction: column;
    gap: 0.4rem;
    min-width: 0;
}

/* Anúncio da sincronização entre a caixa principal e as de canal. Existe no
   DOM desde o primeiro render, vazio — região `aria-live` inserida só na hora
   da mudança não é anunciada por parte dos leitores de tela.
 *
 * `:empty` esconde, em vez de o JavaScript remover o elemento: removê-lo mataria
 * a região viva, que é justamente o que precisa continuar existindo. Enquanto
 * não há o que anunciar, ele não ocupa linha nenhuma do formulário. */
.campo-consentimento__aviso {
    margin: 0;
    padding-left: 2.35rem;
    font-size: 0.9rem;
    color: var(--cor-vermelho-medio);
}

.campo-consentimento__aviso:empty {
    display: none;
}

/* 2,35rem = 1,6rem da caixa do checkbox + 0,75rem do gap: o mesmo recuo da
   explicação e dos documentos do Controle 1. É o que alinha o desdobramento
   com o TEXTO que ele desdobra, em vez de com a caixa. */
.campo-consentimento__avancado {
    padding-left: 2.35rem;
    min-width: 0;
}

/* O `summary` É o botão do disclosure — `<details>` nativo, sem JavaScript
   nenhum, como o resto do formulário. `flex-wrap` para o texto poder quebrar
   naturalmente numa tela estreita em vez de estourar a linha, e `min-height`
   pelo alvo de toque, que aqui é dedo em TV touch de feira. */
.campo-consentimento__resumo {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.2rem 0.55rem;
    min-height: 2.75rem;
    padding: 0.25rem 0;
    font-size: 0.9rem;
    color: var(--cor-vermelho-medio);
    cursor: pointer;
    list-style: none;
}

/* O triângulo padrão do navegador participa do layout como marcador de lista e
   reaparece do lado errado quando o summary vira flex. Removido nos dois
   dialetos e redesenhado abaixo. */
.campo-consentimento__resumo::-webkit-details-marker {
    display: none;
}

/* Marcador em BORDAS, não no caractere "▸": nenhum leitor de tela anuncia uma
   caixa vazia, e não depende de a fonte ter o glifo. Gira ao abrir, que é o
   sinal de estado que o triângulo nativo dava. */
.campo-consentimento__resumo::before {
    content: "";
    flex-shrink: 0;
    width: 0;
    height: 0;
    border-style: solid;
    border-width: 0.32rem 0 0.32rem 0.45rem;
    border-color: transparent transparent transparent currentColor;
    transition: transform 0.15s ease;
}

.campo-consentimento__avancado[open] > .campo-consentimento__resumo::before {
    transform: rotate(90deg);
}

.campo-consentimento__resumo:focus-visible {
    outline: 3px solid var(--cor-marrom);
    outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
    .campo-consentimento__resumo::before {
        transition: none;
    }
}

.rotulo-checkbox input[type="checkbox"] {
    width: 1.6rem;
    height: 1.6rem;
    flex-shrink: 0;
    accent-color: var(--cor-vermelho);
}

/* Texto longo em tela estreita ocupa varias linhas: alinhar o checkbox pelo
   topo o mantem junto da PRIMEIRA linha, em vez de flutuar no meio do
   paragrafo. Ate duas linhas, centralizado continua melhor. */
@media (max-width: 380px) {
    .rotulo-checkbox {
        align-items: flex-start;
    }

    .rotulo-checkbox input[type="checkbox"] {
        margin-top: 0.15rem;
    }
}

/* Campo-armadilha (honeypot): existe no DOM mas nunca visivel a um usuario
   real. O elemento tambem carrega estilo inline equivalente, para nao
   depender deste arquivo ter carregado. */
.campo-armadilha {
    position: absolute;
    left: -9999px;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

/* Botoes ---------------------------------------------------------------------- */

/* O CTA DA EXPERIÊNCIA — e só ele — usa o vermelho de ação da campanha.
 *
 * `.botao-principal` é exclusivo do participante: o painel do operador tem
 * `.botao-admin`, com folha própria. É por isso que a decisão de cor da campanha
 * cabe aqui sem escopar por `:not(.pagina--admin)` e sem duplicar valor nenhum.
 *
 * Estado de foco e de hover continuam nos tokens compartilhados
 * (`--cor-marrom`, `--cor-vermelho-medio`): não foram decisão deste lote, e
 * mudá-los teria arrastado o painel junto — que foi exatamente o defeito que
 * este isolamento corrige. */
.botao-principal {
    display: block;
    width: 100%;
    min-height: 3.5rem;
    padding: 1rem 1.5rem;
    border: none;
    border-radius: 999px;
    background: var(--cor-acao-evento);
    color: #ffffff;
    font-family: inherit;
    font-size: 1.1rem;
    font-weight: 600;
    text-align: center;
    text-decoration: none;
    cursor: pointer;
    transition: background-color 0.15s ease, transform 0.05s ease;
}

.botao-principal:hover {
    background: var(--cor-vermelho-medio);
}

.botao-principal:focus-visible {
    outline: 3px solid var(--cor-marrom);
    outline-offset: 2px;
}

.botao-principal:active {
    transform: translateY(1px);
}

/* "Jogar novamente" é um link com aparência de botão — a ação abre o
   formulário, não cria partida. Como <a> não tem a centralização vertical
   nativa do <button>, ela vem daqui. */
.botao-principal--link {
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Botão inativo continua LEGÍVEL.
 *
 * Branco sobre `#c9b8b8` mede 1,90:1. Isto nasceu do "Começar" desabilitado
 * durante a contagem da tela de instruções — contagem que a V3 removeu —, mas a
 * regra vale para qualquer botão inativo que apareça depois: componente inativo
 * é formalmente isento de 1.4.3, e isento não é motivo para apagar a palavra.
 * Com o marrom institucional o texto mede 7,35:1, e o que comunica "ainda não"
 * continua sendo o preenchimento apagado. */
.botao-principal:disabled,
.botao-principal--desabilitado {
    background: #c9b8b8;
    color: var(--cor-marrom);
    pointer-events: none;
    cursor: not-allowed;
    transform: none;
}

/* Instrucoes ------------------------------------------------------------------- */

.tela-instrucoes {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1.25rem;
}

/* `.contagem` foi removida junto com a espera de 3 s desta tela (V3). A
   contagem que resta é a do runtime, na tela do jogo, e ela usa
   `.camada-estado__titulo` — não esta classe. */

/* Condição de vitória. Fora da lista de mecânica porque não é um passo, é o
   critério — e o critério é o que decide brinde. O verde é o mesmo do
   `hud__item--conquistado`: quem vê "Para vencer" aqui reencontra a mesma cor
   no HUD quando a meta cai. */
.meta-vitoria {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.15rem;
    width: 100%;
    margin: 0;
    padding: 0.7rem 1rem;
    border: 1px solid rgba(44, 143, 67, 0.4);
    border-left: 4px solid var(--cor-verde);
    border-radius: var(--raio);
    background: var(--cor-verde-claro);
    text-align: center;
}

.meta-vitoria__rotulo {
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    /* `--cor-verde-profundo` sobre `--cor-verde-claro` mede 5,63:1 — AA para
       este corpo pequeno, que o verde puro (3,54:1) não alcançaria. */
    color: var(--cor-verde-profundo);
}

.meta-vitoria__valor {
    font-size: 1.05rem;
    font-weight: 700;
    line-height: 1.25;
    color: var(--cor-marrom);
}

.lista-instrucoes {
    text-align: left;
    margin: 0;
    padding-left: 1.25rem;
    color: var(--cor-texto);
}

.lista-instrucoes li {
    margin-bottom: 0.5rem;
}

/* Jogo — chassi comum ----------------------------------------------------------
   Vale para os tres minijogos: HUD, palco, camada de estado. A mecanica de
   cada um so preenche #jogo-root. */

/* A tela de jogo cabe SEMPRE na viewport, sem rolagem: rolagem acidental no
   meio de uma partida por toque é a pior falha possível aqui, e num celular
   deitado (pouca altura) o tabuleiro precisa encolher em vez de empurrar o
   resto para fora. */
body.pagina--jogo {
    height: 100vh;
    height: 100dvh;
    overflow: hidden;
}

.pagina--jogo .pagina {
    justify-content: flex-start;
    padding: 0.75rem 0.75rem 1rem;
    min-height: 0;
}

.pagina--jogo .conteudo {
    max-width: 720px;
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
}

.pagina--jogo .rodape-marca {
    display: none;
}

.hud {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    width: 100%;
    padding: 0.6rem 0.9rem;
    background: var(--cor-superficie);
    border: 1px solid var(--cor-borda);
    border-radius: var(--raio);
    margin-bottom: 0.75rem;
    box-shadow: var(--sombra);
}

.hud__item {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    font-size: 0.7rem;
    color: var(--cor-texto-suave);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.hud__item--tempo,
.hud__item--pontos {
    align-items: flex-end;
}

.hud__valor {
    font-size: 1.35rem;
    font-weight: 800;
    color: var(--cor-marrom);
    font-variant-numeric: tabular-nums;
    text-transform: none;
    letter-spacing: 0;
    white-space: nowrap;
}

/* O primeiro item do HUD é o NOME DO JOGO, e nome de jogo é conteúdo: pode ser
   longo ("Nature Fórmula PRO"). Ele encolhe e quebra linha em vez de empurrar
   tempo e pontos para fora — número é o que precisa ser grande aqui. */
.hud__item:first-child {
    min-width: 0;
    flex-shrink: 1;
}

.hud__item:first-child .hud__valor {
    font-size: 1rem;
    line-height: 1.15;
    white-space: normal;
}

/* Com meta ("640 / 1000") o placar tem o dobro de dígitos e não cabe no mesmo
   corpo do relógio. */
.hud__item--pontos .hud__valor {
    font-size: 1.15rem;
}

/* Ultimos 10 segundos: o numero muda de cor em vez de piscar — piscar cansa a
   vista numa TV e atrapalha quem tem sensibilidade a movimento. */
.hud__item--critico .hud__valor {
    color: var(--cor-vermelho);
}

/* Meta de pontuacao ja alcancada. Existe porque agora concluir nao e vencer:
   sem este sinal, o participante joga 45 s sem saber se ja garantiu o brinde. */
.hud__item--conquistado .hud__valor {
    color: var(--cor-verde);
}

/* Identidade por jogo (classe posta pelo runtime a partir da chave). O HUD e a
   moldura sao compartilhados, entao e aqui que cada jogo ganha o clima dele. */
.jogo-match3 .hud {
    border-color: rgba(44, 143, 67, 0.35);
    box-shadow: inset 0 -3px 0 var(--cor-verde), var(--sombra);
}

.jogo-match3 .hud__valor {
    color: var(--cor-verde-profundo);
}

.jogo-proteja-pet .hud {
    background: var(--cor-chumbo);
    border-color: #000000;
    color: #ffffff;
}

.jogo-proteja-pet .hud__item {
    color: rgba(255, 255, 255, 0.72);
}

.jogo-proteja-pet .hud__valor {
    color: #ffffff;
}

.jogo-proteja-pet .hud__item--critico .hud__valor {
    color: #ff8a80;
}

/* Azul Celeste institucional: o mesmo do herói do card da Trilha e do palco. */
.jogo-trilha .hud {
    border-color: rgba(51, 153, 204, 0.4);
    box-shadow: inset 0 -3px 0 var(--cor-azul), var(--sombra);
}

.jogo-trilha .hud__valor {
    /* `--cor-azul` puro mede 3,20:1 sobre branco — abaixo do 4,5:1 que este
       corpo pede. O mesmo matiz escurecido chega a 6,84:1. */
    color: #1f5f80;
}

.palco-jogo {
    position: relative;
    flex: 1;
    min-height: 0;
    display: flex;
}

.area-jogo {
    position: relative;
    flex: 1;
    /* min-height fica em 0 de propósito: quem manda no tamanho é o espaço que
       sobrou depois do cabeçalho e do HUD, não um piso fixo que geraria
       rolagem em tela baixa. */
    min-height: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0.75rem;
    background: var(--cor-superficie);
    border: 1px solid var(--cor-borda);
    border-radius: var(--raio-grande);
    color: var(--cor-marrom);
    overflow: hidden;
    /* Sem rolagem/zoom acidental no meio da partida — o palco e area de jogo,
       nao de navegacao. */
    touch-action: none;
    user-select: none;
    -webkit-user-select: none;
}

/* Camada de estado (preparação, erro, fim) ----------------------------------- */

.camada-estado {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
    background: rgba(255, 255, 255, 0.94);
    border-radius: var(--raio-grande);
    z-index: 2;
}

.camada-estado--oculta {
    display: none;
}

.camada-estado__caixa {
    text-align: center;
    max-width: 22rem;
}

.camada-estado__titulo {
    font-size: clamp(2.25rem, 9vw, 3.5rem);
    font-weight: 800;
    line-height: 1;
    margin: 0 0 0.5rem;
    color: var(--cor-vermelho);
    font-variant-numeric: tabular-nums;
}

.camada-estado__texto {
    margin: 0;
    color: var(--cor-texto-suave);
}

.camada-estado__acao {
    margin-top: 1.25rem;
}

/* Saída da tela de jogo. Menos peso que a ação principal — quem chega num
   estado de erro deve tentar de novo antes de desistir da partida —, mas com
   alvo de toque de tamanho pleno: numa estação travada, este é o único controle
   que resta. */
.camada-estado__saida {
    margin-top: 0.75rem;
}

.camada-estado__saida-botao {
    display: block;
    width: 100%;
    min-height: 3rem;
    padding: 0.75rem 1.25rem;
    /* A BORDA precisa se distinguir do fundo, não só o texto (WCAG 1.4.11
       pede 3:1 para fronteira de componente). `--cor-borda` mede 1,38:1 sobre
       o branco da camada de estado: o texto lia bem, mas nada dizia que aquilo
       era um botão — e este é o ÚNICO controle da estação quando o jogo falha,
       lido a um metro de distância. `--cor-texto-suave` mede 5,3:1. */
    border: 1px solid var(--cor-texto-suave);
    border-radius: var(--raio);
    background: var(--cor-fundo-suave);
    color: var(--cor-texto);
    font: inherit;
    font-weight: 600;
    cursor: pointer;
}

.camada-estado__saida-botao:hover {
    background: var(--cor-rose);
    border-color: var(--cor-vermelho);
}

.camada-estado__saida-botao:focus-visible {
    outline: 3px solid var(--cor-vermelho);
    outline-offset: 2px;
}

/* Match-3 --------------------------------------------------------------------- */

/* O tabuleiro é o jogo: ocupa o maior tamanho que couber e tem moldura
   própria, para a tela parecer um jogo e não uma lista de ícones sobre fundo
   branco. Em retrato a largura é o limite, em paisagem é a altura — sem isso,
   um celular deitado mostraria um tabuleiro minúsculo com metade da tela
   vazia.

   A área de jogo perde a moldura quando o match-3 está dentro: duas molduras
   concêntricas comem área útil e só deixam o tabuleiro menor. */
.pagina--jogo .area-jogo:has(.match3) {
    padding: 0;
    border-color: transparent;
    box-shadow: none;
    /* Palco, não folha em branco: num celular em pé o tabuleiro é quadrado e
       sobra altura dos dois lados. Sem isto, a sobra virava "página branca com
       ícones" — foi parte da queixa de vazio.

       Só gradiente, nada de textura: o recorte institucional de linhas
       (backgrounds/grafismo-linhas.webp) tem fundo branco opaco e, aplicado
       aqui, desenha retângulos brancos por cima do palco. Ele existe para o
       fundo da página, onde o branco coincide com a superfície. */
    /* VERDE NATURE. O tabuleiro é a linha da fórmula, e o palco precisa dizer
       isso antes de qualquer texto: o rosa institucional era o fundo genérico
       de todas as telas e fazia o match-3 parecer a mesma tela dos outros dois
       jogos. O gradiente vai de branco ao verde claro, nunca ao verde cheio —
       peça colorida sobre fundo saturado perde contorno. */
    background:
        radial-gradient(105% 55% at 50% 50%,
            #ffffff 0%,
            #f2f9f4 52%,
            var(--cor-verde-claro) 100%);
}

.match3 {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    min-height: 0;
    /* Consultado pelo tabuleiro logo abaixo: é o que permite dimensionar pelo
       MENOR lado da área de jogo, em vez de esticar num dos eixos. */
    container-type: size;
}

.tabuleiro {
    position: relative;
    display: grid;
    grid-template-columns: repeat(var(--colunas, 7), 1fr);
    grid-template-rows: repeat(var(--linhas, 7), 1fr);
    gap: clamp(3px, 0.9vmin, 7px);
    padding: clamp(5px, 1.4vmin, 11px);

    /* Base para quem não tem container queries: em retrato dá o quadrado
       certo; em paisagem sobra altura, que é o lado seguro de errar. */
    aspect-ratio: var(--colunas, 7) / var(--linhas, 7);
    width: 100%;
    height: auto;
    max-width: 100%;
    max-height: 100%;

    /* O cálculo que vale: o tabuleiro cabe INTEIRO na área de jogo, seja qual
       for o lado mais curto. Sem isto, um celular em pé esticava a célula
       (47x100 px medidos) e a peça saía deformada — era parte da "leitura
       ruim" do tabuleiro. */
    width: min(100cqw, calc(100cqh * var(--colunas, 7) / var(--linhas, 7)));
    height: min(100cqh, calc(100cqw * var(--linhas, 7) / var(--colunas, 7)));
    margin: auto;
    border-radius: var(--raio-grande);
    /* A peça nova entra vinda de cima do tabuleiro: sem recorte, ela aparece
       flutuando acima da moldura antes de cair. */
    overflow: hidden;
    background:
        linear-gradient(180deg, #ffffff 0%, var(--cor-verde-claro) 100%);
    border: 2px solid rgba(44, 143, 67, 0.32);
    box-shadow:
        inset 0 2px 10px rgba(30, 106, 49, 0.14),
        0 8px 24px rgba(30, 106, 49, 0.16);
}

.tabuleiro--embaralhando {
    animation: tabuleiro-embaralhar 0.32s ease;
}

.peca {
    position: relative;
    display: block;
    padding: 0;
    border: none;
    background: transparent;
    cursor: pointer;
    touch-action: none;
    /* A célula inteira é alvo de toque, mesmo com a peça desenhada por dentro:
       numa TV touch o dedo chega torto e num celular a coluna é estreita. */
    min-width: 0;
    min-height: 0;
}

/* Alvéolo: a casa continua desenhada quando a peça some. Sem ele, o intervalo
   entre a explosão e a queda parece buraco no tabuleiro — que foi justamente
   a queixa. */
.peca::before {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: 26%;
    background: rgba(30, 106, 49, 0.09);
    box-shadow: inset 0 1px 2px rgba(30, 106, 49, 0.14);
}

/* A peça é um azulejo CHEIO de cor institucional, não um símbolo solto: é o
   que dá densidade ao tabuleiro e o que torna a silhueta branca legível de
   longe. O gradiente é volume, não decoração — sem ele o tabuleiro vira uma
   colagem chapada. */
.peca__corpo {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 26%;
    background:
        linear-gradient(158deg,
            rgba(255, 255, 255, 0.32) 0%,
            rgba(255, 255, 255, 0) 46%,
            rgba(0, 0, 0, 0.2) 100%),
        var(--peca-cor, #a6342e);
    box-shadow:
        inset 0 2px 0 rgba(255, 255, 255, 0.3),
        inset 0 -3px 0 rgba(0, 0, 0, 0.2),
        0 2px 4px rgba(61, 38, 36, 0.28);
    /* Só transform e opacity animam — é o que mantém 60 fps num tablet de
       estande com 49 peças na tela. */
    will-change: transform;
}

.peca__corpo .peca__svg {
    width: 74%;
    height: 74%;
    filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.28));
}

.peca__svg {
    width: 100%;
    height: 100%;
    display: block;
    filter: drop-shadow(0 2px 3px rgba(61, 38, 36, 0.22));
}

.peca:focus-visible {
    outline: 3px solid var(--cor-marrom);
    outline-offset: 2px;
    z-index: 2;
}

/* Seleção e dica NÃO usam transform: o JavaScript controla o transform da peça
   para deslizar, cair e voltar, e uma animação CSS venceria o valor inline no
   meio do movimento. Aqui o feedback é anel + brilho. */
.peca--selecionada .peca__corpo {
    filter: brightness(1.16);
}

.peca--selecionada::after {
    content: "";
    position: absolute;
    inset: -4px;
    border: 4px solid var(--cor-verde-profundo);
    border-radius: 30%;
    pointer-events: none;
    z-index: 2;
    box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.85);
    /* Só `opacity` anima aqui (ver @keyframes peca-pulsar). NUNCA transform: o
       JavaScript é dono do transform da peça, e uma animação CSS venceria o
       valor inline e travaria a peça no meio do deslize. */
    animation: peca-pulsar 1s ease-in-out infinite;
}

/* Troca recusada: além de a peça voltar sozinha para o lugar, o par pisca em
   vermelho — o movimento sozinho pode passar despercebido numa tela grande. */
.peca--negada .peca__corpo {
    box-shadow:
        0 0 0 3px var(--cor-vermelho),
        inset 0 2px 0 rgba(255, 255, 255, 0.3),
        0 2px 4px rgba(61, 38, 36, 0.28);
}

/* Dica de jogada possível, depois de alguns segundos parado. */
.peca--dica::after {
    content: "";
    position: absolute;
    inset: -3px;
    border: 3px dashed var(--cor-verde-profundo);
    border-radius: 30%;
    pointer-events: none;
    animation: peca-pulsar 1.1s ease-in-out infinite;
}

.peca--vazia .peca__corpo {
    visibility: hidden;
}

.peca__corpo--sumindo {
    animation: peca-sumir 0.19s ease-in forwards;
}

/* Enquanto desliza ou cai, a peça passa por cima das vizinhas — senão o
   movimento fica cortado pelo azulejo do lado. */
.peca__corpo--movendo {
    z-index: 3;
}

/* Avisos flutuantes ("+90", "Combo x3") ------------------------------------- */

.match3__efeitos {
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 4;
    overflow: hidden;
    border-radius: var(--raio-grande);
}

/* Pílula opaca, não texto com sombra: o aviso nasce EM CIMA das peças, que são
   coloridas e cheias. Só contorno não garantia leitura sobre azul ou vermelho. */
.match3__ganho {
    position: absolute;
    transform: translate(-50%, -50%);
    padding: 0.1rem 0.45rem;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.94);
    box-shadow: 0 2px 6px rgba(61, 38, 36, 0.3);
    font-size: clamp(0.8rem, 2.4vmin, 1.15rem);
    font-weight: 800;
    color: var(--cor-marrom);
    white-space: nowrap;
    animation: ganho-subir 0.7s ease-out forwards;
}

.match3__ganho--forte {
    color: var(--cor-verde-profundo);
    font-size: clamp(1rem, 3.2vmin, 1.5rem);
}

/* Faixa da cascata: multiplicador grande + frase institucional pequena embaixo.
   A frase vem de content/jogos.php e pode ser longa ("Sem glúten e sem
   transgênicos"), então a faixa quebra em duas linhas em vez de forçar
   `nowrap` e vazar do tabuleiro num celular. */
.match3__combo {
    position: absolute;
    left: 50%;
    top: 40%;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.1rem;
    max-width: 92%;
    padding: 0.4rem 1.1rem 0.5rem;
    border-radius: var(--raio-grande);
    background: rgba(255, 255, 255, 0.97);
    box-shadow: 0 8px 22px rgba(30, 106, 49, 0.35);
    text-align: center;
    animation: combo-aparecer 0.9s ease-out forwards;
}

.match3__combo-numero {
    font-size: clamp(1.3rem, 5.2vmin, 2.3rem);
    font-weight: 800;
    line-height: 1;
    color: var(--cor-verde-profundo);
    letter-spacing: -0.01em;
}

.match3__combo-texto {
    font-size: clamp(0.65rem, 2.2vmin, 0.95rem);
    font-weight: 700;
    line-height: 1.15;
    color: var(--cor-marrom);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

@keyframes peca-sumir {
    40% { transform: scale(1.16); }
    100% { transform: scale(0.15); opacity: 0; }
}

@keyframes peca-pulsar {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.55; }
}

@keyframes tabuleiro-embaralhar {
    0% { opacity: 1; }
    45% { opacity: 0.45; }
    100% { opacity: 1; }
}

@keyframes ganho-subir {
    0% { opacity: 0; transform: translate(-50%, -20%) scale(0.8); }
    25% { opacity: 1; transform: translate(-50%, -55%) scale(1.05); }
    100% { opacity: 0; transform: translate(-50%, -180%) scale(1); }
}

@keyframes combo-aparecer {
    0% { opacity: 0; transform: translate(-50%, -50%) scale(0.6); }
    30% { opacity: 1; transform: translate(-50%, -50%) scale(1.12); }
    75% { opacity: 1; transform: translate(-50%, -50%) scale(1); }
    100% { opacity: 0; transform: translate(-50%, -90%) scale(1); }
}

/* Quem pediu menos movimento continua vendo o estado, nunca a animação. O
   módulo do jogo já pula as animações que ele controla; aqui ficam as que são
   puramente da folha de estilo. */
@media (prefers-reduced-motion: reduce) {
    .tabuleiro--embaralhando,
    .peca--selecionada::after,
    .peca--dica::after,
    .peca__corpo--sumindo,
    .match3__ganho,
    .match3__combo {
        animation: none;
    }
}

/* Memória --------------------------------------------------------------------- */

/* Mesma técnica do tabuleiro: o grid inteiro tem proporção fixa e ocupa o
   maior tamanho que couber, e as células saem de `1fr` em vez de proporção
   própria — assim as cartas nunca vazam da área de jogo.

   `--colunas`, `--linhas` e `--proporcao` são calculados pelo módulo a partir
   do número de cartas, e o arranjo é sempre EXATO (colunas × linhas cobre
   todas): dez cartas num grid de quatro colunas deixariam dois buracos, que
   numa TV touch leem como carta faltando. */

/* O módulo LIMITA a carta à faixa 0,62–1,30 e grava o resultado em
   `--proporcao` — e esta folha descartava o cálculo. `height: 100%` dava altura
   definida, `aspect-ratio` calcularia a largura a partir dela e `max-width:
   100%` a cortava, sem a altura encolher junto. Medido: em 6 de 7 resoluções a
   carta violava o limite do próprio módulo, e em 1920×1080 ficava em 0,326 —
   metade do mínimo. As cartas viravam barras verticais de 132×406 px, com o
   isotipo do verso ocupando 4,3% da área.

   É o mesmo defeito que o tabuleiro do match-3 já teve, e a correção é a mesma
   fórmula (ver `.tabuleiro`): dimensionar pelo MENOR lado da área de jogo. */
.jogo-memoria .area-jogo {
    /* Consultado pelo grid logo abaixo. Escopado ao jogo da memória de
       propósito: o match-3 tem container próprio e o catcher não usa nenhum. */
    container-type: size;
}

.memoria {
    /* Um único lugar define o gap: ele entra no `gap` E na conta abaixo. Se os
       dois divergirem, a carta volta a sair da faixa do módulo. */
    --memoria-gap: 0.5rem;

    /* Altura da CARTA — o maior valor que cabe pelos dois eixos, já descontados
       os gaps. É daqui que sai o tamanho da grade, e não o contrário: calcular
       a grade primeiro e dividir por colunas/linhas fazia os gaps saírem do
       bolso das cartas, e a proporção caía fora do clamp do módulo (medido:
       0,602 onde ele pedia 0,62; 1,33 onde pedia 1,30). */
    --carta-altura: min(
        calc((100cqh - (var(--linhas, 5) - 1) * var(--memoria-gap)) / var(--linhas, 5)),
        calc((100cqw - (var(--colunas, 2) - 1) * var(--memoria-gap)) / var(--colunas, 2) / var(--carta-proporcao, 0.78))
    );

    display: grid;
    grid-template-columns: repeat(var(--colunas, 2), 1fr);
    grid-template-rows: repeat(var(--linhas, 5), 1fr);
    gap: var(--memoria-gap);

    /* Base para quem não tem container queries: mantém a proporção pedida e
       erra para o lado de sobrar espaço, nunca para o de deformar a carta. */
    aspect-ratio: var(--proporcao, 0.78);
    width: auto;
    height: auto;
    max-width: 100%;
    max-height: 100%;

    /* O cálculo que vale: cartas na proporção exata + os gaps por fora. */
    width: calc(
        var(--carta-altura) * var(--carta-proporcao, 0.78) * var(--colunas, 2)
        + (var(--colunas, 2) - 1) * var(--memoria-gap)
    );
    height: calc(
        var(--carta-altura) * var(--linhas, 5)
        + (var(--linhas, 5) - 1) * var(--memoria-gap)
    );
    margin: auto;
    /* Perspectiva no CONTAINER, não em cada carta: com perspectiva por carta,
       as das bordas giram com fuga diferente das do centro e o baralho parece
       torto. */
    perspective: 1200px;
}

.carta {
    position: relative;
    padding: 0;
    border: none;
    border-radius: var(--raio);
    background: transparent;
    cursor: pointer;
    touch-action: manipulation;
    transform-style: preserve-3d;
    /* O giro é da CARTA inteira, não de duas camadas trocando de opacidade:
       é o que faz o movimento parecer papel virando em vez de imagem piscando.
       Aqui o transform é da folha de estilo do começo ao fim — ao contrário do
       match-3, onde ele pertence ao JavaScript. */
    transition: transform 0.42s cubic-bezier(.22, .61, .36, 1);
}

.carta--aberta,
.carta--casada {
    transform: rotateY(180deg);
}

.carta__face {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.2rem;
    padding: 0.4rem;
    border-radius: var(--raio);
    overflow: hidden;
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
}

/* Verso institucional: grafismo de arcos em CSS (leve, escala sem asset) com o
   isotipo oficial no centro, na versão NEGATIVA — que é a correta sobre fundo
   vermelho. Nunca o logo virando padrão repetido de fundo. */
.carta__verso {
    background:
        repeating-radial-gradient(circle at 50% 120%,
            transparent 0 10px,
            rgba(255, 255, 255, 0.28) 10px 12px),
        var(--cor-vermelho);
    border: 2px solid var(--cor-vermelho-medio);
}

/* O ISOTIPO DO VERSO ESCALA COM A CARTA — e o `max-width` fixo era o que o
   impedia.

   Com `max-width: 3rem` (48 px) ele parava de crescer aos 48 px de largura em
   QUALQUER tela. Numa carta de 132×170 isso dava 11,7% da área; numa TV, com
   carta de 200×256, 5,1% — quanto maior a tela, MENOR a marca, que é o inverso
   do que se quer numa tela vista a um metro. (Os 4,3% que a auditoria mediu
   somavam esse teto à carta ainda deformada, corrigida no Lote A.)

   Sem o teto e com `max-height`, a peça fica em ~28% da área tanto na carta
   pequena quanto na grande. O arquivo é 224×255 (quase quadrado, levemente
   vertical): `object-fit: contain` garante que o limite de altura encolha a
   arte em vez de deformá-la quando a carta fica baixa (landscape, proporção
   1,30). */
.carta__isotipo {
    width: 58%;
    /* 62%, e nao 50%: medido, com 50% o limite de ALTURA virava o vínculo ativo
       nas duas cartas mais largas que altas (390×844, proporção 1,29, e 844×390,
       1,16) e o isotipo ficava MENOR do que era com o teto antigo de 3 rem —
       −11% e −6% de tinta. Corrigir um teto e criar outro no eixo oposto não é
       correção. Com 62% a altura só morde onde a carta é de fato baixa, e nas
       quatro telas de carta alta o vínculo continua sendo a largura. */
    max-height: 62%;
    height: auto;
    object-fit: contain;
    opacity: 0.9;
}

.carta__frente {
    background: var(--cor-superficie);
    border: 2px solid var(--cor-borda);
    transform: rotateY(180deg);
    /* A face é o contexto de medida da placa do logo (abaixo). Presa à LARGURA
       da face, e não à altura, a placa mantém a mesma forma em toda a faixa de
       proporção que a carta aceita (0,62 a 1,30) — um percentual de altura
       mudaria a normalização junto com o formato da carta. */
    container-type: inline-size;
}

/* O logo da Receita Especial é cinza-prateado, desenhado para fundo escuro:
   sobre superfície clara ele some. `logo_requer_fundo` em content/marcas.php
   diz quais precisam disto — não é preferência estética, é legibilidade. */
.carta--fundo-escuro .carta__frente {
    background: var(--cor-marrom);
    border-color: #000000;
}

.carta--casada .carta__frente {
    border-color: var(--cor-verde);
    box-shadow: inset 0 0 0 2px rgba(44, 143, 67, 0.35);
}

/* Par errado: anel vermelho enquanto as duas cartas ficam abertas. Sem isso, a
   dupla some e o participante não sabe se errou ou se o toque não pegou. */
.carta--errada .carta__frente {
    border-color: var(--cor-vermelho);
    box-shadow: inset 0 0 0 2px rgba(166, 52, 46, 0.35);
}

/* BLOQUEIO DURANTE A COMPARAÇÃO — o quarto estado, que faltava.
 *
 * Entre virar a segunda carta e o par errado voltar (850 ms) o módulo ignora
 * todo toque, e a tela não dizia isso: quem tocava numa terceira carta via
 * exatamente nada acontecer e concluía que o jogo travou. Numa fila, "travou" é
 * o participante chamando o atendente.
 *
 * Só as cartas AINDA FECHADAS apagam — as duas abertas são justamente o que
 * precisa ser olhado nesses 850 ms. `cursor: default` reforça no desktop.
 *
 * Opacidade, nunca `transform`: a carta já tem o `rotateY` da virada, e uma
 * segunda transformação aqui competiria com ela no meio do giro. */
.memoria--comparando .carta:not(.carta--aberta):not(.carta--casada) {
    opacity: 0.62;
    cursor: default;
}

.carta:not(.carta--aberta):not(.carta--casada) {
    transition: transform 0.42s cubic-bezier(.22, .61, .36, 1), opacity 0.18s linear;
}

.carta:focus-visible {
    outline: 3px solid var(--cor-marrom);
    outline-offset: 3px;
}

/* Logo e packshot NUNCA deformam: `object-fit: contain` preserva a proporção
   dos dois. A diferença entre eles é o direito de CRESCER.

   O logo não cresce: `width/height: auto` faz a imagem parar no tamanho nativo,
   e só encolher se não couber. Os arquivos oficiais de logo são pequenos (o da
   Long Life tem 115×107) e esticá-los numa TV touch borraria a marca — que é
   justamente o que a regra de uso do logo proíbe.

   O packshot cresce: são fotos de 384×335, e numa TV a embalagem precisa ser
   reconhecível do outro lado do estande. Ampliar foto perde nitidez; ampliar
   logo descaracteriza a marca. Só o segundo é inaceitável. */
.carta__logo,
.carta__packshot {
    display: block;
    object-fit: contain;
}

/* NORMALIZAÇÃO ÓPTICA — a placa do logo é limitada pelos DOIS eixos, e a
   largura é modulada por marca.

   Antes havia só `max-width: 86%`, e o comentário afirmava que `auto` deixava o
   logo no tamanho nativo. Medido por leitura de pixel: em NENHUMA das 7
   resoluções isso acontecia — os cinco batiam no teto de largura (99,4 px) e,
   com largura igual, a altura virava a razão do arquivo: 16 px (Probionutri,
   6,15:1) contra 93 px (Long Life, 1,08:1). Uma fita fina ao lado de um bloco.
   Em área de tinta efetiva, a marca mais presente ocupava 5,31× a menos
   presente, na mesma partida. Largura igual era o eixo errado.

   A placa `96cqw × 42cqw` fixa a FORMA (razão 0,44 — o mínimo da dispersão
   medida sobre estes cinco arquivos), e `--peso-optico` (content/marcas.php,
   regra 5) ajusta a largura de cada uma para igualar a tinta. Medido depois:
   5,31× → 1,00×.

   `width/height: auto` permanece e é o que garante que nada seja AMPLIADO: a
   maior escala nas 7 resoluções é 0,73× do nativo. */
.carta__logo {
    width: auto;
    height: auto;
    max-width: calc(96cqw * var(--peso-optico, 1));
    /* Trava de segurança: medido, a largura é sempre o vínculo ativo. Ela existe
       para a carta baixa (proporção 1,30), onde 42cqw poderia passar da face. */
    max-height: 88%;
}

/* Sem suporte a container query, a placa cai no comportamento anterior — logo
   desnormalizado, mas nunca deformado nem estourando a carta. */
@supports not (container-type: inline-size) {
    .carta__logo {
        max-width: 86%;
        max-height: 70%;
    }
}

.carta__packshot {
    width: 100%;
    height: 100%;
}

/* Substituto do packshot quando o arquivo não chega: o nome em tipografia da
   interface. Nunca o logo simulado com texto estilizado. */
.carta__nome {
    font-size: clamp(0.7rem, 2.4vmin, 1rem);
    font-weight: 800;
    line-height: 1.1;
    text-align: center;
    color: var(--cor-marrom);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.carta .peca__svg {
    width: 62%;
    height: auto;
}

.peca__isotipo {
    width: 46%;
    height: auto;
}

.peca__rotulo {
    font-size: 0.62rem;
    font-weight: 700;
    line-height: 1.1;
    text-align: center;
    color: var(--cor-marrom);
    text-transform: uppercase;
    letter-spacing: 0.03em;
    padding: 0 0.2rem;
}

/* Sem 3D para quem pediu menos movimento: a carta troca de face na hora, e o
   estado continua legível. */
@media (prefers-reduced-motion: reduce) {
    .carta,
    .carta--aberta,
    .carta--casada {
        transform: none;
    }

    .carta__face {
        backface-visibility: visible;
    }

    .carta__frente {
        transform: none;
        opacity: 0;
    }

    .carta--aberta .carta__frente,
    .carta--casada .carta__frente {
        opacity: 1;
    }

    .carta--aberta .carta__verso,
    .carta--casada .carta__verso {
        opacity: 0;
    }
}

/* Catcher --------------------------------------------------------------------- */

.cena {
    display: block;
    width: 100%;
    height: 100%;
    border-radius: var(--raio);
    touch-action: none;
}

/* Moldura de chumbo: fecha a cena e faz a área clara de jogo saltar. O canvas
   já desenha o próprio chumbo por dentro; aqui a moldura garante que a borda
   arredondada da área não mostre a superfície branca da página por baixo. */
.pagina--jogo .area-jogo:has(.cena) {
    padding: 0;
    background: var(--cor-chumbo);
    border-color: #000000;
}

/* Painel de meta e erro. Fica SEMPRE na tela: um contador que só aparece
   quando se erra chega tarde demais para mudar o que a pessoa vai fazer.
   `pointer-events: none` porque a área inteira é alvo de arrasto do pet — o
   painel não pode roubar um toque. */
.catcher__painel {
    position: absolute;
    top: 0.5rem;
    left: 0.5rem;
    right: 0.5rem;
    display: flex;
    justify-content: space-between;
    gap: 0.5rem;
    pointer-events: none;
    z-index: 1;
}

.catcher__contador {
    padding: 0.2rem 0.6rem;
    border-radius: 999px;
    background: rgba(43, 43, 43, 0.88);
    color: #ffffff;
    font-size: clamp(0.72rem, 2.2vmin, 0.95rem);
    font-weight: 800;
    letter-spacing: 0.02em;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.catcher__contador--bom {
    box-shadow: inset 0 0 0 2px var(--cor-verde);
}

.catcher__contador--ruim {
    box-shadow: inset 0 0 0 2px var(--cor-vermelho-vivo);
}

.catcher__contador--completo {
    background: var(--cor-verde);
}

/* Um erro do limite: o contador vira sólido. Mudança de cor, não piscar —
   piscar cansa a vista numa TV e atrapalha quem tem sensibilidade a
   movimento. */
.catcher__painel--tenso .catcher__contador--ruim {
    background: var(--cor-vermelho-vivo);
}

/* Trilha da Fórmula ------------------------------------------------------------
   CORDAS SOBRE UM CAMPO LIMPO — e essa frase é um requisito, não uma metáfora.

   A Trilha é o terceiro jogo em grade de quatro. Se o tabuleiro ler como
   mosaico de peças, ela vira "mais um match-3" e a diferenciação some
   justamente no card, que é o problema que o quarto jogo existe para resolver.
   Por isso NÃO há borda de célula, NÃO há azulejo e NÃO há quadrado colorido:
   há um campo liso, cordas grossas e pontas com a silhueta do ingrediente. */

.pagina--jogo .area-jogo:has(.trilha) {
    padding: 0;
    border-color: transparent;
    box-shadow: none;
    /* Azul institucional lavado, o mesmo matiz do herói do card — o participante
       reencontra na partida a cor que escolheu na tela anterior. Gradiente
       radial, nunca cor cheia: corda colorida sobre fundo saturado perde
       contorno. */
    background:
        radial-gradient(105% 55% at 50% 50%,
            #ffffff 0%,
            #f3f8fb 52%,
            #e4eff5 100%);
}

.trilha {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    min-height: 0;
    /* Mesma fórmula do match-3: dimensionar pelo MENOR lado da área de jogo. Sem
       isto, um celular em pé estica a célula e a corda sai oval. */
    container-type: size;
}

/* O campo é sempre QUADRADO — 5×5 de células quadradas. Uma corda que anda em
   passos retangulares parece torta mesmo estando certa. */
.trilha__campo,
.trilha__grade {
    width: min(100cqw, 100cqh);
    height: min(100cqw, 100cqh);
    margin: auto;
}

.trilha__campo {
    display: block;
    border-radius: var(--raio-grande);
    background: linear-gradient(180deg, #ffffff 0%, #eaf3f8 100%);
    border: 2px solid rgba(51, 153, 204, 0.34);
    box-shadow:
        inset 0 2px 10px rgba(31, 95, 128, 0.12),
        0 8px 24px rgba(31, 95, 128, 0.14);
    /* O SVG desenha e não recebe toque: quem recebe é a grade de botões por
       cima. Assim o alvo é a célula inteira e o teclado funciona de graça. */
    pointer-events: none;
}

/* A grade fica EM CIMA do campo, ocupando exatamente o mesmo retângulo. */
.trilha__grade {
    position: absolute;
    inset: 0;
    display: grid;
    grid-template-columns: repeat(var(--lado, 5), 1fr);
    grid-template-rows: repeat(var(--lado, 5), 1fr);
    /* Sem rolagem nem zoom acidental no meio de um arrasto longo. */
    touch-action: none;
}

/* A célula é ALVO DE TOQUE, não decoração: nenhuma borda, nenhum fundo. Num
   tabuleiro 5×5 dentro da área de jogo ela mede de 56 px (celular deitado) a
   150 px (TV), sempre acima dos 44 px mínimos. */
.trilha__celula {
    margin: 0;
    padding: 0;
    border: none;
    background: transparent;
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
}

.trilha__celula:focus-visible {
    /* `outline` e não `box-shadow`: precisa aparecer por cima da corda, e a
       corda é SVG numa camada abaixo. */
    outline: 3px solid var(--cor-marrom);
    outline-offset: -3px;
    border-radius: 25%;
}

/* A ponta ligada ganha um anel: é o sinal de "esta cor está resolvida", e é o
   que responde à pergunta "quantas faltam?" sem olhar o HUD. */
.trilha__ponta--ligada {
    filter: drop-shadow(0 0 0.06px rgba(61, 38, 36, 0.9));
}

.trilha__ponta--ligada circle {
    stroke-width: 0.1;
}

.trilha__corda {
    /* Nenhuma animação com `transform` aqui: a corda é redesenhada inteira a
       cada mudança, e uma transição de forma faria o traço "escorregar" para
       posições onde a trilha nunca esteve. */
    transition: opacity 0.14s linear;
}

/* Apagar uma cor precisa ser ÓBVIO: o modelo de jogador precisa de ~1,7
   limpezas por vitória, ou seja, apagar não é caso de canto — é o caminho
   normal. Quem não descobre que dá para recomeçar perde a partida. */
.trilha--apagando .trilha__corda {
    opacity: 0.35;
}

@media (prefers-reduced-motion: reduce) {
    .trilha__corda {
        transition: none;
    }
}

/* Resultado -------------------------------------------------------------------- */

.tela-resultado {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

/* Herói: grafismo institucional de LAÇOS (recorte de 5-marca/BG_14.jpg, 5,7 KB)
   com o isotipo na versão NEGATIVA, que é a correta sobre fundo vermelho.

   O asset anterior era um recorte de `MASCARA_ALINUTRI_01.png` com 1280x150 —
   proporção 8,53:1 dentro de uma caixa de cerca de 2,6:1. Com `cover`, o
   navegador ampliava a faixa 1,78x e mostrava entre 13% e 31% dela: o que
   chegava à tela não era grafismo, era um borrão com o ruído de compressão do
   JPEG de origem ampliado junto.

   `BG_14` estava descartado na documentação como "repete o mesmo motivo em
   variantes mais saturadas". Aberto e medido, é outro motivo: laços grossos em
   `#c62726` sobre `#750207`, com os dois cantos ocupados e o CENTRO LIMPO — que
   é exatamente a forma de que um herói com texto por cima precisa. O recorte
   (0,140)-(1920,940) sai em 2,4:1, a 1,08x da caixa real: dentro do limite de
   1,5x que este projeto adota para autorizar `cover`.

   Contraste do texto branco, medido no pixel do arquivo final SOB CADA CAIXA DE
   TEXTO real: pior caso **5,09:1** (em 1920x1080) e 11,88:1 em 320/390px. Passa
   4,5:1 em toda tela. (Este comentário já disse "6,1:1"; era estimativa sobre a
   cor nominal do laço, não medição sob o texto.) */
.heroi-resultado {
    position: relative;
    padding: 1.5rem 1.25rem 1.75rem;
    border-radius: var(--raio-grande);
    overflow: hidden;
    color: #ffffff;
    background-color: var(--cor-vermelho-profundo);
    background-image: url("../backgrounds/heroi-lacos.webp");
    background-size: cover;
    background-position: center;
    text-align: center;
}

/* EM TELA ESTREITA O HERÓI ANCORA À ESQUERDA, e isto conserta um defeito medido.
 *
 * A caixa do herói acompanha a largura de leitura: 620px de largura por ~269 de
 * altura numa tela grande (2,3:1), mas 288x245 num celular de 320px (1,17:1).
 * O arquivo tem 2,4:1 — logo, `cover` centrado recortava exatamente o miolo, que
 * é o pedaço deliberadamente vazio onde o texto fica. Medido nos pixels da
 * região visível: **0,0% de pixels com arte** em 320px e em 390px, contra 18,6%
 * e 20,1% nas caixas largas. O herói virava um retângulo chapado — e a própria
 * regra deste projeto (`cover` só a menos de 1,5x da razão da caixa) estava
 * sendo violada em 2,05x.
 *
 * Ancorado à esquerda, a região visível passa a começar no laço esquerdo do
 * arquivo, e o texto continua caindo sobre o centro limpo. O limite de 32rem é o
 * ponto em que a caixa cruza 1,8:1. */
@media (max-width: 32rem) {
    .heroi-resultado {
        background-position: left center;
    }
}

.heroi-resultado__isotipo {
    width: 2.75rem;
    height: auto;
    margin-bottom: 0.5rem;
}

.heroi-resultado__rotulo {
    margin: 0;
    font-size: 0.8125rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    opacity: 0.85;
}

.heroi-resultado__pontos {
    margin: 0.1rem 0 0;
    font-size: clamp(3rem, 14vw, 4.5rem);
    font-weight: 800;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    text-shadow: 0 2px 12px rgba(0, 0, 0, 0.35);
}

.heroi-resultado__jogo {
    margin: 0.35rem 0 0;
    font-size: 0.95rem;
    font-weight: 500;
    opacity: 0.92;
}

.card--resgate {
    text-align: left;
}

.resgate__titulo {
    margin: 0 0 0.35rem;
    font-size: 1.1rem;
    font-weight: 700;
    color: var(--cor-marrom);
}

.resgate__texto {
    margin: 0;
    color: var(--cor-texto);
}

.resgate__sufixo {
    font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
    font-size: 1.15rem;
    letter-spacing: 0.12em;
    color: var(--cor-vermelho);
}

.alerta--aviso {
    background: #fdf6ec;
    border: 1px solid var(--cor-mostarda);
    color: var(--cor-marrom);
}

.rotulo-etapa {
    margin: 0;
    font-size: 0.8125rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.09em;
    color: var(--cor-vermelho);
}

/* Conteudo de marca/produto exibido nas telas (vem do catalogo central,
   App\Content\CatalogoConteudo — nunca hardcoded no JS dos jogos). */

.grade-conteudo {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 0.75rem;
    margin-top: 1.25rem;
    text-align: left;
}

.item-conteudo {
    background: var(--cor-superficie);
    border: 1px solid var(--cor-borda);
    border-radius: var(--raio);
    padding: 0.9rem 1rem;
}

/* Packshot oficial: nunca distorcido nem cortado (object-fit: contain
   preserva a proporcao 768x670 original de todas as fotos do site). */
.item-conteudo__imagem {
    display: block;
    width: 100%;
    height: 120px;
    object-fit: contain;
    margin-bottom: 0.6rem;
}

.item-conteudo__marca {
    display: inline-block;
    /* Nome de marca é o menor texto da tela de resultado, e estava em 11,2px.
       Em `rem`, ele não cresce com o `font-size: 1.125rem` que o corpo ganha
       acima de 1280px — então 11,2px valia também numa TV. */
    font-size: 0.8125rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--cor-vermelho);
    margin-bottom: 0.25rem;
}

.item-conteudo__nome {
    font-weight: 600;
    color: var(--cor-marrom);
    margin: 0 0 0.25rem;
}

.item-conteudo__texto {
    font-size: 0.85rem;
    color: var(--cor-texto-suave);
    margin: 0;
}

/* Responsivo -------------------------------------------------------------------
   Celular estreito: Cidade/UF empilham em vez de espremer. */
@media (max-width: 480px) {
    .campo-linha {
        flex-direction: column;
        gap: 1.25rem;
    }

    .campo--uf {
        flex: 1;
    }

    .card {
        padding: 1.25rem;
    }

    .memoria {
        gap: 0.4rem;
    }
}

/* Paisagem com pouca altura: reduz respiro vertical para o botao principal
   continuar alcancavel sem rolagem excessiva. Na tela de jogo o cabecalho
   encolhe ainda mais — ali a area de jogo e o que importa.

   O teto e 40rem (640px), o MESMO da regra de grid em telas-experiencia.css.
   Enquanto eram 560px e 34rem, um monitor de 800x600 entrava no arranjo
   compacto de cards e continuava com o cromo em tamanho cheio — duas metades
   de uma decisao so, discordando entre si. */
@media (orientation: landscape) and (max-height: 40rem) {
    .cabecalho-marca {
        padding: 0.6rem 1rem;
    }

    .cabecalho-marca__logo {
        width: 110px;
    }

    .pagina {
        padding: 1rem 1rem 1.5rem;
    }

    .subtitulo {
        margin-bottom: 1rem;
    }

    /* Em 844x390 sobram cerca de 300px de palco depois do cabeçalho, e o
       título com o subtítulo consumiam quase um terço disso. Encolhidos, os
       cards sobem — sem que a tela deixe de dizer o que se espera dela. */
    h1 {
        font-size: 1.5rem;
        margin-bottom: 0.25rem;
    }

    .subtitulo {
        font-size: 0.9375rem;
        margin-bottom: 0.75rem;
    }

    .pagina--jogo .cabecalho-marca {
        padding: 0.3rem 1rem;
    }

    .pagina--jogo .cabecalho-marca__logo {
        width: 84px;
    }

    .pagina--jogo .hud {
        padding: 0.35rem 0.75rem;
        margin-bottom: 0.5rem;
    }

    .pagina--jogo .hud__valor {
        font-size: 1.1rem;
    }

    /* A memória não precisa de regra por orientação: o módulo mede a área real
       e recalcula colunas, linhas e proporção a cada redimensionamento — o que
       cobre girar o aparelho no meio da partida, que uma media query de
       orientação resolvia só pela metade (o arranjo mudava, o tamanho da carta
       continuava calculado para a outra tela). */
}

/* TV touch / telas grandes: escala tudo junto, sem reescrever componentes. */
@media (min-width: 1280px) {
    :root {
        --largura-conteudo: 700px;
    }

    body {
        font-size: 1.125rem;
    }

    .campo input,
    .campo select {
        min-height: 3.5rem;
    }

    .botao-principal {
        min-height: 4rem;
        font-size: 1.25rem;
    }

    .hud__valor {
        font-size: 1.6rem;
    }

    .peca__rotulo {
        font-size: 0.75rem;
    }
}

@media (prefers-reduced-motion: reduce) {
    * {
        transition: none !important;
        animation: none !important;
    }
}

/* ==========================================================================
   O PAINEL DO OPERADOR FICA NO CROMO ANTERIOR AO LOTE B
   ==========================================================================

   O Lote B revisou a fundação compartilhada — cabeçalho mais baixo, logo menor,
   rodapé e título encolhidos em paisagem de pouca altura — e isso chegou ao
   painel do operador de carona, porque ele usa o mesmo `layout.php`. A revisão
   visual do painel é escopo do Lote E, com decisão própria.

   Estas regras devolvem ao painel exatamente o que `92bc393` renderizava,
   incluindo o cabeçalho que JÁ encolhia em paisagem muito baixa lá (teto de
   560px = 35rem, não os 40rem que o Lote B passou a usar na experiência).

   Todas se apoiam em `.pagina--admin`, que `AdminController` põe em `body` nas
   quatro telas do painel. Quando o Lote E revisar o painel, este bloco sai
   inteiro — é um bloco de transição, não arquitetura.

   Cor NÃO está aqui: `--cor-vermelho` voltou ao valor institucional para todo
   mundo, e a cor de ação da experiência mora em `--cor-acao-evento`, aplicada
   só no CTA do participante. */

.pagina--admin .cabecalho-marca {
    padding: 1.25rem 1rem;
}

.pagina--admin .cabecalho-marca__logo {
    width: clamp(120px, 18vw, 168px);
}

@media (orientation: landscape) and (max-height: 40rem) {
    /* SÓ o `font-size`. A margem NÃO entra aqui: `admin.css` declara
       `.admin-titulo { margin: 0 0 0.35rem }` com especificidade 0,1,0, que já
       vence a regra `h1` da media query (0,0,1) sozinha. Redeclarar a margem
       neste seletor (0,2,0) passaria por cima do painel e mudaria 2,4px de
       espaçamento — medido, foi o que aconteceu na primeira tentativa deste
       isolamento. Restaurar não é sobrescrever com o valor que a gente acha que
       era: é deixar a cascata anterior voltar a valer. */
    .pagina--admin h1 {
        font-size: clamp(1.5rem, 3.5vw, 2.25rem);
    }

    .pagina--admin .subtitulo {
        font-size: clamp(1rem, 2vw, 1.15rem);
        margin-bottom: 1rem;
    }

    .pagina--admin .rodape-marca {
        padding: 1rem;
        font-size: 0.8rem;
    }
}

/* Esta faixa já existia antes do Lote B, com o mesmo teto. */
@media (orientation: landscape) and (max-height: 35rem) {
    .pagina--admin .cabecalho-marca {
        padding: 0.6rem 1rem;
    }

    .pagina--admin .cabecalho-marca__logo {
        width: 110px;
    }
}
