/* ============================================================
   Terras Públicas — Globo 3D · HUD "sala de controle"
   Tokens: /terras/globo/css/styles.css (importado abaixo)
   Origem visual: documents/designs/orbit-veil_design_system.md
   Fundo quase-preto azulado + vidro escuro + acento ciano.
   ============================================================ */

/* Os tokens deixaram de morar aqui em 30/07/2026. Este arquivo tinha o PRIMEIRO
   dos três sistemas do projeto; agora consome o canônico. Tabela de-para, para
   quem procurar o nome antigo:

     --bg-deepest       → --color-void         --accent        → --accent (igual)
     --bg-panel  ┐      → --glass-fill         --accent-soft   → --accent-weak
     --panel-alpha┘       (os dois viraram um: o painel é vidro, não cor sólida)
     --border-glass     → --glass-stroke       --warning       → --caution
     --border-glass-soft→ --color-hairline     --danger        → --danger (igual)
     --text-primary     → --text-1             --success       → (removido: nunca
     --text-secondary   → --text-2                foi usado em regra nenhuma)
     --text-muted       → --text-3
     --hud-gap          → --space-3            --hud-radius    → --radius-lg
     --hud-pad-x/y      → --panel-pad          --z-globo/ficha → --z-globe/record

   Duas correções de nome minhas, de 29/07: `--z-globo` e `--z-ficha` estavam em
   português. A regra do sistema é token em inglês, interface em português — e a
   colisão que gerou tudo isto (--accent × --acento) é exatamente o que acontece
   quando as duas línguas são legais no mesmo lugar. */
@import url("/terras/globo/css/styles.css");

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html,
body {
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: var(--color-void);
  color: var(--text-1);
  font-family: var(--font-ui);
  font-size: 13px;
  line-height: 1.45;
}

/* A escala de empilhamento saiu deste arquivo em 30/07/2026 e mora em
   `/static/css/tokens/layers.css`, com o histórico do porquê (a ficha ficava em
   cima por ordem no DOM, não por decisão) e a nota sobre `--z-sheet`, o degrau
   reservado para a folha móvel que ainda não existe. */

/* ------------------------------------------------------------
   Canvas fullscreen: fica atrás de todo o HUD
   ------------------------------------------------------------ */
#globe-container {
  position: fixed;
  inset: 0;
  z-index: var(--z-globe);
}

#globe-container canvas {
  display: block;
}

/* ------------------------------------------------------------
   Painéis de vidro escuro: --glass-fill + blur + --glass-stroke
   ------------------------------------------------------------ */
.hud-panel {
  position: fixed;
  z-index: var(--z-hud);
  background: var(--glass-fill);
  -webkit-backdrop-filter: blur(var(--glass-blur));
  backdrop-filter: blur(var(--glass-blur));
  border: 1px solid var(--glass-stroke);
  border-radius: var(--radius-lg);
  padding: var(--panel-pad);
  pointer-events: auto;
}

/* Labels de HUD: caixa-alta, letter-spacing largo */
.hud-label,
.panel-title {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--text-3);
}

/* Valores/dados técnicos sempre em mono */
.mono {
  font-family: var(--font-mono);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------
   Status bar (topo, full-width): nome + resumo · itens · data · relógio · ?
   ------------------------------------------------------------ */
#statusbar {
  top: var(--space-3);
  left: var(--space-3);
  right: var(--space-3);
  display: flex;
  align-items: center;
  gap: 16px;
  min-height: 44px;
}

#statusbar .status-brand {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}

#statusbar .app-title {
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* Uma linha dizendo o que o app é. Sem ela, o globo abria sem nenhuma pista. */
#statusbar .app-subtitle {
  font-size: 11px;
  color: var(--text-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

#statusbar .app-title .title-accent {
  color: var(--accent);
}

#statusbar .status-spacer {
  flex: 1;
}

/* Relógio UTC em mono */
#statusbar .hud-clock {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Data dos dados. Ocupa o lugar do antigo badge "LIVE" pulsante — que dizia
   "ao vivo" sobre um cadastro baixado num dia e parado desde então. */
#statusbar .data-chip {
  padding: 3px 8px;
  border: 1px solid var(--glass-stroke);
  border-radius: 999px;
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-2);
  white-space: nowrap;
}

/* Botão "Ver em lista": alterna a visão em lista das mesmas áreas */
#statusbar .lista-btn {
  appearance: none;
  padding: 5px 12px;
  border: 1px solid var(--glass-stroke);
  border-radius: 999px;
  background: transparent;
  color: var(--text-2);
  font-family: var(--font-ui);
  font-size: 11px;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}

#statusbar .lista-btn:hover,
#statusbar .lista-btn.ativo {
  color: var(--accent);
  background: var(--accent-weak);
  border-color: var(--accent-line);
}

#statusbar .lista-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* Botão "?": reabre a explicação inicial a qualquer momento */
#statusbar .help-btn {
  appearance: none;
  width: 26px;
  height: 26px;
  flex: 0 0 auto;
  border: 1px solid var(--glass-stroke);
  border-radius: 50%;
  background: transparent;
  color: var(--text-2);
  font-family: var(--font-ui);
  font-size: 13px;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}

#statusbar .help-btn:hover {
  color: var(--accent);
  background: var(--accent-weak);
  border-color: var(--accent-line);
}

#statusbar .help-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* Contador de itens desenhados (mono) */
#statusbar .feature-count {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-3);
  white-space: nowrap;
}

/* ------------------------------------------------------------
   Focus bar (base-central): botões de presets de câmera
   ------------------------------------------------------------ */
/* ------------------------------------------------------------
   Barra de destaques — as 5 camadas mais procuradas (15/08/2026)

   Sobe 42 px sobre a barra de cidades, a mesma folga que a de cidades tem
   sobre o rodapé: as três faixas do rodapé passam a andar no mesmo ritmo
   vertical, em vez de cada uma escolher seu respiro.
   ------------------------------------------------------------ */
#destaques {
  left: 50%;
  bottom: calc(var(--space-3) + 34px + 42px);
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px;
  max-width: calc(100vw - 2 * var(--space-3));
  overflow-x: auto;
  scrollbar-width: none;
}

#destaques::-webkit-scrollbar { display: none; }

#destaques .destaques-rotulo {
  padding-left: var(--space-2);
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-3);
  white-space: nowrap;
}

#destaques .destaque-btn {
  appearance: none;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  border: 1px solid transparent;
  border-radius: 8px;
  background: transparent;
  color: var(--text-2);
  font-family: var(--font-ui);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.04em;
  padding: 7px 12px;
  cursor: pointer;
  white-space: nowrap;
  transition: color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
}

/* O ponto é a MESMA cor da camada no globo e no painel — é o que liga o botão
   à mancha sem ler rótulo nenhum. Por isso a cor não muda entre estados: o que
   muda é o preenchimento dele. */
#destaques .destaque-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  border: 1px solid var(--cor-camada);
  background: transparent;
  transition: background var(--dur-fast) var(--ease-out);
}

#destaques .destaque-btn:hover {
  color: var(--text-1);
  background: var(--color-hairline);
}

#destaques .destaque-btn[aria-checked='true'] {
  color: var(--text-1);
  border-color: var(--cor-camada);
}

#destaques .destaque-btn[aria-checked='true'] .destaque-dot {
  background: var(--cor-camada);
}

/* Camada grande demora a chegar. Sem sinal, o clique parece ignorado — e o
   segundo clique desliga o que a pessoa acabou de pedir. */
#destaques .destaque-btn.carregando .destaque-dot {
  animation: destaque-pulso 900ms var(--ease-out) infinite;
}

@keyframes destaque-pulso {
  0%, 100% { background: transparent; }
  50%      { background: var(--cor-camada); }
}

@media (prefers-reduced-motion: reduce) {
  #destaques .destaque-btn.carregando .destaque-dot { animation: none; opacity: .55; }
}

/* No celular a barra de cidades já rola sozinha; o rótulo sai para os cinco
   botões caberem sem competir com o mapa. */
@media (max-width: 640px) {
  #destaques .destaques-rotulo { display: none; }
}

#focusbar {
  left: 50%;
  bottom: calc(var(--space-3) + 34px); /* acima do footer HUD */
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px;
  /* A rolagem horizontal existia só no celular, e entre ~768 e ~850 px a barra
     transbordava e era CORTADA — com `overflow: hidden` no body, os atalhos das
     pontas ficavam inalcançáveis, sem barra de rolagem para revelá-los.
     Medido em 30/07 numa janela de 783 px: ia de -11 a 794. Passa a valer em
     qualquer largura; onde couber, não tem efeito nenhum. */
  max-width: calc(100vw - 2 * var(--space-3));
  overflow-x: auto;
  scrollbar-width: none;
}

#focusbar::-webkit-scrollbar { display: none; }

#focusbar .focus-btn {
  appearance: none;
  border: 1px solid transparent;
  border-radius: 8px;
  background: transparent;
  color: var(--text-2);
  font-family: var(--font-ui);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 7px 12px;
  cursor: pointer;
  white-space: nowrap;
  transition: color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}

#focusbar .focus-btn:hover {
  color: var(--text-1);
  background: var(--color-hairline);
}

/* Estado ativo: acento ciano — único lugar onde o ciano aparece em UI */
#focusbar .focus-btn.active,
#focusbar .focus-btn[aria-pressed="true"] {
  color: var(--accent);
  background: var(--accent-weak);
  border-color: var(--accent-line);
}

#focusbar .focus-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* Busca de município (ui/buscamunicipio.js): fica junto dos botões de foco,
   porque é a mesma pergunta — "para onde eu olho". Os botões dão 5 lugares;
   a busca dá os 853. */
#focusbar .busca-municipio {
  appearance: none;
  width: 168px;
  margin-left: 4px;
  padding: 7px 10px;
  border: 1px solid var(--glass-stroke);
  border-radius: 8px;
  background: var(--color-surface-1);
  color: var(--text-1);
  font-family: var(--font-ui);
  font-size: 11px;
  outline: none;
  transition: border-color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out), width var(--dur-base) var(--ease-out);
}

#focusbar .busca-municipio::placeholder { color: var(--text-3); }

#focusbar .busca-municipio:focus {
  width: 210px;
  border-color: var(--accent-line);
  background: var(--accent-weak);
}

#focusbar .busca-municipio:disabled {
  opacity: 0.5;
  cursor: progress;
}

/* Nome que não existe (ou ambíguo): a borda avisa, o title explica */
#focusbar .busca-municipio.busca-erro {
  border-color: var(--danger);
  background: var(--danger-weak);
}

/* ------------------------------------------------------------
   Zoom in/out (direita inferior, acima do footer): botões + / −
   ------------------------------------------------------------ */
#zoombar {
  right: var(--space-3);
  bottom: calc(var(--space-3) + 34px); /* acima do footer HUD */
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 6px;
}

#zoombar .zoom-btn {
  appearance: none;
  width: 34px;
  height: 34px;
  border: 1px solid var(--glass-stroke);
  border-radius: 8px;
  background: transparent;
  color: var(--text-2);
  font-family: var(--font-mono);
  font-size: 16px;
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}

#zoombar .zoom-btn:hover {
  color: var(--accent);
  background: var(--accent-weak);
  border-color: var(--accent-line);
}

#zoombar .zoom-btn:active {
  transform: translateY(1px);
}

#zoombar .zoom-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* ------------------------------------------------------------
   Ficha da área (esquerda inferior): propriedades + vista 2D
   ------------------------------------------------------------ */
#inspector {
  left: var(--space-3);
  bottom: calc(var(--space-3) + 34px); /* acima do footer HUD */
  min-width: 240px;
  max-width: 320px;
  max-height: 45vh;
  overflow-y: auto;
  padding: 12px 14px;
  display: none;
  /* Sobe um degrau: em tela estreita a ficha e o painel de camadas se
     sobrepõem, e quem está lendo a ficha quer a ficha. Ver a escala no topo —
     antes os dois eram 10 e a ordem no DOM decidia. */
  z-index: var(--z-record);
}

#inspector.visible { display: block; }

#inspector .inspector-title {
  font-family: var(--font-ui);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 8px;
  padding-right: 18px;
}

#inspector .inspector-close {
  position: absolute;
  top: 8px;
  right: 10px;
  appearance: none;
  border: none;
  background: transparent;
  color: var(--text-3);
  font-size: 16px;
  cursor: pointer;
}
#inspector .inspector-close:hover { color: var(--text-1); }

/* ⟲ 13/08: A FICHA ESTOURAVA A LARGURA DO PAINEL, relatado pelo dono com
   captura de tela do desktop. Causa: `table-layout` automático somado a
   `white-space: nowrap` na coluna do rótulo. Enquanto os campos eram curtos
   (`area_ha`, `nome`) ninguém via; quando entraram os avisos longos das
   camadas de CFEM e de cobertura — texto de várias linhas, e chave também
   comprida — a tabela cresceu para caber e vazou para fora da caixa.

   `table-layout: fixed` é o que faz o navegador respeitar a largura do
   painel em vez de dimensionar pelo conteúdo. E o rótulo passa a poder
   quebrar: `nowrap` ali fazia sentido para `area_ha`, não para
   `aviso_nao_somar_entre_municipios`. `overflow-wrap: anywhere` no valor
   cobre URL e código de processo, que não têm espaço onde quebrar. */
#inspector .inspector-table {
  width: 100%;
  table-layout: fixed;
  border-collapse: collapse;
  font-family: var(--font-mono);
  font-size: 11px;
}
#inspector .inspector-table td {
  padding: 3px 6px 3px 0;
  border-bottom: 1px solid var(--color-hairline);
  color: var(--text-2);
  vertical-align: top;
  overflow-wrap: anywhere;
}
#inspector .inspector-table td:first-child {
  color: var(--text-3);
  width: 38%;
}

/* Linha que explica de que camada é a área clicada */
#inspector .inspector-sub {
  font-size: 10px;
  line-height: 1.45;
  color: var(--text-3);
  margin: -4px 0 8px;
}

#inspector .inspector-actions {
  margin-top: 10px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  align-items: stretch;
}

/* "Focar nesta área": ação principal da ficha, por isso vem primeiro e cheia */
#inspector .btn-focar {
  appearance: none;
  padding: 8px 12px;
  border: 1px solid var(--accent-line);
  border-radius: 8px;
  background: var(--accent-weak);
  color: var(--accent);
  font-family: var(--font-ui);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out);
}
#inspector .btn-focar:hover { background: var(--accent-medium); }
#inspector .btn-focar:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* ---- "De onde vêm estes dados" (ui/proveniencia.js) ----
   Recolhido por padrão: a resposta honesta é comprida e quase ninguém quer lê-la
   sempre — mas quem quer precisa achar sem sair da tela. */
.prov {
  margin-top: 10px;
  padding-top: 8px;
  border-top: 1px solid var(--color-hairline);
  font-size: 10px;
}

.prov > summary {
  cursor: pointer;
  color: var(--text-2);
  font-weight: 600;
  letter-spacing: 0.04em;
  list-style: none;
}
.prov > summary::-webkit-details-marker { display: none; }
.prov > summary::before {
  content: "▸ ";
  color: var(--text-3);
}
.prov[open] > summary::before { content: "▾ "; }
.prov > summary:hover { color: var(--text-1); }

.prov-aviso,
.prov-lacuna,
.prov-vazio {
  margin-top: 8px;
  line-height: 1.5;
  color: var(--text-3);
}
.prov-lacuna { color: var(--caution); }

.prov-lista {
  margin: 8px 0 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 7px;
}

.prov-lista li {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding-left: 8px;
  border-left: 2px solid var(--glass-stroke);
}

.prov-lista strong {
  color: var(--text-2);
  font-weight: 600;
}

.prov-lista span {
  color: var(--text-3);
  word-break: break-word;
}

.prov-extra {
  font-family: var(--font-mono);
  font-size: 9px;
}

/* Coordenadas + botões de copiar (ui/rotulos.js → blocoDeCoordenadas).
   Monoespaçada porque coordenada se confere dígito a dígito, e fonte
   proporcional embaralha as colunas de números.
   Estas regras se repetem em /static/detalhe.html, que mostra a mesma ficha. */
#inspector .ficha-coord {
  margin-top: 10px;
  padding-top: 8px;
  border-top: 1px solid var(--color-hairline);
  font-size: 10px;
  line-height: 1.5;
}
#inspector .ficha-coord > strong { color: var(--text-1); }
/* Selo do ponto CALCULADO (rotulos.js → coordenadasDaArea, quando a fonte não
   traz ponto e ele sai do contorno). Mesma linguagem visual do selo FICTÍCIO
   (--caution: "ressalva, dado parcial") — este também é um aviso de origem
   do dado, só que sobre o PONTO, não sobre a área inteira. Sem ele, um par
   de coordenadas calculado aparece com a mesma cara de um vindo da fonte, e
   quem olha não tem como saber a diferença.
   ⟲ `border-radius` era 3px cravado aqui e `var(--radius-sm)` (4px) no MESMO
   selo em /static/detalhe.html — dois números pro mesmo elemento, com um
   comentário lá afirmando que os dois seguem a mesma regra. Unificado no
   token: é a mesma ficha nas duas telas (ver topo deste arquivo). */
#inspector .ficha-coord-calc {
  margin-left: 4px;
  padding: 1px 5px;
  border-radius: var(--radius-sm);
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 700;
  color: var(--color-surface-2);
  background: var(--caution);
  white-space: nowrap;
}
#inspector .ficha-coord dl {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 2px 10px;
  margin: 6px 0 0;
}
#inspector .ficha-coord dt { color: var(--text-3); white-space: nowrap; }
#inspector .ficha-coord dd {
  margin: 0;
  font-family: var(--font-mono);
  color: var(--text-2);
  /* Coordenada é para copiar à mão quando o botão falhar (http em rede local). */
  user-select: all;
}
#inspector .ficha-coord-botoes { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; }
#inspector .ficha-coord-botoes button {
  padding: 5px 9px;
  border: 1px solid var(--glass-stroke);
  border-radius: 7px;
  background: var(--color-surface-1);
  color: var(--text-2);
  font-size: 10px;
  font-weight: 600;
  cursor: pointer;
}
#inspector .ficha-coord-botoes button:hover:not(.copiado) { background: var(--accent-weak); color: var(--accent); }
#inspector .ficha-coord-nota { margin: 7px 0 0; color: var(--text-3); }
/* Só aparece quando a área de transferência recusa (http em rede local, ou
   navegador sem permissão). Ver ligarCopiar → mostrarParaSelecionar. */
#inspector .ficha-coord-manual {
  width: 100%;
  margin-top: 8px;
  padding: 6px;
  border: 1px solid var(--glass-stroke);
  border-radius: 6px;
  background: var(--color-void);
  color: var(--text-2);
  font-family: var(--font-mono);
  font-size: 10px;
  line-height: 1.45;
  resize: vertical;
}

/* A nota de "terra em uso" (ui/rotulos.js → notaDeUso). Fica logo abaixo da
   tabela, e NÃO no rodapé junto do aviso da camada: ela ensina a ler um número
   que está ali em cima, e um dado que aponta para dois lados opostos perde
   metade do sentido se a explicação estiver longe dele.
   Estas regras se repetem em /static/detalhe.html, que mostra a mesma ficha. */
#inspector .ficha-nota {
  margin-top: 10px;
  padding: 8px 10px;
  border-left: 2px solid var(--accent);
  border-radius: 0 6px 6px 0;
  background: var(--color-surface-1);
  font-size: 10px;
  line-height: 1.5;
  color: var(--text-2);
}
#inspector .ficha-nota strong { color: var(--text-1); }
#inspector .ficha-nota p { margin: 6px 0 0; }
#inspector .ficha-nota .ficha-nota-ressalva { color: var(--text-3); }

/* O aviso de leitura: "sem cadastro não quer dizer sem dono". Fica embaixo do
   botão porque é o que a pessoa precisa ler antes de sair contando a alguém. */
#inspector .inspector-aviso {
  margin-top: 10px;
  padding-top: 8px;
  border-top: 1px solid var(--color-hairline);
  font-size: 10px;
  line-height: 1.45;
  color: var(--caution);
}

/* "Ver de perto": ação secundária — abre outra aba, tira a pessoa do globo */
#inspector .btn-2d {
  display: block;
  padding: 7px 12px;
  border: 1px solid var(--glass-stroke);
  border-radius: 8px;
  background: var(--color-surface-1);
  color: var(--text-2);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-decoration: none;
  text-align: center;
}
#inspector .btn-2d:hover { color: var(--text-1); background: var(--color-hairline); }

/* ---- "Baixar esta área" (ui/exportar.js, via ui/inspector.js) ----
   Os mesmos três formatos do "Baixar" da lista (#lista .lista-exportar),
   mas para a área desta ficha só — sem isto, levar UM polígono clicado para
   um ofício exigia fechar a ficha, abrir a lista inteira e procurar a área
   de novo entre milhares de linhas.

   Três botões numa linha, e NÃO um botão com menu suspenso como o da lista:
   `#inspector` rola como bloco único (`overflow-y: auto` no próprio
   container, algumas regras acima) — um menu `position: absolute` aqui
   dentro nasceria cortado pela rolagem da ficha, não pela borda da tela. A
   lista escapa disso porque o cabeçalho dela fica FORA do trecho que rola
   (é `.lista-itens` que tem overflow, não `#lista`); a ficha não separa as
   duas coisas, e reestruturar o layout todo por um menu de três itens que já
   cabem numa linha não valeria o risco. Visual herdado de
   `.ficha-coord-botoes`, que já mora nesta mesma ficha — "Baixar" fica com a
   cara de "Copiar", não de um controle novo e estranho. */
#inspector .inspector-exportar {
  margin-top: 10px;
  padding-top: 8px;
  border-top: 1px solid var(--color-hairline);
  font-size: 10px;
  line-height: 1.5;
}
#inspector .inspector-exportar > strong { color: var(--text-1); }

#inspector .inspector-exportar-botoes { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; }
#inspector .inspector-exportar-botoes button {
  padding: 5px 9px;
  border: 1px solid var(--glass-stroke);
  border-radius: 7px;
  background: var(--color-surface-1);
  color: var(--text-2);
  font-size: 10px;
  font-weight: 600;
  cursor: pointer;
}
#inspector .inspector-exportar-botoes button:hover:not(:disabled) { background: var(--accent-weak); color: var(--accent); }
/* Camada FICTÍCIA desabilita o botão em vez de escondê-lo — mesma regra de
   #lista .lista-exportar-botao:disabled, e pelo mesmo motivo: um controle
   que some faz a pessoa procurar o que não está mais lá. */
#inspector .inspector-exportar-botoes button:disabled { opacity: 0.4; cursor: default; }

/* O que foi baixado — mesma lógica de #lista .lista-aviso: fica na tela por
   um tempo e depois some sozinho. */
#inspector .inspector-exportar-aviso {
  margin-top: 7px;
  color: var(--text-3);
}

/* ------------------------------------------------------------
   Painel de camadas (direita): toggles com dot de cor
   ------------------------------------------------------------ */
#layers-panel {
  top: calc(var(--space-3) + 56px);
  right: var(--space-3);
  /* 232px → 252px em 13/08. Com o marcador, o contador, o botão "?" e a chave
     na mesma linha, sobravam ~110 px para o nome e "Terra sem cadastro —
     detalhe de Curvelo" quebrava em quatro linhas — medido no navegador. Vinte
     pixels resolvem sem comer mapa: o painel flutua sobre o globo. */
  width: 252px;
  max-height: calc(100vh - 160px);
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* ------------------------------------------------------------
   Sanfona do painel — só no computador (15/08/2026)

   252 px é o que cabe sem comer mapa, mas os nomes que a seção de território
   ganhou não cabem: "Terra indígena/quilombola sob interesse minerário" e
   "Documentos do processo que citam o município" quebram em três e quatro
   linhas. Aos 340 px cabem em uma ou duas, e a seção volta a ser varrível de
   relance. Em vez de alargar para sempre (que come mapa o tempo todo), o
   painel cresce enquanto o ponteiro está nele — e volta ao sair.

   E o recolhido passa a ESPIAR: hoje `.collapsed` esconde tudo menos o
   cabeçalho, então quem recolhe para ver o mapa precisa clicar duas vezes para
   olhar uma camada. Com a espiada, recolher vira uma escolha barata — é o
   comportamento da barra lateral do Claude Desktop, e a razão é a mesma: o
   estado recolhido só é útil se sair dele não custar nada.

   ⚠️ Tudo isto vive dentro de `hover: hover` E `pointer: fine`, e não é
   detalhe. Em tela de toque o navegador dispara o hover no PRIMEIRO TOQUE: o
   painel cresceria no mesmo gesto que liga a camada, movendo o alvo debaixo do
   dedo. No celular o painel já é folha de largura cheia com abas
   (`@media (max-width: 767px)` mais abaixo), então não há o que alargar lá —
   quem manda no mobile é o clique da aba, como deve ser.

   `:focus-within` anda junto com `:hover` em todas as regras: quem chega às
   chaves por Tab não passa mouse nenhum, e ficaria preso na versão estreita,
   que é justamente a de leitura mais difícil.
   ------------------------------------------------------------ */
@media (hover: hover) and (pointer: fine) {
  #layers-panel {
    transition: width var(--dur-base) var(--ease-out);
  }

  #layers-panel:hover,
  #layers-panel:focus-within {
    width: 340px;
  }

  /* Recolhido + ponteiro em cima = espiada. Sai do jeito que entrou. */
  #layers-panel.collapsed:hover,
  #layers-panel.collapsed:focus-within {
    width: 340px;
  }

  #layers-panel.collapsed:hover .layer-groups,
  #layers-panel.collapsed:hover .regiao-filtro,
  #layers-panel.collapsed:hover .layer-bulk,
  #layers-panel.collapsed:focus-within .layer-groups,
  #layers-panel.collapsed:focus-within .regiao-filtro,
  #layers-panel.collapsed:focus-within .layer-bulk {
    display: flex;
  }
}

#layers-panel .panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--color-hairline);
}

/* Botão de colapso (usado no responsivo < 768px) */
#layers-panel .panel-collapse-btn {
  appearance: none;
  border: none;
  background: transparent;
  color: var(--text-3);
  font-family: var(--font-ui);
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  padding: 2px 6px;
  border-radius: 6px;
  transition: color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out);
}

#layers-panel .panel-collapse-btn:hover {
  color: var(--text-1);
  background: var(--color-hairline);
}

/* ============================================================
   PAINEL DE CAMADAS — dois eixos (ver ui/layerspanel.js)
   A lista agrupa por ASSUNTO; a região é um filtro à parte, acima dela.
   ============================================================ */

/* ---- Filtro de região: o segundo eixo, e ele tem de PARECER outro eixo ----
   Fica fora de `.layer-groups`, separado por uma linha, porque confundi-lo
   visualmente com um grupo de camadas seria repetir a confusão que a
   reorganização desfez — a pessoa achava que região era mais uma coisa para
   ligar. */
#layers-panel .regiao-filtro {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--color-hairline);
}

#layers-panel .regiao-filtro-titulo {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-3);
}

#layers-panel .regiao-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

#layers-panel .regiao-chip {
  appearance: none;
  padding: 4px 9px;
  border: 1px solid var(--glass-stroke);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--text-3);
  font-family: var(--font-ui);
  font-size: 11px;
  line-height: 1.2;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
}

#layers-panel .regiao-chip:hover {
  color: var(--text-1);
  background: var(--color-surface-1);
}

/* A região escolhida não se distingue SÓ por cor: fica preenchida, com peso
   maior e borda de acento. Três canais visuais, e o `aria-checked` no quarto,
   para quem ouve a tela. */
#layers-panel .regiao-chip[aria-checked="true"] {
  background: var(--accent-weak);
  border-color: var(--accent-line);
  color: var(--text-1);
  font-weight: var(--weight-semibold);
}

/* ---- Ligar tudo / Desligar tudo (13/08/2026) ---------------------------
   Mesma lógica visual do filtro de região: fora de `.layer-groups`, com
   linha própria, porque também não é "mais uma camada" — é uma ação sobre
   todas elas. Botões cheios (não outline como `.regiao-chip`) porque aqui
   não há estado ativo/inativo para marcar: é comando, não escolha. */
#layers-panel .layer-bulk {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--color-hairline);
}

#layers-panel .layer-bulk-btns {
  display: flex;
  gap: 6px;
}

#layers-panel .layer-bulk-btn {
  appearance: none;
  flex: 1;
  padding: 6px 8px;
  border: 1px solid var(--glass-stroke);
  border-radius: var(--radius-md);
  background: var(--color-surface-1);
  color: var(--text-2);
  font-family: var(--font-ui);
  font-size: 11px;
  font-weight: var(--weight-semibold);
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
}

#layers-panel .layer-bulk-btn:hover {
  color: var(--text-1);
  background: var(--accent-weak);
  border-color: var(--accent-line);
}

/* A ressalva sobre camadas pesadas puladas — mesma hierarquia visual de
   `.layer-nota-regiao`: informação real, não erro nem decoração. */
#layers-panel .layer-bulk-nota {
  margin: 0;
  font-family: var(--font-ui);
  font-size: 10px;
  line-height: 1.4;
  color: var(--text-3);
}

/* ---- Grupos de assunto ------------------------------------------------- */
#layers-panel .layer-groups {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

#layers-panel .layer-group-titulo {
  margin: 0 0 2px;
  padding: 0 6px;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-3);
}

#layers-panel .layer-list {
  display: flex;
  flex-direction: column;
  gap: 1px;
}

/* Camada cuja fonte está vazia HOJE (ver `vazia` no LAYER_REGISTRY): some com
   o brilho de "isto é uma opção viva" sem sumir da lista — a lacuna é o
   próprio achado (ex.: o INCRA não publica terras devolutas), não um defeito
   a esconder. */
#layers-panel .layer-row.layer-vazia { opacity: 0.6; }
#layers-panel .layer-row.layer-vazia .layer-count { font-style: italic; }
#layers-panel .layer-toggle:disabled { cursor: not-allowed; opacity: 0.5; }

/* Camada que o filtro de região deixou sem nenhuma fonte. Continua na lista,
   apagada: sumir faria a lista mudar de tamanho a cada troca de região e
   esconderia que a camada EXISTE. */
#layers-panel .layer-row.fora-do-filtro { opacity: 0.45; }

/* ---- A linha ------------------------------------------------------------
   COMPACTA, e essa é a mudança de 13/08: a explicação saiu da linha e foi para
   trás do botão "?". Antes cada linha carregava um parágrafo sempre visível, e
   dezenove deles eram uma parede de texto. Grid em vez de flex porque o bloco
   de explicação precisa ocupar a linha INTEIRA quando abre (`grid-column:
   1 / -1`), e não a coluna estreita do nome. */
#layers-panel .layer-row {
  display: grid;
  /* marca · ícone · nome (1fr) · contador · explicar · chave */
  grid-template-columns: auto auto 1fr auto auto auto;
  align-items: center;
  gap: 6px;
  padding: 4px 6px;
  border-radius: var(--radius-md);
  transition: background var(--dur-fast) var(--ease-out);
}

#layers-panel .layer-row:hover { background: var(--color-surface-1); }

/* A altura da linha É o alvo de toque agora — ver o comentário de
   `.layer-toggle::before`. 34 px cobre o piso de 32 px do ponteiro fino; no
   dedo sobe para 44 px, no bloco `@media (pointer: coarse)` que fecha esta
   seção. */
#layers-panel .layer-row { min-height: 34px; }

/* ---- O marcador: cor E FORMA -------------------------------------------
   O painel tinha catorze pontinhos redondos idênticos em catorze matizes, e o
   globo é a única tela do projeto inteiramente dependente de distinguir cor.
   A forma diz o que a camada é NO MAPA — área preenchida, ponto solto,
   contorno — e é informação verdadeira, não um código a decorar. Isso acaba
   com a dependência de cor? Não. Reduz: quem não separa os matizes tem nome,
   forma e contador. O que falta está relatado na entrega. */
#layers-panel .layer-marca {
  flex: 0 0 auto;
  width: 11px;
  height: 11px;
  background: var(--cor-camada, var(--accent));
  transition: transform var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-base) var(--ease-out);
}

/* Área = quadrado cheio (o preenchimento do polígono no globo). */
#layers-panel .layer-marca[data-forma="area"] { border-radius: 2px; }

/* Ponto = círculo menor, como o ponto no globo. Menor de propósito: a fonte
   publica uma localização, não um tamanho. */
#layers-panel .layer-marca[data-forma="ponto"] {
  width: 8px;
  height: 8px;
  border-radius: 50%;
}

/* Só contorno = quadrado VAZADO, que é literalmente o que se vê no mapa. */
#layers-panel .layer-marca[data-forma="linha"] {
  background: transparent;
  border: 2px solid var(--cor-camada, var(--accent));
  border-radius: 2px;
}

/* Satélite = losango, a única marca que não é dado de terra. */
#layers-panel .layer-marca[data-forma="satelite"] {
  width: 9px;
  height: 9px;
  rotate: 45deg;
  border-radius: 1px;
}

/* Brilho na camada LIGADA — pedido do dono, e aqui ele informa: distingue
   "ligada" de "desligada" por um canal a mais que a chave. Estático, sem
   pulsar: brilho que pisca em repouso vira ruído. */
#layers-panel .layer-row.on .layer-marca {
  box-shadow: 0 0 8px -1px var(--cor-camada, var(--accent));
}

/* ---- Ícone do conceito (13/08/2026, ver ui/icones.js) --------------------
   Coluna própria, ao lado do marcador — não no lugar dele. O marcador
   continua sendo a única pista de FORMA (área/ponto/linha); o ícone é
   reconhecimento de ASSUNTO à primeira vista, decorativo (`aria-hidden` no
   SVG — ver icones.js), nunca a única forma de identificar a linha. Herda
   `--cor-camada` do mesmo jeito que `.layer-marca`: a cor identifica O QUE a
   camada é, e o ícone não inventa uma segunda paleta por cima. */
#layers-panel .layer-icone {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 15px;
  height: 15px;
  color: var(--cor-camada, var(--text-3));
  /* Um degrau abaixo do texto ligado, um acima do apagado — o ícone marca
     presença sem competir com o nome pela atenção. */
  opacity: 0.75;
  transition: opacity var(--dur-fast) var(--ease-out);
}

#layers-panel .layer-row.on .layer-icone { opacity: 1; }

#layers-panel .layer-icone-svg {
  width: 100%;
  height: 100%;
}

#layers-panel .layer-text { min-width: 0; }

#layers-panel .layer-name {
  font-size: 12px;
  line-height: 1.3;
  color: var(--text-2);
  transition: color var(--dur-fast) var(--ease-out);
}

#layers-panel .layer-row.on .layer-name {
  color: var(--text-1);
  font-weight: var(--weight-semibold);
}

#layers-panel .layer-count {
  flex: 0 0 auto;
  max-width: 76px;
  font-family: var(--font-mono);
  font-size: 10px;
  line-height: 1.3;
  text-align: right;
  color: var(--text-3);
}

/* Camada que carregou vazia ou falhou: o contador vira palavra, não silêncio */
#layers-panel .layer-empty .layer-count { color: var(--caution); }
#layers-panel .layer-error .layer-count { color: var(--danger); }

/* Camada recortada pelo filtro: o número mostrado é menor que o do arquivo, e
   isso não pode passar como se fosse o total. O ponto avisa que há mais, e o
   `title` do contador diz quanto — escrito por `setStatus`. */
#layers-panel .layer-row.layer-recortada .layer-count::after {
  content: "•";
  margin-left: 3px;
  color: var(--accent);
}

/* ---- Botão "?" — a explicação sob demanda ------------------------------
   Não é tooltip e não depende de hover: é um botão de verdade, com
   `aria-expanded`, que abre o texto na própria linha. Funciona no dedo, no
   mouse e no Tab. */
#layers-panel .layer-explicar {
  appearance: none;
  position: relative;
  width: 17px;
  height: 17px;
  padding: 0;
  border: 1px solid var(--glass-stroke);
  border-radius: 50%;
  background: transparent;
  color: var(--text-3);
  font-family: var(--font-mono);
  font-size: 10px;
  line-height: 1;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
}

#layers-panel .layer-explicar:hover {
  color: var(--text-1);
  border-color: var(--accent-line);
  background: var(--accent-weak);
}

#layers-panel .layer-explicar[aria-expanded="true"] {
  color: var(--text-on-accent);
  background: var(--accent);
  border-color: var(--accent);
}

/* ⚠️ ESTA LINHA NÃO É REDUNDANTE. `hidden` esconde por `display: none` na
   folha do NAVEGADOR, que perde em especificidade para qualquer regra nossa
   com id + classe — e a regra logo abaixo declara `display: flex`. Sem isto, o
   `detalhe.hidden = true` do JS não escondia coisa nenhuma e as catorze
   explicações nasciam todas abertas, espremidas na coluna do nome. Foi
   exatamente o que apareceu na primeira montagem desta tela, no navegador. */
#layers-panel .layer-detalhe[hidden] { display: none; }

/* O bloco de explicação ocupa a linha inteira embaixo, não a coluna do nome:
   texto de 10 px espremido em ~120 px de largura seria pior que o de antes.
   Depende de o bloco ser filho DIRETO de `.layer-row` — ver ui/layerspanel.js. */
#layers-panel .layer-detalhe {
  grid-column: 1 / -1;
  margin-top: 4px;
  padding: 6px 8px;
  border-left: 2px solid var(--accent-line);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  background: var(--color-surface-1);
  display: flex;
  flex-direction: column;
  gap: 5px;
}

#layers-panel .layer-hint,
#layers-panel .layer-aviso,
#layers-panel .layer-nota-regiao {
  margin: 0;
  font-size: 10px;
  line-height: 1.45;
}

#layers-panel .layer-hint { color: var(--text-2); }

/* O aviso é a ressalva que impede a leitura errada do dado ("sem cadastro não
   quer dizer sem dono"). Cor de ressalva, e um símbolo antes do texto para não
   depender só dela. */
#layers-panel .layer-aviso { color: var(--caution); }
#layers-panel .layer-aviso::before {
  content: "⚠ ";
  font-weight: var(--weight-semibold);
}

/* A nota sobre o filtro de região: o que o recorte escolhido faz — ou deixa de
   fazer — com esta camada. É onde o painel confessa que a fonte não separa
   Jequitinhonha de Mucuri. */
#layers-panel .layer-nota-regiao {
  color: var(--text-3);
  font-style: italic;
}

/* ---- A chave ------------------------------------------------------------ */
#layers-panel .layer-toggle {
  appearance: none;
  position: relative;
  flex: 0 0 auto;
  width: 30px;
  height: 17px;
  border-radius: 999px;
  border: 1px solid var(--glass-stroke);
  background: var(--color-hairline);
  cursor: pointer;
  padding: 0;
  transition: background var(--dur-base) var(--ease-out), border-color var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out);
}

/* ---- ÁREA DE TOQUE, e por que NÃO com `[data-target]` --------------------
   Duas razoes, e a segunda é a séria.

   1. `tokens/targets.css` monta o alvo num `::after`, e o `::after` desta chave
      já é a bolinha do interruptor. Dois donos do mesmo pseudo-elemento e um
      dos dois some.

   2. ⚠️ O alvo de `[data-target]` cresce PARA FORA do elemento, sem teto. Isso
      funciona nos botões isolados da statusbar e do zoom, e QUEBRA numa lista
      densa: as linhas do painel têm ~28 px de passo, então dois alvos de 44 px
      empilhados se sobrepõem em ~16 px, e no trecho sobreposto quem ganha o
      clique é o último do DOM — tocar a chave de uma camada ligaria a de
      baixo. Um alvo grande que ativa a coisa errada é pior que um alvo
      pequeno.

   A saída é fazer a LINHA ter a altura do alvo e o alvo caber DENTRO dela: o
   piso de 44 px passa a ser cumprido pela própria linha, e o `::before` só
   estica até a borda dela. Sem sobreposição, e o piso do sistema respeitado.
   Medido no navegador depois da mudança — ver o relatório da entrega. */
#layers-panel .layer-toggle::before {
  content: "";
  position: absolute;
  /* 17 px de chave dentro de 34 px de linha: 8 px para cada lado fecham a
     altura da linha sem passar dela. Na largura, 30 + 2×7 = 44 px, e a
     sobreposição horizontal não existe — a chave é o último item da linha. */
  inset: -8px -7px;
}

@media (pointer: coarse) {
  /* No dedo a linha cresce para 44 px e o alvo cresce junto, ainda contido:
     17 + 2×13 = 43 px de altura dentro de uma linha de 44. */
  #layers-panel .layer-toggle::before { inset: -13px -7px; }
}

#layers-panel .layer-toggle::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: var(--text-3);
  transition: transform var(--dur-base) var(--ease-out), background var(--dur-base) var(--ease-out);
}

#layers-panel .layer-toggle[aria-checked="true"] {
  background: var(--accent-weak);
  border-color: var(--accent-line);
}

#layers-panel .layer-toggle[aria-checked="true"]::after {
  transform: translateX(13px);
  background: var(--accent);
}

/* ---- Camada de fixture --------------------------------------------------
   A marca tem de ser lida antes do nome da camada, não depois. Quem bate o
   olho no painel precisa saber que aquilo é inventado sem abrir nada. */
#layers-panel .layer-fake {
  margin-left: 6px;
  padding: 1px 5px;
  border-radius: 3px;
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.06em;
  color: var(--color-surface-2);
  background: var(--caution);
  vertical-align: middle;
}

#layers-panel .layer-fixture .layer-name,
#layers-panel .layer-fixture .layer-label { font-style: italic; }

/* ---- No dedo, tudo cresce ------------------------------------------------
   ⚠️ ESTE BLOCO FICA NO FIM DA SEÇÃO DE PROPÓSITO. `@media` não adiciona
   especificidade nenhuma: `@media (pointer: coarse) { .layer-explicar { ... } }`
   empata com `.layer-explicar { ... }`, e no empate ganha quem vem por último
   no arquivo. Numa primeira tentativa este bloco estava ANTES das regras base
   e o "?" continuava com 17 px no celular — medido em 375×812, `pointer:
   coarse` ativo e `--target-min: 44px`, e ainda assim 17×17. As linhas e os
   chips "funcionavam" só porque `min-height` não disputava com nada.

   O piso de 44 px do sistema (tokens/targets.css) vale para o dedo; aqui ele
   é cumprido pela ALTURA DA LINHA, e não por pseudo-elemento transbordando —
   ver o comentário de `.layer-toggle::before`. */
@media (pointer: coarse) {
  #layers-panel .layer-row { min-height: 44px; }
  #layers-panel .layer-explicar { width: 28px; height: 28px; font-size: 12px; }
  #layers-panel .regiao-chip { min-height: 36px; padding: 8px 12px; }
  #layers-panel .layer-bulk-btn { min-height: 36px; padding: 8px 12px; }
}

/* Estado colapsado: esconde os grupos E o filtro de região, mantendo só o
   cabeçalho. Era `.layer-list` — escondia as linhas mas deixava os títulos de
   seção boiando sem nada embaixo, e aquilo lê como painel quebrado, não como
   painel recolhido. O filtro entrou na regra em 13/08 pelo mesmo motivo: um
   painel "recolhido" que ainda mostra quatro chips de região não está
   recolhido. */
#layers-panel.collapsed .layer-groups,
#layers-panel.collapsed .regiao-filtro,
#layers-panel.collapsed .layer-bulk {
  display: none;
}

#layers-panel.collapsed {
  width: auto;
}

/* ------------------------------------------------------------
   Footer HUD (base, full-width): créditos de dados + FPS
   ------------------------------------------------------------ */
#footer-hud {
  left: var(--space-3);
  right: var(--space-3);
  bottom: var(--space-3);
  display: flex;
  align-items: center;
  gap: 16px;
  min-height: 30px;
  padding-top: 6px;
  padding-bottom: 6px;
}

#footer-hud .data-credits {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-3);
  letter-spacing: 0.04em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

#footer-hud .footer-spacer {
  flex: 1;
}

#footer-hud .fps-counter {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* ------------------------------------------------------------
   Visão em lista (ui/listapanel.js): as mesmas áreas, à esquerda.
   Escondida por padrão; o botão da barra de cima abre.
   ------------------------------------------------------------ */
#lista {
  top: calc(var(--space-3) + 56px);
  left: var(--space-3);
  width: 300px;
  max-height: calc(100vh - 260px);
  display: none;
  flex-direction: column;
  padding: 10px 6px 10px 12px;
  /* Mesma natureza da ficha: superfície transitória que o usuário abriu e
     fecha. Em 375 px a lista tem 300 px e cruza o painel de camadas. */
  z-index: var(--z-record);
}

#lista.visible { display: flex; }

#lista .lista-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 0 6px 8px 0;
  border-bottom: 1px solid var(--color-hairline);
}

#lista .lista-titulo {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-3);
}

#lista .lista-fechar {
  appearance: none;
  border: none;
  background: transparent;
  color: var(--text-3);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  padding: 0 4px;
}
#lista .lista-fechar:hover { color: var(--text-1); }

/* --- Baixar as áreas ------------------------------------------------------
   O botão fica no cabeçalho da lista porque o conjunto exportado É a lista.
   `margin-left: auto` empurra o par (baixar + fechar) para a direita sem
   disputar o `justify-content` com o título.
   ------------------------------------------------------------ */
#lista .lista-exportar {
  position: relative;
  margin-left: auto;
  /* Folga para o SLOP, não para o desenho. O `×` tem 17 px de largura e um alvo
     de 44 px centrado nele: o retângulo de toque transborda 13,5 px para cada
     lado. Com os 8 px de `gap` do cabeçalho, o slop do "Baixar" e o do `×` se
     cruzavam em 5,5 px — medido a 375 px — e um toque nessa faixa podia cair no
     botão errado. O glifo não muda; o espaço entre eles, sim. */
  margin-right: 8px;
}

#lista .lista-exportar-botao {
  appearance: none;
  background: transparent;
  border: 1px solid var(--color-hairline-strong);
  border-radius: var(--radius-sm);
  color: var(--text-2);
  font: inherit;
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 4px 8px;
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
}
#lista .lista-exportar-botao:hover:not(:disabled) {
  color: var(--text-1);
  border-color: var(--accent);
}
/* Com a lista vazia fica apagado, não some: controle que desaparece faz a
   pessoa procurar o que não sumiu. */
#lista .lista-exportar-botao:disabled {
  opacity: 0.4;
  cursor: default;
}

#lista .lista-menu {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  /* Acima da própria ficha: o menu é transitório e nasce de um clique
     deliberado; ficar por baixo de qualquer coisa o tornaria inalcançável. */
  z-index: var(--z-fallback);
  display: flex;
  flex-direction: column;
  min-width: 168px;
  padding: 4px;
  border: 1px solid var(--color-hairline-strong);
  border-radius: var(--radius-sm);
  /* Opaco, e não vidro: o menu abre sobre a própria lista, e texto sobre texto
     translúcido é o caso em que o scrim do sistema não salva. */
  background: var(--color-surface-1);
  box-shadow: var(--shadow-panel);
}
#lista .lista-menu[hidden] { display: none; }

#lista .lista-menu-item {
  appearance: none;
  background: transparent;
  border: none;
  color: var(--text-2);
  font: inherit;
  font-size: 12px;
  text-align: left;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
  /* Num menu vertical o item É o alvo, e por isso ele cresce de verdade em vez
     de contar com o slop do `::after`. Com 33,4 px desenhados (medido), o slop
     de 44 px transbordava 5,3 px para cada lado e os itens vizinhos, que são
     contíguos, se cruzavam em 10,6 px na vertical — um toque na fronteira podia
     baixar o formato errado. Aqui há espaço para crescer; na barra de 40 px do
     celular não haveria, e é por isso que os outros controles usam o slop. */
  display: flex;
  align-items: center;
  min-height: var(--target-min);
}
#lista .lista-menu-item:hover {
  background: var(--color-surface-2);
  color: var(--text-1);
}

/* O que foi baixado — e o que NÃO foi. Fica na tela, e não só dentro do
   arquivo: quando a camada fictícia é excluída, a contagem do arquivo difere
   da da tela, e é exatamente esse tipo de silêncio que deixou uma linha
   inventada passar por imóvel real. */
#lista .lista-aviso {
  margin: 6px 0 0;
  padding: 6px 8px;
  border-left: 2px solid var(--accent);
  background: var(--color-surface-2);
  border-radius: var(--radius-sm);
  color: var(--text-2);
  font-size: 11px;
  line-height: 1.45;
}
#lista .lista-aviso[hidden] { display: none; }

/* O viewport que rola. Virou um bloco simples (era `display:flex`) porque
   `.lista-itens-espaco` é o único filho de verdade agora (ver ui/listapanel.js,
   conserto de 12/08: janela deslizante em vez de 8.525 nós de uma vez). */
#lista .lista-itens {
  position: relative;
  overflow-y: auto;
  padding-right: 6px;
  margin-top: 6px;
}

/* O espaçador: sua altura é `entradas.length × PASSO_ESTIMADO`, calculada em
   JS — é isto que dá à barra de rolagem o tamanho da lista INTEIRA, mesmo com
   só umas dezenas de linhas de fato desenhadas. `position: relative` é o que
   faz o `top` de `.lista-itens-janela` (a seguir) contar a partir DELE, não
   da janela do navegador. */
#lista .lista-itens-espaco {
  position: relative;
}

/* O grupo com as linhas de fato renderizadas — só ELE ganha um `top` (em JS,
   `inicio × PASSO_ESTIMADO`); as linhas dentro ficam em fluxo normal
   (flex-column como antes do conserto), cada uma com a altura real do seu
   próprio texto. Não é linha-a-linha posicionada: `.lista-item-sub` varia de
   1 a 3 linhas conforme o resumo, e dar `top` fixo por linha exigiria uma
   altura só pra todas — ou cortava texto (perderia titularidade, que o
   projeto nunca omite), ou desperdiçava espaço nas 93% de linhas curtas. Ver
   o comentário grande no topo de ui/listapanel.js. */
#lista .lista-itens-janela {
  position: absolute;
  left: 0;
  right: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

#lista .lista-vazia {
  font-size: 11px;
  line-height: 1.5;
  color: var(--text-3);
  padding: 10px 4px;
}

#lista .lista-item {
  appearance: none;
  width: 100%;
  text-align: left;
  border: none;
  border-radius: 8px;
  background: transparent;
  padding: 7px 8px;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-family: var(--font-ui);
  transition: background var(--dur-fast) var(--ease-out);
}

#lista .lista-item:hover { background: var(--color-hairline); }
#lista .lista-item:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

#lista .lista-item-topo {
  display: flex;
  align-items: center;
  gap: 7px;
}

#lista .lista-dot {
  flex: 0 0 auto;
  width: 7px;
  height: 7px;
  border-radius: 50%;
}

#lista .lista-item-nome {
  flex: 1;
  min-width: 0;
  font-size: 12px;
  color: var(--text-1);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

#lista .lista-item-area {
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
}

#lista .lista-item-sub {
  font-size: 10px;
  line-height: 1.4;
  color: var(--text-3);
  padding-left: 14px;
}

#lista .lista-fake {
  margin-left: 6px;
  padding: 1px 5px;
  border-radius: 3px;
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 700;
  color: var(--color-surface-2);
  background: var(--caution);
}

/* ------------------------------------------------------------
   Cartão de abertura (ui/intro.js): o que é o mapa e como usar.
   Sobrepõe o globo na primeira visita; volta pelo "?" da barra de cima.
   ------------------------------------------------------------ */
#intro {
  position: fixed;
  inset: 0;
  z-index: var(--z-intro);
  display: none;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: var(--scrim-imagery);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
}

#intro.visible {
  display: flex;
}

#intro .intro-card {
  position: relative;
  width: min(560px, 100%);
  max-height: calc(100vh - 48px);
  overflow-y: auto;
  padding: 26px 28px 22px;
  background: var(--glass-fill-strong);
  border: 1px solid var(--glass-stroke);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-raised);
}

#intro .intro-title {
  font-size: 18px;
  font-weight: 700;
  letter-spacing: 0.01em;
  color: var(--text-1);
  margin-bottom: 12px;
}

#intro .intro-lead {
  font-size: 13px;
  line-height: 1.6;
  color: var(--text-2);
  margin-bottom: 10px;
}

#intro .intro-lead strong {
  color: var(--text-1);
  font-weight: 600;
}

#intro .intro-steps {
  margin: 14px 0 4px;
  padding-left: 20px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--text-2);
}

#intro .intro-steps strong {
  color: var(--text-1);
  font-weight: 600;
}

#intro .intro-nota {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--color-hairline);
  font-size: 11.5px;
  line-height: 1.55;
  color: var(--text-3);
}

#intro .intro-nota-fim {
  margin-top: 10px;
  padding-top: 0;
  border-top: none;
  font-size: 11px;
}
/* Link para /app/metodo. Sublinhado desde o repouso: dentro de um parágrafo de
   nota, cor sozinha não se lê como link — e esta é a porta para a página que
   diz o que o mapa NÃO prova, que é o que mais importa alguém achar. */
#intro .intro-link {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
}
#intro .intro-link:hover { color: var(--text-1); }

#intro .intro-btn {
  appearance: none;
  margin-top: 16px;
  padding: 9px 18px;
  border: 1px solid var(--accent-line);
  border-radius: 8px;
  background: var(--accent-weak);
  color: var(--accent);
  font-family: var(--font-ui);
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out);
}

#intro .intro-btn:hover {
  background: var(--accent-medium);
}

#intro .intro-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

#intro .intro-close {
  position: absolute;
  top: 12px;
  right: 14px;
  appearance: none;
  border: none;
  background: transparent;
  color: var(--text-3);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
}

#intro .intro-close:hover {
  color: var(--text-1);
}

/* ------------------------------------------------------------
   Fallback WebGL (plano §8: mensagem gentil, não tela preta)
   ------------------------------------------------------------ */
.webgl-fallback {
  position: fixed;
  inset: 0;
  z-index: var(--z-fallback);
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-void);
  color: var(--text-2);
  font-size: 14px;
  text-align: center;
  padding: 24px;
}

/* A barra de abas é criada por `ui/folha.js` em qualquer largura, mas só existe
   como superfície no celular — no desktop os dois painéis convivem lado a lado
   e não há o que alternar.

   ⚠️ Tem de vir ANTES do media query. Media query não soma especificidade: com
   as duas regras em `#sheet-tabs`, quem vem depois no arquivo ganha. Declarada
   depois, esta escondia a barra também no celular — e foi exatamente o que
   aconteceu na primeira medição. */
#sheet-tabs { display: none; }

/* ------------------------------------------------------------
   Responsivo básico (< 768px): painel de camadas colapsável,
   barras mais compactas
   ------------------------------------------------------------ */
@media (max-width: 767px) {
  body {
    font-size: 12px;
  }

  #statusbar {
    gap: 10px;
    min-height: 40px;
  }

  /* Espaço curto: fica o que orienta (nome, o que é o app, data dos dados e
     ajuda) e sai o que é acessório (contagem e relógio). */
  #statusbar .feature-count,
  #statusbar .hud-clock {
    display: none;
  }

  #statusbar .app-subtitle {
    font-size: 10px;
  }

  #intro .intro-card {
    padding: 22px 18px 18px;
  }

  /* ------------------------------------------------------------------
     UMA SUPERFÍCIE POR VEZ — a folha inferior de duas abas

     O painel de camadas tem 200 px e a ficha tem 320. Somam 520 numa tela de
     375: a sobreposição é ARITMÉTICA, não bug de empilhamento, e elevar a
     ficha por z-index só escolhia quem perdia (era o remendo de 29/07).

     Aqui os dois deixam de flutuar e passam a ser a MESMA folha, alternada
     pelas abas de `ui/folha.js` via `data-aba` no body. Duas superfícies não
     podem se sobrepor quando existe apenas uma — daí `--z-sheet` ser igual a
     `--z-hud`: não há o que arbitrar.

     `--sheet-max-h` (62vh) é o que mantém o globo visível e manipulável. Os
     gestos de arrastar e pinçar dependem de sobrar globo para pegar.

     A pilha vertical, de baixo para cima, escrita como cadeia para não haver
     número mágico: rodapé → atalhos de câmera → abas → folha. Cada degrau soma
     a altura do anterior. Medida no navegador depois de aplicar, não estimada.
     ------------------------------------------------------------------ */
  :root {
    --stack-footer: 30px;                                   /* #footer-hud */
    --stack-focus: calc(var(--stack-footer) + 44px);         /* #focusbar */
    --stack-tabs: calc(var(--stack-focus) + var(--space-1)); /* base de #sheet-tabs */
    /* Altura real da barra de abas, MEDIDA: 36 do alvo visual + 2×4 de padding
       + 2×1 de borda = 46. A primeira versão somava 44 e sobrava 2 px de
       sobreposição — pequena, e o tipo de coisa que só aparece medindo. */
    --tabs-h: 46px;
    --stack-sheet: calc(var(--stack-tabs) + var(--tabs-h) + var(--space-2));
  }

  #layers-panel,
  #inspector {
    top: auto;
    left: var(--space-3);
    right: var(--space-3);
    bottom: calc(var(--space-3) + var(--stack-sheet));
    width: auto;
    max-width: none;
    max-height: var(--sheet-max-h);
    z-index: var(--z-sheet);
    overflow-y: auto;
  }

  /* A aba escolhida decide quem ocupa a folha. `!important` porque
     `#inspector.visible` liga `display: block` e o inspetor não sabe da folha —
     e não deve saber: a folha é apresentação. */
  body[data-aba="area"] #layers-panel { display: none !important; }
  body[data-aba="camadas"] #inspector { display: none !important; }

  /* Barra de abas: só existe no celular. */
  #sheet-tabs {
    display: flex;
    gap: var(--space-1);
    left: var(--space-3);
    right: var(--space-3);
    bottom: calc(var(--space-3) + var(--stack-tabs));
    z-index: var(--z-sheet);
    padding: var(--space-1);
  }

  #sheet-tabs .sheet-tab {
    appearance: none;
    flex: 1;
    min-height: var(--target-visual);
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    background: transparent;
    color: var(--text-2);
    font-family: var(--font-ui);
    font-size: var(--text-meta);
    font-weight: var(--weight-semibold);
    cursor: pointer;
    transition: color var(--dur-fast) var(--ease-out),
                background var(--dur-fast) var(--ease-out);
  }

  #sheet-tabs .sheet-tab.ativa {
    color: var(--accent);
    background: var(--accent-weak);
    border-color: var(--accent-line);
  }

  /* Desabilitada de propósito enquanto não há área escolhida: a aba não pode
     levar a uma folha vazia. */
  #sheet-tabs .sheet-tab:disabled {
    color: var(--text-3);
    cursor: default;
  }

  #sheet-tabs .sheet-tab:focus-visible {
    outline: none;
    box-shadow: var(--shadow-focus);
  }

  /* A lista é a terceira superfície, e é modal: abre e fecha pelo mesmo botão
     da barra de topo. Ganha a geometria da folha e fica acima dela. */
  #lista {
    top: auto;
    left: var(--space-3);
    right: var(--space-3);
    bottom: calc(var(--space-3) + var(--stack-sheet));
    width: auto;
    max-height: var(--sheet-max-h);
    z-index: var(--z-record);
  }

  /* ⚠️ Bug pré-existente, achado ao medir os alvos de toque em 30/07: a
     zoombar fica no canto inferior direito (48 px de largura) e a barra de
     atalhos, centrada e ocupando a largura toda, passava POR BAIXO dela. O
     botão da ponta direita — "Pompéu" na configuração atual — não recebia
     clique nenhum: quem estava por cima naquele recorte era a zoombar.
     Aqui a barra deixa de ser centrada e passa a reservar o espaço da zoombar.
     Continua rolando na horizontal, então nenhum atalho fica inalcançável. */
  #focusbar {
    left: var(--space-3);
    right: calc(var(--space-3) + 48px + var(--space-2));
    transform: none;
    bottom: calc(var(--space-3) + 30px);
    max-width: none;
    overflow-x: auto;
    scrollbar-width: none;
  }

  #focusbar::-webkit-scrollbar {
    display: none;
  }

  #focusbar .focus-btn {
    padding: 6px 9px;
    font-size: 10px;
  }

  #footer-hud .data-credits {
    font-size: 9px;
  }
}

/* Scrollbar discreta para painéis com overflow */
.hud-panel::-webkit-scrollbar {
  width: 6px;
}

.hud-panel::-webkit-scrollbar-thumb {
  background: var(--glass-stroke);
  border-radius: 3px;
}

.hud-panel::-webkit-scrollbar-track {
  background: transparent;
}

/* ------------------------------------------------------------
   Alvo de toque: 44 px sem redesenhar ícone nenhum

   Eram 28 dos 32 controles com 26 px de lado — medido em 30/07/2026. Crescer o
   glifo não é opção: na barra de 40 px do celular não cabe. Então o desenho
   fica como está e a ÁREA cresce por fora, com o `::after` de
   `tokens/targets.css`, que transborda para o canvas do globo — inerte naquele
   recorte, porque o clique volta para o botão.

   Os seletores estão listados aqui, e não como `data-target` no HTML, de
   propósito: seriam seis arquivos de JS a tocar para adicionar um atributo que
   o CSS já sabe onde aplicar. `tokens/targets.css` continua genérico e este
   bloco é a aplicação no projeto.

   Em `pointer: fine` o piso cai para 32 px (`--target-min` no media query do
   token) — a regra de 44 px é do dedo, não do mouse.
   ------------------------------------------------------------ */
#statusbar .help-btn,
#statusbar .lista-btn,
#focusbar .focus-btn,
#zoombar .zoom-btn,
#inspector .inspector-close,
#lista .lista-fechar,
#lista .lista-exportar-botao,
#layers-panel .panel-collapse-btn,
#sheet-tabs .sheet-tab,
.ficha-coord-botoes button {
  position: relative;
}

#statusbar .help-btn::after,
#statusbar .lista-btn::after,
#focusbar .focus-btn::after,
#zoombar .zoom-btn::after,
#inspector .inspector-close::after,
#lista .lista-fechar::after,
#lista .lista-exportar-botao::after,
#layers-panel .panel-collapse-btn::after,
#sheet-tabs .sheet-tab::after,
.ficha-coord-botoes button::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  translate: -50% -50%;
  min-width: var(--target-min);
  min-height: var(--target-min);
  width: 100%;
  height: 100%;
}

/* ⚠️ A folha inteira é rolável e os atalhos de câmera rolam na horizontal. O
   slop não pode virar barreira de rolagem, então ele não captura o gesto —
   só o toque. */
#focusbar .focus-btn::after { touch-action: pan-x; }

/* ============================================================
   Microinterações — 30/07/2026

   Regra que governa tudo aqui: **movimento e brilho carregam significado, ou
   não entram.** Este app existe para qualificar, não para persuadir; uma
   interface que brilha mais do que o dado sustenta mente pelo tom.

   Duas coisas que NÃO foram feitas, e por quê:

   · **Pulso no selo de data.** É exatamente o que o projeto removeu de
     propósito — o antigo badge "LIVE" pulsante dizia "ao vivo" sobre um
     cadastro baixado num dia e parado desde então. Pulso ali volta a mentir.
     Pulso só sobrou onde a coisa é de fato viva: os satélites, cuja posição é
     calculada em tempo real, e o estado de carregando, onde algo está mesmo
     acontecendo.

   · **Glow decorativo.** O sistema veta gradiente e brilho de enfeite ("a
     imagem é o dado"). Glow aqui é só sinal de ESTADO — foco de teclado e
     hover — e nunca fica ligado em repouso.

   Tudo abaixo anima apenas `opacity`, `transform`, `box-shadow` e
   `background-color`: compostas na GPU, sem reflow, sem deslocamento de
   layout. As durações vêm de `tokens/motion.css`, que zera todas sob
   `prefers-reduced-motion` — então nenhuma regra daqui precisa de media query
   própria: o estado final é sempre o mesmo, só desaparece o trajeto.
   ============================================================ */

/* ---- Glow de foco: o público usa teclado -------------------------------
   O sistema pede foco sempre visível, inclusive no mouse. O `outline: 2px`
   que estava nos controles é abrupto e não anima; `--shadow-focus` é um anel
   duplo que cresce do próprio botão.

   ⚠️ Esta lista é NOMINAL, e é a armadilha dela: controle novo não herda nada,
   cai no `outline` padrão do navegador e sai do sistema sem ninguém notar.
   Foi o que aconteceu com os dois controles criados em 13/08 — o "?" de cada
   linha e os chips de região. Medido no navegador, com Tab de verdade: o "?"
   recebia `outline: auto 1px rgb(229,151,0)`, o laranja do Chrome, sobre o
   vidro escuro do painel. Entraram na regra. Quem acrescentar o próximo
   controle ao painel acrescenta aqui também — foi o caso de
   `.layer-bulk-btn` (Ligar/Desligar tudo), no mesmo dia. */
#statusbar .lista-btn:focus-visible,
#statusbar .help-btn:focus-visible,
#focusbar .focus-btn:focus-visible,
#zoombar .zoom-btn:focus-visible,
#layers-panel .layer-toggle:focus-visible,
#layers-panel .layer-explicar:focus-visible,
#layers-panel .regiao-chip:focus-visible,
#layers-panel .panel-collapse-btn:focus-visible,
#layers-panel .layer-bulk-btn:focus-visible,
#inspector .inspector-close:focus-visible,
#inspector .btn-focar:focus-visible {
  outline: none;
  box-shadow: var(--shadow-focus);
}

/* ---- Hover dos controles: clareia o preenchimento, nunca muda o matiz ---- */
#statusbar .help-btn:hover,
#statusbar .lista-btn:hover,
#zoombar .zoom-btn:hover {
  box-shadow: 0 0 0 1px var(--accent-line), 0 4px 16px -6px var(--accent-medium);
}

/* Press não encolhe: encolher em mapa desloca o dedo do alvo (regra do
   sistema). Escurece e afunda 1px, que é o feedback sem mover o alvo. */
#statusbar .help-btn:active,
#statusbar .lista-btn:active,
#focusbar .focus-btn:active,
#zoombar .zoom-btn:active,
#sheet-tabs .sheet-tab:active {
  background: var(--accent-medium);
  translate: 0 1px;
}

/* ---- A linha da camada em realce ---------------------------------------
   Espelha no painel o que `ui/realce.js` faz no globo: a mesma camada acende
   nos dois lugares ao mesmo tempo, o que é o que amarra a lista ao mapa.

   Desde 13/08 vale também para o TECLADO: `realce.js` põe `.em-realce` no
   `focusin` da linha, não só no `pointerover`. Era o único jeito de responder
   "qual mancha é qual?" sem enxergar a diferença de matiz, e estava atrás do
   mouse — fechado para teclado e para toque. */
#layers-panel .layer-row {
  transition: background var(--dur-fast) var(--ease-out);
}

#layers-panel .layer-row.em-realce {
  background: var(--accent-weak);
}

/* O marcador é o identificador da camada. No realce ele ganha um anel da
   PRÓPRIA cor da camada, então o anel nunca contradiz a legenda. */
#layers-panel .layer-marca {
  transition: transform var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-base) var(--ease-out);
}

#layers-panel .layer-row.em-realce .layer-marca {
  transform: scale(1.35);
  /* `--cor-camada` vem inline de ui/layerspanel.js, com o mesmo valor do
     fundo do marcador. Aqui NÃO serve `currentColor`: ele resolve para a cor
     de texto herdada, quase branca, e o anel saía branco — medido em 30/07.
     Legenda que muda de cor no realce mente sobre a camada. */
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--cor-camada, var(--accent)) 30%, transparent),
              0 0 12px -2px var(--cor-camada, var(--accent));
}

/* ---- Carregando: pulso honesto — algo ESTÁ acontecendo ----------------
   `.carregando` é posto por `layerspanel.setCarregando()`, que o main.js liga
   ao ligar as fontes de um conceito e desliga quando todas responderam. A
   espera é real e mensurável: a maior fonte do mapa leva 398 ms só de rede +
   parse + geometria em servidor local, e mais que isso em rede móvel. */
@keyframes tp-respirar {
  0%, 100% { opacity: 0.35; }
  50%      { opacity: 1; }
}

#layers-panel .layer-row.carregando .layer-marca {
  animation: tp-respirar 1.4s var(--ease-in-out) infinite;
}

/* ---- Acabou de ligar: um pulso, uma vez -------------------------------
   O pedido era "pulso quando a camada termina de carregar", e o valor dele é
   fechar o ciclo: a chave respondeu, o dado chegou, ISTO aqui é o que apareceu
   no globo. Uma vez só — confirmação que fica pulsando deixa de ser
   confirmação e vira ruído (mesma regra do anel de "copiado"). A classe é
   removida por tempo em `layerspanel.js`, e não no `animationend`: com
   `prefers-reduced-motion` a animação não roda e o evento nunca chegaria. */
@keyframes tp-acendeu {
  0%   { box-shadow: 0 0 0 0 var(--cor-camada, var(--accent)); }
  40%  { box-shadow: 0 0 0 6px color-mix(in oklab, var(--cor-camada, var(--accent)) 40%, transparent); }
  100% { box-shadow: 0 0 8px -1px var(--cor-camada, var(--accent)); }
}

#layers-panel .layer-row.acabou-de-ligar .layer-marca {
  animation: tp-acendeu var(--dur-slow) var(--ease-out) 1;
}

/* ---- A explicação entra de leve --------------------------------------
   Animação de entrada e não transição de altura: o bloco é escondido com o
   atributo `hidden`, de forma síncrona, porque estado de acessibilidade não
   pode depender de um `transitionend` que sob movimento reduzido talvez nem
   dispare. Ver o comentário em ui/layerspanel.js. */
#layers-panel .layer-detalhe:not([hidden]) {
  animation: tp-entrar var(--dur-base) var(--ease-out) 1;
}

/* ---- Satélites: o único pulso permanente, e é legítimo ----------------
   A camada diz "posição calculada em tempo real", e é verdade: o SGP4 roda a
   cada frame. Aqui o pulso descreve o dado em vez de decorar a tela. */
#layers-panel .layer-row[data-camada-id="satelites-orbita"].on .layer-marca {
  animation: tp-respirar 2.6s var(--ease-in-out) infinite;
}

/* ---- FICTÍCIO: a marca que não pode passar batida -------------------- */
#layers-panel .layer-fake {
  position: relative;
  overflow: hidden;
  isolation: isolate;
}

/* A hachura de --fiction-hatch desliza atrás do texto. Move-se por
   `translate` num pseudo-elemento, não por `background-position`, para o
   navegador compor na GPU em vez de repintar. Devagar de propósito: chama o
   olho sem competir com a leitura. */
#layers-panel .layer-fake::before {
  content: "";
  position: absolute;
  inset: -50% -100%;
  z-index: var(--z-under-content);
  background: var(--fiction-hatch);
  animation: tp-hachura 3.2s linear infinite;
}

@keyframes tp-hachura {
  from { translate: 0 0; }
  to   { translate: 17px 0; }   /* = um período da hachura de 45°, 6+12px */
}

/* ---- Confirmação de cópia: o momento que merece um instante ------------
   Copiar coordenada para levar a um cartório ou a um pedido de LAI é o gesto
   mais consequente desta interface. Merece confirmação inequívoca — e a
   inequívoca é o próprio botão dizer que copiou, não um aviso longe dele. */
/* ⚠️ O `#inspector` é obrigatório aqui, e não é excesso: a regra de repouso é
   `#inspector .ficha-coord-botoes button` (1 id + 1 classe + 1 tipo), então
   `.ficha-coord-botoes button.copiado` — só 2 classes — PERDE. Medido em
   30/07: o ✓ e o anel apareciam mas o fundo não mudava. O segundo seletor
   cobre `/app/detalhe`, que usa o mesmo bloco sem o id. */
#inspector .ficha-coord-botoes button.copiado,
.ficha-coord-botoes button.copiado {
  color: var(--text-on-accent);
  background: var(--accent);
  border-color: var(--accent);
}

.ficha-coord-botoes button.copiado::before {
  content: "✓ ";
  font-weight: var(--weight-semibold);
}

/* O anel se expande UMA vez e some. Sem loop: confirmação que fica pulsando
   deixa de ser confirmação e passa a ser ruído. */
@keyframes tp-anel {
  from { box-shadow: 0 0 0 0 var(--accent-medium); }
  to   { box-shadow: 0 0 0 14px transparent; }
}

#inspector .ficha-coord-botoes button.copiado,
.ficha-coord-botoes button.copiado {
  animation: tp-anel var(--dur-slow) var(--ease-out) 1;
}

/* ---- A ficha entra deslizando o mínimo ------------------------------- */
@keyframes tp-entrar {
  from { opacity: 0; translate: 0 8px; }
  to   { opacity: 1; translate: 0 0; }
}

#inspector.visible,
#lista.visible {
  animation: tp-entrar var(--dur-base) var(--ease-out) 1;
}

/* Trocar de aba na folha é troca de conteúdo, não entrada nova: só o fade,
   sem deslize, senão a folha "salta" a cada toque. */
@keyframes tp-trocar {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@media (max-width: 767px) {
  body[data-aba] #layers-panel,
  body[data-aba] #inspector {
    animation: tp-trocar var(--dur-fast) var(--ease-out) 1;
  }
}

/* ============================================================
   MOVIMENTO REDUZIDO — o que os tokens NÃO alcançam
   ============================================================
   O cabeçalho deste bloco afirma, desde 12/08, que "as durações vêm de
   tokens/motion.css, que zera todas sob `prefers-reduced-motion` — então
   nenhuma regra daqui precisa de media query própria".

   ⟲ Isso era verdade para as transições e para as animações de um disparo,
   que usam `var(--dur-*)`. NÃO era verdade para as três animações INFINITAS
   deste arquivo, cujas durações são literais (1.4s, 2.6s, 3.2s) e portanto
   não passam por token nenhum: `tp-respirar` no marcador que carrega,
   `tp-respirar` no marcador dos satélites e `tp-hachura` no selo FICTÍCIO.
   As três continuavam girando para sempre para quem pediu menos movimento.

   Num portal cujo tema é acessibilidade isso não é detalhe: animação em laço
   na periferia da visão é exatamente o que causa enjoo e dor de cabeça em
   quem tem sensibilidade vestibular ou enxaqueca.

   O estado final é preservado em todos os casos — o marcador dos satélites
   fica aceso, não apagado, e o selo FICTÍCIO mantém a hachura parada. O que
   some é o movimento, não a informação. */
@media (prefers-reduced-motion: reduce) {
  /* A sanfona continua funcionando — só para de deslizar. Quem pediu menos
     movimento quer menos ANIMAÇÃO, não menos função: tirar o alargamento
     junto devolveria a essa pessoa a versão estreita, que é a pior de ler. */
  #layers-panel { transition: none; }

  #layers-panel .layer-row.carregando .layer-marca,
  #layers-panel .layer-row[data-camada-id="satelites-orbita"].on .layer-marca,
  #layers-panel .layer-fake::before {
    animation: none;
  }

  /* O marcador que estaria pulsando fica na opacidade cheia: "carregando" passa
     a ser dito só pelo contador, em palavras, que é onde ele já estava dito. */
  #layers-panel .layer-row.carregando .layer-marca { opacity: 1; }
}

/* ------------------------------------------------------------
   Dica ao pousar o mouse numa área (15/08/2026) — ui/dica.js

   Não é `.hud-panel`: os painéis do HUD são ancorados nos cantos e têm o
   vidro e a borda da moldura. Esta segue o ponteiro e precisa ser lida em
   cima de qualquer coisa que esteja embaixo, inclusive imagem de satélite —
   daí o fundo mais opaco que o do resto do HUD.

   `pointer-events: none` é obrigatório, não estético: a dica nasce a 14 px do
   ponteiro, e sem isso ela roubaria o `pointermove` do canvas no instante em
   que aparecesse, disparando `pointerleave` e apagando a si mesma. Um
   piscar infinito.
   ------------------------------------------------------------ */
#dica {
  position: fixed;
  z-index: 40;
  max-width: 22rem;
  padding: 8px 11px;
  border: 1px solid var(--cor-camada, var(--color-hairline));
  border-left-width: 3px;
  border-radius: 6px;
  background: color-mix(in oklab, var(--color-base) 92%, transparent);
  backdrop-filter: blur(6px);
  box-shadow: 0 6px 20px rgb(0 0 0 / 0.35);
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--dur-fast) var(--ease-out);
}

#dica.visivel { opacity: 1; }

#dica .dica-titulo {
  display: block;
  font-family: var(--font-ui);
  font-size: 12px;
  font-weight: 600;
  color: var(--text-1);
  line-height: 1.3;
}

#dica .dica-corpo {
  display: block;
  margin-top: 3px;
  font-family: var(--font-ui);
  font-size: 11.5px;
  line-height: 1.45;
  color: var(--text-2);
}

@media (prefers-reduced-motion: reduce) {
  #dica { transition: none; }
}
