/* LOTUS — COMPONENTES (FRONT-2, 12/09/2026)
 *
 * A PELE de todo componente do sistema mora aqui, e só aqui. Antes do FRONT-2
 * o mesmo papel era redesenhado em cada tela: o botão primário tinha NOVE
 * aparências em 11 arquivos, o badge tinha 4 bases, o card 19 famílias. Quem
 * mexia numa tela não via as outras oito, e o sistema foi ficando com sotaque
 * por página.
 *
 * A divisão de trabalho (contrato do FRONT-0 + FRONT-2):
 *   tema.css          → COR e ESCALA (tokens). Nunca componente.
 *   componentes.css   → a PELE do componente (este arquivo).
 *   shell/tokens.css  → a RÉGUA MÓVEL (alvo de toque, piso de fonte).
 *   style.css / <style> da tela → LAYOUT: onde a peça fica, que largura tem.
 *
 * Ordem de carga em todas as telas: tema → componentes → shell → tela.
 * Uma tela pode posicionar um componente; não pode repintá-lo. Definição de
 * botão/badge/card/campo fora deste arquivo é o que o aceite do FRONT-2 conta,
 * e o número esperado é zero.
 *
 * ZERO hex aqui: cor é sempre token do tema, senão o tema claro quebra.
 *
 * Mapa das decisões: docs/frontend-fase2/mapa-componentes.md (D1…D13).
 */

/* ═══════════════════════════════════════════════════════════════════
   BOTÃO — 4 papéis × 3 tamanhos
   ═══════════════════════════════════════════════════════════════════
   papel:   .btn-primario · .btn-sec · .btn-perigo · .btn-fantasma
   tamanho: .btn-p · .btn (médio, padrão) · .btn-g
   forma:   .btn-bloco (largura cheia) · .btn-pilula
   estado:  .ativo · :disabled

   Sempre DUAS classes: `class="btn btn-primario"`. A `.btn` sozinha é o
   secundário-neutro do painel (o antigo `button` global do style.css).

   A BASE vale por elemento E por classe (`button, .btn`); as VARIANTES, só por
   classe. É a mesma regra que a tabela segue (D10): 70 dos 226 botões do
   sistema não têm classe nenhuma — 42 só no app.js — e exigir classe de todos
   seria 70 edições para chegar exatamente na pele que já têm. Botão novo
   nasce vestido; quem quer papel, pede papel.

   O ◐ do tema e o seletor de visão NÃO são pegos por isto: `[data-lotus-tema]`
   e `[data-lotus-visao]` têm pele própria no tema.css, com peso maior (0-1-0
   contra 0-0-1). Era por causa dessa base global que cada tela precisava
   desfazer a regra antes de aplicar a sua. */

button, .btn {
  /* a base é o antigo `button` global do style.css:202 — painel + borda */
  font-family: inherit;
  /* o TAMANHO é fixado, não herdado: `font: inherit` funcionava no painel
     (o body dele é --fonte-base) e inflava o botão do mapa-cd e do tetris,
     cujo body não declara tamanho e cai nos 16px do navegador — os dois
     fixavam 13px na regra que saiu daqui (visto na regressão de 12/09) */
  font-size: var(--fonte-base);
  color: var(--texto);
  background: var(--painel);
  border: var(--linha);
  border-radius: var(--raio-md);
  padding: 7px 10px;
  cursor: pointer;
  transition: border-color var(--transicao), background var(--transicao), color var(--transicao);
}
/* A base NÃO define `display` nem `white-space` de propósito. O `.v3-shell .btn`
   usava `inline-flex` + `nowrap`, e generalizar isso quebrou os botões-CARTÃO
   do tetris (o nome do veículo e as três linhas de capacidade viraram uma
   linha só, vazando para fora da tela — visto na regressão visual de 12/09).
   Botão com ícone já alinha pelo `.ico` do FRONT-3; quem quiser uma fileira
   pede `.btn-fileira`. */
.btn-fileira { display: inline-flex; align-items: center; justify-content: center; gap: 6px; white-space: nowrap; }
button:hover, .btn:hover { border-color: var(--ciano); color: var(--ciano); }
button:disabled, .btn:disabled, .btn[disabled] { opacity: .45; cursor: not-allowed; }
/* `hidden` tem de continuar escondendo. Qualquer regra de AUTOR que defina
   `display` vence o `[hidden] { display: none }` do navegador — foi assim que
   o "soltar crachá" do coletor e os dois botões de modo do app.js reapareceram
   na regressão visual de 12/09. A base já não define display, mas o
   `.btn-fileira` define: esta linha é o cinto de segurança. */
button[hidden], .btn[hidden] { display: none; }
button:disabled:hover, .btn:disabled:hover, .btn[disabled]:hover { border-color: var(--borda); color: var(--texto); }

/* ── papéis ────────────────────────────────────────────────────────── */

/* PRIMÁRIO — sólido (D1, Moises 12/09/2026).
   Eram duas peles: translúcida no painel (button.primario, 12% de acento) e
   sólida em sete telas (V3, ocorrências, mapa-cd, tetris, conferência,
   motorista). Venceu a sólida — é a maioria e é a que se lê no galpão, onde a
   tela é vista de lado, com sol e com luva.
   A cor sai de uma variável PRÓPRIA para a guarita poder repintar o papel sem
   criar um quinto papel (D2). */
.btn-primario {
  --btn-primario-fundo: var(--acento);
  --btn-primario-tinta: var(--tinta-sobre-acento);
  background: var(--btn-primario-fundo);
  border-color: var(--btn-primario-fundo);
  color: var(--btn-primario-tinta);
  font-weight: var(--peso-semi);
}
.btn-primario:hover { filter: brightness(1.08); color: var(--btn-primario-tinta); border-color: var(--btn-primario-fundo); }

/* SECUNDÁRIO — o cinza de "a outra opção" (era `button.sec` da conferência e
   do motorista, e o `.btn.secundario` que o app pedia sem existir). */
.btn-sec { background: var(--borda); color: var(--texto); border-color: var(--borda); }
.btn-sec:hover { border-color: var(--ciano); color: var(--ciano); }

/* PERIGO — contorno por padrão, sólido quando o toque é irreversível (D6).
   No painel, apagar tem confirmação e mouse; no celular do motorista o dedo
   erra, e o botão que destrói precisa pesar mais que o vizinho. */
.btn-perigo { background: var(--painel); border-color: color-mix(in srgb, var(--critico) 50%, transparent); color: var(--vermelho); }
.btn-perigo:hover { background: color-mix(in srgb, var(--critico) 10%, transparent); border-color: var(--vermelho); color: var(--vermelho); }
.btn-perigo.btn-forte { background: var(--critico); border-color: var(--critico); color: var(--tinta-sobre-status); }
.btn-perigo.btn-forte:hover { filter: brightness(1.08); background: var(--critico); color: var(--tinta-sobre-status); }

/* FANTASMA — sem fundo nem borda: ação de apoio dentro de um painel já denso
   (era `.v3-shell .btn.ghost`). */
.btn-fantasma { background: transparent; border-color: transparent; }
.btn-fantasma:hover { background: var(--veu-1); border-color: transparent; color: var(--ciano); }

/* ATENÇÃO — não é papel novo: é a COR de um estado que o secundário veste
   (D5). ADIADA no motorista, "recalcular" no tetris, `.btn.warn` do V3. */
.btn-atencao { background: color-mix(in srgb, var(--atencao) 12%, transparent); border-color: color-mix(in srgb, var(--atencao) 45%, transparent); color: var(--ambar); }
.btn-atencao:hover { background: color-mix(in srgb, var(--atencao) 22%, transparent); border-color: var(--ambar); color: var(--ambar); }
.btn-atencao.btn-forte { background: var(--atencao); border-color: var(--atencao); color: var(--tinta-sobre-aviso); }
.btn-atencao.btn-forte:hover { filter: brightness(1.08); background: var(--atencao); color: var(--tinta-sobre-aviso); }

/* ── tamanhos ──────────────────────────────────────────────────────── */

/* pequeno: o antigo `button.mini` e os chips de filtro */
.btn-p { padding: 3px 8px; font-size: var(--fonte-sm); border-radius: var(--raio-md); }

/* grande: a medida das telas de campo. O min-height é o alvo de toque do
   shell — dedo com luva, no galpão. */
.btn-g {
  padding: 14px 16px;
  font-size: var(--fonte-lg);
  font-weight: var(--peso-forte);
  border-radius: var(--m-raio, 10px);
  min-height: var(--m-alvo, 48px);
}
/* O tema.css impõe `min-height: 34px` a todo button na visão celular (0-1-2) e
   venceria o `.btn-g` (0-1-0). Mesmo peso aqui, e este arquivo carrega depois
   do tema — é o mesmo desempate que o shell/tokens.css faz para `button`. */
html[data-visao-efetiva="celular"] .btn-g { min-height: var(--m-alvo, 48px); }

/* ── formas ────────────────────────────────────────────────────────── */
.btn-bloco { width: 100%; }
.btn-pilula { border-radius: 999px; }

/* ── estado ativo (filtro/aba selecionada — era `.btn.ativo` do mapa-cd e
      `.chips button.ativo` das ocorrências) ────────────────────────── */
.btn.ativo { outline: 2px solid var(--acento); outline-offset: -2px; background: var(--realce-acento); color: var(--ciano); }
.btn-primario.ativo, .btn-sec.ativo { outline: 2px solid var(--acento); outline-offset: -2px; }

/* ── a guarita e o coletor repintam o PRIMÁRIO (D2) ────────────────────
   Na guarita o botão grande é o "liberar a cancela", e ele é VERDE desde que
   a tela existe — verde é passar, e quem opera não lê o rótulo, reconhece a
   cor a três metros. Isso não cria um quinto papel: é o MESMO papel primário
   com a cor trocada por variável, no escopo das duas telas.
   O gancho é a classe do app no <html> (app-portaria / app-coletor). */
.app-portaria .btn-primario, .app-coletor .btn-primario {
  --btn-primario-fundo: var(--ok);
  --btn-primario-tinta: var(--tinta-sobre-acento);
}
/* a guarita é lida de pé, a metros do monitor, com o caminhão esperando: o
   botão grande dela é maior que o grande das outras telas (mesma exceção que
   o .m-pare faz para a palavra PARE) */
.app-portaria .btn-g { padding: var(--m-esp-6, 24px); font-size: var(--fonte-xl); }

/* ── identidade do LOGIN (D3) ──────────────────────────────────────────
   A tela de entrar não veste o primário do sistema: ela é a única superfície
   clara do produto e o botão é a tinta do texto sobre o painel. Decisão do
   Moises em 12/09 — a identidade fica, mas a definição mora aqui. */
.btn-login { background: var(--texto); color: var(--painel); border-color: transparent; font-weight: var(--peso-forte); }
.btn-login:hover { filter: brightness(1.15); transform: translateY(-1px); box-shadow: var(--sombra-md); color: var(--painel); border-color: transparent; }
.btn-login:active { transform: scale(.97); }

/* ── movimento ─────────────────────────────────────────────────────────
   O "afunda ao tocar" era do motorista e da conferência; vale para todo botão
   grande — é o único retorno que existe quando não há hover (dedo não paira). */
.btn-g:active:not(:disabled) { transform: scale(.96); }
button, .btn { transition: transform .1s, border-color var(--transicao), background var(--transicao), color var(--transicao); }
@media (prefers-reduced-motion: reduce) {
  button, .btn, .btn-g:active, .btn-login:hover, .btn-login:active { transition: none; transform: none; }
}


/* ═══════════════════════════════════════════════════════════════════
   BADGE — uma base + seis semânticas
   ═══════════════════════════════════════════════════════════════════
   semântica: .badge-ok · .badge-info · .badge-atencao · .badge-critico ·
              .badge-neutro · .badge-carregada · .badge-agendado
   peso:      .badge (contornado, o padrão) · .badge-forte (preenchido)

   Eram 4 bases e 34 variantes: `.badge` do painel (contorno translúcido),
   `.v3-shell .badge` (pílula preenchida), `.badge`+`.st-*` da conferência,
   `.badge`+`.st-*`/`.p-*` das ocorrências e `.b-*` do shell. O mesmo
   significado tinha três nomes (`atencao` fora, `warn` dentro do V3, `st-
   EM_SEPARACAO` na conferência) e o mesmo prefixo `st-` queria dizer duas
   coisas diferentes em duas telas, com paletas independentes.

   O colapso é semântico, não cosmético: os cinco estados de separação e os
   doze de ocorrência/prioridade JÁ eram verde/âmbar/ciano/vermelho/cinza —
   o que faltava era chamá-los pelo que significam.

   D8: a base é CONTORNADA. No painel são 129 badges numa tela; preenchidos
   todos, a tela vira vitral. `.badge-forte` preenche — é o que as telas de
   campo usam, onde se lê a metros e com sol. */

.badge {
  font-size: var(--fonte-sm);
  padding: 2px 8px;
  border-radius: var(--raio-xl);
  border: 1px solid transparent;
  white-space: nowrap;
}
.badge-ok        { color: var(--verde);    border-color: color-mix(in srgb, var(--ok) 40%, transparent);      background: color-mix(in srgb, var(--ok) 8%, transparent); }
.badge-info      { color: var(--ciano);    border-color: color-mix(in srgb, var(--acento) 40%, transparent);  background: color-mix(in srgb, var(--acento) 8%, transparent); }
.badge-atencao   { color: var(--ambar);    border-color: color-mix(in srgb, var(--atencao) 40%, transparent); background: color-mix(in srgb, var(--atencao) 8%, transparent); }
.badge-critico   { color: var(--vermelho); border-color: color-mix(in srgb, var(--critico) 40%, transparent); background: color-mix(in srgb, var(--critico) 8%, transparent); }
.badge-neutro    { color: var(--texto2);   border-color: var(--borda);                                        background: transparent; }
/* CARREGADA (o motorista assinou) é o único estado do armazém que não cabia na
   escala verde/azul: precisa ser distinguível de "conferida" a um relance,
   porque é a diferença entre a carga pronta e a carga já no caminhão. O roxo
   é o mesmo do banner fluvial, que já está na paleta. (D7: o nome é o estado,
   não a cor — `roxo` era cor no nome, o que a Fase 1 tirou do resto.) */
.badge-carregada { color: var(--roxo);     border-color: color-mix(in srgb, var(--roxo) 40%, transparent);    background: color-mix(in srgb, var(--roxo) 10%, transparent); }
.badge-agendado  { color: var(--agendado); border-color: color-mix(in srgb, var(--agendado) 40%, transparent); background: color-mix(in srgb, var(--agendado) 10%, transparent); }

/* PREENCHIDO — a leitura de longe. Vem com peso forte: o badge cheio existe
   para ser lido de relance, e é o que as quatro telas de campo usavam. A tinta segue o fundo (regra 6 do mapa de
   cores): sobre --ok e --acento é a tinta de acento, sobre --atencao a de
   aviso, sobre --critico/--roxo/--agendado a de status. */
.badge-forte { font-weight: var(--peso-forte); }
.badge-forte.badge-ok        { background: var(--ok);       color: var(--tinta-sobre-acento); border-color: transparent; }
.badge-forte.badge-info      { background: var(--acento);   color: var(--tinta-sobre-acento); border-color: transparent; }
.badge-forte.badge-atencao   { background: var(--atencao);  color: var(--tinta-sobre-aviso);  border-color: transparent; }
.badge-forte.badge-critico   { background: var(--critico);  color: var(--tinta-sobre-status); border-color: transparent; }
.badge-forte.badge-neutro    { background: var(--borda);    color: var(--texto);              border-color: transparent; }
.badge-forte.badge-carregada { background: var(--roxo);     color: var(--tinta-sobre-status); border-color: transparent; }
.badge-forte.badge-agendado  { background: var(--agendado); color: var(--tinta-sobre-status); border-color: transparent; }

/* NO CAMPO o badge é maior e negrito: o padrão do painel (11px, peso normal)
   é para quem lê a 50cm, sentado. Conferência, motorista, coletor e portaria
   leem de pé, a metros, com sol ou com luva — a régua móvel do shell vale
   também para o componente, e mora aqui, não no <style> de cada tela. */
html.m-shell .badge { font-size: var(--m-fonte-sec); }

/* o badge que acabou de virar "ok" pisca uma vez — o conferente precisa ver
   que o bipe entrou sem tirar os olhos da carga */
.badge-ok { animation: badge-pulso .5s ease; }
@keyframes badge-pulso { 0% { transform: scale(1); } 40% { transform: scale(1.1); } 100% { transform: scale(1); } }
@media (prefers-reduced-motion: reduce) { .badge-ok { animation: none; } }

/* ── TAG — rótulo de DADO, não de estado ──────────────────────────────
   Tipo de carga, embarcador, base: não dizem como a coisa está, dizem o que
   ela é. Por isso não entram na escala semântica — são sempre preenchidas e
   a cor vem do próprio dado. */
.tag {
  font-size: var(--fonte-sm); padding: 2px 8px; border-radius: var(--raio-xl);
  white-space: nowrap;
  background: var(--veu-2); color: var(--texto2);
  border: 1px solid color-mix(in srgb, var(--borda) 55%, transparent);
}
/* tipo de carga e passagem pela base: preenchidas, porque distinguem a
   NATUREZA da operação — é o que o operador procura primeiro na linha */
.tag-lot  { background: var(--ok);      color: var(--tinta-sobre-acento); border-color: transparent; }
.tag-frac { background: var(--roxo);    color: var(--tinta-sobre-status); border-color: transparent; }
.tag-base { background: var(--atencao); color: var(--tinta-sobre-aviso);  border-color: transparent; }
/* embarcador: a cor vem da PALETA DO TEMA (ciano/verde/âmbar/roxo), como na
   tag do V3 que esta regra substituiu — e NÃO dos tokens --emb-*, que são
   iguais nos dois temas. Os --emb-* existem para o PONTO NO MAPA, onde a cor
   é dado e precisa ser a mesma no claro e no escuro; num rótulo de texto, cor
   que não acompanha o tema é o que o tema-preso chama de preso (90 elementos
   na roteirização, medidos em 12/09 antes desta correção). */
.tag-ype      { color: var(--ciano);    background: color-mix(in srgb, var(--acento) 8%, transparent);  border-color: color-mix(in srgb, var(--acento) 20%, transparent); }
.tag-roan     { color: var(--verde);    background: color-mix(in srgb, var(--ok) 8%, transparent);      border-color: color-mix(in srgb, var(--ok) 20%, transparent); }
.tag-mili     { color: var(--ambar);    background: color-mix(in srgb, var(--atencao) 8%, transparent); border-color: color-mix(in srgb, var(--atencao) 20%, transparent); }
.tag-politriz { color: var(--roxo);     background: color-mix(in srgb, var(--roxo) 8%, transparent);    border-color: color-mix(in srgb, var(--roxo) 20%, transparent); }


/* ═══════════════════════════════════════════════════════════════════
   CARD — uma base, quatro variantes e cinco acentos de estado
   ═══════════════════════════════════════════════════════════════════
   base:    .card (PLANO, sem hover — D9)
   variante: .card-clicavel · .card-elevado · .card-selecionado · .card-erro
   acento:  .card-ok · .card-info · .card-atencao · .card-critico ·
            .card-carregada  (a mesma escala do badge, na borda)

   Eram 19 famílias. A superfície continua vindo por TOKEN (--painel-superficie,
   --painel-desfoque, --card-sombra): é por ela que o Dark Glass ganha vidro e o
   Futurista ganha contorno aceso, sem tocar em estrutura nenhuma.

   D9: o padrão é SEM hover. Dos 62 cards do painel, 49 pediam `sem-hover` —
   a exceção virou regra e o negativo saiu do nome. Card que responde ao mouse
   é card em que se clica, e isso agora se declara: `.card-clicavel`. */

.card {
  background: var(--painel-superficie);
  backdrop-filter: var(--painel-desfoque);
  border: var(--linha);
  border-radius: var(--raio-lg);
  padding: var(--esp-4);
  box-shadow: var(--card-sombra);
  transition: border-color var(--transicao), box-shadow var(--transicao);
}
.card-clicavel { cursor: pointer; }
.card-clicavel:hover { border-color: var(--ciano); }
/* no celular não há hover: o retorno é o toque */
.card-clicavel:active { border-color: var(--ciano); }

/* ELEVADO — o painel do workbench: superfície própria, sem sombra, contorno
   mais fraco. Serve a qualquer bloco que segure OUTROS blocos dentro. */
/* SEM respiro próprio: o elevado é CONTÊINER — ele segura cabeçalho, lista e
   rodapé, e cada um traz o seu padding. Dar a ele o respiro do card comprime
   a lista por dentro e desloca a coluna inteira (medido na regressão de
   12/09: 8,5% da roteirização). */
.card-elevado { background: var(--painel); border-color: color-mix(in srgb, var(--borda) 55%, transparent); border-radius: var(--raio-xl); overflow: hidden; padding: 0; }

/* SELECIONADO — o card que o operador escolheu. Mesmo sinal do .btn.ativo:
   contorno de acento + realce, porque contorno sozinho é fraco para seleção. */
.card-selecionado { border-color: var(--acento); background: var(--realce-acento); }

/* ERRO / AVISO — a barra à esquerda. Era o `.alerta-card`, e é o formato certo
   para qualquer card que precise gritar sem mudar de tamanho. */
.card-erro  { border-left: 3px solid var(--vermelho); }
.card-aviso { border-left: 3px solid var(--ambar); }

/* ACENTO DE ESTADO — a conferência pinta a borda do card com o estado da
   carga, e é a mesma escala do badge: o card e o selo dentro dele dizem a
   mesma coisa com a mesma cor. */
.card-ok         { border-color: var(--verde); }
.card-info       { border-color: var(--ciano); }
.card-atencao    { border-color: var(--ambar); }
.card-critico    { border-color: var(--vermelho); }
.card-carregada  { border-color: var(--roxo); }

/* CARD DE CARGA no celular (era .m-carga-card do shell): o CA- grande, o
   estado pequeno embaixo. Só o conteúdo — a superfície é a do .card. */
.card-carga { margin-bottom: var(--m-esp-2, 8px); }
.card-carga .m-ca { font-size: var(--m-fonte-titulo); font-weight: var(--peso-forte); }
.card-carga .m-estado { font-size: var(--m-fonte-sec); color: var(--texto2); }

/* no campo o card é mais apertado: a tela é pequena e a mão segura o aparelho */
html.m-shell .card { padding: var(--m-esp-3, 12px); border-radius: var(--m-raio, 10px); }

/* A TELA DE ENTRAR mantém a própria caixa (D3): raio grande e respiro de
   cartão de visita — é a primeira coisa que se vê do produto. */
.card-login { border-radius: 22px; padding: 40px 36px; box-shadow: var(--sombra-sm), var(--sombra-lg); }

/* NO PAPEL o card não tem moldura: a borda vira linha impressa à toa e come
   tinta. (Estava no style.css, dentro do @media print do painel — mas todo
   card que for impresso quer isto.) */
@media print { .card { border: none; background: var(--painel); box-shadow: none; } }


/* ═══════════════════════════════════════════════════════════════════
   TABELA — uma base e dois modificadores
   ═══════════════════════════════════════════════════════════════════
   base:  table, .tabela   (D10: pele por ELEMENTO e por classe)
   modif: .tabela-compacta · .tabela-zebrada

   Eram 10 estilos. O `class="tabela"` tinha 20 usos no app.js e **nenhuma
   regra-base própria** — a pele vinha do seletor de elemento, e o nome
   prometia um componente que não existia. Agora existe, e o elemento continua
   valendo: 25 das 51 tabelas do app.js não têm classe, e exigir classe de
   todas seria 25 edições para chegar na pele que já têm.

   O cabeçalho é caixa-alta pequena e cinza, a linha tem filete fino, e a
   linha do corpo responde ao mouse — no painel, tabela é coisa em que se
   clica. Onde não é (a compacta), o modificador desliga. */

table, .tabela { width: 100%; border-collapse: collapse; }
th, .tabela th {
  text-align: left;
  font-size: var(--fonte-sm);
  font-weight: var(--peso-medio);
  color: var(--texto2);
  text-transform: uppercase;
  letter-spacing: var(--caixa-alta);
  padding: 8px 10px;
  border-bottom: var(--linha);
}
td, .tabela td { padding: 8px 10px; border-bottom: 1px solid var(--linha-tabela); }
tbody tr { cursor: pointer; transition: background var(--transicao); }
tbody tr:hover > td { background: var(--realce-acento); }

/* COMPACTA — a tabela que mora DENTRO de outra coisa (a mini-lista da carta de
   carga, o waterfall financeiro, as parcelas do tetris). Aperta o passo e
   desliga o clique: ninguém clica numa linha de conta. */
.tabela-compacta { font-size: var(--fonte-md); }
.tabela-compacta th, .tabela-compacta td { padding: 3px 4px; }
.tabela-compacta tbody tr { cursor: default; }
.tabela-compacta tbody tr:hover > td { background: transparent; }
/* a última linha de uma compacta costuma ser o TOTAL: filete em cima, nenhum
   embaixo, e respiro para separá-la das parcelas */
.tabela-compacta tr.total > td, .tabela-compacta tfoot > tr > td {
  border-top: 2px solid var(--borda); border-bottom: none; padding-top: 6px;
  font-weight: var(--peso-forte);
}

/* ZEBRADA — para tabela longa que se lê na horizontal e não tem filete que
   chegue. Não é usada em nenhuma tela ainda; nasce aqui para que a próxima
   não invente a sua. */
.tabela-zebrada tbody tr:nth-child(even) > td { background: var(--veu-1); }
.tabela-zebrada tbody tr:hover > td { background: var(--realce-acento); }

/* NA TELA ESTREITA a tabela aperta o passo e desce um degrau de fonte: numa
   largura de celular, 8px de respiro por célula é a diferença entre ler a
   linha e rolar de lado. */
@media (max-width: 640px) {
  table, .tabela { font-size: var(--fonte-md); }
  th, td, .tabela th, .tabela td { padding: 6px 5px; }
}

/* número em CÉLULA é alinhado à direita e com dígito de largura fixa, senão a
   coluna não se lê de cima para baixo.
   O seletor é `td.num`/`th.num`, e não `.num` solto, porque `.num` quer dizer
   outra coisa fora da tabela: no mapa do CD é "em fonte mono" (o campo de
   busca de LP-/CA-/chave). Solto, ele alinhou à direita o texto daquele campo
   — 9,4% da tela no celular, achado na regressão de 12/09. */
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }


/* ═══════════════════════════════════════════════════════════════════
   CAMPO — input, select, textarea e o checkbox de conferência
   ═══════════════════════════════════════════════════════════════════
   base:  input, select, textarea, .campo   (pele por elemento E por classe,
          como a tabela: campo sem classe é a maioria absoluta)
   modif: .campo-compacto · .campo-bipe · .campo-login
   peça:  .chk (o quadrado que se marca na conferência)

   Eram 16 peles. Duas delas escreviam o cinza da borda em hex (#30363d na
   conferência), o que fazia o tema claro ignorar o próprio tema. O select do
   motorista não tinha regra nenhuma e vinha com a cara do navegador.

   O FOCO é um só em todo o sistema: contorno de acento. Era ciano no painel,
   ciano no shell, VERDE na guarita e branco-com-sombra no login — quatro
   sinais para a mesma coisa (D11: fica o ciano, que é o acento). */

input, select, textarea, .campo {
  font-family: inherit;
  font-size: var(--fonte-base);
  color: var(--texto);
  background: var(--fundo);
  border: var(--linha);
  border-radius: var(--raio-md);
  padding: 7px 10px;
  transition: border-color var(--transicao);
}
input:focus, select:focus, textarea:focus, .campo:focus {
  outline: none;
  border-color: var(--ciano);
}
input:disabled, select:disabled, textarea:disabled { opacity: .5; cursor: not-allowed; }
textarea { resize: vertical; }
/* o rótulo é do campo: pequeno, cinza, coladinho em cima */
label { font-size: var(--fonte-sm); color: var(--texto2); display: block; margin-bottom: 4px; }

/* COMPACTO — campo dentro de barra de ferramentas ou de linha de tabela */
.campo-compacto { padding: 5px 8px; font-size: var(--fonte-md); }

/* CONTEXTOS DENSOS — onde o campo é compacto por natureza do lugar, e não
   por escolha de quem escreveu a linha: o workbench da montagem (uma tela
   inteira de controles lado a lado) e a calculadora do piso ANTT (uma barra
   de seis campos). Escopo aqui, e não `.campo-compacto` em cada markup, pelo
   mesmo motivo do `.app-portaria`: é propriedade do CONTEXTO. */
.v3-shell input, .v3-shell select, .v3-shell .campo,
.antt-calc input, .antt-calc select {
  padding: 5px 8px; font-size: var(--fonte-md);
}
.v3-shell input, .v3-shell select { background: var(--painel2); border-radius: 7px; }

/* ── no CAMPO (celular) o campo é maior ───────────────────────────────
   16px é o piso do iOS (abaixo disso o Safari dá zoom ao focar) e vem da
   régua do shell; aqui ficam o respiro e o raio, que são pele. */
html.m-shell input, html.m-shell select, html.m-shell textarea, html.m-shell .campo {
  padding: 11px; border-radius: var(--m-raio, 10px);
}

/* CAMPO DE BIPE (§C.3.3) — a guarita lê o CA- a metros, de noite, e o campo
   não abre teclado quando a leitura vem da câmera ou do leitor wedge.
   O seletor tem peso de sobra (elemento + classe) porque a régua do shell
   define font-size e min-height para TODO input, e carrega depois deste
   arquivo: sem o desempate, o bipe voltaria a 16px. */
input.campo-bipe, .campo-bipe {
  width: 100%; font-size: var(--m-fonte-bipe, var(--fonte-xxl)); font-weight: var(--peso-forte);
  text-align: center; letter-spacing: .04em;
  min-height: 64px; border-radius: var(--m-raio, 10px);
  border: 2px solid var(--borda); background: var(--painel); color: var(--texto);
}
html.m-shell input.campo-bipe { font-size: var(--m-fonte-bipe); min-height: 64px; }
input.campo-bipe:focus { border-color: var(--acento); outline: none; }

/* A TELA DE ENTRAR mantém o próprio campo (D3): superfície um degrau acima do
   painel, sem borda até o foco, e o foco com halo — é a única superfície clara
   do produto e o campo precisa aparecer sem moldura. */
.campo-login {
  background: var(--painel2); border-color: transparent; border-radius: 12px;
  padding: 12px 14px; font-size: var(--fonte-lg); font-weight: var(--peso-semi);
  transition: all .18s cubic-bezier(.22,.72,.28,1);
}
.campo-login:focus {
  border-color: var(--acento); background: var(--painel);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--acento) 12%, transparent);
}

/* ERRO NO CAMPO — o valor que o sistema recusa. É o frete abaixo do piso da
   ANTT na montagem (o bloqueio duro é na contratação, mas o número tem de
   SALTAR antes disso). */
.campo-erro, input.campo-erro {
  border-color: var(--vermelho);
  background: color-mix(in srgb, var(--critico) 12%, transparent);
  color: var(--vermelho);
  font-weight: var(--peso-semi);
}
.campo-erro:focus, input.campo-erro:focus { border-color: var(--vermelho); }

/* CHECKBOX DE CONFERÊNCIA — não é o <input type=checkbox> do navegador: é um
   quadrado grande, que o conferente acerta com luva e enxerga de pé. */
.chk {
  width: 32px; height: 32px; border-radius: var(--raio-lg);
  border: 2px solid var(--borda); background: transparent;
  display: flex; align-items: center; justify-content: center;
  font-size: var(--fonte-xl); flex: 0 0 auto; cursor: pointer;
}
.chk-ok { background: var(--ok); border-color: var(--ok); color: var(--tinta-sobre-acento); }


/* ═══════════════════════════════════════════════════════════════════
   SOBREPOSIÇÃO — modal, gaveta e PARE
   ═══════════════════════════════════════════════════════════════════
   base:     .mod (o véu, que também é a área de clicar-fora)
   conteúdo: .mod-caixa (centro) · .mod-gaveta (lateral) · .mod-pare (bloqueio)
   peças:    .mod-titulo · .mod-corpo · .mod-acoes · .mod-campo

   Eram sete mecanismos que não compartilhavam nada: o modal do painel, a
   gaveta de cadastro, três <dialog> da conferência, o PARE das telas de campo
   e os painéis do mapa do CD. Fechamento, véu e animação escritos cinco
   vezes; Esc e foco preso, nenhuma.

   O comportamento mora em web/componentes.js (LotusModal) — sem JS não há Esc
   nem foco preso, e é isso que separa "parece um modal" de "é um modal". */

.mod {
  position: fixed; inset: 0; z-index: 1000;
  background: var(--veu-modal);
  display: none;
  align-items: center; justify-content: center;
  padding: var(--esp-6);
}
.mod.aberto { display: flex; }

.mod-caixa {
  background: var(--painel);
  border: var(--linha);
  border-radius: var(--raio-xl);
  box-shadow: var(--sombra-lg);
  max-width: 720px; width: 100%; max-height: 86vh; overflow-y: auto;
  padding: var(--esp-5);
}
.mod-titulo { font-size: var(--fonte-xl); font-weight: var(--peso-medio); margin: 0 0 var(--esp-3); }
.mod-corpo { color: var(--texto); line-height: 1.5; }
.mod-acoes { display: flex; gap: var(--esp-2); margin-top: var(--esp-4); justify-content: flex-end; }
.mod-acoes .btn { flex: 0 1 auto; }
.mod-campo { width: 100%; margin-top: var(--esp-3); }
/* as opções do `escolher`: uma embaixo da outra, do tamanho do dedo */
.mod-opcoes { display: flex; flex-direction: column; gap: var(--esp-2); margin-top: var(--esp-3); }

/* GAVETA — formulário que entra pela direita, nunca inline no topo da lista
   (GOAL Cadastros §2). No celular ela ocupa a tela inteira: 440px numa tela de
   390 seria a mesma coisa com uma fresta inútil à esquerda. */
.mod-gaveta {
  margin-left: auto; margin-right: 0;
  width: min(440px, 100%); max-width: none;
  height: 100%; max-height: none;
  border-radius: 0; border-right: 0; border-top: 0; border-bottom: 0;
  animation: mod-entra-lado .18s ease-out;
}
.mod:has(> .mod-gaveta) { padding: 0; align-items: stretch; }
@keyframes mod-entra-lado { from { transform: translateX(30px); opacity: 0 } to { transform: none; opacity: 1 } }

/* PARE — erro de operação em tela cheia (§C.3.5). É o único BLOQUEANTE: não
   fecha por Esc nem por clique no véu, porque no galpão aviso que se dispensa
   sem querer é aviso que não existiu. */
.mod-pare {
  background: var(--critico); color: var(--tinta-sobre-status);
  border: 0; border-radius: 0; box-shadow: none;
  max-width: none; width: 100%; height: 100%; max-height: none;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--m-esp-4, 16px); padding: var(--m-esp-6, 24px); text-align: center;
}
.mod:has(> .mod-pare) { padding: 0; background: var(--critico); }
/* 34px: acima do teto da escala (24) de propósito — é a palavra PARE numa tela
   inteira vermelha, tem de ser lida de longe */
.mod-pare b { font-size: 34px; letter-spacing: .06em; }
.mod-pare p { font-size: var(--fonte-xl); line-height: 1.45; max-width: 34ch; }

/* <dialog> NATIVO — a conferência usa os três que já tinha (o navegador dá
   Esc, véu e foco preso de graça). O que faltava era a pele: */
dialog {
  background: var(--painel); color: var(--texto);
  border: var(--linha); border-radius: var(--raio-xl);
  box-shadow: var(--sombra-lg);
  padding: var(--esp-4); max-width: 92vw;
}
dialog::backdrop { background: var(--veu-modal); }

@media (prefers-reduced-motion: reduce) {
  .mod-gaveta { animation: none; }
}


/* ═══════════════════════════════════════════════════════════════════
   SHELL — cabeçalho e rodapé das telas de campo
   ═══════════════════════════════════════════════════════════════════
   .cab-app > .cab-nome + .cab-acoes  ·  .rodape

   As quatro telas de campo (conferência, motorista, coletor, portaria) tinham
   duas molduras diferentes: o <h1 class="cab-app"> que o FRONT-4 desenhou para
   duas delas, e um <header> próprio nas outras duas, com `.marca` e `.quem`
   dizendo exatamente a mesma coisa com outros nomes. O rodapé eram duas
   `<footer style="...">` inline e duas `.rodape` locais.

/* (o desenho abaixo é o do FRONT-4, 11/09/2026 — o que muda no item 7 é o
   ENDEREÇO dele, e as duas telas que passam a usá-lo)
   No celular, "visão: auto" e "sair (Fulano)" caíam cada um numa linha
   inteira: o cabeçalho comia 164px de uma tela de 844px antes de a primeira
   carga aparecer. Agora é uma barra — nome à esquerda, controles agrupados à
   direita — SEM mexer no alvo de toque de 48px, que é o mínimo para dedo com
   luva. No estreito o nome sai do botão "sair": ele já está no #quem, ao lado
   do título, e repetido custava 90px da única linha que existe. */
.cab-app { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
/* min-content, não 0: com 0 o nome do app aceitava uma faixa menor do que a
   maior palavra dele e vazava POR CIMA do ◐ (14px, medidos em 390px). Assim
   ele usa o que precisa e, se não couber, o bloco de controles desce inteiro
   — quebrar é feio, sobrepor é defeito. */
.cab-app .cab-nome { flex: 1 1 auto; min-width: min-content; display: flex; flex-wrap: wrap;
  align-items: baseline; gap: 0 6px; font-weight: var(--peso-forte); letter-spacing: .5px; }
/* na GUARITA o nome da tela é lido a metros, como o campo de bipe — mesma
   exceção de escala, mesmo motivo (o caminhão está esperando) */
.app-portaria .cab-nome { font-size: var(--fonte-xxl); white-space: nowrap; }
/* O GRUPO DE CONTROLES NÃO DEPENDE DA MOLDURA (Moises, 11/09/2026): é o mesmo
   objeto no <h1> das telas de campo e no <header> do painel, que tinha o mesmo
   defeito — no celular o "sair (Fulano)" caía sozinho numa segunda linha. */
.cab-acoes { flex: 0 0 auto; display: flex; align-items: center; gap: 6px; margin-left: auto; }
.cab-acoes #btn-sair { margin-left: 0; }
@media (max-width: 560px) {
  .cab-app { font-size: var(--fonte-lg); }
  .btn-sair-quem { display: none; }
  /* Os controles entram na MESMA linha do nome. No celular o shell os põe em
     16px — que é o piso dos CAMPOS (o iOS dá zoom ao focar abaixo disso), não
     o de um rótulo de botão — e só eles comiam 200 dos 288px úteis. 13px é o
     piso do texto secundário do próprio shell; o alvo de toque de 48px fica
     como está, que é o que o dedo com luva precisa. */
  .cab-acoes button, .cab-acoes #btn-sair { font-size: var(--m-fonte-sec, var(--fonte-base)); }
  /* "LOTUS · MOTORISTA" quebra entre as duas palavras se deixado à vontade —
     e aí o cabeçalho vira três linhas. Ou cabe inteiro, ou desce inteiro. */
  .cab-app .cab-nome > span { white-space: nowrap; }
}

/* O RODAPÉ é o mesmo nas quatro: assinatura discreta, longe do polegar. Era
   `<footer style="margin-top:20px">` inline em duas telas e `.rodape` local
   nas outras duas, com padding diferente em cada uma. */
.rodape {
  text-align: center; color: var(--texto2);
  font-size: var(--m-fonte-sec, var(--fonte-base));
  padding: var(--m-esp-6, 24px) 0 var(--m-esp-2, 8px);
}
