/* Mapa de Desastres Naturais de Maricá — interface pública (Fase 7).
   Identidade IDR: azul-marinho institucional como base, vermelho cereja como ação.
   Sem fontes de CDN: usa a tipografia que o portal já carrega, com fallback de sistema. */

:root {
  --navy: #0a2342;
  --navy-700: #123056;
  --cherry: #e21d2d;
  --cherry-700: #b4121f;
  --ink: #1b2733;
  --muted: #5b6b7b;
  --line: #e2e6ec;
  --bg: #f2f4f7;
  --card: #ffffff;
  --ok: #2f7d4f;
  --warn-bg: #fff4e5;
  --warn-ink: #7a4e00;
  --warn-line: #f2d9a8;
  --shadow: 0 6px 24px rgba(10, 35, 66, 0.14);
  --focus: #7fa8ff;
  --font-title: "Montserrat", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: "Source Sans 3", system-ui, -apple-system, "Segoe UI", sans-serif;
}

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

html, body { height: 100%; }

body {
  margin: 0;
  font-family: var(--font-body);
  color: var(--ink);
  background: var(--bg);
  display: flex;
  flex-direction: column;
  min-height: 100dvh;
}

h1, h2, h3 { font-family: var(--font-title); margin: 0; }
a { color: inherit; }

/* Acessibilidade — foco sempre visível e atalho para o conteúdo. */
:where(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

.skip-link {
  position: absolute;
  left: -999px;
  top: 0;
  z-index: 1200;
  background: #fff;
  color: var(--navy);
  padding: 10px 14px;
  border-radius: 0 0 8px 0;
  font-weight: 600;
}
.skip-link:focus { left: 0; }

.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;
}

/* ---------- Barra do subaplicativo (não substitui o header do portal) ------ */

/* 3 colunas: identidade | ação | vazio. A coluna vazia é o que mantém o botão no
   CENTRO REAL da barra — com um spacer só à esquerda ele acabava colado à direita. */
/* A faixa tem IMAGEM DE FUNDO e altura útil de 78 px — a mesma da barra do Mapa
   do Produtor Rural (`.header-inner{height:78px}`), para os três mapas do IDR
   terem o mesmo peso visual no topo.
   `isolation: isolate` cria contexto de empilhamento próprio: o z-index do véu e
   do conteúdo não disputa com o header do portal nem com os painéis. */
.app-bar {
  position: relative;
  isolation: isolate;
  background: var(--navy);
  color: #fff;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 14px;
  padding: 0 16px;
  min-height: 78px;
  /* ★ OBRIGATÓRIO. O `body` é flex-column e o `main` pede 60–78vh; sem isto a
     barra é o item que cede e ENCOLHE até os 78 px do min-height, mesmo quando o
     conteúdo mede mais. No mobile, onde ela empilha em três linhas (~136 px), o
     efeito era os botões de alerta e tempo vazarem por baixo e sumirem — não é
     `overflow`, é falta de `flex: none`. Mesmo motivo do `.hero`. */
  flex: none;
}

/* Alertas e tempo lado a lado, à direita: são o mesmo tipo de informação. */
.app-bar-indicadores { display: flex; align-items: center; justify-content: flex-end; gap: 8px; }

.app-bar .wordmark { display: flex; align-items: center; gap: 10px; min-width: 0; }
.app-bar .badge {
  background: #fff;
  color: var(--navy);
  font-family: var(--font-title);
  font-weight: 700;
  letter-spacing: 0.5px;
  padding: 6px 10px;
  border-radius: 8px;
  font-size: 16px;
  line-height: 1;
}
.app-bar .wordmark-txt { min-width: 0; }
.app-bar .title { font-family: var(--font-title); font-size: 16px; font-weight: 600; line-height: 1.15; }
.app-bar .subtitle { display: block; font-size: 12px; color: #b9c6da; margin-top: 2px; }

/* ---------- Hero (foto + abertura) ----------------------------------------- */

/* Seção própria, no padrão do Mapa da Mulher e do Produtor Rural: a foto fica
   AQUI, não como fundo da barra. `isolation` dá contexto de empilhamento próprio
   para o véu e o texto não disputarem z-index com o chrome do portal. */
.hero {
  position: relative;
  isolation: isolate;
  background: var(--navy);
  color: #fff;
  overflow: hidden;
  /* `flex: none` é obrigatório: o body é flex em coluna e o `main` pede 78vh.
     Sem isto o hero é o item que cede — encolhia a ZERO, sumindo da página. */
  flex: none;
}

.hero-bg { position: absolute; inset: 0; z-index: 0; }
.hero-bg img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 55%;
  opacity: 0;
  transition: opacity 1.6s ease;
  transform: scale(1.02); /* evita borda clara ao renderizar a escala do fade */
}
.hero-bg img.on { opacity: 1; }

/* O véu não é enfeite: é o que garante o contraste do texto sobre QUALQUER
   quadro da foto. Mais denso à esquerda, onde o texto se apoia. */
.hero-veu {
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    linear-gradient(90deg, rgba(10, 35, 66, 0.92) 0%, rgba(10, 35, 66, 0.74) 48%, rgba(10, 35, 66, 0.42) 100%),
    linear-gradient(180deg, rgba(10, 35, 66, 0.18) 0%, rgba(10, 35, 66, 0.5) 100%);
}

.hero-inner {
  position: relative;
  z-index: 2;
  max-width: 820px;
  padding: clamp(1.75rem, 4vw, 3rem) clamp(1rem, 4vw, 2.5rem);
}
.hero-eyebrow {
  margin: 0 0 8px;
  font-family: var(--font-title);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.9px;
  text-transform: uppercase;
  color: #9fc4f0;
}
.hero-titulo {
  margin: 0 0 12px;
  font-size: clamp(1.35rem, 3.2vw, 2.1rem);
  line-height: 1.18;
  font-weight: 700;
}
.hero-titulo em { font-style: normal; color: #ffd166; }
.hero-lead {
  margin: 0;
  font-size: clamp(0.94rem, 1.6vw, 1.05rem);
  line-height: 1.55;
  color: #dbe6f4;
  max-width: 62ch;
}

/* No celular o hero rouba a tela do mapa, que é o conteúdo. Encurta. */
@media (max-width: 640px) {
  .hero-inner { padding: 18px 16px 20px; }
  .hero-lead { font-size: 0.9rem; }
}

/* ---------- Botão e painel "Tempo agora" ----------------------------------- */

/* Só o glifo (e a temperatura, quando já lida): um botão de ícone ao lado do título. */
.btn-clima {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  flex: none;
  margin-left: 6px;
  padding: 4px 8px;
  min-height: 32px;
  border: 1px solid rgba(255, 255, 255, 0.34);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.1);
  color: #fff;
  font-family: var(--font-title);
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.btn-clima:hover { background: rgba(255, 255, 255, 0.2); }
.btn-clima:focus-visible { outline: 3px solid #fff; outline-offset: 2px; }
.btn-clima[aria-expanded="true"] { background: #fff; color: var(--navy); border-color: #fff; }
.btn-clima-glifo { display: inline-flex; }
.btn-clima-glifo svg { display: block; }
.btn-clima-temp:empty { display: none; }

/* ---------- Botão do Centro de Alertas ------------------------------------- */

/* Mesma forma do botão do tempo — são um par. O que muda é a COR, que carrega a
   severidade: quem passa os olhos pela barra entende o estado sem ler nada. */
/* ★ Precisa vir junto do `display`: o atributo `hidden` do HTML equivale a
   `display: none` na folha do navegador, e QUALQUER regra de autor com `display`
   vence essa — inclusive a linha logo abaixo. Sem isto o botão continuava na
   barra mesmo com `hidden` marcado (medido: 32px de altura, visível). */
.btn-alerta[hidden] { display: none; }
.btn-alerta {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  flex: none;
  padding: 4px 9px;
  min-height: 32px;
  border: 1px solid rgba(255, 255, 255, 0.34);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.1);
  color: #fff;
  font-family: var(--font-title);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.2px;
  line-height: 1;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}
.btn-alerta:hover { background: rgba(255, 255, 255, 0.2); }
.btn-alerta:focus-visible { outline: 3px solid #fff; outline-offset: 2px; }
.btn-alerta[aria-expanded="true"] { background: #fff; color: var(--navy); border-color: #fff; }
.btn-alerta-glifo { display: inline-flex; }
.btn-alerta-glifo svg { display: block; }
.btn-alerta-selo:empty { display: none; }

/* Cores por severidade. Sem alerta, o botão fica discreto como o do tempo: só
   sobe ao olho quando há algo — senão o alarme vira paisagem.
   `--pulso` é a cor da onda: cada nível pulsa na PRÓPRIA cor, para o movimento
   reforçar a severidade em vez de nivelar tudo por baixo. */
.btn-alerta--atencao {
  --pulso: 255, 209, 102;
  background-color: #FFD166; border-color: #FFD166; color: #4A3300;
  animation: alertaPulsa 2.8s ease-in-out infinite;
}
.btn-alerta--atencao:hover { background-color: #ffdc8a; }
.btn-alerta--preventivo {
  --pulso: 232, 128, 26;
  background-color: #E8801A; border-color: #E8801A; color: #fff;
  animation: alertaPulsa 2.5s ease-in-out infinite;
}
.btn-alerta--preventivo:hover { background-color: #f28f2c; }
.btn-alerta--oficial {
  --pulso: 226, 29, 45;
  background-color: #e21d2d; border-color: #e21d2d; color: #fff;
  animation: alertaPulsa 2s ease-in-out infinite;
}
.btn-alerta--oficial:hover { background-color: #b4121f; }

/* Pulsa em TODOS os níveis com alerta — nunca no verde, que é a ausência de
   alerta e não pede reação. A cadência acelera com a gravidade (2,8 s → 2 s):
   o mesmo gesto fica mais urgente sem precisar de outro recurso visual. */
@keyframes alertaPulsa {
  0%, 100% { box-shadow: 0 0 0 0 rgba(var(--pulso), 0.55); }
  50% { box-shadow: 0 0 0 7px rgba(var(--pulso), 0); }
}
@media (prefers-reduced-motion: reduce) {
  .btn-alerta--atencao,
  .btn-alerta--preventivo,
  .btn-alerta--oficial { animation: none; }
  .app-bar-fundo img { transition: none; }
}

/* Faixa enxuta: o boletim é consulta rápida, não pode empurrar o mapa para fora. */
.clima-painel {
  background: #fff;
  border-bottom: 1px solid var(--line);
  box-shadow: 0 10px 24px rgba(16, 34, 54, 0.12);
  padding: 8px 16px 9px;
}
.clima-estado { color: var(--muted); font-size: 12.5px; margin: 0; }

.clima-municipio {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 2px 12px;
  margin-bottom: 7px;
}
.clima-municipio-rotulo {
  font-family: var(--font-title);
  font-size: 10.5px;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--muted);
  margin-right: 6px;
}
.clima-municipio-faixa { font-family: var(--font-title); font-size: 16px; color: var(--navy); }
.clima-resumo { margin: 0; font-size: 12px; color: var(--muted); }
.clima-resumo.chovendo { color: #1F6FB2; font-weight: 600; }

/* Os distritos ROLAM na horizontal em vez de empilhar: 4 cartões em grade ocupavam
   quatro linhas no celular e comiam o mapa inteiro. `scroll-snap` faz cada cartão
   parar alinhado, então dá para percorrer distrito a distrito com o dedo. */
.clima-lista {
  list-style: none;
  margin: 0;
  padding: 0 0 4px;
  display: flex;
  gap: 8px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: thin;
  overscroll-behavior-x: contain;
}

/* `flex: 1 1 216px` + `min-width: 216px` resolve os dois casos com uma regra:
   onde SOBRA espaço os cartões crescem e preenchem a faixa (no desktop 4 cartões
   fixos em 216 px deixavam ~600 px de branco à direita); onde FALTA, o min-width
   impede o encolhimento e a lista volta a rolar, que é o comportamento do celular.
   O max-width evita que num monitor ultralargo o rótulo e o valor de cada linha
   fiquem em pontas opostas do cartão. */
.clima-cartao {
  flex: 1 1 216px;
  min-width: 216px;
  max-width: 420px;
  scroll-snap-align: start;
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 8px 10px;
}
.clima-cartao-topo { display: flex; align-items: center; gap: 8px; }
.clima-glifo { color: var(--navy); flex: none; display: inline-flex; }
.clima-cartao-id { min-width: 0; flex: 1 1 auto; display: flex; flex-direction: column; }
.clima-cartao-id strong { font-family: var(--font-title); font-size: 12.5px; line-height: 1.2; }
.clima-ordinal { font-size: 10.5px; color: var(--muted); }
.clima-temp { font-family: var(--font-title); font-size: 18px; color: var(--navy); flex: none; }
.clima-condicao { margin: 5px 0 6px; font-size: 11.5px; color: var(--muted); }

.clima-detalhes {
  margin: 0;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 1px 10px;
  font-size: 11.5px;
}
.clima-detalhes dt { color: var(--muted); }
.clima-detalhes dd { margin: 0; text-align: right; }

.clima-fonte { margin: 7px 0 0; font-size: 11px; color: var(--muted); }
.clima-fonte a { color: inherit; }

/* Setas de rolagem — no desktop não há gesto de arrastar, e sem elas o 4º distrito
   pode passar despercebido. Somem onde tudo já cabe. */
.clima-nav {
  border: 1px solid var(--line);
  background: #fff;
  color: var(--navy);
  border-radius: 999px;
  width: 30px;
  height: 30px;
  flex: none;
  cursor: pointer;
  font-size: 15px;
  line-height: 1;
  display: none;
}
.clima-nav:hover { background: #eef4fb; }
.clima-nav[disabled] { opacity: 0.35; cursor: default; }
.clima-carrossel { display: flex; align-items: center; gap: 8px; }
.clima-carrossel.tem-transbordo .clima-nav { display: block; }

/* A lista é item flex do carrossel: sem isto ela encolhe ao conteúdo (888 px) e os
   cartões nunca chegam a crescer — era essa a faixa branca à direita no desktop.
   `min-width: 0` é obrigatório para um contêiner rolável dentro de flex, senão o
   conteúdo impõe a largura mínima e o `overflow-x` do celular deixa de funcionar. */
.clima-carrossel .clima-lista { flex: 1 1 auto; min-width: 0; }

/* ⚠️ `justify-content: center` NUNCA pode valer enquanto a lista puder transbordar.
   Num contêiner rolável, centralizar joga o começo do conteúdo para FORA do lado
   esquerdo, e `scrollLeft` já está em 0 — o primeiro cartão fica inalcançável.
   Medido em 375 px: "Maricá (sede)" ficava 310 px à esquerda, sem como voltar.
   Com 4 distritos de no mínimo 216 px + 24 px de espaçamento, o transbordo é
   impossível a partir de ~940 px de lista. Daí o piso conservador de 1100 px:
   acima disso os cartões só encostam no max-width, e aí centralizar é seguro. */
@media (min-width: 1100px) {
  .clima-lista { justify-content: center; }
}

/* Dentro do portal, o header institucional já identifica o IDR e ocupa 90 px, sob uma
   barra de acessibilidade de 41 px. Manter a app-bar cheia empilharia três faixas e
   sobraria pouco para o mapa. Quando o chrome está presente (classe posta por app.js),
   a barra encolhe: fica o nome do sistema e a ação, some o selo e o subtítulo. */
body.tem-chrome-do-portal .app-bar { padding: 6px 16px; gap: 10px; }
body.tem-chrome-do-portal .app-bar .badge,
body.tem-chrome-do-portal .app-bar .subtitle { display: none; }
body.tem-chrome-do-portal .app-bar .title { font-size: 14px; }

/* A altura do botão só é reduzida onde há mouse. Em tela de toque o alvo continua
   com 44 px — encolher o botão principal no celular seria trocar espaço por acerto. */
@media (min-width: 861px) and (pointer: fine) {
  body.tem-chrome-do-portal .app-bar .btn { min-height: 38px; padding: 8px 14px; }
}

/* ---------- Botões --------------------------------------------------------- */

.btn {
  font-family: var(--font-title);
  font-weight: 600;
  font-size: 14px;
  border-radius: 10px;
  border: 1px solid transparent;
  cursor: pointer;
  padding: 10px 16px;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 44px; /* alvo de toque */
}
.btn svg { width: 18px; height: 18px; flex: none; }
.btn-cherry { background: var(--cherry); color: #fff; }
.btn-cherry:hover { background: var(--cherry-700); }
.btn-ghost { background: transparent; color: #fff; border-color: rgba(255, 255, 255, 0.35); }
.btn-ghost:hover { background: rgba(255, 255, 255, 0.1); }
.btn-outline { background: #fff; color: var(--navy); border-color: var(--line); }
.btn-outline:hover { background: var(--bg); }
.btn[disabled] { opacity: 0.55; cursor: not-allowed; }

.link-btn {
  background: none;
  border: none;
  color: var(--navy);
  font-weight: 600;
  font-size: 12px;
  cursor: pointer;
  padding: 4px 2px;
  text-decoration: underline;
}

/* ---------- Aviso: não é canal de emergência ------------------------------- */

.notice {
  background: var(--warn-bg);
  color: var(--warn-ink);
  border-bottom: 1px solid var(--warn-line);
  font-size: 13px;
  padding: 8px 16px;
  display: flex;
  gap: 10px;
  align-items: flex-start;
}
.notice svg { width: 18px; height: 18px; flex: none; margin-top: 1px; }

/* ---------- Layout do mapa ------------------------------------------------- */

/* O mapa é o conteúdo — merece a maior fatia da tela.
   `min-height` em `vh` (e não %) porque o `main` é item de um flex em coluna:
   a porcentagem dependeria da altura do pai, que aqui é o próprio conteúdo.
   O celular fica em 60vh: lá o hero, a barra e o painel de filtros já ocupam
   muito, e esticar o mapa empurraria a lista para longe demais. */
main { position: relative; flex: 1 1 auto; min-height: 60vh; }

@media (min-width: 861px) {
  main { min-height: 78vh; }
}
#map { position: absolute; inset: 0; background: var(--bg); }

.panel {
  position: absolute;
  top: 12px;
  left: 12px;
  z-index: 600;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 14px;
  box-shadow: var(--shadow);
  width: min(320px, calc(100vw - 24px));
  max-height: calc(100% - 24px);
  overflow: auto;
}
.panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--line);
  position: sticky;
  top: 0;
  background: #fff;
  border-radius: 14px 14px 0 0;
}
.panel-head h2 { font-size: 14px; font-weight: 600; }
.panel-body { padding: 12px 14px; display: flex; flex-direction: column; gap: 14px; }

.modes { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.mode {
  font-family: var(--font-title);
  font-weight: 600;
  font-size: 12.5px;
  padding: 10px 6px;
  min-height: 44px; /* alvo de toque */
  border: 1px solid var(--line);
  background: #fff;
  border-radius: 9px;
  cursor: pointer;
  color: var(--muted);
}
.mode[aria-pressed="true"] { background: var(--navy); color: #fff; border-color: var(--navy); }

.field label,
.field .label { font-size: 12px; color: var(--muted); font-weight: 600; display: block; margin-bottom: 4px; }
input, select, textarea {
  font-family: inherit;
  font-size: 14px;
  width: 100%;
  padding: 10px;
  border: 1px solid var(--line);
  border-radius: 9px;
  background: #fff;
  color: var(--ink);
}
textarea { min-height: 90px; resize: vertical; }
input[aria-invalid="true"], select[aria-invalid="true"], textarea[aria-invalid="true"] {
  border-color: var(--cherry);
}

.chips { display: flex; flex-wrap: wrap; gap: 6px; }
.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  padding: 6px 10px;
  min-height: 34px; /* WCAG 2.2 AA (2.5.8) pede 24 px; ficamos acima sem estourar o painel */
  border-radius: 999px;
  border: 1px solid var(--line);
  background: #fff;
  cursor: pointer;
  color: var(--ink);
}
.chip .dot { width: 10px; height: 10px; border-radius: 50%; flex: none; }
.chip[aria-pressed="false"] { opacity: 0.42; }
.chips-actions { display: flex; gap: 10px; margin-top: 2px; }

.counter { font-size: 12px; color: var(--muted); margin: 0; text-align: right; line-height: 1.3; }
.counter b { color: var(--ink); }
.mode-summary { font-size: 12px; color: var(--muted); margin: 0; }

/* ---------- Legenda -------------------------------------------------------- */

/* Canto inferior direito: não disputa espaço com o painel de filtros (topo à esquerda)
   nem com a escala do Leaflet (canto inferior esquerdo). O deslocamento vertical
   deixa a atribuição do OpenStreetMap visível. */
.legend {
  position: absolute;
  right: 12px;
  bottom: 34px;
  z-index: 600;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 14px;
  box-shadow: var(--shadow);
  padding: 10px 12px;
  max-width: min(320px, calc(100vw - 24px));
  max-height: 44%;
  overflow: auto;
}
.legend h3 {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: var(--muted);
  margin-bottom: 8px;
}
.legend ul { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 4px 12px; }
.legend li { display: flex; align-items: center; gap: 7px; font-size: 12px; }
.legend .dot { width: 12px; height: 12px; border-radius: 50%; flex: none; }
.legend .n { margin-left: auto; color: var(--muted); font-variant-numeric: tabular-nums; }

/* ---------- Estados: carregando / vazio / erro ----------------------------- */

/* Faixa no TOPO do mapa, não caixa no centro.
   Antes era `top:50%; left:50%` — com o mapa vazio (que é o estado normal de um
   sistema recém-implantado) a mensagem ficava permanentemente plantada no meio da
   tela, tapando justamente o que a pessoa quer ver. Agora avisa sem bloquear, e sai
   do caminho no mobile. */
.map-status {
  position: absolute;
  z-index: 650;
  top: 12px;
  left: 50%;
  transform: translateX(-50%);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 999px;
  box-shadow: var(--shadow);
  padding: 8px 16px;
  font-size: 13px;
  color: var(--muted);
  max-width: min(440px, calc(100vw - 24px));
  text-align: center;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}
.map-status.is-error { border-radius: 12px; }
.map-status[hidden] { display: none; }
.map-status.is-error { border-color: var(--cherry); color: var(--ink); }
.map-status .retry { margin-top: 10px; }

.spinner {
  width: 18px; height: 18px;
  border: 2px solid var(--line);
  border-top-color: var(--navy);
  border-radius: 50%;
  display: inline-block;
  vertical-align: -3px;
  margin-right: 8px;
  animation: spin 0.8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ---------- Marcadores ----------------------------------------------------- */

.pin { width: 30px; height: 30px; }
.pin .drop {
  width: 30px; height: 30px;
  border-radius: 50% 50% 50% 0;
  transform: rotate(-45deg);
  box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.28);
  display: flex;
  align-items: center;
  justify-content: center;
}
.pin .drop svg { transform: rotate(45deg); width: 16px; height: 16px; color: #fff; }
.pin.is-closed .drop { opacity: 0.5; }

.marker-cluster-idr {
  background: rgba(10, 35, 66, 0.22);
  border-radius: 50%;
}
.marker-cluster-idr div {
  background: var(--navy);
  color: #fff;
  width: 32px; height: 32px;
  margin: 4px;
  border-radius: 50%;
  font-family: var(--font-title);
  font-weight: 600;
  font-size: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Pino arrastável do formulário. */
.pin-draggable .drop { background: var(--cherry); box-shadow: 0 0 0 3px rgba(226, 29, 45, 0.28); }

/* ---------- Popup ---------------------------------------------------------- */

.leaflet-popup-content-wrapper { border-radius: 12px; }
.leaflet-popup-content { margin: 12px 14px; }
.popup { font-family: var(--font-body); min-width: 210px; }
.popup .ptype { display: flex; align-items: center; gap: 8px; font-family: var(--font-title); font-weight: 600; font-size: 14px; }
.popup .ptype .swatch {
  width: 22px; height: 22px;
  border-radius: 6px;
  display: flex; align-items: center; justify-content: center;
  flex: none;
}
.popup .ptype .swatch svg { width: 14px; height: 14px; color: #fff; }
.popup dl { margin: 8px 0 0; display: grid; grid-template-columns: auto 1fr; gap: 3px 8px; font-size: 12.5px; }
.popup dt { color: var(--muted); }
.popup dd { margin: 0; }
.popup .details { margin: 8px 0 0; font-size: 12.5px; white-space: pre-line; }
.popup .status { display: inline-block; font-size: 11px; font-weight: 600; padding: 2px 8px; border-radius: 999px; margin-top: 8px; }
.st-OPEN { background: #e6f0ff; color: #14498f; }
.st-IN_REVIEW { background: #fff0d6; color: #8a5a00; }
.st-CLOSED { background: #eaecef; color: #4a5460; }
.popup .approx { font-size: 11px; color: var(--muted); margin: 8px 0 0; }
.popup figure { margin: 8px 0 0; }
.popup figure img { width: 100%; border-radius: 8px; display: block; }

/* ---------- Lista textual alternativa -------------------------------------- */

.list-view { background: #fff; border-top: 1px solid var(--line); padding: 16px; }
.list-view > header { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 10px; }
.list-view h2 { font-size: 15px; font-weight: 600; }
.list-view table { width: 100%; border-collapse: collapse; font-size: 13px; }
.list-view caption { text-align: left; color: var(--muted); font-size: 12px; padding-bottom: 8px; }
.list-view th, .list-view td { text-align: left; padding: 8px 10px; border-bottom: 1px solid var(--line); vertical-align: top; }
.list-view th { font-family: var(--font-title); font-size: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.3px; }
.list-view .type-cell { display: flex; align-items: center; gap: 8px; }
.list-view .dot { width: 10px; height: 10px; border-radius: 50%; flex: none; }
.list-view .empty { color: var(--muted); padding: 14px 0; }
.table-wrap { overflow-x: auto; }

/* ---------- Rodapé do subaplicativo ---------------------------------------- */

.app-foot {
  background: var(--navy);
  color: #b9c6da;
  font-size: 12px;
  padding: 14px 16px;
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
  align-items: center;
}
.app-foot .spacer { flex: 1 1 auto; }

/* ---------- Formulário em etapas (drawer) ---------------------------------- */

.scrim { position: fixed; inset: 0; background: rgba(10, 35, 66, 0.45); z-index: 1050; display: none; }
.scrim.is-open { display: block; }

/* ---------- Aviso de emergência (antes do formulário) ---------------------- */

/* Fica ACIMA do drawer (z-index 1000): o aviso precede o formulário, e nada da
   página pode aparecer por cima dele. Sem `.is-open` aqui — o controle é o
   atributo `hidden`, porque este modal não tem transição para esperar. */
.scrim-emergencia {
  display: block;
  background: rgba(10, 35, 66, 0.62);
  z-index: 1100;
}
.scrim-emergencia[hidden] { display: none; }

/* A rolagem do fundo trava enquanto o aviso está na tela. */
body.com-modal-emergencia { overflow: hidden; }

.modal-emergencia {
  position: fixed;
  z-index: 1101;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(460px, calc(100vw - 32px));
  max-height: calc(100dvh - 32px);
  overflow-y: auto;
  background: #fff;
  border-radius: 16px;
  box-shadow: 0 24px 64px rgba(10, 35, 66, 0.4);
  padding: 22px;
}
.modal-emergencia[hidden] { display: none; }

.emergencia-topo { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
.emergencia-icone { color: var(--cherry); display: inline-flex; flex: none; }
.emergencia-topo h2 { font-size: 17px; color: var(--navy); }

.emergencia-frase { margin: 0 0 16px; font-size: 15.5px; line-height: 1.45; color: var(--ink); }
.emergencia-frase strong { color: var(--cherry); }

.emergencia-numeros { list-style: none; margin: 0 0 20px; padding: 0; display: grid; gap: 8px; }
.emergencia-numeros li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 11px 14px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--bg);
}
.emergencia-orgao { font-size: 14px; color: var(--ink); }

/* O número é `<a href="tel:">`: no celular, é um toque para ligar — que é o ponto
   inteiro deste aviso. Alvo de 44 px para não errar com a mão trêmula. */
.emergencia-fone {
  font-family: var(--font-title);
  font-size: 18px;
  font-weight: 700;
  color: var(--cherry);
  text-decoration: none;
  white-space: nowrap;
  padding: 4px 6px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
}
.emergencia-fone:hover, .emergencia-fone:focus-visible { text-decoration: underline; }

.emergencia-ok { width: 100%; justify-content: center; font-size: 15px; }

@media (max-width: 400px) {
  .modal-emergencia { padding: 18px 16px; }
  .emergencia-numeros li { flex-direction: column; align-items: flex-start; gap: 2px; }
  .emergencia-fone { padding-left: 0; }
}

.drawer {
  position: fixed;
  top: 0; right: 0;
  height: 100dvh;
  width: min(460px, 100vw);
  background: #fff;
  /* ★ ACIMA do header do portal, que é sticky com z-index:1000 (portal-chrome.css).
     Empatados, o topo da gaveta ficava por baixo dele e o título "Registrar
     ocorrência" aparecia cortado. Enquanto o formulário está aberto ele é o foco
     da tela — cobrir o header é o comportamento correto, e o scrim acompanha. */
  z-index: 1100;
  transform: translateX(100%);
  transition: transform 0.25s ease;
  display: flex;
  flex-direction: column;
  box-shadow: var(--shadow);
}
.drawer.is-open { transform: none; }
.drawer[aria-hidden="true"] { visibility: hidden; }
.drawer.is-open[aria-hidden="false"] { visibility: visible; }

.drawer-head {
  background: var(--navy);
  color: #fff;
  padding: 14px 16px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
.drawer-head h2 { font-size: 16px; font-weight: 600; }
.steps { display: flex; gap: 10px; padding: 12px 16px; border-bottom: 1px solid var(--line); flex-wrap: wrap; }
.step-dot { font-size: 11px; color: var(--muted); display: flex; align-items: center; gap: 6px; }
.step-dot .num {
  width: 22px; height: 22px;
  border-radius: 50%;
  background: var(--bg);
  display: flex; align-items: center; justify-content: center;
  font-weight: 600; color: var(--muted);
}
.step-dot.is-active .num { background: var(--navy); color: #fff; }
.step-dot.is-done .num { background: var(--ok); color: #fff; }
.drawer-body { padding: 16px; overflow: auto; flex: 1 1 auto; display: flex; flex-direction: column; gap: 14px; }
.drawer-foot { padding: 12px 16px; border-top: 1px solid var(--line); display: flex; justify-content: space-between; gap: 10px; }

/* Classe em vez de atributo `style` inline: a CSP da Fase 8 usa `style-src 'self'`,
   sem 'unsafe-inline', e atributos de estilo escritos no HTML seriam bloqueados. */
.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.grid2-tight { gap: 8px; }
.hint { font-size: 12px; color: var(--muted); margin: 0; }
.req { color: var(--cherry); }
.error-text { font-size: 12px; color: var(--cherry-700); margin: 4px 0 0; }

.consent { display: flex; gap: 10px; align-items: flex-start; font-size: 13px; background: var(--bg); padding: 12px; border-radius: 10px; }
.consent input { width: 18px; height: 18px; margin-top: 2px; flex: none; }

/* O opt-in do WhatsApp é OPCIONAL e precisa parecer opcional: fundo mais claro e
   contorno leve, para não ser lido como uma segunda exigência ao lado do
   consentimento obrigatório. */
.consent-opcional { background: #fff; border: 1px dashed var(--line); margin-top: 8px; }
.consent-opcional-nota { color: var(--muted); }

.privacy-note { font-size: 12px; color: var(--muted); background: var(--bg); border-radius: 10px; padding: 10px 12px; }
.photo-note { font-size: 12px; color: var(--muted); background: var(--bg); border-radius: 10px; padding: 10px; display: flex; gap: 8px; }
.photo-note svg { width: 16px; height: 16px; flex: none; }

.review dl { display: grid; grid-template-columns: auto 1fr; gap: 6px 12px; font-size: 13px; margin: 0; }
.review dt { color: var(--muted); }
.review dd { margin: 0; }

.picker-map { height: 220px; border-radius: 10px; border: 1px solid var(--line); overflow: hidden; }

.success { text-align: center; padding: 20px 8px; }
.success .mark {
  width: 56px; height: 56px;
  border-radius: 50%;
  background: #e7f4ec;
  color: var(--ok);
  display: flex; align-items: center; justify-content: center;
  margin: 0 auto 12px;
}
.success .mark svg { width: 30px; height: 30px; }

/* Honeypot: fora da tela, mas alcançável por leitores de tela com rótulo claro. */
.hp-field { position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden; }

/* ---------- Avisos (toasts) — nunca alert() nativo ------------------------- */

.toasts {
  position: fixed;
  z-index: 1100;
  left: 50%;
  bottom: 20px;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: min(420px, calc(100vw - 24px));
}
.toast {
  background: var(--navy);
  color: #fff;
  border-radius: 10px;
  padding: 12px 14px;
  font-size: 13px;
  box-shadow: var(--shadow);
}
.toast.is-error { background: var(--cherry-700); }
.toast.is-ok { background: var(--ok); }

/* ---------- Formulário único (antes eram 4 etapas) -------------------------- */

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

.form-secao { border-top: 1px solid var(--line); padding-top: 14px; display: flex; flex-direction: column; gap: 12px; }
.form-secao:first-of-type { border-top: none; padding-top: 0; }
.form-secao > h3 {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: var(--muted);
  margin: 0;
}

/* Etiquetas de tipo identificadas a partir do relato. Ficam ABAIXO da descrição, no
   fluxo — não em camada flutuante: elas são resultado a conferir, não um menu que
   tapa o campo enquanto a pessoa escreve. */
.tags-tipo { display: flex; flex-direction: column; gap: 6px; margin-top: 4px; }
.tags-tipo:empty { display: none; }
.tags-titulo {
  margin: 2px 0 0;
  font-family: var(--font-title);
  font-size: 11.5px;
  font-weight: 600;
  color: var(--muted);
}
.tags-linha { display: flex; flex-wrap: wrap; gap: 6px; }

.tag-tipo {
  font-family: var(--font-title);
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.2;
  padding: 8px 12px;
  min-height: 36px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: #fff;
  color: var(--ink);
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.tag-tipo:hover { background: #eef4fb; border-color: #b9d3ee; }
.tag-tipo:focus-visible { outline: 3px solid var(--navy); outline-offset: 2px; }
.tag-tipo.principal { border-color: #b9d3ee; background: #eef4fb; }
.tag-tipo.escolhida {
  background: var(--navy);
  border-color: var(--navy);
  color: #fff;
}

/* Tipos além do primário no popup do mapa. */
.popup .ptipos { list-style: none; margin: 4px 0 0; padding: 0; display: grid; gap: 3px; }
.popup .ptipos li { display: flex; align-items: center; gap: 6px; font-size: 12.5px; }
.popup .swatch-mini { width: 9px; height: 9px; border-radius: 50%; flex: none; }

.tags-dica { margin: 2px 0 0; font-size: 12px; color: var(--muted); }
.tags-dica.atencao { color: #8a5a00; font-weight: 600; }

/* Lista do que já foi escolhido — uma ocorrência pode ter vários tipos. O primeiro
   é o primário e leva marca própria: é ele que dá cor e ícone ao pino no mapa. */
.tipos-escolhidos { display: flex; flex-direction: column; gap: 6px; margin-top: 8px; }
.tipos-escolhidos:empty { display: none; }
.tipo-escolhido {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 6px 4px 6px 12px;
  border-radius: 999px;
  background: var(--navy);
  color: #fff;
  font-family: var(--font-title);
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.2;
}
.tipo-escolhido.primario { box-shadow: inset 0 0 0 2px #ffd166; }
.tipo-remover {
  border: none;
  background: rgba(255, 255, 255, 0.18);
  color: #fff;
  border-radius: 50%;
  width: 22px;
  height: 22px;
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
  flex: none;
}
.tipo-remover:hover { background: rgba(255, 255, 255, 0.34); }
.tipo-remover:focus-visible { outline: 2px solid #fff; outline-offset: 1px; }

/* Atalho de localização no topo de "Onde foi": é o caminho de um toque para quem
   está no local, e resolve ponto e endereço de uma vez. */
.atalho-local {
  background: #eef4fb;
  border: 1px solid #b9d3ee;
  border-radius: 12px;
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  align-items: flex-start;
}
.atalho-local .hint { margin: 0; }
.atalho-local .btn { width: 100%; justify-content: center; }
.btn-navy { background: var(--navy); color: #fff; border-color: var(--navy); }
.btn-navy:hover { background: var(--navy-700); border-color: var(--navy-700); }
.btn-navy[disabled] { opacity: 0.6; cursor: default; }

.hint-secao { margin: 0; }

/* Quando o texto não identificou nada, o seletor manual precisa saltar aos olhos —
   é para ele que a dica acima manda a pessoa olhar. */
.field.precisa-atencao select { border-color: #d9a441; box-shadow: 0 0 0 3px rgba(217, 164, 65, 0.22); }

/* CEP e o botão de buscar na mesma linha, com o botão alinhado ao campo. */
/* ★ Alinha pelo TOPO, não pela base. Os dois campos desta linha têm alturas
   diferentes — o do CEP carrega uma dica embaixo do input, o do botão não —, e
   com `align-items:end` o que ficava lado a lado era a BASE das caixas: o botão
   descia ~13px e aparecia desalinhado do campo. Alinhando pelo topo, o rótulo
   em branco do botão ocupa a mesma altura do rótulo "CEP" (as duas regras de
   rótulo são a mesma, .field label/.field .label) e o botão cai exatamente na
   linha do input. */
.linha-cep { display: grid; grid-template-columns: 1fr auto; gap: 10px; align-items: start; }
.linha-cep .btn { min-height: 44px; }
/* Devolve altura ao rótulo vazio da coluna do botão (ver form.js): sem conteúdo
   o bloco mede ZERO e o botão sobe uma linha inteira. O \00a0 vem daqui, e não
   do JS, para não deixar caractere invisível no código-fonte. */
.linha-cep .label:empty::before { content: "\00a0"; }

.acoes-local, .acoes-foto { display: flex; gap: 8px; flex-wrap: wrap; }
.acoes-foto .btn { cursor: pointer; }

/* Prévia da foto anexada — antes não havia como conferir o que foi enviado. */
.foto-previa {
  border: 1px solid var(--line);
  border-radius: 10px;
  overflow: hidden;
  background: var(--bg);
}
.foto-previa[hidden] { display: none; }
.foto-previa img { width: 100%; max-height: 240px; object-fit: contain; display: block; background: #fff; }
.foto-previa-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 10px;
  font-size: 12px;
  color: var(--muted);
}

/* ---------- Alto contraste do portal --------------------------------------- */
/*
   O chrome aplica `html.a11y-contrast::after` — um overlay branco fixo com
   `mix-blend-mode: difference` em z-index 2147483000. Ele INVERTE tudo que estiver
   abaixo, inclusive tiles, marcadores e fotos (RESSALVAS.md §6.13).

   Decisão, item a item:

   - TILES: deixamos inverter. Vira um mapa escuro, que é um visual de alto contraste
     legítimo e aumenta o contraste dos pinos contra o fundo.
   - MARCADORES, LEGENDA E AMOSTRAS DE COR: pré-invertemos. As cores aqui são
     SEMÂNTICAS (cada tipo tem a sua, definida no seed); invertidas, "vermelho = grave"
     deixaria de valer. Como o overlay inverte de novo, elas voltam ao valor real.
   - FOTOS: pré-invertemos. Uma foto de alagamento invertida é ilegível.

   `filter: invert(1)` aplicado antes do blend resulta em invert(invert(x)) = x.
*/
html.a11y-contrast .pin .drop,
html.a11y-contrast .marker-cluster-idr div,
html.a11y-contrast .legend .dot,
html.a11y-contrast .chip .dot,
html.a11y-contrast .list-view .dot,
html.a11y-contrast .popup .swatch,
html.a11y-contrast .popup figure img {
  filter: invert(1);
}

/* ---------- Responsividade ------------------------------------------------- */

/* ---------- Painel recolhível ---------------------------------------------- */

.panel-toggle {
  display: none; /* só no mobile; no desktop há espaço para o painel aberto */
  align-items: center;
  gap: 6px;
  background: none;
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 6px 12px;
  min-height: 36px;
  font-family: var(--font-title);
  font-weight: 600;
  font-size: 12px;
  color: var(--navy);
  cursor: pointer;
}
.panel-toggle-seta {
  width: 0; height: 0;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-top: 6px solid currentColor;
  transition: transform 0.18s ease;
}
.panel-toggle[aria-expanded="false"] .panel-toggle-seta { transform: rotate(-90deg); }

/* ---------- Responsividade ------------------------------------------------- */

/* A barra empilha bem antes do celular: com o título por extenso, o selo e o botão
   do tempo, as 3 colunas já ficam apertadas por volta de 700 px. Empilhada, a ação
   continua CENTRALIZADA — a 3ª coluna some para não abrir vão à direita. */
@media (max-width: 700px) {
  /* Empilhada: a altura passa a ser ditada pelo conteúdo, não pelos 78 px. */
  .app-bar { grid-template-columns: 1fr; justify-items: center; text-align: center; gap: 10px; padding: 12px 16px; }
  .app-bar .wordmark { flex-wrap: wrap; justify-content: center; }
}

@media (max-width: 860px) {
  .legend { display: none; }

  /* O painel deixa de flutuar sobre o mapa e vira uma faixa presa ao topo:
     recolhido mostra só o cabeçalho, e o mapa fica inteiro visível. */
  .panel {
    position: absolute;
    top: 8px; left: 8px; right: 8px;
    width: auto;
    max-height: calc(100% - 16px);
    display: flex;
    flex-direction: column;
  }
  .panel-head { flex-wrap: wrap; padding: 10px 12px; }
  .panel-head h2 { font-size: 13px; }
  .panel-toggle { display: inline-flex; }
  .counter { flex: 1 1 100%; text-align: left; order: 3; }

  .panel-body { overflow: auto; }
  .panel.is-collapsed .panel-body { display: none; }
  .panel.is-collapsed { max-height: none; }

  /* RECOLHIDO = só o botão "Filtros", nada mais. Antes ficavam também o título
     "Ver ocorrências" e o contador, ocupando uma faixa inteira sobre o mapa.
     O painel encolhe para o tamanho do botão e solta o resto da largura. */
  .panel.is-collapsed { right: auto; width: auto; border-radius: 999px; }
  .panel.is-collapsed .panel-head {
    padding: 0;
    border-bottom: none;
    border-radius: 999px;
    justify-content: center;
    flex-wrap: nowrap;
  }
  .panel.is-collapsed .panel-head h2,
  .panel.is-collapsed .panel-head .counter { display: none; }
  .panel.is-collapsed .panel-toggle {
    border: none;
    padding: 0 18px;
    min-height: 44px; /* alvo de toque cheio */
    font-size: 13px;
  }

  /* Recolhido, o painel não pode capturar toques destinados ao mapa. */
  .panel.is-collapsed { pointer-events: auto; }

  /* Os controles do Leaflet ficam abaixo do painel recolhido. */
  .leaflet-top.leaflet-right { margin-top: 56px; }

  /* Chips e modos ganham área de toque maior no celular. */
  .modes { gap: 8px; }
  .chip { min-height: 38px; padding: 8px 12px; font-size: 12.5px; }
  .map-status { top: 64px; }
}

@media (max-width: 480px) {
  .app-bar .subtitle { display: none; }
  .grid2 { grid-template-columns: 1fr; }
  .drawer { width: 100vw; }

  .clima-lista { grid-template-columns: 1fr; }

  /* Formulário no celular: campos e ações ocupam a largura toda. */
  .linha-cep { grid-template-columns: 1fr; }
  .linha-cep .field:last-child .label { display: none; }
  .acoes-local .btn, .acoes-foto .btn { flex: 1 1 100%; justify-content: center; }
  .picker-map { height: 260px; }

  /* A lista textual vira cartões: tabela em 375 px é ilegível.
     O rótulo antes ficava colado no valor na mesma linha ("Bairro: Centro"), tudo
     no mesmo peso — dava um bloco cinza sem hierarquia. Agora o rótulo é uma
     etiqueta acima do valor, o Tipo vira o título do cartão e a descrição (até
     1000 caracteres) é limitada a 4 linhas para não esticar a página. */
  .list-view { padding: 14px 12px; }
  .list-view table, .list-view thead, .list-view tbody, .list-view tr, .list-view td { display: block; }
  .list-view thead { position: absolute; left: -9999px; }

  /* `display:block` na tabela tira o contexto de tabela do <caption>. O navegador
     então cria uma tabela ANÔNIMA só para ele, que encolhe para caber no conteúdo —
     e o texto saía uma palavra por linha, numa coluna de ~90 px. Virando bloco, a
     legenda volta a ocupar a largura toda. */
  .list-view caption { display: block; padding-bottom: 12px; }
  .list-view tr {
    border: 1px solid var(--line);
    border-radius: 12px;
    padding: 12px 14px;
    margin-bottom: 10px;
    display: grid;
    gap: 9px;
  }
  .list-view td { border: none; padding: 0; display: grid; gap: 3px; font-size: 13.5px; }
  .list-view td::before {
    content: attr(data-rotulo);
    font-family: var(--font-title);
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.5px;
    text-transform: uppercase;
    color: var(--muted);
  }

  /* Tipo: título do cartão, sem etiqueta, com o ponto colorido maior. */
  .list-view td:first-child { font-family: var(--font-title); font-size: 15px; font-weight: 600; }
  .list-view td:first-child::before { content: none; }
  .list-view .type-cell { gap: 9px; align-items: flex-start; }
  .list-view .dot { width: 12px; height: 12px; margin-top: 4px; }

  /* Bairro e Situação lado a lado: são curtos e caberiam sozinhos numa linha. */
  .list-view tr td:nth-child(2), .list-view tr td:nth-child(3) { display: inline-grid; }
  .list-view tr {
    grid-template-columns: 1fr 1fr;
  }
  .list-view td:first-child,
  .list-view td:nth-child(4),
  .list-view td:nth-child(5) { grid-column: 1 / -1; }

  /* A descrição é o texto longo do cartão: respira mais que os campos curtos. */
  .list-view td:nth-child(5) { line-height: 1.45; }

  .list-view .empty { border: none; display: block; grid-column: 1 / -1; }
  .list-view .empty::before { content: none; }
}

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

/* ---------- Painel de exportação (gestão) ---------------------------------- */

.export-painel {
  grid-column: 1 / -1;
  margin-top: 10px;
  padding: 14px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: #f7f9fc;
  display: grid;
  gap: 12px;
}
.export-painel[hidden] { display: none; }
.export-grupo { border: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.export-grupo legend {
  font-family: var(--font-title);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--muted);
  padding: 0 0 4px;
}
.export-aviso {
  margin: 0;
  font-size: 12.5px;
  color: var(--ink);
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 8px 10px;
}
.export-acoes { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }

/* =====================================================================
   CENTRO DE ALERTAS CLIMÁTICOS — banner do topo
   Cores escolhidas para contraste AA sobre o próprio fundo (texto escuro
   sobre pastel, não branco sobre saturado, que falha em tela clara).
   ===================================================================== */
/* Deixou de ser faixa permanente (2026-08-10): agora é o PAINEL do ícone da barra,
   irmão do painel do tempo. Some quando fechado, em vez de ocupar altura fixa
   dizendo "nenhum alerta" — que é o estado na maior parte do tempo. */
.ca{
  --ca-bg:#eef7f0; --ca-line:#bfe0c9; --ca-ink:#1d5233; --ca-selo:#2f7d4f;
  margin:0; border-bottom:1px solid var(--ca-line); background:var(--ca-bg); color:var(--ca-ink);
  box-shadow:0 10px 24px rgba(16,34,54,.12);
  animation:caEntra .28s ease both;
}
.ca[hidden]{ display:none; }
.ca:empty{ display:none; border:0; }
@keyframes caEntra{ from{ opacity:0; transform:translateY(-6px); } to{ opacity:1; transform:none; } }
@media (prefers-reduced-motion:reduce){ .ca,.ca *{ animation:none !important; transition:none !important; } }

.ca--atencao{   --ca-bg:#fff8e6; --ca-line:#f0dca6; --ca-ink:#6b4a00; --ca-selo:#8a6100; }
.ca--preventivo{--ca-bg:#fff1e2; --ca-line:#f3c99b; --ca-ink:#7a3d00; --ca-selo:#a35200; }
.ca--oficial{   --ca-bg:#fdecec; --ca-line:#f0b4b4; --ca-ink:#7d1620; --ca-selo:#b4121f; }

.ca__linha{ display:flex; align-items:center; gap:14px; max-width:1200px; margin:0 auto; padding:12px 20px; }
.ca__ic{ flex:0 0 auto; width:30px; height:30px; display:grid; place-items:center; border-radius:10px;
  background:rgba(255,255,255,.72); box-shadow:inset 0 0 0 1px var(--ca-line); }
.ca__ic svg{ width:19px; height:19px; }
.ca--oficial .ca__ic svg{ animation:caPulso 2.4s ease-in-out infinite; }
@keyframes caPulso{ 0%,100%{ transform:scale(1); } 50%{ transform:scale(1.12); } }

.ca__txt{ flex:1 1 auto; min-width:0; display:flex; flex-wrap:wrap; align-items:baseline; gap:4px 10px; }
.ca__selo{ font:700 .64rem/1 system-ui,sans-serif; letter-spacing:.08em; text-transform:uppercase;
  color:#fff; background:var(--ca-selo); padding:4px 9px; border-radius:999px; }
.ca__titulo{ font-size:1rem; font-weight:700; }
.ca__sub{ font-size:.86rem; opacity:.86; }
.ca__mais{ margin-left:8px; font-weight:700; }

.ca__btn{ flex:0 0 auto; display:inline-flex; align-items:center; gap:7px; cursor:pointer;
  background:rgba(255,255,255,.8); color:inherit; border:1px solid var(--ca-line); border-radius:999px;
  padding:8px 14px; font:600 .84rem system-ui,sans-serif; transition:background .16s ease, transform .16s ease; }
.ca__btn:hover{ background:#fff; transform:translateY(-1px); }
.ca__btn:focus-visible{ outline:3px solid var(--ca-selo); outline-offset:2px; }
.ca__btn svg{ width:15px; height:15px; transition:transform .2s ease; }
.ca.is-aberto .ca__btn svg{ transform:rotate(180deg); }

.ca__corpo{ max-width:1200px; margin:0 auto; padding:0 20px 16px; animation:caAbre .24s ease both; }
@keyframes caAbre{ from{ opacity:0; transform:translateY(-4px); } to{ opacity:1; transform:none; } }
.ca__item{ background:rgba(255,255,255,.72); border:1px solid var(--ca-line); border-radius:12px;
  padding:14px 16px; margin-top:10px; }
.ca__item-tit{ margin:0 0 8px; font-size:.98rem; display:flex; align-items:center; gap:9px; flex-wrap:wrap; }
.ca__tag{ font:700 .6rem/1 system-ui,sans-serif; letter-spacing:.07em; text-transform:uppercase;
  padding:4px 8px; border-radius:999px; background:rgba(0,0,0,.07); }
.ca__tag--oficial{ background:var(--ca-selo); color:#fff; }
/* Selo de simulação. Neutro de propósito — não deve competir com a severidade
   nem estragar uma apresentação — mas legível: é a única pista, para quem chega
   no site durante uma demonstração, de que aquele alerta não é para valer. */
.ca__tag--simulado{ background:rgba(0,0,0,.06); color:#42484f; border:1px dashed rgba(0,0,0,.28);
  text-transform:none; letter-spacing:.02em; font-weight:600; }

.ca__nota{ margin:12px 2px 0; font-size:.82rem; opacity:.88; line-height:1.5; }
.ca-det{ display:grid; grid-template-columns:repeat(auto-fit,minmax(210px,1fr)); gap:10px 22px; margin:0; }
.ca-det__item--full{ grid-column:1/-1; }
.ca-det dt{ font:700 .64rem/1 system-ui,sans-serif; letter-spacing:.07em; text-transform:uppercase; opacity:.72; }
.ca-det dd{ margin:3px 0 0; font-size:.9rem; line-height:1.5; }
.ca-det ul{ margin:3px 0 0; padding-left:18px; }
.ca-det li{ margin:2px 0; }

@media (max-width:720px){
  /* ★ A linha PRECISA quebrar aqui. O botão vira largura total logo abaixo e,
     num flex row com `nowrap`, ele não encolhe (flex:0 0 auto) — quem absorvia
     a sobra era o texto, que ia a ZERO: no celular o alerta aparecia sem
     título nenhum, só o ícone e um botão estourando a caixa. Com `wrap` o
     botão desce sozinho para a segunda linha (flex-basis:100%) e o texto
     recupera o espaço ao lado do ícone.
     A ordem é explícita porque `.ca__txt` já tinha `order:2` e, com o botão
     em `order` padrão (0), o texto era desenhado DEPOIS do botão. */
  .ca__linha{ align-items:flex-start; padding:11px 14px; gap:11px; flex-wrap:wrap; }
  .ca__ic{ order:1; }
  .ca__txt{ order:2; flex:1 1 auto; min-width:0; }
  .ca__btn{ order:3; flex:1 0 100%; width:auto; justify-content:center; margin-top:2px; }
  .ca__corpo{ padding:0 14px 14px; }
}

/* ---------- Fontes de monitoramento (faixa própria do mapa) ---------------- */

/* Fica ACIMA do rodapé do portal e é só deste mapa. Discreta de propósito: são
   as fontes que embasam o monitoramento, não patrocinadores. */
.fontes-mon {
  background: #fff;
  border-top: 1px solid var(--line);
  padding: 18px 16px 20px;
  text-align: center;
}
.fontes-mon[hidden] { display: none; }
.fontes-mon__tit {
  font-family: var(--font-title);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 14px;
}
.fontes-mon__lista {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 14px clamp(20px, 5vw, 44px);
}
.fontes-mon__lista a { display: inline-flex; align-items: center; }

/* Logos nas cores originais.
   Havia aqui um filtro que recolorava tudo para um cinza-azulado único, buscando
   coesão visual. Foi REMOVIDO: `brightness(0)` pinta de escuro TODOS os pixels
   opacos, e numa logo com fundo branco (JPEG não tem transparência) isso vira um
   retângulo cinza chapado — a logo só reaparecia no hover, onde o filtro saía.
   Era exatamente o sintoma relatado com o INMET.
   Como a faixa é branca, logo com fundo branco funde no fundo e fica limpa. */
/* Altura maior para as quadradas (CEMADEN, CHM, CENAD) não ficarem minúsculas ao
   lado do INMET, que é bem mais largo que alto. `max-width` segura o INMET para
   ele não dominar a faixa. */
.fontes-mon__lista img {
  height: 46px;
  width: auto;
  max-width: 130px;
  object-fit: contain;
  opacity: 0.85;
  transition: opacity 0.2s ease, transform 0.2s ease;
}
/* Logo cujo wordmark é BRANCO sobre transparência (Secretaria de Transição
   Climática): na faixa branca ela desapareceria por completo. Ganha o fundo
   escuro aqui, em vez de recolorirmos um brasão oficial — o arquivo enviado
   pela secretaria continua intacto. O respiro lateral evita que as letras
   encostem na borda do bloco. */
.fontes-mon__lista img.fontes-mon__chip {
  background: var(--navy, #0a2342);
  padding: 6px 10px;
  border-radius: 8px;
  max-width: 168px;
}
.fontes-mon__lista a:hover img,
.fontes-mon__lista a:focus-visible img {
  opacity: 1;
  transform: translateY(-2px);
}

@media (max-width: 560px) {
  .fontes-mon__lista img { height: 30px; }
}

/* ---------- Simulação de alerta (painel de gestão) ------------------------- */

/* Fica visualmente separado do resto: é ferramenta de teste que muda o SITE
   PÚBLICO, não um filtro. A borda tracejada sinaliza "área de laboratório". */
.simular {
  grid-column: 1 / -1;
  margin-top: 10px;
  padding: 14px;
  border: 1px dashed var(--line);
  border-radius: 12px;
  background: #fbfcfe;
}
/* Com teste no ar o painel inteiro fica marcado — quem abre a gestão vê na hora
   que existe um alerta falso publicado. */
.simular.is-ativo {
  border: 2px solid var(--cherry);
  border-style: solid;
  background: #fdecec;
}

.simular__topo { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; margin-bottom: 6px; }
.simular__tit {
  font-family: var(--font-title);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0;
}
.simular__estado { font-size: 12px; color: var(--muted); }
.simular.is-ativo .simular__estado { color: var(--cherry-700); font-weight: 700; }

.simular__aviso { margin: 0 0 12px; font-size: 12.5px; line-height: 1.45; color: var(--ink); }
.simular__acoes { display: flex; gap: 8px; flex-wrap: wrap; }

/* Preventivo (nosso) e oficial (INMET/Defesa Civil) são coisas diferentes para
   quem apresenta o sistema; separados, o painel conta essa diferença sozinho. */
.simular__grupo { margin-bottom: 12px; }
.simular__rotulo {
  display: block; margin-bottom: 6px;
  font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--muted);
}

/* Cada botão carrega a cor do próprio nível: o operador escolhe pela cor que vai
   ver no site, não pelo nome. */
.sim-btn { font-size: 13px; min-height: 38px; }
.sim-btn--atencao[aria-pressed="true"]    { background-color: #FFD166; border-color: #FFD166; color: #4A3300; }
.sim-btn--preventivo[aria-pressed="true"] { background-color: #E8801A; border-color: #E8801A; color: #fff; }
.sim-btn--oficial[aria-pressed="true"]    { background-color: #e21d2d; border-color: #e21d2d; color: #fff; }

/* =====================================================================
   FAIXA DE ALERTA — linha rolante logo abaixo da barra
   Mesma ideia do "Últimos eventos" do GPS: informação perecível passando
   sozinha, sem exigir clique. Discreta (altura pequena) porque o conteúdo
   da página é o mapa.
   ===================================================================== */
.fa{
  --fa-bg:#fff8e6; --fa-line:#f0dca6; --fa-ink:#6b4a00; --fa-selo:#8a6100;
  display:flex; align-items:stretch; gap:0;
  background:var(--fa-bg); color:var(--fa-ink);
  border-bottom:1px solid var(--fa-line);
  font-size:13px; line-height:1;
}
.fa[hidden]{ display:none; }
/* Sem alerta a faixa continua na tela, em verde: a AUSÊNCIA de risco também é
   informação, e some-la faria a faixa aparecer só em dia ruim — justamente
   quando um elemento novo no topo assusta. */
.fa--ok{       --fa-bg:#eef7f0; --fa-line:#bfe0c9; --fa-ink:#1d5233; --fa-selo:#2f7d4f; }
.fa--preventivo{ --fa-bg:#fff1e2; --fa-line:#f3c99b; --fa-ink:#7a3d00; --fa-selo:#a35200; }
.fa--oficial{   --fa-bg:#fdecec; --fa-line:#f0b4b4; --fa-ink:#7d1620; --fa-selo:#b4121f; }

.fa__selo{
  flex:0 0 auto; display:inline-flex; align-items:center;
  padding:0 12px; background:var(--fa-selo); color:#fff;
  font-family:var(--font-title,inherit); font-size:10.5px; font-weight:700;
  letter-spacing:.09em; text-transform:uppercase;
}
/* A janela recorta; o trilho é que anda. */
.fa__janela{ flex:1 1 auto; overflow:hidden; position:relative; height:30px; }
.fa__trilho{
  position:absolute; top:0; left:0; height:100%;
  display:flex; align-items:center; gap:0; white-space:nowrap;
  will-change:transform;
  animation:faRolar linear infinite;
}
/* -50% e exatamente uma das duas copias: o laco fecha sem salto. */
@keyframes faRolar{ from{ transform:translateX(0); } to{ transform:translateX(-50%); } }
.fa__texto{ padding:0 28px; font-weight:600; }

/* Pausa na leitura: quem passa o mouse (ou foca por teclado) consegue ler com calma. */
.fa:hover .fa__trilho, .fa:focus-within .fa__trilho{ animation-play-state:paused; }

/* Quem pediu menos movimento não recebe texto andando: vira uma linha estática,
   com reticências. A informação continua acessível no painel do Centro de Alertas. */
@media (prefers-reduced-motion:reduce){
  .fa__trilho{ animation:none; position:static; }
  .fa__texto:nth-child(2){ display:none; }
  .fa__janela{ display:flex; align-items:center; }
  .fa__texto{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
}
@media (max-width:640px){
  .fa{ font-size:12px; }
  .fa__selo{ padding:0 9px; font-size:9.5px; }
  .fa__janela{ height:26px; }
}
