/* ============================================================
   SISTEMA JAGUARI — app.css
   Derivado de system_design.css (System Design/): mesmos tokens
   e catálogo de componentes. Construir interface é montar o
   catálogo, nunca inventar estilo (STANDARDS.md §B.7).
   É o **realizado**, ancorado no que está construído (§B.8): o
   componente previsto e ainda não implementado vive na referência,
   que é superconjunto, e desce até aqui quando a feature o exigir.
   Dimensões e escalas validadas com a diretoria — NÃO reduzir:
   lido a distância, tablet no chão de fábrica (STANDARDS.md §B).
   ============================================================ */

/* ---- tokens ---- */
:root{
  --font:'Inter',system-ui,sans-serif;
  --bg:#F7F7F8; --surface:#FFFFFF; --line:#D4D4D8; --line-soft:#E4E4E7;
  --text:#101013; --text-2:#3F3F46; --muted:#71717A;
  --brand:#D71923; --sb-bg:#141417; --sb-item:#B4B4BD; --sb-hover:#232327;
  --th-bg:#E9E9EC; --ok:#15803D; --danger:#B91C1C; --warn:#D97706;
  --done-bd:#BBF7D0;
  --r-panel:10px; --r-btn:9px; --r-chip:7px;
  /* Duas grandezas distintas, e por isso dois tokens: `--sb-w` é a largura da barra, `--sb-col`
     é o espaço que ela toma do layout. São iguais com a barra aberta e divergem quando ela
     recolhe ou se sobrepõe — escrever uma só faria a barra sumir junto com a coluna, ou a
     coluna persistir com a barra fechada. Quem lê o espaço (a grade do shell, os dois trilhos
     de aviso, a contenção da janela dos overlays) lê `--sb-col`; quem lê a barra lê `--sb-w`. */
  --sb-w:310px; --sb-col:var(--sb-w); --hd-h:100px; --fab-lane:96px; --rhythm:20px;
}
*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth;scroll-padding-top:20px}
/* O entrelinhamento do sistema declara-se **aqui**, e uma vez: todo texto que não o recusa
   herda-o. O que o recusa recusa-o por densidade — numérico tabular, chip de altura fixa,
   célula de linha única —, e não por gosto; quem acrescentar uma superfície de prosa não
   declara entrelinhamento nenhum e ela segue este (§B.7). */
body{background:var(--bg);font-family:var(--font);color:var(--text);line-height:1.4;-webkit-font-smoothing:antialiased}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
svg{flex:0 0 auto;width:20px;height:20px}
a{color:inherit;text-decoration:none}
/* `hidden` volta a significar oculto: qualquer `display` de autor — .btn, .formacts — vence
   a regra do navegador, e o elemento marcado como não-ofertado apareceria mesmo assim. */
[hidden]{display:none !important}

/* ============================================================
   SHELL DO APP — moldura de toda interface
   ============================================================ */
.app{display:grid;grid-template-columns:var(--sb-col) minmax(0,1fr);background:var(--bg);position:relative}
/* Recolhimento da barra (§H). O estado vive numa classe de **ancestral**, e não em `.app`: os
   trilhos de aviso (`.toasts`, `.ntoasts`) derivam a sua posição do mesmo token e vivem fora do
   shell, de modo que uma classe em `.app` não os alcançaria. O ancestral é a raiz do documento —
   o mesmo lugar onde o estado de conexão já vive, e o único que sobrevive à navegação, que
   destrói e remonta todo o shell. O seletor empata em especificidade com `:root`: vem depois
   dele, e é a ordem que decide. */
.sb-recolhida{--sb-col:0px}
/* A coluna a zero não recorta o que está dentro dela — quem recorta é a barra. E a barra fechada
   sai do **foco** e da árvore de acessibilidade: sessenta ligações focáveis numa coluna invisível
   são alvos que o teclado percorre sem que nada apareça na tela (§B.2, §H). */
.sidebar{background:var(--sb-bg);display:flex;flex-direction:column;min-height:0;overflow:hidden}
.sb-recolhida .sidebar{visibility:hidden}
.sb-logo{height:var(--hd-h);flex:0 0 auto;display:flex;align-items:center;justify-content:center;border-bottom:1px solid #2A2A2E}
.sb-logo img{height:70px;width:auto}
.sb-search{flex:0 0 auto;display:flex;align-items:center;gap:9px;margin:14px 12px 0;padding:0 13px;min-height:48px;background:#1E1E22;border:1px solid #2A2A2E;border-radius:9px;color:var(--muted)}
.sb-search svg{width:18px;height:18px}
.sb-search input{flex:1 1 auto;min-width:0;border:0;outline:0;background:none;font:inherit;font-size:15px;font-weight:600;color:#E4E4E7}
.sb-search input::placeholder{color:#6B6B75}
/* foco da busca sobre a superfície escura: o anel claro do formulário some no escuro,
   então o indicador é a própria linguagem da barra — borda no tom do item, fundo no
   hover da barra (§B.2) */
.sb-search:focus-within{border-color:var(--sb-item);background:var(--sb-hover)}
.sb-nav{flex:1 1 auto;overflow-y:auto;min-height:0;padding:14px 12px 44px}
.sb-nav::-webkit-scrollbar{width:7px}
.sb-nav::-webkit-scrollbar-thumb{background:#3A3A40;border-radius:4px}
/* O item da barra é alvo de toque e leitura a distância nas duas dimensões: o rótulo em 15,5px
   e o glifo de domínio em 24px, a mesma escala do `.iconbtn` da faixa de topo. O rótulo **quebra**
   em vez de truncar — a interface é nomeada pelo nome inteiro, e uma elipse a meio de
   "Rastreabilidade de Produtos" faz duas entradas lerem igual (§B.4, §H). */
.sb-item{display:flex;align-items:center;gap:12px;width:100%;padding:13px 12px;margin-bottom:3px;text-align:left;color:var(--sb-item);font-size:15.5px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;border-radius:9px;transition:background .1s,color .1s}
.sb-item:hover{background:var(--sb-hover);color:#E4E4E7}
.sb-item.active{background:var(--brand);color:#FFF}
.sb-item svg{width:24px;height:24px;opacity:.85}
.sb-item.active svg{opacity:1}
.sb-item span{flex:1 1 auto;min-width:0;line-height:1.3;overflow-wrap:break-word}
.sb-item .go{width:18px;height:18px;opacity:.55}
.main{display:flex;flex-direction:column;min-width:0;min-height:0;position:relative}
/* shell real: viewport cheio — a altura fixa do `.app` no catálogo é a moldura de
   demonstração, e não desce para cá */
.app.appshell{height:100vh}
/* menu do funcionário: painel ancorado sob o hambúrguer, no canto do cabeçalho */
.usermenu.menu-pop{position:absolute;top:calc(var(--hd-h) - 14px);right:calc((var(--fab-lane) + 32px - 62px)/2 + 12px);z-index:40;box-shadow:0 8px 24px rgba(17,17,20,.12)}
/* o hambúrguer recua ~a largura da barra de rolagem (12px, ajustado) além do centro da
   faixa, alinhando aos botões da faixa lateral, recuados pelo scrollbar-gutter do conteúdo */
.header{height:var(--hd-h);flex:0 0 auto;position:relative;background:var(--surface);border-bottom:1px solid var(--line-soft);display:flex;align-items:center;gap:18px;padding:0 calc((var(--fab-lane) + 32px - 62px)/2 + 12px) 0 30px}
.header h1{flex:1 1 auto;min-width:0;font-size:30px;font-weight:800;text-transform:uppercase;letter-spacing:.01em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* O controle do recolhimento é o alvo de ícone do catálogo, na faixa de cabeçalho e à esquerda do
   título: a posição é a mesma nos dois estados, e é isso que o torna procurável sem olhar (§B.7).
   Preso à borda da barra, ele percorreria os 310px ao recolher.
   O botão declara **os dois sentidos** e a folha escolhe um. É deliberado: a barra vive dentro do
   LiveView e cada navegação remonta-a, de modo que uma marcação alterada a partir do cliente seria
   reposta no estado do servidor a cada passagem — a seta apontaria para o lado errado com a barra
   fechada, sem nada que o acusasse. */
.sb-abrir{display:none}
.sb-recolhida .sb-fechar{display:none}
.sb-recolhida .sb-abrir{display:block}
.iconbtn{width:62px;height:62px;display:inline-flex;align-items:center;justify-content:center;background:var(--surface);border:1px solid var(--line);border-radius:10px;transition:background .1s}
.iconbtn:hover{border-color:var(--muted)}
.iconbtn svg{width:24px;height:24px}
/* Variante destrutiva do alvo de ícone. O tom vive no glifo e na borda, não num preenchimento: o
   `.iconbtn` é alvo pequeno dentro de linha de tabela, e o bloco sólido do `.btn.no` pesaria a
   linha inteira. Mesmo token do botão destrutivo, e o hover conserva o tom em vez de cair no
   esmaecido do hover neutro, que apagaria a única marca de que a ação remove (§H). */
.iconbtn.no{color:var(--danger);border-color:var(--danger)}
.iconbtn.no:hover{border-color:var(--danger);background:rgba(185,28,28,.06)}
/* A área de conteúdo é a dona do ritmo vertical da interface: uma coluna com `gap`
   único entre os blocos de primeiro nível (barra, filtros, tabela, calendário, painéis).
   Nenhum bloco declara o próprio respiro — onde cada um declarava o seu, o espaço
   divergia entre telas e faltava em algumas (§H). */
.content{flex:1 1 auto;overflow-y:auto;scrollbar-gutter:stable;min-height:0;padding:28px calc(32px + var(--fab-lane)) 40px 32px;position:relative;display:flex;flex-direction:column;align-items:stretch;gap:var(--rhythm)}
/* O bloco assenta na sua altura natural e é a página que rola. Um contêiner de rolagem —
   `.tablewrap` e `.conf` são os do sistema — tem mínimo automático **zero** em flex: livre para
   encolher, encolhe até caber e a rolagem da página passa ao seu eixo, de modo que a tabela ganha
   barra vertical própria e `.content` fica sem o que rolar (§B.4, §H). */
.content>*,.vstack>*{flex-shrink:0}
.vstack{display:flex;flex-direction:column;align-items:stretch;gap:var(--rhythm);width:100%;min-width:0}
/* o que é posicionado fora do fluxo não participa do ritmo nem o consome */
.content>.topacts,.content>.fabs{position:absolute}
.content::-webkit-scrollbar{width:10px}
.content::-webkit-scrollbar-thumb{background:#C7C7CC;border-radius:5px}
/* ações de interface (Registros, Exportar): faixa lateral dos FABs, mesmo eixo */
.topacts{position:absolute;top:28px;right:calc((var(--fab-lane) + 32px - 62px)/2);z-index:5;display:flex;flex-direction:column;gap:16px}
.fabs{position:absolute;right:calc((var(--fab-lane) + 32px - 72px)/2);bottom:28px;z-index:5;display:flex;flex-direction:column;gap:16px}
.fab{position:relative;width:72px;height:72px;display:flex;align-items:center;justify-content:center;background:#17171A;color:#FFF;border-radius:50%;box-shadow:0 1px 3px rgba(0,0,0,.14);transition:filter .12s}
.fab:hover{filter:brightness(1.25)}
.fab svg{width:31px;height:31px}
.fab .badge{position:absolute;top:-5px;right:-5px;min-width:27px;height:27px;padding:0 7px;display:flex;align-items:center;justify-content:center;background:var(--brand);color:#FFF;font-size:14px;font-weight:800;font-variant-numeric:tabular-nums;border-radius:14px;border:3px solid var(--bg)}
/* A raiz única que um componente stateful exige, e nada mais: agrupa o FAB com as superfícies
   que ele abre sem entrar no layout, de modo que o botão continue a ser filho direto da coluna
   de `.fabs` e o `gap` entre os dois flutuantes não mude. */
.fabgroup{display:contents}

/* menu do funcionário (hambúrguer, canto superior direito) */
.usermenu{width:280px;background:var(--surface);border:1px solid var(--line);border-radius:var(--r-panel);overflow:hidden}
.usermenu .um-head{padding:16px 18px;border-bottom:1px solid var(--line-soft)}
.usermenu .um-nome{font-size:15px;font-weight:800;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.usermenu .um-user{font-size:13px;color:var(--muted);font-family:ui-monospace,Menlo,monospace;margin-top:2px}
.usermenu .um-meta{padding:12px 18px;border-bottom:1px solid var(--line-soft);display:flex;flex-direction:column;gap:8px}
.usermenu .um-row{display:flex;flex-direction:column;gap:2px}
.usermenu .um-k{font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.07em;color:var(--muted)}
.usermenu .um-v{font-size:13.5px;font-weight:600;color:var(--text-2)}
.usermenu .um-logout{display:flex;align-items:center;gap:11px;width:100%;padding:14px 18px;font-size:15px;font-weight:700;color:var(--danger);text-align:left}
.usermenu .um-logout:hover{background:#FDF2F2}
.usermenu .um-logout svg{width:20px;height:20px}

/* ============================================================
   CONTROLES
   ============================================================ */
/* botões */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:11px;min-height:62px;padding:10px 22px;font-size:16px;font-weight:700;border-radius:var(--r-btn);color:#FFF;transition:filter .12s}
.btn:hover{filter:brightness(.94)}
.btn:active{filter:brightness(.88)}
.btn svg{width:20px;height:20px}
.btn.ok{background:var(--ok)} .btn.no{background:var(--danger)} .btn.brand{background:var(--brand)}
.btn.warn{background:var(--warn)}
.btn.neutral{background:var(--surface);color:var(--text);border:1px solid var(--line)}
.btn.neutral:hover{background:#F1F1F2;filter:none}
.btn.full{width:100%}
.btn[disabled]{opacity:.5;pointer-events:none}
.phx-submit-loading .btn,.btn.phx-click-loading{opacity:.5;pointer-events:none}

/* filtro / seletor base */
/* A barra de filtros é dona do próprio ritmo e da própria largura: ocupa a linha e
   abre o mesmo respiro de 20px que a .totbar antes da tabela/calendário que a segue
   (§H). Nenhuma interface repete espaçamento nem largura por conta. */
.filters{display:flex;flex-wrap:wrap;gap:10px;width:100%}
/* Aninhada numa .totbar (filtros à esquerda, ação à direita, na mesma faixa): a
   .totbar já é dona da linha e do ritmo, e reivindicá-los empurraria o botão irmão
   para a linha seguinte. */
.totbar .filters{width:auto}
/* faixa com muitos totalizadores: eles formam um grupo que embrulha **à direita**. Sem o grupo,
   o embrulho recomeça à esquerda e a faixa parte-se em duas leituras — a de cima alinhada à
   direita, a de baixo à esquerda (§H). O grupo é a faixa inteira: as ações que incidem sobre o
   mesmo conjunto vão na `.totbar` seguinte, porque dez totalizadores nunca partilham linha com
   um botão e a ordem acabaria decidida pelo embrulho. */
.totgroup{display:flex;flex-wrap:wrap;gap:12px;justify-content:flex-end;margin-left:auto;min-width:0}
/* linha de derivados de um painel — os totalizadores que um bloco exibe como leitura, não a faixa
   de ações da seção: por isso não é `.totbar`, que é o primeiro bloco da sua seção e vem antes
   do título (§H). Aqui os valores pertencem ao painel que o título já nomeou. */
/* Alinha ao pé: onde a faixa mistura totalizador e campo — o Valor de Venda Ajustado ao lado
   do Valor de Venda que o autopreenche —, o campo é mais alto pelo rótulo acima, e o que faz
   a linha ler como uma linha é a base comum, não o topo. */
.derivados{display:flex;flex-wrap:wrap;align-items:flex-end;gap:12px;width:100%}
/* O campo que fecha a faixa — o Ajustado ao lado do derivado que o autopreenche — encosta à
   direita e dispensa o mínimo do formulário: ali o rótulo pode quebrar em duas linhas, e 220px
   de piso empurravam-no para uma linha só dele. Onde a faixa não tem largura para os dois, o
   `margin-left:auto` o mantém **debaixo do seu par**, no mesmo eixo, em vez de o atirar para a
   esquerda de tudo. */
.derivados>.field{min-width:170px;margin-left:auto}
/* `fim` alinha os derivados à direita: é o painel em que a entrada vem antes e o derivado a
   fecha, e o último totalizador é a resposta da tela — cai no canto onde a leitura termina. Onde
   o derivado alimenta a entrada, a ordem é a inversa e os totalizadores abrem à esquerda. */
.derivados.fim{justify-content:flex-end}
/* busca livre na barra de filtros — mesma altura/linguagem dos controles (.input) */
.filters .search{display:flex;align-items:center;gap:9px;flex:1 1 220px;min-width:0;min-height:62px;padding:0 14px;background:var(--surface);border:1px solid var(--line);border-radius:var(--r-btn);color:var(--muted);transition:border-color .12s,box-shadow .12s}
.filters .search:focus-within{border-color:var(--text-2);box-shadow:0 0 0 3px rgba(63,63,70,.08)}
.filters .search svg{width:18px;height:18px;flex:0 0 auto}
.filters .search input{flex:1 1 auto;min-width:0;border:0;outline:0;background:none;font:inherit;font-size:16px;font-weight:600;color:var(--text);font-variant-numeric:tabular-nums}
.filters .search input::placeholder{color:#A1A1AA;font-weight:600}
/* Controle numa barra de filtros: largura de repouso do catálogo, **sem crescer**.
   `flex-grow:0` é a regra para **seletor e campo**: é o `flex-wrap` da barra que
   preenche a linha quando os filtros são muitos ou o espaço aperta (§B.4, §H).
   A **busca** é a única que cresce, e cresce por desenho: toma toda a folga que sobra
   na linha depois dos filtros e da ação irmã. */
.filters .select,
.filters .field{flex:0 1 240px;min-width:0}
/* Escala nomeada de largura de filtro — o rótulo dita o degrau, não a tela. */
.filters .f-xs{flex-basis:120px}   /* ano */
.filters .f-sm{flex-basis:150px}   /* mês, situação, fluxo, lote, tipo de registro */
.filters .f-md{flex-basis:190px}   /* data, silo, número, máquina */

/* campos */
.field{display:flex;flex-direction:column;gap:6px;min-width:220px}
.field>label{font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:.07em;color:var(--muted)}
.field.act{justify-content:flex-end}
.input{display:flex;align-items:center;gap:8px;min-height:62px;padding:0 14px;background:var(--surface);border:1px solid var(--line);border-radius:var(--r-btn);font-size:16px;font-weight:600;position:relative;transition:border-color .12s,box-shadow .12s}
/* afixo é overlay absoluto: nunca altera a largura do campo */
.input .affix{position:absolute;top:50%;transform:translateY(-50%);right:12px;color:var(--muted);font-weight:700;font-variant-numeric:tabular-nums;pointer-events:none}
.input .affix.pre{left:12px;right:auto}
.input.suf input{padding-right:36px}
.input.pre input{padding-left:34px}
/* campo numérico estreito numa linha repetível (unidades de item de kit) */
/* sprite de ícones: definido uma vez, fora do fluxo, nunca visível */
.sprite{position:absolute;width:0;height:0}
.input input{flex:1 1 auto;min-width:0;border:0;outline:0;background:none;font:inherit;color:var(--text);font-variant-numeric:tabular-nums}
.input input::placeholder{color:#A1A1AA;font-weight:600}
/* anel de foco do campo: o `<input>` interno tem `outline:0`, então quem indica o foco
   de teclado é a caixa — mesma borda e mesmo anel do seletor e da busca (§B.2) */
.input:focus-within{border-color:var(--text-2);box-shadow:0 0 0 3px rgba(63,63,70,.08)}
.input.err{border-color:var(--danger);box-shadow:0 0 0 3px rgba(185,28,28,.10)}
/* Par do `.input.err` para o seletor: sem ele o campo recusado fica indistinguível do válido, e o
   operador lê o motivo mas procura o campo (§B.2). */
.select.err>select{border-color:var(--danger);box-shadow:0 0 0 3px rgba(185,28,28,.10)}
.input.ro{background:#F4F4F5;color:var(--text-2)}
.input[data-disabled]{background:#F4F4F5;color:#A1A1AA;pointer-events:none}
.field .hint{font-size:12px;color:var(--muted)}
/* grade de formulário: largura uniforme — conteúdo (afixo, chevron, valor) nunca altera a largura do campo */
.fieldgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:16px;width:100%}
.fieldgrid .field{min-width:0}
/* painel de cotação — o derivado é totalizador, a entrada é campo (SPEC Pedidos Transportadoras).
   O bloco é dono do respiro entre a faixa de derivados e a grade de entradas, como toda coluna
   de ritmo: declarado por dentro, ele divergiria entre o formulário e a detail page. */
.cotacao{display:flex;flex-direction:column;gap:16px;width:100%}
.cotacao>*{flex-shrink:0}
.formcol{display:flex;flex-direction:column;gap:16px;width:100%;max-width:560px}
/* painel de leitura que preenche a coluna que o contém, em vez da coluna de entrada */
.formcol.wide{max-width:none}
/* faixa de painéis lado a lado que quebram em coluna quando o espaço aperta (§B.4) */
.panes{display:flex;flex-wrap:wrap;gap:18px;width:100%}
/* Coluna de painel — vale em qualquer faixa (.panes ou .calwrap): escopá-la a um pai só
   a faria perder flex, largura mínima e ritmo interno sob o outro. */
.pane{flex:1 1 440px;min-width:0;display:flex;flex-direction:column;gap:16px}
/* faixa de quatro colunas: base menor, para caberem lado a lado no desktop e caírem
   para duas quando o espaço aperta */
.calwrap.quad>.pane,.panes.quad>.pane{flex:1 1 260px}
.formcol+.formcol{margin-top:16px}
.formcol .field{min-width:0}
/* A ação de uma coluna de formulário tem a largura dos campos que a precedem; a `.hint` que
   diz a condição que falta assenta junto do botão, não ao ritmo dos campos. */
.formcol .formacts{display:flex;flex-wrap:wrap;gap:8px 12px}
.formcol .formacts>.btn{flex:1 1 auto}
.formcol .formacts>.hint{flex-basis:100%;margin:0;font-size:12px;color:var(--muted)}
/* lista de linhas repetíveis (Cargos, Setores): um seletor que cresce + ação por linha */
.linhas{display:flex;flex-direction:column;gap:10px}
.linha{display:flex;align-items:flex-start;gap:10px}
/* A célula é a unidade da linha: rótulo, controle e o erro **daquele** controle, um sob o outro —
   é o que põe a mensagem debaixo do campo que a produziu (§B.2). A linha alinha ao topo para que a
   célula que ganha mensagem cresça para baixo sem empurrar as vizinhas. */
.linha>.cel{display:flex;flex-direction:column;gap:6px;min-width:0;flex:1 1 auto}
.linha>.cel.fixa{flex:0 0 180px}
.linha>.cel.estreita{flex:0 0 120px}
/* `moeda` é a coluna de valor em reais, e é mais larga que `estreita` por uma razão de domínio:
   o percentual tem três dígitos por teto e o valor não tem teto nenhum. Partilhando a largura, o
   preço de quatro dígitos com centavos rolava dentro do campo enquanto a alíquota sobrava. */
.linha>.cel.moeda{flex:0 0 160px}
/* A mensagem de erro carrega o próprio efeito e não o pede ao ancestral: declarada só como
   variante de `.field` e de `.linha`, ela é **inerte** no terceiro lugar que a usar — e o erro
   que pousa sob o título de um bloco (a coleção vazia, a soma que não fecha) saía no tamanho e
   na cor herdados do corpo, que é dizer sem marca alguma. Mesma regra de `.rowlink` (§H). */
.msg{font-size:12px;color:var(--danger);font-weight:600}
.linha>.cel>label{font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:.07em;color:var(--muted)}
/* Alvo de ícone da linha não encolhe: é alvo de toque e o piso vale nas duas dimensões (§B.4). */
.linha>.step,.linha>.iconbtn{flex:0 0 auto}
/* Onde a linha tem rótulos, o alvo de ícone desce a altura de um rótulo para assentar na mesma
   linha de base dos controles. */
/* O toggle mede 30px de traço e os controles medem 62: alinhado ao topo da linha, ele fica na
   altura do rótulo em vez da do campo. Toma a altura do controle e centra o seu conteúdo dentro
   dela — assim o eixo do interruptor cai no eixo do campo vizinho, e não numa margem que teria de
   ser recalculada a cada mudança de altura. */
.linha>.toggle{min-height:62px}
.linha.rotulada>.step,.linha.rotulada>.iconbtn,.linha.rotulada>.toggle{margin-top:23px}

/* Linha densa (Controle de Relatórios): oito controles onde a linha simples tem dois. Cada um
   toma o seu degrau e a quebra de linha absorve o aperto — como na barra de filtros (§H). */
.linha.densa{flex-wrap:wrap}
/* A linha densa quebra por `flex-basis`, **antes** de encolher: o item vai para a linha
   seguinte pela sua largura hipotética, e só depois o que sobrou na linha se reparte. A célula
   que cresce pedia o seu conteúdo (`basis:auto`) e empurrava para baixo a célula seguinte — ou,
   pior, só o botão de remover, sozinho numa linha. Com basis zero ela entra pequena e cresce
   com o que sobra, e a linha fecha inteira; as de largura declarada mantêm o seu degrau. */
.linha.densa>.cel:not(.fixa):not(.estreita):not(.moeda){flex-basis:0}
.linha.densa>.toggle{flex:0 0 auto}

/* seletor de formulário: filtro + menu ancorado abaixo, mesma largura */
.select{display:flex;flex-direction:column;gap:8px}
/* select nativo — mesma linguagem dos controles; chevron desenhado (appearance:none) */
.select>select{width:100%;min-height:62px;padding:0 40px 0 14px;background-color:var(--surface);border:1px solid var(--line);border-radius:var(--r-btn);font:inherit;font-size:16px;font-weight:600;color:var(--text);cursor:pointer;-webkit-appearance:none;appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2371717A' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 12px center;background-size:16px}
.select>select:hover{border-color:var(--muted)}
.select>select:focus{outline:0;border-color:var(--text-2);box-shadow:0 0 0 3px rgba(63,63,70,.08)}
/* trava de seletor dependente visível: mesmo esmaecido de .input[data-disabled] (§E.5, §H) */
.select>select:disabled{background-color:#F4F4F5;color:#A1A1AA;border-color:var(--line-soft);cursor:not-allowed;opacity:1}
.select>select:disabled:hover{border-color:var(--line-soft)}

/* toggle / checkbox / stepper */
.toggle{display:inline-flex;align-items:center;gap:11px;cursor:pointer;font-size:15px;font-weight:600}
.toggle .track{width:52px;height:30px;border-radius:16px;background:#D4D4D8;position:relative;transition:background .14s}
.toggle .track::after{content:"";position:absolute;top:3px;left:3px;width:24px;height:24px;border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,.2);transition:transform .14s}
.toggle.on .track{background:var(--ok)}
.toggle.on .track::after{transform:translateX(22px)}
/* Toggle **travado**: a flag que o tipo do parâmetro não admite (a Média fora do numérico). Fica
   desligada e não responde ao toque, com o esmaecido de controle desabilitado — a mesma linguagem
   do seletor dependente travado (§H). Recusar só na escrita fazia o operador ligar a flag e
   descobrir na submissão que não podia, que é a aparência ativa que não responde. */
.toggle.travado{cursor:not-allowed;color:#A1A1AA}
.toggle.travado .track{background:#E4E4E7}

/* ============================================================
   DADOS
   ============================================================ */
/* tabela de registros */
table.reg{width:max-content;min-width:100%;border-collapse:separate;border-spacing:0}
table.reg th{position:sticky;top:0;z-index:1;background:var(--th-bg);color:var(--text-2);font-size:13px;font-weight:800;text-transform:uppercase;letter-spacing:.04em;padding:14px 10px;text-align:center;white-space:nowrap;border-bottom:1px solid var(--line)}
table.reg th+th,table.reg td+td{border-left:1px solid var(--line-soft)}
table.reg td{font-size:15px;font-weight:600;font-variant-numeric:tabular-nums;padding:0 10px;text-align:center;white-space:nowrap;border-bottom:1px solid var(--line-soft);height:62px}
table.reg tbody tr:last-child td{border-bottom:0}
table.reg tbody tr:nth-child(even) td{background:#FAFAFA}
table.reg tbody tr.rowlink:hover td{background:#F1F1F2}
table.reg td.empty{color:var(--muted)}
table.reg td.ord{font-weight:800}
/* linha de agregação da tabela (Médias do Laboratório): rodapé, não linha de dado — toma a
   superfície do cabeçalho, e o rótulo é o cromo dele. Vive no <tfoot> para não disputar o
   zebrado do <tbody>, que empata em especificidade e resolveria por ordem de declaração. */
table.reg tfoot td{background:var(--th-bg);font-weight:800;font-size:18px;border-top:1px solid var(--line);border-bottom:0}
/* O rótulo da agregação **empilha** na primeira célula do pé, sobre o valor. Uma coluna só para
   ele ficava vazia no cabeçalho e em toda linha do corpo; dar-lhe a célula inteira apagaria a
   média do primeiro parâmetro. Empilhado, não custa coluna nem média — custa a altura de uma
   linha de cromo, e só ao pé. */
table.reg tfoot td .agr{display:block;font-size:13px;font-weight:800;color:var(--text-2);text-transform:uppercase;letter-spacing:.04em}
/* rolagem horizontal interna quando a tabela excede a largura — comportamento de sistema (§H) */
.tablewrap{background:var(--surface);border:1px solid var(--line);border-radius:var(--r-panel);overflow-x:auto;width:100%}
/* rodapé "Carregar mais" da paginação por cursor (§H) */
.load{display:flex;justify-content:center;width:100%}

/* card de ordem — objeto acionável do acompanhamento produtivo, valores a 28px com escala
   dinâmica para leitura a distância (system_design §5.3). Os steppers ↑↓ existem só nas
   filas com prioridade — Pedidos Produção, Pedidos Processamento e Processamento —, e a
   coluna estica à altura do card: a seta de subir no topo, a de descer na base. */
.ogrid{width:100%;table-layout:fixed;border-collapse:separate;border-spacing:0;background:var(--surface);border:1.5px solid #C9C9CF;border-radius:var(--r-panel);container-type:inline-size}
.ogrid th{background:var(--th-bg);color:var(--text-2);font-size:13px;font-weight:800;text-transform:uppercase;letter-spacing:.07em;padding:13px 6px;text-align:center;white-space:nowrap;border-bottom:1px solid var(--line)}
.ogrid th+th,.ogrid td+td{border-left:1px solid var(--line)}
.ogrid td{background:var(--surface);font-size:clamp(17px,4.5cqi,28px);font-weight:800;font-variant-numeric:tabular-nums;padding:18px 6px;text-align:center;line-height:1.15;overflow-wrap:break-word}
.ogrid td.empty{color:var(--muted);font-weight:600}
.ord-wrap{display:flex;gap:12px;width:100%;align-items:stretch}
.ord-main{flex:1 1 auto;min-width:0}
.ord-acts{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin-top:14px}
/* card de ação única: a faixa colapsa a uma coluna e conserva o respiro do rodapé, que o
   botão solto não teria — a mesma forma de `.dfoot.one` no diálogo */
.ord-acts.one{grid-template-columns:1fr}
.step{width:62px;height:62px;display:inline-flex;align-items:center;justify-content:center;background:var(--surface);border:1px solid var(--line);border-radius:10px;color:var(--muted)}
.step:hover{border-color:var(--muted);color:var(--text)}
.step svg{width:19px;height:19px}
.ord-steppers{flex:0 0 62px;display:flex;flex-direction:column;justify-content:space-between;gap:12px}
.ord-steppers .step{height:auto;flex:1 1 0;min-height:62px}

/* card de pedido — objeto dos fluxos de expedição (system_design §5.4). Distinto do card de
   ordem acima: a grade é de pares rótulo/valor e a situação vive numa coluna de estado à
   direita, não numa célula da grade. É a forma que a especificação dá ao objeto espelhado da
   Expedição Empresa, e o CTA aparece só no estado em que há próxima ação — Finalizar Ordem
   quando a ordem está carregada. A grade é a mesma nos oito objetos de expedição — o que varia
   é o par rótulo/valor e o vocabulário de situação (§G). */
.ped{display:grid;grid-template-columns:minmax(0,1fr) minmax(190px,232px);background:var(--surface);border:1.5px solid #C9C9CF;border-radius:var(--r-panel);overflow:hidden;width:100%}
.pgrid{width:100%;table-layout:fixed;border-collapse:separate;border-spacing:0;container-type:inline-size}
/* Um par por linha. O rótulo toma a largura fixa que o mais longo exige e o valor fica com o
   resto: com dois pares na mesma linha o valor dispõe de 130px úteis, e uma palavra sozinha de
   catorze caracteres — "Transportadora" é a corrente — mede 171px a 22px e parte-se ao meio.
   A altura do card é a mesma: o rótulo que precisaria de cinco linhas cabe em uma. */
.pgrid th{background:var(--th-bg);color:var(--text-2);font-size:12px;font-weight:800;text-transform:uppercase;letter-spacing:.05em;line-height:1.25;padding:14px 12px;text-align:left;width:180px;vertical-align:middle;overflow-wrap:break-word}
.pgrid td{font-size:clamp(15px,2.4cqi,22px);font-weight:700;font-variant-numeric:tabular-nums;line-height:1.2;padding:12px 14px;text-align:left;width:auto;vertical-align:middle;overflow-wrap:break-word}
.pgrid tr:not(:last-child) th,.pgrid tr:not(:last-child) td{border-bottom:1px solid var(--line-soft)}
.pgrid th+td,.pgrid td+th{border-left:1px solid var(--line-soft)}
.ped-state{display:flex;flex-direction:column;border-left:1px solid var(--line)}
.ped-main{flex:1 1 auto;display:flex;align-items:center;justify-content:center;gap:10px;padding:18px;font-size:19px;font-weight:700;text-align:center}
.ped-main svg{width:22px;height:22px}
.ped-state.st-pend .ped-main{background:#FCE9CE;color:#8A4B10}
.ped-state.st-sep .ped-main{background:#FBF3D0;color:#7A5B00}
.ped-state.st-emb .ped-main{background:#D4E7FB;color:#1E4E8C}
.ped-state.st-carr .ped-main{background:#D8F0DC;color:#1B6B34}
.ped-state.st-agend .ped-main{background:#DCE4FA;color:#2A3F86}
.ped-cta{display:flex;align-items:center;justify-content:center;gap:9px;padding:14px;font-size:15px;font-weight:800;background:#CDEBD5;color:#166534;border-top:1px solid var(--line-soft)}
/* alvo acionável — o cursor e o anel de foco são do próprio `.rowlink`, e não de cada elemento
   que o recebe: assim a classe não fica inerte no elemento que a folha não previu (§B.2, §H) */
.rowlink{cursor:pointer}
.rowlink:focus-visible{outline:none;box-shadow:0 0 0 3px rgba(20,20,23,.18)}
.ped.rowlink:hover{border-color:var(--muted)}
.ped.rowlink:focus-visible{border-color:var(--text)}
/* o card de grade não tem borda própria — quem a desenha é a `.ogrid` de dentro */
.ord-wrap.rowlink:hover .ogrid{border-color:var(--muted)}
.ord-wrap.rowlink:focus-visible .ogrid{border-color:var(--text)}
.silo2.rowlink:hover{border-color:var(--muted)}
.silo2.rowlink:focus-visible{border-color:var(--text)}
/* O CTA vive **dentro** do bloco de situação e continua a sua cor: o verde do pé é o irmão mais
   fundo do verde de `st-carr`, e não o verde de ação de `§H`, que é do `.btn`. Onde o objeto
   oferece a ação numa situação de outra cor — o kit, que finaliza em `embalado` —, o pé toma o
   azul de `st-emb` pelo mesmo degrau. O degrau é uma conta, não uma escolha: o fundo desce
   (11,5,7) e o texto (5,6,0) sobre os do bloco, de modo que a situação que passar a oferecer
   uma ação traz o seu próprio pé sem se decidir por gosto. */
.ped-cta.emb{background:#C9E2F4;color:#19488C}
.ped-cta.agend{background:#D1DFF3;color:#253986}
.ped-cta.pend{background:#F1E4C7;color:#854510}
.ped-cta:hover{filter:brightness(1.08)}
.ped-cta svg{width:19px;height:19px}

/* conferência — checagem item a item (system_design §5.7). O rodapé é do bloco, não da tela
   que o monta, e trava até tudo conferido. A checkbox é alvo de **ícone sozinho** e por isso
   declara as duas dimensões no piso de 62px (STANDARDS.md §H, §B.4): o operador de luva acerta
   o quadrado, não o glifo dentro dele. */
.ck{width:62px;height:62px;display:inline-flex;align-items:center;justify-content:center;background:var(--ok);color:#FFF;border-radius:8px;transition:filter .12s,transform .06s}
.ck:hover{filter:brightness(.92)}
.ck.off{background:var(--surface);border:1.5px solid var(--line);color:transparent}
.ck svg{width:24px;height:24px}
/* Lista de opções — o vocabulário **fechado** que o operador marca, e não uma coleção de
   registros: as seções de um documento de conferência são cinco, sempre as mesmas, e não há
   estado vazio que a lista possa ter. É o que a separa da grade de conferência, que é tabela
   porque as suas linhas são os itens que alguém lançou. */
.optlist{display:flex;flex-direction:column;background:var(--surface);border:1.5px solid var(--line);border-radius:var(--r-panel);overflow:hidden}
.opt{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:11px 16px}
.opt+.opt{border-top:1px solid var(--line-soft)}
.opt>span{font-size:19px;font-weight:700}
.conf{background:var(--surface);border:1px solid var(--line);border-radius:var(--r-panel);overflow:hidden;width:100%}
table.bgrid{width:100%;border-collapse:separate;border-spacing:0}
table.bgrid th{background:#F4F4F5;color:var(--text-2);font-size:13px;font-weight:800;text-transform:uppercase;letter-spacing:.06em;padding:14px 16px;text-align:center;white-space:nowrap;border-bottom:1px solid var(--line-soft)}
table.bgrid th+th,table.bgrid td+td{border-left:1px solid var(--line-soft)}
table.bgrid td{font-size:19px;font-weight:700;font-variant-numeric:tabular-nums;padding:15px 16px;text-align:center;border-bottom:1px solid var(--line-soft);height:64px}
table.bgrid th.lbl{text-align:left} table.bgrid td.val{text-align:left}
/* A coluna da etapa tem largura declarada, e é a mesma em toda tabela de conferência do sistema:
   deixada ao conteúdo, mede diferente em cada seção — Produtos tem quatro colunas e as outras
   três — e os alvos desencontram-se de uma tabela para a seguinte, que é o oposto da leitura de
   checklist que a conferência pede (§B.7). Cabe o mais longo dos rótulos de etapa sem quebra. */
table.bgrid th.ck-col,table.bgrid td.ck-col{width:168px}
/* A mesma coluna numa tabela de **registros**: `table.reg` zera o respiro vertical das suas
   células, e o alvo de 62px encostava nas bordas em cima e em baixo — duas caixas em linhas
   seguidas ficavam sem nada entre elas. Toma a largura e o respiro da grade de conferência, que é
   onde a marcação nasceu, para que a mesma caixa tenha o mesmo alvo nas duas famílias. */
table.reg th.ck-col,table.reg td.ck-col{width:168px}
table.reg td.ck-col{padding:15px 16px}
/* Coluna de Quantidade — largura declarada, pela mesma razão do `ck-col` acima e com a mesma
   medida. As seções de item de um documento empilham-se numa coluna e a Quantidade é a última de
   cada tabela; deixada ao conteúdo, mede o seu em cada uma e a leitura desce em degraus por onde
   devia ser uma coluna (§B.7). Vale nas duas famílias de tabela — a de registros, que a detail
   page projeta, e a grade de conferência das etapas operacionais. */
table.reg th.qt-col,table.reg td.qt-col,table.bgrid th.qt-col,table.bgrid td.qt-col{width:168px}
/* A faixa assenta ao **fim** do fluxo, não sobre ele. Presa ao pé do scrollport, ocupa 95px dos
   713px da área de conteúdo em toda a rolagem e assenta sobre o que estiver por baixo — tolerável
   onde a conferência é uma tabela só, e não onde ela tem três blocos e o de baixo é um formulário,
   cujos campos ficam por trás dela. O alvo fica onde a tarefa acaba, e é o mesmo
   gesto nas três conferências (§B.7). */
/* A transição que fecha a etapa ocupa a **largura** da faixa, com o respiro dela dos dois lados:
   é a única ação do bloco e o alvo que o operador de luva procura ao fim de uma conferência de
   dezenas de itens (§B.4). Distinta da ação de faixa de topo, que se dimensiona pelo rótulo e
   assenta à direita (§H) — ali há mais de um alvo na linha, aqui não. */
.conf-foot{display:flex;padding:16px 20px;background:var(--surface);border-top:1px solid var(--line)}
.conf-foot .btn{flex:1 1 auto;justify-content:center}
/* Pé de avanço que não fecha uma tabela. Dentro do `.conf` a faixa é o pé do painel e a borda
   superior é a única que lhe falta — o resto vem do recorte do painel. Fora dele, a mesma faixa
   fica com uma borda só, encostada a nada; a variante fecha a caixa e retoma o raio do painel,
   de modo que o avanço leia como peça inteira em vez de sobra da que saiu. É o caso do
   embalamento, a única etapa em dois painéis lado a lado. */
.conf-foot.solta{border:1px solid var(--line);border-radius:var(--r-panel);width:100%}

.block-title{background:var(--th-bg);color:var(--text-2);padding:14px 20px;font-size:14px;font-weight:800;text-transform:uppercase;letter-spacing:.1em;border-bottom:1px solid var(--line)}

/* totalizadores */
.totbar{display:flex;flex-wrap:wrap;align-items:center;gap:12px;width:100%}
.grow{flex:1 1 auto}
.tot{display:flex;flex-direction:column;gap:2px;padding:9px 16px;background:#F4F4F5;border:1px solid var(--line-soft);border-radius:var(--r-btn);min-width:120px;min-height:62px;justify-content:center}
.tot .k{font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.07em;color:var(--muted)}
.tot .v{font-size:20px;font-weight:800;font-variant-numeric:tabular-nums;line-height:1.1}

/* chips de situação — cor local por domínio (§G) */
.chip{display:inline-flex;align-items:center;justify-content:center;gap:.4em;height:30px;min-width:112px;padding:0 14px;border-radius:var(--r-chip);font-size:12.5px;font-weight:700;line-height:1;white-space:nowrap;vertical-align:middle;border:1px solid rgba(0,0,0,.14)}
.chip svg{width:14px;height:14px}
/* bloco de situação que carrega um dado junto do chip — a data do agendamento (§G) */
.chipstack{display:flex;flex-direction:column;align-items:center;gap:7px}
.chipstack .cs-sub{font-size:13.5px;font-weight:700;color:var(--text-2);font-variant-numeric:tabular-nums;line-height:1}
.s-fin{background:#CDEBD5;color:#166534;border-color:#A8D6B4}           /* finalizado — verde */
.s-canc{background:#FBD8D8;color:#991B1B;border-color:#F0B4B4}          /* cancelado — vermelho */
.s-oper{background:#CDEDE7;color:#0F5E54;border-color:#A6DBD1}          /* operante — verde-água */
.s-pend{background:#FCE9CE;color:#8A4B10;border-color:#E9C79B}          /* pendente — pêssego */
.s-sep{background:#FBF3D0;color:#7A5B00;border-color:#E8D9A0}           /* separado — creme */
.s-emb{background:#D4E7FB;color:#1E4E8C;border-color:#AFCDF0}           /* embalado — azul claro */
.s-carr{background:#D8F0DC;color:#1B6B34;border-color:#B0DDB8}          /* carregado — verde claro */
.s-pause{background:#FCEFC7;color:#8A5A00;border-color:#EAD79A}         /* pausada */
.s-agend{background:#D4E7FB;color:#1E4E8C;border-color:#AFCDF0}         /* compra agendada — azul */
.s-entr{background:#CDEBD5;color:#166534;border-color:#A8D6B4}          /* compra entregue — verde */
.s-cri{background:#FBF3D0;color:#7A5B00;border-color:#E8D9A0}           /* criado — creme */
.s-estq{background:#FBF3D0;color:#7A5B00;border-color:#E8D9A0}          /* estoque — creme */
.s-ideal{background:#D8F0DC;color:#1B6B34;border-color:#B0DDB8}         /* ideal */
.s-abaixo{background:#FBF3D0;color:#7A5B00;border-color:#E8D9A0}        /* abaixo */
.s-critico{background:#FBD8D8;color:#991B1B;border-color:#F0B4B4}       /* crítico */
.s-ent{background:#D8F0DC;color:#1B6B34;border-color:#B0DDB8}           /* entrada */
.s-sai{background:#FBD8D8;color:#991B1B;border-color:#F0B4B4}           /* saída */
.s-ativo{background:#D8F0DC;color:#1B6B34;border-color:#B0DDB8}         /* funcionário ativo */
.s-inativo{background:#FBD8D8;color:#991B1B;border-color:#F0B4B4}       /* funcionário inativo */
.s-entrega{background:#CDEBD5;color:#166534;border-color:#A8D6B4}
.s-aguarda{background:#FCE9CE;color:#8A4B10;border-color:#E9C79B}
.s-devol{background:#D4E7FB;color:#1E4E8C;border-color:#AFCDF0}
.s-sinistro{background:#FBD8D8;color:#991B1B;border-color:#F0B4B4}

/* estoque mínimo / multivalorado */
.multi{display:inline-flex;align-items:center;gap:6px;font-weight:600}
.multi .more{color:var(--brand);font-weight:800}
/* placeholder de vazio: travessão multivalorado e mensagem "Nenhum …" sob a tabela */
.empty{color:var(--muted)}
p.empty{padding:18px;text-align:center;font-weight:600}

/* silos (SPEC Controle de Silos — sem wireframe; do texto) */
.silo-sec{width:100%;border-radius:var(--r-panel);padding:16px 18px 18px;border:1px solid var(--line-soft)}
.silo-sec.t-receb{background:#F4F1EC}
.silo-sec.t-comp{background:#F1F4EC}
.silo-sec.t-proc{background:#ECF0F4}
.silo-sec.t-processado{background:#F4ECEC}
.silo-sec.t-prod{background:#F1ECF4}
.silo-sec .sec-lbl{font-size:15px;font-weight:800;text-transform:uppercase;letter-spacing:.1em;color:var(--text-2);margin:0 0 14px;padding-bottom:10px;border-bottom:1px solid var(--line)}
.silo-row{display:flex;gap:20px;flex-wrap:wrap}
.silo2{width:196px;border:1px solid var(--line);border-radius:var(--r-panel);overflow:hidden;background:var(--surface)}
.silo2 .vessel{position:relative;height:112px;background:#F1F1F2;border-bottom:1px solid var(--line)}
.silo2 .fill{position:absolute;left:0;right:0;bottom:0;transition:height .2s}
.silo2 .fill.grao{background:#C6A05E}
.silo2 .fill.torrado{background:#5A3A22}
.silo2 .fill.po{background:#3D2817}
.silo2 .fill::after{content:"";position:absolute;inset:0}
.silo2 .fill.grao::after{background-image:radial-gradient(circle at 3px 3px, rgba(0,0,0,.28) 1.4px, transparent 1.6px);background-size:9px 9px}
.silo2 .fill.torrado::after{background-image:radial-gradient(circle at 3px 3px, rgba(255,255,255,.16) 1.3px, transparent 1.5px);background-size:8px 8px}
.silo2 .fill.po::after{background-image:repeating-linear-gradient(45deg, rgba(255,255,255,.10) 0 2px, transparent 2px 5px)}
.silo2 .peso{position:absolute;top:8px;left:0;right:0;margin:0 auto;width:fit-content;padding:2px 10px;text-align:center;font-size:22px;font-weight:800;font-variant-numeric:tabular-nums;color:var(--text);z-index:1;background:rgba(255,255,255,.9);border:1px solid rgba(0,0,0,.08);border-radius:8px}
.silo2 .estado-tag{position:absolute;bottom:6px;left:6px;z-index:1;font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.05em;padding:2px 7px;border-radius:6px;background:rgba(255,255,255,.9);color:var(--text)}
/* A pergunta que o operador faz ao silo é **o que está dentro**, e por isso o conteúdo é o
   título do card: a matéria ou o produto em 19px, sob a referência do vaso, que é rótulo de
   identidade e cabe no tamanho de um. Como par rótulo/valor a 12,5px o conteúdo era o menor
   texto de um card cuja razão de existir é declará-lo (§B.2). O Lote fica no par, porque é
   qualificador do conteúdo e só se lê depois dele. */
.silo2 .ref{padding:10px 12px 0;font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:.07em;color:var(--muted)}
.silo2 .conteudo{padding:2px 12px 0;font-size:19px;font-weight:800;line-height:1.2;overflow-wrap:break-word}
.silo2.vazio .conteudo{color:var(--muted)}
.silo2 .kv{padding:6px 12px 10px;font-size:12.5px;color:var(--muted);display:flex;justify-content:space-between;gap:10px;line-height:1.5}
.silo2 .kv b{color:var(--text);font-weight:700}
.silo2.vazio .vessel{background:repeating-linear-gradient(45deg,#F4F4F5,#F4F4F5 7px,#ECECEE 7px,#ECECEE 14px)}
.silo2.vazio .peso{color:var(--muted)}

/* calendário & bloco de notas (Compras de Matérias/Insumos, Agenda Laboratório) */
.calwrap{display:flex;flex-wrap:wrap;gap:18px;align-items:stretch;width:100%}
.cal{flex:1 1 560px;min-width:0;background:var(--surface);border:1px solid var(--line);border-radius:var(--r-panel);overflow:hidden}
.cal-wds{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));background:var(--th-bg);border-bottom:1px solid var(--line)}
.cal-wd{padding:11px 4px;text-align:center;font-size:12px;font-weight:800;text-transform:uppercase;letter-spacing:.06em;color:var(--text-2)}
.cal-wd+.cal-wd{border-left:1px solid var(--line-soft)}
.cal-grid{display:grid;grid-template-columns:repeat(7,minmax(0,1fr))}
.cal-day{display:flex;flex-direction:column;gap:5px;min-height:98px;padding:8px;border-bottom:1px solid var(--line-soft);border-left:1px solid var(--line-soft)}
.cal-day:nth-child(7n+1){border-left:0}
.cal-grid .cal-day:nth-last-child(-n+7){border-bottom:0}
.cal-day.out{background:#FAFAFA}
.cal-num{align-self:flex-start;font-size:14px;font-weight:700;font-variant-numeric:tabular-nums;color:var(--text-2);line-height:1}
.cal-day.out .cal-num{color:#A1A1AA}
.cal-day.today .cal-num{display:inline-flex;align-items:center;justify-content:center;min-width:26px;height:26px;padding:0 6px;background:var(--brand);color:#fff;border-radius:13px}
/* faixa de registro no dia — pílula cheia (cor + ícone + valor, §B.2); cor local à interface (§G) */
.cal-ev{display:flex;align-items:center;gap:6px;padding:5px 9px;border-radius:var(--r-chip);border:1px solid transparent;font-size:13px;font-weight:700;font-variant-numeric:tabular-nums;cursor:pointer;transition:filter .1s}
.cal-ev svg{width:13px;height:13px;flex:0 0 auto}
.cal-ev span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cal-ev:hover{filter:brightness(.96)}
.cal-ev:focus-visible{outline:2px solid var(--text-2);outline-offset:2px}
.cal-ev.verba{background:#D8F0DC;color:#1B6B34;border-color:#B0DDB8}     /* verba — verde (§G, local) */
.cal-ev.compra{background:#FBD8D8;color:#991B1B;border-color:#F0B4B4}    /* compra — vermelho (§G, local) */
.cal-ev.agendada{background:#D4E7FB;color:#1E4E8C;border-color:#AFCDF0} /* compra de insumo agendada — azul (§G, local) */
.cal-ev.entregue{background:#CDEBD5;color:#166534;border-color:#A8D6B4} /* compra de insumo entregue — verde */
.cal-ev.cancelada{background:#FBD8D8;color:#991B1B;border-color:#F0B4B4}/* compra de insumo cancelada — vermelho */
/* bloco de notas lateral — texto livre persistente, um por interface */
.notasblock{flex:0 1 300px;min-width:240px;display:flex;flex-direction:column;background:var(--surface);border:1px solid var(--line);border-radius:var(--r-panel);overflow:hidden}
.notasblock .nb-area{flex:1 1 auto;min-height:224px;padding:14px;border:0;outline:0;resize:none;background:var(--surface);font:inherit;font-size:15px;font-weight:600;line-height:1.45;color:var(--text)}
.notasblock .nb-area::placeholder{color:#A1A1AA;font-weight:600}
.notasblock .nb-area:focus-visible{box-shadow:inset 0 0 0 2px rgba(63,63,70,.16)}
.notasblock .nb-foot{display:grid;grid-template-columns:1fr 1fr;gap:10px;padding:12px 14px;border-top:1px solid var(--line-soft)}

/* ============================================================
   OVERLAYS — janela ancorada, notificações, diálogo de confirmação
   ============================================================ */

/* moldura partilhada dos dois overlays do canto inferior direito.
   O teto é da **moldura**, e a reserva que ele desconta é o que a janela **salta** para chegar à
   sua âncora: respiro de topo do conteúdo (28) + recuo do grupo de FABs (28) = 56 abaixo do
   cabeçalho. Ancorada acima da dupla, a reserva incluía também a coluna inteira de botões
   (72+16+72) e o respiro até ela (16) — 232 —, e o que se descontava saía do corpo, que é a
   única região ali que alguém lê: 436px de janela num tablet de 768px, com 2,3 mensagens à
   vista. Ao lado da dupla, a janela alcança a área de conteúdo inteira, 612px no mesmo tablet.
   Posto no corpo, o teto ignora `.wtop` e `.wfoot` e a janela sobe por cima do cabeçalho —
   mediu-se −30px de topo no tablet de 768px.
   A largura é **fluida entre piso e teto**, e contida pela área: fixa, ela é uma tira estreita
   na televisão do galpão e larga demais no tablet retrato. O termo de contenção não é folga —
   é ele que impede a janela de cobrir a faixa de flutuantes ao lado da qual ela assenta, e sem
   ele o piso sozinho transborda no aparelho estreito. */
.window{width:min(clamp(420px,30vw,720px),calc(100vw - var(--sb-col) - var(--fab-lane) - 64px));max-height:calc(100vh - var(--hd-h) - 56px);background:var(--surface);border:1px solid var(--line);border-radius:12px;overflow:hidden;display:flex;flex-direction:column}
/* Ancorada **ao lado** da dupla de FABs e alinhada ao rodapé dela: a janela pertence ao botão que
   a abre, e é por isso que assenta no seu eixo. O respiro é o `gap` do próprio `.fabs`. A dupla
   fica descoberta por desenho — é ela que alterna as duas janelas (SPECIFICATION.md CHAT), e
   cobri-la tiraria do operador o alvo que fecha o que ele abriu. */
.fabs .window{position:absolute;right:calc(100% + 16px);bottom:0}
.window .wtop{display:flex;align-items:center;justify-content:space-between;padding:10px 10px 10px 16px;border-bottom:1px solid var(--line-soft)}
.window .wtop .wt{font-size:15px;font-weight:800}
/* alvo de ícone sozinho: piso de toque nas duas dimensões (§B.4), glifo na escala do alvo (§B.10) */
.window .wtop .wx{width:62px;height:62px;border-radius:8px;display:inline-flex;align-items:center;justify-content:center;color:var(--muted)}
.window .wtop .wx:hover{background:#F1F1F2}
.window .wtop .wx svg{width:24px;height:24px}
/* O corpo absorve o que a moldura lhe deixa e rola. `min-height:0` porque o contêiner de rolagem
   tem mínimo automático do conteúdo em flex, e sem ele empurraria a moldura para além do teto. */
.window .wbody{flex:1 1 auto;min-height:0;padding:16px;display:flex;flex-direction:column;gap:12px;overflow-y:auto}
.window .wfoot{padding:12px 14px;border-top:1px solid var(--line-soft)}

/* chat — `chat-msg`, e não `msg`: a mensagem de validação de campo já é `.msg` em toda
   interface construída, e a colisão de nome faria uma das duas herdar o efeito da outra. */
.chat-msg{display:flex;flex-direction:column;gap:3px}
.chat-msg .who{font-size:12px;font-weight:800;color:var(--text-2)}
/* `overflow-wrap:anywhere` e não `break-word`: a mensagem é a única entrada livre do sistema que
   se re-exibe como prosa em caixa de largura fixa, e o código ou senha que o operador cola não tem
   oportunidade de quebra nenhuma — sem isto o balão vai a 620px dentro de um corpo de 458px e a
   janela corta o resto. `anywhere` também encolhe a largura mínima da caixa, que é o que faz o
   balão da mensagem própria parar de esticar. */
.chat-msg .bubble{max-width:100%;overflow-wrap:anywhere;background:var(--surface);border:1px solid var(--line-soft);border-radius:10px;padding:11px 14px;font-size:14px;line-height:1.45}
.chat-msg .bubble .at{color:var(--brand);font-weight:700}
.chat-msg .time{font-size:11px;color:var(--muted)}
.chat-msg.mine{align-items:flex-end}
.chat-msg.mine .bubble{background:#F0FDF4;border-color:var(--done-bd)}
/* a caixa é do contêiner — a entrada não veste `.input` por desenho (§7.1 da referência) */
.chat-compose{display:flex;align-items:center;gap:10px;background:var(--surface);border:1px solid var(--line);border-radius:var(--r-btn);padding:6px 6px 6px 14px}
.chat-compose input{flex:1 1 auto;min-width:0;border:0;outline:0;background:none;font:inherit;font-size:14px}
/* quem suprime o contorno nativo devolve o seu (§B.2) — o anel de `.input` e da busca */
.chat-compose:focus-within{border-color:var(--text-2);box-shadow:0 0 0 3px rgba(63,63,70,.08)}
.chat-compose .send{flex:0 0 auto;width:62px;height:62px;border-radius:8px;background:var(--ok);color:#fff;display:inline-flex;align-items:center;justify-content:center}
.chat-compose .send svg{width:24px;height:24px}

/* candidatos de menção — a lista que se refaz a cada tecla sobre o campo de composição. Existe
   porque o `usuario` é o token da menção e não é descobrível: Funcionários tem permissão própria,
   e sem a lista a menção obrigatória é adivinhação. Rola no seu próprio eixo, porque com `@`
   sozinho ela traz os quinze setores e todo o quadro — que é justamente o caso de descoberta. */
.mentions{max-height:280px;overflow-y:auto;margin-bottom:10px;background:var(--surface);border:1px solid var(--line);border-radius:var(--r-btn)}
.mentions .mn{display:flex;align-items:center;gap:12px;width:100%;min-height:62px;padding:8px 14px;text-align:left;border-bottom:1px solid var(--line-soft)}
.mentions .mn:last-child{border-bottom:0}
.mentions .mn:hover{background:#F1F1F2}
.mentions .mn svg{width:20px;height:20px;color:var(--muted)}
.mentions .mn-txt{display:flex;flex-direction:column;gap:2px;min-width:0}
.mentions .mn-id{font-size:14px;font-weight:800}
.mentions .mn-meta{font-size:12px;font-weight:600;color:var(--text-2);overflow-wrap:anywhere}

/* notificação — cartão colorido por nível (§J). Dois canais: o fundo e a etiqueta `.lvl`. */
.notif{display:flex;gap:12px;padding:14px 16px;border:1px solid var(--line-soft);border-radius:9px;width:100%}
.notif.crit{background:#FBDCDC}.notif.warn{background:#FCEFC7}.notif.info{background:#DCE9FB}
.notif .body{min-width:0;flex:1 1 auto}
.notif .nmeta{display:flex;align-items:center;gap:9px}
.notif .lvl{font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.06em;padding:2px 7px;border-radius:5px}
.notif.crit .lvl{background:#F7B9B9;color:#7A1414} .notif.warn .lvl{background:#F5DE9A;color:#7A5300} .notif.info .lvl{background:#B7CFF5;color:#123C7A}
.notif .nts{font-size:11.5px;color:var(--text-2);font-variant-numeric:tabular-nums}
/* as margens negativas derivam da caixa de 62px: devolvem à linha os mesmos 16px que os −14px
   devolviam sobre 44px, de modo que o alvo cresce sem engordar o cartão */
.notif .nclose{margin:-23px -10px -23px auto;width:62px;height:62px;color:var(--muted);display:inline-flex;align-items:center;justify-content:center}
.notif .nclose svg{width:24px;height:24px}
/* O texto é composto pelo sistema (§J), mas os códigos e nomes que ele interpola são digitados
   noutra tela: a mesma quebra do balão, pela mesma razão. */
.notif .m{overflow-wrap:anywhere;font-size:13.5px;font-weight:600;color:var(--text);margin-top:6px}
/* Rail dos toasts de chegada: a geometria de `.toasts` no rodapé da área de interface, e não no
   topo, porque o topo é do retorno da ação do próprio operador (§H) e os dois colidiriam. Sem
   `pointer-events:none` — este cartão tem X clicável, que é o que o distingue daquele. */
.ntoasts{position:fixed;bottom:18px;left:calc(50% + var(--sb-col)/2);transform:translateX(-50%);z-index:60;display:flex;flex-direction:column;gap:10px;width:min(440px,calc(100vw - var(--sb-col) - 32px))}

.modal{position:fixed;inset:0;z-index:50;display:grid;place-items:center;padding:20px;background:rgba(17,17,20,.45)}
.modal>.dialog{margin:0}
.dialog{width:100%;max-width:430px;background:var(--surface);border:1px solid var(--line);border-radius:var(--r-panel);box-shadow:0 12px 40px rgba(17,17,20,.18);overflow:hidden}
.dialog .dhead{padding:22px 24px 6px}
.dialog .dhead .dt{font-size:18px;font-weight:800}
.dialog .dhead p{font-size:14px;color:var(--text-2);margin-top:8px}
.dialog .dbody{padding:16px 24px 0}
.dialog .dfoot{display:grid;grid-template-columns:1fr 1fr;gap:12px;padding:18px 24px 22px}
.dialog .dfoot.one{grid-template-columns:1fr}
.viewfinder{display:block;width:100%;aspect-ratio:4/3;border-radius:var(--r-btn);background:var(--bg);object-fit:cover}
.shot{display:block;width:100%;aspect-ratio:4/3;border-radius:var(--r-btn);background:var(--bg);object-fit:cover;border:1px solid var(--line)}
.thumb{display:block;height:44px;aspect-ratio:4/3;border-radius:var(--r-chip);background:var(--bg);object-fit:cover;border:1px solid var(--line);margin:0 auto}

/* ---- responsivo: a barra deixa de tomar coluna e passa a sobrepor-se ---- */
/* Abaixo deste ponto as duas colunas não cabem lado a lado, e a barra deixa de tomar espaço: o
   conteúdo fica com a largura inteira e a barra, quando aberta, **sobrepõe-se** a ele. A regra
   anterior punha `1fr` na grade e deixava a barra de pé no fluxo, de modo que ela se empilhava
   **acima** do conteúdo com sessenta entradas e a altura útil toda — estado que nunca foi
   desenhado, e que só não aparecia porque o parque começa acima deste ponto (§H).
   `--sb-col` a zero leva junto os dois trilhos de aviso, que derivam dele e por isso deixam de
   precisar da sua própria correção aqui. A largura da barra sobreposta é `--sb-w`, declarada
   uma vez. O estado inicial recolhido é do cliente, que o decide na montagem. */
@media (max-width:960px){
  :root{--sb-col:0px}
  .sidebar{position:absolute;top:0;bottom:0;left:0;width:var(--sb-w);z-index:30;box-shadow:0 0 24px rgba(17,17,20,.28)}
}

/* ---- banner de reconexão (STANDARDS.md §H) ---- */
/* app.js marca <html class="disconnected"> enquanto o socket está caído. */
.conn-banner{position:fixed;inset:0 0 auto 0;z-index:50;display:none;align-items:center;justify-content:center;gap:10px;padding:14px 18px;background:var(--warn);color:#fff;font-size:15px;font-weight:700;text-align:center}
html.disconnected .conn-banner{display:flex}
html.disconnected body{pointer-events:none}
html.disconnected .conn-banner{pointer-events:auto}

/* ---- toast de flash — confirmação/erro de ação (CoreComponents.flash) ---- */
/* O toast pertence à **área de interface**, não ao viewport. Centrado em `50%` da tela ele assenta
   deslocado à esquerda do conteúdo, porque a barra lateral ocupa 310px que não são dele — e o
   operador procura a confirmação onde a ação aconteceu. O deslocamento é meia barra, e cai junto
   com a barra no ponto de quebra. */
.toasts{position:fixed;top:18px;left:calc(50% + var(--sb-col)/2);transform:translateX(-50%);z-index:60;display:flex;flex-direction:column;gap:10px;width:min(440px,calc(100vw - var(--sb-col) - 32px));pointer-events:none}
.toast{display:flex;align-items:center;gap:12px;padding:14px 16px;background:var(--surface);border:1px solid var(--line);border-radius:var(--r-panel);box-shadow:0 8px 24px rgba(17,17,20,.14);font-size:14.5px;font-weight:600;color:var(--text)}
.toast .ic{flex:0 0 auto;width:22px;height:22px;display:inline-flex;align-items:center;justify-content:center;border-radius:50%;color:#fff}
.toast .ic svg{width:14px;height:14px}
.toast .tmsg{flex:1 1 auto;min-width:0;line-height:1.4}
.toast.ok .ic{background:var(--ok)}
.toast.err .ic{background:var(--danger)}

/* ============================================================
   TELA DE LOGIN — porta de entrada; a marca vive aqui (§B.1)
   ============================================================ */
.login-wrap{min-height:100vh;display:flex;align-items:center;justify-content:center;padding:24px;background:var(--bg)}
.login-card{width:380px;max-width:100%;background:var(--surface);border:1px solid var(--line);border-radius:var(--r-panel);overflow:hidden}
.login-brand{background:var(--sb-bg);padding:26px;display:flex;justify-content:center}
.login-brand img{height:60px;width:auto}
.login-body{padding:24px;display:flex;flex-direction:column;gap:16px}
.login-err{padding:12px 14px;background:#FDF2F2;border:1px solid var(--danger);border-radius:var(--r-btn);color:var(--danger);font-size:14px;font-weight:700}
/* tela de ausência de acesso (DEVELOPMENT.md §J) — reaproveita o cartão do login */
.noaccess-msg{font-size:15px;font-weight:600;color:var(--text-2);text-align:center}

/* ============================================================
   FOLHA DE EXPORTAÇÃO — o documento gerado (STANDARDS.md §L.8)
   ============================================================ */
/* O PDF é este mesmo catálogo renderizado pelo Chromium: os totalizadores continuam na
   `.totbar` acima da tabela, alinhados à direita pelo `.totgroup` (§H). O que muda é só o
   que o papel não tem — superfície a destacar do fundo, para onde rolar, e página que não
   acaba. O `sticky` do cabeçalho é do scroll e desalinha a paginação; `table-header-group`
   é o que o repete em cada página, e o texto quebra porque sem rolagem horizontal a coluna
   larga sairia cortada pela margem. */
@page{size:A4;margin:14mm}
.folha{background:var(--surface);color:var(--text);font-family:var(--font);display:flex;flex-direction:column;gap:var(--rhythm)}
.folha-hd{font-size:24px;font-weight:800;letter-spacing:-.01em}
.folha .tablewrap{overflow:visible;border-radius:0;border:0;background:none}
.folha table.reg thead{display:table-header-group}
/* A tabela ocupa a página em vez da largura natural do seu conteúdo: sem a rolagem horizontal
   do `.tablewrap`, o que passa da margem é descartado do arquivo, sem nada que o acuse. O
   cabeçalho quebra em fronteira de palavra, a célula quebra também o que fronteira não tem, e
   o corpo vai na escala do papel — os 15px da tela são de alvo de toque e ali custam colunas. */
.folha table.reg{width:100%}
.folha table.reg th{position:static;white-space:normal;font-size:11px;padding:8px 6px}
.folha table.reg td{white-space:normal;overflow-wrap:break-word;height:auto;font-size:11px;padding:8px 6px}
.folha table.reg tfoot td{font-size:13px}
.folha table.reg tfoot td .agr{font-size:10px}
/* A tabela larga vira a folha, não corta: a rolagem horizontal do `.tablewrap` é da tela e no
   papel não tem equivalente. A paisagem é uma `@page` **nomeada** sobre a mesma folha, e o que
   a escolhe é a classe do corpo. */
@page paisagem{size:A4 landscape;margin:14mm}
.folha.paisagem{page:paisagem}
/* O que excede a paisagem reparte-se em faixas de colunas, cada uma repetindo o prefixo de
   identidade do alvo. A faixa seguinte abre página: continuada na mesma, as suas linhas leem-se
   como continuação das de cima, que são de outras colunas. */
.folha-faixa+.folha-faixa{break-before:page}
/* A grade de pares é a seção Informações no papel — a mesma do card, sem o bloco de situação ao
   lado, que é da tela. Fora do `.ped` ela perde a moldura que o card lhe dava. */
.folha .pgrid{border:1px solid var(--line-soft)}
/* O campo de assinatura — onde a conferência do agente ou do motorista converge, e por isso ao
   **fim** do documento e não ao lado. A altura da régua é a do alvo de toque do sistema: é o
   espaço que uma assinatura à mão ocupa, e não um valor escolhido para o papel. Sem Signatário
   digitado, a régua fica em branco para ser preenchida à mão. */
.assin{align-self:center;width:min(340px,60%);margin-top:20px;display:flex;flex-direction:column;align-items:center;gap:7px}
.assin-regua{width:100%;height:62px;border-bottom:1.5px solid var(--text)}
.assin-nome{font-size:15px;font-weight:700}
.assin-cap{font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:.07em;color:var(--muted)}

/* A ETIQUETA — o outro documento que o sistema gera (§L.8, SPECIFICATION.md ETIQUETAS
   PRODUÇÃO). Não é a folha e não herda nada dela: tem um QR e a sua legenda, sobre uma página
   cujo tamanho é o que o operador digitou em centímetros. O **tamanho da página é dado** e vem
   do pedido de impressão; o que é estilo é a **proporção** entre o QR e a legenda, declarada
   aqui uma vez em unidades relativas à caixa da etiqueta. Os dois escalam juntos, de modo que
   a razão é a mesma na etiqueta de 4cm e na de 12cm — uma legenda de medida fixa fica minúscula
   na grande e estoura a pequena, e o documento gera bem nos dois extremos. */
/* O `size:auto` é obrigatório e não é o default: a `@page` nomeada que o omite herda o
   `size:A4` da `@page` global acima, e com ele a **orientação retrato** — que vence o tamanho
   do pedido de impressão mesmo com `preferCSSPageSize` desligado. A etiqueta mais larga que
   alta saía **rodada**, com o documento a gerar bem e a suíte a passar. */
@page etiqueta{size:auto;margin:0}
.etq-pg{page:etiqueta;width:100vw;height:100vh}
.etq{container-type:size;width:100%;height:100%;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2.6cqmin;background:var(--surface);color:var(--text);font-family:var(--font)}
/* O QR herda a cor do texto em vez de a declarar: o módulo escuro é `fill:currentColor`, de
   modo que o contraste que o leitor de chão de fábrica precisa é o mesmo par de tokens do
   resto do sistema, declarado num lugar só. */
.etq-qr{width:74cqmin;height:74cqmin;display:block}
.etq-cod{font-size:14cqmin;line-height:1;font-weight:800;letter-spacing:-.02em}
