/* ============================================================
   cheff-ui.css — Portal do Colaborador · Loja Cheff
   Direção C "Superfície" · fechado em 03/08/2026 · superfície v3 em 03/09/2026 · 70 decisões
   Canônico em: ~/portal/public/cheff-ui.css
   A razão de cada regra está no Guia de UI. Não "conserte" o
   que parece inconsistente sem ler o porquê — quase tudo aqui
   é deliberado e tem custo registrado.
   ============================================================ */

/* ---------- 0.1 COR ------------------------------------------
   A TINTA (--fg) é a cor de COMANDO, não "cor de texto".
   Quatro cores semânticas, e cor SÓ diz estado (decisão 66, 03/09/2026):
     vermelho = queda, erro, destrutivo · verde = positivo ·
     âmbar = atenção (vence hoje, parada, baixo giro) · azul = informação
     neutra (novo, delegada, "atualizado às").
   PROIBIDO continua: cor decorativa, azul de LINK, cor em botão comum,
   cor em ícone de menu, gradiente.
   Fundo da página é N100 (#F5F4F2) e o card é branco: quem separa o bloco
   do fundo é a SOMBRA (decisão 61-62). Cinza de contenção (--fill) marca
   ativo, controle e cabeçalho — nunca decora.
   Todo texto ≥ 4.5:1. Cinza novo entra só depois de medido. */
:root{
  /* ---------- 0.0 TOKENS SEMÂNTICOS (decisão 60, 03/09/2026) ----------
     Nome de PAPEL, nunca de cor. Todo componente lê daqui; fora deste
     bloco não existe #fff nem #000 (travado por teste). O modo escuro é
     uma segunda tabela destes mesmos nomes — nada de regra por tema em
     componente. */
  --page-bg:#F5F4F2;        /* fundo da página — N100 (decisão 61); card branco por cima */
  --surface:#FFFFFF;        /* card, popover, modal, campo, botão secundário */
  --surface-2:#FAF9F8;      /* cabeçalho de card dividido */
  --hover:#FAF9F8;          /* linha sob o cursor */
  --fill:#F5F4F2;           /* contenção: trilho, cabeçalho de tabela, selo neutro */
  --fg:#121110;             /* texto e comando — 18.9:1 no branco */
  --fg-2:#2E2C2A;           /* texto secundário */
  --fg-mut:#6F6B66;         /* apoio — 5.29 no branco · 5.03 no --hover · 4.81 no --fill (decisão 65) */
  --fg-dis:var(--fg-mut);   /* texto de controle desabilitado — mesmo degrau do apoio desde a decisão 65 */
  --on-fg:#FFFFFF;          /* texto sobre --fg e sobre cor forte (primário, toast, badge do menu) */
  --on-fg-mut:rgba(255,255,255,.62);   /* apoio sobre --fg — 4.6:1, medido */
  --knob:#FFFFFF;           /* bolinha do interruptor */
  --logo-filter:none;       /* a logo é PNG preto: no escuro vira invert(1) (único caso de imagem) */
  --line:#ECEBE9;           /* divisor dentro do card (linha, célula) */
  --line-shell:#E0DED9;     /* fio do shell sobre o fundo N100: lateral, topo, rodapé — #ECEBE9 seria mais claro que o fundo */
  --scrim:rgba(18,17,16,.4); /* cortina de modal */
  --line-card:#ECEBE9;      /* fio do card: 1,08 sobre N100, e é deliberado — o halo da sombra faz o contorno (decisão 62) */
  --line-2:#DCDBD8;         /* fio de controle */
  --ring:0 0 0 3px rgba(18,17,16,.08);   /* anel de foco de campo */
  --red:#D2232A;    --red-bg:#FCEBEB;     /* Pantone 485 C — SÓ queda, erro, destrutivo · 5.23 no branco · 4.54 no selo */
  --green:#0E7A46;  --green-bg:#E3F1E9;   /* SÓ positivo · 5.40 · 4.63 */
  --amber:#9A5B00;  --amber-bg:#FBF0DC;   /* atenção · 5.43 · 4.81 (decisão 66) */
  --blue:#2F5D8A;   --blue-bg:#E7EEF6;    /* informação neutra · 6.88 · 5.88 (decisão 66) */

  /* apelidos legados — as 99 views leem estes nomes; não remover */
  --ink:var(--fg);
  --ink-2:var(--fg-2);
  --mut:var(--fg-mut);

  /* série de gráfico — máx. 2 por valor (ver 0.9) */
  --s1:var(--ink);
  --s2:#949089;         /* 3.1:1 — se sustenta sozinho */
  --grid:var(--line);   /* grade e trilho, NUNCA série */

  /* ---------- 0.3 ESPAÇO — base 4, nada fora da régua ---------- */
  --sp-1:4px;  --sp-2:8px;  --sp-3:12px; --sp-4:16px; --sp-5:20px;
  --sp-6:24px; --sp-7:32px; --sp-8:40px; --sp-9:48px; --sp-10:64px;

  /* ---------- 0.4 RAIO — o quadrado vem da logo ----------
     v2 (19/08/2026): 4→6 e 6→10. O raio maior suaviza sem virar bolha;
     o quadrado da marca continua nos cantos vivos da logo e do shell. */
  --r-1:6px; --r-2:10px; --r-full:999px;

  /* ---------- 0.4b SUPERFÍCIE (v2) ----------
     Cinza de CONTENÇÃO, não de decoração: marca o que está ativo, o que é
     controle e o que é cabeçalho. Desde 03/09/2026 (decisão 61) o fundo da
     PÁGINA é este mesmo N100 e o card é branco por cima: o cinza que era
     reprovado em 19/08 foi aprovado quando veio com sombra.
     --mut (#6F6B66, decisão 65) dá 4.81 sobre --surf e passa. */
  --surf:var(--fill);

  /* ---------- 0.5 SOMBRA — quente, nunca preto puro ---------- */
  --sh-1:0 1px 2px rgba(18,17,16,.03);   /* v2: com preenchimento e raio maior, a sombra pesa */
  --sh-2:0 1px 2px rgba(18,17,16,.05), 0 2px 10px -4px rgba(18,17,16,.14);
  --sh-3:0 8px 20px -6px rgba(18,17,16,.16), 0 24px 60px -20px rgba(18,17,16,.28);
  /* sombra do card (decisão 62): halo de 3% faz o contorno, a camada larga
     faz o bloco existir sobre o N100. Escolha do owner na prancheta v2. */
  --card-sh:0 0 0 1px rgba(18,17,16,.03), 0 1px 2px rgba(18,17,16,.05), 0 6px 18px -6px rgba(18,17,16,.16);

  /* ---------- 0.6 MOVIMENTO — tudo < 300ms ---------- */
  --ease-out:cubic-bezier(.23,1,.32,1);
  --ease-in-out:cubic-bezier(.77,0,.175,1);
  --ease-drawer:cubic-bezier(.32,.72,0,1);
  --t-press:140ms; --t-fast:160ms; --t-ui:200ms; --t-panel:260ms;

  /* ---------- medidas ---------- */
  --side-w:224px;  /* v2: era 248 */

  /* Respiro no alto da página. Token PRÓPRIO porque dois lugares precisam
     concordar: o padding da .page e a compensação do cabeçalho grudento
     (que come esse respiro pra que o fundo branco cubra tudo ao grudar).
     Em 20/08/2026 eles discordaram — a .page foi pra 20px e a compensação
     ficou em 32 — e o conteúdo passou a entrar 12px POR BAIXO do
     cabeçalho. Com um token só, não tem como divergir de novo. */
  --page-pt:var(--sp-6);
  --page-px:var(--sp-6);        /* respiro lateral da página; o cabeçalho grudado cobre esse respiro (decisão 76) */

  /* ---------- ESCALA DE CONTROLE (v2, 19/08/2026) ----------
     Três degraus e nada mais. Antes disso, o mesmo cabeçalho de card
     tinha segmentado 30px/11.5, botão pequeno 32px/12.5 e select 40px/16
     — o owner viu na tela e reprovou. Agora barra < ação < campo.
       --bar-h  controle DENTRO de barra/cabeçalho de card: segmentado,
                select de filtro, busca de tabela, tbl-input, botão pequeno
       --ctl-h  botão de ação da página
       --fld-h  campo de formulário (alvo de mira e permanência)
     --bar-fs é a fonte única desses controles. No celular ela volta a 16px
     porque abaixo disso o Safari do iPhone dá zoom sozinho ao focar — a
     regra dura continua valendo exatamente onde ela tem objeto. */
  --bar-h:32px;
  --bar-fs:13px;
  --fld-fs:13.5px; /* fonte do campo de formulário no mouse (owner, 13/09/2026) — 16px no toque, ver abaixo */
  --ctl-h:36px;    /* v2: era 40 */
  --fld-h:46px;    /* campo: alvo de mira e permanência — maior de propósito */
  --w-app:1440px;
}
/* Largura NÃO é o critério certo pra fonte de campo. O que dispara o zoom
   automático do Safari é ser um dispositivo de TOQUE, não a tela ser estreita:
   um iPad em paisagem tem 1024px e zoomaria do mesmo jeito. `pointer:coarse`
   pega o caso certo. Era um defeito da v2, que amarrou --bar-fs a 760px.
   Altura e alvo de toque seguem na largura: lá o critério é o layout. */
@media (max-width:759px){ :root{ --bar-h:44px; --ctl-h:44px; --fld-h:50px; } }
/* Filtros · Ordenar · Colunas cabiam em duas fileiras no iPhone (mais ~60px
   de cabeçalho antes da tabela). Com o padding menor os três entram numa
   linha só, e a altura de 44px do alvo de toque fica intacta. */
@media (max-width:759px){
  .card__head .btn--sm{ padding-left:var(--sp-3); padding-right:var(--sp-3) }
  /* os gatilhos de popover da barra dividem a linha em partes iguais: em
     390px, "Colunas" caía sozinho numa segunda fileira e custava mais 52px
     antes da primeira linha da tabela. */
  .card__head > .pop__wrap{ flex:1 1 0; min-width:0 }
  .card__head > .pop__wrap > .btn{ width:100% }
}
@media (pointer:coarse){ :root{ --bar-fs:16px; --fld-fs:16px } }

/* ---------- 0.0b MODO ESCURO (decisão 69, 03/09/2026) ----------
   Uma segunda tabela de valores para os MESMOS tokens. Nenhum componente
   tem regra de tema; o que não estiver em token não muda de cor, e é isso
   que a guarda da decisão 60 garante. Contrastes medidos ≥ 4,5 em toda
   combinação de texto. "A tinta é a cor de comando": o botão primário no
   escuro é claro com texto escuro (16,46).
   Quem escolheu "escuro" recebe data-theme="dark" do servidor (decisão 70);
   quem escolheu "sistema" não recebe atributo e cai na media query. */
:root[data-theme="dark"]{
  color-scheme:dark;
  --page-bg:#141312;
  --surface:#1E1C1A;        /* 1,09 sobre a página: a sombra some, o fio trabalha */
  --surface-2:#242220;
  --hover:#242220;
  --fill:#2B2926;
  --fg:#F3F1EE;             /* 15,07 na superfície */
  --fg-2:#D3CFC8;           /* 10,94 */
  --fg-mut:#A39C93;         /* 6,26 na superfície · 5,34 no --fill */
  --on-fg:#141312;          /* texto sobre a tinta clara */
  --on-fg-mut:rgba(20,19,18,.62);
  --knob:#F3F1EE;
  --logo-filter:invert(1);
  --line:#33302C;           /* 1,29 sobre a superfície */
  --line-shell:#33302C;
  --line-card:#33302C;
  --line-2:#403C37;
  --ring:0 0 0 3px rgba(243,241,238,.14);
  --scrim:rgba(0,0,0,.55);
  --card-sh:0 0 0 1px rgba(0,0,0,.35);   /* sombra sobre preto não separa; o halo escuro faz o contorno */
  --s2:#A39C93;
  --red:#F28A8D;    --red-bg:#3B1F20;     /* 7,11 na superfície · 6,27 no selo */
  --green:#66C592;  --green-bg:#183227;   /* 8,06 · 6,54 */
  --amber:#E8AC55;  --amber-bg:#3A2C15;   /* 8,46 · 6,75 */
  --blue:#88B4E0;   --blue-bg:#1C2A3A;    /* 7,81 · 6,69 */
}
@media (prefers-color-scheme:dark){
:root:not([data-theme="light"]){
  color-scheme:dark;
  --page-bg:#141312;
  --surface:#1E1C1A;        /* 1,09 sobre a página: a sombra some, o fio trabalha */
  --surface-2:#242220;
  --hover:#242220;
  --fill:#2B2926;
  --fg:#F3F1EE;             /* 15,07 na superfície */
  --fg-2:#D3CFC8;           /* 10,94 */
  --fg-mut:#A39C93;         /* 6,26 na superfície · 5,34 no --fill */
  --on-fg:#141312;          /* texto sobre a tinta clara */
  --on-fg-mut:rgba(20,19,18,.62);
  --knob:#F3F1EE;
  --logo-filter:invert(1);
  --line:#33302C;           /* 1,29 sobre a superfície */
  --line-shell:#33302C;
  --line-card:#33302C;
  --line-2:#403C37;
  --ring:0 0 0 3px rgba(243,241,238,.14);
  --scrim:rgba(0,0,0,.55);
  --card-sh:0 0 0 1px rgba(0,0,0,.35);   /* sombra sobre preto não separa; o halo escuro faz o contorno */
  --s2:#A39C93;
  --red:#F28A8D;    --red-bg:#3B1F20;     /* 7,11 na superfície · 6,27 no selo */
  --green:#66C592;  --green-bg:#183227;   /* 8,06 · 6,54 */
  --amber:#E8AC55;  --amber-bg:#3A2C15;   /* 8,46 · 6,75 */
  --blue:#88B4E0;   --blue-bg:#1C2A3A;    /* 7,81 · 6,69 */
}
}

/* ---------- 0.2 TIPOGRAFIA — Manrope. Hierarquia por tamanho
   e peso, NUNCA por cor. Tracking é específico por tamanho. --- */
body{ margin:0; background:var(--page-bg); color:var(--ink);
  font-family:'Manrope',system-ui,-apple-system,sans-serif;
  font-size:14px; line-height:1.55; -webkit-font-smoothing:antialiased; }
.t-display{ font-size:30px; line-height:1.05; font-weight:800; letter-spacing:-.035em; }
.t-title  { font-size:20px; line-height:1.2;  font-weight:800; letter-spacing:-.025em; }
.t-head   { font-size:15px; line-height:1.3;  font-weight:700; letter-spacing:-.015em; }
.t-panel  { font-size:13px; line-height:1.3;  font-weight:700; letter-spacing:-.01em;  }
.t-caption{ font-size:11.5px; line-height:1.4; font-weight:500; color:var(--mut); }
.t-micro  { font-size:10px; line-height:1.3; font-weight:700; letter-spacing:.12em;
            text-transform:uppercase; color:var(--mut); }
.num      { font-variant-numeric:tabular-nums; }
/* "Número M" da escala do guia (0.2): total, subtotal, placar. Estava na
   TABELA de tipografia desde agosto mas nunca virou classe — 8 lugares
   escreviam 20px/800 à mão. */
.t-num-m  { font-size:20px; line-height:1; font-weight:800; letter-spacing:-.03em;
            font-variant-numeric:tabular-nums; }
/* unidade NÃO é dado — e por isso também não tem o tom do dado.
   O `color` entrou em 20/08/2026: o BI já escrevia `.72em + 700 + --ink-2`
   à mão em 8 lugares, e a prática estava mais completa que a classe.
   ⚠️ Muda o tom da unidade nos 3 usos antigos de `.u` (fica um passo mais
   claro que o número). É melhoria deliberada, não efeito colateral. */
.u        { font-size:.72em; font-weight:700; color:var(--ink-2) }
.prose    { max-width:65ch; }

/* ---------- base ---------- */
*{ box-sizing:border-box }
/* [hidden] SEMPRE vence: sem isso, qualquer elemento com display próprio
   (flex/grid) ignora o atributo e "vaza" na tela. Cobre o caso geral que
   .modal[hidden] etc. cobriam um a um. */
[hidden]{ display:none!important }
a{ color:inherit; text-decoration:none }
button{ font:inherit; color:inherit; cursor:pointer }
/* Controle de formulário herda a fonte da página (lote de ajustes, 13/09/2026).
   Sem isto, campo fora de .field nasce com a fonte do SISTEMA: o envio de
   planilha da Campanha da marca media 22px de altura em Arial 13,33px.
   :where() zera a especificidade: qualquer regra de componente vence. */
:where(input,select,textarea){ font:inherit; color:inherit }
:focus-visible{ outline:2px solid var(--red); outline-offset:2px }  /* único uso não-semântico do vermelho */
/* depois de um toque ou clique, foco movido pelo código não desenha anel (o
   iPhone acendia o anel de teclado no ☰ ao fechar o menu, 14/09/2026). Uma
   tecla qualquer volta a mostrar: quem navega por teclado não perde nada.
   Lido do cheff-ui.js (data-entrada no <html>). */
:root[data-entrada="ponteiro"] :focus-visible{ outline:none }
button:active,[role="button"]:active{ transform:scale(.97) }
button,[role="button"]{ transition:transform var(--t-press) var(--ease-out) }
@media (prefers-reduced-motion:reduce){ *{ transition-duration:0ms!important; animation:none!important } }

/* ============================================================
   1. SHELL — lateral SEMPRE transparente, nunca escura
   ============================================================ */
.app{ display:flex; height:100vh; overflow:hidden }
.side{ width:var(--side-w); flex:0 0 var(--side-w); display:flex; flex-direction:column;
  padding:var(--sp-4) var(--sp-3); background:transparent; border-right:1px solid var(--line-shell) }
/* menu v2 (31/08/2026): os rótulos de grupo (.nav__label) e o espaçador
   entre grupos (.nav__group) morreram — o menu é uma pilha única de botões
   de 1º nível; hierarquia vem do acordeão, não de rótulo em caixa alta. */
.nav__item{ display:flex; align-items:center; gap:var(--sp-3); padding:var(--sp-2) var(--sp-3);
  font-size:13px; color:var(--ink-2); border-radius:var(--r-2);
  transition:background var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out) }
/* v3 (03/09/2026, decisão 68): item ativo = CARD BRANCO elevado, a letra
   original da seção 1 do guia. A v2 tinha trocado por preenchimento cinza
   porque o card branco sumia sobre lateral branca; com o fundo N100 o card
   branco é exatamente o que se lê de longe. Única elevação da lateral. */
.nav__item.is-active{ background:var(--surface); color:var(--ink); font-weight:700;
  border:1px solid var(--line-card); box-shadow:var(--card-sh) }
@media (hover:hover) and (pointer:fine){ .nav__item:hover:not(.is-active){ background:var(--hover) } }
.topbar{ display:flex; align-items:center; gap:var(--sp-4); height:48px; flex:0 0 48px;
  padding:0 var(--sp-5); border-bottom:1px solid var(--line-shell) }
.topbar__l,.topbar__r{ display:flex; align-items:center; gap:var(--sp-3) }
.topbar__r{ flex:1 1 auto; justify-content:flex-end }
@media (max-width:759px){
  /* laterais de largura igual mantêm a logo no centro exato */
  .topbar__l,.topbar__r{ flex:1 1 0 }
  /* z-index 45 (era 20): o menu aberto fica acima de tudo que mora na página
     (balão de gráfico 30, popover 40/39) e abaixo do diálogo (scrim 50). Em 20,
     o balão do BI desenhava por cima do menu (print do owner, 13/09/2026). */
  .side{ position:fixed; inset:0 auto 0 0; z-index:45; background:var(--surface); width:270px;
    transform:translateX(-100%); transition:transform var(--t-panel) var(--ease-drawer);
    box-shadow:var(--sh-3) }
  body.nav-open .side{ transform:translateX(0) }   /* entra e sai pelo MESMO lado */
  /* o menu recebe o foco ao abrir só pra tirar o foco da página: ele mesmo não
     é alvo de Tab (tabindex -1), então não desenha anel */
  .side:focus{ outline:none }
  /* Áreas seguras do iPhone (14/09/2026): com viewport-fit=cover e a barra de
     status translúcida, a página desenha sob o relógio e sob a barra de início.
     O topo e o menu descem o tamanho da faixa; fora do app instalado env() vale 0
     e nada muda. */
  .topbar{ padding-top:env(safe-area-inset-top); height:calc(48px + env(safe-area-inset-top));
    flex-basis:calc(48px + env(safe-area-inset-top)) }
  .side{ padding-top:calc(var(--sp-4) + env(safe-area-inset-top));
    padding-bottom:calc(var(--sp-4) + env(safe-area-inset-bottom)) }
  .content{ padding-bottom:env(safe-area-inset-bottom) }
  .nav__item{ padding:14px var(--sp-4) }
}

/* ============================================================
   2. PÁGINA — Início (saudação) · App (título+ação) · Aninhada
   ============================================================ */
.page{ padding:var(--page-pt) var(--page-px) var(--sp-9); max-width:var(--w-app); margin:0 auto; width:100% }
.page--wide{ max-width:none }                       /* telas de tabela */
/* --- 59. RITMO VERTICAL DA PÁGINA vem do .page, não da view (03/09/2026) ---
   Owner: "quase toda tela nova nasce sem espaçamento, sem respiro; já falei isso
   algumas vezes". Causa: o .page era um bloco sem ritmo e o respiro entre cards
   dependia de cada view lembrar do mb-4 (16 telas faziam à mão; a 17ª esquecia).
   Agora todo filho do .page nasce a 20px do anterior (guia §2: 20px entre blocos;
   16 no celular). Margens manuais (mb-*) COLAPSAM com esta em layout de bloco:
   não somam, então as telas antigas não ficam mais espaçadas do que já eram.
   O cabeçalho da página já traz o próprio respiro (padding-bottom): filho logo
   depois dele não ganha margem. Travado por teste (design-system). */
.page > * + *{ margin-top:var(--sp-5) }
.page > .page__head + *{ margin-top:0 }
@media (max-width:759px){ .page > * + *{ margin-top:var(--sp-4) } }
/* 24px entre cabeçalho e conteúdo. O guia pedia 32; a v2 cortou pra 16 e o
   owner apontou que ficou apertado (20/08). 24 é o meio-termo medido. */
/* ── Barra de rolagem ─────────────────────────────────────────────────────
   No macOS ela é overlay e some sozinha; no Windows é a clássica: ~17px,
   com setas nas pontas, permanente em toda área que rola. O mesmo Portal
   ganhava dois riscos cinza grossos que ninguém desenhou — no menu lateral e
   dentro do campo de aviso (relatado pelo owner em 20/08, print do desktop).
   Cinza é permitido em fio e texto de apoio (decisão 3); barra de sistema
   larga não é nem uma coisa nem outra. Padronizada para os dois sistemas.

   Chrome ≥121 e Firefox obedecem `scrollbar-width`/`-color` e IGNORAM as
   regras `::-webkit-`; as `::-webkit-` ficam para Safari e Chrome antigo.
   As duas descrições desenham a mesma barra: fina, trilho transparente,
   polegar no cinza de fio, escurecendo no hover. */
*{ scrollbar-width:thin; scrollbar-color:var(--line) transparent }
::-webkit-scrollbar{ width:10px; height:10px }
::-webkit-scrollbar-track,
::-webkit-scrollbar-corner{ background:transparent }
::-webkit-scrollbar-thumb{ background:var(--line); border-radius:var(--r-full);
  border:3px solid transparent; background-clip:content-box }
::-webkit-scrollbar-thumb:hover{ background:var(--mut); background-clip:content-box }
/* rolar o menu até o fim não pode continuar rolando a página atrás dele */
.side__nav, .content, .modal__body, .palette__list{ overscroll-behavior:contain }

.page__head{ display:flex; align-items:flex-start; gap:var(--sp-4); padding-bottom:var(--sp-6) }
.page__head--sticky{ position:sticky; top:0; background:var(--page-bg); z-index:5;
  padding-top:var(--page-pt); margin-top:calc(var(--page-pt) * -1);
  /* Decisão 76, causa medida em 15/09/2026: o cabeçalho tinha a largura do
     conteúdo e deixava os 24px de respiro lateral descobertos; a sombra do
     card rolando por baixo aparecia ali como uma linha vertical fina dos dois
     lados. O cabeçalho agora cobre o respiro inteiro da página. */
  margin-inline:calc(var(--page-px) * -1); padding-inline:var(--page-px) }
/* Decisão 76 (15/09/2026): revoga o fio da rodada 2 — "linha esquisita ao
   rolar" (relato repetido do owner). O cabeçalho gruda no MESMO fundo da
   página (--page-bg): não precisa de fio nem sombra pra separar, o conteúdo
   simplesmente passa por baixo. Padding/margin do "grudado" ficam — só a
   borda sai. */
.page__head--sticky.is-stuck{ padding-bottom:var(--sp-4); margin-bottom:var(--sp-4) }
.page__actions{ margin-left:auto; display:flex; gap:var(--sp-2); flex:0 0 auto }
/* Cards irmãos empilhados na página respiram (achado 30/08: Itens × Aguardando
   cadastro colados no detalhe do pedido). Regra global: correção mora aqui,
   nunca na página. */
.page > .card + .card{ margin-top:var(--sp-4) }
.cols{ display:grid; grid-template-columns:minmax(0,1.55fr) minmax(0,1fr);
  gap:var(--sp-4); align-items:start }               /* conteúdo curto NÃO estica */
/* par de colunas do MESMO peso (BI v2: Por empresa / Por canal) — o par
   assimétrico acima é .cols puro; aqui os dois lados pesam igual. */
.cols--eq{ grid-template-columns:1fr 1fr }
/* trilho estreito fixo + conteúdo que sobra (Base de Conhecimento, spec
   2026-09-19): a árvore de seções não pode crescer com o conteúdo — 256px é
   o suficiente pro nome mais longo de área sem quebrar em 2 linhas toda hora. */
.cols--tree{ grid-template-columns:256px minmax(0,1fr) }
@media (max-width:899px){ .cols, .cols--eq, .cols--tree{ grid-template-columns:1fr } }
@media (min-width:900px){ .cols--tree > :first-child{ position:sticky; top:var(--sp-4) } }
@media (max-width:759px){
  .page{ --page-px:var(--sp-4); padding:var(--page-pt) var(--page-px) var(--sp-8) }
  .page__head{ flex-direction:column; gap:var(--sp-4) }
  /* v2.1 (24/08/2026): com 3-4 ações o nowrap empurrava o primário pra fora
     da tela (x=604 em 390px, catálogo/pedido). Quebra linha; o primário
     fecha sozinho em largura cheia, alcançável sem rolagem horizontal. */
  .page__actions{ margin-left:0; width:100%; flex-wrap:wrap }
  .page__actions .btn--primary{ flex:1 1 100% }     /* primário ocupa a largura */
  .page__actions > form:has(> .btn--primary){ flex:1 1 100% }   /* primário embrulhado em form (Emitir) */
  .page__actions > form > .btn--primary{ width:100% }
  /* DUAS ações dividem a linha (08/09/2026). Antes, cada uma virava um bloco
     de largura cheia: no Produtos, "Aplicar flag" + "Exportar Excel" comiam
     150px dos 664 da tela do iPhone, e sobrava UMA linha de tabela — o owner
     descreveu como "a tela toda é um botão só". Com 3+ ações a regra de
     24/08 continua valendo: quebra linha e o primário fecha em largura cheia,
     que é o que impede o primário de sair da tela. */
  .page__actions:has(> :nth-child(2)):not(:has(> :nth-child(3))) > *{ flex:1 1 0; min-width:0 }
  .page__actions:has(> :nth-child(2)):not(:has(> :nth-child(3))) .btn{ width:100% }
  .page__actions:has(> :nth-child(2)):not(:has(> :nth-child(3))) .btn--primary{ flex:1 1 0 }
}

/* ============================================================
   3. CARD — fio 1px + sombra leve, os dois discretos
   ============================================================ */
.card{ background:var(--surface); border:1px solid var(--line-card); border-radius:var(--r-2); box-shadow:var(--card-sh) }
.card__head{ display:flex; align-items:center; gap:var(--sp-2); padding:var(--sp-3) var(--sp-4) }
/* v2: o cabeçalho dividido ganha preenchimento — separa comando de conteúdo.
   --hover e não --surf porque a linha de descrição do cabeçalho é --mut. */
.card__head--divided{ border-bottom:1px solid var(--line-card); background:var(--surface-2) }   /* SÓ quando o corpo é lista */
.card__head--divided:first-child{ border-radius:calc(var(--r-2) - 1px) calc(var(--r-2) - 1px) 0 0 }
/* 15px (decisão 64, 03/09/2026): a 13px o título era MENOR que o texto do
   card e a meio pixel do título das linhas — não havia segundo nível de
   leitura entre o h1 e o corpo. É o .t-head da escala. */
.card__title{ font-size:15px; font-weight:700; letter-spacing:-.015em }
.card__link{ margin-left:auto; font-size:11.5px; color:var(--mut) }  /* link, NUNCA botão */
.card__body{ padding:var(--sp-4) }
.card__foot{ padding:var(--sp-2) var(--sp-4); border-top:1px solid var(--line-card) }
/* rodapé com legenda longa ao lado do botão primário (Transferências,
   09/09/2026): no celular a legenda espremia em ~8 linhas ao dividir a
   largura com o botão. Mesmo padrão do .page__actions — o primário desce
   pra baixo do texto e ocupa a largura inteira. */
.card__foot--stack{ display:flex; justify-content:space-between; align-items:center; gap:var(--sp-3) }
@media (max-width:759px){
  .card__foot--stack{ flex-direction:column; align-items:stretch }
  .card__foot--stack .btn--primary{ width:100% }
}
/* corpo com fio em cima — o par do card__head--divided, pra quando o corpo
   vem DEPOIS de outro corpo (vazio + formulário no mesmo cartão) */
.card__body--divided{ border-top:1px solid var(--line) }
/* Cartão de FORMULÁRIO acompanha a largura do formulário (owner, 20/08).
   Antes: form de 560px dentro de cartão de 1400px — sobrava meia tela de
   cartão vazio e o olho voltava de 1400 pra 560 a cada campo. Cartão de
   lista e de tabela continua full: lá a largura é o conteúdo. */
.card--form{ max-width:calc(560px + var(--sp-4) * 2) }
/* Decisão 71 (13/09/2026): formulário como filho direto do card recebe o
   respiro do corpo. Antes, quem esquecia o .card__body entregava pílulas
   coladas na borda (prints do owner: registrar contato e nova oportunidade).
   Agora a régua é do CSS: o padding nasce certo mesmo sem o embrulho. */
.card > .form{ padding:var(--sp-5) }
.card.is-compact .card__head{ padding:var(--sp-3) var(--sp-4) }
.card.is-compact .card__body{ padding:var(--sp-4) }
/* clicável inteiro SÓ com destino único e nada mais interativo dentro */
a.card{ display:block; color:inherit;
  transition:box-shadow var(--t-fast) var(--ease-out), border-color var(--t-fast) var(--ease-out),
             transform var(--t-press) var(--ease-out) }
@media (hover:hover) and (pointer:fine){ a.card:hover{ box-shadow:var(--sh-2); border-color:var(--line-2) } }
a.card:active{ transform:scale(.99) }               /* .99, não .97: superfície grande */

/* ============================================================
   4. STAT CARD — conjunto de comparação: alturas SE igualam
   ============================================================ */
.stats{ display:grid; grid-template-columns:repeat(4,1fr); gap:var(--sp-3) }
/* faixa de KPIs da home (Task 3): no máximo 3 curados por pessoa — decisão de
   produto, não limite técnico. A base .stats de 4 fica intacta pro resto do
   Portal; no celular a media query abaixo já cai pra 2 colunas sozinha. */
.stats--home{ grid-template-columns:repeat(3,minmax(0,1fr)) }
@media (max-width:899px){ .stats{ grid-template-columns:1fr 1fr } }  /* nunca 1 só */
.stat{ position:relative; display:flex; flex-direction:column; gap:var(--sp-2); height:100%;
  padding:var(--sp-4) }
/* position:relative pro .stat__go ancorar quando card+stat são o MESMO
   elemento (KPI clicável da home, Task 3: <a class="card stat">) — nos usos
   aninhados (<div class="card"><div class="stat">) o ancestral já é o <a
   class="card" style="position:relative"> feito à mão; aqui não sobra estilo
   inline nenhum. */
.stat__value{ font-size:28px; line-height:1; font-weight:800; letter-spacing:-.035em;
  font-variant-numeric:tabular-nums }
.stat__value--none{ color:var(--mut); letter-spacing:0 }  /* — = não apurado. 0 é dado, vai em preto */
.stat__delta{ font-size:12px; font-weight:700; font-variant-numeric:tabular-nums }
/* cor = bom/ruim. seta = direção. NUNCA derive a cor do sinal do número. */
.stat__delta--good{ color:var(--green) }
.stat__delta--bad { color:var(--red) }
.stat__delta--flat{ color:var(--mut) }              /* 0% = traço, sem seta e sem cor */
.stat__spark{ margin-top:auto }
.stat__go{ position:absolute; top:var(--sp-4); right:var(--sp-4) }  /* seta SEMPRE visível */

/* ============================================================
   5. LISTA
   ============================================================ */
.rows{ list-style:none; margin:0; padding:0 }        /* lista NÃO tem padding no contêiner */
.row{ display:flex; align-items:center; gap:var(--sp-3);
  padding:var(--sp-3) var(--sp-4); border-bottom:1px solid var(--line); position:relative }
.row:last-child{ border-bottom:0 }                   /* nunca divisor sobrando */
.row__main{ flex:1 1 auto; min-width:0 }             /* só o miolo estica */
.row__title{ font-size:13.5px; font-weight:500 }     /* 500: não compete com o card */
.row__sub{ font-size:11px; color:var(--mut) }
.row__end{ flex:0 0 auto; font-size:11.5px; color:var(--mut); font-variant-numeric:tabular-nums }
/* conteúdo quebra em 2 · dado trunca em 1 · nunca quebra livre */
.list--text  .row__title{ display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden }
.list--dense .row__title{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
/* âncora esticada: linha clicável SEM aninhar interativos */
.row__link{ position:absolute; inset:0; z-index:1 }
/* ação própria dentro de linha clicável (ex.: Excluir em Meus briefs): fica
   acima do .row__link, senão o clique vira navegação pra linha */
.row__acao{ position:relative; z-index:2; flex:0 0 auto }
.row__action{ position:relative; z-index:2 }
@media (hover:hover) and (pointer:fine){ .row--click:hover{ background:var(--hover) } }
/* Home personalizada (Task 4) — bloco oculto na tela /home/personalizar:
   continua na lista (a posição não se perde ao mostrar de novo), mas o peso
   visual cai pra sinalizar "não aparece na home agora". Opacity, não cor
   nova — a regra é zero quarta cor. */
.row--oculto{ opacity:.5 }

/* Home v2 (spec docs/superpowers/specs/2026-09-19-home-v2-design.md, bloco
   2) — busca universal: campo hero acima das colunas, maior que o campo de
   formulário padrão (--fld-h) DE PROPÓSITO. É o primeiro gesto da tela — o
   dado que motivou a home nova (30 dias de uso_eventos, 19/09) é que Produtos
   é o app mais aberto do Portal e a home existe principalmente pra levar lá.
   Fonte fixa em 16px (nunca --fld-fs, que cai pra 13.5 no mouse): aqui a
   legibilidade do convite pesa mais que a densidade do resto do formulário —
   e 16px elimina de saída o zoom automático do Safari no toque. */
.busca-home{ position:relative; margin-bottom:var(--sp-5) }
.busca-home__form{ position:relative; display:flex; align-items:center }
.busca-home__form > .ti{ position:absolute; left:var(--sp-4); font-size:20px; color:var(--mut); pointer-events:none }
.busca-home__input{ font:inherit; font-size:16px; color:var(--ink); background:var(--surface);
  border:1px solid var(--line-2); border-radius:var(--r-2); height:52px; width:100%;
  padding:0 var(--sp-4) 0 calc(20px + var(--sp-4) + var(--sp-2)) }
.busca-home__input:focus{ outline:none; border-color:var(--ink); box-shadow:var(--ring) }
@media (max-width:759px){ .busca-home__input{ height:50px } }
/* painel de resultado: mesma receita visual do .pop (fio + --sh-2 + --r-2) —
   cresce a partir do campo, nunca centralizado (guia 0.6). Cada grupo é um
   rótulo .t-micro + uma .rows normal: reaproveita o componente de lista da
   rodada 5 em vez de inventar um segundo idioma de linha. */
.busca-home__painel{ position:absolute; top:calc(100% + var(--sp-2)); left:0; right:0; z-index:40;
  background:var(--surface); border:1px solid var(--line); border-radius:var(--r-2);
  box-shadow:var(--sh-2); max-height:min(60vh, 480px); overflow-y:auto }
.busca-home__painel .t-micro{ padding:var(--sp-3) var(--sp-4) var(--sp-1) }
.busca-home__painel .rows{ padding-bottom:var(--sp-2) }
.busca-home__painel .row.is-hi{ background:var(--hover) }
.busca-home__vazio{ padding:var(--sp-4); font-size:12.5px; color:var(--mut) }
/* atenção: âmbar. Nomeada pelo SIGNIFICADO (mesmo idioma de .u-queda/.u-alta
   acima) — vence hoje, ordem parada. Nunca vermelho: vermelho é só
   queda/erro/destrutivo (guia 0.1). */
.u-atencao{ color:var(--amber) }

/* ============================================================
   6. BOTÕES — três níveis e nada mais
   ============================================================ */
.btn{ display:inline-flex; align-items:center; justify-content:center; gap:var(--sp-2);
  height:var(--ctl-h); padding:0 var(--sp-4); border-radius:var(--r-2); border:1px solid transparent;
  font-size:13px; font-weight:700; line-height:1; white-space:nowrap; position:relative;
  transition:transform var(--t-press) var(--ease-out), opacity var(--t-fast) var(--ease-out),
             background var(--t-fast) var(--ease-out), border-color var(--t-fast) var(--ease-out) }
.btn--primary  { background:var(--ink); color:var(--on-fg) }          /* UM por tela */
.btn--secondary{ background:var(--surface); color:var(--ink); border-color:var(--line); font-weight:600 }
.btn--tertiary { background:transparent; color:var(--mut); font-weight:600; padding:0 var(--sp-2) }
.btn--danger   { background:var(--red); color:var(--on-fg) }          /* SÓ no confirmar do diálogo */
.btn--sm{ height:var(--bar-h); padding:0 var(--sp-3); font-size:var(--bar-fs) }
.btn--icon{ width:var(--ctl-h); padding:0 }                   /* só p/ ação universal + aria-label */
.btn--block{ width:100% }
@media (hover:hover) and (pointer:fine){
  .btn--primary:hover,.btn--danger:hover{ opacity:.88 }
  .btn--secondary:hover{ border-color:var(--line-2); background:var(--hover) }
  .btn--tertiary:hover{ color:var(--ink) }
}
/* aria-*, NÃO disabled: disabled tira o elemento da tabulação e quem
   usa teclado perde a posição. O bloqueio do clique é do JS. */
.btn[aria-disabled="true"]{ background:var(--hover); color:var(--fg-dis);
  border-color:var(--line-2); cursor:not-allowed }
.btn[aria-disabled="true"]:active{ transform:none }
/* Botão travado que continua legível e explica o porquê (Expedição SP, coluna
   Etiqueta): cinza mais firme que o desabilitado comum — fundo --fill em vez
   de --hover, texto --fg-mut (4,81:1 no --fill, contra 5,03:1 no --hover). O
   motivo vai no title, no texto .sr-only e, ao toque, num aviso (expedicao.js). */
.btn--travado[aria-disabled="true"]{ background:var(--fill); color:var(--fg-mut);
  border-color:var(--line-2); box-shadow:none }
.btn[aria-busy="true"]{ cursor:progress }
.btn[aria-busy="true"] .btn__label{ visibility:hidden }   /* largura NÃO muda */
.btn__spinner{ display:none; position:absolute; width:15px; height:15px;
  border:2px solid currentColor; border-right-color:transparent;
  border-radius:var(--r-full); animation:spin 620ms linear infinite }
.btn[aria-busy="true"] .btn__spinner{ display:block }
@keyframes spin{ to{ transform:rotate(360deg) } }
/* v2: trilho cinza, ativo = lasca BRANCA elevada (era pílula preta).
   O preto sólido competia com o botão primário da tela, e o guia manda um
   preto por tela. Texto em --ink-2: é controle, não apoio. */
/* v3 (03/09/2026): o trilho ganha fio — sobre a página N100 o cinza do
   trilho é o mesmo do fundo e o segmentado virava só uma pílula branca solta
   com texto ao lado (achado no preview do Focus). O fio é o do shell. */
.seg{ display:inline-flex; background:var(--surf); border:1px solid var(--line-shell);
  border-radius:var(--r-full); padding:3px }
.seg button{ border:0; background:transparent; font-size:var(--bar-fs); font-weight:600;
  color:var(--ink-2); height:calc(var(--bar-h) - 6px); padding:0 var(--sp-3);
  display:inline-flex; align-items:center; border-radius:var(--r-full) }
.seg button[aria-pressed="true"]{ background:var(--surface); color:var(--ink); font-weight:700;
  box-shadow:0 0 0 1px rgba(18,17,16,.07), 0 1px 3px rgba(18,17,16,.14) }

/* ============================================================
   7. GRÁFICO — máx. 2 séries por valor; 3ª vira small multiples
   ============================================================ */
.chart{ position:relative }
.chart svg{ display:block; width:100% }
/* Tooltip do crosshair (guia r.7): superfície escura única do sistema — é
   sobreposição efêmera presa ao cursor, não área da página. Texto em branco;
   o delta mostra só a SETA (direção), sem cor: verde/vermelho foram medidos
   pra superfície branca e aqui virariam tom novo não medido. */
.bi-tip{ position:absolute; z-index:30; pointer-events:none; white-space:nowrap;
  background:var(--ink); color:var(--on-fg); border-radius:var(--r-2); box-shadow:var(--sh-2);
  padding:7px 10px; font-size:11.5px; line-height:1.45;
  transform:translate(-50%,calc(-100% - 12px)) }
.bi-tip__data{ color:var(--on-fg-mut); font-weight:700 }
.bi-tip__num{ font-size:13px; font-weight:800; font-variant-numeric:tabular-nums }
.bi-tip__sub{ color:var(--on-fg-mut); font-variant-numeric:tabular-nums }
.chart .grid{ stroke:var(--grid); stroke-width:1; stroke-dasharray:3 4 }   /* só horizontal */
.chart .axis{ font-size:9.5px; fill:var(--mut); font-weight:600; letter-spacing:.06em }
.chart .s1{ fill:var(--s1) } .chart .s2{ fill:var(--s2) }
.chart .line{ fill:none; stroke:var(--s1); stroke-width:2; stroke-linecap:round; stroke-linejoin:round }
.chart .crosshair{ stroke:var(--ink); stroke-width:1; stroke-dasharray:3 3; opacity:.32 }
/* Barra sob o cursor fica, as outras recuam pro --line-2 (rodada 22, decisão 80).
   Só cor, 150ms: é hover repetido dezenas de vezes, não pode parecer lento. */
.chart .bi-barra{ transition:fill 150ms ease }
@media (prefers-reduced-motion: reduce){ .chart .bi-barra{ transition:none } }
.chart__label{ font-size:10.5px; font-weight:800; fill:var(--ink); font-variant-numeric:tabular-nums }
/* PROIBIDO: pizza, rosca, eixo duplo, 3D, radar, área empilhada 3+,
   grade densa de quadradinhos (reprovada pelo time). */

/* ============================================================
   8. TABELA — toda coluna ordenável (regra permanente da casa)
   ============================================================ */
/* Rolagem horizontal da tabela (revisto em 08/09/2026, owner no iPhone:
   "a rolagem tá esquisita"). Duas coisas mudaram:
   1. `` SAIU. Era necessário no iOS 12 e
      hoje é legado: com ele, contêiner que rola dentro de outro que rola
      (o .content) e coluna `position:sticky` brigam — a rolagem trava,
      treme e a coluna congelada descola. O momentum já é o padrão.
   2. `overscroll-behavior-x: contain` ENTROU. Sem ele, ao chegar na borda
      esquerda da tabela o gesto vaza para o navegador e vira o "voltar" do
      iOS: a pessoa tenta ver as colunas e o app sai da página. */
.tbl__wrap{ overflow-x:auto; overscroll-behavior-x:contain }
/* A barra NATIVA da tabela também é desenhada (16/09/2026, achado da varredura
   das 85 telas): a `.tbl__barra` fixa some quando o rodapé da tabela entra em
   quadro, e quem assumia dali pra frente era a barra overlay do macOS, que é
   invisível em repouso — o mesmo defeito que a decisão 79 foi corrigir, só que
   no fim da tabela. Estilizar `::-webkit-scrollbar` troca a overlay pela barra
   clássica, que ocupa 10px e fica sempre à vista. Mesmos tokens da `.tbl__barra`
   pra serem a MESMA barra aos olhos de quem usa: some uma, entra a outra, no
   mesmo lugar e da mesma cor. Vale também nas `--vscroll`, onde a vertical
   passa a aparecer pelo mesmo motivo. */
.tbl__wrap{ scrollbar-width:auto; scrollbar-color:var(--fg-mut) var(--fill) }
.tbl__wrap::-webkit-scrollbar{ height:10px; width:10px }
.tbl__wrap::-webkit-scrollbar-track{ background:var(--fill) }
.tbl__wrap::-webkit-scrollbar-thumb{ background:var(--fg-mut); border-radius:999px;
  border:2px solid var(--fill); background-clip:padding-box }
@media (hover:hover) and (pointer:fine){
  .tbl__wrap::-webkit-scrollbar-thumb:hover{ background:var(--fg) }
}
/* Cabeçalho de tabela grudado (decisão 77, 15/09/2026): `position:sticky`
   num thead morre dentro de qualquer contêiner com rolagem horizontal
   (`.tbl__wrap{overflow-x:auto}`), e as tabelas de Ordens não cabem em toda
   largura de janela (a do owner tem ~1140px). Por isso o wrap marcado
   `--grudado` NÃO usa sticky: o cheff-ui.js cria um cabeçalho FANTASMA
   (`.tbl__fantasma`, cópia do thead em position:fixed, logo abaixo do
   cabeçalho da página) que aparece quando o thead real passa por baixo e
   acompanha a rolagem horizontal do wrap. Nenhuma coluna se perde. */
.tbl__fantasma{ position:fixed; z-index:4; background:var(--surface); pointer-events:none }
.tbl__fantasma__jan{ overflow:hidden }   /* é ESTA janela que acompanha a rolagem lateral, não a caixa (senão a barra do topo andaria junto) */
.tbl__fantasma table{ table-layout:fixed }
.tbl__fantasma[hidden]{ display:none }
/* Barra de arrastar GRUDADA NA BASE (decisão 79, 16/09/2026). Tabela larga só
   anunciava a rolagem na barra nativa do rodapé DA TABELA — que numa lista de
   120 linhas fica a cinco telas de distância (e no macOS ainda é a barra
   fantasma que some em repouso): pra alcançar as colunas escondidas a pessoa
   descia até o fim, arrastava e voltava. A primeira versão pôs uma segunda
   barra ACIMA do cabeçalho e o owner recusou — "não é assim que fala a melhor
   prática" — com razão: o padrão é a barra seguir EMBAIXO e só parar de fugir
   da tela. Então a `.tbl__barra` é um contêiner de rolagem VAZIO (uma tira de
   1px com a largura do conteúdo), fixo no rodapé da área útil e espelhado nos
   dois sentidos com o `.tbl__wrap` pelo cheff-ui.js. Aparece só quando a
   tabela transborda E o rodapé dela ainda não chegou na tela; some quando a
   barra nativa entra em quadro, pra nunca haver duas. Desenhada SEMPRE (não a
   overlay do sistema): trilho em --fill (contenção) e polegar em --fg-mut
   (apoio, 4,81 sobre o trilho), nenhuma cor nova e os dois já têm par no modo
   escuro. O polegar começou em --line-2 e sumia: 1,14 sobre o trilho é fio,
   não objeto — e ser visto é justamente o pedido. NO TOQUE é só indicador
   (`pointer-events:none`): o dedo arrasta a tabela inteira, e um alvo de 10px
   violaria os 44px do guia — custo aceito, ali ela informa em vez de operar. */
.tbl__barra{ position:fixed; z-index:4; overflow-x:auto; overflow-y:hidden; overscroll-behavior-x:contain;
  scrollbar-width:auto; scrollbar-color:var(--fg-mut) var(--fill) }
.tbl__barra > i{ display:block; height:1px }
.tbl__barra[hidden]{ display:none }
.tbl__barra::-webkit-scrollbar{ height:10px }
.tbl__barra::-webkit-scrollbar-track{ background:var(--fill); border-radius:999px }
.tbl__barra::-webkit-scrollbar-thumb{ background:var(--fg-mut); border-radius:999px;
  border:2px solid var(--fill); background-clip:padding-box }
@media (hover:hover) and (pointer:fine){
  .tbl__barra::-webkit-scrollbar-thumb:hover{ background:var(--fg) }
}
@media (pointer:coarse){ .tbl__barra{ pointer-events:none } }
.tbl{ width:100%; border-collapse:separate; border-spacing:0; font-size:13px }
.tbl th,.tbl td{ padding:var(--sp-2) var(--sp-4); text-align:left; white-space:nowrap;
  border-bottom:1px solid var(--line) }
/* Decisão 77 (15/09/2026): toda linha do corpo (e o rodapé, quando existe)
   tem a MESMA altura — 40px, nem mais nem menos — mesmo quando uma célula
   carrega um selo ou um campo. Sem isso um badge (padding próprio) ou um
   `.tbl__in` engordavam só a linha deles, e a tabela ficava com dentes.
   Zera o padding vertical da célula (o alinhamento vertical sozinho
   centraliza o conteúdo); o padding horizontal continua vindo da regra
   `.tbl th,.tbl td` acima. */
.tbl tbody td, .tbl tfoot th, .tbl tfoot td{ height:40px; padding-block:0; vertical-align:middle }
.tbl .tbl__in{ height:32px }         /* campo de linha cabe nos 40px com respiro */
/* Coluna "Passo" da lista de Ordens (decisão 77): largura travada pra
   tabela caber sem rolar no desktop — situação + apoio truncam cada um na
   própria linha, o título carrega o texto inteiro. */
.tbl-passo{ max-width:170px }
.tbl-passo__ln{ display:block; overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
/* v2: o cabeçalho da tabela é UMA superfície só, as duas linhas e todas as
   células. Pintar só as células com rótulo produzia branco → cinza
   ("ESTOQUE") → branco, um mosaico (defeito relatado pelo owner, 19/08).
   Quem separa os grupos é o fio vertical, não a troca de cor — e o fio
   sobe para --line-2, porque --line sobre --surf praticamente não existe. */
/* O thead é --surface (branco), não --surf (= --fill = --page-bg): achado
   16/09 do owner ("linha esquisita ao rolar") era o thead grudado se
   fundindo com o fundo da página atrás dele, sobrando só o fio de baixo
   boiando sozinho. --surface é a mesma superfície do card (guia §8: "sem
   preenchimento cinza" já valia, só a cor estava errada). */
.tbl thead th, .tbl thead td{ background:var(--surface) }
.tbl thead th{ position:sticky; top:0; z-index:3;  /* acima do .tbl td .btn (z 2): botão de linha não fura o cabeçalho grudado */
  font-size:9.5px; letter-spacing:.12em; text-transform:uppercase; color:var(--ink-2); font-weight:700 }
/* `--head-h` só existe pra empurrar o thead pra baixo do cabeçalho DA
   PÁGINA quando ele está sticky contra o `.content` — ou seja, só dentro
   de `.tbl__wrap--grudado` (ver comentário acima). Nas demais tabelas o
   wrap é o próprio contêiner de rolagem (`overflow-x:auto`), o sticky
   vale contra ELE, e empurrar por `--head-h` (117px) enfiava o thead
   dentro do corpo da tabela (achado 16/09: "Aguardando cadastro" com o
   thead 117px abaixo do topo do wrap). */
.tbl__wrap--grudado .tbl thead th{ position:static }   /* o grudado é o fantasma (cheff-ui.js), não o thead real */
/* decisão 79: quem ganhou fantasma (hoje, toda tabela do conteúdo) tem o
   thead real estático — dois cabeçalhos grudados brigariam, e o real fica
   onde sempre esteve, no topo da tabela. A classe é posta pelo JS: sem JS,
   o sticky da regra acima continua valendo como estava. */
.tbl.is-fantasma thead th{ position:static }
.tbl thead tr.tbl__grps th, .tbl thead th.tbl__grp-edge{ border-left-color:var(--line-2) }
.tbl tbody tr:last-child td{ border-bottom:0 }       /* sem zebra: cansa em 1.800 linhas */
.tbl .num{ text-align:right; font-variant-numeric:tabular-nums }
.tbl th[aria-sort]{ color:var(--ink) }
@media (hover:hover) and (pointer:fine){ .tbl tbody tr:hover{ background:var(--hover) } }
.tbl .frozen{ position:sticky; left:0; z-index:1; background:var(--surface) }
.tbl thead .frozen{ z-index:3; background:var(--surface) }  /* mesma correção do thead: branco, não --surf */
/* a borda da coluna congelada SÓ quando há conteúdo passando por baixo */
.tbl .frozen--edge::after{ content:""; position:absolute; inset:0 0 0 auto; width:12px;
  background:linear-gradient(90deg,var(--line) 0 1px,rgba(18,17,16,.06),transparent);
  opacity:0; transition:opacity var(--t-ui) var(--ease-out); pointer-events:none }
.tbl__wrap.is-scrolled .frozen--edge::after{ opacity:1 }
/* Produtos v2 (12/09/2026): a lista ganhou uma 2ª coluna congelada, a foto,
   antes do SKU. `.frozen` sozinha gruda tudo em left:0 — as duas
   empilhariam uma em cima da outra. A foto fica em left:0 (sem sombra
   própria: --edge é só da ÚLTIMA congelada) e o SKU desloca pela largura
   medida da célula da foto (16px de respiro + 36px de imagem + 16px). */
.tbl .foto-cell.frozen{ left:0 }
.tbl .frozen.frozen--apos-foto{ left:68px }

/* ---- Foto de produto (Produtos v2, 12/09/2026) ----
   Só URL do S3 do Tiny; o Portal nunca copia binário. Ladrilho neutro (--fill)
   quando não há foto: imagem quebrada mente e ícone genérico vira ruído em
   100 linhas. */
.foto{ display:block; object-fit:cover; background:var(--fill); border:1px solid var(--line-card); border-radius:var(--r-1); flex:0 0 auto }
.foto--sm{ width:36px; height:36px }
.foto--lg{ width:88px; height:88px; border-radius:var(--r-2) }
.foto--vazia{ position:relative }
.foto--vazia::after{ content:""; position:absolute; inset:9px; border:1.5px dashed var(--line-2); border-radius:3px }
.foto-cell{ width:1%; padding-top:6px; padding-bottom:6px }
.ident{ display:flex; gap:var(--sp-4); align-items:flex-start; min-width:0 }
@media (max-width:759px){ .ident{ flex-direction:column } }
.tbl__bulk{ display:flex; align-items:center; gap:var(--sp-3); padding:var(--sp-3) var(--sp-4);
  background:var(--ink); color:var(--on-fg); border-radius:var(--r-2) }  /* rodapé, nunca topo */
/* Variante flutuante (Expedição SP, 29/09/2026): a barra de seleção em lote
   sobe do rodapé da janela quando há caixa marcada (public/expedicao.js liga
   .is-open) e some quando não há. Só transform e opacity animam; visibility
   sai depois da descida pra a barra fechada não entrar na tabulação. Sob
   prefers-reduced-motion não há deslocamento, só o fade. */
.tbl__bulk--flutua{ position:fixed; left:0; right:0; bottom:var(--sp-5); z-index:40; flex-wrap:wrap;
  width:max-content; max-width:calc(100vw - 32px); margin:0 auto; box-shadow:var(--sh-3);
  transform:translateY(calc(100% + var(--sp-5))); opacity:0; visibility:hidden;
  transition:transform 220ms var(--ease-out), opacity 160ms var(--ease-out), visibility 0s linear 220ms }
.tbl__bulk--flutua.is-open{ transform:none; opacity:1; visibility:visible; transition-delay:0s }
.tbl__bulk .btn--tertiary{ color:var(--on-fg-mut) }
@media (hover:hover) and (pointer:fine){ .tbl__bulk .btn--tertiary:hover{ color:var(--on-fg) } }
@media (max-width:759px){ .tbl__bulk--flutua{ left:var(--sp-4); right:var(--sp-4); bottom:var(--sp-4);
  width:auto; max-width:none } }
@media (prefers-reduced-motion:reduce){
  .tbl__bulk--flutua{ transform:none; transition:opacity 160ms var(--ease-out), visibility 0s linear 160ms }
  .tbl__bulk--flutua.is-open{ transition-delay:0s }
}

/* Tabelas do Estoque tudo à esquerda (decisão do owner no preview de
   06/08/2026). Precisa cobrir .num: `.tbl .num` (linha ~255) realinha
   números à direita e empata em especificidade — aqui vence por ordem. */
.tbl--left th,
.tbl--left td,
.tbl--left .num { text-align: left; }

/* ============================================================
   9. FORMULÁRIO — "punir tarde, perdoar cedo"
   ============================================================ */
.form{ display:flex; flex-direction:column; gap:var(--sp-6); max-width:560px }
.field{ display:flex; flex-direction:column; gap:var(--sp-2) }
.field > label{ font-size:13px; font-weight:700 }    /* SEMPRE acima, nunca placeholder */
.field__optional{ font-weight:500; color:var(--mut); margin-left:var(--sp-2) }  /* marcamos o opcional */
.field input,.field select,.field textarea{
  font:inherit; font-size:var(--fld-fs);             /* 13,5px no mouse, 16px no toque */
  color:var(--ink); background:var(--surface); border:1px solid var(--line); border-radius:var(--r-2);
  padding:0 var(--sp-4); height:var(--fld-h); width:100%;
  transition:border-color var(--t-fast) var(--ease-out), box-shadow var(--t-fast) var(--ease-out) }
/* Select de formulário: mesmo remédio do .tbl-filter (comentário lá) — sem
   `appearance:none` o macOS/iOS impõe o chrome nativo (fonte de sistema,
   altura própria) e a fonte "feia e grande" volta (owner, 01/09/2026). O
   chevron nativo some junto: entra um em SVG na própria borda direita. */
.field select{ appearance:none; -webkit-appearance:none; padding-right:34px;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2373716e' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat; background-position:right 10px center }
.field textarea{ height:auto; min-height:128px; padding:var(--sp-4); line-height:1.55 }
/* ── Campo de ARQUIVO ────────────────────────────────────────────────────
   O widget nativo ("Escolher arquivo · Nenhum arquivo escolhido") traz a
   fonte, o botão e o cinza do SISTEMA pra dentro de um formulário do
   Portal — no Windows é gritante. 4 campos assim no RH e 1 no X9.
   O `::file-selector-button` deixa estilizar só o botão, sem JS e sem
   esconder o input: o teclado, o arrastar-e-soltar e o leitor de tela
   continuam funcionando, que é o que se perde na gambiarra de label+input
   escondido. O texto "nenhum arquivo" ao lado é do navegador e fica —
   ele é a única confirmação de que o arquivo entrou. */
.field input[type=file]{ padding:0 var(--sp-3); font-size:var(--fld-fs); color:var(--mut);
  display:flex; align-items:center; gap:var(--sp-3); cursor:pointer }
.field input[type=file]::file-selector-button{
  height:var(--ctl-h); padding:0 var(--sp-4); margin-right:var(--sp-3);
  border:1px solid var(--line-2); border-radius:var(--r-1);
  background:var(--surface); color:var(--ink); font:inherit; font-size:13px; font-weight:700;
  cursor:pointer; transition:background var(--t-fast) var(--ease-out) }
.field input[type=file]::file-selector-button:hover{ background:var(--hover) }
.field input[type=file]:focus-visible{ outline:none; border-color:var(--ink);
  box-shadow:var(--ring) }
.field :is(input,select,textarea):focus{ outline:none; border-color:var(--ink);
  box-shadow:var(--ring) }
.field__hint{ font-size:12px; color:var(--mut) }
/* ── Campos LADO A LADO (decisão 72, lote de ajustes 13/09/2026) ──────────
   Campo lado a lado sempre declara a largura. Numa linha flexível genérica
   (.u-hstack) o .field vira item sem base e fica da largura do TEXTO DE AJUDA
   embaixo dele: nos Parâmetros de Compras os campos mediam de 314 a 738px.
   Dois ou três irmãos → .frow (partes iguais). Muitos → .fgrid (colunas
   iguais que quebram sozinhas). Largura fixa num irmão → .field--xs/--sm/--md.
   Travado por teste no design-system.test.js. */
.fgrid{ display:grid; grid-template-columns:repeat(auto-fill, minmax(12rem, 1fr));
  gap:var(--sp-4) var(--sp-3); align-items:start }
.fgrid > .field{ min-width:0 }
/* Rótulo que quebra em duas linhas empurrava a caixa pra baixo e a linha de
   campos ficava torta. Com subgrid, rótulo, caixa e ajuda de todos os campos
   da mesma linha dividem as MESMAS trilhas: as caixas alinham sempre. */
@supports (grid-template-rows: subgrid){
  .fgrid > .field{ grid-row:span 3; display:grid; grid-template-rows:subgrid; row-gap:var(--sp-2); align-content:start }
}
/* grupo de campos com título: o fieldset nativo traz borda e recuo do navegador */
.fset{ border:0; margin:0; padding:0; min-width:0 }
/* botão na linha de campos: alinha com a CAIXA, não com o rótulo. O deslocamento
   é a altura da linha do rótulo (13px × 1,55) + o gap do .field. */
.fgrid__acao{ align-self:start; justify-self:start; display:flex; gap:var(--sp-2); margin-top:calc(13px * 1.55 + var(--sp-2)) }
.fgrid__acao > .btn{ height:var(--fld-h) }
@supports (grid-template-rows: subgrid){
  /* com subgrid o botão senta na trilha da CAIXA, mesmo com rótulo de duas linhas ao lado */
  .fgrid__acao{ grid-row:span 3; display:grid; grid-template-rows:subgrid; row-gap:var(--sp-2); margin-top:0 }
  .fgrid__acao > .fgrid__botoes{ grid-row:2; display:flex; gap:var(--sp-2); align-items:center }
}
.fgrid__botoes{ display:flex; gap:var(--sp-2) }
.fgrid__botoes > .btn{ height:var(--fld-h) }
.field--xs{ width:7rem }
.field__error{ display:none; font-size:12px; color:var(--red); font-weight:600 }
.field.is-invalid :is(input,select,textarea){ border-color:var(--red) }
/* ── Campo DENTRO de linha de tabela (compras-v2, 24/08/2026) ─────────────
   Quantidade/preço/SKU editados linha a linha (remessa, pedido de compra,
   conferência, recebimento). Sem esta classe o input nasce cru do navegador:
   21px de altura e 13px de fonte — abaixo do alvo de 44px no toque e da
   fonte de 16px que evita o zoom do iOS. Altura de AÇÃO (--ctl-h: 36 / 44
   no celular), não de campo: é um controle inline num comando (decisão 56). */
.tbl__in{ font:inherit; font-size:var(--fld-fs); color:var(--ink); background:var(--surface);
  border:1px solid var(--line); border-radius:var(--r-2); padding:0 var(--sp-3);
  height:var(--ctl-h); width:6rem; font-variant-numeric:tabular-nums }
.tbl__in--preco{ width:7.5rem } .tbl__in--sku{ width:9.5rem }
.tbl__in:focus{ outline:none; border-color:var(--ink); box-shadow:var(--ring) }
/* arquivo enviado de dentro de uma linha de tabela (Campanha da marca) */
.tbl__in--arquivo{ width:17rem; padding:0 var(--sp-2) 0 0; border:0; background:transparent;
  color:var(--mut); display:inline-flex; align-items:center; cursor:pointer }
.tbl__in--arquivo::file-selector-button{ height:var(--bar-h); padding:0 var(--sp-3); margin-right:var(--sp-2);
  border:1px solid var(--line-2); border-radius:var(--r-1); background:var(--surface); color:var(--ink);
  font:inherit; font-size:var(--bar-fs); font-weight:700; cursor:pointer }
.field.is-invalid .field__error{ display:flex }
.field.is-invalid .field__hint{ display:none }       /* substitui, não empilha */
.form__summary{ border:1px solid var(--red); border-radius:var(--r-2); padding:var(--sp-4) }

/* ============================================================
   10. ESTADOS — nenhum é beco sem saída
   ============================================================ */
.empty{ display:flex; flex-direction:column; align-items:center; gap:var(--sp-3);
  padding:var(--sp-6) var(--sp-5); text-align:center }
.empty p{ font-size:12.5px; color:var(--mut); max-width:38ch }
/* "nunca teve" e "o filtro cortou" são estados DIFERENTES: um oferece
   criar, o outro oferece limpar filtro. */
.skeleton{ height:12px; border-radius:var(--r-1);
  background:linear-gradient(90deg,var(--line) 25%,var(--fill) 37%,var(--line) 63%);
  background-size:400% 100%; animation:shimmer 1400ms linear infinite }
@keyframes shimmer{ to{ background-position:-135% 0 } }
/* esqueleto espelha a forma final e reserva a altura. Nada abaixo de 300ms. */
.stale{ display:flex; align-items:center; gap:var(--sp-3); padding:var(--sp-3) var(--sp-4);
  border-bottom:1px solid var(--line); background:var(--hover); font-size:12px; color:var(--mut) }

/* ============================================================
   11. FEEDBACK — o que exige ação NÃO desaparece sozinho
   ============================================================ */
/* v3 (03/09/2026, decisões 66-67): selo CHEIO — fundo tingido, sem fio.
   Quatro cores, cada uma com o próprio fundo, todas ≥ 4.5:1 sobre ele.
   O ponto (.badge__dot) só existe no selo neutro: no colorido a cor já é o
   fundo, e o ponto virava ruído. */
.badge{ display:inline-flex; align-items:center; gap:6px; padding:3px 9px; border-radius:var(--r-1);
  font-size:11px; font-weight:700; border:1px solid transparent; color:var(--ink-2); background:var(--fill) }
.badge .ti{ font-size:14px; flex:none }   /* ícone do passo (Expedição SP): cor diz o que fazer, ícone diz o passo */
.badge__dot{ width:6px; height:6px; border-radius:var(--r-full); background:var(--mut) }
.badge--ok       { color:var(--green); background:var(--green-bg) }
.badge--bad      { color:var(--red);   background:var(--red-bg) }
.badge--attention{ color:var(--amber); background:var(--amber-bg) }   /* atenção é ÂMBAR (decisão 66) */
.badge--info     { color:var(--blue);  background:var(--blue-bg) }    /* informação neutra */
/* Decisão 77 (15/09/2026): dentro de tabela o selo é compacto — nunca
   estica a linha de 40px. */
.tbl .badge{ height:22px; padding:0 8px; line-height:22px; font-size:11.5px }

/* Flags de Produto (spec 2026-09-08 §7). A etiqueta é o DADO e o × é a ação:
   com oito flags num produto, oito botões do tamanho de um icon-btn (40px)
   viram uma parede de × e a leitura das etiquetas se perde. No mouse o ×
   aparece no hover ou no foco; no toque fica sempre visível, porque ali não
   existe hover pra revelar — e com 44px de alvo, que é a lei do celular. */
.flag{ display:inline-flex; align-items:center; gap:var(--sp-1) }
.flag__x{ width:20px; height:20px; padding:0; display:inline-flex; align-items:center; justify-content:center;
  border:0; background:transparent; border-radius:var(--r-1); color:var(--mut); cursor:pointer;
  transition:opacity var(--t-fast), color var(--t-fast) }
.flag__x .ti{ font-size:14px }
.flag__x:hover{ color:var(--red) }                  /* destrutivo é neutro em repouso, vermelho no hover */
@media (hover:hover) and (pointer:fine){
  .flag__x{ opacity:0 }
  .flag:hover .flag__x, .flag__x:focus-visible{ opacity:1 }
}
/* No celular o × some: alvo de 44px (a lei do toque) vezes oito flags abre
   buracos entre as etiquetas e a leitura do produto se perde. Ali a remoção
   mora no painel "Gerenciar flags", que é onde há espaço pra um alvo honesto
   — e continua reversível, porque é só remarcar. */
@media (max-width:759px){ .flag__x{ display:none } }
.badge--ok .badge__dot, .badge--bad .badge__dot,
.badge--attention .badge__dot, .badge--info .badge__dot{ display:none }
.toasts{ position:fixed; right:var(--sp-5); bottom:var(--sp-5); z-index:60;
  display:flex; flex-direction:column; gap:var(--sp-2); width:min(340px,calc(100vw - 32px)) }
@media (max-width:759px){ .toasts{ left:var(--sp-4); right:var(--sp-4); width:auto } }
.toast{ display:flex; align-items:flex-start; gap:var(--sp-3); background:var(--ink); color:var(--on-fg);
  border-radius:var(--r-2); padding:var(--sp-4); box-shadow:var(--sh-3); font-size:13px }
/* sucesso 5s · com desfazer 10s · falha NÃO some · máx. 3 na tela */

/* ============================================================
   12. SOBREPOSIÇÕES — Esc fecha · clique fora fecha · botão visível
   ============================================================ */
.scrim{ position:fixed; inset:0; background:var(--scrim); z-index:50 }
.modal{ position:fixed; z-index:51; left:50%; top:50%; width:min(440px,calc(100vw - 32px));
  background:var(--surface); border-radius:var(--r-2); box-shadow:var(--sh-3);
  transform:translate(-50%,-50%) }                   /* exceção: nasce no centro */
.menu{ position:absolute; min-width:210px; background:var(--surface); border:1px solid var(--line);
  border-radius:var(--r-2); box-shadow:var(--sh-2); padding:var(--sp-1);
  transform-origin:top left }                        /* cresce DO GATILHO */
@media (max-width:759px){
  /* no celular o diálogo vira folha de baixo — zona do polegar */
  .modal{ top:auto; bottom:0; left:0; width:100%; transform:none;
    border-radius:var(--r-2) var(--r-2) 0 0; padding-bottom:env(safe-area-inset-bottom) }
}
/* Ao abrir: foco entra na sobreposição e no botão SEGURO.
   Ao fechar: foco volta ao gatilho. Página atrás não rola.
   Uma sobreposição por vez. */

/* ============================================================
   CAMADA DE APP — Portal do Colaborador (03/08/2026)
   Componentes que as telas do Portal precisam e o guia ainda não
   fixa como CSS. Tudo deriva das decisões do guia; nada aqui
   introduz cor, curva ou medida fora da lei. Prefixo por
   componente (lição da rodada 9: `.sw` virou `.tgl`).
   ============================================================ */

/* ---------- shell: esqueleto de layout ---------- */
.main{ flex:1 1 auto; min-width:0; display:flex; flex-direction:column }
.content{ flex:1 1 auto; overflow-y:auto }   /* -webkit-overflow-scrolling saiu: ver .tbl__wrap */
.side__logo{ height:26px; display:block; margin:var(--sp-2) var(--sp-3) var(--sp-4) }
.side__logo, .topbar__logo, .auth__logo{ filter:var(--logo-filter) }
/* overflow-X hidden é DELIBERADO: o conteúdo do menu cabe na largura (199 de
   224px), mas com só o overflow-y a barra vertical rouba largura e o navegador
   passa a desenhar TAMBÉM a horizontal. Era o risco de rolagem lateral que o
   owner viu em 20/08. */
/* ── Área que rola sem barra, com a borda desbotada no lugar dela ────────
   Nasceu no menu lateral (decisão 52) e a barra de abas da ficha do
   colaborador pediu a mesma coisa na horizontal: 7 abas não cabem em 390px,
   e um corte reto na borda parece "acabou aqui" — foi o defeito exato que a
   barra de rolagem tinha. Uma classe, dois eixos.
   `tem-mais` = há conteúdo adiante · `tem-antes` = há conteúdo atrás.
   Ligadas pelo cheff-ui.js. */
.rola{ scrollbar-width:none; -ms-overflow-style:none; --fade:20px;
  transition:mask-image .15s ease }
.rola::-webkit-scrollbar{ width:0; height:0 }
.rola--y{ overflow-y:auto; overflow-x:hidden }
/* anel de foco DENTRO do item quando a lista rola: por fora, o overflow corta
   as bordas de cima e de baixo e sobram só os cantos vermelhos (13/09/2026) */
.rola--y :focus-visible{ outline-offset:-2px }
.rola--x{ overflow-x:auto; overflow-y:hidden }
/* dentro de uma área que rola na horizontal, o segmentado não pode encolher
   pra caber — é justamente disso que ele tem que escapar */
.rola--x > .seg{ width:max-content }
.rola--x > .seg a, .rola--x > .seg button{ flex:0 0 auto; white-space:nowrap }
.rola--y.tem-mais { mask-image:linear-gradient(#000 calc(100% - var(--fade)), transparent) }
.rola--y.tem-antes{ mask-image:linear-gradient(transparent, #000 var(--fade)) }
.rola--y.tem-antes.tem-mais{
  mask-image:linear-gradient(transparent, #000 var(--fade),
                             #000 calc(100% - var(--fade)), transparent) }
.rola--x.tem-mais { mask-image:linear-gradient(90deg, #000 calc(100% - var(--fade)), transparent) }
.rola--x.tem-antes{ mask-image:linear-gradient(90deg, transparent, #000 var(--fade)) }
.rola--x.tem-antes.tem-mais{
  mask-image:linear-gradient(90deg, transparent, #000 var(--fade),
                             #000 calc(100% - var(--fade)), transparent) }

/* o menu usa `.rola .rola--y` no HTML — aqui fica só o que é dele */
.side__nav{ flex:1 1 auto; min-height:0 }

/* espaço da seta reservado mesmo sem destino: sem isto, a linha SEM seta
   empurra o valor 28px pra direita e a coluna de número deixa de alinhar
   (achado do owner no "Por canal": Camicado e Outros fora do prumo).
   Mesma lógica da decisão 13 — a seta não pode aparecer e sumir. */
.row__go--vazio{ visibility:hidden }

/* textarea de composição: começa com a cara de um campo de uma linha e
   cresce conforme o texto (altura controlada no cheff-ui.js). */
.field textarea.cresce{ min-height:var(--fld-h); height:var(--fld-h);
  padding-top:12px; padding-bottom:12px; resize:none;
  /* `hidden` e não `auto`: enquanto o texto cabe, não existe rolagem — e no
     Windows `auto` desenhava a barra clássica COM SETAS dentro do campo de
     uma linha por diferença de arredondamento de line-height. O script liga
     `auto` só quando o campo trava no máximo de linhas. */
  overflow-y:hidden }
.side__foot{ margin-top:auto; padding:var(--sp-3) var(--sp-3) var(--sp-2); border-top:1px solid var(--line-shell);
  display:flex; align-items:center; gap:var(--sp-3) }
.side__foot .t-caption{ line-height:1.3 }
.nav__item .ti{ font-size:16px; flex:0 0 auto }
.nav__count{ margin-left:auto; font-size:11.5px; color:var(--mut); font-variant-numeric:tabular-nums }
/* badge preto no menu = exige ação (Aprovar ideias 2). Contador cinza = só informa. */
.nav__badge{ margin-left:auto; min-width:18px; height:18px; padding:0 6px; border-radius:var(--r-full);
  background:var(--ink); color:var(--on-fg); font-size:10.5px; font-weight:700; display:inline-flex;
  align-items:center; justify-content:center; font-variant-numeric:tabular-nums }
.skip{ position:absolute; left:-9999px; z-index:100; background:var(--ink); color:var(--on-fg);
  padding:var(--sp-2) var(--sp-4); border-radius:var(--r-2) }
.skip:focus{ left:var(--sp-3); top:var(--sp-3) }

/* ---------- menu em árvore: Grupo → App → Página (19/08/2026) ----------
   Mockup aprovado pelo owner em 18/08. Dropdown só com 2+ páginas reais;
   acordeão (um aberto por vez) vive no cheff-ui.js; o pai da rota ativa
   renderiza aberto pelo servidor — carga de página não anima (guia 0.6).
   Nível 3 sem ícone, texto alinhado ao rótulo do pai:
   16px padding + 17px ícone + 12px gap = 45px. */
.nav__item{ border:1px solid transparent }  /* .is-active tem fio de 1px — sem isto o item cresce 2px ao ativar e a lateral pula */
button.nav__item{ width:100%; background:transparent; text-align:left }
.nav__chev{ margin-left:auto; font-size:14px; color:var(--mut); flex:0 0 auto;
  transition:transform var(--t-ui) var(--ease-out) }
button.nav__item[aria-expanded="true"] .nav__chev{ transform:rotate(90deg) }
/* pai da rota ativa engrossa, mas NÃO eleva — única elevação da lateral é o item ativo */
button.nav__item.has-active{ color:var(--ink); font-weight:700 }
/* 0fr → 1fr anima a altura sem medir nada em JS */
.nav__sub{ display:grid; grid-template-rows:0fr;
  transition:grid-template-rows var(--t-ui) var(--ease-out) }
.nav__sub.is-open{ grid-template-rows:1fr }
.nav__sub > div{ min-height:0; overflow:hidden }
.nav__subitem{ display:flex; align-items:center; gap:var(--sp-3);
  padding:var(--sp-2) var(--sp-3) var(--sp-2) 40px; margin-top:1px;
  font-size:12.5px; color:var(--ink-2); border-radius:var(--r-2); border:1px solid transparent;
  transition:background var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out) }
@media (hover:hover) and (pointer:fine){ .nav__subitem:hover:not(.is-active){ background:var(--hover) } }
.nav__subitem.is-active{ background:var(--surface); color:var(--ink); font-weight:700;
  border-color:var(--line-card); box-shadow:var(--card-sh) }
@media (max-width:759px){ .nav__subitem{ min-height:44px; padding-top:12px; padding-bottom:12px } }
/* ---------- menu v2 (31/08/2026): 3º nível + badge que sobe ----------
   Sub-item que também é dropdown (Focus, Mercado Livre, Aprovações): mesmo
   .nav__subitem, em <button>, com chevron um passo menor que o do 1º nível. */
button.nav__subitem{ width:100%; background:transparent; text-align:left }
button.nav__subitem .nav__chev{ font-size:13px }
button.nav__subitem[aria-expanded="true"] .nav__chev{ transform:rotate(90deg) }
button.nav__subitem.has-active{ color:var(--ink); font-weight:700 }
/* 3º nível: sem ícone e sem cor nova — a profundidade é um fio de trilha de
   1px à esquerda, alinhado ao texto do pai (40px de padding do sub-item). */
.nav__sub3{ display:grid; grid-template-rows:0fr;
  transition:grid-template-rows var(--t-ui) var(--ease-out) }
.nav__sub3.is-open{ grid-template-rows:1fr }
.nav__sub3 > div{ min-height:0; overflow:hidden; margin-left:40px;
  border-left:1px solid var(--line) }
.nav__sub3 .nav__subitem{ padding-left:var(--sp-3); font-size:12px }
/* badge de dropdown fechado = SOMA dos filhos; aberto, o badge do pai some
   e o número mora no filho (a view emite os dois — quem alterna é o estado) */
button.nav__item[aria-expanded="true"] > .nav__badge,
button.nav__subitem[aria-expanded="true"] > .nav__badge{ display:none }
/* tag "novo" do menu (decisão 66 do guia: azul = informação neutra; pedido
   do owner de 13/09/2026, variant A do mockup — selo cheio, mesma caixa do
   badge preto de contador). Item com `novoEm` (7 dias); pai colapsado
   acende quando um filho VISÍVEL é novo (ehNovo/temNovo em links.js). O
   contador sempre ganha de "novo" no mesmo item (a view nunca emite os
   dois); no pai aberto o selo some pela mesma regra do badge preto —
   dropdown aberto já mostra o filho novo, repetir no pai seria ruído. */
.nav__novo{ margin-left:auto; flex:0 0 auto; min-width:18px; height:18px; padding:0 5px; border-radius:var(--r-full);
  background:var(--blue-bg); color:var(--blue); font-size:9px; font-weight:800; letter-spacing:.06em; text-transform:uppercase;
  display:inline-flex; align-items:center }
/* Linha do menu que não cabe (owner, 15/09/2026: em "Ferramentas" + "novo" a
   setinha vazava 7px pra direita do botão). Três causas medidas no DOM:
   (1) `.nav__item .ti` (16px) vencia `.nav__chev` (14px, decisão 57) por
   especificidade; (2) o selo levava 8px de margem direita ALÉM do gap de 12px;
   (3) o rótulo não encolhia, então tudo empurrava pra fora. Agora: setinha no
   degrau certo, selo e contador a 8px do rótulo e da setinha quando falta
   espaço (margem negativa sobre o gap; com folga o margin-left:auto do selo
   continua empurrando pra direita), e o rótulo é o único que encolhe, com
   reticências, como rede de segurança pra nome longo que ainda vier. Medido
   nas 60 linhas do menu aberto: nenhuma vaza, nenhuma corta, setinhas no
   mesmo x. */
.nav__item .nav__chev{ font-size:14px }
.nav__item > span:not([class]), .nav__subitem > span:not([class]){ flex:1 1 auto; min-width:0;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.nav__item > span:not([class]) + .nav__novo, .nav__subitem > span:not([class]) + .nav__novo,
.nav__item > span:not([class]) + .nav__badge, .nav__subitem > span:not([class]) + .nav__badge,
.nav__novo + .nav__chev, .nav__badge + .nav__chev{ margin-left:calc(var(--sp-2) - var(--sp-3)) }
button.nav__item[aria-expanded="true"] > .nav__novo, button.nav__subitem[aria-expanded="true"] > .nav__novo{ display:none }
/* selo "atualizado" (owner, 13/09/2026): mesma pílula do "novo", mas só o
   fio azul, sem fundo — precisa distinguir tela que MUDOU de tela NOVA sem
   introduzir uma quinta cor. 3 dias (ehAtualizado em links.js); novo sempre
   vence quando os dois valeriam no mesmo item. Tokens de cor (--blue) já
   têm par de dark mode; nada aqui precisa de regra própria pro tema escuro. */
/* "atualizado" = PONTO azul, sem texto (owner, 13/09/2026: a palavra ficou
   estranha no menu). Mesma cor de informação; o significado vai no title. */
.nav__novo--atu{ min-width:0; width:7px; height:7px; padding:0; border-radius:50%; background:var(--blue); box-shadow:none }
/* módulo ainda não construído: flag "em breve" — cinza informa, não pede ação
   (badge preto continua reservado a "exige ação") */
.nav__soon{ margin-left:auto; flex:0 0 auto; font-size:9.5px; font-weight:600; color:var(--mut);
  border:1px solid var(--line); border-radius:var(--r-1); padding:1px 6px; white-space:nowrap }

/* topo */
.crumbs{ display:flex; align-items:center; gap:var(--sp-2); font-size:12.5px; color:var(--mut) }
.crumbs a{ color:var(--mut) } .crumbs a:hover{ color:var(--ink) }
.crumbs .is-here{ color:var(--ink); font-weight:600 }
.topbar__logo{ height:22px; display:none }
.topbar__title{ display:none; font-size:15px; font-weight:700; letter-spacing:-.015em }
.topbar__center{ display:flex; align-items:center; justify-content:center; flex:0 0 auto }
.kbd{ font-size:10.5px; font-weight:700; color:var(--mut); border:1px solid transparent;
  background:var(--hover); border-radius:var(--r-1); padding:1px 5px; letter-spacing:.04em }
.search-btn{ display:inline-flex; align-items:center; gap:var(--sp-2); height:var(--bar-h); padding:0 var(--sp-3);
  border:1px solid transparent; border-radius:var(--r-2); background:var(--hover); color:var(--mut);
  font-size:var(--bar-fs) }
@media (hover:hover) and (pointer:fine){ .search-btn:hover{ border-color:var(--line-2); background:var(--hover) } }
.icon-btn{ width:40px; height:40px; display:inline-flex; align-items:center; justify-content:center;
  border:0; background:transparent; border-radius:var(--r-2); color:var(--ink) }
.icon-btn .ti{ font-size:20px }
@media (max-width:759px){
  .crumbs, .search-btn{ display:none }
  .topbar__logo{ display:block; margin:0 auto }
  .topbar__title.is-on{ display:block; text-align:center; width:100% }
  .icon-btn{ width:44px; height:44px }
  .icon-btn .ti{ font-size:24px }   /* hambúrguer 24px (guia 0.7) */
}
@media (min-width:760px){ .only-mobile{ display:none!important } }

/* cortina do menu mobile: 28% (guia 1); a do modal (.scrim) segue 40% */
.scrim--nav{ position:fixed; inset:0; background:rgba(18,17,16,.28); z-index:44;
  opacity:0; pointer-events:none; transition:opacity var(--t-panel) var(--ease-drawer) }
body.nav-open .scrim--nav{ opacity:1; pointer-events:auto }
@media (min-width:760px){ .scrim--nav{ display:none } }
body.nav-open, body.overlay-open{ overflow:hidden }   /* página atrás não rola */

/* ---------- barra de progresso de navegação (19/09/2026) ----------
   Toda navegação aqui é troca de página inteira (SSR); sem sinal nenhum, o
   clique "trava" por 300-500ms com a página velha parada. A tinta (--fg) é
   a cor de COMANDO — é ela quem avisa "aceitei seu clique". Cresce até 80%
   e NUNCA completa sozinha (só o próximo carregamento a substitui ou o
   navegador troca de página e ela some); o cheff-ui.js decide quando
   nasce, cresce e some. `--t-nav` foge de propósito da régua de <300ms do
   guia (0.6): aqui a barra dura o tempo da REDE, não de uma transição de
   UI. `will-change` evita que o navegador raster o elemento inteiro a
   cada frame do scaleX. */
.nav-progress{ position:fixed; top:0; left:0; width:100%; height:3px;
  background:var(--fg); transform-origin:left; transform:scaleX(0); opacity:0;
  z-index:200; pointer-events:none; will-change:transform;
  transition:opacity var(--t-fast) var(--ease-out) }
.nav-progress.is-show{ opacity:1 }
.nav-progress.is-grow{ --t-nav:4000ms; transform:scaleX(.8);
  transition:transform var(--t-nav) var(--ease-out) }
/* reduzido: sem crescimento, só a barra estática (a regra global de
   prefers-reduced-motion já zera a duração da transição acima; aqui é só
   o ALVO que muda, de 80% pra 30% — crescer 80% "instantaneamente" ainda
   pareceria um salto grande demais pra quem pediu menos movimento). */
@media (prefers-reduced-motion:reduce){ .nav-progress.is-grow{ transform:scaleX(.3) } }

/* ---------- avatar — neutro: cinza só em fio e texto ---------- */
.ava{ width:32px; height:32px; border-radius:var(--r-full); background:var(--hover);
  border:1px solid var(--line); color:var(--ink-2); font-size:11.5px; font-weight:700;
  display:inline-flex; align-items:center; justify-content:center; flex:0 0 auto; letter-spacing:.02em }
.ava--sm{ width:26px; height:26px; font-size:10px }
.ava--lg{ width:56px; height:56px; font-size:18px; flex:0 0 auto }
/* A foto preenche o avatar em QUALQUER tamanho. Nasceu presa ao --lg em
   20/08 e o diretório, que usa o .ava de 32px, ficou com a foto no tamanho
   original — o owner viu na hora. A regra é do .ava, não do modificador. */
.ava img{ width:100%; height:100%; object-fit:cover; border-radius:var(--r-full) }

/* ---------- página: título e resumo ---------- */
.page__pre{ font-size:11.5px; color:var(--mut); font-weight:500; margin-bottom:var(--sp-1) }
.page__pre a{ color:var(--mut) } .page__pre a:hover{ color:var(--ink) }
/* Régua de leitura da tabela (o "o que esta tela mostra"): no desktop fica
   aberta e é o contrato do dado; no celular nasce FECHADA, porque em 390px
   ela ocupava quatro linhas de texto (~120px) antes da primeira linha da
   tabela. O conteúdo continua ali, a um toque — esconder o contrato do dado
   não é opção (guia r.4). Quem fecha é o cheff-ui.js; sem JS, fica aberta. */
.regua{ font-size:11.5px; color:var(--mut) }
.regua > summary{ display:none; cursor:pointer; padding:var(--sp-1) 0;
  font-weight:700; color:var(--ink-2); list-style:none }
.regua > summary::-webkit-details-marker{ display:none }
.regua > summary::after{ content:" ▸"; color:var(--mut) }
.regua[open] > summary::after{ content:" ▾" }
@media (max-width:759px){
  .regua > summary{ display:block; min-height:44px; display:flex; align-items:center }
}

.page__title{ margin:0;
  /* flex porque o título quase sempre vem com selo (ou ponto de estado) ao
     lado: 6 telas do lote 2 escreviam este mesmo style inline. Sem selo, um
     flex de item único é inócuo. */
  display:flex; align-items:center; gap:var(--sp-3); flex-wrap:wrap }
/* O selo dentro do título HERDA o tracking apertado do h1.t-display
   (-.035em) — pensado pra 30px, cramped nos 12.5px do badge--lg (achado no
   acabamento do fornecedor, plano de acabamentos 2026-09-21, bloco 1.5:
   "Disponibilidade de..." lia junto). Zera só aqui, dentro do título. */
.page__title .badge{ letter-spacing:normal }
.page__sum{ font-size:12.5px; color:var(--mut); margin-top:var(--sp-1) }
.page__sum strong{ color:var(--ink); font-weight:700 }

/* ---------- abas = pílula do guia (rodada 6), com âncora ----------
   O guia não tem "tab": o seletor de período (máx. 4 opções, ativo em
   preto) cobre o caso — aqui em <a> + aria-current, navegação server-side. */
.seg a{ display:inline-flex; align-items:center; font-size:var(--bar-fs); font-weight:600;
  color:var(--ink-2); height:calc(var(--bar-h) - 6px); padding:0 var(--sp-3);
  border-radius:var(--r-full);
  transition:color var(--t-fast) var(--ease-out), background var(--t-fast) var(--ease-out) }
.seg a[aria-current="page"]{ background:var(--surface); color:var(--ink); font-weight:700;
  box-shadow:0 0 0 1px rgba(18,17,16,.07), 0 1px 3px rgba(18,17,16,.14) }
@media (hover:hover) and (pointer:fine){ .seg a:not([aria-current="page"]):hover{ color:var(--ink) } }
@media (max-width:759px){ .seg a{ padding:0 var(--sp-4) } }   /* --bar-h já leva a 44px no celular */
/* pílula futura (aba anunciada, ainda sem conteúdo): mesma caixa da âncora,
   texto de desabilitado (decisão 19: aria-disabled, nunca `disabled`) e o
   PORQUÊ no title — roadmap visível, nunca botão morto sem explicação */
.seg span[aria-disabled="true"]{ display:inline-flex; align-items:center; font-size:var(--bar-fs);
  font-weight:600; color:var(--fg-dis); height:calc(var(--bar-h) - 6px); padding:0 var(--sp-3);
  border-radius:var(--r-full); cursor:not-allowed; white-space:nowrap }
@media (max-width:759px){ .seg span[aria-disabled="true"]{ padding:0 var(--sp-4) } }

/* ---------- nota (substitui o alert do Tabler) ----------
   Nota é fio + texto. Vermelho SÓ erro; atenção é ÂMBAR (decisão 66,
   03/09/2026 — antes era preto, decisão 32). */
.note{ display:flex; gap:var(--sp-3); align-items:flex-start; padding:var(--sp-4) var(--sp-5);
  border:1px solid var(--line); border-radius:var(--r-2); font-size:13px; background:var(--surface) }
.note .ti{ font-size:16px; flex:0 0 auto; margin-top:1px; color:var(--mut) }
.note--attention{ border-color:var(--amber) }
.note--attention .ti{ color:var(--amber) }
.note--info{ border-color:var(--blue) }
.note--info .ti{ color:var(--blue) }
.note--bad{ border-color:var(--red) }
.note--bad, .note--bad .ti{ color:var(--red) }

/* ---------- ponto de estado (Watchdog, X9) ----------
   Preenchido só para estado (guia 0.7). Verde SÓ positivo, vermelho SÓ
   problema, cinza = "não sei" — e "não sei" nunca tem cara de "quebrou". */
.dot{ width:8px; height:8px; border-radius:var(--r-full); background:var(--mut);
  display:inline-block; flex:0 0 auto }
.dot--ok{ background:var(--green) }
.dot--bad{ background:var(--red) }
/* Base de Conhecimento (revisão 19/09/2026): revisão vencida é ATENÇÃO, não
   queda/erro — usar .dot--bad (vermelho) ali era o mesmo erro que o guia
   proíbe em selo (decisão 66: vermelho é só queda/erro/destrutivo). */
.dot--attention{ background:var(--amber) }
.dot--lg{ width:12px; height:12px }
.dot--live{ animation:dot-pulse 2400ms var(--ease-in-out) infinite }
@keyframes dot-pulse{
  0%,100%{ box-shadow:0 0 0 0 rgba(14,122,70,.30) }
  50%{ box-shadow:0 0 0 5px rgba(14,122,70,0) }
}

/* ---------- ordenação de tabela (regra permanente da casa) ---------- */
.tbl th a{ display:inline-flex; align-items:center; gap:3px; color:inherit }
/* <abbr> no cabeçalho (DVA60/DVA90, Q-5): sem o sublinhado pontilhado do
   navegador — num rótulo de 10px caixa alta ele lê como sujeira, não como
   pista. A pista mora no `title` (hover) e no leitor de tela; o cabeçalho
   inteiro já é link de ordenação, e sublinhado dentro de link engana. */
.tbl th abbr[title]{ text-decoration:none; border-bottom:0; cursor:inherit }
.tbl th a .ti{ font-size:12px }
.tbl th a .tbl__sort-hint{ opacity:0; font-size:12px; transition:opacity var(--t-fast) var(--ease-out) }
@media (hover:hover) and (pointer:fine){ .tbl th a:hover .tbl__sort-hint{ opacity:.6 } }
.tbl td .btn{ position:relative; z-index:2 }   /* ação acima da âncora esticada da linha */
/* Âncora esticada em tabela: a contenção mora na CÉLULA, nunca na <tr>
   (08/09/2026 — ver o bloco da decisão 38 mais abaixo). */
.tbl .row__link{ position:absolute; inset:0; z-index:1 }
.tbl tbody td:has(> .row__link){ position:relative }
.tbl__foot{ display:flex; align-items:center; gap:var(--sp-3); padding:var(--sp-3) var(--sp-5);
  border-top:1px solid var(--line); font-size:11.5px; color:var(--mut) }
/* `.pager` / `.pager__nav`: nomes que a tela de linhas do BI (grão item,
   08/09/2026) usou para o mesmo papel do .tbl__foot — o rodapé "mostrando
   X de Y" com Anterior/Próxima. Entraram na main sem CSS e a paginação
   renderizava sem estilo nenhum (a guarda do design system pegou). Aqui eles
   herdam o rodapé que já existe, sem tocar naquela view: quem for unificar
   os dois nomes um dia faz isso na frente do BI. */
.pager{ display:flex; align-items:center; gap:var(--sp-3); padding:var(--sp-3) var(--sp-5);
  border-top:1px solid var(--line); font-size:11.5px; color:var(--mut) }
.pager__nav{ display:flex; align-items:center; gap:var(--sp-2); margin-left:auto }
.tbl__foot .u-end{ margin-left:auto }

/* SKU duplicado no Tiny: pílula preta com o Nº DE CADASTROS ATIVOS somados na
   célula (caso 94861: 12+12+13 lia "37"). Preto = exige ação, mesma linguagem
   do .nav__badge; exceção à regra "sem badge na linha do Estoque" (10/08)
   aprovada pelo owner em 13/08/2026 — some sozinha quando o cadastro é limpo. */
.tbl-dup{ display:inline-flex; align-items:center; justify-content:center;
  min-width:16px; height:16px; padding:0 4px; margin-left:5px; border-radius:var(--r-1);
  background:var(--ink); color:var(--on-fg); font-size:10px; font-weight:700;
  font-variant-numeric:tabular-nums; vertical-align:1px; cursor:help }

/* ---------- utilitários mínimos (substituem d-flex/gap/mb do Tabler) ---------- */
.u-hstack{ display:flex; align-items:center; gap:var(--sp-3) }
.u-vstack{ display:flex; flex-direction:column; gap:var(--sp-4) }
.u-grow{ flex:1 1 auto; min-width:0 }
.u-end{ margin-left:auto }
.u-wrap{ flex-wrap:wrap }
.u-full{ flex-basis:100% }   /* linha inteira dentro de um flex com wrap */
.u-mut{ color:var(--mut) }
.u-sm{ font-size:11.5px }
.u-pre{ white-space:pre-wrap }
/* ⚠️ SEM USO nas views desde 20/08: a decisão 49 alinhou à esquerda também o
   valor no fim de linha de lista, e o `bi.ejs` era o último. Fica porque
   `.tbl th.u-right a` depende dela e porque alinhar número à direita segue
   legítimo em TABELA — quem for usar de novo, leia a decisão 49 antes. */
.u-right{ text-align:right }
.u-mb0{ margin-bottom:0 }
.frow{ display:flex; gap:var(--sp-3) } .frow>*{ flex:1 1 0; min-width:0 }
/* irmão de largura fixa dentro da .frow (UF ao lado da cidade, data ao lado do tipo) */
.frow > .field--xs{ flex:0 0 7rem } .frow > .field--sm{ flex:0 0 11rem }
@media (max-width:759px){ .frow--break > .field--xs, .frow--break > .field--sm{ flex:1 1 auto } }
@media (max-width:759px){ .frow--break{ flex-direction:column } }
.stack-sp2{ gap:var(--sp-2) } .stack-sp4{ gap:var(--sp-4) }
.mt-1{ margin-top:var(--sp-1) } .mt-2{ margin-top:var(--sp-2) } .mt-4{ margin-top:var(--sp-4) } .mt-6{ margin-top:var(--sp-6) }
.mb-4{ margin-bottom:var(--sp-4) } .mb-5{ margin-bottom:var(--sp-5) } .mb-6{ margin-bottom:var(--sp-6) }

/* ---------- caixa de seleção e interruptor (rodada 9: 19px, área 67px) ---------- */
.chk{ display:inline-flex; align-items:center; gap:var(--sp-2); cursor:pointer;
  font-size:13.5px; font-weight:500; padding:var(--sp-2) 0; min-height:28px }
.chk input{ width:19px; height:19px; accent-color:var(--ink); margin:0; flex:0 0 auto }
.tgl{ position:relative; width:46px; height:26px; flex:0 0 auto }
.tgl input{ position:absolute; inset:0; opacity:0; margin:0; cursor:pointer }
.tgl__track{ position:absolute; inset:0; border-radius:var(--r-full); background:var(--line-2);
  transition:background var(--t-fast) var(--ease-out); pointer-events:none }
.tgl__track::after{ content:""; position:absolute; top:3px; left:3px; width:20px; height:20px;
  border-radius:var(--r-full); background:var(--knob); box-shadow:var(--sh-1);
  transition:transform var(--t-fast) var(--ease-out) }
.tgl input:checked + .tgl__track{ background:var(--ink) }
.tgl input:checked + .tgl__track::after{ transform:translateX(20px) }
.tgl input:focus-visible + .tgl__track{ outline:2px solid var(--red); outline-offset:2px }

/* ---------- paleta de navegação (a "busca" do shell) ----------
   ⌘K no desktop; lupa → tela cheia no celular (guia 1: opacidade + 8px,
   200ms, SEM scale). Abrir por teclado não anima (guia 0.6). */
.palette{ position:fixed; inset:0; z-index:55; display:none }
.palette.is-open{ display:block }
.palette__scrim{ position:absolute; inset:0; background:rgba(18,17,16,.4) }
.palette__panel{ position:relative; margin:12vh auto 0; width:min(560px,calc(100vw - 32px));
  background:var(--surface); border-radius:var(--r-2); box-shadow:var(--sh-3); overflow:hidden;
  display:flex; flex-direction:column; max-height:60vh }
.palette.is-open .palette__panel{ animation:palette-in var(--t-ui) var(--ease-out) }
.palette.is-instant .palette__panel{ animation:none }
@keyframes palette-in{ from{ opacity:0; transform:translateY(8px) } }
.palette__head{ display:flex; align-items:center; gap:var(--sp-3); padding:var(--sp-3) var(--sp-4);
  border-bottom:1px solid var(--line) }
.palette__head .ti{ font-size:18px; color:var(--mut) }
/* D13: sem spinner abaixo de 300ms (cheff-ui.js só põe aria-busy depois
   disso) — reusa o MESMO @keyframes spin do botão (`.btn__spinner`), sem
   cor nova: gira o próprio ícone de lupa em currentColor/--mut. */
.palette[aria-busy="true"] .palette__head > .ti{ animation:spin 620ms linear infinite }
.palette__input{ flex:1 1 auto; border:0; outline:0; font:inherit; font-size:16px; color:var(--ink);
  height:40px; background:transparent }
.palette__cancel{ display:none; background:none; border:0; font-size:13.5px; font-weight:600; color:var(--ink) }
.palette__list{ list-style:none; margin:0; padding:var(--sp-1); overflow-y:auto }
.palette__label{ font-size:9.5px; letter-spacing:.17em; text-transform:uppercase; color:var(--mut);
  font-weight:700; padding:var(--sp-3) var(--sp-3) var(--sp-1) }
/* D13: .palette__label--estatico, .palette__item--estatico, .palette__item--link
   e (só em cheff-ui.js) .palette__label--dinamico/.palette__item--dinamico são
   marcadores de JS pros três grupos da paleta (estático/API/links) — nenhum
   tem estilo próprio, todos herdam de .palette__label/.palette__item acima. */
.palette__item a{ display:flex; align-items:center; gap:var(--sp-3); padding:var(--sp-3);
  border-radius:var(--r-2); font-size:13.5px; font-weight:500 }
.palette__item .ti{ font-size:17px; color:var(--mut) }
.palette__item.is-hi a{ background:var(--hover) }
.palette__item .u-end{ font-size:11px; color:var(--mut) }
.palette__empty{ padding:var(--sp-5); font-size:12.5px; color:var(--mut); text-align:center }
@media (max-width:759px){
  /* tela cheia: escalar tela cheia embrulha o estômago — só opacidade+desloc */
  .palette__scrim{ display:none }
  .palette__panel{ margin:0; width:100%; max-height:none; height:100dvh; border-radius:0; box-shadow:none;
    padding-top:env(safe-area-inset-top) }
  .palette__cancel{ display:block }
  .palette__head{ padding:var(--sp-3) var(--sp-4) }
}

/* ---------- modal: estrutura interna + folha de baixo no celular ---------- */
.modal__head{ display:flex; align-items:center; gap:var(--sp-3); padding:var(--sp-4) var(--sp-5);
  border-bottom:1px solid var(--line) }
.modal__title{ font-size:20px; font-weight:800; letter-spacing:-.025em; margin:0 }
.modal__body{ padding:var(--sp-5); overflow-y:auto }
.modal__foot{ display:flex; align-items:center; gap:var(--sp-2); padding:var(--sp-4) var(--sp-5);
  border-top:1px solid var(--line) }
.modal--lg{ width:min(680px,calc(100vw - 32px)) }
.modal{ display:flex; flex-direction:column; max-height:min(78vh,720px) }
.modal[hidden], .scrim[hidden], .palette[hidden]{ display:none }
.modal.is-open{ animation:modal-in var(--t-ui) var(--ease-out) }
@keyframes modal-in{ from{ opacity:0; transform:translate(-50%,-50%) scale(.97) } }
.scrim.is-open{ animation:scrim-in var(--t-ui) var(--ease-out) }
@keyframes scrim-in{ from{ opacity:0 } }
@media (max-width:759px){
  .modal{ max-height:86dvh }
  .modal.is-open{ animation:sheet-in var(--t-panel) var(--ease-drawer) }
  @keyframes sheet-in{ from{ transform:translateY(100%) } }
}

/* ---------- toast: entra de baixo, interrompível ---------- */
.toast{ transition:opacity var(--t-ui) var(--ease-out), transform var(--t-ui) var(--ease-out) }
.toast.is-enter{ opacity:0; transform:translateY(12px) }

/* ---------- Comitê: revelação do placar (portado do portal.css) ----------
   Único momento de cerimônia: raro, é a recompensa do ritual. */
.placar-revelado .placar-linha{ opacity:0; transform:translateY(6px);
  animation:placar-entra 240ms var(--ease-out) forwards }
.placar-revelado .placar-linha:nth-child(1){ animation-delay:0ms }
.placar-revelado .placar-linha:nth-child(2){ animation-delay:50ms }
.placar-revelado .placar-linha:nth-child(3){ animation-delay:100ms }
.placar-revelado .placar-linha:nth-child(4){ animation-delay:150ms }
@keyframes placar-entra{ to{ opacity:1; transform:translateY(0) } }
@media (prefers-reduced-motion:reduce){
  .placar-revelado .placar-linha{ animation:none; opacity:1; transform:none }
}

/* ---------- X9/Watchdog: stat card que filtra (portado; azul → preto) ----------
   Ativo era azul Tabler; a lei não tem azul: ativo = fio preto, como a
   pílula ativa. Navegação 100% server-side via href. */
a.card.stat-filter{ border:1px solid var(--line) }
a.card.stat-filter.is-active{ border-color:var(--ink); box-shadow:0 0 0 1px var(--ink) }
a.card.stat-filter.is-active .t-micro{ color:var(--ink) }

/* ---------- Watchdog: grade de sistemas (portado) ----------
   Alturas iguais pra grade ler como grade (exceção deliberada, como o
   stat card). Problema = borda vermelha: o pontinho sozinho é pequeno
   demais pra puxar o olho numa grade de 6. */
.wd-grid{ display:grid; grid-template-columns:repeat(auto-fill,minmax(230px,1fr)); gap:var(--sp-4) }
a.card.wd-card{ height:100% }
a.card.wd-card--problema{ border-color:var(--red) }
.card--problema{ border-left:3px solid var(--red) }     /* drill-down: a razão da página */
.card--indefinido{ border-left:3px solid var(--line-2) } /* "não sei" ≠ "quebrou" */

/* ---------- pares rótulo/valor (drill-down do watchdog) ---------- */
.kv{ display:grid; grid-template-columns:minmax(120px,180px) 1fr; gap:var(--sp-2) var(--sp-4);
  font-size:13px }
.kv dt{ color:var(--mut); font-weight:400 }
.kv dd{ margin:0 }
@media (max-width:759px){ .kv{ grid-template-columns:1fr } .kv dt{ margin-top:var(--sp-2) } }

/* ---------- complementos ---------- */
/* v2: o ladrilho de ícone (.tile-ico) come largura — a coluna sobe de 240
   para 264 pra descrição não quebrar em 3 linhas e desalinhar a fileira. */
.tile-grid{ display:grid; grid-template-columns:repeat(auto-fill,minmax(264px,1fr)); gap:var(--sp-3) }
.tile-grid .card__body > .ti:first-child{ width:36px; height:36px; flex:0 0 36px;
  display:inline-flex; align-items:center; justify-content:center;
  background:var(--surf); border-radius:8px }
/* destrutivo: neutro em repouso, vermelho no hover; sólido SÓ no confirmar do diálogo (decisão 18) */
.btn--del{ background:transparent; color:var(--mut); border-color:transparent }
/* rodapé grudento de formulário longo (Pedido de compra, 24/08/2026): tabela
   editável com dezenas de linhas — total e botão de emitir ficam à vista
   enquanto se rola. Branco puro (fundo da página), fio em cima, nunca área
   cinza. É o mesmo .card__foot, só que gruda no fim da viewport. */
.card__foot--sticky{ position:sticky; bottom:0; background:var(--surface); z-index:2 }
@media (hover:hover) and (pointer:fine){ .btn--del:hover{ color:var(--red); background:var(--hover) } }
.sr-only{ position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden;
  clip:rect(0,0,0,0); white-space:nowrap; border:0 }
/* Conteúdo sr-only FORA de controle de formulário (ex.: tabela equivalente de
   gráfico) usa --flow: absolute sem ancestral posicionado ancora no documento,
   escapa do clip do .content e estica a rolagem da janela quando a posição
   estática cai abaixo da dobra (bug do BI Estoque, 10/08/2026). No fluxo, a
   caixa 1×1 com margem -1px tem impacto zero e é clipada normalmente. */
.sr-only--flow{ position:relative }

/* ---------- telas sem shell (login, acesso negado) ---------- */
.auth{ min-height:100dvh; display:flex; flex-direction:column; align-items:center;
  justify-content:center; padding:var(--sp-6) var(--sp-6) 12vh; gap:var(--sp-6) }  /* 12vh embaixo = centro ótico, não geométrico */
.auth__logo{ height:56px; display:block }
.auth .card{ width:min(400px,100%) }

/* ---------- Comitê: nota 1–5 (radio estilizado como pílula; escolhido = preto) ---------- */
.rate{ display:flex; gap:var(--sp-1) }
/* position:relative é OBRIGATÓRIO aqui: o <input class="sr-only"> dentro é
   position:absolute e, sem ancestral posicionado, ancora no documento —
   escapa do clip e ESTICA a rolagem horizontal da página. Mesma mecânica do
   bug do BI (10/08) que criou o .sr-only--flow; aqui a âncora tem que ser a
   própria pílula. Achado em 20/08 no focus-nova e focus-editar, ao abrir a
   tela em várias larguras.
   Altura em --fld-h e não --ctl-h: é controle de FORMULÁRIO (alvo de mira e
   permanência), não botão de barra. */
.rate label{ position:relative; flex:1 1 0; height:var(--fld-h); display:flex; align-items:center; justify-content:center;
  border:1px solid var(--line); border-radius:var(--r-2); font-size:13px; font-weight:600; cursor:pointer;
  transition:background var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out),
             border-color var(--t-fast) var(--ease-out), transform var(--t-press) var(--ease-out) }
.rate label:active{ transform:scale(.97) }
@media (hover:hover) and (pointer:fine){ .rate label:hover{ background:var(--hover); border-color:var(--line-2) } }
.rate label:has(input:checked){ background:var(--ink); color:var(--on-fg); border-color:var(--ink) }
.rate label:has(input:focus-visible){ outline:2px solid var(--red); outline-offset:2px }

/* ---------- busca de toolbar (filtro de tabela) ----------
   Controle de barra (40px), não campo de formulário (46px) — mas a fonte
   segue os 16px: menos que isso o iPhone dá zoom sozinho ao focar. */
.tbl-search{ position:relative; display:inline-flex; align-items:center }
.tbl-search .ti{ position:absolute; left:10px; font-size:15px; color:var(--mut); pointer-events:none }
.tbl-search input{ font:inherit; font-size:var(--bar-fs); color:var(--ink); background:var(--hover);
  border:1px solid var(--line); border-radius:var(--r-2); height:var(--bar-h);
  padding:0 var(--sp-3) 0 30px; width:200px; max-width:100%;
  transition:border-color var(--t-fast) var(--ease-out), box-shadow var(--t-fast) var(--ease-out) }
.tbl-search input:focus{ outline:none; border-color:var(--ink); box-shadow:var(--ring) }
@media (max-width:759px){ .tbl-search, .tbl-search input{ width:100% } }

/* ---------- seta de ordenação via CSS ----------
   O <a> do th carrega só o rótulo + a classe `table-sort asc|desc` na coluna
   ativa (contrato guardado por teste). A seta é ::after: visível na ativa,
   aparece no hover nas demais (guia, rodada 8). ↑↓ estão no subset da Manrope. */
.tbl th a::after{ content:"↓"; margin-left:3px; opacity:0;
  transition:opacity var(--t-fast) var(--ease-out) }
@media (hover:hover) and (pointer:fine){ .tbl th a:hover::after{ opacity:.6 } }
.tbl th a.table-sort{ color:var(--ink) }
.tbl th a.table-sort.desc::after{ content:"↓"; opacity:1 }
.tbl th a.table-sort.asc::after{ content:"↑"; opacity:1 }

/* ---------- ajustes da revisão em produção (owner, 03/08/2026) ---------- */
/* placeholder é exemplo, não dado: só a COR o separa do dado (decisão 73,
   13/09/2026). Até então ele era 13,5px contra 15px do valor digitado, e a
   letra mudava de tamanho de caixa para caixa no mesmo formulário e de novo
   quando a pessoa começava a digitar. Revoga o ajuste de 03/08/2026. */
input::placeholder, textarea::placeholder{ font-size:inherit; color:var(--mut); opacity:1 }

/* cabeçalho sem fio + corpo empilhavam 16+20px de respiro — encosta o corpo */
.card__head:not(.card__head--divided) + .card__body{ padding-top:var(--sp-1) }

/* coluna numérica: a seta (mesmo invisível) reservava espaço DEPOIS do rótulo
   e desalinhava o cabeçalho dos números. Em coluna à direita a seta vai ANTES,
   e o rótulo encosta na mesma borda que os dados. */
.tbl th.u-right a{ flex-direction:row-reverse }

/* badge ao lado do título de página (30px) precisa de mais corpo */
.badge--lg{ font-size:12.5px; padding:5px 12px; gap:7px }
.badge--lg .badge__dot{ width:7px; height:7px }

/* Correção (03/08): `.tbl th` (0-1-1) ganhava de `.u-right` (0-1-0) — cabeçalho
   numérico ficava à ESQUERDA com dado à direita. E sem largura própria a coluna
   numérica esticava (pior com busca de 1 resultado). Regra do guia, rodada 8:
   a coluna de identificação leva o espaço que sobra; as de número têm largura
   própria — width:1% + nowrap encolhe a coluna ao conteúdo. */
.tbl th.u-right, .tbl td.u-right{ text-align:right }

/* Correção 2 da revisão (03/08, print do owner): SKU/Conta são IDENTIFICADOR,
   não quantidade — .num neles mantém o dígito tabular mas o alinhamento volta
   pra esquerda, rente ao cabeçalho. */
.tbl th.u-left, .tbl td.u-left{ text-align:left }
/* Sobra de espaço se redistribui NATURALMENTE entre as colunas (decisão do
   owner, 03/08): nada de coluna elástica única nem sobra ancorada — o
   navegador distribui proporcional ao conteúdo e o respiro fica uniforme.
   Página de tabela só usa .page--wide quando a tabela é larga de verdade. */
/* dado longo trunca em 1 linha (guia, rodada 5) — uma linha comprida não pode alargar a coluna da tela inteira */
.tbl td.u-clip{ max-width:26rem; overflow:hidden; text-overflow:ellipsis }

/* ── Tabela com grupos de colunas (Produtos) ─────────────────────────────
   Cabeçalho SEMPRE visível (pedido do owner, 03/08/2026): o wrapper ganha
   scroll vertical interno (--vscroll) — sticky só funciona dentro do
   contêiner de overflow, então a rolagem da tabela mora nela, não na página.
   As DUAS linhas do thead grudam: a de grupo em top:0 com altura FIXA
   (--grp-h) e a de colunas logo abaixo — sem altura fixa o offset da segunda
   linha seria incalculável em CSS puro. Fio à esquerda separa os grupos. */
:root{ --grp-h: 30px }
.tbl__wrap--vscroll{ max-height:max(360px, calc(100dvh - 320px)); overflow:auto }
.tbl thead tr.tbl__grps th{ text-align:center; border-left:1px solid var(--line) }
.tbl td.tbl__grp-edge, .tbl th.tbl__grp-edge{ border-left:1px solid var(--line) }
.tbl__wrap--vscroll thead tr.tbl__grps th, .tbl__wrap--vscroll thead tr.tbl__grps td{
  position:sticky; top:0; z-index:2; background:var(--surf);
  height:var(--grp-h); padding-top:0; padding-bottom:0; vertical-align:middle }
.tbl__wrap--vscroll thead tr:nth-child(2) th{ top:var(--grp-h) }

/* Select de filtro no cabeçalho do card (marca) — mesmo desenho do campo de
   busca de tabela; 16px é o piso do zoom do iOS. `appearance:none` é
   obrigatório: sem ele o macOS/iOS impõe o chrome nativo do select (fonte de
   sistema ~13px, altura própria) e ignora o desenho da casa; o chevron nativo
   some junto, então o ícone Tabler entra por cima (pointer-events:none). */
.tbl-filter{ position:relative; display:inline-flex; align-items:center }
.tbl-filter .ti{ position:absolute; right:10px; font-size:15px; color:var(--mut); pointer-events:none }
.tbl-filter select{ appearance:none; -webkit-appearance:none;
  font:inherit; font-size:var(--bar-fs); color:var(--ink); background:var(--hover);
  border:1px solid var(--line); border-radius:var(--r-2); height:var(--bar-h);
  padding:0 30px 0 var(--sp-3); max-width:100%;
  transition:border-color var(--t-fast) var(--ease-out), box-shadow var(--t-fast) var(--ease-out) }
.tbl-filter select:focus{ outline:none; border-color:var(--ink); box-shadow:var(--ring) }
/* Decisão 36: select vazio ("todos") se veste de placeholder — 13,5px --mut,
   os mesmos do ::placeholder da busca. Placeholder é exemplo, não dado. No
   celular volta a 16px: select focado com fonte <16px dispara zoom no iOS
   (regra dura do guia). Selecionado, o filtro vira dado: sai da classe e
   volta a 16px ink. */
/* Decisão 36 preservada, agora sem quebrar a escala: placeholder e dado
   partem do MESMO tamanho (--bar-fs) e só a COR os separa. */
.tbl-filter select.sel-vazio{ color:var(--mut) }
/* No celular cada select de filtro tomava a linha inteira: os três das Ordens
   (situação, fornecedor, destino) empilhavam ~180px antes da primeira linha
   da tabela. Agora dividem a linha aos pares, mantendo os 44px de alvo e os
   16px de fonte. Select sozinho continua ocupando a largura toda
   (08/09/2026). */
@media (max-width:759px){
  .tbl-filter, .tbl-filter select{ width:100% }
  .tbl-filter.u-hstack{ width:100%; gap:var(--sp-2) }
  .tbl-filter.u-hstack > select{ flex:1 1 calc(50% - var(--sp-2)); width:auto; min-width:8.5rem }
  .tbl-filter.u-hstack > select:only-of-type{ flex-basis:100% }
  /* .filtro (decisão 78) segue a mesma régua dos selects: aos pares no celular. */
  .tbl-filter.u-hstack > .filtro{ flex:1 1 calc(50% - var(--sp-2)); min-width:0; width:auto }
  .tbl-filter.u-hstack > .filtro select{ min-width:0; flex:1 }
  /* Legenda do cabeçalho de card some no celular: o título e o número bastam
     (a legenda quebrava em 4 linhas em 390px, achado 15/09/2026). */
  .card__head .t-caption.u-grow{ display:none }
}

/* Pager do rodapé: no celular o alvo sobe pra 44px (regra dura do guia) —
   btn--sm é 32px, pensado pra ação de linha no desktop. */
@media (max-width:759px){ .tbl__foot .btn{ height:44px } }

/* Decisão 78 (15/09/2026, revoga a 36): filtro de tabela é um BOTÃO — rótulo
   fixo + valor + seta — nunca um select vestido de placeholder. "Todo
   passo"/"Todo fornecedor" já é dado (a opção neutra, primeira da lista),
   nunca um texto de exemplo: o rótulo (.filtro__k) é quem sinaliza "isto é
   um filtro", então o valor pode ser --fg cheio o tempo todo. Filtro ativo
   ganha fio preto — a MESMA linguagem de "isto está filtrando" que o resto
   da casa usa (chip, .btn__count). */
.filtro{ position:relative; display:inline-flex; align-items:center; gap:8px;
  height:var(--bar-h); padding:0 32px 0 12px; border:1px solid var(--line-2);
  border-radius:8px; background:var(--surface); font-size:var(--bar-fs);
  transition:border-color var(--t-fast) var(--ease-out), box-shadow var(--t-fast) var(--ease-out) }
.filtro__k{ color:var(--mut); font-weight:600 }
.filtro select{ appearance:none; -webkit-appearance:none; border:0; background:transparent;
  font:inherit; font-weight:700; color:var(--fg); padding:0; height:100%; cursor:pointer }
.filtro__chev{ position:absolute; right:10px; width:14px; height:14px; color:var(--mut); pointer-events:none }
.filtro.is-on{ border-color:var(--fg); box-shadow:0 0 0 1px var(--fg) inset }
.filtro:focus-within{ outline:none; border-color:var(--fg); box-shadow:var(--ring) }
/* --bar-h/--bar-fs já sobem pra 44px/16px no celular (:root, ~L127): mesma
   régua de toque do resto da barra, sem regra própria aqui. */

/* ============================================================
   BARRA DE CONTROLE — chip, popover e pílula (22/08/2026)
   Nasceram na lapidação do Produtos (Fase 1), mas são componentes
   GLOBAIS de propósito: achado vira componente, nunca conserto de
   página. Tudo na escala de controle: chip é controle de barra
   (--bar-h/--bar-fs); pílula é seleção em overlay (--ctl-h);
   campo de formulário segue --fld-h.
   ============================================================ */

/* chip de filtro ativo: o × remove — o chip INTEIRO é o link de remoção
   (alvo maior que um × de 12px). Fundo --hover, não --surf: texto --ink-2
   passa nos dois, mas o chip vive ao lado de .tbl-search, que já é --hover. */
.chip{ display:inline-flex; align-items:center; gap:6px; height:var(--bar-h);
  padding:0 var(--sp-3); border:1px solid var(--line); border-radius:var(--r-full);
  background:var(--hover); font-size:var(--bar-fs); font-weight:600; color:var(--ink-2);
  white-space:nowrap;
  transition:border-color var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out) }
.chip .ti{ font-size:12px; color:var(--mut) }   /* marca de afordância (decisão 57) */
@media (hover:hover) and (pointer:fine){ .chip:hover{ border-color:var(--line-2); color:var(--ink) } }

/* contador de filtros ativos no gatilho — preto = exige atenção, mesma
   linguagem do .nav__badge e da .tbl-dup */
.btn__count{ min-width:16px; height:16px; padding:0 4px; border-radius:var(--r-full);
  background:var(--ink); color:var(--on-fg); font-size:10px; font-weight:700;
  display:inline-flex; align-items:center; justify-content:center;
  font-variant-numeric:tabular-nums }

/* popover genérico: cresce DO GATILHO (decisão 34) — transform-origin no
   canto do gatilho, entrada scale(.97)+opacity em 200ms ease-out (nunca
   scale(0)), saída mais curta que a entrada. Aberto/fechado pelo
   cheff-ui.js ([data-pop]): Esc, clique fora e botão fecham; foco volta ao
   gatilho. <760px o MESMO painel vira folha de baixo fixa (zona do
   polegar). prefers-reduced-motion zera as durações na regra global. */
.pop__wrap{ position:relative; display:inline-flex }
.pop{ position:absolute; top:calc(100% + var(--sp-2)); left:0; z-index:40;
  min-width:280px; max-width:min(380px, calc(100vw - 32px));
  background:var(--surface); border:1px solid var(--line); border-radius:var(--r-2);
  box-shadow:var(--sh-2); padding:var(--sp-4); transform-origin:top left }
/* Painel largo: o seletor de flags leva nota e prazo POR flag, e em 380px
   os três campos se espremiam numa coluna de 90px. 560 é a largura de
   formulário da casa (guia r.9). */
/* Painel largo, com teto de altura: com a lista de flags MAIS o formulário
   de criar aberto, ele passava do rodapé da janela e o botão de salvar
   sumia. Teto + rolagem interna resolvem sem tirar nada da tela. */
.pop--largo{ max-width:min(560px, calc(100vw - 32px));
  max-height:min(72vh, 640px); overflow-y:auto }
/* Painel do Período: uma coluna só (rodada 1 de feedback, 13/09/2026) —
   duas colunas de 280px espremiam "Comparar com" e o Grão em pilhas de uma
   pill por linha e deixavam o popover mais alto que a viewport. 520 é o
   ponto onde os 8 atalhos (Hoje…Personalizado) quebram em no máximo duas
   linhas; MENOR que o `.pop--largo` de 560 porque aqui não há duas colunas
   de campo a acomodar. `width` (não `max-width`) porque a coluna única já
   define a altura sozinha — não precisa encolher além do necessário. */
/* `.pop` base trava max-width em 380px — sem repetir aqui, o `width` abaixo
   nunca venceria essa trava e o painel voltaria a ficar estreito. */
.pop--periodo{ width:min(520px, calc(100vw - 32px)); max-width:min(520px, calc(100vw - 32px)) }
/* Com o painel já tendo teto e rolagem, a lista não precisa do dela: dois
   contêineres rolando um dentro do outro é justamente o que trava no toque. */
.pop--largo .pop__lista{ max-height:none; overflow:visible }
/* O rodapé do painel gruda no fundo: com oito flags e o formulário de criar
   aberto, o "Salvar flags" caía abaixo da dobra — a pessoa marcava e não via
   como salvar (achado na folha de baixo do celular, 08/09). */
.pop--largo .pop__foot{ position:sticky; bottom:0; z-index:1;
  background:var(--surface); border-top:1px solid var(--line);
  margin-top:var(--sp-2); padding:var(--sp-3) 0 }
/* Gatilho encostado na borda direita: o painel abre alinhado à direita, senão
   `left:0` o joga pra fora da tela (foi o que aconteceu no hub do SKU). O
   crescimento continua saindo do gatilho, como manda o guia (r.12). */
.pop--direita{ left:auto; right:0; transform-origin:top right }
/* Criar flag sem sair do produto: nasce fechado pra não competir com a lista
   de flags que já existem — criar é a exceção, marcar é o caso normal. */
.flags-nova > summary{ cursor:pointer; font-weight:700; font-size:12px; padding:var(--sp-2) 0; list-style:none }
.flags-nova > summary::-webkit-details-marker{ display:none }
.flags-nova > summary::after{ content:" +"; color:var(--mut) }
.flags-nova[open] > summary::after{ content:" −" }
.flags-nova > form{ gap:var(--sp-3) }
.flags-nova .field{ width:100% }
/* "Mais opções" do formulário de flag: o essencial (nome, definição, assunto,
   espécie) fica à vista e o resto — cor do Sinal, grupo que se substitui,
   prazo — nasce recolhido. O owner criou uma flag e perguntou o que era cada
   campo (08/09): campo que não se explica sozinho não pode ser a primeira
   coisa que a pessoa vê. Abre sozinho quando algum deles já tem valor. */
.mais-opcoes > summary{ cursor:pointer; font-weight:700; font-size:13px;
  padding:var(--sp-3) 0; list-style:none; border-top:1px solid var(--line) }
.mais-opcoes > summary::-webkit-details-marker{ display:none }
.mais-opcoes > summary::after{ content:" +"; color:var(--mut) }
.mais-opcoes[open] > summary::after{ content:" −" }
.mais-opcoes__corpo{ display:flex; flex-direction:column; gap:var(--sp-6); padding-top:var(--sp-2) }
.flags-nova .field input, .flags-nova .field select{ width:100% }
.pop.is-open{ animation:pop-in var(--t-ui) var(--ease-out) }
.pop.is-closing{ animation:pop-out var(--t-fast) var(--ease-out) forwards }
@keyframes pop-in{ from{ opacity:0; transform:scale(.97) } }
@keyframes pop-out{ to{ opacity:0; transform:scale(.97) } }
.pop__head{ display:flex; align-items:center; gap:var(--sp-2); margin-bottom:var(--sp-3) }
.pop__sec{ margin-bottom:var(--sp-4) }
.pop__foot{ display:flex; align-items:center; gap:var(--sp-2); margin-top:var(--sp-4) }
.pop__lista{ display:flex; flex-direction:column; max-height:240px; overflow-y:auto }
.pop__item{ display:flex; align-items:center; gap:var(--sp-2); padding:var(--sp-2) var(--sp-3);
  border-radius:var(--r-1); font-size:13px }
@media (hover:hover) and (pointer:fine){ .pop__item:hover{ background:var(--hover) } }
.pop__item[aria-current]{ font-weight:700 }
/* Item do seletor de flags: a linha tem três andares (etiqueta, definição e,
   quando marcada, nota + prazo). Em linha só, a definição virava uma coluna
   de 40px e os campos espremiam o resto — foi assim que o painel chegou à
   produção em 08/09. Coluna resolve, e a busca ocupa a largura toda. */
.pop__item--flag{ flex-direction:column; align-items:stretch; gap:var(--sp-1);
  padding-top:var(--sp-3); padding-bottom:var(--sp-3) }
.pop__item--flag + .pop__item--flag{ border-top:1px solid var(--line) }
.pop__item--flag .chk{ gap:var(--sp-2) }
.pop__item--flag .frow{ gap:var(--sp-3); margin-top:var(--sp-1) }
.pop__item--flag .field--sm{ flex:1 1 0; min-width:0 }
.pop [data-flags-busca]{ width:100% }
@media (max-width:759px){
  .pop{ position:fixed; inset:auto 0 0 0; max-width:none; min-width:0;
    border-radius:var(--r-2) var(--r-2) 0 0; box-shadow:var(--sh-3);
    max-height:80dvh; overflow-y:auto; transform-origin:bottom center }
  .pop.is-open{ animation:pop-sheet var(--t-panel) var(--ease-drawer) }
  .pop.is-closing{ animation:pop-sheet-out var(--t-ui) var(--ease-drawer) forwards }
  @keyframes pop-sheet{ from{ transform:translateY(100%) } }
  @keyframes pop-sheet-out{ to{ transform:translateY(100%) } }
}
/* cortina da folha de baixo: mesmos 28% da cortina do nav (é painel leve,
   não modal de 40%); clique nela fecha (cheff-ui.js). Abaixo do .pop (40)
   e SÓ no celular — no desktop o popover não escurece a página. */
.pop__scrim{ position:fixed; inset:0; z-index:39; background:rgba(18,17,16,.28);
  animation:scrim-in var(--t-ui) var(--ease-out) }
@media (min-width:760px){ .pop__scrim{ display:none } }

/* ---------- Barra de filtros global do BI (spec 2026-09-12) ----------
   Uma linha: período · filtros · chips · (espaço) · visões. É controle,
   não formulário; no celular vira rolagem horizontal e o popover vira folha
   (regra do .pop). Os controles herdam --bar-h/--bar-fs: nada declara altura. */
.fbar{ display:flex; align-items:center; gap:var(--sp-2); flex-wrap:wrap }
.fbar__sp{ flex:1 1 auto }
.pop__cols{ display:grid; grid-template-columns:1fr 1fr; gap:var(--sp-5) }
@media (max-width:759px){
  .fbar{ flex-wrap:nowrap; overflow-x:auto; scrollbar-width:none; margin:0 calc(-1*var(--sp-4)); padding:0 var(--sp-4) 2px }
  .fbar::-webkit-scrollbar{ display:none }
  .fbar__sp{ display:none }
  .pop__cols{ grid-template-columns:1fr }
}
/* sparkline de tabela (Canal × período, Concentração): textura de tendência,
   sem eixo, sem grade (guia 4, stat card) */
.spark{ width:72px; height:24px; flex:0 0 auto }

/* pílula de seleção (radio/checkbox .sr-only dentro): escolhida = preta,
   mesma linguagem do .rate do Comitê. position:relative OBRIGATÓRIO — o
   input absoluto sem ancestral posicionado ancora no documento e estica a
   rolagem (lição do .rate, 20/08). Radio marcado clicado de novo desmarca
   (cheff-ui.js, data-desmarca). Altura de AÇÃO (--ctl-h), não de campo:
   seleção momentânea em overlay, não campo de permanência. */
.pills{ display:flex; flex-wrap:wrap; gap:var(--sp-2) }
.pill{ position:relative; display:inline-flex; align-items:center; height:var(--ctl-h);
  padding:0 var(--sp-4); border:1px solid var(--line); border-radius:var(--r-full);
  font-size:13px; font-weight:600; cursor:pointer;
  transition:background var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out),
             border-color var(--t-fast) var(--ease-out), transform var(--t-press) var(--ease-out) }
.pill:active{ transform:scale(.97) }
@media (hover:hover) and (pointer:fine){ .pill:hover:not(:has(input:checked)){ background:var(--hover); border-color:var(--line-2) } }
.pill:has(input:checked){ background:var(--ink); color:var(--on-fg); border-color:var(--ink) }
.pill:has(input:focus-visible){ outline:2px solid var(--red); outline-offset:2px }

/* pílula-LINK (Consultas prontas, Bloco 6, DoD §5, 12/09/2026): mesma
   linguagem visual da pílula de rádio/checkbox acima, mas em <a> — liga/
   desliga por NAVEGAÇÃO (GET), não por input. `.is-on` é o estado ligado
   (`aria-pressed="true"` no HTML) e `.pill__n` é a contagem em cinza dentro
   da pílula (apoio sobre --ink quando ligada). */
.pill:focus-visible{ outline:2px solid var(--red); outline-offset:2px }
.pill.is-on{ background:var(--ink); color:var(--on-fg); border-color:var(--ink) }
@media (hover:hover) and (pointer:fine){ .pill.is-on:hover{ background:var(--ink); border-color:var(--ink) } }
.pill__n{ margin-left:6px; color:var(--mut); font-variant-numeric:tabular-nums }
.pill.is-on .pill__n{ color:var(--on-fg-mut) }

/* dentro de uma área que rola na horizontal, as pílulas de Consultas não
   podem quebrar linha nem encolher — mesmo motivo do `.rola--x > .seg`
   acima (a barra tem que escapar da largura, não caber nela). */
.rola--x > .pills{ flex-wrap:nowrap; width:max-content }
.rola--x > .pills .pill{ flex:0 0 auto; white-space:nowrap }

/* grade 2 colunas que quebra em 1 no celular — era classe fantasma (UI-7):
   produtos-detalhe e bi-ranking-sku a pediam com o grid escrito em style. */
.grid-quebra{ display:grid; grid-template-columns:1fr 1fr; gap:var(--sp-5); align-items:start }
@media (max-width:759px){ .grid-quebra{ grid-template-columns:1fr } }

/* ============================================================
   SANFONA — <details> nativo (aba Webhooks, 04/08/2026)
   Teclado e leitor de tela de graça; sem JS. Fechado é o padrão: a tela existe
   pra dar visão geral, e detalhe só quando pedido. O que NÃO pode ficar
   escondido é problema — por isso o estado agregado vive no cabeçalho e a
   linha falhando abre sozinha (`open` vindo do servidor).
   ============================================================ */
.wh__item{ border-bottom:1px solid var(--line) }
.wh__item:last-child{ border-bottom:0 }              /* nunca divisor sobrando */
.wh__head{ display:flex; align-items:center; gap:var(--sp-3); width:100%;
  padding:var(--sp-4) var(--sp-5); cursor:pointer; list-style:none;
  transition:background var(--t-fast) var(--ease-out) }
/* o marcador nativo sai: mesma lição do select da tabela — o chrome do sistema
   ignora o desenho da casa. O chevron Tabler entra no lugar e gira. */
.wh__head::-webkit-details-marker{ display:none }
@media (hover:hover) and (pointer:fine){ .wh__head:hover{ background:var(--hover) } }
.wh__head:focus-visible{ outline:2px solid var(--red); outline-offset:-2px }
.wh__nome{ font-size:15px; font-weight:700; letter-spacing:-.015em }
.wh__vol{ font-size:11.5px; color:var(--mut); font-variant-numeric:tabular-nums }
.wh__dir{ margin-left:auto; display:flex; align-items:center; gap:var(--sp-4) }
.wh__cnt{ font-size:11.5px; color:var(--mut) }
.wh__est{ font-size:11.5px; display:inline-flex; align-items:center; gap:var(--sp-2) }
.wh__chev{ font-size:16px; color:var(--mut); transition:transform var(--t-ui) var(--ease-out) }
details[open] > .wh__head .wh__chev{ transform:rotate(180deg) }
.wh__corpo{ padding:0 var(--sp-5) var(--sp-4) calc(var(--sp-5) + var(--sp-4));
  animation:wh-abre var(--t-fast) var(--ease-out) }
@keyframes wh-abre{ from{ opacity:0; transform:translateY(-4px) } to{ opacity:1; transform:none } }
.wh__dest{ border-left:1px solid var(--line); padding-left:var(--sp-5) }  /* fio marca o aninhamento */
@media (prefers-reduced-motion:reduce){ .wh__corpo{ animation:none } }
@media (max-width:759px){ .wh__head{ min-height:44px } .wh__dir{ gap:var(--sp-3) } .wh__cnt{ display:none } }

/* ============================================================
   VER COMO — faixa de simulação (módulo Equipe, Task 12)
   Preta porque é ESTADO DE COMANDO — não é erro (vermelho) nem
   positivo (verde); atenção se resolve em preto. Vive FORA do
   .app, no fluxo: o seletor ~ encolhe o .app pra caber, então a
   faixa fica sempre à vista em toda página, sem position:fixed,
   sem conteúdo escondido embaixo e sem brigar com os sticky
   internos do .content (que rolam no próprio .content).
   Altura fixa 44px = alvo de toque mínimo do botão de sair.
   ============================================================ */
.vercomo{ display:flex; align-items:center; gap:var(--sp-3); height:44px;
  padding:0 var(--sp-5); background:var(--ink); color:var(--on-fg); font-size:13px }
.vercomo .ti{ font-size:16px; flex:0 0 auto }
.vercomo__txt{ flex:1 1 auto; min-width:0;                /* nunca duas linhas: */
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.vercomo__sair{ background:none; border:0; color:var(--on-fg); font:inherit;
  font-weight:700; text-decoration:underline; text-underline-offset:3px;
  cursor:pointer; height:44px; padding:0 var(--sp-2); white-space:nowrap }
.vercomo ~ .app{ height:calc(100vh - 44px) }
@media (max-width:759px){ .vercomo{ padding:0 var(--sp-4) } }

/* ============================================================
   UI v2 — 19/08/2026 · acréscimos
   As mudanças de valor foram aplicadas no lugar de origem de cada
   regra; aqui ficam só as peças NOVAS, que não existiam antes.
   Razão de cada uma no Guia de UI (decisões 37 a 41).
   ============================================================ */

/* --- 37. linha de tabela acende sob o cursor ---
   Em 17 colunas, achar a linha que se está lendo é metade do trabalho.
   Não é zebra (que o guia proíbe): só existe sob o ponteiro. */
@media (hover:hover) and (pointer:fine){
  .tbl tbody tr:hover td      { background:var(--hover) }
  .tbl tbody tr:hover .frozen { background:var(--hover) }
}

/* --- 38. linha INTEIRA clicável na tabela (âncora esticada) ---
   A regra já era lei desde a rodada 8; faltava a peça de CSS que a torna
   possível numa <table>. A coluna congelada é `position:sticky` e por isso
   cria bloco de contenção PRÓPRIO — a âncora esticada não pode morar nela,
   ou cobriria só aquela célula. Ela mora na primeira célula estática, e o
   bloco de contenção vira a <tr>.
   Ressalva registrada na decisão 15 (âncora esticada mata a seleção de
   texto) resolvida aqui: a célula do identificador sobe acima da âncora e
   leva link próprio — clica em qualquer lugar da linha E dá pra copiar o
   código. */
   ⚠️ REESCRITO em 08/09/2026, com o owner no iPhone: *"não importa onde
   clico, abre sempre o mesmo produto"*. A âncora esticada dependia de
   `position:relative` na <tr> criar bloco de contenção — e isso NÃO é
   confiável em elemento de tabela: onde falha, a âncora sobe até o primeiro
   ancestral posicionado e vira uma TAMPA sobre a tela inteira. Toda a página
   virava o link da última linha, e a rolagem da tabela ficava presa embaixo
   dela. Não dá pra depender de um comportamento que varia por motor.
   Agora: a âncora se contém na PRÓPRIA CÉLULA (`position:relative` em
   <td> é suportado em todo lugar), e quem estende o clique ao resto da linha
   é o cheff-ui.js, por delegação. Sem JS, continuam existindo dois links
   reais na linha (o SKU e o nome) — degradação honesta, nunca tela morta. */
/* A célula que hospeda a âncora. `:has()` resolve sozinho nos motores atuais;
   a classe `.tem-link`, que o cheff-ui.js carimba, é o cinto e suspensório
   para quem não tem `:has()` — sem contenção, a âncora vira tampa de tela. */
.tbl--rowlink td:has(> .row__link),
.tbl--rowlink td.tem-link { position:relative }
.tbl--rowlink .row__link  { position:absolute; inset:0; z-index:1 }
.tbl--rowlink td.u-clip   { overflow:visible }
.tbl--rowlink .u-clip__t  { display:block; overflow:hidden; text-overflow:ellipsis;
                           white-space:nowrap; max-width:26rem }
.tbl--rowlink tbody .frozen a{ position:relative; z-index:2; user-select:text }
@media (hover:hover) and (pointer:fine){ .tbl--rowlink tbody tr:hover{ cursor:pointer } }

/* --- 39. `.lnk-sku` passa a existir ---
   Era usada em produtos.ejs e NÃO existia no CSS: o único elemento
   clicável da linha não tinha nenhuma pista visual. Achado do owner em
   19/08/2026 — e a origem do teste de classe fantasma. */
.lnk-sku{ color:inherit }
@media (hover:hover) and (pointer:fine){ .lnk-sku:hover{ text-decoration:underline } }

/* --- BLOCO 1: o menu avisa que rola ---
   Achado do owner (20/08): com o menu em árvore aberto sobram ~600px
   escondidos, e o item da borda aparecia FATIADO ao meio, sem nada dizendo
   que havia mais abaixo. Item cortado lê como defeito, não como "role".
   A máscara desbota a borda quando há conteúdo escondido e some ao chegar
   no fim — por isso depende de animation-timeline. Onde não houver suporte,
   fica como estava: nada é pior que uma borda permanentemente desbotada. */
@supports (animation-timeline: scroll()) {
  .side__nav{
    animation:desbota-fim linear both;
    animation-timeline:scroll(self block);
    animation-range:calc(100% - 40px) 100%;
  }
  @keyframes desbota-fim{
    from{ mask-image:linear-gradient(to bottom, #000 calc(100% - 28px), transparent) }
    to  { mask-image:linear-gradient(to bottom, #000 100%, transparent) }
  }
  @media (prefers-reduced-motion:reduce){ .side__nav{ animation:none; mask-image:none } }
}

/* --- BLOCO 1 (Focus, 20/08/2026): o tamanho do ícone vem do CONTEXTO ---
   A varredura achou 63 ícones com `style="font-size:…"` escrito à mão nas
   views — o valor certo, do jeito errado: nada impedia o próximo virar 18px.
   O guia (0.7) já dizia 16 inline · 17 menu · 20 topo · 24 estado vazio;
   faltava o CSS dizer. Estas três regras cobrem 48 dos 63. */
.btn .ti          { font-size:16px }
.card__head > .ti{ font-size:16px }
.empty .ti        { font-size:24px; color:var(--mut) }
.form__summary .ti{ font-size:16px; color:var(--red) }

/* --- BLOCOS 2 e 3: componentes que viviam dentro de `style` --- */

/* linha de TOTAL de tabela: fio forte em cima separa o somatório do dado */
.tbl__total td, .tbl__total th{ font-weight:700; border-top:1px solid var(--line-2) }
/* Sub-linha de composição (Clientes v2, aba Itens): componente de um kit
   embaixo da linha do kit. Apoio cinza, recuada pelo padding da 1ª célula,
   sem fio próprio — pertence à linha de cima. Qtd e valor ficam no kit. */
.tbl__sub td{ color:var(--mut); font-size:11.5px; border-top:0; padding-top:2px; padding-bottom:6px }
.tbl__sub td:first-child{ padding-left:calc(var(--sp-5) + var(--sp-4)) }
/* Célula de seleção em tabela com linha clicável (CRM › Carteira): a caixa
   fica acima da âncora esticada (guia r.8) e a coluna não estica. */
.tbl__sel{ width:1%; white-space:nowrap }
.tbl__sel input{ position:relative; z-index:2; width:19px; height:19px }
/* Anexos de oportunidade (CRM): grade de miniaturas, 3 por linha no desktop e 2
   no celular; a foto respeita a largura da célula e nunca estica. */
.anexos{ display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:var(--sp-4) }
@media (min-width:760px){ .anexos{ grid-template-columns:repeat(3,minmax(0,1fr)) } }
.anexo{ margin:0; display:flex; flex-direction:column; gap:var(--sp-2) }
.anexo__img{ width:100%; aspect-ratio:4/3; object-fit:cover; border-radius:var(--r-2); border:1px solid var(--line-card); background:var(--fill) }

/* barra de participação (share) em linha de lista. Trilho em --grid, que o
   guia reserva para grade e trilho — nunca para série (0.1). */
.barra{ height:4px; border-radius:var(--r-full); background:var(--grid);
  overflow:hidden; margin-top:6px; max-width:340px }
.barra__preenche{ height:100%; background:var(--ink); border-radius:var(--r-full) }

/* valor no fim de linha de lista. A largura mínima continua sendo ajuste de
   coluna (fica no style), mas tamanho e peso saem da régua. */
.row__valor{ font-size:13.5px; font-weight:700 }
.row__delta{ font-size:12px; font-weight:700 }

/* --- BLOCOS 2 e 3 (BI e Estoque, 20/08/2026) ---
   Três padrões que apareciam só como `style` inline: */

/* seta de "tem detalhe aqui" no fim de linha e no canto do stat card.
   O guia já manda a seta do stat card ser PERMANENTE (decisão 13). */
.stat__go, .row__go{ font-size:16px; color:var(--mut) }

/* link de AÇÃO dentro de card ("ver e decidir", "exportar", "fechar").
   Ação de cabeçalho é link de texto, nunca botão (rodada 3) — mas ela
   estava com cor e peso escritos à mão em 5 lugares do BI Estoque. */
.lnk-acao{ color:var(--ink-2); font-weight:600 }
@media (hover:hover) and (pointer:fine){ .lnk-acao:hover{ text-decoration:underline } }

/* --- BLOCO 1: queda em célula de tabela ---
   Nomeada pelo SIGNIFICADO, não pela cor: quem escrever `u-queda` numa
   célula que não é queda/erro fica visível na revisão. Vermelho segue
   valendo só para queda, erro e destrutivo (guia 0.1). */
.u-queda{ color:var(--red) }
/* alta de DEMANDA numa célula (Compras, tendência 30d vs 61-90d — F-4,
   24/08/2026): verde porque é POSITIVO, não porque "subiu" (guia §4: cor é
   bom/ruim, seta é direção). A queda correspondente NÃO usa u-queda — é
   atenção, preto forte (.u-strong): vermelho segue só pra queda de
   resultado, erro e destrutivo. */
.u-alta{ color:var(--green) }

/* --- BLOCO 1: peso escrito à mão ---
   66 `font-weight:700` inline no Portal. A hierarquia é por tamanho e peso
   (guia 0.2); peso solto na view fura a escala e não dá pra checar. */
/* ── Classes nascidas da varredura do lote 2 (decisão 43: peso e tamanho vêm
      de classe, nunca de `style`) ───────────────────────────────────────── */
/* estado de falha: vermelho + 700. Nomeada pelo SIGNIFICADO, não pela cor —
   quem escrever `u-falho` numa célula que não é falha fica visível na
   revisão. 8 ocorrências à mão no Watchdog e no X9. */
.u-falho{ color:var(--red); font-weight:700 }
/* rótulo de um GRUPO de campos — mesmo 13/700 do rótulo de campo (guia 0.2,
   linha "Painel"), que é o que os dois <legend> do Focus escreviam à mão. */
.field__legend{ font-size:13px; font-weight:700; padding:0 0 var(--sp-2) }
/* "Número M" da escala (0.2) dentro de um cartão de indicador: o mesmo bloco
   do KPI, um degrau abaixo. 4 ocorrências à mão no X9. */
.stat__value--m{ font-size:20px; letter-spacing:-.03em }
/* valor no fim da linha de lista quando ele É o dado (preço, total) e não
   apoio — `.row__end` sozinho é 11.5px cinza, que some ao lado do título. */
.row__end--forte{ font-size:13px; font-weight:700; color:var(--ink) }
/* par rótulo/valor: e-mail, telefone, cidade. 4 ocorrências à mão só na
   ficha do cliente, todas repetindo o mesmo flex de 72px. */
.kv  { display:flex; align-items:center; gap:var(--sp-3); padding:6px 0 }
.kv__k{ flex:0 0 var(--kv-k, 72px) }
.kv--largo{ --kv-k:140px }
.kv--medio{ --kv-k:88px }
.kv__v{ font-size:13.5px; font-weight:500; min-width:0; overflow:hidden; text-overflow:ellipsis }
/* consolidação por conta (hub do SKU, abas Fiscal/Embalagem/Dados): campo
   igual nas N contas ganha a confirmação verde na escala de Legenda
   (11.5/500) — verde é POSITIVO (consistência confirmada), uso permitido
   pela 0.1; divergência usa o badge--attention existente (atenção é PRETO).
   O par divergente quebra a linha: os valores por conta descem pra baixo
   do rótulo, senão 3 valores + badge estouram a linha do .kv. */
.kv__ok{ font-size:11.5px; font-weight:500; color:var(--green); white-space:nowrap }
.kv--quebra{ align-items:flex-start }
.kv--quebra .kv__v{ white-space:normal }
.wd-card .ti{ font-size:20px }

.u-strong{ font-weight:700 }
.u-med   { font-weight:500 }
.u-normal{ font-weight:400 }   /* apoio dentro de linha de total */
/* texto de apoio cortado em 2 linhas — 3 usos na ficha do colaborador */
.u-clamp-2{ display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical;
  overflow:hidden }
.m-0{ margin:0 }
/* Controle de formulário INLINE numa linha de lista, ao lado de um btn--sm.
   Altura de AÇÃO (36px) e não de campo (46px): aqui ele é parte de um
   comando, não de um formulário empilhado — é a escala da decisão 40.
   Estava escrito à mão com 8 propriedades e altura 40px, que não existe na
   escala, e sem anel de foco. */
/* O esqueleto imita LINHAS DE TEXTO, então as larguras precisam variar —
   mas variavam em 13 `style` escritos à mão no integracao. A variação vem
   da posição: mesma aparência, zero inline. */
.skeleton:nth-child(3n+1){ width:78% }
.skeleton:nth-child(3n+2){ width:88% }
.skeleton:nth-child(3n+3){ width:72% }
/* largura de campo: só duas aparecem no Portal, e sempre as mesmas duas */
.field--md{ width:min(380px, 100%) }
.field--sm{ width:11rem }
/* link de texto DENTRO de um parágrafo: sublinhado é o que faz um link ser
   link sem azul (decisão 3 proíbe azul de link). 5 ocorrências à mão. */
.lnk{ color:inherit; text-decoration:underline; text-underline-offset:2px }
/* ── Marca de AFORDÂNCIA (12–14px) ───────────────────────────────────────
   A escala de ícone do guia (0.7) é 16·17·20·24 e vale pro ícone que
   CARREGA significado. Seta de ordenação, chevron de grupo e lupa da busca
   não carregam: elas dizem "dá pra clicar aqui" ao lado de um rótulo de
   13px, e a 16px passam a competir com ele. Fecha a dívida UI-8, que
   pedia exatamente esta decisão: ou o ícone sobe, ou o guia ganha o degrau
   com o porquê registrado. */
.search-btn .ti{ font-size:14px }
.nav__chev, .tbl th a .ti, .tbl th a .tbl__sort-hint{ /* já estavam nesta faixa */ }

/* ícone do cartão de app na home: 20px é a escala (0.7), agora por contexto */
.card--app .card__body > .ti{ font-size:20px }
/* ícone que abre uma linha de lista */
.rows .row > .ti{ font-size:16px; color:var(--mut); flex:0 0 auto }
/* coluna de caixa de seleção: largura mínima, e a caixa sem o respiro que ela
   tem quando é campo de formulário */
.tbl th.th--check{ width:1% }
.chk--nu{ padding:0; min-height:0 }
/* texto que a pessoa cola: SKU, código. Monoespaçado alinha coluna de dígito */
.mono{ font-family:ui-monospace, SFMono-Regular, Menlo, monospace }
.tbl__wrap--divided{ border-top:1px solid var(--line) }
/* botão que É um link: some a cara de botão, fica o sublinhado. Usado onde a
   ação precisa de <button> por acessibilidade mas lê como link no texto. */
.btn--link{ border:0; background:none; padding:0; min-height:0; height:auto;
  cursor:pointer; color:inherit; text-decoration:underline; text-underline-offset:2px;
  font:inherit }

.campo-inline{ height:var(--ctl-h); padding:0 var(--sp-3); font:inherit;
  font-size:var(--fld-fs); color:var(--ink); background:transparent;
  border:1px solid var(--line-2); border-radius:var(--r-1) }
.campo-inline:focus-visible{ outline:none; border-color:var(--ink);
  box-shadow:var(--ring) }   /* apoio dentro de célula forte */
.u-block { display:block }

/* --- 40. o celular NÃO encolhe ---
   A densidade da v2 vale no desktop. No toque, alvo de 44px é lei e a
   régua volta ao que era. */
@media (max-width:759px){
  .row                     { padding:var(--sp-4) }
  .tbl th, .tbl td         { padding:var(--sp-3) var(--sp-4) }
  .nav__item, .nav__subitem{ min-height:44px }
}

/* --- Campanhas ML (03/09/2026): linha de DECISÃO ---
   Linha de lista que carrega um parágrafo de recomendação + badge + botão. No
   desktop segue a anatomia da rodada 5 (miolo estica, fim e ação encostam à
   direita). No celular a linha não cabe em 3 zonas: badge e botão descem pra
   uma segunda linha, alinhados à esquerda, e o botão vira alvo de 44px. */
.row--decisao .row__sub{ font-size:12px; line-height:1.45; margin-top:2px }
@media (max-width:759px){
  .row--decisao{ flex-wrap:wrap; row-gap:var(--sp-2) }
  .row--decisao .row__main{ flex:1 1 100% }
  .row--decisao .row__end{ flex:0 0 auto }
  .row--decisao .row__action .btn{ min-height:44px }
}
/* Campanhas ML — bloco de decisão por anúncio (03/09/2026, feedback do time: "muito
   texto miúdo; o importante grande"). Um bloco por MLB dentro do card: cabeçalho
   (MLB + estado + botão da Central), tabela das 3 melhores com o "Você recebe" em
   Número M, e a sanfona com o ranking completo. Régua 1px entre blocos, nunca fundo. */
.dec{ padding:var(--sp-4); border-top:1px solid var(--line) }
.dec:first-of-type{ border-top:0 }
.dec__head{ display:flex; align-items:flex-start; gap:var(--sp-3); flex-wrap:wrap; margin-bottom:var(--sp-3) }
.dec__id{ flex:1 1 0; min-width:240px }
.dec__head > .btn{ flex:0 0 auto; margin-left:auto }
.dec__mlb{ font-size:14px }
.dec__estado{ font-size:12.5px; color:var(--ink-2); margin-top:var(--sp-1); line-height:1.5 }
.dec__vazio{ font-size:13px; color:var(--mut) }
.tbl--dec td{ vertical-align:middle; padding-top:var(--sp-3); padding-bottom:var(--sp-3) }
.tbl--dec .dec__nome{ font-size:14px; font-weight:700; letter-spacing:-.01em }
.tbl--dec .dec__tags{ margin-top:var(--sp-1); display:flex; gap:var(--sp-1); flex-wrap:wrap }
.tbl--dec .dec__tags:empty{ display:none }
.tbl--dec .dec__n{ font-size:15px; font-weight:700 }
.tbl--dec .dec__sub{ font-size:11.5px; color:var(--mut); margin-top:2px; font-weight:500 }
.tbl--dec .dec__rec td{ background:var(--surface) }   /* recomendada se marca pelo badge, não por fundo (regra: zero área cinza) */
.dec__alerta{ font-size:12.5px; color:var(--ink); margin-top:var(--sp-3) }
.dec__mais{ margin-top:var(--sp-3) }
@media (max-width:759px){
  .dec{ padding:var(--sp-3) 0 }   /* no toque a tabela ocupa a largura toda; o card já dá o respiro lateral */
  .dec__head{ padding:0 var(--sp-3) }
  .dec__alerta, .dec__vazio, .dec__mais{ margin-left:var(--sp-3); margin-right:var(--sp-3) }
}

/* ============================================================
   Assistente de Ideias (spec 2026-09-04). Prefixo brief- (lição da
   rodada 9: classe nova em arquivo único leva prefixo por componente).
   Cor só de token; trilho das etapas é cinza de contenção (0.4b),
   etapa feita/atual é a tinta. Nada aqui declara tema (decisão 69).
   ============================================================ */
.brief-etapas{ display:flex; gap:var(--sp-1); list-style:none; margin:0; padding:0 }
.brief-etapas li{ flex:1 1 0; min-width:0; display:flex; flex-direction:column; gap:var(--sp-2);
  font-size:11.5px; font-weight:500; color:var(--mut) }
.brief-etapas li::before{ content:""; display:block; height:4px; border-radius:var(--r-full); background:var(--grid);
  transition:background var(--t-fast) var(--ease-out) }
.brief-etapas li[data-estado="feita"]::before,
.brief-etapas li[data-estado="atual"]::before{ background:var(--ink) }
.brief-etapas li[data-estado="atual"]{ color:var(--ink); font-weight:700 }
.brief-etapas li span{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
@media (max-width:759px){
  .brief-etapas li span{ display:none }
  .brief-etapas li[data-estado="atual"] span{ display:block }
}
/* fala: ícone 20px (0.7, "ação de card") + texto de corpo; a do colaborador é apoio */
.brief-fala{ display:flex; gap:var(--sp-3); align-items:flex-start }
.brief-fala .ti{ flex:0 0 auto; font-size:20px; color:var(--mut); margin-top:2px }
.brief-fala p{ margin:0; font-size:15px; line-height:1.5; white-space:pre-wrap }
.brief-fala--eu p{ font-size:13.5px; color:var(--ink-2) }
.brief-cartao textarea{ min-height:160px }
/* o .md do resultado: monoespaçado, quebra, rola dentro do card */
.brief-md{ margin:0; white-space:pre-wrap; word-break:break-word; font-size:13px; line-height:1.55;
  font-family:ui-monospace, SFMono-Regular, Menlo, monospace; max-height:60vh; overflow:auto }

/* --- Metas (spec 2026-09-05): grade canais × meses ---
   O campo mora dentro da célula da tabela; largura fixa pra as colunas de mês
   ficarem iguais e a comparação horizontal valer. */
/* O campo é o .tbl__in da casa (altura e fonte de toque já resolvidas nele);
   aqui só a marca de erro, que o .field.is-invalid não alcança dentro da grade. */
.metas-grade__campo.is-erro,
.metas-grade__campo-vend.is-erro{ border-color:var(--red) }
.metas-grade__copiar,
.metas-grade__copiar-vend{ display:block; margin-top:var(--sp-1); font-size:11px; color:var(--mut);
  text-transform:none; letter-spacing:normal }
/* O selo do mês corrente herda caixa alta e tracking do cabeçalho da tabela e
   deixa de ler como selo — aqui ele volta a ser selo. */
.metas-grade thead .badge{ text-transform:none; letter-spacing:normal }
.metas-grade tfoot th,
.metas-grade tfoot td{ border-top:1px solid var(--line-2) }
/* Total da coluna: calculado no navegador enquanto a pessoa digita. Tabular
   porque é número que se compara na vertical (guia 0.2). */
.metas-grade__total{ font-weight:700; font-variant-numeric:tabular-nums }

/* --- Custos por canal (Custos por canal v1, 13/09/2026): 1 canal por linha,
   os 5 percentuais + frete fixo + Total % calculado no navegador. Mesma
   receita da metas-grade (campo dentro da célula), grade só não é "canal ×
   mês" — é "canal × campo de custo", um mês por tela. */
.custos-canal-grade{ min-width:52rem }
.custos-canal-grade__total{ font-weight:700; font-variant-numeric:tabular-nums }
.custos-canal-grade__campo{ width:6.5rem }

/* ---------- reordenar colunas (Todas as Vendas, 09/09/2026) ----------
   A lista É o formulário: o navegador submete na ordem do DOM, então mover a
   linha move a coluna. Sem drag: seta funciona no teclado, no toque e no leitor
   de tela, e não precisa de estado paralelo que possa divergir do que se vê. */
.cols-ord{ list-style:none; margin:0; padding:0; max-height:320px; overflow-y:auto }
.cols-ord li{ display:flex; align-items:center; gap:var(--sp-2); padding:2px 0 }
.cols-ord li > .chk{ flex:1 1 auto; min-width:0 }
.cols-ord__mover{ flex:0 0 auto; display:flex; gap:2px }
.cols-ord__mover .btn{ padding:0 6px; min-width:24px; line-height:1 }

/* ---------- Régua de passos v2 (decisão 75, 15/09/2026) ----------
   Mapa de nomes (spec 2026-09-15): pedido/compras_pedido = Ordem de compra na
   tela · oc/compras_oc = Espelho do pedido · compras_oc_nf = Nota fiscal.
   v2: cada passo é uma COLUNA — barra de 3px no topo (feito = --fg, atual =
   --line-2, futuro = --line) e, abaixo, um ponto de 10px + rótulo (14px;
   atual em peso 800 --fg, feito em --fg, futuro em --mut). Sob o rótulo, a
   data (12px --mut) ou, só no passo atual, um "falta …" curto no lugar da
   data que ainda não existe. Cancelada: toda barra em --line, o selo mora
   no cabeçalho (badgePasso), não aqui. Só tokens — nenhuma cor decorativa. */
.steps{ display:flex; gap:0; list-style:none; margin:0; padding:0 }
.steps__no{ flex:1; min-width:0; padding-right:var(--sp-4) }
.steps__no:last-child{ padding-right:0 }
.steps__bar{ display:block; height:3px; border-radius:2px; background:var(--line) }
.steps__no.is-feito .steps__bar{ background:var(--fg) }
.steps__no.is-atual .steps__bar{ background:var(--line-2) }
.steps__lbl{ display:flex; align-items:center; gap:6px; margin-top:10px;
  font-size:14px; font-weight:600; color:var(--mut); overflow-wrap:anywhere }
.steps__dot{ flex:0 0 auto; width:10px; height:10px; border-radius:50%; background:var(--line) }
.steps__no.is-feito .steps__lbl{ color:var(--fg) }
.steps__no.is-feito .steps__dot{ background:var(--fg) }
.steps__no.is-atual .steps__lbl{ color:var(--fg); font-weight:800 }
.steps__no.is-atual .steps__dot{ background:var(--fg) }
.steps__data{ display:block; margin-top:2px; padding-left:16px; font-size:12px; color:var(--mut); font-weight:500; overflow-wrap:anywhere }
.steps--apagada .steps__bar{ background:var(--line) }
.steps--apagada .steps__lbl, .steps--apagada .steps__data{ color:var(--mut); font-weight:400 }
.steps--apagada .steps__dot{ background:var(--line) }
.steps__frase{ margin:var(--sp-4) 0 0; font-size:14px }
@media (max-width:759px){ .steps__lbl{ font-size:12px } .steps__data{ font-size:11px } }

/* --- 60. A CONTA DA VENDA (16/09/2026) -----------------------------------
   Dentro do pedido: uma barra do tamanho da mercadoria, fatiada por onde o
   dinheiro foi, e a lista com cada parcela. Pedido do owner ("quero uma tabela
   dentro da venda, bem visual, para saber o lucro líquido final"), escolhido
   entre três propostas.

   QUATRO fatias, não sete. A proposta original abria cada custo do canal na
   barra e precisava de seis tons de cinza — o guia limita gráfico a duas
   séries (rodada 7) e o owner tinha aceitado a exceção. Agrupar o canal numa
   fatia só dispensou a exceção: sobraram produto, imposto, canal e o que
   sobrou, todos em token que já existia. A barra responde "quem comeu", e a
   lista logo abaixo abre o canal parcela a parcela — cada uma no seu lugar.

   Cor aqui NÃO é decoração: os três cinzas são contenção (que fatia é qual) e
   o verde é o único estado — o que sobrou. Margem negativa vira vermelha. */
.conta__barra{ display:flex; height:36px; border-radius:var(--r-1); overflow:hidden; background:var(--fill) }
.conta__barra i{ display:block; height:100% }
.conta__leg{ display:flex; flex-wrap:wrap; gap:var(--sp-2) var(--sp-4); margin-top:var(--sp-3) }
.conta__leg span{ display:inline-flex; align-items:center; gap:6px; font-size:12px; font-weight:500; color:var(--fg-2) }
.conta__leg b{ width:10px; height:10px; border-radius:3px; flex:0 0 auto }
.conta__lista{ margin-top:var(--sp-5) }
.conta__l{ display:grid; grid-template-columns:12px 1fr auto auto; gap:var(--sp-3);
  align-items:baseline; padding:9px 0; border-bottom:1px solid var(--line) }
.conta__l:last-child{ border-bottom:0 }
.conta__l b.conta__p{ width:10px; height:10px; border-radius:3px; align-self:center }
.conta__rot{ font-size:13.5px; font-weight:500 }
.conta__rot .conta__orig{ font-size:11.5px; color:var(--mut); font-weight:500; margin-left:6px }
.conta__pct{ font-size:12px; color:var(--mut); min-width:54px; text-align:right;
  font-variant-numeric:tabular-nums }
.conta__v{ font-size:14px; font-weight:700; min-width:92px; text-align:right; white-space:nowrap;
  font-variant-numeric:tabular-nums }
.conta__l--topo{ border-bottom:1px solid var(--line); padding-bottom:var(--sp-3) }
.conta__l--topo .conta__v{ font-size:20px; font-weight:800; letter-spacing:-.03em }
.conta__l--sub .conta__rot{ font-weight:700 }
.conta__l--filho .conta__rot{ padding-left:var(--sp-4); color:var(--fg-2) }
.conta__l--filho .conta__v{ font-weight:500 }
.conta__l--fim{ border-top:1px solid var(--fg); border-bottom:0; margin-top:var(--sp-2); padding-top:var(--sp-3) }
.conta__l--fim .conta__rot{ font-weight:800 }
.conta__l--fim .conta__v{ font-size:28px; font-weight:800; letter-spacing:-.035em }
@media (max-width:759px){
  .conta__l{ grid-template-columns:12px 1fr auto; row-gap:2px }
  .conta__pct{ grid-column:2; text-align:left; min-width:0 }
  .conta__v{ grid-row:1; grid-column:3 }
  .conta__l--fim .conta__v{ font-size:24px }
}

/* ============================================================
   Base de Conhecimento (spec 2026-09-19). Prefixo kb- (lição da rodada 9:
   classe nova em arquivo único leva prefixo por componente). Duas peças sem
   equivalente hoje no sistema — o resto da tela é .card/.row/.pill/.tbl/
   .badge/.dot já existentes, e o corpo do artigo reaproveita .prose (só
   ganhou tipografia de título/lista/código, que ele nunca precisou até
   agora: era usado só pra texto corrido plano). A sanfona de "perguntas
   mais feitas" reusa .wh__item/.wh__head/.wh__chev/.wh__corpo (Webhooks,
   04/08/2026) tal como estão — é o MESMO componente (sanfona <details>
   nativa), só nasceu com nome de módulo por ter sido o primeiro a precisar.
   ============================================================ */

/* Campo de pergunta, o comando da Início e do rodapé do Artigo — não existe
   nada do tamanho/peso dele no sistema hoje (o mais perto, .tbl-search, é
   busca de barra de filtro, 32px). 56px no desktop, 16px de fonte sempre
   (nunca dá zoom no iOS; a versão compacta ainda assim não desce de 16). */
.kb-ask{ display:flex; align-items:center; gap:var(--sp-3); background:var(--surface);
  border:1px solid var(--line-2); border-radius:var(--r-2); box-shadow:var(--card-sh);
  padding:0 var(--sp-2) 0 var(--sp-5); height:56px }
.kb-ask .ti{ color:var(--mut); flex:0 0 auto }
.kb-ask input{ flex:1 1 auto; min-width:0; border:0; background:transparent;
  font-size:16px; outline:0; height:100% }
.kb-ask input::placeholder{ color:var(--mut) }
.kb-ask .btn{ flex:0 0 auto }
.kb-ask--sm{ height:44px; padding-left:var(--sp-4) }
@media (max-width:759px){ .kb-ask{ height:52px } }

/* Variante "rodapé de card" (revisão 19/09/2026): o campo de pergunta que
   TERMINA um card ("Pergunte qualquer outra coisa", "Ligado a este artigo")
   não é outro card por dentro do card — é uma linha chata dele, separada só
   pelo fio de cima, sem borda nem sombra próprias (decisão 9 do guia: nunca
   decorar o que já está contido). O botão vira o círculo de seta do
   protótipo, não o botão de texto "Buscar" — aqui a ação é "perguntar
   direto", não abrir uma busca à parte. Sem ícone de lupa à esquerda pelo
   mesmo motivo. É filho DIRETO do .card (nunca embrulhado em .card__body),
   senão o fio de cima vira um traço curto em vez de ponta a ponta. */
.kb-ask--rodape{ border:0; border-radius:0; box-shadow:none; border-top:1px solid var(--line);
  padding:0 var(--sp-3) 0 var(--sp-5); height:52px }
.kb-ask__go{ flex:0 0 auto; width:36px; height:36px; border-radius:var(--r-full); border:0;
  background:var(--fill); display:grid; place-items:center; cursor:pointer }
@media (hover:hover) and (pointer:fine){ .kb-ask__go:hover{ background:var(--hover) } }
.kb-ask__go:active{ transform:scale(.94) }

/* Árvore de navegação (seções/artigos) DENTRO de um card — nunca reaproveita
   .nav__item: aquele é do menu lateral, que o guia manda transparente
   (decisão "menu lateral transparente, item ativo é card branco elevado");
   este vive num CARD, onde fio+sombra já marcam a contenção, e o ativo é só
   --fill (decisão 61: cinza de contenção nunca decora, mas aqui MARCA "onde
   eu estou" dentro do card, papel diferente do item de menu). Primeiro
   componente do Portal com navegação em árvore dentro do conteúdo. */
.kb-tree{ padding:var(--sp-2) }
/* rótulo = o .t-micro da casa (10px/700/.12em/cor de apoio); a v1 tinha
   reescrito a tipografia à mão com `font:700 10px/1.3 inherit` — shorthand
   inválido (inherit não compõe com peso/tamanho no mesmo `font:`), o
   navegador descartava a declaração inteira e sobrava peso leve com o
   tracking de 0,12em aplicado sobre o tamanho normal (achado da revisão
   19/09/2026). Só padding aqui; a tipografia vem da classe .t-micro no HTML. */
.kb-tree__rotulo{ padding:var(--sp-3) var(--sp-3) var(--sp-1) }
.kb-tree a{ display:flex; align-items:center; gap:var(--sp-2); min-height:36px;
  padding:var(--sp-2) var(--sp-3); border-radius:var(--r-1); font-size:13.5px;
  font-weight:600; color:var(--ink-2); text-decoration:none }
/* título até 2 linhas (guia §5: lista de CONTEÚDO nunca trunca em 1 linha;
   revisão 19/09/2026 achou os títulos da árvore do Artigo cortando "Erro d…"). */
.kb-tree a em{ font-style:normal; flex:1 1 auto; min-width:0;
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden }
.kb-tree a.is-on{ background:var(--fill); color:var(--ink); font-weight:700 }
@media (hover:hover) and (pointer:fine){ .kb-tree a:not(.is-on):hover{ background:var(--hover) } }
.kb-tree__n{ margin-left:auto; flex:0 0 auto; color:var(--mut); font-size:12px;
  font-variant-numeric:tabular-nums }
.kb-tree a.is-on .kb-tree__n{ color:var(--mut) }
.kb-tree__sub{ padding-left:calc(var(--sp-3) + 14px); font-weight:500 }
.kb-tree hr{ border:0; border-top:1px solid var(--line); margin:var(--sp-2) var(--sp-1) }
@media (max-width:759px){ .kb-tree a{ min-height:44px } }

/* Corpo do artigo: até aqui .prose só limitava a largura do texto corrido
   (65 ch, guia 0.2) — nunca precisou estilizar HEADING/LISTA/CÓDIGO porque
   sempre embrulhou texto plano escapado (backlog-item, ideia-detalhe…). O
   markdown-it entrega HTML de verdade agora; cor só de token, link sem azul
   de destaque (regra permanente do guia) — o sublinhado é o único sinal. */
.prose h2, .prose h3{ font-weight:800; letter-spacing:-.015em; color:var(--ink);
  margin:var(--sp-6) 0 var(--sp-2) }
.prose h2:first-child, .prose h3:first-child{ margin-top:0 }
.prose h2{ font-size:18px }
.prose h3{ font-size:15px }
.prose p{ margin:0 0 var(--sp-4) }
.prose p:last-child{ margin-bottom:0 }
.prose ul, .prose ol{ margin:0 0 var(--sp-4); padding-left:20px; display:grid; gap:var(--sp-2) }
.prose li{ line-height:1.65 }
.prose strong{ color:var(--ink); font-weight:700 }
.prose code{ font-family:ui-monospace, SFMono-Regular, Menlo, monospace; font-size:.9em;
  background:var(--fill); padding:1px 5px; border-radius:4px }
.prose pre{ background:var(--fill); padding:var(--sp-4); border-radius:var(--r-2); overflow-x:auto }
.prose pre code{ background:none; padding:0 }
.prose blockquote{ margin:0 0 var(--sp-4); padding-left:var(--sp-4); border-left:2px solid var(--line-2); color:var(--mut) }
.prose a{ text-decoration:underline; text-underline-offset:2px }

/* Rodapé "Isso ajudou?" (revisão 19/09/2026): uma linha só (legenda + Sim +
   Não + botão "Isso está errado"); o campo de texto só aparece ao clicar
   nesse botão. Checkbox escondido + label ("checkbox hack") em vez de
   <details>: dentro de uma linha flex o <details> não estica pro full width
   do card ao abrir sem o truque de display:contents — o checkbox hack
   compõe direto com flex-wrap + flex-basis:100%, sem essa complicação, e
   continua funcionando sem JS. O checkbox fica focável (.sr-only, nunca
   display:none) — sem o anel de foco no toggle, ele desapareceria pro
   teclado. A v1 tinha um <form class="card__body form"> aqui: `.form` tem
   max-width:560px, e o fio de cima cortava pela metade da largura do card. */
.kb-fb{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--sp-3) }
.kb-fb__form{ flex-basis:100%; display:none; padding-top:var(--sp-3); margin-top:var(--sp-1);
  border-top:1px solid var(--line) }
.kb-fb__toggle:checked ~ .kb-fb__form{ display:block }
.kb-fb__toggle + label{ cursor:pointer }
.kb-fb__toggle:focus-visible + label{ outline:2px solid var(--red); outline-offset:2px }

/* Resposta por IA no campo de pergunta (etapa 5, plano 2026-09-21-base-de-
   conhecimento-etapa5-ia.md, item 5). `.kb-ia` é só um card comum — nasce
   sem regra própria de cor (herda --surface/--card-sh do .card de sempre,
   guia decisão 60). `.kb-ia__fontes`/`.kb-ia__foot` são os dois pontos que
   precisam de layout: a lista de fontes ganha um rótulo (.t-caption) acima
   dela, e o rodapé é a MESMA receita flex-wrap+gap do .kb-fb acima (rótulo
   discreto + botões), sem reusar a classe .kb-fb porque o nome dela é do
   componente de FEEDBACK do artigo — layout idêntico, semântica diferente. */
.kb-ia__fontes{ margin-top:var(--sp-3) }
.kb-ia__fontes .t-caption{ display:block; margin-bottom:var(--sp-1) }
.kb-ia__foot{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--sp-3) }

/* Teste de leitura (etapa 4, plano 2026-09-21-base-de-conhecimento-etapa4-
   treinamento, bloco 1, item 2): cada opção é uma LINHA inteira clicável
   (rádio nativo + texto), não uma pílula — o teste se lê de cima pra baixo,
   uma opção por vez, como um formulário de prova, não um filtro. Alvo de
   toque >=44px SEMPRE (não só no celular): é uma decisão que a pessoa
   precisa acertar, nunca uma mira apertada. `--certo`/`--errado` marcam só
   a opção que a PRÓPRIA pessoa escolheu (nunca a correta que ela não
   marcou) — a resposta certa nunca aparece na tela, ver base-treinamento-
   db.js. */
.quiz-opcoes{ list-style:none; margin:0; padding:0; display:grid; gap:var(--sp-2) }
.quiz-opcao{ display:flex; align-items:center; gap:var(--sp-3); min-height:44px;
  padding:var(--sp-2) var(--sp-4); border:1px solid var(--line); border-radius:var(--r-2);
  cursor:pointer; transition:background var(--t-fast) var(--ease-out), border-color var(--t-fast) var(--ease-out) }
.quiz-opcao input{ width:19px; height:19px; accent-color:var(--ink); margin:0; flex:0 0 auto }
@media (hover:hover) and (pointer:fine){ .quiz-opcao:hover{ background:var(--hover); border-color:var(--line-2) } }
.quiz-opcao:has(input:focus-visible){ outline:2px solid var(--red); outline-offset:2px }
.quiz-opcao--certo{ border-color:var(--green); background:var(--green-bg) }
.quiz-opcao--errado{ border-color:var(--red); background:var(--red-bg) }
.quiz-pergunta__explicacao{ margin:var(--sp-2) 0 0; color:var(--mut); font-size:13.5px }

/* Pendentes do BI de vendas (régua única, 21/09/2026): pedido que ainda não é
   venda mora num card só dele e nunca soma em número nenhum. O seletor troca o
   estado; o contador dentro da pílula é apoio (cinza) e só vira tinta na
   pílula ativa, senão quatro números em preto competiriam com o total logo
   abaixo. O resumo usa o Número M, não o G: o número protagonista da tela é a
   venda, e pendente não pode parecer KPI de venda. */
.pend__n{ color:var(--fg-mut); font-weight:700 }
.seg a[aria-current="page"] .pend__n{ color:inherit }
/* o resumo é o segundo corpo do card, logo abaixo do seletor: o respiro de cima
   já veio do corpo do seletor, então aqui ele zera pra não dobrar */
.pend__resumo{ display:flex; flex-wrap:wrap; align-items:baseline; gap:var(--sp-2) var(--sp-5); padding-top:0 }
.pend__frase{ flex:1 1 20rem; max-width:65ch }
.pend__sub{ padding:var(--sp-4) var(--sp-4) var(--sp-1); border-top:1px solid var(--line-card) }

/* ============================================================
   Levantamento Financeiro (BPO), 21/09/2026
   Formulário longo respondido por quem não é do dia a dia do Portal.
   Nada aqui cria cor nem tamanho novo: só arranjo dos componentes da casa.
   ============================================================ */
/* texto de boas-vindas: coluna de leitura (guia 0.2: ~65 caracteres) */
.bpo-intro{ max-width:62ch }
.bpo-intro p{ margin:0 0 var(--sp-3) }
.bpo-intro ul{ margin:0 0 var(--sp-4); padding-left:var(--sp-5); display:flex; flex-direction:column; gap:var(--sp-2) }
.bpo-barra{ max-width:none }
/* pergunta de opção é um fieldset: zera a moldura nativa, o resto é .field */
fieldset.bpo-q{ border:0; margin:0; padding:0; min-width:0 }
.bpo-hint-topo{ margin:0 0 var(--sp-3) }
/* múltipla escolha em lista vertical (guia, rodada 9: acima de 4 opções não é
   pílula). Cada linha tem o alvo de toque da casa. */
.bpo-checks{ display:flex; flex-direction:column }
.bpo-checks .chk{ min-height:36px }
@media (max-width:759px){ .bpo-checks .chk{ min-height:44px } }
.bpo-outro{ display:flex; flex-direction:column; gap:var(--sp-1); margin-top:var(--sp-3) }
/* "Salvo às 14h32": reserva a linha para o campo não pular quando o aviso entra */
.bpo-salvo{ min-height:1.4em; margin-top:var(--sp-1) }
.bpo-anexos{ display:flex; flex-direction:column; gap:var(--sp-4); max-width:560px; margin-top:var(--sp-6) }
.bpo-anexo-ajuda{ margin:0 0 var(--sp-3) }
.bpo-upload{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--sp-3); margin-bottom:var(--sp-2) }
.bpo-upload input[type=file]{ flex:1 1 14rem; min-width:0; font-size:16px }
.bpo-rodape{ display:flex; flex-wrap:wrap; gap:var(--sp-3); max-width:560px; margin-top:var(--sp-7) }
.bpo-enviar{ margin-top:var(--sp-6); display:flex; flex-direction:column; align-items:flex-start; gap:var(--sp-2) }
@media (max-width:759px){ .bpo-rodape .btn, .bpo-enviar .btn{ width:100% } }

/* Expedição SP, card "Precisa de ação": mostra 3 linhas e o resto nasce
   recolhido (owner, 30/09/2026). O botão é o FIM da lista: ao abrir, as linhas
   extras entram acima dele e ele desce junto, com o texto "recolher". Botão de
   verdade (aria-expanded), 44px de toque, com seta que diz o sentido. Sem JS o
   atributo hidden o esconde e a lista aparece inteira. */
.pend-mais{ display:flex; align-items:center; justify-content:space-between; width:100%; min-height:44px;
  padding:0 var(--sp-4); border:0; border-top:1px solid var(--line); background:transparent; color:var(--ink-2);
  font:inherit; font-size:12.5px; font-weight:700; text-align:left; cursor:pointer }
.pend-mais[hidden]{ display:none }
.pend-mais__txt{ min-width:0 }
.pend-mais::after{ content:"▾"; margin-left:var(--sp-2); color:var(--mut) }
.pend-mais[aria-expanded="true"]::after{ content:"▴" }
.pend-mais:focus-visible{ outline:2px solid var(--fg); outline-offset:-2px }
@media (hover:hover) and (pointer:fine){ .pend-mais:hover{ background:var(--hover) } }
