html,body{height:100%;margin:0;padding:0;}
:root{
  /* ── PALETA DO SafeSP - consolidada em 24/08/2026 ──────────────────────
     A regra da direcao A: SE UMA COR NAO SIGNIFICA NADA, ELA SAI.
     Eram 31 cores espalhadas por 4 arquivos que nao conversavam.
     ------------------------------------------------------------------ */

  /* FUNDOS - do mais fundo para o mais proximo */
  --bg:#060c1a;        /* o fundo de tudo */
  --card:#0d1526;      /* cartoes e barras */
  /* 20/09 (RT-318, D11): --panel:#0a1628 SAIU. Zero ocorrencias de var(--panel)
     em app.css, app.js e em qualquer .html (grep de 20/09). Nunca foi pintado. */
  --border:#1a2a45;    /* linha de separacao */

  /* TEXTO - dois niveis, e nao tres.
     O terceiro (--dim, #4a6080) foi REMOVIDO em 24/08 porque REPROVAVA em
     contraste: 2,83:1 sobre o painel, quando o minimo do WCAG AA e 4,5:1.
     Era o mesmo 2,82 que a auditoria M07 tinha apontado em 23/08. Ele
     aparecia em 11 lugares, incluindo a barra de estado do rodape. */
  --text:#c4cfe0;      /* texto normal   - 11,58:1 sobre --card */
  --muted:#7a91b5;     /* texto de apoio -  5,68:1 sobre --card */

  /* AS TRES CORES QUE SIGNIFICAM ALGUMA COISA.
     Nenhuma delas pode ser usada por enfeite - se aparecer, e informacao. */
  --danger:#ff3b5c;    /* RISCO    - area de risco, SOS, alerta grave */
  --warn:#ffb830;      /* ATENCAO  - aviso que nao e emergencia */
  --safe:#00e676;      /* OK       - seguro, ligado, funcionando */

  /* VOCE / INTERATIVO - um azul so.
     Ate 24/08 havia DOIS azuis: --accent (#4a9eff, decorativo) e --police
     (#00d4ff, a posicao do policial). Os dois passavam em contraste, mas o
     primeiro nao significava nada. Ficou um, e ele quer dizer «voce». */
  --police:#00d4ff;

  /* O VERMELHO DO SOS - a unica cor fora das de cima, e de proposito.
     #c62828 com letra branca = 5,62:1. Nao usa --danger porque:
     (1) --danger com letra branca da 3,48:1 e REPROVA no WCAG AA;
     (2) --danger quer dizer «area de RISCO» - informacao que o app MOSTRA.
         O SOS e uma ACAO do policial. Coisas diferentes, cores diferentes.
     Escolhido em 25/08 depois de comparar quatro opcoes em tamanho real e
     sob simulacao de sol forte na tela. Ver SAFESP.md 9.73.
     ⚠️ Esta cor esta escrita na linha do botao, no app.html. */

  /* CANTOS - dois valores, e nao dezesseis.
     4px e a escolha da direcao A: canto quase reto passa a sensacao de
     INSTRUMENTO, e nao de aplicativo de consumo. O 50% fica so para o que
     e circulo de verdade. Eram 16 valores diferentes: 12, 10, 9, 8, 6, 4,
     2, 14, 16, 20 px e cantos mistos. */
  --r:4px;

  /* ── ESCALA UNICA DE LAYOUT - 20/09/2026 (RT-318) ─────────────────────
     NENHUM valor abaixo e novo. Cada um e o valor que JA DOMINA este
     arquivo hoje, contado ocorrencia por ocorrencia. A escala so da NOME
     ao que foi medido - ela nao propoe desenho nenhum.
     A REGRA E: «VENCE O VALOR QUE JA EXISTE». Quando uma regra divergir da
     escala, quem muda e a regra - e so depois de o dono ver na tela.
     ------------------------------------------------------------------ */

  /* ESPACO */
  --e-1:4px; --e-2:6px; --e-3:8px; --e-4:12px; --e-5:16px; --e-6:20px; --e-7:32px;

  /* TEXTO */
  --t-tela:1.375rem; --t-secao:1.0625rem; --t-aba:1rem;
  --t-corpo:.875rem; --t-apoio:.8125rem; --t-detalhe:.75rem;

  /* CANTOS - convivem com o --r:4px acima, que continua sendo o padrao */
  --r-painel:12px; --r-pilula:999px;

  /* ALTURAS */
  --h-alvo:44px; --h-barra:48px;

  /* SOMBRAS */
  --sh-1:0 1px 3px rgba(0,0,0,.6); --sh-2:0 4px 16px rgba(0,0,0,.5); --sh-3:0 8px 24px rgba(0,0,0,.6);
}
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0;}
html,body{height:100%;overflow:hidden;}
/* RT-320: 'Inter' removida da pilha - nenhum arquivo dessa fonte e servido pelo projeto (sem @font-face nem link externo, so Rajdhani local em fontes/fontes.css) */
body{background:var(--bg);color:var(--text);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;font-size:.875rem;display:flex;flex-direction:column;}
/* topbar defined below */
.logo{font-size:1.125rem;font-weight:700;color:var(--text);letter-spacing:1.5px;flex-shrink:0;}
.badge{display:inline-flex;align-items:center;padding:3px 8px;border-radius:var(--r);font-size:.75rem;font-weight:600;border:1px solid transparent;}

    
    .badge-safe{background:rgba(0,230,118,.15);color:var(--safe);border:1px solid rgba(0,230,118,.3);}
    .badge-medium{background:rgba(255,184,48,.15);color:var(--warn);border:1px solid rgba(255,184,48,.3);}
    .badge-danger{background:rgba(255,59,92,.18);color:var(--danger);border:1px solid rgba(255,59,92,.35);}
    .badge-unknown{background:rgba(122,145,181,.15);color:var(--muted);border:1px solid rgba(122,145,181,.2);}
    /* 25/08: @keyframes pb saiu. Animava a sombra do aviso PERIGO - e a sombra
       esta em none!important desde sempre: o pulso rodava INVISIVEL, gastando
       processamento. Decisao do Ramon em 9.78: o aviso e SO COR. */
    /* MAP */
    #map-wrap{position:relative;flex:1;overflow:hidden;}
    #map{width:100%;height:100%;flex:1;min-height:0;}
    .leaflet-control-zoom a{background:var(--card)!important;color:var(--police)!important;border-color:var(--border)!important;}
    .leaflet-control-attribution{background:rgba(6,12,26,.8)!important;color:var(--muted)!important;font-size:.75rem!important;}
    /* FABs */
    .fab{position:absolute;z-index:500;border-radius:50%;border:1px solid var(--border);cursor:pointer;display:flex;align-items:center;justify-content:center;box-shadow:0 4px 16px rgba(0,0,0,.5);transition:all .2s;}
    .fab:active{transform:scale(.92);}
    /* 25/08 (Ramon: «alinhe esse botao»): o Seguir-GPS ficava 10px abaixo do
       centro do SOS (ancorado no painel, que muda de altura). Agora e FIXED com
       a mesma referencia do SOS: SOS h=56 base 100 -> centro a 128px da borda;
       este h=44 -> base 106px. Centros na MESMA linha. */
    /* 13/09 (RT-210): o Seguir-GPS SAIU do leque e do canto direito - o canto
       passou a ser do botao que abre as acoes. Agora fica ao LADO do SOS, na
       mesma linha de baixo (posicao B, escolha do Ramon): 50% + 36px poe a
       borda esquerda a 8px da borda direita do SOS (h=56, centrado), e sobra
       42px ate o botao de abrir em tela de 360px. right:auto anula o canto.
       ATENCAO: a referencia e o SOS, que a regra html.e-pc esconde no
       computador - la o GPS fica sozinho no meio do rodape. */
    #follow-fab-btn{position:fixed;bottom:calc(26px + env(safe-area-inset-bottom,0px));left:calc(50% + 36px);right:auto;width:44px;height:44px;background:var(--card);color:var(--muted);font-size:1.375rem;}
    /* CAMADAS (25/08, Ramon): mesmo desenho do Seguir-GPS, logo ACIMA dele.
       Abre a tela de comunidades (data-action=openCommSheet, ja delegado).
       13/09 (RT-210): "logo ACIMA dele" deixou de ser verdade - o Seguir-GPS
       saiu do canto e foi para o lado do SOS. Este botao ficou do lado das
       ACOES (direita) e abre a LISTA das comunidades proximas; quem acende e
       apaga o DESENHO dos poligonos e o #comm-fab-btn, do lado das camadas. */
    #layers-fab-btn{position:fixed;bottom:calc(82px + env(safe-area-inset-bottom,0px));right:14px;width:44px;height:44px;background:var(--card);color:var(--muted);}
    #follow-fab-btn.active{background:rgba(0,212,255,.15);color:var(--police);border-color:var(--police);}
    #notif-modal{display:none;position:fixed;inset:0;z-index:9000;background:rgba(0,0,0,.75);align-items:center;justify-content:center;}
    #notif-modal.show{display:flex;}
    #notif-modal-box{background:var(--card);border:1px solid var(--card);border-radius:var(--r);padding:28px 22px 22px;max-width:310px;width:88%;text-align:center;box-shadow:0 8px 40px rgba(0,0,0,.6);animation:slideUp .25s ease;}
    @keyframes slideUp{from{opacity:0;transform:translateY(30px)}to{opacity:1;transform:translateY(0)}}
    #loc-pill{display:none !important;}
    #loc-pill.v{display:block !important;}
    
    /* TOAST */
    /* 25/08 (Ramon): toast COMPACTO no topo - cartao centrado, nao de ponta
       a ponta (modelo 1 do quadro de notificacoes dele). */
    /* 30/08 - item 90, A100: era top:48px fixo. Com a barra alta (safe-area,
       linha do DP em duas linhas, ou a busca aberta) o alerta ficava POR BAIXO
       dela. Alerta que nao aparece e o pior defeito possivel neste app. */
    #alert-ticker{position:fixed;top:var(--tbh, 96px);left:0;right:0;z-index:1001;pointer-events:none;display:flex;flex-direction:column;align-items:center;}
    /* sem o «fo ... 5s forwards»: o CSS apagava TODO toast aos 5s, mas os de
       aviso/perigo so saiam aos 8s/12s - viviam invisiveis a metade da vida.
       Quem encerra e o JS (removeToast), no tempo certo de cada tipo. */
    .toast{margin:6px 8px;background:rgba(13,21,38,.97);border:1px solid rgba(13,21,38,.97);border-radius:var(--r);padding:10px 14px;display:flex;align-items:flex-start;gap:10px;animation:si .4s ease;pointer-events:all;width:-moz-fit-content;width:fit-content;min-width:240px;max-width:min(90vw,400px);box-shadow:0 4px 20px rgba(0,0,0,.5);}
    /* 25/08 (Ramon): as listras coloridas por tipo sairam junto com as demais
       bordas coloridas de cards e popups. */
    @keyframes si{from{transform:translateY(-60px);opacity:0;}to{transform:translateY(0);opacity:1;}}
    @keyframes fo{from{opacity:1;}to{opacity:0;}}
    .t-icon{flex-shrink:0;display:flex;align-items:center;margin-top:1px;}
    /* cor do TIPO no icone e no titulo (letra, nao borda - regra 9.84) */
    .toast.danger .t-icon,.toast.danger .t-title{color:var(--danger);}
    .toast.warn .t-icon,.toast.warn .t-title{color:var(--warn);}
    .toast.success .t-icon,.toast.success .t-title{color:var(--safe);}
    .toast.info .t-icon,.toast.info .t-title{color:var(--police);}
    .t-title{font-family:'Rajdhani',sans-serif;font-weight:700;font-size:.8125rem;}
    .t-body{font-size:.75rem;color:var(--muted);margin-top:2px;line-height:1.4;}
    /* BOTTOM */
    /* 25/08 (Ramon): o painel de baixo (Comunidades + km + aviso de
       aproximacao) saiu DE VEZ, em todas as telas. Historia em 9.86-9.88. */
    /* 25/08 (pedido do Ramon): o quadro Comunidades deixou de ser CAIXA e virou
       parte lisa do painel inferior. Continua sendo botao - role=button, cursor
       e o rotulo TOQUE fazem o convite; so a moldura saiu. */


    /* 25/08 (Ramon): o km e o dado que importa na barra - dobrou de tamanho. */

    
    
    /* OVERLAY */
    #danger-overlay{position:absolute;inset:0;z-index:300;pointer-events:none;border:0px solid var(--danger);}
    /* 14/09 (RT-233, decisao do Ramon): A MOLDURA SO NO APARELHO.
   Ate hoje esta regra nunca valeu, porque a classe .on nao era posta por
   ninguem - o app.js so passou a por em 14/09 (updBadge). O html:not(.e-pc)
   e o que mantem a decisao de 13/09 de pe: no computador o app e ferramenta
   de PLANEJAMENTO e nao avisa de area de risco; no aparelho, onde ele e
   usado em servico, avisa. Mesmo padrao do #sos-fab-btn e do #risk-badge
   logo abaixo - a deteccao tem UMA fonte, o _ehComputador() do app.js.
   Para desligar em todo lugar basta devolver o seletor sem o html:not().
   ATENCAO: quem marcou -reduzir animacoes- no aparelho nao ve o pulso; a
   regra de prefers-reduced-motion corta a animacao e sobra a moldura
   PARADA de 4px. Continua sendo aviso - e de proposito. */
html:not(.e-pc) #danger-overlay.on{border-width:4px;animation:dp 2s infinite;}
    @keyframes dp{0%,100%{box-shadow:inset 0 0 60px rgba(255,59,92,.2);}50%{box-shadow:inset 0 0 80px rgba(255,59,92,.35);}}
    /* SHEETS */
    /* 31/08: touch-action:none na ALCA (e so nela) e o que faz o navegador
       entregar o gesto ao arrasto em vez de tentar rolar a gaveta. A gaveta
       continua rolando normalmente - a regra nao a alcanca. */
    .sheet{position:fixed;bottom:0;transform:translateY(100%);left:0;right:0;z-index:700;background:var(--card);border-top:1px solid var(--border);border-radius:var(--r) var(--r) 0 0;max-height:85dvh;overflow-y:auto;transition:transform .4s cubic-bezier(.4,0,.2,1);padding:16px;}
    .sheet.open{transform:translateY(0);}
    .handle{width:100%;min-height:32px;background:transparent;margin:0 auto 4px;cursor:pointer;display:flex;align-items:center;justify-content:center;touch-action:none;}.handle::after{content:'';width:40px;height:4px;background:var(--danger);border-radius:var(--r);display:block;}
    .sheet-title{font-family:'Rajdhani',sans-serif;font-size:1.125rem;font-weight:700;letter-spacing:1px;margin-bottom:14px;}
    /* ALERT ITEMS */
    
    
    
    
    
    
    /* REPORT */
    
    
    
    
    
    
    
    /* MOD */
    
    
    /* DRAWER */
    /* 31/08: era right:-320px com transition:right. O menu era o UNICO painel do
       app a animar uma propriedade de LAYOUT - a .sheet e o #oc-aba sempre usaram
       transform. Animar 'right' obriga o navegador a recalcular a pagina e repintar
       a cada quadro por 320 ms; com internet ruim a repintura expoe os blocos do
       mapa que ainda nao chegaram, e a tela 'apaga e volta'. Relatado pelo Ramon no
       aparelho, e SO neste painel - os outros dois nunca piscaram: teste de controle
       pronto dentro do proprio app. translateX(100%) usa a largura REAL do elemento,
       entao tambem corrige o -320px fixo, que era um numero chutado. Ver 9.136. */
    
    /* NOTIF */
    
    
    /* POPUPS */
    .leaflet-popup-content-wrapper{background:var(--card)!important;border:1px solid var(--card)!important;border-radius:var(--r)!important;}
    .leaflet-popup-tip{background:var(--card)!important;}
    /* 14/09 (FE-12/RT-235, achado V3 de 09/09): 'IBM Plex Sans' era declarada
       SEM arquivo de fonte - o balao caia na fonte do sistema em silencio, e por
       isso o app chegou a ter quatro familias com duas declaradas (ver o bloco 3
       da rodada de 24/08). Agora herda a fonte do app. */
    .leaflet-popup-content{color:var(--text)!important;font-family:inherit!important;margin:10px 14px!important;}
    
    
    .leaflet-control-zoom{display:none !important;}
    /* Alert filters */
    
    
    
    
    
    
    
    /* Route btn in alert */
    /* Communities sheet */
    ::-webkit-scrollbar{width:4px;}::-webkit-scrollbar-thumb{background:var(--muted);border-radius:var(--r);}
    /* SOS markers */
    /* 24/08: @keyframes sosPulse removido. Era codigo morto: o HTML pedia
       'sos-pulse' e aqui estava escrito 'sosPulse' - nomes diferentes, entao
       a animacao NUNCA rodou. Removido a pedido do Ramon. */
    /* Other users markers */

    /* Routing */
    
    
    /* GPS Required Overlay */
    #gps-overlay{position:fixed;inset:0;background:var(--bg);z-index:99999;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:32px;text-align:center;}
    #gps-overlay.hidden{display:none;}
    .gps-icon{font-size:4rem;margin-bottom:24px;}
    .gps-title{font-family:Rajdhani,sans-serif;font-size:1.625rem;font-weight:700;color:#e8f0fe;margin-bottom:12px;}
    .gps-text{font-size:.875rem;color:var(--muted);max-width:320px;line-height:1.7;margin-bottom:32px;}
    .gps-btn{padding:14px 32px;background:rgba(0,212,255,.15);border:1.5px solid var(--police);color:var(--police);border-radius:var(--r);font-family:Rajdhani,sans-serif;font-size:1rem;font-weight:700;cursor:pointer;letter-spacing:.5px;}
    .gps-btn:active{opacity:.8;}
    
    
    
    
    
    #search-input-top:focus{border-color:rgba(0,212,255,.8);box-shadow:0 0 0 2px rgba(0,212,255,.15);}
    #search-results::-webkit-scrollbar{width:4px}#search-results::-webkit-scrollbar-track{background:transparent}#search-results::-webkit-scrollbar-thumb{background:rgba(0,212,255,.3);border-radius:var(--r)}
    /* F4 (25/08): o top:97px FIXO cobria o campo e o X quando a barra ficava
       mais baixa (barra de status do celular). Quem posiciona agora e o JS,
       medindo a borda real da barra a cada busca. */
    #search-results{position:fixed!important;left:0!important;right:0!important;box-shadow:0 8px 24px rgba(0,0,0,.6);border-radius:0 0 var(--r) var(--r);z-index:1001!important;}
    
    .leaflet-control-attribution { display: none !important; }

    /* 31/08 (A111): o tamanho do relogio saiu de dentro da etiqueta e veio
       para ca. Escrito na etiqueta, ele vencia QUALQUER regra desta folha -
       por isso as regras responsivas abaixo nunca chegaram a valer. Agora ele
       encolhe com a tela e NAO some mais em nenhuma largura. */
    /* ── RESPONSIVE MOBILE ── */
    @media (max-width: 600px) {
      #topbar { padding:6px 10px; gap:6px; }
      .logo { font-size:1rem; }
      
      #search-input-top { font-size:.8125rem; }
      #risk-badge { font-size:.75rem; padding:3px 7px; }

      /* 20/09 (RT-318, D5): width:48px e height:48px SAIRAM. Os 11 elementos
         .fab do app.html tem, TODOS, regra POR ID fixando 44x44 (A144), e ID
         (1,0,0) vence classe (0,1,0) em qualquer ordem e dentro de qualquer
         media query. Estas duas nunca chegaram a valer um pixel.
         O font-size FICA: nenhuma regra por ID o declara, fora o
         #follow-fab-btn - apagar aqui seria mudar a cascata, nao limpa-la. */
      .fab { font-size:1.25rem; }
      #sos-fab-btn { width:42px; height:42px; font-size:.8125rem; }
      /* 25/08: o desconto de 112px era o espaco do painel de baixo - saiu junto. */
      
    }
    @media (max-width: 400px) {
      /* 31/08: era display:none. O Ramon pediu que o relogio nunca suma - so
         encolha. Na tela mais estreita ele fica em 1rem e continua legivel. */
    }
    

  /* ── MOBILE RESPONSIVENESS ── */
  @media (max-width: 480px) {
    #topbar { padding: 0 8px; }

    .sheet { border-radius:var(--r) var(--r) 0 0; }
    .sheet-title { font-size: 1rem; }
    
    #loc-pill { font-size:.75rem;padding:3px 8px; }
    #coord-text { font-size:.75rem; }
  }
  @media (max-width: 360px) {

  }

  

  
  
  

  /* ── TOPBAR STATUS BAR ── */
  
  .logo span{color:var(--text)}
  
  
  
  
  
  
  

  /* Topbar layout - final */
  
  
  

  /* ── TOPBAR ── */
  #topbar{position:relative;z-index:1000;background:var(--card);border-bottom:1px solid var(--border);padding:6px 10px;display:flex;align-items:center;gap:6px;flex-shrink:0;height:48px}
  .logo{flex-shrink:0;font-family:Rajdhani,sans-serif;font-size:1.125rem;font-weight:700;letter-spacing:2px;color:var(--police)}
  .logo span{color:var(--text)}
  
  
  
  
  
  
  /* Barra de busca expansivel */
  #topbar-search-bar{width:100%;background:var(--card);border-bottom:1px solid var(--border);padding:8px 12px;display:none;align-items:center;gap:8px;flex-shrink:0}
  #topbar-search-bar.open{display:flex}
  #topbar-search-bar .tsrch-icon{color:var(--muted);font-size:.875rem;flex-shrink:0}
  #search-input-top{flex:1;background:none;border:none;outline:none;color:var(--text);font-size:.875rem}
  #search-clear-top{color:var(--muted);cursor:pointer;font-size:1rem;flex-shrink:0}
  @media (max-width: 300px){.logo{font-size:.875rem}}

  /* ── STATUS BOX ── */
  #status-box{display:flex;align-items:center;gap:3px;justify-content:center;flex:1}
  #risk-badge{
    font-family:Rajdhani,sans-serif;font-size:.75rem;font-weight:700;
    padding:4px 9px;border-radius:var(--r);white-space:nowrap;
    letter-spacing:.3px;transition:background .4s,color .4s;
  }
  #risk-badge{background:rgba(255,255,255,.08);color:var(--text)}
  #risk-badge.badge-safe{background:rgba(0,200,83,.18);color:var(--safe);border:1px solid rgba(0,200,83,.3)}
  /* 25/08: as duas linhas abaixo FALTAVAM, e essa falta era o defeito.
     «#risk-badge{color:var(--text)}» acima e um seletor por ID: ele vence
     qualquer seletor por CLASSE. Existia a versao de ID para .badge-safe e
     para .badge-unknown - por isso SO o verde aparecia - e nao existia para
     atencao nem para PERIGO. O vermelho da area de risco nunca aparecia.
     Contraste sobre a barra (#0d1526): --warn 10,54:1 - --danger 5,23:1. */
  #risk-badge.badge-medium{color:var(--warn)}
  #risk-badge.badge-danger{color:var(--danger)}

  #risk-badge.badge-unknown{background:rgba(255,255,255,.07);color:var(--muted);border:1px solid rgba(255,255,255,.1)}

  @media (min-width: 600px){
    #topbar{padding:6px 20px;gap:10px}
    #status-box{background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.06);border-radius:var(--r);padding:4px 8px;gap:4px}
    #risk-badge{font-size:.75rem;padding:3px 10px}
    .logo{font-size:1.25rem}
  }
  @media (max-width: 599px){
    #status-box{background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.06);border-radius:var(--r);padding:3px 6px;gap:3px}
    #risk-badge{font-size:.75rem;padding:2px 6px}
  }

  .comm-num-tip{background:rgba(255,59,92,.85);color:#fff;border:none;font-family:Rajdhani,sans-serif;font-weight:700;font-size:.75rem;padding:1px 5px;border-radius:var(--r);box-shadow:none}
  .comm-num-tip::before{display:none}

  /* F4 (25/08): aqui havia um top:97px!important de seletor rebuscado - era
     ele que desgarrava a lista da barra no desktop (vao de 4px medido). */

/* === SPLASH SCREEN === */

/* === SafeSP UX polish v1 (safe-area, ultrawide, tap target) === */
#topbar{padding-top:calc(6px + env(safe-area-inset-top,0px))!important}
#gps-blocked-banner{max-width:min(90vw,420px)!important}
#follow-fab-btn{width:44px!important;height:44px!important}


/* === SafeSP UX polish v2 (tap area, banner contrast, blink, a11y) === */
#gps-blocked-banner .t-body{color:#aebfd6!important;font-size:.75rem!important}
/* 25/08 (Ramon): o SEGUNDO pisca do GPS Bloqueado (o suave, deste polish)
   saiu junto com o forte do app.js - decisao da rodada das notificacoes:
   «o aviso e SO COR» (9.78). O ambar no icone e no titulo faz o trabalho. */

/* === SafeSP UX polish v3 (banner estado obtendo, neutro) === */
#gps-blocked-banner.sx-obtaining{animation:none!important;border-color:rgba(120,150,200,.55)!important;background:#15203a!important}

/* === SafeSP UX polish v4 (responsivo: chips, drawer, SOS, icones) === */
#sos-fab-btn{min-width:44px!important;min-height:44px!important}
@media (max-width: 380px){
  #status-box{gap:3px;min-width:0}
  #status-box .badge{min-width:0;flex-shrink:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:30vw;font-size:clamp(.75rem,2.6vw,.8125rem);padding:3px 6px}
}

/* === SafeSP UX polish v5 (Opcao E: chips scroll estilo Maps + topbar font-resiliente + overlay safe-area unificado) === */
/* 20/09 (RT-318, D4): o min-height:48px desta linha SAIU. Ele era repetido,
   identico, pelo #topbar{min-height:48px!important} escrito mais abaixo nesta
   mesma folha (polish v12), que vence por ser o ultimo com a mesma forca.
   O height:auto FICA: esta linha e a unica que o declara. */
#topbar{height:auto!important}
#status-box{overflow-x:auto!important;overflow-y:hidden!important;flex-wrap:nowrap!important;justify-content:flex-start!important;scroll-behavior:smooth;-webkit-overflow-scrolling:touch;scrollbar-width:none;-ms-overflow-style:none}
#status-box::-webkit-scrollbar{display:none}
#status-box>*{flex:0 0 auto!important;max-width:none!important}

/* === SafeSP UX polish v6 (sidebar fluida: 100% width, font-scale 200%, alvos 44px) === */

/* === SafeSP UX polish v7 (drawer respeita safe-area: topo alinhado com a topbar) === */

/* === SafeSP UX polish v9 (redesenho status-box: status primario + contexto secundario, centralizado, sem scroll) === */
#status-box{display:grid!important;grid-template-columns:auto auto!important;justify-content:center!important;align-content:center!important;align-items:center!important;column-gap:6px!important;row-gap:2px!important;overflow:visible!important;line-height:1.15}
/* 09/09 (FE-04, achado E6 da auditoria): o cracha de risco era o elemento de
   seguranca mais importante da tela e o menor (12px). Agora 16px no celular e
   18px no computador (html.e-pc, RT-175). A barra mede a propria altura em
   --tbh (A100/A145), entao nada abaixo dela e posicionado por numero fixo. */
#risk-badge{grid-column:1 / -1!important;justify-self:center!important;font-size:1rem!important;font-weight:700!important;letter-spacing:.5px!important}
html.e-pc #risk-badge{font-size:1.125rem!important}

/* === SafeSP UX polish v10 (compacta status-box p/ topbar ~48px, reconcilia com drawer top) === */
#status-box{row-gap:0!important;line-height:1.05!important}
#risk-badge{padding:3px 12px!important;line-height:1.15!important}

/* === SafeSP UX polish v11 === */
/* 20/09 (RT-318, D4): o #topbar{min-height:54px!important} desta secao SAIU.
   Ele ja PERDIA para o min-height:48px escrito depois (polish v12), entao a
   barra sempre mediu 48px na tela. O 54px existia para casar a altura com a
   BARRA LATERAL, que o FE-06 (09/09) removeu do app. Zero pixel muda. */

/* === SafeSP UX polish v12 (Opcao B: status-box SEM caixa, 1 linha 'SEGURO • C.F. • IR', altura dinamica --tbh) === */
#status-box{background:none!important;border:none!important;box-shadow:none!important;display:flex!important;flex-flow:row wrap!important;justify-content:center!important;align-items:baseline!important;gap:0!important;overflow:visible!important;padding:0!important}
#risk-badge{background:transparent!important;border:none!important;box-shadow:none!important;border-radius:0!important;padding:0!important;white-space:nowrap!important}
#risk-badge{font-size:.8125rem!important;font-weight:700!important}
/* 02/09 (Ramon): este era o ponto separador que dividia
   SEGURO \2022 C.F. 8oDP \2022 IR - SE  na barra de cima.
   Com o #dp-badge e o #ir-badge FORA da barra, ele ficaria pendurado
   depois do banner de risco, sozinho e sem nada para separar. Regra
   desativada por isso - nao por estilo. As demais regras que citam
   #dp-badge e #ir-badge continuam no arquivo e ficaram INERTES: elas
   tambem vestem o #risk-badge, que permanece, entao apaga-las mexeria
   no banner que o Ramon quis manter. Ver SAFESP.md 9.138.
   19/09 (item 5): as 8 regras que vestiam SO #dp-badge e #ir-badge sairam, e
   nas 7 listas compartilhadas sairam so esses dois seletores. O #risk-badge
   ficou com o mesmo estilo, comparado no navegador propriedade a propriedade.
   #risk-badge::after,#dp-badge::after{content:"\2022";margin:0 7px;opacity:.45;font-weight:400;color:var(--muted,#9aa3b2)}
*/
#topbar{min-height:48px!important}

/* === SafeSP UX polish v14 (area de toque do dp-badge clicavel SEM reintroduzir caixa; ir 10px; alinhamento central) === */
#status-box{align-items:center!important}
#risk-badge{padding:11px 3px!important}

/* === A11Y-06: Skip Link === */
/* 14/09 (FE-12/RT-235, achado E3): texto so para leitor de tela - o h1 do app.
   Tecnica padrao: 1px, fora do fluxo, com clip. NAO usar display:none nem
   visibility:hidden - as duas TIRAM o elemento do leitor de tela tambem, que e
   exatamente o contrario do que esta regra existe para fazer. */
.so-leitor{position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;}
.skip-link{position:absolute;top:-9999px;left:0;z-index:10000;background:var(--police);color:#000;padding:8px 16px;font-weight:700;text-decoration:none;border-radius:0 0 var(--r) var(--r)}
.skip-link:focus{top:0}

/* CSP-FIX: substituiu onmouseenter/onmouseleave inline */

/* === SafeSP UX polish v15 (Item 4: uniformizar altura/alinhamento/padding de risk-badge, dp-badge, ir-badge) === */
#status-box{align-items:center!important}
#risk-badge{font-size:.75rem!important;font-weight:700!important;line-height:1.1!important;padding:11px 3px!important;box-sizing:border-box!important}

/* === RODADA DE CSS - 24/08/2026 (ver SAFESP.md 9.60) ===
   Tres correcoes de acessibilidade. Nenhuma muda comportamento do app.

   [1] ALVOS DE TOQUE (WCAG 2.5.5 - 44x44 CSS px)
       Usa min-inline-size/min-block-size, NAO width/height: assim o conteudo
       pode CRESCER o alvo, mas nunca ENCOLHER. O desenho do icone nao muda -
       so a area que responde ao dedo. Vale sobretudo de luva, em movimento.

   [2] ANEL DE FOCO VISIVEL (WCAG 2.4.7)
       :focus-visible, nao :focus - o anel aparece para quem navega por teclado
       e nao pisca ao toque. outline (nao box-shadow) para sobreviver ao modo
       de alto contraste do Windows.

   [3] MENOS MOVIMENTO (WCAG 2.3.3)
       Quem marcou "reduzir animacoes" no proprio aparelho para de receber
       piscadas. Num app de alerta isso importa: piscada continua cansa e
       compete com o alerta de verdade.
*/

/* [1] */
/* 09/09 (FE-06): #search-btn, #menu-btn e .lo-mapbtn sairam desta lista (elementos removidos). */
.fab,
.handle,
.gps-btn {
  min-inline-size: 44px;
  min-block-size: 44px;
}

/* [1b] Alvos que a medicao de 24/08 pegou fora do piso e que estao no MENU
   lateral e no atalho de teclado. Aqui so a ALTURA e forcada: a largura fica
   livre para o texto nao esticar e virar um bloco. O display precisa vir junto
   porque um link solto e "inline", e altura minima NAO vale para inline. */
.skip-link {  /* 09/09 (FE-06): #drawer a / #drawer button sairam da lista */
  min-block-size: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* 09/09 (FE-06): regras do X do menu e do .lo-mapbtn sairam com a barra lateral. */

/* [2] */
:where(a, button, [role="button"], [tabindex]):focus-visible {
  outline: 2px solid var(--police);
  outline-offset: 2px;
}

/* [3] */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ── ICONES DESENHADOS - 24/08/2026 ────────────────────────────────────────
   Substituiram os emojis. Tres motivos, e nenhum e estetico:
   (1) FUNCIONAM SEM INTERNET - vao dentro do HTML, nao sao arquivo a baixar;
   (2) acompanham a cor do texto, sem precisar de uma segunda imagem por estado;
   (3) NAO DEPENDEM DO CELULAR - emoji e desenhado pelo sistema e muda de
       aparencia entre Android, iPhone e versao; o desenho e sempre igual.
   O alinhamento abaixo existe porque svg e, por padrao, uma caixa de texto que
   assenta na linha de base - sem isto o icone fica alguns pixels caido em
   relacao a palavra ao lado. */
/* ── BLOCO 3 - 24/08/2026 - A FONTE DOS BOTOES ─────────────────────────────
   <button>, <input>, <select> e <textarea> NAO HERDAM a fonte do body: o
   navegador impoe a DELE, que costuma ser Arial. Foi assim que o app acabou
   com QUATRO familias de fonte quando so duas estavam declaradas.
   ⚠️ ESTA HIPOTESE FOI LEVANTADA numa maquete, em 24/08, quando a conferencia
   reprovou as MINHAS proprias telas de exemplo pelo mesmo motivo. So virou
   FATO agora, medido no app de verdade: a contagem no navegador acusou
   «Inter, Rajdhani, system-ui, Arial». Uma linha resolve. */
button,input,select,textarea{font:inherit}

svg{vertical-align:middle;flex-shrink:0}

/* ── FUNDO DO MAPA - 25/08/2026 ───────────────────────────────────────────
   O Leaflet pinta o proprio quadro de #ddd - um cinza CLARO. Num app escuro
   isso vira um clarao de meio segundo toda vez que o mapa se move para uma
   area cujos ladrilhos ainda nao chegaram. Nao e defeito do Leaflet: e o
   padrao dele, pensado para paginas claras. */
.leaflet-container{background:var(--bg)}

    /* ══ CAMADA DE OCORRENCIAS DA SSP (29/08/2026) ══════════════════════ */
    /* Duas cores novas, escolhidas com o Ramon em 28/08: celular em AZUL e
       trafico em VERDE. O celular saiu do vermelho de proposito - com 172 mil
       pontos, o --danger deixava de significar RISCO e virava fundo de tela. */
    /* 16/09 (RT-262): --arma. A cor foi MEDIDA contra as oito que ja disputam
       a tela antes de ser escolhida: a mais proxima e o azul do celular, a 38,6
       de distancia perceptual, e o limite util e 35. O vermelho estava fora
       desde o inicio - e o --danger, reservado a risco, SOS e homicidio, e ja
       desenha a area de risco DENTRO do mapa. */
    :root{ --celular:#2f6fed; --trafico:#3fa34d; --estupro:#b1387a; --arma:#6d4aff; }

    .oc-mk{display:inline-flex;align-items:center;justify-content:center;position:relative;
      border-radius:50%;border:1.5px solid #0b1220;box-shadow:0 1px 3px rgba(0,0,0,.6);
      width:26px;height:26px;}
    .oc-mk svg{width:64%;height:64%;}
    .oc-cel{background:var(--celular);color:#fff;}
    .oc-vei,.oc-rec{background:var(--warn);color:#0a1020;}
    .oc-tra,.oc-por{background:var(--trafico);color:#0a1020;}
    .oc-arm{background:var(--arma);color:#fff;}   /* RT-262: branco da 5,15:1 */
    /* O visto branco e a distincao que mais importa na rua: com ele, o veiculo
       ja apareceu; sem ele, foi levado. Sao 1 em cada 4 pontos de veiculo. */
    .oc-selo{position:absolute;right:-3px;bottom:-3px;width:12px;height:12px;border-radius:50%;
      background:#fff;color:#0a1020;display:flex;align-items:center;justify-content:center;
      border:1.2px solid #0b1220;}
    .oc-selo svg{width:9px;height:9px;}
    /* 14/09 (FE-12/RT-235, achado V4): 9,5px -> 12px, o piso do projeto (M07-a).
       O -8px NAO e o que o pacote de 09/09 propunha (-6px) - e decisao do Ramon
       depois de MEDIDO em 14/09: esta pastilha e ancorada pelo canto superior
       DIREITO, entao crescer empurra ela para DENTRO, sobre o icone do crime, e
       nao para o lado do vizinho como o pacote supunha. Com -6px ela cobria 44%
       do marcador; com -8px cobre 35%, contra os 32% de antes. O numero fica
       legivel e o simbolo do crime continua visivel. */
    .oc-cont{position:absolute;right:-8px;top:-8px;min-width:18px;height:18px;padding:0 4px;
      border-radius:9px;background:var(--card);color:var(--text);border:1px solid var(--border);
      font-size:12px;font-weight:700;line-height:16px;text-align:center;}
    .oc-quad{display:inline-block;width:22px;height:16px;border-radius:2px;
      border:1px solid var(--estupro);background:repeating-linear-gradient(45deg,
      rgba(177,56,122,.5) 0 3px,transparent 3px 6px);}

    .oc-pop{font-size:.8125rem;line-height:1.5;}
    .oc-pop b{font-family:'Rajdhani',sans-serif;letter-spacing:.8px;display:block;
      font-size:.875rem;margin-bottom:5px;color:var(--police);}
    .oc-pop .oc-av{display:block;margin-top:8px;padding-top:7px;border-top:1px solid var(--border);
      color:var(--muted);font-size:.75rem;line-height:1.45;}
    .oc-lista{margin-top:8px;display:grid;grid-template-columns:1fr auto;gap:2px 10px;
      font-size:.75rem;max-height:150px;overflow-y:auto;}
    .oc-lista i{font-style:normal;color:var(--muted);font-variant-numeric:tabular-nums;}
    .oc-lista .oc-mais{grid-column:1/-1;color:var(--muted);font-size:.75rem;padding-top:3px;}

    #oc-fab-btn{position:fixed;bottom:calc(138px + env(safe-area-inset-bottom,0px));left:14px;
      width:44px;height:44px;background:var(--card);color:var(--muted);}
    /* 29/08 - o ambar foi testado na tela e o Ramon preferiu o azul padrao:
       exatamente os mesmos valores do #follow-fab-btn.active, para que TODO
       botao ligado no app tenha um unico significado de "ligado". O aceso
       continua informando estado - so acende com a camada ligada. */
    #oc-fab-btn.active{background:rgba(0,212,255,.15);color:var(--police);
      border-color:var(--police);}

    /* 04/09 (RT-139): esta regra FALTAVA desde 03/09, e por isso o botao de
       noticias era INVISIVEL em producao. A classe .fab da apenas borda
       redonda, sombra e position:absolute - quem da posicao, tamanho e fundo
       e a regra POR ID de cada botao. Sem ela o #nt-fab-btn nascia
       transparente, do tamanho do svg (22px) e solto no fluxo da pagina.
       Valores identicos aos do #oc-fab-btn acima, trocando 138px por 194px:
       o passo de 56px que o comentario do app.html ja documentava.
       ARMADILHA: copiou-se o HTML do vizinho sem copiar o CSS dele. */
    #nt-fab-btn{position:fixed;bottom:calc(194px + env(safe-area-inset-bottom,0px));left:14px;
      width:44px;height:44px;background:var(--card);color:var(--muted);}
    #nt-fab-btn.active{background:rgba(0,212,255,.15);color:var(--police);
      border-color:var(--police);}

    /* 05/09 (RT-148): CAMERAS. Regra POR ID obrigatoria (A144): a classe .fab
       nao da posicao, tamanho nem fundo. Valores identicos aos do #nt-fab-btn,
       trocando 194px por 250px (passo de 56px). */
    /* 09/09 (FE-03): Fundo do mapa e Instagram no leque. Regra COPIADA INTEIRA
       do #cm-fab-btn (A144: espelhar o vizinho por inteiro, nunca pela metade).
       O bottom e sobrescrito pelo leque (_posiciona) e so vale como reserva se
       o JS falhar. text-decoration: o Instagram e um <a>. */
    #fundo-fab-btn,#ig-fab-btn,#busca-fab-btn,#ajuda-fab-btn,#filtros-fab-btn{position:fixed;bottom:calc(306px + env(safe-area-inset-bottom,0px));right:14px;
      width:44px;height:44px;background:var(--card);color:var(--muted);text-decoration:none;}
    /* Icone do fundo ATUAL: um dos tres SVGs por vez, decidido por html[data-fundo]. */
    #fundo-fab-btn .ico-fundo{display:none;}
    #fundo-fab-btn .ico-dark{display:block;}
    html[data-fundo="white"] #fundo-fab-btn .ico-dark,
    html[data-fundo="topo3d"] #fundo-fab-btn .ico-dark{display:none;}
    html[data-fundo="white"] #fundo-fab-btn .ico-white{display:block;}
    html[data-fundo="topo3d"] #fundo-fab-btn .ico-topo3d{display:block;}
    #cm-fab-btn{position:fixed;bottom:calc(250px + env(safe-area-inset-bottom,0px));left:14px;
      width:44px;height:44px;background:var(--card);color:var(--muted);}
    #cm-fab-btn.active{background:rgba(0,212,255,.15);color:var(--police);
      border-color:var(--police);}
    /* 13/09 (RT-210): COMUNIDADES no mapa. Regra POR ID obrigatoria (A144): a
       classe .fab nao da posicao, tamanho nem fundo. Regra COPIADA INTEIRA do
       #cm-fab-btn acima, do lado ESQUERDO. O bottom de 232px e o quarto lugar
       da coluna das camadas (base 82 + 3 x 50) e so vale de reserva: quem
       manda no bottom e o _posiciona do leque. */
    #comm-fab-btn{position:fixed;bottom:calc(232px + env(safe-area-inset-bottom,0px));left:14px;
      width:44px;height:44px;background:var(--card);color:var(--muted);}
    #comm-fab-btn.active{background:rgba(0,212,255,.15);color:var(--police);
      border-color:var(--police);}
    /* 09/09 (FE-10): as regras .cm-pop sairam com o balao das cameras (a dica usa .nt-tip). */

    /* ══ GAVETA COMPACTA (29/08) ═══════════════════════════════════════════
       Pedido do Ramon: menos borda, menos caixa, menos espaco vazio. Cada
       grupo era um cartao com borda propria - seis cartoes dentro de um
       cartao. Agora o rotulo em maiuscula ja separa, sem desenhar nada. */
    .oc-grupo{margin-bottom:9px;}
    .oc-rot{font-size:.75rem;letter-spacing:.9px;text-transform:uppercase;
      color:var(--muted);margin:11px 0 5px;font-weight:600;}
    .oc-rot:first-child{margin-top:0;}

    /* cabecalho: titulo + chave liga/desliga + limpar, tudo numa linha */
    .oc-topo{display:flex;align-items:center;gap:9px;margin-bottom:2px;}
    /* 09/09 (FE-07): abas da gaveta unica de filtros. Mesma linguagem do .oc-chip
       (contorno fino, azul quando ativa), sem barra colorida nem gradiente. */
    .ft-abas{display:flex;gap:6px;margin:0 0 12px;border-bottom:1px solid var(--border);}
    .ft-aba{flex:1;min-height:44px;background:transparent;border:none;border-bottom:2px solid transparent;
      color:var(--muted);font-family:Rajdhani,sans-serif;font-size:1rem;font-weight:700;letter-spacing:.5px;cursor:pointer;}
    .ft-aba.on{color:var(--police);border-bottom-color:var(--police);}
    .ft-aba:focus-visible{outline:2px solid var(--police);outline-offset:-2px;border-radius:var(--r);}
    /* 09/09 (FE-08): aba Inspetoria. */
    .ft-ir-status{font-size:.8125rem;color:var(--muted);margin:6px 0 12px;line-height:1.45;}
    .ft-ir-grupo{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:12px;}
    /* 20/09 (RT-318, D11): .ft-ir-cmd SAIU - a classe nao aparece em nenhum
       .js, .html ou .css (grep de 20/09). A aba Inspetoria monta os grupos com
       a classe do proprio grupo e data-ft-ir, escritos em app.js:5921. */
    .oc-topo .oc-esp{flex:1;}

/* ══ 14/09 (RT-239, pedido do Ramon): A GAVETA DE FILTROS ══════════════════
   Auditoria visual "cara de IA". O diagnostico, MEDIDO em producao: a gaveta
   nao tinha teto de largura e ia a 1920px no computador - o trilho de periodo
   atravessava a tela inteira para escolher entre QUATRO valores, e o "Limpar"
   ficava a 1500px da chave. Mais: 27 pilulas arredondadas e 13 cores dentro
   do painel. Cada decisao abaixo e do Ramon, depois de ver renderizado.
   O QUE NAO MUDOU: nenhum id, data-*, aria-* ou evento - so a casca visual.
   MEDIDO depois: caixas com borda 18 -> 10; botoes abaixo de 40px 23 -> 3. */

/* [1] ESTRUTURA (RT-240). O teto de 560px nos FILHOS, do RT-239, SAIU: agora
   quem tem largura e o cartao inteiro, e cada parte ocupa 100% dele.
   Tres partes: cabecalho fixo, miolo que ROLA, rodape fixo. Para o miolo rolar
   sozinho, a .sheet nao pode rolar tambem - dai o overflow:hidden aqui, que
   vence o overflow-y:auto da classe compartilhada por ser seletor de ID. */
#filtros-sheet{display:flex;flex-direction:column;overflow:hidden;padding:0;}
#filtros-sheet .ft-cab{padding:0 20px;flex:0 0 auto;}
#filtros-sheet .ft-miolo{flex:1 1 auto;min-height:0;overflow-y:auto;padding:0 20px;
  overscroll-behavior:contain;}
#filtros-sheet .handle{padding-top:8px;}

/* [2] NO COMPUTADOR VIRA CARTAO CENTRADO (decisao do Ramon, 14/09). Ate aqui a
   gaveta era uma faixa de 1920px com o conteudo espremido no meio - o proprio
   Ramon descreveu como "estranho". O seletor por ID vence o .sheet e o
   .sheet.open da classe compartilhada, entao as outras gavetas do app seguem
   subindo de baixo como sempre. A alca some: nao ha o que arrastar. */
@media (min-width:700px){
  #filtros-sheet{left:50%;right:auto;bottom:auto;top:50%;width:620px;
    max-width:calc(100vw - 40px);max-height:80dvh;border-radius:12px;
    border:1px solid var(--border);box-shadow:0 24px 64px rgba(0,0,0,.6);
    transform:translate(-50%,-46%);opacity:0;pointer-events:none;
    transition:transform .26s cubic-bezier(.4,0,.2,1),opacity .18s;}
  #filtros-sheet.open{transform:translate(-50%,-50%);opacity:1;pointer-events:auto;}
  #filtros-sheet .handle{display:none;}
  #filtros-sheet .ft-cab{padding-top:18px;}
}

/* [3] A ESCADA DE HIERARQUIA. O defeito que o Ramon apontou: o titulo da secao
   era MENOR que as proprias opcoes (13px contra 12px) - o olho nao achava onde
   um grupo comecava. Agora sao cinco niveis e so dois competem pela atencao:
   o titulo da secao e o rodape.
   1 painel 22px . 2 aba 16px . 3 secao 17px . 4 opcao 14px . 5 apoio 12px */
#filtros-sheet .sheet-title{font-size:1.375rem;letter-spacing:.5px;color:var(--text);
  margin:0 0 12px;display:flex;align-items:center;gap:9px;}
#filtros-sheet .ft-abas{margin:0 -20px 0;padding:0 20px;}
#filtros-sheet .ft-sec{padding:20px 0;border-bottom:1px solid #16233a;}
#filtros-sheet .ft-sec:last-child{border-bottom:none;}
#filtros-sheet .ft-t{font-family:'Rajdhani',sans-serif;font-size:1.0625rem;font-weight:700;
  letter-spacing:.3px;color:var(--text);margin:0 0 2px;}
#filtros-sheet .ft-n5{font-size:.75rem;color:var(--muted);margin-top:12px;line-height:1.5;}
#filtros-sheet .ft-n5 b{color:var(--text);font-weight:600;}

/* [4] AS OPCOES sobem de 12 para 14px e o alvo de toque vai a 44px.
   20/09 (RT-307): este bloco MUDOU DE LUGAR. Ele estava AQUI, antes das regras
   do RT-239 que ele deveria sobrepor - e em CSS, empate de forca e decidido
   pela ORDEM: vencia o de baixo, o mais velho. Os botoes ficaram em 12px/40px
   desde 15/09 achando que estavam em 14px/44px. O bloco agora esta depois das
   regras que sobrepoe, logo abaixo da secao [4] das categorias de noticia. */

/* [5] A INSPETORIA vira LISTA: sao 35 itens de escolha UNICA, e p-lula sugere
   que da para somar - nao da. A marca de escolhida diz o estado sem cor. */
#filtros-sheet .ft-lista{display:flex;flex-direction:column;}
#filtros-sheet .ft-lista button{display:flex;align-items:center;justify-content:space-between;
  gap:10px;background:none;border:none;border-bottom:1px solid #16233a;color:var(--muted);
  font-family:inherit;font-size:.875rem;padding:0 2px;min-height:46px;cursor:pointer;text-align:left;}
#filtros-sheet .ft-lista button:last-child{border-bottom:none;}
#filtros-sheet .ft-lista button.on{color:var(--text);}
#filtros-sheet .ft-lista button:focus-visible{outline:2px solid var(--police);outline-offset:-2px;}
#filtros-sheet .ft-marca{color:var(--police);opacity:0;flex:0 0 auto;}
#filtros-sheet .ft-lista button.on .ft-marca{opacity:1;}
/* 18/09 (RT-289, correcao do Ramon): o cabecalho «COP-X» E o botao - nao ha
   mais um «Todas» ao lado. Continua com a cara de titulo de grupo (mesma fonte,
   mesmo cinza, mesmo espacamento de letras), agora com largura total, alvo de
   toque de 36 px e a marca ✓ que a lista usa. Aceso, o nome do comando toma o
   ciano da escolha - a mesma linguagem das inspetorias logo abaixo. */
#filtros-sheet button.ft-grupo{font-family:'Rajdhani',sans-serif;font-size:.8125rem;font-weight:700;
  letter-spacing:1px;color:var(--muted);margin:18px 0 2px;
  display:flex;align-items:center;justify-content:space-between;width:100%;
  background:none;border:none;border-radius:var(--r);padding:6px 4px;min-height:44px;/* 20/09 RT-321: 36 px era alvo de toque abaixo do minimo de 44 (WCAG 2.5.5). Sao 5 botoes, um por COP, empilhados - nao ha grade que quebre linha. */
  cursor:pointer;text-align:left;}
#filtros-sheet button.ft-grupo:hover{color:var(--text);}
#filtros-sheet button.ft-grupo.on{color:var(--police);}
#filtros-sheet button.ft-grupo .ft-marca{opacity:0;}
#filtros-sheet button.ft-grupo.on .ft-marca{opacity:1;}
#filtros-sheet button.ft-grupo:focus-visible{outline:2px solid var(--police);outline-offset:-2px;}

/* [6] O RODAPE FIXO: fora da rolagem, sempre a vista. E a resposta que faltava -
   "o que meus filtros deixaram passar". A contagem vem de graca: _OC.lista.length
   ja e a lista FILTRADA (em _ocMonta) e _NT.pontos.length ja existia. */
#filtros-sheet .ft-rodape{flex:0 0 auto;display:flex;align-items:center;gap:12px;
  padding:12px 20px;border-top:1px solid var(--border);background:var(--card);
  padding-bottom:calc(12px + env(safe-area-inset-bottom,0px));}
#filtros-sheet .ft-esp{flex:0 0 0;}
/* 14/09 (RT-241, decisao do Ramon): o Limpar deixou de ser link e virou BOTAO
   do mesmo tamanho do Ver mapa, ao lado dele - so que de CONTORNO, sem
   preenchimento. E o par classico de acao primaria e secundaria: mesma forma,
   so uma preenchida. Nao usa o --danger de proposito: no SafeSP o vermelho
   quer dizer RISCO, e gastar essa cor num botao de limpar filtro tira forca
   do significado que ela tem no mapa. */
/* 17/09 (RT-283, decisao do Ramon): A ULTIMA FRASE ACIMA ESTA REVOGADA.
   Ele pediu o Limpar em vermelho e escolheu, entre cinco variantes renderizadas
   no rodape REAL desta aba, a de CONTORNO E TEXTO vermelhos. A forma do RT-241
   fica de pe - mesmo tamanho do Ver mapa, sem preenchimento, acao secundaria:
   muda so a cor, de cinza para --danger.
   MEDIDO ANTES DE ESCREVER, sobre a paleta: --danger sobre --card da 5,23:1,
   acima do minimo de 4,5:1 do WCAG AA. A variante que o instinto pedia - fundo
   --danger com texto BRANCO - da 3,48:1 e REPROVA; ela foi mostrada ao Ramon
   justamente para ele ver a reprovacao com os proprios olhos antes de decidir.
   O preenchimento continua sendo so do Ver mapa, entao a hierarquia entre as
   duas acoes nao mudou - o vermelho aqui diz "isto desfaz", nao "isto e o
   principal". Ver SAFESP.md 9.219. */
#filtros-sheet .ft-limpar{background:none;border:1px solid var(--danger);
  color:var(--danger);font-family:'Rajdhani',sans-serif;font-size:.9375rem;font-weight:700;
  letter-spacing:.4px;border-radius:var(--r);padding:0 20px;min-height:44px;cursor:pointer;
  white-space:nowrap;flex:1;max-width:220px;}
#filtros-sheet .ft-limpar:focus-visible{outline:2px solid var(--police);outline-offset:2px;}
#filtros-sheet .ft-ver{background:var(--police);color:#06121f;border:1px solid var(--police);
  border-radius:var(--r);font-family:'Rajdhani',sans-serif;font-size:.9375rem;font-weight:700;
  letter-spacing:.4px;padding:0 20px;min-height:44px;cursor:pointer;white-space:nowrap;
  flex:1;max-width:220px;}
#filtros-sheet .ft-ver:focus-visible{outline:2px solid var(--text);outline-offset:2px;}

/* [2] SEGMENTADO: um bloco so com divisorias, no lugar de N pilulas soltas. */
#filtros-sheet .seg{display:flex;border:1px solid var(--border);border-radius:var(--r);overflow:hidden;}
/* 20/09 (RT-318, D6): font-size:.75rem e min-height:40px SAIRAM desta regra -
   so elas. O bloco [4-bis] mais abaixo (RT-307, 20/09) reescreve as duas com
   .875rem e 44px, com a MESMA forca e depois no arquivo: nunca valeram. */
#filtros-sheet .seg button{flex:1;background:transparent;border:none;border-left:1px solid var(--border);
  color:var(--muted);padding:0 6px;font-family:inherit;cursor:pointer;
  display:flex;align-items:center;justify-content:center;gap:5px;white-space:nowrap;}
#filtros-sheet .seg button:first-child{border-left:none;}
#filtros-sheet .seg button.on{background:rgba(0,212,255,.10);color:var(--text);}
#filtros-sheet .seg button:focus-visible{outline:2px solid var(--police);outline-offset:-2px;}
/* 16/09 (RT-267): a fileira dos ANOS, logo abaixo da dos meses. Herda TODO o
   desenho do .seg - e o mesmo controle segmentado, so que de ano - e ganha
   apenas o respiro entre as duas fileiras. Duas regras, nao um componente
   novo: repetir o desenho aqui seria criar a segunda copia que a A226 acabou
   de cobrar noutro lugar.
   O .seg-parc e a contagem do ano INCOMPLETO. Ela existe porque ano parcial e
   a regra, nao a excecao: a SSP publica com ~2 meses de atraso, entao o ano
   corrente sempre vem pela metade. Discreto de proposito - informa sem
   competir com o ano, que e o que se clica. */
#filtros-sheet .seg-ano{margin-top:8px;}
/* 19/09 (RT-298): .68rem = 10,9 px, abaixo do piso de 12 px do FE-12 (entrou
   depois dele, no RT-267). Sobe para .75rem = 12 px; a opacidade continua
   fazendo o papel de 'parcial'. */
#filtros-sheet .seg-parc{font-size:.75rem;opacity:.62;font-weight:600;}

/* [3] O FILETE no lugar do circulo colorido. A cor continua sendo a MESMA do
   marcador no mapa - la ela e informacao - mas para de competir no painel. */
#filtros-sheet .fil{display:inline-block;width:3px;height:13px;border-radius:2px;flex:0 0 auto;opacity:.45;}
#filtros-sheet .on .fil{opacity:1;}
#filtros-sheet .f-cel{background:var(--celular);}
#filtros-sheet .f-vei,#filtros-sheet .f-rec{background:var(--warn);}
#filtros-sheet .f-tra,#filtros-sheet .f-por{background:var(--trafico);}
#filtros-sheet .f-arm{background:var(--arma);}

/* [4] Categorias de noticia: caixa reta com filete. Sao OITO, com nomes
   longos ("Trafico / operacao policial") - segmentado nao caberia. */
#filtros-sheet .cats{display:flex;flex-wrap:wrap;gap:6px;}
/* 20/09 (RT-318, D6): min-height:40px SAIU - so ele. O bloco [4-bis] mais
   abaixo (RT-307) fixa 44px com a mesma forca e depois no arquivo.
   O font-size:.75rem daqui tambem e sobrescrito la, mas NAO entrou na
   medicao do D6 e por isso fica para a proxima rodada. */
#filtros-sheet .cats button{display:inline-flex;align-items:center;gap:7px;background:transparent;
  border:1px solid var(--border);color:var(--muted);border-radius:var(--r);padding:0 11px;
  font-family:inherit;cursor:pointer;} /* 21/09: font-size:.75rem removido, morto desde o RT-307 porque o bloco 4-bis logo abaixo ja sobrescreve com .875rem */
#filtros-sheet .cats button.on{color:var(--text);border-color:#2b4266;}
#filtros-sheet .cats button:focus-visible{outline:2px solid var(--police);outline-offset:2px;}

/* [4-bis] AS OPCOES sobem de 12 para 14px e o alvo de toque vai a 44px.
   Veio da secao [4] la de cima em 20/09 (RT-307). Precisa ficar DEPOIS das
   regras de .seg button e .cats button acima, senao nao vale de nada. */
#filtros-sheet .seg button{font-size:.875rem;min-height:44px;}
#filtros-sheet .seg button.on{box-shadow:inset 0 0 0 1px var(--police);}
#filtros-sheet .cats button,#filtros-sheet .oc-chip{font-size:.875rem;min-height:44px;padding:0 13px;}
#filtros-sheet .cats button.on{border-color:var(--police);background:rgba(0,212,255,.07);}

/* [5] Rotulos sem MAIUSCULA: maiuscula com letter-spacing e a marca de painel
   gerado. O proprio texto ja separa as secoes. */
#filtros-sheet .oc-rot,#filtros-sheet .nt-rot{text-transform:none;letter-spacing:0;
  font-size:.8125rem;color:var(--muted);margin:16px 0 6px;font-weight:600;}

/* [6] Acao secundaria deixa de ser botao. O alvo de toque continua em 44px. */
/* 19/09 (RT-297): sairam daqui .rotsw, .zerar, .ft-sub e .ft-swlinha - classes
   que nenhum arquivo usa (grep em js/html/css em 19/09; 'zerar' no app.js e
   valor de acao, nao classe). Restos da gaveta anterior ao RT-239/RT-242. */
/* 14/09 (RT-242, pedido do Ramon): 'Filtros avancados' ganha sublinhado e
   destaque no mouse. O sublinhado diz que e clicavel sem virar botao; no hover
   o texto CLAREIA e o traco engrossa. Nada de fundo aparecendo - o efeito e do
   mesmo material do resto do painel. O @media (hover:hover) existe para o dedo
   no celular nao deixar o estado preso depois do toque (A182). */
#filtros-sheet .avanc{width:100%;background:none;border:none;border-top:1px solid var(--border);
  color:var(--muted);font-family:inherit;font-size:.8125rem;padding:13px 0 2px;margin-top:16px;
  cursor:pointer;text-align:left;min-height:44px;
  text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:4px;
  transition:color .15s,text-decoration-thickness .15s;}
@media (hover:hover){
  #filtros-sheet .avanc:hover{color:var(--text);text-decoration-thickness:2px;}
}
#filtros-sheet .avanc:focus-visible{outline:2px solid var(--police);outline-offset:-2px;color:var(--text);}
#filtros-sheet .avanc:focus-visible{outline:2px solid var(--police);outline-offset:-2px;}
    .oc-sw{width:36px;height:20px;border-radius:10px;background:transparent;
      border:1px solid var(--border);position:relative;padding:0;cursor:pointer;
      flex:0 0 auto;transition:background .15s,border-color .15s;}
    .oc-sw::after{content:'';position:absolute;left:2px;top:1.5px;width:14px;height:14px;
      border-radius:50%;background:var(--muted);transition:left .15s,background .15s;}
    /* 29/08: nasceu ambar e o Ramon preferiu o azul depois de ver na tela.
       Mesmos valores do #follow-fab-btn.active: um so significado de
       "ligado" no app inteiro. */
    .oc-sw.on{background:rgba(0,212,255,.15);border-color:var(--police);}
    .oc-sw.on::after{left:18px;background:var(--police);}
    .oc-sw:focus-visible{outline:2px solid var(--police);outline-offset:2px;}
    /* 21/09: referencia a .oc-parada removida do comentario, ela saiu no RT-318 (D11). Continua valendo o motivo: a chave desenhada tem 36x20px. */
    .oc-sw::before{content:'';position:absolute;left:50%;top:50%;width:44px;
      height:44px;transform:translate(-50%,-50%);}
    /* 20/09 (RT-318, D11): .oc-chip.oc-zerar SAIU - 'oc-zerar' nao aparece em
       nenhum .js ou .html (grep de 20/09). O 'zerar' do app.js e VALOR DE ACAO
       (_ocAlterna('zerar','')), nao classe - o RT-297 ja anotara isso na
       secao [6] deste arquivo. */

    /* o controle de periodo.
       20/09 (RT-318, D11): o TRILHO de quatro paradas SAIU daqui - .oc-trilho,
       .oc-cheio e .oc-parada (com .on, :focus-visible e o ::before de 44px).
       Nenhum .js, .html ou .css citava as tres (grep de 20/09): o RT-239
       (14/09) trocou o trilho pelo controle SEGMENTADO, como o proprio
       app.js:5071 registra. A .oc-per foi removida em 21/09, nenhum .js ou .html usa a classe, so o atributo data-oc-per, que e outra coisa. */
    .oc-marcas{display:flex;justify-content:space-between;font-size:.75rem;
      color:var(--muted);padding:0 2px;}
    .oc-marcas b{color:var(--police);font-weight:600;}
    .oc-chips{display:flex;flex-wrap:wrap;gap:6px;}
    .oc-chip{display:inline-flex;align-items:center;gap:6px;background:transparent;
      border:1px solid var(--border);color:var(--muted);border-radius:var(--r);
      padding:6px 10px;font-size:.75rem;font-family:inherit;cursor:pointer;
      transition:border-color .15s,color .15s,background .15s;}
    .oc-chip .oc-mk{width:20px;height:20px;border-width:1px;}
    .oc-chip.on{border-color:var(--police);color:var(--text);background:rgba(0,212,255,.08);}
    .oc-chip:focus-visible{outline:2px solid var(--police);outline-offset:2px;}
    /* 20/09 (RT-318, D11): o seletor de ID #oc-mes SAIU - nenhum elemento tem
       id="oc-mes". O que existe e a CLASSE .oc-chip.oc-mes (logo abaixo) e o
       atributo data-oc-mes, os dois escritos em app.js:5193. */
    .oc-esperando{opacity:.45;pointer-events:none;}

    /* 30/08: o rodape da gaveta SAIU inteiro por pedido do Ramon - a contagem
       e a linha da fonte. A atribuicao CC-BY-4.0 da SSP-SP, que a licenca
       EXIGE, mudou de lugar: agora vive na privacy.html. .oc-vazio FICA: quem
       usa e o #oc-lista, nao o rodape. Ver SAFESP.md 9.127. */
    .oc-vazio{display:block;color:var(--text);}

    /* ══ OCORRENCIAS v2 (29/08): varios meses, filtro por DP, tabela de ruas ══ */
    #oc-espera{display:none;margin:2px 0 12px;padding:9px 11px;border-radius:var(--r);
      background:rgba(0,212,255,.08);border:1px solid var(--police);
      color:var(--police);font-size:.75rem;}
    .oc-chips-mes{margin-top:7px;}
    .oc-chip.oc-mes{min-width:60px;justify-content:center;font-variant-numeric:tabular-nums;}
    /* O aviso de quanto falta baixar aparece ANTES do download, nunca depois. */
    .oc-peso{margin-top:8px;font-size:.75rem;color:var(--warn);}
    .oc-peso b{color:var(--warn);}

    /* 29/08: o botao de texto "Onde estou" comia ~35% da largura no celular.
       Virou o icone do FAB de GPS, DENTRO do campo. O alvo de toque continua
       com 44px - ele e maior que o desenho, como manda a M07-b. */
    .oc-dplinha{position:relative;display:flex;margin-bottom:6px;}
    #oc-dpbusca{flex:1;min-width:0;background:var(--bg);color:var(--text);
      border:1px solid var(--border);border-radius:var(--r);
      padding:8px 44px 8px 10px;font-family:inherit;font-size:.8125rem;
      /* 20/09 (RT-321): sem min-height a caixa ficava com ~35 px de altura efetiva,
         abaixo dos 44 da M07-b. Com box-sizing:border-box (seletor * na linha 50)
         este valor e a altura TOTAL, nao soma aos paddings. O .oc-aqui-ic tem
         top:0;bottom:0 e acompanha sozinho - por isso ele nao precisa de troca. */
      min-height:44px;}
    .oc-aqui-ic{position:absolute;right:0;top:0;bottom:0;width:44px;background:none;
      border:none;color:var(--police);display:flex;align-items:center;
      justify-content:center;cursor:pointer;padding:0;}
    .oc-aqui-ic svg{width:18px;height:18px;}
    .oc-aqui-ic:focus-visible{outline:2px solid var(--police);outline-offset:-2px;
      border-radius:var(--r);}
    #oc-dpbusca::placeholder{color:var(--muted);}
    .oc-dplista{display:flex;flex-wrap:wrap;gap:6px;max-height:172px;overflow-y:auto;
      padding:2px;}
    .oc-dplista .oc-mais{width:100%;color:var(--muted);font-size:.75rem;padding:4px 2px;}

    .oc-abrir{width:100%;justify-content:center;padding:10px;font-size:.8125rem;}
    .oc-rolo{max-height:290px;overflow-y:auto;border:1px solid var(--border);
      border-radius:var(--r);}
    /* 29/08 (2a volta da auditoria, MEDIDO no Chromium a 320/360/412 px): a
       tabela de 4 colunas dava ao NOME DA RUA menos largura que as tres
       colunas auxiliares somadas - 119 px contra 125 em um aparelho de
       320 px. "AVENIDA SENADOR TEOTONIO VILELA" quebrava em QUATRO linhas e
       cabiam 3 ruas e meia na tela. Virou uma lista de duas linhas: o nome
       ocupa a largura inteira (104 -> 206 px), e bairro, pontinhos e numero
       descem para a segunda. Nao ha tabela: nao ha dado tabular aqui, ha uma
       lista ordenada de lugares. */
    .oc-tab{width:100%;font-size:.75rem;}
    .oc-lin{padding:7px 8px;border-bottom:1px solid var(--border);}
    .oc-lin:last-child{border-bottom:none;}
    .oc-l1{display:flex;align-items:baseline;gap:7px;}
    .oc-l2{display:flex;align-items:center;gap:8px;margin-top:2px;padding-left:23px;}
    .oc-pos{flex:0 0 auto;min-width:16px;text-align:right;color:var(--muted);
      font-variant-numeric:tabular-nums;}
    .oc-rua{flex:1;min-width:0;color:var(--text);line-height:1.35;}
    /* 11 px por DECISAO do Ramon, excecao consciente ao piso de 12 px (A97):
       em 12 px o bairro ficava do mesmo tamanho do nome da rua e a unica
       diferenca entre os dois virava a cor. Contraste medido: 5,68:1, AA. */
    /* 12/09 (RT-207): a regra .oc-bai saiu com o bairro da linha da lista.
       ATENCAO: era ela, com flex:1, que empurrava icones e numero para a
       direita - o .oc-tp abaixo recebeu margin-left:auto no lugar. */
    .oc-tp{flex:0 0 auto;white-space:nowrap;display:flex;align-items:center;margin-left:auto;}
    /* pontinho colorido por tipo: diz de que crime e a rua sem gastar largura */
    .oc-pt{display:inline-block;width:7px;height:7px;border-radius:50%;margin-right:2px;}
    .oc-pt.oc-cel{background:var(--celular);}
    .oc-pt.oc-vei,.oc-pt.oc-rec{background:var(--warn);}
    .oc-pt.oc-tra,.oc-pt.oc-por{background:var(--trafico);}
    .oc-pt.oc-arm{background:var(--arma);}
    /* 16/09 (RT-271): a VARIACAO entre dois anos, na propria linha da rua.
   Verde quando cai, vermelho quando sobe - decisao do Ramon. As duas cores
   sao as da paleta, e o uso respeita o significado que ela reserva: --safe e
   «seguro» (rua com menos ocorrencia ficou mais segura) e --danger e «alerta»
   (rua que piorou merece um). MEDIDO: 10,92:1 e 5,23:1 sobre o fundo da
   lista, ambas acima do minimo de 4,5:1 do WCAG AA.
   So aparece quando o recorte tem os MESMOS meses de dois anos - a regra vive
   no _ocComparavel() do app.js, e o porque esta escrito la. */
/* 19/09 (RT-298): .72rem = 11,5 px, abaixo do piso do FE-12 (entrou no RT-284).
   Sobe para .75rem = 12 px. */
.oc-var{flex:0 0 auto;font-size:.75rem;font-weight:700;margin-left:6px;white-space:nowrap;}
.oc-cai{color:var(--safe);}
.oc-sobe{color:var(--danger);}
.oc-igual{color:var(--muted);}
/* 17/09 (RT-286): via SEM registro no ano anterior. Nao e piso (o piso caiu
   no RT-284), e ausencia de conta: nao existe divisao por zero. O ponto e
   discreto de proposito - a explicacao esta no title, para quem passar o
   mouse - e usa o --muted, a cor de "informacao secundaria" da paleta. */
.oc-semb{color:var(--muted);opacity:.6;cursor:help;}
/* 17/09 (RT-286): o aviso no topo da lista quando o recorte INTEIRO nao tem
   comparacao (mes sem par no ano anterior). Herda o .oc-dica e so ganha o
   respiro e a borda que o separam da primeira linha. */
.oc-semcmp{margin:8px 12px 4px;padding:8px 10px;border:1px solid var(--border);
  border-radius:var(--r);line-height:1.45;}
.oc-qtd{flex:0 0 auto;text-align:right;color:var(--text);font-weight:700;
      font-variant-numeric:tabular-nums;}
    /* 44 px por decisao do Ramon: e botao de polegar, na base da lista, usado
       com o aparelho em movimento. Tinha 28 px - passava no minimo de 24 da
       WCAG 2.5.8, mas longe do confortavel. */
    .oc-mais50{width:100%;justify-content:center;margin-top:8px;min-height:44px;}

    /* ══ OCORRENCIAS v3 (29/08): multipla escolha e filtro avancado ══════ */
    /* A cor do chip ligado passa a ser a MESMA do botao Seguir-GPS quando
       ativo (#follow-fab-btn.active), por pedido do Ramon. Um so significado
       de "ligado" no app inteiro vale mais que variacao bonita. */
    .oc-chip.on{background:rgba(0,212,255,.15);color:var(--police);
      border-color:var(--police);}
    .oc-chip.on .oc-mk{filter:none;}

    .oc-dica{margin-top:6px;font-size:.75rem;color:var(--muted);}
    .oc-chip.oc-dia{min-width:48px;justify-content:center;}
    /* A referencia do "Onde estou": sem ela o policial nao tem como saber se
       o app acertou a delegacia dele. */
    .oc-onde{margin:7px 0 2px;padding:8px 10px;border-radius:var(--r);
      background:rgba(0,212,255,.10);border:1px solid var(--police);
      color:var(--text);font-size:.75rem;}
    .oc-onde b{color:var(--police);}
    .oc-dpsel{margin-top:8px;}
    .oc-chip.oc-limpa{color:var(--danger);border-color:var(--border);}

    .oc-av{margin-top:4px;padding-top:12px;border-top:1px solid var(--border);}
    .oc-avcx{margin-top:10px;padding:12px;border:1px solid var(--border);
      border-radius:var(--r);background:rgba(255,255,255,.02);}
    .oc-avcx .oc-rot:first-child{margin-top:0;}

    /* ══ OCORRENCIAS v5 (29/08): a lista de ruas virou ABA LATERAL ═══════ */
    /* Ela mora na esquerda porque a direita ja tem a coluna de FABs e o menu
       abre por la. A aba inteira desliza; o puxador anda junto, colado na
       borda direita dela - fechada, so o puxador fica na tela. */
    /* 29/08 (relatado pelo Ramon no APARELHO, E5): o topo era top:64px, um
       numero CHUTADO. O #topbar nao tem 64 px - ele cresce com
       env(safe-area-inset-top), com min-height:54px!important e com a linha do
       DP, que quebra em DUAS em tela estreita. A barra cobria o titulo da aba.
       30/08: passou a usar a --tbh, que JA EXISTIA no app.js desde a v12 e que
       o #drawer ja usava - eu tinha criado uma --topbar-h duplicada sem
       procurar antes. A --tbh agora mede o fim do CABECALHO, incluindo a barra
       de busca aberta. O 96px e so a rede de seguranca se o JS nao rodar. */
    #oc-aba{position:fixed;left:0;top:calc(var(--tbh, 96px) + 8px);bottom:88px;width:85%;max-width:420px;
      z-index:640;display:none;transform:translateX(-100%);
      transition:transform .32s cubic-bezier(.4,0,.2,1);}
    #oc-aba.tem{display:block;}
    #oc-aba.open{transform:translateX(0);}
    #oc-aba-cx{height:100%;background:var(--card);border-right:1px solid var(--border);
      border-top-right-radius:var(--r);border-bottom-right-radius:var(--r);
      box-shadow:4px 0 22px rgba(0,0,0,.55);padding:12px 12px 10px;
      display:flex;flex-direction:column;overflow:hidden;}
    .oc-aba-tit{font-family:'Rajdhani',sans-serif;font-size:1rem;font-weight:700;
      letter-spacing:1px;text-transform:uppercase;color:var(--police);
      margin-bottom:8px;flex:0 0 auto;}
    #oc-lista{flex:1;min-height:0;display:flex;flex-direction:column;}
    /* dentro da aba a tabela rola sozinha e ocupa a altura que sobrar */
    #oc-lista .oc-rolo{flex:1;min-height:0;max-height:none;}

    /* O puxador: alvo de 44px, o minimo confortavel para o polegar. Fica
       03/09: ate hoje a largura era 26px - o comentario prometia 44 desde
       29/08 e o codigo nunca cumpriu. Ramon relatou no APARELHO (E5) que o
       dedo raspava na moldura do celular para alcancar o botao.
       colado na borda direita da aba, entao acompanha o deslizar. */
    #oc-aba-puxador{position:absolute;left:100%;top:50%;transform:translateY(-50%);
      width:44px;height:64px;padding:0;background:var(--card);color:var(--police);
      border:1px solid var(--border);border-left:none;
      border-top-right-radius:var(--r);border-bottom-right-radius:var(--r);
      box-shadow:3px 0 12px rgba(0,0,0,.5);cursor:pointer;
      /* 03/09: sem touch-action o navegador entende o dedo deslizando como
         rolagem e rouba o gesto - o arrasto lateral nunca chega ao codigo.
         Mesma propriedade que a alca das gavetas ja usa. */
      touch-action:none;
      display:flex;align-items:center;justify-content:center;}
    #oc-aba-puxador svg{width:18px;height:18px;transition:transform .32s ease;}
    #oc-aba.open #oc-aba-puxador svg{transform:rotate(180deg);}
    #oc-aba-puxador:focus-visible{outline:2px solid var(--police);outline-offset:2px;}

    /* a linha da lista e botao: precisa parecer tocavel. Seletor pelo
       atributo, nao pela tag - assim sobrevive a troca de estrutura. */
    [data-oc-rua]{cursor:pointer;}
    [data-oc-rua]:active{background:rgba(0,212,255,.10);}
    [data-oc-rua]:focus-visible{outline:2px solid var(--police);
      outline-offset:-2px;}
    #oc-lista .oc-vazio{padding:14px 4px;color:var(--muted);font-size:.8125rem;}

    /* ══ O NUMERO DO ESTUPRO NA AREA (29/08) ═══════════════════════════════
       Pedido do Ramon: o rosa nao dizia quantos eram, e tom contra tom nao e
       lido como numero por ninguem. O numero vai escrito no meio da area do
       DP. Sem caixa, sem seta, sem fundo: so o algarismo com sombra, para
       nao virar mais um cartao em cima do mapa. */
    .oc-est-num{background:none;border:none;box-shadow:none;padding:0;
      color:#fff;font-family:'Rajdhani',sans-serif;font-weight:700;
      font-size:.875rem;letter-spacing:.5px;
      text-shadow:0 1px 4px rgba(0,0,0,.95),0 0 2px rgba(0,0,0,.9);
      pointer-events:none;white-space:nowrap;}
    .oc-est-num::before{display:none;}
    /* 29/08 (auditoria): abaixo do zoom 12 o rotulo some e so a cor da area
       fica. Uma regra de CSS em vez de mexer nos 93 tooltips um a um. */
    #map.oc-est-oculto .oc-est-num{display:none;}

    /* ══ MODO ESCURO DO MAPA (31/08) ═════════════════════════════════════
       O Ramon relatou no aparelho: "no branco e no dark a fonte esta grande
       e tem ruas que nao aparece o nome". Causa: o Canvas da Esri acaba no
       zoom 16 e o bloco era ESTICADO ate o 17 - a letra crescia junto.
       A base passou a ser o World_Street_Map, que tem bloco nativo ate o
       zoom 18+. Ele e claro; o modo escuro e o MESMO mapa com este filtro.
       invert(1) troca claro por escuro e hue-rotate(180deg) devolve as cores
       ao lugar - sem ele, o verde do parque viraria rosa.
       ⚠️ A classe fica na CAMADA, nao no painel: o Leaflet poe todas as
       camadas de bloco no mesmo painel, e um filtro no painel inverteria
       tambem o satelite. Os marcadores vivem em outro painel e nao entram. */
    .oc-mapa-escuro{filter:invert(1) hue-rotate(180deg) brightness(.92) contrast(1.05);}


/* ── Camada de notícias (03/09/2026) — anexado ao app.css em 03/09/2026 ──
   Segue as classes da camada da SSP (.oc-mk, .oc-pop, .oc-chip) com prefixo nt-.
   Sem gradiente, sem emoji, sem barra colorida (regra visual de 23/08). */
.nt-mk{display:inline-flex;align-items:center;justify-content:center;position:relative;
  border-radius:50%;border:1.5px solid #0b1220;box-shadow:0 1px 3px rgba(0,0,0,.6);}
.nt-mk svg{width:62%;height:62%;}
.nt-mini{width:20px;height:20px;border-width:1px;margin-right:6px;flex:none;}

.nt-pop{font-size:.8125rem;line-height:1.5;}
.nt-pop b{font-family:'Rajdhani',sans-serif;letter-spacing:.8px;display:block;font-size:.875rem;margin-bottom:5px;}
.nt-pop .nt-meta{display:block;margin-top:6px;color:var(--muted);font-size:.75rem;line-height:1.45;}
.nt-pop .nt-link{display:inline-block;margin-top:8px;color:var(--police);text-decoration:underline;min-block-size:44px;line-height:44px;}
/* 14/09: a regra .nt-pop .nt-av saiu daqui. O span que ela pintava foi
   removido do balao no mesmo dia (noticias.js, _ntPopup), entao ela nao
   pintava mais nada. A IRMA dela, #nt-controles .nt-av logo abaixo, FICA:
   essa ainda pinta o aviso da gaveta de filtros da camada. */

.nt-bloco{margin:10px 0;}
.nt-rot{font-family:'Rajdhani',sans-serif;letter-spacing:.8px;font-size:.8125rem;color:var(--muted);margin-bottom:6px;}
.nt-chips{display:flex;flex-wrap:wrap;gap:6px;}
.nt-chip{display:inline-flex;align-items:center;min-block-size:44px;padding:0 12px;border-radius:22px;
  border:1px solid var(--border);background:var(--card);color:var(--muted);font-size:.8125rem;cursor:pointer;}
.nt-chip.on{color:var(--text);border-color:var(--police);}
.nt-chip.nt-cat:not(.on) .nt-mk{filter:grayscale(1);opacity:.55;}
.nt-rodape{margin-top:10px;font-size:.8125rem;color:var(--text);}
#nt-controles .nt-av{margin-top:10px;padding-top:8px;border-top:1px solid var(--border);color:var(--muted);font-size:.75rem;line-height:1.45;}


/* == LEGENDA DO MAPA DE CALOR (04/09, RT-138 parte B) =======================
   Pedido do Ramon: a escala de cores abaixo do cracha de risco, e SO quando a
   mancha de calor esta na tela.
   POR QUE FLUTUA em vez de entrar na barra: o #topbar tem height:48px FIXO, e
   essa altura alimenta a variavel --tbh, que posiciona o #alert-ticker (o
   aviso de risco). Aumentar a barra moveria o alerta - risco que nao vale a
   pena correr por uma legenda.
   z-index 999, ABAIXO do #alert-ticker (1001): se um aviso de risco aparecer,
   ele cobre a legenda. Num app de seguranca essa e a prioridade certa.
   ATENCAO: as paradas do degrade sao AS MESMAS do _OC_CALOR_RAMPA no app.js
   (0% ciano / 35% verde / 62% ambar / 100% vermelho). Se a rampa mudar la,
   mude aqui - senao a legenda passa a descrever um desenho que nao existe. */
#status-box{position:relative;}
/* 14/09 (FE-12/RT-236, achado E8 de 09/09): a LEGENDA DOS CIRCULOS nasce aqui,
   dividindo a caixa com a do mapa de calor. Uma OU outra, nunca as duas - quem
   decide e o _calorLegenda() pelo zoom: calor de 10 a 15, circulos em 16 e 17,
   alfinete no 18. As regras do DESCANSO (.dsc-on, .dsc-nome) ficam SO no
   #calor-legenda e vem depois na cascata, entao continuam valendo. */
#calor-legenda,#circ-legenda{position:absolute;top:100%;left:50%;transform:translateX(-50%);
  margin-top:5px;z-index:999;display:none;align-items:center;gap:6px;
  padding:3px 8px;border-radius:var(--r);background:rgba(0,0,0,.6);
  border:1px solid rgba(255,255,255,.12);white-space:nowrap;pointer-events:none;}
#calor-legenda.v,#circ-legenda.v{display:flex;}
/* ── 14/09 (RT-228): O NOME DO CRIME NA TELA DE DESCANSO ──────────────────
   Decisao do Ramon: o nome aparece LOGO ACIMA da escala de cores, formando um
   bloco so com ela. NAO e coluna: a legenda tem QUATRO filhos (o nome, Baixa,
   a barra <i> e Alta) e flex-direction:column empilharia os quatro.
   E GRID de tres colunas, com o nome atravessando as tres (grid-column:1/-1).
   POR QUE GRID E NAO FLEX COM QUEBRA DE LINHA: a legenda flutua (position
   absolute), e um flex que quebra linha decide a largura ANTES de saber que
   vai quebrar - sobrava espaco vazio nas laterais. MEDIDO em 14/09 com a
   Rajdhani real: flex dava 239px para os TRES nomes do ciclo, inclusive
   TRAFICO DE DROGAS, cujo texto mede 119px; grid acompanha o conteudo e da
   170 a 178px. FRONTEIRA: se um dia entrar um nome MUITO mais largo que a
   escala (~150px), o excesso estica as tres colunas e afasta Baixa e Alta da
   barra. Com os nomes de hoje (158, 155 e 119px) isso nao acontece.
   O display exige .v JUNTO: .v e quem faz a legenda aparecer, e sem essa
   exigencia a .dsc-on sozinha a tornaria visivel na hora errada.
   Volta a ser uma linha so quando ele sai, porque a classe cai junto.
   O elemento .dsc-nome e criado e removido pelo descanso.js; estas regras
   ficam ORFAS e inofensivas se aquele arquivo for retirado do app.html, que e
   como se desfaz a tela de descanso inteira. */
#calor-legenda.v.dsc-on{display:grid;grid-template-columns:auto auto auto;
  justify-content:center;align-items:center;gap:2px 6px;padding:5px 9px;}
#calor-legenda .dsc-nome{font-family:'Rajdhani',sans-serif;font-weight:700;
  font-size:.8125rem;letter-spacing:.8px;color:var(--text);white-space:nowrap;}
#calor-legenda.dsc-on .dsc-nome{grid-column:1 / -1;text-align:center;}
#calor-legenda.dsc-on i{width:96px;}
/* 14/09 (RT-230, pedido do Ramon): os avisos somem enquanto o descanso roda.
   ⚠️ O #alert-ticker E o container dos toasts (o app.js escreve os toasts dentro
   dele), entao esconder um esconde o outro - inclusive o alerta de RISCO. O
   Ramon confirmou sabendo disso: durante o descanso a maquina esta parada e
   QUALQUER movimento encerra tudo, entao o alerta reaparece no primeiro toque.
   A regra cai sozinha ao sair, porque a classe .dsc-ativo sai do <html>. */
html.dsc-ativo #alert-ticker{display:none;}
/* 14/09 (FE-12/RT-235, achado V4): .625rem = 10px estava abaixo do piso de 12px.
   MEDIDO antes de subir, com a Rajdhani real e os tres nomes do ciclo: a caixa
   nao cresce no caso mais largo (178px, onde quem manda e o NOME) e cresce no
   maximo 7px no mais curto (TRAFICO DE DROGAS, 170 -> 177). O grid do RT-232
   absorve sozinho - nada do ajuste daquela rodada se perde. */
#calor-legenda span,#circ-legenda span{font-family:'Rajdhani',sans-serif;font-size:.75rem;
  font-weight:600;letter-spacing:.3px;color:var(--muted);}
/* As bolinhas: a MESMA cor dos circulos no mapa, lida das variaveis, para nunca
   descrever um desenho que nao existe (mesma regra do gradiente do calor).
   MEDIDO em 14/09 com a Rajdhani real: a legenda inteira da 295px em qualquer
   tela. Em aparelho de 300px sobram 3px de cada lado - aperta, mas nao estoura;
   em 360px, o comum, sobram 33px. */
#circ-legenda .lg{width:10px;height:10px;border-radius:50%;flex-shrink:0;border:1px solid rgba(255,255,255,.35);}
#circ-legenda .lg-cel{background:var(--celular);}
#circ-legenda .lg-vei{background:var(--warn);}
#circ-legenda .lg-tra{background:var(--trafico);}
#circ-legenda .lg-n{margin-left:4px;padding-left:8px;border-left:1px solid rgba(255,255,255,.18);}
#calor-legenda i{width:64px;height:7px;border-radius:var(--r);
  background:linear-gradient(90deg,#00d4ff 0%,#00e676 35%,#ffb830 62%,#ff3b5c 100%);}
@media (max-width:380px){#calor-legenda i{width:48px;}}

/* === RT-144 - 04/09/2026 - balao instantaneo dos alfinetes de noticia =====
   O Leaflet desenha o tooltip com estilo PROPRIO e CLARO: fundo branco e
   letra preta. Sem esta regra ele nasceria branco no meio de um app escuro.
   Espelha o .comm-num-tip (linha 346), que ja faz o mesmo nas comunidades -
   muda so a cor, porque aquele e vermelho por ser NUMERO de comunidade e
   este e o TITULO da materia.
   ARMADILHA: o ::before e a setinha do balao. Sem repinta-la sobra um
   triangulo BRANCO apontando para o alfinete. A classe dupla
   (.nt-tip.leaflet-tooltip-top) e de proposito: da especificidade maior que
   a regra do leaflet.css e vence independentemente da ordem de carga. */
.nt-tip{background:rgba(13,21,38,.92);color:var(--text);border:1px solid var(--border);
  font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif; /* 21/09: Inter removida tambem aqui, nenhum arquivo dessa fonte e servido pelo projeto, mesma razao da nota RT-320 da linha 77 */
  font-size:.75rem;font-weight:500;line-height:1.3;padding:6px 9px;
  border-radius:var(--r);box-shadow:0 2px 8px rgba(0,0,0,.45);
  width:max-content;max-width:220px;white-space:normal;
  text-align:center;text-wrap:balance;}
/* 14/09, pedido do Ramon depois de ver o balao corrigido no ar: texto
   CENTRALIZADO. O text-align sozinho centra mas nao reequilibra - MEDIDO no
   titulo da captura, as linhas continuavam com 32, 29 e 21 caracteres. Com
   text-wrap:balance o navegador redistribui as palavras e elas viram 30, 28 e
   24: a diferenca entre a maior e a menor cai de 11 para 6 caracteres.
   O balance e OPCIONAL para o navegador - quem nao entende ignora a linha e
   mostra o mesmo que o text-align sozinho. Nao ha o que quebrar. */
/* 14/09 (item 8 da fila de 13/09) - POR QUE width:max-content.
   O leaflet.css define .leaflet-tooltip{position:absolute;white-space:nowrap}.
   A linha acima troca para normal, e um elemento absoluto SEM largura
   declarada encolhe ate a palavra mais longa: o max-width poe teto, nao poe
   piso. MEDIDO em 14/09 no Leaflet 1.9.4 com o titulo da captura do Ramon:
   a largura calculada era 46px, o balao ficava com 64px e TREZE linhas.
   Com width:max-content: 220px e 3 linhas. Titulo curto cai de 3 para 1.
   O respiro subiu de 4/8 para 6/9 no mesmo pedido. A decisao de 13/09 dizia
   "limitar a largura" - a medicao mostrou o contrario, e foi superada.
   ATENCAO: .nt-tip e compartilhada com as CAMERAS desde o FE-10. */
.nt-tip.leaflet-tooltip-top::before{border-top-color:rgba(13,21,38,.92);}

/* === RT-145 - 04/09/2026 - a barra do topo passa a FLUTUAR sobre o mapa ====
   DECISAO DO RAMON: a barra "some" e as pecas ficam boiando sobre o mapa, na
   mesma disposicao. Logo e aviso de estado SEM caixa; lupa e menu COM pilula
   redonda escura.

   POR QUE O <header> NAO E REMOVIDO DO HTML: a --tbh e calculada em
   o app.js, por getBoundingClientRect().bottom - que mede em relacao a
   JANELA, nao ao documento. Com position:fixed o fundo da barra continua a
   48px do topo da TELA, entao a conta continua certa SOZINHA e o
   #alert-ticker, o #drawer e o #oc-aba nao se mexem. Demolir o header
   obrigaria a reconstruir essa medicao - o terreno exato da A100.
   Nenhuma linha do app.html precisou ser tocada nesta rodada.

   [1] A barra sai do empilhamento e vira vidro. O #map-wrap e flex:1 dentro
   de um body flex-column com height:100%, entao o mapa cresce sozinho os
   48px que a barra devolveu - sem tocar em nada do mapa. */
#topbar{position:fixed!important;top:0;left:0;right:0;
  background:transparent!important;border-bottom:none!important;
  pointer-events:none;}

/* [2] Pilula redonda + o vazio da barra deixando o dedo passar.
   O pointer-events e o ponto critico: sem ele sobraria uma PAREDE INVISIVEL
   de 48px na largura toda, e o policial nao conseguiria arrastar o mapa pelo
   topo - pior que hoje, porque hoje ele ao menos VE a barra que o impede.
   A logo e o aviso de estado ficam de fora de proposito: nao sao clicaveis,
   entao nao ha razao para roubarem toque do mapa.
   O 44px nao e escolha estetica: e o piso de alvo de toque que a regra [1] la
   de cima ja impunha por min-inline-size. Escrever menos que isso nao
   funcionaria (min- vence width) e desligar aquela regra seria remover uma
   protecao existente. */
/* 09/09 (FE-06): as regras dos botoes de busca e menu da barra superior sairam com eles. */

/* [3] CONTORNO das letras soltas. O fundo do mapa e imagem de SATELITE: muda
   de branco para preto a cada metro que o policial anda. MEDIDO pela formula
   do WCAG contra um telhado claro, o aviso de area SEGURA dava 1,35:1 e o de
   ATENCAO 1,40:1 - ilegiveis (o minimo e 4,5:1). Ate o vermelho de risco
   reprovava, com 2,82:1.
   O contorno poe uma borda escura em volta de cada letra: o que ENCOSTA na
   letra passa a ser sempre escuro, seja qual for o fundo. E o que todo mapa
   do mundo faz com nome de rua, e nao custa processamento nenhum.
   Vale para o .logo e o #risk-badge. Ate 19/09 a lista tambem citava #dp-badge
   e #ir-badge, que sairam do app.html em 02/09; sairam daqui no item 5 da
   revisao de 18/09. Se um dia voltarem, recolocar os dois nesta lista. */
.logo,#risk-badge{
  text-shadow:0 0 3px rgba(0,0,0,.95),0 0 6px rgba(0,0,0,.85),
    -1px -1px 0 rgba(0,0,0,.9),1px -1px 0 rgba(0,0,0,.9),
    -1px 1px 0 rgba(0,0,0,.9),1px 1px 0 rgba(0,0,0,.9),
    0 1px 4px rgba(0,0,0,.9);}

/* [4] A barra de busca COBRE o topo enquanto se digita. Decisao do Ramon.
   ARMADILHA EVITADA: a alternativa era pousa-la ABAIXO da barra, com
   top:var(--tbh). Mas a --tbh e calculada a partir da PROPRIA barra de busca
   (o app.js usa o max das duas). Ela se posicionaria pela variavel que ela
   mesma alimenta: um laco. Nao estoura na hora - produz desalinhamento que so
   aparece em certos tamanhos de tela, dos defeitos mais dificeis de achar
   depois. Em top:0 o laco simplesmente nao existe.
   z-index 1002 fica ACIMA do #topbar (1000) para cobri-lo, e abaixo do
   #drawer (2000). O fundo dela continua SOLIDO de proposito: e um campo de
   digitacao, nao pode ficar sobre foto de satelite. */
/* 14/09 (RT-219, decisao do Ramon): a barra deixa de ser uma FAIXA de ponta a
   ponta colada no topo e vira uma peca CENTRALIZADA sobre o mapa. Largura
   maxima 520px e cantos de 10px, os dois escolhidos por ele num desenho
   comparativo. NO CELULAR O LIMITE NAO AGE: ali ela usa a largura toda menos
   24px de folga, porque 520 e mais largo que a tela - a escolha de largura e,
   na pratica, uma decisao sobre telas grandes.
   A ABERTURA PASSOU A SER POR OPACIDADE, nao por display: display nao anima, e
   enquanto ele mandasse nao existiria a transicao de 200ms pedida.
   TRES PECAS ANDAM JUNTAS e tirar uma quebra as outras duas: esta regra, o
   _tbhAgora do bgeo-bridge.js, e a guarda .open no calculo da --tbh (app.js).
   Sem a guarda, a barra FECHADA passaria a contar na altura do cabecalho - ela
   continua ocupando retangulo, so invisivel - e desceria o #alert-ticker, o
   #oc-aba e o proprio #search-results.
   Continua ACIMA do #topbar (1002 contra 1000) e abaixo do #drawer (2000). O
   fundo continua SOLIDO de proposito: e campo de digitacao, nao pode ficar
   sobre foto de satelite. */
#topbar-search-bar{position:fixed;z-index:1002;display:flex;
  top:calc(9px + env(safe-area-inset-top,0px));left:50%;right:auto;
  width:calc(100% - 24px);max-width:520px;
  padding:11px 14px;
  border:1px solid var(--border);border-radius:10px;
  box-shadow:0 6px 22px rgba(0,0,0,.55);
  opacity:0;visibility:hidden;transform:translateX(-50%) translateY(-8px);
  transition:opacity .2s ease,transform .2s ease,visibility .2s;}
#topbar-search-bar.open{opacity:1;visibility:visible;
  transform:translateX(-50%) translateY(0);}

/* 17/09 (RT-283, pedido do Ramon): O X MUDOU DE DONO.
   Ele era IRMAO do campo, colado na parede da caixa, a 14 px da borda e do
   tamanho de um "fechar janela" - e o Ramon leu exatamente isso: "da a sensacao
   de fechar a search bar". A leitura estava certa sobre o desenho e errada
   sobre o comportamento: desde 14/09 (RT-243) o X SO LIMPA; quem fecha e a
   lupa do leque e a tecla Esc. O desenho e que nao tinha acompanhado.
   Agora o campo tem parede propria (.tsrch-campo) e o X mora DENTRO dela, como
   pastilha redonda. E o padrao que o Chrome e o Android usam dentro de campo de
   texto, e ele diz "apaga o que escrevi", nao "fecha a janela".
   MEDIDAS: o circulo tem 20 px e o campo 3 px de respiro, entao a caixa interna
   fica com 28 px e a barra sobe de 42 para 48 px - 6 px a mais. Isso NAO quebra
   nada porque a --tbh e recalculada por um ResizeObserver que observa esta
   barra (app.js, fim do arquivo): o banner de risco, a aba de ocorrencias e a
   lista de resultados descem junto, sozinhos.
   O :focus-within acende a moldura INTEIRA quando o cursor esta no campo; por
   isso o brilho do proprio input e desligado logo abaixo - dois aneis de foco
   dentro um do outro ficam sujos, e o de fora e o que tem forma de campo.
   O .tsrch-campo nao declara cor de texto nem fonte de proposito: tudo continua
   vindo do #search-input-top, para nao existirem dois lugares dizendo o mesmo.
   Ver SAFESP.md 9.219. */
#topbar-search-bar .tsrch-campo{flex:1;min-width:0;display:flex;align-items:center;
  gap:6px;background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.08);
  border-radius:8px;padding:3px 4px 3px 10px;}
#topbar-search-bar .tsrch-campo:focus-within{border-color:rgba(0,212,255,.55);
  box-shadow:0 0 0 2px rgba(0,212,255,.12);}
#topbar-search-bar #search-input-top:focus{box-shadow:none;}
#topbar-search-bar #search-clear-top{width:20px;height:20px;flex-shrink:0;
  display:flex;align-items:center;justify-content:center;border-radius:50%;
  background:rgba(255,255,255,.12);color:var(--text);cursor:pointer;}
#topbar-search-bar #search-clear-top:hover{background:rgba(255,255,255,.20);}
#topbar-search-bar #search-clear-top:focus-visible{outline:2px solid var(--police);
  outline-offset:2px;}
/* 17/09 (RT-286, achado da varredura de vespera): a pastilha tem 20 px e o
   minimo recomendado de alvo de toque e 44 (WCAG 2.5.5). Num app usado com
   uma mao, em movimento, alvo de 20 px erra. O pseudo-elemento abaixo e
   INVISIVEL e so estende a area que aceita o toque: 20 + 12 + 12 = 44 px.
   O desenho nao muda um pixel. position:relative e o que ancora o ::after. */
#topbar-search-bar #search-clear-top{position:relative;}
#topbar-search-bar #search-clear-top::after{content:'';position:absolute;inset:-12px;}

/* [5] A lista de resultados desce para o fim do cabecalho. Ela nasce com
   top:0 num style= dentro do app.html; como o mapa agora comeca no topo da
   TELA, sem isto os resultados apareceriam POR BAIXO da logo e dos botoes.
   O !important e justamente o que vence um style= escrito no HTML - foi assim
   que o app.html ficou intocado nesta rodada. */
#search-results{top:var(--tbh,54px)!important;}
/* 14/09 (RT-219): a lista ACOMPANHA a barra. Sem isto ela continuaria de ponta
   a ponta (left:0!important / right:0!important, linha 223) e ficaria uma faixa
   larga pendurada numa caixa estreita. Os !important daqui vencem aqueles
   porque sao igualmente important e vem DEPOIS no arquivo.
   O top continua saindo da --tbh, que agora so cresce com a barra ABERTA. */
#search-results{left:50%!important;right:auto!important;
  top:calc(var(--tbh,54px) + 6px)!important;
  transform:translateX(-50%);width:calc(100% - 24px);max-width:520px;
  border:1px solid var(--border);border-radius:10px;
  box-shadow:0 6px 22px rgba(0,0,0,.55);}

/* ── 07/09 (RT-175): O QUE NAO SERVE NO COMPUTADOR ───────────────────────────
   A classe .e-pc no <html> vem do _ehComputador() do app.js: UMA decisao so,
   usada aqui e no JS. Sai o SOS (emergencia por WhatsApp) e sai Comunidades -
   a lista e a distancia dependem da posicao, e no computador ela vem da rede.
   Os POLIGONOS das comunidades CONTINUAM no mapa: quem os desenha e o
   renderComm(), que roda sempre e nao passa por aqui.
   O !important e OBRIGATORIO no #sos-fab-btn - ele tem display:flex escrito na
   PROPRIA ETIQUETA, e estilo inline vence qualquer regra normal. E o mesmo
   motivo do #search-results logo acima. Ver armadilha A144. */
html.e-pc #sos-fab-btn{display:none!important;}
html.e-pc #layers-fab-btn{display:none!important;}
/* 13/09 (RT-210): O SEGUIR-GPS SOZINHO NO MEIO DO RODAPE, NO COMPUTADOR.
   A posicao normal dele e medida A PARTIR DO SOS: 50% + 36px poe a borda
   esquerda a 8px da borda direita do SOS, que tem 56px e fica centrado.
   Mas a regra logo ACIMA esconde o SOS no computador - entao la o GPS
   ficava 36px a direita de um botao invisivel, sem simetria nenhuma.
   MEDIDO EM PRODUCAO, 13/09, em tela de 1280: o GPS caia em x=676 com o
   centro da tela em 640. Sem o SOS ao lado, o lugar certo e o centro
   exato: 50% menos metade dos 44px do proprio botao.
   No CELULAR nada muda - la o SOS existe e a regra normal continua valendo.
   Decisao do Ramon, 13/09, depois de ver o efeito na tela. */
html.e-pc #follow-fab-btn{left:calc(50% - 22px);}
/* 13/09 (RT-211): O CRACHA DE STATUS NAO APARECE NO COMPUTADOR.
   Os tres estados que existem de verdade - BUSCANDO GPS, AREA SEGURA e AREA
   DE RISCO - deixam de ser mostrados aqui. No CELULAR nada muda.
   POR QUE visibility E NAO display: medido em producao, 13/09. Com display
   none o cracha sai do fluxo, a #calor-legenda SOBE 19px (de y=48 para y=29)
   e passa a montar em cima da .logo, que termina em y=33 - quatro pixels de
   sobreposicao. O visibility esconde SEM tirar do fluxo: a legenda fica onde
   estava e a logo continua intacta. Decisao do Ramon, 13/09, entre tres
   caminhos medidos.
   A regra vai SEM o sufixo de prioridade, de proposito: nenhuma outra regra
   do arquivo define visibility para este elemento - conferido no navegador, e
   as duas formas dao exatamente o mesmo resultado. Prioridade que nao e
   precisa so atrapalha quem vier depois.
   ATENCAO, O QUE ISTO CUSTA: o cracha e o UNICO aviso visivel de area de
   risco. O outro aviso, a notificacao do sistema (_triggerZoneNotif), depende
   de permissao do navegador - medida como negada no navegador de teste - e
   ainda tem trava de 24h por comunidade. E o #danger-overlay, a moldura
   vermelha que existiria para isso, NUNCA foi ligado por codigo nenhum em
   todo o historico do projeto (quatro buscas no git, todas vazias). Logo: no
   computador, dentro de uma comunidade, a tela nao dira nada. DECISAO DO
   RAMON, 13/09, tomada com este fato na mao: o site no PC e ferramenta de
   planejamento, nao de patrulha.
   Ver tambem a regra da RT-192 mais abaixo, que aumenta a fonte do cracha no
   computador: continua valendo na cascata e deixou de ter efeito visivel. */
html.e-pc #risk-badge{visibility:hidden;}

/* ── 07/09 (RT-176): O LEQUE DOS BOTOES DO MAPA ─────────────────────────────
   Fechado, os botoes do grupo recolhem por VISIBILITY, nunca por display:none.
   A razao e concreta: o calculo de altura do app.js pula quem esta com
   display:none, e no computador o RT-175 esconde Comunidades exatamente assim.
   Se o leque tambem usasse display, os dois estados se confundiriam e a coluna
   abriria com um buraco no meio.

   A REDE DE SEGURANCA e o html.fab-pronto: essa classe so aparece depois que o
   app.js montou o botao principal. Se o JS falhar, NADA e escondido e o mapa
   continua com os cinco botoes como sempre esteve. Esconder sem confirmacao do
   JS deixaria o app sem botao nenhum diante de qualquer erro.
   13/09 (RT-210): a marca unica virou DUAS - html.fab-pronto-esq e
   html.fab-pronto-dir - e os "cinco botoes" acima sao 11, em duas colunas. A
   regra que recolhe, mais abaixo, ja esta escrita nessa forma.

   O grupo ja tem transition:all .2s la em cima, entao a abertura anima de
   graca. O SOS nao pertence ao grupo e nao e tocado por nada disto. */
/* 08/09 (RT-178): O CONSERTO DO LEQUE QUE NAO RECOLHIA.
   O RT-176 subiu com a regra CERTA e mesmo assim os cinco botoes continuavam
   visiveis. A causa, medida em producao: a classe .fab tem transition:all .2s,
   e o estado fechado era aplicado no MESMO quadro em que o botao principal
   nascia. O navegador tentava animar a partir de um estado que ainda nao
   existia e a transicao ficava PRESA em "running" - e transicao em andamento
   tem a MAIOR precedencia da cascata CSS, acima ate do !important. Prova: com
   as transicoes canceladas a mao, opacity ia de 1 para 0 na hora.
   A regra abaixo desliga a animacao SO no primeiro instante; o app.js remove a
   classe fab-iniciando depois de dois quadros, e a animacao volta ao normal. */
html.fab-iniciando .fab{transition:none!important;}
/* 13/09 (RT-210): DUAS marcas, uma por leque, no lugar de uma so. Cada lado so
   autoriza o CSS a recolher DEPOIS que o SEU botao de abrir existe. Com marca
   unica, falhar ao montar um dos dois botoes esconderia o grupo do OUTRO lado
   sem deixar forma de abrir - a rede de seguranca viraria a causa da queda.
   O .fab-solto (Seguir GPS) nao entra em nenhuma das duas: vive fora dos
   leques, ao lado do SOS, e esta SEMPRE a vista. Decisao do Ramon, 13/09. */
html.fab-pronto-esq:not(.fab-aberto-esq) .fab-camada,
html.fab-pronto-dir:not(.fab-aberto-dir) .fab-acao{
  opacity:0;
  visibility:hidden;
  pointer-events:none;
  transform:translateY(10px);
}
#fab-menu-esq,#fab-menu-dir{
  position:fixed;
  bottom:calc(26px + env(safe-area-inset-bottom,0px));
  width:44px;
  height:44px;
  border-radius:50%;
  z-index:501;
  border:1px solid var(--border);
  background:var(--card);
  color:var(--muted);
  display:flex;
  align-items:center;
  justify-content:center;
  cursor:pointer;
  box-shadow:0 4px 16px rgba(0,0,0,.5);
  transition:all .2s;
  font-family:Rajdhani,sans-serif;
}
/* 13/09 (RT-210): um botao de abrir em cada canto de baixo. So o lado das
   camadas pinta de azul - acao nao "fica ativa". */
#fab-menu-esq{left:14px;}
#fab-menu-dir{right:14px;}
#fab-menu-esq:active,#fab-menu-dir:active{transform:scale(.92);}
/* Os MESMOS valores do #follow-fab-btn.active: um significado so para o azul
   em todo o app - "isto esta ativo". Ver a nota da linha 585. */
#fab-menu-esq.active,#fab-menu-dir.active{background:rgba(0,212,255,.15);color:var(--police);border-color:var(--police);}
#fab-menu-esq .fab-rot,#fab-menu-dir .fab-rot{font-size:1.5rem;line-height:1;font-weight:300;}
/* 14/09 (item 1 da fila de 13/09): SO o botao da direita troca o "+" por uma
   engrenagem. O font-size acima deixa de ter efeito nele, porque o span passa a
   conter um <svg> e nao texto - fica ali para o lado da ESQUERDA, que continua
   com + e -.
   O GIRO E DE 45 GRAUS, nao 180: a engrenagem tem 8 dentes, entao 45 e meio
   dente e o desenho fica visivelmente fora de posicao. Com 180 ela voltaria a
   parecer identica, e o botao aberto ficaria igual ao fechado - o app perderia
   o unico sinal visivel de estado que o +/- dava.
   A TECNICA NAO E NOVA: e a mesma do puxador da aba lateral (#oc-aba-puxador
   svg, linhas 814-815), inclusive no tempo de 0,32s, para o movimento ser da
   mesma familia em todo o app. */
#fab-menu-dir .fab-rot{display:flex;align-items:center;justify-content:center;}
#fab-menu-dir .fab-rot svg{width:20px;height:20px;transition:transform .32s ease;}
html.fab-aberto-dir #fab-menu-dir .fab-rot svg{transform:rotate(45deg);}
/* 09/09 (FE-02): a regra .tem-num saiu junto com o contador. O botao mostra
   "+" fechado e "−" aberto; a classe .active (azul) diz se ha camada ligada. */

/* ── 09/09 (FE-02): ESQUEMA DOS BOTOES FLUTUANTES NO MAPA CLARO ─────────────
   O app.js marca <html data-fundo="dark|white|topo3d"> em setLayer(). No fundo
   claro, cartao escuro translucido sobre tile claro ficava dificil de ver
   (pedido do Ramon, item 13). Aqui os botoes flutuantes viram claros.
   O azul "isto esta ativo" continua sendo o MESMO significado, em outra
   luminosidade: #00d4ff sobre branco da 1,6:1 (reprova); #00648a da 5,6:1 sobre #e6f4fa.
   Fundos dark e topo3d (satelite escuro) mantem o esquema original.
   Especificidade: html[data-fundo] + #id = (1,1,1) > #id.active = (1,1,0). */
/* 09/09 (RT-188, parte 1): O SELETOR ERA POR CLASSE E PERDIA A DISPUTA.
   O FE-02 escreveu ".fab" aqui. MEDIDO em producao: dos 7 elementos, so o "+"
   e o puxador ficaram claros; os outros cinco continuaram escuros COM a borda
   clara - um estado misto. A causa e a A144, que este mesmo arquivo ja
   documentava na linha 604: o fundo de cada botao vem da regra POR ID, e ID
   vence classe na cascata do CSS mesmo estando 500 linhas acima. A borda
   mudava porque a borda E da classe .fab. Agora cada ID esta escrito.
   Especificidade: html[attr] + #id = (1,1,1) > #id = (1,0,0). */
/* 09/09 (RT-190): os DOIS BOTOES NOVOS DO FE-03 entram aqui. Sem esta
   linha eles nasceriam com o defeito da A181: fundo por ID, fora das
   regras de cor, escuros no mapa claro e sem contorno no satelite.
   Nao entram nas regras .active: o de fundo tem TRES estados (nao e
   interruptor) e o Instagram e link - nenhum dos dois fica azul.
   12/09 (RT-191): #busca-fab-btn entra junto, pelo mesmo motivo. Ele tambem
   nao e interruptor: abre a caixa de busca, nao liga camada.
   12/09 (RT-194): #ajuda-fab-btn entra junto. E um <a> para /ajuda.html;
   tambem nao liga camada, entao so nas regras de estado normal.
   12/09 (RT-197): #filtros-fab-btn entra junto. Ele ABRE a gaveta de filtros;
   quem liga camada sao os interruptores de Ocorrencias e Noticias. */
/* ══ 14/09 (RT-243, pedido do Ramon): AS TRES PECAS ACOMPANHAM O FUNDO ═════
   A gaveta de filtros, os toasts e a barra de busca ficavam escuras sobre o
   mapa claro. Em vez de listar dezenas de seletores, aqui se REDEFINEM AS
   VARIAVEIS de cor dentro de cada contentor - e elas sao HERDADAS, entao tudo
   dentro muda de uma vez.
   ⚠️ Este vazamento por heranca e a armadilha registrada em 13/09 (mudar
   --text num contentor muda todo o conteudo dele). AQUI ELE E O OBJETIVO, e
   para na borda de cada um dos quatro seletores abaixo - nada fora deles muda.
   Os valores sao os MESMOS que os botoes flutuantes ja usam no fundo claro
   (#1a2a45 sobre branco), para as pecas nao divergirem entre si. */
html[data-fundo="white"] #filtros-sheet,
html[data-fundo="white"] #alert-ticker .toast,
html[data-fundo="white"] #topbar-search-bar,
html[data-fundo="white"] #search-results{
  --card:#ffffff; --text:#1a2a45; --muted:#5f7590; --border:#d8e0ec; --bg:#f4f7fb;
  background:rgba(255,255,255,.97); color:#1a2a45;}
/* ══ 15/09 (RT-245): NO 3D AS QUATRO PECAS FICAM ESCURAS, NAO CLARAS ═══════
   O RT-243 copiou aqui o bloco do fundo CLARO e trocou so o nome do seletor.
   Com isso contrariou a decisao que ESTE MESMO ARQUIVO ja registrava 80
   linhas abaixo (ver o comentario acima de html[data-fundo="topo3d"]
   #oc-aba-cx): sobre o satelite, que e uma FOTO, caixa escura com borda clara
   e o unico contraste que se sustenta sobre telhado branco, asfalto preto e
   mata verde. Os 14 botoes flutuantes e a aba lateral ja seguiam essa regra;
   estas quatro pecas ficavam brancas e destoavam de tudo - defeito relatado
   pelo Ramon em 15/09, visto SO no fundo 3D.
   Aqui NAO se redefinem as variaveis de cor: o escuro ja e o padrao, basta
   nao mexer. Muda so o que SEPARA a caixa da imagem embaixo dela.
   Por que border-color e nao border: as quatro pecas tem bordas diferentes -
   a gaveta tem borda so no TOPO no celular e nos quatro lados no computador
   (linha 682), o toast tem borda da cor do proprio fundo, e o
   #search-results nao tem borda nenhuma. border-color muda a COR e preserva
   a espessura de cada uma; border: 1px solid daria a gaveta lados que ela
   nunca teve no celular.
   Por que uma regra de sombra por peca: cada uma tem a sua profundidade e
   box-shadow substitui, nao soma. Escrever uma sombra unica tiraria do
   cartao do computador a sombra grande que o RT-240 lhe deu.
   Valores: os MESMOS dos botoes flutuantes no 3D - nao foram inventados. */
html[data-fundo="topo3d"] #filtros-sheet,
html[data-fundo="topo3d"] #alert-ticker .toast,
html[data-fundo="topo3d"] #topbar-search-bar{
  border-color:rgba(255,255,255,.85);}
html[data-fundo="topo3d"] #filtros-sheet{
  box-shadow:0 0 0 2px rgba(0,0,0,.62), 0 24px 64px rgba(0,0,0,.6);}
html[data-fundo="topo3d"] #alert-ticker .toast{
  box-shadow:0 0 0 2px rgba(0,0,0,.62), 0 4px 20px rgba(0,0,0,.5);}
html[data-fundo="topo3d"] #topbar-search-bar{
  box-shadow:0 0 0 2px rgba(0,0,0,.62), 0 6px 22px rgba(0,0,0,.55);}
html[data-fundo="topo3d"] #search-results{
  box-shadow:0 0 0 2px rgba(0,0,0,.62), 0 8px 24px rgba(0,0,0,.6);}
/* O botao primario do rodape mantem o ciano nos tres fundos: ele e a acao, e
   trocar a cor dele por fundo tiraria a unica referencia fixa do painel. */

/* 19/09 (RT-291, defeito visto pelo Ramon no fundo claro): a regra abaixo estava
   no MEIO da lista de seletores do fundo branco, logo depois de uma virgula.
   Comentario nao separa seletor: o display:none valia para os 9 botoes da lista
   (comunidades, ocorrencias, noticias, cameras, Seguir GPS, desenho, os dois
   leques e a busca) - e no fundo claro sobravam so Instagram, fundo e filtros.
   Movida para ANTES da lista. Nada mais mudou. */
/* 16/09 (RT-270, decisao do Ramon): o botao de AJUDA sai da tela.
   MOTIVO: as paginas para as quais ele leva (/ajuda.html e as que saem dela)
   ainda nao foram revisadas, e mostrar na apresentacao um caminho que ninguem
   conferiu e oferecer ao publico a unica parte do app sem auditoria.
   POR QUE display:none E NAO visibility: a pilha de botoes se remonta sozinha.
   O _lista() do app.js filtra por display !== 'none' (e o comentario dele diz
   que este e o UNICO jeito de sair da conta), entao a coluna fecha o vao em
   vez de abrir um buraco onde o botao estava. Mesmo mecanismo do RT-175.
   PARA REVERTER: apague as duas linhas abaixo. Nada mais depende delas - o
   <a> continua no app.html, com href e aria-label intactos.
   PENDENCIA ABERTA: revisar /ajuda.html antes de mostrar o botao de novo.
   19/09 (RT-300): a pagina foi revisada (frases atualizadas, secao 'Como usar
   o mapa', X sem JavaScript, modo offline) e o botao VOLTOU - a regra
   #ajuda-fab-btn{display:none;} que ficava aqui saiu. */

html[data-fundo="white"] #layers-fab-btn,
html[data-fundo="white"] #oc-fab-btn,
html[data-fundo="white"] #nt-fab-btn,
html[data-fundo="white"] #cm-fab-btn,
html[data-fundo="white"] #follow-fab-btn,
html[data-fundo="white"] #comm-fab-btn,
html[data-fundo="white"] #fab-menu-esq,
html[data-fundo="white"] #fab-menu-dir,
html[data-fundo="white"] #busca-fab-btn,
html[data-fundo="white"] #ajuda-fab-btn,
html[data-fundo="white"] #filtros-fab-btn,
html[data-fundo="white"] #fundo-fab-btn,
html[data-fundo="white"] #ig-fab-btn,
html[data-fundo="white"] #oc-aba-puxador{
  background:rgba(255,255,255,.94);
  color:#1a2a45;
  border-color:#5f7590;
  box-shadow:0 4px 16px rgba(0,0,0,.22);
}
/* 14/09 (RT-226, defeito achado pelo Ramon): a CAIXA da aba acompanha o fundo
   do mapa. A setinha ao lado dela ja fazia isso desde que foi criada; a caixa
   nao, e ficava escura sobre o mapa claro. So passou a incomodar hoje porque a
   aba nasce ABERTA no computador desde o RT-217 - antes ela quase nao aparecia.
   COMO ISTO MUDA TUDO DE UMA VEZ: o conteudo da aba (nome da rua, contagem,
   bairro, divisorias, o botao Ver mais 50) usa --text, --muted, --border e
   --card. Redefinir essas quatro AQUI DENTRO faz todas as regras de dentro
   seguirem sozinhas, porque variavel de CSS e HERDADA. Nenhuma regra do
   conteudo foi tocada. As cores sao as MESMAS que o puxador ja usa - nao ha
   paleta nova, so a extensao da que existe ao lado. */
/* ⚠️ O TITULO PRECISA DE COR PROPRIA AQUI. Ele usa --police (#00d4ff), que
   sobre o fundo escuro da aba da 10,29:1 e sobre o branco desta regra cairia
   para 1,77:1 - MEDIDO pela formula do WCAG, contra um minimo de 4,5:1. Ficaria
   praticamente ilegivel. O #155e75 e o mesmo azul escurecido ate caber no fundo
   claro: 7,27:1, nivel AAA. Nao e cor nova de significado, e o mesmo "azul de
   destaque" noutro tom - a mesma coisa que --text e --muted fazem logo abaixo.
   Isto so apareceu porque a aba foi RENDERIZADA nos tres fundos antes de
   publicar; lendo o CSS nao se ve. */
html[data-fundo="white"] #oc-aba-cx .oc-aba-tit{color:#155e75;}
html[data-fundo="white"] #oc-aba-cx{
  background:rgba(255,255,255,.96);
  --text:#1a2a45;
  --muted:#5f7590;
  --border:#c3ccd9;
  --card:rgba(255,255,255,.92);
  border-color:#5f7590;
  box-shadow:4px 0 22px rgba(0,0,0,.22);
}
html[data-fundo="white"] #layers-fab-btn.active,
html[data-fundo="white"] #oc-fab-btn.active,
html[data-fundo="white"] #nt-fab-btn.active,
html[data-fundo="white"] #cm-fab-btn.active,
html[data-fundo="white"] #follow-fab-btn.active,
html[data-fundo="white"] #comm-fab-btn.active,
html[data-fundo="white"] #fab-menu-esq.active,
html[data-fundo="white"] #fab-menu-dir.active{
  background:#e6f4fa;
  color:#00648a;
  border-color:#00648a;
}

/* 09/09 (RT-188, parte 2): SATELITE (3D) - escolha do Ramon, opcao B.
   O 3D nao e "escuro": e o fundo mais VARIAVEL dos tres - telhado claro,
   laje, mata, sombra, asfalto. Nenhuma cor de botao contrasta com tudo isso
   ao mesmo tempo, entao o que resolve nao e a COR e sim a SEPARACAO: contorno
   duplo. A borda clara aparece sobre area escura; o anel escuro por fora
   aparece sobre area clara. Sempre um dos dois separa.
   O fundo do botao ja era opaco. Quem deixava a imagem de satelite atravessar
   era o estado LIGADO, azul a 15%. O #0b3247 e exatamente a cor que esses 15%
   de #00d4ff produzem sobre o #0d1526 do fundo - por isso no mapa ESCURO nada
   muda de aparencia, e aqui a imagem para de atravessar.
   Contraste do icone #00d4ff sobre #0b3247: 7,5:1 - calculo WCAG, nao
   medicao de tela. O icone parado segue em var(--muted): 5,7:1 sobre o fundo
   do botao, ja acima do minimo de 4,5:1. */
html[data-fundo="topo3d"] #layers-fab-btn,
html[data-fundo="topo3d"] #oc-fab-btn,
html[data-fundo="topo3d"] #nt-fab-btn,
html[data-fundo="topo3d"] #cm-fab-btn,
html[data-fundo="topo3d"] #follow-fab-btn,
html[data-fundo="topo3d"] #comm-fab-btn,
html[data-fundo="topo3d"] #fab-menu-esq,
html[data-fundo="topo3d"] #fab-menu-dir,
html[data-fundo="topo3d"] #busca-fab-btn,
html[data-fundo="topo3d"] #ajuda-fab-btn,
html[data-fundo="topo3d"] #filtros-fab-btn,
html[data-fundo="topo3d"] #fundo-fab-btn,
html[data-fundo="topo3d"] #ig-fab-btn,
html[data-fundo="topo3d"] #oc-aba-puxador{
  background:#0d1526;
  border-color:rgba(255,255,255,.85);
  box-shadow:0 0 0 2px rgba(0,0,0,.62), 0 4px 16px rgba(0,0,0,.5);
}
/* No 3D a aba continua ESCURA, igual ao puxador: o satelite e uma foto, e
   texto claro sobre fundo escuro e o unico contraste que se sustenta sobre
   qualquer telhado. Muda so a borda e a sombra, que sao o que separa a aba da
   imagem embaixo dela. */
html[data-fundo="topo3d"] #oc-aba-cx{
  border-color:rgba(255,255,255,.85);
  box-shadow:0 0 0 2px rgba(0,0,0,.62), 4px 0 22px rgba(0,0,0,.5);
}
html[data-fundo="topo3d"] #layers-fab-btn.active,
html[data-fundo="topo3d"] #oc-fab-btn.active,
html[data-fundo="topo3d"] #nt-fab-btn.active,
html[data-fundo="topo3d"] #cm-fab-btn.active,
html[data-fundo="topo3d"] #follow-fab-btn.active,
html[data-fundo="topo3d"] #comm-fab-btn.active,
html[data-fundo="topo3d"] #fab-menu-esq.active,
html[data-fundo="topo3d"] #fab-menu-dir.active{
  background:#0b3247;
  color:var(--police);
  border-color:rgba(0,212,255,.9);
  box-shadow:0 0 0 2px rgba(0,0,0,.62), 0 4px 16px rgba(0,0,0,.5);
}

/* -- 12/09 (RT-192): O CRACHA DE RISCO CRESCE DE VERDADE --------------------
   O FE-04 (RT-191) escreveu font-size, padding e line-height do #risk-badge na
   linha 409. Nao teve efeito NENHUM: a linha 446 declara as MESMAS tres com
   !important e a MESMA especificidade (1,0,0), e vem DEPOIS no arquivo. Entre
   dois !important empatados em especificidade vence o ULTIMO - armadilha A184.
   MEDIDO em producao em 12/09: no celular o cracha continuava em 12px, que era
   exatamente o defeito que o FE-04 existia para corrigir. No computador
   funcionava por acidente: html.e-pc #risk-badge tem (1,1,1) e ja ganhava.
   A regra abaixo usa html #risk-badge = (1,0,1), maior que (1,0,0): vence por
   MERITO e nao por posicao. Se amanha alguem acrescentar outra regra por ID no
   fim do arquivo, esta continua valendo - que e o erro que nao queremos repetir.
   PADDING 8px 12px: escolha do Ramon vendo os tres formatos lado a lado. O
   cracha nao tem fundo nem borda (a regra do polish v12 zera os dois), entao o
   padding decide SO a altura: 34px numa barra de 56px, com a segunda linha em 35px.
   19/09 (item 5 da revisao de 18/09): a nota de 12/09 que estava aqui - que
   #dp-badge e #ir-badge eram clicaveis e mediam 52x35 e 42x35 - estava ERRADA:
   os dois sairam do app.html em 02/09 (commit b62979c) e nao existem na pagina.
   Pendencia sem objeto, riscada. */
html #risk-badge{
  font-size:1rem!important;
  letter-spacing:.5px!important;
  padding:8px 12px!important;
  line-height:1.15!important;
}

/* ══════════════════════════════════════════════════════════════════════════
   RT-220 - 14/09/2026 - RETORNO DE TOQUE E O PONTO DE CHEGADA
   Pedido do Ramon: deixar claro que a interacao foi registrada, sem "cara de
   efeito". A discricao mora em tres numeros - tamanho, duracao e opacidade -
   e nao em ter ou nao ter o retorno.
   NENHUMA regra daqui muda layout, posicao, dimensao, cor existente ou
   comportamento: sao estados novos (:active, :hover) e dois elementos que
   nascem e morrem sozinhos, os dois com pointer-events:none.
   prefers-reduced-motion nao aparece aqui porque o bloco da linha ~477 ja
   reduz TODA animacao e transicao do app a 0,01ms - estes herdam de graca.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── [1] O HALO DO TOQUE NO MAPA ──────────────────────────────────────────
   Um anel so, 400ms. O elemento e criado pelo app.js no container do mapa e
   removido sozinho. pointer-events:none e obrigatorio: ele nasce exatamente
   sob o dedo, e sem isso roubaria o toque seguinte. z-index 700 fica acima
   dos paineis do mapa (o mais alto e 650) e abaixo dos controles do Leaflet. */
.halo-toque{position:absolute;width:0;height:0;pointer-events:none;z-index:700;}

/* 14/09 (RT-224): o anel da bolha sob o mouse. As bolhas com numero sao
   pintadas DENTRO do canvas da grade, entao nao existe elemento para receber
   :hover - este span e posicionado por cima pelo app.js (_ligaAnel). Mesma cor
   e mesma espessura do anel dos marcadores do zoom 18, para o mapa ter UMA
   linguagem de "isto esta sob o mouse" em todos os zooms.
   pointer-events:none pelo mesmo motivo do halo: ele nasce exatamente sob o
   ponteiro e sem isso roubaria o clique da bolha que esta destacando. */
.oc-bolha-anel{position:absolute;display:none;pointer-events:none;z-index:660;
  border-radius:50%;border:2px solid rgba(0,212,255,.95);
  transform:translate(-50%,-50%);}
.halo-toque i{position:absolute;left:0;top:0;width:12px;height:12px;
  border-radius:50%;border:2px solid var(--police);
  transform:translate(-50%,-50%) scale(.5);opacity:.7;
  animation:halo-toque 400ms cubic-bezier(.22,.7,.3,1) forwards;}
@keyframes halo-toque{
  to{opacity:0;transform:translate(-50%,-50%) scale(4);}
}

/* ── [2] O PONTO DE CHEGADA: bonequinho, sombra e pulso ───────────────────
   O marcador e RECRIADO a cada busca (app.js, _ptMarca), entao a animacao do
   pulso roda uma vez ao nascer, sem JavaScript nenhum. Os tres aneis saem em
   sequencia curta para o olho seguir a expansao em vez de ver um clarao.
   A sombra elipsoide no chao e o que faz o bonequinho parecer APOIADO num
   ponto, em vez de flutuando perto dele - e o que distingue "e aqui" de "ha
   algo por perto". */
.pt-ponto{position:relative;width:21px;height:34px;}
/* 14/09 (RT-222): abaixo do zoom 15 o bonequinho sai. Uma classe no #map e uma
   regra so - o mesmo desenho de #map.oc-est-oculto (linha ~839), e pelo mesmo
   motivo: o navegador resolve de uma vez, sem o JavaScript tocar em marcador
   nenhum. A conta que justifica o 15 esta no app.js, junto do _PT_ZOOM. */
/* 14/09 (RT-226): a regra #map.pt-oculto .pt-rua SAIU daqui. Ela ESCONDIA o
   bonequinho da rua abaixo do zoom 15, e esconder nao era o que o Ramon queria:
   o marcador continuava existindo e reaparecia quando o zoom subia. Agora quem
   resolve e o _ptZoom no app.js, APAGANDO o ponto. O da busca (.pt-busca)
   nunca foi afetado por zoom e continua assim. */
.pt-ponto svg{display:block;filter:drop-shadow(0 2px 3px rgba(0,0,0,.85));}
.pt-sombra{position:absolute;left:50%;bottom:-3px;transform:translateX(-50%);
  width:16px;height:6px;border-radius:50%;background:rgba(0,0,0,.55);}
.pt-pulso{position:absolute;left:50%;bottom:0;width:0;height:0;}
.pt-pulso i{position:absolute;left:0;top:0;width:10px;height:10px;
  border-radius:50%;border:2px solid #fff;
  transform:translate(-50%,-50%) scale(.4);opacity:0;
  animation:pt-pulso 900ms cubic-bezier(.22,.7,.3,1) forwards;}
.pt-pulso i:nth-child(2){animation-delay:.16s;}
.pt-pulso i:nth-child(3){animation-delay:.32s;}
@keyframes pt-pulso{
  0%{opacity:.85;transform:translate(-50%,-50%) scale(.4);}
  100%{opacity:0;transform:translate(-50%,-50%) scale(9);}
}

/* ── [3] PRESSAO NOS CONTROLES QUE FALTAVAM ───────────────────────────────
   Ja existia em .fab (linha 72), .gps-btn (212), [data-oc-rua] (821) e nos
   dois botoes de leque (1156). Aqui entram os que ficaram de fora, com os
   MESMOS valores - inventar uma segunda linguagem de toque seria pior que
   nao ter nenhuma. Os chips descem menos que os botoes redondos porque sao
   largos: 8% de reducao num chip comprido e um salto, num circulo de 44px
   passa despercebido. */
.oc-chip:active,.nt-chip:active{transform:scale(.96);}
#sos-fab-btn:active{transform:scale(.92);}

/* ── [4] HOVER, SO ONDE EXISTE MOUSE ──────────────────────────────────────
   O app nunca teve :hover - nasceu para celular, onde ele nao existe. O
   @media (hover:hover) garante que nada disto sequer e avaliado no telefone:
   sem ele, alguns navegadores moveis deixam o estado "grudado" depois do
   toque, e o marcador ficaria aceso ate o proximo toque em outro lugar.
   NOS MARCADORES: so .oc-mk e .nt-mk, que sao divIcon e tem elemento proprio.
   FICAM DE FORA, e por medicao: cameras e mapa de calor sao pintura dentro de
   UM canvas - nao ha elemento para receber hover, e destacar um item exigiria
   repintar o canvas a cada movimento do mouse (o mesmo mecanismo que custou a
   armadilha A200). Comunidades e inspetorias sao poligonos SVG sem classe
   propria: o unico seletor disponivel seria .leaflet-interactive, que elas
   COMPARTILHAM com as areas de DP - e essas sao invisiveis de proposito desde
   26/08, entao um hover generico as revelaria.
   O prefixo .leaflet-pane ficou por seguranca: este comentario dizia que .oc-mk
   tambem vestia a LEGENDA da gaveta, mas a legenda usa <i class="fil"> desde o
   RT-239 e .oc-mk so aparece nos marcadores (conferido em 19/09, RT-297). */
@media (hover:hover) and (pointer:fine){
  .fab:hover,#fab-menu-esq:hover,#fab-menu-dir:hover,
  .oc-chip:hover,.nt-chip:hover{border-color:rgba(0,212,255,.55);}
  /* 14/09 (RT-223): o brightness(1.18) SAIU. Ele funcionava - medido em
     laboratorio, o filtro era aplicado igualmente no alfinete e na bolinha com
     numero - mas era IMPERCEPTIVEL: 18% de clareamento sobre o azul #2f6fed
     quase nao se distingue, e no marcador com contador o numero BRANCO domina
     o olhar e branco clareado continua branco. O Ramon reportou como "o
     destaque nao aparece nas bolinhas com numeros"; a medicao mostrou que o
     problema nunca foi o seletor, era a dose.
     O ANEL nao depende da cor de dentro, entao vale igual nos dois desenhos.
     ⚠️ A sombra original (0 1px 3px) e REPETIDA aqui de proposito: box-shadow
     substitui a declaracao inteira, e sem repeti-la o marcador PERDERIA a
     sombra justamente sob o mouse. */
  .leaflet-pane .oc-mk:hover,.leaflet-pane .nt-mk:hover{
    box-shadow:0 1px 3px rgba(0,0,0,.6),0 0 0 2px rgba(0,212,255,.95);}

  /* 14/09 (RT-221): a LISTA LATERAL tinha ficado de fora do bloco acima - foi
     omissao, apontada pelo Ramon no teste. A linha da rua ja tinha cursor de
     mao (linha 820) e o fundo do toque (821); faltava o do mouse parado.
     O :active E REAFIRMADO logo abaixo de proposito: o dele mora ANTES deste
     ponto do arquivo e tem a MESMA forca que este :hover, entao sem repeti-lo
     aqui o hover venceria na hora do toque e o clique ficaria SEM retorno. O
     valor e o mesmo de sempre - nada muda, so a ordem passa a estar certa.
     O PUXADOR usa filter e nao border-color porque a cor da borda dele e
     sobrescrita por html[data-fundo="white"] e html[data-fundo="topo3d"], que
     sao mais especificos: um hover de borda nao apareceria em dois dos tres
     fundos do mapa. O filter ninguem sobrescreve, e e o mesmo recurso do hover
     dos marcadores logo acima. */
  [data-oc-rua]:hover{background:rgba(0,212,255,.05);}
  [data-oc-rua]:active{background:rgba(0,212,255,.10);}
  #oc-aba-puxador:hover{filter:brightness(1.25);}
}


/* == 20/09 (RT-317): GUIA RAPIDO - BOTAO SEMPRE A VISTA + GAVETA ============
   BLOCO NOVO E NO FIM DO ARQUIVO, DE PROPOSITO: nada acima foi tocado, para
   nao colidir com as outras frentes que mexem neste mesmo arquivo hoje.

   [1] O BOTAO. E .fab-solto, como o Seguir-GPS: fica FORA dos dois leques (o
   recolhimento so alcanca .fab-camada e .fab-acao) e esta a vista o tempo todo.
   A POSICAO E O ESPELHO DO SEGUIR-GPS, medida a partir do SOS, que tem 56px e
   e centrado - ou seja, vai de 50%-28px a 50%+28px:
     Seguir-GPS  left:calc(50% + 36px)  -> comeca 8px a DIREITA do SOS
     Guia        left:calc(50% - 80px)  -> 44px terminando em 50%-36px,
                                           8px a ESQUERDA do SOS
   OS TRES CENTROS NA MESMA LINHA: o SOS tem 56px de altura sobre base 20px
   (centro a 48px); este tem 44px sobre base 26px (centro a 48px) - a mesma
   conta que o #follow-fab-btn ja fazia.
   FOLGA ATE O LEQUE DA ESQUERDA, medida na tela mais estreita que o app
   atende (320px): 50% = 160px, entao a borda esquerda deste botao cai em 80px
   e o #fab-menu-esq termina em 58px (left:14px + 44px) - sobram 22px. Em
   360px sobram 42px, a mesma folga que o Seguir-GPS tem do outro lado.
   O z-index vem da .fab (500) e NAO e reescrito: a gaveta esta em 700 e
   precisa cobrir o botao. O SOS, que fica em 1001, e apagado pelo proprio
   toggleSheet enquanto houver gaveta aberta - nada a fazer aqui.

   [2] NO COMPUTADOR o SOS nao existe (html.e-pc #sos-fab-btn) e o Seguir-GPS
   assume o centro (50% - 22px, RT-210). Sem o SOS no meio, a referencia deste
   botao sumiu junto: 50%-80px deixaria um buraco de 14px. Aqui ele reencosta
   nos mesmos 8px do celular - 50%-74px termina em 50%-30px e o Seguir-GPS
   comeca em 50%-22px.

   [3] AS CORES DO BOTAO acompanham o fundo do mapa, como os outros 14
   flutuantes (A181): sem estas duas regras ele nasceria escuro sobre o mapa
   claro e sem contorno sobre o satelite. Os valores sao os MESMOS das listas
   por ID que ja existem no arquivo; elas nao foram tocadas justamente para
   este bloco continuar isolado, e a especificidade e identica (1,1,1) - quem
   vence e quem vem depois, que e este bloco.
   Ele NAO entra nas regras .active: nao e interruptor, abre uma gaveta. */
#guia-fab-btn{position:fixed;bottom:calc(26px + env(safe-area-inset-bottom,0px));
  left:calc(50% - 80px);right:auto;width:44px;height:44px;
  background:var(--card);color:var(--muted);}
html.e-pc #guia-fab-btn{left:calc(50% - 74px);}
#guia-fab-btn:focus-visible{outline:2px solid var(--police);outline-offset:2px;}
html[data-fundo="white"] #guia-fab-btn{background:rgba(255,255,255,.94);color:#1a2a45;
  border-color:#5f7590;box-shadow:0 4px 16px rgba(0,0,0,.22);}
html[data-fundo="topo3d"] #guia-fab-btn{background:#0d1526;
  border-color:rgba(255,255,255,.85);
  box-shadow:0 0 0 2px rgba(0,0,0,.62), 0 4px 16px rgba(0,0,0,.5);}

/* [4] A GAVETA. Tres partes, como a de Filtros (RT-240): cabecalho parado,
   miolo que rola e rodape fixo. O overflow:hidden aqui e o par obrigatorio do
   overflow-y:auto do miolo - se a .sheet tambem rolasse, apareceriam duas
   barras e o rodape sairia da tela. O padding sai do contentor e vai para as
   tres partes, senao o rodape nao encostaria nas bordas. */
#guia-sheet{display:flex;flex-direction:column;overflow:hidden;padding:0;}
#guia-sheet .handle{flex:0 0 auto;padding-top:8px;}
#guia-sheet .gu-cab{flex:0 0 auto;padding:0 20px;}
#guia-sheet .sheet-title{display:flex;align-items:center;gap:8px;margin-bottom:10px;}
#guia-sheet .gu-miolo{flex:1 1 auto;min-height:0;overflow-y:auto;padding:0 20px 4px;
  -webkit-overflow-scrolling:touch;}
/* [5] O TEXTO. 13px de corpo (piso do FE-12 e 12px) em --muted, que e o par de
   --card usado em todo o app; o que importa em cada item vai em <b> com --text.
   A NUMERACAO E DO <ol>, nao escrita a mao: leitor de tela anuncia "item 3 de
   9" sozinho, e o ::marker deixa o numero na fonte do titulo sem tocar no
   texto. Divisoria #16233a e a mesma do #filtros-sheet .ft-sec - nao ha cor
   nova neste bloco. */
#guia-sheet .gu-lista{margin:0;padding:0 0 0 22px;}
#guia-sheet .gu-lista li{font-size:.8125rem;line-height:1.55;color:var(--muted);
  padding:11px 0 11px 4px;border-bottom:1px solid #16233a;}
#guia-sheet .gu-lista li:last-child{border-bottom:none;}
#guia-sheet .gu-lista li::marker{color:var(--police);font-family:'Rajdhani',sans-serif;
  font-size:.9375rem;font-weight:700;}
#guia-sheet .gu-lista b{color:var(--text);font-weight:600;}
/* [6] O FILETE DE COR, no molde do #filtros-sheet .fil: a cor e a MESMA do
   marcador no mapa, e a amostra dispensa escrever o hexadecimal no texto.
   A COMUNIDADE e a unica tracejada, porque no mapa ela e contorno e nao
   preenchimento. Sem gradiente: borda pontilhada da o mesmo recado e nao
   inventa um segundo jeito de desenhar tracejado no app. Com width:0 o
   elemento fica com os 3px da propria borda, igual aos outros cinco. */
#guia-sheet .gu-fil{display:inline-block;width:3px;height:12px;border-radius:2px;
  vertical-align:-1px;margin-right:5px;}
#guia-sheet .gu-f-cel{background:var(--celular);}
#guia-sheet .gu-f-vei{background:var(--warn);}
#guia-sheet .gu-f-tra{background:var(--trafico);}
#guia-sheet .gu-f-arm{background:var(--arma);}
#guia-sheet .gu-f-est{background:var(--estupro);}
#guia-sheet .gu-f-com{background:none;width:0;border-left:3px dashed var(--danger);}
/* [7] O RODAPE, no desenho do .ft-limpar/.ft-ver: dois alvos de 44px, o
   secundario so com contorno e o principal preenchido. A diferenca e a COR do
   secundario - la o contorno e --danger porque aquele botao DESFAZ; aqui ele
   LEVA a pagina inteira de ajuda, entao usa --police, o mesmo azul de
   "prosseguir" do resto do app. Medido sobre --card (#0d1526): --police da
   10,29:1, muito acima do minimo de 4,5:1 do WCAG AA.
   O safe-area no padding de baixo e o que impede a barra de gestos do
   aparelho de cobrir os dois botoes. */
#guia-sheet .gu-rodape{flex:0 0 auto;display:flex;align-items:center;gap:12px;
  padding:12px 20px calc(12px + env(safe-area-inset-bottom,0px));
  border-top:1px solid var(--border);background:var(--card);}
#guia-sheet .gu-esp{flex:0 0 0;}
#guia-sheet .gu-ajuda{display:flex;align-items:center;justify-content:center;
  background:none;border:1px solid var(--police);color:var(--police);
  font-family:'Rajdhani',sans-serif;font-size:.9375rem;font-weight:700;
  letter-spacing:.4px;border-radius:var(--r);padding:0 20px;min-height:44px;
  text-decoration:none;white-space:nowrap;flex:1;max-width:220px;}
#guia-sheet .gu-ajuda:focus-visible{outline:2px solid var(--text);outline-offset:2px;}
#guia-sheet .gu-ver{background:var(--police);color:#06121f;border:1px solid var(--police);
  border-radius:var(--r);font-family:'Rajdhani',sans-serif;font-size:.9375rem;font-weight:700;
  letter-spacing:.4px;padding:0 20px;min-height:44px;cursor:pointer;white-space:nowrap;
  flex:1;max-width:220px;}
#guia-sheet .gu-ver:focus-visible{outline:2px solid var(--text);outline-offset:2px;}
