/* ⭐ A FOLHA DE ESTILO DAS TELAS NOSSAS — editar, adicionar e o indice. Ela nasceu em
   23/09 como copia integral da folha que vivia dentro do `nobreaks-interna.html`, no dia
   em que o assistente de cadastro precisou dos MESMOS controles: "design system fora do
   padrao", dela, olhando uma tela que eu tinha estilizado por conta propria.
   ⚠️ E NO MESMO DIA A PAGINA INTERNA VOLTOU A SER DO ANDRE, com a folha dela inline,
   como ele a deixou em `5b4e5ac7`. Ela pediu: "assim nao preciso puxar a parte do
   Andre". Entao existem duas folhas iguais na origem — a dele, dentro da pagina dele, e
   esta, das telas nossas — e elas vao divergir a partir daqui, DE PROPOSITO: cada lado
   ajusta a sua. Quem for unir os dois modulos junta as duas nesse dia, e nao antes.
   Quem le esta folha: `nobreaks-editar.html`, `nobreaks-novo.html`, `nobreaks-index.html`. */
/* ============================================================================
   planos-lista.html — a tela que faltava no conjunto.

   As outras sete telas apontam para ela no `.crumb` ("Lista de Planos") desde o
   comeco e ela nunca existiu. Implementada em 01/09 a partir do no' 23144:119617
   do arquivo do Figma, lido com `get_design_context`.

   ESTA E' A PRIMEIRA TELA DO CONJUNTO QUE DESENHA NOS DOIS MODOS. Todas as outras
   sao claro-somente por decisao registrada, com as listas do escuro existindo como
   ENTREGA e nao como pintura. Aqui o escuro e' desenhado, porque foi o escuro que o
   Figma mostrou — e por isso ela vale como REFERENCIA do conjunto de tokens nos dois
   modos: nenhuma cor desta folha e' inventada, todas saem do arquivo.

   OS NOMES DOS TOKENS SAO OS DO DESIGN SYSTEM, e nao os nossos apelidos. As outras
   telas dizem `--t1`, `--t2`, `--line`; aqui diz `--foreground`, `--muted-foreground`,
   `--border`, porque e' esse o nome que a equipe de front vai procurar. Os apelidos
   antigos continuam existindo como APELIDOS, apontando para os tokens, porque a casca
   gerada pelo `casca-ds.py` usa os nomes velhos e um gerador nao deve ser reescrito
   para acomodar uma tela.
   ============================================================================ */
:root{
 /* 🔴 O ANEL DE FOCO NUNCA EXISTIU NO MODO CLARO: `--anel` so' era declarado dentro do bloco
    escuro, entao no claro `var(--anel)` nao resolvia e `border-color` caia no currentColor
    (preto) — foi o que ela viu como "cada campo com um estilo de selecao diferente". E eu
    tinha piorado: a primeira correcao trocou o valor NO LUGAR ERRADO, ainda no escuro.
    MEDIDO em 23/09 no `libs/ui-styles/tokens/colors.css` da producao: `--ring` e'
    neutral-400 no claro e gray-500 no escuro. */
 --anel:#A3A3A3;            /* base/ring — o anel de foco (claro), neutral-400 */
 /* ---- os tokens do DS, modo claro. Valores lidos no arquivo do Figma ---- */
 --background:#FFFFFF;
 --card:#FFFFFF;            --card-foreground:#0A0A0A;
 --foreground:#0A0A0A;
 --muted:#F5F5F5;           --muted-foreground:#737373;
 --border:#E5E5E5;          --input:#E5E5E5;
 --primary:#2563EB;         --primary-foreground:#FAFAFA;
 --secondary:#F5F5F5;       --secondary-foreground:#171717;
 --sidebar-border:#E5E5E5;
 /* `custom/background dark:input\30` e `custom/muted dark:input\50`: o par de fundos
    dos controles. No claro sao branco e #F5F5F5; no escuro viram branco a 4% e a 7,5%,
    que e' o jeito do DS clarear sobre fundo escuro em vez de escurecer. */
 --ctl-bg:#FFFFFF;          --ctl-bg-ativo:#F5F5F5;
 /* escala de tipo e de espaco, tambem do arquivo */
 --text-xs:12px;  --lh-xs:16px;
 --text-sm:14px;  --lh-sm:20px;
 --text-xl:20px;  --lh-xl:28px;
 --r-sm:6px; --r-md:8px; --r-lg:10px; --r-xl:14px;
 --motion-fast:.14s; --motion-base:.2s;
 /* ---- apelidos, para a casca gerada continuar valendo ---- */
 --primary-status:#2563EB33;   /* base/primary-foreground-status, lido no node */
 --line:var(--border); --line-2:var(--input);
 --t1:var(--foreground); --t2:var(--muted-foreground); --t3:var(--muted-foreground);
 --acc:var(--primary); --acc-bg:color-mix(in srgb,var(--primary) 10%,var(--card));
 --bg:var(--muted);
 /* ---- OS TOKENS DE ESTADO, medidos no dev do sistema novo em 15/09 ----
    `padrao-saude-medido.md` §2. Eles NAO existem no arquivo do Figma que esta frente
    leu: e' a `[P-22]`, que pedia onze estados e achou seis. Aqui entram com o nome do
    dev (`base/status/*`) e o valor computado de la', para o protótipo nao inventar cor
    nem escrever literal solto no meio da folha. */
 --status-estavel:#16A34A;         --status-estavel-fundo:#16A34A1A;
 --status-parc-instavel:#EA580C;   --status-parc-instavel-fundo:#EA580C1A;
 --status-instavel:#DC2626;        --status-instavel-fundo:#DC26261A;
 /* ⚠️ O TERCEIRO ESTADO NAO E' O MESMO NOS DOIS MODULOS. Na camera o terceiro e'
    `Offline`, e e' vermelho. No nobreak o terceiro modo e' `Bypass`, que NAO e'
    falha: e' o equipamento passando a rede direto. A cor vem do `CM` do modulo, que
    saiu do wireframe da Isabela, e nao do vermelho de la'. Copiar fiel e' copiar a
    ANATOMIA, nao trocar o vocabulario do equipamento. */
 --modo-bypass:#CA8A04;            --modo-bypass-fundo:#CA8A041A;
 /* ⚠️ DIVERGENCIA DE TOKEN, achado 8. O dev usa `--base-primary:#3B82F6` (azul 500) e
    o arquivo do Figma que esta frente leu da' #2563EB (azul 600). Nao troquei por
    conta propria: quem decide cor primaria e' o design system. */
 --primary-dev:#3B82F6;
 /* a escala de espaco do dev, para o padrao copiado nao ter literal */
 --sp-0-5:2px; --sp-1:4px; --sp-1-5:6px; --sp-2:8px; --sp-2-5:10px;
 --sp-4:16px; --sp-6:24px; --sp-20:80px; --sp-28:112px;
 --r-xs:2px; --r-full:9999px;
 --sombra-cartao:0 1px 1px 0 rgb(0 0 0 / .05);
 --lh-none:1;
 --peso-leve:300; --peso-normal:400; --peso-medio:500; --peso-forte:700;
}
/* ---- o modo escuro, valores lidos no mesmo arquivo (no' 23144:119617) ----
   O que muda e o que NAO muda: o `primary` fica parado em #2563EB nos dois modos, e a
   §11.39 tinha marcado isso como "vale perguntar se e' intencional". Os prints do
   escuro respondem: e' intencional, o azul nao se mexe. */
/* ===== DS:ESCURO:CSS:INICIO — gerado por escuro-ds.py. NAO EDITE AQUI ===== */
/* Todos os valores abaixo saem do arquivo do Figma, nos nos 23144:119617 e
   23144:117361, lidos com `get_variable_defs`. Nenhum foi escolhido aqui — e onde o
   arquivo nao respondeu, esta' dito qual e' a duvida. */
:root[data-modo="escuro"]{
 --anel:#6B7280;            /* base/ring no escuro: gray-500 */
 --background:#030712;
 --card:#111827;            --card-foreground:#FAFAFA;
 --foreground:#FAFAFA;
 /* ATENCAO: nesta gramatica `--muted` e' a SUPERFICIE, e nao o texto. Na gramatica
    antiga das outras sete telas o mesmo nome e' o muted-FOREGROUND. Mesmo nome,
    dois papeis — ver o cabecalho do escuro-ds.py. */
 --muted:#1F2937;           --muted-foreground:#9CA3AF;
 /* §11.62 — o mesmo token da regra de superficie, com o NOME CERTO desta gramatica:
    aqui quem e' texto e' o `--muted-foreground`. Apontar para `--muted` pintaria
    texto com a cor da superficie, que e' o bug de 11.55, 11.57 e 11.59. */
 --t2-pint:#9CA3AF;   /* o MESMO valor do --muted-foreground, escrito por extenso.
                         Apontar para o nome daria ciclo: a regra de superficie
                         redefine `--muted-foreground` a partir do `--t2-pint`, e
                         `var()` circular resolve para vazio — a peca ficaria sem cor. */
 --border:#FFFFFF1A;        --input:#FFFFFF26;
 --primary:#2563EB;         --primary-foreground:#F9FAFB;
 --secondary:#1F2937;       --secondary-foreground:#FAFAFA;
 --sidebar-border:#FFFFFF1A;
 --ctl-bg:#FFFFFF0B;        --ctl-bg-ativo:#FFFFFF13;
 /* ---- OS TOKENS DOS COMPONENTES GERADOS (11.57) ----
    Nenhum destes tem valor no `:root`: no claro cada peca cai na reserva do proprio
    `var(--x,#hex)`, que E' o literal medido de antes. A passada nos geradores e'
    no-op no claro por construcao, e nao por sorte.
    E eles existem porque a regra estava CRAVADA DENTRO DO BLOCO GERADO: o
    `.btn.sec:hover` tinha sido consertado a mao no arquivo e o `botoes-ds.py`
    continuava emitindo `#F7F7F7`. Uma passada do gerador desfazia o conserto. */
 --sec:#1F2937;             /* base/secondary */
 --sec-txt:#FAFAFA;         /* base/secondary-foreground */
 --sec-hover:#374151;       /* base/accent — o degrau ACIMA do secundario, para o
                               hover do botao secundario nao empatar com ele */
 --sup:#1F2937;             /* superficie levantada. No claro sao NOVE cinzas quase
                               iguais, e o colapso deles esta' aberto com a Larissa
                               desde a §11.54; no escuro o DS tem UMA superficie. */
 --sup-2:#111827;           /* o degrau ABAIXO da levantada, quando um mora dentro
                               do outro (a pastilha do campo so'-leitura) */
 --acc-hover:#1D4ED8;      /* blue/700. AQUI EU TENTEI CLAREAR E MEDI QUE NAO SERVE.
                               No claro o hover do azul e' #3A72ED, que e' o proprio
                               azul a 90% sobre BRANCO, e a §11.x registrou que
                               escurecer estava errado em seis telas. No escuro eu pus
                               blue/500 #3B82F6 pela mesma logica de "clarear", e o
                               rotulo em `primary-foreground` caiu para 3,52:1 — abaixo
                               do 4,5 que um rotulo de 14px/500 precisa. Com blue/700 da'
                               6,0:1. A direcao do hover nao manda no piso de leitura.
                               (No CLARO o mesmo par mede 4,18:1 e tambem nao passa: e'
                               anterior a este turno e esta' na lista da Larissa.) */
 --linha-3:#6B7280;         /* base/ring — o contorno que escurece no foco */
 --linha-fina:#FFFFFF1A;   /* base/border. E' o contorno de #EDEDF0 da barra de
                              ferramentas do fluxograma. NAO da' para usar `--line` aqui:
                              no claro `--line` e' #E5E5E5 e a reserva #EDEDF0 nunca
                              seria usada — quatro botoes de quatro telas trocaram de
                              contorno em silencio, e o `reserva-ok.js` pegou. */
 --miolo:#111827;           /* o miolo do radio ligado: no claro e' quase-branco
                               sobre cartao branco; no escuro e' o cartao */
 /* ---- OS PLANOS DO FLUXOGRAMA (11.55, promovidos ao DS em 11.59) ----
    Eram do bloco da tela quando so' o `plano-criar-2-fluxograma` desenhava escuro. Agora as
    QUATRO telas com canvas de fase desenham nos dois modos, e um token que quatro telas
    usam nao e' decisao de tela. Os valores claros ficam no `:root` de cada uma. */
 --cv-bg:#0A0A0AB2;        /* alpha/30, lido no no' 23144:117402 */
 --cv-ponto:#FFFFFF26;     /* base/input — a malha de pontos inverte */
 --nc-line:var(--line-2);  /* no escuro a borda do cartao sobe um degrau */
 --ric-bg:var(--card);     /* o degrau abaixo da linha, no escuro, e' escurecer */
 /* ---- TEXTO SOBRE LAVAGEM SEMANTICA (11.55/11.57, promovido ao DS em 11.59) ----
    No claro cada um destes e' a semantica ESCURECIDA A MAO, para dar contraste sobre a
    lavagem clara. No escuro a lavagem e' escura e quem da' contraste e' a propria
    semantica do escuro. Estavam no bloco de duas telas; sete usam. */
 --wrn-txt:var(--wrn); --err-txt:var(--err); --ok-txt:var(--ok); --din-txt:var(--din);
 --wrn-cheio:var(--wrn);   /* 11.62: o ambar CHEIO com texto branco em cima da' 3,19
                              no claro, e nao ha' tinta de texto que salve: #78350F sobre
                              #D97706 da' 2,85. Quem desce e' o preenchimento — amber/700
                              como literal claro. No escuro o ambar e' claro e o texto e'
                              escuro (`--sobre-wrn`), entao aqui ele volta ao `--wrn`. */
 --pause-txt:var(--pause);  /* 11.62: a pausa entrou na mesma familia. No claro
                              #B45309 sobre a propria lavagem da' 4,45 — 0,05
                              abaixo do piso, que continua sendo abaixo. */
 --wrn-txt-forte:#FDE68A;   /* amber-200: a enfase inverte de direcao com o fundo */
 --err-txt-forte:#FECACA;   /* red-200 */
 /* TEXTO SOBRE PREENCHIMENTO semantico. No claro o vermelho e o ambar sao escuros e o
    texto e' branco; no escuro eles sao CLAROS e branco em cima da' 1,6:1. O texto
    escurece — e' a mesma inversao do veu, aplicada a quem senta sobre a cor. */
 --sobre-err:var(--bg); --sobre-wrn:var(--bg); --sobre-ok:var(--bg);
 /* o selo do numero da fase senta sobre o `--t2`, que no escuro e' claro. */
 --sobre-t2:var(--bg);
 /* a etiqueta de apelido do no': lavagem violeta a 16% no claro (#EDE9FB, medido). */
 --alias-bg:color-mix(in srgb,var(--din) 16%,var(--veu));
 /* §11.62 — dois fundos que moravam no bloco de UMA tela e eram literais claros
    nas outras. `.node .md` (a faixa de modo do no') e `.s-pause` pintavam #DBEAFE e
    #FBF0DC cravados: no escuro sobrava fundo claro com texto claro em cima —
    medido 2,08:1 no `.md.man` do simular. Com o token, o fundo acompanha o modo. */
 --md-bg:color-mix(in srgb,var(--acc) 16%,var(--veu));
 --pause:#F59E0B;   /* amber/500: no escuro a pausa clareia, como toda semantica */
 --pause-bg:color-mix(in srgb,var(--pause) 18%,var(--veu));
 /* §11.62 — o losango do Paralelo. No claro ele era #22B8CF, um cyan inventado
    (o `portar-contexto.py` ja' anotava isso), e media 2,38:1 contra o piso 3,0 de
    grafico. Virou cyan/700 #0E7490 (5,36) como literal claro. No escuro ele volta
    a ser cyan/400, que e' o `--par` da biblioteca. Quatro consumidores, entao o
    token mora aqui e nao no bloco de uma tela. */
 --par-txt:#22D3EE;
 --acc-txt:#60A5FA;         /* blue/400. `base/primary` NAO muda de modo, e para
                               PREENCHIMENTO isso serve. Como TEXTO sobre a propria
                               lavagem no escuro ele cai a 3,41 no fluxograma e a 3,59
                               no agendamento. Dois consumidores, entao o token subiu do
                               bloco da tela para o do DS. Blue/400 esta' declarado no
                               no' 23144:117402 do arquivo. */
}
/* ===== DS:ESCURO:CSS:FIM ===== */
/* ===== DS:SUPERFICIE:CSS:INICIO — gerado por superficie-ds.py. NAO EDITE AQUI ===== */
/* §11.62 — quem pinta um fundo desce o apoio um degrau da rampa.
   Medido: #737373 reprovava em 37 combinacoes (4,12 a 4,46). Com #525252 o pior
   fundo medido da' 6,78:1. `--t1` foi recusado: apaga o nivel de apoio. */
.it,.bar,.ro,.bd,.opt,.row,.marca,.simalert,.m-mapa,.pg-ico,.segs,
.viewtoggle,.chip.v,.v-int,.chipr,.fchip .fn,.fn,.cen-fato,.reg,
.uni-u,.ava,.pag,
.pg-chips,.chips,.ph-chips,.st,.alvo,.res-l,.pilula,
.fsb-ico,.fsb-v,.s-end,.s-abort,.cnt,.ph-ico,.det-st,.f-skip,.f-cut,
.f-morto,.st-selo,.phase-tag,.res-b,.selo.neutro,.ric{
  --t2:var(--t2-pint,#525252);
  --t3:var(--t2-pint,#525252);
  /* A LISTA DE PLANOS FALA A OUTRA GRAMATICA: la' o apoio nao e' `--t2`, e' o
     `--muted-foreground` do DS, chamado direto pelo componente. Sem esta linha a
     regra passava ao largo dela — e foi assim que sobraram duas reprovas na
     unica tela que usa a gramatica nova. `--muted` (a SUPERFICIE, naquela
     gramatica) continua intocado: e' o erro que ja' voltou tres vezes. */
  --muted-foreground:var(--t2-pint,#525252);
}
/* ===== DS:SUPERFICIE:CSS:FIM ===== */
*{box-sizing:border-box;margin:0;padding:0}
body{background:var(--background);color:var(--foreground);
  font:400 var(--text-sm)/var(--lh-sm) Inter,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;
  -webkit-font-smoothing:antialiased}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
a{color:inherit;text-decoration:none}
:focus-visible{outline:2px solid var(--primary);outline-offset:2px;border-radius:3px}

/* ===== DS:CASCA:CSS:INICIO — gerado por casca-ds.py. NAO EDITE AQUI ===== */
/* Linha 1: logotipo | busca centrada | acoes. O `1fr auto 1fr` e' o que mantem a busca
   no centro da JANELA e nao no centro do espaco que sobrou — com flex, um logotipo mais
   largo empurraria a busca para a direita. */
/* §11.54 — `var(--card)` e nao `#fff`. A casca era branca cravada, e no modo escuro da
   `planos-lista` o corpo ficava escuro com o cabecalho e a navegacao brancos: a mesma
   tela em dois modos ao mesmo tempo. No claro o `--card` E' `#fff`, entao a troca nao
   muda um pixel nas sete telas claro-somente — e passa a valer na que troca de modo. */
.top{background:var(--card);border-bottom:1px solid var(--line);padding:9px 24px;
  display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:16px}
.logo{display:flex;align-items:center;justify-self:start}
.logo img{height:26px;width:auto;display:block}
/* `.cbusca`, e nao `.search` — pela MESMA razao do `.cico` logo abaixo, e descoberto do
   mesmo jeito: medindo. Cada folha de tela ainda carrega as regras da casca antiga, e
   entre elas cinco que agrupavam `.search` com os campos de busca DA TELA
   (`.busca`, `.libsrc`) mais duas so' para `.search`. Todas vinham DEPOIS deste bloco,
   com especificidade igual — entao quem mandava na busca do cabecalho era a folha da
   tela, nao este gerador. O sintoma que denunciou: pedi 15px de icone e o navegador
   respondeu 16.
   Com nome proprio, o gerador volta a mandar no que ele desenha. As regras `.search` que
   sobraram sao apagadas pelo passo de limpeza no `aplicar()`, porque regra morta que
   ninguem le' e' exatamente o que volta a colidir daqui a tres meses. */
.cbusca{width:min(420px,42vw);border:1px solid var(--line-2);border-radius:9px;
  padding:7px 12px;color:var(--t3);font-size:13px;display:flex;align-items:center;
  gap:9px;background:var(--ctl-bg,var(--card));justify-self:center}
.cbusca svg{width:15px;height:15px;stroke:var(--t3);fill:none;flex:none;display:block}
.tacts{display:flex;align-items:center;gap:14px;justify-self:end}
/* CLASSE PROPRIA, `.cico`, e nao o `.icobtn` das telas.
   Na primeira versao eu reusei `.icobtn` e os botoes da casca sairam com CONTORNO —
   porque `.icobtn` e' um componente de tela, usado no filtro e no versionamento, e la'
   a borda faz sentido. A folha de cada tela define esse `.icobtn` depois do bloco da
   casca, entao ela vencia. No print, os icones do topo e da navegacao sao NUS.
   Duas coisas diferentes com o mesmo nome viram uma briga de cascata; nomes separados
   nao brigam. */
.cico{width:30px;height:30px;border-radius:8px;color:var(--t2);display:grid;
  place-items:center;background:none;border:0;flex:none;cursor:pointer;padding:0}
.cico:hover{background:var(--muted-sup,var(--secondary,#F5F5F5));color:var(--t1)}  /* 11.55: era `--muted`,
   que e' muted-FOREGROUND. No escuro o hover do icone dava #FAFAFA sobre #9CA3AF: 2,43.
   Superficie levantada e' `--muted-sup`; papel de texto nao serve de fundo. */
/* `stroke:currentColor` e' o que faz o desenho seguir a cor do botao — inclusive o
   escurecimento do :hover, que so' muda `color`. Com um stroke fixo, o icone ficaria
   parado enquanto o resto do botao reage. O `fill:none` e' obrigatorio: um icone Lucide
   e' contorno, e sem isso o navegador pinta o interior de preto por padrao. */
.cico svg{width:18px;height:18px;stroke:currentColor;fill:none;display:block}
/* o avatar e' a imagem que o Andre mandou, e nao mais um circulo com gradiente */
.avatar{width:30px;height:30px;border-radius:50%;flex:none;display:block;object-fit:cover;
  /* 11.59: a reserva apontava para o token `muted` cru, e nesta gramatica esse nome e'
     muted-FOREGROUND (#737373). O fundo do avatar era um cinza MEDIO, nao o claro que a
     reserva anunciava. Terceira vez do mesmo erro neste gerador: a §11.55 achou no
     `.cico:hover`, a §11.57 achou o nome com dois significados, e este e' o terceiro
     lugar. `--sup` so' existe no escuro, entao no claro fica o literal medido. */
  background:var(--sup,#EFEFF3)}
/* Linha 2: painel | itens centrados | editar. Mesma grade de tres colunas, pela mesma
   razao: os itens ficam no centro da janela. */
.nav{background:var(--card);border-bottom:1px solid var(--line);padding:0 24px;
  display:grid;grid-template-columns:1fr auto 1fr;align-items:center}
.navmid{display:flex;gap:26px;justify-self:center}
.nav a{padding:13px 2px;font-size:13.5px;color:var(--t2);border-bottom:2px solid transparent;
  margin-bottom:-1px}
.nav a:hover{color:var(--t1)}
.nav a.on{color:var(--t1);font-weight:500;border-bottom-color:var(--acc)}
.nav .cico{justify-self:start}
.nav .cico.dir{justify-self:end}
/* ===== DS:CASCA:CSS:FIM ===== */

/* ===================== a pagina ===================== */
/* ---- casca de aplicacao: a PAGINA nao rola ----
   Medido no no' `21200:12931`: a tela tem 832, o cabecalho ocupa 96, e a `Sidebar
   Lista` vai de y=96 a y=832, ou seja, EXATAMENTE a altura util da tela. Ela nao
   acompanha a pagina, e' limitada pela janela.
   Para isso a casca deixa de crescer: a area de conteudo tem altura fixa, e quem
   rola e' o corpo da tabela, por dentro. E' o que um aplicativo faz de verdade, e e'
   a unica forma de a paginacao ficar no rodape e o painel terminar junto com ela. */
html,body{height:100%;overflow:hidden}
/* As notas e o andaime nao pertencem a' casca: numa aplicacao de verdade elas nao
   existem. Ficam num bloco proprio, atras de um botao, para nao roubar altura da
   area de conteudo nem mentir sobre o tamanho da tela. */
.notas{position:fixed;inset:auto 0 0 0;max-height:60vh;overflow:auto;z-index:80;
  background:var(--card);border-top:1px solid var(--border);padding:16px 24px;
  transform:translateY(100%);transition:transform var(--motion-base) ease}
.notas.aberto{transform:none}
/* o gatilho das notas espelha a abinha do olhinho: aba estreita na borda esquerda,
   logo abaixo dela. Flutuando no rodape ele tapava a contagem da paginacao. */
.btnotas{position:fixed;left:0;top:calc(50% + 34px);z-index:81;width:26px;height:86px;
  padding:0;border:0;border-radius:0 10px 10px 0;background:var(--muted-foreground);
  color:var(--card);font:inherit;font-size:10.5px;letter-spacing:.04em;cursor:pointer;
  writing-mode:vertical-rl;box-shadow:2px 3px 12px -5px rgba(0,0,0,.45)}
.btnotas:hover{opacity:.92}
.pg{padding:24px 24px 0;height:calc(100vh - var(--casca,96px));box-sizing:border-box;
  display:flex;align-items:stretch;gap:22px;overflow:hidden}
.colE{flex:1;min-width:0;min-height:0;display:flex;flex-direction:column;position:relative}
/* Page Header: gap 24 entre o bloco de titulo e a linha de controles; 4 entre titulo
   e subtitulo. Medido no no' I23144:119622;2:16323. */
.ph{display:flex;flex-direction:column;gap:24px;margin-bottom:10px}
.ph-tit{display:flex;flex-direction:column;gap:4px;max-width:720px}
.ph-tit h1{font-size:var(--text-xl);line-height:var(--lh-xl);font-weight:600;
  color:var(--foreground);letter-spacing:-.01em}
/* o subtitulo e' `leading-none` no arquivo, e nao o 16 do text-xs */
.ph-tit p{font-size:var(--text-xs);line-height:1;color:var(--muted-foreground)}
.ph-row{display:flex;align-items:center;justify-content:space-between;gap:16px}

/* a busca: InputGroup, 280x32, raio 10, borda `input` */
.busca{width:280px;height:32px;display:flex;align-items:center;gap:6px;
  padding:4px 10px;border:1px solid var(--input);border-radius:var(--r-lg);
  background:var(--ctl-bg);color:var(--muted-foreground)}
.busca svg{width:16px;height:16px;flex:none;display:block}
.busca input{flex:1;min-width:0;border:0;background:none;font:inherit;
  font-size:var(--text-sm);color:var(--foreground);outline:none}
.busca input::placeholder{color:var(--muted-foreground)}

.ph-acts{display:flex;align-items:center;gap:12px}
/* ButtonGroup: dois botoes de 32 colados, raio so' nas pontas de fora, e um filete de
   1px em `input` entre eles. O separador e' ELEMENTO e nao borda, porque com borda os
   dois lados somariam 2px no meio. */
.bgrp{display:flex;align-items:center}
.bgrp button{width:32px;height:32px;display:grid;place-items:center;
  border:1px solid var(--input);background:var(--ctl-bg);color:var(--foreground)}
.bgrp button:first-child{border-radius:var(--r-md) 0 0 var(--r-md);border-right:0}
.bgrp button:last-child{border-radius:0 var(--r-md) var(--r-md) 0;border-left:0}
.bgrp button[aria-pressed="true"]{background:var(--ctl-bg-ativo)}
.bgrp .sep{width:1px;align-self:stretch;background:var(--input);flex:none}
.bgrp svg,.icobtn svg{width:16px;height:16px;display:block}
/* ESTADOS DO BOTAO, o modelo do `botoes-ds.py` (folha Components / Button).
   ⚠️ DEFEITO QUE ESTAVA AQUI: o repouso vinha pintado com `--ctl-bg-ativo` (#F5F5F5)
   e o hover com `--muted`, que e' O MESMO #F5F5F5. Medido: repouso e hover davam
   o mesmo pixel, ou seja, o botao nascia com cara de apontado e apontar nao fazia
   nada. Repouso e' o chao do Outline: `--ctl-bg`.
   O MODELO, e ele nao e' seis desenhos:
   · sem acao  = Outline: chao `--ctl-bg`, contorno 1 `--border`, raio 8
   · hover     = `--sec` (#F5F5F5), texto `--sec-txt` (#171717). So' o hover e'
                 proprio de cada variante.
   · aberto    = fica no chao do hover enquanto o popover esta' aberto, que e' o
                 `aria-expanded:bg-muted` do botao do repositorio. Botao que abriu
                 painel continua dizendo que abriu.
   · pressionado = a aparencia normal a 60% de opacidade
   · desligado   = a 50%, e o hover nao muda mais o chao
   · foco        = anel de 3px `--anel` COLADO na borda, e no Outline o proprio
                   contorno escurece para `--linha-3`, senao o anel cinza encosta
                   num contorno cinza-claro e some. */
.icobtn{width:32px;height:32px;display:grid;place-items:center;border-radius:var(--r-md);
  border:1px solid var(--input);background:var(--ctl-bg);color:var(--foreground);
  box-sizing:border-box;cursor:pointer;
  transition:background var(--motion-fast),border-color var(--motion-fast),
             opacity var(--motion-fast),box-shadow var(--motion-fast)}
.icobtn:hover{background:var(--sec,#F5F5F5);color:var(--sec-txt,#171717)}
.icobtn[aria-expanded="true"]{background:var(--sec,#F5F5F5);color:var(--sec-txt,#171717)}
.icobtn:active{opacity:.6}
.icobtn:focus-visible{outline:none;border-color:var(--linha-3,#A3A3A3);
  box-shadow:0 0 0 3px var(--anel,#D1D1D1)}
.icobtn:disabled{opacity:.5;cursor:not-allowed}
.icobtn:disabled:hover{background:var(--ctl-bg)}
/* o botao primario: raio 8, 10 de lado e 8 de cima, icone 14, texto 12/16 medium */
.btn-pri{display:inline-flex;align-items:center;gap:4px;height:32px;padding:8px 10px;
  border-radius:var(--r-md);background:var(--primary);color:var(--primary-foreground);
  font-size:var(--text-xs);line-height:var(--lh-xs);font-weight:500;white-space:nowrap}
.btn-pri svg{width:14px;height:14px;display:block}
.btn-pri:hover{background:color-mix(in srgb,var(--primary) 88%,#000)}

/* ===== Filter Bar: as abas ===== */
.fbar{border-bottom:1px solid var(--border);padding:0 12px}
.tabs{display:flex;align-items:center;gap:4px}
.tabs button{display:flex;align-items:center;gap:6px;padding:6px;
  border-bottom:2px solid transparent;color:var(--muted-foreground);
  font-size:var(--text-sm);line-height:var(--lh-sm);font-weight:500}
.tabs button[aria-selected="true"]{border-bottom-color:var(--primary);color:var(--foreground)}
/* Badge Number: pilula de 20 de altura, minimo 20 de largura, `secondary` */
.badge{min-width:20px;height:20px;display:inline-flex;align-items:center;
  justify-content:center;padding:0 4px;border-radius:9999px;border:1px solid transparent;
  background:var(--secondary);color:var(--secondary-foreground);
  font-size:var(--text-xs);line-height:var(--lh-xs);font-weight:500}

/* ===== a tabela =====
   GRADE E NAO <table>, porque as colunas do arquivo tem larguras fixas medidas
   (41 · 475 · 130 · 135 · 148 · 139 · 164 · 44) e a celula precisa ser um flex com
   duas linhas dentro. Com <table> o `text-overflow` da segunda linha nao funciona
   sem um `table-layout:fixed` e um wrapper por celula de qualquer jeito. */
.tab{border:1px solid var(--border);border-radius:var(--r-lg);overflow:hidden;
  background:var(--card)}
.tab-rol{overflow-x:auto}
.grade{display:grid;
  grid-template-columns:41px minmax(320px,475px) 130px 135px 148px 139px 164px 44px;
  min-width:1232px}
.hd,.cl{border-bottom:1px solid var(--border);border-right:1px solid var(--border);
  min-height:40px;display:flex;align-items:center;padding:8px;gap:8px}
.grade > :nth-child(8n){border-right:0}
.hd{font-size:var(--text-sm);line-height:var(--lh-sm);font-weight:500;
  color:var(--foreground);background:var(--card);position:sticky;top:0;z-index:1}
.hd.ord{cursor:pointer}
.hd .rot{flex:1;min-width:0}
.hd .oi{flex:none;color:var(--muted-foreground);display:grid;place-items:center}
.hd .oi svg{width:16px;height:16px;display:block}
.hd.ord:hover .oi{color:var(--foreground)}
.hd[data-dir] .oi{color:var(--primary)}
/* a celula de duas linhas: 12/16 no nome e 11/1 na descricao, gap 2 */
.cl .tx{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.cl .n1{font-size:var(--text-xs);line-height:var(--lh-xs);color:var(--foreground);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cl .n2{font-size:11px;line-height:1;color:var(--muted-foreground);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cl .um{font-size:var(--text-xs);line-height:var(--lh-xs);color:var(--foreground);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cl.mid{justify-content:center}
.cl.fim{justify-content:flex-end}
.grade .lin:hover .cl{background:var(--muted)}
/* o criador: avatar de 20 com as iniciais, ou a foto */
.who{display:flex;align-items:center;gap:6px;min-width:0}
.ava{width:20px;height:20px;border-radius:9999px;flex:none;display:grid;
  place-items:center;background:var(--muted);color:var(--muted-foreground);
  font-size:9.5px;font-weight:600;letter-spacing:.02em;overflow:hidden}
.ava img{width:100%;height:100%;object-fit:cover;display:block}
.kb{width:28px;height:28px;border-radius:var(--r-md);display:grid;place-items:center;
  color:var(--muted-foreground)}
.kb:hover{background:var(--muted);color:var(--foreground)}
.kb svg{width:16px;height:16px;display:block}
.vazio{grid-column:1/-1;padding:34px 16px;text-align:center;
  color:var(--muted-foreground);font-size:var(--text-xs);border-bottom:1px solid var(--border)}

/* ===== Page-Table: a paginacao ===== */
.pag{background:var(--muted);padding:16px;display:flex;align-items:center;
  justify-content:space-between;gap:16px;flex-wrap:wrap}
.pag .conta{font-size:var(--text-xs);line-height:var(--lh-xs);color:var(--muted-foreground)}
.pag .lado{display:flex;align-items:center;gap:32px}
.pag .par{display:flex;align-items:center;gap:8px}
.pag .rot{font-size:var(--text-xs);line-height:var(--lh-xs);color:var(--foreground)}
.pag select{width:70px;height:32px;padding:6px 10px;border:1px solid var(--input);
  border-radius:var(--r-lg);background:var(--ctl-bg);color:var(--muted-foreground);
  font:inherit;font-size:var(--text-sm);appearance:none;cursor:pointer}
.pag .selwrap{position:relative;display:inline-flex;align-items:center}
.pag .selwrap svg{position:absolute;right:10px;width:16px;height:16px;
  pointer-events:none;color:var(--muted-foreground)}
.pag .navs{display:flex;align-items:center;gap:8px}
.pag .navs button{width:32px;height:32px;display:grid;place-items:center;
  border:1px solid var(--input);border-radius:var(--r-md);background:var(--ctl-bg);
  color:var(--foreground)}
.pag .navs button:hover:not([disabled]){background:var(--ctl-bg-ativo)}
.pag .navs button[disabled]{opacity:.5;cursor:default}
.pag .navs svg{width:16px;height:16px;display:block}
.nota{margin-top:14px;font-size:11.5px;line-height:1.5;color:var(--muted-foreground);
  max-width:96ch}
.nota b{color:var(--foreground);font-weight:500}

/* ============================================================================
   nobreaks-interna.html: o que esta tela ACRESCENTA.
   A casca (cabecalho, navegacao, tokens) e' a de `planos-lista.html`.
   A ANATOMIA DA PAGINA e' a de `plano-detalhes.html`, do Plano de Execucao:
   migalha, cabecalho de identidade com a acao na linha do nome, painel de abas,
   e o inspetor de 330 a' direita. Nada disso foi redesenhado.
   ============================================================================ */
html,body{height:100%;overflow:hidden}
/* casca de aplicacao, igual a' da lista: a pagina nao rola, o miolo rola.
   DIVERGE do `plano-detalhes.html`, onde a pagina rola. Duas telas do mesmo modulo
   com rolagem diferente fazem o operador aprender a tela em vez do sistema, e a
   lista ja' precisava da casca fixa para o painel ter onde parar. Declarado. */
/* ⚠️ O RESPIRO LATERAL DA PAGINA É 24, E ELE TEM QUE SER IGUAL DOS DOIS LADOS.
   MEDIDO no dev em 15/09: `cameras-list__main` tem `padding:24px` e `gap:16px`, com a
   tabela a 25 da esquerda e 26 da direita. É o respiro de toda tela do sistema.
   O QUE ESTAVA ERRADO: a página tinha 24 de padding lateral E a face rolante
   acrescentava mais 16, o que dava 40; e como quem rola é a FACE, a barra de rolagem
   comia o respiro da direita por dentro desse 40, enquanto a esquerda ficava inteira.
   O André viu exatamente isso: mais espaço à esquerda do que à direita.
   O CONSERTO: a página deixa de ter padding lateral, e quem o aplica é cada faixa. A
   face rolante aplica 24 POR DENTRO, então a barra fica na borda da janela, fora do
   respiro, e os dois lados ficam com os mesmos 24. */
.page{padding:20px 0 0;height:calc(100vh - var(--casca,96px));box-sizing:border-box;
  display:flex;flex-direction:column;overflow:hidden}
.crumb,.pagehdr,.shell > .ptabs{margin-left:24px;margin-right:24px}
.crumb{font-size:var(--text-xs);color:var(--muted-foreground);margin-bottom:8px;flex:none}
.crumb b{color:var(--foreground);font-weight:500}
/* A migalha volta para a lista. Link e' texto, entao a cor e' `--acc-txt`, que e'
   blue/700 no claro e blue/400 no escuro: azul cheio em texto nao passa no piso. */
.crumb a{color:var(--acc-txt,#1D4ED8);text-decoration:none}
.crumb a:hover{text-decoration:underline;text-underline-offset:2px}
.crumb a:focus-visible{outline:2px solid var(--primary);outline-offset:2px;border-radius:3px}

/* ---- chip de estado: o mesmo `Badge` do no' `21027:1681` da lista ----
   Ele veio junto quando esta tela herdou a casca, e some se a folha da lista sair.
   Mora aqui porque as DUAS telas do modulo precisam dele. */
.pill{display:inline-flex;align-items:center;justify-content:center;gap:4px;
  padding:2px 8px;border:1px solid transparent;border-radius:9999px;
  font-size:var(--text-xs);line-height:var(--lh-xs);font-weight:500;white-space:nowrap;
  color:var(--pc);background:var(--pb,color-mix(in srgb,var(--pc) 12%,var(--card)))}
@keyframes bpulso{0%,100%{opacity:1}50%{opacity:.55}}
.pill.pulsa{animation:bpulso 2.4s ease-in-out infinite}
@media (prefers-reduced-motion:reduce){.pill.pulsa{animation:none}}

/* ---- cabecalho de identidade ---- */
.pagehdr{display:flex;gap:13px;align-items:flex-start;margin-bottom:18px;flex:none}
/* O icone da identidade e' AZUL, e nao cinza. O `plano-detalhes.html` ainda o desenha
   em cinza (`--sup` com `--t2`), mas a tela real de Detalhes de Plano no Attlas 26 usa
   o azul do sistema sobre uma lavagem do proprio azul, e foi o que o Andre apontou:
   em cinza ele fica apagado ao lado de um titulo de 21. Chao `--acc-bg`, que ja' e' a
   lavagem de 10 % do primario sobre o cartao, e tinta `--primary`. */
.pg-ico{width:38px;height:38px;border-radius:var(--r-lg);
  background:color-mix(in srgb,var(--primary) 8%,var(--card));
  color:var(--primary);display:grid;place-items:center;flex:none}
.pg-ico svg{width:19px;height:19px}
.pg-id{min-width:0}
.pg-t{font-size:21px;line-height:1.2;font-weight:600;letter-spacing:-.01em;
  display:flex;align-items:center;gap:10px;flex-wrap:wrap;color:var(--foreground)}
.pg-chips{display:flex;gap:8px;align-items:center;margin-top:6px;
  font-size:var(--text-xs);color:var(--muted-foreground);flex-wrap:wrap}
.pg-chips .tec{display:flex;gap:10px;flex-wrap:wrap}
.pg-chips .tec span{white-space:nowrap}
.pg-chips .tec b{font-weight:500;color:var(--foreground)}
/* A ACAO MORA NA LINHA DA IDENTIDADE, e nao na barra de abas. Decisao registrada no
   `plano-detalhes.html`, com a razao: a barra de abas e' do PAINEL e o que esta' nela
   age sobre a aba aberta; editar age sobre o EQUIPAMENTO, que e' do que fala o
   cabecalho. `align-items:center` com altura 38 alinha o botao com a LINHA DO TITULO,
   e nao com o topo do bloco, que tem duas linhas. */
.pg-acao{margin-left:auto;flex:none;display:flex;align-items:center;gap:8px;height:38px}
/* `.btn2` estava escopado dentro de `.pg-acao` e o botao `Severidade` do log saia
   SEM BORDA e com 21 de altura, porque a regra nao o alcancava. Botao secundario e'
   da tela, nao do cabecalho. */
.btn2{display:inline-flex;align-items:center;gap:6px;height:32px;padding:0 12px;
  border:1px solid var(--input);border-radius:var(--r-md);background:var(--ctl-bg);
  color:var(--foreground);font:inherit;font-size:var(--text-xs);font-weight:500;
  cursor:pointer;white-space:nowrap}
.btn2:hover{background:var(--ctl-bg-ativo)}
.btn2 svg{width:15px;height:15px;flex:none}
.kb2{width:32px;height:32px;padding:0;justify-content:center}
/* a variante `tint` do botão da casca: fundo da primária a 20 %, texto na primária.
   É a mesma gramática de `cor a 10 % no fundo, cor cheia no texto` que a biblioteca
   registrou três vezes, com o alfa que o `--primary-status` do nó já traz. */
.btn2-tint{background:var(--primary-status);border-color:transparent;color:var(--primary);
  font-weight:500}
.btn2-tint:hover{background:color-mix(in srgb,var(--primary) 26%,transparent)}
/* ===================== o popover de FILTROS =====================
   NAO e' invencao desta tela. A peca esta' medida na `biblioteca/componentes-figma.md`,
   secao "Popover de filtros", e implementada em
   `modulo-notificacoes/entrega-frontend/.../filter-popover/`. O que vem de la':

   · GATILHO: o funil, SO' O GLIFO, 32x32, no grupo de acoes a' direita da barra, com
     a busca a' esquerda. Badge de contagem sobre o canto, contando o APLICADO.
   · CAIXA: 226 de largura (`--width-notifications-filter-popover`), borda 1,
     sombra `md`, superficie `--popover`, respiro 10.
   · ANCORAGEM: pela DIREITA do gatilho, ABAIXO dele, folga 4, e UMA posicao so'.
     O painel se limita ao espaco abaixo e o corpo rola por dentro; painel que pede
     espaco que nao tem e' painel que o overlay vira para cima.
   · RITMO: rotulo 24 + linha de opcoes · separador com 8 de ar de cada lado ·
     separadores internos RECUADOS (206) e o do rodape de LARGURA CHEIA (226).
   · RODAPE: 48 de altura, botoes de 28 (`sm`, nao 32), largura natural, vao 6,
     alinhados a' direita. `Limpar` contorno, `Aplicar` cheio.
   · COMMIT: o filtro NAO APLICA AO VIVO. A pessoa monta o recorte e confirma.
     Sair sem aplicar descarta o rascunho; `Aplicar` fica travado ate' o rascunho
     dizer algo diferente do que ja' esta' em vigor.

   DIVERGENCIA DECLARADA, nao escondida: o raio. A biblioteca mediu 10 (`rounded-lg`)
   no simbolo base do `Popover` do DS, e a entrega de Notificacoes escreve
   `--radius-md`, que e' 8. Aqui vale o NODE, que e' 10, e a divergencia esta' no
   `achados-para-escalar.md`.

   A OUTRA ESCOLHA, declarada: Notificacoes usa um combobox por grupo; a biblioteca
   registra DUAS formas de grupo, `rotulo 24 + checkbox 24` e `rotulo 24 + combobox 32`.
   Aqui os tres campos sao listas curtas e FECHADAS (4, 6 e 3 opcoes), entao vale a
   forma de checkbox, que mostra tudo de uma vez e nao cobra um clique para abrir.
   Lista longa ou aberta pediria a forma de combobox. */
.fpop{position:fixed;z-index:60;width:285px;display:flex;flex-direction:column;
  border:1px solid var(--border);border-radius:var(--r-lg);
  background:var(--card);color:var(--foreground);overflow:hidden;
  box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1)}
:root[data-modo="escuro"] .fpop{box-shadow:0 10px 28px rgba(0,0,0,.6)}
.fpop-cab{flex:none;padding:10px 10px 4px}
.fpop-cab h3{margin:0;font-size:var(--text-sm);line-height:var(--lh-sm);font-weight:500}
.fpop-corpo{flex:1 1 auto;min-height:0;overflow-y:auto;padding:4px 0 10px;
  display:flex;flex-direction:column;gap:8px}
.fpop-corpo hr{flex:none;margin:0 10px;border:0;border-top:1px solid var(--border)}
.fg{display:flex;flex-direction:column;gap:8px;padding:0 10px}
.fg-rot{font-size:var(--text-xs);line-height:var(--lh-xs);font-weight:500;
  color:var(--muted-foreground)}
/* UMA POR LINHA, e nao duas. O node de Alarmes poe os checkboxes dois por linha
   (x=6 e x=136,5), e essa e' a gramatica quando a opcao e' so' o rotulo. Aqui cada
   opcao carrega a CONTAGEM na direita, e em duas colunas sobram 99 por celula: medido,
   `Associação`, `Carga` e `Energia` ficaram com a contagem cortada na borda da caixa,
   e os numeros pousavam em tres x diferentes na mesma linha. Uma por linha devolve a
   contagem inteira e uma coluna de numeros que se le de cima a baixo. O corpo rola,
   que e' o que a peca ja' preve. */
.fg-ops{display:flex;flex-direction:column}
/* Linha de opcao e' item de lista, e item de lista responde com CHAO, nao com
   sublinhado: o sublinhado e' do botao-link. O recuo negativo deixa o chao do hover
   ir ate' o respiro da caixa em vez de parar no texto. Mesmo modelo de estado:
   hover `--sec`, pressionado a 60%. */
.fop{display:flex;align-items:center;gap:7px;min-height:24px;margin:0 -6px;
  padding:0 6px;border:0;background:none;font:inherit;font-size:var(--text-xs);
  line-height:var(--lh-xs);color:var(--foreground);text-align:left;cursor:pointer;
  border-radius:6px;transition:background var(--motion-fast),opacity var(--motion-fast)}
.fop:hover{background:var(--sec,#F5F5F5);color:var(--sec-txt,#171717)}
.fop:active{opacity:.6}
.fop:focus-visible{outline:none;box-shadow:0 0 0 3px var(--anel,#D1D1D1)}
.fop .rot{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* A marca e' DESENHO, nao cor: quadrado vazio contra quadrado com visto. */
.fop .cx{width:16px;height:16px;flex:none;border:1px solid var(--input);
  border-radius:4px;display:flex;align-items:center;justify-content:center;
  color:transparent;background:var(--ctl-bg)}
.fop[aria-checked="true"] .cx{background:var(--primary);border-color:var(--primary);
  color:var(--primary-foreground)}
.fop .cx svg{width:12px;height:12px}
.fop .n{margin-left:auto;padding-left:6px;font-variant-numeric:tabular-nums;
  color:var(--muted-foreground)}
.fop.zero .n{opacity:.55}
/* A SEGUNDA FORMA DE GRUPO da biblioteca: `rotulo 24 + combobox 32`. O grupo de
   marcas e' a primeira. Um filtro com periodo e agregacao precisa das duas. */
.fg-campo{display:flex;flex-direction:column;gap:6px}
/* ---- CAMPO DE SELEÇÃO, na anatomia do `z-select` do design system ----
   MEDIDO no dev em 15/09, nos dois tamanhos que ele usa:
   · `cameras-filters__select`: 36 de altura, padding 6/12, raio 10, borda 1
     `--border`, fundo transparente, 14/400, `justify-content:space-between`,
     chevron de 16 com a folga do padding até a borda (13 medidos = 12 + 1 da borda).
   · `pagination-select`: 32 de altura, padding 4/8, raio 10, 12/400, chevron 16 com
     folga de 9. É a variante pequena, e é a que cabe num popover de 285.
   ⚠️ O QUE ESTAVA ERRADO: a seta era a NATIVA do sistema operacional, que encosta na
   borda direita e muda de desenho em cada máquina. O André viu isso no período e na
   agregação. O conserto é `appearance:none` e o chevron do próprio protótipo, com o
   espaço dele reservado no `padding-right`: 8 de folga + 16 de ícone + 8 de respiro.
   O ícone vai em `background-image` porque `<select>` nativo não aceita filho. */
.fg-campo select,.fg-campo input{height:32px;box-sizing:border-box;width:100%;
  padding:4px 8px;border:1px solid var(--border);border-radius:var(--r-lg);
  background:var(--ctl-bg);color:var(--foreground);font:inherit;font-size:var(--text-xs)}
.fg-campo select{appearance:none;-webkit-appearance:none;padding-right:32px;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23737373' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 8px center;background-size:16px 16px}
.fg-campo select:hover,.fg-campo input:hover{border-color:var(--muted-foreground)}
/* ⬅️ "cada campo de input esta com tipo de estilo de selecao diferente" — dela, 23/09. O
   input solto pintava borda PRIMARIA + anel cinza; o grupo pintava borda primaria + anel
   AZUL a 50 %. Medido nos dois variants da producao (`input.variants.ts` e
   `input-group.variants.ts`): o foco e' O MESMO — `border-ring` + `ring-3` + `ring-ring/50`.
   Entao borda no anel, e sombra de 3 no anel a 50 %, nos dois. */
.fg-campo select:focus-visible,.fg-campo input:focus-visible{outline:none;
  border-color:var(--anel);box-shadow:0 0 0 3px color-mix(in srgb,var(--anel) 50%,transparent)}

/* ══ A ABA CONFIGURAÇÕES ═══════════════════════════════════════════════════════════
   Dela, 22/09: "mais uma aba ao lado de Log de Eventos, que é Configurações".
   ⭐ O CAMPO NÃO É PEÇA NOVA: é o `.fg-campo` que já mora nesta folha, na VARIANTE
   GRANDE — que o comentário dele acima já mede e a folha ainda não escrevia:
   `cameras-filters__select`, 36 de altura, recuo 6/12, raio 10, fio `--border`, fundo
   transparente, 14/400. A pequena (32 / 4-8 / 12) existe porque cabe num popover de
   285; uma tela de cadastro não é um popover, então aqui vale a de cima.
   ⚠️ DIVERGÊNCIA DECLARADA, não escolha silenciosa: o `z-input` do kit
   (`input.variants.ts`) dá `px-2.5` (10) e fio `--input`; o dev, medido pelo André em
   15/09, dá 12 e `--border`. Fico com o medido no produto, porque é a mesma página e o
   mesmo produto — e a diferença fica escrita aqui em vez de virar decisão de ninguém.
   ⭐ O RÓTULO e o REPOUSO vêm do kit, esses sim: `formLabelVariants` é
   `text-sm font-medium leading-none`, e o `disabled` do `z-input` é
   `bg-input/50 opacity-50 cursor-not-allowed` — que É o estado de repouso desta aba.
   Não desenhei modo de leitura: usei o que o componente já declara. */
.fg-campo.grande>label{font-size:var(--text-sm);font-weight:var(--peso-medio);
  line-height:var(--lh-none);color:var(--foreground)}
/* 🔴 `background-color` E NAO O ATALHO `background`: o atalho zera o
   `background-image`, e e' nele que mora a seta do select. Medido depois de eu errar:
   `appearance:none` mais `background-image:none` = um dropdown sem seta nenhuma. */
.fg-campo.grande select,.fg-campo.grande input{height:36px;padding:6px 12px;
  font-size:var(--text-sm);background-color:transparent}
/* o gatilho do dropdown, conferido no `selectTriggerVariants` do kit: 36 de altura,
   recuo 6/12, 14/400, cursor de ponteiro, e o chevron de 16 em `--muted-foreground`.
   O espaco da seta fica reservado no recuo da direita: 12 de folga + 16 de icone + 8. */
.fg-campo.grande select{padding-right:36px;background-position:right 12px center;
  background-size:16px 16px;cursor:pointer}
.fg-campo.grande input:disabled,.fg-campo.grande select:disabled{
  pointer-events:none;cursor:not-allowed;opacity:.5;
  background:color-mix(in srgb,var(--input) 50%,transparent)}
/* o porquê de um campo travado. 12/16 apagado, que é o idioma de nota desta página
   (`.hm__chart-header-value`) — e não o `text-sm` do `formMessage`, que é para
   validação e não para procedência. */
.fg-campo .porque{font-size:var(--text-xs);line-height:var(--lh-xs);
  color:var(--muted-foreground)}
/* o cadeado diz, no próprio rótulo, que aquele campo não se edita nem destravado */
.fg-campo .trava{display:inline-flex;vertical-align:-2px;margin-left:5px;
  color:var(--muted-foreground)}
.fg-campo .trava svg{width:13px;height:13px}

/* três colunas é o que cabe sem o campo ficar largo demais para o que ele guarda
   (um IP, um número, um select). Abaixo de 1100 viram duas, abaixo de 720 vira uma. */
.cfg-grade{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--sp-4)}
@media (max-width:1100px){.cfg-grade{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:720px){.cfg-grade{grid-template-columns:1fr}}
/* o par que anda junto: capacidade em VA e em W, latitude e longitude */
.cfg-grade .par{display:flex;gap:var(--sp-2)}
.cfg-grade .par>*{flex:1;min-width:0}

/* ⭐ O PÉ DA FACE, com o gesto do legado: "o lápis destrava e SALVAR confirma, com
   SALVAR desabilitado em repouso" — medido no Attlas 25 pelo André (§1.6 e §1.7 do
   mapa). SALVAR só acende quando algo muda: botão que confirma o que ninguém alterou
   é botão que mente sobre ter feito alguma coisa. */

/* ══ O CARTÃO DE GPS, ao lado dos campos de Localização ════════════════════════════
   Dela, 22/09: "adicione o mapa, use o mapa que sempre usamos aqui, use esse card com
   este formato, encaixe ao lado do card de inputs de Localização".
   ⚠️ A REFERÊNCIA AQUI É A IMAGEM, e é exceção declarada: o cartão `Informações do GPS`
   é tela do sistema rodando e NÃO existe no código desta árvore — procurei. Quando a
   régua é código, é código; quando o código não existe, a referência que ela manda é o
   que há, e fica escrito que foi assim.
   ⭐ O MAPA, esse sim, é código: `attlas-basemap.ts` do Analítico, a paleta do Painel de
   Operações, verbatim. */

.gps-cab{display:flex;align-items:center;gap:var(--sp-1-5);min-width:0}
.gps-cab .gl{display:inline-flex;color:var(--muted-foreground);flex:none}
.gps-cab .gl svg{width:15px;height:15px}
/* o endereço: é o que o cartão da referência diz embaixo do título */
.gps-end{margin:0;font-size:var(--text-xs);line-height:var(--lh-xs);
  color:var(--muted-foreground)}
/* a tela do mapa. O raio e o `overflow` são o que impede o canvas de vazar o canto, e
   o `min-height` é o que dá ao maplibre onde desenhar: caixa de altura zero não pinta. */
.gps-mapa{position:relative;flex:1;min-height:180px;border-radius:var(--r-lg);
  overflow:hidden;border:1px solid var(--border);background:var(--muted)}
.gps-mapa canvas{border-radius:var(--r-lg)}
/* os controles do maplibre na pele desta casa, e não na do plugin */
.gps-mapa .maplibregl-ctrl-group{border-radius:var(--r-md);box-shadow:var(--sombra-cartao);
  border:1px solid var(--border);background:var(--ctl-bg);overflow:hidden}
.gps-mapa .maplibregl-ctrl-group button{width:26px;height:26px;background:transparent}
.gps-mapa .maplibregl-ctrl-group button+button{border-top:1px solid var(--border)}
/* a pele dos creditos, do `ui-map.component.css`: 10px sobre um vidro leve, para o
   texto nao chapar no desenho quando o ⓘ estiver aberto */
.gps-mapa .maplibregl-ctrl-attrib{font-size:10px;background:hsl(0 0% 100% / .6);
  backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px)}
:root[data-modo="escuro"] .gps-mapa .maplibregl-ctrl-attrib{background:hsl(0 0% 0% / .6)}
/* ⭐ O ALFINETE DO `app-ui-map`, o mesmo componente que a tela de edicao de camera usa.
   Medido em `libs/ui-map/ui-map.component.css` do `attlas-2026`.
   🔴 Antes disto eu tinha o alfinete do `mapa-mock.ts` da base — arquivo errado: aquele
   e' o mapa MOCK da pagina inicial, e a camera usa o `ui-map` de verdade. */
.ui-map__pin-wrapper{display:flex;flex-direction:column;align-items:center;cursor:grab;
  filter:drop-shadow(0 2px 6px hsl(0 0% 0% / .3))}
.ui-map__pin-body{position:relative;width:38px;height:44px}
.ui-map__pin-circle{position:absolute;width:24px;height:24px;border-radius:50%;
  top:5px;left:50%;transform:translateX(-50%);z-index:2}
.ui-map__pin-shape{display:block;position:relative;z-index:1}
/* a gota e' CLARA: o preenchimento dela e' o chao da pagina, e nao a cor do dispositivo */
.ui-map__pin-bg-fill{fill:var(--background)}
.ui-map__pin-icon{position:absolute;top:5px;left:0;width:100%;height:24px;
  display:flex;align-items:center;justify-content:center;
  font-size:14px;color:hsl(0 0% 100%);pointer-events:none;z-index:3}
/* 14 e nao os 12 do componente: excecao escopada, dela em 22/09 ("o icone de dentro
   ainda esta muito pequenininho, aumenta so um pouquinho"). No circulo de 24 o glifo
   passa de 50 para 58 por cento — cresce sem encostar na borda. */
.ui-map__pin-icon svg{width:14px;height:14px}
.ui-map__pin-dot{width:8px;height:8px;border-radius:50%;margin-top:2px}
/* ⚠️ No componente a cor e' de ESTADO — editavel azul, so'-leitura neutro. Aqui ela e' a
   da CAMADA DE NOBREAKS (`--ops-layer-ups` = rose-500), por decisao dela em 22/09. */
.ui-map__pin-circle,.ui-map__pin-dot{background:#f43f5e}

.gps-pe{display:flex;flex-wrap:wrap;gap:var(--sp-4);font-size:var(--text-xs);
  line-height:var(--lh-xs);color:var(--muted-foreground)}
.gps-pe b{font-weight:var(--peso-medio);color:var(--foreground);
  font-variant-numeric:tabular-nums}

/* ══ A GAVETA DE EDIÇÃO ════════════════════════════════════════════════════════════
   Dela, 22/09: "toda essa parte de configuração a gente vai fazer como em câmera. Ao
   clicar em Editar, vai abrir uma modal lateral com todas essas configurações. Segue o
   mesmo formatinho que tem ali em câmera."

   ⭐ E A RÉGUA É O COMPONENTE DE PRODUÇÃO, lido no `atmanadmin/attlas-2026`:
   `apps/web-attlas/src/app/modules/cameras/components/camera-edit-sheet/`.
   Não é a imagem do dev.v2 — que eu nem consigo abrir, porque pede reCAPTCHA. É o
   `.html` e o `.css` do componente, classe por classe, com os tokens resolvidos nos
   arquivos de `libs/ui-styles/tokens/`.

   O QUE VEIO DE LÁ, MEDIDO:
     véu        `inset:0`, `rgb(0 0 0 / .4)` no claro e `/.6` no escuro, desfoque, 200ms
     gaveta     720 (`--width-side-sheet-wide` = `--width-w-180`), à direita, fio à
                esquerda, sombra lg, entrada de 280ms em `cubic-bezier(.22,.61,.36,1)`
     cabeçalho  recuo 16, título 16/500, fechar GHOST `icon-sm`, puxado -8 / -4
     corpo      rola por dentro, vão 16, recuo `0 16 20`
     cartão     vão 16, recuo 16, raio xl, fio 1, sombra xs
     ficha      40x40, raio lg, chão primária a 10 %, glifo na primária
     título     14 semibold · descrição 12 normal apagada
     campo      coluna, vão 8; rotulo 12 peso 500 com entrelinha 1; asterisco na destrutiva
     grade      vão `12 16`, duas colunas iguais
     localização  mapa e campos LADO A LADO, vão 12, mapa de 180 (`--height-map-preview`)
     rodapé     `Cancelar` outline sm · `Salvar` default sm, desabilitado até poder

   ⭐ E A LOCALIZAÇÃO DA CÂMERA JÁ PÕE O MAPA AO LADO DOS CAMPOS — que é o que ela tinha
   pedido ontem para esta tela, antes de eu saber que o produto fazia igual.
   ⚠️ O rótulo aqui é **12**, e não os 14 do `z-form` do kit: a câmera usa 12, e o pedido
   foi seguir a câmera. Divergência do kit, declarada.
   ⚠️ `--blur-xs` não apareceu nos arquivos de token que eu li; usei 4px, que é o valor
   do Tailwind. Se o produto usar outro, é uma linha. */

.gav-veu{position:fixed;inset:0;z-index:90;background:rgb(0 0 0 / .4);
  backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);
  animation:gav-veu-entra 200ms ease-out both}
:root[data-modo="escuro"] .gav-veu{background:rgb(0 0 0 / .6)}
.gav-veu[hidden],.gaveta[hidden]{display:none}
@keyframes gav-veu-entra{from{opacity:0}to{opacity:1}}

.gaveta{position:fixed;top:0;right:0;bottom:0;width:720px;max-width:100vw;z-index:91;
  display:flex;flex-direction:column;background:var(--background);
  border-left:1px solid var(--border);
  box-shadow:0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);
  animation:gav-entra 280ms cubic-bezier(.22,.61,.36,1) both}
@keyframes gav-entra{from{transform:translateX(100%)}to{transform:translateX(0)}}
@media (prefers-reduced-motion:reduce){
  .gaveta,.gav-veu{animation:none}}
/* abaixo de 1024 a gaveta toma a tela inteira, como a da câmera */
@media (max-width:1023.98px){.gaveta{width:100vw;border-left:0}
  .gav-local{flex-direction:column}.gav-local .gps-mapa{width:100%;flex:0 0 auto}}

.gav-cab{display:flex;align-items:flex-start;justify-content:space-between;
  flex-shrink:0;padding:16px;gap:8px}
.gav-tit{margin:0;font-size:var(--text-base,16px);font-weight:var(--peso-medio);
  line-height:24px;color:var(--foreground)}
.gav-fechar{flex-shrink:0;margin-right:-8px;margin-top:-4px}
/* ⭐ O FECHAR E' `ghost` `icon-sm`, como no `camera-edit-sheet` — e nao o `.icobtn`
   desta pagina, que tem fio. Medido em `button.variants.ts`: 28x28 (`size-7`), raio
   `min(--r-md,12)`, glifo 16, SEM chao em repouso, `--muted` no hover.
   ⚠️ O fio TRANSPARENTE e' do componente e nao e' enfeite: ele reserva a mesma caixa do
   botao com fio, para o ghost nao mudar de tamanho ao virar outra variante. */
.btn-ghost-icone{display:inline-flex;align-items:center;justify-content:center;
  width:28px;height:28px;padding:0;
  border:1px solid transparent;background-clip:padding-box;
  border-radius:min(var(--r-md),12px);
  background:transparent;color:var(--foreground);
  font:inherit;font-size:var(--text-sm);font-weight:500;cursor:pointer}
.btn-ghost-icone:hover{background:var(--muted)}
:root[data-modo="escuro"] .btn-ghost-icone:hover{
  background:color-mix(in srgb,var(--muted) 50%,transparent)}
.btn-ghost-icone svg{width:16px;height:16px}

.gav-form{display:flex;flex-direction:column;flex:1 1 auto;min-height:0}
.gav-corpo{flex:1 1 auto;min-height:0;overflow-y:auto;overflow-x:hidden;
  display:flex;flex-direction:column;gap:16px;padding:0 16px 20px;
  scrollbar-width:thin}

.gav-cartao{display:flex;flex-direction:column;gap:16px;padding:16px;
  background:var(--card);border:1px solid var(--border);
  border-radius:var(--r-xl,14px);box-shadow:0 1px 2px 0 rgb(0 0 0 / .05)}
.gav-cartao-cab{display:flex;align-items:center;gap:8px}
/* a ficha de glifo: quadrado macio na primária a 10 %, com o glifo na primária cheia */
.gav-ficha{flex-shrink:0;display:flex;align-items:center;justify-content:center;
  width:40px;height:40px;border-radius:var(--r-lg);
  background:#3b82f61a;color:var(--primary)}
:root[data-modo="escuro"] .gav-ficha{background:#2563eb33}
.gav-ficha svg{width:16px;height:16px}
.gav-cartao-tit{display:flex;flex-direction:column;gap:4px;min-width:0}
.gav-cartao-tit b{margin:0;font-size:var(--text-sm);font-weight:600;
  line-height:var(--lh-sm);color:var(--foreground)}
.gav-cartao-tit span{margin:0;font-size:var(--text-xs);font-weight:400;
  line-height:var(--lh-xs);color:var(--muted-foreground)}

.gav-grade{display:grid;gap:12px 16px;grid-template-columns:minmax(0,1fr) minmax(0,1fr)}
.gav-grade .largo{grid-column:1 / -1}
/* 🔴 ESTA REGRA TINHA SUMIDO: ela morava no bloco da fileira dupla da aba, que saiu
   inteiro, e levou junto o par que era de outro dono. Sem ela, Capacidade nominal
   empilhava 3000 sobre 2100 e Coordenadas empilhava latitude sobre longitude. */
.gav-grade .par{display:flex;gap:var(--sp-2)}
.gav-grade .par>*{flex:1;min-width:0}
/* ⚠️ o rótulo é 12, que é o da câmera — e não os 14 do `z-form` do kit */
.gaveta .fg-campo.grande>label{font-size:var(--text-xs);line-height:1}
.gaveta .fg-campo .porque{line-height:var(--lh-xs)}

/* a localização: mapa e campos lado a lado, como no `camera-edit-sheet` */
.gav-local{display:flex;gap:12px;align-items:flex-start}
.gav-local .gps-mapa{flex:1 1 0;min-width:0;height:180px;min-height:0;
  border-radius:var(--r-md)}
.gav-local-campos{flex:1 1 0;min-width:0;display:flex;flex-direction:column;gap:12px}
/* a nota do grupo, que na camera diz por que Via, Area e Subarea nao se digitam */
/* ⬅️ "esse texto faz parte do input, entao naturalmente ele tem que ficar colado no
   input" — dela, 23/09, com uma seta apontando a distancia.
   ⭐ E a distancia certa JA EXISTIA NA TELA, nao precisei escolher: a nota de um campo
   (`.fg-campo .porque`) fica a 6 do input, porque o `.fg-campo` e um flex de `gap:6`.
   Esta nota e do BLOCO, entao ela caia no `gap:16` do `.gav-cartao` — quase o triplo, e
   por isso lia como paragrafo solto em vez de rodape do campo.
   O recuo de 10 e a diferenca entre os dois (16 - 6), e nao um numero escolhido. */
.gav-nota{margin:-10px 0 0;font-size:var(--text-xs);line-height:var(--lh-xs);
  color:var(--muted-foreground)}
/* ⬅️ AQUI MORAVA `.selo-plat`, o selo de versao, medido no `badge.variants.ts` do
   produto. Ele saiu inteiro em 23/09 — "se eu estou no estado Quito nao precisa de
   badges" — e a folha vai junto: regra sem consumidor e' peso morto. */
/* ⬅️ E AQUI MORAVA `.gav-legenda`, que saiu junto com ela: regra sem consumidor é peso
   morto, e é a regra dela. */
/* ⭐ O TOOLTIP DA CASA, no lugar do `title` nativo — dela, 23/09: "tooltips em primary
   azul". E' o mesmo da dashboard, e la' ele veio de uma frase dela de 14/09: *"isso e'
   tooltip, ele precisa ser azul primary e menor em largura"*. A primitiva do produto
   aceita `zColor` e, com cor dada, vira o texto para `--primary-foreground`.
   ⚠️ TETO DE 260: o `title` nativo desenha UMA LINHA, e uma frase de 120 caracteres
   virava uma regua atravessando a tela. Com teto, ela quebra em tres linhas.
   ⚠️ E SEM `text-wrap:balance` — dela, 16/09: "essas larguras do tooltip precisam ser
   ate' o final do texto, nao podem ter espaco vazio". O `balance` reparte o texto
   igualmente e sobra faixa vazia a' direita.
   ⚠️ Z-INDEX 430, e nao os 130 da dashboard: aqui o olhinho vive em 421. */
.tip{position:fixed;z-index:430;pointer-events:none;opacity:0;
  transition:opacity var(--motion-fast) ease;
  max-width:260px;padding:6px 12px;border-radius:var(--r-md,8px);
  background:var(--primary);color:var(--primary-foreground);
  font-size:var(--text-xs);line-height:16px;width:fit-content;
  box-shadow:0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)}
/* a seta aponta para o CENTRO DO ALVO, e nao para o centro do cartao: quando o alvo
   esta' perto da borda o cartao desliza para dentro e os dois deixam de coincidir */
.tip::after{content:"";position:absolute;left:var(--seta,50%);transform:translateX(-50%);
  width:0;height:0;border:6px solid transparent}
.tip[data-lado="baixo"]::after{bottom:100%;border-bottom-color:var(--primary)}
.tip[data-lado="cima"]::after{top:100%;border-top-color:var(--primary)}
.tip.on{opacity:1}
/* ⭐ A SUB-FILEIRA (o "REDE" da ficha do aparelho), com a DIVISORIA que ela pediu em
   23/09: "antes de Rede coloque uma divisória".
   ⚠️ E o fio e os vaos foram MEDIDOS no `divider.variants.ts` do produto, nao
   escolhidos: `bg-border block h-px` — um pixel na cor `--border` — e o espacamento
   `default` e' `my-4`, ou seja 16 em cima e 16 embaixo.
   ⭐ A conta fecha com o que a grade ja' da': ela poe 12 de calha entre fileiras, entao
   os 4 de margem completam os 16 ACIMA do fio, e os 16 de recuo interno ficam ABAIXO
   dele, ate' a palavra. O fio nasce simetrico sem que eu tenha inventado numero nenhum.
   ⚠️ Embaixo do titulo o recuo negativo de 4 deixa 8 ate' os campos: o titulo tem de
   estar mais perto do que ele abre do que do que ele fecha. */
.gav-sub{margin:4px 0 -4px;border-top:1px solid var(--border);padding-top:16px;
  font-size:var(--text-xs);line-height:var(--lh-xs);
  font-weight:600;letter-spacing:.04em;text-transform:uppercase;
  color:var(--muted-foreground)}
/* os sinais ao lado do titulo do cartao */
.gav-tit-linha{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.gav-tit-linha .trava{display:inline-flex;color:var(--muted-foreground)}
.gav-tit-linha .trava svg{width:13px;height:13px}
/* ⭐ A FRASE QUE FAZ A CONTA. Ela nao e' nota de campo — e' consequencia do que a pessoa
   acabou de digitar — entao ganha caixa propria, no cinza de superficie da folha. */
.gav-calc{display:flex;align-items:flex-start;gap:8px;margin:0;
  padding:10px 12px;border-radius:var(--r-lg);
  background:color-mix(in srgb,var(--muted) 60%,transparent);
  font-size:var(--text-xs);line-height:var(--lh-xs);color:var(--muted-foreground)}
.gav-calc svg{width:14px;height:14px;flex:none;margin-top:1px}
.gav-calc b{color:var(--foreground);font-weight:600}
/* 🔴 AQUI MORAVA UMA LUPA EM ABSOLUTO dentro do campo, inventada por mim: o texto
   passava por baixo dela porque o recuo de 12 da classe `.grande` ganhava do meu 32.
   A peca certa e' o `z-input-group` com addon, e com ela o problema nao existe. */
/* o addon ANTES: `pl-2`, sem o encaixe negativo (que so' vale quando ha' botao) */
.grupo-addon.antes{order:-1;padding-left:8px;padding-right:0;margin-right:0}
.grupo-addon svg{width:16px;height:16px;color:var(--muted-foreground)}
/* o limpar do seletor, medido no CSS do componente: sem fio, sem chao, recuo 0 */
.btn-limpar{display:inline-flex;align-items:center;justify-content:center;
  border:0;background:transparent;padding:0;cursor:pointer;
  color:var(--muted-foreground)}
.btn-limpar:hover{color:var(--foreground)}
/* 16, o mesmo da lupa do outro lado do campo — e' o `size-4` que o addon do
   `z-input-group` declara para o glifo. Estava 14, e dois glifos de tamanhos
   diferentes no mesmo campo e' o que ela viu como fora do padrao. */
.btn-limpar svg{width:16px;height:16px}
/* 🔴 O ADDON DE LIMPAR NAO LEVA O RECUO NEGATIVO. No kit o `mr-[-0.3rem]` vem de um
   `compoundVariant` com `has-[>button]`, e existe para encaixar um botao QUE TEM
   PADDING PROPRIO. O limpar do `camera-intersection-picker` tem `padding:0` — sem
   padding para compensar, o recuo negativo so' empurra o glifo para FORA do fio: medido,
   o addon terminava em 318 num grupo de 315. */
.grupo-addon.depois-limpar{margin-right:0}
/* ⭐ O GRUPO DE CAMPO com acao por dentro — o `z-input-group` do kit no `zSize="sm"`,
   que e' o que o `app-input-action` da camera monta.
   🔴 Antes disto eu tinha um botao AO LADO do campo, inferido do nome do componente sem
   abrir o arquivo. O nome ja' dizia: a acao e' DO input. */
.grupo-campo{display:flex;align-items:stretch;width:100%;min-width:0;height:32px;
  border:1px solid var(--input);border-radius:var(--r-lg);transition:border-color .15s}
.grupo-campo:focus-within{border-color:var(--anel);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--anel) 50%,transparent)}
/* por dentro do grupo o campo perde fio, fundo e recuo: quem desenha a moldura e' o grupo */
/* 🔴 A ESPECIFICIDADE PRECISA GANHAR DA `.fg-campo.grande`, que crava 36: dentro do
   grupo quem manda na altura e o GRUPO, e um campo de 36 num grupo de 32 vaza. Medido. */
.gaveta .fg-campo.grande .grupo-campo>input{height:100%;flex:1;min-width:0;
  border:0;background:transparent;border-radius:0;padding:0 10px;
  font-size:var(--text-sm)}
.grupo-campo>input:focus-visible{outline:none;box-shadow:none}
/* o addon: vao 6, recuo 8 a' direita, e o encaixe de -0.3rem que o kit declara */
/* 🔴 O [hidden] PRECISA SER DECLARADO JUNTO: a regra do navegador perde para qualquer
   display de autor. Medido no x de limpar — atributo hidden verdadeiro, display
   computado flex, botao na tela. TERCEIRA vez deste defeito neste projeto. */
.grupo-addon[hidden]{display:none}
.grupo-addon{display:inline-flex;align-items:center;gap:6px;padding-right:8px;
  margin-right:-.3rem;flex:none}
/* o botao `xs` `secondary`: 24 de altura, vao 4, recuo 8, texto 12, glifo 12 */
.btn-xs{display:inline-flex;align-items:center;gap:4px;height:24px;padding:0 8px;
  border:0;border-radius:min(var(--r-md),10px);font:inherit;font-size:var(--text-xs);
  font-weight:500;cursor:pointer;white-space:nowrap;
  background:var(--secondary);color:var(--secondary-foreground)}
.btn-xs:hover{background:color-mix(in srgb,var(--secondary) 80%,transparent)}
.btn-xs svg{width:12px;height:12px;flex:none}
/* readonly nao e' desabilitado: o campo continua legivel e focavel, so' nao se digita */
.gaveta .fg-campo.grande input[readonly]{background:color-mix(in srgb,var(--muted) 45%,transparent);
  cursor:default}

.gav-pe{display:flex;align-items:center;justify-content:flex-end;gap:8px;
  flex-shrink:0;padding:16px;border-top:1px solid var(--border)}

/* ══ O MODAL DE DECISÃO ════════════════════════════════════════════════════════════
   Dela, 22/09: "caso o usuário tiver editado alguma coisa e ele tentar fechar a modal,
   uma modal de decisão tem que aparecer perguntando se ele quer mesmo sair sem salvar".

   ⭐ A peça é o `z-alert-dialog` do kit (`alert-dialog.variants.ts` e o `.html` do
   componente), e o uso é o do `camera-edit-sheet`, que abre exatamente este diálogo no
   `requestClose()` quando o formulário está sujo.
     cartão    **384**, raio **xl (14)**, fio `--border`, chão `--background`,
               `overflow:hidden` e sombra lg
     cabeçalho `flex items-start gap-4 p-4` — vão 16, recuo 16
     mídia     **40×40**, raio **md (8)**; no destrutivo, chão `--destructive` a 10 % e
               glifo na `--destructive`
     textos    vão **6**; título **16/24 medium** (não semibold); descrição 14/20 apagada
     rodapé    faixa própria: fio no topo, chão `--muted` a **50 %**, recuo 16, vão 8,
               ações à direita
   ⚠️ O `overflow:hidden` do cartão não é enfeite: sem ele o chão do rodapé vaza pelos
   cantos arredondados. Está escrito no comentário do componente.
   ⚠️ E o botão `destructive` do kit é **TINGIDO**, não vermelho cheio:
   `bg-destructive/10`, texto na `--destructive`, hover a 20 %. Eu teria feito sólido. */
.dlg-veu{position:fixed;inset:0;z-index:92;background:rgb(0 0 0 / .4);
  animation:gav-veu-entra 200ms ease-out both}
:root[data-modo="escuro"] .dlg-veu{background:rgb(0 0 0 / .6)}
.dlg-veu[hidden],.dlg[hidden]{display:none}
/* ⬅️ dela, 01/10: "parece ter linha dupla no stroke do footer". Era o centro por `translate(-50%,-50%)`: com altura
   ímpar o cartão caía em meio pixel (topo em 350,5) e, transformado, o fio de 1 do rodapé se espalhava por duas linhas
   de pixel. Centrado pelo layout (`inset:0` + `margin:auto`), o navegador encaixa o fio no pixel inteiro. */
.dlg{position:fixed;z-index:93;inset:0;margin:auto;height:fit-content;
  width:100%;max-width:384px;display:flex;flex-direction:column;overflow:hidden;
  border:1px solid var(--border);background:var(--background);
  border-radius:var(--r-xl,14px);
  box-shadow:0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1)}
@media (max-width:420px){.dlg{max-width:calc(100% - 2rem)}}
.dlg-cab{display:flex;align-items:flex-start;gap:16px;padding:16px}
.dlg-media{flex:none;display:flex;align-items:center;justify-content:center;
  width:40px;height:40px;border-radius:var(--r-md);overflow:hidden;
  background:var(--muted);color:var(--foreground)}
/* ⭐ O PAR E' O DA PROPRIA PAGINA (linha 73 desta folha): `--status-instavel-fundo` e'
   `#DC26261A` (o mesmo vermelho a 10 %) e `--status-instavel` e' `#DC2626` cheio.
   E' o par da pilula `Necessita substituicao` da aba Saude. 🔴 Eu tinha escrito
   `var(--destructive)`, que e' o nome do token no KIT e NAO existe aqui — e `var()` de
   token inexistente nao da' erro, so' herda. */
.dlg-media.destrutivo{background:var(--status-instavel-fundo);
  color:var(--status-instavel)}
.dlg-media svg{width:16px;height:16px}
.dlg-txt{display:flex;flex-direction:column;gap:6px;min-width:0;flex:1;
  overflow-wrap:break-word}
.dlg-txt h2{margin:0;font-size:var(--text-base,16px);line-height:24px;
  font-weight:var(--peso-medio);color:var(--foreground)}
.dlg-txt p{margin:0;font-size:var(--text-sm);line-height:20px;color:var(--muted-foreground)}
.dlg-pe{display:flex;align-items:center;justify-content:flex-end;gap:8px;padding:16px;
  border-top:1px solid var(--border);
  background:color-mix(in srgb,var(--muted) 50%,transparent)}
/* os dois botões, no tamanho padrão do kit: 32 de altura, recuo 10/6, raio 10 */
.btn-ds{display:inline-flex;align-items:center;justify-content:center;gap:6px;
  height:32px;padding:6px 10px;border-radius:var(--r-lg);
  border:1px solid transparent;font:inherit;font-size:var(--text-sm);font-weight:500;
  cursor:pointer;white-space:nowrap}
.btn-ds.outline{border-color:var(--border);background:var(--background);
  color:var(--foreground)}
.btn-ds.outline:hover{background:var(--muted)}
/* ⚠️ TINGIDO, e não vermelho cheio — é o que o `destructive` do kit declara */
.btn-ds.destrutivo{background:var(--status-instavel-fundo);color:var(--status-instavel)}
.btn-ds.destrutivo:hover{background:color-mix(in srgb,var(--status-instavel) 20%,transparent)}

/* ── a validação ───────────────────────────────────────────────────────────────────
   Do `camera-edit-sheet`: `aria-invalid` no campo pinta a borda de destrutivo, e a
   mensagem sai em `role="alert"` logo abaixo. ⭐ E só depois do `blur` (`ctrl.touched`),
   "to avoid noisy validation while the operator is still typing" — está escrito lá. */
.gaveta .fg-campo.grande input[aria-invalid="true"],
.gaveta .fg-campo.grande select[aria-invalid="true"],
.gaveta .fg-campo.grande input[aria-invalid="true"]:hover,
.grupo-campo:has(input[aria-invalid="true"]){border-color:var(--status-instavel)}
.fg-campo .erro{font-size:var(--text-xs);line-height:var(--lh-sm);
  color:var(--status-instavel)}
.gav-pe button:disabled{opacity:.5;cursor:not-allowed;pointer-events:none}

/* ---- MULTI-SELECT, na anatomia do `z-combobox zMultiple` ----
   PEDIDO DA LARISSA, trazido pelo André em 15/09: os primeiros filtros deixam de ser
   uma lista de caixas de marcar e viram **um campo onde a pessoa vai acrescentando**.
   DE ONDE SAI A ANATOMIA, e o que é inferência:
   · o componente existe e é `z-combobox` com `zMultiple` — `componentes-zard.md`
     linha 931. Os inputs dizem o desenho: `zSearchPlaceholder` (tem busca dentro),
     `zEmptyText` (tem estado vazio), `zRemoveLabel` (cada escolha tem um remover, ou
     seja, CHIP), `zClearable` (limpa tudo).
   · o GATILHO e o PAINEL foram medidos no `z-select` do dev, que é o irmão dele:
     gatilho 32/4-8/raio 10; painel raio 8, borda 1, fundo `--popover`, padding 4,
     `max-height` 384, item 34 com padding 6/32/6/8, raio 6, 14, e o escolhido com
     fundo `#F5F5F5` e texto `#171717`.
   · o CHIP é o `Badge` da biblioteca, variante secondary: raio full, padding 8x2,
     gap 4, 12/16 medium.
   ⚠️ O PAINEL ABRE NO FLUXO, e não flutuando. No Angular o combobox usa overlay do
   CDK, que não é cortado por nada. Aqui ele vive DENTRO do popover de filtros, que
   rola: um painel absoluto seria cortado pela rolagem do pai na primeira opção fora
   da vista. Então ele empurra o conteúdo, e o popover cresce. É a única diferença
   deliberada, e some quando isto virar componente. */
.msel{position:relative;display:flex;flex-direction:column;gap:6px}
.msel-gat{display:flex;align-items:center;justify-content:space-between;gap:8px;
  width:100%;min-height:32px;box-sizing:border-box;padding:4px 8px;
  border:1px solid var(--border);border-radius:var(--r-lg);background:var(--ctl-bg);
  color:var(--foreground);font:inherit;font-size:var(--text-xs);cursor:pointer;
  text-align:left}
.msel-gat:hover{border-color:var(--muted-foreground)}
.msel-gat:focus-visible{outline:none;border-color:var(--primary);
  box-shadow:0 0 0 3px var(--anel,#D1D1D1)}
.msel-gat[aria-expanded="true"]{border-color:var(--primary)}
.msel-val{flex:1;min-width:0;display:flex;flex-wrap:wrap;gap:4px;align-items:center}
.msel-ph{color:var(--muted-foreground)}
.msel-ch{flex:none;display:inline-flex;color:var(--muted-foreground)}
.msel-ch svg{width:16px;height:16px;transition:transform var(--motion-fast) ease}
.msel-gat[aria-expanded="true"] .msel-ch svg{transform:rotate(180deg)}
/* o chip: Badge secondary, medido na biblioteca */
.msel-chip{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;
  border-radius:var(--r-full);background:var(--secondary);color:var(--secondary-foreground);
  font-size:var(--text-xs);line-height:16px;font-weight:var(--peso-medio);max-width:100%}
.msel-chip b{font-weight:var(--peso-medio);overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.msel-x{display:inline-flex;align-items:center;justify-content:center;width:12px;
  height:12px;flex:none;border:0;background:none;padding:0;cursor:pointer;
  color:var(--muted-foreground);border-radius:var(--r-full)}
.msel-x svg{width:10px;height:10px}
.msel-x:hover{color:var(--foreground)}
/* ⚠️ MESMA ARMADILHA DO `.dois`, e ela apareceu duas vezes na mesma hora: `display`
   de classe vence o `hidden`, que e' regra do navegador. Os tres paineis do log
   nasciam ABERTOS ao mesmo tempo, com o atributo posto e sem efeito. Toda classe que
   liga `display` precisa desligar no `[hidden]`. */
.msel-pop{border:1px solid var(--border);border-radius:var(--r-md);
  background:var(--card);padding:4px;display:flex;flex-direction:column;gap:4px;
  box-shadow:var(--sombra-cartao)}
.msel-pop[hidden]{display:none}
.msel-busca{display:flex;align-items:center;gap:6px;padding:4px 6px;
  border-bottom:1px solid var(--border);margin:-4px -4px 0;color:var(--muted-foreground)}
.msel-busca svg{width:12px;height:12px;flex:none}
.msel-busca input{flex:1;min-width:0;height:24px;border:0;background:none;
  color:var(--foreground);font:inherit;font-size:var(--text-xs);outline:none}
.msel-lista{max-height:180px;overflow-y:auto;scrollbar-width:thin;
  display:flex;flex-direction:column}
.msel-op{display:flex;align-items:center;gap:7px;min-height:28px;padding:4px 8px;
  border:0;background:none;border-radius:var(--r-sm);color:var(--foreground);
  font:inherit;font-size:var(--text-xs);cursor:pointer;text-align:left;width:100%}
.msel-op:hover{background:var(--secondary);color:var(--secondary-foreground)}
.msel-op[aria-selected="true"]{background:var(--secondary)}
.msel-op .rot{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.msel-op .cx{width:14px;height:14px;flex:none;border:1px solid var(--input);
  border-radius:4px;display:grid;place-items:center;color:transparent;background:var(--card)}
.msel-op[aria-selected="true"] .cx{background:var(--primary);border-color:var(--primary);
  color:var(--primary-foreground)}
.msel-op .cx svg{width:10px;height:10px}
.msel-op .n{margin-left:auto;padding-left:6px;font-variant-numeric:tabular-nums;
  color:var(--muted-foreground)}
.msel-op.zero .n{opacity:.55}
.msel-vazio{padding:10px 8px;text-align:center;color:var(--muted-foreground);
  font-size:var(--text-xs)}
.fg-campo .par2{display:flex;gap:6px}
.fg-campo .par2 input{flex:0 0 72px}
.fg-campo .par2 select{flex:1;min-width:0}
/* ⚠️ `display` de CLASSE vence o `hidden` do navegador, que e' regra de UA. Os dois
   campos de data do periodo personalizado ficavam visiveis em `1 hora`, com o atributo
   `hidden` posto e sem efeito nenhum. Quem liga display tem que desligar tambem. */
.fg-campo .dois{display:flex;gap:6px}
.fg-campo .dois[hidden]{display:none}
.fg-campo .dois input{flex:1;min-width:0}
.fg-nota{font-size:11px;line-height:14px;color:var(--muted-foreground)}
/* O separador do rodape e' de largura CHEIA; os internos sao recuados pelo respiro. */
.fpop-pe{flex:none;height:48px;box-sizing:border-box;padding:10px;
  display:flex;justify-content:flex-end;align-items:center;gap:6px;
  border-top:1px solid var(--border);background:var(--card)}
/* A REGUA do `botoes-ds.py`: xs 24 · sm 28 · default 32 · lg 36, e RAIO 8 em TODOS
   os tamanhos, porque o raio nao acompanha a altura. `sm` = 28 de altura, 12 de
   recuo, rotulo 12/500. Aqui e' `sm`, e nao `default`: superficie menor pede
   controle menor, a mesma logica do botao de 24 dentro de celula de tabela.
   Os estados seguem o mesmo modelo do `.icobtn` acima, e o hover e' o unico
   proprio de cada variante. */
.fbt{display:inline-flex;align-items:center;justify-content:center;gap:8px;
  height:28px;padding:0 12px;border-radius:8px;box-sizing:border-box;
  font:inherit;font-size:var(--text-xs);font-weight:500;line-height:1;
  white-space:nowrap;cursor:pointer;
  transition:background var(--motion-fast),border-color var(--motion-fast),
             opacity var(--motion-fast),box-shadow var(--motion-fast)}
.fbt.contorno{border:1px solid var(--border);background:var(--card);color:var(--foreground)}
.fbt.contorno:hover{background:var(--sec,#F5F5F5);color:var(--sec-txt,#171717)}
.fbt.contorno:focus-visible{border-color:var(--linha-3,#A3A3A3)}
/* O hover da primaria ESCURECE para blue/700, e isso ja' foi medido: o rotulo e'
   #F9FAFB, e sobre o azul clareado (#3A72ED) ele da' 4,18, abaixo do piso. Sobre
   blue/700 da' 6,41. A direcao do hover nao manda no piso de leitura. */
.fbt.cheio{border:1px solid var(--primary);background:var(--primary);
  color:var(--primary-foreground)}
.fbt.cheio:hover{background:var(--acc-hover,#1D4ED8);border-color:var(--acc-hover,#1D4ED8)}
.fbt:active{opacity:.6}
.fbt:focus-visible{outline:none;box-shadow:0 0 0 3px var(--anel,#D1D1D1)}
.fbt:disabled{opacity:.5;cursor:not-allowed}
.fbt.cheio:disabled:hover{background:var(--primary);border-color:var(--primary)}
.fbt.contorno:disabled:hover{background:var(--card)}
/* O badge conta o APLICADO, nunca o rascunho: ele relata a tabela, nao o painel. */
.fil-gat{position:relative}
.fil-badge{position:absolute;top:-2px;right:-2px;min-width:16px;height:16px;
  box-sizing:border-box;padding:0 4px;border-radius:999px;background:var(--primary);
  color:var(--primary-foreground);font-size:10px;font-weight:600;line-height:16px;
  text-align:center;pointer-events:none}

/* ---- as duas colunas da pagina ----
   ERRO CORRIGIDO EM 14/09: a primeira versao usou o `.insp` do `plano-detalhes.html`
   para Consulta, Saúde da Bateria e Dispositivos e Impacto. O `.insp` e' o INSPETOR
   DE PROPRIEDADES DA TAREFA, que vive DENTRO do canvas do fluxograma, e por isso tem
   chao cinza: ele e' elemento interno daquele quadro. Aqui nao e' o caso, e o chao
   cinza dizia que os tres blocos eram parte do grafico, o que e' falso.
   O certo e' o `.side`, a coluna de `Dados iniciais`: CONTAINER PROPRIO, chao de
   cartao, borda, raio 12, e um vao de 16 ate' o painel grande. As duas colunas sao
   irmas, e nenhuma esta' dentro da outra. */
/* ===== A BARRA DE ABAS DA PÁGINA =====
   ⚠️ REVERSÃO 15/09, pedida pelo Andre com a dica da Isabela. As cinco faces da tela
   viram ABAS DE PAGINA, no mesmo componente que a `planos-lista.html` usa na Filter
   Bar e que as telas de Monitoramento do `dev.v2` usam no topo (Controladores e PMV):
   rotulo `text-sm` medium, sublinhado de 2 no selecionado, regua de 1 embaixo
   atravessando a largura toda. E' o componente que ja' existe no Figma, e por isso
   este bloco copia `.fbar`/`.tabs` do `planos-lista.html` em vez de inventar. */
/* ⚠️ AS SETAS DA LATERAL NASCIAM AQUI, e a causa e' de uma linha.
   `overflow-x:auto` com o outro eixo em `visible` faz o `overflow-y` COMPUTAR PARA
   `auto` — e' regra do CSS, nao defeito do navegador. E o `margin-bottom:-1px` dos
   botoes, que e' o que faz o sublinhado da aba pousar EM CIMA da regua, deixa o
   conteudo 1px mais alto que a caixa. Medido: `scrollHeight` 36 contra
   `clientHeight` 35. Um pixel basta: o Chrome desenha a barra vertical inteira, com
   botao de seta em cima e embaixo, e ficam duas setas paradas na lateral sem ter o
   que rolar. `overflow-y:hidden` resolve na origem.
   ⚠️ E a correcao anterior estava no lugar errado: eu tinha posto `scrollbar-width`
   nas areas que rolam, tratando o sintoma numa caixa que nao era a culpada. */
.ptabs{border-bottom:1px solid var(--border);padding:0 2px;flex:none;margin-bottom:16px;
  display:flex;align-items:center;gap:4px;overflow-x:auto;overflow-y:hidden}
.ptabs button{display:flex;align-items:center;gap:6px;padding:6px 2px 8px;flex:none;
  border:0;border-bottom:2px solid transparent;background:none;
  color:var(--muted-foreground);font:inherit;
  font-size:var(--text-sm);line-height:var(--lh-sm);font-weight:500;cursor:pointer;
  margin-bottom:-1px}
.ptabs button+button{margin-left:14px}
.ptabs .ic{display:inline-flex;flex:none;color:currentColor}
.ptabs .ic svg{width:15px;height:15px;display:block}
.ptabs button:hover{color:var(--foreground)}
.ptabs button[aria-selected="true"]{border-bottom-color:var(--primary);color:var(--foreground)}
.ptabs button:focus-visible{outline:none;box-shadow:0 0 0 3px var(--anel,#D1D1D1);
  border-radius:var(--r-sm)}

.shell{display:flex;flex-direction:column;flex:1;min-height:0}
.side{background:var(--card);border:1px solid var(--border);border-radius:12px;
  display:flex;flex-direction:column;min-height:0;overflow:hidden}
/* As tres faces em LISTA VERTICAL, e nao em abas lado a lado. Numa coluna de 256 os
   tres rotulos do wireframe nao cabem na horizontal, e abreviar `Dispositivos e
   Impacto` seria renomear conceito para resolver problema visual, que e' anti-padrao
   registrado. A coluna do `plano-detalhes` ja' troca de face por um controle no
   cabecalho; aqui sao tres, entao o controle e' a lista. */
.side-nav{padding:8px;border-bottom:1px solid var(--border);flex:none;
  display:flex;flex-direction:column;gap:2px}
.side-nav button{display:flex;align-items:center;gap:8px;width:100%;padding:7px 10px;
  border:0;background:none;border-radius:var(--r-md);font:inherit;
  font-size:var(--text-xs);line-height:var(--lh-xs);font-weight:500;
  color:var(--muted-foreground);text-align:left;cursor:pointer}
.side-nav button:hover{background:var(--muted);color:var(--foreground)}
.side-nav button[aria-selected="true"]{background:var(--muted);color:var(--foreground)}
.side-nav svg{width:15px;height:15px;flex:none}
.side-rol{flex:1;min-height:0;overflow-y:auto;padding:14px 16px 18px}
/* O titulo da face aceita pastilha NA MESMA LINHA. Empilhada embaixo, a pastilha
   parecia um terceiro nivel de cabecalho; ao lado do titulo ela qualifica o titulo,
   que e' o que ela faz. */
.side-h{font-size:var(--text-sm);line-height:1;font-weight:600;color:var(--foreground);
  display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.side-sub{font-size:11.5px;color:var(--muted-foreground);margin-top:4px}
.side-cab{display:flex;align-items:flex-start;gap:10px;margin-bottom:12px}
.side-cab .cresc{flex:1;min-width:0}

/* ---- o painel grande, a coluna da direita ---- */
/* ⚠️ CARTAO DENTRO DE CARTAO. Enquanto as faces eram duas colunas, o `.panel` era o
   cartao e o conteudo vinha solto dentro dele. Com as cinco faces em abas de pagina,
   o conteudo passou a trazer os proprios blocos em caixa, e o `.panel` virou uma
   segunda moldura em volta: cartao dentro de cartao le' como um objeto pousado sobre
   o outro, que e' anti-padrao ja' registrado. Na tela de referencia os cartoes
   flutuam sobre o CHAO DA PAGINA. Entao o painel deixa de ser superficie. */
.panel{background:transparent;border:0;border-radius:0;
  min-height:0;display:flex;flex-direction:column;flex:1}
/* e quem vira cartao e' cada face que precisa de moldura */
.cartao{background:var(--card);border:1px solid var(--border);border-radius:12px;
  overflow:hidden;min-height:0;display:flex;flex-direction:column;flex:1;
  margin:0 24px 24px}
.pbar{display:flex;align-items:center;gap:10px;padding:12px 14px;flex:none;
  border-bottom:1px solid var(--border);min-width:0}
.segs{flex:none;display:flex;gap:2px;background:var(--muted);padding:3px;
  border-radius:var(--r-lg)}
.segs button{padding:6px 13px;font:inherit;font-size:13px;color:var(--muted-foreground);
  border:0;background:none;border-radius:7px;cursor:pointer}
.segs button.on{background:var(--ctl-bg);color:var(--foreground);font-weight:500;
  box-shadow:0 1px 2px #0000000F}
.pbar .cresc{flex:1;min-width:0}
.pbar .ro{font-size:11px;font-weight:500;padding:3px 10px;border-radius:999px;
  background:var(--muted);color:var(--muted-foreground);white-space:nowrap}
.panelmain{flex:1;min-width:0;min-height:0;display:flex;flex-direction:column;overflow:hidden}
/* as tres abas de informacao rolam por dentro do painel, como o log e o grafico */
/* `scrollbar-width:thin` tira os BOTOES DE SETA da barra de rolagem. No Windows a
   barra classica desenha uma seta em cima e outra embaixo, e numa area que mal rola
   elas aparecem sem ter o que rolar: duas setas paradas na lateral, que foi o que o
   Andre viu. A barra fina nao tem botao, so' o polegar. Vale para as tres areas que
   rolam nesta tela. */
.hm,.logrol,.fpop-corpo,.msel-lista{scrollbar-width:thin}
.panelmain > div{flex:1;min-height:0;display:flex;flex-direction:column}
.panelmain > div[hidden]{display:none}

/* ---- os blocos em grade SAIRAM, e o que ficou no lugar ----
   Esta folha tinha ~50 linhas de `.grelha`, `.bl`, `.pr`, `.reg` e `.linhas`: os
   blocos em caixa que a face de informacao usava, com quatro correcoes registradas em
   cima (a borda de baixo do ultimo cartao, o filho de flex que esticava, o `.pr.col`
   que virava duas colunas, as duas colunas fixas em vez de `auto-fill`).
   Com as duas faces passadas para o PADRAO DE SAUDE, ninguem mais usa nenhuma delas:
   quem carrega numero agora e' `uptime-card__stat` e `metric-card`, medidos em
   `padrao-saude-medido.md`. CSS que ninguem usa nao e' historico, e' armadilha: a
   proxima pessoa acha a regra, acredita que ela vale, e depura o lugar errado.
   As quatro correcoes continuam escritas onde correcao se le', no mapa (6-D.7 a
   6-D.9). A funcao `agrupar()` saiu junto, pelo mesmo motivo. */

/* ---- fichas de parametro ---- */
.fichas{display:flex;flex-wrap:wrap;gap:6px}
.fic{padding:3px 10px;border:1px solid var(--input);border-radius:999px;background:var(--ctl-bg);
  color:var(--muted-foreground);font:inherit;font-size:11px;cursor:pointer;white-space:nowrap}
.fic:hover{border-color:var(--muted-foreground)}
.fic.on{background:var(--primary);border-color:var(--primary);color:var(--primary-foreground);
  font-weight:500}

/* ---- campos ---- */
.cp{margin-bottom:10px}
.cp label{display:block;font-size:11px;font-weight:500;color:var(--muted-foreground);
  margin-bottom:4px}
.cp input,.cp select{width:100%;height:32px;padding:6px 10px;border:1px solid var(--input);
  border-radius:var(--r-md);background:var(--ctl-bg);color:var(--foreground);
  font:inherit;font-size:var(--text-xs);box-sizing:border-box}
.cp .par2{display:flex;gap:8px}
.cp .par2 input{flex:1;min-width:0}
.cp .par2 select{width:104px;flex:none}
.chave{display:flex;align-items:center;gap:8px;margin:12px 0 14px;font-size:var(--text-xs);
  color:var(--foreground)}
.chave i{width:30px;height:17px;border-radius:999px;background:var(--input);flex:none;
  position:relative;transition:background var(--motion-fast) ease}
.chave i::after{content:'';position:absolute;top:2px;left:2px;width:13px;height:13px;
  border-radius:50%;background:var(--card);transition:transform var(--motion-fast) ease}
.chave.on i{background:var(--primary)}
.chave.on i::after{transform:translateX(13px)}
.bts{display:flex;gap:8px}
.bts button{flex:1;height:32px;border-radius:var(--r-md);font:inherit;
  font-size:var(--text-xs);font-weight:500;cursor:pointer}
.bt-pri{border:0;background:var(--primary);color:var(--primary-foreground)}
.bt-sec{border:1px solid var(--input);background:var(--ctl-bg);color:var(--foreground)}
.bt-sec:hover{background:var(--ctl-bg-ativo)}
.bt-tint{border:0;background:var(--primary-status);color:var(--primary)}

/* =====================================================================
   O PADRAO DE SAUDE, COPIADO DA TELA DE CAMERAS
   =====================================================================
   ORIGEM: `dev.v2.attlas.atmansystems.com/#/cameras/devices/<id>`, coluna direita,
   aba `Saúde`. Medido no DOM em 15/09/2026, regra por regra, e escrito em
   `padrao-saude-medido.md`. Pedido da Larissa, trazido pelo Andre: copiar FIEL.

   OS NOMES DE CLASSE SAO OS DO SISTEMA (`uptime-card`, `metric-card`,
   `health-metrics__*`) de proposito. Quem levar isto para Angular nao precisa
   traduzir nome nenhum: acha a classe no dev e ve' a mesma regra.

   O QUE MUDA DE LA' PARA CA', e por que:
   1. LARGURA. La' o padrao vive numa coluna de 314, com cartao de 270 e pecas de 114.
      Aqui a face tem 1228. A grade 2x2 vira 4 em linha, e a densidade das barras foi
      mantida (passo ~34, barra ~17) em vez do NUMERO de barras: sete varetas de 17
      espalhadas em 1196 nao sao o mesmo desenho, sao o mesmo numero.
   2. O SELETOR DE PERIODO. La' ele mora no cabecalho da secao. Aqui o recorte todo
      mora no `Filtros`, por decisao do Andre (6-D.5): "a aba tem que mostrar
      informacoes referentes aquela aba". Entao o gatilho de `Filtros` OCUPA a posicao
      do seletor de periodo, com o mesmo tamanho e o mesmo tipo de botao.
   3. CARTAO DENTRO DE CARTAO, com raio 14 por DENTRO de raio 10. Contraria o
      anti-padrao desta frente e a intuicao de que o filho tem raio menor. O Andre
      decidiu em 15/09: fiel ao sistema, e escalar para a Barbara (achado 9). */

.hm{flex:1;min-height:0;overflow-y:auto;scrollbar-width:thin;
  display:flex;flex-direction:column;gap:var(--sp-4);padding:0 24px 24px}
.hm__separator{height:1px;background:var(--border);flex:none}
/* O cabeçalho NOMEIA o cartão logo abaixo, então ele anda junto dele: com o gap de 16
   da coluna inteira, o título ficava solto entre a barra de abas e o cartão. */
.hm__header{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-2)}
.hm__header + *{margin-top:calc(var(--sp-2) - var(--sp-4))}
.hm__section-title{margin:0;font-size:var(--text-sm);font-weight:var(--peso-medio);
  color:var(--foreground);line-height:var(--lh-none)}

/* ---- o cartao grande ---- */
.uptime-card{display:flex;flex-direction:column;gap:var(--sp-4);padding:var(--sp-4);
  background:var(--card);border:1px solid var(--border);border-radius:var(--r-lg);
  box-shadow:var(--sombra-cartao)}
.uptime-card__head{display:flex;align-items:flex-start;justify-content:space-between;
  gap:var(--sp-2)}
.uptime-card__head-text{display:flex;flex-direction:column;gap:var(--sp-1);min-width:0}
.uptime-card__title{margin:0;font-size:var(--text-sm);font-weight:var(--peso-medio);
  color:var(--foreground);line-height:var(--lh-none)}
/* O SUBTITULO E' A PECA QUE FAZ O PADRAO FUNCIONAR: ele diz COMO o numero foi
   apurado, nao repete o titulo. `Proporção em janelas de 5 min` na tela de camera. */
.uptime-card__subtitle{margin:0;font-size:var(--text-xs);font-weight:var(--peso-leve);
  color:var(--muted-foreground);line-height:var(--lh-xs)}
.uptime-card__acoes{display:flex;align-items:center;gap:var(--sp-2);flex:none}
.uptime-card__badges{display:flex;align-items:center;gap:var(--sp-2)}
.uptime-card__badge{display:inline-flex;align-items:center;gap:var(--sp-1);
  padding:var(--sp-0-5) var(--sp-2);border-radius:var(--r-full);
  font-size:var(--text-xs);font-weight:var(--peso-medio);line-height:var(--lh-xs);
  white-space:nowrap}
.uptime-card__badge--rede{background:var(--status-estavel-fundo);color:var(--status-estavel)}
.uptime-card__badge--bateria{background:var(--status-parc-instavel-fundo);
  color:var(--status-parc-instavel)}
.uptime-card__badge--bypass{background:var(--modo-bypass-fundo);color:var(--modo-bypass)}
.uptime-card__badge--semdado{background:var(--muted);color:var(--muted-foreground)}
/* la' sao duas colunas porque a coluna tem 270; aqui cabem quatro */
.uptime-card__grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:var(--sp-2)}
@media (max-width:900px){.uptime-card__grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
.uptime-card__stat{display:flex;flex-direction:column;gap:var(--sp-1);padding:var(--sp-4);
  background:var(--card);border:1px solid var(--border);border-radius:var(--r-xl);
  box-shadow:var(--sombra-cartao);overflow:hidden}
.uptime-card__stat-label{display:flex;align-items:center;gap:var(--sp-1);
  font-size:var(--text-xs);font-weight:var(--peso-normal);color:var(--card-foreground);
  line-height:var(--lh-xs)}
.uptime-card__stat-value{font-size:18px;font-weight:var(--peso-forte);
  color:var(--card-foreground);line-height:var(--lh-none);font-variant-numeric:tabular-nums}
.uptime-card__stat-sub{font-size:var(--text-xs);font-weight:var(--peso-normal);
  color:var(--muted-foreground);line-height:var(--lh-xs)}
/* a UNICA cor sem palavra desta tela, e ela tem a palavra logo acima, no rotulo */
.uptime-card__stat-sub--rede{color:var(--status-estavel)}
.uptime-card__stat-sub--bateria{color:var(--status-parc-instavel)}
.uptime-card__stat-sub--bypass{color:var(--modo-bypass)}
.uptime-card__info{font-size:var(--text-xs);color:var(--muted-foreground);cursor:help;
  display:inline-flex;align-items:center}
.uptime-card__info svg{width:12px;height:12px}
.uptime-card__legend{display:flex;gap:var(--sp-4);flex-wrap:wrap;justify-content:center}
.uptime-card__legend-item{display:flex;align-items:center;gap:var(--sp-1-5);
  font-size:var(--text-xs);color:var(--foreground)}
.uptime-card__legend-item::before{content:'';width:var(--sp-2);height:var(--sp-2);
  border-radius:var(--r-xs);flex-shrink:0}
.uptime-card__legend-item--rede::before{background:var(--status-estavel)}
.uptime-card__legend-item--bateria::before{background:var(--status-parc-instavel)}
.uptime-card__legend-item--bypass::before{background:var(--modo-bypass)}
.uptime-card__legend-item--semdado::before{background:var(--muted)}
.uptime-card__instab-title{margin:0;font-size:var(--text-xs);font-weight:var(--peso-medio);
  color:var(--foreground);line-height:var(--lh-xs)}
.uptime-card__instab{display:flex;gap:var(--sp-2)}
.uptime-card__chip{flex:1 1 0;display:flex;align-items:center;gap:var(--sp-2);
  padding:var(--sp-2) var(--sp-2-5);background:var(--card);border:1px solid var(--border);
  border-radius:var(--r-lg);font-size:var(--text-xs);color:var(--foreground);
  line-height:var(--lh-xs);min-width:0}
.uptime-card__chip span{font-weight:var(--peso-forte);white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis}
.uptime-card__chip-icon{color:var(--muted-foreground);flex-shrink:0;display:inline-flex}
.uptime-card__chip-icon svg{width:12px;height:12px}

/* ---- as barras de disponibilidade ----
   La' e' ECharts num canvas de 236x92, com a altura declarada `calc(52px + 40px)`:
   52 para as barras e 40 para os rotulos, separados de proposito. Aqui e' CSS puro,
   porque o protótipo nao carrega biblioteca de grafico; o que se copia e' a medida.
   MEDIDO: barra ~17 de largura, passo ~33,7 entre centros, topo arredondado ~5,
   e DIA SEM LEITURA E' BARRA CINZA CHEIA, nao espaco vazio: a ausencia aparece. */
.avail-bars{--ab-barras:52px; --ab-rotulos:40px}
/* a face de saude reusa a CAIXA, mas o desenho dela e' uma linha: a altura vem do
   token do grafico de linha do padrao, como no cartao de `Leituras selecionadas` */
.avail-bars > .tela{height:var(--sp-28);border:0;border-radius:0;background:none;
  position:relative;overflow:hidden;margin:var(--sp-2) 0}
.avail-bars > .tela svg{position:absolute;inset:0;width:100%;height:100%}
.avail-bars__plot{height:var(--ab-barras);display:grid;grid-auto-flow:column;
  grid-auto-columns:1fr;align-items:end}
.avail-bars__col{display:flex;flex-direction:column;justify-content:flex-end;
  align-items:center;height:100%}
.avail-bars__bar{width:17px;max-width:100%;height:100%;display:flex;flex-direction:column;
  justify-content:flex-end;border-radius:5px;overflow:hidden;background:var(--muted)}
.avail-bars__seg{width:100%;flex:none}
.avail-bars__seg--rede{background:var(--status-estavel)}
.avail-bars__seg--bateria{background:var(--status-parc-instavel)}
.avail-bars__seg--bypass{background:var(--modo-bypass)}
/* MEDIDO no canvas da camera: os rotulos ficam junto das barras, no alto da faixa de
   40, e nao centralizados nela. Centralizados, abriam um vao entre eixo e legenda. */
.avail-bars__labels{height:var(--ab-rotulos);display:grid;grid-auto-flow:column;
  grid-auto-columns:1fr;align-items:start;padding-top:var(--sp-1)}
.avail-bars__label{font-size:var(--text-xs);line-height:var(--lh-xs);
  color:var(--muted-foreground);text-align:center;white-space:nowrap}
/* a tabela que o leitor de tela le' no lugar do desenho. NAO E' ENFEITE: e' o que
   torna o grafico legivel sem visao, e copiar fiel inclui copiar isto. */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0,0,0,0);white-space:nowrap;border:0}

/* ---- os cartoes de metrica ---- */
.hm__cards{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:var(--sp-2)}
@media (max-width:900px){.hm__cards{grid-template-columns:repeat(2,minmax(0,1fr))}}
.metric-card{display:flex;flex-direction:column;gap:var(--sp-2);padding:var(--sp-4);
  background:var(--card);border:1px solid var(--border);border-radius:var(--r-xl);
  box-shadow:var(--sombra-cartao);overflow:hidden}
.metric-card__head{display:flex;align-items:center;justify-content:space-between;
  gap:var(--sp-1)}
.metric-card__head-left{display:flex;align-items:center;gap:var(--sp-1);min-width:0}
.metric-card__label{font-size:var(--text-sm);font-weight:var(--peso-medio);
  color:var(--card-foreground);line-height:var(--lh-sm);white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
.metric-card__info{font-size:var(--text-xs);color:var(--muted-foreground);flex-shrink:0;
  cursor:help;display:inline-flex}
.metric-card__info svg{width:12px;height:12px}
.metric-card__feature-icon{color:var(--muted-foreground);flex-shrink:0;display:inline-flex}
.metric-card__feature-icon svg{width:14px;height:14px}
.metric-card__value{margin:0;font-size:18px;font-weight:var(--peso-forte);
  color:var(--card-foreground);line-height:var(--lh-none);font-variant-numeric:tabular-nums}
.metric-card__sub{margin:0;font-size:var(--text-xs);font-weight:var(--peso-normal);
  color:var(--muted-foreground);line-height:var(--lh-xs)}
/* O padrao colore o `sub` da ESTATISTICA, nao o do cartao de metrica. `Reprovado` com
   o sub em cinza le' como um dado qualquer, entao o mesmo recurso foi estendido aqui,
   com o mesmo nome de classe. Fica dito: e' extensao, nao leitura. */
.metric-card__sub--instavel{color:var(--status-instavel)}
.metric-card__sub--bateria{color:var(--status-parc-instavel)}

/* ---- o cartao do grafico de linha ---- */
.hm__chart-card{display:flex;flex-direction:column;gap:var(--sp-4);padding:var(--sp-4);
  background:var(--card);border:1px solid var(--border);border-radius:var(--r-lg);
  box-shadow:var(--sombra-cartao)}
.hm__chart-header{display:flex;align-items:center;justify-content:space-between;
  min-height:var(--sp-4)}
.hm__chart-title-row{display:flex;align-items:center;gap:var(--sp-1)}
.hm__chart-title{margin:0;font-size:var(--text-sm);font-weight:var(--peso-medio);
  color:var(--foreground);line-height:var(--lh-none)}
.hm__chart-info{font-size:var(--text-xs);color:var(--muted-foreground);flex-shrink:0;
  cursor:help;display:inline-flex}
.hm__chart-info svg{width:12px;height:12px}
/* la' o valor de agora fica na PONTA DIREITA do cabecalho, em 12 muted */
.hm__chart-header-value{margin:0;font-size:var(--text-xs);font-weight:var(--peso-normal);
  color:var(--muted-foreground);line-height:var(--lh-xs)}
/* ⚠️ RESPIRO DO GRÁFICO, pedido do André em 15/09. A altura do desenho continua a de
   token (`--spacing-28`, 112), porque ela é do padrão; o que entrou é ar POR FORA,
   8 em cima e 8 embaixo, para a curva não encostar no cabeçalho nem na legenda. O ar
   por dentro do SVG cresceu junto, na conta das margens do traçado. */
.hm__chart-wrapper{display:flex;flex-direction:column;padding:var(--sp-2) 0}
.hm__chart-empty{display:flex;align-items:center;justify-content:center;text-align:center;
  height:var(--sp-20);color:var(--muted-foreground);font-size:var(--text-sm)}
.hm__chart-legend{display:flex;gap:var(--sp-4);flex-wrap:wrap;justify-content:center}
.hm__legend-item{display:flex;align-items:center;gap:var(--sp-1-5);font-size:var(--text-xs);
  font-weight:var(--peso-normal);color:var(--foreground)}
.hm__legend-item::before{content:'';display:inline-block;width:var(--sp-2);
  height:var(--sp-2);border-radius:var(--r-xs);flex-shrink:0;background:var(--lc,var(--primary))}
.hm__legend-item b{font-weight:var(--peso-medio);color:var(--foreground)}

/* ---- o grafico ---- */
/* ---- o cabecalho do cartao do grafico ----
   MODELO: o cartao `Ciclo semaforico` da tela de Monitoramento de Controladores, no
   `dev.v2` (Attlas 26), que a Isabela apontou. A anatomia que se copia de la' e' a do
   CABECALHO DO CARTAO: icone, titulo, relogio da leitura, pastilha `Ao vivo` e a acao
   de tempo real, tudo na MESMA linha do titulo do cartao, com regua embaixo.
   A razao de cada peca estar aqui e nao na barra de abas do painel e' a mesma que o
   Andre aplicou no log: o que age sobre o grafico mora NO grafico. O relogio da
   ultima leitura e o botao de tempo real falam do grafico, nao da tela. */
.gcab{flex:none;display:flex;align-items:center;gap:10px;padding:12px 14px;
  border-bottom:1px solid var(--border)}
.gcab .gic{width:28px;height:28px;flex:none;border-radius:var(--r-md);
  display:grid;place-items:center;background:var(--muted);color:var(--muted-foreground)}
.gcab .gic svg{width:16px;height:16px}
.gcab h3{margin:0;font-size:var(--text-sm);line-height:var(--lh-sm);font-weight:500}
.gcab .gsub{font-size:11px;line-height:14px;color:var(--muted-foreground)}
/* A pastilha `Ao vivo` NAO e' so' cor: ela tem rotulo, e o ponto ao lado pulsa. */
.vivo{display:inline-flex;align-items:center;gap:6px;flex:none;
  padding:3px 10px;border-radius:999px;font-size:11px;font-weight:500;
  background:color-mix(in srgb,#16A34A 12%,var(--card));color:#15803D;
  border:1px solid color-mix(in srgb,#16A34A 35%,var(--card))}
.vivo i{width:6px;height:6px;border-radius:50%;background:#16A34A}
.vivo.on i{animation:bate 1.6s ease-in-out infinite}
@keyframes bate{0%,100%{opacity:1}50%{opacity:.35}}
@media (prefers-reduced-motion:reduce){.vivo.on i{animation:none}}
.gcab .relo{flex:none;font-size:11px;color:var(--muted-foreground);
  font-variant-numeric:tabular-nums;white-space:nowrap}

.graf{flex:1;min-height:0;display:flex;flex-direction:column;padding:14px 16px;gap:10px}
/* No topo do grafico ficam so' as series LIGADAS, como ficha que se remove no
   clique. A escolha completa mora no painel de Consulta. Catorze fichas em cima e
   catorze no painel seria a mesma coisa dita duas vezes, e as de cima comiam tres
   linhas da altura do grafico. */
.graf .top{display:flex;align-items:center;gap:10px;flex-wrap:wrap;flex:none}
.graf .top .rot{font-size:11px;color:var(--muted-foreground);flex:none}
.fic.rem{padding-right:6px;display:inline-flex;align-items:center;gap:5px}
.fic.rem b{font-weight:500}
.fic.rem .x{opacity:.75;font-size:13px;line-height:1}
.graf .tela{flex:1;min-height:120px;border:1px solid var(--border);border-radius:var(--r-lg);
  background:var(--card);position:relative;overflow:hidden}
/* No padrão o gráfico de linha tem altura de token (`--spacing-28`, 112) e NAO tem
   moldura: ele desenha direto no chão do cartão, porque o cartão já é a moldura.
   Cartão dentro de cartão aqui seria a terceira caixa. */
.hm__chart-wrapper .tela{height:var(--sp-28);border:0;border-radius:0;background:none;
  position:relative;overflow:hidden}
.graf svg,.hm__chart-wrapper svg{position:absolute;inset:0;width:100%;height:100%}
.graf .leg{display:flex;gap:14px;flex-wrap:wrap;font-size:11px;
  color:var(--muted-foreground);flex:none}
.graf .leg span{display:inline-flex;align-items:center;gap:6px}
.graf .leg i{width:10px;height:2px;border-radius:2px;background:var(--lc)}

/* ---- a tabela do log ----
   ARMADILHA, e e' a MESMA da grade da lista, de novo: `.lin2` e' `display:contents`,
   entao as celulas sao NETAS da grade, nao filhas. O seletor `.logt > *` pegava so'
   os cabecalhos, e as celulas ficavam sem altura, sem respiro e sem regua: 20px de
   passo, texto grudado, nenhuma separacao. Medido: `.th` com 40 e `.td` com 20.
   Em grade com linha `display:contents`, a folha da celula se escreve por CLASSE,
   nunca por filho direto. */
/* MESMA ARMADILHA do `.btn2` e do `.logt > *`, terceira vez: `.cresc` so' existia
   escopado em `.side-cab` e em `.pbar`, entao dentro da `.logbar` ele nao crescia e o
   funil ficava colado na busca em vez de ir para a DIREITA da barra, que e' o padrao
   das outras telas: busca de um lado, grupo de acoes do outro. Espacador e' da tela. */
.cresc{flex:1;min-width:0}
/* 14 e nao 16: e' a mesma goteira da `.pbar` logo acima e da celula da `.logt`
   logo abaixo. Duas barras empilhadas no mesmo painel com goteiras diferentes
   desalinham as bordas direitas em 2, que e' pouco para ter razao e o bastante
   para se ver. Medido: `Última leitura` e o funil fechavam com 2 de diferenca. */
.logbar{display:flex;align-items:center;gap:10px;padding:12px 14px;flex:none;
  border-bottom:1px solid var(--border)}
.logrol{flex:1;min-height:0;overflow:auto}
.logt{display:grid;grid-template-columns:56px 156px 124px 140px minmax(280px,1fr) 160px;
  min-width:max-content;align-content:start}
.logt .th,.logt .td{display:flex;align-items:center;min-height:44px;padding:10px 14px;
  border-bottom:1px solid var(--border);font-size:var(--text-xs);line-height:var(--lh-xs)}
.logt .th{font-weight:500;color:var(--muted-foreground);background:var(--card);
  position:sticky;top:0;z-index:2;white-space:nowrap;min-height:40px;
  border-bottom:1px solid var(--border)}
.logt .td{color:var(--foreground)}
.logt .td.mut{color:var(--muted-foreground)}
.logt .td.num{justify-content:center;color:var(--muted-foreground);
  font-variant-numeric:tabular-nums}
.logt .td.dt{font-variant-numeric:tabular-nums;white-space:nowrap}
/* a descricao e' a unica que pode quebrar: as outras sao rotulo curto */
.logt .td.ds{white-space:normal}
/* o realce pega a LINHA inteira, e quem pinta e' a celula, porque a linha nao tem
   caixa. Mesma regra da grade da lista. */
.logt .lin2:hover .td{background:var(--muted)}
.sev{display:inline-flex;align-items:center;justify-content:center;padding:3px 10px;
  border-radius:999px;font-size:11px;line-height:var(--lh-xs);font-weight:500;
  white-space:nowrap;color:var(--sc);background:var(--sb)}

/* ====================== DS:DEMO:INICIO ===================== */
/* Gerado por demo-ds.py. NAO EDITE AQUI: edite o gerador e rode nas telas.
   Anatomia lida do `dev-eye.ts` da Barbara (modulo de alarmes). Todo seletor
   comeca por `.demo`, e isso NAO e' estetica: as varreduras de contraste isentam
   `\.demo\b` com nome, porque o andaime e' escuro nos dois modos de proposito.
   Classe fora desse prefixo entraria na medicao do produto. */

/* ---- a abinha (minimizada): 26x46, colada na borda esquerda, arrasta na vertical ---- */
.demo-tab{position:fixed;left:0;width:26px;height:46px;border-radius:0 10px 10px 0;
  background:var(--t1,#0A0A0A);color:var(--card,#FFFFFF);border:0;padding:0;cursor:grab;
  z-index:420;touch-action:none;display:flex;align-items:center;justify-content:center;
  box-shadow:2px 3px 12px -5px rgba(0,0,0,.45)}
.demo-tab[hidden]{display:none}   /* `display:flex` de classe vence o
   `[hidden]{display:none}` do agente do usuario: sem esta linha a abinha
   continuava aparecendo na borda, atras do painel aberto. */
.demo-tab:hover{opacity:.92}
.demo-tab:active{cursor:grabbing}
.demo-tab svg{width:14px;height:14px;display:block}
.demo-tab:focus-visible{outline:none;box-shadow:2px 3px 12px -5px rgba(0,0,0,.45),0 0 0 3px #D1D1D1}

/* ---- o painel: flutuante, arrastavel, sem veu (nao bloqueia a tela) ---- */
.demo-painel{position:fixed;width:290px;max-width:92vw;max-height:calc(100vh - 32px);
  background:var(--card,#FFFFFF);border:1px solid var(--line-2,#DBDBDB);border-radius:10px;
  z-index:421;overflow:hidden;display:flex;flex-direction:column;
  box-shadow:0 18px 44px -18px rgba(0,0,0,.45)}
.demo-painel[hidden]{display:none}
.demo-cab{display:flex;align-items:center;gap:8px;padding:11px 10px 11px 14px;font-size:13px;
  cursor:grab;touch-action:none;user-select:none;color:var(--t1,#0A0A0A);
  border-bottom:1px solid var(--line,#E5E5E5)}
.demo-cab:active{cursor:grabbing}
.demo-cab svg{width:14px;height:14px;flex:none}
.demo-cab .demo-sp{margin-left:auto}
.demo-x{background:none;border:0;color:var(--t2,#737373);font-size:15px;cursor:pointer;
  padding:2px 6px;border-radius:6px;line-height:1;display:grid;place-items:center}
.demo-x:hover{background:var(--sup,#F5F5F5);color:var(--t1,#0A0A0A)}
.demo-x svg{width:13px;height:13px}
.demo-corpo{overflow-y:auto;padding-bottom:6px}
.demo-aviso{margin:12px 14px 0;border-radius:8px;padding:8px 10px;font-size:11px;
  color:var(--t1,#0A0A0A);
  background:color-mix(in srgb,var(--wrn,#D97706) 16%,var(--card,#fff));
  border:1px solid color-mix(in srgb,var(--wrn,#D97706) 45%,var(--card,#fff))}

/* ---- os grupos: rotulo em mono maiusculo, e as opcoes embaixo ---- */
.demo-grp{padding:14px 14px 0}
.demo-gl{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:10px;
  letter-spacing:1.1px;text-transform:uppercase;color:var(--t2,#737373);margin-bottom:8px}
.demo-opts{display:flex;flex-direction:column;gap:6px}
.demo-opts.demo-linha{flex-direction:row;flex-wrap:wrap}
/* a barra original vira o corpo do painel: ela deixa de ser barra e passa a ser pilha */
.demo-painel .demo,.demo-painel .demobar{position:static!important;display:block!important;
  inset:auto!important;transform:none!important;background:none!important;border:0!important;
  box-shadow:none!important;padding:0!important;margin:0!important;width:auto!important;
  max-width:none!important;border-radius:0!important;opacity:1!important;
  pointer-events:auto!important;z-index:auto!important;font-size:inherit!important}
/* o botao de caso: o `.opt` dela.
   `.demo-painel .demo-opts button` e' 0,3,1 DE PROPOSITO. As quatro telas com barra
   trazem cada uma o seu proprio `.demo button` (0,1,1) e `.demo button:hover` (0,2,1),
   restos dos cinco desenhos de barra que existiam antes. Com 0,1,1 aqui, o estado
   normal so' vencia por vir depois na folha e o HOVER perdia — foi assim que o botao
   ficava com fundo #2C2C34 e o texto escuro por cima, ilegivel. Especificidade que
   depende da ordem nao e' especificidade, e' sorte. */
.demo-painel .demo-opts button{display:flex;align-items:center;gap:9px;text-align:left;width:100%;
  cursor:pointer;border:1px solid var(--line,#E5E5E5);background:var(--sup,#F5F5F5);
  color:var(--t1,#0A0A0A);border-radius:8px;padding:8px 10px;font:inherit;font-size:12.5px;
  font-weight:600;line-height:1.35}
.demo-painel .demo-opts.demo-linha button{width:auto}
/* HOVER: E' O DELA, `.opt:hover { border-color: var(--primary) }` — so' a borda muda.
   O caminho ate' aqui vale registro. O hover parecia quebrado (fundo #2C2C34 com texto
   escuro por cima, ilegivel) e o Andre pediu para inverter o texto. So' que o fundo
   escuro nao era desta folha: vinha do `.demo button:hover` que cada uma das quatro
   telas ainda carregava, resto das barras antigas. Tirado o resto, o hover dela
   funciona como ela desenhou. O Andre: *"deixe o mesmo tipo de hover que foi aplicado
   no da Barbara, lembre-se que o foco e' tentar manter o mesmo padrao, entao pode
   copiar."* A inversao ficou no historico da §11.63 e nao no codigo: um padrao com uma
   excecao por tela deixa de ser padrao. */
.demo-painel .demo-opts button:hover{border-color:var(--acc,#2563EB)}

.demo-painel .demo-opts button.on{border-color:var(--acc,#2563EB);
  background:color-mix(in srgb,var(--acc,#2563EB) 12%,var(--card,#fff))}
/* Selecionado e sob o cursor: nao precisa de regra propria. As duas dela pedem a mesma
   borda azul, e o fundo continua sendo a lavagem do `.on` — que e' como o painel dela
   se comporta. (Na volta em que o hover invertia, ESTA linha era obrigatoria e faltou:
   o `.on` e o `:hover` tem a mesma especificidade, o `.on` vinha depois e segurava o
   fundo azul enquanto o texto ja' tinha invertido. No escuro dava 1,18:1.) */
.demo-painel .demo-opts button:focus-visible{outline:none;border-color:var(--acc,#2563EB);
  box-shadow:0 0 0 3px var(--acc-bg,#E9EFFD)}
.demo-painel .demo-opts button:disabled{opacity:.5;cursor:default}
/* a pastilha de sigla, quando a tela escreve uma */
.demo-painel .demo-opts button .k{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-size:10px;color:var(--t2,#737373);background:var(--card,#fff);
  border:1px solid var(--line,#E5E5E5);border-radius:5px;padding:1px 5px;flex:none}
.demo-dica{font-size:10.5px;color:var(--t2,#737373);margin-top:8px;line-height:1.5;
  padding:0 14px}
@media (prefers-reduced-motion:reduce){.demo-tab{transition:none}}
/* ======================= DS:DEMO:FIM ======================= */

/* ⬅️ o `input[type=number]` nativo desenha as setinhas do sistema (▲▼) dentro do campo — a
   producao usa o `z-number-input`, que tem o passo proprio fora do texto. Ate' ele existir
   aqui, o campo fica como texto: sem spinner, mesma caixa dos outros. Dela, 23/09. */
input[type=number]{appearance:textfield;-moz-appearance:textfield}
input[type=number]::-webkit-outer-spin-button,input[type=number]::-webkit-inner-spin-button{
  -webkit-appearance:none;margin:0}

/* ⬅️ "separa na tela de Quito o que for só Quito" — dela, 24/09. A marca de PROCEDÊNCIA
   do campo cuja única fonte é o edital de Quito: texto 11 apagado, fio tracejado (o
   mesmo sinal de "veio de fora" dos wireframes da pasta), raio 4, colada ao rótulo. Só
   aparece na versão Quito — na Attlas o campo nem existe. É peça do protótipo, para ela
   ver a separação; se for para a tela final, vira o `z-badge` outline do kit. */
.tag-quito{display:inline-block;margin-left:6px;padding:0 6px;border:1px dashed var(--border);
  border-radius:4px;font-size:11px;line-height:16px;font-weight:500;letter-spacing:.02em;
  color:var(--muted-foreground);vertical-align:1px}

/* ============================================================================
   GATEWAY · O QUE A FOLHA DO NOBREAKS NAO TINHA, trazido de onde ja estava medido.
   Tudo acima desta linha e a `nobreaks-base.css` da frente de Nobreaks (worktree
   `attlas-design-nobreaks`, branch `modulo/nobreaks-config`, 28/09/2026), copiada
   INTEIRA e sem uma linha alterada: e a casca da lista, da interna, da gaveta, do
   dialogo, dos filtros e do olhinho, e nada disso se redecide aqui.
   Os blocos abaixo vieram, tambem verbatim, de dois lugares:
     [DASH]  o <style> de `telas/nobreaks-dashboard.html` — a barra do painel, o
             cartao e seu cabecalho, as grades de cartoes, os ladrilhos, as barras,
             a rosca, o rodape de cartao, o ranking, o bloco de erro.
     [LISTA] o <style> de `prototipos-html/nobreaks-lista.html` (a lista do Andre) —
             a area de trabalho com o painel lateral, a coluna de acoes presa, a linha
             selecionada, o menu da linha e o menu de colunas, e o painel de 314.
   A unica edicao: o `.sel` do dashboard (o seletor de periodo) virou `.sel-periodo`,
   porque `.sel` ja e o estado da linha selecionada na lista (`.lin.sel`) e as duas
   regras iam se somar. O que e proprio do Gateway vem no fim, marcado.
   ============================================================================ */

/* ===== [LISTA] a area de trabalho, o painel e os menus ===== */
/* ⚠️ 29/09: o trecho copiado da lista do André começa NO MEIO de um comentário dele; sem este
   `/*` o texto abaixo era lido como seletor e ENGOLIA a regra `.area{…display:flex…}` — a caixa
   da tabela crescia sem teto e o rodapé caía fora da janela ("Você removeu o rodapé. Cadê o
   rodapé da tabela?"). Mesma armadilha do `.pop-grupo` de 22/09.
   media 24 de respiro a esquerda e **46** a direita, que e' o que o Andre viu.
   MEDIDO no dev: `padding:24px` igual dos quatro lados, e nada reservado para peca
   que nao esta' na tela. Entao o vao passa a existir SO' com o painel aberto. */
.area{flex:1;min-height:0;display:flex;flex-direction:column}
/* o `gap` mora na `.pg`, entre a coluna e o painel, e nao na `.area`: quem desliga
   e' a pagina, olhando o estado que a `.area` publica no `data-painel`. */
.pg:has(.area[data-painel="0"]){gap:0}
.pg:has(.area[data-painel="0"]) > #painel{display:none}
/* ⚠️ A CAIXA DA TABELA TERMINA NOS DADOS, e nao no pe' da janela.
   Ela era `flex:1` e esticava ate' o fim da area: com dez linhas sobravam 28 de
   branco DENTRO do rolador, depois da ultima celula, e a paginacao ficava colada no
   pe' da tela longe do conteudo. O Andre pediu o contrario: *"deve deixar ele sempre
   bem alinhado, o maximo que possivel"*.
   `flex:0 1 auto` com `max-height:100%` da' as duas coisas: a caixa encolhe para o
   conteudo quando ele e' menor, e trava na altura da area quando e' maior, e ai' o
   rolador rola. O branco passa a ficar DEPOIS da caixa, na pagina, em vez de dentro
   dela.
   ⚠️ E A BORDA DE BAIXO VOLTOU. Ela era zero porque a caixa encostava no pe' da
   janela e a borda ficava no corte; agora a caixa termina no meio da tela, e sem o
   lado de baixo ela le' como conteudo vazando. Mesma armadilha do `.bl:last-child` na
   tela interna: regra certa para a caixa que encosta, errada para a que termina.
   ⚠️ DIVERGENCIA DECLARADA: o dev NAO faz assim. Medido em 15/09 na lista de camaras,
   `data-table` e' `flex:1 1 auto` e deixa 155 de branco dentro do rolador com quatro
   linhas. Aqui a decisao e' do Andre, e esta' registrada como tal. */
.area .tab{flex:0 1 auto;min-width:0;min-height:0;display:flex;flex-direction:column;
  max-height:100%;border-radius:var(--r-lg)}
/* o rolador e' o CORPO da tabela: ele rola nos dois eixos, e a paginacao fica
   presa no rodape, fora dele. `min-height:0` e' obrigatorio: sem ele o filho de
   pai `column` nao encolhe e o excedente fica inalcancavel. */
.area .tab-rol{flex:0 1 auto;min-height:0;overflow:auto}
.area .pag{flex:none}
/* o rodape da paginacao acompanha o raio da caixa, agora que ela tem os quatro lados */
.area .pag{border-radius:0 0 var(--r-lg) var(--r-lg)}
/* O painel CANCELA o respiro da pagina em TODOS os lados que tocam a janela, como a
   regra de produto manda para folha lateral. Medido no no' `21200:12931`, a 1280x832:
   tabela de 24 a 944 (920 de largura), VAO DE 22, e painel de 966 a 1280, do alto da
   barra de navegacao ate' o pe' da janela, com 736 de altura.
   Sem o vao, a borda direita da tabela cai debaixo da borda esquerda do painel: as
   duas viram uma linha so', e a coluna cortada encosta nela. Aí o corte deixa de ler
   como "a tabela acaba aqui" e passa a ler como conteudo vazando por baixo da folha. */
.pg > .painel{margin:-24px -24px 0 0}

/* ---- a grade: UMA SO', e ela NAO perde coluna quando o painel abre ----
   REVOGA a decisao anterior deste prototipo, que tirava cinco colunas. Medido no
   no' `21200:12931` do arquivo do Figma: a tela tem 1280, o painel ocupa 314 a
   partir de x=966, e a area da tabela fica com 968. As colunas CONTINUAM TODAS,
   e o que a tabela ganha e' rolagem lateral dentro do proprio conteiner.
   O painel nao passa por cima: ele divide a largura. */
/* LARGURAS MEDIDAS, nao estimadas. A conta de cada coluna e':
   rotulo sem quebra + icone de ordenacao (16) + vao (8) + respiro (16) = natural + 40.
   Seis rotulos estavam estourando a caixa e passando POR BAIXO do icone, porque
   `.rot` era `flex:1;min-width:0` sem corte: `Número de Série` pedia 146 e tinha 132,
   `Capacidade` pedia 115 e tinha 96, `Autonomia` 107 contra 98, `Última Conexão` 140
   contra 128, `Carga` 79 contra 78 e `Disp.` 72 contra 62.
   O conserto tem DUAS metades, e as duas sao necessarias: alargar ate' o natural, e
   deixar o rotulo QUEBRAR em duas linhas em vez de escorrer por baixo do icone.
   Alargar sozinho conserta hoje e volta a quebrar com a primeira palavra maior. */
/* AS LARGURAS DEPOIS DO CORTE. A conta de cada coluna continua a mesma, medida e nao
   estimada: rotulo sem quebra + icone de ordenacao (16) + vao (8) + respiro (16). O
   que mudou e' quem sobrou, e o `nth-child` tem que acompanhar: com 16 colunas ele
   zerava a borda da decima sexta, e com dez ele zeraria a borda do MEIO da linha. */
/* ⚠️ `nth-child` NAO SERVE MAIS: o numero de colunas mudou de fixo para variavel, e
   uma contagem cravada zera a borda no meio da linha. Quem marca o fim agora e' o JS,
   com uma classe na ultima celula de cada linha. Dois defeitos pagos com a mesma
   licao: a regra de 8 colunas que sobrou da casca (6-D.17) e esta. */
.grade .ult{border-right:0}
/* O ROTULO NUNCA QUEBRA, e nunca quebra DENTRO da palavra.
   A tentativa anterior deixou `overflow-wrap:anywhere` com folga de 1px em
   `Capacidade` (pedia 115, tinha 116) e `Autonomia` (pedia 107, tinha 108): qualquer
   arredondamento sub-pixel partia a palavra e saía `Capacidad / e` e `Autonomi / a`.
   Quebrar dentro da palavra e' pior que cortar, porque inventa uma palavra que nao
   existe. Agora o rotulo e' uma linha so' e a coluna tem 12 de folga sobre o que ele
   pede, medido com a tipografia do proprio cabecalho. */
.hd .rot{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.hd{align-items:center}
/* com o painel aberto a grade perde largura visivel e passa a rolar: a coluna
   elastica trava no minimo e a soma das fixas excede o conteiner. */
.area[data-painel="1"] .tab-rol{overflow-x:auto}

/* ---- a coluna de acoes nao rola: ela fica presa na direita ----
   O no' mostra os tres pontinhos POR CIMA do conteudo, sempre visiveis. O motivo e'
   de trabalho, nao de desenho: com treze colunas dentro de uma caixa de 920, chegar
   na acao exigiria rolar ate' o fim da linha toda vez.
   `position:sticky` numa celula de grid gruda na borda do proprio rolador. Ela
   precisa de chao OPACO, senao o conteudo aparece por baixo; e o chao nao pode ser
   fixo, senao vira um retangulo branco sobre a linha sob o ponteiro ou selecionada.
   Por isso o chao padrao fica aqui e as regras de hover e de selecao, que sao mais
   especificas, continuam mandando. */
.grade .fix{position:sticky;right:0;z-index:2;background:var(--card);
  border-left:1px solid var(--border);border-right:0;
  box-shadow:-6px 0 8px -8px rgba(0,0,0,.18)}
:root[data-modo="escuro"] .grade .fix{box-shadow:-6px 0 8px -8px rgba(0,0,0,.6)}
.grade .hd.fix{z-index:3}

.grade .lin.sel .cl{background:color-mix(in srgb,var(--primary) 9%,var(--card))}
.grade .lin.sel:hover .cl{background:color-mix(in srgb,var(--primary) 9%,var(--card))}
.cl{cursor:default}
.grade .lin .cl{cursor:pointer}
.num{font-variant-numeric:tabular-nums}
.zero{color:var(--muted-foreground)}
.msk{color:var(--muted-foreground)}
.menu{position:absolute;z-index:40;min-width:max-content;padding:4px;
  border:1px solid var(--border);border-radius:var(--r-lg);background:var(--card);
  box-shadow:0 10px 28px rgba(0,0,0,.14)}
:root[data-modo="escuro"] .menu{box-shadow:0 10px 28px rgba(0,0,0,.6)}
.menu button{display:flex;align-items:center;gap:9px;width:100%;height:32px;
  padding:0 10px;border-radius:var(--r-md);background:none;border:0;
  font:inherit;font-size:var(--text-xs);color:var(--foreground);text-align:left;
  white-space:nowrap;cursor:pointer}
.menu button:hover{background:var(--muted)}
.menu button.destr{color:#DC2626}
.menu button.destr:hover{background:color-mix(in srgb,#DC2626 10%,var(--card))}
.menu hr{margin:4px 6px;border:0;border-top:1px solid var(--border)}
/* ---- O MENU DE OCULTAR COLUNAS ----
   LIDO no Figma em 15/09, nos dois estados da `Lista de Plano`: `21479:14047` (menu
   aberto, colunas todas visiveis) e `21480:15928` (tres colunas ja' ocultas).
   O QUE OS DOIS NOS ENSINAM, e nao estava escrito em lugar nenhum:
   1. o menu e' um `DropdownMenu` com um ROTULO DE GRUPO no topo (`Ocultar colunas`) e
      um item por coluna, com o CHECK a' direita quando ela esta' na tabela;
   2. a coluna oculta vira `hidden` e as que ficam **CRESCEM para preencher os 1232**.
      Medido: a coluna do nome vai de 475 para 851 quando tres somem. A tabela nao
      deixa buraco, e e' por isso que a coluna elastica existe;
   3. os itens de rotulo longo TRUNCAM no menu (`Modo de Lança...`), e nao quebram.
   O QUE E' DESTA TELA: as colunas que o Andre chamou de importantes nao entram na
   escolha. Elas aparecem no menu, com o check, e DESABILITADAS: sumir do menu
   esconderia a regra, e deixar clicavel prometeria um gesto que a tela recusa. */
.menu .mlabel{padding:6px 10px 4px;font-size:11px;line-height:14px;font-weight:500;
  color:var(--muted-foreground)}
.menu button.col{justify-content:space-between;gap:12px}
.menu button.col .rot{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.menu button.col .ck{flex:none;width:15px;height:15px;color:var(--primary);
  display:grid;place-items:center}
.menu button.col .ck svg{width:15px;height:15px}
.menu button.col[aria-checked="false"] .ck{visibility:hidden}
/* travada: o check fica, o rotulo apaga e o cursor diz que nao ha' gesto */
.menu button.col[aria-disabled="true"]{color:var(--muted-foreground);cursor:default}
.menu button.col[aria-disabled="true"]:hover{background:none}
.menu button.col[aria-disabled="true"] .ck{color:var(--muted-foreground)}
.menu svg{width:15px;height:15px;flex:none}

/* ---- o painel lateral, do no' `21525:18677` (Sidebar Lista) ----
   Medida, cor, raio e espacamento saem DO NODE, nao deste arquivo. O que esta
   tela escolhe e' so' o conteudo, que vem do Attlas 25 e do documento.
   Largura 314, borda so' do lado por onde entrou, sombra `shadow/xs`. */
.painel{flex:none;width:314px;align-self:stretch;min-height:0;display:flex;
  flex-direction:column;border-left:1px solid var(--border);background:var(--background);
  filter:drop-shadow(0 1px 1px rgba(0,0,0,.05));overflow:hidden;
  animation:entra var(--motion-base) ease-out}
@keyframes entra{from{transform:translateX(14px);opacity:0}to{transform:none;opacity:1}}
@media (prefers-reduced-motion:reduce){.painel{animation:none}}

/* cabecalho: 48 de altura, px 16, e DENTRO dele uma fileira de 282.
   So' o titulo e a cruz. O lapis do wireframe nao existe neste no'. */
.pn-top{display:flex;align-items:center;justify-content:center;height:48px;
  padding:0 16px;border-bottom:1px solid var(--border);flex:none}
.pn-top .dentro{display:flex;align-items:center;justify-content:space-between;width:282px}
.pn-top .tit{font-size:var(--text-sm);line-height:1;font-weight:500;color:var(--foreground)}
.pn-ico{width:28px;height:28px;border-radius:var(--r-md);display:grid;place-items:center;
  border:0;background:none;color:var(--foreground);cursor:pointer}
.pn-ico:hover{background:var(--muted)}
.pn-ico svg{width:16px;height:16px;display:block}

/* corpo: pl 16, pr 4, py 16, e a coluna de 8 da barra de rolagem a direita */
.pn-rol{flex:1;min-height:0;overflow-y:auto;padding:16px 4px 16px 16px}
.pn-in{display:flex;flex-direction:column;gap:16px;align-items:flex-start}

/* cabecalho do equipamento: tipo, nome, e os chips */
.pn-cab{display:flex;flex-direction:column;gap:8px;width:282px}
.pn-tipo{font-size:var(--text-xs);line-height:var(--lh-xs);font-weight:500;
  color:var(--muted-foreground);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pn-nome{font-size:var(--text-sm);line-height:1;font-weight:600;color:var(--foreground);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pn-badges{display:flex;gap:4px;align-items:center;flex-wrap:wrap}

/* o segmentado do shadcn: chao `muted`, 32 de altura, 3 de respiro, raio 10;
   a aba viva e' branca, raio 8, com a `shadow/sm` de duas camadas */
.pn-abas{display:flex;align-items:center;height:32px;padding:3px;width:282px;
  background:var(--muted);border-radius:var(--r-lg)}
.pn-abas button{flex:1;min-width:0;height:100%;display:flex;align-items:center;
  justify-content:center;gap:6px;padding:4px 6px;border:1px solid transparent;
  border-radius:var(--r-md);background:none;font:inherit;font-size:var(--text-sm);
  line-height:var(--lh-sm);font-weight:500;color:var(--muted-foreground);cursor:pointer}
.pn-abas button[aria-selected="true"]{background:var(--ctl-bg);color:var(--foreground);
  box-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px -1px rgba(0,0,0,.1)}

.pn-reg{width:282px;height:1px;background:var(--border);flex:none}
.pn-h{width:282px;font-size:var(--text-sm);line-height:1;font-weight:600;
  color:var(--foreground)}
.pn-desc{width:282px;font-size:var(--text-xs);line-height:var(--lh-xs);
  font-weight:400;color:var(--muted-foreground)}
/* os pares: rotulo 12/500 no cinza, valor 12/400 no preto, altura 16 */
.pn-pares{display:flex;flex-direction:column;width:282px}
.pn-pares.g8{gap:8px}
.pn-pares.g12{gap:12px}
.pn-par{display:flex;align-items:center;justify-content:space-between;height:16px;
  font-size:var(--text-xs);line-height:var(--lh-xs);white-space:nowrap}
.pn-par .k{font-weight:500;color:var(--muted-foreground);flex:none}
.pn-par .v{font-weight:400;color:var(--foreground);overflow:hidden;
  text-overflow:ellipsis;font-variant-numeric:tabular-nums}
/* o botao de acao secundaria: chao `primary-foreground-status`, texto `primary` */
.pn-bt2{display:flex;align-items:center;justify-content:center;gap:4px;width:282px;
  height:28px;padding:8px 10px;border:0;border-radius:var(--r-md);
  background:var(--primary-status);color:var(--primary);font:inherit;
  font-size:var(--text-xs);line-height:var(--lh-xs);font-weight:500;cursor:pointer}
.pn-bt2 svg{width:14px;height:14px;flex:none}
/* a leitura continua: onde a camera mostra video, o nobreak mostra a bateria */
.pn-gauge{width:282px}
.pn-gauge .gr{height:8px;border-radius:9999px;background:var(--muted);overflow:hidden}
.pn-gauge .gr i{display:block;height:100%;border-radius:9999px;background:var(--bc)}
.pn-gauge .dois{display:flex;align-items:baseline;justify-content:space-between;
  gap:10px;margin-top:8px}
.pn-gauge .big{font-size:var(--text-xl);line-height:1;font-weight:600;
  font-variant-numeric:tabular-nums;color:var(--foreground)}
.pn-gauge .sub{font-size:var(--text-xs);line-height:var(--lh-xs);
  color:var(--muted-foreground);font-variant-numeric:tabular-nums}
/* rodape: borda em cima, respiro 16, e o primario ocupando a largura */
.pn-pe{flex:none;padding:16px;border-top:1px solid var(--border);background:var(--background)}
.pn-pe button{width:100%;height:32px;border:0;border-radius:var(--r-md);
  background:var(--primary);color:var(--primary-foreground);font:inherit;
  font-size:var(--text-sm);line-height:var(--lh-sm);font-weight:500;cursor:pointer}
/* o log de eventos */
.ev{display:flex;gap:9px;padding:8px 0;border-bottom:1px solid var(--border);width:282px}
.ev:last-child{border-bottom:0}

/* ===== [DASH] a pagina que rola, a barra do painel e os controles dela ===== */
.rol{height:100%;overflow:auto;padding:24px 24px 40px;box-sizing:border-box}
.barra-painel{display:flex;align-items:center;justify-content:space-between;
  gap:16px;flex-wrap:wrap;padding:16px;background:var(--card);
  color:var(--card-foreground,var(--foreground));
  border:1px solid var(--border);border-radius:var(--r-xl);
  box-shadow:0 1px 2px rgba(0,0,0,.05)}
/* ⚠️ A BASE TEM DE SER NUMERO E NAO `auto`, e e' a parte que custou medicao la':
   com `flex-wrap` o navegador distribui os itens em LINHAS antes de encolher
   qualquer um, e com `auto` o tamanho hipotetico do titulo e' a frase inteira numa
   linha so' — entao as duas metades nunca dividiam uma linha para encolher dentro
   dela. 256 e' o que o titulo pede na hora de decidir onde a linha quebra. */
/* ⬅️ "a distância entre título e descrição é a mesma" — dela, 21/09. Medido nos três
   lugares onde esse par existe: barra do topo 4, título de seção 0, cabeçalho de cartão
   0. A barra era a ímpar, e virou 0 como as outras duas.
   ⭐ Zero não cola as duas linhas: o título tem 28 de entrelinha sobre 18 de corpo e a
   descrição 16 sobre 12 — a caixa de linha já paga o respiro, nos três casos. Em 18/09
   isto foi de 8 para 4 pelo mesmo motivo; agora fecha em 0. */
.barra-painel__tit{display:flex;flex:1 1 256px;flex-direction:column;gap:0;min-width:0}
/* 🔴 O `#barraDesc` ficou VAZIO desde 16/09, quando ela mandou apagar a linha de
   contexto — e filho de altura zero continua sendo ITEM DE FLEX: o `gap:4` era aplicado
   dos dois lados dele, e o vão entre o titulo e a hora da leitura media 8.
   ⚠️ Ele fica no DOM porque o JS escreve o recorte nele quando ha' filtro; apagar seria
   o defeito do `#kvCarga`. `:empty` tira do FLUXO sem tirar do documento. */
.barra-painel__tit > p:empty{display:none}

/* ⬅️ AQUI MORAVAM O INTERRUPTOR DE TEMPO REAL (`.tr`, com trilho e tique) E A REGRA DE
   ITEM DESLIGADO (`.periodo-item[aria-disabled]`). Os dois sairam em 23/09 com o modo ao
   vivo: sem interruptor nao ha' o que desenhar, e sem ele ninguem mais desliga um atalho.
   Conferido no MONTADO antes de cortar: `class="tr"` aparecia ZERO vezes em markup.
   ⚠️ O interruptor que continua na tela e' o `.interruptor`, com regras proprias e
   identicas — foi por isso que este pode sumir sem nada mudar de aparencia. */
.periodo-item[aria-disabled="true"]:hover{background:none}
/* 🔴 SEM ALVO desde 16/09: ela mandou apagar a frase, e a regra fica aqui so' para o
   caso de o texto voltar. Se nao voltar ate' a proxima varredura, ela sai. */
.periodo-nota{margin:2px 8px 4px;font-size:var(--text-2xs);line-height:16px;
  color:color-mix(in srgb,var(--muted-foreground) 82%,var(--foreground))}
/* O seletor e' pelo LUGAR e nao pela etiqueta: a barra virou `h1` quando o cabecalho
   de pagina saiu, e uma regra escrita em `h2` teria deixado de pintar em silencio. */
.barra-painel__tit>h1{margin:0;font-size:var(--text-lg);line-height:28px;
  font-weight:600;color:var(--foreground)}
.barra-painel__tit p{margin:0;font-size:var(--text-xs);line-height:var(--lh-xs);
  color:var(--muted-foreground)}
/* Os controles nunca cedem: cada um ja' esta' no piso, e um grupo de botoes de
   icone que encolhesse encolheria os alvos. */
.barra-painel__ctl{display:flex;flex:0 0 auto;align-items:center;gap:12px;flex-wrap:wrap}
/* O FILETE SEPARA O QUE AGE SOBRE A LEITURA DO QUE AGE SOBRE A TELA. Tudo a' sua
   esquerda muda QUAIS numeros aparecem; os dois a' direita nao mudam nenhum. */
.barra-painel__filete{width:1px;height:20px;background:var(--border);flex:none}
/* O ALFINETE MANTEM A BARRA NO TOPO DA ROLAGEM. Mesmo glifo nos dois estados: o
   estado e' dito pelo `aria-pressed` e pela cor. Um segundo glifo seria uma segunda
   coisa a aprender para um interruptor que ja' se anuncia. */
.barra-painel__ctl .icobtn[aria-pressed="true"]{color:var(--primary)}
/* O FUNIL COM CORTE LIGADO se marca do mesmo jeito, pela cor: um segundo glifo seria
   uma segunda coisa a aprender para um controle que ja' se anuncia. */
.barra-painel__ctl .icobtn.marcado{color:var(--primary);border-color:var(--primary)}
/* ⚠️ O ALFINETE SO' FUNCIONA SE NENHUM ANCESTRAL RECORTAR. `position:sticky`
   resolve contra o rolador mais proximo, entao um `overflow:hidden` entre ele e a
   rolagem vira um botao que nao faz nada visivel. Aqui o rolador e' o `.rol`. */
.barra-painel-caixa.fixa{position:sticky;inset-block-start:0;z-index:40}
/* PRESO e' onde tudo pinta: o instante em que a barra esta' de fato parada no topo
   e de fato cobrindo alguma coisa.

   🔴 O AR DE 24 NAO PODE SER PADDING — dela, 16/09, com video: "o card nao pode ficar
   pulando no scroll". Medido no instante em que `presa` acende: o topo da caixa fica
   em 127 e o MIOLO da barra desce de 127 para 151. Vinte e quatro pixels de pulo.

   A versao antiga dizia "a margem negativa devolve o padding", e devolve — NO FLUXO.
   Por isso o que esta' abaixo nao se mexe. Mas com a barra PRESA o topo dela nao e'
   mais decidido pela margem: esta' cravado pela ancora do `sticky`. A margem negativa
   deixa de puxar qualquer coisa para cima e o padding sobra inteiro, empurrando o
   conteudo para baixo de uma vez.

   ⭐ O chao de cima passa a ser um PSEUDO-ELEMENTO: ele cobre a faixa por onde o
   conteudo passa e nao ocupa lugar nenhum, entao nao ha' o que a ancora empurre. A
   caixa mantem a altura em qualquer estado.
   ⚠️ O par horizontal fica: o `sticky` daqui so' crava o eixo vertical. */
.barra-painel-caixa.presa{margin-inline:-24px;padding-inline:24px;
  background:var(--background)}
.barra-painel-caixa.presa::before{content:"";position:absolute;inset-inline:0;
  inset-block-end:100%;height:24px;pointer-events:none;background:var(--background)}
/* O QUE PASSA SOB A BARRA PRESA SE DISSOLVE EM VEZ DE SER CORTADO: uma faixa que
   comeca no chao da propria pagina e termina transparente. E' o token de fundo e
   nao branco — escrito literal seria uma faixa branca sobre pagina escura no
   instante em que o modo virasse. `to bottom` e nao sombra: sombra escurece o que
   esta' embaixo, e o que se quer e' o chao avancando sobre o conteudo. */
.barra-painel-caixa.presa::after{content:"";position:absolute;inset-inline:0;
  inset-block-start:100%;height:40px;pointer-events:none;
  background:linear-gradient(to bottom,var(--background),transparent)}
.barra-painel-caixa{position:relative;margin-bottom:16px}
/* A PALAVRA DO ATUALIZAR e' a unica da barra, e ela existe porque recarregar e' a
   unica acao daqui cujo resultado e' invisivel: a palavra e' o que diz ao operador
   que alguma coisa aconteceu. Abaixo de 1024 a palavra sai e o glifo fica; o
   `aria-label` esta' no botao em toda largura, e nao so' na estreita — um nome que
   aparecesse num ponto de quebra seria um controle sem nome no leitor de tela na
   tela larga, onde a palavra so' esta' pintada. */
.btn-sec .palavra{display:inline;line-height:16px}
/* TELA CHEIA: o painel cobre a janela. O `.rol` continua sendo quem rola. */
body.cheia .top,body.cheia .nav{display:none}
body.cheia .pg{height:100vh}
body.cheia .barra-painel-caixa{margin-inline:0}
body.cheia .barra-painel-caixa.presa{margin-inline:-16px;padding-inline:16px}

/* ---- Select: o controle de recorte. Altura 32, mesmo chao do Outline ---- */
.sel-periodo{display:inline-flex;align-items:center;gap:6px;height:32px;padding:0 10px;
  border:1px solid var(--input);border-radius:var(--r-md);background:var(--ctl-bg);
  color:var(--foreground);font-size:var(--text-xs);line-height:var(--lh-xs);
  white-space:nowrap;cursor:pointer;
  transition:background var(--motion-fast),border-color var(--motion-fast)}
.sel-periodo:hover{background:var(--accent)}
.sel-periodo[aria-expanded="true"]{background:var(--accent)}
.sel-periodo svg{width:14px;height:14px;display:block;color:var(--muted-foreground)}
.sel-periodo .rot{color:var(--muted-foreground)}
.btn-sec{display:inline-flex;align-items:center;gap:6px;height:32px;padding:0 12px;
  border:1px solid var(--input);border-radius:var(--r-md);background:var(--ctl-bg);
  color:var(--foreground);font-size:var(--text-xs);line-height:16px;font-weight:500;white-space:nowrap;
  cursor:pointer;transition:background var(--motion-fast),opacity var(--motion-fast)}
.btn-sec:hover{background:var(--accent)}
.btn-sec:disabled{opacity:.5;cursor:not-allowed}
.btn-sec svg{width:14px;height:14px;display:block}
.periodo{position:absolute;z-index:70;display:flex;align-items:flex-start;
  flex-direction:row-reverse;gap:8px}
/* as medidas sao as do produto rodando: lista 232, calendario 510 com 12 de respiro,
   gap 8 entre os dois, e `row-reverse` porque o gatilho mora na ponta direita */
.periodo-lista{width:232px;flex:none;padding:4px;border:1px solid var(--border);
  border-radius:var(--r-lg);background:var(--popover,var(--card));
  box-shadow:0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1)}
/* o item do nó: 36 de altura viram 28, e o texto sobe de 12 para 14 — o que ocupava a
   altura era o recuo de 8, e não a letra */
.periodo-item{display:flex;width:100%;align-items:center;gap:6px;padding:4px 6px;
  max-height:28px;border-radius:var(--r-md);font-size:var(--text-sm);line-height:20px;
  color:var(--foreground);text-align:left}
.periodo-item:hover{background:var(--accent);color:var(--accent-fg)}
.periodo-item .tique{width:14px;flex:none;color:var(--primary)}
.periodo-item .rot{flex:1;min-width:0}
.periodo-item .seta{width:14px;height:14px;flex:none;color:var(--muted-foreground)}
.periodo-item[aria-expanded="true"]{background:var(--accent)}
.periodo-item .reg{height:1px;background:var(--border)}
.dash{display:block}

/* ===== [DASH] o cartao, seu cabecalho, as grades, os ladrilhos ===== */
.card{border:1px solid var(--border);border-radius:var(--r-xl);background:var(--card);
  padding:16px;margin-bottom:16px}
.card:last-child{margin-bottom:0}
/* 16 entre o cabecalho e o conteudo: e o que os nos da familia `Card_custom` desenham
   (cabecalho com recuo 16 e conteudo com recuo 16 embaixo e nos lados). */
/* ⬅️ "titulos dos cards fora do padrao, consultar dashboard de cameras" — dela, 16/09.
   ⭐ Medido no COMPONENTE do produto (`dashboard-card.component.css` do modulo Dashboard):
   `.ind-head` tem `gap: spacing-4` — 16, e nao 12. */
.card-cab{display:flex;align-items:flex-start;gap:16px;margin-bottom:16px}
/* ⭐ 14 NO TITULO E 12 NA DESCRICAO — dela, 15/09, riscando o bloco do cabecalho.
   O produto desenha 16/24 sobre 14/21 no cartao de grafico; nesta tela sao ONZE
   cabecalhos, e o que pesa pouco uma vez pesa onze. Os dois degraus descem um lugar na
   escala e continuam nos pares do design system: 14/20 e 12/16.
   ⭐ E o bloco passa a medir 36 exatos (20+16), que e a altura da caixa de glifo ao
   lado: o cabecalho vira uma fileira so, sem sobra de um lado nem do outro. */
/* 🔴 O PESO ERA O DEFEITO, nao o tamanho: 14 sobre 12 e' o que o produto desenha e e'
   o que ela pediu em 15/09. Mas `.ind-title` usa `font-weight-medium` — 500 — e aqui
   estava 600. Num cabecalho isso passa; em TREZE cabecalhos e' a tela inteira meio grau
   mais pesada que o resto do sistema. */
.card-cab h2{font-size:var(--text-sm);line-height:20px;font-weight:500;margin:0}
/* a caixa de glifo, na medida do `.ind-media` do produto: 40 com raio `md`, chao
   tingido e o traco na cor cheia.
   ⚠️ E O GLIFO ENCOLHE ENQUANTO A CAIXA CRESCE: 18 dentro de 36 e' metade da caixa; o
   produto desenha 16 dentro de 40, que e' 40 %. Os dois erros se disfarcavam — a caixa
   parecia certa porque o glifo a preenchia. */
/* ⚠️ RAIO 10, E AS DUAS FONTES DA CASA DISCORDAM EM 2px: o componente Angular
   `dashboard-card.component.css` usa `--radius-md` (8); o no' `2856:117814`, que ela
   nomeou como "card todo de referencia", usa `rounded-lg` (10). Vale o no'. */
.cab-glifo{flex:none;width:40px;height:40px;border-radius:var(--r-lg,10px);
  display:grid;place-items:center;color:var(--primary);
  background:color-mix(in srgb, var(--primary) 10%, transparent)}
.cab-glifo svg{width:16px;height:16px;display:block;stroke:currentColor;fill:none}
/* titulo sobre descricao, que e' o `__heading` do produto */
.cab-tit{display:flex;flex-direction:column;min-width:0}
.cab-desc{margin:0;font-size:var(--text-xs);line-height:16px;color:var(--muted-foreground)}
/* o subtitulo de meia-secao: mesma familia, peso e cor abaixo do titulo de cartao */
.card-cab h2.sub{font-size:var(--text-xs);font-weight:500;color:var(--muted-foreground)}
.card-cab .cresce{flex:1}
.duas{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.duas>.card{margin-bottom:16px}
/* a fileira de tres, na ordem que ela ditou */
/* ⭐ A DUPLA DA PRIMEIRA FILEIRA, na proporção medida no dashboard de câmeras: 841
   contra 525 numa faixa de 1382 dá 62/38, que é praticamente 8 contra 5. A série
   precisa da largura (uma hora por minuto), o retrato não: oito fileiras de barra se
   leem inteiras em 500. */
.serie-e-retrato{display:grid;grid-template-columns:8fr 5fr;gap:16px;margin-bottom:16px}
.serie-e-retrato>.card{margin-bottom:0}
/* ⭐ A FILEIRA NAO DIVIDE IGUAL — dela, 15/09: *"pode reduzir a largura do card se
   necessario e aumentar a do card ao lado"*. Quem tem rotulo longo (`Operativo em modo
   bateria`) fica com 7; quem tem grafico mais ladrilho fica com 5, e assim o ladrilho
   para de ser uma faixa de 360 e se aproxima dos 150 do `uf-gauge__stat` do produto.
   ⚠️ A ALTURA CONTINUA A MESMA NAS DUAS, e nao por acaso: a grade estica as duas ate a
   mais alta, e o grafico come a sobra (ver `preencheSobras`). */
.duas-graf{display:grid;grid-template-columns:7fr 5fr;gap:16px;margin-bottom:16px}
/* o par de baixo (indicadores e tabela) segue dividindo igual */
.duas-graf.iguais{grid-template-columns:1fr 1fr}
.duas-graf>.card{margin-bottom:0}
.tres{display:grid;grid-template-columns:1fr 1fr 1fr;gap:16px;margin-bottom:16px}
/* ⭐ DOIS TERCOS PARA O CARTAO UNIDO: a fileira da Estabilidade ficou com dois cartoes
   depois da uniao, e 50/50 apertaria o mapa de calor, que hoje cabe em um terco. Quem
   precisa da largura e' o unido — 24 colunas de hora em cima, e embaixo uma lista de
   quatro colunas. O `span` so' existe enquanto ha' tres colunas de verdade. */
@media (min-width:80rem){.tres>.card.larga{grid-column:span 2}}
.tres>.card{margin-bottom:0}
/* ⚠️ A DIVISORIA SECUNDARIA SAIU DA FOLHA junto com o uso dela: o cartao de
   distribuicao virou ABAS (dela, 14/09) e nao ha' mais duas metades lado a lado. A
   regra ficava aqui sem alvo, e regra morta e' o que volta a colidir daqui a tres
   meses — esta folha ja' pagou duas vezes por isso.
   ⭐ O QUE APRENDI COM ELA FICA REGISTRADO NO `achados-para-escalar.md`, achado 10: */
.ladrilhos{display:grid;grid-template-columns:repeat(auto-fit,minmax(0,1fr));gap:8px;
  margin-top:16px}
/* raio 14 e sombra xs: o no do Figma mantem o mesmo raio do cartao hospedeiro */
.ladrilho{display:flex;flex-direction:column;align-items:center;gap:8px;padding:8px;
  border:1px solid var(--border);border-radius:var(--r-xl);background:var(--card);
  box-shadow:0 1px 2px 0 rgb(0 0 0 / 0.05)}
/* o chao de alerta do quadro dela: no impacto, `sem protecao` e' o numero que manda
   agir, e um ladrilho igual aos outros nao diz isso */
.ladrilho.alerta{background:color-mix(in srgb, #DC2626 5%, var(--card));
  border-color:color-mix(in srgb, #DC2626 22%, var(--border))}
.ladrilho .ico{display:block;width:16px;height:16px;padding-top:2px;flex:none;
  color:var(--muted-foreground)}
.ladrilho .ico svg{width:16px;height:16px;display:block}
.ladrilho .txt{display:flex;flex-direction:column;align-items:center;gap:2px;
  width:100%;min-width:0;text-align:center}
.ladrilho .rot{width:100%;font-size:var(--text-xs);line-height:16px;font-weight:500;
  color:var(--foreground);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ladrilho .val{font-size:var(--text-sm);line-height:1;font-weight:700;
  font-variant-numeric:tabular-nums}
/* o qualificador do valor nao compete com ele: peso normal e tinta fraca */
.ladrilho .val .de{font-weight:400;color:var(--muted-foreground)}

/* ══ A LISTA DO NO `3033:523314` (`Card_custom` do Modulo — Cameras) ══════════════════
   Dela, 15/09: "Distribuicao por estado e Indicadores operacionais podem seguir este
   padrao, pode ter rolagem". */
.card.coluna{display:flex;flex-direction:column}
/* ⭐ A CAIXA DE CONTEÚDO DO CARTÃO: ela cresce para ocupar a sobra, empilha em coluna
   e aceita encolher (`min-height:0` é o que deixa um rolador dentro dela funcionar).
   🔴 ISTO ERA `.card.coluna>[id]`, e a troca é de 21/09, dela: "encara isso agora".
   O seletor por atributo casava QUALQUER filho direto com id — e "ter id" não é um
   papel, é um detalhe de como o JS acha o elemento. Quem ganhasse um id herdava
   crescimento, coluna e altura mínima zero sem pedir: quebrou o `.card-pe` (rodapé
   empilhado), a `.est-grade` (grade sem colunas), o `.graf-rod` e, em 21/09, a
   `.legenda-linha` (seis itens, um por linha, com 420 de largura cada). Cada uma
   ganhou um remendo desfazendo o estrago, e a peça seguinte quebrava igual.
   ⭐ Agora o seletor diz o PAPEL, e são as dezoito caixas que o declaram. Peça nova com
   id não herda nada. */
.card.coluna>.corpo-card{flex:1 1 auto;min-height:0;display:flex;flex-direction:column}
.lista-fig{display:flex;flex-direction:column;min-width:0}
/* a lista ocupa a sobra do cartao; o teto e quem dispara a rolagem */
.card.coluna .lista-fig{flex:1 1 auto}
.lf-item{flex:1 0 auto;display:flex;align-items:center;gap:12px;padding:6px 0 7px;
  border-bottom:1px solid var(--line);min-width:0}
.lf-item:last-child{border-bottom:0}
.rol-lista{flex:1 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain;
  padding-right:8px;scrollbar-gutter:stable}
/* ⭐ A BARRA E' ESTA, E O NO' DELA CONFIRMA: o componente `Scroll` do `2856:117814`
   desenha `w-8`, chao `var(--base/sidebar-border)` e `rounded-[100px]` — exatamente o
   que estava aqui. 🔴 Eu tinha trocado por uma segunda receita (6px, `--muted-foreground`
   a 28 %), e era eu errando pela segunda vez no mesmo assunto: primeiro inventei um
   rolador quando este ja' existia, depois "consertei" a barra que ja' estava certa. */
.rol-lista::-webkit-scrollbar{width:8px}
.rol-lista::-webkit-scrollbar-thumb{background:var(--sidebar-border,var(--border));
  border-radius:100px}
.rol-lista::-webkit-scrollbar-track{background:transparent}

/* ---- o rodape do cartao ----
   No no ele sangra ate' a borda: fio no topo, chao proprio e recuo de 16. Como o cartao
   ja' tem 16 de recuo, o rodape puxa as margens de volta para encostar nos fios. */
.card-rod{display:flex;align-items:center;justify-content:space-between;gap:12px;
  margin:16px -16px -16px;padding:16px;border-top:1px solid var(--border);
  background:color-mix(in srgb, var(--secondary) 50%, transparent);
  border-radius:0 0 calc(var(--r-xl) - 1px) calc(var(--r-xl) - 1px)}
.card-rod .par{min-width:0;display:flex;flex-direction:column}
.card-rod .par b{font-size:var(--text-xs);line-height:16px;font-weight:600;
  color:var(--foreground)}
.card-rod .par span{font-size:var(--text-xs);line-height:16px;color:var(--muted-foreground)}
.card-rod .dir{flex:none;display:flex;align-items:center;gap:8px;
  font-size:var(--text-xs);line-height:16px;color:var(--muted-foreground)}
.card-rod .dir svg{width:14px;height:14px;display:block}

/* ---- pares rotulo/valor ---- */
/* ⭐ A LINHA DE LISTA DO NO' `2870:124786`: recuo 6/7, vao 12, fio embaixo de cada uma,
   nome forte, sublinha cinza, valor em zinc-600 e uma calha de 4 quando existe proporcao */
.secao{display:flex;flex-direction:column;gap:0;margin:28px 0 12px}
.secao:first-child{margin-top:0}
.secao h2{margin:0;font-size:var(--text-sm);line-height:20px;font-weight:600;color:var(--foreground)}
.secao .leg{font-size:var(--text-xs);line-height:16px;color:var(--muted-foreground)}
.dash>.secao:first-child{margin-top:0}
/* a fileira de KPI paga 16 embaixo, e a proxima secao paga 28 em cima: sobra vao */
.dash>.secao:first-child{margin-top:8px}

.card-cab .etq{flex:none;align-self:flex-start;margin-left:auto;
  display:inline-flex;align-items:center;justify-content:center;gap:4px;
  height:20px;padding:2px 8px;border-radius:var(--r-md,8px);
  font-size:var(--text-xs);line-height:16px;font-weight:500;white-space:nowrap;
  color:var(--secondary-foreground,var(--foreground));
  background:var(--secondary,var(--muted));border:1px solid transparent}
.card-cab .etq.est{background:color-mix(in srgb,var(--primary) 10%,var(--card))}
/* `outline`: sem chao, fio visivel e tinta de conteudo — e' o que o DS faz */
.card-cab .etq.campo{background:transparent;border-color:var(--border);
  color:var(--foreground)}

/* dois cartoes empilhados ocupando UMA coluna da grade, como na referencia */
.pilha{display:flex;flex-direction:column;gap:16px;min-width:0}
.pilha>.card{margin-bottom:0}
.duas-graf>.pilha{min-width:0}
.legenda-linha{display:flex;flex-wrap:wrap;justify-content:center;gap:16px;margin-top:6px;
  font-size:var(--text-xs);line-height:16px;color:var(--foreground)}
.legenda-linha span{display:inline-flex;align-items:center;gap:6px}
.legenda-linha i{display:inline-block;width:8px;height:8px;border-radius:2px;flex:none}
/* o valor, quando houver um que responda alguma coisa */
.legenda-linha b{font-weight:500;color:var(--foreground)}
/* ══ COMPONENTES DA ESTRUTURA DA REFERÊNCIA, 16/09 (quarta passada) ═══════════════════
   Tudo abaixo e' FORMA tomada da referencia com os tokens desta tela. Nenhuma cor,

/* ===== [DASH] os ladrilhos de estado da primeira dobra ===== */
.est-grade.mini{grid-auto-flow:column;grid-auto-columns:minmax(0,1fr);
  grid-template-columns:none;gap:12px;margin:0 0 16px}
/* ⭐ AS MEDIDAS SAO AS DO `event-counter-card` DO PRODUTO, lidas no CSS dele: o cartao
   e' `padding: spacing-4` (16) com `gap: spacing-2` (8). Estava 12/14 e 6. */
.est-grade.mini .est-tile{padding:16px;gap:8px;border-radius:var(--r-xl,14px)}
.est-grade.mini .est-tile::before{display:none}
/* 🔴 `white-space:nowrap` + `ellipsis` vem de `.est-tile .r`, escrita para a legenda
   estreita do outro cartao. Em 154 de largura ela CORTAVA `Operativo — Modo Bateria`
   em `Operativo — Mod…`, e rotulo cortado esconde qual estado e'. Aqui ele quebra.
   ⭐ `min-height` de duas linhas: sem ele, os cinco rotulos curtos subiriam o numero em
   16px e a fileira de oito viraria um serrote. */
/* ⭐ CABECALHO DO LADRILHO, pelo `event-counter-card`: `space-between` poe o rotulo a
   esquerda e o glifo a direita. E o rotulo e' `text-sm` MEDIUM na cor do cartao — nao
   `muted`, que e' como estava. */
.est-grade.mini .est-tile .r{display:flex;align-items:center;justify-content:space-between;
  gap:8px;white-space:normal;overflow:visible;text-overflow:clip;
  color:var(--foreground)}
.est-grade.mini .est-tile .rt{display:inline-flex;align-items:center;gap:4px;
  font-size:var(--text-sm,14px);line-height:20px;font-weight:500;min-width:0}
/* ⬅️ AQUI MORAVA O ⓘ do rotulo, e ele saiu em 23/09 junto com o tooltip do badge: o
   ladrilho inteiro ja' tem hover, e tooltip dentro de tooltip abre os dois no mesmo
   gesto. O que os dois diziam virou a legenda de baixo. */
/* ⭐ O NUMERO DESCE, EM VEZ DE O ROTULO TER ALTURA MINIMA. Com `Operativo —` fora, os
   oito rotulos cabem em uma linha e o `min-height:32px` virou 16px de ar morto em cada
   ladrilho. `margin-top:auto` alinha os oito numeros pelo PE' do ladrilho, que a grade
   ja' estica ate' o mais alto — entao eles continuam alinhados se um rotulo voltar a
   quebrar, sem numero magico nenhum. ⚠️ So' funciona porque `.est-tile` e' `flex`. */
.est-grade.mini .est-tile .n{margin-top:auto}
/* o glifo herda a cor do estado: a bolinha so' tinha cor, e o glifo tem cor E forma */
.est-grade.mini .est-tile .r i{flex:none;width:16px;height:16px;color:var(--tom)}
.est-grade.mini .est-tile .r i svg{display:block;width:16px;height:16px}
/* `text-2xl` (24) em `font-weight-bold`, que e' o `--event-counter-card__value`. */
/* `text-2xl` (24) em `font-weight-bold`, que e' o `event-counter-card__value`.
   ⭐ E A FILEIRA DO NUMERO VIROU FLEX, porque agora ela tem DOIS moradores: o valor e o
   badge de variacao. No componente do produto e' `.event-counter-card__numbers`, com
   `align-items:center`, `flex-wrap` e `gap: spacing-2` — o `wrap` existe para o badge
   descer em vez de espremer o numero quando a coluna aperta. */
.est-grade.mini .est-tile .n{display:flex;align-items:center;flex-wrap:wrap;gap:8px;
  font-size:var(--text-2xl,24px);line-height:32px;font-weight:700;
  font-variant-numeric:tabular-nums}
/* O BADGE, medido no `badge.variants.ts`: base `border px-2 py-0.5 text-xs font-medium`
   com `gap-1` e glifo `size-3`; `outline` e' texto sem fundo (o fio da base fica) e
   `pill` e' raio total. A cor vem por `style`, do tom — `--trend-up` e' o sucesso e
   `--trend-down` e' o destrutivo. */
/* ⭐ REMEDIDO NO FIGMA em 23/09, no no' `2856:117145` — a faixa de KPI do modulo de
   Cameras, que ela mandou implementar. Quatro coisas estavam fora, e as quatro sao do
   desenho e nao de gosto:
     · o badge tem FUNDO (`--base/background`), e eu tinha deixado transparente;
     · a fileira do numero tem ALTURA FIXA de 32, que e' o que mantem os ladrilhos da
       fileira na mesma linha de base mesmo quando um deles nao tem badge;
     · o verde e o vermelho sao os SATURADOS — `--base/status-estavel` #16a34a e
       `--base/destructive` #dc2626 —, e eu tinha usado os escuros de TEXTO desta folha
       (`--ok-txt` #166534 e `--err-txt` #991B1B), que sao outra dupla;
     · e o texto nao leva sinal: quem diz a direcao e' a seta.
   O resto ja' batia: fio 1, raio total, 8 de padding lateral, 2 de vertical, vao 4,
   glifo 12, texto 12/16 medium. */
.est-grade.mini .est-tile .var-badge{display:inline-flex;align-items:center;gap:4px;
  padding:2px 8px;border:1px solid var(--border);border-radius:9999px;
  background:var(--background);
  font-size:var(--text-xs,12px);line-height:var(--lh-xs,16px);font-weight:500;
  white-space:nowrap;flex:none;
  /* ⚠️ `cursor:default` FICA, mesmo sem tooltip: o badge nunca foi clicavel, e o produto
     escreveu essa razao no CSS do proprio componente. */
  cursor:default}
/* a fileira do numero tem altura fixa no desenho: e' ela que alinha os ladrilhos entre
   si quando um tem badge e o outro nao */
.est-grade.mini .est-tile .n{height:32px}
/* ⭐ A LEGENDA, medida no `event-counter-card__caption` do produto: `text-xs` (12),
   `line-height` xs, peso NORMAL e cor `muted`. Ela e' o slot que o componente ja' tinha
   para isto — e e' melhor que o tooltip por um motivo que vale escrever: NAO EXIGE GESTO.
   A explicacao fica lida antes de alguem precisar procura-la. */
.est-grade.mini .est-tile .cap{font-size:var(--text-xs,12px);line-height:var(--lh-xs,16px);
  font-weight:400;color:var(--muted-foreground)}
.est-grade.mini .est-tile .var-badge svg{width:12px;height:12px;display:block}
/* ⚠️ os degraus sao 8 → 4 → 2, e nao 8 → 3: com OITO cartoes, tres colunas deixam a
   ultima fileira com dois e um buraco, que le' como cartao faltando. */
/* ⚠️ ABAIXO DE 1280 A FILEIRA QUEBRA EM LINHAS, e aí o fluxo de coluna atrapalha: o que
   se quer é 4 e depois 2 por linha, empilhando. O `grid-auto-flow` volta para `row`. */
@media (max-width:79.998rem){.est-grade.mini{grid-auto-flow:row;
  grid-template-columns:repeat(4,minmax(0,1fr))}}
@media (max-width:47.998rem){.est-grade.mini{grid-auto-flow:row;
  grid-template-columns:repeat(2,minmax(0,1fr))}}

/* 🔴 O BLOCO `.seg` SAIU JUNTO COM O CONTROLE — 16/09. Ele so' existia para o seletor
   de janela do cartao de disponibilidade, que ela mandou tirar; sem alvo, ficaria sendo
   uma regra que alguem copia daqui a tres meses achando que a casa tem controle
   segmentado dentro de cartao. `.segs`, no bloco do gerador, e' outro seletor. */
/* a regra do titulo mirava `:first-child`; com a migalha antes dele ela pegaria a
   migalha. Passou a mirar o `h1`, que e' o que ela sempre quis dizer. */
.migalha{display:flex;align-items:center;gap:6px;font-size:var(--text-xs);line-height:16px;
  color:var(--muted-foreground);margin-bottom:2px}
.migalha [aria-current]{color:var(--foreground)}
.migalha .sep{color:var(--muted-foreground)}   /* sem opacidade: a 60 % dava 2,3:1 */
.est-grade.energia{grid-template-columns:repeat(4,minmax(0,1fr));gap:16px;margin:0 0 16px}
.est-grade.energia .est-tile{padding:14px 16px;gap:4px;border-radius:var(--r-xl,14px)}
.est-grade.energia .est-tile .n{font-size:var(--text-xl,20px);line-height:28px;font-weight:700}
.est-grade.energia .est-tile::before{display:none}   /* indicador, nao estado: sem fio de cor */
.card-cab>.btn-sec{margin-left:auto;align-self:flex-start}
/* ⬅️ "fora do padrao do badge" — dela, 16/09, no `ESTIMATIVA` do indicador de custo.
   🔴 ERA MEU: a rodada de badge mexeu nas duas primeiras linhas desta regra e deixou a */
.est-grade{display:grid;grid-template-columns:repeat(auto-fit,minmax(104px,1fr));
  gap:8px;margin-top:0}   /* a `.pilha-estado` ja' paga 14 embaixo; somar dava 28 */
/* 🔴 A REGRA `.card.coluna>[id]` DA LINHA 1088 PEGA ESTE BLOCO, e ela venceu na
   primeira passada: ela casa QUALQUER filho direto com id e crava
   `display:flex;flex-direction:column`, entao a grade virou coluna e os seis ladrilhos
   sairam com 734 de largura cada, um por linha. Medido antes de perceber.
   ⚠️ E o seletor generico esta' certo no que ele resolve — e' ele que faz o miolo do
   cartao esticar para a altura do vizinho da fileira. O que ele nao previa e' um filho
   com id que NAO deve esticar. Aqui a excecao e' declarada com a mesma especificidade e
   depois dele: grade de verdade, e sem crescer. */
/* 🔴 E O MESMO SELETOR ABRIA UM VÃO DE 90px ENTRE A BARRA E OS LADRILHOS. Com
   `flex:1 1 auto`, o miolo do grafico ESTICA para o cartao alcancar a altura do vizinho
   da fileira — e a barra empilhada tem 10px de altura, entao os outros 90 viravam
   buraco branco no meio do cartao. Crescer so' faz sentido para quem DESENHA na altura
   que ganha; a barra nao usa altura nenhuma. Os dois param de crescer e a sobra desce
   para o pe' do cartao, onde ela le' como respiro e nao como falha de carregamento. */
.est-tile{position:relative;overflow:hidden;min-width:0;
  border:1px solid var(--border);border-radius:var(--r-md,8px);padding:8px 10px;
  display:flex;flex-direction:column;gap:1px}
.est-tile::before{content:"";position:absolute;inset:0 0 auto 0;height:2px;background:var(--tom)}
.est-tile .r{font-size:var(--text-xs);line-height:16px;color:var(--muted-foreground);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* ⚠️ O NUMERO CAI DE 24 PARA 14/600. Na fileira ele era manchete e o olho varria seis
   numeros na horizontal; aqui ele e' o valor de uma legenda, e legenda com numero de
   manchete competiria com o titulo do proprio cartao, que tambem e' 14. O peso e' que
   separa os dois. */
.est-tile .n{font-size:var(--text-sm);line-height:20px;font-weight:600;color:var(--foreground)}
.est-tile .p{font-size:var(--text-xs);line-height:16px;color:var(--muted-foreground)}

/* ===== [DASH] botao de contorno, barras, rodape, ranking, rosca, erro ===== */
.btn-out{display:inline-flex;align-items:center;gap:4px;height:32px;padding:8px 10px;
  border-radius:var(--r-md);border:1px solid var(--input);background:var(--ctl-bg);
  color:var(--foreground);font-size:var(--text-xs);line-height:var(--lh-xs);
  font-weight:500;white-space:nowrap}
.btn-out svg{width:14px;height:14px;display:block}
.btn-out:hover{background:var(--sec,#F5F5F5);color:var(--sec-txt,#171717)}
/* ⚠️ O AVISO E' PECA NOVA: o componente da casa nao tem um, e o anexo dela pede. Ele
   segue o vocabulario do resto — raio `--r-lg`, recuo 12 — e usa o vermelho de alarme
   diluido no chao do cartao, que e' como o ladrilho `Sem protecao` ja' faz. */
.barras{display:flex;flex-direction:column;gap:8px}
/* ⚠️ DOIS GRUPOS DE BARRAS NAO SAO UMA LISTA — dela, 14/09, apontando `Bypass`
   encostado em `Desconhecido`. Em `Por modo` o primeiro grupo sao os modos de verdade
   (rede, bateria, bypass) e o segundo e' a AUSENCIA de modo (desconhecido, nao se
   aplica). Sem vao os cinco liam como uma lista so', e `Desconhecido` entrava como se
   fosse um quarto modo — que e' justamente o que ele nao e'.
   O vao e' maior que o passo interno (7) de proposito: a distancia entre grupos tem de
   vencer a distancia entre irmaos, senao ela nao agrupa nada. */
.barras+.barras{margin-top:16px}
/* ⭐ A FILEIRA E' A DO `dashboard-meters` DO PMV — dela, 14/09, com o cartao
   `Mensagens mais utilizadas` como referencia: NOME EM CIMA, valor impresso na
   direita da mesma linha, e a BARRA EMBAIXO ocupando a largura inteira.

   ⚠️ A MUDANCA NAO E' DE ARRUMACAO, E' DE ESCALA DE LEITURA. Na fileira de tres
   colunas (`104px 1fr 46px`) a barra dividia a largura com o rotulo e com o numero, e
   sobrava um terco dela para desenhar a grandeza. Com o rotulo fora da linha a calha
   fica INTEIRA — a mesma diferenca de 23px para 246px que o cartao partido ja' tinha
   custado, agora resolvida pela anatomia em vez de por um conserto local.

   A UF do PMV chama esta peca de MEDIDOR e a separa do `bar-rows` pela PERGUNTA: o
   medidor responde *"quanto deste total"* — cada barra e' fracao de 100 e vale
   sozinha. E' o caso de toda barra desta tela: estado sobre a frota, faixa de
   autonomia sobre o parque, carga sobre a capacidade. */
.barras .l{display:grid;grid-template-columns:1fr auto;
  grid-template-areas:"rot num" "tr tr";align-items:center;
  column-gap:12px;row-gap:4px;font-size:var(--text-xs);line-height:16px}
/* ⬅️ "padding, os cards podem ter scroll, nao aumentar altura dos cards" — dela, 16/09,
   riscando a beira de cada uma das oito linhas do `Distribuicao por estado`.
   🔴 A linha tinha 26 de altura e recuo ZERO — rotulo de 16, vao de 4 e a calha de 6, e
   nada em volta. Oito empilhadas eram uma parede.
   🔴 E O ROLADOR AQUI ERA UMA CLASSE MINHA (`.lista-rola`, com `flex:1 1 0`) QUANDO O
   MODELO JA' EXISTIA: `.rol-lista`, mais acima nesta folha, com a barra da casa e com o
   comentario que descreve exatamente a armadilha da base ZERO. Terceira variante de uma
   decisao que ja' tinha duas tentativas registradas e uma conclusao escrita. */
/* ══ O RODAPE DE CARTAO ═══════════════════════════════════════════════════════════
   Medido no no' `2856:117814`: fio de 1 no topo, recuo 16, chao `--muted` a 50 % e
   largura inteira. ⚠️ SANGRA ate' a borda — o cartao paga 16, o rodape puxa −16 de volta
   nos lados e embaixo e devolve os 16 como recuo proprio. Mesma conta da faixa cinza do
   topo, do outro lado do cartao. */
.card-pe{margin:16px -16px -16px;padding:16px;
  border-top:1px solid var(--border);
  background:color-mix(in srgb,var(--muted) 50%,var(--card));
  border-radius:0 0 calc(var(--r-xl,14px) - 1px) calc(var(--r-xl,14px) - 1px);
  display:flex;align-items:center;justify-content:space-between;gap:16px}
.card-pe .pe-txt{display:flex;flex-direction:column;min-width:0}
.card-pe .pe-1{font-size:var(--text-xs);line-height:16px;font-weight:600;color:var(--foreground);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.card-pe .pe-2{font-size:var(--text-xs);line-height:16px;color:var(--muted-foreground);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* o bloco da direita do no': glifo de 14, vao 8, texto 12 */
.card-pe .pe-dir{flex:none;display:flex;align-items:center;gap:8px;
  font-size:var(--text-xs);line-height:16px;color:var(--muted-foreground);white-space:nowrap}
.card-pe .pe-dir svg{width:14px;height:14px;display:block}

/* ══ A LINHA DO `lista-graph-cam` ═════════════════════════════════════════════════════
   Medida no mesmo no': fio embaixo, `pt-6 pb-7`, vao 12, nome 12/16 em 600 com sublinha
   12/16 apagada a esquerda, e a direita o valor (12, entrelinha 1) sobre uma barra de
   ALTURA 4 com raio total — trilho na mesma cor a 20 %, preenchimento na cor cheia.
   ⚠️ SEM A PILULA DE NUMERACAO do no': la' e' um RANKING e o numero e' a posicao. Oito
   estados de frota nao sao ranking — numera-los diria que `Modo rede` e' "o primeiro"
   de uma corrida que nao existe.
   ⚠️ E A COR E' A DO ESTADO, nao o primario do no': la' todas as barras medem a mesma
   grandeza; aqui cada barra e' um estado, e a cor e' a chave de leitura do cartao. */
.lista-rank{display:flex;flex-direction:column}
.lista-rank .l{display:grid;grid-template-columns:minmax(0,1fr) minmax(96px,40%);
  align-items:center;column-gap:12px;
  padding-block:6px 7px;border-bottom:1px solid var(--border)}
.lista-rank .l:last-child{border-bottom:0}
.lista-rank .rot{min-width:0;font-size:var(--text-xs);line-height:16px;font-weight:600;
  color:var(--foreground);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lista-rank .sub{grid-column:1;font-size:var(--text-xs);line-height:16px;
  color:var(--muted-foreground);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lista-rank .dir{grid-column:2;grid-row:1/span 2;display:flex;flex-direction:column;gap:8px}
.lista-rank .n{font-size:var(--text-xs);line-height:1;text-align:right;
  color:var(--muted-foreground);font-variant-numeric:tabular-nums}
/* ⬅️ "fundo cinza no graph como nos outros" — dela, 18/09.
   ⚠️ DIVERGENCIA DECLARADA DO NO': o `2856:117814` pinta o trilho na propria cor da
   barra a 20 %, e la' faz sentido porque todas as barras do cartao medem a mesma
   grandeza. Aqui cada linha e' um ESTADO com cor propria — cinco trilhos tingidos numa
   lista so' — e todo o resto da tela (`.barras`, `.pilha-estado`) usa `--muted`.
   A consistencia dentro da tela ganha da fidelidade ao no'. */
.lista-rank .calha{display:block;height:4px;border-radius:9999px;overflow:hidden;
  background:var(--muted)}
/* ⭐ A PILULA NUMERADA do `BadgeNumber` do no': altura 20, largura minima 20, raio
   total, chao `--secondary`, fio de 1 transparente, recuo lateral 4 e texto 12/16 em
   `medium`. E' a mesma badge do zard ja' medida hoje, na forma `pill`.
   ⚠️ So' entra onde o numero E' a posicao. Na lista de estados ela mentiria: oito
   estados nao sao uma corrida. */
.lista-rank.com-pos .l{grid-template-columns:auto minmax(0,1fr) minmax(96px,40%)}
.lista-rank .pos{grid-column:1;grid-row:1/span 2;justify-self:start;align-self:center;
  display:inline-flex;align-items:center;justify-content:center;
  height:20px;min-width:20px;padding:0 4px;border-radius:9999px;
  border:1px solid transparent;background:var(--secondary,var(--muted));
  color:var(--secondary-foreground,var(--foreground));
  font-size:var(--text-xs);line-height:16px;font-weight:500;
  font-variant-numeric:tabular-nums}
.lista-rank.com-pos .rot{grid-column:2}
.lista-rank.com-pos .sub{grid-column:2}
.lista-rank.com-pos .dir{grid-column:3}
.lista-rank .calha i{display:block;height:100%;border-radius:9999px}
/* ⚠️ A EXCECAO, e agora ela tem NOME em vez de ficar presa a um cartao. `.rol-lista`
   tem base `auto` de proposito — a lista mede o proprio conteudo e a GRADE da' a altura
   da fileira. Isso vale enquanto a lista NAO e' o item mais alto do par. Quando ela e',
   base `auto` faz a fileira inteira crescer e o cartao vizinho e' esticado junto — meia
   pagina de branco num cartao por causa do conteudo do outro, que foi o que ela riscou
   no `Previsao de substituicoes` em 16/09.
   ⭐ `.nao-manda` diz o que faz: ESTE ROLADOR NAO DA' A ALTURA DA FILEIRA. Com base
   ZERO a altura vem do outro cartao e a lista rola dentro do que sobra. */
.card.coluna>.rol-lista.nao-manda{flex-basis:0}
/* ⭐ CINCO LINHAS A' VISTA, que e' o que o no' `2856:117814` mostra num cartao de 350 —
   com o trilho de 93 dizendo que ha' mais. Cinco linhas de 46 sao 230.
   ⚠️ O comentario do `.rol-lista` rejeita `max-height`, e a rejeicao e' de OUTRO caso:
   la' o teto brigava com uma fileira que ja' era maior que ele. Aqui o teto e' sempre
   MENOR que o conteudo (dez linhas nunca cabem em cinco), entao ele corta e a lista rola.
   ⚠️ E aqui NAO se usa `nao-manda`: o irmao `Previsao de substituicoes` tem 178 de
   altura natural, e a lista ficaria com 23px — meia linha de dez. Trocar branco demais
   por janela nenhuma nao e' reduzir altura, e' mudar de defeito. */
.card.coluna>.rol-lista.ate-cinco{max-height:230px}
/* ⬅️ "mais espaço para aumentar altura do conteúdo" — dela, 21/09. Eram três linhas
   (138) e sobravam 50px de faixa vazia entre a lista e o rodapé; a linha mede 46, então
   cabia mais uma inteira. Quatro linhas = 184, e os 4 que sobram o rodapé usa para se
   ancorar no pé.
   ⚠️ Cinco pediria 230 e o cartão voltaria a esticar a fileira, que é o que ela mandou
   reduzir duas rodadas atrás. */
.card.coluna>.rol-lista.ate-quatro{max-height:184px}
/* 🔴 E QUEM PÕE TETO NA LISTA TIRA O ELÁSTICO DO CARTÃO. A lista era o `flex:1 1 auto`
   que crescia até a altura da fileira; travada, ninguém absorve a sobra e o rodapé para
   onde o conteúdo acaba — 31px acima do fundo, medido em 21/09. `margin-top:auto` come
   a folga e ancora o rodapé no pé, que é a mesma receita da legenda do KPI de 14/09.
   ⚠️ Só nos cartões COM teto: onde o conteúdo preenche, `auto` vale zero e o rodapé
   perderia os 16 de respiro. */
.card.coluna>.ate-cinco~.card-pe,
.card.coluna>.ate-quatro~.card-pe{margin-top:auto}
/* 🔴 ESTE REMENDO SAIU EM 21/09 junto com o `[id]`: o pé nunca precisou ser
   desfeito, ele só sofria. Comentário mantido pelo registro do que aconteceu.
   O texto antigo dizia: `.card.coluna>[id]` casa com QUALQUER filho que tenha um id —
   foi escrita para os containers de grafico e pegava tambem o `#ultLeitura`, um
   paragrafo de UMA linha. Os dois cresciam e dividiam a sobra: a lista ficava com 87 e o
   texto de 16 pixels ficava com 103.
   ⭐ Mesma familia das tres colisoes de classe desta sessao: um seletor que descreve uma
   COINCIDENCIA ("ter id") e nao uma intencao. Ter id nao e' ser o conteudo elastico. */
.barras .rot{grid-area:rot}
.barras .n{grid-area:num}
.barras .calha{grid-area:tr}
/* o nome sobe para o `--foreground`: fora da fileira de tres colunas ele deixou de ser
   rotulo de celula e virou o TITULO da leitura, que e' o que o medidor do PMV desenha */
.barras .rot{color:var(--foreground);min-width:0;white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis}
/* e o valor desce para o cinza, que e' a troca simetrica: ele qualifica o nome */
.barras .n{color:var(--muted-foreground);font-variant-numeric:tabular-nums}
/* ⚠️ NAO CHAMAR ISTO DE `.tr`: esse nome ja e a fileira do interruptor de tempo real,
   e a regra de la (flex + recuo de 8) apagava a altura do preenchimento colorido. */
/* ⬅️ "engrossar um pouquinho essa barra" — dela, 21/09. 6 → 8.
   ⚠️ Vale para TODA a tela de propósito: esta é a mesma peça em `Capacidade por
   região`, `Cenário de corte`, `Interseções protegidas` e `Dispositivos protegidos`.
   Engrossar só num cartão criaria a quinta altura de barra da tela — a varredura de
   18/09 já anotou quatro (4 no `.lista-rank`, 6 aqui, 7 no `.spark`) como achado em
   aberto. Com 8 as barras da casa ficam em 4 e 8, dois degraus da grade; sobra o
   `.spark` em 7, que é o próximo a alinhar. */
.barras .calha{display:block;height:8px;border-radius:9999px;background:var(--muted);overflow:hidden}
.barras .calha i{display:block;height:100%;border-radius:9999px}

/* ---- a pizza ----
   Dela, 15/09: "pode tentar em forma de pizza?". A forma so' cabe porque as quatro
   faixas FECHAM O TODO (somam a frota); e' o mesmo teste de denominador que tirou a
   barra do `Cinco piores`. */
.grafz{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;
  align-items:center;justify-content:center;gap:36px}
/* a rosca do no' `2870:124778`: caixa 192, raio externo 96 e interno 60,5 (razao 0,63) */
.rosca{position:relative;flex:none;width:192px;max-width:100%;aspect-ratio:1}
/* `overflow:visible` porque a raiz de um SVG recorta por padrao, e a fatia em realce
   cresce 6 alem da caixa de 192 — e' na borda que o efeito acontece */
.rosca .pz{display:block;width:100%;height:100%;overflow:visible}
/* o realce do hover, como nos tres quadros do Cameras: a fatia sob o ponteiro em cor
   cheia, as outras esmaecidas. O crescimento nao esta' aqui: e' troca de tracado, no
   corpo, porque escalar cresceria o raio de dentro junto e abriria fenda no buraco. */
.rosca .pz .fat{transition:opacity .12s ease}
.grafz.realce .fat{opacity:.28}
.grafz .fat.ativa{opacity:1}
/* e a legenda acende a fatia: com 6,8 graus, `abaixo de 50 %` so' se alcanca por aqui */
/* o fio entre as fatias e' o chao do cartao, e nao o `white` cravado do no': no tema
   escuro um aro branco em volta de cada fatia viraria luz. UM pixel, como no no' —
   com dois a fatia de 6,8 graus some dentro dos proprios fios. */
.rosca .pz .fat{stroke:var(--card);stroke-width:1;stroke-linejoin:round}
/* ⚠️ O MIOLO E' HTML POR CIMA, e nao `<text>` dentro do SVG: `font-size` dentro de um
   `viewBox` escalado e' RAZAO e nao tamanho, e isso ja' fez 12 virar 15,7 / 14,6 /
   22,8 em tres graficos desta tela. Fora do SVG, 30 e' 30. */
.rosca .miolo{position:absolute;inset:0;display:flex;flex-direction:column;
  align-items:center;justify-content:center;text-align:center;pointer-events:none}
/* ⬅️ "reduzir texto dentro do gráfico" — dela, 21/09. Era 30/36, o `--text-3xl` do nó
   do Câmeras, onde o miolo carrega uma contagem curta. Aqui ele carrega `96,25 %`, que
   é o dobro de caracteres, e encostava nas bordas do buraco de 120.
   ⬅️ "pode reduzir mais" — dela, 21/09, na segunda passada: 30 → 24 → **20/28**, que é o
   `--text-xl` e o mesmo degrau do número dos ladrilhos de estado logo acima. Medido, o
   texto fica com folga dos dois lados dentro do buraco de 120. */
.rosca .miolo b{font-size:var(--text-xl,20px);line-height:28px;font-weight:700;
  color:var(--foreground);font-variant-numeric:tabular-nums}
/* 🔴 ERA `.rosca .miolo span`, E PEGAVA O NÚMERO. O `valor()` embrulha todo valor de
   demonstração num `<span class="mock">`, e esse span nasce DENTRO do `<b>` do miolo:
   a regra da unidade descia o percentual de 30 para 12px. Descoberto em 21/09, com a
   rosca da disponibilidade imprimindo `96,25 %` do tamanho da legenda.
   ⚠️ É a QUINTA colisão de nome desta tela (`.leg span`, `.rod`, `.chip`, `.card.coluna>[id]`),
   e a lição escrita três linhas abaixo nesta mesma folha já dizia: nome próprio resolve,
   especificidade só adia. A unidade ganhou classe. */
.rosca .miolo .unid{font-size:var(--text-xs);line-height:16px;color:var(--muted-foreground)}
/* ⚠️ OITO ENTRE LINHAS, DEZESSEIS ENTRE ITENS. O no' do Cameras declara 16 nos dois
   eixos, mas a legenda dele tem tres itens curtos e nunca quebra — o vao vertical dele
   nunca foi desenhado. Aqui os quatro rotulos sao faixas inteiras, a legenda quebra, e
   16 entre linhas de 16 de altura abre um vao tao alto quanto o texto. O 8/16 e' do
   proprio DS: e' o que o no' `16541:609762` do PMV declara na legenda que quebra. */
/* 🔴 `legr`, e nao `leg`: `.leg` ja' e' de outra legenda desta tela, e a regra dela
   — `.leg span{color:var(--muted-foreground)}` — pegava qualquer `span` aqui dentro,
   inclusive o numero. Mesma familia do defeito 9-U, em que uma colisao de nome apagou
   o preenchimento de toda barra da tela. Nome proprio resolve; especificidade so'
   adia. */
/* ⬅️ "números extras na parte de baixo, em cima da legenda se houver" — dela, 21/09.
   Eles ficam entre o desenho e a legenda, centrados como ela, e em 12/16 apagado: são o
   apoio da leitura do miolo, não uma segunda leitura. */
.grafz .extras{margin:0;width:100%;text-align:center;
  font-size:var(--text-xs);line-height:16px;color:var(--muted-foreground)}
/* ⬅️ "espaço muito grande entre a legenda da primeira linha e a da segunda" — dela,
   21/09. Era 8 entre linhas; a legenda de carga do cartão ao lado já estava em 4. */
.grafz .legr{width:100%;display:flex;flex-wrap:wrap;align-items:center;
  justify-content:center;gap:4px 16px}
/* 🔴 "não precisa desse espaço entre o símbolo e o número" — dela, 21/09, cercando o
   `( 304 )`. E o ar dentro dos parênteses NÃO estava escrito no texto: o item era
   `display:flex` com `gap:6`, e o conteúdo dele é
   `<i>` · "Faixa segura (" · `<span class="mock">304</span>` · ")".
   ⭐ CADA TRECHO DE TEXTO SOLTO VIRA ITEM DE FLEX ANÔNIMO, então o vão de 6 separava
   também o "(" do número e o número do ")". O valor só é um elemento porque o
   `valor()` o embrulha para marcar procedência — onde o número é publicado e não tem
   embrulho, o parêntese fechava colado, e era isso que fazia a legenda parecer
   diferente de um cartão para o outro.
   ⭐ O vão sai do contêiner e vira margem do quadrado, que é o único lugar onde ele
   precisava existir. */
.grafz .legr .l{display:flex;align-items:center;gap:0;white-space:nowrap;
  font-size:var(--text-xs);line-height:16px;color:var(--foreground)}
.grafz .legr .l i{flex:none;width:8px;height:8px;border-radius:2px;margin-right:6px}
.bloco-erro[hidden],.dash[hidden]{display:none}
/* contêiner: `flex-col items-center justify-center gap-6 rounded-lg border-dashed
   p-6 text-center text-balance md:p-12` */
.bloco-erro{display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:24px;border-radius:var(--r-lg);border:0 dashed var(--border);padding:24px;
  text-align:center;text-wrap:balance;min-height:320px;margin-bottom:16px}
@media (min-width:768px){.bloco-erro{padding:48px}}
/* cabeçalho: `flex max-w-sm flex-col items-center gap-2 text-center`
   ⚠️ COM UMA EXCEÇÃO ESCOPADA, dela em 21/09: "tem mais espaço para texto aqui". O
   `max-w-sm` do componente (384) quebrava a frase em TRÊS linhas dentro de um cartão
   de 1.400. A medida passa a ser 72ch, que é a que este bloco já usava antes de virar
   o formato do componente — não é valor novo, é o valor que saiu na troca. A 14px dá
   ~510 e a frase cai para duas linhas.
   ⭐ E abre SÓ o cabeçalho: nas ações o `max-w-sm` fica, porque ali é um botão
   centrado e largura sobrando não muda nada para ele. */
.bloco-erro .cabeca{display:flex;flex-direction:column;align-items:center;gap:8px;
  max-width:72ch;text-align:center}
/* ícone: `bg-muted text-foreground mb-2 flex size-10 rounded-lg`, glifo `size-5!` */
.bloco-erro .ico{flex:none;display:flex;align-items:center;justify-content:center;
  width:40px;height:40px;margin-bottom:8px;border-radius:var(--r-lg);
  background:var(--muted);color:var(--foreground)}
.bloco-erro .ico svg{width:20px;height:20px;pointer-events:none}
/* título: `text-lg font-medium tracking-tight` */
.bloco-erro b{font-size:var(--text-lg);line-height:var(--lh-xl);font-weight:500;
  letter-spacing:-0.025em;color:var(--foreground)}
/* descrição: `text-muted-foreground text-sm/relaxed` — 14 x 1,625 = 22,75 */
.bloco-erro span{font-size:var(--text-sm);line-height:1.625;color:var(--muted-foreground)}
/* ações: `flex w-full max-w-sm items-center justify-center gap-2 text-sm` */
.bloco-erro .acoes{display:flex;align-items:center;justify-content:center;gap:8px;
  width:100%;max-width:24rem;font-size:var(--text-sm)}

/* A LEITURA VELHA SE MARCA, e nao se esconde: o numero continua sendo o ultimo que
   chegou, e o que muda e' o quanto se pode confiar nele. */
/* A IDADE DA LEITURA OCUPA O LUGAR DA FRASE — dela, 14/09, riscando a descricao. E a
   troca tem razao: a frase dizia o que a tela e', que o titulo ja' diz; a idade diz
   se o que esta' na tela ainda vale, que e' a coisa que muda e a unica que ninguem
   consegue deduzir olhando. Numa tela de acompanhamento, uma descricao permanente
   ocupa a linha mais bem colocada da pagina para nao dizer nada de novo.
   `::first-letter` maiusculiza sem mexer no texto gerado, que continua comecando em
   minuscula para poder ser reusado no meio de frase. */
.barra-painel__lido{margin:2px 0 0;font-size:var(--text-xs);line-height:var(--lh-xs);
  color:var(--muted-foreground);font-variant-numeric:tabular-nums}
.barra-painel__lido::first-letter{text-transform:uppercase}
.barra-painel__lido .velho{color:#9A3412;font-weight:500}  /* orange-800 */
:root[data-modo="escuro"] .barra-painel__lido .velho{color:#FDBA74}  /* orange-300 */

/* ---- o relogio do cenario ---- */
.relogio{display:inline-flex;align-items:center;gap:6px;font-variant-numeric:tabular-nums}

/* ============================================================================
   ===== GATEWAY · o que é próprio deste módulo =================================
   Cada regra abaixo diz de onde saiu. Nada aqui redesenha peça que a folha acima já
   tem: são apelidos de token, o glifo do tipo, e as poucas peças que o Nobreaks não
   precisou (a tabela de dados brutos sob o gráfico, o passo-a-passo do assistente, a
   tabela de descoberta, o link de interseção dentro da célula).
   ============================================================================ */
:root{
 /* OFFLINE É VERMELHO, e não o cinza `status-offline` do ciclo de vida. Medido no tema
    do produto (`libs/ui-styles/tokens/theme.css:80`): `--base-status-disconnected` é
    `--destructive`, e é com ele que a tabela de câmeras pinta a conectividade offline
    (`cameras-table.component.css`, `--connectivity-OFFLINE`). O par é o mesmo par de
    `instavel` desta folha (#DC2626 cheio, #DC2626 a 10 % no chão). */
 --status-desconectado:var(--status-instavel);
 --status-desconectado-fundo:var(--status-instavel-fundo);
 /* A COR DO TIPO `Gateway` NO 26: `#10B981` (emerald-500), a mesma no pino do mapa, no
    painel da interseção e na página de dispositivo do projeto da Larissa
    (`IntersectionConfigSheet.tsx:112-149`, `MapCanvas.tsx:5672`). Não se escolhe outra. */
 --tipo-gateway:#10B981;
}
/* o alfinete do mapa leva a cor do tipo, como o do nobreak leva a da camada de UPS */
.ui-map__pin-circle,.ui-map__pin-dot{background:var(--tipo-gateway)}
/* a caixa de glifo da identidade, na página interna: a cor do tipo a 10 % no chão e
   cheia no traço — a mesma gramática da `.pg-ico` (primário a 8 %) e da `.cab-glifo`
   (primário a 10 %), com a cor do tipo no lugar do primário. Cor por tipo é o que o
   Modelo de Tráfego do 26 faz com semáforo, câmera e gateway. */
.pg-ico.tipo{background:color-mix(in srgb,var(--tipo-gateway) 10%,var(--card));
  color:var(--tipo-gateway)}
/* o link de interseção dentro da célula: texto, na cor de link da migalha (blue/700
   no claro, blue/400 no escuro — azul cheio em texto não passa no piso). */
.lk{color:var(--acc-txt,#1D4ED8);text-decoration:none}
.lk:hover{text-decoration:underline;text-underline-offset:2px}
/* o serial é o id do gateway no TTN, o que está na etiqueta: monoespaçado e tabular,
   como a tabela de câmeras faz com o serial (`cameras-table__td--mono`) */
.mono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  letter-spacing:-.01em;font-variant-numeric:tabular-nums}

/* ---- a tabela de dados brutos ABAIXO do gráfico (skill: "não ao lado") ----
   A mesma grade do log (`.logt`), com a altura de linha do log (44) e o teto de cinco
   linhas do `.ate-cinco` (230): quem quer "o que ele leu às onze" rola dentro dela. */
.bruta{margin-top:var(--sp-2);border-top:1px solid var(--border)}
.bruta .logrol{max-height:230px}
.bruta .logt .th{min-height:36px;padding:8px 14px}

/* ---- o assistente: os passos, verbatim do `nobreaks-novo.html` (que os mediu no
   `controller-creation-panel.component.css` da produção), com UMA troca de nome:
   o círculo do passo era `.num`, e `.num` já é a célula tabular da lista. ---- */
.passos{flex:0 0 auto;display:flex;align-items:center;gap:4px;padding:0 16px 16px;
  position:relative;overflow-x:hidden}
.passos::after{content:"";position:absolute;left:16px;right:16px;bottom:0;
  border-bottom:1px solid var(--border)}
.passos ol{list-style:none;margin:0;padding:0;display:flex;align-items:center;gap:4px;
  flex:1 1 auto;min-width:0}
.passo{display:inline-flex;align-items:center;gap:4px;flex:0 1 auto;min-width:0;
  color:var(--muted-foreground);white-space:nowrap}
.passo-num{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;
  border-radius:9999px;background:var(--muted);color:var(--muted-foreground);
  border:1px solid var(--border);font-size:var(--text-xs);font-weight:600;line-height:1;
  flex:0 0 auto}
.passo-num svg{width:12px;height:12px}
.passo.ativo .passo-num{background:var(--primary);color:var(--primary-foreground);
  border:2px solid color-mix(in srgb,var(--primary) 30%,var(--background))}
.passo.feito .passo-num{background:color-mix(in srgb,var(--primary) 22%,var(--background));
  color:var(--primary);border:2px solid color-mix(in srgb,var(--primary) 35%,var(--background))}
.passo .rot{font-size:var(--text-xs);line-height:var(--lh-xs);font-weight:600;color:inherit;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.passo.ativo .rot{color:var(--foreground)}
.passo .sep{display:inline-flex;align-items:center;color:var(--muted-foreground);flex:0 0 auto}
.passo .sep svg{width:14px;height:14px}
/* o cartão de chamada do passo de busca, do nó `2:36542` do Figma de Câmeras, como o
   `nobreaks-novo.html` o fixou: fio da primária a 30 %, chão a 5 %, raio xl, ficha a 20 % */
.chamada{display:flex;align-items:center;gap:12px;padding:16px;
  border:1px solid color-mix(in srgb,var(--primary) 30%,var(--background));
  border-radius:var(--r-xl,14px);
  background:color-mix(in srgb,var(--primary) 5%,var(--card))}
.chamada-ficha{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;
  width:40px;height:40px;border-radius:var(--r-lg);
  background:color-mix(in srgb,var(--primary) 20%,var(--background));color:var(--primary)}
.chamada-ficha svg{width:16px;height:16px}
.chamada-tx{display:flex;flex-direction:column;gap:4px;min-width:0;flex:1}
.chamada-tx b{font-size:var(--text-sm);line-height:var(--lh-sm);font-weight:500;
  color:var(--foreground)}
.chamada-tx span{font-size:var(--text-xs);line-height:var(--lh-xs);color:var(--muted-foreground)}
/* a tabela de descoberta dentro da gaveta: a grade do log, com a caixa de seleção do
   `z-checkbox` (16, raio 4, primário quando marcada — o `.fop .cx` do popover) */
.desc-tab{border:1px solid var(--border);border-radius:var(--r-lg);overflow:hidden}
.desc-tab .logrol{max-height:264px}
.desc-tab .logt{grid-template-columns:44px minmax(220px,1fr) 190px 170px}
.desc-tab .td.cx-cel{justify-content:center}
.desc-tab .lin2.marcada .td{background:color-mix(in srgb,var(--primary) 9%,var(--card))}
.cx{width:16px;height:16px;flex:none;border:1px solid var(--input);border-radius:4px;
  display:inline-flex;align-items:center;justify-content:center;color:transparent;
  background:var(--ctl-bg);cursor:pointer;padding:0}
.cx[aria-checked="true"]{background:var(--primary);border-color:var(--primary);
  color:var(--primary-foreground)}
.cx svg{width:12px;height:12px}
/* o resultado por gateway no passo final: uma linha por POST, com o chip dizendo o que
   o 25 escrevia em texto ("'X' adicionado com sucesso!") */
.res-lin{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:10px 0;border-bottom:1px solid var(--border);font-size:var(--text-sm)}
.res-lin:last-child{border-bottom:0}
.res-lin .rot{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* o campo que a página inteira desliga quando não está em edição: o valor pousado na
   linha, no chão apagado do `input[readonly]` da gaveta — "lápis destrava, Salvar confirma" */
.fg-campo.grande input:disabled,.fg-campo.grande select:disabled{
  background:color-mix(in srgb,var(--muted) 45%,transparent);color:var(--foreground);
  opacity:1;cursor:default}
/* a face de Configurações: o rodapé de Cancelar/Salvar só existe em edição, e sangra
   como o `.gav-pe` da gaveta (fio em cima, recuo 16, ações à direita) */
.cfg-pe{display:flex;align-items:center;justify-content:flex-end;gap:8px;flex:none;
  padding:12px 16px;border-top:1px solid var(--border);
  background:color-mix(in srgb,var(--muted) 50%,transparent)}
.cfg-pe[hidden]{display:none}
.cfg-corpo{flex:1;min-height:0;overflow-y:auto;padding:16px;display:flex;
  flex-direction:column;gap:16px;scrollbar-width:thin}
/* o carregando da lista: o esqueleto do `z-skeleton` (chão `muted`, raio md, pulso)
   na altura da célula — é o que o `data-table` do produto desenha em `loading` */
.esq{display:block;height:16px;width:100%;border-radius:var(--r-md);background:var(--muted);
  animation:esqpulsa 1.6s ease-in-out infinite}
@keyframes esqpulsa{0%,100%{opacity:1}50%{opacity:.5}}
@media (prefers-reduced-motion:reduce){.esq{animation:none}}
/* o estado de erro da lista, no formato do estado vazio do DS (`empty.variants.ts`):
   o mesmo bloco que o dashboard usa (`.bloco-erro`), dentro da caixa da tabela */
.tab .bloco-erro{min-height:260px;margin:0;border-bottom:1px solid var(--border)}
/* o vazio da lista no formato do estado vazio do DS: ladrilho 40 em `muted` com glifo 20,
   título 18/28/500, descrição 14 apagada, ação centrada — medido no `empty.variants.ts`
   pela frente de Nobreaks em 21/09 */
.vazio-ds{grid-column:1/-1;display:flex;flex-direction:column;align-items:center;
  justify-content:center;gap:8px;padding:48px 24px;text-align:center;text-wrap:balance;
  border-bottom:1px solid var(--border)}
.vazio-ds .ico{width:40px;height:40px;margin-bottom:8px;border-radius:var(--r-lg);
  background:var(--muted);color:var(--foreground);display:flex;align-items:center;
  justify-content:center}
.vazio-ds .ico svg{width:20px;height:20px}
.vazio-ds b{font-size:var(--text-lg,18px);line-height:28px;font-weight:500;
  letter-spacing:-.025em;color:var(--foreground)}
.vazio-ds span{font-size:var(--text-sm);line-height:1.625;color:var(--muted-foreground);
  max-width:24rem}
.vazio-ds .acoes{margin-top:16px;display:flex;gap:8px;justify-content:center}
/* ---- o dashboard: a tabela dentro do cartão ----
   a grade do log dentro do cartão, sem a segunda moldura (o cartão já é a moldura —
   mesma razão do `.hm__chart-wrapper .tela`) */
.card .logt{min-width:0}
.card .logrol{max-height:230px;overflow:auto;scrollbar-width:thin}
/* o gráfico de barras por hora do dashboard e da aba Estado: uma coluna por hora, na
   altura de token do gráfico de linha (`--sp-28`, 112) mais os rótulos (16) */
.horas{display:grid;grid-template-columns:repeat(24,minmax(0,1fr));gap:2px;
  height:var(--sp-28);align-items:end}
.horas i{display:block;border-radius:2px 2px 0 0;background:var(--primary);min-height:1px}
.horas i.zero{background:var(--muted)}
.horas-rot{display:grid;grid-template-columns:repeat(24,minmax(0,1fr));gap:2px;
  margin-top:4px;font-size:var(--text-2xs,11px);line-height:16px;color:var(--muted-foreground)}
.horas-rot span{text-align:center;overflow:hidden;visibility:hidden}
.horas-rot span:nth-child(6n+1){visibility:visible}
/* a linha de disponibilidade: o SVG desenha no `.tela` do padrão de saúde */
.tela-linha{position:relative;height:var(--sp-28);margin:var(--sp-2) 0}
.tela-linha svg{position:absolute;inset:0;width:100%;height:100%}
/* uma cor de série só, a do primário; o eixo e as guias no fio da casa */
.tela-linha .guia{stroke:var(--border);stroke-width:1}
.tela-linha .traco{stroke:var(--primary);stroke-width:2;fill:none}
.tela-linha .area{fill:color-mix(in srgb,var(--primary) 10%,transparent)}

/* os tokens que a folha do dashboard declara no proprio :root e a base nao tem — os
   mesmos valores, lidos em `nobreaks-dashboard.html` (linhas 356-357 e 454) */
:root{--accent:var(--secondary,#F5F5F5); --accent-fg:var(--secondary-foreground,#171717);
  --text-2xs:11px; --text-base:16px; --text-lg:18px; --text-2xl:24px}
:root[data-modo="escuro"]{--accent:var(--sec-hover,#374151); --accent-fg:var(--sec-txt,#FAFAFA)}
.ev .pt2{width:7px;height:7px;border-radius:9999px;margin-top:5px;flex:none;background:var(--ec)}
.ev .t1{font-size:var(--text-xs);line-height:var(--lh-xs);color:var(--foreground)}
.ev .t2{font-size:11px;line-height:15px;color:var(--muted-foreground);
  font-variant-numeric:tabular-nums}
/* MEDIDO em 28/09 no dashboard de Gateways: numa fileira `.duas` de 1fr 1fr os dois cartões
   saíam com 544 e 634 — o item de grade tem `min-width:auto`, e a tabela de dentro (colunas
   fixas, `min-width:max-content` no `.logt`) empurrava a coluna. O cartão cede e a tabela
   rola por dentro, que é o que o `.logrol` existe para fazer. */
.duas>.card,.tres>.card,.duas-graf>.card{min-width:0}

/* ===== GATEWAY · o assistente, na anatomia do `nobreaks-novo.html` (28/09) ==========
   ⬅️ Dela, 28/09: "use nobreak como referência, principalmente ao adicionar e editar".
   As regras abaixo são as do <style> do `nobreaks-novo.html` (que as mediu no
   `controller-creation-panel` e no `discovery-step` da produção, com as correções dela
   de 23 e 24/09), copiadas com UMA diferença: o que lá era da página inteira (`.fpop`
   a 240, `.conta`) aqui leva a classe `.desc` do assistente, porque esta folha também
   veste a lista, cujo popover de filtros mede 285 e não pode mudar. */
/* o cartão de busca: `align-items:flex-start` e o botão nascendo na linha do campo
   (rótulo 12 + calha 6 = 18) */
/* `.campo-chave`, e nao `.chave`: `.chave` ja existe na folha do Nobreaks (medido em 28/09 — o campo saiu centrado e 12px abaixo do vizinho). Nome generico em folha compartilhada ja tem dono. */
/* "botão primary está fora do padrão" — dela, 23/09: `z-button default` = h-9 (36),
   px-4 (16), text-sm; vale para o Buscar e para o Continuar do rodapé */
/* 01/10: o seletor só pegava o `.btn2`, e o primário do rodapé saía em 32/12 ao lado do Cancelar em 36/14 */
.gav-pe .btn2,.gav-pe .btn-pri{height:36px;padding:0 16px;font-size:var(--text-sm)}
.btn-pri:disabled{opacity:.5;cursor:default}
/* a barra de ferramentas do `discovery-step__toolbar`: space-between, gap 12, quebra;
   o campo nunca fica mais estreito que o placeholder inteiro (min 384) */
.ferramentas{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}
.ferramentas .fg-campo{flex:1 1 auto;min-width:384px}
.ferramentas-fim{display:flex;align-items:center;gap:12px;flex:0 0 auto}
.ferramentas .conta-desc{font-size:var(--text-xs);line-height:var(--lh-xs);color:var(--muted-foreground);
  white-space:nowrap;flex:none}
.ferramentas .icobtn{flex:none;position:relative}
/* o popover do passo, medido no `discovery-step__filter-popover`: 240, raio md, título 14
   semibold, corpo com gap 12 e recuo 8/16/12, rodapé sem fio; vive ACIMA da gaveta (91) */
.fpop.desc{z-index:120;width:240px;border-radius:var(--r-md)}
.fpop.desc .fpop-cab{padding:12px 16px 8px}
.fpop.desc .fpop-cab h3{font-weight:600}
.fpop.desc .fpop-corpo{gap:12px;padding:8px 16px 12px}
.fpop.desc .fg{gap:6px;padding:0}
.fpop.desc .fg-rot{font-size:var(--text-sm);line-height:var(--lh-sm);font-weight:400;color:var(--foreground)}
.fpop.desc .fpop-pe{height:auto;padding:8px 16px 12px;border-top:0}
.fpop.desc .fg select{width:100%;height:32px;padding:0 10px;border:1px solid var(--input);
  border-radius:var(--r-md);background:var(--ctl-bg);color:var(--foreground);font:inherit;font-size:var(--text-sm)}
/* o corpo respira depois da divisória do stepper */
.gaveta .gav-corpo{padding-top:16px}
/* a tabela de achados É A DA LISTA (`.tab`, `.hd`, `.cl`, `.n1`, `.n2`, `.um`): aqui só o
   número de colunas e o estado de seleção. O nome é `medium` na produção (`cell-name`). */
.grade-tab{display:grid;grid-template-columns:44px minmax(0,2.1fr) minmax(0,1.3fr) minmax(0,1fr)}
.grade-tab .cl .n1{font-weight:500}
.grade-tab .lin:last-child .cl{border-bottom:0}
.grade-tab .lin:hover .cl{background:var(--muted);cursor:pointer}
.grade-tab .lin.sel .cl{background:color-mix(in srgb,var(--primary) 6%,var(--card))}
/* "check fora do padrão" — dela, 23/09: o `checkbox.variants.ts` do produto — 16, borda
   `--input`, raio 4, shadow-sm; marcado `bg-primary` com o glifo `status.check` de 12 */
.grade-tab input[type=checkbox]{appearance:none;-webkit-appearance:none;width:16px;height:16px;
  margin:0;border:1px solid var(--input);border-radius:4px;background:var(--card);
  box-shadow:0 1px 2px 0 rgb(0 0 0 / .05);cursor:pointer;flex:none;position:relative;
  transition:background var(--motion-fast),border-color var(--motion-fast),box-shadow var(--motion-fast)}
.grade-tab input[type=checkbox]:hover{box-shadow:0 4px 6px -1px rgb(0 0 0 / .1),0 2px 4px -2px rgb(0 0 0 / .1)}
.grade-tab input[type=checkbox]:checked{background:var(--primary);border-color:var(--primary)}
.grade-tab input[type=checkbox]:checked::after{content:"";position:absolute;inset:0;
  background:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23FAFAFA' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><path d='M4.5 12.5l5 5 10-11'/></svg>") center/12px 12px no-repeat}
.grade-tab input[type=checkbox]:focus-visible{outline:none;box-shadow:0 0 0 4px color-mix(in srgb,var(--primary) 50%,transparent)}
/* o vazio do `discovery-step__empty`: ficha 48, raio lg, primária a 10 %, glifo 20; texto
   14 apagado com `pre-line` (a mensagem inicial quebra em duas linhas de propósito) */
.grade-tab .vazio{display:flex;flex-direction:column;align-items:center;gap:8px;width:100%;
  padding:24px 16px;text-align:center;grid-column:1/-1}
.grade-tab .vazio .vazio-ficha{display:inline-flex;align-items:center;justify-content:center;
  width:48px;height:48px;margin-bottom:8px;border-radius:var(--r-lg);
  background:color-mix(in srgb,var(--primary) 10%,var(--background));color:var(--primary)}
.grade-tab .vazio .vazio-ficha svg{width:20px;height:20px}
/* dela, 01/10: "tem espaço para colocar tudo numa linha" — a frase do vazio (56 caracteres) cabe inteira em 520 */
.grade-tab .vazio p{margin:0;max-width:520px;font-size:var(--text-sm);line-height:var(--lh-sm);
  color:var(--muted-foreground);white-space:pre-line}
/* o resumo do último passo: rótulo apagado à esquerda, valor a 600 à direita ("12px
   regular" + "semibold", dela, 23/09) */
.resumo{display:flex;flex-direction:column;gap:8px}
.resumo .linha{display:flex;justify-content:space-between;gap:16px;font-size:var(--text-xs);line-height:var(--lh-xs)}
.resumo .linha>span{color:var(--muted-foreground)}
.resumo .linha>b{font-weight:600;color:var(--foreground);text-align:right}
/* o botão de voltar no stepper é uma SETA (`action.arrow-left`), não o chevron do separador */
.passos>.btn-ghost-icone{flex:0 0 auto;margin-right:4px}
.pastilha{display:inline-flex;align-items:center;gap:4px;padding:4px 0;border:0;
  background:transparent;color:var(--muted-foreground);white-space:nowrap;font:inherit}
button.pastilha{cursor:pointer}
button.pastilha:hover{color:var(--foreground)}
/* ⬅️ "a linha da tab vai até o final, ela não é blocada" — dela, 28/09, riscando as duas
   pontas da régua das abas da interna. A folha do Nobreaks dá à barra a MESMA margem de 24
   da migalha e do cabeçalho, e a régua parava 24 antes de cada borda. No produto é o
   contrário: o `module-page.css` diz que "the hero rule has to reach both edges the way
   the tab bar above it does, while the text inside stays aligned with the content below"
   — o recuo é da faixa (padding), não da régua (margem). Medido depois: régua de 0 à
   largura da janela; primeira aba a 24. */
.shell > .ptabs{margin-left:0;margin-right:0;padding-left:24px;padding-right:24px}
/* ⬅️ "linha dupla, apague uma" — dela, 28/09, na lista. MEDIDO: a célula de Firmware termina em
   1440 com fio à direita e a coluna de ações começa em 1440 com fio à esquerda (o `.fix` leva o
   fio do lado por onde o conteúdo passa por baixo). Dois fios de 1 encostados. O da vizinha sai;
   o do `.fix` fica, porque é o que se vê quando a grade rola por baixo dele. */
.grade .hd:has(+ .hd.fix),.grade .cl:has(+ .cl.fix){border-right:0}
/* ⬅️ "segue o modelo de cards de analítico, tudo na mesma linha distribuídos por igual" — dela,
   28/09, sobre os cartões da aba Estado. MEDIDO no `incident-indicator-strip.component.css` do
   Analítico: `grid-template-columns: repeat(5, 1fr)`, vão `spacing-3` (12); abaixo de 63.998rem,
   dois por linha. Aqui o número de cartões varia com a dependência D1 (6 ou 1), então a contagem
   vem do JS em `--n`; o resto é a régua do Analítico. */
.hm__cards.linha-unica{grid-template-columns:repeat(var(--n,6),minmax(0,1fr));gap:12px}
@media (max-width:63.998rem){.hm__cards.linha-unica{grid-template-columns:repeat(2,minmax(0,1fr))}}

/* ===== GATEWAY · o log de eventos no padrão do log da câmera (28/09) =============
   Medido em `camera-event-log-tab.component.css` e `libs/ui-styles/tokens/colors.css`
   do `attlas-2026` (o dev.v2 pede login; o código é a régua). */
:root{
 /* os dois tons que a badge de severidade usa e a folha do Nobreaks não tinha:
    `--warning` = amber-500, `--info` = blue-500 (`colors.css:162-168`) */
 --warning:#F59E0B; --info:#3B82F6;
}
:root[data-modo="escuro"]{ --warning:#FBBF24; --info:#60A5FA }   /* amber-400 · blue-400 (`colors.css:1125-1131`) */
/* a badge: recuo 0/8, raio sm (6), 12 medium; crítico = destrutivo a 12 %, atenção = warning
   a 16 %, informativo = info a 12 % — "a mesma linguagem visual da tela de Eventos" */
.sev-log{display:inline-flex;align-items:center;padding:0 8px;border-radius:var(--r-sm);
  font-size:var(--text-xs);line-height:var(--lh-xs);font-weight:500;white-space:nowrap}
.sev-log--critical{background:color-mix(in srgb,var(--status-instavel) 12%,transparent);color:var(--status-instavel)}
.sev-log--warning{background:color-mix(in srgb,var(--warning) 16%,transparent);color:var(--warning)}
.sev-log--info{background:color-mix(in srgb,var(--info) 12%,transparent);color:var(--info)}
/* a categoria: glifo do catálogo + rótulo, vão 8 */
.cat-log{display:inline-flex;align-items:center;gap:8px;color:var(--foreground);white-space:nowrap}
.cat-log svg{width:14px;height:14px;flex:none;color:var(--muted-foreground)}
/* a busca do log é o `z-input-group sm` de 288 (`container-2xs`); o × só existe com texto */
.busca-log{width:288px;max-width:100%}
.busca-log .btn-ghost-icone{width:24px;height:24px;margin-right:-4px}
.busca-log .btn-ghost-icone[hidden]{display:none}
.busca-log .btn-ghost-icone svg{width:14px;height:14px}
/* o popover do log: 256 (`container-3xs`), recuo 16, vão 12, raio md, título 14/500, rótulo
   12/500 apagado, seletor `sm` de 32, rodapé à direita sem fio */
.fpop.log{width:256px;border-radius:var(--r-md)}
.fpop.log .fpop-cab{padding:16px 16px 0}
.fpop.log .fpop-cab h3{font-weight:500}
.fpop.log .fpop-corpo{gap:12px;padding:12px 16px 0}
.fpop.log .fg{gap:8px;padding:0}
.fpop.log .fpop-pe{height:auto;padding:8px 16px 16px;border-top:0}
/* a coluna `#` da tabela, o `showIndex` do `app-data-table` */
.logt .th.num{justify-content:center;color:var(--muted-foreground)}

/* ===== GATEWAY · o cabeçalho da interna de dispositivo (28/09) ==================
   ⬅️ Dela: "página interna segue o mesmo formato de todas as páginas internas de dispositivos,
   incluindo interna de cada câmera e analítico". MEDIDO em `camera-detail-header.component.css`
   (o `detail-page-header` do Analítico tem a mesma anatomia): cabeçalho com 16 em cima e embaixo;
   ladrilho 40 (`w-10`) raio lg na primária a 10 %; vão 12 até o texto; coluna de texto com vão 4;
   linha do nome com vão 12 e o grupo ponto+nome com vão 8; ponto de 8 (`w-2`); nome `text-xl`
   semibold, entrelinha 1, sem quebra; régua 1×16; badges com vão 8; metadados 12 apagado com vão 8 e
   filetes de 1×12; ações com vão 12. ⚠️ ISTO SUBSTITUI o `.pagehdr`/`.pg-*` da interna de Nobreaks
   (que vinha do `plano-detalhes`, com ladrilho 38, nome 21 e chips de valor em preto): a régua das
   internas de dispositivo é a da câmera, e a de Nobreaks é de outro dono. */
.dh{padding:16px 0;margin:0 24px;flex:none}
.dh-main{display:flex;align-items:flex-start;gap:12px;justify-content:space-between}
.dh-tile{display:flex;align-items:center;justify-content:center;width:40px;height:40px;flex-shrink:0;
  border-radius:var(--r-lg);background:color-mix(in srgb,var(--primary) 10%,transparent);color:var(--primary)}
.dh-tile svg{width:16px;height:16px}
.dh-info{display:flex;flex-direction:column;gap:4px;min-width:0;flex:1}
.dh-linha{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.dh-grupo{display:flex;align-items:center;gap:8px;min-width:0}
.dh-dot{width:8px;height:8px;border-radius:9999px;flex-shrink:0;background:var(--muted-foreground)}
.dh-dot--online{background:var(--status-estavel)}
.dh-dot--offline{background:var(--status-desconectado)}
.dh-nome{margin:0;font-size:var(--text-xl);font-weight:600;color:var(--foreground);line-height:1;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.dh-regua{display:block;width:1px;height:16px;background:var(--border);flex-shrink:0}
.dh-badges{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
.dh-meta{display:flex;align-items:center;gap:8px;margin:0;flex-wrap:wrap}
.dh-meta-item{display:flex;align-items:center;gap:4px;font-size:var(--text-xs);line-height:var(--lh-xs)}
.dh-meta-item dt,.dh-meta-item dd{margin:0;font-weight:400;color:var(--muted-foreground)}
.dh-meta-item dd .lk{color:var(--acc-txt,#1D4ED8)}
.dh-meta-sep{width:1px;height:12px;background:var(--border);flex-shrink:0}
.dh-acoes{display:flex;align-items:center;gap:12px;flex-shrink:0}
/* o Editar é o `z-button outline sm`: h-7 (28), px-2.5 (10), 12,8px, glifo 14 */
.dh-editar{height:28px;padding:0 10px;font-size:.8rem;gap:4px}
/* a trilha do `detail-page-header`: 12 apagado, vão 6, chevron na cor do fio, o atual em foreground */
.dh-trilha{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin:0 24px;flex:none;
  font-size:var(--text-xs);line-height:var(--lh-xs);color:var(--muted-foreground)}
.dh-crumb{color:inherit;text-decoration:none}
.dh-crumb:hover,.dh-crumb:focus-visible{color:var(--foreground);text-decoration:underline}
.dh-crumb--on{color:var(--foreground)}
.dh-sep{display:inline-flex;color:var(--border)}
.dh-sep svg{width:14px;height:14px}
/* ⬅️ "seta da cor errada" — dela, 29/09, no ⇅ da coluna ordenada. A folha do Nobreaks pinta o
   glifo da coluna ativa na primária; o `sortable-header.css` do produto não tem cor nenhuma no
   `.sort-icon` (herda o texto do cabeçalho) — o que muda entre ativo e inativo é a OPACIDADE:
   `.sort-icon-idle{opacity:.35}`, `.7` no hover, e o ativo cheio. */
.hd .oi{color:var(--foreground);opacity:.35}
.hd.ord:hover .oi{color:var(--foreground);opacity:.7}
.hd[data-dir] .oi{color:var(--foreground);opacity:1}

/* ===== GATEWAY · a tabela da lista É a `app-data-table` da lista de câmeras (29/09) ==========
   ⬅️ Dela: "formato de tabela e design seguir câmera, inclusive formato de data e hora", e
   "use github para ajustar design system". MEDIDO em `core/shared/components/data-table/
   data-table.css`, `libs/ui-shared/components/table/table.variants.ts` (o `z-table`:
   th h-10 px-2 semibold, td p-2, hover `bg-muted/50`, selecionada `bg-muted`),
   `sortable-header.css`, `pagination.css`, `cameras-table.component.css` e nos tokens
   (`--radius-md` 8, `--height-h-10` 40, `--width-w-96` 384, `--text-2xs` 11).
   ⚠️ ISTO SUBSTITUI a grade `.grade/.hd/.cl` da lista de Nobreaks nesta tela (a grade continua
   na folha porque o assistente `Novo Gateway` usa a `.grade-tab` dela). A divergência que o
   André registrou ("a caixa termina nos dados") NÃO vale aqui: a câmera é `flex:1 1 auto`, a
   caixa enche a área e o rodapé fica preso embaixo. */
:root{--custom-muted-dark-input-50:var(--muted);--custom-background-dark-input-30:var(--background)}
:root[data-modo="escuro"]{--custom-muted-dark-input-50:#ffffff13;--custom-background-dark-input-30:#ffffff0b}
.data-table{display:flex;flex:1 1 auto;flex-direction:column;max-height:100%;min-height:0;min-width:0;width:100%;
  border:1px solid var(--border);border-radius:var(--r-md);background:transparent;overflow:hidden}
.data-table__scroll{flex:1 1 auto;min-height:0;min-width:0;overflow:auto;scrollbar-width:thin;
  scrollbar-color:color-mix(in srgb,var(--muted-foreground) 50%,transparent) transparent}
.data-table__table{width:100%;min-width:0;table-layout:auto;border-collapse:separate;border-spacing:0;font-size:var(--text-xs)}
.data-table__head{position:sticky;top:0;z-index:1;background:var(--background)}
/* z-table: `[&_th]:h-10 px-2 text-left align-middle font-semibold text-foreground` + o filete de baixo e da direita */
.data-table__th{position:sticky;top:0;height:40px;padding:0 8px;text-align:left;vertical-align:middle;font-weight:600;
  color:var(--foreground);background:var(--background);border-bottom:1px solid var(--border);border-right:1px solid var(--border);
  white-space:nowrap;overflow:hidden}
.data-table__th-label{display:inline-block;min-width:0;overflow:hidden;text-overflow:ellipsis}
/* z-table: `[&_td]:p-2 align-middle`; o data-table: 40 de altura, nowrap, reticências */
.data-table__td{height:40px;padding:8px;color:var(--foreground);vertical-align:middle;
  border-bottom:1px solid var(--border);border-right:1px solid var(--border);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.data-table__th:last-child,.data-table__td:last-child{border-right:none}
/* a coluna `#`: encolhe ao conteúdo (width 1% + nowrap), centrada, apagada, dígitos tabulares; o filete
   da direita é dela mesmo (não desliga com as gridlines) */
.data-table__th--index,.data-table__td--index{width:1%;white-space:nowrap;text-align:center;border-right:1px solid var(--border)}
.data-table__td--index{color:var(--muted-foreground);font-variant-numeric:tabular-nums}
.data-table__th--fit,.data-table__td--fit{width:1%;white-space:nowrap}
.data-table__th--end,.data-table__td--end{text-align:right}
.data-table__th--numeric,.data-table__td--numeric{font-variant-numeric:tabular-nums}
/* colunas de texto livre: teto de 384 (`--width-w-96`) para o nowrap não esticar a tabela */
.data-table__th--text,.data-table__td--text{max-width:384px}
.data-table__td--mono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:var(--text-xs);letter-spacing:-.01em}
.data-table__td--muted{color:var(--muted-foreground)}
/* a célula composta: nome + meta apagado em 11 (`--text-2xs`) separados por ·, vão 2, padding vertical 4 */
.data-table__td--composite{text-align:left;padding-top:4px;padding-bottom:4px}
.data-table__composite{display:flex;flex-direction:column;justify-content:center;gap:2px;min-width:0;overflow:hidden}
.data-table__composite-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%}
.data-table__composite-meta{display:inline-flex;align-items:center;gap:6px;min-width:0}
.data-table__composite-meta-part,.data-table__composite-meta-sep{color:var(--muted-foreground);font-size:11px;line-height:1}
.data-table__composite-meta-part.mono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;letter-spacing:-.01em}
/* o cabeçalho ordenável: cursor, sem seleção, chão `--custom-muted-dark-input-50` no hover, anel no foco */
.data-table__th:has(.sortable-header){cursor:pointer;user-select:none}
.data-table__th:has(.sortable-header):hover{background:var(--custom-muted-dark-input-50)}
.data-table__th:has(.sortable-header):focus-within{outline:2px solid var(--anel);outline-offset:-2px}
.sortable-header{display:flex;align-items:center;justify-content:space-between;gap:16px;cursor:pointer;user-select:none;white-space:nowrap;outline:none}
.sortable-header.cell-end{flex-direction:row-reverse}
.sortable-label{color:inherit;font:inherit;overflow:hidden;text-overflow:ellipsis}
.sortable-unit{margin-inline-start:4px;color:var(--muted-foreground);font-weight:400}
/* o glifo: `text-sm` (14), sem cor própria — herda o texto; o que muda é a opacidade */
.sort-icon{display:inline-flex;align-items:center;font-size:var(--text-sm);line-height:1}
.sort-icon svg{width:14px;height:14px;display:block}
.sort-icon-idle{display:inline-flex;opacity:.35}
.sortable-header:hover .sort-icon-idle{opacity:.7}
/* as linhas: hover `bg-muted/50`, selecionada `bg-muted`; a ativa (painel aberto) leva a lavagem
   `muted` a 60 % em cada célula e o filete de 2 na primária na borda esquerda da primeira */
.data-table__row--clickable{cursor:pointer}
.data-table__row--data:hover>td{background:color-mix(in srgb,var(--muted) 50%,transparent)}
/* ⬅️ dela, 29/09: "a cor aqui é aquele azul clarinho do Table Hover. Na seleção." É o token
   `--base-table-select` do tema (`theme.css`: slate-100 no claro, slate-800 no escuro), "o chão de
   seleção da própria listagem" que o `incidents-queue` pinta na linha cujo cartão lateral está aberto —
   e que o ponteiro não repinta (`--on:hover` mantém). O `bg-muted` do z-table fica para a seleção por
   checkbox. */
:root{--base-table-select:#F1F5F9}
:root[data-modo="escuro"]{--base-table-select:#1E293B}
.data-table__row--data[data-state="selected"]>td,.data-table__row--data[data-state="selected"]:hover>td{background:var(--base-table-select)}
/* ⬅️ dela, 29/09, sobre o filete azul e a lavagem a 60 %: "isso aqui não existe na linha
   selecionada e a cor da linha selecionada também é outra cor". A lavagem + filete são o
   `.data-table__row--active` da UF-005 (Prioridade Seletiva, 01/09) e não é o que a lista de
   câmeras mostra: a linha com o painel aberto é `data-state=selected`, e o `z-table` pinta
   `data-[state=selected]:bg-muted` (`table.variants.ts`, igual desde 31/07). Só isso. */
.data-table__row--data:focus-visible{outline:2px solid var(--anel);outline-offset:-2px}
/* o kebab da linha é o `z-button ghost icon-sm`: 28, raio md, chão `muted` no hover — o `.kb` já é isso */
/* o estado (vazio/erro) ocupa a caixa: `.data-table__state` centrado com 24 de respiro */
.data-table__state{display:flex;flex:1 1 auto;align-items:center;justify-content:center;padding:24px}
.data-table__state .vazio-ds{border:0;min-height:0}
/* o rodapé: preso embaixo, chão `muted`, raio de baixo o da caixa; a `pagination-bar` tem 12 de
   padding (não 16), info 12 apagado à esquerda, controles com vão 32 à direita */
.data-table__footer{position:sticky;bottom:0;z-index:1;flex-shrink:0;background:var(--muted)}
.pagination-bar{display:flex;align-items:center;justify-content:space-between;padding:12px;flex-shrink:0;
  border-radius:0 0 var(--r-md) var(--r-md);background:var(--muted)}
.pagination-info{color:var(--muted-foreground);font-size:var(--text-xs);line-height:var(--lh-xs)}
.pagination-controls{display:flex;align-items:center;gap:32px}
.pagination-controls-buttons{display:flex;align-items:center;gap:8px}
.pagination-label{font-size:var(--text-xs);line-height:var(--lh-xs);color:var(--foreground)}
.pagination-select-wrapper{display:flex;align-items:center;gap:8px}
/* ⬅️ dela, 29/09: "não era para tirar o input de linhas por página, era para manter" — e antes,
   circulando-o: "acabei de falar do input". O que estava fora do padrão era a PEÇA (um <select>
   nativo, com a lista do sistema operacional). Aqui é o `z-select sm` de `pagination.html`,
   MEDIDO em `select.variants.ts` e `select.component.ts`:
   gatilho `flex items-center justify-between gap-2 rounded-lg border border-input shadow-xs
   min-h-8 py-1 px-2 text-xs`, chão `--custom-background-dark-input-30` (`pagination.css`),
   mínimo 4.5rem, chevron `size-4 opacity-50`, anel `ring-[3px] ring-ring/50` aberto ou em foco;
   painel `rounded-md border bg-popover shadow-lg` com `p-1`; item sm `min-h-8 py-1 text-xs
   pl-2 pr-8 rounded-sm mb-0.5`, `hover/selected: bg-accent`, check `size-3.5 right-2`. Os tokens
   desta folha: popover = `--card`, accent = `--muted`, ring = `--anel`. */
.pagination-select{position:relative;display:inline-flex;min-width:4.5rem}
.pagination-select__trigger{display:flex;width:100%;align-items:center;justify-content:space-between;gap:8px;
  min-height:32px;padding:4px 8px;border:1px solid var(--input);border-radius:var(--r-lg);
  background:var(--custom-background-dark-input-30);color:var(--foreground);font:inherit;
  font-size:var(--text-xs);line-height:var(--lh-xs);cursor:pointer;box-shadow:0 1px 2px 0 rgb(0 0 0 / .05);
  transition:color .15s,box-shadow .15s}
.pagination-select__trigger:focus-visible,.pagination-select__trigger[aria-expanded="true"]{outline:none;
  border-color:var(--anel);box-shadow:0 0 0 3px color-mix(in srgb,var(--anel) 50%,transparent)}
.pagination-select__valor{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:left}
.pagination-select__chev{display:inline-flex;width:16px;height:16px;flex-shrink:0;opacity:.5}
.pagination-select__chev svg{width:16px;height:16px;display:block}
.pagination-select__panel{position:absolute;z-index:60;display:flex;flex-direction:column;max-height:384px;
  padding:4px;overflow:hidden;border:1px solid var(--border);border-radius:var(--r-md);
  background:var(--card);color:var(--foreground);box-shadow:0 10px 15px -3px rgb(0 0 0 / .1),0 4px 6px -4px rgb(0 0 0 / .1)}
:root[data-modo="escuro"] .pagination-select__panel{box-shadow:0 10px 15px -3px rgb(0 0 0 / .5),0 4px 6px -4px rgb(0 0 0 / .5)}
.pagination-select__item{position:relative;display:flex;align-items:center;gap:8px;min-height:32px;
  padding:4px 32px 4px 8px;margin-bottom:2px;border-radius:var(--r-sm);font-size:var(--text-xs);
  line-height:var(--lh-xs);white-space:nowrap;cursor:pointer;user-select:none;outline:none}
.pagination-select__item:last-child{margin-bottom:0}
.pagination-select__item:hover,.pagination-select__item:focus-visible,.pagination-select__item[aria-selected="true"]{background:var(--muted);color:var(--foreground)}
.pagination-select__check{position:absolute;right:8px;display:flex;width:14px;height:14px;align-items:center;justify-content:center}
.pagination-select__check svg{width:14px;height:14px}
/* os quatro botões são `z-button outline icon-xs`: 24, raio min(radius-md,10px) = 8, glifo 12, borda e chão
   `background`, `muted` no hover, 50 % desabilitado */
.pg-bt{width:24px;height:24px;display:grid;place-items:center;border:1px solid var(--border);border-radius:var(--r-md);
  background:var(--background);color:var(--foreground);cursor:pointer;padding:0;box-shadow:0 1px 2px 0 rgb(0 0 0 / .05)}
.pg-bt svg{width:12px;height:12px;display:block}
.pg-bt:hover:not([disabled]){background:var(--muted)}
.pg-bt[disabled]{opacity:.5;cursor:not-allowed}
.pg-bt:focus-visible{outline:none;border-color:var(--anel);box-shadow:0 0 0 3px color-mix(in srgb,var(--anel) 50%,transparent)}
/* a página em volta, medida em `cameras-list.page.css`: vão 16 entre título, barra e tabela; a
   descrição em `text-sm` apagado (a casca do Nobreaks tinha 24/10 e 12) */
.ph{gap:16px;margin-bottom:16px}
.ph-tit p{font-size:var(--text-sm);line-height:var(--lh-sm)}
/* o cabeçalho do painel NÃO tem o lápis do `cameras-side-detail` — dela, 29/09: "esse botão de editar não existe aqui"; editar fica no menu da linha e na interna */

/* a página em volta, medida no DOM em 29/09: a casca (barra + navegação) tem 103, não 96 — sem isto a
   `.pg` passava 7 do pé da janela; e a lista de câmeras tem 24 de respiro nos QUATRO lados
   (`cameras-list__main{padding:24}`), com a caixa da tabela terminando 24 antes do pé */
:root{--casca:103px}
.pg:has(.data-table){padding-bottom:24px}

/* ⬅️ dela, 29/09: "não tem essa rolagem aqui para uma coisa que tem 11 linhas […] usa a referência".
   A referência (UF-004 §5, item 5, e o que o André mediu no dev em 15/09) diz que a caixa da
   tabela é `flex:0 1 auto; max-height:100%`: TERMINA NA ÚLTIMA LINHA quando há poucas e só rola
   por dentro quando as linhas excedem a área. O `flex:1 1 auto` que eu tinha posto enchia a área
   e, com a barra horizontal comendo altura, sobrava uma rolagem vertical de poucos pixels. */
.data-table{flex:0 1 auto}

/* ⚠️ `display:flex` na classe vence o `hidden` do atributo: o estado vazio escondido continuava
   ocupando 48 (os 24 de padding) dentro da caixa, a caixa batia no teto e sobrava rolagem com
   dez linhas. O produto não tem o problema porque o Angular não renderiza o ramo; aqui o nó
   fica no DOM e precisa desta regra. */
.data-table__state[hidden]{display:none}

/* ⬅️ dela, 29/09: "ao abrir essa barra lateral de detalhes, contrai um pouquinho a tabela. Não tem
   necessidade de ter rolagem aqui. Se for necessário, coloca três pontinhos no final do texto".
   É o `layout='fixed'` do `data-table` (`data-table.css`): `table-layout:fixed`, as colunas com
   `width` declarado a mantêm e as demais dividem a sobra; e, como o modo fixo lê o `width:1%` do
   ordinal ao pé da letra, o `#` recebe a própria largura (`--width-w-10` = 40). O texto das
   colunas de texto corta com reticências pelo `overflow:hidden` da célula, e o `title` guarda o
   valor inteiro. */
.data-table__table--fixed{table-layout:fixed}
.data-table__table--fixed .data-table__th--index,.data-table__table--fixed .data-table__td--index{width:40px}

/* ===== GATEWAY · o painel lateral segue o cartão do gateway da Prioridade Seletiva (29/09) ==========
   Dela, com o print do `priority-antenna-card`: "Modelo, IP, Estado eu acho que é interessante", "este
   verde na badge", "coloque informações da instalação", "verifique no design system se os pesos dos
   textos dentro dessa sidebar estão do jeito que deveria". MEDIDO em
   `priority-detail-row.component.css` (rótulo `--text-2xs-half` 11.5 / 18 regular apagado; valor
   `--text-xs` 12 / 18 MEDIUM na cor do texto, reticências, à direita; `padding-block` 3),
   `priority-card-section.component.css` (título `--text-3xs` 10 / 15 semibold, `tracking-wide`
   .025em, caixa alta, apagado, 4 abaixo) e `badge.variants.ts` (`success xs`: h-5, px-1.5, 10.5 /
   18 medium, `rounded-md`, `--success` sobre `--success-foreground` — aqui `--status-estavel` e
   `--status-estavel-fundo`, os mesmos valores). ⚠️ O `cameras-side-detail` pesa ao contrário (dt 500
   apagado, dd 400): a régua escolhida aqui é a do cartão que ela mandou. */
#painel .pn-h{font-size:10px;line-height:15px;font-weight:600;letter-spacing:.025em;text-transform:uppercase;color:var(--muted-foreground)}
#painel .pn-h+.pn-pares{margin-top:-12px}
#painel .pn-pares.g8{gap:0}
#painel .pn-par{height:auto;padding:3px 0;gap:12px}
#painel .pn-par .k{font-size:11.5px;line-height:18px;font-weight:400;color:var(--muted-foreground)}
#painel .pn-par .v{font-size:var(--text-xs);line-height:18px;font-weight:500;color:var(--foreground);text-align:right}
#painel .pn-par .v .zero{font-weight:400}
/* a badge `.pn-estado` (saúde do cartão da Prioridade) SAIU com a linha Estado — dela, 29/09: "apaga esse estado daqui" */

/* ===== GATEWAY · o menu de colunas É o `cameras-column-visibility` (29/09) ==========================
   ⬅️ Dela: "dropdown está com ícones fora do padrão. Verifique padrão." MEDIDO em
   `cameras-column-visibility.component.{html,css}`: popover `w-40` (160) com raio lg e `p-1`; título
   12 / 16 medium apagado com padding 4 6 8; itens num bloco com `p-1` e vão 10 (`spacing-2-5`); cada
   item 28 de altura, 14 / 20 regular, padding 4 32 4 6, raio md, hover `accent` (= `muted` aqui), com
   o check `status.check` de 16 à direita (`right: 8`) NA COR DO TEXTO (`currentColor`), não na
   primária; desabilitado a 60 %. O gatilho é `action.columns` = FA `sliders` (três barras). */
.menu.colunas{width:160px;min-width:160px;padding:4px;border-radius:var(--r-lg)}
.menu.colunas .mlabel{display:flex;align-items:center;max-height:24px;padding:4px 6px 8px;
  font-size:var(--text-xs);line-height:var(--lh-xs);font-weight:500;color:var(--muted-foreground)}
.menu.colunas .itens{display:flex;flex-direction:column;gap:10px;padding:4px}
.menu.colunas button.col{position:relative;height:28px;padding:4px 32px 4px 6px;gap:6px;
  font-size:var(--text-sm);line-height:var(--lh-sm);border-radius:var(--r-md)}
.menu.colunas button.col .ck{position:absolute;right:8px;top:6px;width:16px;height:16px;color:currentColor}
.menu.colunas button.col .ck svg{width:16px;height:16px}
.menu.colunas button.col[aria-disabled="true"]{color:var(--foreground);opacity:.6;cursor:not-allowed}
.menu.colunas button.col[aria-disabled="true"] .ck{color:currentColor}
/* ⬅️ dela, 29/09, circulando a descrição quebrada em duas linhas: "tá vendo que aqui tem mais espaço
   para o texto?" — o teto de 720 na `.ph-tit` é da casca do Nobreaks (herdado de planos-lista); o
   `cameras-list__heading` (`cameras-list.page.css`) não tem largura máxima: o h1 e o p ocupam a linha. */
.ph-tit{max-width:none}
/* ⬅️ dela, 29/09, apontando o branco sob o painel: "essa barra de detalhes fica colada […] embaixo não
   tem esse padding todo, ele tem que ficar fixo colado ali" — dito em vários módulos. O respiro de 24
   que a página ganhou embaixo (para a caixa da tabela) NÃO é do painel: como na página de câmeras, o
   `cameras-list__side-detail` é irmão do miolo com padding e vai do alto da navegação ao pé da janela.
   A `.pg > .painel` já cancelava o alto e a direita; agora cancela o pé também. */
.pg:has(.data-table) > .painel{margin-bottom:-24px}

/* ===== GATEWAY · a aba Log de eventos do painel É a linha do tempo do `pmv-side-detail` (29/09) ==========
   ⬅️ Dela: "todos os logs de eventos devem seguir o de PMV" (`#/pmv/devices`). MEDIDO em
   `pmv-side-detail.component.css`: lista em coluna; item flex `stretch` com vão 8; trilho de 12 com toco
   1×6, PONTO NEUTRO de 8 (`muted-foreground` — "o Figma usa um só cinza, seja qual for a severidade") e fio
   de 1 `border`; corpo com vão 4 e 16 embaixo: data 12 light apagado, título 14 medium, origem 12 com o
   glifo apagado (vão 4), situação 12 apagado. Vazio: 14 apagado, centrado, 24 8 de padding. */
.pmv-side-detail__event-list{display:flex;flex-direction:column;margin:0;padding:0;list-style:none;width:282px}
.pmv-side-detail__event-item{display:flex;align-items:stretch;gap:8px}
.pmv-side-detail__event-rail{display:flex;flex:0 0 auto;flex-direction:column;align-items:center;width:12px}
.pmv-side-detail__event-rail-stub{width:1px;height:6px;background:var(--border)}
.pmv-side-detail__event-rail-line{flex:1 1 auto;width:1px;background:var(--border)}
.pmv-side-detail__event-dot{flex:0 0 auto;width:8px;height:8px;border-radius:9999px;background:var(--muted-foreground)}
.pmv-side-detail__event-body{display:flex;flex:1 1 auto;flex-direction:column;gap:4px;min-width:0;padding-bottom:16px}
.pmv-side-detail__event-datetime{font-size:var(--text-xs);line-height:var(--lh-xs);font-weight:300;color:var(--muted-foreground)}
.pmv-side-detail__event-title{font-size:var(--text-sm);line-height:var(--lh-sm);font-weight:500;color:var(--foreground)}
.pmv-side-detail__event-source{display:flex;align-items:center;gap:4px;font-size:var(--text-xs);line-height:var(--lh-xs);color:var(--foreground)}
.pmv-side-detail__event-source svg{width:12px;height:12px;color:var(--muted-foreground)}
.pmv-side-detail__event-situation{display:block;font-size:var(--text-xs);line-height:var(--lh-xs);color:var(--muted-foreground)}
.pmv-side-detail__empty-state{width:282px;margin:0;padding:24px 8px;font-size:var(--text-sm);line-height:var(--lh-sm);color:var(--muted-foreground);text-align:center}
/* ===== GATEWAY · a aba Estado da interna É a página interna de instância do Analítico (29/09) ==============
   ⬅️ Dela: "tudo dentro da aba Estado pode ir para a dashboard e no local de Estado vamos ter algo parecido
   com a página interna dos dispositivos" (`#/analytics/instances/:id`). MEDIDO em `instance-detail.page.css`:
   página em coluna com vão 16; bloco-cartão com 16 de recuo, borda, raio lg, chão `card`, vão 8; cabeça de
   painel com vão 10 — ladrilho 40 raio md na primária a 12 % com glifo de 16, título 14 semibold, dica 12
   apagada com vão 2; pares em colunas `auto-fit` de 192 com vão 16 × 20, rótulo 12 apagado SOBRE o valor 14
   medium (quebra em qualquer ponto); `mono` = só dígitos tabulares (o produto não troca a família). */
.instance-page{display:flex;flex-direction:column;gap:16px;min-width:0}
.instance-page__block{display:flex;flex-direction:column;gap:8px;min-width:0;padding:16px;border:1px solid var(--border);border-radius:var(--r-lg);background:var(--card)}
.instance-page__panel-head{display:flex;align-items:center;gap:10px;min-width:0}
.instance-page__panel-titles{display:flex;flex:1 1 auto;flex-direction:column;gap:2px;min-width:0}
.instance-page__tile{display:grid;place-items:center;flex:none;width:40px;height:40px;border-radius:var(--r-md);
  background:color-mix(in srgb,var(--primary) 12%,transparent);color:var(--primary)}
.instance-page__tile svg{width:16px;height:16px}
.instance-page__card-title{display:flex;align-items:center;gap:8px;margin:0;font-size:var(--text-sm);line-height:var(--lh-sm);font-weight:600;color:var(--foreground)}
.instance-page__card-hint{margin:0;font-size:var(--text-xs);line-height:var(--lh-xs);color:var(--muted-foreground)}
.instance-page__rows{margin:0}
.instance-page__rows--split{display:grid;grid-template-columns:repeat(auto-fit,minmax(192px,1fr));gap:16px 20px}
.instance-page__row{display:flex;flex-direction:column;align-items:flex-start;gap:2px;min-width:0}
.instance-page__rows dt{font-size:var(--text-xs);line-height:var(--lh-xs);color:var(--muted-foreground)}
.instance-page__rows dd{margin:0;min-width:0;font-size:var(--text-sm);line-height:var(--lh-sm);font-weight:500;color:var(--foreground);overflow-wrap:anywhere}
.instance-page__mono{font-variant-numeric:tabular-nums}
/* o mapa da instalação: a mesma caixa `gps-mapa` da gaveta, com altura própria dentro do bloco */
.instance-page__mapa{flex:none;height:240px;margin-top:8px}
.instance-page__mapa[hidden]{display:none}
/* ===== GATEWAY · dashboard § 3b · Leitura por gateway (29/09) ===== */
/* a seção com o seletor na mesma linha do título: o `z-select` à direita, alinhado ao pé do título */
.secao.secao--com-acao{flex-direction:row;align-items:flex-end;justify-content:space-between;gap:16px}
.secao.secao--com-acao>div{display:flex;flex-direction:column;min-width:0}
.sel-gw{min-width:240px}
.sel-gw .pagination-select__trigger{background:var(--card)}
.fileira-gw{margin-bottom:16px}

/* ⬅️ dela, 29/09: "considere o espaço para Servidor do TTN: duas colunas" — o endereço do servidor não cabe
   numa coluna de 192 e quebrava no meio; o par ocupa duas colunas da grade (e uma só quando a grade cabe uma) */
.instance-page__row--largo{grid-column:span 2}
@media (max-width:28rem){.instance-page__row--largo{grid-column:auto}}

/* ===== GATEWAY · o mini mapa do painel lateral (29/09) ==================================================
   ⬅️ Dela: "no painel lateral de detalhes faltou o mini mapa" (`#/pmv/devices`). MEDIDO em
   `pmv-side-detail.component.css`: bloco de localização em coluna com vão 12; linha do endereço
   `space-between` com vão 8, endereço 14 apagado com reticências, olho `ghost icon-sm` (28) no fim;
   mapa de largura toda, `--height-map-preview` = 180, borda `border`, raio md. */
.pn-local{display:flex;flex-direction:column;gap:12px;width:282px}
.pn-local__linha{display:flex;align-items:center;justify-content:space-between;gap:8px}
.pn-local__end{flex:1 1 auto;min-width:0;font-size:var(--text-sm);line-height:var(--lh-sm);color:var(--muted-foreground);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pn-local__olho{margin-left:auto;flex:none}
.pn-local__mapa{width:100%;height:180px;border:1px solid var(--border);border-radius:var(--r-md);overflow:hidden}

/* ===== GATEWAY · a aba Log de Eventos da interna É o `pmv-event-log-tab` (29/09) ============================
   ⬅️ Dela: "todos os logs de eventos devem seguir o de PMV". MEDIDO em `pmv-event-log-tab.component.css`:
   severidades `info` (`--info` a 12 %) · `warning` (`--warning` a 16 %) · `error` (`--destructive` a 12 %) ·
   `critical` (CHEIA: `--destructive` com o texto claro); situação em bloco — "Ativo" em `--warning` medium,
   "Resolvido" na cor do texto regular, com o instante embaixo em 12 apagado; usuário ausente "—" apagado.
   Os filtros do popover são `z-select sm` de largura toda (`filter-select`). */
.sev-log--error{background:color-mix(in srgb,var(--status-instavel) 12%,transparent);color:var(--status-instavel)}
.sev-log--critical{background:var(--status-instavel);color:#FFFFFF}
.sit-log{display:block;color:var(--warning);font-weight:500;white-space:nowrap}
.sit-log--resolvido{color:var(--foreground);font-weight:400}
.sit-log-em{display:block;color:var(--muted-foreground);font-size:var(--text-xs);white-space:nowrap}
.user-vazio{color:var(--muted-foreground)}
.fpop.log .fsel-z{display:flex;width:100%}
.fpop.log .fsel-z .pagination-select__trigger{background:var(--card)}

/* ===== GATEWAY · a dashboard pela régua das três de guia (29/09) =================================
   ⬅️ Dela: "dashboards de guia: alarms/dashboard, cameras/dashboard, pmv/dashboard". MEDIDO no
   `attlas-2026`: `dashboard-toolbar.component.css` (cartão com 16 de recuo, raio xl, `shadow-card`;
   título `text-xl` 20 semibold; descrição `text-sm` 14 apagada; controles com vão 12; filete 1×20),
   `period-picker.component.css` (gatilho `outline` com o valor e o chevron, `space-between`, mínimo
   `spacing-40` = 160), `pmv-dashboard.page.css` e `alarms dashboard.page.css` (título de seção
   `text-base` 16 semibold; blocos com vão 16), os cartões de widget do PMV e das câmeras
   (`pmv-dashboard-donut-card`, `pmv-dashboard-ranked-list`, `availability-trend-chart`: cartão com 16 de
   recuo, raio xl, vão 12; cabeça com vão 12; ladrilho 36 (`spacing-9`) raio md em `info` sobre
   `info-foreground`, ou aviso/perigo nos rankings; título 16 semibold; descrição 14 apagada) e a faixa
   de KPIs (`dashboard-kpi-strip`: vão 16). O chip de leitura é o `dashboard-live-chip`/`dash-live`.
   O que a casca do Nobreaks tinha diferente: título 18, descrição 12, seção 14, cartão com ladrilho 40
   na primária e título 14 medium, vãos de 28/12. */
.barra-painel__tit{gap:4px}
.barra-painel__tit>h1{font-size:var(--text-xl);line-height:var(--lh-xl,28px)}
.barra-painel__tit p{font-size:var(--text-sm);line-height:var(--lh-sm)}
.dash-live{display:inline-flex;align-items:center;gap:6px;font-size:var(--text-xs);line-height:var(--lh-xs);color:var(--muted-foreground);white-space:nowrap;flex:none}
.dash-live__dot{width:8px;height:8px;border-radius:9999px;background:var(--status-estavel);flex:none}
.dash-live--velho .dash-live__dot{background:var(--warning)}
.sel-periodo{justify-content:space-between;gap:8px;min-width:160px;padding:0 10px;border:1px solid var(--border);
  background:var(--background);color:var(--foreground);font-size:var(--text-sm);line-height:var(--lh-sm);font-weight:500;border-radius:var(--r-lg)}
.sel-periodo:hover,.sel-periodo[aria-expanded="true"]{background:var(--muted)}
.sel-periodo svg{color:var(--foreground);opacity:.5;width:16px;height:16px}
.period-picker__value{white-space:nowrap}
.secao{margin:0 0 16px;gap:2px}
.secao h2{font-size:var(--text-base,16px);line-height:24px}
.card-cab{gap:12px;margin-bottom:12px}
.cab-glifo{width:36px;height:36px;border-radius:var(--r-md);color:var(--info);background:color-mix(in srgb,var(--info) 10%,transparent)}
.cab-glifo[data-tom="aviso"]{color:var(--warning);background:color-mix(in srgb,var(--warning) 10%,transparent)}
.cab-glifo[data-tom="perigo"]{color:var(--status-instavel);background:color-mix(in srgb,var(--status-instavel) 10%,transparent)}
.card-cab h2{font-size:var(--text-base,16px);line-height:24px;font-weight:600}
.cab-desc{font-size:var(--text-sm);line-height:var(--lh-sm)}
.est-grade.mini{gap:16px}
/* o título de seção é semibold (600) nas três dashboards de guia; um h2 da casca pesava 700 */
.dash .secao h2{font-weight:600}
/* ⬅️ dela, 30/09, riscando a borda direita do painel: "tem que ter um padding aqui para o conteúdo respirar".
   A casca do Nobreaks fixava tudo em 282 dentro de um rolador com 4 de padding à direita: quando a barra de
   rolagem aparece (15), sobram 299 e o conteúdo de 16 + 282 passa POR BAIXO dela. O `cameras-side-detail`
   tem 16 de padding nos dois lados (`__content{padding:16}`) e o conteúdo é fluido. Aqui: 16 dos dois lados
   no rolador e larguras `auto`, esticadas pela coluna. */
#painel .pn-rol{padding:16px}
#painel .pn-in{align-items:stretch}
#painel .pn-cab,#painel .pn-abas,#painel .pn-reg,#painel .pn-h,#painel .pn-desc,#painel .pn-pares,#painel .pn-bt2,#painel .pn-gauge,#painel .pn-local,#painel .pmv-side-detail__event-list,#painel .pmv-side-detail__empty-state{width:auto;min-width:0}
/* dela, 01/10: "o título Detalhes está desalinhado" — o `.pn-top` já tem 16 de cada lado; somar mais 16 na fileira punha o
   título em 32 e o conteúdo em 16. Sem o segundo recuo, título e cruz alinham com o conteúdo e o Ver detalhes */
#painel .pn-top .dentro{width:100%;padding:0;box-sizing:border-box}

/* ⬅️ dela, 30/09, riscando a barra de rolagem dentro da área: "a rolagem é da página e não interna". A casca
   do Nobreaks prendia a página em `calc(100vh − casca)` e punha um rolador (`.rol`) por dentro; nas três
   dashboards de guia quem rola é a página do módulo, com a barra na borda da janela. Na dashboard a página
   passa a ter altura livre e o `.rol` deixa de rolar; a barra fixada gruda no topo da janela. */
body:has(#dash) .pg{height:auto;min-height:calc(100vh - var(--casca,103px))}
body:has(#dash) .rol{height:auto;overflow:visible}
body.cheia:has(#dash) .pg{height:auto;min-height:100vh}
/* …e a casca trava `html`, `body` e a `.pg` em `overflow:hidden` com altura fixa: sem soltar os três, a página
   nem tem como rolar (medido: documento com 606 de altura sobre 3418 de conteúdo). Só na dashboard. */
html:has(#dash),body:has(#dash){height:auto;min-height:100%;overflow:visible}
body:has(#dash) .pg{overflow:visible}
/* ⬅️ dela, 30/09, riscando a tabela do passo 1 do assistente: "aqui tem que ter rolagem". A `.tab` da lista é
   `overflow:hidden` e, dentro da gaveta, encolhia para caber (425 de altura para 3213 de conteúdo) sem rolar.
   Dentro da gaveta ela ocupa a altura que sobra e rola por dentro — o cabeçalho da grade já é `sticky`. */
/* ⬅️ dela, 01/10: "aqui na modal esse card vai até o final do conteúdo se não houver mais dados" — a caixa da tabela
   termina na última linha (ou no vazio) e só ocupa a altura que sobra quando há linhas demais, aí rola por dentro */
.gaveta .tab{flex:0 1 auto;min-height:0;overflow:auto}

/* ⬅️ dela, 30/09: "faltou protocolo na lista" — a grade do passo 1 ganha a coluna Protocolo do 25, entre o nome e a conexão */
/* tirada e devolvida em 01/10 — dela, 01/10: "sim, recoloca com a nota no doc" — Modelo, Protocolo e Firmware VOLTAM: o 25 não os guarda, mas o 26 consegue puxar quando o serviço de gateway existir (doc §3.11) */
.gaveta .grade-tab{grid-template-columns:44px minmax(0,2fr) minmax(0,.9fr) minmax(0,1.3fr) minmax(0,1fr)}
/* ⬅️ dela, 30/09, na aba Log de Eventos da interna: "rodapé fica colado na base, até onde é possível ter a altura
   da tabela". É o que o `pmv-event-log-tab` faz: `.pmv-event-log__table{flex:1 1 auto;min-height:0}` — a caixa da
   tabela enche a altura que sobra na aba e o rodapé de paginação, `sticky` no pé da caixa, fica na base. A caixa
   que termina nos dados (GTW-13) é a da LISTA, onde a caixa é a página; na aba, a caixa é o cartão. */
#c-log .data-table{flex:1 1 auto;min-height:0}

@keyframes cred-gira{to{transform:rotate(360deg)}}

/* medido: `.grupo-addon svg{color:muted-foreground}` (a regra do olho) pintava de cinza o disco do glifo
   do botão que mora no mesmo addon; dentro do `z-button` o glifo herda a cor do botão */
.grupo-addon .btn-xs svg{color:inherit}

/* ===== GATEWAY · o passo Localização do assistente = o passo Configurações da câmera (30/09) ==========
   ⬅️ Dela, com o print: "padrão de localização errado, falta inputs aqui, puxa de câmera o padrão".
   MEDIDO em `camera-creation-settings-step.component.css`: introdução 12/16 de recuo, chão primária a 6 % sobre
   `card`, borda primária a 18 % sobre `border`, raio xl, glifo 40 raio lg primária a 15 %, título 14 semibold
   (entrelinha 1.2), subtítulo 12 apagado; lista com vão 12; painel `card` + borda, raio xl, `shadow-xs`, borda
   primária a 30 % quando aberto; cabeçalho-botão 12/16 com vão 12, texto 14; chevron 20 apagado (primária
   quando aberto); título medium (primária semibold quando aberto); pílula 4/12 raio cheio `muted`, 12 medium;
   selo 4/8 raio cheio 12 medium (pendente = warning a 18 %; inválido = destructive a 18 %); conteúdo 16 com
   filete em cima e vão 16; seção com vão 12, título 14 semibold 1.2, subtítulo 12 apagado; grade de campos
   12/16; grade mapa|campos 1fr 1fr vão 16; mapa 187 com borda, raio lg, chão foreground a 3 %; coluna de campos
   com vão 12. `camera-topology-fields`: campo com vão 6, rótulo 14 medium, dica 12 apagada a toda a largura.
   `camera-intersection-picker`: painel `popover` com borda, raio md, sombra md, recuo 4, teto 240; item 6/10
   raio md com o check de 14 na primária, o chip do código 2/6 raio sm `muted` 12 medium e o nome 14; item
   escolhido em primary-foreground-status; hover/ativo em `accent`; dica 12/10 em 14 apagado; título do
   painel 6/10, 12 medium apagado, filete embaixo. `ui-map`: grupo de controles `secondary` raio lg sem sombra,
   botões 24. */
.loc-intro{display:flex;align-items:center;gap:12px;padding:12px 16px;border-radius:var(--r-xl,14px);
  background:color-mix(in srgb,var(--primary) 6%,var(--card));border:1px solid color-mix(in srgb,var(--primary) 18%,var(--border))}
.loc-intro-glifo{display:inline-flex;align-items:center;justify-content:center;width:40px;height:40px;flex:none;
  border-radius:var(--r-lg);background:color-mix(in srgb,var(--primary) 15%,transparent);color:var(--primary)}
.loc-intro-glifo svg{width:18px;height:18px}
.loc-intro-tx{display:flex;flex-direction:column;gap:4px;min-width:0}
.loc-intro-tx h2{margin:0;font-size:var(--text-sm);line-height:1.2;font-weight:600;color:var(--foreground)}
.loc-intro-tx p{margin:0;font-size:var(--text-xs);line-height:var(--lh-xs);color:var(--muted-foreground)}
.loc-lista{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:12px}
.loc-cartao{display:flex;flex-direction:column;background:var(--card);border:1px solid var(--border);
  border-radius:var(--r-xl,14px);box-shadow:0 1px 2px 0 rgb(0 0 0 / .05)}
.loc-cartao--aberto{border-color:color-mix(in srgb,var(--primary) 30%,var(--border))}
.loc-cab{appearance:none;background:transparent;border:0;width:100%;display:flex;align-items:center;gap:12px;
  padding:12px 16px;color:var(--foreground);font:inherit;font-size:var(--text-sm);line-height:var(--lh-sm);text-align:left;cursor:pointer;border-radius:inherit}
.loc-cab:focus-visible{outline:2px solid var(--anel);outline-offset:-2px}
.loc-chevron{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;color:var(--muted-foreground);flex:none}
.loc-chevron svg{width:14px;height:14px}
.loc-cartao--aberto .loc-chevron{color:var(--primary)}
.loc-tit{flex:1 1 auto;font-weight:500;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* ⬅️ dela, 30/09: "peso menor na tipografia aqui" — o título do painel aberto fica na primária, mas no mesmo
   medium (500) do fechado; o print da câmera mostra medium, a folha diz semibold: a tela é a régua */
.loc-tit--ativo{color:var(--primary);font-weight:500}
.loc-pill{flex:none;display:inline-flex;align-items:center;padding:4px 12px;border-radius:9999px;background:var(--muted);
  color:var(--muted-foreground);font-size:var(--text-xs);font-weight:500;line-height:1;font-variant-numeric:tabular-nums}
.loc-selo-cx{display:contents}
.loc-selo{flex:none;display:inline-flex;align-items:center;padding:4px 8px;border-radius:9999px;font-size:var(--text-xs);font-weight:500;line-height:1}
.loc-selo--pending{background:color-mix(in srgb,var(--warning) 18%,transparent);color:var(--warning)}
.loc-selo--invalid{background:color-mix(in srgb,var(--status-instavel) 18%,transparent);color:var(--status-instavel)}
.loc-cx{display:flex;flex-direction:column;gap:16px;padding:16px;border-top:1px solid var(--border)}
.loc-sec{display:flex;flex-direction:column;gap:12px}
.loc-sec-cab{display:flex;flex-direction:column;gap:4px}
.loc-sec-cab h3{margin:0;font-size:var(--text-sm);line-height:1.2;font-weight:600;color:var(--foreground)}
.loc-sec-cab p{margin:0;font-size:var(--text-xs);line-height:var(--lh-xs);color:var(--muted-foreground)}
.so-leitor{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
.loc-grade{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:16px;align-items:stretch}
.loc-cartao--mapa-grande .loc-grade{grid-template-columns:minmax(0,1fr)}
.loc-mapa{position:relative;display:block;width:100%;height:187px;min-height:187px;border:1px solid var(--border);
  border-radius:var(--r-lg);background:color-mix(in srgb,var(--foreground) 3%,var(--card));overflow:hidden}
.loc-cartao--mapa-grande .loc-mapa{height:360px}
.loc-mapa .maplibregl-ctrl-group{background:var(--secondary);border:0;border-radius:var(--r-lg);box-shadow:none;overflow:hidden}
.loc-mapa .maplibregl-ctrl-group button{width:24px;height:24px;background:transparent;border:0;display:flex;align-items:center;justify-content:center;color:var(--foreground)}
.loc-mapa .maplibregl-ctrl-group button:hover{background:var(--muted)}
.loc-mapa .maplibregl-ctrl-group button+button{border-top:0}
.loc-mapa .maplibregl-ctrl-expand svg{width:12px;height:12px}
.loc-mapa .maplibregl-ctrl-zoom-in .maplibregl-ctrl-icon,.loc-mapa .maplibregl-ctrl-zoom-out .maplibregl-ctrl-icon{display:none}
.loc-mapa .maplibregl-ctrl-zoom-in::before{content:'+';font-weight:700;font-size:13px;line-height:1}
.loc-mapa .maplibregl-ctrl-zoom-out::before{content:'\2212';font-weight:700;font-size:13px;line-height:1}
.loc-campos{display:flex;flex-direction:column;gap:12px;min-width:0}
.loc-par{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px 16px}
.loc-topo{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px 16px}
.loc-topo .fg-campo.grande{gap:6px}
.gaveta .loc-topo .fg-campo.grande>label{font-size:var(--text-sm);line-height:var(--lh-sm)}
.loc-dica{grid-column:1 / -1;margin:0;font-size:var(--text-xs);line-height:var(--lh-xs);color:var(--muted-foreground)}
.loc-dica[hidden]{display:none}
/* (o `.int-limpar` que morava aqui saiu em 01/10 — dela: "esse não é o X padrão, o input está com X desalinhado". O seletor
   de interseção usa o `.btn-limpar` + `.depois-limpar` da folha: glifo de 16 como a lupa e sem o encaixe negativo) */
.int-painel{position:fixed;z-index:120;max-height:240px;overflow-y:auto;background:var(--card);color:var(--foreground);
  border:1px solid var(--border);border-radius:var(--r-md);padding:4px;scrollbar-width:thin;scrollbar-gutter:stable;
  box-shadow:0 4px 6px -1px rgb(0 0 0 / .1),0 2px 4px -2px rgb(0 0 0 / .1)}
.int-lista{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:1px}
.int-item{display:flex;align-items:flex-start;gap:8px;width:100%;padding:6px 10px;border:0;background:transparent;border-radius:var(--r-md);
  cursor:pointer;user-select:none;text-align:left;font:inherit;color:var(--foreground)}
.int-check{flex:0 0 auto;margin-top:2px;width:14px;color:var(--primary)}
.int-check svg{width:14px;height:14px}
.int-cod{flex:0 0 auto;margin-top:2px;padding:2px 6px;border-radius:var(--r-sm,6px);background:var(--muted);font-variant-numeric:tabular-nums;
  font-size:var(--text-xs);line-height:var(--lh-xs);font-weight:500;color:var(--muted-foreground);white-space:nowrap}
.int-nome{flex:1 1 auto;min-width:0;white-space:normal;overflow-wrap:break-word;font-size:var(--text-sm);line-height:var(--lh-sm)}
.int-item[aria-selected="true"]{background:color-mix(in srgb,var(--primary) 10%,transparent)}
.int-item:hover,.int-item:focus-visible{background:var(--muted);color:var(--foreground)}
.int-dica{margin:0;padding:12px 10px;font-size:var(--text-sm);color:var(--muted-foreground)}
.int-titulo{margin:0 0 4px;padding:6px 10px;border-bottom:1px solid var(--border);font-size:var(--text-xs);font-weight:500;color:var(--muted-foreground)}

/* ===== GATEWAY · o passo Conclusão do assistente = o passo Conclusão da câmera (30/09) ================
   ⬅️ Dela: "esse card em azul na verdade tem que ser verde; pode tirar o design do Figma" (nó 2:36932 de
   "Módulo - Câmeras"). MEDIDO em `camera-creation-review-step.component.css`: faixa 12/16, raio xl, chão
   `status-estavel-foreground` (o verde claro), borda estavel a 25 %, vão 12; ladrilho 40 raio md em estavel a
   30 %, glifo estavel; título 14 semibold, subtítulo 12 apagado. Lista com vão 12; painel `card` + borda, raio
   xl, `shadow-xs`, borda primária a 40 % quando aberto; cabeçalho-botão 12/16, vão 12, título 14 medium,
   chevron 20 apagado; o recolher é `grid-template-rows 0fr→1fr` em 220 ms; conteúdo 0/16/12 com vão 12;
   seção com vão 4 e título 14 semibold; linha `space-between` pela base, vão 16, rótulo 14 apagado, valor 14
   à direita; pílula 4/8 raio cheio 12 medium (validada = estavel sobre estavel-foreground; não = muted a 60 %). */
.conc-faixa{display:flex;align-items:center;gap:12px;padding:12px 16px;border-radius:var(--r-xl,14px);
  background:color-mix(in srgb,var(--status-estavel) 12%,var(--card));border:1px solid color-mix(in srgb,var(--status-estavel) 25%,transparent);color:var(--foreground)}
.conc-faixa-glifo{display:inline-flex;align-items:center;justify-content:center;width:40px;height:40px;flex:none;
  border-radius:var(--r-md);background:color-mix(in srgb,var(--status-estavel) 30%,transparent);color:var(--status-estavel)}
.conc-faixa-glifo svg{width:18px;height:18px}
.conc-faixa-tx{display:flex;flex-direction:column;gap:4px;min-width:0}
/* ⬅️ dela: "verifique tamanhos de texto" — LIDO no nó do Figma (get_design_context, 30/09): a faixa tem título 12
   medium com entrelinha 1 e subtítulo 12 medium apagado com entrelinha 16, vão 8 entre eles e 16 até o ladrilho
   (raio lg); o painel: cabeçalho 14 medium, chevron 16, conteúdo com vão 8 e 16 embaixo; seção com vão 8, título
   12 SEMIBOLD, rótulo 12 MEDIUM apagado, valor 12 regular, linhas de 16; um filete entre seções. */
.conc-faixa{gap:16px}
.conc-faixa-glifo{border-radius:var(--r-lg)}
.conc-faixa-tx{gap:8px}
.conc-faixa-tx h4{margin:0;font-size:var(--text-xs);line-height:1;font-weight:500;color:var(--foreground)}
.conc-faixa-tx p{margin:0;font-size:var(--text-xs);line-height:var(--lh-xs);font-weight:500;color:var(--muted-foreground)}
.conc-lista{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:12px}
.conc-cartao{display:flex;flex-direction:column;overflow:hidden;background:var(--card);border:1px solid var(--border);
  border-radius:var(--r-xl,14px);box-shadow:0 1px 2px 0 rgb(0 0 0 / .05)}
.conc-cartao--aberto{border-color:color-mix(in srgb,var(--primary) 40%,var(--border))}
.conc-cab{appearance:none;background:transparent;border:0;width:100%;display:flex;align-items:center;gap:12px;padding:12px 16px;
  color:var(--foreground);font:inherit;font-size:var(--text-sm);line-height:var(--lh-sm);text-align:left;cursor:pointer}
.conc-cab:focus-visible{outline:2px solid var(--anel);outline-offset:-2px}
.conc-tit{flex:1 1 auto;font-weight:500;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.conc-chevron{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;color:var(--muted-foreground);flex:none}
.conc-chevron svg{width:16px;height:16px}
.conc-cx{display:grid;grid-template-rows:0fr;transition:grid-template-rows 220ms ease}
.conc-cx--aberto{grid-template-rows:1fr}
.conc-clip{min-height:0;overflow:hidden}
.conc-corpo{display:flex;flex-direction:column;gap:8px;padding:0 16px 16px}
.conc-sec{display:flex;flex-direction:column;gap:8px}
.conc-sec+.conc-sec{border-top:1px solid var(--border);padding-top:8px}
.conc-sec h5{margin:0;font-size:var(--text-xs);line-height:var(--lh-xs);font-weight:600;color:var(--foreground)}
.conc-linhas{margin:0;display:flex;flex-direction:column;gap:8px}
.conc-linha{display:flex;align-items:center;justify-content:space-between;gap:16px;min-width:0;min-height:16px}
.conc-linha dt{margin:0;font-size:var(--text-xs);line-height:var(--lh-xs);font-weight:500;color:var(--muted-foreground);flex-shrink:0}
.conc-linha dd{margin:0;font-size:var(--text-xs);line-height:var(--lh-xs);font-weight:400;color:var(--foreground);text-align:right;word-break:break-word}
.conc-linha dd.apagado{color:var(--muted-foreground)}
.conc-selo{display:inline-flex;align-items:center;padding:4px 8px;border-radius:9999px;font-size:var(--text-xs);font-weight:500;line-height:1;
  background:color-mix(in srgb,var(--muted) 60%,transparent);color:var(--muted-foreground)}
.conc-selo--ok{background:color-mix(in srgb,var(--status-estavel) 12%,var(--card));color:var(--status-estavel)}
/* o Alert do pé da Conclusão (Figma: `Alert` default — `card`, borda, raio lg, 8/10, vão 8; `circle-alert` 16 com 2 de
   topo; texto 14 medium entrelinha 20; X = botão ghost 24 raio md) */
.conc-alerta{display:flex;align-items:center;gap:8px;padding:8px 10px;background:var(--card);border:1px solid var(--border);border-radius:var(--r-lg)}
.conc-alerta-glifo{display:inline-flex;align-self:flex-start;padding-top:2px;color:var(--foreground)}
.conc-alerta-glifo svg{width:16px;height:16px}
.conc-alerta p{flex:1 1 auto;min-width:0;margin:0;font-size:var(--text-sm);line-height:var(--lh-sm);font-weight:500;color:var(--foreground)}
.conc-alerta-x{width:24px;height:24px;border-radius:var(--r-md);color:var(--foreground);flex:none}
.conc-alerta-x svg{width:16px;height:16px}

/* ===== GATEWAY · o cartão Localização da gaveta = o do `camera-edit-sheet` (30/09) ========================
   ⬅️ Dela, com o print: "essa parte de localização é igual em câmeras. Aqui tá faltando input, tá muito vazio.
   Puxa lá de câmera." MEDIDO em `camera-edit-sheet.component.css`: cartão com vão 16; Endereço como campo
   inteiro em cima; `__location` flex com vão 12; mapa `flex:1 1 0`, `--height-map-preview` 180, raio md,
   borda, chão `muted`; coluna de campos `flex:1 1 0` com vão 12; grade 2 colunas com vão 12/16; rótulo 12
   medium. O mapa leva os controles do `ui-map` (ampliar em cima, zoom embaixo). */
.gav-local .gps-mapa{border:1px solid var(--border);border-radius:var(--r-md);background:var(--muted);overflow:hidden}
.gav-local .gps-mapa canvas{border-radius:0}
.gav-cartao.gav-mapa-grande .gav-local{flex-direction:column}
.gav-cartao.gav-mapa-grande .gav-local .gps-mapa{flex:0 0 auto;width:100%;height:360px}
.gav-topo .loc-dica{grid-column:1 / -1}
.gaveta .gav-topo .fg-campo.grande>label{font-size:var(--text-sm);line-height:var(--lh-sm)}
.gaveta .gav-topo .fg-campo.grande{gap:6px}
.gps-mapa .maplibregl-ctrl-group{background:var(--secondary);border:0;border-radius:var(--r-lg);box-shadow:none;overflow:hidden}
.gps-mapa .maplibregl-ctrl-group button{width:24px;height:24px;background:transparent;border:0;display:flex;align-items:center;justify-content:center;color:var(--foreground)}
.gps-mapa .maplibregl-ctrl-group button:hover{background:var(--muted)}
.gps-mapa .maplibregl-ctrl-group button+button{border-top:0}
.gps-mapa .maplibregl-ctrl-expand svg{width:12px;height:12px}
.gps-mapa .maplibregl-ctrl-zoom-in .maplibregl-ctrl-icon,.gps-mapa .maplibregl-ctrl-zoom-out .maplibregl-ctrl-icon{display:none}
.gps-mapa .maplibregl-ctrl-zoom-in::before{content:'+';font-weight:700;font-size:13px;line-height:1}
.gps-mapa .maplibregl-ctrl-zoom-out::before{content:'\2212';font-weight:700;font-size:13px;line-height:1}
.gaveta .fg-campo.grande .grupo-campo>input[readonly]{color:var(--foreground)}
/* ⬅️ dela, 30/09, duas vezes: "subárea aqui embaixo em largura total, como em nobreak" — Subárea (e, na gaveta, a
   Altitude) numa linha inteira do cartão, sob o mapa e a coluna, com a dica dos derivados embaixo */
.loc-abaixo,.gav-abaixo{display:flex;flex-direction:column;gap:12px}
.loc-abaixo .loc-dica,.gav-abaixo .loc-dica{margin-top:-4px}
/* ⬅️ dela, 30/09, na coluna Severidade do log: "badges fora do padrão". A folha do `pmv-event-log-tab` dá raio sm e
   recuo 0/8 (16 de altura), mas o badge do módulo é a `.pill` — o `Badge` do Figma (nó 21027:1681) que já veste o
   "Online" do cabeçalho e o Online/Offline da lista: fio 1 transparente, recuo 2/8, raio total, 12/16 medium. A
   severidade passa a ter a mesma forma; os tons ficam (info, warning, destructive a 12–16 %; crítico sólido). */

/* ===== GATEWAY · o Log de Eventos da interna = o `camera-event-log-tab` (30/09) ======================================
   ⬅️ Dela: "toda a parte de log está fora do padrão", com o link da interna de câmera. MEDIDO em
   `camera-event-log-tab.component.css`: o host tem 24 de recuo (o da página já dá) e a coluna com vão 16; SEM cartão
   em volta — a barra fica solta e a `app-data-table` traz a própria moldura; barra flex com vão 12; busca
   `z-input-group sm` em `flex:0 1 var(--container-2xs)` (288); ações à direita (`margin-left:auto`) com o funil
   `outline icon` (32) e o badge da contagem a -8/-8, 20 de altura e mínimo 20, recuo 0/4, 12/16; severidade raio sm,
   recuo 0/8, 12 medium, e o crítico TINGIDO (destructive a 12 %), não sólido; categoria ícone + rótulo com vão 8. */
/* o `:host` do `camera-event-log-tab` tem `padding: spacing-6` (24) — o cartão antigo dava esse respiro por margem */
#c-log.camera-event-log{display:flex;flex-direction:column;flex:1 1 auto;gap:16px;min-height:0;min-width:0;padding:24px}
#c-log.camera-event-log[hidden]{display:none}
.camera-event-log__toolbar{display:flex;align-items:center;gap:12px;flex:none}
.busca.camera-event-log__search{width:auto;flex:0 1 288px;min-width:0}
.camera-event-log__search input[type=search]::-webkit-search-cancel-button,
.camera-event-log__search input[type=search]::-webkit-search-decoration{-webkit-appearance:none;appearance:none}
.camera-event-log__search-x{width:24px;height:24px;margin-right:-4px;color:var(--muted-foreground);flex:none}
.camera-event-log__search-x[hidden]{display:none}
.camera-event-log__search-x svg{width:14px;height:14px}
.camera-event-log__toolbar-actions{display:flex;align-items:center;gap:12px;margin-left:auto}
.camera-event-log__filter-trigger{position:relative;border:1px solid var(--border);background:var(--background)}
.camera-event-log__filter-badge{position:absolute;top:-8px;right:-8px;min-width:20px;height:20px;padding:0 4px;
  display:inline-flex;align-items:center;justify-content:center;border-radius:9999px;background:var(--primary);
  color:var(--primary-foreground);font-size:var(--text-xs);line-height:var(--lh-xs);font-weight:500}
.camera-event-log__filter-badge[hidden]{display:none}
.sev-log--critical{background:color-mix(in srgb,var(--status-instavel) 12%,transparent);color:var(--status-instavel)}
#c-log .data-table__td--numeric{white-space:nowrap}
/* ⬅️ dela, 30/09: "aqui em cima o recuo ficou alto demais, tem que ser 24 pixels também". O painel das abas já começa
   16 abaixo da fileira de abas (é o respiro que a aba Estado usa); somado aos 24 do `:host` dava 40. O topo leva só
   a diferença (8), e o vão entre as abas e a busca fica em 24, igual aos lados. */
#c-log.camera-event-log{padding-top:8px}

/* ===== GATEWAY · a fileira de disponibilidade distribuída como a da Nobreaks (30/09) ================================
   ⬅️ Dela: "distribui esses gráficos melhor, usa a dashboard de nobreak como referência da distribuição de conteúdo".
   COPIADO da folha da `nobreaks-dashboard.html` (só leitura, worktree do Nobreaks): `.cresce-graf`/`.graf-meio` (o
   gráfico ocupa a sobra), `.graf` (texto 12 apagado, grade e eixo `--border` a .8), `.card.faixa-topo>.topo` (cabeçalho
   + barra do total, 14 entre eles), `.pilha-estado` (20 de altura, raio cheio, fio de 2 entre fatias, piso de 3),
   `.lista-rank` (nome 12/600 com a fração embaixo, contagem e barra de 4 à direita em 40 %, fio entre linhas) e a
   legenda no pé (`margin-top:auto`, 12 acima, centrada). */
.cresce-graf{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;align-items:stretch;justify-content:flex-start}
.graf-meio{flex:1 1 auto;min-height:0;width:100%;display:flex;align-items:center;justify-content:center}
.tend-caixa{position:relative;min-height:140px}
.tend-caixa>svg{position:absolute;inset:0;width:100%;height:100%}
.graf{display:block;overflow:visible}
.graf text{font:inherit;font-size:var(--text-xs);fill:var(--muted-foreground)}
.graf .grade-h,.graf .eixo{stroke:var(--border);stroke-width:1;opacity:.8}
.graf .traco{stroke:var(--primary);stroke-width:2;fill:none;stroke-linejoin:round}
.graf .area{fill:color-mix(in srgb,var(--primary) 10%,transparent)}
.cresce-graf>.legenda-linha,.card.coluna>.legenda-linha{margin-top:auto;padding-top:12px}
.card.faixa-topo>.topo .card-cab{margin-bottom:14px}
.pilha-estado{display:flex;height:20px;border-radius:9999px;overflow:hidden;background:var(--muted);margin-bottom:8px}
.pilha-estado i{display:block;height:100%;min-width:3px}
.pilha-estado i+i{border-left:2px solid var(--card)}
.legenda-linha.estados{justify-content:center;gap:4px 12px}
.lista-rank{display:flex;flex-direction:column}
.lista-rank .l{display:grid;grid-template-columns:minmax(0,1fr) minmax(96px,40%);align-items:center;column-gap:12px;
  padding-block:6px 7px;border-bottom:1px solid var(--border)}
.lista-rank .l:last-child{border-bottom:0}
.lista-rank .rot{min-width:0;font-size:var(--text-xs);line-height:16px;font-weight:600;color:var(--foreground);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lista-rank .sub{grid-column:1;font-size:var(--text-xs);line-height:16px;color:var(--muted-foreground);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lista-rank .dir{grid-column:2;grid-row:1/span 2;display:flex;flex-direction:column;gap:8px}
.lista-rank .n{font-size:var(--text-xs);line-height:1;text-align:right;color:var(--muted-foreground);font-variant-numeric:tabular-nums}
.lista-rank .calha{display:block;height:4px;border-radius:9999px;overflow:hidden;background:var(--muted)}
.lista-rank .calha i{display:block;height:100%;border-radius:9999px}

/* ===== GATEWAY · o hover dos gráficos da dashboard (30/09) ============================================================
   ⬅️ Dela: "lembra que os gráficos têm hover, tá? E no gráfico de pizza tem uma pequena animação de opacidade quando
   você coloca o hover sobre uma das partes". COPIADO da folha da `nobreaks-dashboard.html` (só leitura): a `.dica`
   (o `Charts / Tooltip`: fixa, 156–280, recuo 6/10, fio #F2F2F2, raio md, sombra; cabeçalho 12/16 medium zinc-600;
   pastilha 8 raio 2; nome 400 apagado, valor 500), a `.corte` (tracejado 3 3 apagado a .7), o `.ponto` (chão do
   cartão, anel de 2 na cor da série) e o `.alvo` (transparente, mira). O esmaecimento da rosca (`.grafz.realce .fat`
   a .28, transição de .12 s) já estava na folha; faltava quem o acendesse. */
.dica{position:fixed;z-index:120;pointer-events:none;opacity:0;transition:opacity var(--motion-fast);
  display:flex;flex-direction:column;gap:8px;min-width:156px;max-width:280px;padding:6px 10px;
  border:1px solid #F2F2F2;border-radius:var(--r-md,8px);background:var(--popover,var(--card));color:var(--foreground);
  font-size:var(--text-xs);box-shadow:0 4px 6px rgb(0 0 0 / 0.1), 0 2px 4px rgb(0 0 0 / 0.1)}
:root[data-modo="escuro"] .dica{border-color:var(--border)}
.dica.on{opacity:1}
.dica-cab{display:flex;align-items:center;justify-content:space-between;gap:10px;font-size:var(--text-xs);line-height:16px;font-weight:500;color:#52525B}
:root[data-modo="escuro"] .dica-cab{color:#A1A1AA}
.dica-linhas{display:flex;flex-direction:column;gap:6px;width:100%}
.dica-l{display:flex;gap:8px;align-items:center;width:100%}
.dica-l i{flex:none;width:8px;height:8px;border-radius:2px}
.dica-l .n{flex:1 1 0;min-width:0;font-size:var(--text-xs);line-height:1;font-weight:400;color:var(--muted-foreground);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dica-l .v{flex:none;font-size:var(--text-xs);line-height:1;font-weight:500;color:var(--foreground);white-space:nowrap;font-variant-numeric:tabular-nums}
.graf .ponto{fill:var(--card);stroke-width:2;pointer-events:none}
.graf .corte{stroke:var(--muted-foreground);stroke-width:1;stroke-dasharray:3 3;opacity:.7;pointer-events:none}
.graf .alvo{fill:transparent;cursor:crosshair}
.grafz .legr .l[data-i]{cursor:default}
/* ===== GATEWAY · distribuir o conteúdo pela altura do cartão, sem crescer o cartão (30/09) =========================
   ⬅️ Dela: "se houver só três linhas da parte de frota, distribui melhor; caso tenha mais, você pode usar rolagem,
   porque eu não quero aumentar a altura dos cards" e, no "Uplinks recebidos pela frota", "distribuir melhor".
   · A LISTA NÃO MANDA NA ALTURA DA FILEIRA: base 0 (\`flex:1 1 0\`), então quem dá a altura é o cartão mais alto (a rosca,
     o ranking); a lista ocupa o que sobra, as linhas se repartem por igual quando são poucas e a caixa rola quando
     são muitas. Vale para Firmware e Sub-banda.
   · O GRÁFICO DE UPLINKS OCUPA A SOBRA: as colunas são percentuais da caixa, então a caixa cresce até o pé do cartão
     (o mínimo continua o de antes) e o rótulo das horas fica embaixo.
   ⬅️ E "verifica se esses pequenos gráficos estão com a mesma espessura dos pequenos gráficos lá da lista de
   nobreak": o medidor do painel da \`nobreaks-lista.html\` (\`.pn-gauge .gr\`) tem 8 de altura, raio cheio, trilho
   \`muted\`. As barras de \`.barras\` já tinham 8; as da \`.lista-rank\` (Firmware, Ranking) tinham 4 e passam a 8. */
.lista-rank .calha{height:8px}
#cardFw>#fw{flex:1 1 0;min-height:0;overflow-y:auto}
#fw>.lista-rank{min-height:100%}
#fw .lista-rank .l{flex:1 0 auto;align-content:center}
.card.coluna>.corpo-card:has(>#horas){flex:1 1 auto;min-height:0;display:flex;flex-direction:column}
#horas{flex:1 1 auto;height:auto;min-height:var(--sp-28)}
/* ⬅️ dela, 30/09: "aqui não dá para ser gráfico de pizza, não? Tá ridículo isso aqui" — uma rosca por sub-banda (em uso +
   livre = o limite), lado a lado e centradas na sobra do cartão; a rosca é a da casa (`.grafz .rosca`, o mesmo realce),
   em 136 para caber duas ou três na largura; nome 12/600 e gateway 12 apagado embaixo; legenda no pé */
#banda.banda-roscas{flex:1 1 auto;min-height:0;display:grid;grid-template-columns:repeat(auto-fit,minmax(128px,1fr));
  gap:16px;align-content:center;justify-items:center}
.banda-item{margin:0;display:flex;flex-direction:column;align-items:center;gap:12px;min-width:0;max-width:100%}
.banda-item .rosca{width:136px}
.banda-item figcaption{display:flex;flex-direction:column;align-items:center;gap:2px;text-align:center;min-width:0;max-width:100%;
  font-size:var(--text-xs);line-height:16px}
.banda-item figcaption b{font-weight:600;color:var(--foreground)}
.banda-item figcaption span{color:var(--muted-foreground);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%}
/* o badge de variação do `event-counter-card`: `z-badge outline pill` — fio `--border`, chão `--background`, 2/8,
   12/16 medium, ícone 12 (já medido no nó 2856:117145 pela Nobreaks: `.est-grade.mini .est-tile .var-badge`). Aqui só a
   dica ganha o ponteiro padrão: o badge não é clicável (o próprio componente escreve essa razão). */
.est-grade.mini .est-tile .var-badge[data-drot]{cursor:default}

/* ===== GATEWAY · "Gateways mudos" em dois cartões com gráfico (30/09) =================================================
   ⬅️ Dela: "isso aqui podia ser dois cards com dois gráficos … eu preciso ver um total de offline de todos eles, de uma
   forma um pouco melhor; eu não preciso ver uma lista". O total em destaque no número do ladrilho (`event-counter-card
   __value`: 2xl bold 24/32) com a frase 12 apagada ao lado; as colunas ocupam a sobra do cartão (`.cresce-graf`), com o
   número 12 medium em cima, a barra no raio 2/2/0/0 das colunas de uplink (`.horas i`), o fio de base `--border` e o
   rótulo 12 apagado embaixo; faixa vazia fica em 2 no `muted`. */
.mudo-num{display:flex;align-items:baseline;gap:8px;margin:-4px 0 12px;min-width:0}
.mudo-num b{font-size:var(--text-2xl,24px);line-height:32px;font-weight:700;color:var(--foreground);font-variant-numeric:tabular-nums}
.mudo-num span{font-size:var(--text-xs);line-height:16px;color:var(--muted-foreground);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* 🔴 NÃO É o nome curto do menu de colunas da lista: aquele nome já existia, e a regra daqui o virou em fileira —
   dela, 30/09, "bug". Terceira colisão de nome genérico no projeto. */
.graf-silencio{flex:1 1 auto;min-height:160px;display:flex;width:100%}
.graf-silencio-grade{flex:1 1 auto;display:grid;grid-template-columns:repeat(var(--n),minmax(0,1fr));gap:12px;align-items:stretch;width:100%}
.graf-silencio-grade .col{display:flex;flex-direction:column;align-items:center;gap:6px;min-width:0;cursor:default}
.graf-silencio-grade .v{font-size:var(--text-xs);line-height:16px;font-weight:500;color:var(--foreground);font-variant-numeric:tabular-nums}
.graf-silencio-grade .v.zero{color:var(--muted-foreground)}
.graf-silencio-grade .bar{flex:1 1 auto;width:100%;display:flex;align-items:flex-end;justify-content:center;border-bottom:1px solid var(--border)}
.graf-silencio-grade .bar i{display:block;width:100%;max-width:56px;border-radius:2px 2px 0 0;transition:opacity var(--motion-fast)}
.graf-silencio-grade .col:hover .bar i{opacity:.8}
.graf-silencio-grade .rot{font-size:var(--text-xs);line-height:16px;color:var(--muted-foreground);text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}
#fileira2{margin-bottom:16px}
/* ⬅️ dela, 30/09, no Log de eventos do painel: "essa linha vertical tem que ir até o final — quando começa a linha do footer
   é que acaba a linha do log de eventos". A lista e o ÚLTIMO item crescem até o pé do rolador (o trilho do último item é
   `flex:1`, então ele estica junto), e o rolador perde o recuo de baixo nesta aba para o trilho encostar no fio do rodapé. */
#painel .pn-rol:has(.pmv-side-detail__event-list){padding-bottom:0;display:flex;flex-direction:column}
#painel .pn-rol:has(.pmv-side-detail__event-list)>.pn-in{flex:1 0 auto;display:flex;flex-direction:column}
#painel .pn-in>.pmv-side-detail__event-list,#painel .pn-in :has(>.pmv-side-detail__event-list){flex:1 0 auto;display:flex;flex-direction:column}
#painel .pmv-side-detail__event-item:last-child{flex:1 0 auto}
/* ⬅️ dela, 30/09: "se a altitude é necessária, coloca a subárea e a altitude uma do lado da outra para economizar espaço" —
   na gaveta a linha de baixo vira a grade de duas colunas dos outros pares (12/16); a dica dos derivados fica na linha
   inteira. No assistente, sem Altitude, a Subárea continua ocupando a linha. */
.gav-abaixo{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:12px 16px}
.gav-abaixo>.loc-dica{grid-column:1 / -1;margin-top:-4px}
/* ⬅️ dela, 30/09: "ao fixar a barra no topo, acima do card de dashboard tem que ter um espaço em branco — é como é no
   nobreak". Lá o rolador é o `.rol` com 24 de recuo, e o `sticky` para 24 abaixo do topo dele, com o `::before` pintando
   o chão nesse vão. Aqui A PÁGINA rola (GTW-20), então o `sticky` resolve contra a janela: a parada passa a 24 e o mesmo
   `::before` de 24 cobre o vão. */
body:has(#dash) .barra-painel-caixa.fixa{inset-block-start:24px}
/* ⬅️ dela, 30/09: "verifique se os inputs estão todos no mesmo tamanho; a altitude está com o input maior, isso não pode
   acontecer". MEDIDO na gaveta: os campos soltos tinham 36 e os de grupo (com lupa, olho ou ação dentro) 32. Todos passam a
   36 — o `z-input` padrão (`h-9`) que o `camera-edit-sheet` usa em Nome, Endereço, Latitude e Longitude. Vale para a
   gaveta de edição e para o assistente, que moram na mesma `.gaveta`. */
.gaveta .grupo-campo{height:36px}
.gaveta .grupo-campo>input{height:100%}
/* ⬅️ dela, 30/09: "aumenta só um pouquinho a altura do mapa, só para ficar na mesma linha do input". Com os campos em 36 a
   coluna ao lado cresceu e o mapa de altura fixa ficou mais baixo que Via/Área. O mapa passa a esticar até o pé da coluna
   (a grade já é \`align-items:stretch\`); os 187 / 180 do produto ficam como mínimo. */
.loc-mapa{height:auto}
.gav-local{align-items:stretch}
.gav-local .gps-mapa{height:auto;min-height:180px}

/* ===== GATEWAY · período e filtros da dashboard = os da Nobreaks (30/09) ============================================
   ⬅️ Dela: "o período está incompleto, segue o mesmo input que no nobreak, tem mais datas, inclusive personalizada" e "os
   filtros também estão incompletos, tenho que filtrar a dashboard por gateway; olha como é o filtro lá do nobreak".
   COPIADO da `nobreaks-dashboard.html` (só leitura): `.periodo`/`.periodo-lista`/`.periodo-item`/`.cal*`/`.horas`/
   `.campo-hora` e `.pop*`/`.campo-sel`/`.opcoes`/`.busca-int`/`.btn-fantasma` — com o PREFIXO `rp-` porque três desses
   nomes já existem nesta folha com outro dono (`.horas` é o gráfico de uplinks; `.periodo` e `.periodo-item` vieram
   da casca). Medidas iguais às de lá: lista 232, itens 28 em 14, calendário 510 com dias de 32 raio lg, campos 36 raio
   lg, painel 320, opções 296 com teto de 288. */
.rp-periodo{position:absolute;z-index:70;display:flex;align-items:flex-start;flex-direction:row-reverse;gap:8px}
.rp-lista{width:232px;flex:none;padding:4px;border:1px solid var(--border);border-radius:var(--r-lg);background:var(--popover,var(--card));
  box-shadow:0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1)}
.rp-item{display:flex;width:100%;align-items:center;gap:6px;padding:4px 6px;max-height:28px;border:0;background:none;border-radius:var(--r-md);
  font:inherit;font-size:var(--text-sm);line-height:20px;color:var(--foreground);text-align:left;cursor:pointer}
.rp-item:hover,.rp-item[aria-expanded="true"]{background:var(--accent);color:var(--accent-fg)}
.rp-tique{width:14px;flex:none;color:var(--primary);display:inline-flex}
.rp-tique svg{width:14px;height:14px}
.rp-rot{flex:1;min-width:0}
.rp-seta{width:14px;height:14px;flex:none;color:var(--muted-foreground);display:inline-flex}
.rp-seta svg{width:14px;height:14px}
.rp-cal{width:510px;flex:none;padding:12px;border:1px solid var(--border);border-radius:var(--r-lg);background:var(--popover,var(--card));box-shadow:0 10px 28px rgba(0,0,0,.14)}
.rp-cal-meses{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.rp-cal-cab{display:flex;align-items:center;gap:8px;height:32px}
.rp-cal-nav{width:24px;height:24px;display:grid;place-items:center;border:0;background:none;border-radius:var(--r-sm);color:var(--muted-foreground);flex:none;cursor:pointer}
.rp-cal-nav:hover{background:var(--accent);color:var(--foreground)}
.rp-cal-nav svg{width:14px;height:14px}
.rp-cal-vao{width:24px;height:24px;flex:none}
.rp-cal-mes-rot{flex:1;text-align:center;font-size:var(--text-xs);font-weight:500}
.rp-cal-mes-rot::first-letter{text-transform:uppercase}
.rp-cal-semana,.rp-cal-grade{display:grid;grid-template-columns:repeat(7,1fr)}
.rp-cal-semana span{height:16px;display:grid;place-items:center;font-size:var(--text-xs);color:var(--muted-foreground)}
.rp-cal-cel{width:32px;height:32px;display:grid;place-items:center;position:relative}
.rp-cal-cel.dentro{background:color-mix(in srgb,var(--primary) 10%,transparent)}
.rp-cal-cel.ini{border-radius:var(--r-sm) 0 0 var(--r-sm)}
.rp-cal-cel.fim{border-radius:0 var(--r-sm) var(--r-sm) 0}
.rp-cal-cel.so{border-radius:var(--r-sm)}
.rp-cal-dia{width:32px;height:32px;display:grid;place-items:center;border:0;background:none;border-radius:var(--r-lg);font:inherit;font-size:var(--text-sm);
  color:var(--foreground);font-variant-numeric:tabular-nums;cursor:pointer}
.rp-cal-dia:hover{background:var(--accent)}
.rp-cal-dia.fora{color:var(--muted-foreground);opacity:.45;cursor:not-allowed}
.rp-cal-dia.fora:hover{background:none}
.rp-cal-dia.ponta,.rp-cal-dia.ponta:hover{background:var(--primary);color:var(--primary-foreground);font-weight:500}
.rp-cal-horas{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-top:12px;padding-top:12px;border-top:1px solid var(--border)}
.rp-hora-rot{display:block;font-size:var(--text-2xs,11px);line-height:16px;color:var(--muted-foreground);margin-bottom:4px}
.rp-campo-hora{display:flex;align-items:center;gap:4px;height:32px;padding:0 4px 0 10px;border:1px solid var(--input);border-radius:var(--r-md);background:var(--ctl-bg)}
.rp-campo-hora input{flex:1;min-width:0;width:100%;border:0;background:none;font:inherit;font-size:var(--text-xs);color:var(--foreground);outline:none;font-variant-numeric:tabular-nums}
.rp-campo-hora button{width:24px;height:24px;display:grid;place-items:center;flex:none;border:0;background:none;border-radius:var(--r-sm);color:var(--muted-foreground)}
.rp-campo-hora button svg{width:14px;height:14px}
.rp-pop{position:absolute;z-index:70;display:flex;flex-direction:column;width:min(320px, calc(100vw - 32px));max-height:calc(100dvh - 128px);
  border:1px solid var(--border);border-radius:var(--r-lg);background:var(--popover,var(--card));box-shadow:0 10px 28px rgba(0,0,0,.14)}
.rp-pop-cab{display:flex;align-items:center;gap:8px;padding:12px 16px 8px}
.rp-pop-cab h3{margin:0;font-size:var(--text-sm);line-height:20px;font-weight:600;color:var(--foreground)}
.rp-pop-corpo{flex:1;min-height:0;overflow-y:auto;display:flex;flex-direction:column;gap:12px;padding:8px 16px 12px}
.rp-par{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:12px}
.rp-grupo{display:flex;flex-direction:column;gap:8px;min-width:0}
.rp-grupo-rot{display:block;font-size:var(--text-sm);line-height:var(--lh-sm);font-weight:400;color:var(--foreground)}
.rp-pop-pe{display:flex;align-items:center;justify-content:flex-end;gap:8px;padding:8px 12px;border-top:1px solid var(--border)}
.rp-campo{display:flex;align-items:center;gap:8px;width:100%;height:36px;padding:6px 12px;border:1px solid var(--input);border-radius:var(--r-lg);
  background:var(--ctl-bg);color:var(--foreground);font:inherit;font-size:var(--text-sm);text-align:left;cursor:pointer}
.rp-campo:hover{background:var(--accent)}
.rp-val{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rp-val.rp-vazio{color:var(--muted-foreground)}
.rp-campo svg{width:14px;height:14px;flex:none;color:var(--muted-foreground)}
.rp-campo:disabled{opacity:.5;cursor:not-allowed}
.rp-campo:disabled:hover{background:var(--ctl-bg)}
.rp-btn-fantasma{display:inline-flex;align-items:center;height:32px;padding:0 10px;border:0;background:none;border-radius:var(--r-md);color:var(--foreground);
  font:inherit;font-size:var(--text-xs);font-weight:500;cursor:pointer}
.rp-btn-fantasma:hover{background:var(--accent)}
.rp-btn-fantasma:disabled{opacity:.5;cursor:not-allowed}
.rp-btn-fantasma:disabled:hover{background:none}
.rp-opcoes{position:absolute;z-index:72;width:296px;max-height:288px;display:flex;flex-direction:column;border:1px solid var(--border);border-radius:var(--r-lg);
  background:var(--popover,var(--card));box-shadow:0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1)}
.rp-busca{display:flex;align-items:center;gap:6px;margin:6px;padding:0 8px;height:30px;border:1px solid var(--input);border-radius:var(--r-md);background:var(--ctl-bg);flex:none}
.rp-busca svg{width:14px;height:14px;flex:none;color:var(--muted-foreground)}
.rp-busca input{flex:1;min-width:0;border:0;background:none;font:inherit;font-size:var(--text-xs);color:var(--foreground);outline:none}
.rp-busca input::-webkit-search-cancel-button{-webkit-appearance:none;appearance:none}
.rp-busca button{width:20px;height:20px;display:grid;place-items:center;flex:none;border:0;background:none;border-radius:var(--r-sm);color:var(--muted-foreground)}
.rp-busca button svg{width:12px;height:12px}
.rp-opcoes-rol{flex:1;min-height:0;overflow:auto;padding:0 4px 4px}
.rp-op{display:flex;width:100%;align-items:center;gap:6px;padding:4px 6px;min-height:28px;border:0;background:none;border-radius:var(--r-md);font:inherit;
  font-size:var(--text-sm);line-height:20px;color:var(--foreground);text-align:left;cursor:pointer}
.rp-op:hover{background:var(--accent);color:var(--accent-fg)}
.rp-op-rot{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rp-op-vazio{margin:0;padding:14px 10px;text-align:center;font-size:var(--text-xs);color:var(--muted-foreground)}
.rp-reg{height:1px;margin:4px 0;background:var(--border)}
/* ⬅️ dela, 30/09, de novo na coluna Severidade: "badge fora do padrão · padrão [o Online do cabeçalho] · cores permanecem as
   mesmas". A forma é a da `.pill` do módulo (fio 1 transparente, recuo 2/8, raio total, 12/16 medium) e os tons ficam os
   da severidade. Vale ACIMA da folha do `camera-event-log-tab` (raio sm, 0/8): é a decisão dela para este módulo. */
.sev-log{padding:2px 8px;border:1px solid transparent;border-radius:9999px;line-height:var(--lh-xs)}

/* ⬅️ dela, 30/09: "muda a cor desses gráficos para não ficar a dashboard toda azul" — a paleta de gráficos do produto
   (`ui-styles/tokens/colors.css`: `--chart-1..5` = orange-600 · teal-600 · cyan-900 · amber-400 · amber-500 no claro;
   blue-700 · emerald-500 · amber-500 · purple-500 · rose-500 no escuro). Sub-banda em `--chart-2`, downlinks em `--chart-3`. */
:root{--chart-1:#EA580C;--chart-2:#0D9488;--chart-3:#164E63;--chart-4:#FBBF24;--chart-5:#F59E0B}
:root[data-modo="escuro"]{--chart-1:#1D4ED8;--chart-2:#10B981;--chart-3:#F59E0B;--chart-4:#A855F7;--chart-5:#F43F5E}
/* o gráfico de downlinks sob os ladrilhos: colunas no chão da série (`--chart-3` a 30 %) com a parte confirmada na cor cheia,
   o fio de base e os rótulos do passo das colunas de uplink (`.horas-rot`); ocupa a sobra do cartão */
.down-graf{flex:1 1 auto;min-height:96px;margin-top:16px;display:grid;grid-template-columns:repeat(var(--n),minmax(0,1fr));gap:2px;
  align-items:end;border-bottom:1px solid var(--border)}
.down-graf i{display:flex;align-items:flex-end;min-height:2px;border-radius:2px 2px 0 0;background:color-mix(in srgb,var(--chart-3) 30%,var(--card));overflow:hidden}
.down-graf i b{display:block;width:100%;background:var(--chart-3)}
.down-graf i:hover{opacity:.85}
/* a rosca de sub-banda também no cartão do gateway (dela: "pizza"): a mesma `.banda-roscas`, ocupando o cartão */
#gwBanda.banda-roscas{flex:1 1 auto;min-height:0;display:grid;grid-template-columns:repeat(auto-fit,minmax(128px,1fr));gap:16px;align-content:center;justify-items:center}
.hm__chart-card:has(#gwBanda){display:flex;flex-direction:column}
.hm__chart-card:has(#gwBanda)>.legenda-linha{margin-top:auto;padding-top:12px}
/* o glifo do Atualizar gira enquanto a leitura está em curso (a mesma animação de 1 s do `auth.spinner`) */
#btAtualizar svg.gira{animation:cred-gira 1s linear infinite}
#btAtualizar:disabled{opacity:.7;cursor:progress}
/* a tendência com o eixo do piso ao teto: a média tracejada (3 3, a primária a .7), e os pontos de mínimo (vermelho) e máximo
   (verde) no chão do cartão com anel de 2, o valor em 12 medium ao lado */
.graf .tend-media{stroke:var(--primary);stroke-width:1.5;stroke-dasharray:3 3;opacity:.7;pointer-events:none}
.graf .tend-marca{fill:var(--card);stroke-width:2;pointer-events:none}
.graf .tend-marca.tend-min{stroke:var(--status-instavel)}
.graf .tend-marca.tend-max{stroke:var(--status-estavel)}
.graf .tend-rot{font-size:var(--text-xs);font-weight:500;pointer-events:none}
.graf text.tend-rot.tend-min{fill:var(--status-instavel)}
.graf text.tend-rot.tend-max{fill:var(--status-estavel)}
.legenda-linha .sw{width:18px;height:4px;flex:none;overflow:visible}
.legenda-linha .sw.ponto{width:10px;height:10px}
/* ⬅️ dela, 30/09, no Downlinks e confirmações: "gostei, mas não gostei desse verde [o ciano escuro]; downlink coloca vermelho,
   vermelho clarinho, nem muito escuro nem muito claro; confirmações verde; a taxa de confirmação outra cor; cores contrastantes
   para o usuário entender". Downlink = red-400 (`--serie-down`), confirmação = o verde de estável, taxa = `--chart-5`
   (amber-500 da paleta de gráficos). Na coluna: a altura inteira são os downlinks, a parte verde é o confirmado e a ponta
   vermelha que sobra é o que ficou sem confirmação — por isso a legenda diz "Sem confirmação". */
:root{--serie-down:#F87171}
.down-graf i{background:var(--serie-down)}
.down-graf i b{background:var(--status-estavel)}
/* ⬅️ dela, 30/09, com o link do dashboard de PMV: "confere o título e o subtítulo dos cards se é desse tamanho mesmo". MEDIDO
   nos 17 componentes `pmv-dashboard-*` do attlas-2026: título `text-base` 16 semibold na cor do texto, subtítulo `text-sm` 14
   apagado, ladrilho 36 raio md, vão 12. Os 14 cartões com cabeçalho já batiam; os dois cartões de dentro da "Leitura por
   gateway" vinham do painel de saúde da câmera (14 medium sobre 12) e passam ao mesmo par. */
.hm__chart-card .hm__chart-title{font-size:var(--text-base,16px);line-height:24px;font-weight:600;color:var(--foreground)}
.hm__chart-card .hm__chart-header-value{font-size:var(--text-sm);line-height:var(--lh-sm);color:var(--muted-foreground)}
/* ⬅️ AQUI MORAVAM as regras do passo Credenciais do assistente (`.cred-*`, o `z-switch`, as variantes pri/perigo/grande do
   `.btn-xs` e o glifo de disco com furo). O passo saiu em 01/10 — dela: "tirar o passo Credenciais" — e a folha vai junto:
   regra sem consumidor é peso morto. Fica o `@keyframes cred-gira`, que o Atualizar da dashboard usa. */
/* o botão Buscar no vazio da tabela de descoberta (no lugar do cartão Servidor · Chave · Buscar, que saiu em 01/10) */
/* dela, 01/10: "reduz a distância e coloca um botão um pouco menor" — 12 da frase ao botão (o vão 8 do vazio + 4) e o botão
   no tamanho sm do kit (28 de altura, recuo 10) */
.vazio .vazio-buscar{margin-top:4px;height:28px;padding:0 10px}
/* o Nome no topo do painel de Localização (dela, 01/10): a seção de identificação do `camera-creation-settings-step`, sem
   título, e o filete de 1 com 16 de respiro entre ela e a Localização (`.settings-step__section + .settings-step__section`) */
.loc-sec+.loc-sec{border-top:1px solid var(--border);padding-top:16px}

/* ══ DASHBOARD v2 — só o que o 25 guarda (dela, 01/10: "na dashboard crie uma v2 para estes dados ao lado") ══
   O mapa da frota: a caixa do mini mapa do painel (`pn-local__mapa`: borda, raio md) com altura de cartão; o ponto
   de cada gateway é o `status-dot` do produto aumentado para 12 com anel de 2 no chão, para separar do mapa. */
.mapa-frota{height:320px;border:1px solid var(--border);border-radius:var(--r-md);overflow:hidden}
/* ⬅️ dela, 01/10: "quero os ícones e mapa como em analíticos" (#/analytics/metrics?subtab=virtualLoop): o ponto de 12 saiu; o alfinete é o `camera-map-pin` do produto (`camera-map-pin-palette.css`), com os
   tokens desta folha: disco 28 (spacing-7), anel de 2 no branco do traço do marcador, chão no verde de estável ou no vermelho
   de offline, glifo branco de 14, halo de 4 a 18 % (28 % no hover), sombra sm. SEM `position`: o MapLibre posiciona pelo
   `.maplibregl-marker` e um position do elemento desloca o pino a cada zoom (comentário do produto). */
.camera-map-pin{--camera-map-pin:var(--status-estavel);display:flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;
  border:2px solid #fff;border-radius:9999px;background:var(--camera-map-pin);color:#fff;cursor:pointer;
  box-shadow:0 1px 3px 0 rgb(0 0 0 / .1),0 1px 2px -1px rgb(0 0 0 / .1);
  transition:background-color .15s,border-color .15s,box-shadow .15s,opacity .15s;z-index:3}
.camera-map-pin svg{width:14px;height:14px;display:block}
.camera-map-pin::before{content:'';position:absolute;inset:-4px;border-radius:9999px;
  background:color-mix(in srgb,var(--camera-map-pin) 18%,transparent);transition:background .15s;pointer-events:none}
.camera-map-pin:hover{background:color-mix(in srgb,var(--camera-map-pin) 88%,var(--foreground))}
.camera-map-pin:hover::before{background:color-mix(in srgb,var(--camera-map-pin) 28%,transparent)}
.camera-map-pin--offline{--camera-map-pin:var(--status-instavel)}
.camera-map-pin:focus-visible{outline:1px solid var(--anel);outline-offset:2px}
/* dela, 01/10, na v2: "muito espaço em branco, já falei para distribuir isso" — o cartão Por interseção estica até a altura
   do Mapa da frota ao lado (mesma fileira), e a tabela come a sobra do cartão em vez de parar no teto de 230 do `.card .logrol` */
#cardInter>.corpo-card{flex-direction:column;min-height:0}
#cardInter .logrol{flex:1 1 0;max-height:none}
/* a fileira de TRÊS cartões de silêncio (01/10, a v2 unida à Dashboard): em um terço da largura o rodapé não cabe em uma
   linha e cortava as duas frases e a do canto; empilha — as frases em cima, o destaque do canto embaixo, sem reticências */
#fileira2 .card-pe{flex-direction:column;align-items:flex-start;gap:8px}
#fileira2 .card-pe .pe-1,#fileira2 .card-pe .pe-2,#fileira2 .card-pe .pe-dir{white-space:normal;overflow:visible;text-overflow:clip}
#fileira2 .card-pe .pe-dir{flex:0 1 auto;min-width:0}
/* e o rótulo de faixa ("Mais de 30 dias") quebra em duas linhas em vez de virar "Mais de 3…" */
#fileira2 .graf-silencio-grade .rot{white-space:normal;overflow:visible;text-overflow:clip}
/* a Subárea sozinha na linha sob o mapa (a Altitude saiu em 01/10) ocupa as duas colunas */
.gav-abaixo>.largo{grid-column:1 / -1}
/* dela, 01/10: o Endereço da Instalação ocupa TRÊS colunas da grade (é longo: as duas vias, o bairro e a cidade) e o resto
   começa depois dele. Abaixo de 3 colunas de 192 + vãos de 20 (616 de caixa) ele toma a linha inteira. */
.instance-page__row--tres{grid-column:span 3}
@media (max-width:48rem){.instance-page__row--tres{grid-column:1 / -1}}

/* ══ EXPANDIR CARTÃO — copiado VERBATIM da folha da `nobreaks-dashboard.html` (01/10; dela, 01/10: "expandir mapa e modal central como é em todos os outros gráficos, poder expandir e ver o gráfico maior como em nobreak"). O botão é o ghost `icon-sm`
   (28, glifo 16, sem fio) e a modal é o `dashboard-widget-expand-dialog` (860 de largura máxima, 500 de altura mínima,
   85dvh de teto, véu a 20 % com blur 4). ══ */
.card-expandir,.wx-fechar{width:28px;height:28px;flex:none;
  border:0;border-radius:min(var(--r-md,12px),12px);
  background:transparent;color:inherit;
  display:grid;place-items:center;cursor:pointer;
  transition:background var(--motion-fast,.15s),color var(--motion-fast,.15s)}
.card-expandir{margin-left:auto}
.card-expandir:hover,.wx-fechar:hover{background:var(--muted);color:var(--foreground)}
.card-expandir:focus-visible,.wx-fechar:focus-visible{outline:2px solid var(--ring);
  outline-offset:2px}
.card-expandir svg,.wx-fechar svg{width:16px;height:16px;display:block}

/* O MODAL, medido no `dashboard-widget-expand-dialog`. Os dois numeros sao tokens do
   produto: `--dashboard-widget-modal-max-width: 860px` e `min-height: 500px`. */
.wx-veu{position:fixed;inset:0;z-index:94;display:flex;align-items:center;
  justify-content:center;padding:16px;
  background:color-mix(in srgb,var(--foreground) 20%,transparent);
  backdrop-filter:blur(4px)}
.wx-veu[hidden]{display:none}
.wx{display:flex;flex-direction:column;width:100%;max-width:860px;min-height:500px;
  max-height:85dvh;border:1px solid var(--border);border-radius:var(--r-xl,14px);
  background:var(--background);overflow:hidden}
/* ⬅️ A regra do `.wx-fechar` subiu e virou a MESMA do `.card-expandir`: os dois sao o
   ghost `icon-sm` do design system, e escrever duas vezes era como eles comecaram a
   divergir — um ganhou cinza, o outro ganhou outline. */
.wx-cab{display:flex;align-items:flex-start;justify-content:space-between;flex-shrink:0;
  gap:16px;padding:16px}
.wx-txt{display:flex;flex-direction:column;gap:2px;min-width:0}
.wx-tit{margin:0;font-size:var(--text-base,16px);line-height:24px;font-weight:500;
  color:var(--foreground)}
.wx-sub{margin:0;font-size:var(--text-sm,14px);line-height:20px;color:var(--muted-foreground)}
/* `padding-top:0` e' do componente: o cabecalho ja' deu o ar de cima. */
/* o lugar guardado do corpo que foi para o modal: ele nao desenha nada, so' segura a
   altura do cartao para a fileira nao se reorganizar atras do veu */
.wx-vago{flex:none;overflow:hidden;pointer-events:none}
.wx-corpo{display:flex;flex-direction:column;flex:1;min-height:0;padding:16px;
  padding-top:0;overflow:auto}
/* ⬅️ "distribuir melhor" — dela, 23/09, com o modal de cameras ao lado. La' o desenho
   ocupa o MEIO da caixa, centrado, com a legenda embaixo. O nosso esticava o corpo na
   largura e o deixava achatado no topo. Entao o conteudo movido para ca' se centra e
   cresce nas duas dimensoes — e' o ponto de expandir. */
.wx-corpo{align-items:center;justify-content:center}
.wx-corpo > *{flex:1;min-height:0;width:100%;display:flex;flex-direction:column;
  align-items:center;justify-content:center}
/* o desenho movido nao leva mais a largura travada do cartao de origem */
.wx-corpo svg{max-width:100%}
/* 🔴 A ROSCA SAIA 0x0 NO MODAL, e a causa era CSS circular que eu mesmo escrevi:
   `width:auto` na rosca + `height:min(100%,…)` no desenho. A largura dependia do
   conteudo, o conteudo da altura, e a altura de uma porcentagem de um pai cuja altura vem
   do flex — o navegador resolve isso em ZERO.
   ⭐ A saida e' tirar a circularidade: CAIXA QUADRADA E DEFINIDA para a rosca, e o `.pz`
   volta a ser `100%` dela, que e' exatamente como ele ja' funciona dentro do cartao.
   ⚠️ A estrutura, medida, e' `.corpo-card > .grafz > .rosca > (svg.pz + .miolo)`: a rosca
   e' NETA do que o modal recebe, e nao filha — foi por isso que a minha primeira regra
   mirou no lugar errado. */
/* ⬅️ "reduz o tamanho pq ta quebrando no hover" — dela, 23/09. 380 nao cabia: a
   fatia sob o ponteiro CRESCE 6 unidades para fora (`RG=RE+6` no tracado), o corpo do
   modal e' `overflow:auto`, e o que cresce alem da caixa era cortado — ou empurrava
   barra de rolagem. Foi para 320 e, no recado seguinte dela ("reduz mais"), para 260.
   ⭐ E 260 nao e' so' "menor": a 380 a rosca ocupava quase toda a altura util e a legenda
   ficava espremida contra o pe'; a 260 sobra ar em volta, que e' o que faz o desenho ler
   como peca centrada em vez de peca encaixada a forca. */
.wx-corpo .rosca{flex:none;width:260px;height:260px;margin:0 auto;
  display:flex;align-items:center;justify-content:center}
.wx-corpo .rosca .pz{width:100%;height:100%}
/* ⬅️ "centralizar" — dela, 23/09, com um retangulo em volta da area do desenho.
   🔴 A CAUSA, medida: a legenda tinha `margin-top:auto` — 92px de calculado —, e e' ela
   que estava empurrando o desenho para o alto. O `justify-content:center` do `.grafz` nao
   fazia nada porque, com a margem automatica, o conteudo JA' ocupava a altura inteira:
   0 de ar em cima, 0 embaixo, e 128 de buraco no meio.
   ⚠️ E aquele `auto` tem razao de ser NO CARTAO: ele cola a legenda no pe' para as
   legendas de cartoes vizinhos ficarem na mesma linha. Dentro do modal nao ha' vizinho,
   entao ele so' atrapalha — a legenda volta a andar junto do desenho.
   ⚠️ E A PRIMEIRA TENTATIVA NAO PEGOU, por especificidade: eu escrevi
   `.wx-corpo .grafz > *` (duas classes) contra `.grafz>.legr` (duas classes tambem),
   e a do cartao vem DEPOIS na folha — empate de especificidade, ganha a ultima. A regra
   abaixo espelha os TRES seletores do original com `.wx-corpo` na frente, entao sao tres
   classes contra duas e a ordem deixa de decidir. */
.wx-corpo .cresce-graf>.legenda-linha,
.wx-corpo .grafz>.legr,
.wx-corpo .card.coluna>.legenda-linha{margin-top:0}

/* o que é só do gateway: as peças que desenham em div ou canvas crescem na modal (na Nobreaks tudo era svg) */
.wx-corpo .mapa-frota{height:62dvh;min-height:420px;width:100%}
.wx-corpo .graf-silencio{min-height:360px}
.wx-corpo .horas{height:360px;width:100%}
.wx-corpo .down-graf{min-height:320px;width:100%}
.wx-corpo .tend-caixa{min-height:360px;width:100%}
.wx-corpo .horas-rot,.wx-corpo .legenda-linha{width:100%}
/* dela, 01/10, no Downlinks expandido: "bug" — o `.wx-corpo > *` da Nobreaks centra os filhos do corpo, e a fileira de
   ladrilhos (Downlinks · Confirmações · Taxa) encolhia até a largura do conteúdo, cortando os rótulos em "D…", "C…", "T…".
   Na modal a fileira volta a ocupar a largura inteira, sem crescer na altura. */
.wx-corpo .ladrilhos{align-self:stretch;width:100%;flex:none}

/* ══ A TABELA DO CARTÃO "Interseções habilitadas sem gateway" (dela, 01/10: "estrutura da tabela" (Figma Módulo - Câmeras, nó 2633:70403) e "tabela fica dentro do card mesmo" (#/cameras/dashboard)). A barra fica a 24 da tabela (o `gap 24` do nó); a
   coluna de seleção é a de 40 do nó, com o checkbox do produto (`checkbox.variants.ts`, o mesmo da descoberta). ══ */
.hab-tab{display:flex;flex-direction:column;gap:24px;min-width:0}
.hab-tab .data-table{min-width:0}
.hab-chk{width:40px}
.hab-tab input[type=checkbox]{appearance:none;-webkit-appearance:none;width:16px;height:16px;
  margin:0;border:1px solid var(--input);border-radius:4px;background:var(--card);
  box-shadow:0 1px 2px 0 rgb(0 0 0 / .05);cursor:pointer;flex:none;position:relative;vertical-align:middle;
  transition:background var(--motion-fast),border-color var(--motion-fast),box-shadow var(--motion-fast)}
.hab-tab input[type=checkbox]:checked{background:var(--primary);border-color:var(--primary)}
.hab-tab input[type=checkbox]:checked::after{content:"";position:absolute;inset:0;
  background:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23FAFAFA' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><path d='M4.5 12.5l5 5 10-11'/></svg>") center/12px 12px no-repeat}
.hab-tab input[type=checkbox]:focus-visible{outline:none;box-shadow:0 0 0 4px color-mix(in srgb,var(--primary) 50%,transparent)}

/* o título do `z-dropdown-menu-label` do Exportar (dela, 01/10, com o print do Exportar da dashboard de câmeras (#/cameras/dashboard)): 14/20 medium apagado, recuo 6/8 — o `.mlabel` da casa é o
   título 11 do seletor de colunas, outra peça */
.menu .mlabel--ds{padding:6px 8px;font-size:var(--text-sm,14px);line-height:20px;font-weight:500;color:var(--muted-foreground);text-transform:none;letter-spacing:0}
.menu button svg{flex:none}
.hab-tab .ph-acts{gap:8px}

/* ⬅️ "alinhar os cards e graficos" — dela, 01/10, na fileira do Tráfego de rádio. Todo cartão da tela começa o corpo a
   73 do topo (cabeçalho 44 + 12); três fugiam: o Downlinks em 89 (o `margin-top:16px` dos `.ladrilhos`, que lá é o
   respiro depois de um parágrafo), a Ocupação de sub-banda em 93 (as roscas centradas na sobra) e o Firmware em 75
   (o `margin-bottom:14px` da `.faixa-topo` copiada da Nobreaks). Os três passam a 73, junto com os vizinhos. */
#down.ladrilhos{margin-top:0}
#banda.banda-roscas{align-content:start}
#cardFw.faixa-topo>.topo .card-cab{margin-bottom:12px}
