/* Fluxo público.
   @prd: R42, S1..S9, S17, S18

   WCAG 2.1 AA: contraste mínimo 4,5:1 em texto, alvo de toque de 44px, foco
   sempre visível. Sem framework e sem webfont — R42 orça o fluxo completo em
   1 Mbps, e fonte remota é bloqueio de render em rede ruim. */

:root {
  --tinta: #12201b;
  --tinta-2: #46574f;
  --papel: #f4f6f3;
  --papel-2: #e7ebe6;
  --linha: #c8d0c9;
  --acento: #0e6b4f;
  --acento-escuro: #0a4f3a;
  --perigo: #a6382c;
  --ok: #0e6b4f;
  --raio: 10px;
  --alvo: 44px;
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

@media (prefers-color-scheme: dark) {
  :root {
    --tinta: #e6ece8;
    --tinta-2: #a7b5ad;
    --papel: #101815;
    --papel-2: #1a2521;
    --linha: #2c3a34;
    --acento: #56b992;
    --acento-escuro: #7fd0af;
    --perigo: #e08578;
  }
}

* { box-sizing: border-box; }

/* `hidden` é display:none do agente do usuário e perde para qualquer regra
   explícita de display. Sem isto, .passos (flex) e .previa continuam visíveis
   depois de ocultadas. Mesma correção já aplicada em admin.css. */
[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--papel);
  color: var(--tinta);
  line-height: 1.55;
  font-size: 17px;
  -webkit-text-size-adjust: 100%;
}

.skip {
  position: absolute;
  left: -9999px;
  background: var(--acento);
  color: #fff;
  padding: 10px 16px;
}
.skip:focus { left: 8px; top: 8px; z-index: 10; }

:focus-visible {
  outline: 3px solid var(--acento);
  outline-offset: 2px;
}

/* ---------------------------------------------------------------- topo
   O topo veste a campanha: `--acento` e `--acento-escuro` são reescritas por
   `aplicarTema` com as cores do partido, vindas do mesmo lugar que pinta a
   faixa do card. Um eleitor que chega por link do candidato e encontra verde
   institucional não reconhece a campanha como dele — e reconhecer é o que
   antecede compartilhar. @prd: R43, R44, D3, S1 */
.topo {
  padding: 14px 20px 10px;
  border-bottom: 1px solid var(--linha);
  background: var(--papel-2);
  border-top: 4px solid var(--acento);
}
.topo-marca { display: flex; align-items: center; gap: 10px; }
.logo-partido {
  width: 30px; height: 30px; object-fit: contain; flex: none;
  background: #fff; border-radius: 6px; padding: 3px;
}
.campanha {
  margin: 0;
  font-weight: 600;
  font-size: 0.95rem;
  letter-spacing: 0.01em;
}

/* O nome e o número do candidato, na linguagem da peça eleitoral: nome em
   bold, número como bloco. É a mesma hierarquia do card que o eleitor vai
   receber, o que faz a página parecer a antessala dele. @prd: R12, D3 */
.faixa-candidato {
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px; margin-top: 10px; padding: 10px 14px;
  border-radius: var(--raio);
  background: var(--acento);
  color: var(--tinta-acento, #fff);
}
/* O retrato vem quadrado do servidor e é arredondado aqui. O anel claro o
   separa da faixa em qualquer cor de partido — sem ele, foto de fundo escuro
   sobre faixa escura vira um borrão. @prd: R43, D3 */
.faixa-retrato {
  width: 44px; height: 44px; flex: none;
  border-radius: 50%; object-fit: cover;
  border: 2px solid rgba(255, 255, 255, .85);
  background: var(--papel-2);
}
.faixa-texto { display: grid; gap: 1px; min-width: 0; }
.faixa-texto strong {
  font-size: 1.02rem; letter-spacing: -0.01em; text-transform: uppercase;
  line-height: 1.15;
}
.faixa-texto span { font-size: 0.76rem; opacity: 0.86; letter-spacing: 0.06em;
  text-transform: uppercase; }
.faixa-numero {
  font-family: ui-monospace, Consolas, monospace;
  font-weight: 700; font-size: 1.5rem; line-height: 1;
  padding: 6px 11px; border-radius: 8px; flex: none;
  /* A tinta é DERIVADA da luminância da cor secundária, no servidor. Fixar
     preto aqui deixaria o número ilegível em todo partido de cor escura — e o
     número é o elemento de maior valor da peça. @prd: R12, L1 */
  background: var(--acento-escuro); color: var(--tinta-acento-2, #10160f);
}
.passos {
  display: flex;
  gap: 6px;
  list-style: none;
  margin: 10px 0 0;
  padding: 0;
}
.passos li {
  height: 4px;
  flex: 1;
  background: var(--linha);
  border-radius: 2px;
}
.passos li[aria-current="step"] { background: var(--acento); }
.passos li.feito { background: var(--acento-escuro); }

/* ---------------------------------------------------------------- telas */
main { padding: 22px 20px 40px; max-width: 560px; margin: 0 auto; }
main:focus { outline: none; }

.tela[hidden] { display: none; }

h1 {
  font-size: 1.5rem;
  line-height: 1.25;
  margin: 0 0 8px;
  text-wrap: balance;
}

.lede { color: var(--tinta-2); margin: 0 0 18px; }
.nota { color: var(--tinta-2); font-size: 0.88rem; }
.nota code { font-family: ui-monospace, Consolas, monospace; }

.aviso {
  border-left: 4px solid var(--acento);
  background: var(--papel-2);
  padding: 12px 14px;
  border-radius: 0 var(--raio) var(--raio) 0;
  margin: 0 0 20px;
  font-size: 0.92rem;
}

/* --------------------------------------------------------------- botões */
.botao {
  display: block;
  width: 100%;
  min-height: var(--alvo);
  padding: 12px 18px;
  margin-top: 14px;
  font: inherit;
  font-weight: 600;
  border: 1px solid var(--acento);
  border-radius: var(--raio);
  background: transparent;
  color: var(--acento);
  cursor: pointer;
}
.botao.primario { background: var(--acento); color: #fff; border-color: var(--acento); }
.botao.fantasma { border-color: var(--linha); color: var(--tinta-2); }
.botao.perigo { border-color: var(--perigo); color: var(--perigo); }
.botao:disabled { opacity: 0.45; cursor: not-allowed; }
.botao:not(:disabled):hover { filter: brightness(1.08); }

.acoes { display: flex; flex-direction: column; gap: 0; }
@media (min-width: 480px) {
  .acoes { flex-direction: row; gap: 10px; }
  .acoes .botao { margin-top: 14px; }
}

/* -------------------------------------------------------------- opções */
fieldset {
  border: 1px solid var(--linha);
  border-radius: var(--raio);
  padding: 10px 14px 14px;
  margin: 0 0 16px;
}
legend {
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--tinta-2);
  padding: 0 6px;
}

.opcao {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  min-height: var(--alvo);
  padding: 8px 0;
  cursor: pointer;
}
.opcao input { width: 22px; height: 22px; margin-top: 3px; flex: none; accent-color: var(--acento); }
.opcao small { display: block; color: var(--tinta-2); font-size: 0.84rem; }
.opcao.destaque {
  border: 2px solid var(--acento);
  border-radius: var(--raio);
  padding: 12px 14px;
  background: var(--papel-2);
}

.campo { display: block; margin-bottom: 16px; font-size: 0.9rem; color: var(--tinta-2); }
.campo input {
  display: block;
  width: 100%;
  min-height: var(--alvo);
  margin-top: 6px;
  padding: 10px 12px;
  font: inherit;
  color: var(--tinta);
  background: var(--papel-2);
  border: 1px solid var(--linha);
  border-radius: var(--raio);
}

.detalhes { margin-bottom: 16px; font-size: 0.9rem; }
.detalhes summary { cursor: pointer; min-height: var(--alvo); display: flex; align-items: center; }

/* --------------------------------------------------------------- grades */
/* Seletor de estilo. Dois botões grandes, lado a lado, acima da grade.
   Controle segmentado e não abas: o eleitor está de pé, com uma mão, e
   precisa acertar de primeira. */
.estilos {
  display: flex;
  gap: 8px;
  margin: 0 0 16px;
  padding: 4px;
  background: var(--papel-2);
  border-radius: var(--raio);
}
.estilos button {
  flex: 1;
  min-height: 44px;
  border: 0;
  border-radius: calc(var(--raio) - 4px);
  background: transparent;
  color: var(--tinta-2);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  padding: 10px 8px;
}
.estilos button[aria-selected="true"] {
  background: var(--papel);
  color: var(--acento);
  box-shadow: 0 1px 3px rgba(0, 0, 0, .12);
}
.estilos button:focus-visible {
  outline: 3px solid var(--acento);
  outline-offset: 2px;
}

.grade {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 12px;
  /* DUAS colunas no celular, e não quantas couberem.
     `auto-fill` com 150px produzia três colunas de ~95px num aparelho comum, e
     a miniatura ficava do tamanho de uma unha — o eleitor escolhe entre cinco
     lugares, e cinco cartões grandes decidem melhor que quinze pequenos.
     @prd: S4, R42 */
  grid-template-columns: repeat(2, 1fr);
}
@media (min-width: 560px) {
  .grade { grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); }
}
.grade button {
  width: 100%;
  min-height: var(--alvo);
  padding: 14px 12px;
  font: inherit;
  text-align: left;
  background: var(--papel-2);
  color: var(--tinta);
  border: 2px solid var(--linha);
  border-radius: var(--raio);
  cursor: pointer;
}
.grade button:hover { border-color: var(--acento); }
.grade button strong { display: block; }
.grade button span { color: var(--tinta-2); font-size: 0.85rem; }

/* A peça de exemplo dentro do cartão.

   O padding do botão é 14px 12px e a imagem tem que sangrar até a borda —
   miniatura com moldura de fundo dentro de um cartão que já tem borda vira
   duas molduras concêntricas. As margens negativas desfazem o padding
   exatamente, e o topo arredondado acompanha o raio do cartão menos a borda
   de 2px, senão sobra um fio de fundo nos cantos.

   `aspect-ratio: 1` porque o exemplo sai no formato `feed`, que é quadrado, e
   declarar aqui reserva o espaço mesmo antes de o arquivo chegar — sem isso a
   grade pula quando cada miniatura carrega, e o dedo já a caminho de um
   cenário acerta outro. @prd: R42, S4 */
.grade button .exemplo {
  display: block;
  width: calc(100% + 24px);
  margin: -14px -12px 10px;
  /* 16:9, a mesma proporção em que o servidor recorta. Declarar aqui reserva o
     espaço antes de o arquivo chegar: sem isso a grade pula a cada imagem que
     carrega, e o dedo já a caminho de um cenário acerta outro. */
  aspect-ratio: 16 / 9;
  /* `height: auto` NÃO é redundante, e a falta dela foi ao ar.

     Os atributos `width`/`height` do `<img>` — que existem para reservar o
     espaço antes de a imagem chegar — viram dica de estilo do navegador. A
     regra acima sobrescreve a largura e não sobrescrevia a altura, então ela
     ficava presa nos 360px do atributo. E `aspect-ratio` só calcula a dimensão
     que FALTA: com largura e altura ambas definidas, ele é ignorado em
     silêncio.

     Resultado medido na página no ar: caixa de 215×360, proporção 0,60, e o
     `object-fit: cover` cortando as laterais da miniatura — o aviso do topo
     aparecia como "A GERADA POR IA · EXEMP". */
  height: auto;
  object-fit: cover;
  border-radius: calc(var(--raio) - 2px) calc(var(--raio) - 2px) 0 0;
  background: var(--linha);
}
/* O olhinho, IRMÃO do botão e não filho dele.

   O cartão inteiro é um `<button>`; botão dentro de botão é HTML inválido e no
   celular o toque cai no elemento errado — quem quis espiar acaba na tela da
   selfie. Aqui ele flutua sobre a miniatura, ancorado no `<li>`.

   44px de `--alvo`, cheios: ícone de 20px num cartão de 215px é errar o toque
   na metade das vezes, e quem erra vai parar na tela seguinte. O quadrado é
   invisível; o que se vê é o disco menor dentro dele.

   O fundo escuro não é enfeite: o ícone pousa sobre céu de Ipanema, mármore do
   Congresso e interior escuro de igreja, e nenhuma cor única se lê sobre as
   três. @prd: S4, R42 */
.grade li { position: relative; }
/* `.grade .lupa` e não `.lupa`: a lupa É um `<button>` dentro de `.grade`, e
   `.grade button` — que dá 100% de largura, padding e borda aos cartões — tem
   especificidade (0,1,1) contra (0,1,0) de uma classe sozinha. Vencia.
   Medido na página no ar: alvo de 219×44 em vez de 44×44, ocupando a largura
   inteira do cartão. Duas classes fazem (0,2,0) e passam na frente. */
.grade .lupa {
  position: absolute;
  top: 0;
  right: 0;
  width: var(--alvo);
  height: var(--alvo);
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  background: none;
  color: #fff;
  cursor: pointer;
}
.grade .lupa svg {
  width: 22px;
  height: 22px;
  border-radius: 999px;
  padding: 5px;
  background: rgba(17, 17, 17, 0.62);
}
.grade .lupa:hover svg, .grade .lupa:focus-visible svg { background: rgba(17, 17, 17, 0.85); }

/* A lupa aberta. */
.lupa-fundo {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: grid;
  place-items: center;
  padding: 16px;
  background: rgba(17, 17, 17, 0.86);
  overflow: auto;
}
.lupa-fundo[hidden] { display: none; }
.lupa-caixa {
  position: relative;
  width: min(100%, 520px);
  display: flex;
  flex-direction: column;
  gap: 12px;
  background: var(--papel);
  border-radius: var(--raio);
  padding: 16px;
}
.lupa-caixa h2 { margin: 0; padding-right: var(--alvo); font-size: 1.05rem; }
.lupa-caixa img {
  display: block;
  width: 100%;
  height: auto;          /* mesma armadilha da miniatura: sem isto o atributo
                            de altura prende a caixa e a imagem distorce */
  border-radius: calc(var(--raio) - 4px);
  background: var(--linha);
}
.lupa-fechar {
  position: absolute;
  top: 4px;
  right: 4px;
  width: var(--alvo);
  height: var(--alvo);
  font-size: 1.6rem;
  line-height: 1;
  border: 0;
  background: none;
  color: var(--tinta-2);
  cursor: pointer;
}
/* Trava a rolagem do fundo enquanto a lupa está aberta: rolar a grade atrás do
   diálogo faz a pessoa perder o lugar de onde veio. */
body.travado { overflow: hidden; }

/* Texto da política de privacidade (L5). O operador escreve em parágrafos e
   quebras de linha; sem `pre-wrap` tudo vira um bloco só e ninguém lê. Rola
   dentro da caixa para o botão de fechar nunca sair da tela. */
.politica-texto {
  white-space: pre-wrap;
  max-height: 60vh;
  overflow: auto;
  font-size: 0.92rem;
  line-height: 1.5;
}

/* Altura igual em todos os cartões da linha.

   "Congresso Brasilia" quebra em duas linhas e "Ruas" não; sem isto o cartão
   mais alto estica a linha e os vizinhos ficam com uma faixa de fundo embaixo,
   como se estivessem desalinhados por engano. */
.grade li { display: flex; }
.grade button { display: flex; flex-direction: column; }
.grade button strong { flex: 1 0 auto; }

/* -------------------------------------------------------------- selfie */
/* Dois caminhos lado a lado: câmera e galeria. Um campo só com `capture`
   força a câmera no celular e some com a galeria — e no computador o atributo
   é ignorado, sobrando só o seletor de arquivo. @prd: R4, S5 */
.alvos {
  display: grid;
  gap: 12px;
  grid-template-columns: 1fr;
}
@media (min-width: 420px) {
  .alvos { grid-template-columns: 1fr 1fr; }
}

.alvo {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  min-height: 116px;
  border: 2px dashed var(--linha);
  border-radius: var(--raio);
  cursor: pointer;
  text-align: center;
  padding: 18px 14px;
}
.alvo:hover { border-color: var(--acento); }
.alvo small { color: var(--tinta-2); font-size: 0.8rem; }
/* O botão da câmera é `<button>`, não `<label>`: `capture` não abre câmera no
   computador, então quem abre é o getUserMedia. Herdar a tipografia mantém os
   dois alvos idênticos aos olhos de quem escolhe. */
button.alvo { font: inherit; color: inherit; background: transparent; width: 100%; }

/* Câmera ao vivo. Espelhada, como o visor de qualquer aplicativo de selfie —
   a pessoa precisa se ver como se olha no espelho para se enquadrar. */
.camera { margin-top: 16px; }
.camera video {
  width: 100%;
  /* 52vh, e não 60: esconder os seletores não bastava. Num telefone alto o
     vídeo em retrato sozinho empurrava "Capturar" para baixo da dobra, e a
     pessoa precisava rolar a tela justamente enquanto se enquadrava.
     Este número é o que faz o botão caber SEMPRE, e não "quase sempre". */
  max-height: 52vh;
  border-radius: var(--raio);
  background: #000;
  transform: scaleX(-1);
  display: block;
}
.camera-acoes { display: flex; gap: 10px; margin-top: 10px; }
.camera-acoes .botao { flex: 1; }
.alvo:focus-within { outline: 3px solid var(--acento); outline-offset: 2px; }
/* O campo fica escondido e FORA do caminho do toque. Sem `pointer-events`
   ele continua interceptando o clique no meio da área — funciona por acidente,
   porque o próprio campo também abre o seletor, e deixa de funcionar assim que
   alguém o reposiciona. Quem recebe o toque é o rótulo, que é o alvo de 44px
   que a WCAG pede. */
.alvo input {
  position: absolute; opacity: 0; width: 1px; height: 1px;
  pointer-events: none;
}
.alvo-texto { font-weight: 600; color: var(--acento); }

.previa { margin: 16px 0 0; text-align: center; }
.previa img { max-width: 220px; width: 100%; border-radius: var(--raio); }
.previa figcaption { color: var(--tinta-2); font-size: 0.84rem; margin-top: 6px; }

/* ---------------------------------------------------------------- fila */
.barra {
  height: 8px;
  background: var(--papel-2);
  border-radius: 4px;
  overflow: hidden;
  margin: 20px 0 10px;
}
.barra-fill {
  height: 100%;
  width: 0%;
  background: var(--acento);
  /* 1,1 s cobre com folga o passo de 1 s do relógio: cada avanço termina de
     deslizar quando o próximo chega, e o movimento fica contínuo em vez de
     saltar. */
  transition: width 1.1s linear;
  position: relative;
  overflow: hidden;
}

/* Brilho que atravessa a barra. Existe porque a barra sozinha, avançando 0,3%
   por segundo no meio da composição, é indistinguível de uma barra parada — e
   uma barra parada, numa espera de minutos, lê-se como "travou". Este é o
   único sinal na tela que se move rápido o bastante para dizer "está vivo". */
.barra-fill::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg,
    transparent, rgba(255, 255, 255, .55), transparent);
  animation: barra-brilho 1.6s ease-in-out infinite;
}
@keyframes barra-brilho {
  from { transform: translateX(-100%); }
  to   { transform: translateX(100%); }
}
/* Concluído para de brilhar: o movimento significa "trabalhando". */
.barra-fill.pronto::after { animation: none; }

.barra-numeros {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin: 0 0 6px;
  font-variant-numeric: tabular-nums;  /* o número não dança ao mudar */
}
.barra-numeros strong { font-size: 1.5rem; color: var(--acento); }
.barra-numeros span { color: var(--tinta-2); font-size: 0.86rem; }

@media (prefers-reduced-motion: reduce) {
  .barra-fill { transition: none; }
  /* Sem o brilho, o número é quem carrega o sinal de vida — e ele muda
     sozinho a cada segundo. */
  .barra-fill::after { animation: none; }
}

/* ----------------------------------------------------------- resultado */
.resultado { margin: 0 0 8px; }
.resultado img {
  width: 100%;
  border-radius: var(--raio);
  background: var(--papel-2);
  display: block;
}
.selo-ia {
  font-size: 0.82rem;
  color: var(--tinta);
  background: var(--papel-2);
  border: 1px solid var(--linha);
  border-top: none;
  padding: 10px 12px;
  border-radius: 0 0 var(--raio) var(--raio);
}

.ficha { margin: 0; }
.ficha dt {
  font-size: 0.76rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--tinta-2);
  margin-top: 14px;
}
.ficha dd { margin: 2px 0 0; }

/* ------------------------------------------------------------- estados */
.erro {
  color: var(--perigo);
  border-left: 3px solid currentColor;
  padding-left: 10px;
  margin-top: 14px;
}
.ok {
  color: var(--ok);
  border-left: 3px solid currentColor;
  padding-left: 10px;
  margin-top: 14px;
}

.rodape {
  border-top: 1px solid var(--linha);
  padding: 16px 20px 28px;
  color: var(--tinta-2);
  font-size: 0.84rem;
  max-width: 560px;
  margin: 0 auto;
}
.rodape a { color: var(--acento); }
.rodape p { margin: 6px 0; }
