/* =====================================================================
   OLT Observer — camada de componentes
   Depende de tokens.css. Carregada DEPOIS de base.css.

   Escrita para um contexto especifico: analista de NOC ao telefone com
   o cliente. Isso muda tudo. Ele nao navega, nao explora, nao le — ele
   procura uma resposta e precisa dela em segundos, com o cliente
   esperando do outro lado.

   Consequencias no desenho:
     - o dado tem peso; a explicacao se esconde atras de um "por que?"
     - a decisao vem antes do numero ("nao despachar" > "50")
     - nada pisca, nada anima: movimento numa tela de operacao rouba
       atencao que esta em outro lugar
   ===================================================================== */

/* ---------------------------------------------------- estrutura ---- */
.pagina { display: grid; gap: var(--e-5); max-width: 1400px; }

.pagina > header { display: grid; gap: var(--e-1); }
.pagina > header h1 {
  font: 500 var(--t-2xl)/1.2 var(--fonte-titulo);
  letter-spacing: -0.01em;
}
/* No tema claro o titulo de pagina usa o azul escuro institucional em
   vez do preto generico — mais presenca de marca no que e visto
   primeiro em toda tela. 10.3:1 sobre o novo --sup-base (formula WCAG).
   No escuro --tinta ja e a cor certa (quase branco); nao muda aqui. */
[data-theme="light"] .pagina > header h1 { color: var(--marca-tinta); }
/* Titulo introduzindo uma PILHA de cartoes soltos (nao um .bloco unico)
   — cada item ja se basta como cartao; empacotar tudo num .bloco por
   fora enfiaria caixa dentro de caixa, com o mesmo fundo se repetindo. */
/* Peso 500, nao 600: a Rubik em 600 fica MUITO pesada em tamanho de
   titulo pequeno, e o azul da marca ja diferencia o titulo do corpo
   sozinho. Cor + peso forte + (antes) sublinhado eram tres enfases
   empilhadas na mesma palavra. */
.pagina > h2 { font: 500 var(--t-lg)/1.25 var(--fonte-titulo); color: var(--marca-primaria); }
.pilha-gavetas { display: flex; flex-direction: column; gap: var(--e-3); }
.pagina > header p { color: var(--tinta-2); font-size: var(--t-sm); }

/* Faixa de estado: sempre no topo, sempre igual, em todas as telas.
   E o "onde estou e como esta" que o operador le sem procurar. */
.faixa {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--e-3) var(--e-5);
  padding: var(--e-3) var(--e-4);
  background: var(--sup-1);
  border: 1px solid var(--linha);
  border-radius: var(--raio-lg);
}
.faixa__item { display: flex; align-items: baseline; gap: var(--e-2); }
.faixa__valor {
  font: 500 var(--t-xl)/1 var(--fonte-titulo);
  font-variant-numeric: tabular-nums;
}
.faixa__rotulo { font-size: var(--t-xs); color: var(--tinta-2); text-transform: uppercase;
  letter-spacing: .06em; }
.faixa__sep { width: 1px; align-self: stretch; background: var(--linha); }
.faixa--alerta { border-color: var(--estado-alerta); }

/* ------------------------------------------------------- cartoes ---- */
.bloco {
  /* Ver `.conteudo` em base.css: item de grid nasce podendo estourar a
     propria trilha. Um cartao nunca deve ser mais largo que a coluna
     que o contem — quem tem conteudo largo de verdade usa `.envolve`,
     que rola por dentro. */
  min-width: 0;
  background: var(--sup-1);
  border: 1px solid var(--linha);
  border-radius: var(--raio-lg);
  padding: var(--e-5);
  display: grid; gap: var(--e-4);
  /* Uma sombra de 1px, so para o cartao pousar. Nao e profundidade
     decorativa: e o que separa objeto de mancha. */
  box-shadow: 0 1px 2px rgb(51 61 71 / 7%);
}
/* CABECALHO DE CARTAO — de faixa cheia para tipografia + fio.
   -------------------------------------------------------------------
   Era `background: var(--marca-primaria)` cheio, sangrando ate a borda.
   Bonito num cartao; em 43 cabecalhos de 17 telas, vira parede.

   E havia um defeito objetivo junto: o cabecalho de AVISO usava fundo
   FRACO e o de rotina usava ciano SATURADO — entao "O que chama
   atencao" aparecia mais quieto que "Optico". A hierarquia estava
   invertida, e a tela mandava o olho para o lugar errado.

   Agora o cartao normal e mudo: rotulo em caixa alta, discreto, sobre
   um fio. Cor virou EXCECAO — quem tem fundo colorido e so o aviso, e
   por isso ele finalmente se destaca. O azul escuro institucional
   assume como tinta do titulo, que e o papel que o manual da a ele. */
.bloco > header {
  display: flex; align-items: center; gap: var(--e-3); flex-wrap: wrap;
  margin: calc(var(--e-5) * -1) calc(var(--e-5) * -1) 0;
  padding: var(--e-3) var(--e-5);
  border-bottom: 1px solid var(--linha);
  border-radius: var(--raio-lg) var(--raio-lg) 0 0;
}
.bloco > header h2 {
  font: 600 var(--t-sm)/1.3 var(--fonte-titulo);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--tinta-2);
}
/* O AVISO e o unico colorido — e ganha um friso de 3px, para ler como
   sinalizado mesmo por quem nao distingue bem as cores. */
.bloco > header.header--critico,
.bloco > header.header--alerta {
  padding-left: calc(var(--e-5) - 3px);
  border-left: 3px solid;
}
.bloco > header.header--critico {
  background: var(--estado-critico-fraco);
  border-left-color: var(--estado-critico);
  border-bottom-color: var(--estado-critico-fraco);
}
.bloco > header.header--critico h2 { color: var(--estado-critico-forte); }
.bloco > header.header--alerta {
  background: var(--estado-alerta-fraco);
  border-left-color: var(--estado-alerta);
  border-bottom-color: var(--estado-alerta-fraco);
}
.bloco > header.header--alerta h2 { color: var(--estado-alerta-forte); }
.bloco--largo { grid-column: 1 / -1; }

/* Bloco que E um aviso. Vira COMPONENTE em 2026-08-06: a mesma borda
   esquerda de 3px estava escrita a mao, inline, em 20 templates e 30
   lugares — o recurso visual mais repetido da aplicacao, e nenhum
   deles era o mesmo codigo. Cada tela reinventava o aviso.

   MENOS E MAIS, na pratica: onde o bloco JA tem cabecalho colorido
   (.header--critico / .header--alerta), a borda esquerda nao entra —
   seriam duas marcacoes dizendo a mesma coisa no mesmo cartao. A regra
   e uma so: ou a faixa do cabecalho, ou a borda lateral. Nunca as
   duas. */
.bloco--critico { border-left: 3px solid var(--estado-critico); }
.bloco--alerta  { border-left: 3px solid var(--estado-alerta); }
.bloco--ok      { border-left: 3px solid var(--estado-ok); }

/* Grade de duas colunas que vira uma no celular. Breakpoint escolhido
   pelo CONTEUDO — abaixo de 900px a tabela de vigilancia deixa de caber
   sem rolagem horizontal, e rolagem horizontal em tela de operacao e
   onde o operador perde a coluna que importa. */
.duas { display: grid; gap: var(--e-5); align-items: start; }
@media (min-width: 900px) { .duas { grid-template-columns: 1fr 1fr; } }
@media (min-width: 1200px) { .duas--assimetrica { grid-template-columns: 5fr 7fr; } }

/* ---------------------------------------------- cartao de decisao --- */
/* O componente central do painel. A DECISAO vem antes do numero: quem
   olha de longe precisa ler "nao despachar", nao "50". */
.decisoes { display: grid; gap: var(--e-3);
  /* 150px e o menor cartao que ainda cabe um numero de 4 digitos sem
     quebrar. Abaixo disso o valor vira duas linhas e o cartao perde a
     leitura de relance, que e a razao de ele existir. */
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.decisao {
  display: grid; gap: var(--e-1);
  padding: var(--e-4);
  border-radius: var(--raio-md);
  background: var(--sup-2);
  border-left: 3px solid var(--linha-forte);
  /* Virou <a> em 28/08/2026 (clicar leva ao consolidado por tras do
     cartao) — sem isto herda a cor/sublinhado do "a" global de
     base.css e some a cor semantica que cada .decisao--* define. */
  color: inherit; text-decoration: none;
}
a.decisao:hover { background: var(--sup-3); }
.decisao__acao { font: 500 var(--t-sm)/1.3 var(--fonte-titulo); }
.decisao__valor { font: 600 var(--t-3xl)/1 var(--fonte-titulo); font-variant-numeric: tabular-nums; }
.decisao__causa { font-size: var(--t-xs); color: var(--tinta-2); font-family: var(--fonte-mono); }

.decisao--poupar   { border-left-color: var(--estado-ok); }
.decisao--poupar   .decisao__acao { color: var(--estado-ok); }
.decisao--despachar{ border-left-color: var(--estado-critico); }
.decisao--despachar .decisao__acao { color: var(--estado-critico); }
/* --estado-alerta, NAO --marca-acento: revisao de 2026-08-06.
   O amarelo institucional ficou com um emprego so — assinatura da
   marca (a faixa do cabecalho, o marcador do item ativo do menu, a
   aba selecionada). Ele NAO pode significar "atencao" ao mesmo tempo:
   a mesma cor dizendo "voce esta aqui" num canto e "cuidado" no outro
   e o conflito que fazia a interface parecer barulhenta sem motivo.
   Estado tem a escala semantica propria, e ela ja existe. */
.decisao--investigar { border-left-color: var(--estado-alerta); }
.decisao--investigar .decisao__acao { color: var(--estado-alerta); }

/* ------------------------------------------- grafico de barras ---- */
/* Portas crônicas no Dashboard (28/08/2026): comparar magnitude entre
   poucos itens nomeados é trabalho de barra, não de pizza — pizza é
   para parte-do-todo, não para ranking. Serie unica (nao ha categoria
   pra distinguir, so "porta problematica"), entao UMA cor so, sem
   legenda: o titulo da secao ja diz o que e. O texto nunca usa a cor
   da barra — fica nos tokens de tinta, como em toda tabela da tela. */
.grafico-barras { display: grid; gap: var(--e-3); }
.grafico-barras__linha {
  display: grid; grid-template-columns: minmax(120px, auto) 1fr auto;
  align-items: center; gap: var(--e-3);
  text-decoration: none; color: inherit;
}
.grafico-barras__rotulo code { font-size: var(--t-sm); }
.grafico-barras__trilho {
  display: block; height: 20px; border-radius: var(--raio-cheio);
  background: var(--sup-2); overflow: hidden;
}
.grafico-barras__barra {
  display: block; height: 100%; min-width: 4px;
  border-radius: var(--raio-cheio);
  background: var(--estado-critico);
}
/* Inventário de fabricante (04/09/2026): "quem é pior" a barra vermelha
   já servia — "qual fatia do parque" não é problema nenhum, é so
   composição. --estado-energia já é documentado como "informativo, não
   urgente" (ver tokens.css) — é essa a cor certa aqui, não o critico. */
.grafico-barras__barra--informativo { background: var(--estado-energia); }
.grafico-barras__valor {
  font-size: var(--t-sm); font-variant-numeric: tabular-nums;
  color: var(--tinta-2); white-space: nowrap;
}
@media (max-width: 640px) {
  .grafico-barras__linha { grid-template-columns: 1fr; gap: var(--e-1); }
  .grafico-barras__valor { justify-self: end; }
}

/* --------------------------------------------- criterio de ordenacao */
/* Controle secundario DENTRO de um cartao (troca a ordem de um grafico
   que ja esta na tela) — nao e navegacao de secao de pagina, por isso
   nao reaproveita `.abas` (feita pra ficar no topo, fonte maior,
   sublinhado de acento). E tambem nao usa o raio-cheio + fundo colorido
   de `.selo`: aquela forma ja significa ESTADO (bom/atencao/ruim) nesta
   aplicacao inteira — usar a mesma pilula aqui faria o criterio ativo
   parecer um badge de status, bem ao lado do selo real de "aberta
   agora". raio-md e cor neutra marcam que e outra coisa: escolha, nao
   estado. */
.criterios { display: flex; flex-wrap: wrap; gap: var(--e-1); margin-bottom: var(--e-3); }
.criterios a {
  display: inline-flex; align-items: center; min-height: 32px;
  padding: var(--e-1) var(--e-3); border-radius: var(--raio-md);
  border: 1px solid var(--linha);
  font-size: var(--t-xs); font-weight: 500;
  color: var(--tinta-2); text-decoration: none;
}
.criterios a:hover { color: var(--tinta); border-color: var(--linha-forte); }
.criterios a[aria-current="page"] {
  background: var(--sup-2); color: var(--tinta); border-color: var(--linha-forte);
}
/* No dedo, 32px e pouco: o minimo praticavel e ~44px (HIG/Material), e
   estes atalhos sao usados por tecnico em campo, em pe, com uma mao so.
   Medido em 375px em 21/09/2026. Vale para todas as telas que usam o
   componente — inicio, incidentes, historico e quedas da ONU. */
@media (max-width: 640px) {
  .criterios { gap: var(--e-2); }
  .criterios a { min-height: 44px; padding-inline: var(--e-4); }
}

/* table.dados mora em base.css — uma definicao so. */

.envolve { overflow-x: auto; margin-inline: calc(var(--e-5) * -1); padding-inline: var(--e-5); }

/* --------------------------------------------------------- ao vivo -- */
/* Sobrou so o PONTO: a Identificacao ao vivo — CTO, que era dona deste
   bloco, saiu em 21/09/2026. Quem usa hoje e o card "Consumo agora"
   (`partes/consumo.html`), que continua sendo leitura em laco de
   verdade. `.ao-vivo` e `.ao-vivo__indicador` sairam junto com ela —
   CSS que ninguem aplica e divida que parece componente. */
.ao-vivo__ponto {
  width: 8px; height: 8px; border-radius: 50%; background: var(--estado-critico);
  animation: ao-vivo-pulsar 1.2s ease-in-out infinite;
}
@keyframes ao-vivo-pulsar { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } }
@media (prefers-reduced-motion: reduce) { .ao-vivo__ponto { animation: none; } }

/* -------------------------------------------------------- sinais ---- */
.sinal { font-variant-numeric: tabular-nums; font-weight: 600; white-space: nowrap; }
/* A COR DE TEXTO, nao a de fundo. Os tokens `--estado-*` sao calibrados
   para preenchimento e borda; para TEXTO existem os `-texto`, criados
   em 07/10/2026 e medidos contra a pior superficie do produto (o cartao
   de papel quente da Wixx no claro):

                     telgo cartao/chao    wixx cartao/chao
       critico            5,57 / 4,73        4,90 / 5,25
       alerta             5,47 / 4,66        4,82 / 5,17
       ok                 6,22 / 5,29        5,48 / 5,87

   Esta classe continuava na cor de fundo. Medido em 08/10/2026 no
   cartao de campo, tema CLARO: bom 2,68 · atencao 1,53 · ruim 3,33 --
   os tres reprovando o piso de 4,5 da AA, no numero principal da tela
   que o tecnico le EM CIMA DA ESCADA, no sol. No tema escuro o token
   `-texto` resolve para a propria cor plena (ver tokens.css:414), entao
   la nada muda: 5,51 a 10,32, como ja estava. */
.sinal--bom      { color: var(--estado-ok-texto); }
.sinal--atencao  { color: var(--estado-alerta-texto); }
.sinal--ruim     { color: var(--estado-critico-texto); }
.sinal--sem_dado { color: var(--tinta-3); }

/* ---------------------------------------------------------------------
   Modulo de campo (/campo) -- tecnico sozinho, celular na mao, na rua.
   Alvo de toque acima do token padrao (--alvo-toque, 48px) de
   proposito: luva e sol pedem mais. Excecao deliberada, so aqui.
   --------------------------------------------------------------------- */
.campo-opcoes { display: grid; gap: var(--e-3); }
.campo-opcao {
  display: flex; align-items: center; gap: var(--e-4);
  min-height: 88px; padding: var(--e-4) var(--e-5);
  background: var(--sup-1); border: 1px solid var(--linha); border-radius: var(--raio-lg);
  color: var(--tinta); text-decoration: none;
}
.campo-opcao .ic { width: 32px; height: 32px; flex: none; color: var(--marca-primaria); }
.campo-opcao__texto { display: grid; gap: var(--e-1); min-width: 0; }
.campo-opcao__texto strong { font: 600 var(--t-md)/1.3 var(--fonte-titulo); }
.campo-opcao__texto span { color: var(--tinta-2); font-size: var(--t-sm); }
.campo-opcao--breve { opacity: .55; }
.campo-btn { min-height: 56px; width: 100%; font-size: var(--t-md); }
/* Botao dentro do cabecalho de um grupo: no celular ocupa a linha
   inteira (alvo grande); no trilho largo fica compacto a direita. */
/* `.campo-btn--grupo` saiu em 07/10/2026 junto com o botao "Atualizar
   ao vivo" da lista de campo — ver a nota em `campo_buscar.html`. As
   regras foram embora com ele: classe sem dono vira mobilia que o
   proximo acha que esta em uso. */

.campo-cartoes { display: grid; gap: var(--e-2); }
.campo-cartao {
  display: flex; align-items: center; justify-content: space-between; gap: var(--e-3);
  min-height: 64px; padding: var(--e-3) var(--e-4);
  border: 1px solid var(--linha); border-radius: var(--raio-md);
  color: var(--tinta); text-decoration: none;
}
.campo-cartao__texto { display: grid; gap: 2px; min-width: 0; }
.campo-cartao__texto strong { font-weight: 600; overflow-wrap: anywhere; }
.campo-cartao__texto span { color: var(--tinta-2); font-size: var(--t-sm); }
/* `flex: none` mantem a coluna do numero com a largura do conteudo --
   e ate 08/10/2026 esse conteudo era curto. Quando a subida passou a
   sair com a idade ("subida -29.6 · ha 30 min"), a coluna cresceu
   sozinha e espremeu o nome do cliente em 7 caracteres, quebrando em
   cinco linhas a 375px. Era o pior lugar possivel para acontecer: 375px
   e o tecnico em cima da escada.

   O TETO E A CORRECAO. `max-width` ainda vale num item com `flex:
   none`, entao a coluna para de crescer e a linha da subida quebra
   DENTRO dela, alinhada a direita como o resto. O nome fica com os
   outros ~58%. */
.campo-cartao__sinal { display: grid; justify-items: end; flex: none; margin-left: auto;
  max-width: 42%; font-variant-numeric: tabular-nums; line-height: 1.2; }
.campo-cartao__sinal > .sinal { font: 600 var(--t-lg)/1.2 var(--fonte-titulo); }
.campo-cartao__sinal small { font-size: var(--t-xs); color: var(--tinta-3);
  text-align: right; }

.campo-sinal { text-align: center; gap: var(--e-2); }
.campo-sinal__estado { display: flex; justify-content: center; gap: var(--e-2); flex-wrap: wrap; }
.campo-sinal__valor {
  font: 700 clamp(3rem, 14vw, 4.5rem)/1 var(--fonte-titulo);
  font-variant-numeric: tabular-nums;
}
.campo-sinal__valor small { font-size: .35em; font-weight: 500; }
.campo-sinal__leitura { font: 600 var(--t-lg)/1.25 var(--fonte-titulo); }
.campo-sinal__acao { color: var(--tinta-2); }
.campo-sinal--bom { border-color: var(--estado-ok); }
.campo-sinal--atencao { border-color: var(--estado-alerta); }
.campo-sinal--ruim { border-color: var(--estado-critico); }
.campo-leituras { display: grid; gap: var(--e-3); margin: 0; }
.campo-leituras > div { display: flex; justify-content: space-between; gap: var(--e-3); }
.campo-leituras dt { color: var(--tinta-2); }
.campo-leituras dd { margin: 0; font-variant-numeric: tabular-nums; }

/* Auditoria de CTO (campo_cto.html / campo_cto_ok.html) */
.campo-form { display: grid; gap: var(--e-4); }
.campo-cartao--fixo { cursor: default; }
.campo-foto {
  display: grid; justify-items: center; gap: var(--e-1); min-height: 88px; padding: var(--e-4);
  border: 2px dashed var(--linha-forte); border-radius: var(--raio-lg); background: var(--sup-2);
  color: var(--tinta-2); text-align: center; cursor: pointer;
}
.campo-foto .ic { width: 28px; height: 28px; color: var(--marca-primaria); }
.campo-foto strong { color: var(--tinta); font-size: var(--t-md); }
.campo-foto span { font-size: var(--t-xs); }
.campo-foto:focus-within { outline: 2px solid var(--marca-primaria); outline-offset: 2px; }
.campo-foto__previa { display: block; width: 100%; max-height: 320px; object-fit: cover;
  border-radius: var(--raio-md); border: 1px solid var(--linha); }
/* `display: block` acima venceria o [hidden] do navegador (mesma
   especificidade, ordem de autor) -- a previa apareceria quebrada
   antes de qualquer foto. Mesmo furo ja visto na sentinela. */
.campo-foto__previa[hidden] { display: none; }
/* Grade de portas: alvo grande, numero grande -- e so um jeito de
   digitar 1..16 com luva, nao um mapa da caixa. */
.porta-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--e-2); }
.porta-grid input { position: absolute; opacity: 0; pointer-events: none; }
.porta-grid label {
  display: grid; place-items: center; min-height: 56px;
  border: 2px solid var(--linha); border-radius: var(--raio-md); background: var(--sup-1);
  font: 600 var(--t-xl)/1 var(--fonte-titulo); cursor: pointer;
}
.porta-grid input:checked + label { border-color: var(--marca-primaria-forte); background: var(--marca-primaria-fraca); color: var(--marca-primaria-forte); }
.porta-grid input:focus-visible + label { outline: 2px solid var(--marca-primaria-forte); outline-offset: 2px; }
/* Confere / nao confere: cor E palavra, dois alvos grandes. */
.segmento { display: grid; grid-template-columns: 1fr 1fr; gap: var(--e-2); }
.segmento input { position: absolute; opacity: 0; pointer-events: none; }
.segmento label {
  display: grid; justify-items: center; gap: 2px; min-height: 64px; padding: var(--e-3);
  border: 2px solid var(--linha); border-radius: var(--raio-md); background: var(--sup-1);
  font-weight: 500; text-align: center; cursor: pointer;
}
.segmento label small { font-weight: 400; font-size: var(--t-xs); color: var(--tinta-3); }
.segmento input:checked + .segmento__sim { border-color: var(--estado-ok); background: var(--estado-ok-fraco); color: var(--estado-ok-forte); }
.segmento input:checked + .segmento__nao { border-color: var(--estado-critico); background: var(--estado-critico-fraco); color: var(--estado-critico-forte); }
.segmento input:focus-visible + label { outline: 2px solid var(--marca-primaria-forte); outline-offset: 2px; }
.campo-confirmado { justify-items: center; text-align: center; }
.campo-confirmado__ok { width: 64px; height: 64px; border-radius: 50%; background: var(--estado-ok-fraco);
  display: grid; place-items: center; }
.campo-confirmado__ok .ic { width: 34px; height: 34px; color: var(--estado-ok-forte); }
/* Tendencia do sinal (partes/tendencia.html + estatico/js/tendencia.js).
   Marcas finas, grade solida recuada, cor de estado so nos limiares e na
   faixa "fora do ar"; series em --grafico-* (identidade). */
.tendencia__cabecalho { display: flex; flex-wrap: wrap; align-items: center; gap: var(--e-2) var(--e-4); }
.tendencia__atalhos { max-width: 100%; }
/* No celular os dez atalhos viram uma tira que rola de lado (como a
   barra de navegacao), em vez de tres linhas de chips. */
@media (max-width: 640px) {
  /* `.abas` (definida mais abaixo) tem flex-wrap: wrap; a dupla classe
     ganha a especificidade sem !important. */
  .abas.tendencia__atalhos { flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .tendencia__atalhos a { white-space: nowrap; }
  .tendencia__barra { font-size: var(--t-xs); }
  /* No celular o grafico e a tabela rolam de lado dentro do card em vez
     de estourar a pagina: 7 dias de duas series nao cabem legiveis em
     375px, e a tabela de resumo vira a leitura principal. */
  .tendencia__area, .tendencia__rolagem { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .tendencia svg { min-width: 640px; }
}
.tendencia__barra { display: flex; flex-wrap: wrap; align-items: center; gap: var(--e-2) var(--e-4);
  margin: var(--e-2) 0 var(--e-3); font-size: var(--t-sm); color: var(--tinta-2); }
.tendencia__nav { display: inline-flex; gap: var(--e-1); }
.tendencia__botao { min-width: var(--alvo-toque, 44px); padding: 0 var(--e-2); font-size: var(--t-md); line-height: 1; }
.tendencia__botao[aria-disabled="true"] { opacity: .35; pointer-events: none; }
.tendencia__janela { font-variant-numeric: tabular-nums; white-space: nowrap; }
.tendencia__escala { color: var(--marca-primaria-forte, var(--tinta-2)); text-decoration: underline dotted; }
.tendencia__periodo summary { cursor: pointer; color: var(--tinta-2); }
.tendencia__form { display: flex; flex-wrap: wrap; align-items: end; gap: var(--e-2) var(--e-3); margin-top: var(--e-2); }
.tendencia__form label { display: flex; flex-direction: column; gap: var(--e-1); font-size: var(--t-xs); }
.tendencia { position: relative; }
.tendencia svg { width: 100%; height: auto; display: block; touch-action: pan-y; cursor: crosshair; }
#tendencia.htmx-request .tendencia { opacity: .55; transition: opacity var(--transicao, .15s); }
.tendencia__grade { stroke: var(--linha); stroke-width: 1; }
.tendencia__fora { fill: var(--estado-critico); opacity: .12; }
.tendencia__banda { stroke: none; opacity: .14; }
.tendencia__banda--descida { fill: var(--grafico-descida); }
.tendencia__banda--subida { fill: var(--grafico-subida); }
.tendencia__linha { fill: none; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.tendencia__linha--descida { stroke: var(--grafico-descida); }
.tendencia__linha--subida { stroke: var(--grafico-subida); stroke-dasharray: 6 4; }
.tendencia__solto--descida { fill: var(--grafico-descida); }
.tendencia__solto--subida { fill: var(--grafico-subida); }
.tendencia__leitura { fill: var(--grafico-subida); stroke: var(--sup-1); stroke-width: 2; }
.tendencia__limiar { stroke-dasharray: 4 4; stroke-width: 1; }
.tendencia__limiar--atencao { stroke: var(--estado-alerta); opacity: .7; }
.tendencia__limiar--ruim { stroke: var(--estado-critico); opacity: .7; }
.tendencia__marco { stroke: var(--tinta-2); stroke-width: 1.5; stroke-dasharray: 6 4; }
.tendencia__queda { stroke: var(--estado-critico); stroke-width: 1; opacity: .8; }
.tendencia__eixo, .tendencia__rotulo { fill: var(--tinta-3); font: 11px var(--fonte-corpo); font-variant-numeric: tabular-nums; }
.tendencia__eixo--borda { fill: var(--tinta-3); opacity: .8; }
/* Halo da cor do fundo: rotulo legivel mesmo cruzando linha ou faixa. */
.tendencia__rotulo { paint-order: stroke; stroke: var(--sup-1); stroke-width: 3px; stroke-linejoin: round; }
.tendencia__rotulo--atencao { fill: var(--estado-alerta-forte, var(--estado-alerta)); }
.tendencia__rotulo--ruim, .tendencia__rotulo--fora { fill: var(--estado-critico); }
.tendencia__selecao { fill: var(--marca-primaria); opacity: .18; }
.tendencia__mira-linha { stroke: var(--tinta-2); stroke-width: 1; pointer-events: none; }
.tendencia__mira-ponto { stroke: var(--sup-1); stroke-width: 2; pointer-events: none; }
.tendencia__mira-ponto--descida { fill: var(--grafico-descida); }
.tendencia__mira-ponto--subida { fill: var(--grafico-subida); }
.tendencia__dica { position: absolute; z-index: 2; pointer-events: none; background: var(--sup-2, var(--sup-1));
  color: var(--tinta); border: 1px solid var(--linha); border-radius: var(--raio-sm); box-shadow: var(--sombra-1);
  padding: var(--e-1) var(--e-2); font-size: var(--t-xs); white-space: nowrap; }
.tendencia__dica-quando { color: var(--tinta-3); margin-bottom: 2px; }
.tendencia__dica-linha { display: flex; align-items: center; gap: var(--e-1); font-variant-numeric: tabular-nums; }
.tendencia__dica-linha strong { color: var(--tinta); }
.tendencia__resumo { margin-top: var(--e-2); font-size: var(--t-xs); }
.tendencia__resumo td, .tendencia__resumo th { padding-top: 2px; padding-bottom: 2px; }
.tendencia__amostra { display: inline-block; width: 14px; height: 0; vertical-align: middle; margin-right: 4px; border-top: 2px solid var(--grafico-descida); }
.tendencia__amostra--subida { border-top: 2px dashed var(--grafico-subida); }
.tendencia__amostra--leitura { width: 8px; height: 8px; border: 0; border-radius: 50%; background: var(--grafico-subida); }

/* Fila do NOC (provisionar.html, aba CTO) */
.abas--filtro { font-size: var(--t-sm); }
.cto-mini { display: block; width: 72px; height: 48px; object-fit: cover; border-radius: var(--raio-sm);
  border: 1px solid var(--linha); background: var(--sup-2); }
.cto-resolver { min-width: 240px; }
.cto-resolver .campo { margin: 0; flex: 1; }

.selo {
  display: inline-flex; align-items: center; gap: var(--e-1);
  padding: 2px var(--e-2); border-radius: var(--raio-cheio);
  font-size: var(--t-xs); font-weight: 500; white-space: nowrap;
}
.selo--bom     { background: var(--estado-ok-fraco);      color: var(--estado-ok); }
.selo--atencao { background: var(--estado-alerta-fraco); color: var(--estado-alerta); }
.selo--ruim    { background: var(--estado-critico-fraco); color: var(--estado-critico); }
.selo--neutro  { background: var(--sup-2);                color: var(--tinta-2); }

/* ------------------------------------------------------- caixas ----- */
/* A quebra do incidente por CTO na tabela de incidentes. Os chips
   quebram linha em vez de esticar a coluna: numa porta de 7 caixas a
   celula viraria uma faixa horizontal e empurraria as outras colunas
   para fora da tela. `max-width` e o que segura isso — sem ele, o
   `white-space: nowrap` de cada selo soma e a tabela estoura. */
/* `min-width` junto porque a tabela vive num `.envolve` que rola na
   horizontal: sem ele, numa tela estreita a coluna encolhe ate caber um
   chip por linha e a linha do incidente vira uma torre. */
.caixas { min-width: 17rem; max-width: 26rem; }
.caixas__chips { display: flex; flex-wrap: wrap; gap: var(--e-1); align-items: center; }
.caixas .sub-celula { margin-top: var(--e-1); }

/* --------------------------------------------------- explicacao ----- */
/* Onde foi parar o texto que enchia a tela. Fica a um clique de quem
   precisa, e fora do caminho de quem esta atendendo. */
.porque { font-size: var(--t-sm); }
.porque > summary {
  cursor: pointer; color: var(--marca-primaria); font-size: var(--t-xs);
  list-style: none; display: inline-flex; align-items: center; gap: var(--e-1);
}
.porque > summary::-webkit-details-marker { display: none; }
.porque > summary::before { content: "?"; display: inline-grid; place-items: center;
  width: 14px; height: 14px; border: 1px solid currentColor; border-radius: 50%;
  font-size: 10px; line-height: 1; }
.porque[open] > summary { margin-bottom: var(--e-2); }
.porque p { color: var(--tinta-2); line-height: 1.6; max-width: 68ch; }

/* ---------------------------------------------------------- vazio --- */
.vazio { display: grid; gap: var(--e-2); justify-items: start; padding: var(--e-5) 0;
  color: var(--tinta-2); font-size: var(--t-sm); }
.vazio strong { color: var(--tinta); font: 500 var(--t-md)/1.3 var(--fonte-titulo); }

/* ---------------------------------------------------------- icone --- */
/* Manual da Telgo: estilo linha, cantos arredondados, azul claro, sem
   preenchimento. Os glifos de texto que estavam aqui antes tinham pesos
   opticos diferentes e nunca alinhavam. */
.ic { width: 18px; height: 18px; flex: none; stroke: currentColor; fill: none;
  stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }

/* ------------------------------------------------------- cabecalho -- */
.cabecalho__acoes { margin-left: auto; display: flex; align-items: center; gap: var(--e-3); }
.quem { display: inline-flex; align-items: center; gap: var(--e-2); font-size: var(--t-sm); }
.quem__nome { color: var(--tinta-2); }
/* No celular o nome do operador sai: ele sabe quem e. O que nao pode
   sair e o botao de sair nem o de tema. */
@media (max-width: 640px) { .quem__nome { display: none; } }
.so-largo { display: none; }
@media (min-width: 640px) { .so-largo { display: inline; } }

/* O menu recebe a marca: icone em azul claro institucional, e o item
   ativo ganha o amarelo como marcador — a unica cor que "chama". */
.nav a { display: flex; align-items: center; gap: var(--e-3); }
.nav a .ic { color: var(--marca-primaria); }
.nav a[aria-current="page"] { position: relative; }
.nav a[aria-current="page"]::before {
  content: ""; position: absolute; left: 0; top: 20%; bottom: 20%;
  width: 3px; border-radius: 0 2px 2px 0; background: var(--marca-acento);
}

/* ------------------------------------------------ apoio de tabela --- */
/* Informacao secundaria DENTRO da celula: host abaixo do nome, modelo
   abaixo do fabricante. Evita coluna extra so para um dado de apoio —
   coluna a mais e coluna que o olho precisa descartar. */
.sub-celula { display: block; font-size: var(--t-xs); color: var(--tinta-3); font-weight: 400; }

/* A COR DO DESVIO, DENTRO DA SUB-CELULA. `.sinal--ruim` e
   `.sinal--atencao` sao seletores de uma classe so (linhas 273-274), e
   a regra acima tambem — mesma especificidade, e quem vem DEPOIS no
   arquivo vence. O cinza de apoio apagava a cor de tres mensagens cuja
   unica funcao e chamar atencao. Medido no navegador em 07/10/2026:
   rgb(136,145,160) onde devia sair rgb(242,85,90).

       campo_buscar  "a OLT nao respondeu a esta leitura"
       campo_onu     "a referencia era de outra ONU"
       clientes      "cadastro diz <outra placa/porta>"

   Nenhuma delas tinha erro no molde: as tres pediam a cor certa e a
   folha devolvia cinza, calada. Este arquivo ja documenta a mesma
   armadilha em `.frota__valor` — la a saida foi NAO declarar `color`;
   aqui a sub-celula precisa do cinza como padrao, entao o desvio sobe
   de especificidade para recuperar o seu. */
.sub-celula.sinal--ruim    { color: var(--estado-critico-texto); }
.sub-celula.sinal--atencao { color: var(--estado-alerta-texto); }
.sub-celula.sinal--bom     { color: var(--estado-ok-texto); }

.pino { display: inline-block; width: 8px; height: 8px; border-radius: 50%; }
.pino--bom      { background: var(--estado-ok); }
.pino--atencao  { background: var(--estado-alerta); border-radius: 2px; transform: rotate(45deg); }
.pino--ruim     { background: var(--estado-critico); border-radius: 2px; }
.pino--vazia    { background: var(--tinta-3); opacity: .5; }
.pino--neutro   { background: var(--tinta-3); }
/* Sem contato NAO usa o cinza de "vazia": e alarme, nao ausencia. O anel
   o separa do vermelho de "muitos clientes fora", que e outra coisa. */
.pino--sem_contato { background: var(--estado-critico); border-radius: 2px;
  box-shadow: 0 0 0 3px var(--estado-critico-fraco); }
/* Forma muda junto com a cor — redundancia para daltonicos, mesmo
   principio do .estado (ver base.css). Bom fica circulo (a forma que
   ja tinha), atencao vira losango, ruim/sem_contato viram quadrado. */

.volta { font-size: var(--t-sm); }
.volta a { color: var(--tinta-2); }

/* --------------------------------------------------------- busca ---- */
.busca__campos { display: flex; flex-wrap: wrap; gap: var(--e-3); align-items: flex-end;
  min-width: 0; }
.busca .campo { margin: 0; }
.campo--cresce { flex: 1; min-width: 240px; }

/* ------------------------------------------------------- alertas ---- */
.lista-alertas { display: grid; gap: var(--e-3); list-style: none; }
.lista-alertas li { display: flex; gap: var(--e-3); align-items: flex-start;
  font-size: var(--t-sm); line-height: 1.55; }
.lista-alertas .ic { color: var(--estado-alerta); margin-top: 2px; }

/* ------------------------------------------------- acoes na linha --- */
/* Varios formularios de um botao so na mesma celula. Sem o flex eles
   empilhariam, e a linha da tabela cresceria tres vezes. */
/* Varios formularios de um botao so na mesma celula.
   `display: contents` no <form> NAO funciona aqui: o elemento sai do
   fluxo mas os botoes nao viram filhos diretos do flex de forma
   confiavel, e eles se sobrepoem. Cada form vira um item inline do
   proprio flex — mais simples e previsivel. */
/* O FLEX VAI NUM DIV DENTRO DA CELULA, nunca no <td>.
   Um <td> com display:flex deixa de ser celula de tabela: para de
   participar do layout da linha, e o conteudo VAZA para fora dela em
   vez de faze-la crescer. Foi exatamente o que aconteceu aqui — os
   botoes apareciam por cima da linha seguinte. */
.acoes-linha { white-space: nowrap; }
.acoes-linha > div { display: flex; gap: var(--e-2); flex-wrap: wrap; align-items: center; }
.acoes-linha form { margin: 0; display: inline-flex; }
.acoes-linha .btn {
  font-size: var(--t-xs); padding: 0 var(--e-3); white-space: nowrap;
  /* O botao geral respeita o alvo minimo de toque (44px). Dentro de uma
     linha de tabela isso engorda a linha inteira tres vezes. Aqui ele
     encolhe — e no celular a media query devolve o alvo, porque ai o
     dedo e o ponteiro. */
  min-height: 28px;
}
@media (max-width: 640px) { .acoes-linha .btn { min-height: var(--alvo-min); } }


/* ------------------------------------------------- formulario ------- */
/* Coluna unica com largura maxima legivel. Formulario de configuracao em
   duas colunas obriga o olho a decidir por onde comecar, e sobra vazio
   de um lado — a assimetria que o usuario apontou. */
.coluna { display: grid; gap: var(--e-5); max-width: 620px; }
.coluna--larga { max-width: 900px; }

/* Duas integracoes independentes e de peso comparavel: lado a lado
   preenchem a tela e cabem juntas no campo de visao. A regra que vale e
   a MESMA de antes — o que nao pode e emparelhar blocos desiguais, que
   deixa um vazio de um lado. Cada coluna mantem a largura maxima
   legivel; o limite e a linha de texto, nao a tela. */
.painel-config { display: grid; gap: var(--e-5); align-items: start; }
@media (min-width: 1100px) {
  .painel-config { grid-template-columns: repeat(2, minmax(0, 620px)); }
}

/* Campos que nao precisam da largura toda param antes. Um campo de porta
   com 600px de largura sugere que cabe mais coisa nele do que cabe. */
.campo--curto { max-width: 140px; }
.campo--medio { max-width: 300px; }

/* Dois campos lado a lado quando sao a MESMA decisao (porta e seguranca
   se escolhem juntas — errar o par e a falha mais comum). */
.par { display: flex; gap: var(--e-3); flex-wrap: wrap; align-items: flex-end; }
.par > .campo { margin: 0; }

@media (max-width: 640px) {
  /* iOS da zoom em campo com fonte menor que 16px. Aqui a regra volta. */
  .campo input, .campo select, .campo textarea { font-size: var(--t-lg); }
}

/* Linha de acao ao pe do formulario, separada do ultimo campo por uma
   regua: marca onde a leitura acaba e a decisao comeca. */
.acoes { display: flex; gap: var(--e-3); align-items: center; flex-wrap: wrap;
  padding-top: var(--e-4); border-top: 1px solid var(--linha); }

/* A coluna de acoes precisa reservar espaco: sem largura minima ela
   encolhe ate os botoes transbordarem da celula. */
.col-acoes { min-width: 190px; }
.acoes-linha { padding-block: var(--e-2); }

/* ------------------------------------------- acoes de conta (28/08/2026) */
/* Consolida corrigir-nome + nova-senha/destravar + desativar/reativar
   atras de UM disclosure por linha, em vez de tres controles sempre
   visiveis. Expande INLINE (empurra a linha, nao flutua por cima) de
   proposito: um popover posicionado absoluto dentro de `.envolve`
   (que tem overflow-x:auto para a tabela rolar) arrisca ser cortado
   pela propria rolagem — inline nunca corta. */
.acoes-conta > summary { list-style: none; cursor: pointer; }
.acoes-conta > summary::-webkit-details-marker { display: none; }
.acoes-conta__corpo {
  display: grid; gap: var(--e-3);
  margin-top: var(--e-2); padding: var(--e-3);
  background: var(--sup-2); border-radius: var(--raio-md);
  border: var(--borda) solid var(--linha);
}
.acoes-conta__corpo .linha-form { flex-wrap: nowrap; }
.acoes-conta__corpo input[type="text"] { min-width: 0; flex: 1; }

/* Abaixo de 1100px a grade vira uma coluna, e as posicoes fixas de
   linha/coluna dos blocos precisam sair do caminho — senao sobra buraco
   onde a segunda coluna existia. */
@media (max-width: 1099px) {
  .painel-config > .bloco { grid-column: 1 !important; grid-row: auto !important; }
}

/* ----------------------------------------------------------- abas --- */
/* A aba selecionada vive no ENDERECO, nao no navegador: o link pode ser
   guardado e compartilhado, e quem volta de um POST cai onde estava.
   Sem JavaScript — uma tela de configuracao nao pode depender dele. */
.abas { display: flex; gap: var(--e-1); border-bottom: 1px solid var(--linha);
  margin-bottom: calc(var(--e-5) * -1 + var(--e-2)); flex-wrap: wrap; }
.abas a {
  padding: var(--e-3) var(--e-4);
  font: 500 var(--t-md)/1 var(--fonte-titulo);
  color: var(--tinta-2); text-decoration: none;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.abas a:hover { color: var(--tinta); }
.abas a[aria-current="page"] {
  color: var(--tinta);
  /* Amarelo institucional marca onde voce esta — mesmo papel que ele
     tem no menu lateral, para a regra ser uma so na aplicacao inteira. */
  border-bottom-color: var(--marca-acento);
}
.coluna--larga { display: grid; gap: var(--e-5); max-width: 720px; }

/* -------------------------------------------------- saude da OLT ---- */
/* Cartoes largos o bastante para o numero ser lido de longe, e estreitos
   o bastante para caberem cinco numa linha — quem abre a tela de uma OLT
   quer o estado dela num olhar, nao um rolar. */
.saude { display: grid; gap: var(--e-3);
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); }
.medida {
  display: grid; gap: 2px; padding: var(--e-4);
  background: var(--sup-1); border: 1px solid var(--linha);
  border-radius: var(--raio-lg); border-left-width: 3px;
}
.medida__rotulo { font-size: var(--t-xs); color: var(--tinta-2);
  text-transform: uppercase; letter-spacing: .06em; }
.medida__valor { font: 600 var(--t-2xl)/1.1 var(--fonte-titulo);
  font-variant-numeric: tabular-nums; }
.medida__detalhe { font-size: var(--t-xs); color: var(--tinta-3); }

/* A cor mora na BORDA e no valor, nunca no fundo: cinco cartoes com
   fundo colorido viram um semaforo quebrado, e o olho para de
   distinguir o que e grave do que e so diferente. */
.medida--bom     { border-left-color: var(--estado-ok); }
.medida--atencao { border-left-color: var(--estado-alerta); }
.medida--atencao .medida__valor { color: var(--estado-alerta); }
.medida--ruim    { border-left-color: var(--estado-critico); }
.medida--ruim    .medida__valor { color: var(--estado-critico); }
.medida--neutro  { border-left-color: var(--linha-forte); }

/* ----------------------------------------------------------- gaveta -- */
/* Configuração esporádica recolhida: fechada por padrão, abre no clique.
   Reaproveita .bloco (mesma superfície e borda) mas o <summary> é a
   dobradiça. Sem JavaScript — <details> nativo cuida do estado. */
.gaveta { padding: 0; }
.gaveta > summary {
  display: flex; align-items: center; gap: var(--e-3); flex-wrap: wrap;
  padding: var(--e-4) var(--e-5);
  cursor: pointer; list-style: none;
  border-radius: var(--raio-lg);
}
.gaveta > summary::-webkit-details-marker { display: none; }
/* Seta que gira ao abrir — a affordance de "isto expande". */
.gaveta > summary::before {
  content: ""; width: 8px; height: 8px; flex: none;
  border-right: 2px solid var(--tinta-2); border-bottom: 2px solid var(--tinta-2);
  transform: rotate(-45deg); transition: transform var(--transicao);
}
.gaveta[open] > summary::before { transform: rotate(45deg); }
.gaveta > summary:hover { background: var(--sup-2); }
.gaveta__titulo { font: 500 var(--t-lg)/1.2 var(--fonte-titulo); color: var(--marca-primaria); }
/* O resumo empurrado para a direita: informa o estado sem abrir. */
.gaveta__resumo { margin-left: auto; display: flex; align-items: center; gap: var(--e-2);
  font-size: var(--t-sm); color: var(--tinta-2); }
.gaveta__corpo { padding: 0 var(--e-5) var(--e-5); display: grid; gap: var(--e-4);
  border-top: 1px solid var(--linha); padding-top: var(--e-4); }
/* No celular o resumo desce para baixo do título, para não competir. */
@media (max-width: 560px) {
  .gaveta__resumo { margin-left: 0; width: 100%; }
}
/* Grade de saude dentro do <summary> de uma gaveta (visao "frota", uma
   gaveta por OLT): flex-basis 100% forca a propria linha, abaixo do
   titulo, em vez de disputar espaco horizontal com ele. */
.gaveta__saude { flex-basis: 100%; margin: 0; }
/* Explicações de referência dentro da gaveta: título curto em Rubik e
   parágrafo com medida de linha confortável (mesma leitura do .porque). */
.gaveta__corpo h3 { font: 600 var(--t-md)/1.3 var(--fonte-titulo);
  color: var(--tinta); margin-bottom: var(--e-2); }
/* Sub-cabeçalho dentro do corpo de uma gaveta (ex.: "Parece
   infraestrutura" dentro de "Fora agora"): mesmo estilo de `.bloco >
   header`, que não alcança mais aqui — agora há um nível a mais
   (.gaveta__corpo) entre a caixa e o header. */
.gaveta__corpo > header { display: flex; align-items: baseline; gap: var(--e-3); flex-wrap: wrap; }
.gaveta__corpo > header h2 {
  font: 600 var(--t-lg)/1.25 var(--fonte-titulo); color: var(--marca-primaria);
}
.gaveta__corpo .explica { color: var(--tinta-2); font-size: var(--t-sm);
  line-height: 1.6; max-width: 68ch; }

/* -------------------------------------------------- abas por placa -- */
/* Abas em CSS puro: radio escondido + :checked revela o painel. Sem
   JavaScript, troca instantânea — a página carrega a saúde do Zabbix, e
   recarregar por aba seria lento. Cada placa GPON do chassi é uma aba.

   Estrutura: os radios são IRMÃOS diretos de .placas, seguidos de
   .placas__abas (os labels) e .placas__conteudo (os painéis). Assim
   `radio:checked ~` alcança tanto a aba quanto o painel corretos. */
.placas__radio { position: absolute; opacity: 0; width: 0; height: 0; }
.placas__abas { display: flex; gap: var(--e-1); flex-wrap: wrap;
  border-bottom: 1px solid var(--linha); margin-bottom: var(--e-4); }
.placas__aba {
  display: inline-flex; align-items: center; gap: var(--e-2);
  padding: var(--e-3) var(--e-4); cursor: pointer;
  font: 500 var(--t-md)/1 var(--fonte-titulo); color: var(--tinta-2);
  border-bottom: 2px solid transparent; margin-bottom: -1px; white-space: nowrap;
}
.placas__aba:hover { color: var(--tinta); }
.placas__meta { font-size: var(--t-xs); color: var(--tinta-3); font-weight: 400; }
/* Placa única num chassi Huawei: mesmo visual da aba ativa, mas estático —
   não é clicável (uma placa só não navega para lugar nenhum). Serve para
   as Huawei ficarem visualmente iguais entre si, tenham 1 placa ou 4. */
.placas__abas--fixa { cursor: default; }
.placas__aba--fixa { color: var(--tinta); border-bottom-color: var(--marca-acento); cursor: default; }
/* Foco visível para navegação por teclado (WCAG): o radio é invisível,
   então o anel de foco vai para o label. */
.placas__radio:focus-visible + label,
.placas__radio:focus-visible ~ .placas__abas .placas__aba { outline: 2px solid var(--marca-primaria); outline-offset: -2px; }

.placas__painel { display: none; }
.placas__conteudo > .placas__painel { display: none; }

/* Até 12 placas — mais que qualquer chassi GPON real. O radio marcado
   revela a aba e o painel de mesma posição. */
.placas__radio:nth-of-type(1):checked ~ .placas__abas .placas__aba:nth-child(1),
.placas__radio:nth-of-type(2):checked ~ .placas__abas .placas__aba:nth-child(2),
.placas__radio:nth-of-type(3):checked ~ .placas__abas .placas__aba:nth-child(3),
.placas__radio:nth-of-type(4):checked ~ .placas__abas .placas__aba:nth-child(4),
.placas__radio:nth-of-type(5):checked ~ .placas__abas .placas__aba:nth-child(5),
.placas__radio:nth-of-type(6):checked ~ .placas__abas .placas__aba:nth-child(6),
.placas__radio:nth-of-type(7):checked ~ .placas__abas .placas__aba:nth-child(7),
.placas__radio:nth-of-type(8):checked ~ .placas__abas .placas__aba:nth-child(8) {
  color: var(--tinta); border-bottom-color: var(--marca-acento);
}
.placas__radio:nth-of-type(1):checked ~ .placas__conteudo > .placas__painel:nth-child(1),
.placas__radio:nth-of-type(2):checked ~ .placas__conteudo > .placas__painel:nth-child(2),
.placas__radio:nth-of-type(3):checked ~ .placas__conteudo > .placas__painel:nth-child(3),
.placas__radio:nth-of-type(4):checked ~ .placas__conteudo > .placas__painel:nth-child(4),
.placas__radio:nth-of-type(5):checked ~ .placas__conteudo > .placas__painel:nth-child(5),
.placas__radio:nth-of-type(6):checked ~ .placas__conteudo > .placas__painel:nth-child(6),
.placas__radio:nth-of-type(7):checked ~ .placas__conteudo > .placas__painel:nth-child(7),
.placas__radio:nth-of-type(8):checked ~ .placas__conteudo > .placas__painel:nth-child(8) {
  display: block;
}

/* ----------------------------------------------- frota (Saude) ----- */
/* Correcao de 2026-08-06: a versao anterior era um CARTAO por metrica —
   10 OLTs x 6 metricas = 60 cartoes, cada um com numero em peso 600 e
   borda colorida. O Jaime resumiu: "muita informacao, muitas cores,
   virou um caos". Ele estava certo, e a raiz era estrutural: seis
   metricas IGUAIS repetidas em dez equipamentos e uma MATRIZ, nao um
   conjunto de cartoes. Cartao serve pra conteudo heterogeneo; matriz
   pede tabela — so assim o olho consegue varrer uma COLUNA e responder
   "quem esta com processador alto?", que e a pergunta real do NOC.

   Nao virou <table> de verdade porque cada linha precisa continuar
   sendo uma gaveta (o espelho de SFP abre dentro dela), e <details>
   nao vive num <tr>. A solucao: todas as linhas usam o MESMO
   grid-template — o alinhamento vertical da a leitura de coluna, a
   semantica de <details> continua intacta.

   AS TRES REGRAS DE COR AQUI:
   1. Verde nao existe. "Esta tudo bem" e a linha de base e deve ser
      silenciosa — num painel onde a maioria esta ok, pintar o ok de
      verde gasta a mesma tinta do vermelho e rouba a forca dele.
      Valor normal = tinta neutra, peso normal.
   2. So o DESVIO ganha tinta — e ganha peso junto (600). A hierarquia
      nasce da anomalia, nao e distribuida igualmente.
   3. Cor nunca sozinha: o desvio carrega a forma do .sinal que ja
      existe no design system (losango = atencao, quadrado = ruim). */
/* A FROTA E UMA TABELA, NAO DEZ CARTOES.
   -------------------------------------------------------------------
   `.frota__linha` e um `.bloco`, entao cada OLT herdava fundo, borda,
   raio e — depois que pus sombra no cartao, em 14/08/2026 — sombra
   tambem. Dez cartoes empilhados, cada um pedindo a atencao que o
   conjunto deveria pedir uma vez. Com 10 OLTs, quatro cabiam na tela.

   Agora o CARTAO e a lista inteira; a linha e linha, separada por fio.
   O `.bloco` da linha e neutralizado aqui em vez de trocado no
   template, porque `<details class="gaveta bloco">` tambem carrega o
   comportamento de gaveta — que continua valendo. */
.frota {
  display: grid; gap: 0;
  background: var(--sup-1);
  border: 1px solid var(--linha);
  border-radius: var(--raio-lg);
  box-shadow: 0 1px 2px rgb(51 61 71 / 7%);
  overflow: hidden;
}
.frota__linha {
  background: none; border: 0; border-radius: 0; box-shadow: none;
  gap: 0;
  border-bottom: 1px solid var(--linha);
}
.frota > .frota__linha:last-child { border-bottom: 0; }
.frota__cabecalho { border-bottom: 1px solid var(--linha); background: var(--sup-2); }

/* O primeiro track de 10px e onde cai o ::before (a seta da gaveta).
   O cabecalho tem uma celula vazia na mesma posicao pra alinhar. */
.frota__cabecalho,
.frota__linha > summary {
  display: grid;
  grid-template-columns:
    10px minmax(160px, 2.2fr) repeat(6, minmax(72px, 1fr)) minmax(64px, 0.7fr);
  gap: var(--e-3);
  align-items: baseline;
}
.frota__cabecalho {
  padding: var(--e-2) var(--e-4);
  font-size: var(--t-xs); font-weight: var(--peso-forte);
  text-transform: uppercase; letter-spacing: .04em;
  color: var(--tinta-2);
}
.frota__cabecalho > span:first-child { content: ""; }   /* vaga da seta */

.frota__linha { padding: 0; }
.frota__linha > summary { padding: var(--e-2) var(--e-4); }

/* Fabricante ao LADO do nome, nao embaixo: empilhado, cada OLT
   ocupava duas alturas de texto — vinte linhas para dez equipamentos. */
.frota__olt { display: flex; flex-wrap: wrap; align-items: baseline;
  gap: 0 var(--e-2); min-width: 0; }
.frota__olt a { font: 500 var(--t-md)/1.25 var(--fonte-titulo); }
.frota__fab { font-size: var(--t-xs); color: var(--tinta-3); }

.frota__celula { display: grid; gap: 1px; min-width: 0; }
/* O rotulo por celula existe SEMPRE no DOM (leitor de tela precisa
   dele — o cabecalho e um <div>, nao um <th>, e nao se associa a
   celula nenhuma), mas fica invisivel no desktop, onde o cabecalho ja
   diz a mesma coisa. No celular ele reaparece, porque la o cabecalho
   sai de cena. */
.frota__rotulo {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
/* NAO declara `color` aqui, e isso e deliberado: `.sinal--atencao` /
   `.sinal--ruim` tambem sao seletores de uma classe so, e este bloco
   vem DEPOIS deles no arquivo — um `color` aqui venceria por ordem e
   apagaria justamente a cor do desvio, deixando a tela inteira
   monocromatica. Foi o que aconteceu na primeira versao. O valor
   normal herda --tinta do body, que ja e o que queremos. */
.frota__valor {
  font-variant-numeric: tabular-nums;
  font-size: var(--t-md);
}
/* Uptime e contexto, nao metrica com limiar: nao pode competir de
   igual pra igual com processador a 100%. */
.frota__valor--neutro { color: var(--tinta-2); }
.frota__valor--vazio { color: var(--tinta-3); }
.frota__quando { font-size: var(--t-xs); color: var(--tinta-3); white-space: nowrap; }

/* 78rem (1248px), nao os 60rem do resto da aplicacao — este breakpoint
   e por CONTEUDO, medido: os tracks somam 794px de largura minima
   (10 + 160 + 6x72 + 64, mais 8 gaps de 12 e o padding do bloco). Numa
   tela de 960px sobram 680px uteis depois do menu lateral (232) e do
   padding (48) — a tabela NAO CABE e os rotulos do cabecalho colidem
   ("TEMPERATURVENTOINHAS"). So a partir de ~1100px ela cabe; 78rem da
   folga. Abaixo disso vale a versao de duas colunas, que funciona bem
   em qualquer largura. */
@media (max-width: 78rem) {
  .frota__cabecalho { display: none; }
  /* A SETA SAI DO FLUXO AQUI, e isso nao e detalhe: enquanto ela
     ocupava uma faixa de 10px na grade, o posicionamento automatico
     jogava a PRIMEIRA metrica dentro dessa faixa — 10px de largura,
     transbordando por cima da metrica seguinte. Os rotulos saiam
     escritos um sobre o outro ("RESPOSTPROCESSADOR"). Fora do fluxo,
     as seis metricas caem limpas em duas colunas iguais. */
  .frota__linha > summary {
    position: relative;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    padding-left: calc(var(--e-4) + var(--e-4));
    row-gap: var(--e-3);
  }
  .frota__linha > summary::before {
    position: absolute; left: var(--e-4); top: calc(var(--e-3) + 4px);
  }
  /* O nome da OLT ocupa a linha inteira; as metricas caem em duas
     colunas embaixo, cada uma com o proprio rotulo de volta. */
  .frota__olt { grid-column: 1 / -1; }
  .frota__rotulo {
    position: static; width: auto; height: auto; clip: auto;
    margin: 0; overflow: visible;
    font-size: var(--t-xs); color: var(--tinta-3);
    text-transform: uppercase; letter-spacing: .04em;
  }
  .frota__quando { grid-column: 1 / -1; }
}

/* ---------------------------------------------- tabela interativa ---- */
/* Ordenar clicando no cabecalho e redimensionar arrastando a borda.
   A classe e posta pelo js/tabela.js — sem JS a tabela continua
   legivel e completa, so nao ordena. */
.dados--interativa th {
  position: relative; cursor: pointer; user-select: none;
  padding-right: calc(var(--e-3) + 10px);   /* espaco da seta e da alca */
}
.dados--interativa th:focus-visible { outline: 2px solid var(--marca-secundaria); outline-offset: -2px; }

/* A seta so aparece na coluna ordenada. Marcar todas com um simbolo
   "ordenavel" encheria o cabecalho de ruido para dizer o obvio. */
.dados--interativa th[aria-sort="ascending"]::after,
.dados--interativa th[aria-sort="descending"]::after {
  content: "▲"; font-size: .62em; margin-left: var(--e-2); opacity: .85;
}
.dados--interativa th[aria-sort="descending"]::after { content: "▼"; }

/* Alca de 16px, INTEIRA dentro da coluna. 8px era alvo pequeno demais,
   para o mouse e sobretudo para o dedo no tablet do NOC.
   
   E ela nao pode avancar para fora (`right: -8px`), por mais tentador
   que seja dobrar a area montando na borda: TODO `th` aqui e
   `position: sticky`, e o th SEGUINTE, por vir depois no DOM, pinta por
   cima da parte que avanca. O resultado e uma alca que se ve, tem o
   cursor certo, e nao recebe o clique — `elementFromPoint` no meio dela
   devolvia o th vizinho. Pego na bancada, com sonda de evento. */
.col-pega {
  position: absolute; top: 0; right: 0; width: 16px; height: 100%;
  cursor: col-resize; touch-action: none; z-index: 1;
}
/* O realce e uma listra fina no meio da alca, nao a alca inteira: pintar
   16px sugeriria que a coluna cresceu. */
.col-pega:hover::before {
  content: ""; position: absolute; inset: 15% auto 15% 50%;
  width: 2px; background: var(--marca-secundaria);
}

/* Durante o arraste o cursor vale para a pagina toda: sair de cima da
   alca no meio do movimento nao pode trocar o cursor nem selecionar
   texto. */
body.redimensionando { cursor: col-resize; user-select: none; }

/* `table-layout: fixed` e o que faz a largura arrastada COLAR — mas ele
   tambem reparte a tabela em colunas iguais, ignorando o conteudo. Posto
   desde o inicio, espremia 8 colunas em partes iguais e quebrava palavra
   no meio: "Despach a tecnico", "JDEURO PA-CX35". Visto na bancada antes
   de ir para a tela.
   Por isso ele so entra QUANDO a pessoa arrasta a primeira coluna — o
   JS congela as larguras atuais e acrescenta esta classe. Ate la, o
   navegador distribui pelo conteudo, que e o que se quer. */
.dados--larguras-fixas { table-layout: fixed; }
.dados--larguras-fixas td { overflow-wrap: anywhere; }


/* Agrupamento por SENTIDO na tabela de optico. A equipe confundia RSSI
   com o Rx da ONU porque os dois sao "um numero em dBm" na mesma lista;
   separados por descida/subida a confusao nao tem onde nascer. */
.dados__sentido td {
  padding-top: 1.1rem;
  border-bottom: 1px solid var(--borda);
  font: 600 var(--t-xs)/1.4 var(--fonte-titulo, inherit);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--texto-suave);
}
.dados tbody tr:first-child.dados__sentido td { padding-top: 0; }
/* Medida que este fabricante nao entrega. Fica visivel de proposito: a
   lacuna e informacao, e escondi-la faria a Huawei parecer completa. */
.dados__ausente { color: var(--texto-suave); font-style: italic; }

/* Segunda linha do cabecalho: a unidade e o sentido da medida, sem
   competir com o nome da coluna. */
.th__nota {
  display: block;
  font-weight: 400;
  font-size: var(--t-xs);
  letter-spacing: 0.06em;
  color: var(--texto-suave);
  text-transform: none;
}

/* Nome que se repete na linha seguinte vira ditto. O leitor de tela
   recebe o nome inteiro pelo aria-label; o olho recebe silencio. */
.repetido { color: var(--tinta-3); user-select: none; }

/* Contagem que MEDE, em vez de decorar. Todas as ocorrencias usavam o
   mesmo selo amarelo — 2 e 4 pintados igual. Aqui o normal e tinta
   comum, e so o que passa do esperado ganha peso e cor. */
.conta {
  font-variant-numeric: tabular-nums;
  font-weight: var(--peso-forte);
  color: var(--tinta-2);
}
.conta--forte {
  color: var(--estado-alerta-forte);
  background: var(--estado-alerta-fraco);
  border-radius: 3px; padding: .1em .4em;
}


/* =====================================================================
   MOSAICO DE INDICADORES — o Dashboard responde por decisao
   =====================================================================
   O painel era organizado pela estrutura do dado: uma secao por
   conceito, cada uma com gaveta. Para responder "preciso mandar alguem
   agora?" o operador abria tres e somava de cabeca. Pior, o texto que
   explicava a cobertura do retrato era o MAIOR elemento da tela — cinco
   linhas de prosa listando OLT por OLT.

   Aqui cada azulejo responde UMA pergunta, e quem quer detalhe clica.
   A cobertura vira um numero (26%) em vez de um paragrafo: mais curto
   E mais visivel, porque paragrafo em painel ninguem le.

   Cor e excecao, como no resto da casa: `--apagado` e o normal. Um
   "0 para despachar" nao merece verde, merece silencio. */
.mosaico {
  display: grid; gap: var(--e-3);
  grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr));
}
.azulejo {
  display: grid; gap: var(--e-1); align-content: start;
  padding: var(--e-4);
  background: var(--sup-1);
  border: 1px solid var(--linha);
  border-left: 3px solid var(--linha);
  border-radius: var(--raio-lg);
  box-shadow: 0 1px 2px rgb(51 61 71 / 7%);
  color: inherit; text-decoration: none;
}
a.azulejo:hover { border-color: var(--marca-primaria); }
a.azulejo:hover .azulejo__ir { opacity: 1; }
a.azulejo:focus-visible { outline: 2px solid var(--marca-primaria); outline-offset: 2px; }

.azulejo__rotulo {
  font: 600 var(--t-xs)/1.2 var(--fonte-titulo);
  letter-spacing: .09em; text-transform: uppercase; color: var(--tinta-3);
}
.azulejo__valor {
  font: 600 1.9rem/1 var(--fonte-titulo);
  font-variant-numeric: tabular-nums; color: var(--tinta);
}
.azulejo__nota {
  font-size: var(--t-xs); color: var(--tinta-2);
  overflow-wrap: anywhere;
}
/* A seta so aparece no hover: em cinco azulejos, cinco setas fixas
   viram ruido — e todos sao clicaveis, entao a seta nao distingue. */
.azulejo__ir {
  font-size: var(--t-xs); color: var(--marca-primaria);
  opacity: 0; transition: opacity 120ms;
}
@media (prefers-reduced-motion: reduce) { .azulejo__ir { transition: none; } }

/* Estado. O friso de 3px na esquerda carrega a gravidade sem depender
   de cor sozinha — quem nao distingue vermelho de amarelo ainda ve que
   aquele azulejo tem marca e os outros nao. */
.azulejo--apagado .azulejo__valor { color: var(--tinta-3); }
.azulejo--alerta  { border-left-color: var(--estado-alerta); }
.azulejo--alerta  .azulejo__valor { color: var(--estado-alerta-forte); }
.azulejo--critico { border-left-color: var(--estado-critico); }
.azulejo--critico .azulejo__valor { color: var(--estado-critico-forte); }


/* =====================================================================
   FILA DE CAMPO — a porta crônica que merece deslocamento de equipe

   Não é uma tabela porque não se compara linha a linha: cada item aqui
   é uma ordem de serviço em potencial, e o que importa é ler os quatro
   fatos dela junto — onde, quanto custou, com que frequência, e que
   tipo de equipe resolve. Tabela com essas cinco colunas morria no
   celular; empilhado, o mesmo conteúdo cabe em 375px sem rolagem
   lateral.
   ================================================================== */
.fila { display: grid; gap: var(--e-2); }

.fila__titulo {
  font: var(--peso-forte) var(--t-md)/1.3 var(--fonte-titulo);
  color: var(--tinta);
  display: grid; gap: var(--e-1);
  margin: var(--e-2) 0 0;
}

.ordem {
  display: grid; gap: var(--e-2);
  padding: var(--e-4) 0;
  border-top: 1px solid var(--linha);
}
.ordem:last-child { padding-bottom: 0; }

.ordem__topo {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: var(--e-4); flex-wrap: wrap;
}

.ordem__alvo { display: grid; gap: var(--e-1); min-width: 0; }
.ordem__alvo > div:first-of-type {
  font: var(--peso-medio) var(--t-md)/1.3 var(--fonte-corpo);
  color: var(--tinta);
}

/* O número que ORDENA a fila fica do tamanho do papel que exerce. Se a
   perda é o critério, ela não pode aparecer como um dado lateral. */
.ordem__perda { text-align: right; flex: none; }
.ordem__perda-valor {
  display: block;
  font: var(--peso-forte) var(--t-2xl)/1 var(--fonte-titulo);
  font-variant-numeric: tabular-nums;
  color: var(--estado-alerta-forte);
}
.ordem__perda-rotulo {
  display: block; margin-top: var(--e-1);
  font-size: var(--t-xs); line-height: 1.25; color: var(--tinta-3);
}

.ordem__fatos {
  margin: 0; font-size: var(--t-sm); color: var(--tinta-2);
  font-variant-numeric: tabular-nums;
}
.ordem__fatos strong { color: var(--tinta); }

/* A instrução de despacho é a saída da tela. Fio à esquerda em vez de
   fundo colorido: marca sem competir com o número da perda. */
.ordem__acao {
  margin: 0; padding-left: var(--e-3);
  border-left: 2px solid var(--marca-primaria);
  font-size: var(--t-sm); color: var(--tinta-2);
}
.ordem__acao strong { color: var(--tinta); }


/* =====================================================================
   OLT MUDA — o aviso que precede os números

   Vermelho cheio na borda esquerda, largura inteira, acima dos
   azulejos. É o único elemento da página com esse tratamento, e é
   deliberado: dois avisos "máximos" na mesma tela viram um só, ignorado.

   Fundo com o vermelho a 8% em vez de sólido — a tela é escura e um
   bloco vermelho cheio queimaria ao lado dos azulejos, além de puxar o
   olho para longe do TEXTO, que é onde está a informação.
   ================================================================== */
.mudo {
  display: grid; gap: var(--e-3);
  padding: var(--e-4) var(--e-5);
  margin-bottom: var(--e-4);
  background: color-mix(in srgb, var(--estado-critico) 8%, var(--sup-1));
  border: 1px solid color-mix(in srgb, var(--estado-critico) 35%, transparent);
  border-left: 4px solid var(--estado-critico);
  border-radius: var(--raio-lg);
}

.mudo__titulo {
  margin: 0;
  font: var(--peso-forte) var(--t-md)/1.2 var(--fonte-titulo);
  letter-spacing: .04em; text-transform: uppercase;
  color: var(--estado-critico);
}

.mudo__olt { display: grid; gap: var(--e-1); }
.mudo__olt > a {
  font: var(--peso-medio) var(--t-lg)/1.3 var(--fonte-corpo);
  color: var(--tinta);
}

.mudo__fatos {
  margin: 0; font-size: var(--t-sm); color: var(--tinta-2);
  font-variant-numeric: tabular-nums;
}
.mudo__fatos strong { color: var(--tinta); }

/* O erro cru, em mono: é texto de máquina e o operador vai comparar com
   o que ele mesmo vê no terminal. Rola sozinho em vez de esticar a
   página quando a mensagem é longa. */
.mudo__erro {
  display: block; overflow-x: auto; white-space: nowrap;
  padding: var(--e-1) var(--e-2);
  background: var(--sup-base); border-radius: var(--raio-sm);
  font-size: var(--t-xs); color: var(--tinta-3);
}

/* A frase que transforma alarme em ressalva: sem ela o operador lê os
   azulejos abaixo como se estivessem completos. */
.mudo__ressalva {
  margin: 0; padding-top: var(--e-3);
  border-top: 1px solid color-mix(in srgb, var(--estado-critico) 25%, transparent);
  font-size: var(--t-sm); color: var(--tinta-2);
}
.mudo__ressalva strong { color: var(--estado-critico); }


/* Agrupamento dentro de um formulário longo — o <fieldset> semântico,
   com o visual do resto. Existe porque "Aviso de operação" mora no mesmo
   form do SMTP mas responde outra pergunta: um é COMO enviar, o outro é
   QUANDO avisar. Sem a separação, o campo de destino do alarme lia como
   mais um endereço de remetente. */
.campo-grupo {
  display: grid; gap: var(--e-4);
  margin: var(--e-2) 0 0;
  padding: var(--e-4) var(--e-4) var(--e-5);
  border: 1px solid var(--linha);
  border-radius: var(--raio-md);
  background: var(--sup-base);
  /* Este painel e REBAIXADO: usa o fundo da pagina, nao a superficie do
     cartao. As tintas sao calibradas contra o cartao, entao aqui dentro
     a --tinta-3 cai de 4,9:1 para 4,45:1 no tema claro da Telgo —
     abaixo do piso AA de 4,5 para 12px (medido no navegador,
     21/09/2026). Subir o degrau AQUI, e nao em cada span, faz a
     proxima dica escrita dentro de um fieldset ja nascer legivel. */
  --tinta-3: var(--tinta-2);
}
.campo-grupo > legend {
  padding: 0 var(--e-2);
  font: var(--peso-forte) var(--t-sm)/1.2 var(--fonte-titulo);
  letter-spacing: .04em; text-transform: uppercase;
  color: var(--tinta-2);
}


/* Cabeçalho que separa DOIS SISTEMAS na mesma página. O Coletor mostra o
   parque (plataforma) e, abaixo, o v1 — que fala só com as Datacom. Sem
   essa divisa o "5/5" do v1 lia como se fosse o parque de dez. */
.secao-v1 {
  display: grid; gap: var(--e-2);
  margin: var(--e-6) 0 calc(var(--e-4) * -1);
  padding-top: var(--e-5);
  border-top: 2px solid var(--linha);
}
.secao-v1 h2 {
  margin: 0; display: flex; align-items: center; gap: var(--e-3);
  flex-wrap: wrap;
  font: var(--peso-forte) var(--t-xl)/1.2 var(--fonte-titulo);
  color: var(--tinta);
}
.secao-v1 > p { margin: 0; max-width: 68ch; }

/* ---- Consumo agora (16/09/2026): trafego da ONT direto da OLT, ao vivo.
   Mesmos tokens de serie da tendencia (--grafico-descida/subida), pra a
   descida ter a mesma cor nos dois cards da tela. ---- */
.consumo__cabecalho { flex-wrap: wrap; gap: var(--e-2) var(--e-3); }
.consumo__vivo { display: inline-flex; align-items: center; gap: var(--e-1); font-size: var(--t-xs); color: var(--tinta-3); }
.consumo__parar { margin-left: auto; font-size: var(--t-xs); }
.consumo__acoes { display: flex; flex-wrap: wrap; gap: var(--e-2); align-items: center; margin-top: var(--e-2); }
.consumo__kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--e-2) var(--e-4); margin: var(--e-2) 0; }
.consumo__kpi { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.consumo__kpi-rotulo { display: inline-flex; align-items: center; gap: var(--e-1); font-size: var(--t-xs); color: var(--tinta-3); }
.consumo__amostra { width: 10px; height: 10px; border-radius: 2px; flex: none; }
.consumo__amostra--descida { background: var(--grafico-descida); }
.consumo__amostra--subida { background: var(--grafico-subida); }
.consumo__valor { font: var(--peso-forte) var(--t-xl)/1.15 var(--fonte-titulo); font-variant-numeric: tabular-nums; color: var(--tinta); }
.consumo__valor--menor { font-size: var(--t-md); }
.consumo__instantaneo { font-size: var(--t-xs); color: var(--tinta-3); font-variant-numeric: tabular-nums; }
.consumo__valor small { font-size: var(--t-xs); font-weight: 400; color: var(--tinta-3); }
.consumo__grafico { position: relative; overflow-x: auto; }
.consumo__svg { width: 100%; height: auto; display: block; min-width: 480px; }
.consumo__grade { stroke: var(--linha); stroke-width: 1; }
.consumo__marca { stroke: var(--linha-forte, var(--linha)); stroke-width: 1; }
/* Valor ao lado da bolinha: halo da superficie pra ler por cima da linha. */
.consumo__marcador { font: 600 11px var(--fonte-corpo); font-variant-numeric: tabular-nums;
  paint-order: stroke; stroke: var(--sup-1); stroke-width: 3px; stroke-linejoin: round; }
.consumo__marcador--descida { fill: var(--grafico-descida); }
.consumo__marcador--subida { fill: var(--grafico-subida); }
.consumo__mira-linha { stroke: var(--tinta-2); stroke-width: 1; pointer-events: none; }
.consumo__mira-ponto { stroke: var(--sup-1); stroke-width: 2; pointer-events: none; }
.consumo__mira-ponto--descida { fill: var(--grafico-descida); }
.consumo__mira-ponto--subida { fill: var(--grafico-subida); }
.consumo__dica { position: absolute; z-index: 2; pointer-events: none; background: var(--sup-2, var(--sup-1));
  border: 1px solid var(--linha); border-radius: var(--raio-sm); padding: var(--e-1) var(--e-2);
  font-size: var(--t-xs); white-space: nowrap; box-shadow: 0 2px 8px rgb(0 0 0 / .25); }
.consumo__dica-quando { color: var(--tinta-3); margin-bottom: 2px; }
.consumo__dica-linha { display: flex; align-items: center; gap: var(--e-1); font-variant-numeric: tabular-nums; }
.consumo__linha { fill: none; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.consumo__linha--descida { stroke: var(--grafico-descida); }
.consumo__linha--subida { stroke: var(--grafico-subida); stroke-dasharray: 6 4; }
.consumo__ponta { stroke: var(--sup-1); stroke-width: 2; }
.consumo__ponta--descida { fill: var(--grafico-descida); }
.consumo__ponta--subida { fill: var(--grafico-subida); }
.consumo__eixo { fill: var(--tinta-3); font: 11px var(--fonte-corpo); font-variant-numeric: tabular-nums; }
.consumo__eixo--borda { opacity: .8; }
.consumo__resumo { margin-top: var(--e-2); }
.consumo__estado { margin: var(--e-2) 0 0; font-size: var(--t-sm); color: var(--tinta-2); }
.consumo__aviso { margin: var(--e-2) 0 0; font-size: var(--t-xs); color: var(--estado-alerta-forte, var(--estado-alerta)); }
.consumo__meta { display: flex; flex-wrap: wrap; gap: var(--e-1) var(--e-3); margin: var(--e-2) 0 0; font-size: var(--t-xs); color: var(--tinta-3); }

/* ============================================================= incidente ===
   A pericia de UM incidente (`incidente.html`). Desenhada com a Iris,
   21/09/2026: o dado existia — 822 incidentes guardados — e nao tinha
   porta de entrada.
   ========================================================================= */
.trilha { font-size: var(--t-sm); color: var(--tinta-3); margin-bottom: var(--e-3); }
.trilha a { color: var(--tinta-2); }
.trilha strong { color: var(--tinta); }

/* `.pagina > header { display: grid }` (la em cima) ganharia de uma
   classe sozinha num <header>. Por isso o seletor leva o pai: empata em
   elemento, ganha em classe, e continua sem `!important`. */
.pagina > .cabeca-incidente {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--e-5); margin-bottom: var(--e-5);
}
.cabeca-incidente__que {
  display: flex; gap: var(--e-4); align-items: flex-start;
  flex: 1 1 auto; min-width: 0;
}
.cabeca-incidente__que svg {
  width: 2.5rem; height: 2.5rem; color: var(--estado-critico);
  flex-shrink: 0; margin-top: 2px;
}
.cabeca-incidente h1 { margin: 0; }
/* A causa desceu do H1 para uma linha propria (07/10). Ela nao e
   subtitulo do lugar — e o DIAGNOSTICO —, entao vem na tinta cheia e um
   degrau acima do `__onde`, que e so endereco. */
.cabeca-incidente__causa {
  margin: var(--e-1) 0 0; color: var(--tinta); font-size: var(--t-lg);
  font-weight: var(--peso-medio);
}

/* ------------------------- formulario de classificar (07/10/2026) ---
   Dois campos rotulados, nao uma linha de inputs soltos. Jaime: "quero
   um campo mais estruturado, onde o operador sera induzido a informar o
   dado". Rotulo visivel e o que induz; placeholder some ao digitar. */
.forma-classificar { display: grid; gap: var(--e-2); max-width: 32rem; }
.forma-classificar .campo { margin-bottom: 0; }
.forma-classificar button { justify-self: start; margin-top: var(--e-2); }
/* A marca do rotulo: "obrigatorio" em cor de estado, "opcional" em
   tinta fraca. As duas palavras aparecem para que a diferenca seja
   LIDA, e nao deduzida da ausencia de asterisco. */
.marca-campo {
  margin-left: var(--e-2);
  font-size: var(--t-xs); font-weight: 400; color: var(--tinta-3);
  text-transform: lowercase; letter-spacing: 0;
}
.marca-campo--obrigatorio { color: var(--estado-critico); font-weight: 500; }

/* O "+" do seletor de motivo. Fechado e um link discreto; so abre quem
   nao achou o caso na lista, que e o caminho raro. Alvo de 44px porque
   `summary` tambem e controle. */
.mais-motivo { margin-top: var(--e-4); }
.mais-motivo > summary {
  display: inline-flex; align-items: center; min-height: var(--alvo-min);
  color: var(--marca-primaria); font-size: var(--t-sm); cursor: pointer;
}
.mais-motivo > summary::marker { content: ""; }
.mais-motivo > summary:hover { text-decoration: underline; }
.mais-motivo[open] > summary { margin-bottom: var(--e-2); }

/* -------------------------------- secao dentro de um bloco (07/10) ---
   Nasceu da revisao estrutural: "A quebra por CTO", "Outras portas da
   placa" e "Historico desta porta" respondem UMA pergunta so ("mando
   equipe, para onde?") e estavam em tres caixas separadas, duas delas
   lado a lado em `.duas-colunas`. Caixas irmas de alturas diferentes
   esticam: os chips de CTO ficavam orfaos no meio de um retangulo
   vazio. Como secoes de um bloco unico, cada uma ocupa o que precisa e
   o fio de 1px diz que sao partes da mesma resposta. */
/* `min-width: 0` NAO E ZELO. `.bloco` e grid, e item de grid nasce com
   `min-width: auto` — ele se dimensiona pelo conteudo e IGNORA a
   trilha. Com a tabela de 599px da placa dentro, a secao foi para 353
   onde cabiam 293, e a 375px a pagina inteira passou a rolar de lado
   (418 de largura; a barra de cima esticou junto para cobrir).
   O `.envolve` por dentro nao salva: ele rola o que ja estourou.
   Mesma armadilha ja documentada em `.campo`, em base.css. */
.bloco__secao { padding: var(--e-4) var(--e-5); min-width: 0; }
.bloco__secao + .bloco__secao { border-top: 1px solid var(--linha); }
.bloco__secao > h3 {
  margin: 0 0 var(--e-3);
  font: 600 var(--t-xs)/1.3 var(--fonte-titulo);
  letter-spacing: 0.09em; text-transform: uppercase; color: var(--tinta-3);
}
/* A `.ressalva` e um componente de RODAPE DE BLOCO: ela sangra para as
   bordas E come o padding de baixo (`margin-bottom` negativo), porque
   foi feita para encostar na borda inferior do cartao. Dentro de uma
   secao isso puxa o conteudo seguinte para cima dela — no render de
   07/10 o texto da ressalva ficou ATRAS da tabela de portas irmas.
   Aqui ela mantem o sangramento horizontal (para nao virar um segundo
   componente visual) e devolve o espaco vertical. */
/* SEM SANGRAR. A `.ressalva` original estoura a caixa de proposito com
   margem negativa de `--e-5`, para encostar nas bordas do `.bloco`.
   Dentro de uma secao isso vira aritmetica de dois paddings somados, e
   a 375px ela estourou a PAGINA em 19px — o `.bloco__secao` chegava a
   394 num viewport de 375, e a barra de cima esticava junto para cobrir
   a rolagem. Medido no render de 07/10.
   Contida, com raio proprio, ela continua lendo como faixa e nao
   depende de quanto padding existe acima dela. */
.bloco__secao .ressalva {
  margin: var(--e-3) 0 0;
  border-radius: var(--raio-sm);
}
.bloco__secao > h3 + .ressalva { margin-top: 0; margin-bottom: var(--e-3); }
.cabeca-incidente__onde { margin: var(--e-1) 0 0; color: var(--tinta-2); }
.cabeca-incidente__acoes { display: flex; gap: var(--e-3); align-items: center; flex: 0 0 auto; }
@media (max-width: 720px) { .pagina > .cabeca-incidente { flex-wrap: wrap; } }

.faixa__valor--texto { font-family: var(--fonte-mono, monospace); font-size: var(--t-xl); }
.faixa__valor small { font-size: var(--t-lg); color: var(--tinta-3); font-weight: 400; }

/* Quando o alerta NAO saiu, isso e o fato mais importante da tela — foi
   assim que um incidente de quase dois dias passou sem ninguem ser
   avisado. Linha inteira, cor de estado, nao nota de rodape. */
.aviso-linha {
  display: flex; gap: var(--e-3); align-items: flex-start;
  padding: var(--e-4); border-radius: var(--raio-md); margin: var(--e-5) 0;
  background: var(--sup-1); border-left: 4px solid var(--linha-forte);
}
.aviso-linha svg { width: 20px; height: 20px; flex-shrink: 0; margin-top: 2px; }
.aviso-linha--ruim { border-left-color: var(--estado-critico); }
.aviso-linha--ruim svg { color: var(--estado-critico); }
/* A variante de ATENCAO, para o aviso que limita a leitura sem ser uma
   falha — "por CTO a medicao so comeca em 06/10". Vermelho ali seria
   mentira de gravidade: nao ha nada quebrado, ha um alcance. */
.aviso-linha--atencao { border-left-color: var(--estado-alerta); }
.aviso-linha--atencao svg { color: var(--estado-alerta); }

/* Subtitulo do cabecalho de bloco: o `.bloco > header` ja e flex, entao
   isto so recua o peso. Serve para a regra do recorte ("minimo 2
   ocorrencias") viajar junto do titulo em vez de virar rodape que
   ninguem le antes de interpretar a tabela. */
.bloco__apoio { color: var(--tinta-3); font-size: var(--t-xs); margin: 0; }

.duas-colunas { display: grid; grid-template-columns: 1fr 1fr; gap: var(--e-5); }
@media (max-width: 900px) { .duas-colunas { grid-template-columns: 1fr; } }

.bloco__miolo { padding: 0 var(--e-4) var(--e-4); margin: 0; }

/* A ressalva NUNCA e nota apagada no rodape: ela muda COMO o numero
   acima deve ser lido. Fica colada nele, com fundo proprio e tamanho de
   leitura — nao de letra miuda. */
.ressalva {
  /* A CAIXA vai de ponta a ponta; o TEXTO respeita a medida de leitura.
     Sao duas coisas diferentes e por isso ha um `span` dentro: `p` herda
     `max-width: var(--medida)` (base.css), o que deixava a faixa
     flutuando no meio do cartao com o fio de cima pendurado. Tirar a
     medida do `p` sem devolve-la ao texto daria linha de 150 caracteres.
     Faixa de ponta a ponta no rodape do cartao: `.bloco` tem
     `padding: var(--e-5)` e e grid, entao o filho para na margem
     interna e o fio de cima fica pendurado no meio do nada. As
     margens negativas devolvem o sangramento — e o ultimo `--e-5`
     negativo come o padding de baixo, encostando a faixa na borda. */
  margin: 0 calc(-1 * var(--e-5)) calc(-1 * var(--e-5));
  padding: var(--e-3) var(--e-5);
  border-top: 1px solid var(--linha);
  border-radius: 0 0 var(--raio-lg) var(--raio-lg);
  font-size: var(--t-sm); color: var(--tinta-2);
  background: var(--sup-2);
  max-width: none;
}
.ressalva > span { display: block; max-width: var(--medida); }

.antes { list-style: none; margin: 0; padding: 0 var(--e-4); }
.antes li {
  display: grid; grid-template-columns: auto 1fr; gap: var(--e-1) var(--e-3);
  padding: var(--e-3) 0; border-bottom: 1px solid var(--linha);
}
.antes li:last-child { border-bottom: 0; }
.antes li a { grid-row: 1 / 3; align-self: center; font-family: monospace; }

.linha-tempo { list-style: none; margin: 0; padding: var(--e-2) var(--e-4) var(--e-4); }
.linha-tempo__item {
  display: grid; grid-template-columns: 11rem 1fr; gap: var(--e-4);
  padding: var(--e-3) 0 var(--e-3) var(--e-4);
  border-left: 2px solid var(--linha); position: relative;
}
.linha-tempo__item::before {
  content: ""; position: absolute; left: -5px; top: 1.15rem;
  width: 8px; height: 8px; border-radius: 50%; background: var(--linha-forte);
}
/* Abertura e fechamento sao marcos do MOTOR; queda e o que o cliente
   sentiu. Tamanho separa os dois tipos de fato, cor separa o sentido. */
.linha-tempo__item--abre::before,
.linha-tempo__item--fecha::before { width: 12px; height: 12px; left: -7px; }
.linha-tempo__item--abre::before { background: var(--estado-critico); }
.linha-tempo__item--fecha::before { background: var(--estado-ok); }
.linha-tempo__item--antes::before { background: var(--estado-alerta); }
.linha-tempo__hora {
  font-variant-numeric: tabular-nums; color: var(--tinta-2); font-size: var(--t-sm);
}
.linha-tempo__fato { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
@media (max-width: 720px) {
  .linha-tempo__item { grid-template-columns: 1fr; gap: var(--e-1); }
}

/* ------------------------------------------------------- historico --- */
/* A busca do histórico é o campo que mais recebe texto longo (nome de
   trecho tem 40+ caracteres), então ela cresce e os campos de data
   ficam no tamanho do seu conteúdo. */
.campo--largo { flex: 1 1 22rem; }

.paginas {
  display: flex; align-items: center; gap: var(--e-4);
  padding: var(--e-3) var(--e-4); font-size: var(--t-sm); color: var(--tinta-2);
}
.paginas a { color: var(--marca-primaria); }

/* Lista dentro de um campo de formulario: quando UM controle comanda
   mais de um comportamento, cada um vira um item — texto corrido
   esconde o segundo. Ver o campo "Para quem avisar" em Configuracoes.

   Tinta-2, nao tinta-3: isto nao e legenda, e a explicacao que faz o
   campo ser preenchido. Da 7,6:1 no claro e 8,0:1 no escuro. */
.lista-avisos {
  margin: var(--e-2) 0 0; padding-left: var(--e-4);
  font-size: var(--t-xs); color: var(--tinta-2); line-height: var(--linha-normal);
}
.lista-avisos li + li { margin-top: var(--e-2); }
/* O NOME do aviso e o que se procura ao bater o olho; a explicacao
   vem depois. Com o corpo na tinta-2, o negrito sozinho nao separava
   mais os dois niveis. */
.lista-avisos strong { color: var(--tinta); }

/* ------------------------------------------------ historico por queda
   Uma linha por queda (ver `quedas.py`). A duracao e a informacao que
   manda, e ela tem um problema de leitura: 2 min contra 2 dias e 1440x
   — barra proporcional faz a piscada sumir. Entao o peso vem em TRES
   DEGRAUS, tirados da decisao real do NOC (ignorar / atender /
   despachar) e dos cortes medidos no parque: 70% abaixo de 5 min,
   88,7% abaixo de 1 h.

   O traco e codificacao SECUNDARIA (`aria-hidden`), nunca a unica: a
   duracao continua escrita ao lado, e quem nao distingue a cor le o
   numero. */
.fora {
  display: inline-flex; align-items: center; gap: var(--e-2);
  font-variant-numeric: tabular-nums; color: var(--tinta);
}
.fora__traco {
  flex: none; height: 4px; border-radius: 2px; background: var(--cor-fora);
  width: var(--largura-fora);
}
.fora--piscada { --cor-fora: var(--traco-piscada); --largura-fora: 10px; }
.fora--sentida { --cor-fora: var(--traco-sentida); --largura-fora: 22px; }
.fora--longa   { --cor-fora: var(--traco-longa);   --largura-fora: 34px; }

/* A hora da queda em tabular: a coluna e uma pilha de HH:MM:SS e sem
   isto os digitos dancam de linha para linha. */
.quedas__hora { font-variant-numeric: tabular-nums; white-space: nowrap; }

/* "11h 15min" e "voltou 19:40:00" sao unidades de leitura: quebradas em
   duas linhas a celula triplica de altura e o olho perde o par
   duracao/retorno. Medido em 375px: a linha ia a 78px de altura.

   So estas duas — a primeira tentativa foi `.quedas .sub-celula`, que
   pegou tambem "caiu de novo as 19:02:00" e ENGORDOU a tabela em 33px
   em vez de enxugar. Texto que pode quebrar, quebra. */
.quedas .fora, .quedas__voltou { white-space: nowrap; }

/* No celular a tabela tem tres colunas competindo por ~341px. O
   respiro de 12px de cada lado custa 72px so em padding — mais que uma
   coluna inteira. Apertar aqui e o que faz a causa ("Fibra rompida")
   caber junto com o resto, em vez de ficar do lado de la da rolagem
   horizontal: e ela que diz ao tecnico o que levar na mochila. */
@media (max-width: 640px) {
  .dados.quedas th, .dados.quedas td { padding-left: var(--e-2); padding-right: var(--e-2); }
}

/* Cabecalho de dia DENTRO da tabela. E ele que torna o flapping
   visivel: "6 quedas" e uma frase, nao uma conta que o operador faz de
   cabeca rolando a lista. */
.dia-linha > th {
  padding: var(--e-3) var(--e-3) var(--e-2);
  background: var(--sup-base);
  border-bottom: 1px solid var(--linha);
  font: var(--peso-forte) var(--t-xs)/1.3 var(--fonte-titulo);
  letter-spacing: .04em; text-transform: uppercase;
  text-align: left;
}
.dia-linha__data { color: var(--tinta); }
.dia-linha__conta {
  margin-left: var(--e-3);
  font-weight: var(--peso-normal); letter-spacing: 0; text-transform: none;
  color: var(--tinta-2);
}

/* ------------------------------------------------- evento de placa
   Dezesseis portas de um slot caindo juntas nao sao dezesseis
   rompimentos de fibra. O cabecalho aparece UMA vez, acima das portas
   do evento — mesmo idioma do cabecalho de dia de `.dia-linha`, porque
   e o mesmo gesto: agrupar linhas que contam um fato so.

   Dois graus, e a diferenca tem que ser legivel SEM cor: `inteira` tem
   o fio grosso a esquerda e a frase inteira; `parcial` tem fio fino e
   uma frase curta que nao conclui nada. */
table.dados .placa-linha > th {
  padding: var(--e-3) var(--e-3) var(--e-2);
  background: var(--sup-base);
  border-top: 1px solid var(--linha);
  border-bottom: 1px solid var(--linha);
  text-align: left; font-weight: var(--peso-normal);
  /* `.dados th` e cabecalho de COLUNA: caixa alta, sem quebra,
     espacamento de letra. Aqui dentro corre uma FRASE, e frase em caixa
     alta numa linha so de 2.160px nao se le — a tabela e mais larga que
     a area visivel, entao o fim dela ficava do lado de la da rolagem.
     Medido em 21/09/2026. */
  text-transform: none; white-space: normal; letter-spacing: normal;
  /* Mesmo painel rebaixado de `.campo-grupo`, mesmo problema: a
     --tinta-3 e calibrada contra a superficie do cartao e cai para
     4,45:1 aqui no tema claro da Telgo, abaixo do piso AA. Medido em
     21/09/2026. */
  --tinta-3: var(--tinta-2);
}
table.dados .placa-linha--inteira > th { border-left: 4px solid var(--estado-critico); }
table.dados .placa-linha--parcial > th { border-left: 2px solid var(--estado-alerta); }
.placa-linha__topo {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--e-2);
}
.placa-linha__nome {
  font: var(--peso-forte) var(--t-sm)/1.3 var(--fonte-titulo);
  color: var(--tinta);
}
.placa-linha__fato {
  display: block; margin-top: var(--e-2);
  font-size: var(--t-xs); line-height: var(--linha-normal); color: var(--tinta-2);
}
/* `sticky` mantem o texto no comeco enquanto a tabela rola de lado:
   sem isso, rolar para ver a coluna "A OLT informou" levava a frase
   junto e ela sumia pela esquerda.

   A largura sai do PROPRIO texto, deixando ele quebrar: uma celula com
   `colspan` nao impoe largura a tabela quando o conteudo pode quebrar.
   A primeira tentativa foi `container-type: inline-size` na `.envolve`
   com `cqw` — e isso MATOU a rolagem horizontal, porque containment
   proibe a tabela de ser mais larga que o container: o nome da OLT
   passou a quebrar em cinco linhas. `.envolve` existe justamente para a
   tabela poder ser mais larga. */
.placa-linha__topo, .placa-linha__fato { position: sticky; left: 0; }
/* 84ch (~650px) e a medida de leitura; `90vw` e o teto do celular,
   onde a area visivel da tabela e ~341px e 84ch estouraria em mais do
   dobro. O `min()` deixa cada um mandar onde e o menor. */
.placa-linha__fato { max-width: min(84ch, 80vw); }
/* A porta que pertence a um evento fica recuada: sem isto, o cabecalho
   parece um separador solto e nao o pai daquelas linhas. */
.placa-membro > td:first-child { border-left: 4px solid var(--linha); }

/* A linha DESTA porta na lista das irmas. Fundo sozinho nao serve —
   quem nao distingue a diferenca fica sem saber onde esta; por isso a
   linha tambem carrega o selo "esta" no texto. */
.dados__atual > td { background: var(--sup-2); }

/* O nome da OLT numa lista de incidentes. Sao 38 a 52 caracteres
   ("ANS - DC Cidade Jardim - Huawei MA5600T-IEC-19 - OLT"), e numa
   tabela de nove colunas a celula ficava com 96px: o nome quebrava em
   SEIS linhas e a linha inteira ia a 115px de altura. Medido em
   21/09/2026, com e sem o evento de placa — identico, e anterior a ele.

   NAO corta com reticencias, e a razao e concreta: existem DUAS OLTs
   "ANS - DC London" no parque (MA5800X2 - OLT I e MA5600T-IEC-19 -
   OLT II). Cortadas em 22ch, as duas viram "ANS - DC London - Hua…" —
   indistinguiveis numa lista cuja primeira pergunta e "qual OLT?".

   Tambem NAO se corta pelo padrao do nome ("SIGLA - LOCAL - modelo"):
   presumir formato de texto livre ja custou caro no nome da ONU, onde
   26% do parque nao segue o padrao.

   Entao a celula ganha PISO de largura e quebra em duas linhas em vez
   de seis. O nome inteiro continua na tela, que e o unico jeito de as
   duas London se distinguirem. */
.celula-olt { min-width: 22ch; }

/* "desde 21/09 08:22" e uma unidade de leitura: quebrado em tres
   linhas ("desde" / "21/09" / "08:22") ele triplica a altura da linha
   e o olho perde o par data/hora. Mesma razao do `.quedas__voltou`. */
.sub-celula.quando { white-space: nowrap; }

/* ------------------------------------- encerrar um desvio de sinal ---
   A acao mora dentro de uma celula de tabela, e na primeira
   renderizacao os tres controles disputavam a mesma linha: o select
   comia a largura, o campo de nota saia cortado no meio do placeholder
   ("nota (obrigatoria em “O") e o botao encostava na borda. So apareceu
   abrindo a pagina.

   Empilhado, cada controle tem a largura inteira da coluna e o botao
   fica onde o olho ja termina de ler. */
.forma-encerrar {
  display: flex; flex-direction: column; gap: var(--e-2);
  min-width: 15rem;
}
.forma-encerrar select,
.forma-encerrar input { width: 100%; }
/* O botao nao estica: ele e a ACAO e precisa parecer uma, nao uma
   quarta faixa cinza do formulario. */
.forma-encerrar button { align-self: flex-start; }

/* --------------------------------- selo que tambem filtra (06/10) ---
   Jaime pediu o filtro de Estado nos proprios selos do resultado. A
   Iris travou tres coisas:

   "mostrar:" na frente — tirar o `<select>` tira a DESCOBERTA. Sem o
   rotulo, quem nunca viu a tela nao sabe que aqueles numeros filtram.

   ATIVO E PREENCHIDO, inativo e contorno. Nao e so cor: le de relance
   e sobrevive a daltonismo, a mesma distincao do cartao de desvio na
   parede. Cor sozinha nao pode carregar estado.

   Alvo de 44px no toque. Como selo, eles eram leitura e podiam ser
   pequenos; como controle, nao. */
.filtro-estado {
  display: inline-flex; align-items: center; gap: var(--e-2);
  flex-wrap: wrap;
}
.filtro-estado__rotulo {
  color: var(--tinta-3); font-size: 0.8125rem;
}
/* A COR DA FAMILIA, resolvida uma vez em `--selo-cor`: texto, borda e
   chapa saem dela, entao o estado ativo nao precisa repetir nada.
   No claro vai a variante `-forte`, calibrada para fundo claro; no
   escuro, a cor plena — e a mesma regra que tokens.css ja aplica em
   `--traco-sentida`/`--traco-longa` ("no escuro a `-forte` sumiria"). */
a.selo--neutro  { --selo-cor: var(--tinta-2); }
a.selo--bom     { --selo-cor: var(--estado-ok); }
a.selo--ruim    { --selo-cor: var(--estado-critico); }
/* `atencao` FALTAVA na primeira versao (06/10), e o buraco nao era
   discreto: sem `--selo-cor` o `color` fica sem valor e o `border: 1px
   solid var(--selo-cor)` vira declaracao invalida — o chip sai SEM
   caixa e sem cor, como texto solto no meio de dois pills. Visto no
   render do filtro "So programados". Os 18 selos de atencao do resto do
   produto sao `<span>` e nunca passaram por aqui; o primeiro que virou
   link encontrou o buraco. */
a.selo--atencao { --selo-cor: var(--estado-alerta); }
[data-theme="light"] a.selo--bom     { --selo-cor: var(--estado-ok-forte); }
[data-theme="light"] a.selo--ruim    { --selo-cor: var(--estado-critico-forte); }
[data-theme="light"] a.selo--atencao { --selo-cor: var(--estado-alerta-forte); }

/* Inativo: contorno da cor, fundo do cartao. */
a.selo {
  background: transparent; color: var(--selo-cor);
  border: 1px solid var(--selo-cor);
  text-decoration: none; cursor: pointer;
}
a.selo:hover { background: color-mix(in srgb, var(--selo-cor) 10%, transparent); }
/* So o raio. A cor e a espessura do foco vem da regra global de
   base.css, que ja tem a troca de cor do tema claro calibrada para
   WCAG 2.4.11 — pintar o anel de `currentColor` aqui jogaria fora essa
   calibragem e poria anel verde/vermelho nao conferido no claro.
   Mas a regra global tambem crava `--raio-sm`, o que QUADRARIA o pill
   no foco; isto devolve o raio cheio. */
a.selo:focus-visible { border-radius: var(--raio-cheio); }

/* Ativo: CHAPA CHEIA, com o rotulo na cor da superficie.

   A primeira versao usava uma chapa translucida de 18% da propria cor,
   como os selos de leitura da tabela. Medido no render, isso REPROVA:
   o rotulo caiu para 3,73:1 no escuro e 4,18:1 no claro, abaixo dos
   4,5:1 que a WCAG pede para texto de 12px — e no escuro `--estado-
   critico` sobre o cartao so tem 4,64:1 de folga TOTAL, ou seja,
   qualquer chapa translucida come o que nao existe.

   A chapa cheia resolve pelo outro lado: o texto passa a ser a cor do
   cartao, e o par vira o mesmo contraste da cor contra o cartao, agora
   a favor. Medido nos seis casos (tres familias x dois temas):
   4,64 a 8,15:1. De quebra, chapa cheia e um "selecionado" que se le
   de longe, bem mais forte que um veu de 18%. */
a.selo--ativo {
  background: var(--selo-cor); border-color: var(--selo-cor);
  color: var(--sup-1); font-weight: 600;
}
/* Sem isto, passar o mouse no ativo cairia para o veu de 10% da regra
   acima — o selecionado "apagaria" sob o cursor. */
a.selo--ativo:hover { background: var(--selo-cor); }

/* ------------------------------------- ranking do historico (06/10) ---
   A coluna do LUGAR precisa de piso. A tabela vive num `.envolve` que
   ja rola na horizontal, entao a coluna nao precisa caber na tela — mas
   sem `min-width` ela encolhe ate o limite e o nome do trecho quebra
   uma palavra por linha ("Telgo- / Gpon-Ans- / Dc- / London"), jogando
   a linha para 130px de altura a 375px. Medido no render. */
.ranking__lugar { min-width: 11rem; }
/* Mesmo piso, mesma razao, na tabela das portas irmas: sem ele o nome
   do trecho quebra uma palavra por linha a 375px. */
.porta-irma { min-width: 10rem; }

/* A hora da leitura e legenda, nao estado. Deliberadamente NAO e um
   `.selo`: nesta linha o selo passou a significar "clique para
   filtrar", e um pill que nao clica ao lado de tres que clicam convida
   ao clique morto. Mesmo corpo e mesma tinta do rotulo "mostrar:", para
   que os dois textos de apoio leiam como um registro so. */
/* O `white-space: nowrap` SAIU do bloco e desceu para as metades. Desde
   07/10/2026 o rótulo tem duas, com validades diferentes ("estado e
   sinal às 15:49 · cadastro de 15:17"), e segurar a linha inteira
   empurrava o cabeçalho para fora da tela a 375px. Cada metade continua
   inteira; a quebra só pode cair no meio, entre elas. */
.lido-da-olt { color: var(--tinta-3); font-size: 0.8125rem; }
/* HIERARQUIA POR FORÇA, NÃO POR OPACIDADE. A metade de agora é a que
   responde a pergunta de quem está no telefone, então ela vem primeiro e
   mais firme. Apagar a outra com `opacity` resolveria o visual e
   reprovaria o contraste (--tinta-3 já está em 5,3:1; a .72 cai para
   ~3,3). Sobe-se a primeira em vez de afundar a segunda. */
.lido-da-olt__forte { color: var(--tinta-2); white-space: nowrap; }
.lido-da-olt__fraco { white-space: nowrap; }
/* A cor do desvio, de novo por cima do cinza de apoio — `.lido-da-olt` é
   seletor de uma classe e vem DEPOIS de `.sinal--*` no arquivo. Segunda
   vez que esta armadilha aparece no mesmo dia; a trava que a varre em
   todos os moldes está em `tests/test_sub_celula_estrutura.py`. */
.lido-da-olt.sinal--atencao { color: var(--estado-alerta-texto); }
.lido-da-olt.sinal--ruim    { color: var(--estado-critico-texto); }

/* O "Atualizar" DEIXA DE SER UM LINK PELADO (Jaime, 13/10/2026).

   Ele e o caminho barato — SNMP/Zabbix, o mesmo que o ciclo ja usa — e
   o do rodape abre sessao CLI. A medicao esta no proprio codigo desta
   casa: "CLI, OLT inteira ~256 s; SNMP, OLT inteira 1,9 s (1.300 ONUs),
   CPU identica". Duas ordens de grandeza. Jaime: "precisamos evidenciar
   o botao ATUALIZAR, para que a operacao sempre opte por ele".

   NAO vira `.selo`: no mesmo cabecalho os selos sao o filtro de estado,
   e um selo que nao filtra ao lado de tres que filtram repetiria o
   acidente do "selo que virou botao sem avisar".

   NAO vira `.btn`: a 40rem o `.btn` da casa estica para 100% de largura,
   e um botao de borda a borda dentro desta linha de cabecalho empurraria
   o resto para fora. Dai corpo proprio, compacto, que so cresce para o
   alvo de toque onde o dedo e o ponteiro — a mesma regra que `a.selo` ja
   segue logo abaixo. */
.btn-releitura {
  display: inline-flex; align-items: center; gap: var(--e-1);
  min-height: 32px; padding-inline: var(--e-3);
  border: 1px solid var(--linha-forte); border-radius: var(--raio-md);
  background: var(--sup-2); color: var(--tinta-2);
  font-size: 0.8125rem; font-weight: 500; text-decoration: none;
  white-space: nowrap;
}
.btn-releitura:hover { background: var(--sup-3); color: var(--tinta); }

@media (max-width: 900px) {
  /* Alvo de toque, pela mesma razao de `a.selo` aqui embaixo. Largura
     nunca: ele divide a linha com o rotulo de duas validades. */
  .btn-releitura { min-height: var(--alvo-min); }
  /* Controle precisa de alvo; selo de leitura nao precisava. */
  /* O `padding-inline` nao e enfeite: com 44px de altura e
     `--raio-cheio`, um rotulo curto como "todos" vira um CIRCULO, que
     le como botao de radio e nao como etiqueta. A folga horizontal
     devolve a proporcao de pill. */
  a.selo {
    min-height: 44px; display: inline-flex; align-items: center;
    padding-inline: var(--e-3);
  }
  .filtro-estado { width: 100%; }
}

/* A saída para o cliente que não está no cadastro (clientes.html,
   07/10/2026). Fica abaixo da tabela, sozinha, com respiro — perto
   demais do rodapé da tabela leria como legenda de coluna. */
.escape-olt { margin-top: var(--e-3); }

/* O botão de medir a CTO, na tela de campo (07/10/2026). Jaime:
   "imagine o técnico em cima de uma escada no poste (...) precisa ser um
   botão com mais destaque".

   Três coisas que mudam por causa da escada, e não do gosto:

   ALVO MAIOR que o `--alvo-toque` de 48px. Mão ocupada, possivelmente
   com luva, e um erro de toque aqui custa descer a escada para repetir.
   64px é a altura dos próprios cartões de cliente — o botão passa a ter
   o mesmo peso físico do que ele atualiza.

   PESO FORTE no texto. Sol direto lava o contraste real da tela muito
   abaixo do que o cálculo diz; traço mais grosso resiste onde peso
   médio some.

   SEM `transition` de fundo. A página recarrega inteira a cada leitura
   (0,5 s a 3 s, sem spinner); animar o hover de um botão que vai
   desaparecer no reload é enfeite que só aparece no desktop. */
.campo-btn--medir {
  min-height: 64px;
  font-weight: var(--peso-forte);
  letter-spacing: 0.01em;
  /* A BORDA É O QUE SALVA O TEMA CLARO. Medido no navegador, a razão
     entre o botão e a página — WCAG 1.4.11 pede 3:1 para a FORMA de um
     controle, não só para o texto dentro dele:

                      preenchimento × página   borda × página
       telgo escuro          9,50                   1,68
       telgo claro           1,67  REPROVA          9,40
       wixx  escuro          6,07                   1,19
       wixx  claro           2,75  REPROVA         19,82

     O azul da Telgo é claro por natureza: sobre o papel do tema claro
     ele quase não existe como objeto, e o técnico no sol veria texto
     flutuando, não um botão. As duas pontas se complementam — no escuro
     o preenchimento carrega, no claro a borda —, e com ela sempre
     presente toda combinação tem ao menos um limite acima de 3:1.

     A cor é `--marca-tinta`, a MESMA do texto do botão: nenhuma cor
     nova de marca, e o contorno lê como parte da peça. */
  border: 2px solid var(--marca-tinta);
}
/* O segundo, no fim da lista, ganha respiro do último cartão para não
   ser tocado por engano por quem só queria rolar. */
.campo-cartoes > .campo-btn--medir { margin-top: var(--e-3); }

/* O motivo provável de um evento de massa (08/10/2026). A conclusão em
   corpo maior que o resto do bloco, porque é ela que se lê de relance
   num incidente aberto; as evidências ficam em lista, miúdas, para quem
   quiser conferir o raciocínio antes de despachar alguém. */
.diagnostico__titulo {
  font: var(--peso-forte) var(--t-lg)/1.3 var(--fonte-titulo);
  margin: 0 0 var(--e-1);
}
.diagnostico__onde { margin: 0 0 var(--e-3); color: var(--tinta-2); }
.diagnostico__evidencias {
  margin: 0; padding-left: var(--e-4);
  color: var(--tinta-3); font-size: var(--t-sm);
}
.diagnostico__evidencias li { margin-bottom: var(--e-1); }

/* O log da porta, dentro do motivo provável (08/10/2026). A distância no
   tempo fica numa coluna própria, alinhada, porque é ela que se compara
   entre linhas — "13 s antes" e "41 s depois" só dizem alguma coisa um
   ao lado do outro. */
.porta-log { margin-top: var(--e-4); }
.porta-log__titulo {
  font: var(--peso-forte) var(--t-sm)/1.3 var(--fonte-titulo);
  color: var(--tinta-2); margin: 0 0 var(--e-2);
}
.porta-log__lista { list-style: none; margin: 0 0 var(--e-2); padding: 0; }
.porta-log__lista li {
  display: grid; grid-template-columns: 7.5rem 1fr; gap: var(--e-3);
  padding: var(--e-1) 0; font-size: var(--t-sm);
}
.porta-log__quando {
  color: var(--tinta-3); text-align: right;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.porta-log__fato { color: var(--tinta); min-width: 0; }
/* No celular a distância sobe para cima do fato: duas colunas de 7,5rem
   e texto corrido não cabem em 375px sem partir palavra. */
@media (max-width: 30rem) {
  .porta-log__lista li { grid-template-columns: 1fr; gap: 0; }
  .porta-log__quando { text-align: left; }
}
