@charset "UTF-8";
/* ============================================================================
   APURAÇÃO 2026 · 2º TURNO + PROJEÇÃO HALLEY
   design-system.css — v2 · editorial, dois temas, mapa interativo.

   Substitui styles.css sem alterar uma linha de index.html, app.js ou mapa.js.
   Todos os seletores existem no HTML ou são gerados pelo JS.
   Nenhuma cor, número ou texto novo entra pela folha de estilo.

   v1: tema escuro, estados vazios, tabelas, projeção.
   v2: mapa Brasil → UF → município, tema claro completo, botão de tema.
       Nada da v1 foi removido — paleta, contraste e estados vazios seguem
       exatamente como aprovados.

   ÍNDICE
   00 · Tokens
   01 · Base e tipografia
   02 · Acessibilidade (pular, foco, seleção)
   03 · Estrutura (.app)
   04 · Topbar, marca, selos, botão de tema, frescor
   05 · Busca, atalhos, sugestões
   06 · Cartões (base)
   07 · Herói e seções
   08 · Estado vazio (aguardando) e esqueleto
   09 · Painel de apuração (ativo)
   10 · Projeção Halley
   11 · Detalhes / JSON bruto
   12 · Recorte (UF e município)
   12b · Mapa interativo (Brasil → UF → município)
   13 · Insights do 1º turno
   14 · Tabelas (empates, votos, comparecimento)
   15 · Exterior
   16 · Erro e botões
   17 · Rodapé
   18 · Utilidades numéricas
   19 · Responsivo (mobile first: base estreita, ganhos via min-width)
   20 · Tema claro (edição do dia)
   21 · Movimento, contraste e impressão
   ========================================================================== */

/* ============================================================================
   00 · TOKENS
   Um token por decisão. O JS lê alguns deles inline (--lula, --flavio, --txt-3,
   --linha, --oficial, --alerta, --imprensa-bg): esses nomes são contrato.
   ========================================================================== */

:root {
  color-scheme: dark;

  /* ---- 00.1 Superfícies (cinza neutro, sem azul; quase preto de papel à noite) */
  --bg:              #0B0C0E;
  --bg-fundo:        #08090B;
  --superficie:      #101215;
  --superficie-2:    #15181C;
  --superficie-3:    #1D2127;
  /* Municipio SEM dado no mapa: precisa contrastar com --bg, senao o
     territorio parece um buraco (era o caso: #1D2127 sobre #0B0C0E). */
  --sem-dado:        #333B45;
  --superficie-4:    #262B32;
  --veu:             rgba(11, 12, 14, 0.94);
  --poco:            rgba(0, 0, 0, 0.38);          /* fundo de bloco cru (<pre>) */
  --hover-linha:     rgba(255, 255, 255, 0.022);   /* hover de linha de tabela */

  /* ---- 00.2 Traços (1px sempre; a hierarquia vem do alfa, não da espessura) */
  --linha:           rgba(255, 255, 255, 0.075);
  --linha-forte:     rgba(255, 255, 255, 0.16);
  --linha-suave:     rgba(255, 255, 255, 0.045);
  --linha-clara:     rgba(255, 255, 255, 0.28);

  /* ---- 00.3 Texto (contraste medido sobre --superficie) */
  --txt:             #ECEEF0;  /* 16,1:1  títulos, números e valores */
  --txt-2:           #AAB1BA;  /*  8,7:1  corpo de leitura */
  --txt-3:           #868D98;  /*  5,6:1  rótulos micro, legendas */
  --txt-fantasma:    rgba(236, 238, 240, 0.20); /* número que existe para não existir */

  /* ---- 00.4 Origem do dado — o sistema de confiança da tela */
  --projecao:        #E2B15C;                          /* estimativa  9,5:1 */
  --projecao-bg:     rgba(226, 177, 92, 0.10);
  --projecao-borda:  rgba(226, 177, 92, 0.30);
  --parcial:         #74B3E0;                          /* parcial TSE 8,3:1 */
  --parcial-bg:      rgba(116, 179, 224, 0.10);
  --parcial-borda:   rgba(116, 179, 224, 0.30);
  --oficial:         #61C08F;                          /* oficial TSE 8,4:1 */
  --oficial-bg:      rgba(97, 192, 143, 0.10);
  --oficial-borda:   rgba(97, 192, 143, 0.30);
  --imprensa:        #A99BE0;                          /* imprensa    7,6:1 */
  --imprensa-bg:     rgba(169, 155, 224, 0.10);
  --imprensa-borda:  rgba(169, 155, 224, 0.30);
  --alerta:          #E3796E;                          /* falha       6,5:1 */
  --alerta-bg:       rgba(227, 121, 110, 0.09);
  --alerta-borda:    rgba(227, 121, 110, 0.30);

  /* ---- 00.5 Candidatos (só onde identifica candidato) */
  --lula:            #E0635C;                          /* 5,5:1 */
  --lula-bg:         rgba(224, 99, 92, 0.13);
  --lula-borda:      rgba(224, 99, 92, 0.32);
  --flavio:          #6E96F2;                          /* 6,5:1 */
  --flavio-bg:       rgba(110, 150, 242, 0.13);
  --flavio-borda:    rgba(110, 150, 242, 0.32);

  /* ---- 00.6 Foco (neutro de propósito: foco não é origem de dado) */
  --foco:            #D8DEE6;
  --foco-halo:       rgba(216, 222, 230, 0.18);
  --foco-largura:    2px;

  /* ---- 00.6b Mapa e trilhos (v2)
     --trilho é o fundo vazio de qualquer barra: no escuro precisa ser visível,
     no claro precisa ser mais escuro que o cartão. --mapa-traco é a linha que
     separa estados: no escuro é o próprio papel (vira respiro), no claro é
     tinta a 24% (vira contorno), porque preenchimento pálido sobre branco
     não se separa sozinho. */
  --trilho:          #1D2127;
  --mapa-traco:      #0B0C0E;
  --mapa-traco-largura: 0.6;

  /* ---- 00.7 Tipografia */
  --fonte:           -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Roboto,
                     "Helvetica Neue", Arial, "Noto Sans", sans-serif;
  --fonte-titulo:    Georgia, "Iowan Old Style", "Palatino Linotype", "Book Antiqua",
                     "Times New Roman", serif;
  --fonte-num:       ui-monospace, "SFMono-Regular", "SF Mono", "Roboto Mono", Menlo,
                     Consolas, "Liberation Mono", "Courier New", monospace;

  --fs-micro:        0.625rem;   /* 10px · carimbo, chave de coluna */
  --fs-rot:          0.6875rem;  /* 11px · rótulo caixa alta */
  --fs-pe:           0.7188rem;  /* 11,5px · nota de pé */
  --fs-sub:          0.8125rem;  /* 13px · texto de apoio */
  --fs-corpo:        clamp(0.875rem, 0.85rem + 0.12vw, 0.9375rem);
  --fs-titulo:       clamp(0.9375rem, 0.9rem + 0.14vw, 1.0625rem);
  --fs-h3:           clamp(0.9375rem, 0.9rem + 0.1vw, 1rem);
  --fs-h2:           clamp(1.125rem, 1.02rem + 0.5vw, 1.4375rem);
  --fs-h1:           clamp(1.4375rem, 1.2rem + 0.9vw, 1.875rem);
  --fs-num-heroi:    clamp(2.75rem, 2.1rem + 3.2vw, 4.25rem);
  --fs-num-cand:     clamp(1.5rem, 1.3rem + 0.9vw, 2rem);
  --fs-num-proj:     clamp(1.375rem, 1.2rem + 0.6vw, 1.625rem);
  --fs-num-insight:  clamp(1.875rem, 1.55rem + 1.4vw, 2.5rem);
  --fs-num-total:    0.9375rem;  /* 15px */

  --lh-apertada:     1.15;
  --lh-titulo:       1.3;
  --lh-corpo:        1.6;
  --tr-acao:         -0.01em;    /* tracking de título */
  --tr-numero:       -0.04em;    /* tracking de número grande */
  --tr-rotulo:       0.12em;     /* tracking de caixa alta */

  /* ---- 00.8 Espaço (base 4px) */
  --e-1:             2px;
  --e1:              4px;
  --e-meio:          6px;
  --e2:              8px;
  --e-dez:           10px;
  --e3:              12px;
  --e4:              16px;
  --e-20:            20px;
  --e5:              24px;
  --e-28:            28px;
  --e6:              32px;
  --e-40:            40px;
  --e7:              48px;
  --e-56:            56px;
  --e8:              64px;
  --e-80:            80px;

  --pad-app:         clamp(16px, 4vw, 32px);
  --pad-cartao:      clamp(16px, 3.2vw, 24px);
  --gap-grade:       clamp(12px, 1.8vw, 20px);
  --gap-secao:       clamp(32px, 5vw, 56px);

  /* ---- 00.9 Forma (editorial: canto curto, nada de bolha) */
  --r-xs:            2px;
  --r-sm:            3px;
  --r:               4px;
  --r-md:            6px;
  --r-lg:            8px;
  --r-pilula:        999px;

  --borda:           1px solid var(--linha);
  --borda-forte:     1px solid var(--linha-forte);
  --realce-topo:     2px solid transparent;

  --sombra-1:        0 1px 2px rgba(0, 0, 0, 0.40);
  --sombra-2:        0 2px 6px rgba(0, 0, 0, 0.35), 0 24px 48px -32px rgba(0, 0, 0, 0.90);
  --sombra-interna:  inset 0 1px 0 rgba(255, 255, 255, 0.02);
  --sombra-cartao:   var(--sombra-1);

  /* ---- 00.10 Movimento */
  --t-1:             110ms;
  --t-2:             200ms;
  --t-3:             320ms;
  --curva:           cubic-bezier(0.2, 0.6, 0.2, 1);
  --curva-saida:     cubic-bezier(0.4, 0, 0.2, 1);

  /* ---- 00.11 Camadas */
  --z-busca:         20;
  --z-sugestoes:     30;
  --z-pular:         90;

  /* ---- 00.12 Medidas */
  --largura-max:     1240px;
  --largura-leitura: 68ch;
  --altura-input:    44px;
  --barra-fina:      3px;
  --barra-media:     4px;
}

/* ============================================================================
   01 · BASE E TIPOGRAFIA
   ========================================================================== */

*,
*::before,
*::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-behavior: smooth;
  background: var(--bg-fundo);
}

body {
  margin: 0;
  min-height: 100vh;
  background: var(--bg);
  color: var(--txt);
  font-family: var(--fonte);
  font-size: var(--fs-corpo);
  line-height: var(--lh-corpo);
  font-kerning: normal;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overflow-x: hidden; /* rede de segurança: nenhuma tela deve rolar de lado */
}

h1,
h2,
h3,
h4 {
  margin: 0;
  font-family: var(--fonte);
  font-weight: 600;
  line-height: var(--lh-titulo);
  letter-spacing: var(--tr-acao);
  color: var(--txt);
  text-wrap: balance;
}

p { margin: 0; }

ul,
ol { margin: 0; padding: 0; }

b,
strong { font-weight: 600; color: var(--txt); }

small { font-size: inherit; }

img,
svg { max-width: 100%; }

a {
  color: var(--txt-2);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--linha-forte);
  text-underline-offset: 2px;
  transition: color var(--t-1) var(--curva),
              text-decoration-color var(--t-1) var(--curva);
}
a:hover { color: var(--txt); text-decoration-color: currentColor; }

button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
  letter-spacing: inherit;
}

button { cursor: pointer; }

table { border-collapse: collapse; }

[hidden] { display: none !important; }

/* ============================================================================
   02 · ACESSIBILIDADE
   Pular bloco, foco sempre visível, seleção legível.
   ========================================================================== */

.pular {
  position: fixed;
  top: var(--e2);
  left: var(--e2);
  z-index: var(--z-pular);
  transform: translateY(-200%);
  padding: var(--e-dez) var(--e4);
  background: var(--superficie-3);
  border: var(--borda-forte);
  border-radius: var(--r-sm);
  color: var(--txt);
  font-size: var(--fs-sub);
  font-weight: 600;
  text-decoration: none;
  box-shadow: var(--sombra-2);
  transition: transform var(--t-2) var(--curva);
}
.pular:focus,
.pular:focus-visible { transform: translateY(0); color: var(--txt); }

:focus-visible {
  outline: var(--foco-largura) solid var(--foco);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

::selection {
  background: rgba(116, 179, 224, 0.30);
  color: #FFFFFF;
}

/* Barra de rolagem discreta, coerente com o tema escuro */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--superficie-4) transparent;
}
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
  background: var(--superficie-4);
  border: 3px solid var(--bg);
  border-radius: var(--r-pilula);
}

/* ============================================================================
   03 · ESTRUTURA
   ========================================================================== */

.app {
  width: 100%;
  max-width: var(--largura-max);
  margin-inline: auto;
  padding: clamp(20px, 4vw, 40px) var(--pad-app) var(--e7);
}

/* ============================================================================
   04 · TOPBAR, MARCA, SELOS, FRESCOR
   ========================================================================== */

.topbar {
  display: flex;
  flex-direction: column;
  gap: var(--e4);
  padding-bottom: var(--e5);
  border-bottom: var(--borda);
  /* Header fixo: fica no topo e o conteúdo passa por baixo. Fundo --bg é opaco
     nos dois temas (não é rgba) — é isso que impede o texto de "vazar" por
     trás do header na rolagem. z-index acima da barra de busca (20). */
  position: sticky;
  top: 0;
  z-index: 45;
  background: var(--bg);
}

.topbar-marca { min-width: 0; }

.marca-linha {
  display: flex;
  align-items: center;
  gap: var(--e-dez);
  min-width: 0;
}

.marca-ponto {
  flex: none;
  width: 7px;
  height: 7px;
  border-radius: var(--r-pilula);
  background: var(--oficial);
  box-shadow: 0 0 0 3px var(--oficial-bg);
}

.topbar h1 {
  font-family: var(--fonte-titulo);
  font-size: var(--fs-h1);
  font-weight: 600;
  line-height: var(--lh-apertada);
  letter-spacing: -0.015em;
  text-wrap: balance;
}

.marca-turno {
  display: inline-block;
  margin-left: var(--e-meio);
  padding: 2px 6px;
  border: var(--borda-forte);
  border-radius: var(--r-xs);
  color: var(--txt-3);
  font-family: var(--fonte);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: var(--tr-rotulo);
  text-transform: uppercase;
  vertical-align: 0.16em;
  white-space: nowrap;
}

.marca-disputa {
  margin-top: var(--e-meio);
  color: var(--txt-2);
  font-size: var(--fs-sub);
  overflow-wrap: break-word;
}

.marca-disputa b {
  font-family: var(--fonte-num);
  font-size: 0.9375rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
}
.num-lula { color: var(--lula); }
.num-flavio { color: var(--flavio); }

.topbar-estado {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--e2);
  min-width: 0;
}

/* Selos + botão de tema na mesma linha, alinhados pela base
   Carimbo retangular, não pílula: é a legenda do sistema de confiança. */
.selos-linha {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--e2);
  min-width: 0;
}

.selos {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e-meio);
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Alternador de tema: 30×30 visual (como o contrato pede), com área de toque
   real de 44×44 — o ::after transparente é o que o dedo acerta no celular. */
.tema-btn {
  position: relative;
  flex: none;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: var(--borda);
  border-radius: var(--r-pilula);
  background: var(--superficie-2);
  color: var(--txt-3);
  font-size: 0.75rem;
  line-height: 1;
  transition: color var(--t-1) var(--curva),
              background-color var(--t-1) var(--curva),
              border-color var(--t-1) var(--curva);
}
.tema-btn::after {
  content: "";
  position: absolute;
  inset: -7px;
  border-radius: var(--r-pilula);
}
.tema-btn:hover {
  color: var(--txt);
  background: var(--superficie-3);
  border-color: var(--linha-forte);
}
.tema-btn:active { background: var(--superficie-4); }
#tema-icone { pointer-events: none; }

.selo {
  display: inline-flex;
  align-items: center;
  gap: var(--e1);
  padding: 3px 7px;
  border: 1px solid transparent;
  border-radius: var(--r-xs);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: var(--tr-rotulo);
  line-height: 1.5;
  text-transform: uppercase;
  white-space: nowrap;
}

.selo::before {
  content: "";
  flex: none;
  width: 4px;
  height: 4px;
  border-radius: var(--r-pilula);
  background: currentColor;
}

.selo-projecao {
  color: var(--projecao);
  background: var(--projecao-bg);
  border-color: var(--projecao-borda);
}
.selo-parcial {
  color: var(--parcial);
  background: var(--parcial-bg);
  border-color: var(--parcial-borda);
}
.selo-oficial {
  color: var(--oficial);
  background: var(--oficial-bg);
  border-color: var(--oficial-borda);
}
.selo-imprensa {
  color: var(--imprensa);
  background: var(--imprensa-bg);
  border-color: var(--imprensa-borda);
}

/* Selo embutido em título de cartão: mesmo carimbo, menor */
.selo-inline {
  margin-left: var(--e2);
  padding: 1px 5px;
  font-size: 0.5938rem;   /* 9,5px */
  font-weight: 600;
  letter-spacing: 0.1em;
  vertical-align: 0.14em;
  white-space: nowrap;
}
.selo-inline::before { display: none; }

/* Frescor da coleta: verde / âmbar / vermelho, sempre com texto junto */
.frescor {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--e-meio);
  margin: 0;
  color: var(--txt-3);
  font-family: var(--fonte-num);
  font-size: var(--fs-pe);
  font-variant-numeric: tabular-nums;
  line-height: 1.5;
}

.frescor-dot {
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: var(--r-pilula);
  background: var(--oficial);
  animation: respirar 2.8s var(--curva) infinite;
}

.frescor.parado { color: var(--projecao); }
.frescor.parado .frescor-dot {
  background: var(--projecao);
  animation-duration: 1.1s;
}

.frescor.morto { color: var(--alerta); }
.frescor.morto .frescor-dot {
  background: var(--alerta);
  animation: none;
}

/* ============================================================================
   05 · BUSCA, ATALHOS, SUGESTÕES
   ========================================================================== */

.busca-barra {
  position: sticky;
  /* Para abaixo do header fixo (--topbar-h), senão as duas barras se
     sobrepõem no topo quando a seção do mapa chega lá. */
  top: var(--topbar-h, 0px);
  z-index: var(--z-busca);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--e3);
  margin: var(--e4) calc(var(--pad-app) * -1) var(--e5);
  padding: var(--e3) var(--pad-app);
  background: var(--veu);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border-bottom: var(--borda);
}

.busca-campo {
  position: relative;
  display: flex;
  align-items: center;
  flex: 1 1 100%;
  min-width: 0;
}

.busca-icone {
  position: absolute;
  left: var(--e3);
  display: flex;
  color: var(--txt-3);
  pointer-events: none;
  transition: color var(--t-1) var(--curva);
}
.busca-icone svg { width: 15px; height: 15px; }
.busca-campo:focus-within .busca-icone { color: var(--txt-2); }

#busca {
  width: 100%;
  min-height: var(--altura-input);
  padding: 10px 44px 10px 38px;
  background: var(--superficie);
  color: var(--txt);
  border: var(--borda);
  border-radius: var(--r);
  font-size: 1rem;              /* 16px no mobile: evita zoom automático do iOS */
  letter-spacing: 0;
  outline: none;
  transition: border-color var(--t-1) var(--curva),
              background-color var(--t-1) var(--curva);
  -webkit-appearance: none;
  appearance: none;
}

#busca::placeholder { color: var(--txt-3); opacity: 1; }

#busca:hover { border-color: var(--linha-forte); }

#busca:focus,
#busca:focus-visible {
  background: var(--superficie-2);
  border-color: var(--linha-clara);
  outline: var(--foco-largura) solid var(--foco);
  outline-offset: 1px;
}

#busca::-webkit-search-cancel-button { display: none; }

.busca-limpar {
  position: absolute;
  right: var(--e1);
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  padding: 0;
  border: 0;
  border-radius: var(--r-pilula);
  background: transparent;
  color: var(--txt-3);
  font-size: 1.125rem;
  line-height: 1;
  transition: background-color var(--t-1) var(--curva),
              color var(--t-1) var(--curva);
}
.busca-limpar:hover {
  background: var(--superficie-3);
  color: var(--txt);
}
.busca-limpar:active { background: var(--superficie-4); }

.busca-atalhos {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e-meio);
  min-width: 0;
}

.atalho {
  min-height: 32px;
  padding: 5px 10px;
  border: var(--borda);
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--txt-2);
  font-size: var(--fs-pe);
  font-weight: 500;
  letter-spacing: 0.01em;
  transition: color var(--t-1) var(--curva),
              border-color var(--t-1) var(--curva),
              background-color var(--t-1) var(--curva);
}
.atalho:hover {
  color: var(--txt);
  border-color: var(--linha-forte);
  background: var(--superficie-2);
}
.atalho:active { background: var(--superficie-3); }

/* Seleção de escopo é estado de interface — nunca usa cor de origem de dado */
.atalho.ativo {
  color: var(--txt);
  border-color: var(--linha-clara);
  background: var(--superficie-3);
  box-shadow: inset 0 -2px 0 var(--txt);
}

.sugestoes {
  position: absolute;
  left: var(--pad-app);
  right: var(--pad-app);
  top: calc(100% - var(--e2));
  z-index: var(--z-sugestoes);
  max-height: min(60vh, 340px);
  overflow-y: auto;
  overscroll-behavior: contain;
  list-style: none;
  margin: 0;
  padding: var(--e1);
  background: var(--superficie-2);
  border: var(--borda-forte);
  border-radius: var(--r);
  box-shadow: var(--sombra-2);
}

.sugestoes li {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--e3);
  min-height: 42px;
  padding: var(--e-dez) var(--e3);
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: background-color var(--t-1) var(--curva);
}
.sugestoes li:hover { background: var(--superficie-3); }
.sugestoes li[aria-selected="true"] {
  background: var(--superficie-3);
  box-shadow: inset 2px 0 0 var(--txt);
}

.sugestoes .sug-nome {
  min-width: 0;
  font-size: var(--fs-corpo);
  color: var(--txt);
  overflow-wrap: break-word;
}

.sugestoes .sug-uf {
  flex: none;
  color: var(--txt-3);
  font-family: var(--fonte-num);
  font-size: var(--fs-pe);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.sugestoes .sug-vazio {
  color: var(--txt-3);
  cursor: default;
  justify-content: flex-start;
}

/* ============================================================================
   06 · CARTÕES (BASE)
   Superfície chapada, 1px de borda, sombra quase imperceptível.
   ========================================================================== */

.cartao {
  min-width: 0;
  background: var(--superficie);
  border: var(--borda);
  border-radius: var(--r-md);
  box-shadow: var(--sombra-cartao), var(--sombra-interna);
  overflow: hidden;
}

/* Acento de 2px = origem do dado que domina o cartão */
.cartao-painel { border-top: var(--realce-topo); border-top-color: var(--parcial); }
.cartao-projecao { border-top: var(--realce-topo); border-top-color: var(--projecao); }

/* Progressivo: acentos nas seções de referência (ignorado por navegador antigo) */
.cartao-tabela:has(#tabela-votos) { border-top: var(--realce-topo); border-top-color: var(--oficial); }
.cartao:has(#exterior) { border-top: var(--realce-topo); border-top-color: var(--imprensa); }

.cartao-topo {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--e-meio) var(--e3);
  padding: var(--e3) var(--pad-cartao);
  border-bottom: var(--borda);
  min-width: 0;
}

.cartao-topo h2 {
  font-size: var(--fs-titulo);
  font-weight: 600;
  letter-spacing: -0.012em;
  min-width: 0;
}

.cartao-topo h3 {
  font-size: var(--fs-h3);
  font-weight: 600;
  letter-spacing: -0.008em;
  min-width: 0;
}

.cartao-meta {
  color: var(--txt-3);
  font-family: var(--fonte-num);
  font-size: var(--fs-pe);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
  white-space: nowrap;
}
.cartao-meta:empty { display: none; }

.cartao-link {
  color: var(--txt-3);
  font-size: var(--fs-rot);
  letter-spacing: 0.02em;
  text-decoration-color: var(--linha);
  white-space: nowrap;
}
.cartao-link:hover { color: var(--txt-2); }

.cartao-corpo {
  min-width: 0;
  padding: var(--pad-cartao);
}
.cartao-corpo.sem-padding { padding: 0; }

/* ============================================================================
   07 · HERÓI E SEÇÕES
   ========================================================================== */

.linha-heroi {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--gap-grade);
  margin-bottom: var(--gap-secao);
}

.secao { margin-bottom: var(--gap-secao); }

.secao-topo {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--e1) var(--e4);
  padding-bottom: var(--e-dez);
  margin-bottom: var(--e4);
  border-bottom: var(--borda);
}

.secao-topo h2 {
  font-family: var(--fonte-titulo);
  font-size: var(--fs-h2);
  font-weight: 600;
  letter-spacing: -0.012em;
  line-height: 1.2;
  min-width: 0;
}

.secao-nota {
  color: var(--txt-3);
  font-size: var(--fs-rot);
  letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: break-word;
}

.grade-insights {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 288px), 1fr));
  gap: var(--gap-grade);
}

.grade-dupla {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--gap-grade);
}

/* ============================================================================
   08 · ESTADO VAZIO (AGUARDANDO) E ESQUELETO
   O vazio é desenhado como ficha em branco: carimbo, linha para preencher,
   número fantasma e texto curto. Vazio de propósito, nunca quebrado.
   ========================================================================== */

.vazio {
  display: flex;
  flex-direction: column;
  gap: var(--e4);
  min-width: 0;
}

.vazio-selo {
  display: inline-flex;
  align-items: center;
  gap: var(--e-meio);
  align-self: flex-start;
  padding: 3px 7px;
  border: 1px solid transparent;
  border-radius: var(--r-xs);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: var(--tr-rotulo);
  line-height: 1.5;
  text-transform: uppercase;
}
.vazio-selo::before {
  content: "";
  flex: none;
  width: 4px;
  height: 4px;
  border-radius: var(--r-pilula);
  background: currentColor;
}
.vazio-selo.espera {
  color: var(--txt-2);
  background: var(--superficie-2);
  border-color: var(--linha-forte);
}
.vazio-selo.parcial {
  color: var(--parcial);
  background: var(--parcial-bg);
  border-color: var(--parcial-borda);
}
.vazio-selo.erro {
  color: var(--alerta);
  background: var(--alerta-bg);
  border-color: var(--alerta-borda);
}

/* O traço grande do vazio: linha pautada esperando o número */
.vazio-num {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--e-dez);
  padding-bottom: var(--e3);
  border-bottom: 1px dashed var(--linha-forte);
  color: var(--txt-fantasma);
  font-family: var(--fonte-num);
  font-size: clamp(2.5rem, 2rem + 2.6vw, 3.5rem);
  font-variant-numeric: tabular-nums;
  font-weight: 400;
  letter-spacing: -0.05em;
  line-height: 1;
}

.vazio-num small {
  color: var(--txt-3);
  font-family: var(--fonte);
  font-size: var(--fs-rot);
  font-weight: 500;
  letter-spacing: var(--tr-rotulo);
  text-transform: uppercase;
  line-height: 1.4;
}

.vazio-titulo {
  font-family: var(--fonte-titulo);
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.35;
  color: var(--txt);
}

.vazio-texto {
  max-width: 52ch;
  color: var(--txt-2);
  font-size: var(--fs-sub);
  line-height: 1.65;
  overflow-wrap: break-word;
}
.vazio-texto strong { color: var(--txt); font-weight: 600; }

.vazio-lista {
  display: flex;
  flex-direction: column;
  gap: var(--e-meio);
  list-style: none;
  margin: 0;
  padding: 0;
}

.vazio-lista li {
  position: relative;
  padding-left: var(--e4);
  color: var(--txt-3);
  font-size: var(--fs-rot);
  font-variant-numeric: tabular-nums;
  line-height: 1.6;
}
.vazio-lista li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.72em;
  width: 6px;
  height: 1px;
  background: var(--linha-clara);
}
.vazio-lista strong { color: var(--txt-2); font-weight: 600; }

/* Esqueleto de carregamento: pulso, sem varredura de gradiente */
.esqueleto {
  height: 88px;
  border: 1px solid var(--linha-suave);
  border-radius: var(--r-sm);
  background: var(--superficie-2);
  animation: pulsar 1.9s var(--curva) infinite;
}
.esqueleto + .esqueleto { margin-top: var(--e3); }
.esqueleto-alto { height: 200px; margin: 0; }

/* ============================================================================
   09 · PAINEL DE APURAÇÃO (ATIVO)
   O número de seções apuradas é o maior da tela: dimensiona a confiança de tudo.
   ========================================================================== */

.painel-secoes {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--e1) var(--e3);
  margin-bottom: var(--e3);
}

.painel-secoes .num {
  color: var(--txt);
  font-family: var(--fonte-num);
  font-size: var(--fs-num-heroi);
  font-variant-numeric: tabular-nums;
  font-weight: 400;
  letter-spacing: var(--tr-numero);
  line-height: 0.95;
  min-width: 0;
}

.painel-secoes .rot {
  color: var(--txt-3);
  font-size: var(--fs-rot);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.06em;
  line-height: 1.45;
  text-transform: uppercase;
  overflow-wrap: break-word;
}

.barra-progresso {
  height: var(--barra-fina);
  margin-bottom: var(--e5);
  border-radius: var(--r-xs);
  background: var(--trilho);
  overflow: hidden;
}

.barra-progresso > span {
  display: block;
  height: 100%;
  border-radius: var(--r-xs);
  background: var(--parcial);
  transition: width var(--t-3) var(--curva-saida);
}

.candidatos {
  display: flex;
  flex-direction: column;
  gap: var(--e4);
}

.candidato {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  gap: var(--e1) var(--e3);
  min-width: 0;
}

.candidato-nome {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--e-meio);
  min-width: 0;
  color: var(--txt);
  font-size: var(--fs-titulo);
  font-weight: 600;
  letter-spacing: -0.012em;
  line-height: 1.3;
}

.candidato-num {
  flex: none;
  padding: 1px 5px;
  border: 1px solid transparent;
  border-radius: var(--r-xs);
  font-family: var(--fonte-num);
  font-size: var(--fs-rot);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  letter-spacing: 0.02em;
  line-height: 1.5;
}

.cand-lula .candidato-num {
  color: var(--lula);
  background: var(--lula-bg);
  border-color: var(--lula-borda);
}
.cand-flavio .candidato-num {
  color: var(--flavio);
  background: var(--flavio-bg);
  border-color: var(--flavio-borda);
}

.candidato-pct {
  color: var(--txt);
  font-family: var(--fonte-num);
  font-size: var(--fs-num-cand);
  font-variant-numeric: tabular-nums;
  font-weight: 500;
  letter-spacing: -0.035em;
  line-height: 1;
  white-space: nowrap;
}

.candidato-votos {
  grid-column: 1 / -1;
  color: var(--txt-3);
  font-family: var(--fonte-num);
  font-size: var(--fs-sub);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
  overflow-wrap: break-word;
}

.candidato-barra {
  grid-column: 1 / -1;
  height: var(--barra-fina);
  margin-top: var(--e1);
  border-radius: var(--r-xs);
  background: var(--trilho);
  overflow: hidden;
}

.candidato-barra > span {
  display: block;
  height: 100%;
  border-radius: var(--r-xs);
  transition: width var(--t-3) var(--curva-saida);
}
.cand-lula .candidato-barra > span { background: var(--lula); }
.cand-flavio .candidato-barra > span { background: var(--flavio); }

.totais {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--e3) var(--e4);
  margin-top: var(--e5);
  padding-top: var(--e4);
  border-top: var(--borda);
}

.total-item {
  display: flex;
  flex-direction: column;
  gap: var(--e-1);
  min-width: 0;
}

.total-rot {
  color: var(--txt-3);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.1em;
  line-height: 1.5;
  text-transform: uppercase;
}

/* Percentual na frente do valor numerico nos totais (Comparecimento,
   Validos, Brancos, Nulos, Abstenciones, Eleitorado). Fica menor e em cor de
   apoio para o numero absoluto continuar sendo o protagonista. */
.total-pct {
  color: var(--txt-3);
  font-size: 0.78em;
  font-weight: 600;
  letter-spacing: 0;
  margin-right: 1px;
}

.total-val {
  color: var(--txt);
  font-family: var(--fonte-num);
  font-size: var(--fs-num-total);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
  overflow-wrap: break-word;
}

/* ============================================================================
   10 · PROJEÇÃO HALLEY
   Sempre marcada como estimativa: âmbar no selo, no aviso e no acento do cartão.
   ========================================================================== */

.proj-aviso {
  display: flex;
  align-items: flex-start;
  gap: var(--e-dez);
  padding: var(--e-dez) var(--e3);
  border: 1px solid var(--projecao-borda);
  border-left: 2px solid var(--projecao);
  border-radius: var(--r-sm);
  background: var(--projecao-bg);
  color: var(--txt-2);
  font-size: var(--fs-rot);
  line-height: 1.6;
}

.proj-aviso > span[aria-hidden="true"] {
  flex: none;
  color: var(--txt-2);
  font-family: var(--fonte-num);
  font-size: var(--fs-rot);
  font-weight: 600;
  line-height: 1.6;
  opacity: 0.85;
}

.proj-aviso strong { color: var(--txt); font-weight: 600; }

.proj-linha {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  gap: var(--e-meio) var(--e3);
  min-width: 0;
}

.proj-nome {
  min-width: 0;
  color: var(--txt);
  font-size: var(--fs-titulo);
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.3;
  overflow-wrap: break-word;
}

.proj-pct {
  color: var(--txt);
  font-family: var(--fonte-num);
  font-size: var(--fs-num-proj);
  font-variant-numeric: tabular-nums;
  font-weight: 500;
  letter-spacing: -0.03em;
  line-height: 1;
  white-space: nowrap;
}

.proj-barra {
  display: block;
  grid-column: 1 / -1;
  height: var(--barra-media);
  border-radius: var(--r-xs);
  background: var(--trilho);
  overflow: hidden;
}

.proj-barra > span {
  display: block;
  height: 100%;
  border-radius: var(--r-xs);
  transition: width var(--t-3) var(--curva-saida);
}

.proj-sub {
  grid-column: 1 / -1;
  color: var(--txt-3);
  font-size: var(--fs-rot);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
}

.chance {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--e3) var(--e4);
  margin-top: var(--e5);
  padding-top: var(--e4);
  border-top: var(--borda);
}

.chance-item {
  display: flex;
  flex-direction: column;
  gap: var(--e-1);
  min-width: 0;
}

.chance-val {
  color: var(--txt);
  font-family: var(--fonte-num);
  font-size: 0.875rem;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
  overflow-wrap: break-word;
}

/* ============================================================================
   11 · DETALHES / JSON BRUTO
   Estrutura desconhecida: o dado cru fica visível, sem virar número inventado.
   ========================================================================== */

.detalhes {
  margin-top: var(--e4);
  padding-top: var(--e3);
  border-top: var(--borda);
}

.detalhes summary {
  display: flex;
  align-items: center;
  gap: var(--e2);
  min-height: 24px;
  color: var(--txt-3);
  font-size: var(--fs-rot);
  font-weight: 600;
  letter-spacing: 0.08em;
  line-height: 1.5;
  text-transform: uppercase;
  cursor: pointer;
  list-style: none;
  transition: color var(--t-1) var(--curva);
}
.detalhes summary::-webkit-details-marker { display: none; }
.detalhes summary:hover { color: var(--txt-2); }

.detalhes summary::before {
  content: "+";
  flex: none;
  color: var(--txt-3);
  font-family: var(--fonte-num);
  font-size: var(--fs-sub);
  line-height: 1;
}
.detalhes[open] > summary::before { content: "\2212"; }

.detalhes pre {
  max-height: 280px;
  margin: var(--e3) 0 0;
  padding: var(--e3);
  overflow: auto;
  overscroll-behavior: contain;
  border: var(--borda);
  border-radius: var(--r-sm);
  background: var(--poco);
  color: var(--txt-2);
  font-family: var(--fonte-num);
  font-size: 0.6875rem;
  line-height: 1.6;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* ============================================================================
   12 · RECORTE (UF E MUNICÍPIO)
   ========================================================================== */

.recorte { margin-bottom: var(--gap-secao); }

.recorte .cartao {
  border-color: var(--linha-forte);
  background: var(--superficie-2);
}

.recorte-topo {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--e3);
  min-width: 0;
}

.recorte-nome {
  font-family: var(--fonte-titulo);
  font-size: clamp(1.25rem, 1.1rem + 0.6vw, 1.5rem);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.2;
  overflow-wrap: break-word;
}

.recorte-sub {
  margin-top: var(--e1);
  color: var(--txt-3);
  font-size: var(--fs-rot);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
}

.recorte-numeros {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--e4);
  margin-top: var(--e5);
}

.recorte-num {
  display: flex;
  flex-direction: column;
  gap: var(--e-1);
  min-width: 0;
}

.recorte-num .v {
  color: var(--txt);
  font-family: var(--fonte-num);
  font-size: 0.9375rem;
  font-variant-numeric: tabular-nums;
  font-weight: 500;
  letter-spacing: -0.015em;
  overflow-wrap: break-word;
}

.recorte-num .r {
  color: var(--txt-3);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.1em;
  line-height: 1.5;
  text-transform: uppercase;
}

.pilula-vencedor {
  display: inline-flex;
  align-items: center;
  gap: var(--e-meio);
  padding: 3px 8px;
  border: 1px solid transparent;
  border-radius: var(--r-xs);
  font-size: var(--fs-rot);
  font-weight: 600;
  letter-spacing: 0.03em;
  white-space: nowrap;
}

.pilula-lula {
  color: var(--lula);
  background: var(--lula-bg);
  border-color: var(--lula-borda);
}
.pilula-flavio {
  color: var(--flavio);
  background: var(--flavio-bg);
  border-color: var(--flavio-borda);
}

/* ============================================================================
   12b · MAPA INTERATIVO (BRASIL → UF → MUNICÍPIO)
   Três níveis, uma superfície. O mapa é uma prancha impressa, não um painel
   de controle: sem sombra própria, sem glow, sem animação de entrada.
   Quem manda no desenho é o preenchimento calculado pelo mapa.js
   (cor = candidato vencedor, fill-opacity = tamanho da margem). O CSS cuida
   de moldura, traço, foco, carregamento e do índice lateral — que é a
   alternativa acessível obrigatória: mapa coroplético não é a única porta.
   ========================================================================== */

/* ---- 12b.1 Cabeçalho da seção: título, nota e "voltar" na mesma linha ---- */

.secao-mapa .secao-topo {
  align-items: center;
  row-gap: var(--e2);
}

.btn-voltar { margin-left: auto; }

/* ---- 12b.2 Grade: prancha à esquerda, índice à direita ---- */

.mapa-grade {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--gap-grade);
  align-items: start;
}

/* ---- 12b.3 Prancha ---- */

.mapa-caixa {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 240px;
  padding: var(--e3);
  /* fio interno: dá a sensação de moldura de mapa impresso, sem sombra extra */
  box-shadow: var(--sombra-cartao), inset 0 0 0 1px var(--linha-suave);
}

.mapa-svg {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-width: 0;
  min-height: 180px;
}

.mapa-svg svg {
  display: block;
  max-width: 100%;
  height: auto;
}

/* Drill-down: a malha anterior fica no lugar, esmaecida, até a nova chegar.
   Nada de tela em branco entre um nível e outro. */
.mapa-svg[aria-busy="true"] { cursor: progress; }

.mapa-svg[aria-busy="true"] svg {
  opacity: 0.35;
  transition: opacity var(--t-2) var(--curva);
}

/* ---- 12b.4 Estados dos paths ----
   fill e fill-opacity vêm por atributo (dado). O traço é a única coisa que o
   CSS decide: no escuro ele é o papel (vira respiro entre estados), no claro
   é tinta a 24% (vira contorno, porque preenchimento pálido sobre branco
   não se separa sozinho). Ver token --mapa-traco. */

.mapa-svg path {
  stroke: var(--mapa-traco);
  stroke-width: var(--mapa-traco-largura);
  stroke-linejoin: round;
  stroke-linecap: round;
  cursor: pointer;
  transition: fill-opacity var(--t-1) var(--curva),
              stroke var(--t-1) var(--curva),
              stroke-width var(--t-1) var(--curva);
}

/* Destaque de alvo: contorno BRANCO. Branco puro (#fff) de propósito — não é
   tinta de texto, é marcação de alvo, e não deve competir com os tokens de
   origem do dado.

   paint-order: stroke desenha o traço ATRÁS do preenchimento: o 2px vira halo
   externo em volta da forma, em vez de comer 1px da borda do estado por
   dentro. Sem ele, o traço de 2px fica metade dentro e acinzentado pelo
   preenchimento translúcido. */
.mapa-svg path:hover {
  stroke: #fff;
  stroke-width: 2;
  paint-order: stroke;
}

/* Foco de teclado: mesmo branco, mesmos 2px — o anel é o próprio traço. */
.mapa-svg path:focus-visible {
  stroke: #fff;
  stroke-width: 2;
  paint-order: stroke;
  outline: none;
}

/* Selecionado: branco mais grosso (2,5px) para separar do hover — é o recorte
   atual, um estado que fica, não um alvo sob o cursor. */
.mapa-svg path.ativo {
  stroke: #fff;
  stroke-width: 2.5;
  paint-order: stroke;
}

/* Tema claro: branco sobre o cartão (#FFFFFF) dá 1,00:1 e sobre o papel
   (#F4F6F9) 1,08:1, o halo desaparece. A sombra de 1px acompanha o contorno
   do path e desenha o limite do branco.
   Alfa 0,50 e não 0,45: a 0,45 a sombra fica #93979D e o fio escuro contra o
   cartão rende 2,94:1 (abaixo dos 3:1 de elemento gráfico). A 0,50 rende
   3,43:1 no cartão e 3,38:1 no papel, e o branco contra a sombra 3,43:1.
   Este bloco é o FALLBACK: vale enquanto o path não tiver data-nivel. */
[data-tema="claro"] .mapa-svg path:hover,
[data-tema="claro"] .mapa-svg path:focus-visible,
[data-tema="claro"] .mapa-svg path.ativo {
  filter: drop-shadow(0 0 1px rgba(14, 23, 38, 0.50));
}

/* ---- Duas escalas de mapa, duas espessuras ------------------------------
   A mesma espessura não serve para os dois níveis. Medido no documento, em
   1280px de tela:
     estado    · mediana 82,7 x 54,9 · maior 224,7 x 158 (AM) · menor 12,3 x 7,3 (DF)
     município · mediana 13,5 x 12,1 · maior 82,5 x 56,1 · menor 1,6 x 0,8 (853 de MG)
   Um traço de 2,5px num município de 13px cobre 19% da forma: o branco come o
   preenchimento, invade o vizinho e a sombra vira ruído. Num estado de 83px o
   mesmo 2,5px é discreto. Daí 2 / 2,5 no estado e 1 / 1,4 no município.
   O mapa.js ainda não emite data-nivel: até emitir, valem as regras acima. */

.mapa-svg path[data-nivel="estado"]:hover {
  stroke: #fff;
  stroke-width: 2;
  paint-order: stroke;
}

.mapa-svg path[data-nivel="estado"]:focus-visible {
  stroke: #fff;
  stroke-width: 2;
  paint-order: stroke;
  outline: none;
}

.mapa-svg path[data-nivel="estado"].ativo {
  stroke: #fff;
  stroke-width: 2.5;
  paint-order: stroke;
}

.mapa-svg path[data-nivel="municipio"]:hover {
  stroke: #fff;
  stroke-width: 1;
  paint-order: stroke;
}

.mapa-svg path[data-nivel="municipio"]:focus-visible {
  stroke: #fff;
  stroke-width: 1;
  paint-order: stroke;
  outline: none;
}

.mapa-svg path[data-nivel="municipio"].ativo {
  stroke: #fff;
  stroke-width: 1.4;
  paint-order: stroke;
}

/* Sombra só no estado. No município de 13px ela não desenha limite de nada:
   o fio de 1px some dentro do próprio halo e suja a divisa com o vizinho. */
[data-tema="claro"] .mapa-svg path[data-nivel="estado"]:hover,
[data-tema="claro"] .mapa-svg path[data-nivel="estado"]:focus-visible,
[data-tema="claro"] .mapa-svg path[data-nivel="estado"].ativo {
  filter: drop-shadow(0 0 1px rgba(14, 23, 38, 0.50));
}

[data-tema="claro"] .mapa-svg path[data-nivel="municipio"]:hover,
[data-tema="claro"] .mapa-svg path[data-nivel="municipio"]:focus-visible,
[data-tema="claro"] .mapa-svg path[data-nivel="municipio"].ativo {
  filter: none;
}

/* ---- Porte miúdo: forma pequena não leva o traço da forma grande --------
   Dentro do mesmo nível o tamanho varia muito. Medido no mapa do Brasil:
     DF 12,3 x 7,3 · SE 23 x 27 · ES 28 x 45 · AL 39 x 22 · AM 224,7 x 158
   Todos levavam 2px: no DF isso é 16% da largura e 27% da altura; no AM é
   elegante. O mapa.js marca os pequenos com data-porte="miudo".
   Quando os dois atributos coexistem no path, o porte vence o nível: o seletor
   com [data-nivel][data-porte] tem (0,4,1) contra (0,3,1) das regras de nível,
   então não depende da ordem em que os blocos aparecem. */

.mapa-svg path[data-nivel][data-porte="miudo"]:hover {
  stroke-width: 1;
}

.mapa-svg path[data-nivel][data-porte="miudo"]:focus-visible {
  stroke-width: 1.2;
}

.mapa-svg path[data-nivel][data-porte="miudo"].ativo {
  stroke-width: 1.2;
}

/* Rede de segurança: path marcado como miúdo mas ainda sem data-nivel
   (janela de transição). Fica depois do bloco de nível, então empata em
   especificidade e vence por ordem. */
.mapa-svg path[data-porte="miudo"]:hover {
  stroke-width: 1;
}

.mapa-svg path[data-porte="miudo"]:focus-visible {
  stroke-width: 1.2;
}

.mapa-svg path[data-porte="miudo"].ativo {
  stroke-width: 1.2;
}

/* Tema claro: em 12px de largura a sombra não desenha limite nenhum, vira
   borrão em volta do halo. Sai nas formas miúdas. */
[data-tema="claro"] .mapa-svg path[data-nivel][data-porte="miudo"]:hover,
[data-tema="claro"] .mapa-svg path[data-nivel][data-porte="miudo"]:focus-visible,
[data-tema="claro"] .mapa-svg path[data-nivel][data-porte="miudo"].ativo,
[data-tema="claro"] .mapa-svg path[data-porte="miudo"]:hover,
[data-tema="claro"] .mapa-svg path[data-porte="miudo"]:focus-visible,
[data-tema="claro"] .mapa-svg path[data-porte="miudo"].ativo {
  filter: none;
}

/* O traço de destaque em pixel de TELA, não em unidade do viewBox.
   Sem isto, o mesmo 2px do CSS renderiza 2,18px no mapa do Brasil (viewBox de
   465,4 desenhado em 506px, escala 1,09) e 1,07px no mapa do estado (escala
   1,07), porque stroke-width no SVG é multiplicado pela escala do desenho.
   A região já traz o atributo no path e por isso sempre foi 1px de verdade.
   Com esta linha, 1px e 2px querem dizer 1px e 2px em qualquer nível e em
   qualquer zoom do navegador. */
.mapa-svg path:hover,
.mapa-svg path:focus-visible,
.mapa-svg path.ativo {
  vector-effect: non-scaling-stroke;
}

/* ---- 12b.5 Erro dentro da prancha ----
   O mapa.js escreve um <p class="insight-pe"> quando a malha não carrega.
   Aqui ele deixa de ser nota de pé e vira aviso legível, centralizado. */

.mapa-svg > p,
.mapa-svg .insight-pe {
  max-width: 42ch;
  margin: 0 auto;
  color: var(--alerta);
  font-family: var(--fonte);
  font-size: var(--fs-sub);
  line-height: 1.6;
  text-align: center;
  overflow-wrap: break-word;
}

/* ---- 12b.6 Esqueleto da malha ---- */

.esqueleto-mapa {
  width: 100%;
  height: 300px;
  border-radius: var(--r-sm);
}

/* ---- 12b.7 Legenda: cor = vencedor, intensidade = margem ---- */

.mapa-legenda {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--e-meio) var(--e4);
  margin-top: var(--e3);
  color: var(--txt-3);
  font-size: var(--fs-rot);
  line-height: 1.5;
}

.legenda-item {
  display: inline-flex;
  align-items: center;
  gap: var(--e-meio);
  color: var(--txt-2);
}

/* O quadradinho herda a cor do candidato por style inline (mapa.js/HTML);
   o CSS só dá forma e um fio para o swatch não desaparecer no tema claro. */
.legenda-item i {
  flex: none;
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: var(--r-xs);
  border: 1px solid var(--linha-forte);
}

.legenda-int {
  color: var(--txt-3);
  font-style: normal;
}

/* ---- 12b.8 Índice lateral: a alternativa acessível ao mapa ---- */

.mapa-lateral {
  padding: var(--e3) var(--e3) var(--e2);
  max-height: 420px;
  overflow-y: auto;
  overscroll-behavior: contain;
  /* reserva a calha da barra: a lista não "pula" ao ganhar rolagem */
  scrollbar-gutter: stable;
}

.mapa-lista-titulo {
  font-family: var(--fonte-titulo);
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.25;
  color: var(--txt);
}

.mapa-itens {
  list-style: none;
  margin: var(--e2) 0 0;
  padding: 0;
}

/* Fio entre linhas: lê como índice de jornal, não como lista de app */
.mapa-itens > li + li { border-top: 1px solid var(--linha-suave); }

.mapa-item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: baseline;
  gap: var(--e1) var(--e2);
  width: 100%;
  min-height: 34px;
  padding: var(--e-meio) var(--e2);
  border: 0;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--txt-2);
  font-size: 0.78125rem;
  line-height: 1.45;
  text-align: left;
  transition: background-color var(--t-1) var(--curva),
              color var(--t-1) var(--curva);
}

.mapa-item:hover,
.mapa-item:focus-visible {
  background: var(--superficie-3);
  color: var(--txt);
}

/* Nome comprido quebra em duas linhas — nunca vira reticência.
   Cortar "São Raimundo Nonato" em "São Raimun…" é perder o dado. */
.mapa-item-nome {
  min-width: 0;
  overflow-wrap: break-word;
}

.mapa-item-num {
  color: var(--txt-3);
  font-family: var(--fonte-num);
  font-size: var(--fs-pe);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
  text-align: right;
  white-space: nowrap;
}

.mapa-item-tag {
  font-size: var(--fs-pe);
  font-weight: 600;
  letter-spacing: 0.01em;
  text-align: right;
  white-space: nowrap;
}

/* ============================================================================
   13 · INSIGHTS DO 1º TURNO
   ========================================================================== */

.insight {
  display: flex;
  flex-direction: column;
  gap: var(--e-dez);
  min-width: 0;
}

.insight-num {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--e2);
  color: var(--txt);
  font-family: var(--fonte-num);
  font-size: var(--fs-num-insight);
  font-variant-numeric: tabular-nums;
  font-weight: 400;
  letter-spacing: -0.05em;
  line-height: 1;
}

.insight-num .sufixo {
  color: var(--txt-3);
  font-family: var(--fonte);
  font-size: var(--fs-rot);
  font-weight: 500;
  letter-spacing: 0.08em;
  line-height: 1.4;
  text-transform: uppercase;
}

.insight-titulo {
  color: var(--txt);
  font-size: var(--fs-corpo);
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.4;
  text-wrap: balance;
}

.insight-texto {
  color: var(--txt-2);
  font-size: var(--fs-sub);
  line-height: 1.65;
  overflow-wrap: break-word;
}
.insight-texto strong { color: var(--txt); font-weight: 600; }

.insight-pe {
  color: var(--txt-3);
  font-size: var(--fs-pe);
  font-variant-numeric: tabular-nums;
  line-height: 1.6;
  overflow-wrap: break-word;
}
.insight-pe strong { color: var(--txt-2); font-weight: 600; }
.insight-pe a { color: var(--txt-2); }

.mini-lista {
  display: flex;
  flex-direction: column;
  list-style: none;
  margin: 0;
  padding: 0;
}

.mini-lista li {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--e3);
  padding: var(--e1) 0;
  color: var(--txt-2);
  font-size: 0.78125rem;
  line-height: 1.6;
  min-width: 0;
}
.mini-lista li + li { border-top: 1px solid var(--linha-suave); }

.mini-lista .v {
  flex: none;
  color: var(--txt);
  font-family: var(--fonte-num);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
  white-space: nowrap;
}

.duelo {
  display: flex;
  flex-direction: column;
  gap: var(--e2);
}

.duelo-linha {
  display: grid;
  grid-template-columns: 54px minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--e2);
  min-width: 0;
  font-size: 0.78125rem;
}

.duelo-barra {
  display: block;
  height: var(--barra-media);
  border-radius: var(--r-xs);
  background: var(--trilho);
  overflow: hidden;
}

.duelo-barra > span {
  display: block;
  height: 100%;
  border-radius: var(--r-xs);
  transition: width var(--t-3) var(--curva-saida);
}

.duelo .v {
  color: var(--txt);
  font-family: var(--fonte-num);
  font-variant-numeric: tabular-nums;
  font-weight: 500;
  white-space: nowrap;
}

.duelo-nota {
  margin-top: var(--e-1);
  color: var(--txt-3);
  font-size: var(--fs-pe);
  line-height: 1.6;
}

/* ============================================================================
   14 · TABELAS
   Desktop: tabela compacta, números à direita.
   Celular: as 4 colunas continuam (o cabeçalho é o rótulo do dado), com tipo
   menor e padding apertado; o nome do município quebra em vez de ser cortado.
   ========================================================================== */

.tabela {
  width: 100%;
  font-size: 0.78125rem;
  font-variant-numeric: tabular-nums;
  text-align: left;
}

.tabela thead th {
  padding: var(--e2) var(--e3);
  border-bottom: var(--borda);
  color: var(--txt-3);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.1em;
  line-height: 1.5;
  text-transform: uppercase;
  white-space: nowrap;
}

.tabela td {
  padding: var(--e-dez) var(--e3);
  border-bottom: 1px solid var(--linha-suave);
  color: var(--txt-2);
  vertical-align: top;
  overflow-wrap: break-word;
}

.tabela tbody tr:last-child td { border-bottom: 0; }
.tabela tbody tr:hover td { background: var(--hover-linha); }

.tabela .num {
  color: var(--txt);
  font-family: var(--fonte-num);
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}

.tabela .destaque {
  color: var(--txt);
  font-weight: 600;
}

/* UF/sigla: usado em tabelas, listas e recorte */
.uf {
  color: var(--txt-3);
  font-family: var(--fonte-num);
  font-size: 0.6875rem;
  font-weight: 400;
  letter-spacing: 0.04em;
  white-space: nowrap;
}

table .uf { margin-left: var(--e1); }

/* Votos por candidato */
.tabela-votos .linha-nome {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--e1) var(--e-meio);
  min-width: 0;
}

.tabela-votos .barra-mini {
  display: block;
  height: 2px;
  margin-top: var(--e1);
  border-radius: var(--r-xs);
  transition: width var(--t-3) var(--curva-saida);
}

/* Comparecimento */
.comp-rolo {
  display: flex;
  flex-direction: column;
  gap: var(--e5);
}

.comp-grupo h4 {
  margin: 0 0 var(--e2);
  color: var(--txt-3);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.1em;
  line-height: 1.5;
  text-transform: uppercase;
}

.comp-linha {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  gap: var(--e1) var(--e2);
  padding: var(--e-meio) 0;
  color: var(--txt-2);
  font-size: 0.78125rem;
  line-height: 1.5;
  min-width: 0;
}

.comp-linha .v {
  color: var(--txt);
  font-family: var(--fonte-num);
  font-size: 0.8125rem;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.comp-barra {
  display: block;
  grid-column: 1 / -1;
  height: 2px;
  border-radius: var(--r-xs);
  background: var(--trilho);
  overflow: hidden;
}

.comp-barra > span {
  display: block;
  height: 100%;
  border-radius: var(--r-xs);
  background: var(--txt-3);
  transition: width var(--t-3) var(--curva-saida);
}

/* Piauí: marcação regional que o app.js aplica inline (verde = dado oficial) */
.comp-linha.pi { color: var(--oficial); }
.comp-linha.pi .v { color: var(--oficial); font-weight: 600; }
.comp-linha.pi .comp-barra > span { background: var(--oficial); }

/* ============================================================================
   15 · EXTERIOR
   ========================================================================== */

.ext-grid {
  display: flex;
  flex-direction: column;
  gap: var(--e4);
  min-width: 0;
}

.ext-placar {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: var(--e2);
  text-align: center;
}

.ext-lado {
  display: flex;
  flex-direction: column;
  gap: var(--e-1);
  min-width: 0;
}

.ext-nome {
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.ext-pct {
  font-family: var(--fonte-num);
  font-size: clamp(1.25rem, 1.1rem + 0.5vw, 1.5rem);
  font-variant-numeric: tabular-nums;
  font-weight: 500;
  letter-spacing: -0.035em;
  line-height: 1.15;
  white-space: nowrap;
}

.ext-votos {
  color: var(--txt-3);
  font-family: var(--fonte-num);
  font-size: var(--fs-pe);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.ext-x {
  color: var(--txt-3);
  font-size: var(--fs-sub);
  line-height: 1;
}

.ext-paises {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--e3);
  padding-top: var(--e3);
  border-top: var(--borda);
  text-align: center;
}

.ext-paises div {
  display: flex;
  flex-direction: column;
  gap: var(--e-1);
  min-width: 0;
}

.ext-paises .n {
  color: var(--txt);
  font-family: var(--fonte-num);
  font-size: 0.9375rem;
  font-variant-numeric: tabular-nums;
  font-weight: 500;
}

.ext-paises .r {
  color: var(--txt-3);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.1em;
  line-height: 1.5;
  text-transform: uppercase;
}

/* ============================================================================
   16 · ERRO E BOTÕES
   ========================================================================== */

.erro-bloco {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--e3);
  padding: var(--e4);
  border: 1px solid var(--alerta-borda);
  border-left: 2px solid var(--alerta);
  border-radius: var(--r-sm);
  background: var(--alerta-bg);
}

.erro-bloco p {
  color: var(--txt-2);
  font-size: var(--fs-sub);
  line-height: 1.65;
  overflow-wrap: break-word;
}
.erro-bloco strong { color: var(--txt); font-weight: 600; }

.btn {
  min-height: 38px;
  padding: var(--e2) var(--e3);
  border: var(--borda-forte);
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--txt);
  font-size: var(--fs-rot);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  transition: background-color var(--t-1) var(--curva),
              border-color var(--t-1) var(--curva),
              color var(--t-1) var(--curva),
              transform var(--t-1) var(--curva);
}

.btn:hover {
  background: var(--superficie-3);
  border-color: var(--linha-clara);
}

.btn:active {
  background: var(--superficie-4);
  transform: translateY(1px);
}

/* ============================================================================
   17 · RODAPÉ
   ========================================================================== */

.rodape {
  display: flex;
  flex-direction: column;
  gap: var(--e-dez);
  max-width: var(--largura-leitura);
  margin-top: var(--e7);
  padding-top: var(--e4);
  border-top: var(--borda);
  color: var(--txt-3);
  font-size: var(--fs-pe);
  line-height: 1.65;
}

.rodape-aviso {
  padding-left: var(--e3);
  border-left: 1px solid var(--linha-forte);
  color: var(--txt-2);
}

.rodape strong { color: var(--txt-2); font-weight: 600; }

/* ============================================================================
   18 · UTILIDADES NUMÉRICAS
   Qualquer número que mude na tela tem largura fixa de dígito.
   ========================================================================== */

.painel-secoes .num,
.painel-secoes .rot,
.candidato-pct,
.candidato-votos,
.candidato-num,
.proj-pct,
.proj-sub,
.chance-val,
.total-val,
.insight-num,
.recorte-num .v,
.recorte-sub,
.mini-lista .v,
.duelo .v,
.ext-pct,
.ext-votos,
.ext-paises .n,
.comp-linha .v,
.tabela,
.vazio-num,
.vazio-lista li,
.frescor,
.cartao-meta,
.secao-nota,
.marca-disputa b {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1, "lnum" 1;
}

/* ============================================================================
   19 · RESPONSIVO (mobile first)
   Base = 320–430px. Ganhos entram por min-width.
   ========================================================================== */

/* Telas estreitas extremas: aperta o respiro sem quebrar palavra */
@media (max-width: 359px) {
  .marca-turno { margin-left: var(--e1); }
  .painel-secoes .num { font-size: 2.5rem; }
  .duelo-linha { grid-template-columns: 46px minmax(0, 1fr) auto; }
}

/* Celular: a tabela continua tabela (o cabeçalho é o rótulo), só que mais densa.
   Sem rolagem lateral e sem palavra cortada: a coluna do nome quebra linha. */
@media (max-width: 639px) {
  /* Mapa no celular: prancha mais baixa, lista mais curta, tipografia menor.
     O SVG continua encolhendo por max-width — nunca rola de lado. */
  .mapa-caixa { min-height: 200px; padding: var(--e2); }
  .mapa-svg { min-height: 150px; }
  .mapa-lateral { max-height: 360px; }
  .mapa-item { font-size: 0.75rem; }
  .mapa-item-num,
  .mapa-item-tag { font-size: 0.6875rem; }
  .mapa-legenda { font-size: 0.6875rem; }

  .tabela { font-size: 0.75rem; }
  .tabela thead th {
    padding: 7px var(--e2);
    font-size: 0.5625rem;
    letter-spacing: 0.08em;
  }
  .tabela td { padding: var(--e2); }
  .tabela td:first-child { overflow-wrap: break-word; }
  .tabela .uf { font-size: 0.625rem; }
  .tabela-votos .linha-nome { gap: var(--e1); }
}

@media (min-width: 420px) {
  .duelo-linha { grid-template-columns: 60px minmax(0, 1fr) auto; }
}

/* Tablet deitado / desktop estreito */
@media (min-width: 560px) {
  .totais { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .chance { grid-template-columns: repeat(auto-fit, minmax(104px, 1fr)); }
  .recorte-numeros { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .busca-campo { flex: 1 1 320px; }
  #busca { font-size: 0.9375rem; }
  .topbar-estado { align-items: flex-start; }
}

/* Duas colunas de verdade */
@media (min-width: 768px) {
  .topbar {
    flex-direction: row;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--e5);
  }
  .topbar-estado { align-items: flex-end; text-align: right; }
  .frescor { justify-content: flex-end; }
  .busca-barra { flex-wrap: nowrap; }
  .busca-campo { flex: 1 1 340px; }
  .busca-atalhos { flex: 0 1 auto; flex-wrap: wrap; justify-content: flex-end; }
  .cartao-topo { align-items: center; }
  .vazio-texto { font-size: 0.84375rem; }
  .insight-num { line-height: 0.98; }
}

/* Herói em duas colunas: painel manda, projeção acompanha */
@media (min-width: 900px) {
  .linha-heroi {
    grid-template-columns: minmax(0, 1.06fr) minmax(0, 0.94fr);
  }
  .grade-dupla { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .mapa-grade {
    grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr);
  }
  .mapa-lateral { max-height: 620px; }
}

/* Desktop largo: respiro maior, sem esticar a linha de leitura */
@media (min-width: 1120px) {
  .app { padding-top: var(--e-40); }
  .topbar { padding-bottom: var(--e-28); }
  .cartao-topo { padding: var(--e4) var(--pad-cartao); }
  .insight-texto { max-width: 46ch; }
  .vazio-texto { max-width: 56ch; }
}

/* ============================================================================
   20 · TEMA CLARO (EDIÇÃO DO DIA)
   O app grava data-tema no <html> antes da primeira pintura (script inline no
   head), então o CSS só troca tokens: nenhum componente é remontado, nenhuma
   classe nova aparece, nenhum texto muda.

   Regra de ouro do claro: papel não aceita a mesma tinta do escuro.
   Todas as cores semânticas foram escurecidas até passar AA sobre branco.
   Pior caso medido: --txt-3 sobre --superficie-3 = 4,75:1.
   ========================================================================== */

/* ---- 20.1 Tokens ---- */

[data-tema="claro"] {
  /* No claro o --superficie-3 (#EDF0F4) ficava a 7 unidades do --bg (#F4F6F9):
     municipio sem dado sumia no fundo. Este tom separa sem competir com os
     estados coloridos. */
  --sem-dado:        #CBD3DE;
  color-scheme: light;

  /* superfícies */
  --bg:              #F4F6F9;
  --bg-fundo:        #EDF0F4;
  --superficie:      #FFFFFF;
  --superficie-2:    #FAFBFC;
  --superficie-3:    #EDF0F4;
  --superficie-4:    #E2E6EC;
  --veu:             rgba(244, 246, 249, 0.94);
  --poco:            rgba(14, 23, 38, 0.05);
  --hover-linha:     rgba(14, 23, 38, 0.035);

  /* traços: no papel o fio precisa ser mais escuro para existir */
  --linha:           rgba(14, 23, 38, 0.12);
  --linha-forte:     rgba(14, 23, 38, 0.24);
  --linha-suave:     rgba(14, 23, 38, 0.07);
  --linha-clara:     rgba(14, 23, 38, 0.46);

  /* texto */
  --txt:             #0E1726;
  --txt-2:           #3B4A5D;
  --txt-3:           #5F6B7A;
  --txt-fantasma:    rgba(14, 23, 38, 0.16);

  /* origem do dado — escurecida para AA sobre branco */
  --projecao:        #8A5A00;
  --projecao-bg:     rgba(138, 90, 0, 0.09);
  --projecao-borda:  rgba(138, 90, 0, 0.30);
  --parcial:         #1B5B86;
  --parcial-bg:      rgba(27, 91, 134, 0.08);
  --parcial-borda:   rgba(27, 91, 134, 0.28);
  --oficial:         #1C6647;
  --oficial-bg:      rgba(28, 102, 71, 0.08);
  --oficial-borda:   rgba(28, 102, 71, 0.28);
  --imprensa:        #5A3CA8;
  --imprensa-bg:     rgba(90, 60, 168, 0.08);
  --imprensa-borda:  rgba(90, 60, 168, 0.28);
  --alerta:          #A32B44;
  --alerta-bg:       rgba(163, 43, 68, 0.07);
  --alerta-borda:    rgba(163, 43, 68, 0.28);

  /* candidatos */
  --lula:            #B0332D;
  --lula-bg:         rgba(176, 51, 45, 0.09);
  --lula-borda:      rgba(176, 51, 45, 0.28);
  --flavio:          #28499C;
  --flavio-bg:       rgba(40, 73, 156, 0.09);
  --flavio-borda:    rgba(40, 73, 156, 0.28);

  /* foco: tinta sobre papel */
  --foco:            #0E1726;
  --foco-halo:       rgba(14, 23, 38, 0.12);

  /* barras e mapa */
  --trilho:          rgba(14, 23, 38, 0.10);
  --mapa-traco:      rgba(14, 23, 38, 0.24);
  --mapa-traco-largura: 0.75;

  /* sombras: no papel elas pesam; aqui ficam 14× mais leves */
  --sombra-1:        0 1px 2px rgba(14, 23, 38, 0.07);
  --sombra-2:        0 2px 6px rgba(14, 23, 38, 0.07), 0 24px 48px -32px rgba(14, 23, 38, 0.35);
  --sombra-interna:  inset 0 1px 0 rgba(255, 255, 255, 0.9);
}

/* ---- 20.2 Base ---- */

[data-tema="claro"] ::selection {
  background: rgba(27, 91, 134, 0.18);
  color: #0E1726;
}

/* ---- 20.3 Bordas e sombras ----
   Token resolve a cor; estas regras resolvem onde a sombra do escuro não
   funciona no papel (a barra fixa precisa de um fio de profundidade, e a
   prancha do mapa precisa de moldura visível). */

[data-tema="claro"] .busca-barra {
  box-shadow: 0 8px 20px -18px rgba(14, 23, 38, 0.45);
}

[data-tema="claro"] .pular {
  box-shadow: 0 10px 30px -18px rgba(14, 23, 38, 0.45);
}

[data-tema="claro"] .sugestoes {
  background: var(--superficie);
}

[data-tema="claro"] .cartao-meta,
[data-tema="claro"] .cartao-link {
  color: var(--txt-3);
}

/* ---- 20.4 Busca ---- */

/* No escuro o campo é um degrau acima do véu; no claro ele é o papel branco
   sobre a barra cinza — é o contraste que diz "aqui se digita". */
[data-tema="claro"] #busca {
  background: var(--superficie);
}

[data-tema="claro"] .atalho.ativo {
  background: var(--superficie);
  box-shadow: inset 0 -2px 0 var(--txt);
}

/* ---- 20.5 Esqueleto ----
   O esqueleto do escuro é um retângulo quase preto; sobre cartão branco ele
   precisa de um degrau de cinza e de um fio, senão some. */

[data-tema="claro"] .esqueleto {
  background: var(--superficie-3);
  border-color: var(--linha);
}

[data-tema="claro"] .esqueleto-mapa {
  background: var(--superficie-3);
}

/* ---- 20.6 Barras ----
   O trilho vem do token --trilho (10% de tinta). As barras de candidato
   mantêm a cor do candidato: vermelho e azul já são escuros o bastante. */

[data-tema="claro"] .barra-progresso > span {
  background: var(--parcial);
}

/* ---- 20.7 Tabelas ----
   No escuro o cabeçalho é transparente; no claro uma faixa de 3,5% separa
   o rótulo do corpo sem virar "tabela de sistema". */

[data-tema="claro"] .tabela thead th {
  background: rgba(14, 23, 38, 0.035);
  border-bottom-color: var(--linha-forte);
}

[data-tema="claro"] .tabela td {
  border-bottom-color: var(--linha-suave);
}

[data-tema="claro"] .tabela tbody tr:last-child td {
  border-bottom: 0;
}

/* ---- 20.8 Detalhes (JSON bruto) ----
   O "poço" escuro vira uma folha de papel levemente acinzentada. Se algum dia
   entrar um modal de detalhes, ele herda estes mesmos tokens: --superficie
   para o painel, --veu para o fundo atrás, --sombra-2 para a borda flutuante. */

[data-tema="claro"] .detalhes pre {
  background: var(--poco);
  border-color: var(--linha);
  color: var(--txt-2);
}

[data-tema="claro"] .detalhes summary {
  color: var(--txt-3);
}

/* ---- 20.9 Mapa ----
   Preenchimento pálido sobre branco perde definição: o traço sobe para 0,75px
   de tinta a 24% e o esmaecimento de carregamento sobe de 0,35 para 0,5,
   senão a malha antiga desaparece antes da nova chegar. */

[data-tema="claro"] .mapa-caixa {
  box-shadow: var(--sombra-cartao), inset 0 0 0 1px var(--linha);
}

[data-tema="claro"] .mapa-svg[aria-busy="true"] svg {
  opacity: 0.5;
}

/* Traço e espessura do mapa vêm só dos tokens (--mapa-traco / -largura).
   Nada de repetir a regra base aqui: repetir criaria especificidade igual à
   de :focus-visible e o foco perderia. */

[data-tema="claro"] .legenda-item i {
  border-color: rgba(14, 23, 38, 0.30);
}

[data-tema="claro"] .mapa-lateral {
  background: var(--superficie);
}

[data-tema="claro"] .mapa-itens > li + li {
  border-top-color: var(--linha-suave);
}

/* ---- 20.10 Carimbos e selos ---- */

/* O carimbo "em preparação" usa superficie-2, que no claro é quase branco:
   sobre o cartão branco ele desapareceria. Passa a usar superficie-3. */
[data-tema="claro"] .vazio-selo.espera {
  background: var(--superficie-3);
  border-color: var(--linha-forte);
}

[data-tema="claro"] .tema-btn {
  background: var(--superficie);
}

[data-tema="claro"] .tema-btn:hover {
  background: var(--superficie-3);
}

/* ---- 20.11 Troca de tema ----
   Só cor, só 200ms: o olho entende que a mesma página virou, não que outra
   carregou. O reduced-motion (seção 21) zera isto como zera o resto. */

html { transition: background-color var(--t-2) var(--curva); }

body,
.cartao,
.busca-barra,
#busca,
.mapa-caixa,
.mapa-lateral,
.sugestoes,
.tabela thead th,
.esqueleto {
  transition: background-color var(--t-2) var(--curva),
              border-color var(--t-2) var(--curva),
              color var(--t-2) var(--curva);
}

/* ============================================================================
   21 · MOVIMENTO, CONTRASTE E IMPRESSÃO
   ========================================================================== */

@keyframes respirar {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.40; }
}

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

/* Quem pediu menos movimento recebe menos movimento — inclusive as barras */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0ms !important;
  }
}

/* Mais contraste sem trocar de tema: engrossa traços e texto secundário */
@media (prefers-contrast: more) {
  :root {
    --linha:         rgba(255, 255, 255, 0.20);
    --linha-suave:   rgba(255, 255, 255, 0.12);
    --linha-forte:   rgba(255, 255, 255, 0.34);
    --txt-2:         #C6CCD4;
    --txt-3:         #A3AAB4;
  }
  [data-tema="claro"] {
    --linha:         rgba(14, 23, 38, 0.26);
    --linha-suave:   rgba(14, 23, 38, 0.16);
    --linha-forte:   rgba(14, 23, 38, 0.44);
    --txt-2:         #2A3646;
    --txt-3:         #485462;
  }
}

/* Impressão: papel aceita menos tinta, mas a hierarquia continua */
@media print {
  :root {
    --bg: #FFFFFF;
    --superficie: #FFFFFF;
    --superficie-2: #FFFFFF;
    --superficie-3: #F2F3F5;
    --txt: #111315;
    --txt-2: #33383E;
    --txt-3: #5B6169;
    --linha: rgba(0, 0, 0, 0.18);
    --linha-forte: rgba(0, 0, 0, 0.34);
    --linha-suave: rgba(0, 0, 0, 0.10);
    --linha-clara: rgba(0, 0, 0, 0.50);
    --veu: #FFFFFF;
    --poco: rgba(0, 0, 0, 0.04);
    --hover-linha: rgba(0, 0, 0, 0.03);
    --trilho: rgba(0, 0, 0, 0.12);
    --mapa-traco: #FFFFFF;
  }
  body { background: #FFFFFF; }
  .busca-barra,
  .pular { display: none !important; }
  .cartao { box-shadow: none; break-inside: avoid; }
  .mapa-lateral { max-height: none; overflow: visible; }
  .mapa-caixa { break-inside: avoid; }
  .mapa-svg path { stroke: #FFFFFF; }
  .esqueleto { display: none; }
  .detalhes { display: none; }
}

/* ============================================================================
   21 · SELETOR DE TURNO DO MAPA  (integração — mesmo mapa, dois turnos)
   Segmented control: um único mapa; a aba só troca a fonte de dados.
   ============================================================================ */

.mapa-controles {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--e3); flex-wrap: wrap; margin-bottom: var(--e3);
}

.mapa-tabs {
  display: inline-flex; gap: 2px; padding: 3px;
  background: var(--superficie-2);
  border: 1px solid var(--linha);
  border-radius: 999px;
}

.mapa-tab {
  border: 0; background: transparent;
  color: var(--txt-3);
  font-size: 0.78rem; font-weight: 600; letter-spacing: 0.02em;
  padding: 6px 15px; border-radius: 999px; white-space: nowrap;
  transition: background .15s, color .15s, box-shadow .15s;
}
.mapa-tab:hover { color: var(--txt); background: var(--superficie-3); }
.mapa-tab:focus-visible { outline: 2px solid var(--parcial); outline-offset: 2px; }
.mapa-tab[aria-selected="true"],
.mapa-tab.ativo {
  background: var(--superficie-4, var(--superficie-3));
  color: var(--txt);
  box-shadow: inset 0 0 0 1px var(--linha-forte);
}

.mapa-controles-nota {
  font-size: 0.74rem; color: var(--txt-3); line-height: 1.4;
}

/* estado vazio dentro da área do mapa */
.mapa-vazio {
  display: flex; flex-direction: column; gap: var(--e3);
  padding: clamp(20px, 5vw, 44px) clamp(16px, 4vw, 36px);
  max-width: 560px; min-height: 220px;
  justify-content: center;
}
.mapa-vazio .vazio-titulo { font-size: 1rem; }
.mapa-vazio .vazio-texto { font-size: 0.85rem; }

@media (max-width: 480px) {
  .mapa-controles { align-items: flex-start; }
  .mapa-tabs { width: 100%; }
  .mapa-tab { flex: 1 1 0; text-align: center; padding: 7px 10px; }
  .mapa-controles-nota { font-size: 0.72rem; }
}

/* ============================================================================
   22 · SELETOR DE TURNO DOS INSIGHTS  (integração — mesmos cartões, dois turnos)
   Reaproveita .mapa-controles/.mapa-tabs/.mapa-tab; aqui só o respiro próprio
   da seção de insights, para o seletor não colar no cabeçalho nem na grade.
   ============================================================================ */

.insights-controles { margin-top: calc(var(--e2) * -1); }

@media (max-width: 480px) {
  .insights-controles { margin-top: 0; }
}

/* ============================================================================
   23 · RESPIIRO DOS SELETORES DE SEÇÃO  (tensões e referência oficial)
   Mesmo componente do mapa/insights; aqui só o ajuste de margem para o
   seletor não colar no cabeçalho da seção.
   ============================================================================ */

.secao-controles { margin-top: calc(var(--e2) * -1); }

@media (max-width: 480px) {
  .secao-controles { margin-top: 0; }
}

/* ============================================================================
   24 · LISTA DO MAPA POR VOTOS  (votos por candidato e por estado)
   Linha de duas colunas: UF + % apurado à esquerda, votos à direita.
   Números tabulares, cor só nos votos (vermelho Lula / azul Flávio).
   ============================================================================ */

.mapa-item-voto {
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--e1) var(--e3);
}

.mapa-item-voto .mapa-item-nome { white-space: nowrap; }

.mapa-item-votos {
  text-align: right;
  font-family: var(--fonte-num);
  font-size: 0.8125rem;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
  white-space: nowrap;
}

.v-lula { color: var(--lula); }
.v-flavio { color: var(--flavio); }

.mapa-estado-totais {
  margin: var(--e2) 0 0;
  color: var(--txt-2);
  font-family: var(--fonte-num);
  font-size: var(--fs-pe);
  font-variant-numeric: tabular-nums;
  line-height: 1.5;
}

/* Estado sem dado: cinza do tema, sem parecer erro */
.mapa-svg path.sem-dado { stroke: var(--linha-forte); }
/* sem-dado no hover: o halo é branco como em todo path (é a marcação de
   alvo). Quem continua diferenciando o município sem dado é o preenchimento
   cinza, que não muda. Antes o traço ficava em --txt-3 e o alvo não se
   destacava do resto. */
.mapa-svg path.sem-dado:hover { stroke: #fff; }

/* ============================================================================
   25 · LISTA DE VOTOS POR ESTADO (TSE por UF)
   Linha 1: sigla + os DOIS percentuais colados nela (urnas e eleitorado).
   Linha 2: total de votos e cada candidato — informação secundária.
   ============================================================================ */

.mapa-item-uf {
  display: block;
  width: 100%;
  padding: var(--e2);
  /* Rede de segurança: se algum dia o conteúdo não couber, quem rola é o item,
     nunca a página. Em uso normal não aparece barra. */
  overflow-x: auto;
  overscroll-behavior-x: contain;
  /* Container de consulta: as regras de largura abaixo respondem à largura
     REAL da lista (330px numa janela de 1024, 417px numa de 1280), não à da
     janela — a barra lateral não tem a mesma largura em todas as telas. */
  container-type: inline-size;
}

/* Linha 1: sigla + os dois percentuais. Linha 2: o Total, sozinho, sem
   empurrar nada. Grid de 2 colunas com o Total ocupando a linha inteira —
   é isso que impede o "Total" de cair no meio dos percentuais. */
.mapa-item-uf .uf-topo {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: baseline;
  column-gap: var(--e-meio);
  row-gap: var(--e-1);
}

.mapa-item-uf .uf-nome {
  grid-column: 1;
  grid-row: 1;
  color: var(--txt);
  font-weight: 700;
  letter-spacing: 0.02em;
  font-size: 0.8125rem;
}

/* Uma linha só: sigla, os dois percentuais E o Total. O Total vem dentro do
   .uf-pcts (mapa.js 3.1.6), então quem manda no encaixe é o gap daqui.
   4px de gap (era 6) + 0.72rem no texto (era 0,75) é o que faz o item mais
   largo — BR, com 8 dígitos no Total — caber sem empurrar nada para baixo. */
.mapa-item-uf .uf-pcts {
  grid-column: 2;
  grid-row: 1;
  display: inline-flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 3px;
  min-width: 0;
  color: var(--txt-2);
  font-family: var(--fonte-num);
  font-size: 0.68rem;
  font-variant-numeric: tabular-nums;
}

.mapa-item-uf .uf-pct-item { white-space: nowrap; }

.mapa-item-uf .uf-sep { color: var(--txt-3); }

/* Total: mesma linha dos percentuais, tipografia de apoio (não compete com os
   candidatos). Sem margem: cada pixel aqui é o que faz o item BR (8 dígitos no
   Total) caber na linha 1 em vez de descer. */
.mapa-item-uf .uf-total {
  color: var(--txt-3);
  font-family: var(--fonte-num);
  font-size: 0.6875rem;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
  white-space: nowrap;
}

/* Linha 3: Lula e Flávio sempre lado a lado, em colunas de largura IGUAL.
   Colunas iguais (1fr 1fr, não auto) são o que faz a coluna do Lula começar
   no mesmo x em todos os estados — a sensação de tabela. */
.mapa-item-uf .uf-cands {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: var(--e2);
  row-gap: 2px;
  margin-top: var(--e-1);
  white-space: nowrap;
}

.mapa-item-uf .uf-cand {
  min-width: 0;
  display: inline-flex;
  align-items: baseline;
  gap: 3px;
}

.mapa-item-uf .uf-cand b { font-weight: 600; color: var(--txt-2); }

.mapa-item-uf .uf-pct { color: var(--txt-3); font-size: 0.6875rem; }

/* Lista estreita (janela ~1024, celular): os dois candidatos continuam na
   mesma linha e as colunas continuam iguais — só o "(% )" desce para a
   segunda linha da própria coluna quando não couber. Nunca quebra entre
   Lula e Flávio, e nada fica escondido atrás de rolagem. */
@container (max-width: 400px) {
  .mapa-item-uf .uf-cand {
    display: flex;
    flex-wrap: wrap;
    row-gap: 0;
    white-space: normal;
  }
}

/* ============================================================================
   26 · POPUP DO ESTADO NO MAPA  (hover + foco)
   Foto redonda com anel na cor do candidato. A inicial fica atrás da imagem:
   se a foto do TSE não carregar, aparece a letra — nunca ícone quebrado.
   ============================================================================ */

.mapa-popup {
  position: fixed;
  z-index: 60;
  max-width: min(384px, calc(100vw - 16px));
  padding: var(--e3) var(--e4);
  background: var(--superficie-2);
  border: 1px solid var(--linha-forte);
  border-radius: var(--r-md);
  box-shadow: var(--sombra-2);
  color: var(--txt);
  font-size: var(--fs-sub);
  line-height: 1.35;
  pointer-events: none;
}
.mapa-popup[hidden] { display: none; }

.pop-topo {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--e1) var(--e-meio);
  font-family: var(--fonte-titulo);
  font-size: 0.9375rem;
  margin-bottom: var(--e2);
  line-height: 1.3;
}

/* percentuais colados no nome do estado, na mesma linha de leitura */
.pop-pcts {
  color: var(--txt-2);
  font-family: var(--fonte-num);
  font-size: var(--fs-pe);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
  white-space: nowrap;   /* UF e percentuais nunca se separam */
}
.pop-topo b { font-weight: 600; }

.pop-linha {
  color: var(--txt-3);
  font-size: var(--fs-pe);
  font-variant-numeric: tabular-nums;
  margin-bottom: var(--e2);
}

.pop-cand {
  display: flex;
  align-items: center;
  gap: var(--e-dez);
  margin-top: var(--e2);
}

/* círculo: inicial no fundo, foto por cima; anel = cor do candidato */
.pop-foto {
  position: relative;
  flex: none;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: var(--r-pilula);
  border: 2px solid var(--linha-forte);
  background: var(--superficie-3);
  color: var(--txt-2);
  font-size: 0.8125rem;
  font-weight: 700;
  overflow: hidden;
}
.pop-foto::before { content: attr(data-inicial); }
.pop-foto img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.pop-cand.cand-lula .pop-foto { border-color: var(--lula); }
.pop-cand.cand-flavio .pop-foto { border-color: var(--flavio); }

.pop-info {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.pop-nome {
  color: var(--txt);
  font-weight: 600;
  font-size: 0.8125rem;
}
.pop-partido {
  color: var(--txt-3);
  font-size: var(--fs-pe);
  letter-spacing: 0.02em;
}
.pop-num {
  color: var(--txt-2);
  font-family: var(--fonte-num);
  font-size: 0.78125rem;
  font-variant-numeric: tabular-nums;
}
.pop-num b { color: var(--txt); font-weight: 600; }
.pop-cand.cand-lula .pop-num b { color: var(--lula); }
.pop-cand.cand-flavio .pop-num b { color: var(--flavio); }

.pop-fonte {
  margin-top: var(--e2);
  padding-top: var(--e-meio);
  border-top: 1px solid var(--linha);
  color: var(--txt-3);
  font-size: 0.6563rem;
  line-height: 1.45;
}

.pop-vazio {
  color: var(--txt-2);
  font-size: var(--fs-pe);
}

/* ============================================================================
   27 · BARRA DE FILTRO COLADA NA SEÇÃO DO MAPA
   Mesmo componente, agora dentro da seção que ele controla. Só o respiro
   muda: sem margem em cima, menos embaixo.
   ============================================================================ */

.busca-barra--mapa {
  margin: 0 calc(var(--pad-app) * -1) var(--e4);
  border-top: var(--borda);
  border-bottom: var(--borda);
}

@media (max-width: 640px) {
  .busca-barra--mapa { margin-bottom: var(--e3); }
  .busca-barra--mapa .busca-atalhos {
    overflow-x: auto;
    flex-wrap: nowrap;
    padding-bottom: 2px;
    scrollbar-width: none;
  }
  .busca-barra--mapa .busca-atalhos::-webkit-scrollbar { display: none; }
}

/* ============================================================================
   28 · BANNER DE ATUALIZAÇÃO — o único amarelo da tela
   A mesma <aside>, sem JS novo. Em tela larga é um cartão amarelo na faixa
   vazia da ESQUERDA, com o topo alinhado ao topo da caixa "Apuração oficial"
   (.linha-heroi, medido em 134px). Abaixo disso, o mesmo cartão amarelo no
   canto inferior esquerdo.

   Por que amarelo em todos os estados: o amarelo é a identidade do banner (e o
   único amarelo do site). Trocar o fundo por vermelho/âmbar em .parado/.erro
   faria o cartão competir com o sistema de cores de origem do dado (âmbar =
   projeção, vermelho = falha) e apagaria justamente o destaque pedido. Então o
   estado vai para o ponto, para a faixa de 3px na borda esquerda e para a cor
   do texto do site — o fundo continua amarelo.

   Por que o cartão lateral só entra em 1800px:
   o .app tem max-width de --largura-max (1240px) e fica centrado, então a faixa
   vazia mede (100vw - 1240px)/2. Em 1500px sobram 130px por lado — um cartão de
   240-270px invadiria o conteúdo. Em 1800px a faixa tem 280px e o cartão de
   244px entra com 52px de respiro até o texto. Abaixo disso vale o layout B.
   A largura tem trava própria (min(270px, faixa - 36px)): se a largura máxima
   do app mudar, o cartão encolhe em vez de invadir.
   ========================================================================== */

/* ---- 28.1 Tokens do destaque ----
   Amarelo de alerta (não pastel) e tinta escura fixa: em cima do amarelo o
   texto é escuro nos DOIS temas, senão perde contraste. */

:root {
  --destaque-amarelo:  #F2C14E;                    /* tema escuro: um tom fechado */
  --destaque-tinta:    #1A1A1A;                    /* texto sobre o amarelo */
  --destaque-tinta-2:  rgba(26, 26, 26, 0.72);     /* rótulo e notas */
  --destaque-fio:      rgba(26, 26, 26, 0.20);
  --destaque-bom:      #1C6647;
  --destaque-atencao:  #8A5A00;
  --destaque-erro:     #A32B44;
}

[data-tema="claro"] {
  --destaque-amarelo:  #FFD54A;                    /* tema claro: amarelo cheio */
}

/* ---- 28.2 Layout B (padrão): cartão neutro no canto inferior ESQUERDO ---- */

.banner-atualizacao {
  position: fixed;
  left: calc(var(--e4) + env(safe-area-inset-left, 0px));
  right: auto;
  bottom: calc(var(--e4) + env(safe-area-inset-bottom, 0px));
  z-index: 55;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--e-dez);
  max-width: min(460px, calc(100vw - 2 * var(--e4) - env(safe-area-inset-left, 0px)));
  padding: 12px 14px;
  background: var(--superficie);
  border: var(--borda);
  border-radius: 13px;                 /* cartão, não pílula */
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.22),
              0 22px 44px -22px rgba(0, 0, 0, 0.55);
  color: var(--txt-2);
  font-family: var(--fonte-num);
  font-size: 0.875rem;                 /* 14px */
  font-variant-numeric: tabular-nums;
  line-height: 1.45;
  text-align: justify;
}

/* Ponto de status: sobre amarelo ele precisa de anel, senão some */
.banner-dot {
  flex: none;
  width: 12px;
  height: 12px;
  border-radius: var(--r-pilula);
  background: var(--destaque-bom);
  box-shadow: 0 0 0 2px rgba(26, 26, 26, 0.35);
}

.banner-texto {
  display: inline-flex;
  align-items: baseline;
  gap: var(--e2);
  flex-wrap: wrap;
  min-width: 0;
}

/* Texto principal: tinta cheia, peso maior — é o que se lê de longe */
#banner-dado {
  color: var(--txt);
  font-weight: 600;
  letter-spacing: -0.01em;
}

.banner-sep { color: var(--txt-3); }

#banner-prox { color: var(--txt-3); }

/* Carimbo do TSE separado por barra vertical — a barra é CSS, então o layout
   não depende do caractere que o JS escreve em .banner-sep. */
.banner-fonte {
  display: inline-flex;
  align-items: center;
  gap: var(--e2);
  color: var(--txt-3);
  font-size: 0.8125rem;        /* 13px */
  letter-spacing: 0.01em;
}

.banner-fonte::before {
  content: "│";
  color: var(--linha-forte);
  font-weight: 400;
}

.banner-fonte:empty { display: none; }

/* A barra vertical pertence ao fim da linha do site: se o cartão quebrar em
   duas linhas, ela fecha a primeira ("… próxima em 4 s │") em vez de abrir a
   segunda parecendo citação. No celular, onde a linha do site some, ela volta
   para a frente do carimbo do TSE. */
@media (min-width: 561px) {
  .banner-texto::after {
    content: "│";
    color: var(--linha-forte);
    font-weight: 400;
  }
  .banner-fonte::before { display: none; }
}

/* ---- 28.3 Estados ---- */

.banner-atualizacao.parado,
.banner-atualizacao.atencao {
  border-left: 3px solid var(--destaque-atencao);
}
.banner-atualizacao.parado .banner-dot,
.banner-atualizacao.atencao .banner-dot {
  background: var(--destaque-atencao);
}
.banner-atualizacao.parado #banner-dado,
.banner-atualizacao.atencao #banner-dado { color: var(--destaque-atencao); }

.banner-atualizacao.erro,
.banner-atualizacao.alerta {
  border-left: 3px solid var(--destaque-erro);
}
.banner-atualizacao.erro .banner-dot,
.banner-atualizacao.alerta .banner-dot {
  background: var(--destaque-erro);
}
.banner-atualizacao.erro #banner-dado,
.banner-atualizacao.alerta #banner-dado { color: var(--destaque-erro); }

/* Respiro para o cartão não cobrir o rodapé (só existe no layout B).
   Declarado antes das media queries: depois delas, este seletor venceria
   o 96px do celular e o 0 do cartão lateral. */
body { padding-bottom: 76px; }

/* ---- 28.4 Celular: compacto, uma linha por informação ---- */

@media (max-width: 560px) {
  .banner-atualizacao {
    right: var(--e2);
    left: calc(var(--e2) + env(safe-area-inset-left, 0px));
    bottom: calc(var(--e2) + env(safe-area-inset-bottom, 0px));
    max-width: none;
    padding: 10px 12px;
    font-size: 0.875rem;       /* 14px */
  }
  .banner-dot { width: 10px; height: 10px; }
  .banner-sep,
  #banner-prox { display: none; }
  .banner-fonte { font-size: 0.8125rem; }
  body { padding-bottom: 96px; }
}

/* ---- 28.5 Layout A: cartão amarelo na faixa lateral ESQUERDA (>= 1800px) ----
   Em 1920px o .app começa em x=340, o texto em x=372 e o topo do card
   "Apuração oficial" está em y=134: o cartão nasce exatamente nessa linha. */

@media (min-width: 1560px) {
  .banner-atualizacao {
    top: 134px;
    bottom: auto;
    /* Cola na borda esquerda da tela, dentro da faixa vazia. A largura
       acompanha a sobra: 146px numa tela de 1560, 280px de 1800 pra cima. */
    left: 16px;
    right: auto;
    width: clamp(146px, calc((100vw - var(--largura-max)) / 2 - 24px), 280px);
    max-width: none;
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    /* Linha do meio elástica: rótulo no topo, site centrado no vazio,
       TSE ancorado no pé — sem buraco entre o texto e o fio. */
    grid-template-rows: auto 1fr auto;
    align-items: center;
    gap: var(--e2);
    min-height: 236px;
    padding: 18px;
    border-radius: 13px;
    font-size: 0.9375rem;      /* 15px */
    line-height: 1.45;
    text-align: justify;
    text-justify: inter-word;
    hyphens: auto;
  }

  /* Rótulo do cartão — só existe neste layout */
  .banner-atualizacao::before {
    content: "ATUALIZAÇÃO";
    grid-column: 1 / -1;
    margin-bottom: var(--e-meio);
    color: var(--txt-3);
    font-family: var(--fonte);
    font-size: 0.6875rem;      /* 11px */
    font-weight: 700;
    letter-spacing: 0.12em;
    line-height: 1.4;
    text-transform: uppercase;
  }

  .banner-dot {
    width: 11px;
    height: 11px;
  }

  /* Empilha: "Site: …" e, abaixo, a próxima consulta */
  .banner-texto {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--e-1);
    min-width: 0;
  }

  .banner-sep { display: none; }

  #banner-dado::before {
    content: "Site: ";
    color: var(--txt-3);
    font-weight: 400;
  }

  #banner-prox {
    color: var(--txt-3);
    font-size: 0.8125rem;      /* 12px */
    letter-spacing: 0.01em;
  }

  /* Fio escuro de largura toda separando o que é do site e o que é do TSE */
  .banner-fonte {
    grid-column: 1 / -1;
    display: block;
    margin-top: var(--e2);
    padding-top: var(--e3);
    border-top: 1px solid var(--destaque-fio);
    color: var(--txt);
    font-size: 0.9375rem;      /* 15px */
    overflow-wrap: break-word;
  }
  .banner-fonte::before,
  .banner-texto::after { display: none; }

  /* O cartão fica no topo: o rodapé não precisa de respiro */
  body { padding-bottom: 0; }
}

/* ---- 28.6 Impressão: estado ao vivo não é documento ---- */

@media print {
  .banner-atualizacao { display: none !important; }
  body { padding-bottom: 0; }
}

/* utilitário de leitor de tela (anúncio do estado) */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}


/* ============================================================================
   MUNICIPIO SEM DADO NO MAPA
   O JS pinta o path com fill="var(--superficie-3)". No tema claro isso ficava
   praticamente igual ao fundo e o mapa parecia cheio de buracos. Aqui a cor e
   trocada por um cinza neutro com contraste real contra --bg, nos dois temas.
   A borda do municipio continua a mesma, entao a malha segue legivel.
   ========================================================================== */
#mapa-svg path.sem-dado {
  fill: var(--sem-dado);
}

/* ============================================================================
   29 · GRÁFICO DA PROJEÇÃO (preparação — o arquiteto emite o SVG)
   Contrato: o container é .projecao-grafico e dentro dele um <svg> com as
   classes abaixo. Nada aqui depende de markup existente: enquanto o SVG não
   existir, estas regras não têm efeito nenhum.
   Cores só por token: as linhas herdam --lula / --flavio, que já mudam com o
   tema — o JS não precisa saber qual tema está ativo.
   ========================================================================== */

.projecao-grafico {
  display: block;
  width: 100%;
  height: auto;
}

.projecao-grafico svg {
  width: 100%;
  height: auto;
  max-height: 260px;
}

.projecao-grafico .eixo { stroke: var(--linha-forte); stroke-width: 1; }

/* Grade: --linha (alfa 0,075) dá 1,09:1 — abaixo do limiar de percepção, a
   grade simplesmente não existe. --linha-forte integral dá 1,59:1 (escuro) e
   1,69:1 (claro): guia o olho sem competir com as séries. */
.projecao-grafico .grid { stroke: var(--linha-forte); stroke-width: 1; stroke-opacity: 1; }

.projecao-grafico .rotulo-eixo {
  fill: var(--txt-3);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}

/* Série cheia = dado oficial; tracejada = projeção. A diferença de traço é o
   segundo canal (além da cor) para quem não distingue vermelho de azul. */
.projecao-grafico .linha-oficial {
  fill: none;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.projecao-grafico .linha-projecao {
  fill: none;
  stroke-width: 1.5;
  /* 6 4 em vez de 5 4: com traço fino, 5px lê como pontilhado trêmulo */
  stroke-dasharray: 6 4;
  stroke-linecap: round;
  /* sem opacidade: o tracejado é o canal que distingue estimativa de dado.
     A 0,85 a linha caía para 4,24:1 e o rótulo da série para 3,55:1 — abaixo
     do 4,5:1 de AA. A 1,0 fica em 5,46:1 (escuro) e 6,25:1 (claro). */
  opacity: 1;
}

.projecao-grafico .lula { stroke: var(--lula); }
.projecao-grafico .flavio { stroke: var(--flavio); }

.projecao-grafico .rotulo-serie {
  /* 10,5px/600 e não 12px/700: com o gutter de 96px do viewBox, "Flávio 48,45%"
     em 12px/700 passa de 90px e o SVG corta o rótulo na borda direita.
     Medido no gráfico em produção: 123,1px de texto contra 89px disponíveis. */
  font-size: 10.5px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}
.projecao-grafico .rotulo-serie.lula { fill: var(--lula); }
.projecao-grafico .rotulo-serie.flavio { fill: var(--flavio); }

/* a linha da virada é rastro, não portador de informação: 2,54:1 (escuro) e
   2,24:1 (claro). Quem carrega o dado é o rótulo em --txt-2 (8,67:1 / 9,04:1). */
.projecao-grafico .virada { stroke: var(--txt-3); stroke-opacity: .55; stroke-dasharray: 2 4; }

.projecao-grafico-notas {
  font-size: 0.75rem;
  color: var(--txt-3);
  line-height: 1.5;
}

@media (max-width: 560px) {
  .projecao-grafico svg { max-height: 200px; }
}

/* ============================================================================
   30 · TABELA DA LISTA — 4 colunas em todos os níveis
   Contrato com o arquiteto (o markup é dele):
     .lista-tabela            container
       .lista-tabela-cabecalho   linha de rótulos (Nome | Lula | Flávio | Margem)
       .lista-total             1ª linha: total consolidado do recorte (BR/Região/UF)
       .lista-linha             cada estado ou município do recorte
   Em toda linha a ordem das células é: nome | votos Lula | votos Flávio | margem.
   As três grades (cabeçalho, total, linha) usam as MESMAS colunas e o mesmo
   padding — é isso que faz os números ficarem em coluna de uma linha para a
   outra, e não dançando conforme o tamanho do número.
   ========================================================================== */

/* ---- 30.1 Altura do header fixo ----
   Medida no navegador, não chutada: 94px acima de 1100, 88px entre 761 e 1099,
   130px abaixo disso. Serve para o scroll-margin e para a barra de busca. */
/* Altura real do header por faixa (medida com getBoundingClientRect):
   1280 → 105,5 · 1024 → 99,7 · 820 → 129,6 (header em 2 linhas) ·
   700 → 108,3 · 390/360 → 103,4. O valor de cada faixa é o maior do intervalo:
   se --topbar-h ficar menor que o header real, a barra de busca gruda por
   baixo dele e o scroll-margin para de funcionar. */
:root { --topbar-h: 106px; }
@media (max-width: 1099px) { :root { --topbar-h: 151px; } }
@media (max-width: 767px)  { :root { --topbar-h: 109px; } }
@media (max-width: 560px)  { :root { --topbar-h: 104px; } }

/* Âncora (inclusive :target) para de cair atrás do header fixo: toda seção ou
   item com id reserva a altura do header + respiro antes de encostar no topo. */
[id] { scroll-margin-top: calc(var(--topbar-h, 0px) + 8px); }

/* ---- 30.2 Grades ---- */

.lista-tabela {
  display: grid;
  width: 100%;
  min-width: 0;
  font-variant-numeric: tabular-nums;
}

.lista-tabela-cabecalho,
.lista-linha,
.lista-total {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 88px 88px 64px;
  align-items: baseline;
  gap: var(--e-meio) var(--e2);
  padding: var(--e-meio) var(--e2);
  min-width: 0;
}

/* ---- 30.3 Cabeçalho de colunas ---- */

.lista-tabela-cabecalho {
  border-bottom: var(--borda);
  color: var(--txt-3);
  font-size: 0.6875rem;          /* 11px */
  font-weight: 600;
  letter-spacing: 0.08em;
  line-height: 1.5;
  text-transform: uppercase;
}

/* Rótulo genérico da 1ª coluna: o texto ("Estado" / "Município" / "Nome") vem
   do JS — aqui só garantimos que ele não empurra as colunas de número. */
.lista-cab-nome {
  min-width: 0;
  text-align: left;
  overflow-wrap: break-word;
}

.lista-tabela-cabecalho > :nth-child(2),
.lista-tabela-cabecalho > :nth-child(3),
.lista-tabela-cabecalho > :nth-child(4) { text-align: right; }

/* ---- 30.4 Linhas comuns ---- */

.lista-linha {
  border-bottom: 1px solid var(--linha-suave);
  color: var(--txt-2);
  font-size: 0.78125rem;
  line-height: 1.45;
}
.lista-linha:last-child { border-bottom: 0; }
.lista-linha:hover { background: var(--hover-linha); }

.lista-linha > :first-child,
.lista-total > :first-child {
  color: var(--txt);
  overflow-wrap: break-word;
}

/* Item que o app manda rolar até aqui (clique no município no mapa) não pode
   parar atrás do header fixo. */
.lista-linha,
.lista-total { scroll-margin-top: calc(var(--topbar-h, 0px) + 12px); }

/* ---- 30.5 Linha de total consolidado ----
   Destaque por superfície e fio, NUNCA por cor: a linha precisa ler como
   "total", não como "quem ganhou". Por isso fundo neutro (superficie-3), fios
   fortes em cima e embaixo, e peso 600 só nos números. */

.lista-total {
  background: var(--superficie-3);
  border-top: 1px solid var(--linha-forte);
  border-bottom: 1px solid var(--linha-forte);
  color: var(--txt);
  font-size: 0.78125rem;
  line-height: 1.45;
}

.lista-total .lista-nome {
  color: var(--txt);
  font-weight: 700;
  letter-spacing: 0.01em;
}

/* As cores de candidato continuam vindo de .lula / .flavio */
.lista-total .lista-votos { font-weight: 600; }
.lista-total .lista-margem { color: var(--txt-2); font-weight: 600; }
.lista-total .lista-pct { color: var(--txt-3); font-weight: 400; }

/* ---- 30.6 Números ---- */

.lista-votos {
  font-family: var(--fonte-num);
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
  color: var(--txt);
}
.lista-votos.lula { color: var(--lula); }
.lista-votos.flavio { color: var(--flavio); }

/* O percentual vai em linha própria DENTRO da célula. Motivo medido: com a
   coluna de 88px, "18.435.265 (51,2%)" tem 125px e vazava 37px sobre a coluna
   vizinha (o número de Flávio aparecia por cima do de Lula). Empilhado, o
   número (79px) e o percentual (45px) cabem sem cortar nem invadir. */
.lista-pct {
  display: block;
  margin-left: 0;
  color: var(--txt-3);
  font-size: 0.6875rem;
  font-weight: 400;
  line-height: 1.4;
}

.lista-margem {
  color: var(--txt-2);
  font-family: var(--fonte-num);
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}

/* ---- 30.7 Estados vazios e nota de rodapé ---- */

.lista-vazia {
  padding: var(--e6) var(--e4);
  border: 0;
  color: var(--txt-3);
  font-size: var(--fs-sub);
  line-height: 1.6;
  text-align: center;
  text-wrap: balance;
}

.lista-nota {
  margin-top: var(--e2);
  color: var(--txt-3);
  font-size: 0.75rem;
  line-height: 1.5;
}

/* ---- 30.8 Rolagem da lista ----
   Brasil = 28 linhas, Nordeste = 9, municípios de PE = 184. A lista rola
   dentro de si (o resto da página não se mexe) e a barra é discreta nos dois
   temas. scroll-padding-top deixa respiro ao rolar até um item. */

.lista-scroll {
  max-height: 62vh;
  overflow-y: auto;
  overscroll-behavior: contain;
  scroll-padding-top: calc(var(--topbar-h, 0px) + 12px);
  scrollbar-width: thin;
  scrollbar-color: var(--superficie-4) transparent;
}

.lista-scroll::-webkit-scrollbar { width: 10px; }
.lista-scroll::-webkit-scrollbar-track { background: transparent; }
.lista-scroll::-webkit-scrollbar-thumb {
  background: var(--superficie-4);
  border: 3px solid var(--bg);
  border-radius: var(--r-pilula);
}

/* ---- 30.9 Celular: duas linhas por item ----
   nome + margem em cima; Lula e Flávio lado a lado embaixo, cada um na sua
   metade. Nenhum dos dois pode sumir: o número pode encolher, nunca ser
   escondido ou truncado (por isso nowrap + font-size 12px, medido com 9
   dígitos em cada coluna). */

@media (max-width: 560px) {
  .lista-tabela-cabecalho { display: none; }

  .lista-linha,
  .lista-total {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto;
    row-gap: 2px;
    padding: var(--e-meio) var(--e2);
  }

  .lista-linha > :first-child,
  .lista-total > :first-child { grid-column: 1 / 3; grid-row: 1; }

  .lista-linha > .lista-votos:nth-child(2),
  .lista-total > .lista-votos:nth-child(2) { grid-column: 1; grid-row: 2; text-align: left; }

  .lista-linha > .lista-votos:nth-child(3),
  .lista-total > .lista-votos:nth-child(3) { grid-column: 2; grid-row: 2; text-align: left; }

  .lista-linha > .lista-margem,
  .lista-total > .lista-margem { grid-column: 3; grid-row: 1; }

  .lista-votos { font-size: 0.75rem; }     /* 12px */
  .lista-pct { font-size: 0.625rem; }
  .lista-margem { font-size: 0.625rem; }
  .lista-total .lista-votos { font-size: 0.75rem; }
}

/* ============================================================================
   BANNER DE ATUALIZAÇÃO NO HEADER (retângulo horizontal, sempre visível)
   O cartão flutuante saiu: agora o banner é o terceiro filho do .topbar, entre
   a marca (esquerda) e os selos (direita). O header fica preso no topo, então
   o estado da atualização acompanha a rolagem sem cobrir conteúdo nenhum.
   Este bloco vence as regras antigas por especificidade (.topbar .banner-...),
   inclusive o layout de coluna lateral que existia a partir de 1560px.
   ========================================================================== */

.topbar {
  position: sticky;
  top: 0;
  z-index: 60;
  background: var(--bg);
  padding-top: var(--e3);
  /* backdrop-filter saiu: --bg é opaco nos dois temas, então o blur não tinha
     nada para desfocar — só custava uma camada de composição na rolagem. */
}

/* Marca e selos não encolhem: quem cede largura é o banner. Sem isto o h1
   quebra em duas linhas, a marca vai a 99px e o header salta de 104 para
   140px (medido em 1280). */
.topbar-marca,
.topbar-estado { flex: 0 0 auto; }

/* O título da marca NUNCA quebra. Era o defeito original do header: com o h1
   em duas linhas a marca ia a 99px e o header a 140px. */
.topbar h1 {
  white-space: nowrap;
  text-wrap: nowrap;
}

/* A faixa: duas linhas, 14px, no máximo 360px de largura.
   Grid de duas colunas — o ponto ocupa a coluna 1 nas DUAS linhas, então as
   duas linhas de texto começam no mesmo x (o ponto nunca empurra só a
   primeira). Altura resultante: 2 × (14 × 1,35) + 3 de row-gap + 8 de padding
   + 2 de borda = 50,8px. */
.topbar .banner-atualizacao {
  position: static;
  inset: auto;
  align-self: center;
  display: grid;
  grid-template-columns: 8px minmax(0, 1fr);
  grid-template-rows: auto auto;
  column-gap: 8px;
  row-gap: 3px;
  align-content: center;
  flex: 1 1 360px;
  min-width: 0;
  width: auto;
  max-width: 360px;
  min-height: 0;
  height: auto;
  margin: 0;
  padding: 4px 8px;
  border: var(--borda);
  border-radius: var(--r-xs);
  background: var(--superficie-2);
  box-shadow: none;
  color: var(--txt-3);
  font-size: 14px;
  line-height: 1.35;
  text-align: left;
  white-space: nowrap;
  overflow: hidden;
  transition: background-color var(--t-2) var(--curva),
              border-color var(--t-2) var(--curva);
}

/* o rótulo vertical e o "Site:" eram do cartão; no retângulo não cabem */
.topbar .banner-atualizacao::before { content: none; }
.topbar #banner-dado::before { content: none; }

/* Linha 1 — "atualizado há 7 s · próxima em 4 s" */
.topbar .banner-texto {
  grid-column: 2;
  grid-row: 1;
  display: inline-flex;
  flex-direction: row;
  align-items: baseline;
  flex-wrap: nowrap;
  gap: 6px;
  min-width: 0;
  overflow: hidden;
}

/* o "│" de fechamento de linha vinha do cartão; na faixa o separador é o "·" */
.topbar .banner-texto::after { content: none; }

.topbar .banner-sep { display: inline; flex: none; color: var(--txt-3); }

/* Linha 1 em --txt-2 (8,23:1 escuro / 8,72:1 claro) — a hierarquia desce
   para o carimbo do TSE, que fica em --txt-3. */
.topbar #banner-dado {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--txt-2);
  font-weight: 600;
  letter-spacing: -0.01em;
}

.topbar #banner-prox { display: inline; flex: none; color: var(--txt-3); }

/* Linha 2 — "Dados TSE atualizados em 20:43:38", na coluna 2 e na mesma
   coluna de texto da linha 1 (mesmo x de início). */
.topbar .banner-fonte {
  grid-column: 2;
  grid-row: 2;
  display: inline-flex;
  align-items: baseline;
  flex: none;
  margin: 0;
  padding: 0;
  border: 0;
  overflow: visible;
  color: var(--txt-3);
  font-size: 14px;
  line-height: 1.35;
  letter-spacing: 0;
  white-space: nowrap;
}

/* a linha 2 é uma linha inteira: não leva separador à frente */
.topbar .banner-fonte::before { content: none; }

.topbar .banner-dot {
  grid-column: 1;
  grid-row: 1 / span 2;
  align-self: center;
  flex: none;
  width: 8px;
  height: 8px;
  box-shadow: none;
  background: var(--oficial);
  transition: background-color var(--t-2) var(--curva);
}

/* ---- Estados da faixa: ponto + tingimento + cor do texto ----------------
   O amarelo não carrega estado em faixa: como fio de 3px sobre papel dá
   1,36:1 (invisível) e, como fundo, derruba o texto de atenção para 3,53:1.
   Aqui o estado entra em três canais redundantes: o ponto, o tingimento de
   9–10% e a cor do texto. Pares medidos (fundo / texto):

   ok       --superficie-2 #15181C · #FAFBFC
            texto --txt .............. 15,31:1 · 17,34:1
            meta  --txt-3 .............  5,32:1 ·  5,24:1
   parado   tingimento --projecao-bg 10% / 9%  →  #2A2722 · #F0EDE5
   atenção  texto --projecao .........  7,56:1 ·  5,07:1
            meta  --txt-2 .............  6,88:1 ·  7,73:1
            (a --txt-3 sobre o âmbar fica em 4,45:1 no escuro: reprova por
             0,05, por isso a meta sobe um degrau só neste estado)
   erro     tingimento --alerta-bg 9% / 7%     →  #282123 · #F4ECEF
   alerta   texto --alerta ...........  5,42:1 ·  6,06:1
            meta  --txt-3 .............  4,71:1 ·  4,67:1
   ---------------------------------------------------------------------- */

.topbar .banner-atualizacao.ok {
  background-image: none;
  border-color: var(--linha);
}

.topbar .banner-atualizacao.parado,
.topbar .banner-atualizacao.atencao {
  border-color: var(--projecao-borda);
  /* gradiente de uma parada = a tinta translúcida do token composta sobre a
     superfície; mesmo resultado de um rgba, sem hardcodar alfa */
  background-image: linear-gradient(var(--projecao-bg), var(--projecao-bg));
}
.topbar .banner-atualizacao.parado .banner-dot,
.topbar .banner-atualizacao.atencao .banner-dot { background: var(--projecao); }
.topbar .banner-atualizacao.parado #banner-dado,
.topbar .banner-atualizacao.atencao #banner-dado { color: var(--projecao); }
.topbar .banner-atualizacao.parado #banner-prox,
.topbar .banner-atualizacao.atencao #banner-prox,
.topbar .banner-atualizacao.parado .banner-fonte,
.topbar .banner-atualizacao.atencao .banner-fonte { color: var(--txt-2); }

.topbar .banner-atualizacao.erro,
.topbar .banner-atualizacao.alerta {
  border-color: var(--alerta-borda);
  background-image: linear-gradient(var(--alerta-bg), var(--alerta-bg));
}
.topbar .banner-atualizacao.erro .banner-dot,
.topbar .banner-atualizacao.alerta .banner-dot { background: var(--alerta); }
.topbar .banner-atualizacao.erro #banner-dado,
.topbar .banner-atualizacao.alerta #banner-dado { color: var(--alerta); }

/* O respiro de 76/96px no pé da página existia para o cartão flutuante não
   cobrir o rodapé. Com a faixa dentro do header ele é só espaço morto — some
   quando (e somente quando) a faixa está no header. */
body:has(.topbar .banner-atualizacao) { padding-bottom: 0; }

/* ---- Largura: duas linhas sempre, uma linha só no celular --------------
   Em 360px de faixa cada linha tem ~324px de caixa e pede ~302px de texto:
   sobra folga, então NADA é escondido a partir de 768px — "próxima em Xs"
   fica na linha 1 em todas as larguras de desktop. A linha 2 (carimbo do TSE)
   só sai no celular, onde a faixa vira uma linha ao lado do título.
   ---------------------------------------------------------------------- */

@media (max-width: 767px) {
  .topbar .banner-fonte { display: none; }
}

/* Abaixo de 370px a linha 1 com "próxima em" (303px) não cabe nos 294px de
   caixa: o par sai e fica só o estado. A fonte NUNCA desce de 14px. */
@media (max-width: 369px) {
  .topbar #banner-prox,
  .topbar .banner-sep { display: none; }
}

/* Entre 768 e 1099 a coluna do meio não comporta a faixa (marca 262-304 +
   selos 342 + vãos 48 deixam 174 a 368px, e a linha 1 precisa de 321px no pior
   estado). Aqui o header quebra em duas linhas: marca e selos em cima, faixa
   de 360px embaixo. De 1100 para cima a faixa volta para a linha do header. */
@media (min-width: 768px) and (max-width: 1099px) {
  .topbar { flex-wrap: wrap; gap: var(--e3); padding-bottom: var(--e3); }
  .topbar-estado { order: 2; }
  .topbar .banner-atualizacao { order: 3; flex: 0 0 360px; max-width: 360px; }
}

/* ---- Celular: a faixa entra entre a marca e os selos -------------------
   A topbar é coluna. Para o header fixo não roubar tela, a linha da disputa
   ("Presidente · Lula 13 × Flávio 22") sai do header: ela está inteira no
   cartão de apuração, a 200px daqui. Mantida, o header passa de 140px. */
@media (max-width: 767px) {
  .topbar { gap: 4px; padding-top: 2px; padding-bottom: var(--e2); }
  .topbar-marca .marca-disputa { display: none; }
  .topbar .banner-atualizacao {
    flex: 0 0 auto;
    align-self: stretch;
    width: 100%;
    max-width: none;
    /* uma linha só no celular: colapsa a segunda linha do grid e o ponto
       deixa de ocupar duas linhas (senão o span cria uma linha implícita) */
    grid-template-rows: auto;
    align-content: center;
  }
  .topbar .banner-dot { grid-row: 1; }
}

@media (max-width: 400px) {
  .topbar .selos { gap: 4px; }
  .topbar .selo { padding: 2px 5px; font-size: 9px; letter-spacing: .06em; }
  /* Abaixo de 401px a fonte continua 14px e "próxima em" continua na linha 1
     (layout do topo do arquivo). Só abaixo de 370px o par sai — ali a linha 1
     típica mede 303px e a caixa tem 294px. */
}

@media (max-width: 560px) {
  .topbar .banner-atualizacao { padding: 4px 8px; }
  .topbar .banner-dot { width: 7px; height: 7px; }
}

@media print {
  body:has(.topbar .banner-atualizacao) { padding-bottom: 0; }
}

/* ============================================================================
   31 · GRÁFICO DA NOITE (.grafico-noite / .graf-*)
   Contrato do SVG que o app.js JÁ emite hoje (montarGrafico): 4 séries com
   atributos de apresentação — stroke-width, stroke-dasharray, stroke-opacity,
   font-size, opacity. Atributo de apresentação perde para regra CSS, então
   este bloco ajusta o gráfico inteiro sem tocar em app.js.

   O bloco 29 (.projecao-grafico) cobre o contrato NOVO. Os dois convivem: se o
   arquiteto trocar o SVG, este bloco fica sem consumidor e o 29 assume.

   Nenhuma cor nova: séries em --lula / --flavio, eixo em --txt-3, grade em
   --linha-forte.
   ========================================================================== */

.graf-titulo {
  margin: 0 0 2px;
  font-size: var(--fs-titulo);
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--txt);
}

/* Eixo: número tabular 10px. --txt-3 = 5,61:1 (escuro) / 5,43:1 (claro). */
.graf-eixo {
  font-family: var(--fonte-num);
  font-size: 10px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
  fill: var(--txt-3);
}

/* Grade horizontal: o app.js aplicava stroke-opacity 0,45 sobre --linha-forte
   (0,16 de alfa) = 1,19:1, invisível. Integral dá 1,59:1 no escuro e 1,69:1 no
   claro — guia sem competir. Grade é ornamento: fica de propósito abaixo de 3:1. */
.graf-grid {
  stroke: var(--linha-forte);
  stroke-opacity: 1;
}

/* Coluna da hora: mais fraca que a linha do eixo Y (1,28:1 / 1,35:1) */
.graf-grid-x { stroke-opacity: 0.6; }

/* Séries: 2px sólida (TSE) × 1,5px tracejada (Halley) */
.graf-ofi {
  fill: none;
  stroke-width: 2;
}

.graf-proj {
  fill: none;
  stroke-width: 1.5;
  stroke-dasharray: 6 4;
  stroke-linecap: round;
  stroke-opacity: 1;
}

/* Ponta de série: ponto cheio (oficial) × anel (projeção). O anel só aparece
   quando o app.js emitir .graf-ponto.graf-proj — enquanto não emitir, a regra
   não tem consumidor. */
.graf-ponto { stroke: none; }

.graf-ponto.graf-proj {
  fill: var(--superficie);
  stroke-width: 1.5;
}

/* Rótulos das pontas: 10,5px/600 e SEM opacidade.
   O app.js aplica opacity="0.75": composto sobre --superficie dá 3,55:1 no
   escuro (abaixo do 4,5:1 de AA). A 1,0 fica em 5,46:1 / 6,25:1.
   Não subir para 11px: o viewBox reserva 96px de gutter e "Flávio 48,45%
   proj." mede 123,1px — o SVG corta o texto na borda direita. */
.graf-rotulo {
  font-family: var(--fonte-num);
  font-size: 10.5px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
  opacity: 1;
}

.graf-rotulo-proj { opacity: 1; }

/* Virada: a linha é rastro (2,54:1 / 2,24:1), a informação está no rótulo
   (--txt-2 = 8,67:1 / 9,04:1). */
.graf-virada {
  stroke: var(--txt-3);
  stroke-width: 1;
  stroke-dasharray: 2 4;
  stroke-opacity: 0.55;
}

.graf-virada-txt {
  fill: var(--txt-2);
  font-family: var(--fonte);
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.01em;
}

/* Legenda do gráfico: amostras de traço (sólida × tracejada) */
.graf-legenda text {
  fill: var(--txt-3);
  font-family: var(--fonte);
  font-size: 10.5px;
  letter-spacing: 0.01em;
}

/* ---- 30.10 Linha de total — classe real do arquiteto ----
   O arquiteto emite .mapa-item.mapa-item-uf.mapa-item-br.mapa-item-total;
   nenhuma regra em .lista-total casava com isso, e a linha do BR saía igual às
   outras. Aqui só entram superfície e fio (nunca cor de candidato no fundo):
   a linha tem que ler como "total", não como "quem ganhou". .lista-total fica
   como alias, para o caso de ele trocar de nome de novo. */
.mapa-item-total,
.lista-total {
  background: var(--superficie-3);
  border-top: 1px solid var(--linha-forte);
  border-bottom: 1px solid var(--linha-forte);
}

.mapa-item-total:hover { background: var(--superficie-3); }

.mapa-item-total .uf-nome {
  color: var(--txt);
  font-weight: 700;
}

.mapa-item-total .uf-total { color: var(--txt-2); }

/* Números em 600 no total; os rótulos continuam leves */
.mapa-item-total .uf-cand b,
.mapa-item-total .lista-votos { font-weight: 600; }

.mapa-item-total .uf-margem { color: var(--txt-3); }

/* Cores de candidato dentro da linha de total — só no que identifica o
   candidato (nome, número, %), nunca no contêiner inteiro. Pega tanto a
   classe no número (.lula / .cand-lula) quanto no agrupador (.v-lula). */
.mapa-item-total .lula,
.mapa-item-total .cand-lula,
.mapa-item-total [class*="lula"] { color: var(--lula); }

.mapa-item-total .flavio,
.mapa-item-total .cand-flavio,
.mapa-item-total [class*="flavio"] { color: var(--flavio); }

/* ---- 30.11 Respiro do grupo de botões (ordenar / visão da lista) ----
   O grupo chega do JS com style="margin:0 0 8px" inline — sem !important o
   margin-top nunca aplica. O escopo é estreito: só o grupo de chips dentro do
   cartão da lista. Medido antes: 8px acima (colado) e 8px abaixo. */
#mapa-lista [role="group"],
.mapa-ordem,
#mapa-visao,
[role="group"][aria-label*="Visão" i] {
  margin-top: 12px !important;
  margin-bottom: 10px !important;
  align-items: center;
}

/* Botões do grupo com a MESMA largura entre si (largura mínima comum), e não
   cada um do tamanho do próprio texto. */
.mapa-ordem > button,
#mapa-visao > button,
[role="group"][aria-label*="Visão" i] > button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 64px;
  height: 26px;
  padding: 0 var(--e2);
}

/* Quando o grupo divide a linha com o "Voltar ao Brasil", os dois se alinham
   pelo centro — mesma linha de base visual, sem depender da altura do chip. */
.secao-topo .mapa-ordem,
.secao-topo [role="group"] { align-self: center; }
.btn-voltar,
.secao-topo .btn { align-self: center; }
