/* ComprasFlow — front-end próprio (tela cheia, estilo app). */
:root{
  --bg:#eef1ec;
  --surface:#ffffff;
  --surface-2:#f5f6f2;
  --border:#dbdfd5;
  --ink:#1a231e;
  --ink-soft:#5c6b60;
  --ink-faint:#8b9890;
  --primary:#1f4b3f;
  --primary-ink:#ffffff;
  --primary-soft:#e0ece5;
  --primary-strong:#163a30;
  --accent:#c1652f;
  --accent-ink:#ffffff;
  --accent-soft:#f5e4d5;
  --success:#2f7a4f;
  --success-soft:#e2f0e6;
  --danger:#b23a3a;
  --danger-soft:#f7e3e1;
  --warn:#a9791f;
  --warn-soft:#f3ead2;
  /* Cor própria do papel "Administrador" nos Comentários da Requisição
     (ver .cf-comment-avatar/.cf-comment-role-badge mais abaixo) — Requisitante
     e Comprador reaproveitam --primary/--accent (já usados no resto do app),
     mas nenhuma cor existente sobrava pra Administrador sem repetir uma
     tonalidade já usada (--success é um verde próximo demais de --primary) ou
     usar uma cor com outro significado já fixado no app (--danger = ação
     destrutiva, --warn = pendência). */
  --role-admin:#3a5a8c;
  --role-admin-soft:#dfe6f2;
  /* Cor própria do papel "Gestor" (v2.29.15), mesmo espírito de --role-admin
     acima — Gestor é "quase Administrador" nas capacidades, mas precisa de
     cor própria nos Comentários pra não ser confundido visualmente com o
     Administrador de verdade. */
  --role-gestor:#6a4f9c;
  --role-gestor-soft:#e6e0f2;
  /* v2.35.3 — cores próprias dos 5 status da Fábrica (COT_STATUS_FABRICA_TONE
     em frontend.js), separadas de --warn/--danger/--accent/--success: esses
     4 tokens também pintam botões/avisos/badges em telas sem nenhuma relação
     com Cotação, então reaproveitá-los aqui faria qualquer um deles mudar de
     cor junto sem o usuário ter pedido. Pedido do usuário: Aguardando =
     amarelo, Sem Resposta = cinza, Não Tem = cinza (igual Sem Resposta),
     Cotado = verde claro, Comprado = roxo. Cada status tem 3 variantes:
     "-dot" (quadradinho da listagem COT-01, pode ser bem vivo — não carrega
     texto em cima) e a dupla "normal"/"-soft" (texto/fundo da pílula do
     seletor dentro da COT-02, onde o amarelo precisa ser mais escuro pra não
     perder legibilidade do texto — ver mockup aprovado). */
  --st-yellow:#8a6d0a; --st-yellow-dot:#e8b600; --st-yellow-soft:#fbf0bd;
  --st-gray:#5f6a74; --st-gray-dot:#8b96a1; --st-gray-soft:#e7eaed;
  --st-green:#1f9a5a; --st-green-dot:#30c172; --st-green-soft:#dcf5e7;
  --st-purple:#7c3aed; --st-purple-dot:#8b5cf6; --st-purple-soft:#ece4fb;
  --radius-sm:8px;
  --radius-md:14px;
  --radius-lg:20px;
  --shadow-sm:0 1px 2px rgba(20,30,24,.06);
  --shadow-md:0 8px 24px rgba(20,30,24,.10);
  --shadow-lg:0 20px 60px rgba(20,30,24,.22);
  color-scheme:light;
}
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]){
    --bg:#10140f; --surface:#181e1a; --surface-2:#1f2620; --border:#2c352e;
    --ink:#eef1ec; --ink-soft:#a7b3ab; --ink-faint:#71807a;
    --primary:#6fbf9a; --primary-ink:#0c1f16; --primary-soft:#1e3830; --primary-strong:#8fd4b2;
    --accent:#e08a4f; --accent-ink:#241407; --accent-soft:#3a2a18;
    --success:#7ecb98; --success-soft:#1f3a2a; --danger:#e08585; --danger-soft:#3a1f1f;
    --warn:#e0c26a; --warn-soft:#3a301a;
    --role-admin:#8fa9d6; --role-admin-soft:#26344a;
    --role-gestor:#b3a0d9; --role-gestor-soft:#332a47;
    --st-yellow:#e8c84a; --st-yellow-dot:#f0cc33; --st-yellow-soft:#3d3310;
    --st-gray:#a7b0b8; --st-gray-dot:#8b96a1; --st-gray-soft:#2a2e33;
    --st-green:#6fe3a0; --st-green-dot:#3ddb84; --st-green-soft:#163a27;
    --st-purple:#b79cf0; --st-purple-dot:#9c7cf0; --st-purple-soft:#2c2140;
    --shadow-sm:0 1px 2px rgba(0,0,0,.3); --shadow-md:0 8px 24px rgba(0,0,0,.4); --shadow-lg:0 20px 60px rgba(0,0,0,.55);
  }
}

html.cf-app-active, html.cf-app-active body{ height:100%; margin:0; background:var(--bg); }
body.cf-app-body{ margin:0; }

.cf-app-fullscreen *, .cf-login-screen *{ box-sizing:border-box; }
.cf-app-fullscreen, .cf-login-screen{
  font-family:'Inter',system-ui,-apple-system,Segoe UI,sans-serif;
  font-size:14px; line-height:1.45; color:var(--ink); -webkit-font-smoothing:antialiased;
  min-height:100vh; background:var(--bg);
}
.cf-app-fullscreen h1,.cf-app-fullscreen h2,.cf-app-fullscreen h3,
.cf-login-screen h1,.brand-name{ font-family:'Manrope',Inter,system-ui,sans-serif; font-weight:800; letter-spacing:-.01em; }
.cf-app-fullscreen .mono,.cf-app-fullscreen input[type="date"],.cf-app-fullscreen input[type="number"]{
  font-family:'IBM Plex Mono',ui-monospace,monospace; font-variant-numeric:tabular-nums;
}
.cf-app-fullscreen a{ color:inherit; }
.cf-app-fullscreen button{ font-family:inherit; }
/* Pedido do usuário: todo o sistema (o app, não a tela de login) escrito em
   maiúsculas. text-transform:uppercase é uma propriedade herdada, então uma
   única regra no elemento raiz já cobre título, rótulos, tabelas, badges,
   texto digitado etc.; os campos de formulário (input/textarea/select/
   button) são reforçados explicitamente porque nem todo navegador herda
   propriedades de texto neles. Isso é só visual — quem realmente grava o
   valor em maiúsculas nos campos de texto é o listener em uppercaseInput()
   (frontend.js), pra que a busca, os relatórios e o wp-admin também vejam o
   dado já em maiúsculas, não só a tela do app. */
.cf-app-fullscreen{ text-transform:uppercase; }
.cf-app-fullscreen input,
.cf-app-fullscreen textarea,
.cf-app-fullscreen select,
.cf-app-fullscreen button{ text-transform:uppercase; }
.cf-app-fullscreen input::placeholder,
.cf-app-fullscreen textarea::placeholder{ text-transform:uppercase; }
/* v2.22.0 — pedido do usuário: e-mail, senha e endereço/URL passam a
   aceitar minúsculas normalmente, em vez de serem forçados pra maiúsculas
   como o resto do app. [data-no-upper] é o atributo que fieldHtml() (ver
   frontend.js) grava nos campos marcados com noUpper:true (hoje: Usuário,
   Senha e Endereço do módulo Acessos, e Teams do Fornecedor); .no-upper é
   a mesma exceção aplicada onde esses valores aparecem DEPOIS de salvos —
   colunas de listagem e a grade de detalhe (ver renderView()/detailItem()/
   detailItemWide() em frontend.js) — pra não mostrar em maiúsculas um
   valor que foi digitado (e continua gravado) em minúsculas. */
.cf-app-fullscreen [data-no-upper],
.cf-app-fullscreen [data-no-upper]::placeholder{ text-transform:none; }
.cf-app-fullscreen .no-upper{ text-transform:none; }
.cf-app-loading{ display:flex; align-items:center; justify-content:center; min-height:100vh; color:var(--ink-faint); font-size:14px; }

/* ---------- tela de login ---------- */
.cf-login-screen{
  display:flex; align-items:center; justify-content:center; padding:24px;
}
.cf-login-card{
  width:100%; max-width:360px; background:var(--surface); border:1px solid var(--border);
  border-radius:var(--radius-lg); box-shadow:var(--shadow-lg); padding:36px 30px;
}
.cf-login-brand{ text-align:center; margin-bottom:26px; }
.cf-login-logo{
  display:inline-flex; align-items:center; justify-content:center; width:52px; height:52px;
  border-radius:14px; background:linear-gradient(155deg,var(--primary),var(--primary-strong));
  color:var(--primary-ink); font-weight:800; font-size:18px; margin-bottom:12px;
}
.cf-login-brand h1{ font-size:20px; margin:0 0 2px; }
.cf-login-brand p{ margin:0; color:var(--ink-faint); font-size:12.5px; }
.cf-login-error{
  background:var(--danger-soft); color:var(--danger); border-radius:8px; padding:10px 12px;
  font-size:12.5px; font-weight:600; margin-bottom:16px; text-align:center;
}
/* Mensagem de sucesso (v2.29.15 — "link enviado", "senha redefinida") no
   mesmo molde de .cf-login-error acima, só trocando a cor pra --success. */
.cf-login-success{
  background:var(--success-soft); color:var(--success); border-radius:8px; padding:10px 12px;
  font-size:12.5px; font-weight:600; margin-bottom:16px; text-align:center;
}
/* "Esqueci minha senha" / "Voltar ao login" (v2.29.15) — link discreto
   centralizado abaixo do formulário/botão. */
.cf-login-link{
  display:block; text-align:center; margin-top:16px; font-size:12px; font-weight:600;
  color:var(--ink-soft); text-decoration:none;
}
.cf-login-link:hover{ color:var(--primary); text-decoration:underline; }
.cf-login-form{ display:flex; flex-direction:column; gap:6px; }
.cf-login-form label{ font-size:11.5px; font-weight:700; color:var(--ink-soft); margin-top:10px; }
.cf-login-form input{
  padding:10px 12px; border-radius:8px; border:1px solid var(--border); background:var(--surface-2);
  color:var(--ink); font-size:13.5px; outline:none;
}
.cf-login-form input:focus{ border-color:var(--primary); background:var(--surface); }
.cf-login-form button{
  margin-top:20px; padding:11px; border-radius:8px; border:none; background:var(--accent);
  color:var(--accent-ink); font-weight:700; font-size:13.5px; cursor:pointer;
}
.cf-login-form button:hover{ filter:brightness(1.06); }

/* ---------- shell do app ---------- */
#app{ display:flex; min-height:100vh; }
.sidebar{
  width:248px; flex:none; background:var(--surface); border-right:1px solid var(--border);
  display:flex; flex-direction:column; padding:20px 14px; gap:18px; position:sticky; top:0; height:100vh;
  /* v2.23.1 — a lista de módulos do menu lateral só cresceu a cada versão
     (Preços de Fábrica, Acessos, Itens Cotados, Calcular Preço de Venda...)
     e, sem rolagem própria, o conteúdo passou a ultrapassar os 100vh da
     barra lateral. Como isso não era recortado (sem overflow definido aqui,
     o padrão do navegador é "visible"), o excesso vazava para fora da
     barra e esticava a página inteira (#app/body/html) além da tela — o
     efeito observado pelo usuário foi os cabeçalhos "congelados" das
     tabelas (v2.14.0) voltando a rolar junto com o mouse, porque a PÁGINA
     TODA passou a rolar, arrastando título/busca/cabeçalho da tabela junto
     (eles nunca dependeram de position:sticky próprio — só ficavam fixos
     por estarem fora da área que rola). A barra lateral agora rola por
     conta própria quando não cabe, sem afetar o resto da página.
  */
  overflow-y:auto; overflow-x:hidden;
}
.brand{ display:flex; align-items:center; gap:10px; padding:4px 8px 10px; }
.brand-mark{
  width:34px;height:34px;border-radius:10px; background:linear-gradient(155deg,var(--primary),var(--primary-strong));
  display:flex;align-items:center;justify-content:center; color:var(--primary-ink);flex:none; box-shadow:var(--shadow-sm);
}
.brand-name{ font-size:17px; color:var(--ink); }
.brand-sub{ font-size:11px; color:var(--ink-faint); margin-top:1px; }

nav.modules{ display:flex; flex-direction:column; gap:3px; }
.nav-label{ font-size:10.5px; text-transform:uppercase; letter-spacing:.09em; color:var(--ink-faint); padding:10px 10px 4px; }
.nav-item{
  display:flex;align-items:center;gap:10px; padding:9px 10px;border-radius:var(--radius-sm);
  color:var(--ink-soft);cursor:pointer;border:1px solid transparent; font-size:13.5px;font-weight:600;
  transition:background .12s ease,color .12s ease;
}
.nav-item svg{ flex:none;width:17px;height:17px; }
.nav-item:hover{ background:var(--surface-2); color:var(--ink); }
.nav-item.active{ background:var(--primary-soft); color:var(--primary-strong); }
.nav-count{
  margin-left:auto;font-size:11px;font-weight:700; background:var(--surface-2);color:var(--ink-soft);
  border-radius:999px;min-width:20px;text-align:center;padding:1px 6px;
}
.nav-item.active .nav-count{ background:var(--surface); color:var(--primary-strong); }
/* Contador em destaque (laranja) — usado em "Avisos" e "Itens Cotados" pra
   chamar atenção pra algo que precisa de uma decisão, diferente da contagem
   neutra (cinza) do resto da navegação. */
.nav-count-alert{ background:var(--accent)!important; color:#fff!important; }
/* Contador de requisições com comentário novo (ver renderNav()/navItemHtml()
   em frontend.js) — vermelho de propósito, diferente do laranja usado em
   "Avisos"/"Itens Cotados" (uma pendência de decisão), pra ler como
   "notificação não lida", não como "ação pendente". Convive lado a lado com
   o .nav-count cinza normal (total de requisições) no mesmo item de menu. */
.nav-count-danger{ background:var(--danger)!important; color:#fff!important; }

/* Grupos do menu lateral (v2.25.0, ajustado na v2.25.1 — ver comentário
   abaixo) — Comercial/Compras/Relatórios/Gestão/Cadastros, cada um abrindo/
   fechando por conta própria (não é um acordeão exclusivo: abrir um não
   fecha os outros), pra caber mais itens sem a barra lateral rolar demais.
   Estado (aberto/fechado) fica em navGroupsOpen, guardado em localStorage —
   ver frontend.js.

   v2.25.1 — correção pedida pelo usuário depois de ver o menu real: o
   cabeçalho do grupo (ex: "COMPRAS") tinha ficado com fonte MENOR (10.5px,
   herdada do antigo rótulo passivo .nav-label) do que os itens dentro dele
   (.nav-item, 13.5px) — o oposto da hierarquia visual esperada (grupo em
   destaque, item mais discreto). Agora o cabeçalho do grupo usa o mesmo
   tamanho/peso de um item comum, com ícone próprio e a seta encostada na
   borda direita (antes ficava colada no rótulo, à esquerda); os itens DENTRO
   de um grupo (.nav-group-body .nav-item) passam a ser menores, mais leves e
   com um recuo extra à esquerda, pra ficar claro que estão "dentro" do
   grupo — só em telas largas, a barra lateral: no celular (ver
   @media max-width:820px mais abaixo) o menu continua achatado numa fileira
   de ícones, sem essa diferenciação. */
.nav-group{ display:flex; flex-direction:column; }
.nav-group-header{
  display:flex;align-items:center;gap:10px; padding:9px 10px;border-radius:var(--radius-sm);
  color:var(--ink-soft);cursor:pointer;border:1px solid transparent; font-size:13.5px;font-weight:700;
  text-transform:uppercase; letter-spacing:.02em; user-select:none;
  transition:background .12s ease,color .12s ease;
}
.nav-group-header svg{ flex:none;width:17px;height:17px; }
.nav-group-header:hover{ background:var(--surface-2); color:var(--ink); }
.nav-group-label{ flex:1; }
.nav-group-chevron{ display:flex;flex:none;margin-left:auto; transition:transform .15s ease; color:var(--ink-faint); }
.nav-group-chevron svg{ width:11px;height:11px; }
.nav-group.open .nav-group-chevron{ transform:rotate(90deg); }
.nav-group-body{ display:none; flex-direction:column; gap:2px; }
.nav-group.open .nav-group-body{ display:flex; }
@media (min-width:821px){
  /* Item dentro de um grupo: mais discreto que o cabeçalho do grupo acima
     dele e recuado, pra reforçar visualmente que pertence àquele grupo.
     Escopado a telas largas de propósito — na barra inferior do celular os
     grupos viram display:contents (ver adiante) e todo .nav-item, dentro ou
     fora de grupo, precisa manter o MESMO tamanho compacto de ícone; sem
     esse escopo, esta regra (mais específica que a .nav-item do celular)
     venceria por especificidade e quebraria o layout da barra inferior. */
  .nav-group-body .nav-item{ padding-left:32px;font-size:12px;font-weight:500; }
  .nav-group-body .nav-item svg{ width:15px;height:15px; }
  .nav-group-body .nav-item.active{ font-weight:700; }
  /* "Nova Requisição" (v2.25.2) — é uma AÇÃO (abre o painel na hora), não uma
     tela como as outras, então ganha a cor de destaque do app pra se
     diferenciar visualmente dos demais itens do grupo Comercial. v2.29.13 —
     negrito removido (pedido explícito do usuário: "quero que fique normal,
     sem negrito") — mantém só a cor de destaque, no mesmo peso dos outros
     itens do grupo (.nav-group-body .nav-item, font-weight:500 acima). */
  .nav-group-body .nav-item[data-action="nova-requisicao"]{ color:var(--primary); font-weight:500; }
  .nav-group-body .nav-item[data-action="nova-requisicao"]:hover{ background:var(--primary-soft); }
}

.sidebar-foot{ margin-top:auto;padding-top:10px;border-top:1px solid var(--border); }
.status-pill{
  display:flex;align-items:center;gap:7px;font-size:11.5px;color:var(--ink-soft);
  padding:8px 9px;border-radius:var(--radius-sm);background:var(--surface-2);
}
.status-dot{ width:7px;height:7px;border-radius:50%;background:var(--success);flex:none; }
/* status-pill virou <button> (v2.29.15, abre "Meu Perfil") — reset do visual
   padrão de botão pra continuar idêntico ao <div> que era antes. */
button.status-pill{ border:none;width:100%;text-align:left;cursor:pointer;font:inherit; }
button.status-pill:hover{ background:var(--primary-soft); }
.theme-toggle{
  margin-top:8px;width:100%;display:flex;align-items:center;justify-content:center;gap:6px;
  padding:8px;border-radius:var(--radius-sm);border:1px solid var(--border);
  background:var(--surface);color:var(--ink-soft);font-size:12px;font-weight:600;cursor:pointer;text-decoration:none;
}
.theme-toggle:hover{ color:var(--ink); }
/* Código da tela atual (ver SCREEN_CODES em frontend.js) — discreto de
   propósito, só pra servir de referência rápida ("mexe na REQ-02") sem
   chamar atenção durante o uso normal do sistema. */
.cf-screen-tag{
  margin-top:8px;text-align:center;font-size:10px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  letter-spacing:.04em;color:var(--ink-faint);opacity:.7;user-select:text;
}

main.content{ flex:1;min-width:0;display:flex;flex-direction:column; }
.topbar{
  display:flex;align-items:flex-start;justify-content:space-between;gap:16px;flex-wrap:wrap;
  padding:26px 32px 18px;border-bottom:1px solid var(--border);background:var(--surface);
}
.topbar h1{ font-size:22px;margin:0 0 4px; }
.topbar p{ margin:0;color:var(--ink-soft);font-size:13px;max-width:56ch; }
.btn{
  display:inline-flex;align-items:center;gap:7px; padding:9px 15px;border-radius:var(--radius-sm);border:1px solid transparent;
  font-size:13px;font-weight:700;cursor:pointer;white-space:nowrap; transition:filter .12s ease, background .12s ease;
}
.btn svg{ width:15px;height:15px;flex:none; }
.btn:hover{ filter:brightness(0.97); }
.btn-primary{ background:var(--accent);color:var(--accent-ink); }
.btn-primary:hover{ filter:brightness(1.06); }
.btn-ghost{ background:transparent;border-color:var(--border);color:var(--ink-soft); }
.btn-ghost:hover{ background:var(--surface-2);color:var(--ink); }
.btn-soft{ background:var(--primary-soft);color:var(--primary-strong); }
.btn-danger{ background:var(--danger);color:#fff; }
.btn-danger:hover{ filter:brightness(1.06); }
.btn-sm{ padding:6px 10px;font-size:12px;border-radius:7px; }
.btn-icon{ padding:7px;border-radius:8px;background:transparent;border:1px solid var(--border);color:var(--ink-soft); }
.btn-icon:hover{ background:var(--surface-2);color:var(--ink); }
/* Botão de Lixeira no rodapé do painel de detalhe (ver openGenericDetail() em
   frontend.js) — tingido de "perigo" o tempo todo, não só no hover, pra
   deixar claro que é uma ação destrutiva antes mesmo de encostar o mouse. */
.btn-icon.danger{ color:var(--danger);border-color:var(--danger-soft); }
.btn-icon.danger:hover{ background:var(--danger-soft);color:var(--danger);border-color:var(--danger-soft); }
/* Botão "Excluir" nas linhas da lista de fábricas de Preços de Fábrica e
   Carteira e Pendências (v2.29.12) — mesmo espírito de .btn-icon.danger
   acima, só que pro botão ghost com texto em vez de ícone sozinho. */
.btn-ghost.btn-ghost-danger{ color:var(--danger);border-color:var(--danger-soft); }
.btn-ghost.btn-ghost-danger:hover{ background:var(--danger-soft);color:var(--danger);border-color:var(--danger-soft); }
.btn[disabled]{ opacity:.5;cursor:not-allowed; }
.btn-link-danger{
  display:inline-flex;flex-direction:column;align-items:flex-start;background:none;border:none;padding:0;cursor:pointer;
}
.btn-link-danger .lbl{ display:inline-flex;align-items:center;gap:7px;color:var(--danger);font-size:12px;font-weight:700;letter-spacing:.02em;text-transform:uppercase; }
.btn-link-danger .cap{ font-size:10px;color:var(--ink-faint);margin-top:2px; }
.btn-link-danger[disabled]{ opacity:.5;cursor:not-allowed; }

.toolbar{
  display:flex;gap:10px;align-items:center;flex-wrap:wrap;
  padding:16px 32px;background:var(--surface);border-bottom:1px solid var(--border);
}
.search-box{
  display:flex;align-items:center;gap:8px; background:var(--surface-2);border:1px solid var(--border);border-radius:var(--radius-sm);
  padding:8px 12px;min-width:220px;flex:1;max-width:340px;
}
.search-box svg{ width:15px;height:15px;color:var(--ink-faint);flex:none; }
.search-box input{ border:none;background:transparent;outline:none;color:var(--ink);font-size:13px;width:100%; }
select.filter-select{
  padding:8px 30px 8px 12px;border-radius:var(--radius-sm);border:1px solid var(--border);
  background:var(--surface-2) url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="none" stroke="%235c6b60" stroke-width="1.6"><path d="M5 8l5 5 5-5"/></svg>') no-repeat right 8px center/13px;
  color:var(--ink);font-size:13px;appearance:none;cursor:pointer;font-family:inherit;
}
/* Pedido do usuário (mockup for01-logo-filtros-contato-mockup.html): mesmo
   com padding igual, .search-box (uma div) e select.filter-select (um
   <select> nativo) renderizavam com alturas levemente diferentes — todo
   navegador dá ao <select> uma altura "de fábrica" própria, por causa do
   line-height padrão do elemento. Travando height+box-sizing explícitos
   nos dois, a altura fica garantidamente idêntica, não só parecida por
   coincidência do padding. 38px = a altura que os dois já tinham na
   listagem de Fornecedores (FOR-01), vira o padrão em toda a Toolbar do
   sistema, pros filtros extras (`.filter-extra`, ver frontend.js) incluídos. */
.search-box, select.filter-select{ height:38px;box-sizing:border-box; }
.toolbar-count{ font-size:12px;color:var(--ink-faint);margin-left:auto; }
/* Container dos filtros extras de um módulo (hoje só Fornecedores/FOR-01:
   Portfólio, Marcas, UF, Contato — ver cfg.filtrosExtras em frontend.js).
   display:contents faz os <select class="filter-select"> de dentro dele se
   comportarem como filhos diretos de .toolbar pro layout flex (mesmo gap,
   mesmo wrap), sem um "embrulho" a mais no meio. Vazio/escondido nos
   módulos que não definem filtrosExtras. */
.filter-extra{ display:contents; }

.view-area{ flex:1;padding:22px 32px 48px;overflow:auto; }
.empty-state{
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:10px;padding:70px 20px;color:var(--ink-faint);text-align:center;
}
.empty-state svg{ width:42px;height:42px;opacity:.5; }
.empty-state strong{ color:var(--ink-soft);font-size:14px; }

/* ---------- tabela ---------- */
/* Pedido do usuário: em todas as tabelas do sistema, congelar título, filtro
   e cabeçalho da tabela, rolando só os dados. O título (.topbar) e o filtro
   (.toolbar) já ficam fora de .table-wrap (são elementos irmãos, antes da
   tabela), então na prática o que faltava era a PRÓPRIA tabela ficar de
   tamanho fixo, com rolagem só dentro dela, e o cabeçalho (thead) grudado no
   topo dessa rolagem. .table-wrap ganha uma altura máxima (o que sobra da
   tela, descontando o espaço já ocupado por título/filtro/margens — por
   isso o "- 300px" abaixo) e rolagem própria (overflow:auto no lugar de
   hidden — continua cortando os cantos arredondados igual antes, só que
   agora também rola quando o conteúdo não cabe); o `min-height` evita que a
   tabela fique espremida demais numa tela muito baixa. Com isso,
   `position:sticky` no `thead th` gruda o cabeçalho no topo dessa rolagem
   interna — funciona porque .table-wrap passa a ser o "ancestral com
   rolagem" mais próximo do thead. Quando a tabela é curta (poucas linhas),
   o max-height simplesmente não é atingido — a tabela fica do tamanho
   normal, sem barra de rolagem nenhuma. No celular (ver media query mais
   abaixo), a tabela vira uma lista de cartões e isso tudo é desligado, já
   que o cabeçalho já não aparece nesse layout. */
.table-wrap{
  background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-md);
  overflow:auto;box-shadow:var(--shadow-sm);
  max-height:calc(100vh - 300px);min-height:260px;
}
table{ width:100%;border-collapse:collapse; }
thead th{
  text-align:left;font-size:10.5px;text-transform:uppercase;letter-spacing:.07em;
  color:var(--ink-faint);padding:11px 16px;border-bottom:1px solid var(--border);
  background:var(--surface-2);font-weight:700;
  position:sticky;top:0;z-index:1;
  /* Feedback do usuário depois de testar ao vivo (v2.14.0): flutuando por
     cima das linhas durante a rolagem, o cabeçalho ficava sutil demais —
     só a borda de 1px embaixo não se destacava o suficiente das linhas
     passando por baixo. Uma sombra leve reforça a separação sem ficar
     pesada quando a tabela está parada (sem rolar, a sombra mal se nota,
     já que não tem nada "por baixo" ainda). */
  box-shadow:0 2px 4px rgba(20,30,24,.08);
}
/* Altura padrão de linha, em TODAS as tabelas do sistema (Fornecedores,
   Requisições, Cotações, Produtos): 30px (1px de padding + 28px de
   line-height, ambos de cima e de baixo) — pedido do usuário, mockup
   aprovado (for01-logo-filtros-contato-mockup.html), pra caber o logo de
   28px da listagem de Fornecedores (ver `tbody .avatar` logo abaixo) sem
   cortar. Era 18px (padding de 1px + line-height de 16px) até a v2.41.x;
   o logo precisou crescer primeiro, a linha só acompanhou o tamanho dele —
   os dois estão amarrados (ver thread do pedido). Texto não quebra em mais
   de uma linha (white-space:nowrap) — se o conteúdo não couber, a própria
   tabela aumenta a largura da coluna em vez de esticar a altura da linha.
   Colunas com listas muito longas (Marcas/Portfólio) continuam usando
   `.cell-truncate` (corte com "..." + tooltip) em vez de alargar sem limite,
   exceção deliberada já existente desde a v2.3.0. Exceções que NÃO seguem
   esta altura (já eram especiais antes desta mudança, por motivos próprios
   — ver os comentários de cada uma): `.perm-table tbody td` (Acessos) e
   `.preco-itens-table-wrap td` (tabelas dentro do painel de detalhe). */
tbody td{
  padding:1px 16px;border-bottom:1px solid var(--border);vertical-align:middle;
  font-size:13.3px;line-height:28px;white-space:nowrap;
}
tbody tr:last-child td{ border-bottom:none; }
tbody tr:hover{ background:var(--surface-2); }

/* Linhas verticais entre colunas (v2.29.25, pedido do usuário, mockup
   aprovado) — só na listagem de Requisições (REQ-01, ver renderView() em
   frontend.js, que só aplica esta classe quando cfg.key==='requisicoes');
   as demais tabelas do app continuam sem divisórias. Sem linha depois da
   última coluna (:not(:last-child)). */
.tabela-linhas-coluna th:not(:last-child),
.tabela-linhas-coluna td:not(:last-child){ border-right:1px solid var(--border); }
/* Cabeçalho da coluna "Comentários" (REQ-01) virou só o ícone de balão, em
   vez do texto — centralizado, do tamanho de um ícone normal de tabela (ver
   c.thContent/c.thClass em renderView(), frontend.js). */
th.th-icon{ text-align:center; }
th.th-icon svg{ width:13px;height:13px;vertical-align:middle; }

/* Coluna "Ver" (v2.34.0, pedido do usuário): o botão de Visualizar virou a
   PRIMEIRA coluna de toda tabela do sistema (era sempre a última, com
   cabeçalho vazio — ver renderView()/renderProdutosView()/
   renderClientesView()/renderTermTable()/renderCotar() em frontend.js).
   th.th-ver centraliza o rótulo "VER", e td.actions:first-child centraliza
   o botão embaixo dele — só quando .actions é a PRIMEIRA célula da linha
   (exatamente os casos que viraram "Ver"); .actions como ÚLTIMA célula
   (Carteira, Preços de Fábrica, Usuários — botões de texto como "Abrir"/
   "Editar", nunca o ícone de Visualizar) continua com o td.actions{
   text-align:right } de sempre, logo abaixo, sem mudança nenhuma. */
th.th-ver{ text-align:center; }
td.actions:first-child{ text-align:center; }

td.actions{ text-align:right; }
/* Botão de ação (Exibir/Editar) dentro de tabela: por padrão o navegador dá
   ao <button> um line-height baseado no font-size nativo dele (~17px), bem
   maior que os 16px de line-height da célula — isso fazia o botão ficar com
   ~31px de altura e esticar a linha inteira para ~35px, mesmo com o padding
   reduzido. Corrigido travando altura/largura explícitas (16px, do tamanho
   da linha de texto) e centralizando o ícone com flex, em vez de depender
   do line-height do texto do botão. */
td.actions .btn-icon{
  margin-left:4px;padding:1px;border-radius:5px;
  width:16px;height:16px;box-sizing:border-box;
  display:inline-flex;align-items:center;justify-content:center;
}
td.actions .btn-icon svg{ width:12px;height:12px;flex:none; }

.cell-identity{ display:flex;align-items:center;gap:8px; }
.avatar{
  width:34px;height:34px;border-radius:9px;flex:none;object-fit:cover;
  background:var(--primary-soft);color:var(--primary-strong);
  display:flex;align-items:center;justify-content:center;font-weight:800;font-size:12.5px;
  border:1px solid var(--border);
}
/* Dentro de uma linha de tabela, o avatar padrão de 34px não cabe mais —
   encolhido pra 28px só nesse contexto, pedido do usuário, mockup aprovado
   (for01-logo-filtros-contato-mockup.html): antes (até a v2.41.x) era 14px/
   fonte 6.5px, ilegível, pra caber na linha de 18px de então; a linha
   cresceu pra 30px (ver `tbody td` acima) justamente pra acomodar este
   logo maior, sem precisar diminuí-lo mais que isso. Fora de tabela (ex:
   hero de detalhe), o próprio HTML já sobrescreve width/height inline com
   um tamanho maior, sem depender desta regra. */
tbody .avatar{ width:28px;height:28px;border-radius:8px;font-size:11px; }
.cell-identity .name{ font-weight:700;color:var(--ink); }
.cell-identity .sub, tbody .sub{ font-size:11.5px;color:var(--ink-faint); }
/* Badges dentro de tabela: versão compacta pra caber na linha de 18px, sem
   afetar o tamanho normal do badge usado fora de tabelas (detalhes, formulário). */
tbody .badge{ padding:1px 7px;font-size:10px; }

/* Colunas de texto longo (Marcas / Portfólio): trunca com "..." e mostra a
   lista inteira no title (tooltip nativo do navegador) ao passar o mouse. */
.cell-truncate{
  display:inline-block;max-width:220px;white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis;vertical-align:middle;
}
/* Traço neutro da coluna "Comentários" quando a requisição ainda não tem
   nenhum comentário — mockup aprovado: sem ícone nenhum nesse caso, só o
   traço, igual a qualquer outra célula vazia da tabela (ver `— ` já usado em
   várias colunas). */
.cell-dash{ color:var(--ink-faint); }
/* Ícone de balão + badge de não lidos da coluna "Comentários" (só em
   Requisições, ver comentariosCellHtml() em frontend.js). Botão sem borda —
   só o ícone — clicável, pra abrir a tela de comentários direto da linha. */
.cf-comment-cell{
  background:none;border:none;padding:0;cursor:pointer;color:var(--ink-soft);
  display:inline-flex;align-items:center;position:relative;
}
.cf-comment-cell:hover{ color:var(--ink); }
.cf-comment-cell svg{ width:15px;height:15px;flex:none; }
tbody .cf-comment-cell svg{ width:13px;height:13px; }
.cf-comment-badge{
  position:absolute;top:-6px;right:-8px;background:var(--danger);color:#fff;
  font-size:9px;font-weight:800;border-radius:999px;min-width:14px;height:14px;
  display:inline-flex;align-items:center;justify-content:center;padding:0 3px;
  line-height:1;box-shadow:0 0 0 2px var(--surface);
}

.badge{
  display:inline-flex;align-items:center;gap:5px;padding:3px 9px;border-radius:999px;
  font-size:11px;font-weight:700;white-space:nowrap;
}
.badge-primary{ background:var(--primary-soft);color:var(--primary-strong); }
.badge-accent{ background:var(--accent-soft);color:var(--accent); }
.badge-muted{ background:var(--surface-2);color:var(--ink-faint);border:1px dashed var(--border); }
.badge-warn{ background:var(--warn-soft);color:var(--warn); }
.badge-success{ background:var(--success-soft);color:var(--success); }
.badge-danger{ background:var(--danger-soft);color:var(--danger); }
/* Ícone dentro de um badge (hoje só a estrela do "★ Principal" do Contato de
   Fornecedor, v2.41.0 — ver fornecedorContatoPrincipalCellHtml()/
   fornecedorContatosDetailHtml() em assets/frontend.js). Nenhum outro badge
   do sistema embute ícone, então isto não afeta os demais. */
.badge svg{ width:11px;height:11px;flex:none; }
/* v2.43.0 — mesma informação de badge-muted/badge-success/badge-danger
   acima, só que como TEXTO SIMPLES, sem a pílula (fundo/padding/raio) — só
   a cor. Pedido do usuário, mockup aprovado (prf01-logo-autocomplete-
   mockup.html): colunas "Marca"/"Validade" (listagem de Preços de Fábrica,
   PRF-01) e "Colunas" (listagem de Carteira e Pendências, CTP-01) deixaram
   de usar pílula colorida — "Validade" mantém a cor (vermelho/vencida,
   verde/válida) mesmo sem o fundo; ver precoFabricaValidadeTexto() em
   assets/frontend.js. As pílulas badge-* continuam existindo, sem mudança,
   em todos os outros lugares que já as usavam (inclusive o hero de detalhe
   da própria Preços de Fábrica, PRF-02). */
.plain-muted{ color:var(--ink-faint); }
.plain-success{ color:var(--success);font-weight:600; }
.plain-danger{ color:var(--danger);font-weight:600; }
/* v2.35.3 — pílulas dos 5 status da Fábrica (ver comentário em --st-yellow
   etc., no :root, e em COT_STATUS_FABRICA_TONE em frontend.js). Classes
   próprias (não reaproveitam badge-warn/badge-danger/badge-accent/
   badge-success acima) pra não recolorir nenhum outro badge do sistema que
   use essas mesmas classes genéricas em telas sem nenhuma relação com
   Cotação. */
.badge-st-yellow{ background:var(--st-yellow-soft);color:var(--st-yellow); }
.badge-st-gray{ background:var(--st-gray-soft);color:var(--st-gray); }
.badge-st-green{ background:var(--st-green-soft);color:var(--st-green); }
.badge-st-purple{ background:var(--st-purple-soft);color:var(--st-purple); }

/* Status da Fábrica na listagem de Cotações (COT-01, v2.32.2, mockup
   "quadradinho" aprovado pelo usuário): texto normal + um quadradinho da
   cor do status ao lado, em vez do badge/pill de fundo colorido — mesmas
   5 cores de sempre (ver COT_STATUS_FABRICA_TONE em assets/frontend.js),
   só aplicadas no quadradinho em vez do fundo inteiro da célula. Usado só
   aqui — a tela "Cotar" continua com o <select class="badge ..."> de
   sempre, sem nenhuma mudança. Prefixo "cot-" pra não colidir com o
   ".status-dot" já existente (bolinha verde "online" do status-pill do
   topo, ver linha ~266 acima — mesmo nome, propósito totalmente
   diferente). */
.cot-status-cell{ display:inline-flex;align-items:center;gap:7px;color:var(--ink);font-weight:500; }
.cot-status-dot{ width:10px;height:10px;flex:none;border-radius:3px; }
.dot-warn{ background:var(--warn); }
.dot-muted{ background:var(--ink-faint); }
.dot-danger{ background:var(--danger); }
.dot-accent{ background:var(--accent); }
.dot-success{ background:var(--success); }
/* v2.35.3 — quadradinhos dos 5 status da Fábrica, mesma ideia do bloco
   ".badge-st-*" acima: cor própria, puxando "-dot" (mais vivo que a dupla
   normal/soft da pílula, ver comentário em --st-yellow-dot etc. no :root). */
.dot-st-yellow{ background:var(--st-yellow-dot); }
.dot-st-gray{ background:var(--st-gray-dot); }
.dot-st-green{ background:var(--st-green-dot); }
.dot-st-purple{ background:var(--st-purple-dot); }

@media (max-width:820px){
  .sidebar{
    position:fixed;left:0;right:0;bottom:0;top:auto;height:auto;width:auto;
    flex-direction:row;align-items:center;padding:8px 10px;
    padding-bottom:calc(8px + env(safe-area-inset-bottom,0px));
    z-index:40;border-right:none;border-top:1px solid var(--border); gap:6px;overflow-x:auto;
  }
  .sidebar .brand,.sidebar-foot{ display:none; }
  nav.modules{ flex-direction:row;gap:4px; }
  .nav-label{ display:none; }
  /* No celular a barra vira uma fileira de ícones (sem os grupos abrir/
     fechar, que só fazem sentido com a barra lateral vertical) — os grupos
     ficam "transparentes" pro layout (display:contents), então cada
     nav-item aparece direto na fileira, do jeito que já funcionava antes
     dos grupos existirem; o cabeçalho do grupo (nome + seta) some. */
  .nav-group,.nav-group-body{ display:contents; }
  .nav-group-header{ display:none; }
  .nav-item{ flex-direction:column;gap:2px;font-size:9.5px;padding:6px 10px;min-width:56px;text-align:center; }
  .nav-item .nav-count{ display:none; }
  main.content{ padding-bottom:64px; }
  .topbar,.toolbar,.view-area{ padding-left:18px;padding-right:18px; }
  /* A rolagem própria da tabela (ver .table-wrap fora deste media query) é
     coisa de tela larga, com cabeçalho de coluna visível — no celular o
     cabeçalho já some (thead{display:none} logo abaixo) e a lista de
     cartões deve rolar junto com o resto da página, como sempre rolou. */
  .table-wrap{ max-height:none;min-height:0;overflow:visible; }
  table,thead,tbody,th,td,tr{ display:block; }
  thead{ display:none; }
  tbody tr{ border-bottom:1px solid var(--border);padding:12px 4px;display:flex;flex-direction:column;gap:6px; }
  /* No celular a tabela vira uma lista de cartões (um campo por linha,
     empilhados) — a altura fixa de 18px e o white-space:nowrap do desktop
     não se aplicam aqui, senão o valor de campos mais longos vazaria da tela. */
  tbody td{
    border:none;padding:0 12px;display:flex;justify-content:space-between;gap:12px;align-items:center;
    white-space:normal;line-height:1.3;
  }
  tbody td[data-label]::before{
    content:attr(data-label);font-size:10.5px;text-transform:uppercase;letter-spacing:.05em;
    color:var(--ink-faint);font-weight:700;flex:none;
  }
  td.actions{ justify-content:flex-end;padding-top:4px; }
  td.actions::before{ display:none; }
  /* Desfaz o tamanho fixo de 16px usado no desktop (ver comentário acima da
     regra `td.actions .btn-icon` fora do media query) — no celular o botão
     volta ao tamanho natural, maior e mais fácil de tocar. */
  td.actions .btn-icon{ padding:7px;width:auto;height:auto;display:inline-block; }
  td.actions .btn-icon svg{ width:auto;height:auto; }
  .cell-truncate{ max-width:100%;min-width:0;flex:1;text-align:right; }
  tbody .avatar{ width:34px;height:34px;border-radius:9px;font-size:12.5px; }
}

/* ---------- painel lateral ---------- */
.backdrop{
  position:fixed;inset:0;background:rgba(10,14,11,.42);opacity:0;pointer-events:none;
  transition:opacity .18s ease;z-index:50;
}
.backdrop.open{ opacity:1;pointer-events:auto; }
/* ---------- painel: modal central retangular ----------
   Era uma gaveta deslizando pela direita (position:fixed;right:0). Mudança
   pedida pelo usuário (mockup "Visualizar/Editar/Lixeira" aprovado): agora é
   um cartão centralizado na tela, fechando com escala+opacidade em vez de
   deslizar. .panel-wide/.panel-xwide continuam existindo, só a largura-base
   mudou (ver comentário em cada uma). */
.panel{
  position:fixed;top:50%;left:50%;
  width:min(640px,92vw);max-height:min(780px,88vh);
  background:var(--surface);box-shadow:var(--shadow-lg);border-radius:20px;
  transform:translate(-50%,-50%) scale(.96);opacity:0;pointer-events:none;
  transition:opacity .18s ease,transform .18s cubic-bezier(.32,.72,0,1);
  z-index:51;display:flex;flex-direction:column;overflow:hidden;
}
.panel.open{ transform:translate(-50%,-50%) scale(1);opacity:1;pointer-events:auto; }
.panel.panel-wide{ width:min(760px,94vw); }
/* 1400px -> 1480px na v2.26.5: o botão de remover produto (REQ-02) virou
   mais uma coluna na mesma linha dos outros campos do produto (ver
   .item-grid-single logo abaixo) — um pouco mais de largura evita apertar
   o resto da linha. */
.panel.panel-xwide{ width:min(1480px,97vw);max-height:min(860px,92vh); }
@media (max-width:560px){
  .panel{ width:94vw;max-height:92vh;border-radius:16px; }
}
.panel-head{
  display:flex;align-items:flex-start;justify-content:space-between;gap:10px;
  padding:22px 24px 16px;border-bottom:1px solid var(--border);flex:none;
}
.panel-head h2{ font-size:18px;margin:0 0 3px; }
.panel-head p{ margin:0;font-size:12px;color:var(--ink-faint); }
/* O formulário (<form id="recordForm">) é filho direto de .panel (que é
   flex-column), mas um <form> comum não vira container flex sozinho — sem
   esta regra, .panel-body (dentro dele) nunca ganha uma altura limitada e o
   "overflow:auto" abaixo não tem efeito nenhum: o painel simplesmente cresce
   até sair da tela quando o conteúdo é grande (como acontece com várias
   linhas de Marcas/Portfólio), sem barra de rolagem e sem acesso aos campos
   e ao botão Salvar que ficam mais abaixo. */
.panel > form{ display:flex; flex-direction:column; flex:1; min-height:0; }
.panel-body{ flex:1;overflow:auto;padding:22px 24px;min-height:0; }
.panel-foot{
  padding:14px 24px;border-top:1px solid var(--border);display:flex;align-items:center;justify-content:flex-end;gap:8px;
  background:var(--surface);flex:none;
}
/* Rodapé com dois grupos (Lixeira/Excluir Definitivamente à esquerda, Editar/
   Reativar à direita) — ver openGenericDetail()/openReferenciaDetail()/
   openRequisicaoDetail() em frontend.js. Quando só o grupo da direita tem
   conteúdo (a maioria das telas — nenhuma ação de lixeira, ex: formulário,
   Calcular Preço de Venda), a regra abaixo empurra ele pro canto sem precisar
   de um caso especial. */
.panel-foot{ justify-content:space-between; }
.panel-foot-left{ display:flex;align-items:center;gap:8px; }
.panel-foot-right{ display:flex;align-items:center;gap:8px;margin-left:auto; }
.panel-foot-caption{ font-size:10px;color:var(--ink-faint);margin-top:2px; }
.detail-inactive-banner{
  margin:0 0 20px;padding:11px 14px;border-radius:10px;background:var(--danger-soft);color:var(--danger);
  font-size:12px;display:flex;align-items:center;gap:9px;flex:none;
}
.detail-inactive-banner svg{ flex:none;width:16px;height:16px; }
.badge-inactive{ background:var(--danger-soft);color:var(--danger); }
.panel-foot-left .btn-icon svg{ width:16px;height:16px;flex:none; }
.btn-link-danger .lbl svg{ width:15px;height:15px;flex:none; }

/* Confirmação de Lixeira/Excluir Definitivamente — telas próprias no mockup
   aprovado (não um confirm() nativo do navegador), reaproveitando o mesmo
   #detailPanel encolhido pela classe .panel-confirm. */
.panel.panel-confirm{ width:min(460px,90vw); }
.confirm-body{ display:flex;flex-direction:column;align-items:center;text-align:center;gap:14px;padding:32px 28px 8px; }
.confirm-icon{ width:56px;height:56px;border-radius:50%;display:flex;align-items:center;justify-content:center;flex:none; }
.confirm-icon svg{ width:28px;height:28px; }
.confirm-icon.tone-warn{ background:var(--warn-soft);color:var(--warn); }
.confirm-icon.tone-danger{ background:var(--danger-soft);color:var(--danger); }
.confirm-title{ font-family:'Manrope',Inter,system-ui,sans-serif;font-weight:800;font-size:17px;text-transform:uppercase;letter-spacing:-.01em; }
.confirm-title.tone-danger{ color:var(--danger); }
.confirm-text{ font-size:13px;color:var(--ink-soft);line-height:1.5; }
.confirm-actions{ padding:22px 28px 28px;display:flex;justify-content:center;gap:10px;flex:none; }

.field-grid{ display:grid;grid-template-columns:1fr 1fr;gap:14px 14px; }
/* Cabeçalho da "Nova Requisição" em 2 linhas (v2.29.23, mockup aprovado,
   substitui o .field-grid-3 da v2.29.22) — grids próprios, só usados pelo
   formulário de Requisição (ver openRequisicaoForm() em frontend.js), sem
   tocar no .field-grid genérico (continua 1fr/1fr pros outros formulários).
   Requisitante e Categoria usam o MESMO valor fixo — como ficam na 1ª
   coluna de uma linha e na 2ª coluna da outra, só largura fixa igual
   garante que fiquem alinhados/com a mesma largura nas duas linhas; fr não
   garantiria isso (fr é proporcional à coluna, não ao valor absoluto).
   v2.29.24 (pedido do usuário): aumentado de 210px para 300px, pra ficar do
   mesmo tamanho do campo "Produto" da linha de produtos (.item-grid-single,
   coluna 1.25fr — ~300px é o quanto essa coluna mede num painel largo, já
   descontando as outras colunas fixas/gap daquele grid; os dois grids têm
   proporções diferentes, então a largura bate certinho só numa janela
   grande, mas aproxima bem na maioria das telas).
   Data fica fixa e estreita (110px, só o suficiente pra "DD/MM/AAAA").
   Cliente, Tipo de Requisição e Local Cotar dividem o espaço que sobra em
   cada linha (fr) — aumentar o valor fixo de Requisitante/Categoria reduz
   proporcionalmente o espaço sobrando pra Tipo de Requisição, encolhendo o
   vão entre o chip "Urgente" e o campo Categoria. */
.requisicao-fields-top{ display:grid;grid-template-columns:300px 110px 1fr;gap:14px 14px; }
.requisicao-fields-bottom{ display:grid;grid-template-columns:1.3fr 300px 1fr;gap:14px 14px;margin-top:14px; }
.field{ display:flex;flex-direction:column;gap:5px;min-width:0; }
.field.col-2{ grid-column:1 / -1; }
@media (max-width:520px){ .field-grid{ grid-template-columns:1fr; } .requisicao-fields-top,.requisicao-fields-bottom{ grid-template-columns:1fr; } .field.col-2{ grid-column:auto; } }
.field label{ font-size:11.5px;font-weight:700;color:var(--ink-soft); }
.field .hint{ font-size:11px;color:var(--ink-faint); }
.field input[type="text"],.field input[type="email"],.field input[type="tel"],
.field input[type="date"],.field input[type="number"],.field textarea,.field select{
  padding:9px 11px;border-radius:8px;border:1px solid var(--border);background:var(--surface-2);
  color:var(--ink);font-size:13.3px;outline:none;width:100%;
}
.field textarea{ min-height:72px;resize:vertical;font-family:inherit; }
.field input:focus,.field select:focus,.field textarea:focus{ border-color:var(--primary);background:var(--surface); }
.field.invalid input,.field.invalid select,.field.invalid textarea{ border-color:var(--danger);background:var(--danger-soft); }
.field .error-msg{ font-size:11px;color:var(--danger);display:none; }
.field.invalid .error-msg{ display:block; }
/* Campo gerado pelo servidor, nunca digitado (type:'auto' — ver fieldHtml()
   em assets/frontend.js; hoje só o Código da Tabela de Vendas, v2.27.0): só
   o texto mais apagado e o cursor de "bloqueado" — o fundo já é igual ao de
   um campo comum sem foco (var(--surface-2) na regra acima), de propósito,
   pra não parecer quebrado/vazio antes de salvar. */
.field input:disabled{ color:var(--ink-faint);cursor:not-allowed; }
/* Checkbox genérico (type:'checkbox' — ver fieldHtml() em assets/frontend.js;
   hoje só "Cálculo Manual" da Tabela de Vendas, v2.27.1): o rótulo do campo
   (field.label, ex: "Cálculo Manual") continua em cima, igual aos outros
   tipos — aqui só o checkbox + o texto explicativo (field.checkboxLabel) lado
   a lado, clicáveis como um todo. */
.checkbox-field{ display:flex;align-items:flex-start;gap:8px;font-size:12.5px;font-weight:400;color:var(--ink);cursor:pointer;line-height:1.4; }
.checkbox-field input[type="checkbox"]{ width:16px;height:16px;flex:none;margin-top:1px;accent-color:var(--primary);cursor:pointer; }
.currency-input{ display:flex;align-items:center;border:1px solid var(--border);border-radius:8px;background:var(--surface-2);overflow:hidden; }
.currency-input span{ padding:0 0 0 11px;color:var(--ink-faint);font-size:12.5px; }
.currency-input input{ border:none!important;background:transparent!important;flex:1; }

.cf-list-wrap{ display:flex;flex-direction:column;gap:7px;margin-bottom:8px; }
.cf-list-row{ display:flex;align-items:center;gap:7px; }
.cf-list-row .cf-list-input{ flex:1; }
.cf-list-remove{
  flex:none;width:26px;height:26px;border-radius:7px;border:1px solid var(--border);
  background:var(--surface-2);color:var(--ink-faint);font-size:16px;line-height:1;cursor:pointer;
}
.cf-list-remove:hover{ background:var(--danger-soft);color:var(--danger);border-color:var(--danger-soft); }
.cf-list-add-btn{ align-self:flex-start; }

/* ---- campo de Contatos (v2.41.0, Fornecedor — mockup aprovado) ----
   Um cartão por pessoa, com cabeçalho (numeração + estrela "Principal" +
   remover) e uma grade de 6 sub-campos. Ver contatosFieldBlock()/
   renderContatosField() em assets/frontend.js. */
.cf-contatos-wrap{ display:flex;flex-direction:column;gap:12px;margin-bottom:8px; }
.empty-contatos{ color:var(--ink-faint);font-size:13px;font-style:italic;margin:0; }
.contato-card{
  border:1px solid var(--border);border-radius:var(--radius-md);background:var(--surface-2);
  padding:12px 14px;
}
.contato-card.is-principal{ border-color:var(--warn);background:var(--warn-soft); }
.contato-card-head{ display:flex;align-items:center;gap:8px;margin-bottom:10px; }
.contato-card-num{ font-size:10.5px;text-transform:uppercase;letter-spacing:.06em;color:var(--ink-faint);font-weight:700;flex:1; }
.star-btn{
  display:inline-flex;align-items:center;gap:5px;padding:5px 10px;border-radius:999px;
  border:1px solid var(--border);background:var(--surface);color:var(--ink-soft);font-size:11.5px;
  font-weight:700;cursor:pointer;flex:none;
}
.star-btn svg{ width:13px;height:13px;flex:none; }
.star-btn.is-on{ background:var(--warn);border-color:var(--warn);color:#fff; }
.star-btn:not(.is-on):hover{ background:var(--surface-2); }
.contato-card .btn-icon{ flex:none; }
.contato-card .btn-icon svg{ width:14px;height:14px;flex:none; }
.contato-fields{ display:grid;grid-template-columns:1fr 1fr;gap:10px 14px; }
.contato-subfield{ display:flex;flex-direction:column;gap:4px; }
.contato-subfield label{ font-size:10.5px;text-transform:uppercase;letter-spacing:.05em;color:var(--ink-faint);font-weight:700; }
@media (max-width:520px){ .contato-fields{ grid-template-columns:1fr; } }

/* ---- Contatos no painel "Visualizar" do Fornecedor (openGenericDetail(),
   fornecedorContatosDetailHtml()) ---- */
.contatos-detail-section{ margin-top:22px; }
.contatos-detail-title{ margin:0 0 10px;font-size:13px;color:var(--ink-faint);text-transform:uppercase;letter-spacing:.05em;font-weight:700; }
.contatos-detail-grid{ display:grid;grid-template-columns:1fr 1fr;gap:12px; }
@media (max-width:520px){ .contatos-detail-grid{ grid-template-columns:1fr; } }
.contato-view-card{ border:1px solid var(--border);border-radius:var(--radius-md);background:var(--surface-2);padding:12px 14px; }
.contato-view-card.is-principal{ border-color:var(--warn);background:var(--warn-soft); }
.cvc-head{ display:flex;align-items:center;gap:8px;flex-wrap:wrap; }
.cvc-nome{ font-weight:700;color:var(--ink); }
.cvc-depto{ font-size:12px;color:var(--ink-faint);margin-top:2px; }
.cvc-meta{ display:flex;flex-direction:column;gap:4px;margin-top:8px;font-size:12.5px; }
.cvc-meta a, .cvc-meta span{ color:var(--ink-soft);text-decoration:none; }
.cvc-meta a:hover{ text-decoration:underline; }

/* ---- pares marca/código (Referências Cruzadas) ---- */
.cf-pair-wrap{ display:flex;flex-direction:column;gap:7px;margin-bottom:8px; }
.cf-pair-row{ display:flex;align-items:center;gap:7px; }
.cf-pair-row .cf-pair-marca{ flex:1;min-width:0; }
.cf-pair-row .cf-pair-codigo{ flex:1;min-width:0; }
.cf-pair-remove{
  flex:none;width:26px;height:26px;border-radius:7px;border:1px solid var(--border);
  background:var(--surface-2);color:var(--ink-faint);font-size:16px;line-height:1;cursor:pointer;
}
.cf-pair-remove:hover{ background:var(--danger-soft);color:var(--danger);border-color:var(--danger-soft); }

/* ---- tela "Referências Cruzadas": cartões com número livre de marcas ---- */
.ref-cards{ display:flex;flex-direction:column;gap:10px; }
.ref-card{
  background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-sm);
  padding:14px 16px;
}
.ref-card-head{ display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:8px; }
.ref-card-title-group{ display:flex;align-items:center;gap:8px;min-width:0; }
.ref-card-title{ font-weight:700;color:var(--ink); }
.ref-card-actions{ display:flex;gap:6px;flex:none; }
/* Registro inativo (na lixeira) — continua na mesma listagem, só esmaecido,
   em vez de sumir (mockup "Visualizar/Editar/Lixeira" aprovado). Usado tanto
   em linhas de tabela (tr.row-inactive) quanto nos cartões de Referências
   Cruzadas (.ref-card.row-inactive). */
tr.row-inactive td{ background:var(--surface-2);color:var(--ink-faint); }
tr.row-inactive td .name,tr.row-inactive td .cell-identity .name{ color:var(--ink-faint); }
.ref-card.row-inactive{ background:var(--surface-2); }
.ref-card.row-inactive .ref-card-title{ color:var(--ink-faint); }
.ref-card-pills{ display:flex;flex-wrap:wrap;gap:8px; }
.ref-pill{
  display:inline-flex;align-items:center;gap:6px;background:var(--surface-2);border:1px solid var(--border);
  border-radius:999px;padding:5px 12px;font-size:12.5px;color:var(--ink-soft);
}
.ref-pill strong{ color:var(--primary-strong);font-weight:700; }
.ref-pill .mono{ color:var(--ink); }

.image-field{ display:flex;align-items:center;gap:14px; }
.image-preview{
  width:64px;height:64px;border-radius:12px;object-fit:cover;border:1px solid var(--border);
  background:var(--surface-2);display:flex;align-items:center;justify-content:center;color:var(--ink-faint);flex:none;
}
.image-actions{ display:flex;gap:8px;flex-wrap:wrap; }
.image-actions input[type="file"]{ display:none; }

.detail-grid{ display:grid;grid-template-columns:1fr 1fr;gap:16px; }
@media (max-width:520px){ .detail-grid{ grid-template-columns:1fr; } }
.detail-item{ display:flex;flex-direction:column;gap:3px; }
.detail-item.col-2{ grid-column:1/-1; }
.detail-item .k{ font-size:10.5px;text-transform:uppercase;letter-spacing:.06em;color:var(--ink-faint);font-weight:700; }
.detail-item .v{ font-size:14px;color:var(--ink); }
.detail-item .v.empty{ color:var(--ink-faint);font-style:italic; }
.detail-hero{ display:flex;align-items:center;gap:16px;margin-bottom:20px; }
.detail-hero .avatar{ width:64px;height:64px;border-radius:14px;font-size:20px; }
.detail-hero h3{ margin:0;font-size:17px; }
.detail-hero .sub{ color:var(--ink-faint);font-size:12.5px;margin-top:2px; }

/* ---------- Preços de Fábrica (v2.22.0) ---------- */
/* Tabela de itens dentro do detalhe de uma fábrica (ver
   openPrecoFabricaDetail(), assets/frontend.js). Usa uma altura máxima
   própria (bem menor que a de .table-wrap, pensada pra tela inteira) em
   vez de reaproveitar aquela classe: dentro do painel de detalhe já existe
   uma rolagem própria (.panel-body), então uma tabela tão alta quanto a
   da tela cheia deixaria duas barras de rolagem uma dentro da outra. */
.preco-itens-table-wrap{
  background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-md);
  overflow:auto;max-height:320px;
}
.preco-itens-table-wrap thead th{
  position:sticky;top:0;z-index:1;background:var(--surface-2);
  text-align:left;font-size:10.5px;text-transform:uppercase;letter-spacing:.07em;
  color:var(--ink-faint);padding:10px 14px;border-bottom:1px solid var(--border);font-weight:700;
}
.preco-itens-table-wrap td{ padding:9px 14px;border-bottom:1px solid var(--border);font-size:13px; }
.preco-itens-table-wrap tr:last-child td{ border-bottom:none; }

/* ---------- detalhe da Requisição (REQ-03) em formato de tabela, v2.29.29 ----------
   Mesma técnica/raciocínio de .preco-itens-table-wrap acima (tabela dentro de
   um painel que já tem rolagem própria — .panel-body — então max-height bem
   menor que .table-wrap da tela cheia, pra nunca empilhar duas barras de
   rolagem). Reaproveitada nas quatro tabelas desta tela: "Dados da
   requisição", "Produtos", "Cotações recebidas" e "Log de alterações". */
.detail-table-wrap{
  background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-md);
  overflow:auto;max-height:360px;box-shadow:var(--shadow-sm);
}
.detail-table-wrap table{ width:100%;border-collapse:collapse; }
/* "Observação"/"O que fez" podem ter texto longo — ao contrário do resto do
   sistema (tbody td é white-space:nowrap por padrão, ver mais acima), essas
   colunas precisam quebrar linha em vez de alargar a tabela sem limite. */
.detail-table-wrap table.wrap-cells td{ white-space:normal; }
/* Zebra sutil dentro de um MESMO grupo de produto na tabela de "Cotações
   recebidas" (linhas de fábrica diferentes para o mesmo produto, agrupadas
   por rowspan na coluna "Produto") — nunca entre produtos diferentes. */
.detail-table-wrap tr.row-grupo-par{ background:var(--surface-2); }
.produto-nome{ font-weight:700;font-size:13px;color:var(--ink); }
.produto-sub{ font-size:11px;color:var(--ink-faint);margin-top:2px; }

/* ---------- Acessos (v2.21.0) — agenda de login/senha/endereço ---------- */
/* Campo de senha do formulário: mesmo espírito visual do .currency-input
   (input sem borda própria dentro de uma "caixa" com botão ao lado). */
.password-input{ display:flex;align-items:center;gap:6px; }
.password-input input{ flex:1; }
.password-input .btn-icon{ flex:none;padding:6px; }
.password-input .btn-icon svg{ width:15px;height:15px; }
/* Indicador mascarado na listagem (coluna "Senha") — pontos maiores e mais
   espaçados que um texto normal, só para parecer claramente "oculto" em vez
   de um valor de verdade truncado. */
.senha-dots{ font-family:'IBM Plex Mono',ui-monospace,monospace;letter-spacing:2px;color:var(--ink-faint); }
/* Tela de detalhe: usuário/senha + botão(ões) de copiar/mostrar na mesma linha. */
.acesso-cred-row{ display:flex;align-items:center;gap:6px; }
.acesso-cred-row .btn-icon{ padding:5px;flex:none; }
.acesso-cred-row .btn-icon svg{ width:13px;height:13px; }
.senha-reveal{ font-family:'IBM Plex Mono',ui-monospace,monospace;letter-spacing:1.5px;text-transform:none; }
/* Aviso neutro (não é erro nem alerta) quando o acesso não exige login. */
.acesso-sem-login{
  margin:0 0 20px;padding:11px 14px;border-radius:10px;background:var(--surface-2);color:var(--ink-soft);
  font-size:12.5px;display:flex;align-items:center;gap:9px;flex:none;border:1px dashed var(--border);
}
.acesso-sem-login svg{ flex:none;width:16px;height:16px;color:var(--ink-faint); }
.acesso-acessar-wrap{ margin-bottom:20px; }
.acesso-acessar-wrap:empty{ margin-bottom:0; }
.acesso-acessar-btn{ display:inline-flex; }

/* ---------- prioridade da requisição ---------- */
.priority-group{ display:flex;gap:8px;flex-wrap:wrap; }
.priority-chip{
  display:flex;align-items:center;gap:7px;padding:8px 13px;border-radius:999px;
  border:1px solid var(--border);background:var(--surface-2);font-size:12.5px;font-weight:700;
  color:var(--ink-soft);cursor:pointer;transition:background .12s ease,border-color .12s ease,color .12s ease;
}
.priority-chip input{ width:14px;height:14px;accent-color:currentColor; }
.priority-chip.is-active.tone-accent{ background:var(--accent-soft);border-color:var(--accent);color:var(--accent); }
.priority-chip.is-active.tone-primary{ background:var(--primary-soft);border-color:var(--primary);color:var(--primary-strong); }
.priority-chip.is-active.tone-danger{ background:var(--danger-soft);border-color:var(--danger);color:var(--danger); }

/* ---------- itens da requisição ---------- */
.item-card{ border:1px solid var(--border);border-radius:12px;background:var(--surface-2);padding:14px;margin-bottom:10px; }
.item-card-head{ display:flex;align-items:center;justify-content:space-between;margin-bottom:10px; }
.item-num{ font-size:10.5px;font-weight:800;text-transform:uppercase;letter-spacing:.06em;color:var(--ink-faint); }
.item-grid-top{ display:grid;grid-template-columns:1.1fr 1.6fr 70px 90px;gap:10px; }
.item-grid-bottom{ display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:10px; }
/* 8ª coluna (40px, v2.26.5) — botão de remover produto, que deixou de ficar
   numa linha própria acima do cartão (.item-card-head) e passou a ser mais
   um campo na mesma linha dos demais (ver itemRowHtml() em
   assets/frontend.js), alinhado pela base (.item-field[style*="align-self"]
   inline no próprio elemento) com os campos que têm rótulo. */
/* v2.29.18 (pedido do usuário): 9ª coluna "Cod Interno" entre Marcas e
   Observação — Portfólio (1fr->.8fr) e Produto (1.4fr->1.3fr) ficaram um
   pouco mais estreitos pra abrir esse espaço sem alargar a linha inteira.
   Marcas (1.3fr->1.2fr) também cedeu um pouco, já que virou um campo
   fechado (.marcas-select, ver mais abaixo) que não precisa mais da mesma
   largura que tinha como caixa de chips.
   v2.29.19 (pedido do usuário): Cod Interno passou de fração (1.1fr, ficava
   largo demais sobrando espaço vazio — ver print) pra largura FIXA, só o
   suficiente pra um código de até uns 5 dígitos (mesmo raciocínio de
   Qtd/Unid., que já são colunas de largura fixa por terem conteúdo curto) —
   o espaço que sobrou foi redistribuído pra Produto (1.15fr->1.3fr) e
   Observação (.95fr->1.1fr), que se beneficiam mais de espaço extra.
   v2.29.20 (pedido do usuário): os 72px da v2.29.19 eram estreitos demais
   pro PRÓPRIO RÓTULO "Cod Interno" acima do campo (não pro conteúdo digitado
   — o rótulo é sempre maior que um código curto) — "COD INTERNO" quebrava em
   duas linhas. 92px é o suficiente pro rótulo (10px, caixa alta, negrito)
   caber numa linha só, do jeito que o usuário pediu ("deixe o tamanho do
   campo... com o tamanho do titulo"). */
.item-grid-single{ display:grid;grid-template-columns:54px .8fr 1.25fr 58px 68px 1.2fr 92px 1.05fr 40px;gap:10px;align-items:start; }
/* Correção (v2.26.6): faltava um tamanho explícito pro SVG do ícone dentro
   desse botão (.btn-icon, reaproveitado de outras telas) — sem isso, o
   navegador usa o tamanho padrão de um <svg> sem width/height (bem maior
   que o botão), o ícone fica cortado/invisível e o botão em si cresce,
   desalinhando a coluna da linha dos outros campos. Mesma ideia das outras
   regras "<contexto> .btn-icon svg{...}" já usadas no resto do app (ver
   td.actions, .panel-foot-left, etc. — este .btn-icon nunca tem um tamanho
   de ícone genérico, cada tela define o seu). */
.item-grid-single .item-field .btn-icon{ display:inline-flex;align-items:center;justify-content:center; }
.item-grid-single .item-field .btn-icon svg{ width:14px;height:14px;flex:none; }
/* Campo "Item" (v2.26.4) — numeração automática (01, 02...) de cada produto
   da requisição, sempre em primeiro lugar na linha, antes de Portfólio. Só
   de leitura (preenchido pelo índice da linha, não guardado em
   reqItemsState) — ver itemRowHtml() e pad2() em assets/frontend.js. */
.item-field input[disabled]{ background:var(--surface-2);color:var(--ink-faint);text-align:center;font-weight:700; }
/* min-width:0 é o que impede uma coluna do grid de crescer pra caber um
   conteúdo que não quebra linha (ver .marcas-select-text acima) — por
   padrão um item de grid tem min-width:auto (= largura do conteúdo), não 0. */
.item-grid-single .item-field{ min-width:0; }
@media (max-width:560px){
  .item-grid-top{ grid-template-columns:1fr 1fr; }
  .item-grid-bottom{ grid-template-columns:1fr; }
  .item-grid-single{ grid-template-columns:1fr 1fr; }
  .item-field.wide{ grid-column:1/-1; }
  /* No celular (grid de 2 colunas), o campo do botão de remover ocupa a
     linha inteira sozinho, alinhado à direita, em vez de dividir uma
     coluna estreita com outro campo. */
  .item-grid-single .item-field:last-child{ grid-column:1/-1;display:flex;justify-content:flex-end; }
}
/* white-space:nowrap (v2.29.20) — um rótulo de campo nunca deveria quebrar
   linha (ficava "COD" numa linha e "INTERNO" na linha de baixo quando a
   coluna era mais estreita que o texto, como aconteceu com "Cod Interno"
   na v2.29.19 — ver a largura da coluna logo abaixo, agora dimensionada
   pra caber exatamente esse rótulo sem quebrar). */
.item-field label{ font-size:10px;text-transform:uppercase;letter-spacing:.04em;color:var(--ink-faint);font-weight:700;margin-bottom:4px;display:block;white-space:nowrap; }
.item-field input,.item-field select{
  width:100%;padding:8px 9px;border-radius:7px;border:1px solid var(--border);
  background:var(--surface);font-size:12.8px;color:var(--ink);outline:none;
}
.item-field input:focus,.item-field select:focus{ border-color:var(--primary); }

/* ---------- chips de marcas ---------- */
/* v2.26.7 (pedido do usuário): o campo Marcas (.chip-box) ficava visivelmente
   mais alto que os outros campos da mesma linha (.item-field input/select,
   logo acima) — a causa era um padding DOBRADO: o próprio .chip-box já tinha
   6px de padding vertical, e o <input> de dentro (.chip-input) somava mais
   3px de padding vertical só dele. Correção: .chip-box passou a usar o
   MESMO padding (8px 9px) dos outros campos da linha, e .chip-input perdeu
   o padding vertical próprio (0, só 2px nas laterais) — com isso a conta
   fica idêntica à dos outros campos (padding + borda + linha de texto do
   mesmo tamanho de fonte), então a altura bate certinho sem precisar de um
   min-height "no olho" (o 36px antigo foi removido). Quando há marcas
   (chips) suficientes pra quebrar linha, a caixa ainda cresce normalmente
   — só a altura de UMA linha (o estado mais comum) é que agora é igual. */
.chip-box{
  display:flex;flex-wrap:wrap;gap:5px;align-items:center;padding:8px 9px;
  border:1px solid var(--border);border-radius:7px;background:var(--surface);
}
.chip-box:focus-within{ border-color:var(--primary); }
.marca-chip{
  display:inline-flex;align-items:center;gap:5px;padding:3px 6px 3px 9px;border-radius:999px;
  background:var(--primary-soft);color:var(--primary-strong);font-size:11.5px;font-weight:700;white-space:nowrap;
}
.marca-chip button{
  border:none;background:transparent;color:inherit;cursor:pointer;font-size:11px;line-height:1;
  padding:2px;display:flex;align-items:center;justify-content:center;opacity:.7;
}
.marca-chip button:hover{ opacity:1; }

/* Colunas "Marcas"/"Portfólio" da listagem de Fornecedores (FOR-01, v2.33.0
   tentou chips; v2.33.1, pedido do usuário, trocou pra "Opção A — texto
   curto + contador", mesmo mockup `for01-coluna-marcas-mockup.html`):
   mostra as 2 primeiras marcas/itens de portfólio por extenso, com um "+N"
   mais apagado no final cobrindo o resto da lista (tooltip nativo com os
   nomes restantes) — substitui o texto corrido cortado com "..."
   (.cell-truncate), que escondia a contagem e cortava nomes no meio. Ver
   listCurtoHtml() em assets/frontend.js. */
.marcas-curto{ color:var(--ink); }
.marcas-curto .contador{ color:var(--ink-faint);font-weight:600; }

.chip-input{
  flex:1;min-width:60px;border:none;outline:none;background:transparent;font-size:12.8px;
  color:var(--ink);padding:0 2px;
}

/* ---------- Autocomplete de Produto (catálogo) — v2.23.0 ----------
   Usado no campo "Produto" dos itens de Requisição e da Cotação avulsa (ver
   attachProdutoSuggestDropdown() em assets/frontend.js): dropdown posicionado
   sob o campo de texto, mesmo texto livre continua funcionando pra quem não
   encontrar o produto no catálogo. */
.produto-suggest-wrap{ position:relative; }
.produto-suggest-list{
  display:none;position:absolute;left:0;right:0;top:100%;margin-top:4px;z-index:30;
  background:var(--surface);border:1px solid var(--border);border-radius:8px;
  box-shadow:0 8px 24px rgba(0,0,0,.14);max-height:220px;overflow-y:auto;
}
.produto-suggest-list.open{ display:block; }
.produto-suggest-opt{ padding:7px 10px;font-size:12.5px;color:var(--ink);cursor:pointer; }
.produto-suggest-opt:hover{ background:var(--primary-soft); }
.produto-suggest-opt .muted{ color:var(--ink-faint);font-weight:400; }
.produto-linked-badge{
  position:absolute;right:8px;top:50%;transform:translateY(-50%);font-size:12px;
  pointer-events:none;
}
.field .produto-suggest-wrap input[type="text"]{ padding-right:26px; }
.item-field .produto-suggest-wrap input[type="text"]{ padding-right:24px; }
/* Trecho digitado destacado dentro de uma sugestão — usado pelo campo
   "Cod Interno" (ver attachCodigoInternoSuggestDropdown() em frontend.js),
   que busca por código OU descrição no mesmo catálogo do campo "Produto". */
.produto-suggest-opt mark{ background:var(--primary-soft);color:var(--primary-strong);border-radius:3px;padding:0 1px;font-weight:700; }
/* Lista de sugestões do "Cod Interno" (v2.29.21, pedido do usuário, mockup
   aprovado) — campo fechado continua estreito (só cabe um código curto),
   mas a LISTA que abre embaixo dele não pode acompanhar essa largura (a
   base ".produto-suggest-list" acima usa left:0;right:0, preso ao wrapper
   estreito) — uma descrição mais longa quebrava em várias linhas. Esta
   classe (só no wrapper do Cod Interno — ver itemRowHtml() em frontend.js;
   o campo "Produto" continua com o comportamento de sempre) tira a largura
   presa ao campo e deixa a lista crescer sozinha até caber a sugestão mais
   comprida INTEIRA, nunca cortando com "..." (sem overflow/ellipsis, só
   nowrap). Fica centralizada embaixo do campo (left:50% + translateX(-50%))
   pra crescer pros dois lados conforme o texto precisa — por cima da coluna
   Observação à direita e por cima da coluna Marcas à esquerda, exatamente
   como pedido ("a largura pode também expandir para o lado do campo
   marcas") — com um teto (max-width) só pra nunca estourar a tela numa
   janela estreita. */
.codigo-interno-suggest-wrap .produto-suggest-list{
  left:50%;right:auto;transform:translateX(-50%);
  width:max-content;max-width:min(620px, calc(100vw - 60px));
}
.codigo-interno-suggest-wrap .produto-suggest-opt{ white-space:nowrap; }
.produto-suggest-empty{ padding:10px 9px;font-size:12px;color:var(--ink-faint);text-align:center; }

/* ---------- Marcas: campo fechado com busca (v2.29.18, pedido do usuário) ----------
   Substituiu a caixa de chips (.chip-box acima, que cresce em altura
   conforme marcas vão sendo adicionadas e destoa da altura dos outros
   campos da linha). Agora o campo FECHADO tem a mesma altura/borda/fonte de
   um <input>/<select> normal e nunca cresce — ao clicar, abre um dropdown
   com busca (igual um autocompletar: digitar já filtra a lista) e uma
   linha "+ Adicionar" quando o texto não bate com nenhuma marca já
   cadastrada (state.vocabulario.marcas). Mockup aprovado pelo usuário antes
   desta implementação ("Mockup — campo Marcas"). */
.marcas-select-wrap{ position:relative;min-width:0; }
.marcas-select{
  width:100%;min-width:0;padding:8px 9px;border-radius:7px;border:1px solid var(--border);
  background:var(--surface);font-size:12.8px;color:var(--ink);cursor:pointer;user-select:none;
  display:flex;align-items:center;justify-content:space-between;gap:6px;
}
.marcas-select.placeholder .marcas-select-text{ color:var(--ink-faint); }
.marcas-select:hover{ border-color:#c4cbbd; }
.marcas-select.open{ border-color:var(--primary); }
/* min-width:0 no próprio item flex com o texto é o que realmente permite o
   ellipsis funcionar quando a lista de marcas selecionadas não cabe —
   sem isso o item cresce pra caber o texto inteiro (não quebra linha) e
   empurra a coluna do grid inteira, que é o efeito que o usuário reportou
   como bug na primeira versão do mockup ("a largura do campo marcas
   aumenta de acordo com a quantidade de marcas inseridas"). */
/* v2.29.21 (pedido do usuário): as marcas já escolhidas, mostradas no campo
   fechado (ex: "SKF, FAG +1"), não podem aparecer em negrito — era
   font-weight:600. */
.marcas-select-text{ min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:400; }
.marcas-select-chevron{ flex:none;color:var(--ink-faint);transition:transform .15s ease; }
.marcas-select.open .marcas-select-chevron{ transform:rotate(180deg); }
.marcas-dropdown{
  display:none;position:absolute;left:0;right:0;top:calc(100% + 4px);z-index:30;
  background:var(--surface);border:1px solid var(--border);border-radius:10px;
  box-shadow:0 10px 28px rgba(20,30,20,.16);overflow:hidden;
}
.marcas-dropdown.open{ display:block; }
/* Busca sempre no TOPO do dropdown, com foco automático ao abrir — digitar
   já filtra a lista abaixo, sem precisar clicar em outro campo separado
   (pedido do usuário: "é possivel fazer do tipo auto completar, quando
   começar a digitar ir aparecendo as sugestões?"). */
.marcas-dropdown-search{
  display:flex;align-items:center;gap:7px;padding:8px 10px;border-bottom:1px solid var(--border);
}
.marcas-dropdown-search svg{ flex:none;color:var(--ink-faint); }
.marcas-dropdown-search input{
  flex:1;min-width:0;border:none;outline:none;background:transparent;font-size:12.8px;
  color:var(--ink);font-family:inherit;
}
.marcas-dropdown-search input::placeholder{ color:var(--ink-faint); }
.marcas-dropdown-list{ max-height:192px;overflow-y:auto;padding:6px; }
.marcas-opt{
  display:flex;align-items:center;gap:9px;padding:7px 8px;border-radius:7px;cursor:pointer;font-size:12.5px;
}
.marcas-opt:hover{ background:var(--primary-soft); }
/* v2.29.19: tentativa de corrigir o checkbox desalinhado só resetando
   padding/borda/fundo vazados de ".item-field input" — não resolveu de vez
   (usuário reportou que continuava desalinhado). Causa de verdade: um
   checkbox NATIVO (appearance padrão do navegador) é um widget desenhado
   pelo sistema operacional, não uma caixa comum — `border`/`background`/
   `border-radius` do CSS simplesmente não têm efeito nele (por isso a v2.29.19
   não mudou nada visualmente), e cada navegador posiciona esse widget de um
   jeito ligeiramente diferente em relação à linha de texto ao lado, mesmo
   com align-items:center no flex pai. v2.29.20: `appearance:none` tira o
   desenho nativo e transforma o checkbox numa caixa comum, 100% controlada
   por este CSS — a partir daí o align-items:center do .marcas-opt (flex)
   garante o alinhamento de verdade, sem depender de como cada navegador
   desenha o widget nativo. O "✓" marcado é desenhado à mão com ::after
   (borda em L rotacionada 45°, truque clássico de checkmark em CSS puro). */
.marcas-opt input[type="checkbox"]{
  -webkit-appearance:none;appearance:none;-moz-appearance:none;
  width:14px;height:14px;flex:none;padding:0;margin:0;
  border:1.5px solid var(--border);border-radius:4px;background:var(--surface);
  display:inline-block;position:relative;cursor:pointer;
}
.marcas-opt input[type="checkbox"]:checked{ background:var(--primary);border-color:var(--primary); }
.marcas-opt input[type="checkbox"]:checked::after{
  content:"";position:absolute;left:4px;top:1px;width:3px;height:7px;
  border:solid var(--primary-ink);border-width:0 1.6px 1.6px 0;transform:rotate(45deg);
}
/* Nome da marca sem negrito (pedido do usuário) — era font-weight:600. */
.marcas-opt span{ font-weight:400; }
.marcas-opt span mark{ background:var(--primary-soft);color:var(--primary-strong);border-radius:3px;padding:0 1px; }
/* Linha "+ Adicionar 'X'" — só aparece quando o texto digitado não bate com
   nenhuma marca já cadastrada; sempre a primeira linha da lista filtrada. */
.marcas-opt-nova{
  display:flex;align-items:center;gap:8px;padding:7px 8px;border-radius:7px;cursor:pointer;
  font-size:12.5px;font-weight:700;color:var(--primary-strong);
}
.marcas-opt-nova:hover{ background:var(--primary-soft); }
.marcas-opt-nova svg{ flex:none; }
.marcas-dropdown-empty{ padding:14px 10px;text-align:center;font-size:12px;color:var(--ink-faint); }

/* ---------- Cotações: nova cotação a partir de requisição (comparação de preços por fábrica) ----------
   v2.17.0: as cotações já recebidas (antes cartões soltos, `.cotacao-existing-row`)
   e a linha de preencher uma cotação nova (antes uma grade própria,
   `.cotacao-row-grid`) passaram a ser exibidas como uma única tabela — mesmas
   12 colunas nos dois casos (Fábrica, Ref. Fábrica, Marca, Qtd, Vlt. Unit.,
   IPI, PIS/COF, Frete, Preço Final, Prazo, Comparativo, Ver Cotação/ação),
   pedido do usuário depois de ver o mockup aprovado. Altura de linha, divisória
   entre colunas e badge/botão compactos seguem o mesmo padrão de 18px já usado
   em todas as tabelas do sistema desde a v2.8.1/v2.8.2 (ver `tbody .avatar`,
   `tbody .badge`, `td.actions .btn-icon` acima). Como 12 colunas não cabem numa
   tela estreita, o grid tem uma largura mínima e o wrapper
   `.cotacao-table-scroll` rola horizontalmente em vez de espremer os campos —
   mesmo princípio já usado nas tabelas do sistema (largura em vez de quebrar).
   Larguras diferentes por coluna: mais espaço pra texto livre (Fábrica), menos
   pra valores curtos (Qtd, IPI, Frete).
   v2.20.0: acrescentada a 13ª coluna "Status" (à esquerda de tudo, ver
   COT_STATUS_FABRICA_ORDER em frontend.js) — status da resposta de cada
   fábrica cotada, que trava/destrava as colunas de resposta da linha
   (`.is-locked`, ver `.cotacao-table-row.is-locked` abaixo).
   v2.37.6 (pedido do usuário): a coluna "Comparativo" (1fr, penúltima faixa
   antes da ação) saiu — essa comparação passa a viver numa tela própria (ver
   cotTableHeadHtml() em frontend.js). min-width recalculada na mesma proporção
   fr usada desde a v2.37.1 (1480px → 1344px).
   v2.37.9 (pedido do usuário): a última faixa (ação — "Ver Cotação" até a
   v2.37.8, hoje só o ícone de remover linha nas cotações NOVAS) encolheu de
   110px pra 40px — tinha sido dimensionada pro botão "Ver Cotação" (texto
   largo), que já não existe mais aqui; 40px é só o suficiente pro ícone de
   16px (ver .btn-icon.danger abaixo). min-width caiu junto, -70px (1344px →
   1274px). */
.cotacao-none-yet{ margin:0 0 10px;font-size:12px;color:var(--ink-faint);font-style:italic; }
.cotacao-table-scroll{ overflow-x:auto; }
/* v2.37.10 (pedido do usuário, mockup "cot-status-icones-mockup.html"
   aprovado): 1ª faixa (Status) de 90px pra 42px — o <select> com o nome do
   status escrito por extenso virou um ícone (ver .status-ic-wrap/
   cotStatusIconHtml() em frontend.js), que só precisa de ~22px + um
   respiro pequeno. Diferente das outras colunas de texto livre da tabela
   (não encolhidas nesta rodada — ver nota mais abaixo, antes de
   ".cot-cell"), nenhum dado é cortado aqui: o nome completo do status
   continua existindo no title (tooltip) e nas opções do próprio <select>,
   só parou de ficar escrito na célula. min-width caiu junto (-48px). */
/* v2.37.11 (pedido do usuário, mockup "cot-forn-bug-qtd-mockup.html"
   aprovado): a faixa única "Qtd" (0.4fr) virou duas — "Qtd Solic."
   (0.4fr, igual era antes) + "Qtd Disp." (0.4fr nova) — ver
   cotTableHeadHtml() em frontend.js. min-width recalculada na mesma
   proporção fr usada desde a v2.37.1 (1226px → 1284px). A última faixa
   (ação, 40px) não muda nesta visão (Por Produto) — continua existindo
   normalmente, só deixou de existir na grade .has-marcas abaixo (Por
   Fornecedor). */
/* v2.40.0 (pedido do usuário, mockup "anexo-cotacao-mockup.html" aprovado):
   +1 faixa (36px, "Anexo" — botão de clipe, ver cotAnexoCellHtml() em
   frontend.js), inserida antes da faixa de ação (40px) — min-width subiu
   junto (1284px → 1320px). Mesma faixa adicionada na grade .has-marcas
   abaixo, só que no final (lá não existe faixa de ação). */
.cotacao-table-head,.cotacao-table-row{
  display:grid;grid-template-columns:42px 1.6fr 1fr 0.85fr 0.4fr 0.4fr 0.65fr 0.65fr 0.75fr 0.95fr 0.75fr 0.8fr 36px 40px;
  gap:8px;min-width:1320px;
}
/* v2.35.1 — visão "Por Fornecedor" ganhou uma 14ª coluna, "Marcas" (as
   marcas pedidas pelo cliente), então essas linhas precisam de uma grade
   própria com uma coluna a mais — ver o comentário em cotTableHeadHtml()
   (assets/frontend.js) pra quando a classe "has-marcas" é aplicada.
   "Produto" encolheu um pouco (1.6fr → 1.3fr) pra abrir espaço sem alargar
   demais a tabela inteira.
   v2.35.2: ordem das colunas trocada — "Marcas" passou de antes pra depois
   de "Produto" (pedido do usuário), então a 2ª coluna da grade agora é a
   largura de "Produto" (1.3fr) e a 3ª é a de "Marcas" (0.9fr) — só a ORDEM
   das larguras mudou, os valores em si continuam os mesmos.
   v2.37.1 (pedido do usuário, depois de testar o rateio de frete ao vivo):
   "IPI"/"PIS/COF" alargadas (0.45fr/0.6fr → 0.65fr/0.75fr) pra caber o
   valor completo (ex: "15.25") sem cortar, "Vlt. Unit."/"Preço Final"
   encolhidas (0.85fr/0.95fr → 0.65fr/0.75fr) pra abrir espaço sem alargar
   a tabela toda, e "Frete" alargada (0.55fr → 0.95fr) pra caber o checkbox
   de rateio (v2.37.0) + o valor junto sem cortar — min-width subiu junto
   (+30px/+40px) pra não espremer demais em telas estreitas.
   v2.37.6 (pedido do usuário): mesma remoção da coluna "Comparativo" (1fr)
   que a grade base, acima — min-width recalculada na mesma proporção
   (1600px → 1460px).
   v2.37.9: mesma redução da última faixa (110px → 40px) que a grade base,
   acima — min-width recalculada junto (1460px → 1390px).
   v2.37.10: mesma redução da 1ª faixa (Status: 90px → 42px) que a grade
   base, acima — min-width recalculada junto (1390px → 1342px).
   v2.37.11 (pedido do usuário, mockup "cot-forn-bug-qtd-mockup.html"
   aprovado): duas mudanças juntas, só nesta grade (visão "Por
   Fornecedor"): (1) mesmo split de "Qtd" em "Qtd Solic."+"Qtd Disp." (+1
   faixa, 0.4fr) que a grade base, acima; (2) a última faixa (ação, 40px)
   foi REMOVIDA de vez — nesta visão ela já não tinha mais nenhum conteúdo
   em nenhum estado de linha (nem o ícone de remover linha das novas, nem
   o botão "Ver Cotação" das existentes, que já tinham saído daqui em
   rodadas anteriores — ver cotEditableRowHtml()/cotExistingRowHtml()/
   cotExistingEditavelRowHtml() em frontend.js), então a faixa em si virou
   peso morto. min-width recalculada com as duas mudanças juntas
   (1342px → 1354px). */
/* v2.40.0: mesma faixa "Anexo" (36px) acrescentada acima, aqui no final
   (visão "Por Fornecedor" não tem faixa de ação) — min-width recalculada
   junto (1354px → 1390px). */
.cotacao-table-head.has-marcas,.cotacao-table-row.has-marcas{
  grid-template-columns:42px 1.3fr 0.9fr 1fr 0.85fr 0.4fr 0.4fr 0.65fr 0.65fr 0.75fr 0.95fr 0.75fr 0.8fr 36px;
  min-width:1390px;
}
.cotacao-table-head{ padding:6px 2px;margin-bottom:2px;border-bottom:1px solid var(--border); }
.cotacao-table-head span{ font-size:10px;text-transform:uppercase;letter-spacing:.04em;color:var(--ink-faint);font-weight:700; }
.cotacao-table-row{
  align-items:center;padding:1px 2px;border-bottom:1px solid var(--border);
}
.cotacao-table-row:last-child{ border-bottom:none; }
/* v2.37.6: .is-vencedora (selo "Vencedora" desta tabela) foi removida — o
   JS parou de aplicar essa classe aqui (ver cotExistingRowHtml() em
   frontend.js); a comparação agora vive só na tela de Requisição, que usa a
   classe separada .cotacao-compare-item-row.is-vencedora (mais abaixo), não
   tocada por esta mudança.
   Linha travada (status é "Comprado" — ver cotExistingRowHtml()/
   cotExistingRowDispatchHtml() em frontend.js): colunas de resposta mostram
   o que tiver salvo, com "—" só quando o campo em si está vazio. O select de
   status em si NÃO fica apagado — é ele que segue ativo pra o usuário poder
   avançar o status. */
.cotacao-table-row.is-locked .cot-cell:not(:first-child){ color:var(--ink-faint); }
/* Divisória vertical fina entre colunas (pedido do usuário), numa cor discreta
   que não compete com a linha horizontal entre registros.
   v2.37.10 (pedido do usuário: "veja se consegue diminuir a largura de
   alguma coluna para sem perda ou corte de dados"): junto com a coluna
   Status (acima), revisei as outras colunas pra ver se alguma tinha
   gordura pra cortar. Decidi NÃO encolher nenhuma outra, porque esta regra
   corta com reticências (overflow:hidden + text-overflow:ellipsis) o que
   não couber — ou seja, qualquer coluna que hoje já usa sua largura cheia
   passaria a cortar dado de verdade, exatamente o que foi pedido pra
   evitar: Ref. Fábrica/Marca/Prazo são texto livre digitado pela fábrica
   ou pelo usuário, sem tamanho máximo, e nem têm um title de reserva pra
   consultar o valor cortado na linha travada (Comprado); Qtd já é a faixa
   mais estreita da grade (0.4fr); e Vlt. Unit./IPI/PIS COF/Frete/Preço
   Final foram alargadas de propósito na v2.37.1, depois de um corte real
   relatado pelo usuário ("15.25" aparecendo cortado) — encolher de novo
   reabriria o mesmo problema. A coluna Status pôde encolher porque é
   diferente: um <select> de 5 opções fixas, não texto livre — o nome
   completo nunca desaparece, só passou a morar no title/nas options em vez
   de ficar escrito na célula (ver cotStatusIconHtml() em frontend.js). */
.cot-cell{
  font-size:12.5px;line-height:16px;color:var(--ink);white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis;border-right:1px solid var(--border);padding-right:8px;
}
.cot-cell:last-child{ border-right:none;padding-right:0; }
.cot-cell-strong{ font-weight:700;color:var(--ink); }
/* v2.37.11 (pedido do usuário, mockup aprovado): estilo da célula "Qtd
   Solic." nas linhas ainda abertas pra edição (novas ou existentes com
   status diferente de "Comprado") — mesmo tom apagado que
   ".is-locked .cot-cell:not(:first-child)" já usa pra travado, aplicado
   aqui direto porque a linha em si não está travada (as outras células
   continuam no tom normal); sinaliza visualmente "só leitura" sem
   precisar de um ícone de cadeado por célula. */
.cot-cell-readonly{ color:var(--ink-faint); }
.cot-cell-end{ display:flex;justify-content:flex-end;overflow:visible; }
/* Badge (Mais barata/Vencedora) e botão "Ver Cotação" no tamanho compacto já
   usado dentro de qualquer tabela do sistema — mesmos números de
   `tbody .badge`/`td.actions .btn-icon` acima. */
.cot-cell .badge{ padding:1px 7px;font-size:10px; }
/* v2.37.10 (pedido do usuário, mockup "cot-status-icones-mockup.html"
   aprovado): Status da Fábrica deixou de ser um <select> com o nome escrito
   por extenso (precisava de 90px pra caber "SEM RESPOSTA" sem cortar) e
   virou um ícone colorido (reaproveita as cores `.badge-st-*` já
   existentes, ver COT_STATUS_FABRICA_TONE/COT_STATUS_FABRICA_ICON em
   frontend.js) com o nome completo só no title (tooltip). O <select> de
   verdade continua ali, do mesmo tamanho do ícone, só que invisível por
   cima dele (.status-ic-select) — clicar continua abrindo as 5 opções
   escritas por extenso, então fica de fora das regras genéricas de
   `select`/`input` da linha editável logo abaixo
   (`:not(.status-ic-select)`), que dariam a ele a aparência de campo de
   formulário (borda, fundo) em vez de ficar transparente. */
.status-ic-wrap{ position:relative; width:22px; height:22px; flex:none; }
.status-ic-btn{
  width:22px; height:22px; border-radius:7px; display:flex; align-items:center; justify-content:center;
  pointer-events:none;
}
.status-ic-btn svg{ width:13px; height:13px; }
.status-ic-select{
  position:absolute; inset:0; width:100%; height:100%; opacity:0; border:none; margin:0; padding:0;
  cursor:pointer; -webkit-appearance:none; appearance:none;
}
.cotacao-table-row .btn.btn-ghost.btn-sm{
  height:18px;padding:0 10px;font-size:10.5px;border-radius:9px;
  display:inline-flex;align-items:center;
}
.cotacao-table-row .btn-icon.danger{
  width:16px;height:16px;padding:1px;border-radius:5px;box-sizing:border-box;
  display:inline-flex;align-items:center;justify-content:center;
}
/* Anexo de comprovante na Cotação (v2.40.0, pedido do usuário, mockup
   "anexo-cotacao-mockup.html" aprovado): botão de clipe por linha — cinza
   (.badge-st-gray) sem comprovante, verde (.badge-st-green) com uma
   bolinha quando já tem um anexado. Mesmo tamanho/posicionamento do
   .status-ic-btn acima, mas sem o <select> transparente por cima (este é
   um <button> de verdade, ver abrirCotAnexoModal() em frontend.js). */
.cot-cell-anexo{ display:flex; align-items:center; justify-content:center; }
.anexo-btn{
  position:relative; width:22px; height:22px; border-radius:7px; border:none; cursor:pointer;
  display:flex; align-items:center; justify-content:center; padding:0;
}
.anexo-btn svg{ width:13px; height:13px; }
.anexo-dot{
  position:absolute; top:1px; right:1px; width:6px; height:6px; border-radius:50%;
  background:var(--success); border:1.5px solid var(--surface);
}
.cotacao-table-row .btn-icon.danger svg{ width:12px;height:12px;flex:none; }
/* Linha editável (preencher uma cotação nova): campos digitados à mão (ou
   calculados) encolhidos pra caber perto da altura de linha da tabela — um
   pouco mais alto que as outras colunas (pedido do usuário, v2.20.1), pra
   não ficar desproporcional ao lado dos campos maiores das outras colunas. */
.cotacao-table-row.is-editable .cot-cell select:not(.status-ic-select),
.cotacao-table-row.is-editable .cot-cell > input{
  width:100%;height:22px;padding:0 6px;border-radius:5px;border:1px solid var(--border);
  background:var(--surface);font-size:11.5px;color:var(--ink);outline:none;box-sizing:border-box;
}
.cotacao-table-row.is-editable .cot-cell select:not(.status-ic-select):focus,
.cotacao-table-row.is-editable .cot-cell > input:focus{ border-color:var(--primary); }
.cotacao-table-row.is-editable .currency-input,
.cotacao-table-row.is-editable .percent-input{
  height:22px;background:var(--surface);border-radius:5px;
}
/* v2.37.1: .percent-input (IPI / PIS-COF) nunca teve display:flex, diferente
   do .currency-input (que tem a regra global em .currency-input, linha ~738).
   Sem flex, o <input> interno assume a largura padrão do navegador (~155px),
   maior que o próprio container, e o excesso é cortado silenciosamente pelo
   overflow:hidden do .cot-cell pai — por isso "7.8" aparecia como "7.".
   flex:1 + min-width:0 faz o input respeitar a largura real da coluna. */
.cotacao-table-row.is-editable .percent-input{ display:flex; align-items:center; }
.cotacao-table-row.is-editable .currency-input input,
.cotacao-table-row.is-editable .percent-input input{ font-size:11.5px;padding:0 4px; }
.cotacao-table-row.is-editable .percent-input input{ flex:1; min-width:0; }
.cotacao-table-row.is-editable .currency-input span,
.cotacao-table-row.is-editable .percent-input span{ font-size:11px; }
/* Preço Final é calculado, não digitado — visual levemente diferente (fundo
   cinza, texto em negrito) deixa claro que não é pra editar ali. */
.cotacao-table-row.is-editable .currency-input.is-readonly{ background:var(--surface-2); }
.cotacao-table-row.is-editable .currency-input.is-readonly input{ font-weight:700;color:var(--ink);cursor:default; }
.cotacao-add-row-btn{ margin-top:8px; }
@media (max-width:640px){
  .cotacao-table-head{ display:none; }
  .cotacao-table-row{ grid-template-columns:1fr 1fr;min-width:0; }
  /* v2.35.1: sem isto, a regra ".has-marcas" (mais específica, 2 classes)
     ganharia da regra genérica acima mesmo aqui dentro — ver o comentário
     perto de ".cotacao-table-head.has-marcas" (fora da media query). */
  .cotacao-table-row.has-marcas{ grid-template-columns:1fr 1fr;min-width:0; }
  .cot-cell{ border-right:none;white-space:normal; }
  .cotacao-table-scroll{ overflow-x:visible; }
}

/* ---------- COT-02: alternância "Por Produto" / "Por Fornecedor" (v2.35.0) ----------
   Pedido do usuário, mockup aprovado "cot02-dois-layouts-mockup.html" —
   mesmas dimensões do mockup. */
.mode-toggle-wrap{ margin:4px 0 18px; }
.mode-toggle{
  display:inline-flex; background:var(--surface-2); border:1px solid var(--border);
  border-radius:10px; padding:4px; gap:4px;
}
.mode-btn{
  border:none; background:transparent; padding:9px 16px; border-radius:7px;
  font-family:inherit; font-weight:600; font-size:13px; color:var(--ink-soft); cursor:pointer;
}
.mode-btn.active{ background:var(--primary); color:var(--primary-ink); }
.mode-hint{ margin:10px 2px 0; font-size:12.5px; color:var(--ink-faint); }

/* ---------- COT-02: faixa de resumo de status (v2.37.5) ----------
   Pedido do usuário, mockup aprovado "cot02-resumo-status-fornecedor-mockup.html"
   — só aparece no topo da visão "Por Fornecedor" (ver cotStatusSummaryHtml()
   em frontend.js), logo abaixo do alternador Por Produto/Por Fornecedor.
   Reaproveita as mesmas 4 cores de status já usadas nos badges/pontinhos da
   tabela (--st-yellow/--st-gray/--st-green/--st-purple, ver :root) — "Sem
   Resposta" e "Não Tem" compartilham a cor cinza, igual ao badge, só o texto
   do chip muda. */
.status-summary{
  display:flex; align-items:center; gap:10px; flex-wrap:wrap;
  margin:0 0 16px; padding:10px 14px; border:1px solid var(--border);
  border-radius:10px; background:var(--surface-2);
}
.ss-label{ font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:.03em; color:var(--ink-soft); white-space:nowrap; }
.ss-chip{
  display:inline-flex; align-items:center; gap:6px; padding:5px 10px;
  border-radius:999px; font-size:12.5px; font-weight:600; white-space:nowrap;
}
.ss-chip .dot{ width:7px; height:7px; border-radius:50%; flex:none; }
.ss-chip b{ font-weight:700; }
.ss-chip.is-zero{ opacity:.5; }
.ss-chip.st-aguardando{ background:var(--st-yellow-soft); color:var(--st-yellow); }
.ss-chip.st-aguardando .dot{ background:var(--st-yellow-dot); }
.ss-chip.st-semresposta,
.ss-chip.st-naotem{ background:var(--st-gray-soft); color:var(--st-gray); }
.ss-chip.st-semresposta .dot,
.ss-chip.st-naotem .dot{ background:var(--st-gray-dot); }
.ss-chip.st-cotado{ background:var(--st-green-soft); color:var(--st-green); }
.ss-chip.st-cotado .dot{ background:var(--st-green-dot); }
.ss-chip.st-comprado{ background:var(--st-purple-soft); color:var(--st-purple); }
.ss-chip.st-comprado .dot{ background:var(--st-purple-dot); }
.ss-total{ margin-left:auto; font-size:12px; color:var(--ink-faint); white-space:nowrap; }
@media (max-width:720px){
  .ss-total{ margin-left:0; width:100%; }
}

/* Bloco de fornecedor (visão Por Fornecedor) — mesma moldura de ".item-card"
   (visão Por Produto), com uma faixa de cabeçalho destacada (igual ao
   mockup) pro campo "Fábrica", já que ali ele vale pra TODAS as linhas do
   bloco, não só uma. */
.forn-group{ border:1px solid var(--border); border-radius:12px; margin-bottom:10px; overflow:hidden; }
.forn-group-head{
  padding:12px 14px; background:var(--primary-soft); border-bottom:1px solid var(--border);
  display:flex; align-items:center; gap:12px; flex-wrap:wrap;
}
.forn-group-head .fl{ font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:.03em; color:var(--primary-strong); white-space:nowrap; }
.forn-group-head .produto-suggest-wrap{ min-width:260px; }
.forn-group-head input[type="text"]{
  border:1px solid var(--primary); border-radius:7px; padding:8px 10px; font-size:13px;
  font-weight:600; width:100%; font-family:inherit; background:var(--surface); color:var(--ink);
  box-sizing:border-box;
}
.forn-group-head .btn{ margin-left:auto; }
.forn-group .cotacao-table-scroll{ padding:10px 14px 14px; }

/* v2.37.6 (pedido do usuário, mockup "cot02-fabrica-travada-sem-
   comparativo-mockup.html" aprovado): bloco cujo nome de fábrica já tem
   cotação salva (ver cotFornecedorGroupHtml() em frontend.js) — o cabeçalho
   fica mais baixo (sem o <input>, só o nome + cadeado) e o botão "Remover
   fornecedor" continua do mesmo jeito, só sem o "margin-left:auto" sobrando
   de um <input> que não existe mais nesse estado (padding reduzido já
   resolve o alinhamento). */
.forn-group-head.is-locked{ padding:8px 14px; }
.forn-group-head .fabrica-locked{
  display:inline-flex; align-items:center; gap:6px; font-size:13px; font-weight:700; color:var(--ink);
}
.forn-group-head .fabrica-locked svg{ width:13px; height:13px; flex:none; color:var(--primary-strong); }

/* v2.37.9 (pedido do usuário, mockup "cot02-coluna-estreita-logo-fabrica-
   mockup.html" aprovado): logo da fábrica antes do nome, nos dois estados do
   cabeçalho do bloco (ver cotFabricaLogoHtml()/cotFornecedorGroupHtml() em
   frontend.js). No estado editável, .fabrica-field agrupa a logo e o campo de
   texto (.produto-suggest-wrap já tinha min-width:260px — segue valendo, só
   ficou aninhado um nível mais dentro). .fabrica-logo é a versão compacta do
   padrão já usado em avatarHtml() (34px em Fornecedores/Produtos, 14px em
   tabela) — aqui 22px, do tamanho certo pro cabeçalho reduzido do bloco. */
.forn-group-head .fabrica-field{ display:flex; align-items:center; gap:8px; flex:1; min-width:0; }
.forn-group-head .fabrica-locked{ gap:7px; }
.fabrica-logo{
  width:22px; height:22px; border-radius:6px; flex:none; object-fit:cover;
  background:var(--surface); color:var(--primary-strong); border:1px solid var(--border);
  display:flex; align-items:center; justify-content:center; font-weight:800; font-size:9px;
}

/* v2.43.0 — autocompletar com logo do campo "Nome da fábrica" ao cadastrar
   fábrica nova em Preços de Fábrica/Carteira e Pendências (pedido do
   usuário, mockup aprovado "prf01-logo-autocomplete-mockup.html"; ver
   attachFabricaNovaSuggestDropdown()/fabricaNovaMatchNoteHtml() em
   frontend.js). .fabrica-nova-suggest-opt só acrescenta o layout em flex
   (com o .fabrica-logo de 22px ao lado do nome) por cima da classe base
   .produto-suggest-opt, que já traz padding/cor/cursor. */
.fabrica-nova-suggest-opt{ display:flex; align-items:center; gap:8px; }
.fabrica-nova-match{
  display:flex; align-items:center; gap:8px; margin-top:6px; padding:7px 10px;
  border-radius:9px; font-size:11.5px; line-height:1.5;
}
.fabrica-nova-match.found{ background:var(--success-soft); color:var(--success); }
.fabrica-nova-match.found b{ color:var(--ink); font-weight:700; }
.fabrica-nova-match.notfound{ background:var(--surface-2); color:var(--ink-soft); border:1px solid var(--border); }

/* ---------- COT-02: rateio de frete entre produtos da mesma fábrica (v2.37.0) ----------
   Pedido do usuário, mockup aprovado "cot-frete-rateio-mockup.html" — checkbox
   de rateio na célula de Frete de cada linha (visão Por Fornecedor) e, quando
   algum produto da fábrica está marcado, a calculadora abaixo da tabela do
   bloco (ver cotFreteCalcHtml() em frontend.js). */
/* v2.37.1: overflow:visible quebrava a otimização de "tamanho mínimo automático
   = 0" do CSS Grid (ver spec de Grid). Como .cotacao-table-head e
   .cotacao-table-row são grids independentes que só compartilham as mesmas
   proporções de coluna, o conteúdo desta célula (checkbox + valor) forçava a
   trilha do Frete a crescer só nas linhas, nunca no cabeçalho — por isso as
   colunas desalinhavam a partir do Frete para a direita. overflow:hidden
   restaura o comportamento padrão de todas as outras .cot-cell. */
.cot-cell-frete{ display:flex; align-items:center; gap:4px; overflow:hidden; min-width:0; }
.cot-cell-frete .currency-input{ flex:1; min-width:0; }
.frete-rateio-toggle{ display:flex; align-items:center; flex:none; cursor:pointer; }
.frete-rateio-toggle input[type="checkbox"]{ width:14px; height:14px; margin:0; cursor:pointer; accent-color:var(--accent); }
/* Linha marcada: leve destaque laranja, igual ao tom do badge "frete
   rateado" (cot-cell-strong fica preservado por especificidade). */
.cotacao-table-row.is-rateio{ background:var(--accent-soft); }
.cotacao-table-row.is-rateio .cot-cell{ background:transparent; }

.frete-calc{
  margin-top:0; border-top:2px dashed var(--border); background:var(--surface-2);
  padding:12px 14px 14px;
}
.frete-calc-head{ display:flex; align-items:center; gap:8px; margin-bottom:10px; }
.frete-calc-head svg{ width:15px; height:15px; color:var(--accent); flex:none; }
.frete-calc-head .t{ font-weight:700; font-size:12.5px; color:var(--ink); }
.frete-calc-grid{ display:grid; grid-template-columns:repeat(4,minmax(120px,1fr)); gap:10px; align-items:end; }
.fc-field label{
  display:block; font-size:10px; font-weight:700; color:var(--ink-soft); text-transform:uppercase;
  letter-spacing:.03em; margin-bottom:4px;
}
.fc-field .currency-input{ height:32px; background:var(--surface); border-radius:7px; border:1px solid var(--border); }
.fc-field .currency-input input{ font-size:13px; }
.fc-field.readout .val{
  border:1px solid var(--border); border-radius:7px; padding:7px 10px; font-size:13px;
  font-family:'IBM Plex Mono',ui-monospace,monospace; background:var(--primary-soft); color:var(--primary-strong);
  font-weight:700; box-sizing:border-box;
}
.fc-field.readout.total .val{ background:var(--accent-soft); color:var(--accent); }
.fc-note{ font-size:11px; color:var(--ink-faint); margin:10px 2px 0; line-height:1.5; }
@media (max-width:640px){
  .frete-calc-grid{ grid-template-columns:1fr 1fr; }
}

/* Lista de produtos ad-hoc da cotação avulsa (sem requisição) — mesmas
   dimensões de campo já usadas no resto do formulário. */
.avulsa-itens-manager{ margin-bottom:18px; }
.field-label{ font-size:11.5px; font-weight:700; color:var(--ink-soft); display:block; margin-bottom:8px; }
.avulsa-item-row{
  display:grid; grid-template-columns:1fr 100px 90px 32px; gap:8px; align-items:center; margin-bottom:8px;
}
.avulsa-item-row input[type="text"],
.avulsa-item-row input[type="number"],
.avulsa-item-row select{
  width:100%; height:32px; padding:0 10px; border-radius:7px; border:1px solid var(--border);
  background:var(--surface); font-size:12.5px; color:var(--ink); box-sizing:border-box;
}
@media (max-width:640px){
  .avulsa-item-row{ grid-template-columns:1fr 1fr; }
  .avulsa-item-row .produto-suggest-wrap{ grid-column:1 / -1; }
}

/* ---------- Requisição: comparação de cotações recebidas + escolha da vencedora ---------- */
.cotacao-compare-card{ border:1px solid var(--border);border-radius:12px;background:var(--surface-2);padding:14px;margin-bottom:10px; }
.cotacao-compare-item-row{
  display:flex;align-items:center;justify-content:space-between;gap:10px;padding:10px 12px;
  border-radius:8px;border:1px solid var(--border);background:var(--surface);margin-bottom:6px;
}
.cotacao-compare-item-row:last-child{ margin-bottom:0; }
.cotacao-compare-item-row.is-vencedora{ border-color:var(--success);background:var(--success-soft); }
.cotacao-compare-info{ display:flex;flex-direction:column;gap:2px; }
.cotacao-compare-info .fornecedor{ font-weight:700;font-size:13px;color:var(--ink); }
.cotacao-compare-info .detalhes{ font-size:11.5px;color:var(--ink-faint); }
.cotacao-compare-actions{ display:flex;align-items:center;gap:8px;flex:none; }
.cotacao-progress{
  display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 14px;
  border-radius:10px;background:var(--surface-2);border:1px solid var(--border);margin-top:16px;flex-wrap:wrap;
}
.cotacao-progress-label{ font-size:12.5px;color:var(--ink-soft);font-weight:600; }

/* v2.38.0 (pedido do usuário, mockups "cot-comparativo-matriz-mockup.html"
   aprovados em várias rodadas): botão genérico "link" — texto colorido, sem
   fundo nem borda — usado no "‹ Voltar ao comparativo" da nova tela
   "Calcular Preços de Venda da Requisição" (REQ-05). Modificador de .btn,
   igual a .btn-ghost/.btn-soft/.btn-danger acima, só que nunca existiu até
   agora porque nenhuma tela anterior precisou de um botão sem moldura. */
.btn-link{ background:transparent;color:var(--ink-soft);padding:9px 2px; }
.btn-link:hover{ color:var(--primary);text-decoration:underline;filter:none; }
.btn-link.btn-sm{ padding:6px 2px; }

/* ---------- Requisição: alternância Lista/Comparativo + matriz de cotações (v2.38.0) ----------
   Pedido do usuário, mockup "cot-comparativo-matriz-mockup.html" aprovado em
   várias rodadas (v4/v5) — ver cotacoesMatrixHtml()/cotComparativoVisao em
   frontend.js. Classes prefixadas "cotmx-" pra não colidir com nada do COT-01/
   COT-02 (.cel/.matrix/.tabs/.tab-btn/.badge já existem com outro significado
   nesses módulos). Reaproveita as variáveis de cor já existentes no :root
   (--success/--success-soft/--warn/--primary/--border/--surface/--surface-2/
   --ink/--ink-soft/--ink-faint), já com suporte a dark mode. */
.cotmx-tabs{ display:flex;gap:6px;margin-bottom:14px; }
.cotmx-tab-btn{
  font-size:12px;font-weight:700;padding:7px 14px;border-radius:8px;border:1px solid var(--border);
  background:var(--surface);color:var(--ink-soft);cursor:pointer;font-family:inherit;
}
.cotmx-tab-btn:hover{ background:var(--surface-2);color:var(--ink); }
.cotmx-tab-btn.active{ background:var(--primary);color:var(--primary-ink);border-color:var(--primary); }
.cotmx-tab-btn.active:hover{ background:var(--primary);color:var(--primary-ink); }

.cotmx-grid{ display:grid;gap:10px;margin-bottom:4px; }

.cotmx-produto-card{ background:transparent;padding:10px 2px;display:flex;flex-direction:column;justify-content:center;min-width:0; }
.cotmx-pnome{ font-weight:700;font-size:12.5px;color:var(--ink);line-height:1.3; }
.cotmx-pmarca{ font-size:10.5px;color:var(--ink-soft);margin-top:3px; }
.cotmx-pmarca b{ color:var(--ink);font-weight:600; }
.cotmx-pqtd{ font-size:10.5px;color:var(--ink-faint);margin-top:2px; }
.cotmx-split{ font-size:10.5px;margin-top:6px;font-weight:700; }
.cotmx-split.ok{ color:var(--success); }
.cotmx-split.bad{ color:var(--warn); }

.cotmx-cel{
  background:var(--surface);border:1px solid var(--border);border-radius:10px;padding:10px 12px;
  cursor:pointer;transition:border-color .12s ease,background .12s ease;display:flex;flex-direction:column;
  gap:3px;min-width:0;
}
.cotmx-cel:hover:not(.vazia):not(.filler){ border-color:var(--primary); }
.cotmx-forn{ font-size:11.5px;font-weight:700;color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis; }
.cotmx-nomeprod{ font-size:11px;color:var(--ink-soft);line-height:1.3; }
.cotmx-marca{ font-size:10.5px;color:var(--ink-faint); }
.cotmx-marca b{ color:var(--ink-soft);font-weight:600; }
.cotmx-preco{ font-size:15px;font-weight:800;color:var(--ink);line-height:1.25;margin-top:2px; }
.cotmx-meta{ font-size:10.5px;color:var(--ink-faint); }
.cotmx-flag{ font-size:10px;font-weight:700;color:var(--success);margin-top:1px; }
.cotmx-qtd-split{ margin-top:5px;display:flex;align-items:center;gap:5px; }
.cotmx-qtd-split label{ font-size:10px;color:var(--ink-faint); }
.cotmx-qtd-split input{
  width:54px;font-size:11px;padding:3px 5px;border:1px solid var(--success);border-radius:5px;
  background:var(--surface);color:var(--ink);font-family:inherit;
}

.cotmx-cel.barata{ border-color:var(--success);border-left-width:3px; }
.cotmx-cel.selecionada{ background:var(--success-soft);border-color:var(--success); }
.cotmx-cel.selecionada .cotmx-forn{ color:var(--success); }
.cotmx-cel.dim{ opacity:.45; }
.cotmx-cel.vazia{
  color:var(--ink-faint);cursor:default;background:var(--surface-2);border-style:dashed;
  align-items:flex-start;justify-content:center;
}
.cotmx-cel.vazia .cotmx-forn{ color:var(--ink-soft);font-weight:600; }
.cotmx-cel.filler{ background:transparent;border-style:dashed;border-color:var(--border);cursor:default;opacity:.3; }
.cotmx-estado{ font-size:11px;font-style:italic;color:var(--ink-faint); }
@media (max-width:960px){
  .cotmx-grid{ grid-template-columns:1fr!important; }
  .cotmx-produto-card{ padding-top:16px; }
}

/* ---------- "Cotações recebidas": cards por produto na visão "Por
   Fornecedor" de Nova Cotação (COT-02, v2.45.0) ----------
   Pedido do usuário, mockups "cot02-bloco-recolhivel-mockup.html" até
   "cot02-card-detalhado-mockup.html" aprovados em 5 rodadas — ver
   cotRecebidasMatrixHtml()/cotRecebidaCardHtml() em frontend.js. Reaproveita
   DIRETO (sem alterar nenhuma regra acima) .cotmx-grid/.cotmx-produto-card/
   .cotmx-cel/.cotmx-cel.barata/.cotmx-cel.filler/.cotmx-flag — as mesmas
   classes que o Comparativo (cotacoesMatrixHtml()) já usa em produção.
   Tudo que é NOVO aqui fica prefixado "cotcard-" e é somado como classe
   ADICIONAL no mesmo elemento ".cotmx-cel" (ex: class="cotmx-cel
   cotcard-wrap barata"), nunca como alteração da regra ".cotmx-cel" em si —
   assim a tela de Comparativo não corre nenhum risco. */
.cotcard-received-wrap{ margin:0 0 26px;padding-bottom:22px;border-bottom:2px dashed var(--border);overflow-x:auto; }
.cotcard-received-head{ display:flex;align-items:center;gap:8px;margin:0 0 10px; }
.cotcard-received-head h4{ font-size:13px;margin:0;font-weight:800;color:var(--ink); }
.cotcard-received-head svg{ width:15px;height:15px;color:var(--primary-strong); }

.cotcard-wrap{ position:relative;cursor:default; }
.cotcard-corner{ position:absolute;top:7px;right:7px;display:flex;align-items:center;gap:3px; }
.cotcard-status-ic{ width:19px;height:19px;border-radius:6px;display:flex;align-items:center;justify-content:center;flex:none; }
.cotcard-status-ic svg{ width:11px;height:11px; }
.cotcard-icon-btn{
  width:19px;height:19px;border-radius:6px;border:1px solid var(--border);background:var(--surface-2);
  color:var(--ink-soft);display:flex;align-items:center;justify-content:center;cursor:pointer;flex:none;padding:0;
}
.cotcard-icon-btn svg{ width:11px;height:11px; }
.cotcard-icon-btn:hover{ background:var(--surface);color:var(--ink); }
.cotcard-icon-btn.danger:hover{ background:var(--danger-soft);color:var(--danger);border-color:var(--danger); }
.cotcard-icon-btn.ok{ background:var(--success);color:#fff;border-color:var(--success); }
.cotcard-icon-btn.ok:hover{ background:var(--primary-strong); }

.cotcard-head{ display:flex;align-items:flex-start;gap:6px;padding-right:72px; }
.cotcard-logo-mini{ flex:none; }
.cotcard-logo-mini .fabrica-logo{ width:19px;height:19px;border-radius:5px;font-size:8px; }
/* v2.45.2 (pedido do usuário, ao vivo, com print): nenhum texto do card pode
   cortar com "..." — nem o nome da fábrica, nem nenhum outro campo. Antes,
   só o nome (.cotcard-forn) tinha white-space:nowrap+ellipsis; trocado por
   min-width:0 (deixa o item flex encolher dentro de .cotcard-head, em vez
   de empurrar o card) + overflow-wrap:anywhere (quebra a linha, inclusive
   no meio de uma palavra sem espaço, se precisar — nunca corta visualmente
   o texto). Os demais campos (.cotcard-line2/.cotcard-line3) nunca tiveram
   nowrap/ellipsis, mas ganharam o mesmo overflow-wrap de proteção, por
   segurança, pro mesmo pedido valer pra "qualquer outra descrição".

   v2.45.3 (pedido do usuário, revisando o acima): só pro NOME DA FÁBRICA,
   voltou a cortar com "..." — mas agora com o card mais largo (ver
   cotRecebidasMatrixHtml() em frontend.js, "minmax(220px,1fr)", antes
   "190px") e um orçamento de 12 caracteres (max-width:12ch) reservado só
   pra ele: um nome de até 12 caracteres cabe inteiro, sem quebrar linha;
   passou disso, corta com "...". .cotcard-line2/.cotcard-line3 (Ref./
   Marca/Valor, Qtd./Prazo) NÃO entraram nesse pedido — continuam com
   overflow-wrap:anywhere (nunca cortam, quebram linha se precisar), como
   decidido na v2.45.2. O atributo title="" (ver cotRecebidaCardHtml()) deixa
   o nome completo visível ao passar o mouse quando cortado. */
.cotcard-forn{ font-size:11.5px;font-weight:700;color:var(--ink);min-width:0;max-width:12ch;white-space:nowrap;overflow:hidden;text-overflow:ellipsis; }
.cotcard-line2{ font-size:11px;color:var(--ink-soft);display:flex;align-items:baseline;gap:4px;flex-wrap:wrap;overflow-wrap:anywhere; }
.cotcard-line2 .sep{ color:var(--ink-faint); }
.cotcard-valor{ font-weight:800;color:var(--ink);font-size:13px;margin-left:1px; }
.cotcard-line3{ font-size:10.5px;color:var(--ink-faint);overflow-wrap:anywhere; }

/* v2.45.3 (pedido do usuário, mockup "cot02-coluna-produto-fixa-mockup.html"
   aprovado): com a barra de rolagem horizontal das "Cotações recebidas" já
   em produção (v2.45.1), só os cards de fábrica devem rolar — a coluna de
   produto (.cotmx-produto-card, a mesma classe-base que o Comparativo já usa
   em produção, intocada) fica fixa. Classe ADICIONAL, somada na mesma célula
   (ver cotRecebidasMatrixHtml() em frontend.js: class="cotmx-produto-card
   cotcard-produto-fixo"), nunca uma alteração de ".cotmx-produto-card" em
   si — a tela de Comparativo não corre nenhum risco. position:sticky;left:0
   trava a coluna na borda esquerda de ".cotcard-received-wrap" (o contêiner
   que rola); background:var(--surface) fica explícito (a classe-base é
   transparente, contando com o fundo branco do painel por trás — aqui
   precisa ser opaco de verdade, pra tampar os cards de fábrica que passam
   por baixo enquanto a grade rola); borda+sombra sutil à direita marcam a
   divisão entre a coluna fixa e a área que rola. */
.cotmx-produto-card.cotcard-produto-fixo{
  position:sticky;left:0;z-index:4;background:var(--surface);
  padding:10px 14px 10px 2px;border-right:1px solid var(--border);
  box-shadow:6px 0 10px -6px rgba(20,30,24,.18);
}

.cotcard-wrap.is-editing{ border-color:var(--primary);box-shadow:0 0 0 2px var(--primary-soft); }
.cotcard-edit-grid{ display:grid;grid-template-columns:1fr 1fr;gap:6px 8px;margin-top:2px; }
.cotcard-edit-field label{ display:block;font-size:9px;font-weight:700;color:var(--ink-faint);text-transform:uppercase;letter-spacing:.03em;margin-bottom:2px; }
.cotcard-mini-input{ width:100%;height:24px;border:1px solid var(--border);border-radius:6px;padding:0 6px;font-size:11px;background:var(--surface);font-family:inherit;color:var(--ink); }
.cotcard-currency{ display:flex;align-items:center;border:1px solid var(--border);border-radius:6px;background:var(--surface);height:24px;overflow:hidden; }
.cotcard-currency span{ padding:0 0 0 6px;color:var(--ink-faint);font-size:10px; }
.cotcard-currency input{ border:none;background:transparent;flex:1;min-width:0;font-size:11px;padding:0 4px;width:100%;font-family:inherit;color:var(--ink); }
@media (max-width:960px){
  .cotcard-head{ padding-right:46px; }
}

/* ---------- Comparativo: tela "Calcular Preços de Venda da Requisição" (CMP-03, v2.38.0 — antes REQ-05) ----------
   Pedido do usuário, mesmo mockup acima — ver abrirCalcularPrecosRequisicao()/
   renderCalcPrecosReqBody() em frontend.js. Classes prefixadas "cotvr-". */
.cotvr-head-row{
  display:grid;grid-template-columns:1.4fr 110px 90px 110px 170px 140px 38px;gap:12px;
  font-size:10.5px;font-weight:700;color:var(--ink-faint);text-transform:uppercase;letter-spacing:.02em;
  padding:0 4px 8px;
}
.cotvr-row{
  display:grid;grid-template-columns:1.4fr 110px 90px 110px 170px 140px 38px;gap:12px;align-items:center;
  padding:12px 4px;border-bottom:1px solid var(--border);
}
.cotvr-row:last-child{ border-bottom:none; }
.cotvr-row.enviado{ opacity:.55; }
.cotvr-nome{ font-weight:700;font-size:12.5px;color:var(--ink); }
.cotvr-sub{ font-size:10.5px;color:var(--ink-faint);margin-top:2px; }
.cotvr-forn{ font-size:12px;color:var(--ink-soft); }
.cotvr-qtd{ font-size:12px;color:var(--ink-soft); }
.cotvr-preco{ font-size:12.5px;font-weight:700;color:var(--ink); }
.cotvr-select{
  font-size:11.5px;padding:6px 8px;border-radius:7px;border:1px solid var(--border);width:100%;
  background:var(--surface);color:var(--ink);font-family:inherit;
}
.cotvr-select:focus{ border-color:var(--primary); }
.cotvr-venda{ font-size:13px;font-weight:800;color:var(--success); }
.cotvr-venda .f{ display:block;font-size:10px;font-weight:500;color:var(--ink-faint); }
.cotvr-foot{
  display:flex;align-items:center;justify-content:space-between;margin-top:16px;border-top:1px solid var(--border);
  padding-top:16px;gap:14px;flex-wrap:wrap;
}
.cotvr-nota{ font-size:11.5px;color:var(--ink-soft);margin-top:14px;max-width:760px;line-height:1.6; }
@media (max-width:860px){
  .cotvr-head-row{ display:none; }
  .cotvr-row{ grid-template-columns:1fr 1fr;row-gap:8px; }
}
/* v2.39.0 — percentuais de uma Tabela de Venda "Cálculo Manual", digitados
   linha a linha dentro desta mesma tela (ver calcManualPctRowHtml()/
   manualTotalPctFor() em frontend.js — bug corrigido nesta rodada: essa
   tela não tinha nenhum suporte a tabelas manuais, sempre calculava com
   0% de margem silenciosamente). Reaproveita .field/.percent-input (já
   usados nos formulários genéricos) só com uma moldura própria em volta. */
.cotvr-manual-row{
  background:var(--surface-2);border-radius:var(--radius-md);padding:12px 14px 4px;
  margin:-4px 0 12px;display:flex;flex-wrap:wrap;gap:12px 14px;align-items:flex-end;
}
.cotvr-manual-row .field{ min-width:110px;flex:1; }
.cotvr-manual-total{ font-size:12px;font-weight:700;color:var(--ink);white-space:nowrap;padding-bottom:9px; }
@media (max-width:860px){
  .cotvr-manual-row{ flex-direction:column;align-items:stretch; }
  .cotvr-manual-total{ padding-bottom:0; }
}

/* ---------- relatórios ---------- */
.cf-stat-grid{ display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:14px;margin-bottom:26px; }
.cf-stat-tile{
  background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-md);
  padding:18px 20px;box-shadow:var(--shadow-sm);
}
.cf-stat-value{ font-family:'Manrope',Inter,system-ui,sans-serif;font-weight:800;font-size:24px;color:var(--primary-strong); }
.cf-stat-label{ font-size:12px;color:var(--ink-soft);margin-top:4px; }
.cf-bars-grid{ display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:20px; }
.cf-bars-block{
  background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-md);
  padding:18px 20px;box-shadow:var(--shadow-sm);
}
.cf-bars-block h3{ margin:0 0 14px;font-size:14px; }
.cf-bar-row{ display:flex;align-items:center;gap:10px;margin-bottom:9px;font-size:12.5px; }
.cf-bar-label{ width:38%;color:var(--ink-soft);white-space:nowrap;overflow:hidden;text-overflow:ellipsis; }
.cf-bar-track{ flex:1;height:8px;border-radius:999px;background:var(--surface-2);overflow:hidden; }
.cf-bar-fill{ height:100%;border-radius:999px;background:var(--primary); }
.cf-bar-value{ width:26px;text-align:right;font-weight:700;color:var(--ink); }

/* ---------- Página Inicial (HOME-01) ---------- */
.cf-home{ display:flex;flex-direction:column;gap:16px; }
.cf-home-hero{
  display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap;
  background:linear-gradient(135deg,var(--primary-soft),var(--surface-2));
  border:1px solid var(--border);border-radius:var(--radius-md);padding:20px 26px;
}
.cf-home-brand{ font-family:'Manrope',Inter,system-ui,sans-serif;font-weight:800;font-size:24px;color:var(--primary-strong);letter-spacing:.01em; }
.cf-home-tagline{ font-size:12.5px;color:var(--ink-soft);margin-top:2px; }
.cf-home-logo-img{ max-width:140px;max-height:56px;object-fit:contain;border-radius:8px;background:var(--surface);padding:6px;box-shadow:var(--shadow-sm); }
.cf-home-logo-placeholder{
  width:132px;height:52px;border:1.5px dashed var(--ink-faint);border-radius:10px;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;
  background:rgba(255,255,255,.35);text-align:center;padding:4px;
}
.cf-home-logo-placeholder span{ font-size:9.5px;font-weight:700;color:var(--ink-soft);letter-spacing:.03em; }
.cf-home-logo-placeholder small{ font-size:8.5px;color:var(--ink-faint); }

.cf-home-greeting{ display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap; }
.cf-home-greeting-left{ display:flex;align-items:center;gap:12px; }
.cf-home-greeting-name{ font-size:16.5px;font-weight:700;color:var(--ink); }
.cf-home-greeting-sub{ font-size:12px;color:var(--ink-faint);margin-top:1px; }

.cf-home-kpis{ display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px; }
.cf-home-kpi{ background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-md);padding:14px 16px;box-shadow:var(--shadow-sm); }
.cf-home-kpi-head{ display:flex;align-items:center;justify-content:space-between;margin-bottom:8px;font-size:10.5px;font-weight:700;color:var(--ink-faint);text-transform:uppercase;letter-spacing:.03em; }
.cf-home-kpi-icon svg{ width:14px;height:14px;display:block; }
.cf-home-kpi-value{ font-family:'Manrope',Inter,system-ui,sans-serif;font-weight:800;font-size:22px;color:var(--ink); }
.cf-home-kpi-sub{ font-size:10.5px;color:var(--ink-faint);margin-top:2px; }

.cf-home-cols{ display:flex;gap:16px;align-items:flex-start;flex-wrap:wrap; }
.cf-home-panel{ flex:1;min-width:280px;background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-md);padding:16px 18px;box-shadow:var(--shadow-sm); }
.cf-home-panel-head{ display:flex;align-items:center;justify-content:space-between;font-size:13.5px;font-weight:700;margin-bottom:10px;color:var(--ink); }
.cf-home-panel-badge{ background:var(--danger-soft);color:var(--danger);font-size:11px;font-weight:700;border-radius:9px;padding:1px 8px; }
.cf-home-panel-link{ background:none;border:none;padding:0;font-size:11.5px;font-weight:600;color:var(--primary);cursor:pointer; }
.cf-home-panel-link:hover{ text-decoration:underline; }

.cf-home-atencao-item{ display:flex;align-items:flex-start;gap:10px;padding:8px 0;border-bottom:1px solid var(--surface-2); }
.cf-home-atencao-item:last-child{ border-bottom:none; }
.cf-home-atencao-icon{ width:28px;height:28px;border-radius:8px;display:flex;align-items:center;justify-content:center;flex-shrink:0; }
.cf-home-atencao-icon svg{ width:14px;height:14px; }
.cf-home-atencao-text{ flex:1;min-width:0; }
.cf-home-atencao-title{ font-size:12.5px;font-weight:600;color:var(--ink); }
.cf-home-atencao-sub{ font-size:11px;color:var(--ink-faint);margin-top:1px; }
.cf-home-atencao-link{ background:none;border:none;padding:0;font-size:11.5px;font-weight:600;color:var(--primary);cursor:pointer;flex-shrink:0; }
.cf-home-atencao-link:hover{ text-decoration:underline; }

.cf-home-recentes-head{
  display:grid;grid-template-columns:1fr 1.3fr 1fr .7fr;gap:6px;
  font-size:10.5px;font-weight:700;color:var(--ink-faint);text-transform:uppercase;letter-spacing:.02em;
  padding-bottom:6px;border-bottom:1px solid var(--surface-2);
}
.cf-home-recente-row{
  display:grid;grid-template-columns:1fr 1.3fr 1fr .7fr;gap:6px;align-items:center;
  font-size:12px;padding:7px 0;border-bottom:1px solid var(--surface-2);cursor:pointer;
}
.cf-home-recente-row:last-child{ border-bottom:none; }
.cf-home-recente-row:hover{ background:var(--surface-2); }
.cf-home-recente-cliente{ overflow:hidden;text-overflow:ellipsis;white-space:nowrap; }

.cf-home-item-cotado{ display:flex;align-items:center;justify-content:space-between;gap:10px;padding:9px 0;border-bottom:1px solid var(--surface-2);cursor:pointer; }
.cf-home-item-cotado:last-child{ border-bottom:none; }
.cf-home-item-cotado:hover{ background:var(--surface-2); }
.cf-home-item-cotado-nome{ font-size:12.5px;font-weight:600;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap; }
.cf-home-item-cotado-preco{ font-size:13px;font-weight:700;color:var(--primary-strong);flex-shrink:0; }

.cf-home-empty{ display:flex;align-items:center;gap:8px;color:var(--ink-faint);font-size:12.5px;padding:10px 0; }
.cf-home-empty svg{ width:16px;height:16px;flex-shrink:0; }

.cf-home-chart{ background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-md);padding:16px 18px;box-shadow:var(--shadow-sm); }

@media (max-width:820px){
  .cf-home-cols{ flex-direction:column; }
  .cf-home-hero{ padding:16px 18px; }
  .cf-home-recentes-head,.cf-home-recente-row{ grid-template-columns:1fr 1fr .6fr; }
  .cf-home-recente-row .cf-home-recente-cliente,.cf-home-recentes-head span:nth-child(2){ display:none; }
}

/* ---------- toasts ---------- */
.toast-stack{ position:fixed;bottom:20px;right:20px;display:flex;flex-direction:column;gap:8px;z-index:80; }
@media (max-width:820px){ .toast-stack{ bottom:80px;right:14px;left:14px; } }
.toast{
  display:flex;align-items:center;gap:9px;background:var(--surface);border:1px solid var(--border);
  border-left:4px solid var(--primary);box-shadow:var(--shadow-md);border-radius:10px;
  padding:11px 14px;font-size:12.8px;color:var(--ink);max-width:340px; animation:toast-in .18s ease;
}
.toast.danger{ border-left-color:var(--danger); }
.toast.success{ border-left-color:var(--success); }
@keyframes toast-in{ from{opacity:0;transform:translateY(6px);} to{opacity:1;transform:translateY(0);} }

/* ---------- popup de notificação (v2.36.0) ----------
   Variante mais completa do .toast genérico acima (ícone + título +
   descrição + botões Ver/Dispensar + X), usada só pelo sistema de
   notificação (ver showNotifToast() em frontend.js) — o .toast simples
   (mensagem de uma linha, some sozinho em ~3.6s) continua existindo do
   jeito que sempre foi, pra feedback rápido de salvar/excluir/erro. Vive no
   mesmo #toastStack (canto inferior direito), empilhando com ele quando os
   dois aparecerem juntos. NÃO tem nenhuma animação/timer de saída — pedido
   do usuário: só fecha por clique da própria pessoa (ver os 3
   addEventListener de "Ver"/"Dispensar"/X em showNotifToast()). */
.toast.toast-notif{ align-items:flex-start;max-width:360px;padding:12px 13px;gap:10px;border-left-color:var(--primary); }
.toast-notif .toast-icon{
  flex:none;width:34px;height:34px;border-radius:9px;display:flex;align-items:center;justify-content:center;
  background:var(--primary-soft);color:var(--primary-strong);
}
.toast-notif .toast-icon svg{ width:18px;height:18px;flex:none; }
.toast-notif .toast-icon.tone-warn{ background:var(--warn-soft);color:var(--warn); }
.toast-notif .toast-icon.tone-danger{ background:var(--danger-soft);color:var(--danger); }
.toast-notif .toast-body{ flex:1;min-width:0; }
.toast-notif .toast-title{ margin:0 0 2px;font-size:13px;font-weight:700;color:var(--ink); }
.toast-notif .toast-desc{ margin:0;font-size:12px;color:var(--ink-soft);line-height:1.4; }
.toast-notif .toast-actions{ display:flex;gap:14px;margin-top:8px; }
.toast-notif .toast-link,.toast-notif .toast-dismiss{
  border:none;background:none;padding:0;font-size:11.5px;font-weight:700;cursor:pointer;font-family:inherit;
}
.toast-notif .toast-link{ color:var(--primary-strong); }
.toast-notif .toast-dismiss{ color:var(--ink-faint); }
.toast-notif .toast-link:hover,.toast-notif .toast-dismiss:hover{ text-decoration:underline; }
.toast-notif .toast-close{
  flex:none;border:none;background:none;color:var(--ink-faint);cursor:pointer;padding:2px;
  margin:-2px -2px 0 0;border-radius:6px;display:flex;
}
.toast-notif .toast-close:hover{ background:var(--surface-2);color:var(--ink); }
.toast-notif .toast-close svg{ width:14px;height:14px;flex:none; }

/* Botões de mudo/notificação nativa no rodapé da barra lateral (ver
   appShellHtml()/wireNotifControls() em frontend.js). */
.notif-controls{ display:flex;gap:6px;margin-top:8px; }
.notif-controls .btn-icon{ flex:1;display:flex;align-items:center;justify-content:center; }
.notif-controls .btn-icon svg{ width:15px;height:15px;flex:none; }
.notif-controls .btn-icon.is-active{ background:var(--primary-soft);color:var(--primary-strong);border-color:var(--primary-soft); }
.notif-controls .btn-icon.is-blocked{ color:var(--ink-faint);cursor:not-allowed; }

/* ---------- Calcular Preço de Venda / Itens Cotados / Avisos ---------- */
/* Caixa de destaque com o resultado calculado (Preço de Venda), no painel da
   tela "Calcular Preço de Venda" e no detalhe de "Itens Cotados". */
.result-highlight{
  background:var(--accent-soft);border:1px solid var(--accent);border-radius:var(--radius-md);
  padding:16px 18px;text-align:center;
}
.result-highlight .k{ font-size:10.5px;text-transform:uppercase;letter-spacing:.07em;color:var(--primary-strong);font-weight:700;margin-bottom:6px; }
.result-highlight .v{ font-family:'IBM Plex Mono',ui-monospace,monospace;font-size:28px;font-weight:700;color:var(--accent); }
.result-highlight .f{ font-family:'IBM Plex Mono',ui-monospace,monospace;font-size:11.5px;color:var(--ink-soft);margin-top:6px; }
/* Lista de percentuais somados (componentes da Tabela de Venda escolhida). */
.comp-breakdown{ border:1px solid var(--border);border-radius:10px;background:var(--surface-2);overflow:hidden; }
.comp-row{ display:flex;align-items:center;justify-content:space-between;padding:9px 14px;font-size:12.5px;color:var(--ink-soft);border-bottom:1px solid var(--border); }
.comp-row:last-child{ border-bottom:none; }
.comp-row.total{ background:var(--surface);font-weight:700;color:var(--ink); }
/* Botões empilhados verticalmente (as três decisões de "Itens Cotados"). */
.stack-buttons{ display:flex;flex-direction:column;gap:10px; }
.stack-buttons .btn{ justify-content:center; }
/* Cartões de "Avisos" (Comprador) — reaproveita .item-card, só que sem o
   fundo cinza (fica igual a um cartão comum, mais destacado que uma linha de
   tabela, já que cada aviso pede uma ação). */
.aviso-card{ background:var(--surface);box-shadow:var(--shadow-sm); }
.aviso-card.is-resolvido{ opacity:.55; }
.aviso-card-head{ display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:10px; }
.aviso-headline{ font-size:14px;font-weight:700;color:var(--ink); }
.aviso-quando{ font-size:11.5px;color:var(--ink-faint);margin-top:2px; }
.aviso-grid{ display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:12px 16px;margin:12px 0; }
.aviso-actions{ display:flex;justify-content:flex-end;margin-top:4px; }

/* ---------- Comentários da Requisição (REQ-04) ---------- */
/* Ponto de entrada dentro do detalhe da Requisição (openRequisicaoDetail()):
   linha clicável "Comentários · N comentários · M novos" com um chevron à
   direita, no mesmo espírito de .cotacao-progress logo acima. */
.cf-comentarios-entry{
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  margin-top:22px;padding:13px 14px;border-radius:10px;border:1px solid var(--border);
  background:var(--surface-2);cursor:pointer;transition:background .12s ease;
}
.cf-comentarios-entry:hover{ background:var(--primary-soft); }
.cf-comentarios-entry-left{ display:flex;align-items:center;gap:10px;font-size:13px;font-weight:600;color:var(--ink); }
.cf-comentarios-entry-left svg{ width:17px;height:17px;flex:none;color:var(--ink-soft); }
.cf-comentarios-entry-chevron{ display:flex;flex:none;color:var(--ink-faint); }
.cf-comentarios-entry-chevron svg{ width:15px;height:15px; }

/* Botão "Voltar à requisição" no topo da tela de comentários — reaproveita o
   ícone de chevron (que aponta pra direita) espelhado, em vez de desenhar um
   segundo path só pra isso. */
.cf-comentarios-back{
  display:inline-flex;align-items:center;gap:6px;background:none;border:none;padding:0;
  margin-bottom:16px;color:var(--ink-soft);font-size:12.5px;font-weight:700;cursor:pointer;
}
.cf-comentarios-back:hover{ color:var(--ink); }
.cf-comentarios-back svg{ width:14px;height:14px;transform:rotate(180deg); }

.cf-comment-list{ display:flex;flex-direction:column;gap:16px; }
.cf-comment-item{ display:flex;flex-direction:column;gap:6px; }
.cf-comment-head{ display:flex;align-items:center;gap:9px; }
/* Avatar com iniciais colorido pelo PAPEL do autor NO MOMENTO em que postou
   (snapshot gravado em _cf_autor_papel — ver includes/rest-comentarios.php),
   não pelo papel atual dele. Três cores bem distintas: Requisitante reaproveita
   --primary (verde, cor principal do app), Comprador reaproveita --accent
   (laranja, já usado nos botões primários), Administrador usa --role-admin
   (azul, criada só pra isso — ver comentário em :root). */
.cf-comment-avatar{
  width:30px;height:30px;border-radius:50%;flex:none;display:flex;align-items:center;justify-content:center;
  font-weight:800;font-size:11px;color:#fff;
}
.cf-comment-avatar.role-requisitante{ background:var(--primary); }
.cf-comment-avatar.role-comprador{ background:var(--accent); }
.cf-comment-avatar.role-administrador{ background:var(--role-admin); }
.cf-comment-avatar.role-gestor{ background:var(--role-gestor); }
.cf-comment-name{ font-weight:700;font-size:13px;color:var(--ink); }
.cf-comment-role-badge{
  font-size:9.5px;font-weight:800;letter-spacing:.04em;padding:2px 8px;border-radius:999px;
}
.cf-comment-role-badge.role-requisitante{ background:var(--primary-soft);color:var(--primary-strong); }
.cf-comment-role-badge.role-comprador{ background:var(--accent-soft);color:var(--accent); }
.cf-comment-role-badge.role-administrador{ background:var(--role-admin-soft);color:var(--role-admin); }
.cf-comment-role-badge.role-gestor{ background:var(--role-gestor-soft);color:var(--role-gestor); }
.cf-comment-time{ margin-left:auto;font-size:11px;color:var(--ink-faint);white-space:nowrap; }
/* white-space:pre-wrap preserva as quebras de linha do texto original — sem
   isso, todo o comentário viraria uma única linha (\n vira espaço em branco
   normal no HTML), mesmo o servidor guardando as quebras corretamente. */
.cf-comment-text{
  font-size:13.3px;color:var(--ink);line-height:1.55;white-space:pre-wrap;
  padding-left:39px;word-break:break-word;
}

/* Divisória "M NOVOS COMENTÁRIOS", posicionada imediatamente antes do
   primeiro comentário novo para o usuário atual (ver
   primeiroComentarioNovoIndex() em frontend.js). */
.cf-comments-divider{
  display:flex;align-items:center;gap:10px;margin:4px 0;
  color:var(--danger);font-size:10.5px;font-weight:800;letter-spacing:.06em;
}
.cf-comments-divider::before,.cf-comments-divider::after{
  content:'';flex:1;height:0;border-top:1px dashed var(--danger);opacity:.45;
}

.cf-comment-compose{ margin-top:22px;padding-top:16px;border-top:1px solid var(--border); }
.cf-comment-textarea{
  width:100%;min-height:76px;resize:vertical;padding:10px 12px;border-radius:8px;
  border:1px solid var(--border);background:var(--surface-2);color:var(--ink);
  font-size:13.3px;font-family:inherit;outline:none;
}
.cf-comment-textarea:focus{ border-color:var(--primary);background:var(--surface); }
.cf-comment-send-row{ display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:10px; }
.cf-comment-caption{ font-size:10.5px;color:var(--ink-faint); }

::selection{ background:var(--accent-soft); }
:focus-visible{ outline:2px solid var(--accent);outline-offset:2px; }
@media (prefers-reduced-motion: reduce){ *{ animation:none!important;transition:none!important; } }

/* ==================== v2.28.0: Exportar Relatórios, Histórico de
   Alterações, Licença no App, Marcas Duplicadas, Relatórios Visuais ==================== */

/* ---------- Exportar Relatórios (CSV/PDF) ---------- */
.cf-relatorios-head{ display:flex;justify-content:flex-end;margin-bottom:16px; }
.cf-export-dropdown{ position:relative; }
.cf-export-menu{
  position:absolute;top:calc(100% + 6px);right:0;min-width:170px;z-index:20;
  background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-sm);
  box-shadow:var(--shadow-md);padding:6px;display:none;flex-direction:column;gap:2px;
}
.cf-export-dropdown.open .cf-export-menu{ display:flex; }
.cf-export-menu button{
  display:block;width:100%;text-align:left;padding:8px 10px;border-radius:6px;border:none;
  background:transparent;color:var(--ink);font-size:12.5px;font-weight:600;cursor:pointer;
}
.cf-export-menu button:hover{ background:var(--surface-2); }

/* Folha de impressão (v2.28.0, "Exportar PDF" = window.print() nativo, sem
   nenhuma biblioteca — ver exportRelatoriosPdf() em assets/frontend.js):
   esconde tudo que não é o conteúdo dos Relatórios, e tira interações
   (dropdown de exportação, hover de gráfico) que não fazem sentido no papel. */
@media print{
  .sidebar, .topbar, .toolbar, .backdrop, .toast-stack, .panel{ display:none!important; }
  .cf-app-fullscreen, .content, .view-area{ height:auto!important;overflow:visible!important; }
  .cf-relatorios-head{ display:none!important; }
  body{ background:#fff!important; }
}

/* ---------- Histórico de Alterações (detalhe de Cotação) ---------- */
.cf-historico-block{ margin-top:22px;padding-top:18px;border-top:1px solid var(--border); }
.cf-historico-block h3{ margin:0 0 14px;font-size:14px; }
.cf-historico-timeline{ display:flex;flex-direction:column;gap:0; }
.cf-historico-item{ display:flex;gap:12px;position:relative;padding-bottom:16px; }
.cf-historico-item:last-child{ padding-bottom:0; }
.cf-historico-item::before{
  content:'';position:absolute;left:4px;top:14px;bottom:-2px;width:1px;background:var(--border);
}
.cf-historico-item:last-child::before{ display:none; }
.cf-historico-dot{
  width:9px;height:9px;border-radius:50%;background:var(--primary);flex:none;margin-top:4px;
  box-shadow:0 0 0 3px var(--primary-soft);z-index:1;
}
.cf-historico-content{ flex:1;min-width:0; }
.cf-historico-desc{ font-size:12.8px;color:var(--ink);line-height:1.5; }
.cf-historico-de{ color:var(--ink-faint);text-decoration:line-through; }
.cf-historico-para{ color:var(--primary-strong);font-weight:700; }
.cf-historico-meta{ font-size:11px;color:var(--ink-faint);margin-top:2px; }

/* ---------- Licença no App ---------- */
.cf-licenca-card{
  background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-md);
  padding:22px 24px;box-shadow:var(--shadow-sm);max-width:560px;
}
.cf-licenca-head{ margin-bottom:14px; }
.cf-licenca-msg{
  display:flex;align-items:flex-start;gap:8px;padding:10px 12px;border-radius:8px;
  font-size:12.5px;line-height:1.5;margin-bottom:16px;
}
.cf-licenca-msg svg{ width:16px;height:16px;flex:none;margin-top:1px; }
.cf-licenca-msg.tone-warn{ background:var(--warn-soft);color:var(--warn); }
.cf-licenca-msg.tone-danger{ background:var(--danger-soft);color:var(--danger); }
.cf-licenca-sub{ font-size:11px;color:var(--ink-faint);margin:14px 0 0; }

/* ---------- Marcas Duplicadas ---------- */
.cf-dup-list{ display:flex;flex-direction:column;gap:10px; }
.cf-dup-row{
  display:flex;align-items:center;gap:12px;padding:12px 14px;border:1px solid var(--border);
  border-radius:10px;background:var(--surface-2);flex-wrap:wrap;
}
.cf-dup-names{ display:flex;align-items:center;gap:8px;flex:1;min-width:220px;flex-wrap:wrap; }
.cf-dup-name{ font-weight:700;color:var(--ink);font-size:13px; }
.cf-dup-vs{ font-size:11px;color:var(--ink-faint);font-style:italic; }
/* Reaproveita .checkbox-field (v2.27.1) também para radio — mesmo visual de
   campo de escolha já usado em Tabela de Venda "Cálculo Manual". */
.checkbox-field input[type="radio"]{ width:16px;height:16px;flex:none;margin-top:1px;accent-color:var(--primary);cursor:pointer; }

/* ---------- Relatórios Visuais (gráficos SVG) ---------- */
.cf-relatorios-visuais{ margin-top:26px; }
.cf-relatorios-visuais > h2{ font-size:16px;margin:0 0 14px; }
.cf-svgchart-grid{ display:grid;grid-template-columns:repeat(auto-fit,minmax(320px,1fr));gap:20px; }
.cf-svgchart-block{
  background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-md);
  padding:18px 20px;box-shadow:var(--shadow-sm);overflow-x:auto;
}
.cf-svgchart-block h3{ margin:0 0 14px;font-size:14px; }
/* max-width (nunca width:100%) é de propósito (v2.28.1, corrige um bug
   visual): o <svg> agora tem width/height explícitos no próprio desenho
   (ver svgBarChartHtml(), assets/frontend.js) — max-width só encolhe em
   telas estreitas, sem esticar o desenho pra preencher um cartão largo
   (o que, com poucas barras, deixava o gráfico gigantesco). */
.cf-svgchart{ display:block;max-width:100%;height:auto; }
.cf-svgchart-bar{ fill:var(--primary); }
.cf-svgchart-label{ fill:var(--ink-soft);font-size:10.5px;font-family:'Inter',system-ui,sans-serif; }
.cf-svgchart-value{ fill:var(--ink);font-size:11px;font-weight:700;font-family:'Inter',system-ui,sans-serif; }

/* ---------- Carteira e Pendências (v2.29.0, mockup aprovado) ----------
   Classes novas (não existia nada parecido no app antes): lista de
   fábricas, filtro avançado gerado a partir das colunas da planilha, e o
   modal de envio/substituição — nomes e valores portados quase sem
   alteração do mockup-carteira-pendencias.html aprovado, já que usam as
   mesmas variáveis de cor/raio/sombra do app de verdade. */
.carteira-row-nome{ font-weight:700;color:var(--ink); }
.carteira-row-sub{ font-size:11px;color:var(--ink-faint);margin-top:1px; }

.role-banner{
  display:flex;align-items:center;gap:8px;background:var(--warn-soft);color:var(--warn);border-radius:8px;
  padding:8px 12px;font-size:11.5px;font-weight:600;margin-bottom:12px;
}
.role-banner svg{ width:15px;height:15px;flex:none; }

.hide-badge{
  display:block;font-size:8px;font-weight:800;color:var(--accent);letter-spacing:.02em;margin-top:3px;
}

.note-callout{
  display:flex;gap:9px;align-items:flex-start;background:var(--surface-2);border:1px solid var(--border);
  border-radius:10px;padding:11px 13px;margin-top:14px;font-size:12px;color:var(--ink-soft);line-height:1.55;
}
.note-callout svg{ width:15px;height:15px;flex:none;margin-top:1px;color:var(--ink-faint); }
.note-callout b{ color:var(--ink); }
.note-callout.tone-warn{ background:var(--warn-soft);border-color:var(--warn); }
.note-callout.tone-warn svg{ color:var(--warn); }

/* Filtro avançado, gerado dinamicamente a partir das colunas da planilha
   desta fábrica (ver renderCarteiraFiltroHtml(), assets/frontend.js) —
   nunca o mesmo conjunto de campos de uma fábrica para outra. */
.adv-filter{
  background:var(--surface-2);border:1px solid var(--border);border-radius:var(--radius-md);
  padding:14px 16px;margin:14px 0 16px;
}
.adv-filter-head{ display:flex;align-items:center;gap:8px;margin-bottom:10px; }
.adv-filter-head svg{ width:15px;height:15px;color:var(--primary-strong);flex:none; }
.adv-filter-head span{ font-size:11px;font-weight:800;letter-spacing:.04em;color:var(--primary-strong); }
.adv-filter-grid{ display:grid;grid-template-columns:repeat(auto-fill,minmax(170px,1fr));gap:10px; }
.adv-filter-field{ display:flex;flex-direction:column;gap:4px; }
.adv-filter-field label{ font-size:9.5px;font-weight:700;color:var(--ink-faint);letter-spacing:.03em; }
.adv-filter-field input, .adv-filter-field select{
  padding:7px 9px;border-radius:7px;border:1px solid var(--border);background:var(--surface);
  color:var(--ink);font-size:12px;outline:none;width:100%;
}
.adv-filter-field input:focus, .adv-filter-field select:focus{ border-color:var(--primary); }
.adv-filter-daterange{ display:flex;gap:5px; }
.adv-filter-foot{ display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:12px;padding-top:10px;border-top:1px dashed var(--border); }
.adv-filter-count{ font-size:11.5px;color:var(--ink-soft); }
.adv-filter-count b{ color:var(--ink); }
.link-btn{ background:none;border:none;color:var(--primary-strong);font-size:11.5px;font-weight:700;cursor:pointer;padding:0; }

/* Modal de envio/substituição de planilha (dois passos — ver
   openCarteiraUploadModal()/renderCarteiraUploadModal()). */
.upload-dropzone{
  border:1.5px dashed var(--border);border-radius:12px;padding:22px;text-align:center;background:var(--surface-2);
  display:flex;flex-direction:column;align-items:center;gap:8px;cursor:pointer;
}
.upload-dropzone svg{ width:28px;height:28px;color:var(--ink-faint); }
.upload-dropzone .ud-title{ font-weight:700;font-size:13px;color:var(--ink); }
.upload-dropzone .ud-sub{ font-size:11px;color:var(--ink-faint); }
.upload-file-picked{
  display:flex;align-items:center;gap:10px;background:var(--success-soft);border-radius:10px;padding:10px 12px;margin-top:4px;
}
.upload-file-picked svg{ width:18px;height:18px;color:var(--success);flex:none; }
.upload-file-picked .ufp-name{ font-weight:700;font-size:12.5px;color:var(--ink); }
.upload-file-picked .ufp-meta{ font-size:10.5px;color:var(--ink-faint); }
/* Modal de anexo de comprovante na Cotação (v2.40.0, pedido do usuário,
   mockup "anexo-cotacao-mockup.html" aprovado) — reaproveita o
   #detailPanel (ver comentário em abrirCotAnexoModal(), frontend.js) com
   este conteúdo próprio. Dropzone/preview de arquivo escolhido reaproveitam
   .upload-dropzone/.upload-file-picked acima; só a área de "colar"
   (Ctrl+V) e o estado "já tem um anexado" são novos. */
.cot-anexo-paste-area{
  border:1.5px dashed var(--border);border-radius:12px;padding:18px;text-align:center;
  background:var(--surface-2);color:var(--ink-faint);font-size:12px;margin-bottom:10px;
}
.cot-anexo-paste-area b{ color:var(--ink); }
.cot-anexo-current{
  display:flex;align-items:center;gap:10px;background:var(--success-soft);border-radius:10px;padding:12px 14px;
}
.cot-anexo-current svg{ width:20px;height:20px;color:var(--success);flex:none; }
.cot-anexo-current a{ font-weight:700;font-size:13px;color:var(--primary-strong);text-decoration:none; }
.cot-anexo-current a:hover{ text-decoration:underline; }
/* Lightbox de visualização do print (v2.40.0) — nunca fica exposto numa
   linha/tela sozinho, só abre ao clicar no link "Ver print" (ver
   abrirCotAnexoLightbox(), frontend.js). z-index acima de .panel/.backdrop
   (51/50) pra sempre aparecer por cima, mesmo com um modal aberto. */
.cf-lightbox-backdrop{
  position:fixed;inset:0;background:rgba(10,14,11,.78);z-index:70;
  display:flex;align-items:center;justify-content:center;padding:30px;cursor:zoom-out;
}
.cf-lightbox-img{ max-width:92vw;max-height:88vh;border-radius:8px;box-shadow:var(--shadow-lg);cursor:default; }
.cf-lightbox-close{
  position:absolute;top:18px;right:22px;width:34px;height:34px;border-radius:50%;border:none;
  background:rgba(255,255,255,.14);color:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;
}
.cf-lightbox-close svg{ width:16px;height:16px; }
.cf-lightbox-pdf-card{
  background:var(--surface);border-radius:12px;padding:28px;display:flex;flex-direction:column;align-items:center;
  gap:12px;cursor:default;
}
.cf-lightbox-pdf-card svg{ width:40px;height:40px;color:var(--primary-strong); }

/* Recortador de logo (v2.44.0) — pedido do usuário: "ha uma maneira de eu
   subir uma imagem de qualquer tamanho e ter a opção do sistema fazer esse
   recorte quadrado?" (escopo confirmado só pro campo "Logo do Fornecedor",
   ver abrirRecortadorLogo() em frontend.js). Mesmo padrão de overlay de tela
   cheia do lightbox de anexo acima (.cf-lightbox-backdrop), com conteúdo
   próprio; z-index acima dele (80) porque o recorte abre em cima do
   #formPanel, que já é mais alto que o #detailPanel onde o lightbox de
   anexo normalmente aparece. */
.cf-croptool-backdrop{
  position:fixed;inset:0;background:rgba(10,14,11,.5);z-index:80;
  display:flex;align-items:center;justify-content:center;padding:20px;
}
.cf-croptool-card{
  background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-md);
  box-shadow:var(--shadow-lg);padding:20px 22px;max-width:360px;width:100%;
}
.cf-croptool-card h3{ font-size:14px;margin:0 0 3px;font-weight:800;color:var(--ink); }
.cf-croptool-card p{ font-size:12px;color:var(--ink-soft);margin:0 0 16px;line-height:1.5; }
.cf-croptool-stage{
  width:280px;height:280px;max-width:100%;margin:0 auto;border-radius:14px;overflow:hidden;position:relative;
  background:repeating-conic-gradient(var(--surface-2) 0% 25%, var(--surface) 0% 50%) 50% / 16px 16px;
  border:1px solid var(--border);cursor:grab;touch-action:none;user-select:none;
}
.cf-croptool-stage.dragging{ cursor:grabbing; }
.cf-croptool-stage img{ position:absolute;left:0;top:0;transform-origin:0 0;pointer-events:none;display:block; }
.cf-croptool-zoom{ display:flex;align-items:center;gap:10px;margin-top:14px; }
.cf-croptool-zoom svg{ width:15px;height:15px;color:var(--ink-faint);flex:none; }
.cf-croptool-zoom input[type="range"]{ flex:1;accent-color:var(--primary); }
.cf-croptool-actions{ display:flex;gap:8px;margin-top:16px;justify-content:flex-end; }
.cf-croptool-hint{ font-size:11px;color:var(--ink-faint);text-align:center;margin-top:10px;line-height:1.5; }

.col-tag-list{ display:flex;flex-direction:column;gap:7px;margin-top:10px; }
.col-tag-row{ display:flex;align-items:center;justify-content:space-between;gap:10px;padding:7px 10px;background:var(--surface-2);border-radius:8px; }
.col-tag-row .ctr-name{ font-size:12.5px;font-weight:600;color:var(--ink); }
.col-tag-row label{ display:flex;align-items:center;gap:6px;font-size:11px;color:var(--ink-soft);cursor:pointer;font-weight:600; }
.col-tag-row input[type="checkbox"]{ width:14px;height:14px;accent-color:var(--accent); }

/* ==================== v2.30.0: Tarefas (individuais e em grupo) ====================
   Mockup aprovado "Tarefas — individuais e em grupo" (análise dos
   gerenciadores de tarefas mais usados do mercado — Todoist, Linear, Trello,
   Asana, ClickUp — ver includes/rest-tarefas.php para o desenho de dados/
   permissões). Tela 100% custom (como "Carteira e Pendências"): a barra de
   ferramentas/toolbar padrão (.toolbar) fica escondida (ver renderCurrentView()
   em frontend.js) e esta tela desenha a própria (.tar-toolbar), reaproveitando
   .search-box/select.filter-select já existentes acima. */
.tar-tabs{ display:flex;gap:6px;margin-bottom:12px;flex-wrap:wrap; }
.tar-tab{ padding:8px 15px;border-radius:999px;font-size:12.5px;font-weight:700;color:var(--ink-soft);border:1px solid var(--border);background:var(--surface);cursor:pointer; }
.tar-tab.active{ background:var(--primary-soft);color:var(--primary-strong);border-color:transparent; }

.tar-toolbar{
  display:flex;gap:10px;align-items:center;flex-wrap:wrap;
  background:var(--surface);border:1px solid var(--border);border-bottom:none;
  border-radius:14px 14px 0 0;padding:13px 16px;
}
.tar-view-toggle{ display:flex;border:1px solid var(--border);border-radius:var(--radius-sm);overflow:hidden;margin-left:auto; }
.tar-view-btn{ padding:7px 13px;font-size:12px;font-weight:700;background:var(--surface);color:var(--ink-soft);cursor:pointer;border:none;display:flex;align-items:center;gap:5px; }
.tar-view-btn svg{ width:13px;height:13px; }
.tar-view-btn.active{ background:var(--primary-soft);color:var(--primary-strong); }
.tar-body{ background:var(--surface);border:1px solid var(--border);border-top:none;border-radius:0 0 14px 14px;box-shadow:var(--shadow-sm); }

.tar-quickadd{ display:flex;align-items:center;gap:10px;padding:13px 16px;border-bottom:1px solid var(--border); }
.tar-quickadd svg.plus{ width:16px;height:16px;color:var(--ink-faint);flex:none; }
.tar-quickadd input{ flex:1;border:none;outline:none;background:transparent;font-size:13.3px;color:var(--ink); }
.tar-quickadd input::placeholder{ color:var(--ink-faint); }
.tar-quickadd button[type="submit"]{ flex:none; }
/* Seletor de responsável da tarefa rápida (v2.37.13) — só aparece pra quem
   gerencia Tarefas (CFG.canManageTarefas); reaproveita o visual do
   select.filter-select já usado em toda a tela, só com largura menor pra
   caber ao lado do campo de título dentro da mesma linha. */
.tar-quickadd select.tar-quickadd-resp{ flex:none;width:auto;max-width:150px;padding:7px 26px 7px 10px;font-size:12.5px; }

.tar-smart-heading{ display:flex;align-items:center;gap:8px;padding:14px 16px 6px;font-size:10.5px;font-weight:800;text-transform:uppercase;letter-spacing:.07em;color:var(--ink-faint); }
.tar-smart-heading.late{ color:var(--danger); }
.tar-smart-heading .count{ background:var(--surface-2);border-radius:999px;padding:1px 7px;font-size:10px;font-weight:700; }

/* v2.40.0 (pedido do usuário, mockup "tarefas-redesign-mockup.html"
   aprovado) — redesenho da linha da listagem: barra de cor lateral por
   prioridade (border-left, trocado pela cor certa em ".tar-row.prio-*"
   abaixo — mesma paleta de TAR_PRIORIDADE_TONE em frontend.js, só com o
   prefixo "prio-" no lugar de "badge-"), prévia da descrição
   (.tar-row-desc), bolinha de status (.tar-status-cell, reaproveitando
   .cot-status-dot já existente da Cotação) e indicador de comentários
   (reaproveita .tar-subprogress, já usado por subtarefas/anexos). */
.tar-row{ display:flex;align-items:center;gap:12px;padding:10px 16px 10px 13px;border-bottom:1px solid var(--border);border-left:3px solid transparent; }
.tar-row:last-child{ border-bottom:none; }
.tar-row:hover{ background:var(--surface-2); }
.tar-row.prio-muted{ border-left-color:var(--ink-faint); }
.tar-row.prio-primary{ border-left-color:var(--primary); }
.tar-row.prio-warn{ border-left-color:var(--warn); }
.tar-row.prio-danger{ border-left-color:var(--danger); }
.tar-row.done{ border-left-color:var(--success); }
.tar-checkbox{ width:17px;height:17px;border-radius:6px;border:1.5px solid var(--border);flex:none;accent-color:var(--success);cursor:pointer; }
.tar-row.done .tar-row-title{ color:var(--ink-faint);text-decoration:line-through; }
.tar-row-main{ flex:1;min-width:0;display:flex;flex-direction:column;gap:4px;cursor:pointer; }
.tar-row-title{ font-size:13.3px;font-weight:600;color:var(--ink); }
.tar-row-desc{ font-size:11.5px;color:var(--ink-faint);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:520px; }
.tar-row-meta{ display:flex;gap:6px;flex-wrap:wrap;align-items:center; }
.tar-status-cell{ display:inline-flex;align-items:center;gap:5px;font-size:10.5px;font-weight:700;color:var(--ink-soft); }
.tar-link-chip{ display:inline-flex;align-items:center;font-size:10.5px;font-weight:700;padding:2px 8px;border-radius:999px;background:var(--surface-2);color:var(--ink-soft);border:1px dashed var(--border); }
.tar-group-chip{ display:inline-flex;align-items:center;gap:4px;font-size:10.5px;font-weight:700;padding:2px 8px 2px 6px;border-radius:999px; }
.tar-row-right{ display:flex;align-items:center;gap:12px;flex:none; }
.tar-due{ font-size:11.5px;color:var(--ink-soft);white-space:nowrap; }
.tar-due.late{ color:var(--danger);font-weight:700; }
.tar-due.today{ color:var(--warn);font-weight:700; }
.tar-due.done{ color:var(--success); }
.tar-subprogress{ font-size:11px;color:var(--ink-faint);background:var(--surface-2);border-radius:999px;padding:2px 7px;white-space:nowrap;display:inline-flex;align-items:center;gap:3px; }
.tar-subprogress svg{ width:10px;height:10px;flex:none; }
@media (max-width:760px){ .tar-row-desc{ max-width:260px; } }

.avatar-stack{ display:flex; }
.avatar-stack .avatar{ width:26px;height:26px;border-radius:50%;font-size:10px;border:2px solid var(--surface);margin-left:-9px; }
.avatar-stack .avatar:first-child{ margin-left:0; }
.avatar-stack .avatar-more{ background:var(--surface-2);color:var(--ink-faint);font-size:9.5px; }

/* ---- quadro kanban ---- */
.tar-board{ display:grid;grid-template-columns:repeat(3,1fr);gap:16px;padding:16px; }
.tar-col{ background:var(--surface-2);border-radius:14px;padding:12px;display:flex;flex-direction:column;gap:10px;min-height:140px; }
.tar-col-head{ display:flex;align-items:center;justify-content:space-between;padding:0 4px 2px; }
.tar-col-title{ font-size:11.5px;font-weight:800;text-transform:uppercase;letter-spacing:.05em;color:var(--ink-soft);display:flex;align-items:center;gap:7px; }
.tar-col-count{ background:var(--surface);border-radius:999px;padding:1px 7px;font-size:10.5px;font-weight:700;color:var(--ink-faint); }
.tar-card{ background:var(--surface);border:1px solid var(--border);border-radius:10px;padding:11px 12px;box-shadow:var(--shadow-sm);display:flex;flex-direction:column;gap:9px;cursor:pointer; }
.tar-card-title{ font-size:13px;font-weight:600;color:var(--ink); }
.tar-card-foot{ display:flex;align-items:center;justify-content:space-between;gap:8px; }
@media (max-width:980px){ .tar-board{ grid-template-columns:1fr; } }

/* ---- grupos de tarefas ---- */
.tar-groups-grid{ display:grid;grid-template-columns:repeat(3,1fr);gap:16px; }
.tar-group-card{ background:var(--surface);border:1px solid var(--border);border-radius:14px;padding:16px;box-shadow:var(--shadow-sm);display:flex;flex-direction:column;gap:11px;cursor:pointer; }
.tar-group-dot{ width:10px;height:10px;border-radius:50%;flex:none; }
.tar-group-head{ display:flex;align-items:center;gap:9px; }
/* Botão "Editar grupo" (lápis) no cabeçalho do cartão — mesmo padrão de
   "<contexto> .btn-icon svg{...}" já usado no resto do app (ver o comentário
   em assets/frontend.css, seção de Itens de Portfólio): sem isto o ícone sai
   sem largura/altura (padrão do navegador pra um <svg> sem width/height). */
.tar-group-head .btn-icon{ margin-left:auto;flex:none; }
.tar-group-head .btn-icon svg{ width:14px;height:14px;flex:none; }
.tar-group-name{ font-weight:700;font-size:14px;flex:1; }
.tar-progress-bar{ height:6px;border-radius:999px;background:var(--surface-2);overflow:hidden; }
.tar-progress-fill{ height:100%;background:var(--success); }
.tar-group-stats{ display:flex;justify-content:space-between;font-size:11.5px;color:var(--ink-faint); }
.tar-new-group-card{ border:1.5px dashed var(--border);border-radius:14px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;color:var(--ink-faint);font-weight:700;font-size:12.5px;min-height:142px;background:none;cursor:pointer; }
.tar-new-group-card svg{ width:22px;height:22px; }
@media (max-width:980px){ .tar-groups-grid{ grid-template-columns:1fr 1fr; } }
@media (max-width:620px){ .tar-groups-grid{ grid-template-columns:1fr; } }

/* ---- checklist de subtarefas (painel de detalhe) ---- */
.tar-checklist{ display:flex;flex-direction:column;gap:9px; }
.tar-checklist-item{ display:flex;align-items:center;gap:9px;font-size:13px; }
.tar-checklist-item.done span{ color:var(--ink-faint);text-decoration:line-through; }
.tar-checklist-item button{ margin-left:auto;background:none;border:none;color:var(--ink-faint);cursor:pointer;padding:2px; }
.tar-checklist-item button:hover{ color:var(--danger); }
.tar-checklist-item button svg{ width:13px;height:13px;flex:none; }
.tar-checklist-add{ display:flex;align-items:center;gap:9px;margin-top:4px; }
.tar-checklist-add input{ flex:1;border:none;border-bottom:1px dashed var(--border);outline:none;background:transparent;font-size:12.5px;color:var(--ink);padding:4px 0; }

/* ---- anexos de tarefa (v2.30.1) ---- */
.tar-anexos{ display:flex;flex-direction:column;gap:7px; }
.tar-anexo-item{ display:flex;align-items:center;gap:9px;font-size:13px;background:var(--surface-2);border-radius:10px;padding:8px 10px; }
.tar-anexo-info{ display:flex;align-items:center;gap:8px;flex:1;min-width:0;color:var(--ink);text-decoration:none; }
.tar-anexo-info:hover .tar-anexo-nome{ text-decoration:underline; }
.tar-anexo-info svg{ width:15px;height:15px;flex:none;color:var(--ink-faint); }
.tar-anexo-nome{ overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:600; }
.tar-anexo-meta{ font-size:11px;color:var(--ink-faint);white-space:nowrap;flex:none; }
.tar-anexo-item button{ margin-left:auto;background:none;border:none;color:var(--ink-faint);cursor:pointer;padding:2px;flex:none; }
.tar-anexo-item button:hover{ color:var(--danger); }
.tar-anexo-item button svg{ width:13px;height:13px;flex:none; }
.tar-anexo-item button:disabled{ opacity:.5;cursor:default; }
.tar-anexo-add{ display:inline-flex;align-items:center;gap:7px;margin-top:9px;font-size:12.5px;color:var(--primary);cursor:pointer;font-weight:600; }
.tar-anexo-add svg{ width:14px;height:14px;flex:none; }
.tar-anexo-add.loading{ opacity:.6;pointer-events:none; }

/* ================= Administrador → Configurações (v2.31.0) =================
   Permissões ("Por Papel"/"Por Usuário") e Ordem dos Menus — mockup aprovado
   "Novo menu 'Administrador' → Configurações". Mesmos tokens de sempre
   (--surface/--border/--ink/--primary etc., ver :root no topo deste
   arquivo); nenhuma cor nova foi introduzida. */
.settings-shell{ display:grid;grid-template-columns:220px 1fr;gap:20px;align-items:start; }
@media (max-width:760px){ .settings-shell{ grid-template-columns:1fr; } }
.settings-nav{ display:flex;flex-direction:column;gap:4px;background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:8px; }
.settings-nav-item{
  display:flex;align-items:center;justify-content:space-between;gap:8px;
  padding:10px 12px;border-radius:8px;background:none;border:none;text-align:left;
  font-size:13.3px;font-weight:600;color:var(--ink-soft);cursor:pointer;
}
.settings-nav-item:hover{ background:var(--surface-2);color:var(--ink); }
.settings-nav-item.active{ background:var(--primary-soft);color:var(--primary-strong); }
.settings-nav-item.soon{ cursor:default;color:var(--ink-faint); }
.settings-nav-item.soon:hover{ background:none;color:var(--ink-faint); }
.tag-soon{ font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.03em;color:var(--ink-faint);background:var(--surface-2);border:1px dashed var(--border);border-radius:999px;padding:2px 7px; }
.settings-content{ background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:18px;min-width:0; }

.cf-config-subtabs{ display:flex;gap:6px;margin-bottom:16px;border-bottom:1px solid var(--border);padding-bottom:10px; }
.cf-config-subtab{ background:none;border:none;padding:8px 14px;border-radius:999px;font-size:12.5px;font-weight:700;color:var(--ink-soft);cursor:pointer; }
.cf-config-subtab:hover{ background:var(--surface-2);color:var(--ink); }
.cf-config-subtab.active{ background:var(--primary);color:var(--primary-ink); }

/* ---- tabela "Por Papel" ---- */
.perm-table{ width:100%;border-collapse:collapse;font-size:13px; }
.perm-table thead th{ text-align:left;font-size:11px;text-transform:uppercase;letter-spacing:.03em;color:var(--ink-faint);padding:8px 10px;border-bottom:1px solid var(--border);position:sticky;top:0;background:var(--surface); }
.perm-table tbody td{ padding:10px;border-bottom:1px solid var(--border);vertical-align:middle; }
.perm-group-row td{ background:var(--surface-2);font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.03em;color:var(--ink-soft);padding:7px 10px; }
.perm-mod-nome{ font-weight:700;color:var(--ink); }
.perm-mod-desc{ font-size:11.5px;color:var(--ink-faint);margin-top:2px; }
.perm-cell{ text-align:center; }
.perm-checkbox input{ width:17px;height:17px;cursor:pointer;accent-color:var(--primary); }
.perm-cell-locked{ text-align:center;color:var(--ink-faint);display:table-cell; }
.perm-cell-locked svg{ width:13px;height:13px;flex:none;vertical-align:-2px;margin-right:3px; }
.perm-table-legend{ display:flex;align-items:flex-start;gap:7px;margin-top:14px;font-size:11.5px;color:var(--ink-faint); }
.perm-table-legend svg{ width:13px;height:13px;flex:none;margin-top:1px; }

/* ---- "Por Usuário" (exceções) ---- */
.exception-list{ display:flex;flex-direction:column;gap:8px;margin-bottom:14px; }
.exception-row{ display:flex;align-items:center;gap:14px;flex-wrap:wrap;background:var(--surface-2);border-radius:10px;padding:10px 12px; }
.exc-user{ display:flex;flex-direction:column;gap:2px;min-width:130px; }
.exc-user-papel{ font-size:10.5px;font-weight:700;text-transform:uppercase;color:var(--ink-faint); }
.exc-chips{ display:flex;gap:6px;flex-wrap:wrap;flex:1; }
.exc-chip{ display:inline-flex;align-items:center;gap:5px;background:var(--primary-soft);color:var(--primary-strong);font-size:11.5px;font-weight:600;border-radius:999px;padding:4px 6px 4px 10px; }
.exc-remove{ background:none;border:none;color:var(--primary-strong);cursor:pointer;padding:2px;display:inline-flex; }
.exc-remove svg{ width:10px;height:10px;flex:none; }
.exc-remove:hover{ color:var(--danger); }
.add-exception{
  display:inline-flex;align-items:center;gap:7px;background:none;border:1.5px dashed var(--border);
  border-radius:10px;padding:10px 14px;color:var(--ink-faint);font-weight:700;font-size:12.5px;cursor:pointer;
}
.add-exception:hover{ border-color:var(--primary);color:var(--primary); }
.add-exception svg{ width:14px;height:14px;flex:none; }
.user-search-box{ display:flex;flex-direction:column;gap:12px;background:var(--surface-2);border-radius:10px;padding:14px;max-width:420px; }
.exc-busca-resultados{ display:flex;flex-direction:column;gap:2px;margin-top:4px; }
.exc-busca-resultado{ padding:7px 9px;border-radius:7px;font-size:12.5px;cursor:pointer;display:flex;justify-content:space-between;gap:8px; }
.exc-busca-resultado:hover{ background:var(--surface); }
.exc-busca-vazia{ font-size:11.5px;color:var(--ink-faint);padding:4px 2px; }
.exc-usuario-escolhido{ font-size:12px;color:var(--success);margin-top:4px; }

/* ---- "Ordem dos Menus" — sem arrastar-e-soltar de propósito, mesma
   decisão já tomada pro board de Tarefas; reordenar é sempre um clique num
   botão com seta, nunca um drag. ---- */
.reorder-block{ margin-bottom:22px; }
.reorder-block h3{ font-size:12.5px;font-weight:700;color:var(--ink-soft);margin:0 0 10px; }
.reorder-item{ display:flex;align-items:center;gap:10px;background:var(--surface-2);border-radius:9px;padding:9px 12px;margin-bottom:6px; }
.reorder-label{ font-size:13px;font-weight:600;color:var(--ink);flex:1; }
.reorder-actions{ display:flex;gap:4px;flex:none; }
.reorder-actions .btn-icon svg{ width:13px;height:13px;flex:none; }
.pin-tag{ font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:.03em;color:var(--ink-faint);background:var(--surface);border:1px dashed var(--border);border-radius:999px;padding:3px 8px;flex:none; }
.reorder-group-item{ border:1px solid var(--border);border-radius:10px;margin-bottom:6px;overflow:hidden; }
.reorder-group-head{ display:flex;align-items:center;gap:10px;padding:10px 12px;cursor:pointer;background:var(--surface-2); }
.reorder-group-head svg:first-child{ width:16px;height:16px;flex:none;color:var(--ink-soft); }
.reorder-group-item.open .reorder-group-head{ background:var(--primary-soft); }
.reorder-group-body{ padding:8px 12px 10px 30px;background:var(--surface); }
.reorder-group-body .reorder-item{ background:var(--surface-2); }
#ordemRestaurarBtn svg{ width:14px;height:14px;flex:none; }
