/* ============================================================
   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);

  /* ---------- 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:15px;   /* fonte do campo de formulário — 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; } }
@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 }
:focus-visible{ outline:2px solid var(--red); outline-offset:2px }  /* único uso não-semântico do vermelho */
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 }
  .side{ position:fixed; inset:0 auto 0 0; z-index:20; 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 */
  .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(--sp-6) 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) }
.page__head--sticky.is-stuck{ border-bottom:1px solid var(--line-shell);
  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 */
@media (max-width:899px){ .cols{ grid-template-columns:1fr } }
@media (max-width:759px){
  .page{ padding:var(--page-pt) var(--sp-4) 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% }
}

/* ============================================================
   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) }
/* 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) }
.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 }
.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 }

/* ============================================================
   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 }
.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 }
.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)
   ============================================================ */
.tbl__wrap{ overflow-x:auto; -webkit-overflow-scrolling:touch }
.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) }
/* 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. */
.tbl thead th, .tbl thead td{ background:var(--surf) }
.tbl thead th{ position:sticky; top:0; z-index:2;
  font-size:9.5px; letter-spacing:.12em; text-transform:uppercase; color:var(--ink-2); font-weight:700 }
.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(--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 }
.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 */

/* 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);             /* 15px 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:13.5px; 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) }
.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) }
.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__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 */
.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 }
}
/* 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:touch }
.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 }
.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 }
/* 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:19;
  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 */

/* ---------- 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) }
.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 }
.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) }
.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 */
.tbl .row__link{ position:absolute; inset:0; z-index:1 }
.tbl tbody tr{ 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) }
.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 }
@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) }
.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) }
.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 }
  .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: menor e cinza. O campo continua 16px
   (limite do zoom do iOS) — só o texto de exemplo encolhe. */
input::placeholder, textarea::placeholder{ font-size:13.5px; 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) }
@media (max-width:759px){ .tbl-filter, .tbl-filter select{ width:100% } }

/* 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 } }

/* ============================================================
   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 }
.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 }
@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 } }

/* 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 }

/* 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. */
.tbl--rowlink tbody tr   { position:relative }
.tbl--rowlink .row__link { position:absolute; inset:0; z-index:1 }
.tbl--rowlink td.u-clip  { overflow:visible; position:static }
.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) }

/* 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) }
}
