/* Componentes do hub admin. Os tokens vivem em tokens.css (fonte única,
   compartilhada com os relatórios de scripts/). */

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

/* 🔴 A CALHA DA BARRA DE ROLAGEM FICA SEMPRE RESERVADA, e isto conserta o "a página toda treme"
   relatado em 02/09/2026.
   Mecanismo, medido: trocar de aba passa pelo estado "carregando…", que colapsa a página para uma
   tela (`scrollHeight` 3741 -> 900). Aí a barra de rolagem DESAPARECE, a área útil alarga ~15px, e
   TUDO se desloca para a direita; quando o relatório monta (~3700px) ela volta e tudo volta. Dois
   deslocamentos horizontais da página inteira por troca de aba, e nas abas de relatório são os
   maiores porque são as páginas mais altas.
   ⚠️ Não se enxerga em Chromium headless nem em macOS: os dois usam barra SOBREPOSTA, que não
   consome largura. Só aparece em barra clássica (Windows, e Linux com tema clássico) - foi por isso
   que passou pelas provas visuais automatizadas. `scrollbar-gutter` reserva o espaço mesmo quando
   não há barra, então a largura nunca muda. */
html { scrollbar-gutter: stable; }

body {
   background: var(--bg); color: var(--text);
   font-family: var(--font); font-size: 13px; line-height: 1.45;
   padding: 14px; -webkit-text-size-adjust: 100%;
}

/* O estado "carregando…" não colapsa mais a página: sem isto ela pisca entre ~3.700px e uma tela
   a cada troca de aba, a rolagem salta para o topo e a barra de rolagem some e volta.
   🔴 O valor tem que deixar a página SEMPRE mais alta que o viewport (daí `100vh` menos o que
   existe acima, não `70vh`, que media 830px numa tela de 900 e ainda deixava a barra alternar,
   medido em 04/09/2026). Alternância de barra é o que desloca a página onde ela ocupa largura -
   o `scrollbar-gutter` acima já protege disso, e isto tira a causa. */
#conteudo { min-height: calc(100vh - 100px); }
.container { max-width: 1440px; margin: 0 auto; }

/* ───────────────────────────── cabeçalho ───────────────────────────── */

.topo { display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap; margin-bottom: 10px; }
.marca { font-size: 19px; font-weight: 800; letter-spacing: -.3px; }
.marca em { font-style: normal; color: var(--muted); font-weight: 500; }
.topo-meta { display: flex; gap: 8px; flex-wrap: wrap; margin-left: auto; align-items: center; }
.chip-meta {
   font-size: 11px; color: var(--muted); background: var(--surface);
   border: 1px solid var(--border); border-radius: 6px; padding: 2px 8px;
}
.chip-meta b { color: var(--primary); font-weight: 600; }

.abas {
   position: sticky; top: 0; z-index: 20; background: var(--bg);
   display: flex; gap: 6px; align-items: center; padding: 8px 0;
   border-bottom: 1px solid var(--border); margin-bottom: 12px; flex-wrap: wrap;
}
.aba {
   font: inherit; font-size: 12px; font-weight: 600; padding: 5px 14px;
   border-radius: 999px; border: 1px solid var(--border);
   background: var(--surface); color: var(--text); cursor: pointer;
}
.aba:hover { border-color: var(--primary); color: var(--primary); }
.aba[aria-selected="true"] { background: var(--primary); border-color: var(--primary); color: #fff; }

.btn {
   font: inherit; font-size: 12px; font-weight: 600; padding: 4px 11px;
   border-radius: 6px; border: 1px solid var(--border);
   background: var(--surface); color: var(--text); cursor: pointer;
}
.btn:hover { border-color: var(--primary); color: var(--primary); }
.btn[disabled] { opacity: .5; cursor: not-allowed; }

/* ───────────────────────────── banner ───────────────────────────── */

.banner {
   border-radius: var(--radius); padding: 10px 14px; margin-bottom: 12px;
   border: 1px solid var(--crit-border); background: var(--crit-bg); color: var(--crit);
   font-weight: 600; display: flex; gap: 10px; align-items: center;
}
.banner.warn { border-color: var(--warn-border); background: var(--warn-bg); color: var(--warn); }
.banner small { font-weight: 500; opacity: .85; }

/* ───────────────────────────── grid e cards ───────────────────────────── */

.grid { display: grid; gap: 10px; }
.g6 { grid-template-columns: repeat(6, 1fr); }
.g4 { grid-template-columns: repeat(4, 1fr); }
.g3 { grid-template-columns: repeat(3, 1fr); }
.g2 { grid-template-columns: repeat(2, 1fr); }
.cols-32 { grid-template-columns: 3fr 2fr; }
@media (max-width: 1100px) { .g6 { grid-template-columns: repeat(3, 1fr); } .g3, .g2, .cols-32 { grid-template-columns: 1fr; } }
/* `.g4` não tinha regra nenhuma: quatro tiles de R$ numa tela de 390px alargavam a PÁGINA inteira
   para ~530px, e o celular abria o painel com zoom de afastar e rolagem lateral. */
@media (max-width: 700px)  { .g6, .g4, .g3 { grid-template-columns: repeat(2, 1fr); } }

.card {
   background: var(--surface); border: 1px solid var(--border);
   border-radius: var(--radius); padding: 12px 14px; min-width: 0;
}
.card-head { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; flex-wrap: wrap; }
.card h2 {
   font-size: 12px; font-weight: 700; text-transform: uppercase;
   letter-spacing: .7px; color: var(--muted);
}
.card h2 .nota { text-transform: none; letter-spacing: 0; font-weight: 500; }
.card-acao { margin-left: auto; display: flex; gap: 6px; align-items: center; }

/* Stat tiles */
.stat-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 11px 13px; }
.stat-label { font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .6px; color: var(--muted); }
.stat-value { font-size: 25px; font-weight: 800; letter-spacing: -.6px; line-height: 1.15; margin-top: 3px; }
.stat-value small { font-size: 14px; font-weight: 700; color: var(--muted); }
.stat-sub { font-size: 11px; color: var(--muted); margin-top: 2px; }
.stat-sub b { color: var(--text); font-weight: 600; }

/* ───────────────────────────── tabelas ───────────────────────────── */

/* Scroll VERTICAL dentro da tabela, não na página: a lista de Assinantes tem ~470
 * linhas, e sem o teto chegar ao diagnóstico embaixo era rolar a página inteira.
 * O `max-height` só age em quem passa dele - as tabelas equivalentes dos gráficos
 * (≤13 linhas) nem percebem. E é este overflow-y que faz o `position: sticky` do
 * `th` funcionar de fato: antes o wrap só tinha overflow-x, o container não rolava
 * na vertical e o cabeçalho "sticky" ia embora junto com a página. */
.tabela-wrap { overflow: auto; max-height: min(70vh, 760px); }
table { border-collapse: collapse; width: 100%; font-size: 12px; }
th, td { text-align: left; padding: 5px 8px; border-bottom: 1px solid var(--border); white-space: nowrap; }
th {
   font-size: 10.5px; text-transform: uppercase; letter-spacing: .5px;
   color: var(--muted); font-weight: 700; position: sticky; top: 0; z-index: 1;
   background: var(--surface); cursor: pointer; user-select: none;
   /* Com `border-collapse: collapse` a borda do th NÃO acompanha o sticky (fica
    * colada na posição original e o cabeçalho rola "sem chão") - o risco de baixo
    * vira sombra, que é do elemento e viaja com ele. */
   border-bottom: none; box-shadow: 0 1px 0 var(--border);
}
th[data-ord]::after { content: ' ↕'; opacity: .3; }
th[data-ord][aria-sort="ascending"]::after  { content: ' ↑'; opacity: 1; color: var(--primary); }
th[data-ord][aria-sort="descending"]::after { content: ' ↓'; opacity: 1; color: var(--primary); }
tbody tr:hover { background: var(--surface2); }
td.num, th.num { text-align: right; font-family: var(--mono); }
td.mut { color: var(--muted); }

/* Tabela equivalente sob cada gráfico — caminho de acessibilidade e de conferência */
details.dados { margin-top: 8px; }
details.dados > summary {
   cursor: pointer; font-size: 11px; color: var(--muted); font-weight: 600;
   list-style: none; padding: 2px 0;
}
details.dados > summary:hover { color: var(--primary); }
details.dados[open] > summary { margin-bottom: 6px; }

/* ───────────────────────────── badges ───────────────────────────── */

.badge {
   display: inline-block; font-size: 10.5px; font-weight: 700; padding: 1px 7px;
   border-radius: 999px; border: 1px solid var(--border); background: var(--surface2);
   color: var(--muted); white-space: nowrap;
}
.badge.wix  { background: hsl(213 96% 57% / .12); border-color: hsl(213 96% 57% / .3); color: var(--primary); }
.badge.mp   { background: hsl(160 60% 40% / .14); border-color: hsl(160 60% 40% / .32); color: var(--c2); }
.badge.ok   { background: var(--ok-bg);   border-color: var(--ok-border);   color: var(--ok); }
.badge.warn { background: var(--warn-bg); border-color: var(--warn-border); color: var(--warn); }
.badge.crit { background: var(--crit-bg); border-color: var(--crit-border); color: var(--crit); }

.legenda { display: flex; gap: 12px; flex-wrap: wrap; font-size: 11px; color: var(--muted); margin-bottom: 6px; }
.legenda span { display: inline-flex; align-items: center; gap: 5px; }
.legenda i { width: 10px; height: 10px; border-radius: 3px; display: inline-block; }

/* ───────────────────────────── filtros ───────────────────────────── */

.filtros { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; margin-bottom: 10px; }
.filtros label { font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .5px; color: var(--muted); }
select, input[type="search"] {
   font: inherit; font-size: 12px; padding: 4px 9px; border: 1px solid var(--border);
   border-radius: 6px; background: var(--surface); color: var(--text);
}
select:focus, input:focus { outline: none; border-color: var(--primary); }
input[type="search"] { min-width: 190px; }

/* ───────────────────────────── gráficos ───────────────────────────── */

.chart { position: relative; width: 100%; }
.chart svg { display: block; width: 100%; height: auto; overflow: visible; }
.chart .grade line { stroke: var(--border); stroke-width: 1; }
.chart .eixo { fill: var(--muted); font-size: 10px; font-family: var(--font); }
.chart .rotulo-dado { fill: var(--text); font-size: 10px; font-weight: 700; font-family: var(--font); }
/* Coluna zerada: toco na linha de base + "0" em cinza. Slot sem marca nenhuma lê como
   gráfico cortado, e foi assim que o calendário de renovação passou por "mostra só 5". */
.chart .marca-zero { fill: var(--border); }
.chart .rotulo-dado.zero { fill: var(--muted); font-weight: 600; }
.chart .marca-serie { transition: opacity 120ms ease; }
.chart.hover .marca-serie { opacity: .45; }
.chart.hover .marca-serie.destaque { opacity: 1; }
.chart .crosshair { stroke: var(--muted); stroke-width: 1; stroke-dasharray: 3 3; pointer-events: none; }
.chart .hit { fill: transparent; cursor: crosshair; }

.tip {
   left: 50%;   /* antes do 1º toque ele não tem posição, e em 0 metade dele ficava fora da tela */
   position: absolute; pointer-events: none; z-index: 40; opacity: 0;
   transform: translate(-50%, -100%); transition: opacity 120ms ease;
   background: var(--surface); border: 1px solid var(--border); border-radius: 8px;
   padding: 7px 9px; font-size: 11.5px; box-shadow: 0 6px 20px hsl(215 50% 12% / .16);
   min-width: 130px;
}
.tip.on { opacity: 1; }
.tip .tip-tit { font-weight: 700; margin-bottom: 4px; }
.tip .tip-l { display: flex; align-items: center; gap: 6px; justify-content: space-between; }
.tip .tip-l i { width: 8px; height: 8px; border-radius: 2px; flex: none; }
.tip .tip-l span { color: var(--muted); margin-right: auto; }
.tip .tip-l b { font-family: var(--mono); font-weight: 700; }
.tip .tip-tot { border-top: 1px solid var(--border); margin-top: 4px; padding-top: 4px; }

/* ───────────────── relatório de ops embutido ───────────────── */

/* O relatório traz o próprio `.container{max-width:1440px}`; como o nosso também é
   1440, o de dentro não constrange nada — e o padding do body dele é zerado via JS
   após o load, senão soma com o nosso e a margem esquerda foge das outras abas. */
#rel {
   width: 100%; border: 0; display: block;
   background: var(--bg); border-radius: var(--radius);
   min-height: 400px;
}

.vazio { color: var(--muted); font-size: 12px; padding: 14px 0; text-align: center; }
.rodape { color: var(--muted); font-size: 11px; margin-top: 16px; padding-top: 10px; border-top: 1px solid var(--border); }
.erro { border-color: var(--crit-border); background: var(--crit-bg); color: var(--crit); }

/* ───────────── filtro global e blocos que não se aplicam ───────────── */

.filtro-global {
   background: var(--surface); border: 1px solid var(--border);
   border-radius: var(--radius); padding: 7px 12px;
}
/* A barra de período fica entre as abas e o conteúdo, então precisa da mesma respiração
   vertical que os cards têm entre si. `[hidden]` vem do reset do browser, mas `display:flex`
   do `.filtros` o venceria - daí a regra explícita (sem ela a barra aparece nas abas em que
   não se aplica, que é justamente o que o `hidden` existe para evitar). */
.barra-periodo { margin: 0 0 10px; }
/* Inerte, não escondida: mantém a altura para a página não saltar na troca de aba (ver app.js).
   Fica visivelmente apagada para ninguém tentar usá-la, e o motivo vem no chip ao lado. */
.barra-periodo.inerte { opacity: .5; }
.barra-periodo.inerte label { text-decoration: line-through; }
/* Página da Biblioteca (monitor, estudo): a barra some da vista e FICA no fluxo, então a altura da
   página não muda (a mesma trepidação que o `inerte` evita), e não há motivo a explicar - página
   pronta simplesmente não tem período. */
.barra-periodo.oculta { visibility: hidden; }

/* ───── Biblioteca (cabeçalho): monitores, estudos e o preview, fora da barra de abas ───── */
.biblio { position: relative; display: inline-block; }
.biblio-menu {
   position: absolute; right: 0; top: calc(100% + 6px); z-index: 40; min-width: 340px; max-width: 420px;
   background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
   box-shadow: 0 10px 30px rgba(0,0,0,.14); padding: 8px; text-align: left;
}
.biblio-menu h4 {
   margin: 6px 8px 4px; font-size: 10.5px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
   color: var(--muted);
}
.biblio-menu h4 small { font-weight: 500; letter-spacing: 0; text-transform: none; margin-left: 6px; }
.biblio-item {
   display: block; width: 100%; text-align: left; font: inherit; font-size: 12.5px; color: var(--text);
   background: none; border: 0; border-radius: 6px; padding: 7px 8px; cursor: pointer; text-decoration: none;
}
.biblio-item:hover { background: var(--surface2); }
.biblio-item .bi-rot { font-weight: 600; display: block; }
.biblio-item .bi-sub { color: var(--muted); font-size: 11.5px; display: block; }
.biblio-item[aria-current="true"] { background: var(--surface2); box-shadow: inset 3px 0 0 var(--primary); }
/* No celular o botão cai na 2ª linha do cabeçalho, à esquerda, e o menu ancorado em `right:0` com
   340px abria para FORA da tela pela esquerda. Ali ele vira faixa presa à janela, com rolagem própria. */
@media (max-width: 700px) {
   .biblio { position: static; }
   .biblio-menu {
      position: fixed; left: 10px; right: 10px; top: 56px; min-width: 0; max-width: none;
      max-height: calc(100vh - 72px); overflow-y: auto;
   }
}

/* Na barra, o lugar da página aberta pela Biblioteca: um pill inerte com o nome, para a pessoa
   saber onde está sem a página ganhar pill permanente. */
.aba-doc { font-size: 12px; color: var(--muted); padding: 5px 4px; }
.aba-doc b { color: var(--text); }

/* Bloco "Leituras" da Visão geral: a lista da Biblioteca onde quem abre o painel esbarra nela. */
.leituras { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 8px; }
.leitura {
   display: block; text-align: left; font: inherit; border: 1px solid var(--border); border-radius: 8px;
   background: var(--surface); color: var(--text); padding: 9px 11px; cursor: pointer;
}
.leitura:hover { border-color: var(--primary); }
.leitura .bi-rot { font-weight: 600; font-size: 13px; display: block; }
.leitura .bi-sub { color: var(--muted); font-size: 11.5px; display: block; margin-top: 2px; }
.barra-periodo input[type="date"] {
   font: inherit; font-size: 12px; padding: 3px 7px; border: 1px solid var(--border);
   border-radius: 6px; background: var(--surface); color: var(--text);
}
#periodo-custom { display: inline-flex; gap: 6px; align-items: center; }
#periodo-custom[hidden] { display: none; }

/* "mostrando 2000 de 2450" - o corte que era silencioso. Fica DENTRO do card, colado na
   tabela, porque é propriedade daquela lista e não da página. */
.corte {
   margin-top: 8px; font-size: 11.5px; color: var(--muted);
   display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
}
.corte b { color: var(--text); }
.corte .btn { padding: 1px 8px; font-size: 11px; }
.nao-aplica { padding: 22px 10px; line-height: 1.6; }
.nao-aplica b { color: var(--text); }
.nao-aplica small { display: inline-block; margin-top: 4px; opacity: .8; }

/* ─────────────── diagnóstico e recomendações (fim de cada aba) ─────────────── */

/* Mesmo markup dos dois relatórios de ops - o renderizador é um só
   (public/diagnostico.js). A CSS é que continua em três lugares, porque os relatórios
   têm que seguir autocontidos. Ao mexer aqui, mexer nos dois `<style>` de scripts/. */
.diagnostico { margin-top: 12px; }
.insight {
   display: flex; gap: 8px; align-items: flex-start;
   padding: 7px 10px; border-radius: 8px; margin-bottom: 6px;
}
.insight.ok { background: var(--ok-bg); }
.insight.warn { background: var(--warn-bg); }
.insight.crit { background: var(--crit-bg); }
.insight-icon { font-weight: 800; }
.insight.ok .insight-icon { color: var(--ok); }
.insight.warn .insight-icon { color: var(--warn); }
.insight.crit .insight-icon { color: var(--crit); }
.insight-body { min-width: 0; font-size: 12.5px; }
.insight-head { display: flex; gap: 7px; align-items: baseline; flex-wrap: wrap; }
/* O rótulo separa "tem trabalho aqui" de "só saiba disso" antes de a frase ser lida. */
.insight-tag {
   font-size: 9.5px; font-weight: 800; text-transform: uppercase; letter-spacing: .06em;
   padding: 1px 6px; border-radius: 4px; flex-shrink: 0; color: #fff;
}
.insight-tag.ok { background: var(--ok); }
.insight-tag.warn { background: var(--warn); }
.insight-tag.crit { background: var(--crit); }
/* Recência do evento (`quando()` em diagnostico.js): `quente` ocorreu hoje e herda a cor da
   severidade; `frio` está na janela mas parou, e o contorno neutro é o que separa "agir
   agora" de "já passou" antes de a frase ser lida. */
.insight-quando {
   font-size: 9.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
   padding: 1px 6px; border-radius: 4px; flex-shrink: 0;
   border: 1px solid var(--border); color: var(--muted); background: var(--surface);
}
.insight.crit .insight-quando.quente { border-color: var(--crit); color: var(--crit); }
.insight.warn .insight-quando.quente { border-color: var(--warn); color: var(--warn); }
.insight-acao { margin-top: 3px; color: var(--muted); font-size: 12px; }
.insight-acao b { color: var(--text); }
.insight-acao code, .insight-head code {
   font-family: var(--mono); font-size: 11.5px; background: var(--surface2);
   border-radius: 3px; padding: 0 4px;
}
.insight-ref { display: inline-block; margin-top: 3px; font-size: 11px; color: var(--primary); text-decoration: none; }
.insight-ref:hover { text-decoration: underline; }
.diagnostico-nota { font-size: 11px; color: var(--muted); margin-top: 6px; }

/* A barra de abas é sticky: sem a margem, o link do `ref` para debaixo dela. */
[id^="sec-"] { scroll-margin-top: 60px; }

/* ───────────────────── notas de rodapé da página ───────────────────── */

/* O marcador é o único elemento clicável DENTRO de um título, então precisa de área de
   toque própria — daí o padding em vez de só o `sup` cru. */
.nota-ref { font-size: 9px; font-weight: 800; margin-left: 2px; }
.nota-ref a {
   color: var(--primary); text-decoration: none; padding: 0 2px;
   border-radius: 3px; background: var(--surface2);
}
.nota-ref a:hover { background: var(--primary); color: #fff; }

.notas {
   margin-top: 18px; padding: 14px 16px; background: var(--surface);
   border: 1px solid var(--border); border-radius: var(--radius);
}
.notas h2 {
   font-size: 12px; font-weight: 700; text-transform: uppercase;
   letter-spacing: .7px; color: var(--muted); margin-bottom: 10px;
}
.notas ol { margin: 0; padding-left: 22px; }
.notas li {
   font-size: 12px; color: var(--muted); line-height: 1.55;
   padding: 3px 0; scroll-margin-top: 60px;   /* a barra de abas é sticky */
}
.notas li b { color: var(--text); }
.notas li code {
   font-family: var(--mono); font-size: 11.5px;
   background: var(--surface2); border-radius: 3px; padding: 0 4px;
}
/* Realce ao chegar pelo marcador: sem isso o salto leva a uma lista de 8 itens
   iguais e a pessoa tem que reencontrar qual era. */
.notas li:target { color: var(--text); }
.notas li:target::marker { color: var(--primary); font-weight: 800; }

/* ───────────────────────────── celular (≤ 700px) ─────────────────────────────
 *
 * O painel é desktop first, mas tem que ser USÁVEL no celular: nada fora da tela, nenhuma coluna
 * inalcançável, nenhum menu que abre onde o dedo não chega. Medido em 19/09/2026 com viewport de
 * 390px (Playwright). Tabela larga continua rolando na horizontal DENTRO do `.tabela-wrap`, e
 * isso é o desenho: esconder coluna no celular seria a tela mentir sobre o que o dado tem.
 */
@media (max-width: 700px) {
   body { padding: 10px; }
   /* A barra de abas é sticky e quebrava em 3 linhas (117px presos no topo de uma tela de 800).
      Vira uma fila só, que rola de lado. Altura fixa, então a troca de aba não mexe nela (4d). */
   .abas { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
   .abas::-webkit-scrollbar { display: none; }
   .aba, .aba-doc { flex: none; white-space: nowrap; }
   /* Alvo de toque: 5px de padding dava botão de 24px de altura. */
   .aba { padding: 8px 14px; }
   .btn { padding: 7px 11px; }
   select, input[type="search"], .barra-periodo input[type="date"] { padding: 7px 9px; font-size: 16px; }
   input[type="search"] { min-width: 0; flex: 1 1 160px; }
   /* R$ 17.327,76 em 25px quebrava em duas linhas dentro de meia tela. */
   .stat-value { font-size: 20px; }
   .card { padding: 10px 11px; }
   /* Tabela alta dentro de página alta: com 70vh o dedo ficava preso rolando a tabela sem
      conseguir sair dela para a página. */
   .tabela-wrap { max-height: 60vh; }
   /* Identificador de código (`plan_code`, nome de env) não tem onde quebrar e empurrava o card. */
   .insight-body, .notas li, .card h2 { overflow-wrap: anywhere; }
   /* Filtros rotulados (Assinantes): rótulo e select em par, uma linha cada. Soltos no flex-wrap,
      o rótulo ficava no fim de uma linha e o select dele no começo da seguinte. */
   .filtros-grade { display: grid; grid-template-columns: auto 1fr; gap: 6px 8px; }
   .filtros-grade select { width: 100%; }
   .filtros-grade > .btn, .filtros-grade > .mut { grid-column: 1 / -1; }
   /* Frota: o minmax de 300px do card passaria da largura numa tela de 320. */
   .frota-grid { grid-template-columns: 1fr; }
   /* Carimbo e descrição do monitor: o `margin-left:auto` inline empurrava a descrição para uma
      linha própria colada à direita. */
   .filtros .chip-meta { margin-left: 0 !important; }
   .tip { max-width: calc(100vw - 32px); }
}

/* ───────────── aba KPIs: o Metabase embutido (28/09/2026) ───────────── */
/* Altura útil da tela, e o quadro rola por DENTRO: o Metabase é aplicação com rolagem própria,
   então não se mede `scrollHeight` como nos monitores (daria o tamanho da janela). O mínimo
   evita um quadro achatado em janela baixa. */
#kpi {
   width: 100%; border: 0; display: block;
   background: var(--bg); border-radius: var(--radius);
   height: calc(100vh - 160px); min-height: 640px;
}

/* A barra de período em modo KPIs: mesmo elemento, outro conteúdo (ver index.html). */
.barra-periodo .so-kpi { display: none; align-items: center; gap: 8px; flex-wrap: wrap; }
.barra-periodo.modo-kpi .so-kpi { display: inline-flex; }
.barra-periodo.modo-kpi .so-periodo { display: none !important; }

/* ───────────── aba Frota: o Kuma da frota 4G (05/10/2026) ───────────── */
/* A barra em modo Frota: mesmo elemento, outro conteúdo (ver index.html e o modo KPIs acima). */
.barra-periodo .so-frota { display: none; align-items: center; gap: 8px; flex-wrap: wrap; }
.barra-periodo.modo-frota .so-frota { display: inline-flex; }
.barra-periodo.modo-frota .so-periodo { display: none !important; }
.frota-grid { display: grid; gap: 10px; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); }
.frota-item {
   min-width: 0; padding: 10px 12px; background: var(--surface);
   border: 1px solid var(--border); border-left: 4px solid var(--ok); border-radius: var(--radius);
}
.frota-item.crit { border-left-color: var(--crit); }
.frota-item.warn { border-left-color: var(--warn); }
.frota-topo { display: flex; align-items: center; gap: 8px; }
.frota-nome { font-weight: 600; overflow-wrap: anywhere; }
.frota-msg { margin-top: 6px; font-size: 13px; overflow-wrap: anywhere; }
.frota-meta { margin-top: 4px; font-size: 12px; color: var(--muted); }
/* Uma barra por batida, mais nova à direita; a largura se divide entre elas, então 50 batidas
   cabem num card de celular sem rolar. */
.frota-barras { display: flex; gap: 2px; height: 18px; margin-top: 8px; }
.frota-barras .fb { flex: 1 1 0; min-width: 2px; max-width: 8px; border-radius: 2px; background: var(--ok); }
.frota-barras .fb.crit { background: var(--crit); }
.frota-barras .fb.warn { background: var(--warn); }
