/* ============================================================
   NavSupply Coletor — componentes compartilhados (Fase 3, ui.js).
   Carregado DEPOIS de style.css em index.html (2ª <link>). Todas as regras
   abaixo usam só os tokens JÁ EXISTENTES em style.css (--accent, --ink,
   --r-sm, --surface...) — NUNCA os nomes-alvo de _TOKENS_ALVO.md
   (--action, --navy, --radius...), porque a Onda 1 (fora desta fase) vai
   redefinir essas variáveis atuais para os valores novos por alias. CSS
   escrito com os nomes atuais funciona hoje E herda a paleta nova sozinho
   quando a Onda 1 subir, sem tocar neste arquivo de novo.

   Classes novas usam sempre o prefixo `ui-` para não colidir nem ser
   confundidas com as classes legadas (.btn, .badge, .msg-info, .tk-grid...)
   enquanto os dois sistemas convivem — a Fase 4 troca a marcação tela a
   tela. Exceção deliberada: a `appHeader` (§1) REAPROVEITA as classes de
   identidade já existentes do header escuro (.topbar/.tb-mark/.tb-titulo/
   .tb-kicker/.tb-user/.tb-emp/.tb-emp-btn) — já totalmente estilizadas em
   style.css — para não obrigar a reescrever a régua .shell.largo .tb-kicker
   etc. nesta fase; só o botão-ícone escuro troca de nome (.icon-btn vira
   .ui-icon-btn), com a régua escopada abaixo.
   ============================================================ */

/* ============================================================ 1 — appHeader
   Reaproveita .topbar/.tb-mark/.tb-titulo/.tb-kicker/.tb-user/.tb-emp(-btn)
   de style.css — já estilizados, tema --ink preservado. Só o botão-ícone
   escuro (voltar/menu E o novo "?") precisa de régua própria, porque
   .topbar .icon-btn (antigo) tem CSS escopado que um .ui-icon-btn genérico
   (fundo claro, §10) não cobriria — decisão do dono (pergunta 1): manter os
   dois no padrão atual da topbar (44px desde a camada 2, tema --ink), fora da régua geral. */
/* Camada 2 do rebranding NavSupply (29/10/2026): o botão do menu da topbar é o .btn-menu do kit (44px, sem caixa,
   três traços ou a seta de voltar em --on-ink), o mesmo do layout() em style.css; só o "?" de ajuda mantém um
   filete (é um glifo solto, sem ele não se lê como botão). */
.topbar .ui-icon-btn {
  width: 44px; height: 44px; min-width: 0; min-height: 0; flex: none; padding: 0;
  border: 0; background: none; color: var(--on-ink);
  border-radius: var(--radius); display: flex; align-items: center; justify-content: center;
  cursor: pointer; transition: background var(--t) var(--ease);
}
.topbar .ui-icon-btn:hover { background: var(--navy-hover-lateral); }
.topbar .ui-icon-btn:active { background: var(--ink-line); }
.topbar .ui-icon-btn:focus-visible { outline: 2px solid var(--brass-hi); outline-offset: -2px; }
.topbar #tb-ajuda { border: 1px solid var(--ink-line); font-weight: 700; }

/* ============================================================ 2 — pageTitle
   Reproduz .titulo-tela (style.css:374-378), classes novas. */
.ui-titulo { margin-bottom: 18px; }
.ui-kicker { font-weight: 600; font-size: 11px; letter-spacing: .12em; color: var(--fg-3); text-transform: uppercase; margin-bottom: 5px; }
.ui-titulo h1 { font-weight: 600; font-size: 23px; line-height: 1.15; letter-spacing: -0.025em; }
.ui-passo { font-size: 13px; color: var(--fg-3); margin-top: 6px; }
.ui-passo b { color: var(--action-text); }
@media (min-width: 900px) {
  .shell.largo .ui-titulo { display: flex; align-items: baseline; gap: 10px; margin-bottom: 8px; }
  .shell.largo .ui-titulo h1 { font-size: 18px; }
  .shell.largo .ui-kicker { margin-bottom: 0; }
}

/* ============================================================ 3 — kpiStrip
   variante "tira" reproduz .tk-resumo/.tk-stat (aparece em qualquer largura);
   "ladrilho" reproduz .pend-tile (só desktop — decisão do dono, pergunta 2:
   continua restrita a .shell.largo/900px nesta fase). */
/* CAMADA 3b (30/10/2026; §7 do guia do kit): a tira de KPIs tem DUAS caras, e o que muda é só se o item é botão.
   - INDICADOR (o item é um <div>, sem onClick): o do kit — rótulo de 11px em caixa NORMAL (era 10px caixa alta com tracking) e valor
     de 17px/600 (19px no `forte`; na mesa 15 e 17: a tira mora em cima de grades densas). Não finge botão: sem hover, sem cursor, sem marcador.
   - SEGMENTO DA RÉGUA (o item é um <button>, com onClick): a MESMA régua dos chips (§4 abaixo) — o NÚMERO em cima (18px/600) e o rótulo embaixo
     (13px, --fg-3), o marcador quadrado de 8px no canto (âmbar na `atencao`, vermelho na `erro`; sem tom, transparente), hover --surface,
     altura mínima de 44px no TC22. Nenhuma tela mudou de marcação: o rótulo continua vindo ANTES do valor no DOM e a ordem visual é do `order`. */
.ui-kpi { display: flex; flex-wrap: wrap; }
.ui-kpi--tira {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  margin: 0 0 12px; box-shadow: none; overflow: hidden;
}
.ui-kpi--tira .ui-kpi-item {
  display: flex; flex-direction: column; gap: 2px; text-align: left;
  padding: 10px 16px 11px; border-right: 1px solid var(--border);
  background: none; border-top: 0; border-bottom: 0; border-left: 0;
  font-family: var(--font); cursor: default; color: inherit;
}
.ui-kpi--tira .ui-kpi-item:last-child { border-right: 0; }
.ui-kpi-rotulo { display: flex; align-items: center; gap: 5px; font-style: normal; font-size: 11px; font-weight: 600; letter-spacing: 0; text-transform: none; color: var(--fg-3); }
.ui-kpi-rotulo .ico { width: 13px; height: 13px; color: var(--fg-3); }
.ui-kpi-valor { font-size: 17px; font-weight: 600; font-variant-numeric: tabular-nums; color: var(--fg); }
.ui-kpi-item--atencao .ui-kpi-valor { color: var(--warn-text); }
.ui-kpi-item--erro .ui-kpi-valor { color: var(--danger); }
.ui-kpi--tira .ui-kpi-item--forte .ui-kpi-valor { font-size: 19px; }
button.ui-kpi-item { cursor: pointer; }
/* o item-botão: segmento da régua */
.ui-kpi--tira button.ui-kpi-item {
  position: relative; min-height: 44px; justify-content: center; padding: 8px 18px 8px 24px;
  transition: background var(--t) var(--ease), box-shadow var(--t) var(--ease);
}
.ui-kpi--tira button.ui-kpi-item .ui-kpi-valor { order: -1; font-size: 18px; line-height: 1.15; }
.ui-kpi--tira button.ui-kpi-item .ui-kpi-rotulo { font-size: 13px; font-weight: 450; }
.ui-kpi--tira button.ui-kpi-item::before { content: ""; position: absolute; left: 10px; top: 13px; width: 8px; height: 8px; background: var(--marcador, transparent); }
.ui-kpi--tira button.ui-kpi-item.ui-kpi-item--atencao { --marcador: var(--warn); }
.ui-kpi--tira button.ui-kpi-item.ui-kpi-item--erro { --marcador: var(--danger); }
.ui-kpi--tira button.ui-kpi-item:hover { background: var(--surface-2); }
.ui-kpi--tira button.ui-kpi-item:focus-visible { outline: 2px solid var(--action-line); outline-offset: -2px; }
@media (min-width: 900px) {
  .shell.largo .ui-kpi--tira { margin-bottom: 8px; }
  .shell.largo .ui-kpi--tira .ui-kpi-item { padding: 6px 14px 7px; }
  .shell.largo .ui-kpi--tira .ui-kpi-valor { font-size: 15px; }
  .shell.largo .ui-kpi--tira .ui-kpi-item--forte .ui-kpi-valor { font-size: 17px; }
  /* o segmento-botão na mesa: o kit em linha — marcador, número e rótulo na mesma base */
  .shell.largo .ui-kpi--tira button.ui-kpi-item { min-height: 34px; flex-direction: row; align-items: baseline; justify-content: flex-start; gap: 8px; padding: 5px 16px 5px 14px; }
  .shell.largo .ui-kpi--tira button.ui-kpi-item::before { position: static; align-self: center; order: -2; flex: none; }
  .shell.largo .ui-kpi--tira button.ui-kpi-item .ui-kpi-valor { font-size: 18px; }
}

.ui-kpi--ladrilho { display: none; }
@media (min-width: 900px) {
  .ui-kpi--ladrilho { display: flex; flex-wrap: wrap; gap: 10px; max-width: 1400px; margin: 0 auto 18px; }
  .ui-kpi--ladrilho .ui-kpi-item {
    flex: 1 1 200px; display: flex; flex-direction: column-reverse; gap: 4px; text-align: left;
    padding: 14px 16px; border: 1px solid var(--line); border-radius: var(--r);
    background: var(--surface); box-shadow: var(--sh-1); font-family: var(--font); color: inherit;
    transition: box-shadow var(--t) var(--ease), border-color var(--t) var(--ease);
  }
  .ui-kpi--ladrilho .ui-kpi-rotulo { font-size: 13px; font-weight: 600; letter-spacing: 0; text-transform: none; color: var(--fg-2); }
  .ui-kpi--ladrilho .ui-kpi-rotulo .ico { width: 15px; height: 15px; }
  .ui-kpi--ladrilho .ui-kpi-valor { font-size: 28px; font-weight: 700; line-height: 1; color: var(--action-text); }
  .ui-kpi--ladrilho .ui-kpi-item--atencao .ui-kpi-valor { color: var(--warn-text); }
  .ui-kpi--ladrilho .ui-kpi-item--erro .ui-kpi-valor { color: var(--danger); }
  .ui-kpi--ladrilho button.ui-kpi-item:hover { box-shadow: var(--sh-2); border-color: var(--line-hi); }
  .ui-kpi--ladrilho button.ui-kpi-item:focus-visible { outline: 2px solid var(--action-line); outline-offset: 2px; }
}

/* ============================================================ 4 — filterChips (a RÉGUA do kit)
   CAMADA 3b (30/10/2026; §7 do guia do kit, "o kit é a fonte da verdade"). UMA receita para os três controles que filtram uma lista que
   continua à vista: UI.filterChips (.ui-chips), o legado .seg-filtro (2 usos em app-conf.js; a receita antiga morou em style.css) e o
   item-botão da UI.kpiStrip (§3 acima). A caixa é uma só (.regua do kit: fundo --surface-2, filete --border, canto --radius) e cada
   segmento é um <button aria-pressed>, separado do vizinho por um filete vertical. Nenhuma marcação mudou: o contador (.ui-chip-n e
   .n) continua DEPOIS do rótulo no DOM, e quem o põe na frente é o `order`.
   - TC22 (< 900px): o segmento é uma coluna — o NÚMERO em cima (18px/600, tabular), o rótulo embaixo (13px, --fg-3; ativo --fg) — com
     44px de altura no mínimo (o dedo de luva) e o marcador quadrado de 8px no canto de cima. Chip sem contagem ("15 dias") fica só com
     o rótulo, centrado.
   - Mesa (>= 900px): o kit em linha — marcador, número e rótulo na mesma base (padding 5px 14px, no mínimo 34px).
   - Estado: o marcador (::before, --marcador) nasce transparente, como no kit (só o que pede ação ou está escolhido leva cor);
     `.atencao` pinta âmbar (--warn), `.erro` vermelho (--danger), `.neutro` o --fg-3 (o --neutro do kit fecha 2,70:1 sobre --surface-2; revisão de 02/11/2026), e o ATIVO (aria-pressed="true") o dourado.
     O ATIVO = fundo --surface + sublinhado de 2px em --action-line (inset 0 -2px 0) + marcador dourado: o dourado do indicador, que
     fecha 3,58:1 sobre --surface no claro (o --brass/--ouro puro dá 2,43:1 e a auditoria (l) do harness_tokens o recusa).
   - MUDANÇA DE DECISÃO (visível): o ativo deixa de ser NAVY CHEIO (pedido do dono em 22/09/2026, antes do rebranding: "para não competir
     com o dourado de seleção dentro da lista") e passa ao sublinhado dourado do kit; o navy volta a ser só do botão primário.
   - `.ui-chips--rola` (frente AB, 15/10/2026): a faixa que ROLA na horizontal quando os chips não cabem (celular, 390px) — os botões não
     encolhem nem quebram o rótulo; a barra de rolagem fica escondida (é gesto de dedo). Toda régua agora rola por dentro em vez de
     empurrar a página; o `--rola` só diz que os botões NÃO encolhem (flex: 0 0 auto). */
.ui-chips, .seg-filtro {
  display: flex; align-items: stretch; max-width: 100%; margin: 12px 0 4px; padding: 0;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius);
  overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain; scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.ui-chips::-webkit-scrollbar, .seg-filtro::-webkit-scrollbar { display: none; }
.ui-chips button, .seg-filtro button {
  position: relative; flex: 1 1 auto; min-height: 44px; padding: 6px 14px; cursor: pointer;
  border: 0; border-right: 1px solid var(--border); border-radius: 0; background: transparent;
  font-family: var(--font); font-size: 13px; line-height: 1.3; color: var(--fg-3); white-space: nowrap;
  display: inline-flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px;
  transition: background var(--t) var(--ease), box-shadow var(--t) var(--ease), color var(--t) var(--ease);
}
.ui-chips button:last-child, .seg-filtro button:last-child { border-right: 0; }
.ui-chips button::before, .seg-filtro button::before {
  content: ""; position: absolute; left: 7px; top: 7px; width: 8px; height: 8px; background: var(--marcador, transparent);
}
.ui-chips button.atencao, .seg-filtro button.atencao { --marcador: var(--warn); }
.ui-chips button.erro, .seg-filtro button.erro { --marcador: var(--danger); }
.ui-chips button.neutro, .seg-filtro button.neutro { --marcador: var(--fg-3); }   /* o --neutro do kit fecha 2,70:1 sobre --surface-2 no claro (o piso do marcador é 3:1); o --fg-3 fecha 5,04:1 */
.ui-chip-n, .seg-filtro button .n {
  order: -1; min-width: 0; padding: 0; border-radius: 0; background: none;
  font-size: 18px; font-weight: 600; font-variant-numeric: tabular-nums; line-height: 1.15; color: var(--fg);
}
.ui-chips button:hover, .seg-filtro button:hover { background: var(--surface); color: var(--fg); }
.ui-chips button:active, .seg-filtro button:active { background: var(--surface); }
.ui-chips button:focus-visible, .seg-filtro button:focus-visible { outline: 2px solid var(--action-line); outline-offset: -2px; }
.ui-chips button[aria-pressed="true"], .seg-filtro button[aria-pressed="true"] {
  --marcador: var(--action-line); background: var(--surface); color: var(--fg); box-shadow: inset 0 -2px 0 var(--action-line);
}
.ui-chips button[aria-pressed="true"]:hover, .seg-filtro button[aria-pressed="true"]:hover { background: var(--surface); }
@media (min-width: 900px) {
  .ui-chips button, .seg-filtro button {
    flex-direction: row; align-items: baseline; justify-content: center; gap: 8px; min-height: 34px; padding: 5px 16px 5px 14px;
  }
  .ui-chips button::before, .seg-filtro button::before { position: static; align-self: center; order: -2; flex: none; }
  .ui-chip-n, .seg-filtro button .n { line-height: 1.1; }
}
/* Régua com 5 ou mais segmentos, na MESA: modo COMPACTO (revisão de 02/11/2026). A ficha de recebimento (aba Itens) tem 5 (Todos, Sem vínculo, Sugestões,
   Fora da OC, Divergentes) dentro de um painel de metade da janela (595px a 1262, 604px a 1280) e, com o respiro de 14px/16px de cada segmento e os 8px
   entre o marcador, o número e o rótulo, a régua media 635px: o quinto segmento saía cortado pela rolagem escondida (scrollbar-width: none), sem pista
   nenhuma. Aqui o marcador sai do fluxo (fica absoluto no canto de dentro do respiro da esquerda, como no TC22), o respiro cai para 7px/17px e o vão para
   5px: a régua passa a cerca de 510px com contagens de 1 dígito e a cerca de 575px no pior caso (3 dígitos no "Todos" e 2 nos outros), e a altura e a
   tipografia são as mesmas. Quem tem menos de 5 segmentos não muda. Abaixo de uns 1200px de janela nem assim cabe: a régua rola por dentro (o último
   segmento aparece cortado na borda, a pista de sempre dos chips que rolam). */
@media (min-width: 900px) {
  .ui-chips:has(> button:nth-child(5)) button, .seg-filtro:has(> button:nth-child(5)) button { padding: 5px 7px 5px 17px; gap: 5px; }
  .ui-chips:has(> button:nth-child(5)) button::before, .seg-filtro:has(> button:nth-child(5)) button::before { position: absolute; left: 6px; top: 50%; margin-top: -4px; order: 0; }
}
/* Chips que ROLAM na horizontal (frente AB, 15/10/2026, Boletos para completar; `UI.filterChips({ rola: true })`).
   Quando os chips não cabem na linha (celular, TC22 de 390px) a faixa rola de lado DENTRO dela mesma — a página não ganha
   rolagem lateral. Os botões não encolhem (flex: 0 0 auto) nem quebram o rótulo, mantêm os 44px de toque, e o chip cortado na
   borda é a pista de que há mais. A barra de rolagem fica escondida (é gesto de dedo; no teclado o foco leva o chip à vista).
   Cabe na linha (computador): nada muda — sem rolagem, o visual é o de sempre. */
.ui-chips--rola { max-width: 100%; min-width: 0; overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
.ui-chips--rola::-webkit-scrollbar { display: none; }
.ui-chips--rola button { flex: 0 0 auto; }

/* ============================================================ 5 — filterBar (a .barra-filtros do kit)
   Composição de busca + filterChips + extras, reproduz .tk-filtros. CAMADA 3b (§8 do guia): é a .barra-filtros do kit — flex com gap 8
   que quebra sozinho; a busca é o campo do kit (borda --border-interactive, foco --action-line, placeholder --fg-3) com 44px no TC22 (era
   38) e 34px na mesa (o `--h-controle` do kit; era 38), e o select da barra acompanha (44 e 34). */
.ui-filterbar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin: 0 0 10px; }
.ui-filterbar .ui-chips { margin: 0; flex: none; }
.ui-filterbar-busca { flex: 1; min-width: 200px; max-width: 380px; margin: 0; height: 44px; padding: 0 12px; font-size: 14px; }
/* `.ui-filterbar ` na frente: o `input[type=search]` global de style.css (16px, padding 12px) e o min-height de 36px do .ui-input da mesa têm especificidade igual ou maior que
   a classe sozinha; sem isto a busca da mesa nascia com 36px e o respiro vertical do campo global. No TC22 a fonte segue a global (16px). */
.ui-filterbar .ui-filterbar-busca { height: 44px; padding: 0 12px; }
.ui-conta { font-size: 12.5px; color: var(--fg-3); font-variant-numeric: tabular-nums; }
.ui-conta b { color: var(--fg-2); font-weight: 600; }
@media (min-width: 900px) {
  .ui-filterbar .ui-filterbar-busca { height: 34px; min-height: 34px; font-size: 14px; }
  .shell.largo .ui-filterbar { gap: 8px; margin-bottom: 8px; }
}

/* ============================================================ 6 — dataTable
   Reproduz .estoque/.tk-grid/.tk-sug-grid. Container sempre width:100% do
   pai — NUNCA min-width mágico; cada coluna pede largura via <col> no
   <colgroup> (equivalente ao que .rec-grid já faz com classe própria).
   CAMADA 3b (30/10/2026; §9 e §11 do guia do kit): a tabela do kit nos nomes de sempre. Cabeçalho navy (--th-bg/--th-fg) com th de 12px/600
   (eram 10,5px), o tracking e a caixa alta que já existiam; célula de 10px 12px no TC22 e 8px 12px na mesa (as grades densas — .rec-grid,
   .pd-grade, .st-grade, .ng-grid — têm regra própria, mais específica, e seguem como estavam); filete --border entre as linhas, SEM zebra;
   hover --surface-2; número à direita (.ui-num); th ordenável com sublinhado no hover e a seta que sobe a 100% (inativa fica a .45: o
   harness_tokens exige >= .4 — sem a pista a coluna ordenável não se descobre no toque); foco por DENTRO da célula. A linha-mãe de uma
   GAVETA aberta ganha o fundo de seleção e o filete dourado de 3px; a gaveta é a linha-filha do kit (--papel-fundo, padding 12px 16px,
   filete embaixo) e os blocos .gaveta-fatos/.gaveta-obs/.gaveta-acoes estão disponíveis (a galeria os mostra). */
.ui-table-viewport {
  overflow: auto; width: 100%; border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface); box-shadow: var(--sh-1);
  scrollbar-width: thin; scrollbar-color: var(--line-hi) transparent;
}
.ui-table-viewport::-webkit-scrollbar { width: 8px; height: 8px; }
.ui-table-viewport::-webkit-scrollbar-track { background: transparent; }
.ui-table-viewport::-webkit-scrollbar-thumb { background: var(--line-hi); border-radius: 999px; border: 2px solid transparent; background-clip: content-box; }
.ui-table-viewport::-webkit-scrollbar-thumb:hover { background: var(--fg-3); background-clip: content-box; }
.ui-table { width: 100%; border-collapse: separate; border-spacing: 0; font-size: 14px; font-variant-numeric: tabular-nums; }
.ui-table th {
  position: sticky; top: 0; z-index: 5; background: var(--th-bg); text-align: left;
  font-size: 12px; font-weight: 600; letter-spacing: .07em; text-transform: uppercase;
  color: var(--th-fg); padding: 9px 12px; border-bottom: 1px solid var(--th-bg);
  cursor: pointer; user-select: none; white-space: nowrap;
}
.ui-table th.ui-num { text-align: right; }
.ui-table th[tabindex="-1"] { cursor: default; }
.ui-table th[tabindex="0"]:hover { text-decoration: underline; text-underline-offset: 3px; }
.ui-seta-ord { font-size: 8.5px; margin-left: 4px; opacity: .45; }
.ui-table th:hover .ui-seta-ord { opacity: 1; }
.ui-table th:focus-visible { outline: 2px solid var(--action-line); outline-offset: -2px; }
.ui-table th[aria-sort] { color: var(--brass-hi); }
.ui-table th[aria-sort] .ui-seta-ord { opacity: 1; }
.ui-table td { padding: 10px 12px; text-align: left; border-top: 1px solid var(--border); color: var(--fg-2); vertical-align: top; }
.ui-table td.ui-num { text-align: right; }
.ui-table tbody tr:first-child td { border-top: 0; }
.ui-table tbody tr:hover > td { background: var(--surface-2); }
@media (min-width: 900px) {
  .ui-table td { padding: 8px 12px; }
  .ui-table th { padding: 7px 12px; }
}
.ui-table-cel-exp { display: flex; gap: 8px; align-items: flex-start; }
.ui-table-cel-txt { min-width: 0; }
.ui-table-abre, .ui-table-abre-vazio {
  flex: none; width: 26px; height: 26px; margin-top: -2px;
  display: flex; align-items: center; justify-content: center;
}
/* o botão de abrir a gaveta (camada 3b; o .btn-gaveta do kit): o chevron "seta" de icons.js, SEM caixa em repouso, que gira 90 graus
   quando a linha está aberta e ganha o contorno dourado (--action-line, 3,58:1) e o texto de ação. Sem icons.js (a galeria dos testes,
   o harness_ui) o botão sai vazio e o ::before desenha o ▸/▾ de antes (`:empty`). Alvo de toque de 44px sem engordar a linha: o ::after. */
.ui-table-abre {
  position: relative; border: 1px solid transparent; border-radius: var(--radius); background: none;
  color: var(--fg-3); cursor: pointer; padding: 0; font-size: 12px; line-height: 1;
  transition: background var(--t) var(--ease), border-color var(--t) var(--ease), color var(--t) var(--ease);
}
.ui-table-abre::after { content: ""; position: absolute; inset: -10px; }   /* 24px do miolo + 2x10px = 44px de alvo de toque */
.ui-table-abre svg { width: 16px; height: 16px; transition: transform var(--t) var(--ease); }
.ui-table-abre:empty::before { content: "▸"; }
.ui-table-abre:hover { background: var(--surface-2); color: var(--fg); }
.ui-table-abre[aria-expanded="true"] { color: var(--action-text-hi); border-color: var(--action-line); }
.ui-table-abre[aria-expanded="true"] svg { transform: rotate(90deg); }
.ui-table-abre[aria-expanded="true"]:empty::before { content: "▾"; }
.ui-table-abre:active { background: var(--surface-2); }
.ui-table-abre:focus-visible { outline: 2px solid var(--action-line); outline-offset: 1px; }
.ui-table-row--selecionado td { background: var(--surface-2); }
.ui-table-row--selecionado td:first-child { box-shadow: inset 3px 0 0 var(--action-line); }
.ui-table-row--atencao td:first-child { box-shadow: inset 3px 0 0 var(--warn); }
.ui-table-row--erro td:first-child { box-shadow: inset 3px 0 0 var(--danger); }
/* registro FECHADO (frente AA, 15/10/2026: nota do recebimento já lançada, finalizada, arquivada, cancelada ou recusada): o texto da linha
   apaga para o olho pular; o tom do estado fica na célula do status da tela, nunca em outro badge */
.ui-table-row--fechado td { color: var(--fg-3); }
.ui-table .ui-table-row--fechado .tk-nome { color: var(--fg-3); font-weight: 450; }
/* correlação NF × OC (recebimento): 5º tom, o hover genérico não pode
   apagar o realce (mesmo raciocínio de style.css:1339-1341).
   Achado ao usar de verdade (Fase 4/LOTE2, NF): ".ui-table-row--correlacionado:hover
   td" (2 classes/pseudo + 1 elemento) tem MENOS especificidade que ".ui-table
   tbody tr:hover td" (2 + 3 elementos) — o hover genérico vencia mesmo
   assim. Cadeia completa (".ui-table tbody tr.-- td") empata na cadeia de
   elementos e ganha na classe. */
.ui-table-row--correlacionado td { background: var(--accent-dim); }
.ui-table-row--correlacionado td:first-child { outline: 2px solid var(--action-line); outline-offset: -2px; }
.ui-table tbody tr.ui-table-row--correlacionado:hover td { background: var(--accent-dim); }
/* A LINHA-MÃE da gaveta aberta (camada 3b; o .linha-item.com-gaveta do kit): fundo de seleção (--action-dim, o --selecao frio) e o filete
   dourado de 3px à esquerda, igual ao --selecionado. Dois caminhos, em REGRAS SEPARADAS (um seletor que o navegador não entende derruba a
   regra inteira): a classe `ui-table-row--com-gaveta`, que UI.dataTable põe na linha aberta (vale em qualquer navegador), e o :has() para a
   tela que alterna o botão no lugar, sem repintar a tabela (o "Ajustar" do Pedido: aria-expanded muda, a classe não). O hover não apaga. */
.ui-table tbody tr.ui-table-row.ui-table-row--com-gaveta > td { background: var(--action-dim); }
.ui-table tbody tr.ui-table-row.ui-table-row--com-gaveta > td:first-child { box-shadow: inset 3px 0 0 var(--action-line); }
.ui-table tbody tr.ui-table-row:has([data-toggle][aria-expanded="true"]) > td { background: var(--action-dim); }
.ui-table tbody tr.ui-table-row:has([data-toggle][aria-expanded="true"]) > td:first-child { box-shadow: inset 3px 0 0 var(--action-line); }
/* `>` (filho direto) nas 3 regras de linha — hover acima e as 2 da linha
   expandida aqui: a linha expandida pode trazer OUTRO dataTable dentro
   (instância recursiva, spec da Fase 3 §6; Fase 4 — Pedido, aba Trocas: as
   sugestões de troca). Com seletor de descendente, as células da tabela
   de dentro herdavam o padding/fundo da gaveta e o hover
   da linha de fora. Para toda tabela sem aninhamento o efeito é idêntico
   (<td> é sempre filho direto do <tr>), e a especificidade não muda.
   Camada 3b: a gaveta é a .linha-gaveta do kit — fundo --papel-fundo (a "faixa dentro da folha"), padding 12px 16px, SEM filete de
   cima e o filete --border embaixo. */
.ui-table-drawer > td { border-top: 0; border-bottom: 1px solid var(--border); padding: 12px 16px; background: var(--papel-fundo); }
.ui-table tr.ui-table-drawer:hover > td { background: var(--papel-fundo); }
.ui-table tbody tr.ui-table-drawer:last-child > td { border-bottom: 0; }
/* tabela DENTRO da linha expandida: cabeçalho fixo (sticky) perderia a
   disputa de z-index com o cabeçalho fixo da tabela de fora ao rolar (mesmo
   z-index, e a de dentro vem depois no DOM — pintava por cima); e a caixa
   de dentro não leva a sombra de repouso da de fora (seria "card dentro de
   card"). */
.ui-table-drawer .ui-table th { position: static; }
.ui-table-drawer .ui-table-viewport { box-shadow: none; }
/* camada 4a: a GAVETA NA LARGURA DA JANELA. O td da gaveta (colspan = todas as colunas) tem a largura da TABELA, e numa tabela mais larga
   que o viewport (a que rola de lado: 9 colunas a 390px) o conteúdo da gaveta ficava espalhado pela largura inteira, com só a 1ª coluna
   dos fatos à vista. Quando o viewport rola (UI.rolagem põe --scroll-r/-l e grava --ui-vp-w = a largura VISÍVEL; ui.js §17), o bloco de
   dentro da gaveta (o filho direto do td: .gaveta, .tk-caixa...) fica sticky à esquerda (16px = o padding do td) e limita-se a essa
   largura menos os 2x16px de respiro: acompanha a janela enquanto a tabela rola por baixo. Tabela que cabe: nenhuma das duas classes,
   nenhuma regra, nenhuma mudança.
   EXCEÇÃO (revisão de 03/11/2026): a gaveta das Trocas (.tk-caixa.pd-sug) carrega uma UI.dataTable ANINHADA de 7 colunas (~650px). Com o sticky e o
   max-width a tabela de dentro passava a rolar sozinha e o botão "Usar" (a última coluna) ficava fora da janela, sem a grade de fora poder levá-lo à
   vista (a gaveta deixa de acompanhar a rolagem de fora). Essa gaveta fica na largura da grade, como antes da 4a: a grade de fora rola e o "Usar"
   aparece. A 4b decide se a tabela aninhada vira rolagem própria (com pista) ou colunas empilhadas. */
.ui-table-viewport--scroll-r .ui-table-drawer > td > :not(.pd-sug),
.ui-table-viewport--scroll-l .ui-table-drawer > td > :not(.pd-sug) { position: sticky; left: 16px; max-width: calc(var(--ui-vp-w) - 32px); }
.ui-table-vazio { text-align: center; color: var(--fg-3); padding: 22px; }
.ui-table-vazio .ui-empty { padding: 0; }
.ui-table-vazio .vazio-ancora { display: none; }   /* camada 3a: o vazio dentro da célula é a frase só (sem âncora) */

/* O CONTEÚDO da gaveta (camada 3b; .gaveta, .gaveta-fatos, .fato, .gaveta-obs e .gaveta-acoes do kit, §11): classes disponíveis para a
   tela que monta o corpoExpandido. Os fatos são uma grade de rótulo (12px, --fg-3) em cima e valor (14px, --fg) embaixo, 200px por
   coluna, que quebra sozinha; a observação é uma linha de 13px com o rótulo apagado; as ações moram embaixo, separadas por um filete. */
.gaveta { max-width: 1180px; font-size: 14px; }
.gaveta-fatos { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 10px 24px; margin: 0; }
/* camada 4a: no TC22 a gaveta tem a largura da janela (uns 326px úteis a 390px: a regra acima, de 200px por coluna, daria UMA só) — duas colunas fixas */
@media (max-width: 899px) { .gaveta-fatos { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px 16px; } }
.gaveta .fato { margin: 0; min-width: 0; }
.gaveta .fato dt { font-size: 12px; color: var(--fg-3); }
.gaveta .fato dd { margin: 0; font-size: 14px; color: var(--fg); overflow-wrap: anywhere; }
.gaveta-obs { margin-top: 10px; font-size: 13px; color: var(--fg-2); }
.gaveta-obs span { margin-right: 8px; color: var(--fg-3); }
.gaveta-acoes { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--border); }

/* ============================================================ 7 — statusBadge
   CAMADA 3a (30/10/2026; §10 do guia do kit): CARIMBO = texto + um quadrado de 8px na frente (::before, a cor do estado em
   --marcador), sem pílula, sem borda e sem fundo — o mesmo desenho do .badge de style.css. Mapa: --erro -> --danger, --atencao ->
   --warn (com o texto em --warn-text), --ok -> --ok, --neutro e --mais -> --neutro (do kit; texto --fg-3). 12px/600, altura mínima
   de 20px, sem quebra de linha (.ui-badge.occ-selo, em style.css, é o que pode). Nunca mais de 1 badge
   visível por linha (mais o "+N" agregado).
   Caixa NORMAL, sem tracking (revisão independente do visual-lote1,
   24/09/2026): o `text-transform: uppercase` + `letter-spacing` que havia
   aqui contrariava o DESIGN.md ("em badge é peso e cor, não caixa alta") e
   fazia o mesmo dado sair "FORA DA NOTA" na tabela do computador e "fora da
   nota" no .badge do TC22. Vale para o app inteiro — o texto sai como quem
   chama escreveu. */
.ui-badge {
  display: inline-flex; align-items: center; gap: 6px; min-height: 20px; padding: 0;
  margin-left: 7px; vertical-align: 2px; font-size: 12px; font-weight: 600; line-height: 1.3;
  color: var(--fg); white-space: nowrap; --marcador: var(--neutro);
}
.ui-badge::before { content: ""; display: inline-block; flex: none; width: 8px; height: 8px; background: var(--marcador); }
.ui-badge--erro { --marcador: var(--danger); }
.ui-badge--atencao { color: var(--warn-text); --marcador: var(--warn); }
.ui-badge--ok { --marcador: var(--ok); }
.ui-badge--neutro { color: var(--fg-3); --marcador: var(--neutro); }
.ui-badge--mais { cursor: default; color: var(--fg-3); --marcador: var(--neutro); }
.ui-badge--mais:focus-visible { outline: 2px solid var(--action-line); outline-offset: 1px; }

/* ============================================================ 8 — callout
   Mostra só o mais grave (dos não-fixos) + "+N avisos"; fixos sempre
   visíveis, um bloco por item. Cores nos tokens semânticos de tokens.css
   (--danger-bg/--warn-bg/--ok-bg) — eram cor solta com RGB da paleta ANTIGA,
   fixo nos dois temas (achado da revisão independente, 22/09/2026: no
   escuro saía com o contraste da paleta claro, porque nunca seguia a
   redefinição de tema). */
/* CAMADA 3a (30/10/2026; §15 do guia do kit): a NOTA do kit, a mesma dos .msg-* de style.css — fundo do estado, sem borda nos
   quatro lados, FILETE ESQUERDO de 3px na cor do estado, raio --radius, padding de 10px 12px; o ícone fica (16px, cor do estado). */
.ui-callout { display: flex; gap: 10px; border: 0; border-left: 3px solid var(--fg-3); border-radius: var(--radius); padding: 10px 12px; margin: 11px 0; font-size: 14.5px; line-height: 1.4; }
.ui-callout .ico { flex: none; width: 16px; height: 16px; margin-top: 2px; }
.ui-callout--erro { background: var(--danger-bg); border-left-color: var(--danger); color: var(--fg-erro); }
.ui-callout--erro .ico { color: var(--danger); }
.ui-callout--atencao { background: var(--warn-bg); border-left-color: var(--warn); color: var(--warn-text); }
.ui-callout--atencao .ico { color: var(--warn-text); }
.ui-callout--ok { background: var(--ok-bg); border-left-color: var(--ok); color: var(--fg-ok); }
.ui-callout--ok .ico { color: var(--fg-ok); }
/* info é NEUTRO, não cor de ação (régua do dono, 22/09/2026, revisão pós-
   Onda 1 de tokens): --accent-dim (e o --accent-hi, que saiu na camada 4a) são ALIAS do dourado de
   ação (tokens.css), e um fundo tingido de dourado em "isto é só uma nota"
   lia como se fosse seleção/link. Só erro/atenção/ok têm cor; texto em
   --fg (não --fg-3, que fica só no ícone — texto de nota precisa ler igual
   ao resto do corpo). */
.ui-callout--info { background: var(--surface-2); border-left-color: var(--fg-3); color: var(--fg); }
.ui-callout--info .ico { color: var(--fg-3); }
.ui-callout-mais { margin: 6px 0; font-size: 13px; }
.ui-callout-mais summary { cursor: pointer; color: var(--fg-3); font-weight: 600; padding: 4px 0; list-style: none; }
.ui-callout-mais summary::-webkit-details-marker { display: none; }
.ui-callout-mais summary::before { content: "▸ "; }
.ui-callout-mais[open] summary::before { content: "▾ "; }
.ui-callout-mais .ui-callout { margin: 8px 0 0; }

/* ============================================================ 9 — emptyState
   Frase + botão, sem borda tracejada nem ícone grande.
   CAMADA 3a (30/10/2026; §16 do guia do kit): o vazio do kit — padding de 44px 20px, a ÂNCORA da marca em --border acima (o
   marcaAncora(40, "vazio-ancora") de icons.js: o desenho de linha que o kit usa no "nada aqui"), título de 15px/600 em --fg,
   texto de 13,5px em --fg-3 até 56ch e a próxima ação numa linha centralizada. O UI.emptyState desenha a âncora sozinho quando
   icons.js está carregado (todo "nada aqui", que nunca é erro; `marca: false` a tira) e aceita um `titulo`. Na célula de uma
   tabela (.ui-table-vazio) o vazio é compacto: sem âncora, sem padding. Os .vazio* abaixo são as classes do kit, para a tela que
   monta o vazio à mão (camada 4); .vazio.erro leva o quadrado vermelho dos carimbos na frente (o erro NÃO leva a âncora). */
.ui-empty, .vazio-marca { display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 44px 20px; text-align: center; }
.ui-empty p, .vazio-texto { max-width: 56ch; margin: 0; font-size: 13.5px; line-height: 1.55; color: var(--fg-3); }
.ui-empty .vazio-titulo, .vazio-titulo { font-size: 15px; font-weight: 600; line-height: 1.35; color: var(--fg); }
.vazio-ancora { display: inline-flex; margin-bottom: 6px; color: var(--border); }
.vazio-acao { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; margin-top: 12px; }
.ui-empty .ui-btn { margin: 0; }
.vazio { padding: 20px 4px; text-align: center; color: var(--fg-3); }
.vazio.erro { color: var(--fg); }
.vazio.erro::before { content: ""; display: inline-block; width: 8px; height: 8px; margin-right: 8px; background: var(--danger); vertical-align: 1px; }

/* ============================================================ 10 — button
   Primário/secundário/perigo/texto × 2 tamanhos, sem escopo de contêiner.
   CAMADA 3a (30/10/2026; §13 do guia do kit): as mesmas variantes do .btn de style.css — base de folha com borda
   --border-interactive, hover --surface-2, :active desce 1px, desabilitado a 50%; primário = .btn-prim (navy), secundário =
   .btn-sec (folha + borda forte), texto = .btn-ter (transparente), perigo = .btn-perigo (transparente, borda e texto --danger).
   Alturas do coletor: 52px (normal) e 44px (pequeno) no TC22; a partir de 900px, 40px e 32px. Ícone dentro: 16px. */
.ui-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  border: 1px solid var(--border-interactive); border-radius: var(--radius); background: var(--surface); color: var(--fg);
  font-family: var(--font); font-weight: 600; font-size: 15px; letter-spacing: -0.01em;
  padding: 0 16px; cursor: pointer;
  transition: background var(--t) var(--ease), border-color var(--t) var(--ease), box-shadow var(--t) var(--ease);
}
.ui-btn .ico { width: 16px; height: 16px; }
.ui-btn--normal { min-height: 52px; }
.ui-btn--pequeno { min-height: 44px; padding: 0 14px; font-size: 14px; }
@media (min-width: 900px) { .ui-btn--normal { min-height: 40px; } .ui-btn--pequeno { min-height: 32px; padding: 0 12px; } }
.ui-btn--full { width: 100%; }
.ui-btn:not(:disabled):hover { background: var(--surface-2); }
.ui-btn:not(:disabled):active { background: var(--surface-2); transform: translateY(1px); }
.ui-btn:focus-visible { outline: 2px solid var(--action-line); outline-offset: 2px; }
.ui-btn:disabled { opacity: .5; cursor: not-allowed; }
/* [hidden] precisa vencer o display:inline-flex acima — sem esta linha o
   atributo nativo NÃO esconde o botão (regra "botão de lote só aparece
   quando vale", DESIGN.md; 1º uso: rodapé da aba Compra do Pedido). */
.ui-btn[hidden] { display: none; }
/* primário: navy + texto claro (decisão já tomada) — nos tokens ATUAIS usa
   --ink/--on-ink até a Onda 1 trocar (a spec explica: --navy ainda não
   existe). */
.ui-btn--primario { background: var(--navy); border-color: var(--navy); color: var(--on-navy); }
.ui-btn--primario:not(:disabled):hover { background: var(--navy-hi); border-color: var(--navy-hi); }
.ui-btn--primario:not(:disabled):active { background: var(--navy-hi); }
.ui-btn--primario:focus-visible { outline-color: var(--brass-hi); }
/* secundário = .btn-sec do kit: folha + borda forte (antes: transparente com borda de divisória) */
.ui-btn--secundario { background: var(--surface); border-color: var(--border-interactive); color: var(--fg); }
.ui-btn--secundario:not(:disabled):hover { background: var(--surface-2); }
/* perigo = .btn-perigo do kit: transparente, borda e texto --danger, fundo --danger-bg no hover (antes: cheio em --danger com
   brightness no hover). O confirmar cheio de um diálogo de perigo é do modal (camada 3b). */
.ui-btn--perigo { background: transparent; border-color: var(--danger); color: var(--danger); }
.ui-btn--perigo:not(:disabled):hover { background: var(--danger-bg); border-color: var(--danger); }
.ui-btn--texto { background: transparent; border-color: transparent; color: var(--action-text); padding: 0 4px; min-height: 0; }
.ui-btn--texto:not(:disabled):hover { text-decoration: underline; background: transparent; }
/* camada 4a (02/11/2026): o botão de TEXTO no TC22. O `min-height: 0` acima vencia o 44px/52px do tamanho (vem depois no arquivo) e o deixava com a altura
   da linha (~17px, o "17px" que a camada 3b registrou: a altura, e não a fonte; antes da 3a já era assim): alvo de toque de 44px, e a fonte sobe para os
   16px do corpo do coletor (era 15px, ou 14px no .pequeno). Na mesa nada muda (continua sem altura própria: é link). */
@media (max-width: 899px) { .ui-btn--texto { font-size: 16px; min-height: 44px; } }
/* perigo-suave (25/09/2026): ação destrutiva secundária — texto, ícone e
   borda em --danger, SEM fundo vermelho. Desde a camada 3a o --perigo também é assim (o kit só tem um perigo): os dois ficam
   idênticos e o nome continua porque as telas já o usam (harness_negociacao G20). Mesmo tom do .inv-acoes .btn-sec.perigo. */
.ui-btn--perigo-suave { background: transparent; border-color: var(--danger); color: var(--danger); }
.ui-btn--perigo-suave:not(:disabled):hover { background: var(--danger-bg); border-color: var(--danger); }
@media (min-width: 900px) { .shell.largo .ui-btn--pequeno { min-height: 32px; padding: 4px 10px; } }   /* camada 3a: eram 26px; o piso do mini na mesa é 32px */

/* botão-ícone único fora da topbar: 28px de miolo no computador, alvo de
   toque ≥44px no TC22, sempre com foco (corrige .pop-x/.btn-pontos, que
   hoje não têm :focus-visible). */
.ui-icon-btn {
  width: 44px; height: 44px; display: inline-flex; align-items: center; justify-content: center;
  background: transparent; border: 1px solid transparent; border-radius: var(--r-sm);
  color: var(--fg-3); cursor: pointer; padding: 0;
  transition: background var(--t) var(--ease), border-color var(--t) var(--ease), color var(--t) var(--ease);
}
.ui-icon-btn:hover { color: var(--fg); border-color: var(--line-hi); background: var(--surface-2); }
.ui-icon-btn:focus-visible { outline: 2px solid var(--action-line); outline-offset: 1px; }
.ui-icon-btn--perigo { color: var(--danger); }
.ui-icon-btn--perigo:hover { background: var(--danger-bg); border-color: var(--danger); }
@media (min-width: 900px) { .ui-icon-btn { width: 28px; height: 28px; } }
/* dentro da topbar o tamanho/tema é o outro (§1) — nunca os 28/44px daqui */
.topbar .ui-icon-btn { width: 44px; height: 44px; }
@media (min-width: 900px) { .topbar .ui-icon-btn { width: 44px; height: 44px; } }

/* ============================================================ 11 — input/select
   Rótulo acessível sempre; erro com aria-invalid + borda + texto visível. */
.ui-label { display: block; font-size: 12.5px; color: var(--fg-2); font-weight: 550; margin: 12px 0 4px; }
.ui-field { position: relative; display: flex; align-items: center; }
.ui-field--icone .ico { position: absolute; left: 14px; color: var(--fg-3); pointer-events: none; }
.ui-field--icone .ui-input { padding-left: 44px; }
/* CAMADA 3b (30/10/2026; §8.2 do guia do kit): o campo é o .inp do kit — borda de 1px em --border-interactive (3,5:1; o filete --border de
   antes era divisória, 1,3:1: o campo não se achava na folha), canto --radius, fundo --surface, hover com a borda em --fg-3, foco com a
   borda e UM anel de 1px em --action-line (o halo de 3px em tom de seleção saiu), placeholder --fg-3 e a seta do select em --seta-select.
   ALTURAS: TC22 como sempre (17px de fonte e 14px de respiro: 48px, bem acima dos 44 de toque); na mesa o `.ui-input`/`.ui-select` caem
   para 36px (o kit mede 34: o --h-controle). Os campos de QUANTIDADE e de CÓDIGO do coletor (.tk-qtd, .st-qtd, .goc-preco, o input do
   modal de quantidade...) têm classe e regra próprias em style.css e NÃO mudam de altura nem de fonte. */
.ui-input, .ui-select {
  width: 100%; background: var(--surface); color: var(--fg);
  border: 1px solid var(--border-interactive); border-radius: var(--radius);
  font-family: var(--font); font-size: 17px; padding: 14px;
  transition: border-color var(--t) var(--ease), box-shadow var(--t) var(--ease);
}
textarea.ui-input { resize: vertical; min-height: 76px; line-height: 1.45; }
.ui-input:hover:not(:focus):not(:disabled), .ui-select:hover:not(:focus):not(:disabled) { border-color: var(--fg-3); }
.ui-input:focus, .ui-select:focus { outline: none; border-color: var(--action-line); box-shadow: 0 0 0 1px var(--action-line); }
.ui-input:disabled, .ui-select:disabled { opacity: .6; cursor: not-allowed; }
.ui-input::placeholder { color: var(--fg-3); }
.ui-input[aria-invalid="true"], .ui-select[aria-invalid="true"] { border-color: var(--danger); }
.ui-field-erro { margin-top: 6px; font-size: 12.5px; color: var(--danger); }
.ui-field--numerico .ui-input { height: 34px; padding: 0 8px; text-align: right; font-size: 14px; font-variant-numeric: tabular-nums; }
.ui-select {
  appearance: none;
  background-image: var(--seta-select);
  background-repeat: no-repeat; background-position: right 14px center; padding-right: 38px;
}
/* `input.ui-input` e `select.ui-select` (0,1,1): o `input[type=text]` global de style.css (16px, padding 12px: 45px) tem a mesma especificidade e vem ANTES (ui.css carrega depois),
   enquanto a classe sozinha (0,1,0) perdia para ele e o campo da mesa ficava nos 45px do TC22 */
@media (min-width: 900px) {
  input.ui-input, select.ui-select { min-height: 36px; padding: 7px 12px; font-size: 14px; }
  select.ui-select { padding-right: 34px; background-position: right 12px center; }
  .ui-field--icone input.ui-input { padding-left: 40px; }
}
/* a dica do campo (camada 3b; .dica-campo do kit): 12px/450 em --fg-3, quebra em vez de cortar; a `dica-alerta` (o aviso que o campo
   pede para ler) vira --warn-text em 600 e leva o MARCADOR quadrado de 8px (--warn) na frente, como o carimbo; `dica-marcada` leva só o
   marcador, com o texto no tom normal. */
.dica-campo { font-size: 12px; font-weight: 450; line-height: 1.4; color: var(--fg-3); overflow-wrap: anywhere; }
.dica-campo.dica-alerta { color: var(--warn-text); font-weight: 600; }
.dica-campo.dica-marcada::before, .dica-campo.dica-alerta::before {
  content: ""; display: inline-block; width: 8px; height: 8px; margin-right: 6px; background: var(--warn); vertical-align: 0;
}

/* ============================================================ 12 — tabs
   Diferente de filterChips: troca o painel de conteúdo. Reproduz .pd-abas
   (sublinhado 2px em --accent na aba ativa), sem roving tabindex/setas
   (simplificação aceita na revisão 2 da spec — Tab normal entre botões). */
.ui-tabs { display: flex; gap: 2px; margin: 0 0 12px; box-shadow: inset 0 -1px 0 var(--border); max-width: 100%; overflow-x: auto; overflow-y: hidden; scrollbar-width: none; }
.ui-tabs::-webkit-scrollbar { display: none; }
/* CAMADA 3b (30/10/2026; §ABAS do guia do kit, .aba/.aba.ativa): texto de 14px/600, SEM caixa, a aba ativa em --fg com o sublinhado de 2px em
   --action-line (o dourado do indicador, 3,58:1; o --brass puro dá 2,43:1) — o mesmo da .pd-abas e do harness_tokens (l). 44px de altura no
   TC22 (o dedo), 40px na mesa. O CONTADOR é um número em --fg sobre --surface-2 (canto --radius), igual na aba ativa e nas outras:
   o --accent cheio (o dourado de preenchimento) saiu — a aba ativa já se lê pelo texto e pelo sublinhado. Foco por dentro, em --action-line.
   O FILETE do contêiner (1px --border) é um box-shadow inset, e não um border-bottom: com o border + margin-bottom: -1px nos botões, o último px do
   sublinhado de 2px caía FORA da caixa de preenchimento e o overflow-y: hidden o recortava (a aba ativa saía com 1px de dourado; achado da revisão
   de 02/11/2026, medido em pixels pintados). Agora o sublinhado e o filete dividem a última linha do contêiner, sem recorte. */
.ui-tabs button {
  background: none; border: 0; border-bottom: 2px solid transparent;
  min-height: 44px; padding: 10px 14px; cursor: pointer; font-family: var(--font); font-size: 14px;
  font-weight: 600; letter-spacing: .01em; color: var(--fg-3); white-space: nowrap; flex: none;
  display: inline-flex; align-items: center; gap: 7px;
  transition: color var(--t) var(--ease), border-color var(--t) var(--ease);
}
.ui-tabs button:hover { color: var(--fg); }
.ui-tabs button[aria-selected="true"] { color: var(--fg); border-bottom-color: var(--action-line); }
.ui-tabs button:focus-visible { outline: 2px solid var(--action-line); outline-offset: -2px; }
.ui-tabs-n { font-size: 12px; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--fg); background: var(--surface-2); border-radius: var(--radius); padding: 1px 7px; }
@media (min-width: 900px) { .ui-tabs button { min-height: 40px; } }

/* ============================================================ 13 — actionFooter
   O primário e os secundários (antes dele) — nunca 3 full-width empilhados na mesa. TC22: empilha em coluna, primário sempre no topo.
   Mesa (>= 700px, camada 3b): uma linha ALINHADA À DIREITA (.campo-acao do kit), botões na largura natural (ver o bloco da 3b logo abaixo). */
.ui-footer { display: flex; flex-direction: column-reverse; gap: 8px; margin-top: 10px; }
.ui-footer-esq { display: flex; gap: 8px; }
.ui-footer-esq .ui-btn { flex: 1; }
.ui-footer-dir .ui-btn { width: 100%; }
/* CAMADA 3b (30/10/2026; .campo-acao do kit, §8.2): na MESA o rodapé é uma linha ALINHADA À DIREITA, gap de 8px, os secundários antes do
   primário e todos na largura natural do rótulo (antes: secundários na ponta esquerda e o primário na direita, com o vão no meio). No TC22
   segue em coluna (o primário no topo, como sempre foi: column-reverse) com os botões de largura inteira. O grupo dos secundários vazio
   (só há o primário) não ocupa lugar: sem o :empty ele ainda somava um gap de 8px à esquerda. */
.ui-footer-esq:empty { display: none; }
@media (min-width: 700px) {
  .ui-footer { flex-direction: row; justify-content: flex-end; align-items: center; }
  .ui-footer-esq .ui-btn, .ui-footer-dir .ui-btn { width: auto; flex: none; min-height: 36px; padding: 0 18px; font-size: 14px; }
}

/* ============================================================ 14 — drawer
   Lista de links, sem botões cinza com ícone (corrige .drawer-foot de hoje).
   Mesma largura/comportamento do menu lateral atual (300px/82vw). */
.ui-drawer {
  width: 300px; max-width: 82vw; height: 100%;
  background: var(--surface); border-right: 1px solid var(--line);
  display: flex; flex-direction: column; box-shadow: var(--sh-3);
}
.ui-drawer-marca { display: flex; align-items: center; gap: 10px; padding: 16px 18px 14px; }
.ui-drawer-marca img { height: 22px; width: auto; }
.ui-drawer-marca-txt { font-weight: 700; font-size: 13px; letter-spacing: .04em; }
.ui-drawer-user {
  display: flex; align-items: center; gap: 12px; margin: 0 12px 4px; padding: 14px;
  border-radius: var(--r-sm); background: var(--ink); color: var(--on-ink); border: 1px solid var(--ink-line);
}
.ui-drawer-avatar {
  width: 40px; height: 40px; flex: none; border-radius: var(--r-pill);
  background: var(--avatar-bg-dim); border: 1px solid var(--ink-line); color: var(--brass-hi);
  display: flex; align-items: center; justify-content: center; font-weight: 600; font-size: 17px;
}
.ui-drawer-user-nome { font-weight: 600; font-size: 15px; }
.ui-drawer-user-filial { font-size: 12px; color: var(--on-ink-2); margin-top: 2px; }
.ui-drawer-trocar {
  background: none; border: 0; padding: 0 0 0 2px; color: var(--brass-hi); font-family: var(--font);
  font-size: 12px; font-weight: 600; cursor: pointer; text-decoration: underline; text-underline-offset: 2px;
}
.ui-drawer-trocar:hover { color: var(--on-ink); }
.ui-drawer-body { flex: 1; padding: 10px 12px 4px; overflow-y: auto; }
.ui-drawer-secao { font-size: 10.5px; font-weight: 600; letter-spacing: .12em; text-transform: uppercase; color: var(--fg-3); margin: 14px 2px 8px; }
.ui-drawer-stat { padding: 0 2px; }
.ui-drawer-stat-linha { display: flex; align-items: center; justify-content: space-between; gap: 10px; font-size: 12.5px; padding: 5px 0; }
.ui-drawer-stat-k { color: var(--fg-3); }
.ui-drawer-stat-v { font-weight: 600; font-variant-numeric: tabular-nums; text-align: right; }
.ui-drawer-stat-v--ok { color: var(--fg-ok); }
.ui-drawer-stat-v--atencao { color: var(--warn-text); }
.ui-drawer-stat-v--erro { color: var(--danger); }
/* link do menu: texto + ícone opcional, SEM fundo cinza nem borda —
   generaliza .u-trocar para toda a lista */
.ui-drawer-link {
  display: flex; align-items: center; gap: 10px; width: 100%; min-height: 44px;
  padding: 10px 8px; border: 0; border-radius: var(--r-sm); background: transparent; color: var(--fg);
  font-family: var(--font); font-size: 14.5px; font-weight: 550; text-align: left; cursor: pointer;
  transition: background var(--t) var(--ease);
}
.ui-drawer-link:hover { background: var(--surface-2); }
.ui-drawer-link:focus-visible { outline: 2px solid var(--action-line); outline-offset: -2px; }
.ui-drawer-link .ico { color: var(--fg-3); flex: none; }
.ui-drawer-foot { padding: 12px; border-top: 1px solid var(--line); }
.ui-drawer-sair {
  display: flex; align-items: center; justify-content: center; gap: 9px; width: 100%;
  padding: 13px; border: 1px solid var(--line-btn); background: var(--surface-2); color: var(--fg);
  border-radius: var(--r-sm); font-family: var(--font); font-weight: 600; font-size: 14px; cursor: pointer;
}
.ui-drawer-sair:hover { background: var(--surface-3); }
.ui-drawer-sair:focus-visible { outline: 2px solid var(--action-line); outline-offset: 1px; }

/* ============================================================ 15 — modal
   2 tamanhos + variante formulário + variante espera. Mobile-first: ancorado
   embaixo, centraliza a partir de 700px (reproduz style.css:1447-1449). */
.ui-modal-bk {
  /* --scrim já existe (mesmo valor solto que drawer/modal usavam, agora
     token — achado da revisão independente, 22/09/2026) e já se adapta ao
     tema escuro (preto puro lá, era o mesmo azulado do claro aqui). */
  position: fixed; inset: 0; background: var(--scrim); z-index: 60;
  display: flex; align-items: flex-end; justify-content: center; padding: 14px;
  animation: fadein .2s var(--ease);
}
/* CAMADA 3b (30/10/2026; #modal do kit, §14): o UI.modal ganha a MESMA guarda geral do .modal-card (v224, 29/10/2026): a caixa nunca passa da
   janela (100vh menos os 14px de respiro do .ui-modal-bk de cada lado; dvh por cima, para o celular com a barra do navegador) e ROLA por dentro
   quando o conteúdo não cabe; o rodapé (.ui-footer) é STICKY: fica à vista rolando, com o fundo da caixa, sangrando até a borda (menos o
   --mpad, de volta como padding: a geometria de quem cabe sem rolar fica a mesma). A receita visual é a do kit: título de 16px/650 com um
   filete --border embaixo de ponta a ponta (o ::after, que NÃO soma altura: mora na margem do título, como o do .modal-card) e o texto de
   apoio de 13px em --fg-3. Foi um achado do dono em 29/10/2026 (o vínculo nascia com o rodapé fora da tela); o UI.modal tem 5 usos
   (ajuda, nota do Coletor, devolução ao fornecedor, contagem guardada, boletos) e nenhum deles estava coberto. */
.ui-modal {
  --mpad: 20px;
  position: relative; background: var(--surface); border: 1px solid var(--line-hi);
  border-radius: var(--radius-flutuante); padding: var(--mpad); width: 100%; max-width: 480px;
  max-height: calc(100vh - 28px); max-height: calc(100dvh - 28px); overflow-y: auto;
  box-shadow: var(--sh-3); animation: slideup .28s var(--ease); text-align: left;
}
.ui-modal--largo { max-width: 760px; }
.ui-modal--formulario { text-align: left; }
.ui-modal--espera { cursor: progress; max-width: 440px; text-align: center; }   /* camada 3b: o modal do kit é todo à esquerda (era centralizado); só a espera segue centralizada */
.ui-modal-x { position: absolute; z-index: 2; top: 10px; right: 10px; width: 30px; height: 30px; min-width: 0; min-height: 0; }   /* z-index: o título (position: relative, por causa do filete) vem depois do X no DOM e o cobriria */
/* camada 4a: alvo de toque de 44px no TC22 (o desenho segue 30x30): ::after de -8px (caixa de preenchimento de 28px + 2x8 = 44), o molde do chevron da gaveta (.ui-table-abre::after) */
@media (max-width: 899px) { .ui-modal-x::after { content: ""; position: absolute; inset: -8px; } }
.ui-modal-titulo { position: relative; font-weight: 650; font-size: 16px; letter-spacing: -0.01em; margin-bottom: 12px; padding-right: 34px; }
.ui-modal-titulo::after { content: ""; position: absolute; left: calc(var(--mpad) * -1); right: calc(var(--mpad) * -1); bottom: -6px; height: 1px; background: var(--border); }
.ui-modal-sub { color: var(--fg-3); font-size: 13px; line-height: 1.45; margin: 0 0 10px; }   /* o -6px de cima saiu: o filete do título mora nessa margem e o apoio encostava nele */
.ui-modal-corpo { max-height: 60vh; overflow-y: auto; }
.ui-modal--formulario .ui-modal-corpo { text-align: left; }
.ui-modal > .ui-footer { position: sticky; bottom: calc(var(--mpad) * -1); z-index: 1; background: var(--surface);
  margin: 10px calc(var(--mpad) * -1) calc(var(--mpad) * -1); padding: 0 var(--mpad) var(--mpad); }
.ui-modal > .ui-footer::before { content: ""; position: absolute; left: 0; right: 0; top: -8px; height: 8px; background: var(--surface); }
@media (min-width: 700px) { .ui-modal-bk { align-items: center; } }
@media (min-width: 900px) { .ui-modal { --mpad: 18px; } }   /* o respiro do #modal do kit na mesa (o TC22 segue com 20px); o padding, o filete do título e o rodapé sticky leem o --mpad */

/* ============================================================ 16 — details
   Bloco recolhível NATIVO (<details>/<summary>) para campo/filtro de uso
   raro dentro da PRÓPRIA tela — auditoria de design, 25/09/2026 (regra 9 do
   modelo de ações; DESIGN.md "Componentes"). Não é menu: nada flutua, o
   conteúdo abre no lugar, a 1 clique, com foco/teclado/leitor de tela do
   próprio navegador. Summary = linha de texto com chevron discreto (borda
   girada em --fg-3 — sem ícone, ui.css não depende de icons.js), caixa
   normal (peso e cor, não caixa alta — DESIGN.md/Tipografia), foco em
   --action-line como todo controle do app. Marcador nativo escondido nos
   dois motores (list-style + ::-webkit-details-marker). Toque ≥44px no
   TC22; 32px no computador. Marcação: UI.details (ui.js §16). */
.ui-details { border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); margin-top: 8px; }
.ui-details > summary {
  display: flex; align-items: center; gap: 8px; min-height: 44px; padding: 10px 12px;
  cursor: pointer; user-select: none; list-style: none; border-radius: var(--radius);
  font-size: 13px; font-weight: 600; color: var(--fg-2);
  transition: background var(--t) var(--ease), color var(--t) var(--ease);
}
.ui-details > summary::-webkit-details-marker { display: none; }
.ui-details > summary::before {
  content: ""; flex: none; width: 6px; height: 6px; margin: 0 4px 0 2px;
  border: solid var(--fg-3); border-width: 0 1.5px 1.5px 0;
  transform: translateY(-1px) rotate(-45deg);
  transition: transform .14s var(--ease);
}
.ui-details[open] > summary::before { transform: translateY(-2px) rotate(45deg); }
.ui-details > summary:hover { color: var(--fg); background: var(--surface-2); }
.ui-details > summary:focus-visible { outline: 2px solid var(--action-line); outline-offset: -2px; }
.ui-details[open] > summary { border-bottom: 1px solid var(--border); border-radius: var(--radius) var(--radius) 0 0; }
/* nota à direita do título ("2 filtros ativos"): visível também FECHADO —
   é como a tela avisa que há algo escolhido lá dentro sem obrigar a abrir */
.ui-details-nota { margin-left: auto; font-weight: 550; font-size: 12px; color: var(--fg-3); font-variant-numeric: tabular-nums; }
.ui-details-corpo { padding: 12px; }
/* dentro da barra de filtros (Torre: linha/navio/cliente recolhidos), o
   bloco ocupa a linha inteira ABAIXO de busca e chips — os frequentes
   continuam à vista, os raros abrem embaixo sem empurrar nada para o lado */
.ui-filterbar > .ui-details { flex: 1 1 100%; margin-top: 0; }
@media (min-width: 900px) {
  .shell.largo .ui-details > summary { min-height: 32px; padding: 6px 10px; }
  .shell.largo .ui-details-corpo { padding: 10px; }
}
@media (prefers-reduced-motion: reduce) { .ui-details > summary::before { transition: none; } }

/* ============================================================ 17 — rolagem lateral
   Indicador de rolagem HORIZONTAL em tabela larga (auditoria de design,
   25/09/2026 — regra 8: "toda tabela larga sinaliza rolagem"). Vale para
   .ui-table-viewport (UI.dataTable) E .tk-viewport (telas ainda não
   migradas). Quem liga/desliga as classes é UI.rolagem (ui.js §17), lendo
   scrollWidth/clientWidth/scrollLeft; aqui é só o desenho.

   Por que ::after com position:sticky, e não ::after absolute: um filho
   absoluto de um contêiner com overflow ROLA junto com o conteúdo — a
   sombra sairia da borda no primeiro arrasto. Sticky prende o pseudo-
   elemento à área VISÍVEL do próprio viewport: left:0 segura na borda
   esquerda visível (e a largura 100% do bloco termina exatamente na borda
   direita visível), bottom:0 segura embaixo. A altura é o clientHeight
   que UI.rolagem grava em --ui-sombra-alt (100vh antes do 1º cálculo), com
   margin-top negativa igual: cobre a área visível inteira de baixo para
   cima sem somar NADA ao scrollHeight (a caixa termina onde o conteúdo
   termina; o que sobra para cima de y=0 não é rolável). Um ::before no
   topo com o mesmo truque somaria a altura ao scrollHeight — por isso as
   DUAS sombras vivem no mesmo ::after, como duas camadas de background,
   ligadas pela largura (0 → 22px) para animar sem custo.
   pointer-events:none — nunca captura toque/clique/arrasto do conteúdo.
   z-index 6: um degrau acima dos <th> sticky (5, ui.css §6 e .tk-grid th) e
   no mesmo nível do canto Item da negociação (o ::after vem depois na
   árvore e pinta por cima). Cor: --scrim (véu de drawer/modal, já gira com
   o tema) atenuado pela opacity do pseudo-elemento — nenhum token novo.
   position:sticky é Chrome ≥ 56 — dentro do piso de suporte do TC22. */
.ui-table-viewport, .tk-viewport { --ui-sombra-esq: 0px; }
.ui-table-viewport::after, .tk-viewport::after {
  content: ""; display: block; position: sticky; left: 0; bottom: 0; z-index: 6;
  width: 100%; height: var(--ui-sombra-alt, 100vh); margin-top: calc(-1 * var(--ui-sombra-alt, 100vh));
  pointer-events: none; opacity: .35;
  background-image: linear-gradient(to right, var(--scrim), transparent), linear-gradient(to left, var(--scrim), transparent);
  background-repeat: no-repeat;
  background-position: var(--ui-sombra-esq) 0, right 0;
  background-size: 0 100%, 0 100%;
  transition: background-size .18s var(--ease);
}
.ui-table-viewport--scroll-l::after { background-size: 22px 100%, 0 100%; }
.ui-table-viewport--scroll-r::after { background-size: 0 100%, 22px 100%; }
.ui-table-viewport--scroll-l.ui-table-viewport--scroll-r::after { background-size: 22px 100%, 22px 100%; }
.ui-table-viewport[data-sem-sombra]::after, .tk-viewport[data-sem-sombra]::after { content: none; }
/* negociação: coluna Item fixa (sticky, 340px em style.css .ng-grid — era
   260 até a Frente 3, que pôs "venda · custo" na linha do rádio) — a sombra
   esquerda nasce na borda direita dela, não na borda do viewport */
.ng-viewport { --ui-sombra-esq: 340px; }
@media (prefers-reduced-motion: reduce) { .ui-table-viewport::after, .tk-viewport::after { transition: none; } }

/* ============================================================ 18 — barras
   Barra horizontal simples (Auditoria, 28/09/2026 — ui.js §19). Trilho em
   --surface-3 (mesmo tom neutro do "n" da aba/chip); o preenchimento é a
   ÚNICA cor da régua — navy (positivo) ou --danger (negativo), nunca as
   duas juntas na mesma barra. Sem sombra/raio novo: --radius-pill nos dois
   elementos, como qualquer trilho/pill do resto do app. */
.ui-barras { display: flex; flex-direction: column; gap: 10px; }
.ui-barra-item { display: flex; flex-direction: column; gap: 4px; }
.ui-barra-cab { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.ui-barra-rotulo { font-size: 13px; color: var(--fg); }
.ui-barra-sub { margin-left: 6px; font-size: 12px; color: var(--fg-3); }
.ui-barra-valor { font-size: 13px; font-weight: 600; color: var(--fg); font-variant-numeric: tabular-nums; white-space: nowrap; }
.ui-barra-trilho { height: 8px; border-radius: var(--radius-pill); background: var(--surface-3); overflow: hidden; }
.ui-barra-fill { height: 100%; border-radius: var(--radius-pill); }
.ui-barra-fill--positivo { background: var(--navy); }
.ui-barra-fill--negativo { background: var(--danger); }

/* ============================================================ 20 — multiSelect
   Escolha de VÁRIOS valores numa lista longa (frente W, 14/10/2026; ui.js §20).
   Botão com o resumo + popover ancorado embaixo dele. Valores só de
   tokens.css (nunca cor/raio/sombra soltos): raio --radius; contorno de campo
   --border-interactive (WCAG 1.4.11); DOURADO só para o que é seleção ou foco
   (borda do botão com escolha feita, caixa marcada, anel de foco) — o popover
   não cria um segundo botão primário (navy fica para o primário da tela).
   Sombra: o popover é elemento flutuante, o 5º lugar permitido pelo DESIGN.md
   (drawer, modal, toast, menu flutuante e este). z-index 30: acima do
   cabeçalho fixo das tabelas (5-7) e da topbar (20), abaixo do drawer (40). */
.ui-multi { position: relative; display: inline-block; flex: 0 1 auto; min-width: 0; max-width: 100%; }
.ui-multi-btn {
  display: inline-flex; align-items: center; gap: 8px; max-width: min(100%, 420px); min-height: 38px; padding: 0 10px 0 12px;
  border: 1px solid var(--border-interactive); border-radius: var(--radius);
  background: var(--surface); color: var(--fg);
  font-family: var(--font); font-size: 14px; font-weight: 450; text-align: left; cursor: pointer;
  transition: background var(--t) var(--ease), border-color var(--t) var(--ease);
}
.ui-multi-btn:hover { background: var(--surface-2); }
.ui-multi-btn:focus-visible { outline: 2px solid var(--action-line); outline-offset: 2px; }
.ui-multi--tem > .ui-multi-btn { border-color: var(--action-line); background: var(--action-dim); font-weight: 600; }
.ui-multi-resumo { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ui-multi-seta {
  flex: none; width: 6px; height: 6px; border: solid var(--fg-3); border-width: 0 1.5px 1.5px 0;
  transform: translateY(-2px) rotate(45deg); transition: transform .14s var(--ease);
}
.ui-multi-btn[aria-expanded="true"] .ui-multi-seta { transform: translateY(1px) rotate(-135deg); }
.ui-multi-pop {
  position: absolute; z-index: 30; top: calc(100% + 4px); left: 0; display: flex; flex-direction: column;
  width: 320px; max-width: calc(100vw - 32px);
  background: var(--surface); border: 1px solid var(--border-interactive); border-radius: var(--radius-flutuante);
  box-shadow: var(--shadow);
}
.ui-multi-pop[hidden] { display: none; }
.ui-multi-pop--dir { left: auto; right: 0; }
/* `.ui-multi ` na frente: o `input[type=search]` global de style.css (16px, padding 12, margin 8px 0) tem mais especificidade que uma classe só */
.ui-multi .ui-multi-busca { flex: none; width: calc(100% - 16px); height: 36px; min-height: 0; margin: 8px 8px 0; padding: 0 10px; font-size: 14px; }
.ui-multi-lista { max-height: min(320px, 50vh); overflow-y: auto; padding: 4px 0; overscroll-behavior: contain; }
.ui-multi-op {
  display: flex; align-items: center; gap: 10px; min-height: 36px; padding: 6px 12px;
  font-size: 14px; color: var(--fg); cursor: pointer; user-select: none;
}
.ui-multi-op[hidden] { display: none; }
.ui-multi-op:hover { background: var(--surface-2); }
.ui-multi-op:focus-visible { outline: 2px solid var(--action-line); outline-offset: -2px; }
.ui-multi-caixa {
  flex: none; position: relative; width: 18px; height: 18px;
  border: 2px solid var(--border-interactive); border-radius: var(--radius); background: var(--surface);
}
.ui-multi-op[aria-selected="true"] .ui-multi-caixa { background: var(--action); border-color: var(--action-line); }
.ui-multi-op[aria-selected="true"] .ui-multi-caixa::after {
  content: ""; position: absolute; left: 4px; top: 0; width: 5px; height: 10px;
  border: solid var(--sobre-accent); border-width: 0 2px 2px 0; transform: rotate(45deg);
}
.ui-multi-rot { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ui-multi-n { flex: none; font-size: 12px; color: var(--fg-3); font-variant-numeric: tabular-nums; }
.ui-multi-nada { padding: 12px; font-size: 13px; color: var(--fg-3); text-align: center; }
.ui-multi-rodape { display: flex; justify-content: space-between; gap: 8px; padding: 8px; border-top: 1px solid var(--border); }
.ui-multi-acao {
  min-height: 32px; padding: 0 12px; border: 1px solid var(--border-interactive); border-radius: var(--radius);
  background: transparent; color: var(--fg-2); font-family: var(--font); font-size: 13px; font-weight: 600; cursor: pointer;
}
.ui-multi-acao:not(:disabled):hover { background: var(--surface-2); }
.ui-multi-acao:focus-visible { outline: 2px solid var(--action-line); outline-offset: 2px; }
.ui-multi-acao:disabled { opacity: .45; cursor: not-allowed; }
/* computador (.shell.largo): 34px, a mesma altura dos chips e da busca da barra de filtros (camada 4a, 02/11/2026: eram 32px, a altura dos chips ANTES
   da camada 3b; a 3b passou chips e busca a 34px e deixou o botão para a 4) */
@media (min-width: 900px) { .shell.largo .ui-multi-btn { min-height: 34px; } }
/* celular e TC22: alvo de toque de 44px em TUDO que se toca — o botão, o campo de busca do popover, as opções e o Limpar/Fechar
   (o select antigo do grupo media 44px; o campo de busca tem `.ui-multi ` na frente para ganhar do input[type=search] global
   e por isso a altura dele é dita aqui, com a mesma especificidade da regra de 36px acima); abaixo de 600px o popover vira
   uma folha presa à base da janela (cabe em 390px, sem rolagem lateral e sem depender de onde o botão está) */
@media (max-width: 899px) {
  .ui-multi-btn, .ui-multi-op, .ui-multi-acao { min-height: 44px; }
  .ui-multi .ui-multi-busca { height: 44px; min-height: 44px; }
}
@media (max-width: 600px) {
  .ui-multi-pop { position: fixed; top: auto; left: 8px; right: 8px; bottom: 8px; width: auto; max-width: none; }
  .ui-multi-lista { max-height: 48vh; }
}
@media (prefers-reduced-motion: reduce) { .ui-multi-btn, .ui-multi-seta { transition: none; } }

/* ============================================================ animações
   compartilhadas por modal (mesmas de style.css:172,785 — declaradas aqui
   também porque dev-ui.html não carrega o resto do app que já as define). */
@keyframes fadein { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@keyframes slideup { from { transform: translateY(20px); } to { transform: none; } }
@media (prefers-reduced-motion: reduce) { .ui-modal-bk, .ui-modal { animation: none !important; } }

/* ============================================================ "Aguarde…"
   Camada global de ocupado — toda gravação (api() com método != GET, exceto
   `silencioso`) que passar de 250ms trava a tela. Pedido do Ícaro, 23/09/2026
   (ver o comentário grande perto de `api()` em app.js, com o levantamento de
   cada chamada). z-index acima de drawer-backdrop (40) e modal-bk (60) —
   porque a gravação pode começar com qualquer um deles já aberto na tela
   (ex.: as duas do Sempre Tem, que já tinham a própria `stEspera`; a camada
   global some por cima sem brigar com ela) — mas ABAIXO de #toast/#flash
   (MÉDIO, revisão independente do 2be4689: o toast/flash do bipe descartado
   por `leituraPermitida()` ficavam atrás da camada, escondidos — a pessoa
   nunca via o aviso "aguarde terminar a gravação"; ver z-index deles em
   style.css). `.carregando-faixa` (GRAVE 5, "Recarregar a tela" quando há
   stEspera própria) fica ACIMA da camada — não compete com ela, mas ainda
   abaixo do toast/flash.
   `top/right/bottom/left: 0` ANTES de `inset: 0` — mesmo padrão de fallback
   do DESIGN.md ("piso de suporte"): num WebView que não reconheça `inset`
   (a declaração cai por engano, nunca por certeza — não custa o fallback),
   fica com os 4 lados explícitos, idênticos ao que `inset: 0` faria. */
.carregando-overlay {
  position: fixed; top: 0; right: 0; bottom: 0; left: 0; inset: 0; z-index: 100;
  background: var(--scrim);
  display: flex; align-items: center; justify-content: center;
  animation: fadein .15s var(--ease);
}
/* GRAVE 5: faixa fixa no topo com só o botão "Recarregar a tela" — usada
   quando há stEspera própria (Sempre Tem) e o cartão não é desenhado (evita
   duplicar a mensagem de espera), mas a pessoa ainda precisa de uma saída
   depois de 60s. z-index maior que o `.modal-bk.st-espera` (60) E que a
   própria camada (100) — nunca fica escondida atrás de nenhuma das duas. */
.carregando-faixa {
  position: fixed; top: 0; left: 0; right: 0; z-index: 105;
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: var(--space-3);
  padding: 10px var(--space-4);
  background: var(--surface); color: var(--fg); border-bottom: 1px solid var(--border);
  box-shadow: var(--shadow);
  font-size: var(--fs-3);
  animation: fadein .15s var(--ease);
}
.carregando-faixa .btn.carregando-recarregar { margin: 0; min-height: 0; padding: 8px 14px; width: auto; }
/* achado do orquestrador (23/09/2026, foto pedido-compra-aguarde-1920.png):
   spinner+texto soltos sobre o scrim ficavam ilegíveis por cima do conteúdo
   claro do modal por trás — viram um CARTÃO sólido, mesma régua de
   `.modal-card` (fundo/borda/raio/sombra — elemento flutuante, sombra
   permitida pelo DESIGN.md), legível nos dois temas pelos mesmos tokens. */
.carregando-caixa {
  display: flex; flex-direction: column; align-items: center; gap: var(--space-3);
  text-align: center; padding: 16px 24px;
  background: var(--surface); color: var(--fg);
  border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow);
  max-width: calc(100vw - 32px);
}
.carregando-spinner {
  width: 34px; height: 34px;
  border: 3px solid var(--border);
  border-top-color: var(--action-line);
  border-radius: 50%;
  animation: ui-spin .7s linear infinite;
}
.carregando-texto { color: var(--fg); font-size: var(--fs-4); font-weight: 550; }
/* GRAVE B (revisão do 824a9a9): "Recarregar a tela", depois de 60s sem
   resposta — escondido até então; `.gap` do cartão já espaça, então zera a
   margem própria de `.btn` (senão dobra o respiro). */
.carregando-caixa .btn.carregando-recarregar { margin: 0; min-height: 0; padding: 10px 16px; width: auto; }

/* spinner pequeno DENTRO do botão que disparou a gravação (o último <button>
   clicado, se a chamada começou até ~1s depois). O conteúdo original (JS
   embrulha texto solto + ícone num <span>) só fica invisível — `display:
   contents` não cria caixa nem tira o filho do fluxo/flex do botão (a
   largura não muda, nada "pula" o layout ao redor); `visibility: hidden`
   nele HERDA para os filhos, inclusive um nó de texto direto (ex.: "Reservar"
   solto ao lado de um ícone), que `*:not()` sozinho não esconderia. */
button[aria-busy="true"] { position: relative; }
.ui-botao-conteudo-oculto { display: contents; visibility: hidden; }
.ui-spinner-inline {
  position: absolute; inset: 0; margin: auto;
  width: 15px; height: 15px;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: ui-spin .6s linear infinite;
}

@keyframes ui-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .carregando-overlay, .carregando-faixa { animation: none; }
  .carregando-spinner, .ui-spinner-inline { animation-duration: 1.8s; }
}
