/* Nexus RFID — página operacional.
 *
 * Ferramenta interna, lida em pé, muitas vezes num monitor ruim de
 * corredor: densidade e contraste antes de qualquer efeito. Nenhuma
 * fonte externa, nenhum framework — a rede do hospital pode não ter
 * saída para a internet.
 *
 * Todas as cores são tokens. Os três estados de tema (claro, escuro por
 * preferência do sistema, escuro escolhido) redefinem só os tokens.
 */


/* AS CORES E OS TOKENS MORAM EM `tema.css`, que é GERADO.
 *
 * Para mudar qualquer cor, edite `design/paleta.json` e rode
 * `design/gerar.sh` — os dois lados (esta página e o armário) saem do
 * mesmo arquivo, e é isso que os impede de divergir.
 *
 * Aqui ficam os tokens que NÃO são cor: raio, sombra, famílias e a escala
 * tipográfica. Eles não se derivam de uma semente, e misturá-los com o que
 * se deriva faria o gerador ter de preservar edições humanas.
 */
:root {
  /* FORMA — a escala do Material 3, e não um raio para tudo.
   *
   * O raio carrega significado: 4 diz "campo de texto", 12 diz "cartão",
   * 28 diz "diálogo", e cheio diz "isto é um controle, toque". Um valor
   * único aplicado em tudo apaga essa gramática, e foi o que havia aqui —
   * `--raio: 6px` em campo, cartão, pílula e modal. */
  --forma-xs:    4px;
  --forma-sm:    8px;
  --forma-md:   12px;
  --forma-lg:   16px;
  --forma-xl:   28px;
  --forma-cheia: 999px;

  /* Compatibilidade: regras antigas ainda pedem --raio. */
  --raio:        var(--forma-sm);
  --raio-pequeno:var(--forma-xs);
  --raio-grande: var(--forma-md);

  /* ELEVAÇÃO em níveis, como o Material define. Num ERP quase tudo vive
   * entre 0 e 2: sombra aqui é hierarquia, não enfeite. */
  --elev-1: 0 1px 2px rgba(16, 32, 48, .08), 0 1px 3px 1px rgba(16, 32, 48, .05);
  --elev-2: 0 1px 2px rgba(16, 32, 48, .10), 0 2px 6px 2px rgba(16, 32, 48, .07);
  --elev-3: 0 4px 8px 3px rgba(16, 32, 48, .08), 0 1px 3px rgba(16, 32, 48, .12);
  --sombra: var(--elev-1);

  /* CAMADAS DE ESTADO — a assinatura tátil do Material. O elemento não
   * troca de cor ao ser tocado: ele recebe por cima um véu da PRÓPRIA cor
   * de conteúdo, numa opacidade fixa. Por isso o mesmo gesto se parece
   * igual num botão claro e num escuro, sem ninguém escolher dois tons. */
  --estado-hover:    .08;
  --estado-foco:     .10;
  --estado-pressao:  .10;

  /* MOVIMENTO: curva padrão do Material. Curto, porque é uma ferramenta. */
  --curva: cubic-bezier(.2, 0, 0, 1);
  --rapido: 120ms;

  /* PILHA DO SISTEMA, e não uma fonte baixada. A rede de um hospital pode
   * não ter saída para a internet, e um `<link>` para um provedor de fontes
   * falha em silêncio: a página carrega com a fonte de recurso e ninguém
   * descobre por que ela ficou diferente. A identidade vem da escala e dos
   * pesos, que são nossos de qualquer jeito. */
  --fonte: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, "Cascadia Mono", "SF Mono", Consolas, "Liberation Mono", monospace;
}

:root[data-theme="dark"], :root:not([data-theme="light"]) {
  --sombra: 0 1px 2px rgba(0, 0, 0, .5);
}
* { box-sizing: border-box; }

/* Precisa vir antes de qualquer regra com `display`. O `hidden` do
 * navegador é só um `display: none` de folha de estilo padrão, e
 * qualquer `display` nosso o vence — a tela de login ficaria visível por
 * cima da aplicação, que foi exatamente o que aconteceu. */
[hidden] { display: none !important; }

/* FUNDO EM MALHA, e não cor chapada.
 *
 * Três gradientes radiais no tom da própria paleta, muito lavados. Dão
 * profundidade à página sem nada se mover: custo zero de CPU, e nada que
 * dispute a leitura de uma tabela de quatrocentas linhas.
 *
 * ESTÁTICO DE PROPÓSITO. Um fundo animado num painel ligado o dia inteiro
 * é processador queimando atrás de uma tela de estoque — e esta folha é a
 * mesma que serve o navegador de quem abre a página num corredor.
 *
 * `fixed` para a malha não rolar junto: ela é o plano de fundo da sala,
 * não do documento.
 */
body {
  margin: 0;
  background-color: var(--ground);
  background-image:
    radial-gradient(62rem 44rem at 10% -10%, var(--acento-fraco) 0%, transparent 55%),
    radial-gradient(52rem 38rem at 94% 2%, var(--terciaria-fraca) 0%, transparent 50%);
  background-attachment: fixed;
  background-repeat: no-repeat;
  color: var(--texto);
  font: 14px/1.5 var(--fonte);
  -webkit-font-smoothing: antialiased;
}

/* TIPOGRAFIA — a escala do Material, em densidade de ERP.
 *
 * O Material foi desenhado para um celular a trinta centímetros do rosto;
 * esta tela é um monitor de corredor com quarenta linhas de tabela. Os
 * papéis são os mesmos (title, body, label) e os tamanhos encolhem — o que
 * NÃO encolhe é o espaçamento de letra dos rótulos em caixa alta, que é o
 * que os mantém legíveis pequenos.
 */
h1, h2, h3 { margin: 0; text-wrap: balance; }
h1 { font-size: 20px; line-height: 1.4; font-weight: 600; letter-spacing: -.01em; }
h2 { font-size: 16px; line-height: 1.45; font-weight: 600; letter-spacing: -.005em; }
h3 { font-size: 13px; line-height: 1.5; font-weight: 600; }
p { margin: 0; }

.sub { color: var(--texto2); font-size: 12px; line-height: 1.45; }
.mono { font-family: var(--mono); font-size: 12px; }

/* NÚMERO QUE SE COMPARA NA VERTICAL usa largura fixa de dígito. Sem isso,
 * "1.111" ocupa menos que "8.888" e a coluna dança a cada atualização. */
.num { font-variant-numeric: tabular-nums; }

/* O rótulo do Material: pequeno, caixa alta, espaçado. */
.rotulo {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--texto3);
}

:focus-visible {
  outline: 2px solid var(--acento);
  outline-offset: 2px;
  border-radius: 3px;
}

/* ---------------- marca ---------------- */
.marca { display: flex; align-items: center; gap: 12px; }
.marca-sigla {
  display: grid; place-items: center;
  width: 34px; height: 34px; flex: none;
  background: var(--acento); color: #fff;
  border-radius: var(--forma-md);
  font-weight: 700; font-size: 13px; letter-spacing: .06em;
}
:root[data-theme="dark"] .marca-sigla,
:root:not([data-theme="light"]) .marca-sigla { color: var(--sobre-acento); }
.marca.compacta .marca-sigla { width: 28px; height: 28px; font-size: 11px; }

/* ---------------- login ---------------- */
.login { min-height: 100vh; display: grid; place-items: center; padding: 24px; }

.cartao-login {
  width: min(360px, 100%);
  display: flex; flex-direction: column; gap: 8px;
  background: var(--superficie);
  border: 1px solid var(--borda);
  border-radius: var(--forma-lg);
  padding: 28px;
  box-shadow: var(--elev-2);
}
.cartao-login .marca { margin-bottom: 16px; }
.cartao-login label { font-size: 12px; color: var(--texto2); margin-top: 6px; }
.cartao-login .botao { margin-top: 18px; }

/* O "i" do campo de e-mail: a ressalva sem o peso de uma frase.
 *
 * `title` NATIVO, e não uma bolha desenhada por nós. É a tela de login: ela
 * carrega antes de qualquer decisão de sessão, e uma dica própria custaria
 * CSS e JS para repetir o que o navegador já faz há trinta anos - com o
 * atraso, o posicionamento e o toque no celular já resolvidos.
 *
 * `cursor: help` é o que avisa que há algo ali antes de a pessoa parar o
 * mouse; sem ele, o "i" parece enfeite. */
/* O "i" vale em qualquer tela, e não só no login.
 *
 * Ele nasceu escopado em `.cartao-login` porque foi lá que apareceu primeiro.
 * Quando a tela de impressão passou a usá-lo, ele saiu como uma letra "i"
 * solta, sem o círculo e sem o cursor de ajuda — e ninguém percebia que havia
 * uma explicação ali (visto na bancada em 2026-09-27). */
.pista,
.cartao-login .pista {
  display: inline-flex; align-items: center; justify-content: center;
  width: 14px; height: 14px; margin-left: 4px;
  border: 1px solid var(--borda-forte); border-radius: 50%;
  font-size: 10px; font-style: italic; line-height: 1;
  color: var(--texto3); cursor: help; user-select: none;
}
.pista:hover, .pista:focus-visible,
.cartao-login .pista:hover,
.cartao-login .pista:focus-visible { color: var(--texto2); border-color: var(--texto3); }

input, select, textarea {
  font: inherit;
  color: var(--texto);
  background: var(--superficie2);
  border: 1px solid var(--borda-forte);
  /* Campo de texto do Material: canto pequeno. E o raio que diz "aqui se
   * digita" - se ele for igual ao do botao, os dois viram a mesma coisa. */
  border-radius: var(--forma-xs);
  padding: 9px 12px;
  width: 100%;
  transition: border-color var(--rapido) var(--curva), box-shadow var(--rapido) var(--curva);
}
/* FOCO COM DOIS FIOS, como o campo preenchido do Material: a borda muda de
 * cor E ganha espessura por dentro. Só a cor nao basta para quem enxerga
 * mal, e esta tela vive em monitor de corredor. */
input:focus, select:focus, textarea:focus {
  border-color: var(--acento);
  box-shadow: inset 0 0 0 1px var(--acento);
  outline: none;
}

.erro {
  color: var(--grave);
  background: var(--grave-fundo);
  border-radius: var(--raio);
  padding: 8px 10px;
  font-size: 13px;
  margin-top: 12px;
}

/* ---------------- botões ----------------
 *
 * As quatro variantes do Material, e cada uma diz uma coisa diferente
 * sobre a ação: `primario` (filled) é a ação principal da tela e só deve
 * haver uma; o padrão (outlined) é ação comum; `tonal` é apoio com algum
 * peso; `fantasma` (text) é ação secundária ou destrutiva de baixa
 * frequência. Quem tem quatro botões iguais na tela não hierarquizou nada.
 *
 * CANTO CHEIO. É o que separa "isto se toca" de "isto é um bloco" à
 * distância, sem depender de cor — e é a mudança mais visível ao trocar os
 * 6px que havia aqui pela escala do Material.
 */
.botao {
  position: relative;
  isolation: isolate;          /* a camada de estado não vaza para os vizinhos */
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font: inherit;
  font-weight: 500;
  letter-spacing: .01em;
  min-height: 36px;
  border-radius: var(--forma-cheia);
  padding: 6px 18px;
  border: 1px solid var(--borda-forte);
  background: var(--superficie);
  color: var(--texto);
  cursor: pointer;
  transition: box-shadow var(--rapido) var(--curva), border-color var(--rapido) var(--curva);
}

/* A CAMADA DE ESTADO, uma vez só para todas as variantes.
 *
 * Véu da própria cor de conteúdo, em opacidade fixa — é assim que o
 * Material define, e é o que faz o toque parecer igual no botão claro e no
 * escuro sem ninguém escolher dois tons à mão. */
.botao::after {
  content: "";
  position: absolute;
  inset: 0;
  background: currentColor;
  opacity: 0;
  transition: opacity var(--rapido) var(--curva);
  pointer-events: none;
  z-index: -1;
}
.botao:hover::after         { opacity: var(--estado-hover); }
.botao:focus-visible::after { opacity: var(--estado-foco); }
.botao:active::after        { opacity: var(--estado-pressao); }

.botao[disabled] { opacity: .38; cursor: not-allowed; }   /* 38% é o valor do Material */
.botao[disabled]::after { opacity: 0; }

.botao.primario {
  background: var(--acento); border-color: var(--acento); color: #fff;
  font-weight: 600;
}
:root[data-theme="dark"] .botao.primario,
:root:not([data-theme="light"]) .botao.primario { color: var(--sobre-acento); }
/* O `primario` NÃO troca de fundo ao passar o mouse: quem faz isso é a
 * camada de estado, que já está lá. Trocar as duas coisas ao mesmo tempo
 * dava um salto de cor que destoava do resto. */
.botao.primario { box-shadow: var(--elev-1); }
.botao.primario:hover { box-shadow: var(--elev-2); }

/* Tonal: apoio com peso. O fundo é o contêiner da marca, e o texto é a
 * marca escura — legível sem gritar. */
.botao.tonal {
  background: var(--acento-fraco);
  border-color: transparent;
  color: var(--acento-forte);
}

.botao.fantasma { border-color: transparent; background: transparent; color: var(--texto2); }
.botao.fantasma:hover { color: var(--acento); }
.botao.pequeno { min-height: 30px; padding: 4px 12px; font-size: 12px; }
.botao.perigo { color: var(--grave); }
.botao.perigo:hover { border-color: var(--grave); }

/* ---------------- estrutura ---------------- */
.topo {
  display: flex; align-items: center; gap: 20px;
  padding: 10px 20px;
  background: var(--superficie);
  border-bottom: 1px solid var(--borda);
  position: sticky; top: 0; z-index: 10;
  flex-wrap: wrap;
}
/* O menu segue o item de navegação do Material: pílula, e o selecionado
 * ganha o contêiner da marca — não um sublinhado, que é idioma de web
 * antiga e some em tela pequena. */
.menu { display: flex; gap: 2px; flex: 1 1 auto; flex-wrap: wrap; }
.menu a {
  padding: 7px 14px;
  border-radius: var(--forma-cheia);
  color: var(--texto2);
  text-decoration: none;
  font-weight: 500;
  transition: background var(--rapido) var(--curva), color var(--rapido) var(--curva);
}
.menu a:hover { background: var(--superficie2); color: var(--texto); }
.menu a.ativo { background: var(--acento-fraco); color: var(--acento-forte); font-weight: 600; }

.topo-fim { display: flex; align-items: center; gap: 12px; }
/* Quando marca + menu + usuario nao cabem numa linha (~1120 px), o usuario era o que caia, sozinho e
 * a esquerda, numa segunda linha. Agora a marca e o usuario ficam juntos na primeira e o menu ocupa
 * a segunda inteira. */
@media (max-width: 1120px) {
  .topo .marca { order: 1; }
  .topo-fim { order: 2; margin-left: auto; }
  .menu { order: 3; flex: 1 0 100%; }
}
.quem { display: flex; flex-direction: column; line-height: 1.25; text-align: right; }
.quem span:first-child { font-weight: 600; font-size: 13px; }

.conteudo {
  max-width: 1180px;
  margin: 0 auto;
  padding: 22px 20px 60px;
  display: flex; flex-direction: column; gap: 20px;
}

.cabeca-secao { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.cabeca-secao .sub { flex: 1; }

/* ---------------- painéis ---------------- */
/* Cartão do Material, variante com contorno: a borda de um fio e a sombra
 * de nível 1. Num ERP com muitos blocos empilhados, cartão elevado demais
 * vira relevo de brinquedo - a hierarquia tem de vir do tom, nao da altura. */
.painel {
  background: var(--superficie);
  border: 1px solid var(--borda);
  border-radius: var(--forma-md);
  box-shadow: var(--elev-1);
  overflow: hidden;
}
.painel > header {
  padding: 12px 16px;
  border-bottom: 1px solid var(--borda);
  display: flex; align-items: center; gap: 10px;
  background: var(--superficie2);
}
.painel > header h2 { flex: 1; }
.painel .corpo { padding: 16px; }

.grade { display: grid; gap: 14px; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); }

/* ---------------- equipamento ---------------- */
/* O CARTÃO DE EQUIPAMENTO É CHEIO, como o mostrador da Telemetria.
   A abertura responde "está tudo bem?" para quem passa pela sala, e isso
   se lê pela mancha antes do algarismo. */
.equip-cheio {
  display: flex; flex-direction: column; gap: 14px;
  padding: 16px;
  border: 0;
  background: var(--acento-cheio);
  color: var(--sobre-cheio);
  box-shadow: var(--elev-2);
}
.equip-cheio > header {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 0; border: 0; background: none;
}
.equip-cheio .nome { flex: 1; font-weight: 620; font-size: 16px; }

/* Sobre um cartão cheio, o segundo plano não é outra cor: é um VÉU da
   própria cor de conteúdo. É a mesma ideia da camada de estado do
   Material, e o que mantém o cartão legível quando a paleta muda. */
.selo-vidro, .porta-cheia, .total-equip {
  background: color-mix(in oklab, var(--sobre-cheio) 14%, transparent);
}
.selo-vidro {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 10px; border-radius: var(--forma-cheia);
  font-size: 11px; font-weight: 600; letter-spacing: .04em;
  color: var(--sobre-cheio);
}
.selo-vidro .ponto { background: currentColor; }
.sub-claro { color: color-mix(in oklab, var(--sobre-cheio) 78%, transparent); font-size: 12px; }

.total-equip {
  display: flex; align-items: baseline; gap: 8px;
  padding: 10px 14px; border-radius: var(--forma-md);
  color: inherit; text-decoration: none;
  transition: background var(--rapido) var(--curva);
}
.total-equip:hover { background: color-mix(in oklab, var(--sobre-cheio) 24%, transparent); }
.total-equip strong { font-size: 26px; font-weight: 700; }
.total-equip span { font-size: 12px; opacity: .85; }

.portas-cheias {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr)); gap: 10px;
}
.porta-cheia {
  display: flex; flex-direction: column; gap: 2px;
  padding: 10px 12px; border-radius: var(--forma-md);
}
.porta-cheia .rotulo { color: inherit; opacity: .85; }
.porta-cheia strong { font-size: 22px; font-weight: 700; line-height: 1.1; }
.porta-cheia .unidade { font-size: 11px; opacity: .8; margin-top: -2px; }
.porta-cheia .temp-porta {
  display: flex; align-items: center; gap: 5px;
  margin-top: 6px; padding-top: 6px;
  border-top: 1px solid color-mix(in oklab, var(--sobre-cheio) 22%, transparent);
  font-size: 13px; font-weight: 600; font-variant-numeric: tabular-nums;
}

.problemas { display: flex; flex-wrap: wrap; gap: 6px; }

.vazio { padding: 16px; color: var(--texto3); font-size: 13px; }

/* Nota de atenção dentro de um painel: o que a tela mostra existe, mas não
   faz o que se esperaria. Fundo lavado porque INFORMA — o preenchimento
   forte fica para o que se opera. */
.nota-atencao {
  margin: 0 16px 12px; padding: 12px 14px; border-radius: 10px;
  background: var(--alerta-fundo); color: var(--alerta);
  font-size: 13px; line-height: 1.5;
}
.nota-atencao .mono { color: inherit; }

/* Linha de registro desativado: continua legível, mas recua. */
tr.apagada td { opacity: .55; }

/* ---------------- selos ---------------- */
.selo {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 9px;
  border-radius: var(--forma-sm);
  font-size: 11px; font-weight: 600; letter-spacing: .01em;
  background: var(--superficie2); color: var(--texto2);
  border: 1px solid var(--borda);
  white-space: nowrap;
}
.selo.ok    { background: var(--ok-fundo);    color: var(--ok);    border-color: transparent; }
.selo.atencao { background: var(--alerta-fundo);color: var(--alerta);border-color: transparent; }
.selo.grave { background: var(--grave-fundo); color: var(--grave); border-color: transparent; }
.selo.acento{ background: var(--acento-fraco);color: var(--acento);border-color: transparent; }

/* DOIS NÍVEIS DE ÊNFASE, e o Material tem os dois de propósito: o par
   `error`/`onError` (preenchimento forte, texto branco) para o que pede
   ação, e `errorContainer`/`onErrorContainer` (fundo lavado, texto escuro)
   para o que apenas informa. O que havia aqui era só o segundo — daí a
   sensação de que nada gritava.

   O forte é para OFFLINE, falta de energia, emergência. Aplicá-lo em tudo
   devolveria o problema ao contrário: se tudo grita, nada é ouvido. */
.selo.cheio {
  border-color: transparent;
  color: var(--sobre-cheio);
  background: var(--acento-cheio);   /* sem estado: "em uso", "fechada" - informa, não alerta */
  font-weight: 700; letter-spacing: .05em;
  padding: 4px 11px;
  display: inline-flex; align-items: center; gap: 5px;
}
.selo.cheio.grave  { background: var(--grave-cheio); }
.selo.cheio.alerta { background: var(--alerta-cheio); }
.selo.cheio.ok     { background: var(--ok-cheio); }
.selo.cheio .icone { width: 13px; height: 13px; }

.ponto { width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex: none; }

/* ---------------- tabela ---------------- */
.rolagem { overflow-x: auto; }
table { border-collapse: collapse; width: 100%; font-size: 13px; }
th, td { text-align: left; padding: 9px 16px; border-bottom: 1px solid var(--borda); vertical-align: middle; }
th {
  font-size: 11px; text-transform: uppercase; letter-spacing: .05em;
  color: var(--texto3); font-weight: 600;
  background: var(--superficie2);
  position: sticky; top: 0;
}
tbody tr:last-child td { border-bottom: 0; }
tbody tr:hover { background: var(--superficie2); }
td.acoes { text-align: right; white-space: nowrap; }

/* ---------------- árvore de locais ---------------- */
.arvore { padding: 8px 0; }
.no {
  display: flex; align-items: center; gap: 9px;
  padding: 6px 16px;
}
.no:hover { background: var(--superficie2); }
.no .traco { color: var(--texto3); font-family: var(--mono); white-space: pre; }
.no .nome-no { font-weight: 500; }
.no .sgln { color: var(--texto3); font-family: var(--mono); font-size: 11px; margin-left: auto; }

/* ---------------- alertas ---------------- */
.linha-alerta {
  display: grid;
  grid-template-columns: auto 1fr auto auto;
  gap: 12px; align-items: center;
  padding: 10px 16px;
}
.linha-alerta + .linha-alerta { border-top: 1px solid var(--borda); }

/* ---------------- aviso flutuante ---------------- */
.aviso {
  position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%);
  background: var(--texto); color: var(--ground);
  padding: 10px 18px; border-radius: var(--raio);
  box-shadow: var(--sombra); font-size: 13px;
  max-width: 90vw;
  z-index: 50;
}
.aviso.ruim { background: var(--grave); color: #fff; }

/* Token de credencial: aparece uma vez só, e precisa ser copiável. */
.token {
  font-family: var(--mono); font-size: 12px;
  background: var(--acento-fraco); color: var(--texto);
  border: 1px dashed var(--acento);
  border-radius: var(--raio);
  padding: 10px 12px;
  word-break: break-all;
  margin-top: 10px;
}

@media (max-width: 620px) {
  .topo { gap: 10px; }
  .quem { display: none; }
  .conteudo { padding: 16px 12px 48px; }
}

@media (prefers-reduced-motion: no-preference) {
  .botao, .menu a { transition: background .12s, color .12s, border-color .12s; }
}

/* ---------------- diálogo de formulário ---------------- */
.veu {
  position: fixed; inset: 0;
  background: rgba(8, 14, 20, .55);
  display: grid; place-items: center;
  padding: 20px;
  z-index: 40;
  overflow-y: auto;
}
.dialogo {
  width: min(560px, 100%);
  /* 560px é largura de FORMULÁRIO — dois campos lado a lado e olho. */
  background: var(--superficie);
  border: 1px solid var(--borda);
  /* 28px: o canto de diálogo do Material. É o maior raio do sistema, e
   * existe para dizer "isto está por cima de tudo" antes de qualquer
   * leitura - a sombra sozinha nao diz isso em tela clara. */
  border-radius: var(--forma-xl);
  box-shadow: var(--elev-3), 0 12px 40px rgba(0, 0, 0, .18);
  max-height: 90vh;
  display: flex; flex-direction: column;
}
.dialogo > header {
  padding: 14px 18px;
  border-bottom: 1px solid var(--borda);
  background: var(--superficie2);
  border-radius: 10px 10px 0 0;
}
.dialogo > footer {
  padding: 12px 18px;
  border-top: 1px solid var(--borda);
  display: flex; gap: 8px; justify-content: flex-end;
}
.campos {
  padding: 18px;
  display: grid; gap: 14px;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  overflow-y: auto;
}
/* DIÁLOGO QUE MOSTRA LISTA, e não formulário.
 *
 * A classe era usada em dois lugares — as etiquetas de um evento e o resultado
 * da importação de planilha — e NÃO EXISTIA NO CSS. Os dois ficavam nos 560px
 * de formulário. */
.dialogo.largo { width: min(880px, 100%); }

/* O QUE NÃO É CAMPO OCUPA A LINHA INTEIRA.
 *
 * `.campos` é uma grade de DUAS COLUNAS, feita para pares de campos de
 * formulário. Uma tabela posta ali dentro virava mais um "campo": ficava com
 * metade da largura do diálogo, a outra metade vazia ao lado, e transbordava
 * na horizontal dentro da própria metade. Medido antes de mexer: diálogo de
 * 560px, colunas de 254px, tabela precisando de 320.
 *
 * Um `.campo` continua obedecendo à grade; qualquer outro filho — tabela,
 * parágrafo, o `.rolagem` da lista de etiquetas — passa a ocupar as duas
 * colunas, que é o que se quer em todos os casos que existem hoje. */
.campos > :not(.campo) { grid-column: 1 / -1; min-width: 0; }

/* A LISTA DE ETIQUETAS DE UM EVENTO.
 *
 * Rolagem VERTICAL própria, e não a do diálogo: um inventário move centenas de
 * EPCs, e sem um teto aqui a lista empurrava o rodapé — com o botão Fechar —
 * para fora da tela. O `max-height` do diálogo cortava o que passasse de 90vh,
 * e o que ficava de fora era justamente a saída.
 *
 * A coluna do EPC recebe largura de EPC: 24 caracteres em monoespaçada têm
 * tamanho previsível, e deixar a tabela distribuir sozinha espremia o código
 * para dar espaço a um botão de uma palavra. */
.lista-etiquetas {
  max-height: min(420px, 55vh);
  overflow-y: auto;
  overflow-x: auto;
  border: 1px solid var(--borda);
  border-radius: var(--forma-md, 8px);
}
.lista-etiquetas table { width: 100%; }
.lista-etiquetas td.mono { white-space: nowrap; width: 1%; }
.lista-etiquetas td.acoes { text-align: right; }

.campo { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
/* Um campo que ocupa a linha toda: nome, SGLN, descrição. */
.campo.largo { grid-column: 1 / -1; }
.campo > label { font-size: 12px; color: var(--texto2); }
.campo .ajuda { font-size: 11px; color: var(--texto3); }
.campo.caixa {
  flex-direction: row; align-items: center; gap: 8px;
}
.campo.caixa input { width: auto; }
.campo.caixa > label { font-size: 13px; color: var(--texto); }

@media (max-width: 560px) {
  .campos { grid-template-columns: 1fr; }
}

/* ---------------- lista de alertas configuráveis ---------------- */
.alerta-cfg {
  display: grid;
  grid-template-columns: 1fr auto auto;
  gap: 14px; align-items: center;
  padding: 9px 16px;
}
.alerta-cfg + .alerta-cfg { border-top: 1px solid var(--borda); }
.alerta-cfg .chave { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--texto2); }

/* ---- rastreio ---------------------------------------------------- */

.linha-busca { display: flex; gap: 8px; }
.linha-busca input {
  flex: 1;
  font-family: var(--mono);
  font-size: 13px;
  padding: 9px 12px;
  border: 1px solid var(--borda);
  border-radius: var(--forma-xs);
  background: var(--superficie);
  color: var(--texto);
}
.linha-busca input:focus {
  outline: none;
  border-color: var(--acento);
  box-shadow: inset 0 0 0 1px var(--acento);
}
.ajuda { display: block; margin-top: 8px; color: var(--texto3); font-size: 12px; }

/* O ESTADO DE AGORA ANTES DA HISTÓRIA. Quem abre um rastro quase sempre
   quer a resposta curta - "onde está e em que pé" -, e só desce para a
   linha do tempo quando ela não basta. */
.estado-agora {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
  padding-bottom: 14px;
  margin-bottom: 14px;
  border-bottom: 1px dashed var(--borda);
}
.estado-agora strong { font-size: 17px; }

.ficha { display: grid; gap: 12px; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); }
.ficha-item { display: flex; flex-direction: column; gap: 2px; line-height: 1.3; }

/* A LINHA AUTOMÁTICA SE DISTINGUE DAS OUTRAS, e por fundo e não por cor de
   texto: numa lista de trinta e cinco eventos, a pergunta "isto alguém fez
   ou o sistema concluiu" tem de ter resposta antes da leitura. */
tr.automatico > td { background: var(--alerta-fundo); }

/* ---- saldo atual -------------------------------------------------- */

/* ÁRVORE FIXA À ESQUERDA, detalhe à direita. Quem procura uma caixa não
   quer perder o mapa a cada clique — e num monitor de corredor há largura
   de sobra para os dois. Abaixo de 900px vira uma coluna só: aí a árvore
   passa a ser o índice, e o detalhe vem depois dela. */
.saldo-dois {
  display: grid;
  grid-template-columns: minmax(240px, 320px) 1fr;
  gap: 20px;
  align-items: start;
}
.saldo-dois > div { display: flex; flex-direction: column; gap: 20px; }

@media (max-width: 900px) {
  .saldo-dois { grid-template-columns: 1fr; }
}

.arvore-saldo { padding: 6px 0 10px; max-height: 70vh; overflow: auto; }

.no-saldo {
  display: flex; align-items: center; gap: 8px;
  padding-top: 7px; padding-bottom: 7px; padding-right: 12px;
  cursor: pointer;
  border-left: 3px solid transparent;
  transition: background var(--rapido) var(--curva);
}
.no-saldo:hover { background: var(--superficie2); }
.no-saldo.ativo {
  background: var(--acento-fraco);
  border-left-color: var(--acento);
}
.no-saldo.ativo .nome-local { font-weight: 600; color: var(--acento-forte); }

/* VAZIO FICA NA LISTA, só apagado: sumir com ele deixaria quem procura sem
   saber se o local não tem nada ou se não existe — e as duas coisas levam
   a ações opostas. */
.no-saldo.vazio { color: var(--texto3); }
.no-saldo.vazio .qtd { opacity: .72; }

.no-saldo .glifo { color: var(--texto3); font-size: 12px; flex: none; }
.no-saldo .nome-local { flex: 1; font-size: 13px; }
.no-saldo .qtd { font-size: 13px; font-weight: 600; }

.portas-saldo { margin-top: 14px; display: flex; flex-direction: column; gap: 7px; }
.pilulas { display: flex; gap: 6px; flex-wrap: wrap; }

/* A linha inteira é o alvo do clique, então ela precisa parecer alvo. */
table.clicavel tbody tr { cursor: pointer; }
table.clicavel tbody tr:hover { background: var(--superficie2); }

td a { color: var(--acento); text-decoration: none; }
td a:hover { text-decoration: underline; }

/* O NÚMERO DERIVADO SE DISTINGUE DO GUARDADO. Na porta, a quantidade não é
   saldo dela — é quantas unidades do armário foram lidas ali por último. Em
   peso normal e na mesma cor, alguém somaria armário + portas e chegaria ao
   dobro. */
.no-saldo .qtd.derivado {
  font-weight: 500;
  color: var(--texto3);
  font-variant-numeric: tabular-nums;
}

/* ---- posição ------------------------------------------------------ */

/* PROPORÇÃO ANTES DE NÚMERO. A pergunta desta tela — "quanto do meu
   material está parado fora do armário" — se lê antes numa faixa do que
   numa coluna de inteiros. */
.barra-posicao {
  display: flex;
  height: 10px;
  border-radius: var(--forma-cheia);
  overflow: hidden;
  background: var(--superficie3);
  margin-bottom: 14px;
}
.fatia { display: block; height: 100%; background: var(--texto3); }
.fatia.ok      { background: var(--ok); }
.fatia.atencao { background: var(--alerta); }
.fatia.grave   { background: var(--grave); }
.fatia.acento  { background: var(--acento); }

.celulas { display: flex; gap: 10px; flex-wrap: wrap; }

.celula-posicao {
  display: flex; align-items: center; gap: 8px;
  font: inherit;
  padding: 8px 12px;
  border: 1px solid var(--borda);
  border-radius: var(--forma-md);
  background: var(--superficie);
  color: var(--texto);
  cursor: pointer;
  transition: border-color var(--rapido) var(--curva), background var(--rapido) var(--curva);
}
.celula-posicao:hover { border-color: var(--acento); background: var(--superficie2); }
.celula-posicao strong { font-size: 15px; }

/* PARADO DEMAIS SE MARCA, e só onde o tempo acusa alguma coisa: consumido
   há noventa dias é histórico, "em uso há nove" é a razão da tela. Marcar
   os dois ensinaria a ignorar a marca. */
.celula-posicao.alarme {
  border-color: var(--alerta);
  background: var(--alerta-fundo);
}
.celula-posicao.alarme .sub { color: var(--alerta); font-weight: 600; }

/* O recorte fica no cabeçalho da seção, ao lado do título — é um ajuste da
   leitura, não uma ação. Botão diria "faça isto"; um seletor diz "veja
   assim". */
.recorte { display: flex; align-items: center; gap: 8px; }
.recorte select { width: auto; min-width: 11rem; }

/* O QUE FICOU DE FORA aparece ao lado do que ficou dentro. Um filtro que só
   encolhe o total faz o consumido do mês parecer o consumido de sempre. */
.celula-posicao .fora { color: var(--texto3); font-style: italic; }

/* ---- telemetria --------------------------------------------------- */

/* MOSTRADOR CHEIO, e não contêiner lavado.
 *
 * O resto da aplicação é formulário e tabela, e ali o certo é fundo pálido
 * com texto colorido. Esta tela é painel: lida em pé, muitas vezes num
 * monitor de corredor, decidindo se alguém precisa ir até o equipamento.
 * O que chega primeiro é a mancha de cor; o algarismo vem depois. Com
 * fundo pálido a tela ficava brilhante e sem peso — parecia rascunho, e
 * não instrumento. */
.mostradores {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr));
  gap: 12px;
}

/* DOIS BLOCOS, PORQUE SÃO DOIS TIPOS DE DADO.
 *
 * `.tile` é o número OPERACIONAL — saldo, total, contagem, alerta: à esquerda,
 * rótulo em cima e o algarismo embaixo, como um indicador de planilha.
 * `.tile.medida` é a MEDIDA de um sensor — temperatura, umidade, bateria,
 * "sem leitura": centrado, com o ícone em um disco, como um instrumento.
 * A cor de família (`frio`, `umidade`…) só existe do lado da medida; o lado
 * operacional usa o azul da marca e os três estados.
 *
 * O FUNDO É `--fundo` MISTURADO COM A SUPERFÍCIE. No claro a mistura é total
 * (a cor cheia do token); no escuro ela cede um quinto para o plano, e o cartão
 * deixa de ser uma mancha saturada sobre o fundo. Escurecer só melhora o
 * contraste do texto branco — que já passava. */
.tile {
  --fundo: var(--acento-cheio);
  --mistura: 100%;
  display: flex; flex-direction: column; align-items: flex-start; justify-content: space-between;
  gap: 10px;
  min-height: 92px;
  padding: 14px 16px;
  border-radius: var(--forma-md);
  background: color-mix(in oklab, var(--fundo) var(--mistura), var(--superficie));
  color: var(--sobre-cheio);
  box-shadow: var(--elev-1);
  text-align: left;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .tile { --mistura: 80%; }
}
:root[data-theme="dark"] .tile { --mistura: 80%; }

.tile-rotulo {
  display: flex; align-items: center; gap: 6px;
  font-size: 11px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
  /* O rótulo cede contraste para o número: os dois em branco cheio
     disputariam a mesma leitura, e quem manda aqui é o valor. */
  opacity: .88;
}
.tile-valor {
  font-size: 30px; font-weight: 700; line-height: 1;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.02em;
}
/* A unidade senta na linha de base do número, e não flutua no meio dele. */
.tile-valor small { font-size: 14px; font-weight: 600; margin-left: 3px; opacity: .9; letter-spacing: 0; }

/* A MEDIDA: centrada nos dois eixos, ícone em disco do tamanho do texto. */
.tile.medida {
  align-items: center; justify-content: center; text-align: center;
  gap: 8px;
  min-height: 104px;
  padding: 14px 12px;
  box-shadow: var(--elev-1), inset 0 0 0 1px color-mix(in oklab, var(--sobre-cheio) 14%, transparent);
}
.tile.medida .tile-rotulo { justify-content: center; gap: 8px; line-height: 1.3; }
.tile.medida .tile-rotulo .icone {
  box-sizing: content-box;
  width: 14px; height: 14px; padding: 5px;
  border-radius: var(--forma-cheia);
  background: color-mix(in oklab, var(--sobre-cheio) 20%, transparent);
}
.tile.medida .tile-valor { display: flex; align-items: baseline; justify-content: center; }
.tile.largo { min-height: 104px; }
.tile.largo .tile-valor { font-size: 34px; }

/* DENTRO DE CARTÃO, O BLOCO ENCOLHE. A grade de 9,5rem é a da seção de
   sensores, que ocupa a largura da página; a mesma medida dentro de um
   cartão de 16rem cabe uma coluna só, e dois mostradores que deviam estar
   lado a lado viram uma pilha. */
.mt-cartao .mostradores,
.equip-link .mostradores { grid-template-columns: repeat(auto-fit, minmax(6.5rem, 1fr)); }
.mt-cartao .tile, .equip-link .tile { min-height: 72px; padding: 11px 10px; }
.mt-cartao .tile-valor, .equip-link .tile-valor { font-size: 24px; }

/* UMA COR POR PAPEL, e o papel é o que a coisa É — não o que ela parece.
   `inativo` é cinza da própria família: "sem leitura" não pode ser
   confundido com "fora da faixa", que é o vermelho. */
.tile.acento     { --fundo: var(--acento-cheio); }
.tile.frio       { --fundo: var(--frio-cheio); }
.tile.umidade    { --fundo: var(--umidade-cheio); }
.tile.energia    { --fundo: var(--energia-cheio); }
.tile.compressor { --fundo: var(--compressor-cheio); }
.tile.ok         { --fundo: var(--ok-cheio); }
.tile.alerta     { --fundo: var(--alerta-cheio); }
.tile.grave      { --fundo: var(--grave-cheio); }
.tile.inativo    { --fundo: var(--inativo-cheio); }
.tile.inativo .tile-valor { opacity: .75; }

/* O TOTAL QUE EMOLDURA AS PARTES não é uma delas, e não pode ter a cor de
   uma delas. Ardósia é a mesma que veste o diagnóstico: "isto é contexto,
   não é medida". Sem ela, o total e uma disposição qualquer saíam no mesmo
   teal, um ao lado do outro — e um é a soma do outro. */
.tile.neutro     { --fundo: var(--secundaria-cheia); }

/* O bloco que leva a algum lugar se comporta como controle: só ele muda
   ao passar o mouse. Camada de estado, e não uma segunda cor. */
.tile.clicavel { text-decoration: none; cursor: pointer; }
.tile.clicavel:hover { box-shadow: var(--elev-2); filter: brightness(1.08); }

/* A FAIXA DE RESUMO abre a tela; o detalhe vem quieto embaixo. Os blocos
   aqui são poucos e largos — três ou quatro —, ao contrário da grade de
   sensores, que é uma fileira de oito. */
.faixa-resumo {
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  margin-bottom: 18px;
}

.icone { width: 15px; height: 15px; flex: none; }

/* ---- cabeçalho e abas do equipamento ---- */

.tel-cabeca {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: 12px;
  margin-bottom: 14px;
}
.tel-identidade { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.tel-identidade h1 { margin: 0; }

.tel-firmware {
  display: flex; flex-direction: column; align-items: center;
  padding: 4px 14px;
  border-radius: var(--forma-sm);
  background: var(--superficie2);
  border: 1px solid var(--borda);
  font-size: 10px; font-weight: 700; letter-spacing: .08em;
  color: var(--texto3);
}
.tel-firmware b { font-size: 13px; color: var(--texto); letter-spacing: 0; }

/* As guias da telemetria (tempo real e um gráfico por porta) têm a forma do
   controle segmentado, a mesma da faixa de contexto e das abas das telas. */
.tel-abas {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: 10px;
  margin-bottom: 18px;
}
.tel-abas nav {
  display: inline-flex; gap: 2px; flex-wrap: wrap;
  padding: 3px; max-width: 100%;
  background: var(--superficie3);
  border-radius: 18px;
}
.tel-abas .aba {
  padding: 5px 14px;
  border: 0; border-radius: var(--forma-cheia);
  background: none; cursor: pointer;
  font: inherit; font-size: 13px; font-weight: 500;
  color: var(--texto2);
  transition: background var(--rapido) var(--curva), color var(--rapido) var(--curva);
}
.tel-abas .aba:hover { color: var(--texto); }
.tel-abas .aba.ativa { background: var(--superficie); color: var(--texto); font-weight: 600; box-shadow: var(--elev-1); }
.tel-abas .aba:focus-visible { outline: 2px solid var(--acento); outline-offset: 2px; }
.tel-acoes { display: flex; align-items: center; gap: 12px; padding-bottom: 6px; }

/* ---- títulos de seção ---- */

.secao-titulo {
  display: flex; align-items: center; gap: 8px;
  margin: 26px 0 12px;
  font-size: 11px; font-weight: 800; letter-spacing: .09em;
  color: var(--texto2);
}
.secao-barra {
  width: 4px; height: 15px; border-radius: 2px;
  background: var(--acento);
}

/* ---- bateria e controladores ---- */

.tel-inferior {
  display: grid;
  grid-template-columns: minmax(13rem, 15rem) 1fr;
  gap: 20px;
  align-items: start;
}
@media (max-width: 900px) { .tel-inferior { grid-template-columns: 1fr; } }

.bateria-cartao { padding: 14px; display: grid; gap: 10px; }
.bateria-alarmes { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; }

.mt-grade { display: grid; grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr)); gap: 16px; }
.mt-cartao { padding: 16px; display: grid; gap: 14px; }
.mt-cartao > header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 0; border: 0; background: none;
}
.mt-cartao h3 { margin: 0; font-size: 16px; }

/* A faixa de refrigeração é fato mecânico, não severidade: ela diz se o
   compressor está puxando, o que explica uma temperatura ainda caindo. */
.mt-refrigeracao {
  padding: 9px; border-radius: var(--forma-sm); text-align: center;
  font-size: 12px; font-weight: 700; letter-spacing: .06em;
  color: var(--sobre-cheio);
}
.mt-refrigeracao.ligada { background: var(--compressor-cheio); }
.mt-refrigeracao.parada { background: var(--superficie4); color: var(--texto2); }
.mt-refrigeracao.muda   { background: var(--inativo-cheio); }

/* ---- diagnóstico ---- */

/* Cartões IGUAIS entre si e numa cor só: o diagnóstico responde "esta
   placa está saudável?", e nenhum contador dele é mais importante que
   outro. Dar cor própria a cada um competiria com as medições. */
.diag-grade {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
  gap: 12px;
}
.diag-cartao {
  display: flex; flex-direction: column; gap: 6px;
  padding: 13px 15px;
  border-radius: var(--forma-md);
  background: var(--secundaria-cheia);
  color: var(--sobre-cheio);
}
.diag-cartao .rotulo {
  font-size: 10px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  opacity: .85;
}
.diag-cartao strong { font-size: 20px; font-weight: 700; font-variant-numeric: tabular-nums; }
.diag-cartao.lista strong { font-size: 14px; font-weight: 600; line-height: 1.4; }

/* ---- lista de equipamentos ---- */

.equip-link { text-decoration: none; color: inherit; display: block; }
.equip-link:hover { border-color: var(--acento); }
.equip-link > header { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }

/* ---- o gráfico ---- */

.caixa-grafico { position: relative; }
.serie { width: 100%; height: auto; display: block; }
.grade-graf  { stroke: var(--borda); stroke-width: 1; }
.rotulo-graf { fill: var(--texto3); font-size: 13px; font-family: var(--fonte); }

/* A marca do tempo é mais fraca que a grade de valor: ela orienta, mas
   não é o que se lê. Tracejada para não competir com as séries. */
.tique-graf { stroke: var(--borda); stroke-width: 1; stroke-dasharray: 3 5; opacity: .7; }

/* A FAIXA-ALVO É O QUE DÁ SENTIDO AO NÚMERO. Sem ela, 4 °C e 25 °C são
   igualmente "um número" para quem não sabe que a câmara é de vacina —
   com ela, sair da faixa é coisa que se vê. Verde de `ok`, bem lavado:
   ela é o fundo contra o qual a curva se julga, e não um traço a mais. */
.faixa-alvo  { fill: var(--ok); opacity: .10; }
.rotulo-faixa { fill: var(--ok); font-size: 12px; font-weight: 600; font-family: var(--fonte); }

/* Percorrer com o ponteiro: guia vertical e o balão com os valores
   daquele instante. O equivalente ao arrastar o dedo no painel. */
.guia-graf { stroke: var(--texto3); stroke-width: 1.5; pointer-events: none; }
.balao-graf {
  position: absolute; top: 8px; transform: translateX(-50%);
  display: flex; flex-direction: column; gap: 3px;
  padding: 8px 11px;
  border-radius: var(--forma-sm);
  background: var(--secundaria-cheia);
  color: var(--sobre-cheio);
  font-size: 12px;
  box-shadow: var(--elev-2);
  pointer-events: none;
  white-space: nowrap;
}
.balao-graf .quando { font-weight: 700; letter-spacing: .03em; opacity: .9; }
.balao-graf span { display: flex; align-items: center; gap: 6px; }
.balao-graf strong { margin-left: auto; font-variant-numeric: tabular-nums; }
.balao-graf i { width: 9px; height: 9px; border-radius: 50%; flex: none; }
.balao-graf .sem { opacity: .8; font-style: italic; }

.legenda { display: flex; flex-wrap: wrap; gap: 8px 16px; margin-top: 10px; }
.legenda-item { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--texto2); }
.legenda-item i { width: 10px; height: 10px; border-radius: 50%; display: inline-block; }

/* ---------------- editor de modelo de etiqueta ---------------- */

/* Três painéis: o ZPL, a prévia e o dicionário.
 *
 * O EDITOR PRECISA SER O MAIOR. Ele é onde se trabalha; a prévia se olha de
 * relance e o dicionário se consulta. Em tela estreita os três empilham, e a
 * ordem do HTML já é a ordem útil. */
.editor-etiqueta {
  display: grid;
  gap: 16px;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1.4fr);
  align-items: start;
}
.editor-etiqueta > :first-child { grid-row: span 2; }

@media (max-width: 900px) {
  .editor-etiqueta { grid-template-columns: 1fr; }
  .editor-etiqueta > :first-child { grid-row: auto; }
}

/* O ZPL é código: monoespaçada, e sem correção automática do navegador —
 * `^FO20,20` virando `^Fo20,20` no celular seria um comando que não existe. */
textarea.codigo {
  width: 100%;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 13px;
  line-height: 1.5;
  tab-size: 2;
  white-space: pre;
  overflow-wrap: normal;
  overflow-x: auto;
}

/* A FOLHA BRANCA ATRÁS DA ETIQUETA. Sem ela o desenho flutua no fundo do
 * painel e não se lê como papel — e o que se quer enxergar é justamente a
 * margem: o que está perto demais da borda. */
.folha-etiqueta {
  background: var(--superficie);
  border: 1px solid var(--borda);
  border-radius: var(--forma-md, 8px);
  padding: 10px;
  color: var(--texto);
  overflow-x: auto;
}

.dicionario { display: grid; gap: 14px; }
.grupo-variaveis > h3 {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--texto2);
  margin: 0 0 6px;
}

/* Cada variável é um BOTÃO, e não texto para copiar à mão: copiar
 * `{{produto.referencia}}` na unha é onde nasce o erro de digitação que o
 * servidor recusa depois. */
.variavel {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 10px;
  width: 100%;
  text-align: left;
  padding: 6px 8px;
  margin-bottom: 4px;
  background: var(--superficie2);
  border: 1px solid var(--borda);
  border-radius: var(--forma-sm, 6px);
  cursor: pointer;
  color: var(--texto);
}
.variavel:hover { border-color: var(--acento); }
.variavel code { font-size: 12px; }

/* O corpo do painel do editor tem o recuo dos campos (16px), e o que ja trazia recuo proprio
 * (a grade de campos) o perde aqui: dois recuos somados empurravam os campos para dentro e deixavam
 * o textarea, as notas e a barra de botoes colados na borda do cartao. */
.editor-etiqueta .corpo > .campos { padding: 0; margin-top: 14px; overflow: visible; }
.editor-etiqueta .corpo > p.sub { margin: 10px 0 0; }
.editor-etiqueta .folha-etiqueta { margin-bottom: 4px; }

/* SALVAR E EXCLUIR NAS PONTAS: o destrutivo longe do principal, para nao se clicar um no lugar do
 * outro. */
.barra-acao-editor {
  display: flex; gap: 10px; justify-content: space-between; align-items: center;
  margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--borda);
}

/* Titulo da tela com a acao na ponta, e nao colada ao lado do titulo. */
.cabeca-secao.espalhada { justify-content: space-between; align-items: center; }
.acoes-cabeca { display: flex; gap: 8px; flex-wrap: wrap; }

/* A VARIAVEL EM DUAS LINHAS: o nome tecnico em cima, o rotulo embaixo. Lado a lado, o rotulo
 * ("Numero de controle", "Tipo em destaque") quebrava em duas linhas dentro de uma coluna estreita
 * e os botoes ficavam de alturas diferentes. */
.editor-etiqueta .variavel { flex-direction: column; align-items: flex-start; gap: 1px; padding: 6px 10px; }
.editor-etiqueta .variavel .sub { font-size: 11px; }
.editor-etiqueta .dicionario { grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); align-items: start; }
.editor-etiqueta .dicionario .grupo-variaveis { min-width: 0; }

/* ---------------- barra da impressora ---------------- */

/* A IMPRESSORA E O ESTADO DELA, lado a lado e antes de tudo.
 *
 * Ela decide o resto da tela — qual modelo, qual resolução, se há porta para
 * conectar — então vem primeiro e sozinha. O resto só aparece depois. */
.barra-impressora {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}
.barra-impressora > .campo { flex: 1 1 260px; }

.barra-impressora .conexao { display: flex; gap: 8px; }

/* O BOTÃO DE CONEXÃO É O ÚNICO QUE MUDA SOZINHO nesta tela, e quem está na
 * frente da impressora olha de longe: ele é maior que os outros.
 *
 * Verde só com a palavra junto ("● Conectada"). Cor sozinha não serve a quem
 * não a distingue, e é a mesma razão pela qual os alertas do armário têm ícone
 * e texto. */
.botao.conectar {
  min-width: 150px;
  min-height: 44px;
  font-weight: 600;
}
.botao.conectar.conectado {
  background: var(--ok-cheio);
  border-color: var(--ok-cheio);
  color: #fff;
}

/* ---------------- tela de impressão ---------------- */

/* A barra da impressora é um painel, e painel não tem recuo próprio — sem
 * isto o rótulo "Impressora" encostava na borda. */
.barra-impressora { padding: 14px 16px; align-items: center; }
.barra-impressora > .campo { flex: 1 1 260px; max-width: 420px; }
.estado-impressora { display: flex; gap: 6px; align-items: center; flex: 1 1 auto; flex-wrap: wrap; }
.barra-impressora .conexao { margin-left: auto; }
.botao.conectar:not(.conectado):not([disabled]) {
  background: var(--acento); border-color: var(--acento); color: var(--sobre-acento);
}

/* DE ONDE VEM À ESQUERDA, O QUE SE DIGITA E A AÇÃO À DIREITA. As duas cabem
 * sem rolar num monitor de corredor, e o botão fica ao lado dos campos. */
.mesa-impressao {
  display: grid;
  gap: 16px;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.3fr);
  align-items: start;
}
.coluna-origem { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
@media (max-width: 900px) {
  .mesa-impressao { grid-template-columns: 1fr; }
}

.pilha { display: flex; flex-direction: column; gap: 14px; }
.campo > span { font-size: 12px; color: var(--texto2); display: flex; gap: 6px; align-items: baseline; }

/* O CAMPO DO LEITOR É O MAIOR DA TELA: é onde o cursor mora, e quem aponta
 * o leitor precisa ver de longe que ele está pronto para receber. */
.painel.leitura { padding: 14px 16px; display: flex; flex-direction: column; gap: 8px; border-color: var(--acento-fraco); }
.painel.leitura input {
  font-size: 17px; padding: 13px 14px;
  background: var(--superficie);
  border-width: 2px; border-color: var(--acento-fraco);
}
.painel.leitura input:focus { border-color: var(--acento); box-shadow: none; }
#leitura-resumo { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; min-height: 22px; }
.aviso-leitura { color: var(--alerta); font-size: 12px; }

.cartao-produto {
  display: flex; flex-direction: column; gap: 6px;
  padding: 12px 14px;
  border-radius: var(--forma-sm);
  background: var(--superficie2);
  border: 1px solid var(--borda);
}
.cartao-produto strong { font-size: 15px; line-height: 1.35; }

.obrigatorio { color: var(--grave); font-weight: 700; }
.na-etiqueta {
  font-style: normal; font-size: 10px; font-weight: 600; letter-spacing: .03em;
  text-transform: uppercase;
  color: var(--acento-forte); background: var(--acento-fraco);
  padding: 1px 6px; border-radius: var(--forma-xs);
}
.campos-trabalho { grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); }
.campo.falta input { border-color: color-mix(in oklab, var(--grave) 45%, var(--borda-forte)); }
input[readonly] { background: var(--superficie3); color: var(--texto2); }

/* O QUE O LEITOR PREENCHEU ACENDE E APAGA. Um bipe muda quatro campos de uma
 * vez; sem isto, quem olha não sabe o que veio do código. */
@keyframes preenchido {
  from { box-shadow: 0 0 0 3px var(--acento); }
  to   { box-shadow: 0 0 0 3px transparent; }
}
.campo.preenchido input { animation: preenchido 1.4s var(--curva); }
@media (prefers-reduced-motion: reduce) {
  .campo.preenchido input { animation: none; border-color: var(--acento); }
}

.faixa-reimpressao {
  display: flex; gap: 10px; align-items: center; flex-wrap: wrap;
  padding: 10px 16px;
  background: var(--alerta-fundo);
  border-bottom: 1px solid var(--borda);
  font-size: 13px;
}
.faixa-reimpressao .botao { margin-left: auto; }

/* A BARRA DE AÇÃO: quantidade, o que falta, e o botão — nesta ordem de
 * leitura, e o botão sempre no mesmo canto. */
.barra-acao {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  padding: 14px 16px;
  border-top: 1px solid var(--borda);
  background: var(--superficie2);
}
.quantidade { display: flex; flex-direction: column; gap: 4px; }
.quantidade > span { font-size: 12px; color: var(--texto2); }
.passo { display: flex; align-items: center; gap: 4px; }
.passo input { width: 64px; text-align: center; font-variant-numeric: tabular-nums; -moz-appearance: textfield; }
.passo input::-webkit-inner-spin-button { -webkit-appearance: none; }
.passo .botao { min-width: 36px; padding: 6px 0; font-size: 16px; }
.pendencias { flex: 1 1 200px; margin: 0; font-size: 13px; color: var(--texto2); }
.pendencias .pronto { color: var(--ok); font-weight: 600; }
kbd {
  font-family: var(--mono); font-size: 11px;
  padding: 1px 5px; border-radius: var(--forma-xs);
  border: 1px solid var(--borda-forte); background: var(--superficie);
}
.botao.grande { min-height: 48px; min-width: 200px; font-size: 15px; }

/* O RESULTADO */
#saida > header .pilulas { justify-content: flex-end; }
.progresso { height: 4px; background: var(--superficie3); }
.progresso > div { height: 100%; width: 0; background: var(--acento); transition: width .3s var(--curva); }
.nota-saida {
  margin: 12px 16px 0; padding: 10px 14px; border-radius: var(--forma-sm);
  background: var(--alerta-fundo); color: var(--texto); font-size: 13px; line-height: 1.5;
}
.nota-saida.grave { background: var(--grave-cheio); color: var(--sobre-cheio); }
#resumo-saida:not(:empty) { padding-bottom: 12px; }
.tabela-saida td.mono { white-space: nowrap; }
.tabela-saida td.acoes { text-align: right; width: 1%; }

/* A ficha da unidade no diálogo de reimpressão. */
.dialogo .corpo { padding: 16px 18px; display: flex; flex-direction: column; gap: 12px; overflow-y: auto; }
.ficha-unidade {
  display: grid; grid-template-columns: max-content 1fr; gap: 6px 14px;
  margin: 0; font-size: 13px;
}
.ficha-unidade dt { color: var(--texto2); }
.ficha-unidade dd { margin: 0; overflow-wrap: anywhere; }

/* O BOTÃO DE IMPRIMIR NÃO SAI DA TELA. Com o formulário inteiro ele ficava
 * abaixo da dobra num monitor de 760px — preencher e depois rolar para achar
 * a ação é o caminho mais longo da tela. `clip` e não `hidden` no painel:
 * `hidden` faz do painel o contêiner de rolagem, e o `sticky` passaria a
 * grudar nele, não na janela. */
.painel.painel-trabalho { overflow: clip; }
.painel-trabalho .barra-acao {
  position: sticky; bottom: 0; z-index: 5;
  box-shadow: 0 -6px 16px -8px rgba(16, 32, 48, .18);
}

/* Instruções numeradas dentro de um diálogo — a ordem é a informação. */
.passos { margin: 0; padding-left: 22px; display: grid; gap: 10px; font-size: 13px; line-height: 1.55; }
.passos code { font-family: var(--mono); font-size: 12px;
  background: var(--superficie2); border: 1px solid var(--borda);
  border-radius: var(--forma-xs); padding: 2px 6px; }
.linha-copiar { display: flex; gap: 8px; align-items: center; margin-top: 6px; flex-wrap: wrap; }
.linha-copiar code { flex: 1 1 auto; overflow-wrap: anywhere; }
.dialogo .corpo h3 { font-size: 13px; margin-top: 4px; }
.dialogo .corpo p { margin: 0; font-size: 13px; line-height: 1.55; }

/* ---------------- movimentar ---------------- */

.barra-selecao {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 10px 16px;
  border-bottom: 1px solid var(--borda);
  background: var(--superficie2);
}
.barra-selecao .sub { flex: 1 1 auto; }

/* TETO DE ALTURA NA LISTA: um estoque devolve centenas de linhas, e sem isto
 * o passo 3 — o destino, que é onde se decide — some abaixo da dobra. */
.lista-mov { max-height: min(460px, 52vh); overflow-y: auto; }
.lista-mov table { width: 100%; }
.lista-mov td.mono { white-space: nowrap; }
.lista-mov .sub.mono { display: block; }

.col-marca { width: 1%; padding-right: 0; }
.col-marca input { width: 18px; height: 18px; cursor: pointer; }

/* A LINHA MARCADA MUDA DE FUNDO, e não só a caixinha: numa lista de
 * duzentas linhas, procurar o que está selecionado por um quadrado de 18px é
 * o que faz alguém movimentar o lote errado. */
tr.marcada > td { background: var(--acento-fraco); }

/* O filtro mora na barra de seleção e ocupa o espaço que sobra: ele é o
 * campo mais usado da lista quando ela passa de vinte linhas. */
.filtro-lista { flex: 1 1 220px; min-width: 180px; }
.barra-selecao.sutil { padding-top: 6px; padding-bottom: 6px; background: transparent; }
.barra-selecao.sutil:empty, .barra-selecao.sutil .sub:empty { display: none; }
.lista-mov td.vazio { text-align: center; }

/* ---------------- relatórios ---------------- */

/* A LISTA DE RELATÓRIOS FICA À ESQUERDA E PARADA: escolher outro é o gesto
 * mais repetido desta tela, e um seletor no topo obrigaria a rolar de volta. */
.mesa-relatorio {
  display: grid;
  gap: 16px;
  grid-template-columns: minmax(200px, 250px) minmax(0, 1fr);
  align-items: start;
}
.corpo-relatorio { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
@media (max-width: 860px) {
  .mesa-relatorio { grid-template-columns: 1fr; }
}

.lista-relatorios nav { display: flex; flex-direction: column; }
.item-relatorio {
  display: flex; flex-direction: column; gap: 2px;
  padding: 11px 16px;
  text-align: left;
  background: transparent;
  border: none;
  border-left: 3px solid transparent;
  border-bottom: 1px solid var(--borda);
  color: var(--texto);
  cursor: pointer;
  font: inherit;
}
.item-relatorio:last-child { border-bottom: none; }
.item-relatorio:hover { background: var(--superficie2); }
.item-relatorio.ativo {
  background: var(--acento-fraco);
  border-left-color: var(--acento);
}
.item-relatorio.ativo strong { color: var(--acento-forte); }
.item-relatorio .sub { font-size: 11px; line-height: 1.35; }

.filtros-relatorio { padding-bottom: 0; }
.tabela-relatorio { max-height: min(560px, 60vh); overflow: auto; }
/* O CABEÇALHO FICA, porque numa tabela de duzentas linhas rolar até perder o
 * nome da coluna é perder o significado do número. */
.tabela-relatorio thead th {
  position: sticky; top: 0; z-index: 1;
  background: var(--superficie2);
}
.tabela-relatorio th.num, .tabela-relatorio td.num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* O gráfico: três séries numa escala só, e a forma distingue cada uma —
 * quem não separa cores ainda lê o tracejado da máxima. */
.grafico-temp svg { display: block; width: 100%; }
.legenda-grafico {
  display: flex; gap: 16px; flex-wrap: wrap;
  margin-top: 8px; font-size: 12px; color: var(--texto2);
}
.legenda-grafico span { display: flex; align-items: center; gap: 6px; }
.legenda-grafico .traco { width: 20px; height: 0; border-top-width: 2px; display: inline-block; }
.legenda-grafico .cheio      { border-top: 2px solid var(--acento-forte); }
.legenda-grafico .tracejado  { border-top: 2px dashed var(--alerta); }
.legenda-grafico .pontilhado { border-top: 2px dotted var(--acento); }

/* A LINHA QUE ABRE DETALHE PRECISA PARECER CLICÁVEL. Sem isto, o recurso
 * existe e ninguém descobre — é o pior desfecho de uma funcionalidade. */
table.com-detalhe tbody tr { cursor: pointer; }
table.com-detalhe tbody tr:hover > td { background: var(--acento-fraco); }

/* ---------------- faixa de contexto ---------------- */

/* CABEÇALHO EM DUAS FAIXAS, E SÓ A DE CIMA É NAVEGAÇÃO ENTRE ÁREAS.
 *
 * Eram três níveis empilhados (guia, subguia, aba da página) com três formas
 * diferentes de dizer "selecionado". Agora:
 *   1. a barra do topo escolhe a ÁREA (pílula);
 *   2. a faixa de contexto diz ONDE A PESSOA ESTÁ (migalhas) e deixa trocar de
 *      tela dentro da área (controle segmentado, à direita);
 *   3. as abas de dentro da página (Nova caixa / Consultar…) usam o mesmo
 *      controle segmentado, só que menor, ao lado do título — são modos de
 *      ver a mesma tela, e não outra tela.
 *
 * O invólucro é que fica grudado no topo: as duas faixas rolam juntas. */
.cabecalho { position: sticky; top: 0; z-index: 10; }
.cabecalho .topo { position: static; }
/* Com quatro linhas o cabeçalho passa de 180 px; grudado, comia um quarto de uma tela de tablet. */
@media (max-width: 1120px) { .cabecalho { position: static; } }

.faixa-contexto {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px 16px; flex-wrap: wrap;
  padding: 8px 20px;
  background: var(--superficie2);
  border-bottom: 1px solid var(--borda);
}
.migalhas { display: flex; align-items: center; gap: 8px; min-width: 0; font-size: 13px; color: var(--texto2); }
.migalhas a { color: var(--texto2); text-decoration: none; }
.migalhas a:hover { color: var(--texto); text-decoration: underline; }
.migalhas .sep { color: var(--texto3); }
.migalhas [aria-current="page"] { color: var(--texto); font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* A SUBGUIA NO MEIO DA TELA. Com `space-between` ela ficava na ponta direita, longe do ponteiro e
 * de onde se olha. Em tela larga a faixa vira tres colunas - migalhas a esquerda, subguia centrada,
 * uma coluna vazia a direita que a equilibra -, e a subguia fica no centro de verdade, mesmo
 * quando as migalhas sao compridas. So vale quando as tres colunas cabem: a subguia de Configuracoes
 * tem oito opcoes (~830 px) e cada coluna lateral precisa das migalhas inteiras (~210 px); abaixo
 * disso as migalhas ficavam espremidas e cortadas. Em tela menor volta ao fluxo normal, com a
 * subguia centrada na linha em que cair. */
@media (min-width: 1360px) {
  .faixa-contexto { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); }
  .faixa-contexto .migalhas { grid-column: 1; }
  .faixa-contexto .submenu { grid-column: 2; justify-self: center; }
}
@media (max-width: 1359px) {
  .faixa-contexto .submenu { margin-inline: auto; }
}

/* CONTROLE SEGMENTADO: trilho um tom abaixo, opção escolhida como plano
 * levantado. Serve à faixa de contexto e às abas de dentro das páginas. */
.submenu, .abas {
  display: inline-flex; gap: 2px; flex-wrap: wrap;
  padding: 3px;
  background: var(--superficie3);
  border-radius: 18px; max-width: 100%;
}
.submenu a, .abas .aba {
  padding: 5px 14px;
  border: 0;
  border-radius: var(--forma-cheia);
  background: none;
  font: inherit; font-size: 13px; font-weight: 500; letter-spacing: 0; text-transform: none;
  color: var(--texto2);
  text-decoration: none;
  cursor: pointer;
  transition: background var(--rapido) var(--curva), color var(--rapido) var(--curva);
}
.submenu a:hover, .abas .aba:hover { color: var(--texto); }
.submenu a.ativo, .abas .aba.ativa {
  background: var(--superficie);
  color: var(--texto);
  font-weight: 600;
  box-shadow: var(--elev-1);
}
.submenu a:focus-visible, .menu a:focus-visible, .abas .aba:focus-visible {
  outline: 2px solid var(--acento); outline-offset: 2px;
}
.submenu[hidden] { display: none; }

/* ---------------- aplicativos ---------------- */
.grade-apps {
  display: grid; gap: 16px;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  align-items: start;
}
.cartao-app .corpo { display: flex; flex-direction: column; gap: 12px; }
.cartao-app .hash { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.notas-app { margin: 0; font-size: 13px; line-height: 1.55; }
.codigo-linha {
  margin: 0; padding: 8px 10px; overflow-x: auto;
  font-family: var(--mono); font-size: 12px;
  background: var(--superficie2); border: 1px solid var(--borda); border-radius: var(--forma-xs);
}

/* ---------------- análise da unidade ---------------- */
.analise-duas { display: grid; gap: 20px; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.analise-duas h3, #analise-item h3 { font-size: 13px; margin: 0 0 8px; color: var(--texto2); }
.barra-tempo { margin-bottom: 10px; }
.barra-tempo-rotulo { display: flex; justify-content: space-between; gap: 8px; align-items: baseline; font-size: 13px; margin-bottom: 4px; }
/* UMA COR SÓ nas barras: o comprimento é a informação, e o rótulo diz de
 * quem é. Colorir por local faria a cor parecer significar alguma coisa. */
.barra-tempo-trilho { height: 8px; background: var(--superficie3); border-radius: var(--forma-cheia); overflow: hidden; }
.barra-tempo-trilho > div { height: 100%; background: var(--acento); border-radius: var(--forma-cheia); }
.epc-duplo .epc-hex { display: block; font-size: 13px; }
.epc-duplo .sub { display: block; font-size: 11px; }

/* ---------------- fluxos permitidos (pontos de controle) ---------------- */
.fluxo-resumo { font-size: 13px; line-height: 1.45; white-space: nowrap; }
.fluxo-resumo + .fluxo-resumo { margin-top: 2px; }
#fluxo-lista { display: flex; flex-direction: column; gap: 10px; }
.fluxo-linha {
  display: grid; gap: 12px 16px; align-items: start;
  grid-template-columns: minmax(0, 2fr) minmax(0, 3fr) auto;
  padding: 12px; border: 1px solid var(--borda); border-radius: 12px;
  background: var(--superficie2);
}
.fluxo-origem, .fluxo-estados { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.fluxo-origem select { width: 100%; }
.fluxo-origem .caixa { display: flex; align-items: center; gap: 6px; font-size: 13px; }
.fluxo-origem .caixa input { width: auto; margin: 0; }
.marcadores { display: flex; flex-wrap: wrap; gap: 6px; }
.marcador { display: inline-flex; cursor: pointer; position: relative; }
.marcador input { position: absolute; opacity: 0; pointer-events: none; }
.marcador span {
  padding: 4px 10px; border-radius: 999px; font-size: 12.5px;
  border: 1px solid var(--borda); background: var(--superficie); color: var(--texto2);
}
.marcador input:checked + span { background: var(--acento); border-color: var(--acento); color: var(--sobre-cheio); }
.marcador input:focus-visible + span { outline: 2px solid var(--acento); outline-offset: 2px; }
@media (max-width: 720px) {
  .fluxo-linha { grid-template-columns: 1fr; }
}
.modo-fluxo { display: flex; flex-wrap: wrap; gap: 8px; }
.modo-fluxo .marcador span { padding: 6px 14px; font-size: 13px; }

/* Linha do tempo: o que passou fora do fluxo. A faixa à esquerda é o sinal que
 * se vê rolando a tabela; o selo diz o quê. */
tr.fora-do-fluxo > td:first-child { box-shadow: inset 3px 0 0 var(--grave); }

/* ---------------- vocabulário ---------------- */
.vocab-nome { width: 100%; min-width: 180px; font-weight: 600; }
.vocab-trava { margin-top: 4px; color: var(--texto3); font-size: 12px; line-height: 1.4; }
.interruptor { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; font-size: 13px; white-space: nowrap; }
.interruptor input { width: auto; margin: 0; accent-color: var(--acento); }
.interruptor input:disabled + span { color: var(--texto3); }

/* Ambiente de QA: impossível de não ver, e fora do fluxo do resto da página. */
.faixa-qa {
  position: sticky; top: 0; z-index: 60;
  padding: 6px 16px; text-align: center;
  background: repeating-linear-gradient(-45deg, #8a4b00, #8a4b00 12px, #6f3c00 12px, #6f3c00 24px);
  color: #fff; font-size: 12px; font-weight: 700; letter-spacing: .08em;
}

/* Comissionar: o estado do leitor no lugar do seletor de impressora. */
.estado-leitor { display: flex; align-items: center; min-height: var(--alt-controle, 38px); }
.comis-pendente { padding: 0 16px; }
.comis-pendente .nota-atencao { margin: 0 0 12px; }

/* Pontos de controle do armário: o que vale em linhas fixas, o resto recolhido. */
tr.linha-fixa td { background: var(--superficie2); }
tr.grupo-recolhido > td { padding: 8px 12px; }
tr.grupo-recolhido summary { cursor: pointer; color: var(--texto2); font-size: 13px; display: flex; align-items: center; gap: 12px; }
.subtabela { width: 100%; margin-top: 8px; }

/* Painel: portais, leitores, coletores e impressoras numa faixa discreta. */
.faixa-apoio { margin-top: 18px; }
.faixa-apoio h3 { font-size: 13px; color: var(--texto2); margin: 0 0 8px; font-weight: 600; }
.chips-apoio { display: flex; flex-wrap: wrap; gap: 8px; }
.chip-apoio {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 6px 12px; border: 1px solid var(--borda); border-radius: 999px;
  background: var(--superficie); color: var(--texto); text-decoration: none; font-size: 13px;
}
.chip-apoio:hover { border-color: var(--borda-forte); }
.chip-apoio .nome { font-weight: 600; }
.estado-apoio { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; font-weight: 600; }
.estado-apoio .ponto { width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.estado-apoio.ok { color: var(--ok); }
.estado-apoio.grave { color: var(--grave); }

/* ---------------- painel: cartão de monitoramento ----------------
 * A faixa de cima diz o estado antes de qualquer leitura: verde online,
 * vermelha offline. A temperatura é o mostrador grande; o resto é menor. */
.monitor-card {
  display: flex; flex-direction: column; gap: 12px;
  padding: 14px 16px 12px;
  border-radius: var(--forma-md);
  background: var(--superficie);
  border: 1px solid var(--borda);
  border-top: 5px solid var(--ok);
  box-shadow: var(--elev-1);
}
.monitor-card.offline { border-top-color: var(--grave); }
.monitor-card > header { display: flex; align-items: center; gap: 8px; }
.monitor-card .nome { flex: 1; font-weight: 700; font-size: 16px; min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.monitor-total { display: flex; align-items: baseline; gap: 8px; color: var(--texto2); text-decoration: none; }
.monitor-total strong { font-size: 22px; font-weight: 800; color: var(--texto); }
.monitor-total:hover strong { color: var(--acento); }
.monitor-portas { display: grid; grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr)); gap: 10px; }
.monitor-porta { display: flex; flex-direction: column; gap: 6px; }
.monitor-card .tile { min-height: 104px; }
.monitor-card .tile-valor { font-size: 38px; }
.monitor-card .tile-valor small { font-size: 16px; }
.monitor-itens { font-size: 12px; color: var(--texto2); font-variant-numeric: tabular-nums; text-align: center; }
.monitor-itens .fora { color: var(--grave); font-weight: 650; }
/* Os cartões dividem a linha inteira: `--n` (1 a 3) vem do número de cartões, e
 * dois cartões ocupam a largura toda em vez de deixar um terceiro trilho vazio. */
.grade-monitor { grid-template-columns: repeat(var(--n, 3), minmax(0, 1fr)); }
@media (max-width: 900px) { .grade-monitor { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); } }
.monitor-card > footer { font-size: 12px; }

/* Nota informativa, irmã da `.nota-atencao` — mesma forma, tom neutro.
 *
 * A DISTINÇÃO É DE NATUREZA, e não de estilo: `.nota-atencao` avisa que algo
 * NÃO faz o que se esperaria ("este item não se move sozinho"); esta aqui só
 * conta um fato útil ("esta caixa tem 3 de 5 dentro"). Pintar as duas de
 * âmbar ensinaria a ignorar o âmbar. */
.nota {
  margin: 0 16px 12px; padding: 12px 14px; border-radius: 10px;
  background: var(--superficie2); color: var(--texto2);
  font-size: 13px; line-height: 1.5;
}

/* As abas de dentro de uma tela (Nova caixa / Consultar…) têm a forma do controle
 * segmentado, definido junto da faixa de contexto. Aqui só o respiro. */
.abas { margin-bottom: 18px; align-self: flex-start; }

/* Diálogo largo: o de receita mostra uma tabela de itens, e 560px a espreme
 * a ponto de a quantidade cair embaixo do nome. */
.dialogo.largo { width: min(760px, 100%); }

/* A tabela de montagem do kit: um campo por célula, e a linha que falta
 * marcada na própria célula — numa lista de vinte, "lote em 3 linhas" sem
 * dizer quais manda a pessoa caçar. */
.tabela-kit input { width: 100%; min-width: 8rem; }
.tabela-kit td.falta input {
  border-color: color-mix(in oklab, var(--grave) 45%, var(--borda-forte));
}
.painel-trabalho fieldset.campo { border: 0; padding: 0; margin: 0; gap: 6px; }
.painel-trabalho fieldset.campo label { display: flex; align-items: center; gap: 8px; }

/* O filtro inicial da Gestão de Caixas: duas opções lado a lado, porque é
 * uma escolha entre dois caminhos, e não uma lista. */
.filtro-busca { border: 0; padding: 0; margin: 0; flex-direction: row; gap: 18px; }
.filtro-busca legend { font-size: 12px; color: var(--texto2); margin-bottom: 6px; }
.filtro-busca label { display: flex; align-items: center; gap: 6px; }
.filtro-busca input { width: auto; }

/* Título dentro do corpo de um painel — abaixo do cabeçalho, acima de uma
 * tabela que pertence ao mesmo assunto. */
.subtitulo {
  margin: 8px 0 4px; font-size: 12px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--texto2);
}

/* Uma opção de marcar com o "i" ao lado: os dois na mesma linha, alinhados
 * pelo centro. `.recuo` é a pergunta que depende da de cima — o recuo diz, sem
 * texto, que ela só vale depois do sim da primeira. */
.bloco-caixa { display: flex; flex-direction: column; gap: 6px; }
.linha-opcao { display: flex; align-items: center; gap: 8px; }
.linha-opcao.recuo { padding-left: 26px; }

/* ---------------- ícone do alerta ---------------- */
/* Disco cheio com o glifo do tipo dentro; a cor é a gravidade. Aviso (1, `.leve`) usa o
 * azul da marca, e não uma cor de família: nenhuma medida é a origem dele. */
.alerta-icone {
  display: grid; place-items: center;
  width: 40px; height: 40px;
  border-radius: var(--forma-cheia);
  color: var(--sobre-cheio);
  background: var(--acento-cheio);
}
.alerta-icone.grave  { background: var(--grave-cheio); }
.alerta-icone.alerta { background: var(--alerta-cheio); }
.alerta-icone .icone { width: 22px; height: 22px; }
.linha-alerta strong + .selo { margin-left: 6px; vertical-align: 1px; }

/* ---------------- formulário em grupos ---------------- */
/* O TÍTULO DE GRUPO agrupa campos que a pessoa preenche juntos (produto, conteúdo,
 * rastro, impressão). Não é decoração: sem ele, doze campos numa grade de duas
 * colunas liam-se como uma lista só, e o opcional se misturava ao obrigatório. */
.grupo-campos {
  grid-column: 1 / -1;
  display: flex; align-items: baseline; gap: 8px;
  margin: 10px 0 0;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--borda);
  font-size: 11px; font-weight: 650; letter-spacing: .07em; text-transform: uppercase;
  color: var(--texto2);
}
.grupo-campos:first-child { margin-top: 0; }
.grupo-campos .opcional { font-weight: 500; letter-spacing: 0; text-transform: none; color: var(--texto3); }

/* AS OPÇÕES DE IMPRESSÃO lado a lado, como escolha única visível de uma vez. */
.painel-trabalho fieldset.campo { flex-direction: row; flex-wrap: wrap; gap: 8px; }
.painel-trabalho fieldset.campo > legend { flex-basis: 100%; padding: 0; font-size: 12px; color: var(--texto2); }
.painel-trabalho fieldset.campo > label {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 14px;
  border: 1px solid var(--borda-forte);
  border-radius: var(--forma-cheia);
  font-size: 13px; color: var(--texto);
  cursor: pointer;
}
.painel-trabalho fieldset.campo > label:has(input:checked) {
  background: var(--acento-fraco); border-color: var(--acento); color: var(--acento-forte); font-weight: 600;
}
.painel-trabalho fieldset.campo input { width: auto; }

/* ---------------- telefone ---------------- */
/* No celular o cabeçalho tomava 40% da altura (marca, duas linhas de menu, tema e
 * sair, migalhas, três linhas de subguias) e ficava grudado no topo, deixando
 * pouco espaço para a tela. Agora: marca e ações numa linha, o menu e as subguias
 * cada um numa linha que rola de lado, e nada fica grudado — a pessoa que
 * precisa do menu sobe a tela, como em qualquer página. */
@media (max-width: 620px) {
  .cabecalho { position: static; }
  .topo { gap: 6px 10px; padding: 8px 12px; }
  .topo .marca { order: 1; }
  .topo-fim { order: 2; margin-left: auto; gap: 4px; }
  .menu { order: 3; flex: 1 0 100%; flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
  .menu::-webkit-scrollbar, .submenu::-webkit-scrollbar { display: none; }
  .menu a { white-space: nowrap; padding: 6px 12px; }

  .faixa-contexto { padding: 8px 12px; gap: 6px; }
  .faixa-contexto .submenu {
    flex: 1 0 100%; flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none;
    border-radius: var(--forma-cheia);
  }
  .submenu a { white-space: nowrap; flex: none; }

  .faixa-resumo { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .faixa-resumo .tile { min-height: 84px; padding: 12px; }
  .tile-valor { font-size: 26px; }

  /* Árvore de locais: nome e ações não cabem numa linha só; o código (URN) desce
   * para a sua e as ações quebram junto. */
  .no { flex-wrap: wrap; padding: 8px 12px; }
  .no .sgln { flex: 1 0 100%; margin-left: 0; word-break: break-all; }
  .no .acoes { display: flex; flex-wrap: wrap; gap: 6px; margin-left: auto; }

  /* Alerta: o ícone e o texto ficam na primeira linha; hora e ação descem. */
  .linha-alerta { grid-template-columns: auto 1fr; gap: 8px 12px; padding: 10px 12px; }
  .linha-alerta > :nth-child(n+3) { grid-column: 2; justify-self: start; }

  /* Cabeçalho de painel com nome, texto de apoio e botões: quebra em vez de vazar. */
  .painel > header { flex-wrap: wrap; }
  .painel > header h2 { flex: 1 1 12rem; min-width: 0; }
}

/* ---------------- "+ dados" (catálogo público) ---------------- */

.dados-pub { display: flex; flex-direction: column; gap: 12px; }
.busca-pub { display: flex; align-items: flex-end; gap: 10px; flex-wrap: wrap; }
.busca-pub .campo { flex: 1 1 14rem; }
.fonte-pub { font-size: 12px; color: var(--texto2); margin: 0; }
#pub-resultado { display: flex; flex-direction: column; gap: 14px; }
#pub-resultado > .botao { align-self: flex-start; }
#pub-resultado > .fonte-pub + .botao { margin-top: -4px; }
.dado-bloco h3 {
  margin: 0 0 6px; padding-bottom: 4px;
  border-bottom: 1px solid var(--borda);
  font-size: 11px; font-weight: 650; letter-spacing: .07em; text-transform: uppercase; color: var(--texto2);
}
.dado-bloco dl { display: grid; grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr)); gap: 6px 16px; margin: 0; }
.dado-bloco dl > div { min-width: 0; }
.dado-bloco dt { font-size: 11px; color: var(--texto3); }
.dado-bloco dd { margin: 0; font-size: 13px; overflow-wrap: anywhere; }

/* ---------------- Base pública ---------------- */
.grupos-bp { display: grid; grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr)); gap: 8px 14px; }
.grupo-bp {
  background: var(--superficie); border-radius: var(--forma-md); box-shadow: var(--elev-1);
  padding: 8px 12px; min-width: 0;
}
.grupo-bp > summary { cursor: pointer; font-weight: 600; font-size: 13px; display: flex; justify-content: space-between; gap: 8px; }
.grupo-bp table { margin-top: 6px; }
.grupo-bp td { padding: 4px 6px; font-size: 12px; }
.grupo-bp td.num { text-align: right; }
.codigo-bp {
  margin: 8px 0; padding: 10px 12px; overflow-x: auto;
  background: var(--superficie3); border-radius: var(--forma-sm);
  font: 12px/1.5 var(--mono); white-space: pre;
}
#bp-mais { margin-top: 12px; }
.titulo-reg-bp { display: flex; align-items: baseline; gap: 10px; margin: 22px 0 4px; font-size: 14px; }

/* A FICHA E A ABA "+ dados" ROLAM DENTRO DO DIÁLOGO. O diálogo tem teto de 90vh e é uma
 * coluna (cabeçalho, corpo, rodapé), mas o corpo dessas duas não tinha `overflow`: os dados
 * passavam do teto e o que sobrava era cortado, sem barra para alcançar. Cabeçalho e rodapé
 * ficam parados; só o corpo rola. */
.dialogo > header, .dialogo > footer, .dialogo > .abas { flex: none; }
.dialogo > .dados-pub, .dialogo > .aba-extra {
  flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 16px 18px;
}
.dialogo > .aba-extra .dados-pub { overflow: visible; }
.dialogo.com-abas > .abas { margin: 12px 18px 0; }
/* A altura não pula ao trocar de aba: a aba "+ dados" vazia encolhia o diálogo para um terço e o
 * recentralizava na tela. */
.dialogo.com-abas { height: min(700px, 90vh); }
